V3.0: 门店分级与风险等级页面、数据填充脚本、后端API

- 新增V3.0数据库表结构(12-15)和数据填充脚本(16)
- 新增后端路由: store-grade, enterprise, product, intelligence, alert, scheduler, target
- 新增前端页面: StoreGradePage, EnterprisePage, ProductLifecyclePage, IntelligencePage, AlertManagementPage, DataImportPage, SchedulerManagementPage, TargetManagementPage
- 门店分级: 自动分级算法(达成率40%+毛利率25%+会员15%+风险20%)
- 风险等级: 基于mv_store_risk_rating模型展示风险分布和原因
- 弹窗: 雷达图+详细指标+分级原因+风险原因(primary_issue)
- FilterableTable: filterOptions支持{value,label}对象格式
This commit is contained in:
freedakgmail
2026-08-05 20:09:39 +08:00
parent 814abf4a68
commit d04e837d9c
30 changed files with 5052 additions and 144 deletions
+212
View File
@@ -0,0 +1,212 @@
-- ============================================================
-- 12_v3_target_tables.sql
-- V3.0 目标管理系统表族 + 调度任务表 + 预警规则表
-- ============================================================
-- ============================================================
-- 1. 目标管理系统表族 (T-101 ~ T-105)
-- ============================================================
-- T-101: 年度战略目标
CREATE TABLE IF NOT EXISTS analytics.v3_annual_target (
id SERIAL PRIMARY KEY,
year INT NOT NULL,
metric TEXT NOT NULL, -- revenue / profit / store_count / member_count
target_value NUMERIC(14,2) NOT NULL,
description TEXT,
created_by TEXT DEFAULT 'system',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(year, metric)
);
-- T-102: 区域年度目标
CREATE TABLE IF NOT EXISTS analytics.v3_regional_target (
id SERIAL PRIMARY KEY,
year INT NOT NULL,
region TEXT NOT NULL,
revenue_target NUMERIC(14,2) NOT NULL,
profit_target NUMERIC(14,2),
store_count_target INT,
member_count_target INT,
weight_pct NUMERIC(5,2) DEFAULT 100, -- 区域占比权重
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(year, region)
);
-- T-103: 门店月度目标(兼容现有 dim_store_target
CREATE TABLE IF NOT EXISTS analytics.v3_store_monthly_target (
id SERIAL PRIMARY KEY,
year INT NOT NULL,
month DATE NOT NULL, -- YYYY-MM-01
store_code TEXT NOT NULL,
store_name TEXT,
region TEXT,
grade TEXT DEFAULT 'B', -- A/B/C/D 分级
revenue_target NUMERIC(14,2) NOT NULL,
bill_count_target INT,
avg_bill_value_target NUMERIC(8,2),
member_penetration_target NUMERIC(5,2),
cost_rate_target NUMERIC(5,2),
profit_target NUMERIC(14,2),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(month, store_code)
);
-- T-104: 日级目标
CREATE TABLE IF NOT EXISTS analytics.v3_daily_target (
id SERIAL PRIMARY KEY,
target_date DATE NOT NULL,
store_code TEXT NOT NULL,
store_name TEXT,
revenue_target NUMERIC(12,2) NOT NULL,
bill_count_target INT,
avg_bill_value_target NUMERIC(8,2),
package_target NUMERIC(12,2), -- 套餐目标
loss_target NUMERIC(8,2), -- 损耗目标
arrival_target NUMERIC(8,2), -- 到货目标
weight_pct NUMERIC(5,2) DEFAULT 0, -- 当日占月度权重
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(target_date, store_code)
);
-- T-105: 个人任务
CREATE TABLE IF NOT EXISTS analytics.v3_personal_task (
id SERIAL PRIMARY KEY,
target_date DATE NOT NULL,
store_code TEXT NOT NULL,
employee_name TEXT NOT NULL,
position TEXT, -- 岗位
metric TEXT NOT NULL, -- 指标名
target_value NUMERIC(12,2) NOT NULL,
actual_value NUMERIC(12,2),
completion_rate NUMERIC(5,2), -- 完成率%
status TEXT DEFAULT '待执行',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================
-- 2. 调度任务注册表 (T-121)
-- ============================================================
CREATE TABLE IF NOT EXISTS analytics.v3_scheduled_task (
id SERIAL PRIMARY KEY,
task_name TEXT NOT NULL UNIQUE,
description TEXT,
cron_expr TEXT NOT NULL, -- cron 表达式
handler TEXT NOT NULL, -- 处理函数标识
is_enabled BOOLEAN DEFAULT true,
last_run_at TIMESTAMPTZ,
next_run_at TIMESTAMPTZ,
last_status TEXT, -- success / failed / running
last_error TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================
-- 3. 预警规则引擎表族 (T-130 ~ T-131)
-- ============================================================
-- T-130: 预警规则
CREATE TABLE IF NOT EXISTS analytics.v3_alert_rule (
id SERIAL PRIMARY KEY,
rule_name TEXT NOT NULL,
description TEXT,
metric TEXT NOT NULL, -- 监控指标
operator TEXT NOT NULL DEFAULT '<', -- < / <= / > / >= / =
threshold NUMERIC(14,2) NOT NULL, -- 阈值
severity TEXT DEFAULT 'yellow', -- red / yellow
push_targets TEXT, -- 推送对象(逗号分隔角色)
escalation_path TEXT, -- 升级路径
is_enabled BOOLEAN DEFAULT true,
check_interval TEXT DEFAULT 'hourly', -- hourly / daily / weekly / monthly
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- T-131: 预警日志
CREATE TABLE IF NOT EXISTS analytics.v3_alert_log (
id SERIAL PRIMARY KEY,
rule_id INT REFERENCES analytics.v3_alert_rule(id) ON DELETE CASCADE,
rule_name TEXT,
store_code TEXT,
store_name TEXT,
metric_value NUMERIC(14,2),
threshold NUMERIC(14,2),
severity TEXT,
push_status TEXT DEFAULT 'pending', -- pending / sent / failed
handle_status TEXT DEFAULT 'pending', -- pending / handling / resolved / ignored
handle_comment TEXT,
triggered_at TIMESTAMPTZ DEFAULT NOW(),
handled_at TIMESTAMPTZ
);
-- ============================================================
-- 4. 门店自动分级表 (T-160)
-- ============================================================
CREATE TABLE IF NOT EXISTS analytics.v3_store_grade (
id SERIAL PRIMARY KEY,
grade_month DATE NOT NULL,
store_code TEXT NOT NULL,
store_name TEXT,
region TEXT,
grade TEXT NOT NULL, -- A / B / C / D
revenue_achievement_pct NUMERIC(5,2),
inspection_score NUMERIC(5,2),
complaint_rate NUMERIC(5,2),
overall_score NUMERIC(5,2),
reason TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(grade_month, store_code)
);
-- ============================================================
-- 索引
-- ============================================================
CREATE INDEX IF NOT EXISTS idx_v3_annual_target_year ON analytics.v3_annual_target(year);
CREATE INDEX IF NOT EXISTS idx_v3_regional_target_year ON analytics.v3_regional_target(year);
CREATE INDEX IF NOT EXISTS idx_v3_store_monthly_target_month ON analytics.v3_store_monthly_target(month);
CREATE INDEX IF NOT EXISTS idx_v3_store_monthly_target_store ON analytics.v3_store_monthly_target(store_code);
CREATE INDEX IF NOT EXISTS idx_v3_daily_target_date ON analytics.v3_daily_target(target_date);
CREATE INDEX IF NOT EXISTS idx_v3_daily_target_store ON analytics.v3_daily_target(store_code);
CREATE INDEX IF NOT EXISTS idx_v3_personal_task_date ON analytics.v3_personal_task(target_date);
CREATE INDEX IF NOT EXISTS idx_v3_personal_task_store ON analytics.v3_personal_task(store_code);
CREATE INDEX IF NOT EXISTS idx_v3_scheduled_task_enabled ON analytics.v3_scheduled_task(is_enabled);
CREATE INDEX IF NOT EXISTS idx_v3_alert_rule_enabled ON analytics.v3_alert_rule(is_enabled);
CREATE INDEX IF NOT EXISTS idx_v3_alert_log_rule ON analytics.v3_alert_log(rule_id);
CREATE INDEX IF NOT EXISTS idx_v3_alert_log_triggered ON analytics.v3_alert_log(triggered_at);
CREATE INDEX IF NOT EXISTS idx_v3_alert_log_handle_status ON analytics.v3_alert_log(handle_status);
CREATE INDEX IF NOT EXISTS idx_v3_store_grade_month ON analytics.v3_store_grade(grade_month);
CREATE INDEX IF NOT EXISTS idx_v3_store_grade_store ON analytics.v3_store_grade(store_code);
-- ============================================================
-- 初始化默认调度任务
-- ============================================================
INSERT INTO analytics.v3_scheduled_task (task_name, description, cron_expr, handler, is_enabled) VALUES
('daily_report', '每日08:30生成昨日日报', '30 8 * * *', 'dailyReport', true),
('daily_target_card', '每日09:00生成日目标卡', '0 9 * * *', 'dailyTargetCard', true),
('hourly_achievement_check', '每小时比对日目标达成率', '0 * * * *', 'hourlyAchievementCheck', true),
('daily_review_template', '每日22:30生成日复盘模板', '30 22 * * *', 'dailyReviewTemplate', false),
('weekly_data_package', '每周一09:00生成上周数据包', '0 9 * * 1', 'weeklyDataPackage', false),
('monthly_business_report', '每月1日09:00生成月度经营分析报告', '0 9 1 * *', 'monthlyBusinessReport', false),
('monthly_mid_progress', '每月15日14:00生成月中进度报告', '0 14 15 * *', 'monthlyMidProgress', false),
('alert_engine_scan', '每5分钟扫描预警规则', '*/5 * * * *', 'alertEngineScan', true)
ON CONFLICT (task_name) DO NOTHING;
-- ============================================================
-- 初始化默认预警规则
-- ============================================================
INSERT INTO analytics.v3_alert_rule (rule_name, description, metric, operator, threshold, severity, push_targets, check_interval) VALUES
('营收达成率红灯', '日营收达成率低于80%触发红灯', 'revenue_achievement_pct', '<', 80, 'red', 'store,regional', 'hourly'),
('营收达成率黄灯', '日营收达成率低于90%触发黄灯', 'revenue_achievement_pct', '<', 90, 'yellow', 'store', 'hourly'),
('毛利率异常', '理论毛利率低于40%', 'theoretical_margin_pct', '<', 40, 'yellow', 'store,regional', 'daily'),
('会员渗透率低', '会员账单占比低于20%', 'member_bill_share_pct', '<', 20, 'yellow', 'store', 'daily'),
('客诉率偏高', '客诉率超过5%', 'complaint_rate', '>', 5, 'red', 'store,regional,hq', 'daily'),
('巡检低分', '食安巡检得分低于90', 'inspection_score', '<', 90, 'red', 'store,regional', 'daily'),
('离职率偏高', '月度离职率超过15%', 'turnover_rate', '>', 15, 'red', 'regional,hq', 'monthly')
ON CONFLICT DO NOTHING;