feat: 全页面增加营业收入/优惠指标 + 修复趋势预测空数据 + 区域对比口径统一 + StorePage最新经营日概览

- 后端: 所有API的discount改为从bill_fact累计discount_total
- 后端: revenue/daily-summary增加consumption字段
- 后端: situational-awareness/forecast修复c175字符串比较为timestamp
- 后端: region/comparison去掉未知区域排除,统一口径
- 后端: daily-card增加营业收入/优惠指标,返回target_date/baseline_date
- 前端: BossPage/DashboardPage/BankPage/StorePage/ExpenseOverviewTab/RegionalPage/RegionComparisonPage/RevenuePage 均增加营业收入和优惠指标卡
- 前端: StorePage日均经营概览改为最新经营日概览,显示具体对比日期
- 前端: 日期格式统一截取YYYY-MM-DD显示
This commit is contained in:
freedakgmail
2026-08-02 14:56:00 +08:00
parent a1a8b7ee5e
commit 271ad8041d
13 changed files with 204 additions and 76 deletions
+12 -2
View File
@@ -313,6 +313,8 @@ router.get('/stores/:code/daily-card', async (req: AuthRequest, res) => {
),
today_stats AS (
SELECT c003 AS store_name,
round(sum(COALESCE(NULLIF(c009,'')::numeric,0)), 2) AS consumption,
round(sum(COALESCE(NULLIF(c068,'')::numeric,0)), 2) AS discount,
round(sum(${RECEIVED_COLS}), 2) AS received,
count(*) AS bill_count,
round(sum(${RECEIVED_COLS}) / count(*), 2) AS avg_bill
@@ -322,6 +324,8 @@ router.get('/stores/:code/daily-card', async (req: AuthRequest, res) => {
),
week_ago_stats AS (
SELECT
round(sum(COALESCE(NULLIF(c009,'')::numeric,0)), 2) AS consumption,
round(sum(COALESCE(NULLIF(c068,'')::numeric,0)), 2) AS discount,
round(sum(${RECEIVED_COLS}), 2) AS received,
count(*) AS bill_count,
round(sum(${RECEIVED_COLS}) / count(*), 2) AS avg_bill
@@ -330,12 +334,16 @@ router.get('/stores/:code/daily-card', async (req: AuthRequest, res) => {
GROUP BY c003
)
SELECT t.store_name, '收入' AS module,
td.business_date AS target_date,
(td.business_date - interval '7 days')::date AS baseline_date,
jsonb_build_array(
jsonb_build_object('metric', '营业收入', 'value', t.consumption, 'baseline', COALESCE(w.consumption, 0), 'is_anomaly', t.consumption < (COALESCE(w.consumption, 0) * 0.8)),
jsonb_build_object('metric', '优惠', 'value', t.discount, 'baseline', COALESCE(w.discount, 0), 'is_anomaly', t.discount > (COALESCE(w.discount, 0) * 1.2)),
jsonb_build_object('metric', '实收', 'value', t.received, 'baseline', COALESCE(w.received, 0), 'is_anomaly', t.received < (COALESCE(w.received, 0) * 0.8)),
jsonb_build_object('metric', '账单数', 'value', t.bill_count, 'baseline', COALESCE(w.bill_count, 0), 'is_anomaly', t.bill_count::numeric < (COALESCE(w.bill_count, 0) * 0.8)),
jsonb_build_object('metric', '客单价', 'value', t.avg_bill, 'baseline', COALESCE(w.avg_bill, 0), 'is_anomaly', t.avg_bill < (COALESCE(w.avg_bill, 0) * 0.9))
) AS anomalies
FROM today_stats t
FROM today_stats t, target_day td
LEFT JOIN week_ago_stats w ON true
`, params)
const tasks = await query(`
@@ -343,7 +351,9 @@ router.get('/stores/:code/daily-card', async (req: AuthRequest, res) => {
WHERE t.store_code = $1 AND t.status IN ('待启动', '进行中')
ORDER BY t.priority LIMIT 3
`, [code])
sendSuccess(res, { anomalies: result.rows, todos: tasks.rows })
const targetDate = result.rows[0]?.target_date
const baselineDate = result.rows[0]?.baseline_date
sendSuccess(res, { anomalies: result.rows, todos: tasks.rows, target_date: targetDate, baseline_date: baselineDate })
} catch (err: any) {
sendError(res, err.message)
}