From e946cdefef312608622ba797045d3688086c0252 Mon Sep 17 00:00:00 2001 From: freedakgmail Date: Thu, 30 Jul 2026 09:16:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=97=A8=E5=BA=97=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=A3=8E=E9=99=A9=E7=AD=89=E7=BA=A7=E5=92=8C?= =?UTF-8?q?=E7=BB=8F=E8=90=A5=E8=B1=A1=E9=99=90=E8=AF=A6=E7=BB=86=E8=AF=B4?= =?UTF-8?q?=E6=98=8E+=E4=BF=AE=E5=A4=8D=E5=90=8E=E7=AB=AF=E4=B8=8D?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E7=9A=84=E8=A7=86=E5=9B=BE=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/StoreDetailPage.tsx | 56 +++++++++++++++++++++++++++- server/src/routes/data.ts | 8 ++-- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/client/src/pages/StoreDetailPage.tsx b/client/src/pages/StoreDetailPage.tsx index 6839366..0b8610a 100644 --- a/client/src/pages/StoreDetailPage.tsx +++ b/client/src/pages/StoreDetailPage.tsx @@ -87,6 +87,25 @@ export function StoreDetailPage() { if (!sd) return
加载中...
const sc = sd.scorecard + const action = sd.action + const risk = sd.risk + + const riskDesc: Record = { + '绿色': { color: 'text-green-600 bg-green-50 border-green-200', desc: '各项指标健康,经营状态良好,维持现有运营策略即可。' }, + '黄色': { color: 'text-yellow-600 bg-yellow-50 border-yellow-200', desc: '存在单项指标偏差,需关注并针对性改善,避免风险升级。' }, + '红色': { color: 'text-red-600 bg-red-50 border-red-200', desc: '多项指标异常,经营风险较高,需立即介入并制定整改计划。' }, + } + + const quadrantDesc: Record = { + '明星门店': '高营收高毛利,是公司的核心利润来源。应总结其成功经验并推广至其他门店。', + '现金牛门店': '高营收但毛利偏低,通过成本优化有较大利润提升空间。', + '潜力门店': '营收偏低但毛利较好,具备增长潜力,需提升客流和营收规模。', + '问题门店': '营收和毛利均偏低,需全面诊断并考虑调整经营策略或选址。', + } + + const riskInfo = risk?.risk_level ? riskDesc[risk.risk_level] : null + const quadrant = action?.management_quadrant || '' + const quadrantInfo = quadrantDesc[quadrant] return (
@@ -96,8 +115,8 @@ export function StoreDetailPage() {

{sc.store_name}

- {sd.risk && } - {sd.benchmark && {sd.benchmark.management_quadrant}} + {risk?.risk_level && } + {quadrant && {quadrant}}
{/* 核心指标 */} @@ -110,6 +129,39 @@ export function StoreDetailPage() {
+ {/* 风险与经营状态说明 */} +
+ {riskInfo && ( +
+
+ 风险等级:{risk.risk_level} + {risk.primary_issue && — {risk.primary_issue}} +
+

{riskInfo.desc}

+
+ )} + {quadrantInfo && ( +
+
+ 经营象限:{quadrant} + {action?.scale_tier && — {action.scale_tier}} +
+

{quadrantInfo}

+
+ )} +
+ + {/* 行动建议 */} + {action?.action_priority && ( +
+
+ 行动优先级:{action.action_priority} + {action.problem_combination && 问题:{action.problem_combination}} + {action.business_type && {action.business_type}} +
+
+ )} + {/* Tab bar */}
{TABS.map(t => ( diff --git a/server/src/routes/data.ts b/server/src/routes/data.ts index 975698a..b5affe2 100644 --- a/server/src/routes/data.ts +++ b/server/src/routes/data.ts @@ -108,13 +108,12 @@ router.get('/stores/quadrant', async (req: AuthRequest, res) => { router.get('/stores/:code', async (req: AuthRequest, res) => { try { const code = req.params.code - const [scorecard, risk, platform, benchmark, action, execution] = await Promise.all([ + const [scorecard, risk, platform, benchmark, action] = await Promise.all([ query(`SELECT * FROM analytics.v_store_scorecard WHERE store_code = $1`, [code]), query(`SELECT * FROM analytics.mv_store_risk_rating WHERE store_code = $1`, [code]), query(`SELECT * FROM analytics.v_store_platform_economics WHERE store_code = $1`, [code]), - query(`SELECT * FROM analytics.v_store_benchmark WHERE store_code = $1`, [code]), - query(`SELECT * FROM analytics.v_store_action_list WHERE store_code = $1`, [code]), - query(`SELECT * FROM analytics.v_store_execution_priority WHERE store_code = $1`, [code]), + query(`SELECT * FROM analytics.v_store_benchmark_composite WHERE store_code = $1`, [code]), + query(`SELECT * FROM analytics.v_store_action_priority_deep_april WHERE store_code = $1`, [code]), ]) if (scorecard.rows.length === 0) { @@ -127,7 +126,6 @@ router.get('/stores/:code', async (req: AuthRequest, res) => { platform: platform.rows[0], benchmark: benchmark.rows[0], action: action.rows[0], - execution: execution.rows[0], }) } catch (err: any) { sendError(res, err.message)