评审3真问题全修:排序白名单四列(余列不排序)/服务页签图改P50P90双线 (员工级无每日率序列)/CSV扩csvExport注释行+rows适配;advisory全采: 异常卡补employee_name(一行后端)/showEmployee复用开关/formula_note归位/ 伪卡片下钻衔接/compare仅显示态
15 KiB
云客经营管理后台·批次D(员工总览+员工详情)实施计划
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 补上管理闭环最大断点——员工总览(41 人多维一张表)与员工详情(五维/页签/四对比/事实下钻),打通「异常→员工全景→事实」链路;附带驾驶舱 KPI 环比与时间预设补全(体验级小项)。
Architecture: 纯前端为主(消费批次B已就绪的 employees/detail/metrics sections/drilldown 端点)+ 两处小后端增强(dashboard kpis 加 prev 块;无新端点)。新页 EmployeeAnalyticsView/EmployeeAnalyticsDetailView + 对比抽屉;复用 C3 六组件(FilterBar/DataAsOfBadge/AnomalyList/MetricDrilldownDrawer/MetricDefsDrawer)与 useManagementFilters。依据 v2 计划 §6/§7/§13 + 批次B契约清单。
Tech Stack: 同批次C(Vue3+TS+Element Plus+useChart+vitest);后端 FastAPI 小改。
执行者必读
- 消费的端点 as-built 形态(写 client 前已核对 management.py:321-443):
GET /employees(行结构见批次C client 的 EmployeeRow——已含 metrics/comparisons/score 摘要/anomaly_count/weight);GET /employees/{id}:{user_id,name,is_on_job,accounts[{channel,account_id,nick_name,user_name}],metrics(22字段dict 含 user_id 键),score{total_score,grade,score_status,trial,dimensions{name,weight,score,status,metrics{code:{value,score,sample_size,sample_status,formula_note}}},metrics_detail{code:{value,prev,baseline,median,sample_size,sample_status,score,unit,name}}},anomalies[],prev(dict|null),baseline(dict|null),scope,data_as_of,metric_version,config_source};GET /employees/{id}/metrics?section=:{section,metrics(该域字段dict),trend[{day,cols...}](无数据日计数0/分位None),comparisons(源指标名键),scope,data_as_of,metric_version};- drilldown/metric-definitions 已有 client。
- 前端惯例同批次C必读(seq 守卫/useChart/URL query/csvExport.ts 全量翻页+中文 BOM/命名路由跳转)。
- 不做:辅导/快照(E);员工对比不新开 API(勾选 2-5 行客户端拼数据);「指标解释抽屉」= 复用 MetricDefsDrawer(点击列头 ? 图标打开)——不做每指标单独解释面板(v1 §6.5 的完整版二期)。
- 仓库并行会话照旧;中文 conventional 提交;master 直提。
文件地图
| 文件 | 动作 |
|---|---|
yunkes/src/api/management.ts |
补 getEmployeeDetail/getEmployeeMetrics + types(D0) |
yunkes/src/composables/useManagementFilters.ts |
预设补 今日/昨日/本周/上周(D0) |
yunkes/src/views/management/EmployeeAnalyticsView.vue |
新建(D1) |
yunkes/src/components/management/EmployeeCompareDrawer.vue |
新建(D1,对比抽屉) |
yunkes/src/views/management/EmployeeAnalyticsDetailView.vue |
新建(D2) |
yunkes/src/router/index.ts + MainLayout.vue |
两路由+两菜单(D1/D2 各自) |
yunke-server/app/api/routers/management.py + api_assembly.py |
dashboard kpis 加 prev 块(D3) |
yunkes/src/components/management/ManagementKpiCard.vue + AnomalyList.vue + 驾驶舱页 |
delta 显示 + 员工跳详情(D3) |
Task D0: client 补全 + 预设扩展
api/management.ts追加:
export interface EmployeeAccount { channel: string; account_id: string; nick_name: string | null; user_name: string | null }
export interface ScoreMetricDetail { value: number | null; prev: number | null; baseline: number | null; median: number | null; sample_size: number; sample_status: string; score: number | null; unit: string; name: string }
// formula_note 在 dimensions[dim].metrics[code] 上(scoring.py 维度级明细),不在 metrics_detail
export interface EmployeeDetailResp {
user_id: string; name: string | null; is_on_job: boolean | null
accounts: EmployeeAccount[]
metrics: Record<string, number | string | null>
score: {
total_score: number | null; grade: string | null; score_status: string; trial: boolean
dimensions: Record<string, { name: string; weight: number; score: number | null; status: string; metrics?: Record<string, { value: number | null; score: number | null; sample_size: number; sample_status: string; formula_note?: string }> }>
metrics_detail: Record<string, ScoreMetricDetail>
}
anomalies: AnomalyCard[]
prev: Record<string, number | string | null> | null
baseline: Record<string, number | string | null> | null
scope: MgmtScope; data_as_of: number | null; metric_version: string; config_source: 'db' | 'default'
}
export interface SectionResp {
section: string; metrics: Record<string, number | null>
trend: Record<string, number | null>[]
comparisons: Record<string, { current: number | null; prev: number | null; baseline: number | null; median: number | null }>
scope: MgmtScope; data_as_of: number | null; metric_version: string
}
export type MetricsSection = 'overview' | 'service' | 'customer' | 'workload' | 'calls'
export const getEmployeeDetail = (userId: string, channel: MgmtChannel, start: number, end: number) =>
getJson<EmployeeDetailResp>(`/management/employees/${userId}`, { channel, start, end })
export const getEmployeeMetrics = (userId: string, section: MetricsSection, channel: MgmtChannel, start: number, end: number) =>
getJson<SectionResp>(`/management/employees/${userId}/metrics`, { section, channel, start, end })
(写入前 curl 真机抽查 detail 响应键核对——同批次C C1 惯例,以真实响应为准修。)
useManagementFilters.ts预设补:Preset加'today' | 'yesterday' | 'thisWeek' | 'lastWeek';presetRange四分支(today=当天单日窗;yesterday=昨日单日;thisWeek=本周一..今天;lastWeek=上周一..周日,周一为一周起点);vitest 补 5 例(today/yesterday/thisWeek 周中+周一/lastWeek 跨月)。FilterBar 的预设选项组同步加(el-select options),分组显示:常用(今日/昨日/近7/近30)/日历(本周/上周/本月/上月)/自定义。- vue-tsc +
npm run test(23+ 过)+ commitfeat(management): client补员工详情/分段接口+时间预设补今日昨日本周上周
Task D1: 员工总览页
Files: Create EmployeeAnalyticsView.vue + EmployeeCompareDrawer.vue;改 router(/management/employees)+ MainLayout(管理驾驶舱下加「员工分析」菜单项)。
页面结构:
ManagementFilterBar(复用;compare 选择器在此页透出——el-select 对比方式:上期/个人基线/团队中位数→apply({compare}))
工具行:keyword el-input(placeholder 姓名/ID搜索) | status el-select(全部/在职/离线) | 视图 el-radio-group×4
(management=概览/workload=负载/service=服务/customer=客户经营——切换列组)| 指标口径按钮 | 导出 CSV | DataAsOfBadge
主表 el-table(服务端排序 sort-change→query;行选择框多选 2-5 人→「对比」按钮开抽屉):
固定列:姓名(链接进详情)+ID 小字、在职 tag
management 视图列:综合分(total_score+grade tag+trial*)、异常(anomaly_count 红数字+weight)、活跃客户、消息量、串/被回、维度三列(customer/service/workload score 各 0-100 或「--」)
workload 视图列:活跃客户、活跃群(日均)、消息收/发、通话量/秒、串
service 视图列:首响P50/P90(formatMsDuration)、2h回复率、24h回复率(formatRatio)、被回/串
customer 视图列:新客/降温/沉睡/回流(期末+期内注)、活跃占比
列头 ? 图标→打开 MetricDefsDrawer(复用)
空数据/样本不足单元格显示「--」灰字(sample_status=insufficient 时 total 亦然)
分页 el-pagination(服务端 page/page_size 20;total)
行为:query 真源(view/keyword/status/sort_by/sort_order/page 全进 URL);seq 守卫;服务端排序仅四列(后端 sort_by 白名单:anomaly_severity[默认]/total_score/active_friends/cust_threads——其余列头不显示排序箭头,tooltip「该列不支持服务端排序」);sort_by=total_score 时 null 排最后由后端保证;compare 参数仅客户端显示态(employees 端点无此参数,行恒带全部四对比值);CSV:扩展 utils/csvExport.ts 支持可选前置注释行(exportListToCsv(..., preamble?: string[])——含口径说明如「1:1口径·窗口 20260810-20260908·试算」)+ fetchPage 适配器(/employees 返回 {rows,total},适配为 csvExport 期望的 {items,total}),导出当前视图列全量翻页。
EmployeeCompareDrawer:props { rows: EmployeeRow[] }(勾选行已有数据,不另发请求);内容:五维分对比条(3 可用维度每人一行,横向 bar 0-100)+ 关键指标表(活跃客户/P90/2h率/异常数 每人一列)+ 顶部说明「同口径同时窗对比,不产生优劣结论」;>5 人禁开。
路由/菜单:
{ path: '/management/employees', name: 'management-employees',
component: () => import('@/views/management/EmployeeAnalyticsView.vue'),
meta: { title: '员工分析' } },
- vue-tsc/test/build + 真机初查(表格渲染 41 人/切视图列变/排序翻页/keyword/CSV 打开内容对)+ commit
feat(management): 员工总览页——四视图/服务端排序分页/对比抽屉/CSV导出
Task D2: 员工详情页
Files: Create EmployeeAnalyticsDetailView.vue;router 加 /management/employees/:userId(props:true;activeMenu 需高亮父菜单「员工分析」——MainLayout 的 el-menu :default-active 绑定的是路径,嵌套路由时用 route.meta 或 watch 设 index——看 MainLayout 现有 active 处理方式,最简方案:菜单 index 用路径匹配 + 详情页 route path 前缀匹配高亮,若现结构不支持则 meta.activeMenu='/management/employees' 并在 el-menu :default-active 计算)。
页面结构:
头部卡:姓名(+在职 tag)+ID | 账号清单(渠道 tag+account_id+昵称,点击跳 staff-chat/通讯录按渠道)
| 本期试算分大数字+grade tag+score_status(insufficient 时灰注「样本不足·不参与考核」)+trial*
| DataAsOfBadge | 返回列表链接
五维条(v1 §7.2 概览的核心):横向五条 bar——3 可用维度实分数值,action/risk 灰「待数据」占位
(ScoreBreakdown 简版:直接在页内画,不新建组件,el-progress/自定义 div)
el-tabs 五页签(懒加载:激活才调 getEmployeeMetrics):
概览: 六数卡取自**detail.metrics**(msg/活跃/串/通话——section 端点字段有限,期值以 detail 为准)
+ 四对比小表(comparisons 直渲染,源指标名行)
服务质量: 数卡 P50/P90 + 2h/24h回复率(**客户端从 metrics.reply_2h_count/cust_threads 派生,
与 derive_metrics 同式**——section 趋势无每日率序列) + 趋势图=**首响 P50/P90 双线(ms 轴)
±串数(次轴可选)**——不做率右轴(员工级无每日率数据,率的团队级序列在驾驶舱)
客户经营: 期末四态数卡(取自 detail.metrics) + 降温/沉睡下钻按钮(→DrilldownDrawer lifecycle 分支)
工作负载: 数卡取 detail.metrics(收发/活跃客户/群/通话量) + 趋势图用 section=workload 的
active_friends/active_rooms 双线(trend 列为日值 active_rooms)
通话: 通话四数(detail.metrics) + call_followup 下钻按钮
**页签下钻按钮与 MetricDrilldownDrawer 的衔接**:抽屉是 card 驱动——按钮合成最小伪卡片
`{title:'首响P90明细', drilldown:{type:'metric',query:{metric_code:'first_reply_p90',user_id}}}` 传入
异常区:AnomalyList(复用,@drill→MetricDrilldownDrawer 复用)
评分明细折叠面板(el-collapse「评分怎么算出来的」): metrics_detail 表(code/名称/当前/上期/基线/中位/样本/得分)
+ prev/baseline 原始 PeriodMetrics 两个 JSON 折叠(调试用,灰字注明)
行为:query 真源(channel/start/end/compare/section 进 URL,页签切换 replace);seq 守卫每页签独立(切页签取消旧渲染);404 员工→el-result 错误页+返回链接;「创建辅导记录」按钮占位禁用(tooltip「批次E上线」)。
- vue-tsc/test/build + 真机初查(王云青详情:五维条/五页签懒加载/异常/评分明细展开/账号跳聊天)+ commit
feat(management): 员工详情页——五维条/五页签懒加载/四对比/评分明细/事实下钻复用
Task D3: 驾驶舱 KPI 环比 + 异常跳员工
后端(management.py dashboard + api_assembly.py):①dashboard 端点 kpis 加 prev_kpis 块(active_customers/active_employees/msg_total/cust_threads——dashboard 走 assemble_employees(with_prev=False),需加一次 prev 窗 period_metrics 全员调用,B5 实测三窗合计 ~0.3s,加一窗 +0.1s 量级)+ msg_delta((cur-prev)/prev,prev=0→null)。lifecycle/通话不加环比(期末/全渠道口径环比意义弱,注明)。②异常卡补 employee_name(assemble_employees 手里已有全员 name——组装 anomalies 时带上,一行);同步 AnomalyCard type。测试补:dashboard 响应含 prev_kpis 且数字=prev 窗聚合 + anomalies[0].employee_name 非空。
前端:KpiCard 加 delta?: number | null prop(↑绿↓红,方向语义由调用方定——涨=好传正绿;不传不显示);驾驶舱三卡接 delta(活跃客户/活跃员工/消息量);AnomalyList 的 title 下加员工行(employee_name 链接→/management/employees/{user_id})+ 新增 showEmployee?: boolean prop(默认 true;D2 员工详情页复用时传 false 免自链接)。
- 后端 pytest(test_management_api.py 补 prev_kpis 断言)+ 前端走查三卡箭头/异常跳员工 + commit
feat(management): 驾驶舱KPI环比(prev_kpis+delta箭头)+异常卡跳员工详情
Task D4: 真机走查 + 验收
- 全链路走查(Playwright):驾驶舱→异常卡→员工详情(新链路!)→页签→下钻→聊天;员工总览→对比抽屉→CSV;1366px;刷新保持;
- 验收对照(v1 §19.1 员工子集):能查看所有员工多维状态 ✓/任一分数展开为指标公式样本事实 ✓(评分明细面板)/四对比 ✓/样本不足不评分显示 ✓/异常两次点击进事实 ✓/默认排序非总分榜 ✓;
- 四门禁(vue-tsc/vitest/build/后端 pytest);
- commit 收尾零散 + 走查记录追加核实文档「批次D走查」小节。
批次D验收清单
- 员工总览:41 人四视图/服务端排序分页/keyword/对比 2-5 人/CSV 含口径注释;
- 员工详情:五维条 3+2 占位/五页签懒加载/四对比/评分明细可展开/三处下钻按钮进抽屉/账号跳聊天;
- 驾驶舱:三 KPI 有环比箭头/异常卡可跳员工详情(闭环打通);
- 时间预设全套(今日/昨日/近7/近30/本周/上周/本月/上月/自定义);
- URL 全参数保持;四门禁绿;后端仅 dashboard 一处小改且测试补齐。
批次E-F
E:followups 辅导闭环(写端点+schemas_management+详情页按钮激活)+ 考核快照(生成/冻结/列表/导出)。F:调度接入(analytics_tick 第三步+full_sync 13/14 步+scheduler 镜像重建还 9d3cc8e 旧账)+ dashboard 性能修复(unreplied 索引三选一)+ 服务器部署+回测试运行。