diff --git a/client/src/components/store-expense/ExpenseOverviewTab.tsx b/client/src/components/store-expense/ExpenseOverviewTab.tsx index 0271f4d..19871c8 100644 --- a/client/src/components/store-expense/ExpenseOverviewTab.tsx +++ b/client/src/components/store-expense/ExpenseOverviewTab.tsx @@ -31,7 +31,7 @@ export function ExpenseOverviewTab({ month }: { month: string }) {
- + diff --git a/client/src/components/store-expense/LossDiagnosisTab.tsx b/client/src/components/store-expense/LossDiagnosisTab.tsx index f307467..43711ad 100644 --- a/client/src/components/store-expense/LossDiagnosisTab.tsx +++ b/client/src/components/store-expense/LossDiagnosisTab.tsx @@ -116,7 +116,7 @@ function StoreDetailModal({ store, onClose }: { store: StoreDetail | null, onClo { label: '面积(㎡)', value: formatNumber(store.area_sqm) }, { label: '坪效', value: formatNumber(store.received_per_sqm) }, { label: '账单数', value: formatNumber(store.bill_count) }, - { label: '租约到期', value: store.lease_expiry_date ? new Date(store.lease_expiry_date).toLocaleDateString('zh-CN') : '-' }, + { label: '租约到期', value: store.lease_expiry_date ? String(store.lease_expiry_date).substring(0, 10) : '-' }, ] return ( @@ -197,9 +197,9 @@ export function LossDiagnosisTab({ month }: { month: string }) { const rows = (data as any)?.data || [] const meta = (data as any)?.meta || { page, pageSize: PAGE_SIZE, total: 0 } - const p0Count = rows.filter((r: any) => r.priority === 'P0').length - const p1Count = rows.filter((r: any) => r.priority === 'P1').length - const totalLoss = rows.reduce((sum: number, r: any) => sum + parseFloat(r.actual_store_contribution || 0), 0) + const p0Count = meta.evalStats ? Number(meta.evalStats.p0_count) : rows.filter((r: any) => r.priority === 'P0').length + const p1Count = meta.evalStats ? Number(meta.evalStats.p1_count) : rows.filter((r: any) => r.priority === 'P1').length + const totalLoss = meta.evalStats ? Number(meta.evalStats.total_loss) : rows.reduce((sum: number, r: any) => sum + parseFloat(r.actual_store_contribution || 0), 0) return (
diff --git a/client/src/components/store-expense/RentRiskTab.tsx b/client/src/components/store-expense/RentRiskTab.tsx index 5b6ab6d..9769286 100644 --- a/client/src/components/store-expense/RentRiskTab.tsx +++ b/client/src/components/store-expense/RentRiskTab.tsx @@ -76,7 +76,7 @@ export function RentRiskTab({ month }: { month: string }) { { key: 'rent_rate_pct', label: '租金率', align: 'right', render: (r) => 20 ? 'text-red-600 font-medium' : ''}>{formatPercent(r.rent_rate_pct)} }, { key: 'area_sqm', label: '面积(㎡)', align: 'right', render: (r) => formatNumber(r.area_sqm) }, { key: 'received_per_sqm', label: '坪效', align: 'right', render: (r) => formatNumber(r.received_per_sqm) }, - { key: 'lease_expiry_date', label: '租约到期', render: (r) => r.lease_expiry_date ? new Date(r.lease_expiry_date).toLocaleDateString('zh-CN') : '-' }, + { key: 'lease_expiry_date', label: '租约到期', render: (r) => r.lease_expiry_date ? String(r.lease_expiry_date).substring(0, 10) : '-' }, { key: 'risk_level', label: '风险等级', render: (r) => {r.risk_level} }, { key: 'suggestion', label: '建议' }, ]} diff --git a/client/src/components/store-expense/StoreEvaluationTab.tsx b/client/src/components/store-expense/StoreEvaluationTab.tsx index 654daf4..d121c30 100644 --- a/client/src/components/store-expense/StoreEvaluationTab.tsx +++ b/client/src/components/store-expense/StoreEvaluationTab.tsx @@ -59,7 +59,7 @@ function EvalDetailModal({ store, onClose }: { store: EvalStoreDetail | null, on { label: '租金率', value: formatPercent(store.rent_rate_pct), warn: parseFloat(store.rent_rate_pct) > 20 }, { label: '坪效', value: formatNumber(store.received_per_sqm), warn: parseFloat(store.received_per_sqm) < 1000 }, { label: '面积(㎡)', value: formatNumber(store.area_sqm) }, - { label: '租约到期', value: store.lease_expiry_date ? new Date(store.lease_expiry_date).toLocaleDateString('zh-CN') : '-' }, + { label: '租约到期', value: store.lease_expiry_date ? String(store.lease_expiry_date).substring(0, 10) : '-' }, ] return ( @@ -167,7 +167,7 @@ export function StoreEvaluationTab({ month }: { month: string }) { { key: 'actual_store_contribution', label: '贡献利润', align: 'right', render: (r) => {formatCurrency(r.actual_store_contribution)} }, { key: 'actual_store_contribution_rate_pct', label: '贡献率', align: 'right', render: (r) => formatPercent(r.actual_store_contribution_rate_pct) }, { key: 'received_per_sqm', label: '坪效', align: 'right', render: (r) => formatNumber(r.received_per_sqm) }, - { key: 'lease_expiry_date', label: '租约到期', render: (r) => r.lease_expiry_date ? new Date(r.lease_expiry_date).toLocaleDateString('zh-CN') : '-' }, + { key: 'lease_expiry_date', label: '租约到期', render: (r) => r.lease_expiry_date ? String(r.lease_expiry_date).substring(0, 10) : '-' }, { key: 'evaluation_detail', label: '评估详情', render: (r) => {r.evaluation_detail} }, ]} /> diff --git a/client/src/pages/BomPenetrationPage.tsx b/client/src/pages/BomPenetrationPage.tsx index db86d81..9ce6487 100644 --- a/client/src/pages/BomPenetrationPage.tsx +++ b/client/src/pages/BomPenetrationPage.tsx @@ -45,16 +45,15 @@ function buildTree(flatTree: any[]): BomTreeNode[] { const roots: BomTreeNode[] = [] flatTree.forEach((n: any) => { const node: BomTreeNode = { ...n, children: [] } - nodeMap.set(node.material_code + '_' + node.level, node) + nodeMap.set(node.path, node) }) flatTree.forEach((n: any) => { - const key = n.material_code + '_' + n.level - const node = nodeMap.get(key)! + const node = nodeMap.get(n.path)! if (n.level === 1) { roots.push(node) } else { - const parentKey = n.parent_material_code + '_' + (n.level - 1) - const parent = nodeMap.get(parentKey) + const parentPath = n.path.split(' -> ').slice(0, -1).join(' -> ') + const parent = nodeMap.get(parentPath) if (parent) parent.children.push(node) else roots.push(node) } @@ -176,7 +175,7 @@ export function BomPenetrationPage() { const childrenToRender = hasChildren ? node.children : (lazyLoaded || []) const isZero = node.theoretical_qty === 0 && node.issue_qty === 0 && node.theoretical_amt === 0 && node.issue_amt === 0 rows.push( - +
{showChevron ? ( diff --git a/client/src/pages/RegionalPage.tsx b/client/src/pages/RegionalPage.tsx index a2be755..4759aae 100644 --- a/client/src/pages/RegionalPage.tsx +++ b/client/src/pages/RegionalPage.tsx @@ -55,7 +55,7 @@ export function RegionalPage() { const pageLoading = riskLoading || weeklyLoading || priorityLoading const weeklyMutation = useMutation({ - mutationFn: ({ id, text }: { id: number; text: string }) => api.put(`/tasks/${id}/weekly-check`, { weekly_comment: text }), + mutationFn: ({ id, text }: { id: number; text: string }) => api.put(`/tasks/${id}/weekly-check`, { check_comment: text }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['tasks/weekly-check'] }) setWeeklyModal(null) diff --git a/client/src/pages/RevenuePage.tsx b/client/src/pages/RevenuePage.tsx index 917412d..5c3411b 100644 --- a/client/src/pages/RevenuePage.tsx +++ b/client/src/pages/RevenuePage.tsx @@ -68,7 +68,7 @@ export function RevenuePage() { received: Number(r.received || 0), bills: Number(r.bill_count || 0), avg_bill: Number(r.avg_bill_value || 0), - discount_rate: Number(r.avg_discount_rate_pct || 0), + discount_rate: Number(r.discount_rate_pct || 0), })) // 环比 diff --git a/client/src/pages/StoreDetailPage.tsx b/client/src/pages/StoreDetailPage.tsx index 9838557..99fa3ff 100644 --- a/client/src/pages/StoreDetailPage.tsx +++ b/client/src/pages/StoreDetailPage.tsx @@ -47,7 +47,7 @@ export function StoreDetailPage() { const { data: healthData } = useQuery({ queryKey: ['store-health', code, month], - queryFn: () => api.get('/situational-awareness/health-score', { params: { month } }), + queryFn: () => api.get('/situational-awareness/health-score', { params: { month, store_code: code } }), }) const { data: dailyData } = useQuery({ @@ -125,8 +125,8 @@ export function StoreDetailPage() { const quadrant = action?.management_quadrant || '' const quadrantInfo = quadrantDesc[quadrant] - // 公司均值 - const companyAvg = { daily_rev: 20144, bill: 36.8, discount: 20.5, margin: 71.5, member: 15.9, repeat: 37.0, delivery: 36.1, combo: 20.6, items: 4.05 } + // 公司均值(从API获取,fallback到默认值) + const companyAvg = sd.companyAvg || { daily_rev: 20144, bill: 36.8, discount: 20.5, margin: 71.5, member: 15.9, repeat: 37.0, delivery: 36.1, combo: 20.6, items: 4.05 } // 偏差项明细 const deviations: { label: string; store: number; company: number; unit: string; good: 'high' | 'low' }[] = [ diff --git a/client/src/pages/StoreGradePage.tsx b/client/src/pages/StoreGradePage.tsx index bf5cec3..d07f853 100644 --- a/client/src/pages/StoreGradePage.tsx +++ b/client/src/pages/StoreGradePage.tsx @@ -8,6 +8,7 @@ import { formatCurrency, formatNumber, formatPercent } from '@/lib/utils' import { useState } from 'react' import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, PieChart, Pie, Cell, RadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, Radar } from 'recharts' import { Tabs } from '@/components/Tabs' +import { MonthPicker } from '@/components/MonthPicker' const GRADE_COLORS: Record = { A: '#22c55e', B: '#3b82f6', C: '#eab308', D: '#ef4444' } const RISK_COLORS: Record = { '红色': '#ef4444', '黄色': '#eab308', '绿色': '#22c55e' } @@ -20,18 +21,18 @@ export function StoreGradePage() { const { data: gradeData, isLoading: gradeLoading } = useQuery({ queryKey: ['store-grade/grades', month], - queryFn: () => api.get('/store-grade/grades', { params: { month: month + '-01' } }), + queryFn: () => api.get('/store-grade/grades', { params: { month } }), enabled: tab === 'grade', }) const { data: closureData, isLoading: closureLoading } = useQuery({ queryKey: ['store-grade/closure-analysis', month], - queryFn: () => api.get('/store-grade/closure-analysis', { params: { month: month + '-01' } }), + queryFn: () => api.get('/store-grade/closure-analysis', { params: { month } }), enabled: tab === 'closure', }) const autoGradeMutation = useMutation({ - mutationFn: () => api.post('/store-grade/auto-grade', null, { params: { month: month + '-01' } }), + mutationFn: () => api.post('/store-grade/auto-grade', null, { params: { month } }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['store-grade/grades'] }) }, @@ -89,12 +90,7 @@ export function StoreGradePage() {

自动分级 · 风险监控 · 关停测算 · {month}

- setMonth(e.target.value)} - className="rounded border px-2 py-1 text-sm" - /> + {tab === 'grade' && (