日期:2026-08-19 状态:待审阅
需要基于 mp_user_points_details 明细表建立一套使用量统计系统,支持按日期、用户、模型、中转站四个维度查看数据,供平台管理员(superadmin)查看全部用户、组织管理员(admin)查看本公司(cpid)用户的统计数据。
核心诉求:
审查中发现并修复了视频积分明细 token 恒为 0 的 bug:
AIVideoGenerationService::markVideoTaskSuccess() 更新数据库后未同步内存中 $task->result_json,导致随后扣费解析 token 时读到旧空值。markVideoTaskSuccess 同步内存属性,并新增 points:backfill-video-tokens 命令回填历史数据(已执行完毕)。analyzeErrorMessage(错误友好翻译)与 geminiGenerateText(潜在未接线路径)两处缺失的 token 记录。mp_model_relay_map用途:维护模型名与中转站的对应关系,统计任务按模型名关联出中转站。
| 字段 | 类型 | 说明 |
|---|---|---|
| id | bigint unsigned PK AI | |
| model | varchar(255) NOT NULL UNIQUE | 模型名 |
| relay_name | varchar(100) NOT NULL | 中转站名称 |
| remark | varchar(255) NULL | 备注 |
| created_at / updated_at | timestamp |
migration 中初始化以下映射(智能分析所得,后续可人工增改):
| 模型 | 中转站 |
|---|---|
| deepseek-chat / deepseek-reasoner / deepseek-v4-flash / deepseek-v4-pro | DeepSeek 官方 |
| deepseek-v3-2-251201 | 火山方舟 |
| doubao-seed-2-0-mini/lite/pro-260215 | 火山方舟 |
| doubao-seedream-4-5-251128 / doubao-seedream-5-0-260128 / doubao-seedream-5-0-lite-260128 | 火山方舟 |
| doubao-seedance-1-5-pro-251215 / doubao-seedance-2-0-260128 / doubao-seedance-2-0-fast-260128 | 火山方舟 |
| doubao-seedance-2.0 | 百度 |
| zhizhen-20 / zhizhen-20-fast / zhizhen-20-mini | 智帧 |
| gpt-5.4 / gpt-5.6-terra / gpt-5.6-sol / gpt-5.6-luna / gpt-image-2 / GptImage2 | GPT 中转站 |
| gemini-3-pro-preview / gemini-3-flash-preview / gemini-3.1-pro-preview / gemini-3.1-flash-image-preview-t / gemini-3.6-flash | Gemini 中转站 |
| NanoBanana2 / NanoBananaPro | NanoBanana |
未命中映射的模型在统计中归为 unknown。
mp_points_daily_stats用途:按 (stat_date, uid, model, relay) 维度预聚合的日粒度统计。
| 字段 | 类型 | 说明 |
|---|---|---|
| id | bigint unsigned PK AI | |
| stat_date | date NOT NULL | 统计日期(按明细 created_at 归属) |
| uid | bigint unsigned NOT NULL | 用户 ID |
| cpid | bigint NOT NULL DEFAULT 0 | 用户所属组织(组织管理员过滤用) |
| model | varchar(255) NOT NULL | 模型名 |
| relay | varchar(100) NOT NULL DEFAULT 'unknown' | 中转站名称 |
| call_count | int unsigned NOT NULL DEFAULT 0 | 调用次数 |
| tokens_consumed | bigint NOT NULL DEFAULT 0 | token 消耗合计(核心指标) |
| points_consumed | decimal(13,1) NOT NULL DEFAULT 0 | 积分消耗合计(附带指标) |
| created_at / updated_at | timestamp |
索引:
uk_date_uid_model_relay (stat_date, uid, model, relay)idx_stat_date_cpid (stat_date, cpid)idx_relay (relay)idx_model (model)stats:points-daily参数:
--date=YYYY-MM-DD:只统计指定日期(默认昨天)--from=YYYY-MM-DD --to=YYYY-MM-DD:批量补跑日期区间统计口径:
mp_user_points_details,按 created_at 归属到日期。type IN (chat, image, video),排除 system/company(发放/回收,无模型、无 token)。test_mode,测试用户记录全部纳入(按用户确认)。charge_info->model,为空回退 api_type,再为空归 unknown。mp_model_relay_map 关联,未命中归 unknown。call_count = COUNT(*),tokens_consumed = SUM(tokens_consumed),points_consumed = SUM(points_consumed)。写入方式:按日期在事务内先删除该日旧数据再批量插入(幂等,可重复执行)。
调度:Kernel::schedule 中每天 00:10 执行 stats:points-daily,withoutOverlapping() 防止并发。
GET /api/points/stats权限:
superadmin:查询全部用户数据。admin:自动限定 cpid 为当前登录用户所属组织。请求参数:
| 参数 | 必填 | 说明 |
|---|---|---|
| start_date / end_date | 否 | 日期范围,默认近 30 天 |
| uid | 否 | 用户 ID,支持逗号分隔多个 |
| model | 否 | 模型名 |
| relay | 否 | 中转站名称 |
| group_by | 否 | 聚合维度,date/uid/model/relay 任意组合(如 date,model),默认四维全部分组 |
| page / page_size | 否 | 分页,默认 15,最大 100 |
响应(沿用现有 ApiResponse 风格):
{
"code": 0,
"data": {
"list": [
{
"stat_date": "2026-08-18",
"uid": 142858,
"nickname": "用户昵称",
"model": "zhizhen-20",
"relay": "智帧",
"call_count": 10,
"tokens_consumed": 1309900,
"points_consumed": 840.0
}
],
"meta": {
"current_page": 1,
"last_page": 10,
"per_page": 15,
"total": 145
},
"summary": {
"call_count": 1000,
"tokens_consumed": 100000000,
"points_consumed": 80000.0
}
}
}
GET /api/points/stats/filters返回当前权限范围内的可选值,供前端下拉框使用:
database/migrations/xxxx_create_mp_model_relay_map_table.phpdatabase/migrations/xxxx_create_mp_points_daily_stats_table.phpapp/Console/Commands/PointsDailyStatsCommand.phpapp/Services/PointsStatsService.phpapp/Http/Controllers/Points/PointsStatsController.phpapp/Transformer/Points/PointsStatsTransformer.php(如有需要)routes/api.php 新增路由--date 统计结果与明细表 SQL 对账一致。