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 展示常量(与原型保持一致,非数据映射) ====================
const NODE_CHARS = ['险', '合', '组', '场', '报', '内', '技', '控'];
const NODE_COLORS = ['blue', 'violet', 'green', 'orange', 'blue', 'violet', 'orange', 'green'];
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(() => {});
}, []);
// 衍生展示数据:API 成功则用 API 字段直接构建,失败则回退 mock
const statusCards = useMemo(() => {
if (!nodeStatsApi) return STATISTIC_CARDS;
const { nodeStats, archivedProjectCount, delayedProjectCount } = nodeStatsApi;
const nodes = (nodeStats || []).map((node, i) => ({
key: node.nodeCode || `NODE_${i}`,
title: node.nodeName,
value: Number(node.pendingCount) || 0,
char: NODE_CHARS[i] || node.nodeName.charAt(1) || '-',
colorClass: NODE_COLORS[i] || 'blue',
}));
nodes.push(
{ key: 'archived', title: '已归档项目', value: Number(archivedProjectCount) || 0, char: '档', colorClass: 'cyan' },
{ key: 'delayed', title: '项目延期', value: Number(delayedProjectCount) || 0, char: '延', colorClass: 'red' },
);
return nodes;
}, [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 => (
))}
{/* ===== 第二行:服务行业项目统计 + 评价类别占比 ===== */}
{/* ===== 第三行:项目执行情况 ===== */}
{}}
/>
);
}