import React, { useCallback, useEffect, useMemo, useState } from 'react'; import DriverBack from '~/pages/Container/Driver/components/DriverBack'; import EnterpriseTypeChart from './components/EnterpriseTypeChart'; import ProjectTypeChart from './components/ProjectTypeChart'; import ProjectCompletionTable from './components/ProjectCompletionTable'; import './index.css'; import { STATISTIC_CARDS, INFO_ALERTS, PROJECT_SUMMARY, ENTERPRISE_TYPE_STATS, PROJECT_TYPE_DISTRIBUTION, PROJECT_TOTAL, PROJECT_COMPLETION_LIST, } from './mockData'; import { fetchProjectNodeStats, fetchNotices, fetchIndustryStat, fetchEvalTypeRatio, fetchProjectExecution, } from '~/api/institution'; // ==================== UI 展示常量(与原型保持一致,非数据映射) ==================== function mockIndustryToApiFormat() { return { list: ENTERPRISE_TYPE_STATS.categories.map((name, i) => ({ industryCode: '', industryName: name, projectCount: ENTERPRISE_TYPE_STATS.projectCount[i], statutoryProjectCount: ENTERPRISE_TYPE_STATS.statutoryCount[i], })), }; } function mockEvalTypeToApiFormat() { return { totalProjectCount: PROJECT_TOTAL, items: PROJECT_TYPE_DISTRIBUTION.map(item => ({ evalTypeCode: '', evalTypeName: item.name, count: item.value, })), }; } function mockExecutionToApiFormat() { return { list: PROJECT_COMPLETION_LIST.map(item => ({ projectId: item.id, projectNo: item.projectCode, projectName: item.projectName, customerName: item.evalCompany, evalTypeCode: '', evalTypeName: item.evalType, projectLeaderName: item.projectLeader, planEndDate: item.endDate, })), }; } // ==================== 子组件 ==================== function StatusCard({ item }) { return (
{item.char}
{item.title} {item.value}
); } function ReminderCard({ item }) { return (
{item.char}
{item.title} {item.value}
); } // ==================== 主组件 ==================== export default function InstitutionDashboard() { const handleReminderClick = useCallback(() => {}, []); // 各 API 的原始返回数据(null 表示接口未成功,走 mock) const [nodeStatsApi, setNodeStatsApi] = useState(null); const [noticesApi, setNoticesApi] = useState(null); const [industryStatApi, setIndustryStatApi] = useState(null); const [evalTypeRatioApi, setEvalTypeRatioApi] = useState(null); const [projectExecutionApi, setProjectExecutionApi] = useState(null); useEffect(() => { fetchProjectNodeStats() .then(setNodeStatsApi) .catch(() => {}); fetchNotices() .then(setNoticesApi) .catch(() => {}); fetchIndustryStat() .then(setIndustryStatApi) .catch(() => {}); fetchEvalTypeRatio() .then(setEvalTypeRatioApi) .catch(() => {}); fetchProjectExecution() .then(setProjectExecutionApi) .catch(() => {}); }, []); // 衍生展示数据:始终渲染固定卡片集合(8 个节点 + 已归档 + 项目延期), // 仅用 API 数据覆盖对应数值,保证无论接口返回多少节点,卡片项数都不减少。 const statusCards = useMemo(() => { if (!nodeStatsApi) return STATISTIC_CARDS; const { nodeStats = [], archivedProjectCount = 0, delayedProjectCount = 0 } = nodeStatsApi || {}; const nodeByName = new Map(); (nodeStats || []).forEach((n) => { if (n && n.nodeName) nodeByName.set(n.nodeName, n); }); return STATISTIC_CARDS.map((card) => { let value = card.value; if (card.key === 'archived') { value = Number(archivedProjectCount) || 0; } else if (card.key === 'delayed') { value = Number(delayedProjectCount) || 0; } else { const node = nodeByName.get(card.title); if (node) value = Number(node.pendingCount) || 0; } return { ...card, value }; }); }, [nodeStatsApi]); const projectSummary = useMemo(() => { if (!nodeStatsApi) return PROJECT_SUMMARY; return { total: Number(nodeStatsApi.totalProjects) || 0, statutory: Number(nodeStatsApi.statutoryProjects) || 0, }; }, [nodeStatsApi]); const alertItems = useMemo(() => { if (!noticesApi) return INFO_ALERTS; return [ { key: 'qualCheck', title: '资质现场审查通知', value: Number(noticesApi.qualOnSiteReviewCount) || 0, char: '审', colorClass: 'yellow' }, { key: 'supervisionCheck', title: '监督检查通知', value: Number(noticesApi.inspectionCount) || 0, char: '检', colorClass: 'red' }, { key: 'unreadNotice', title: '未读监管通知', value: Number(noticesApi.unreadRegulatoryCount) || 0, char: '未', colorClass: 'blue' }, ]; }, [noticesApi]); const industryStatData = useMemo(() => { return (industryStatApi && industryStatApi.list && industryStatApi.list.length > 0) ? industryStatApi : mockIndustryToApiFormat(); }, [industryStatApi]); const evalTypeRatioData = useMemo(() => { return (evalTypeRatioApi && evalTypeRatioApi.items && evalTypeRatioApi.items.length > 0) ? evalTypeRatioApi : mockEvalTypeToApiFormat(); }, [evalTypeRatioApi]); const projectExecutionData = useMemo(() => { return (projectExecutionApi && projectExecutionApi.list && projectExecutionApi.list.length > 0) ? projectExecutionApi : mockExecutionToApiFormat(); }, [projectExecutionApi]); const legendColors = useMemo(() => ({ project: '#4285f4', statutory: '#ffab31', }), []); return (
{/* ===== 第一行:项目节点统计 + 通知提醒 ===== */}

当前项目节点统计

项目总数:{projectSummary.total} 法定项目:{projectSummary.statutory}
{statusCards.map(item => ( ))}

通知提醒

{alertItems.map(item => ( ))}
{/* ===== 第二行:服务行业项目统计 + 评价类别占比 ===== */}

服务行业项目统计

项目数 法定项目

评价类别占比

{/* ===== 第三行:项目执行情况 ===== */} {}} />
); }