c2a9e27e49
文档: - 01-项目概述与架构: 技术架构、数据流、部署拓扑 - 02-数据接入与治理: 原始数据导入、物化视图、门店名映射 - 03-指标体系与API开发: 指标分层、SQL模式、常见陷阱 - 04-前端页面开发: 组件规范、页面模板、月份参数管理 - 05-部署与运维: 部署脚本、FRP隧道、PM2、备份 - 06-调试排查手册: 问题分类、8个实际案例、工具速查 - 07-通用方法论: 核心原则、实施阶段、快速复制Checklist 修复: - situational-awareness.ts: salary_month→salary_period, 日期格式改中文 - 客流-人力匹配: 改用attendance_records打卡数据解析在岗人数 - 客流数据除以30天对齐日均
4.7 KiB
4.7 KiB
02 · 数据接入与治理
1. 原始数据导入
1.1 数据源
| 表名 | 数据来源 | 关键字段 | 数据量级 |
|---|---|---|---|
bill_records |
收银系统导出 | c003(门店) c005(账单号) c009(消费) c068(优惠) c114(实收) c175(下单时间) c176(结账时间) c191(收银员) | 千万级/月 |
salary_detail_records |
薪资系统导出 | org_level5(门店) salary_period(薪资周期) actual_attend(实际出勤) actual_hours(实际工时) | 万级/月 |
attendance_records |
考勤系统导出 | department(部门路径) position(岗位) day_01~day_31(每日打卡) | 万级/月 |
1.2 导入关键点
- 字段映射:原始Excel列名(c001~c200)需建立映射文档,明确每列含义
- 日期格式:
salary_period格式为中文"2026年4月",非"2026-04",查询时需用to_char($1::date, 'YYYY"年"FMMM"月"') - 空值处理:实收字段 c114 可能为空字符串,需
COALESCE(NULLIF(c114,'')::numeric, 0) - 数据去重:导入时按 record_id + import_id 去重
1.3 门店名映射
不同数据源门店名不一致,需维护 store_name_mapping 映射表:
CREATE TABLE public.store_name_mapping (
salary_name TEXT, -- 薪资/考勤系统中的名称
bill_name TEXT -- 账单系统中的名称
);
典型映射:
| salary_name | bill_name |
|---|---|
| 双安店 | 双安总店 |
| 百子湾店 | 百子湾路店 |
| 安宁庄快手店 | 安宁庄快手 |
| 海淀大街店 | 海淀大街 |
| 哈马尔罕大钟寺店 | 大钟寺店 |
| 阿里疆(温泉路店) | 温泉店 |
映射查找模式(代码中复用):
// 构建查找表:同时用原名和映射名
const staffLookup: Record<string, any> = {}
for (const [store, data] of Object.entries(staffSummary)) {
staffLookup[store] = data // 原名
const mapped = nameMap[store]
if (mapped && mapped !== store) {
staffLookup[mapped] = data // 映射名
}
}
2. 物化视图体系
2.1 核心物化视图
| 视图名 | Schema | 用途 | 关键字段 |
|---|---|---|---|
mv_store_risk_rating_monthly |
analytics | 门店风险评级 | store_code, store_name, risk_level, received, month_start |
mv_store_platform_economics_monthly |
analytics | 平台经济性 | store_code, meituan_received, taobao_received, jd_received |
mv_bill_hourly |
public | 小时客流 | store_name, hour, bills, avg_guests |
mv_risk_anomaly |
public | 异常账单 | store_name, bill_no, consumption, anomaly_reason, month |
mv_risk_zero |
public | 零实收 | store_name, bill_no, zero_received_type, month |
mv_risk_cashier |
public | 收银员风险 | store_name, cashier, bill_count, anomaly_bills, month |
mv_channel_daily |
public | 支付渠道 | business_date, cash, alipay, wechat, meituan, month |
mv_time_hourly |
public | 时间维度汇总 | closing_hour, bill_count, received, month |
2.2 物化视图管理要点
- Schema前缀:部分视图在
analyticsschema,部分在publicschema,代码中需注意 - 刷新机制:物化视图需手动刷新
REFRESH MATERIALIZED VIEW,不自动更新 - 索引:重建物化视图后需重新创建索引
- 阈值调优:异常判断阈值需根据业务调整(如"消费-优惠与实收不平"阈值从0.05元提高到1元)
2.3 异常账单阈值设计
-- 异常类型判断(CASE WHEN顺序重要)
CASE
WHEN consumption > 0 AND received = 0 THEN '有消费无实收'
WHEN discount > consumption THEN '优惠大于消费'
WHEN abs(consumption - discount - received) > 1 THEN '消费-优惠与实收不平'
ELSE NULL
END
关键教训:阈值0.05元太严格,会将舍入差异标为异常。建议初始阈值设为1元,后续根据数据分布调整。
3. 数据质量校验
3.1 校验流程
- 数据范围:
SELECT DISTINCT month FROM bill_records ORDER BY month确认最新月份 - 门店数:
SELECT count(DISTINCT c003) FROM bill_records WHERE month = '2026-04' - 金额一致性:
SELECT sum(c009), sum(c068), sum(c114)对比前后端 - 物化视图刷新状态:对比物化视图和原始表的记录数
3.2 常见数据问题
| 问题 | 症状 | 排查方法 |
|---|---|---|
| 物化视图stale | API数据与数据库不一致 | 直接查原始表对比物化视图 |
| 月份格式不匹配 | 查询返回0条 | 检查 salary_period 实际格式 |
| 门店名不一致 | 部分门店无数据 | 对比不同表的门店名列表 |
| Schema前缀错误 | relation does not exist |
检查 \dn 和 pg_matviews |
| 列不存在 | column does not exist |
检查 information_schema.columns |