fix: 门店成本分析Tab - 用v_inventory_cost_classified_april替代不存在的v_store_category_cost_benchmark_april

This commit is contained in:
freedakgmail
2026-07-30 09:09:34 +08:00
parent efb27127e2
commit a6d83be0ad
2 changed files with 28 additions and 5 deletions
+4 -4
View File
@@ -261,10 +261,10 @@ export function StoreDetailPage() {
<DataTable
columns={[
{ key: 'category_name', label: '原料分类' },
{ key: 'theoretical_cost_rate_pct', label: '理论成本率', align: 'right', render: (r) => formatPercent(r.theoretical_cost_rate_pct) },
{ key: 'actual_cost_rate_pct', label: '实际成本率', align: 'right', render: (r) => formatPercent(r.actual_cost_rate_pct) },
{ key: 'variance_pct', label: '差异', align: 'right', render: (r) => <span className={Number(r.variance_pct) > 20 ? 'text-red-600' : 'text-green-600'}>{Number(r.variance_pct).toFixed(1)}%</span> },
{ key: 'benchmark_rate_pct', label: '同类基准', align: 'right', render: (r) => formatPercent(r.benchmark_rate_pct) },
{ key: 'consumption_amount', label: '消耗金额', align: 'right', render: (r) => formatCurrency(r.consumption_amount) },
{ key: 'actual_cost_rate_pct', label: '占比', align: 'right', render: (r) => formatPercent(r.actual_cost_rate_pct) },
{ key: 'benchmark_rate_pct', label: '公司基准', align: 'right', render: (r) => formatPercent(r.benchmark_rate_pct) },
{ key: 'variance_pct', label: '差异', align: 'right', render: (r) => <span className={Number(r.variance_pct) > 2 ? 'text-red-600' : 'text-green-600'}>{Number(r.variance_pct).toFixed(1)}%</span> },
]}
data={cost.categories}
/>
+24 -1
View File
@@ -383,7 +383,30 @@ router.get('/stores/:code/cost', async (req: AuthRequest, res) => {
try {
const [costResult, catResult] = await Promise.all([
query(`SELECT * FROM analytics.v_store_theoretical_actual_cost_april WHERE store_code = $1`, [req.params.code]),
query(`SELECT * FROM analytics.v_store_category_cost_benchmark_april WHERE store_code = $1`, [req.params.code]),
query(`
WITH store_cat AS (
SELECT finance_category AS category_name,
round(sum(consumption_amount)::numeric, 2) AS consumption_amount,
round(sum(consumption_amount)::numeric / nullif(sum(sum(consumption_amount)) OVER (), 0) * 100, 1) AS actual_cost_rate_pct
FROM analytics.v_inventory_cost_classified_april
WHERE sales_store_code = $1 AND finance_category IS NOT NULL
GROUP BY finance_category
ORDER BY sum(consumption_amount) DESC
),
company_cat AS (
SELECT finance_category,
round(sum(consumption_amount)::numeric / nullif(sum(sum(consumption_amount)) OVER (), 0) * 100, 1) AS benchmark_rate_pct
FROM analytics.v_inventory_cost_classified_april
WHERE finance_category IS NOT NULL
GROUP BY finance_category
)
SELECT s.category_name, s.consumption_amount, s.actual_cost_rate_pct,
COALESCE(c.benchmark_rate_pct, 0) AS benchmark_rate_pct,
round(s.actual_cost_rate_pct - COALESCE(c.benchmark_rate_pct, 0), 1) AS variance_pct
FROM store_cat s
LEFT JOIN company_cat c ON s.category_name = c.finance_category
ORDER BY s.consumption_amount DESC
`, [req.params.code]),
])
sendSuccess(res, { cost: costResult.rows[0], categories: catResult.rows })
} catch (err: any) { sendError(res, err.message) }