diff --git a/src/api/risk-workorder.ts b/src/api/risk-workorder.ts index 3169a9d..a08d099 100644 --- a/src/api/risk-workorder.ts +++ b/src/api/risk-workorder.ts @@ -90,7 +90,7 @@ export type CreateRiskRequest = { /** 风险查询参数 */ export type RiskQueryParams = { - projectId?: number; + projectId?: number | string; pageNum: number; pageSize: number; category?: string; @@ -379,3 +379,88 @@ export const getMyWorkOrderStatistics = () => { "/api/v1/workorder/my/statistics" ); }; + +// ==================== SSE风险评估API ==================== + +/** 风险评估任务VO */ +export type RiskAssessmentTaskVO = { + taskId: string; + userId?: number; + status: string; // pending, processing, completed, failed + statusDesc: string; + progress: number; + progressMessage: string; + projectId: number; + projectName: string; + createTime: string; + startTime?: string; + completeTime?: string; + result?: RiskAssessmentResultVO; + errorMessage?: string; +}; + +/** 风险评估结果VO */ +export type RiskAssessmentResultVO = { + projectId: number; + projectName: string; + overallRiskLevel: string; + overallRiskScore: number; + assessmentSummary: string; + riskAreas: string[]; + identifiedRisks: Array<{ + riskName: string; + category: string; + probability: number; + impact: number; + mitigationPlan: string; + }>; + recommendations: string[]; +}; + +/** 任务统计信息 */ +export type RiskTaskStats = { + total: number; + processing: number; + completed: number; + failed: number; +}; + +/** 提交异步风险评估任务 */ +export const submitRiskAssessment = (projectId: number) => { + return http.request>( + "post", + `/api/v1/risk/sse/assess/${projectId}` + ); +}; + +/** 查询我的风险评估任务列表 */ +export const getMyRiskAssessmentTasks = () => { + return http.request>( + "get", + "/api/v1/risk/sse/my-tasks" + ); +}; + +/** 查询任务统计信息 */ +export const getMyRiskTaskStats = () => { + return http.request>( + "get", + "/api/v1/risk/sse/my-tasks/stats" + ); +}; + +/** 查询单个任务状态 */ +export const getRiskTaskStatus = (taskId: string) => { + return http.request>( + "get", + `/api/v1/risk/sse/task/${taskId}` + ); +}; + +/** 获取任务评估结果 */ +export const getRiskTaskResult = (taskId: string) => { + return http.request>( + "get", + `/api/v1/risk/sse/task/${taskId}/result` + ); +}; diff --git a/src/router/enums.ts b/src/router/enums.ts index 656f393..a4a044b 100644 --- a/src/router/enums.ts +++ b/src/router/enums.ts @@ -15,7 +15,6 @@ const home = 0, // 平台规定只有 home 路由的 rank 才能为 0 ,所以 frame = 12, nested = 13, permission = 14, - system = 15, monitor = 16, tabs = 17, about = 18, @@ -29,7 +28,8 @@ const home = 0, // 平台规定只有 home 路由的 rank 才能为 0 ,所以 mind = 26, guide = 27, menuoverflow = 28, - riskWorkorder = 29; + riskWorkorder = 29, + system = 99; export { home, diff --git a/src/views/risk-assessment/index.vue b/src/views/risk-assessment/index.vue index 681244d..548ad8b 100644 --- a/src/views/risk-assessment/index.vue +++ b/src/views/risk-assessment/index.vue @@ -6,10 +6,12 @@ import { getRiskList, getRiskStatistics, deleteRisk, + submitRiskAssessment, type RiskVO, type RiskStatisticsVO, type RiskQueryParams } from "@/api/risk-workorder"; +import { getProjectList, type ProjectItem } from "@/api/project"; import { message } from "@/utils/message"; import dayjs from "dayjs"; import * as echarts from "echarts"; @@ -62,6 +64,9 @@ const queryParams = ref({ // 趋势周期 const trendPeriod = ref("month"); +// 项目列表 +const projectList = ref([]); + // 分页 const pagination = ref({ currentPage: 1, @@ -87,7 +92,7 @@ const statCards = computed(() => [ bgColor: "#ecf5ff" }, { - title: "高风险", + title: "严重风险", value: statistics.value.criticalCount || 0, trend: "↑ 5% 较上月", trendUp: true, @@ -96,7 +101,7 @@ const statCards = computed(() => [ bgColor: "#fef0f0" }, { - title: "中风险", + title: "高风险", value: statistics.value.highCount || 0, trend: "↓ 3% 较上月", trendUp: false, @@ -105,8 +110,9 @@ const statCards = computed(() => [ bgColor: "#fdf6ec" }, { - title: "低风险", - value: statistics.value.mediumCount + statistics.value.lowCount || 0, + title: "中低风险", + value: + (statistics.value.mediumCount || 0) + (statistics.value.lowCount || 0), trend: "↓ 2% 较上月", trendUp: false, icon: "ri:checkbox-circle-line", @@ -202,16 +208,28 @@ function getStatusLabel(status?: string): string { async function loadRiskList() { loading.value = true; try { - const res = await getRiskList({ - ...queryParams.value, + const params: any = { pageNum: pagination.value.currentPage, - pageSize: pagination.value.pageSize - }); - const responseData = res.data as any; - if (responseData.code === 200 && responseData.data) { - const tableData = responseData.data; - dataList.value = tableData.rows || []; - pagination.value.total = tableData.total || 0; + pageSize: pagination.value.pageSize, + keyword: queryParams.value.keyword, + category: queryParams.value.category, + riskLevel: queryParams.value.riskLevel, + status: queryParams.value.status + }; + // projectId 转换为字符串避免精度丢失 + if (queryParams.value.projectId) { + params.projectId = String(queryParams.value.projectId); + } + const res = await getRiskList(params); + // res.data 直接是业务数据 { total, rows, code, msg } + const businessData = res.data as any; + console.log("API业务数据:", businessData); + if (businessData.code === 200) { + const rows = businessData.rows || []; + dataList.value = rows; + // 处理字符串类型的total + pagination.value.total = parseInt(businessData.total) || rows.length || 0; + console.log("风险列表数据:", rows); } } catch (error) { message("加载风险列表失败", { type: "error" }); @@ -220,13 +238,46 @@ async function loadRiskList() { } } +// 加载项目列表 +async function loadProjectList() { + try { + const res = await getProjectList({ pageNum: 1, pageSize: 100 }); + // res.data 直接是业务数据 { total, rows, code, msg } + const businessData = res.data as any; + if (businessData.code === 200) { + projectList.value = businessData.rows || []; + console.log("项目列表:", projectList.value); + } + } catch (error) { + console.error("加载项目列表失败", error); + } +} + // 加载统计数据 async function loadStatistics() { try { const res = await getRiskStatistics(); const statsResponse = res.data as any; if (statsResponse.code === 200 && statsResponse.data) { - statistics.value = statsResponse.data; + const data = statsResponse.data; + // 处理字符串类型的统计数据 + statistics.value = { + totalCount: parseInt(data.totalCount) || 0, + identifiedCount: parseInt(data.identifiedCount) || 0, + assignedCount: parseInt(data.assignedCount) || 0, + mitigatingCount: parseInt(data.mitigatingCount) || 0, + resolvedCount: parseInt(data.resolvedCount) || 0, + closedCount: parseInt(data.closedCount) || 0, + criticalCount: parseInt(data.criticalCount) || 0, + highCount: parseInt(data.highCount) || 0, + mediumCount: parseInt(data.mediumCount) || 0, + lowCount: parseInt(data.lowCount) || 0, + categoryStats: data.categoryStats || {}, + levelStats: data.levelStats || {}, + trendData: data.trendData || {}, + averageRiskScore: parseFloat(data.averageRiskScore) || 0, + unresolvedHighCount: parseInt(data.unresolvedHighCount) || 0 + }; updateCharts(); } } catch (error) { @@ -247,21 +298,25 @@ function updatePieChart() { const data = [ { value: statistics.value.criticalCount || 0, - name: "高风险", + name: "严重", itemStyle: { color: "#f56c6c" } }, { value: statistics.value.highCount || 0, - name: "中风险", + name: "高", itemStyle: { color: "#e6a23c" } }, { - value: - (statistics.value.mediumCount || 0) + (statistics.value.lowCount || 0), - name: "低风险", + value: statistics.value.mediumCount || 0, + name: "中", + itemStyle: { color: "#409eff" } + }, + { + value: statistics.value.lowCount || 0, + name: "低", itemStyle: { color: "#67c23a" } } - ]; + ].filter(item => item.value > 0); const option = { tooltip: { trigger: "item", @@ -412,9 +467,24 @@ function handleCurrentChange(val: number) { loadRiskList(); } -// 新建风险 -function handleCreate() { - message("新建风险功能开发中", { type: "info" }); +// 新建风险评估 - 使用SSE异步评估 +async function handleCreate() { + if (!queryParams.value.projectId) { + message("请先选择项目", { type: "warning" }); + return; + } + try { + const res = await submitRiskAssessment(queryParams.value.projectId); + const responseData = res.data as any; + if (responseData.code === 200) { + message("风险评估任务已提交,AI正在分析中...", { type: "success" }); + // 可以在这里启动SSE连接监听进度 + } else { + message(responseData.message || "提交失败", { type: "error" }); + } + } catch (error) { + message("提交风险评估任务失败", { type: "error" }); + } } // 查看风险详情 @@ -440,6 +510,16 @@ async function handleDelete(row: RiskVO) { } } +// 分配工单 +function handleAssignWorkOrder(row: RiskVO) { + message(`为风险分配工单: ${row.riskName}`, { type: "info" }); +} + +// 标记已完成 +function handleComplete(row: RiskVO) { + message(`标记风险已完成: ${row.riskName}`, { type: "success" }); +} + // 窗口大小变化时重新渲染图表 function handleResize() { pieChart?.resize(); @@ -447,6 +527,7 @@ function handleResize() { } onMounted(() => { + loadProjectList(); loadRiskList(); loadStatistics(); initPieChart(); @@ -468,11 +549,17 @@ onMounted(() => {
- + @@ -543,18 +630,27 @@ onMounted(() => {
- 高风险 - 19% + 严重 + {{ + statistics.criticalCount || 0 + }}
- 中风险 - 38% + + {{ statistics.highCount || 0 }} +
+
+ + + {{ + statistics.mediumCount || 0 + }}
- 低风险 - 43% + + {{ statistics.lowCount || 0 }}
@@ -657,14 +753,29 @@ onMounted(() => {