| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- 'use strict';
- /**
- * 智能问数 · 指标层
- * ----------------------------------------------------------------------------
- * 把「指标 = 维度 × 聚合 × 时间粒度 × 口径」从列注册表升级为一等对象:
- * · 基础指标:合计 / 加权(比率按曝光或进店人数加权)/ 比值(客单价)
- * · 派生指标:基于基础指标动态计算(7 日移动平均等),模型引用指标 key,
- * 不自己组合口径——flash 模型引用比自算的出错率低一个量级。
- * 与 REPORT_COLUMNS 的关系:列注册表服务表格语义(label/同义词/类型),
- * 本注册表服务问数聚合语义(怎么算),两者键保持一致。
- */
- const BASE = {
- grossAmt: { name: '营业额', unit: 'money', agg: 'sum', synonyms: ['流水', 'GMV', '销售额'] },
- validOrderCnt: { name: '有效订单', unit: 'int', agg: 'sum', synonyms: ['单量', '订单量'] },
- incomeAmt: { name: '收入', unit: 'money', agg: 'sum', synonyms: ['到账'] },
- expenseAmt: { name: '支出', unit: 'money', agg: 'sum', synonyms: ['费用'] },
- expUv: { name: '曝光人数', unit: 'int', agg: 'sum', synonyms: ['曝光'] },
- orderUserCnt: { name: '下单人数', unit: 'int', agg: 'sum', synonyms: ['购买人数'] },
- actOrdCnt: { name: '活动订单', unit: 'int', agg: 'sum' },
- actSubsidyAmt: { name: '活动补贴', unit: 'money', agg: 'sum' },
- clkExpRate: { name: '进店转化率', unit: 'pct', agg: 'weighted', weightBy: 'expUv' },
- ordClkRate: { name: '下单转化率', unit: 'pct', agg: 'weighted', weightBy: 'orderUserCnt' },
- perActualPay: { name: '客单价', unit: 'money', agg: 'ratio', num: 'grossAmt', den: 'validOrderCnt' },
- };
- /** 派生指标:基于基础指标按窗口动态计算(按天粒度) */
- const DERIVED = {
- gross_mov7: { name: '营业额7日移动平均', unit: 'money', base: 'grossAmt', window: 7 },
- orders_mov7: { name: '有效订单7日移动平均', unit: 'int', base: 'validOrderCnt', window: 7 },
- uv_mov7: { name: '曝光人数7日移动平均', unit: 'int', base: 'expUv', window: 7 },
- };
- const ALL = { ...BASE, ...DERIVED };
- function get(key) { return ALL[key] || null; }
- /** 常驻提示词:聚合口径一句话说清(含派生指标) */
- function manifestText() {
- const lines = Object.entries(ALL).map(([key, m]) => {
- const how = m.agg === 'sum' ? '合计'
- : m.agg === 'weighted' ? `加权平均(按${(BASE[m.weightBy] || {}).name || m.weightBy}加权)`
- : m.agg === 'ratio' ? `比值(${(BASE[m.num] || {}).name || m.num} / ${(BASE[m.den] || {}).name || m.den})`
- : `${m.window} 日移动平均(基于${(BASE[m.base] || {}).name || m.base})`;
- return `- ${key}|${m.name}|${how}`;
- });
- return lines.join('\n');
- }
- /** 单日聚合:把当天门店行聚成一个数(口径与 summarizeRows 同源——比率加权) */
- function dayValue(key, rows) {
- const m = ALL[key];
- if (!m || !rows.length) return null;
- if (m.agg === 'weighted') {
- let wv = 0;
- let w = 0;
- for (const r of rows) {
- const weight = Number(r[m.weightBy]) || 0;
- wv += (Number(r[key]) || 0) * weight;
- w += weight;
- }
- return w > 0 ? +(wv / w).toFixed(4) : null;
- }
- if (m.agg === 'ratio') {
- const num = rows.reduce((s, r) => s + (Number(r[m.num]) || 0), 0);
- const den = rows.reduce((s, r) => s + (Number(r[m.den]) || 0), 0);
- return den > 0 ? +(num / den).toFixed(2) : null;
- }
- return Math.round(rows.reduce((s, r) => s + (Number(r[key]) || 0), 0) * 100) / 100;
- }
- module.exports = { BASE, DERIVED, ALL, get, manifestText, dayValue };
|