studytime-analysis: 新增留存状态判定 — 最近14天无完课标记为流失,否则正常
This commit is contained in:
parent
ed6c864197
commit
cde77e762d
@ -7,4 +7,4 @@ lark_wiki_operate_as_bot 2a37701f568849f03eb46dd938baeda171380fe252b698ac8bda69c
|
|||||||
vala_git_workspace_backup 4cf352bec88fe84af065ba1ffcbb06647b77df0e01860faaf0bca9fd64b968ec
|
vala_git_workspace_backup 4cf352bec88fe84af065ba1ffcbb06647b77df0e01860faaf0bca9fd64b968ec
|
||||||
cron-schedule b1879fa59d60e3d99cea1138674f7abac84a4aecd32743b801d41bfd6ed7181d
|
cron-schedule b1879fa59d60e3d99cea1138674f7abac84a4aecd32743b801d41bfd6ed7181d
|
||||||
study-analysis 33217dc132073ecd47b921800834f6df89494da9e7708fa90f15b3de7742e37f
|
study-analysis 33217dc132073ecd47b921800834f6df89494da9e7708fa90f15b3de7742e37f
|
||||||
studytime-analysis 042178f9f7e97eeef366fd619403f4d0c8e0dce290abf17af662dddfa67c4e83
|
studytime-analysis a3b2570583717cf5af2720f047de23752ee42cba8ff4a3f859d216e0580026ae
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import sys
|
|||||||
import psycopg2
|
import psycopg2
|
||||||
import psycopg2.extras
|
import psycopg2.extras
|
||||||
import pymysql
|
import pymysql
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from collections import defaultdict, OrderedDict
|
from collections import defaultdict, OrderedDict
|
||||||
|
|
||||||
# ── 配置 ──────────────────────────────────────────────
|
# ── 配置 ──────────────────────────────────────────────
|
||||||
@ -148,6 +148,21 @@ def fetch_role_info(role_id):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def check_retention(records, cutoff_days=14):
|
||||||
|
"""
|
||||||
|
检查角色留存状态
|
||||||
|
- 最近 cutoff_days 天内有完课记录 → "正常"
|
||||||
|
- 否则 → "流失"
|
||||||
|
当无任何完课记录时,返回 "无完课记录"
|
||||||
|
"""
|
||||||
|
if not records:
|
||||||
|
return "无完课记录"
|
||||||
|
# 用本地时间比较(与 PG 存储时区一致 UTC+8)
|
||||||
|
cutoff = datetime.now() - timedelta(days=cutoff_days)
|
||||||
|
has_recent = any(r["updated_at"].replace(tzinfo=None) >= cutoff for r in records)
|
||||||
|
return "正常" if has_recent else "流失"
|
||||||
|
|
||||||
|
|
||||||
def fetch_completion_records(role_id):
|
def fetch_completion_records(role_id):
|
||||||
"""查询指定角色全部完课记录(包含寒暑假)"""
|
"""查询指定角色全部完课记录(包含寒暑假)"""
|
||||||
params = {}
|
params = {}
|
||||||
@ -321,7 +336,7 @@ def analyze_weekly_trend(records):
|
|||||||
|
|
||||||
# ── 输出格式化 ────────────────────────────────────────
|
# ── 输出格式化 ────────────────────────────────────────
|
||||||
|
|
||||||
def format_report(role_id, role_info, all_records, non_holiday_records, holiday_count, day_counts, weekday_periods, weeks_data, analysis):
|
def format_report(role_id, role_info, retention_status, all_records, non_holiday_records, holiday_count, day_counts, weekday_periods, weeks_data, analysis):
|
||||||
"""生成 Markdown 格式分析报告
|
"""生成 Markdown 格式分析报告
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -352,6 +367,8 @@ def format_report(role_id, role_info, all_records, non_holiday_records, holiday_
|
|||||||
lines.append(f"| 年龄 | {role_info['age']} 岁 |")
|
lines.append(f"| 年龄 | {role_info['age']} 岁 |")
|
||||||
if role_info['phone_tail']:
|
if role_info['phone_tail']:
|
||||||
lines.append(f"| 账号手机号后4位 | {role_info['phone_tail']} |")
|
lines.append(f"| 账号手机号后4位 | {role_info['phone_tail']} |")
|
||||||
|
if retention_status:
|
||||||
|
lines.append(f"| 最近留存状态 | {retention_status} |")
|
||||||
lines.append(f"")
|
lines.append(f"")
|
||||||
|
|
||||||
# ── 数据概况 ──
|
# ── 数据概况 ──
|
||||||
@ -566,12 +583,15 @@ def main():
|
|||||||
# 角色基本信息(MySQL)
|
# 角色基本信息(MySQL)
|
||||||
role_info = fetch_role_info(role_id)
|
role_info = fetch_role_info(role_id)
|
||||||
|
|
||||||
|
# 留存状态判定
|
||||||
|
retention_status = check_retention(all_records)
|
||||||
|
|
||||||
# 一周分布分析:仅用非寒暑假数据
|
# 一周分布分析:仅用非寒暑假数据
|
||||||
day_counts, weekday_periods = analyze_weekly_distribution(non_holiday_records)
|
day_counts, weekday_periods = analyze_weekly_distribution(non_holiday_records)
|
||||||
# 跨周趋势分析:用全部数据
|
# 跨周趋势分析:用全部数据
|
||||||
weeks_data, analysis = analyze_weekly_trend(all_records)
|
weeks_data, analysis = analyze_weekly_trend(all_records)
|
||||||
|
|
||||||
report = format_report(role_id, role_info, all_records, non_holiday_records, holiday_count, day_counts, weekday_periods, weeks_data, analysis)
|
report = format_report(role_id, role_info, retention_status, all_records, non_holiday_records, holiday_count, day_counts, weekday_periods, weeks_data, analysis)
|
||||||
|
|
||||||
print(report)
|
print(report)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user