fix(risk-assessment): 修正统计数据处理及图表更新逻辑
Some checks failed
Lint Code / Lint Code (push) Failing after 3m6s

- 修正 getRiskStatistics 接口返回数据结构,去除 code 和 data 包装,直接使用业务数据
- 添加详细日志输出统计数据和图表输入数据,便于调试追踪
- 优化饼图和趋势图初始化逻辑,改为懒初始化实例,避免无效初始化
- 饼图数据转换中新增字符串转数字的兼容处理,过滤数值为0的项
- 趋势图调整为使用风险等级分布数据 levelStats,支持字符串及数字类型转换
- 延迟更新图表,确保 DOM 渲染完成后初始化和设置图表
- 移除无用的图表初始化调用,改为数据加载完成后统一更新图表
- 增加 DOM 元素存在性检查及相关警告,防止渲染时出现异常
This commit is contained in:
2026-03-31 18:38:46 +08:00
parent c7abf48c6a
commit d698fae12a

View File

@@ -261,15 +261,11 @@ async function loadRiskList() {
params.projectId = String(queryParams.value.projectId); params.projectId = String(queryParams.value.projectId);
} }
const res = await getRiskList(params); const res = await getRiskList(params);
// res.data 直接是业务数据 { total, rows, code, msg }
const businessData = res.data as any; const businessData = res.data as any;
console.log("API业务数据:", businessData);
if (businessData.code === 200) { if (businessData.code === 200) {
const rows = businessData.rows || []; const rows = businessData.rows || [];
dataList.value = rows; dataList.value = rows;
// 处理字符串类型的total
pagination.value.total = parseInt(businessData.total) || rows.length || 0; pagination.value.total = parseInt(businessData.total) || rows.length || 0;
console.log("风险列表数据:", rows);
} }
} catch (error) { } catch (error) {
message("加载风险列表失败", { type: "error" }); message("加载风险列表失败", { type: "error" });
@@ -278,65 +274,55 @@ async function loadRiskList() {
} }
} }
// 加载项目列表
async function loadProjectList() { async function loadProjectList() {
try { try {
const res = await getProjectList({ pageNum: 1, pageSize: 100 }); const res = await getProjectList({ pageNum: 1, pageSize: 100 });
// res.data 直接是业务数据 { total, rows, code, msg }
const businessData = res.data as any; const businessData = res.data as any;
if (businessData.code === 200) { if (businessData.code === 200) {
projectList.value = businessData.rows || []; projectList.value = businessData.rows || [];
console.log("项目列表:", projectList.value);
} }
} catch (error) { } catch (error) {
console.error("加载项目列表失败", error); console.error("加载项目列表失败", error);
} }
} }
// 加载统计数据
async function loadStatistics() { async function loadStatistics() {
try { try {
const res = await getRiskStatistics(); const res = await getRiskStatistics();
const statsResponse = res.data as any; const data = res.data as any;
if (statsResponse.code === 200 && statsResponse.data) {
const data = statsResponse.data; statistics.value = {
// 处理字符串类型的统计数据 totalCount: parseInt(data.totalCount) || 0,
statistics.value = { identifiedCount: parseInt(data.identifiedCount) || 0,
totalCount: parseInt(data.totalCount) || 0, assignedCount: parseInt(data.assignedCount) || 0,
identifiedCount: parseInt(data.identifiedCount) || 0, mitigatingCount: parseInt(data.mitigatingCount) || 0,
assignedCount: parseInt(data.assignedCount) || 0, resolvedCount: parseInt(data.resolvedCount) || 0,
mitigatingCount: parseInt(data.mitigatingCount) || 0, closedCount: parseInt(data.closedCount) || 0,
resolvedCount: parseInt(data.resolvedCount) || 0, criticalCount: parseInt(data.criticalCount) || 0,
closedCount: parseInt(data.closedCount) || 0, highCount: parseInt(data.highCount) || 0,
criticalCount: parseInt(data.criticalCount) || 0, mediumCount: parseInt(data.mediumCount) || 0,
highCount: parseInt(data.highCount) || 0, lowCount: parseInt(data.lowCount) || 0,
mediumCount: parseInt(data.mediumCount) || 0, categoryStats: data.categoryStats || {},
lowCount: parseInt(data.lowCount) || 0, levelStats: data.levelStats || {},
categoryStats: data.categoryStats || {}, trendData: data.trendData || {},
levelStats: data.levelStats || {}, averageRiskScore: parseFloat(data.averageRiskScore) || 0,
trendData: data.trendData || {}, unresolvedHighCount: parseInt(data.unresolvedHighCount) || 0
averageRiskScore: parseFloat(data.averageRiskScore) || 0, };
unresolvedHighCount: parseInt(data.unresolvedHighCount) || 0 setTimeout(() => {
};
updateCharts(); updateCharts();
} }, 100);
} catch (error) { } catch (error) {
console.error("加载统计数据失败", error); console.error("加载统计数据失败", error);
} }
} }
// 初始化饼图
function initPieChart() {
if (!pieChartRef.value) return;
pieChart = echarts.init(pieChartRef.value);
updatePieChart();
}
// 更新饼图 - 使用 categoryStats 分类统计数据 // 更新饼图 - 使用 categoryStats 分类统计数据
function updatePieChart() { function updatePieChart() {
if (!pieChart) return; if (!pieChartRef.value) return;
if (!pieChart) {
pieChart = echarts.init(pieChartRef.value);
}
// 从 categoryStats 获取分类统计数据
const categoryStats = statistics.value.categoryStats || {}; const categoryStats = statistics.value.categoryStats || {};
const categoryColors: Record<string, string> = { const categoryColors: Record<string, string> = {
schedule: "#409eff", // 进度 - 蓝色 schedule: "#409eff", // 进度 - 蓝色
@@ -359,13 +345,17 @@ function updatePieChart() {
other: "其他风险" other: "其他风险"
}; };
// 构建饼图数据 // 构建饼图数据 - 处理字符串类型的值
const data = Object.entries(categoryStats) const data = Object.entries(categoryStats)
.map(([key, value]) => ({ .map(([key, value]) => {
value: parseInt(String(value)) || 0, const numValue =
name: categoryNames[key] || key, typeof value === "string" ? parseInt(value) : (value as number) || 0;
itemStyle: { color: categoryColors[key] || "#909399" } return {
})) value: numValue,
name: categoryNames[key] || key,
itemStyle: { color: categoryColors[key] || "#909399" }
};
})
.filter(item => item.value > 0) .filter(item => item.value > 0)
.sort((a, b) => b.value - a.value); .sort((a, b) => b.value - a.value);
@@ -416,45 +406,53 @@ function updatePieChart() {
pieChart.setOption(option); pieChart.setOption(option);
} }
// 初始化趋势图
function initTrendChart() { function initTrendChart() {
if (!trendChartRef.value) return; if (!trendChartRef.value) return;
trendChart = echarts.init(trendChartRef.value); trendChart = echarts.init(trendChartRef.value);
updateTrendChart(); updateTrendChart();
} }
// 更新趋势图 - 使用风险状态分布数据
function updateTrendChart() { function updateTrendChart() {
if (!trendChart) return; if (!trendChartRef.value) return;
if (!trendChart) {
trendChart = echarts.init(trendChartRef.value);
}
// 使用状态统计数据展示风险状态分布 const levelStats = statistics.value.levelStats || {};
const statusData = [ const levelData = [
{ {
name: "已识别", name: "严重",
value: statistics.value.identifiedCount || 0, value:
color: "#909399" typeof levelStats.critical === "string"
? parseInt(levelStats.critical)
: (levelStats.critical as number) || 0,
color: "#f56c6c"
}, },
{ {
name: "已分派", name: "",
value: statistics.value.assignedCount || 0, value:
color: "#409eff" typeof levelStats.high === "string"
}, ? parseInt(levelStats.high)
{ : (levelStats.high as number) || 0,
name: "缓解中",
value: statistics.value.mitigatingCount || 0,
color: "#e6a23c" color: "#e6a23c"
}, },
{ {
name: "已解决", name: "",
value: statistics.value.resolvedCount || 0, value:
color: "#67c23a" typeof levelStats.medium === "string"
? parseInt(levelStats.medium)
: (levelStats.medium as number) || 0,
color: "#409eff"
}, },
{ {
name: "已关闭", name: "",
value: statistics.value.closedCount || 0, value:
color: "#13c2c2" typeof levelStats.low === "string"
? parseInt(levelStats.low)
: (levelStats.low as number) || 0,
color: "#67c23a"
} }
]; ].filter(item => item.value > 0);
const option = { const option = {
tooltip: { tooltip: {
@@ -474,7 +472,7 @@ function updateTrendChart() {
}, },
xAxis: { xAxis: {
type: "category", type: "category",
data: statusData.map(item => item.name), data: levelData.map(item => item.name),
axisLine: { lineStyle: { color: "#dcdfe6" } }, axisLine: { lineStyle: { color: "#dcdfe6" } },
axisLabel: { color: "#606266", fontSize: 12 }, axisLabel: { color: "#606266", fontSize: 12 },
axisTick: { show: false } axisTick: { show: false }
@@ -489,7 +487,7 @@ function updateTrendChart() {
{ {
name: "风险数量", name: "风险数量",
type: "bar", type: "bar",
data: statusData.map((item, index) => ({ data: levelData.map((item, index) => ({
value: item.value, value: item.value,
itemStyle: { itemStyle: {
color: item.color, color: item.color,
@@ -510,7 +508,6 @@ function updateTrendChart() {
trendChart.setOption(option); trendChart.setOption(option);
} }
// 更新图表
function updateCharts() { function updateCharts() {
updatePieChart(); updatePieChart();
updateTrendChart(); updateTrendChart();
@@ -566,24 +563,15 @@ async function handleCreate() {
} }
try { try {
// 直接传递字符串ID避免精度丢失
const res = await submitRiskAssessment(String(queryParams.value.projectId)); const res = await submitRiskAssessment(String(queryParams.value.projectId));
console.log("风险评估API响应:", res);
console.log("res.data:", res.data);
const responseData = res.data as any; const responseData = res.data as any;
// 扁平化结构res.data 直接是 { code: 200, data: {...}, message: "..." }
if (responseData.code === 200) { if (responseData.code === 200) {
message("风险评估任务已提交AI正在分析中...", { type: "success" }); message("风险评估任务已提交AI 正在分析中...", { type: "success" });
} else { } else {
console.error(
"响应code不是200:",
responseData.code,
responseData.message
);
message(responseData.message || "提交失败", { type: "error" }); message(responseData.message || "提交失败", { type: "error" });
} }
} catch (error) { } catch (error) {
console.error("风险评估请求异常:", error); console.error("风险评估请求异常", error);
message("提交风险评估任务失败", { type: "error" }); message("提交风险评估任务失败", { type: "error" });
} }
} }
@@ -631,8 +619,7 @@ onMounted(() => {
loadProjectList(); loadProjectList();
loadRiskList(); loadRiskList();
loadStatistics(); loadStatistics();
initPieChart(); // 初始化的图表会在数据加载后通过 updateCharts 自动渲染
initTrendChart();
window.addEventListener("resize", handleResize); window.addEventListener("resize", handleResize);
}); });