# 租户端数据统计分析看板 — 设计方案 > 所属端:租户端(机构管理端) > 状态:已实现(后端契约与租户过滤已对齐 [2026-04-09]) > 创建日期:2026-03-31 > 最后更新:2026-04-09 --- ## 1. 需求背景 机构领导需要一个数据统计看板来了解: - 活动运营情况:活动办得怎么样,报名和参赛情况 - 运营效率:审核速度、评审进度、整体运营时效 - 评委工作量:每位评委评了多少作品、评分质量 ## 2. 数据来源盘点 基于现有系统已实现的功能,可用的数据表和字段: | 数据表 | 可用维度 | 可用指标 | |--------|----------|----------| | t_contest | 活动名称、类型、状态(ongoing/finished)、发布状态、各时间节点 | 活动数量、阶段分布 | | t_contest_registration | 活动ID、审核状态(pending/passed/rejected)、报名时间 | 报名数、通过率、时间分布 | | t_contest_work | 活动ID、状态(submitted/reviewing/accepted/awarded)、提交时间、最终得分、排名、奖项 | 作品数、评审状态分布、得分分布、获奖分布 | | t_contest_work_score | 作品ID、评委ID、分数、评分时间 | 评委评分量、评分时间分布 | | t_contest_work_judge_assignment | 作品ID、评委ID、状态 | 分配完成率 | | t_contest_judge | 活动ID、评委ID | 评委数量、评委-活动关联 | | t_contest_notice | 活动ID、发布时间 | 公告数量 | ## 3. 看板设计 ### 3.1 整体结构 ``` ┌──────────────────────────────────────────────────────────────┐ │ 数据统计 时间范围: [本月▾] [活动▾] │ ├──────────────────────────────────────────────────────────────┤ │ │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │活动数│ │报名数│ │通过数│ │作品数│ │已评审│ │获奖数│ │ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │ │ │ │ ┌───── 报名转化漏斗 ─────┐ ┌────── 月度趋势 ──────────┐ │ │ │ 报名 → 通过 → 提交 │ │ 📈 报名量/作品量折线图 │ │ │ │ → 评审完成 → 获奖 │ │ │ │ │ └────────────────────────┘ └──────────────────────────┘ │ │ │ │ ┌───── 活动对比 ─────────────────────────────────────────┐ │ │ │ 表格:各活动 报名/通过率/作品提交率/评审完成率/获奖率 │ │ │ └───────────────────────────────────────────────────────┘ │ │ │ │ ┌──── 评委工作量 ────────┐ ┌────── 奖项分布 ──────────┐ │ │ │ 表格:评委 评审量/均分 │ │ 🥧 饼图:各奖项占比 │ │ │ └────────────────────────┘ └──────────────────────────┘ │ │ │ │ ┌──── 评审效率 ──────────────────────────────────────────┐ │ │ │ 平均评审周期 │ 日均评审量 │ 待评审积压 │ 评分标准差 │ │ │ └───────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────┘ ``` ### 3.2 模块详细设计 #### 模块A:核心指标卡片(顶部) 6 个数字卡片,一行排列: | 指标 | 数据来源 | 计算方式 | |------|----------|----------| | 活动总数 | t_contest | COUNT WHERE tenant 可见 | | 累计报名 | t_contest_registration | COUNT WHERE tenant_id | | 报名通过 | t_contest_registration | COUNT WHERE registration_state='passed' | | 作品总数 | t_contest_work | COUNT WHERE valid_state=1 | | 已完成评审 | t_contest_work | COUNT WHERE status IN ('accepted','awarded') | | 获奖作品 | t_contest_work | COUNT WHERE award_level IS NOT NULL AND award_level != 'none' | #### 模块B:报名转化漏斗 展示从报名到获奖的转化路径和各环节转化率: ``` 报名人数 (12) → 通过审核 (10) → 提交作品 (8) → 评审完成 (5) → 获奖 (3) 83.3% 80.0% 62.5% 60.0% ``` 数据来源: - 报名人数:registration COUNT - 通过审核:registration COUNT WHERE state='passed' - 提交作品:work COUNT WHERE valid_state=1 - 评审完成:work COUNT WHERE status IN ('accepted','awarded') - 获奖:work COUNT WHERE award_name IS NOT NULL #### 模块C:月度趋势图 折线图,X轴为月份,Y轴双轴: - 左轴:报名数量(按 registration_time 月份分组) - 右轴:作品数量(按 submit_time 月份分组) 时间范围:最近6个月 数据来源: ```sql -- 月度报名 SELECT DATE_FORMAT(registration_time, '%Y-%m') as month, COUNT(*) FROM t_contest_registration WHERE tenant_id=? GROUP BY month ORDER BY month -- 月度作品 SELECT DATE_FORMAT(submit_time, '%Y-%m') as month, COUNT(*) FROM t_contest_work WHERE tenant_id=? AND valid_state=1 GROUP BY month ORDER BY month ``` #### 模块D:活动对比表 表格形式,每行一个活动: | 列 | 数据来源 | |----|----------| | 活动名称 | t_contest.contest_name | | 报名数 | registration COUNT | | 通过率 | passed COUNT / total COUNT × 100% | | 作品提交率 | work COUNT / passed registration COUNT × 100% | | 评审完成率 | (accepted+awarded) COUNT / work COUNT × 100% | | 获奖率 | awarded COUNT / work COUNT × 100% | | 平均得分 | AVG(final_score) | #### 模块E:评委工作量 表格形式,每行一个评委: | 列 | 数据来源 | |----|----------| | 评委姓名 | users.nickname via t_contest_judge | | 关联活动数 | t_contest_judge COUNT DISTINCT contest_id | | 已分配作品数 | t_contest_work_judge_assignment COUNT | | 已评分作品数 | t_contest_work_score COUNT | | 评分完成率 | scored / assigned × 100% | | 平均打分 | AVG(total_score) | | 评分标准差 | STDDEV(total_score)(衡量评分一致性,越小越一致) | #### 模块F:奖项分布 饼图/环形图,展示获奖作品中各奖项的占比: 数据来源: ```sql SELECT award_name, COUNT(*) FROM t_contest_work WHERE tenant_id=? AND award_name IS NOT NULL AND valid_state=1 GROUP BY award_name ``` #### 模块G:评审效率指标 4 个数字卡片: | 指标 | 计算方式 | |------|----------| | 平均评审周期 | AVG(score_time - submit_time),从作品提交到第一次评分的平均天数 | | 日均评审量 | 最近30天 score COUNT / 30 | | 待评审积压 | assignment COUNT WHERE status='assigned'(已分配未评分) | | 评分一致性 | 所有作品的评委间评分标准差的平均值(越小越好) | ### 3.3 筛选条件 顶部全局筛选栏: | 筛选 | 类型 | 说明 | |------|------|------| | 时间范围 | 下拉 | 本月/本季度/本年/全部/自定义时间段 | | 指定活动 | 下拉 | 全部活动 / 选择特定活动(切换后所有模块联动) | ### 3.4 交互设计 - 数字卡片可点击,跳转到对应管理页面(如点击「累计报名」跳到报名管理) - 活动对比表的活动名称可点击,切换筛选到该活动 - 评委工作量表的评委名可点击查看评分明细 - 所有图表支持 hover 显示详细数据 - 支持将看板数据导出为 PDF/Excel ## 4. 菜单位置 新增一级菜单「数据统计」,放在「活动管理」之后: ``` 工作台 活动管理 ├── ... 数据统计(新增) ├── 运营概览 — 核心卡片 + 漏斗 + 趋势 + 活动对比 └── 评审分析 — 评委工作量 + 评审效率 + 奖项分布 系统设置 ├── ... ``` ## 5. 后端 API 设计 上下文路径以部署为准(开发环境一般为 `/api`)。实现类:`AnalyticsController` / `AnalyticsService` / `AnalyticsMapper`。 **多租户**:非超级租户时,活动范围由 `t_biz_contest.contest_tenants`(JSON 授权)限定;报名/作品/评分等子表再按 `tenant_id` 过滤。超级租户不按 `contest_tenants` 限活动。 ### 5.1 运营概览 ``` GET /analytics/overview 参数: timeRange: 可选。month | quarter | year;不传或 all 表示不限时间。 作用于 summary、funnel、contestComparison 的时间过滤(报名按 registration_time,作品按 submit_time)。 contestId: 可选。指定单个活动;须属于当前租户可见活动。 返回: { summary: { totalContests, totalRegistrations, passedRegistrations, totalWorks, reviewedWorks, awardedWorks }, funnel: { registered, passed, submitted, reviewed, awarded }, // 对象,非数组 monthlyTrend: [{ month: 'YYYY-MM', registrations, works }], // 最近 6 个自然月,与 timeRange 独立 contestComparison: [{ contestId, contestName, registrations, passRate, submitRate, reviewRate, awardRate, avgScore }] } ``` 指标口径简述:`reviewedWorks` / 漏斗 `reviewed` 为作品 `status IN ('accepted','awarded')`;`awardedWorks` 为 `award_level` 非空且不为 `none`。 ### 5.2 评审分析 ``` GET /analytics/review 参数: contestId: 可选,同上。 timeRange: 可传(与前端下拉一致);当前实现中评审分析各模块为「可见活动」全量统计,该参数预留,不参与过滤。 返回: { efficiency: { avgReviewDays, dailyReviewCount, pendingAssignments, avgScoreStddev }, judgeWorkload: [{ judgeId, judgeName, contestCount, assignedCount, scoredCount, completionRate, avgScore, scoreStddev }], awardDistribution: [{ awardName, count, percentage }] } ``` `efficiency`:`avgReviewDays` 为作品提交至首次评分的平均天数;`dailyReviewCount` 为近 30 天评分条数 / 30;`pendingAssignments` 为分配状态 `assigned` 的条数;`avgScoreStddev` 为「多评委作品」分数标准差再对作品取平均。 ## 6. 技术方案 - 前端图表库:使用 ECharts 或 Ant Design Charts(@ant-design/charts) - 数据缓存:统计数据变化不频繁,后端可加 5 分钟缓存 - 大数据量:月度趋势等聚合查询用 GROUP BY + 索引优化 - 导出:前端生成 PDF(html2canvas + jsPDF)或 CSV