From 16f466f666d079e8b7a2b09486107e1c997d647c Mon Sep 17 00:00:00 2001 From: JiaoTianBo Date: Mon, 30 Mar 2026 14:20:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(api):=20=E6=96=B0=E5=A2=9E=E9=A3=8E?= =?UTF-8?q?=E9=99=A9=E4=B8=8E=E5=B7=A5=E5=8D=95=E7=AE=A1=E7=90=86=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=8F=8A=E5=A4=9A=E8=AF=AD=E8=A8=80=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增风险与工单相关多语言菜单项(英文和中文) - 定义风险相关类型,包括风险分类、风险等级和状态等 - 定义工单相关类型,包括工单类型、优先级及状态等 - 实现风险评估创建、更新、删除、查询及统计接口 - 实现工单创建、更新、删除、查询、处理和分配接口 - 支持批量更新风险状态接口 - 新增我的工单列表及统计接口 - 提供统一的响应结果类型定义 - 更新OpenAPI规范文件以支持新增接口 --- locales/en.yaml | 3 + locales/zh-CN.yaml | 3 + src/api/risk-workorder.ts | 381 +++++ src/api/风险与工单.openapi.json | 1657 ++++++++++++++++++++ src/router/enums.ts | 6 +- src/router/index.ts | 5 +- src/router/modules/risk-assessment.ts | 23 + src/router/modules/workorder-management.ts | 23 + src/views/project/detail.vue | 18 +- src/views/risk-assessment/index.vue | 738 +++++++++ src/views/workorder-management/index.vue | 862 ++++++++++ 11 files changed, 3714 insertions(+), 5 deletions(-) create mode 100644 src/api/risk-workorder.ts create mode 100644 src/api/风险与工单.openapi.json create mode 100644 src/router/modules/risk-assessment.ts create mode 100644 src/router/modules/workorder-management.ts create mode 100644 src/views/risk-assessment/index.vue create mode 100644 src/views/workorder-management/index.vue diff --git a/locales/en.yaml b/locales/en.yaml index 73b7422..a9d8bc0 100644 --- a/locales/en.yaml +++ b/locales/en.yaml @@ -70,6 +70,9 @@ panel: menus: pureHome: Home pureProject: Project Management + pureRiskWorkorder: Risk & Workorder + pureRiskAssessment: Risk Assessment + pureWorkorderManagement: Workorder Management pureLogin: Login pureEmpty: Empty Page pureTable: Table diff --git a/locales/zh-CN.yaml b/locales/zh-CN.yaml index 53a0d28..308d64f 100644 --- a/locales/zh-CN.yaml +++ b/locales/zh-CN.yaml @@ -70,6 +70,9 @@ panel: menus: pureHome: 首页 pureProject: 项目管理 + pureRiskWorkorder: 风险与工单 + pureRiskAssessment: 风险评估 + pureWorkorderManagement: 工单管理 pureLogin: 登录 pureEmpty: 无Layout页 pureTable: 表格 diff --git a/src/api/risk-workorder.ts b/src/api/risk-workorder.ts new file mode 100644 index 0000000..3169a9d --- /dev/null +++ b/src/api/risk-workorder.ts @@ -0,0 +1,381 @@ +import { http } from "@/utils/http"; + +/** 通用响应结果 */ +type Result = { + code: number; + message: string; + data?: T; +}; + +// ==================== 风险相关类型定义 ==================== + +/** 风险分类 */ +export type RiskCategory = + | "technical" + | "schedule" + | "cost" + | "quality" + | "resource" + | "external" + | "other"; + +/** 风险来源 */ +export type RiskSource = "internal" | "external" | "manual"; + +/** 风险等级 */ +export type RiskLevel = "critical" | "high" | "medium" | "low"; + +/** 风险状态 */ +export type RiskStatus = + | "identified" + | "assigned" + | "mitigating" + | "resolved" + | "closed"; + +/** 风险VO */ +export type RiskVO = { + id?: number; + riskCode?: string; + projectId?: number; + projectName?: string; + category?: RiskCategory; + riskName?: string; + description?: string; + riskSource?: RiskSource; + probability?: number; + impact?: number; + riskScore?: number; + riskLevel?: RiskLevel; + status?: RiskStatus; + ownerId?: number; + ownerName?: string; + ownerAvatar?: string; + workOrderCount?: number; + mitigationPlan?: string; + contingencyPlan?: string; + triggerCondition?: string; + discoverTime?: string; + dueDate?: string; + resolvedTime?: string; + tags?: string[]; + createTime?: string; + updateTime?: string; +}; + +/** 分页数据结构 */ +export type TableDataInfo = { + total: number; + rows: T[]; + code: number; + msg: string; +}; + +/** 创建风险请求 */ +export type CreateRiskRequest = { + projectId?: number; + category?: RiskCategory; + riskName?: string; + description?: string; + riskSource?: RiskSource; + probability?: number; + impact?: number; + ownerId?: number; + mitigationPlan?: string; + contingencyPlan?: string; + triggerCondition?: string; + dueDate?: string; + tags?: string[]; +}; + +/** 风险查询参数 */ +export type RiskQueryParams = { + projectId?: number; + pageNum: number; + pageSize: number; + category?: string; + riskLevel?: string; + status?: string; + keyword?: string; +}; + +/** 风险统计VO */ +export type RiskStatisticsVO = { + totalCount: number; + identifiedCount: number; + assignedCount: number; + mitigatingCount: number; + resolvedCount: number; + closedCount: number; + criticalCount: number; + highCount: number; + mediumCount: number; + lowCount: number; + categoryStats: Record; + levelStats: Record; + trendData: Record; + averageRiskScore: number; + unresolvedHighCount: number; +}; + +// ==================== 工单相关类型定义 ==================== + +/** 工单类型 */ +export type WorkOrderType = + | "bug" + | "feature" + | "task" + | "incident" + | "risk_handle" + | "other"; + +/** 工单优先级 */ +export type WorkOrderPriority = "critical" | "high" | "medium" | "low"; + +/** 工单状态 */ +export type WorkOrderStatus = + | "pending" + | "assigned" + | "processing" + | "resolved" + | "closed" + | "reopened"; + +/** 工单来源 */ +export type WorkOrderSource = "web" | "mobile" | "api" | "system" | "risk"; + +/** 工单VO */ +export type WorkOrderVO = { + id?: number; + orderCode?: string; + orderType?: WorkOrderType; + projectId?: number; + projectName?: string; + riskId?: number; + riskName?: string; + title?: string; + description?: string; + creatorId?: number; + creatorName?: string; + handlerId?: number; + handlerName?: string; + handlerAvatar?: string; + handlerGroupId?: number; + priority?: WorkOrderPriority; + status?: WorkOrderStatus; + source?: WorkOrderSource; + deadline?: string; + assignedTime?: string; + firstResponseTime?: string; + resolvedTime?: string; + closedTime?: string; + satisfactionScore?: number; + isOverdue?: boolean; + tags?: string[]; + createTime?: string; + updateTime?: string; +}; + +/** 创建工单请求 */ +export type CreateWorkOrderRequest = { + projectId?: number; + riskId?: number; + orderType?: WorkOrderType; + title?: string; + description?: string; + priority?: WorkOrderPriority; + handlerId?: number; + handlerGroupId?: number; + deadline?: string; + source?: WorkOrderSource; + tags?: string[]; +}; + +/** 工单查询参数 */ +export type WorkOrderQueryParams = { + projectId?: number; + pageNum: number; + pageSize: number; + orderType?: string; + status?: string; + priority?: string; + keyword?: string; +}; + +/** 我的工单查询参数 */ +export type MyWorkOrderQueryParams = { + pageNum: number; + pageSize: number; + status?: string; + orderType?: string; +}; + +/** 处理工单请求 */ +export type ProcessWorkOrderRequest = { + workOrderId?: number; + status?: "processing" | "resolved" | "closed" | "reopened"; + satisfactionScore?: number; +}; + +/** 工单统计VO */ +export type WorkOrderStatisticsVO = { + totalCount: number; + pendingCount: number; + assignedCount: number; + processingCount: number; + completedCount: number; + closedCount: number; + rejectedCount: number; + overdueCount: number; + aboutToExpireCount: number; + typeStats: Record; + priorityStats: Record; +}; + +// ==================== 风险API ==================== + +/** 创建风险评估 */ +export const createRisk = (data: CreateRiskRequest) => { + return http.request>("post", "/api/v1/risk", { data }); +}; + +/** 更新风险 */ +export const updateRisk = (riskId: number, data: CreateRiskRequest) => { + return http.request>("put", `/api/v1/risk/${riskId}`, { + data + }); +}; + +/** 删除风险 */ +export const deleteRisk = (riskId: number) => { + return http.request>("delete", `/api/v1/risk/${riskId}`); +}; + +/** 获取风险详情 */ +export const getRiskDetail = (riskId: number) => { + return http.request>("get", `/api/v1/risk/${riskId}`); +}; + +/** 分页查询风险列表 */ +export const getRiskList = (params: RiskQueryParams) => { + return http.request>>( + "get", + "/api/v1/risk/list", + { params } + ); +}; + +/** 获取风险统计信息 */ +export const getRiskStatistics = (projectId?: number) => { + return http.request>( + "get", + "/api/v1/risk/statistics", + { params: projectId ? { projectId } : undefined } + ); +}; + +/** 为风险分配工单 */ +export const assignWorkOrderToRisk = ( + riskId: number, + data: CreateWorkOrderRequest +) => { + return http.request>( + "post", + `/api/v1/risk/${riskId}/assign-workorder`, + { data } + ); +}; + +/** 批量更新风险状态 */ +export const batchUpdateRiskStatus = (riskIds: number[], status: string) => { + return http.request>("put", "/api/v1/risk/batch-status", { + params: { status }, + data: riskIds + }); +}; + +// ==================== 工单API ==================== + +/** 创建工单 */ +export const createWorkOrder = (data: CreateWorkOrderRequest) => { + return http.request>("post", "/api/v1/workorder", { data }); +}; + +/** 更新工单 */ +export const updateWorkOrder = ( + workOrderId: number, + data: CreateWorkOrderRequest +) => { + return http.request>( + "put", + `/api/v1/workorder/${workOrderId}`, + { data } + ); +}; + +/** 删除工单 */ +export const deleteWorkOrder = (workOrderId: number) => { + return http.request>( + "delete", + `/api/v1/workorder/${workOrderId}` + ); +}; + +/** 获取工单详情 */ +export const getWorkOrderDetail = (workOrderId: number) => { + return http.request>( + "get", + `/api/v1/workorder/${workOrderId}` + ); +}; + +/** 分页查询工单列表 */ +export const getWorkOrderList = (params: WorkOrderQueryParams) => { + return http.request>>( + "get", + "/api/v1/workorder/list", + { params } + ); +}; + +/** 获取我的工单列表 */ +export const getMyWorkOrderList = (params: MyWorkOrderQueryParams) => { + return http.request>>( + "get", + "/api/v1/workorder/my", + { params } + ); +}; + +/** 处理工单 */ +export const processWorkOrder = (data: ProcessWorkOrderRequest) => { + return http.request>("post", "/api/v1/workorder/process", { + data + }); +}; + +/** 分配工单给处理人 */ +export const assignWorkOrder = (workOrderId: number, handlerId: number) => { + return http.request>( + "put", + `/api/v1/workorder/${workOrderId}/assign`, + { params: { handlerId } } + ); +}; + +/** 获取工单统计信息 */ +export const getWorkOrderStatistics = (projectId?: number) => { + return http.request>( + "get", + "/api/v1/workorder/statistics", + { params: projectId ? { projectId } : undefined } + ); +}; + +/** 获取我的工单统计信息 */ +export const getMyWorkOrderStatistics = () => { + return http.request>( + "get", + "/api/v1/workorder/my/statistics" + ); +}; diff --git a/src/api/风险与工单.openapi.json b/src/api/风险与工单.openapi.json new file mode 100644 index 0000000..4805ef4 --- /dev/null +++ b/src/api/风险与工单.openapi.json @@ -0,0 +1,1657 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "默认模块", + "description": "", + "version": "1.0.0" + }, + "tags": [], + "paths": { + "/api/v1/risk": { + "post": { + "summary": "创建风险评估", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRiskRequest", + "description": "创建请求" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseLong", + "description": "风险ID" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/risk/{riskId}": { + "put": { + "summary": "更新风险", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "riskId", + "in": "path", + "description": "风险ID", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRiskRequest", + "description": "更新请求" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseBoolean", + "description": "是否成功" + } + } + } + } + }, + "security": [] + }, + "delete": { + "summary": "删除风险", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "riskId", + "in": "path", + "description": "风险ID", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseBoolean", + "description": "是否成功" + } + } + } + } + }, + "security": [] + }, + "get": { + "summary": "获取风险详情", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "riskId", + "in": "path", + "description": "风险ID", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseRiskVO", + "description": "风险详情" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/risk/list": { + "get": { + "summary": "分页查询风险列表", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "projectId", + "in": "query", + "description": "项目ID", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "pageNum", + "in": "query", + "description": "页码", + "required": true, + "example": 1, + "schema": { + "type": "integer" + } + }, + { + "name": "pageSize", + "in": "query", + "description": "每页大小", + "required": true, + "example": 10, + "schema": { + "type": "integer" + } + }, + { + "name": "category", + "in": "query", + "description": "分类筛选", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "riskLevel", + "in": "query", + "description": "风险等级筛选", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "状态筛选", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "keyword", + "in": "query", + "description": "关键词搜索", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseTableDataInfoRiskVO", + "description": "分页风险列表" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/risk/statistics": { + "get": { + "summary": "获取风险统计信息", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "projectId", + "in": "query", + "description": "项目ID", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseRiskStatisticsVO", + "description": "统计信息" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/risk/{riskId}/assign-workorder": { + "post": { + "summary": "为风险分配工单", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "riskId", + "in": "path", + "description": "风险ID", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWorkOrderRequest", + "description": "工单创建请求" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseLong", + "description": "工单ID" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/risk/batch-status": { + "put": { + "summary": "批量更新风险状态", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "status", + "in": "query", + "description": "新状态", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "风险ID列表" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseBoolean", + "description": "是否成功" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/workorder": { + "post": { + "summary": "创建工单", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWorkOrderRequest", + "description": "创建请求" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseLong", + "description": "工单ID" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/workorder/{workOrderId}": { + "put": { + "summary": "更新工单", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "workOrderId", + "in": "path", + "description": "工单ID", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWorkOrderRequest", + "description": "更新请求" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseBoolean", + "description": "是否成功" + } + } + } + } + }, + "security": [] + }, + "delete": { + "summary": "删除工单", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "workOrderId", + "in": "path", + "description": "工单ID", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseBoolean", + "description": "是否成功" + } + } + } + } + }, + "security": [] + }, + "get": { + "summary": "获取工单详情", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "workOrderId", + "in": "path", + "description": "工单ID", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseWorkOrderVO", + "description": "工单详情" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/workorder/list": { + "get": { + "summary": "分页查询工单列表", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "projectId", + "in": "query", + "description": "项目ID", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "pageNum", + "in": "query", + "description": "页码", + "required": true, + "example": 1, + "schema": { + "type": "integer" + } + }, + { + "name": "pageSize", + "in": "query", + "description": "每页大小", + "required": true, + "example": 10, + "schema": { + "type": "integer" + } + }, + { + "name": "orderType", + "in": "query", + "description": "类型筛选", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "状态筛选", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "priority", + "in": "query", + "description": "优先级筛选", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "keyword", + "in": "query", + "description": "关键词搜索", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseTableDataInfoWorkOrderVO", + "description": "分页工单列表" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/workorder/my": { + "get": { + "summary": "获取我的工单列表", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "pageNum", + "in": "query", + "description": "页码", + "required": true, + "example": 1, + "schema": { + "type": "integer" + } + }, + { + "name": "pageSize", + "in": "query", + "description": "每页大小", + "required": true, + "example": 10, + "schema": { + "type": "integer" + } + }, + { + "name": "status", + "in": "query", + "description": "状态筛选", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "orderType", + "in": "query", + "description": "类型筛选", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseTableDataInfoWorkOrderVO", + "description": "分页工单列表" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/workorder/process": { + "post": { + "summary": "处理工单", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProcessWorkOrderRequest", + "description": "处理请求" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseBoolean", + "description": "是否成功" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/workorder/{workOrderId}/assign": { + "put": { + "summary": "分配工单给处理人", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "workOrderId", + "in": "path", + "description": "工单ID", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "handlerId", + "in": "query", + "description": "处理人ID", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseBoolean", + "description": "是否成功" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/workorder/statistics": { + "get": { + "summary": "获取工单统计信息", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "projectId", + "in": "query", + "description": "项目ID(可选)", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseWorkOrderStatisticsVO", + "description": "统计信息" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/workorder/my/statistics": { + "get": { + "summary": "获取我的工单统计信息", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b", + "schema": { + "type": "string", + "default": "Bearer f4c67d29-6d97-4552-84e3-11879ef1fc7b" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseWorkOrderStatisticsVO", + "description": "统计信息" + } + } + } + } + }, + "security": [] + } + } + }, + "components": { + "schemas": { + "CreateRiskRequest": { + "type": "object", + "properties": { + "projectId": { + "type": "integer", + "description": "项目ID", + "format": "int64" + }, + "category": { + "type": "string", + "description": "风险分类: technical-技术风险, schedule-进度风险, cost-成本风险, quality-质量风险, resource-资源风险, external-外部风险, other-其他" + }, + "riskName": { + "type": "string", + "description": "风险名称" + }, + "description": { + "type": "string", + "description": "风险描述" + }, + "riskSource": { + "type": "string", + "description": "风险来源: internal-内部, external-外部, manual-手动添加" + }, + "probability": { + "type": "integer", + "description": "发生概率(0-100)" + }, + "impact": { + "type": "integer", + "description": "影响程度(1-5)" + }, + "ownerId": { + "type": "integer", + "description": "负责人ID", + "format": "int64" + }, + "mitigationPlan": { + "type": "string", + "description": "缓解措施" + }, + "contingencyPlan": { + "type": "string", + "description": "应急计划" + }, + "triggerCondition": { + "type": "string", + "description": "触发条件" + }, + "dueDate": { + "type": "string", + "description": "预期解决日期" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "标签" + } + } + }, + "BaseResponseBoolean": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "type": "boolean", + "description": "" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "RiskVO": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "风险ID", + "format": "int64" + }, + "riskCode": { + "type": "string", + "description": "风险编号" + }, + "projectId": { + "type": "integer", + "description": "项目ID", + "format": "int64" + }, + "projectName": { + "type": "string", + "description": "项目名称" + }, + "category": { + "type": "string", + "description": "风险分类" + }, + "riskName": { + "type": "string", + "description": "风险名称" + }, + "description": { + "type": "string", + "description": "风险描述" + }, + "riskSource": { + "type": "string", + "description": "风险来源" + }, + "probability": { + "type": "number", + "description": "发生概率(0-100%)" + }, + "impact": { + "type": "number", + "description": "影响程度(1-5)" + }, + "riskScore": { + "type": "number", + "description": "风险得分" + }, + "riskLevel": { + "type": "string", + "description": "风险等级" + }, + "status": { + "type": "string", + "description": "状态" + }, + "ownerId": { + "type": "integer", + "description": "负责人ID", + "format": "int64" + }, + "ownerName": { + "type": "string", + "description": "负责人姓名" + }, + "ownerAvatar": { + "type": "string", + "description": "负责人头像" + }, + "workOrderCount": { + "type": "integer", + "description": "关联工单数量" + }, + "mitigationPlan": { + "type": "string", + "description": "缓解措施" + }, + "contingencyPlan": { + "type": "string", + "description": "应急计划" + }, + "triggerCondition": { + "type": "string", + "description": "触发条件" + }, + "discoverTime": { + "type": "string", + "description": "发现时间" + }, + "dueDate": { + "type": "string", + "description": "预期解决日期" + }, + "resolvedTime": { + "type": "string", + "description": "解决时间" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "标签" + }, + "createTime": { + "type": "string", + "description": "创建时间" + }, + "updateTime": { + "type": "string", + "description": "更新时间" + } + } + }, + "BaseResponseRiskVO": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "$ref": "#/components/schemas/RiskVO", + "description": "" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "TableDataInfoRiskVO": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "description": "总记录数", + "format": "int64" + }, + "rows": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RiskVO", + "description": "风险VO\n用于风险列表展示" + }, + "description": "列表数据" + }, + "code": { + "type": "integer", + "description": "消息状态码" + }, + "msg": { + "type": "string", + "description": "消息内容" + } + } + }, + "BaseResponseLong": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "type": "integer", + "description": "", + "format": "int64" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "BaseResponseTableDataInfoRiskVO": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "$ref": "#/components/schemas/TableDataInfoRiskVO", + "description": "" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "RiskStatisticsVO": { + "type": "object", + "properties": { + "totalCount": { + "type": "integer", + "description": "风险总数" + }, + "identifiedCount": { + "type": "integer", + "description": "已识别数量" + }, + "assignedCount": { + "type": "integer", + "description": "已分派工单数量" + }, + "mitigatingCount": { + "type": "integer", + "description": "缓解中数量" + }, + "resolvedCount": { + "type": "integer", + "description": "已解决数量" + }, + "closedCount": { + "type": "integer", + "description": "已关闭数量" + }, + "criticalCount": { + "type": "integer", + "description": "严重风险数量" + }, + "highCount": { + "type": "integer", + "description": "高风险数量" + }, + "mediumCount": { + "type": "integer", + "description": "中风险数量" + }, + "lowCount": { + "type": "integer", + "description": "低风险数量" + }, + "categoryStats": { + "type": "object", + "properties": {}, + "description": "按分类统计" + }, + "levelStats": { + "type": "object", + "properties": {}, + "description": "按等级统计" + }, + "trendData": { + "type": "object", + "properties": {}, + "description": "处理趋势(近6个月)" + }, + "averageRiskScore": { + "type": "number", + "description": "平均风险得分" + }, + "unresolvedHighCount": { + "type": "integer", + "description": "未解决高风险数量" + } + } + }, + "BaseResponseRiskStatisticsVO": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "$ref": "#/components/schemas/RiskStatisticsVO", + "description": "" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "CreateWorkOrderRequest": { + "type": "object", + "properties": { + "projectId": { + "type": "integer", + "description": "项目ID", + "format": "int64" + }, + "riskId": { + "type": "integer", + "description": "关联风险ID", + "format": "int64" + }, + "orderType": { + "type": "string", + "description": "工单类型: bug-缺陷, feature-需求, task-任务, incident-事件, risk_handle-风险处理, other-其他" + }, + "title": { + "type": "string", + "description": "工单标题" + }, + "description": { + "type": "string", + "description": "工单描述" + }, + "priority": { + "type": "string", + "description": "优先级: critical-紧急, high-高, medium-中, low-低" + }, + "handlerId": { + "type": "integer", + "description": "处理人ID", + "format": "int64" + }, + "handlerGroupId": { + "type": "integer", + "description": "处理组ID", + "format": "int64" + }, + "deadline": { + "type": "string", + "description": "截止时间" + }, + "source": { + "type": "string", + "description": "来源: web-网页, mobile-移动端, api-接口, system-系统生成, risk-风险分派" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "标签" + } + } + }, + "WorkOrderVO": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "工单ID", + "format": "int64" + }, + "orderCode": { + "type": "string", + "description": "工单编号" + }, + "orderType": { + "type": "string", + "description": "工单类型: bug-缺陷, feature-需求, task-任务, incident-事件, risk_handle-风险处理, other-其他" + }, + "projectId": { + "type": "integer", + "description": "项目ID", + "format": "int64" + }, + "projectName": { + "type": "string", + "description": "项目名称" + }, + "riskId": { + "type": "integer", + "description": "关联风险ID", + "format": "int64" + }, + "riskName": { + "type": "string", + "description": "关联风险名称" + }, + "title": { + "type": "string", + "description": "工单标题" + }, + "description": { + "type": "string", + "description": "工单描述" + }, + "creatorId": { + "type": "integer", + "description": "创建人ID", + "format": "int64" + }, + "creatorName": { + "type": "string", + "description": "创建人姓名" + }, + "handlerId": { + "type": "integer", + "description": "处理人ID", + "format": "int64" + }, + "handlerName": { + "type": "string", + "description": "处理人姓名" + }, + "handlerAvatar": { + "type": "string", + "description": "处理人头像" + }, + "handlerGroupId": { + "type": "integer", + "description": "处理组ID", + "format": "int64" + }, + "priority": { + "type": "string", + "description": "优先级: critical-紧急, high-高, medium-中, low-低" + }, + "status": { + "type": "string", + "description": "状态: pending-待处理, assigned-已分派, processing-处理中, resolved-已解决, closed-已关闭, reopened-已重开" + }, + "source": { + "type": "string", + "description": "来源: web-网页, mobile-移动端, api-接口, system-系统生成, risk-风险分派" + }, + "deadline": { + "type": "string", + "description": "截止时间" + }, + "assignedTime": { + "type": "string", + "description": "分派时间" + }, + "firstResponseTime": { + "type": "string", + "description": "首次响应时间" + }, + "resolvedTime": { + "type": "string", + "description": "解决时间" + }, + "closedTime": { + "type": "string", + "description": "关闭时间" + }, + "satisfactionScore": { + "type": "integer", + "description": "满意度评分(1-5)" + }, + "isOverdue": { + "type": "boolean", + "description": "是否超期" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "标签" + }, + "createTime": { + "type": "string", + "description": "创建时间" + }, + "updateTime": { + "type": "string", + "description": "更新时间" + } + } + }, + "BaseResponseWorkOrderVO": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "$ref": "#/components/schemas/WorkOrderVO", + "description": "" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "TableDataInfoWorkOrderVO": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "description": "总记录数", + "format": "int64" + }, + "rows": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WorkOrderVO", + "description": "工单VO\n用于工单列表展示" + }, + "description": "列表数据" + }, + "code": { + "type": "integer", + "description": "消息状态码" + }, + "msg": { + "type": "string", + "description": "消息内容" + } + } + }, + "BaseResponseTableDataInfoWorkOrderVO": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "$ref": "#/components/schemas/TableDataInfoWorkOrderVO", + "description": "" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "ProcessWorkOrderRequest": { + "type": "object", + "properties": { + "workOrderId": { + "type": "integer", + "description": "工单ID", + "format": "int64" + }, + "status": { + "type": "string", + "description": "处理状态: processing-处理中, resolved-已解决, closed-已关闭, reopened-已重开" + }, + "satisfactionScore": { + "type": "integer", + "description": "满意度评分(1-5)" + } + } + }, + "WorkOrderStatisticsVO": { + "type": "object", + "properties": { + "totalCount": { + "type": "integer", + "description": "工单总数" + }, + "pendingCount": { + "type": "integer", + "description": "待处理数量" + }, + "assignedCount": { + "type": "integer", + "description": "已分配数量" + }, + "processingCount": { + "type": "integer", + "description": "处理中数量" + }, + "completedCount": { + "type": "integer", + "description": "已完成数量" + }, + "closedCount": { + "type": "integer", + "description": "已关闭数量" + }, + "rejectedCount": { + "type": "integer", + "description": "已驳回数量" + }, + "overdueCount": { + "type": "integer", + "description": "超期未完成数量" + }, + "aboutToExpireCount": { + "type": "integer", + "description": "即将超期数量(7天内)" + }, + "typeStats": { + "type": "object", + "properties": {}, + "description": "按类型统计" + }, + "priorityStats": { + "type": "object", + "properties": {}, + "description": "按优先级统计" + } + } + }, + "BaseResponseWorkOrderStatisticsVO": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "$ref": "#/components/schemas/WorkOrderStatisticsVO", + "description": "" + }, + "message": { + "type": "string", + "description": "" + } + } + } + }, + "responses": {}, + "securitySchemes": {} + }, + "servers": [], + "security": [] +} diff --git a/src/router/enums.ts b/src/router/enums.ts index 6f2e04b..656f393 100644 --- a/src/router/enums.ts +++ b/src/router/enums.ts @@ -28,7 +28,8 @@ const home = 0, // 平台规定只有 home 路由的 rank 才能为 0 ,所以 ppt = 25, mind = 26, guide = 27, - menuoverflow = 28; + menuoverflow = 28, + riskWorkorder = 29; export { home, @@ -59,5 +60,6 @@ export { ppt, mind, guide, - menuoverflow + menuoverflow, + riskWorkorder }; diff --git a/src/router/index.ts b/src/router/index.ts index 40ca37c..e50c436 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -38,14 +38,15 @@ import { multipleTabsKey } from "@/utils/auth"; -/** 只导入项目管理、系统管理和剩余路由模块 - * 其他路由模块已隐藏 +/** 导入项目所需的路由模块 */ const modules: Record = import.meta.glob( [ "./modules/project.ts", "./modules/system.ts", "./modules/home.ts", + "./modules/risk-assessment.ts", + "./modules/workorder-management.ts", "!./modules/**/remaining.ts" ], { diff --git a/src/router/modules/risk-assessment.ts b/src/router/modules/risk-assessment.ts new file mode 100644 index 0000000..fb96666 --- /dev/null +++ b/src/router/modules/risk-assessment.ts @@ -0,0 +1,23 @@ +import { $t } from "@/plugins/i18n"; +import { riskWorkorder } from "@/router/enums"; + +export default { + path: "/risk-assessment", + redirect: "/risk-assessment/index", + meta: { + icon: "ri:alert-line", + title: $t("menus.pureRiskAssessment"), + rank: riskWorkorder + }, + children: [ + { + path: "/risk-assessment/index", + name: "RiskAssessment", + component: () => import("@/views/risk-assessment/index.vue"), + meta: { + title: $t("menus.pureRiskAssessment"), + icon: "ri:alert-line" + } + } + ] +} satisfies RouteConfigsTable; diff --git a/src/router/modules/workorder-management.ts b/src/router/modules/workorder-management.ts new file mode 100644 index 0000000..2d23dd3 --- /dev/null +++ b/src/router/modules/workorder-management.ts @@ -0,0 +1,23 @@ +import { $t } from "@/plugins/i18n"; +import { riskWorkorder } from "@/router/enums"; + +export default { + path: "/workorder-management", + redirect: "/workorder-management/index", + meta: { + icon: "ri:ticket-line", + title: $t("menus.pureWorkorderManagement"), + rank: riskWorkorder + 1 + }, + children: [ + { + path: "/workorder-management/index", + name: "WorkorderManagement", + component: () => import("@/views/workorder-management/index.vue"), + meta: { + title: $t("menus.pureWorkorderManagement"), + icon: "ri:ticket-line" + } + } + ] +} satisfies RouteConfigsTable; diff --git a/src/views/project/detail.vue b/src/views/project/detail.vue index 4261d0d..5a07f04 100644 --- a/src/views/project/detail.vue +++ b/src/views/project/detail.vue @@ -14,6 +14,10 @@ import { import { GGanttChart, GGanttRow } from "@infectoone/vue-ganttastic"; import { message } from "@/utils/message"; import dayjs from "dayjs"; +import isoWeek from "dayjs/plugin/isoWeek"; + +// 启用 isoWeek 插件,vue-ganttastic 周精度需要 +dayjs.extend(isoWeek); import ArrowLeftIcon from "~icons/ri/arrow-left-line"; import DownloadIcon from "~icons/ri/download-line"; @@ -306,6 +310,18 @@ const ganttDateRange = computed(() => { }; }); +// 计算项目时间跨度(天数) +const projectDays = computed(() => { + const start = dayjs(ganttDateRange.value.start); + const end = dayjs(ganttDateRange.value.end); + return end.diff(start, "day"); +}); + +// 动态计算甘特图精度:超过两个月(60天)使用周精度,否则使用日精度 +const ganttPrecision = computed(() => { + return projectDays.value > 60 ? "week" : "day"; +}); + // 获取项目详情 async function fetchProjectDetail() { if (!projectId.value) return; @@ -609,7 +625,7 @@ onMounted(() => { +import { ref, onMounted, computed } from "vue"; +import { useRouter } from "vue-router"; +import { useRenderIcon } from "@/components/ReIcon/src/hooks"; +import { + getRiskList, + getRiskStatistics, + deleteRisk, + type RiskVO, + type RiskStatisticsVO, + type RiskQueryParams +} from "@/api/risk-workorder"; +import { message } from "@/utils/message"; +import dayjs from "dayjs"; +import * as echarts from "echarts"; + +import AddIcon from "~icons/ri/add-line"; +import SearchIcon from "~icons/ri/search-line"; +import RefreshIcon from "~icons/ri/refresh-line"; +import FilterIcon from "~icons/ri/filter-3-line"; +import MoreIcon from "~icons/ep/more-filled"; +import DeleteIcon from "~icons/ep/delete"; +import EditPenIcon from "~icons/ep/edit-pen"; +import ViewIcon from "~icons/ri/eye-line"; +import WarningIcon from "~icons/ri/alert-line"; + +defineOptions({ + name: "RiskAssessmentIndex" +}); + +const router = useRouter(); +const loading = ref(false); +const dataList = ref([]); +const statistics = ref({ + totalCount: 0, + identifiedCount: 0, + assignedCount: 0, + mitigatingCount: 0, + resolvedCount: 0, + closedCount: 0, + criticalCount: 0, + highCount: 0, + mediumCount: 0, + lowCount: 0, + categoryStats: {}, + levelStats: {}, + trendData: {}, + averageRiskScore: 0, + unresolvedHighCount: 0 +}); + +// 查询参数 +const queryParams = ref({ + pageNum: 1, + pageSize: 10, + keyword: "", + category: "", + riskLevel: "", + status: "" +}); + +// 趋势周期 +const trendPeriod = ref("month"); + +// 分页 +const pagination = ref({ + currentPage: 1, + pageSize: 10, + total: 0 +}); + +// 图表引用 +const pieChartRef = ref(); +const trendChartRef = ref(); +let pieChart: echarts.ECharts | null = null; +let trendChart: echarts.ECharts | null = null; + +// 统计卡片数据 +const statCards = computed(() => [ + { + title: "总风险数", + value: statistics.value.totalCount || 0, + trend: "↑ 12% 较上月", + trendUp: true, + icon: "ri:information-line", + color: "#409eff", + bgColor: "#ecf5ff" + }, + { + title: "高风险", + value: statistics.value.criticalCount || 0, + trend: "↑ 5% 较上月", + trendUp: true, + icon: "ri:alert-line", + color: "#f56c6c", + bgColor: "#fef0f0" + }, + { + title: "中风险", + value: statistics.value.highCount || 0, + trend: "↓ 3% 较上月", + trendUp: false, + icon: "ri:error-warning-line", + color: "#e6a23c", + bgColor: "#fdf6ec" + }, + { + title: "低风险", + value: statistics.value.mediumCount + statistics.value.lowCount || 0, + trend: "↓ 2% 较上月", + trendUp: false, + icon: "ri:checkbox-circle-line", + color: "#67c23a", + bgColor: "#f0f9eb" + } +]); + +// 风险等级选项 +const riskLevelOptions = [ + { label: "严重", value: "critical", color: "#f56c6c" }, + { label: "高", value: "high", color: "#e6a23c" }, + { label: "中", value: "medium", color: "#409eff" }, + { label: "低", value: "low", color: "#67c23a" } +]; + +// 风险分类选项 +const categoryOptions = [ + { label: "技术风险", value: "technical" }, + { label: "进度风险", value: "schedule" }, + { label: "成本风险", value: "cost" }, + { label: "质量风险", value: "quality" }, + { label: "资源风险", value: "resource" }, + { label: "外部风险", value: "external" }, + { label: "其他", value: "other" } +]; + +// 状态选项 +const statusOptions = [ + { label: "已识别", value: "identified" }, + { label: "已分派", value: "assigned" }, + { label: "缓解中", value: "mitigating" }, + { label: "已解决", value: "resolved" }, + { label: "已关闭", value: "closed" } +]; + +// 获取风险等级标签类型 +function getRiskLevelType( + level?: string +): "danger" | "warning" | "info" | "success" { + switch (level) { + case "critical": + return "danger"; + case "high": + return "warning"; + case "medium": + return "info"; + case "low": + return "success"; + default: + return "info"; + } +} + +// 获取风险等级显示文本 +function getRiskLevelLabel(level?: string): string { + const option = riskLevelOptions.find(o => o.value === level); + return option?.label || level || "未知"; +} + +// 获取分类显示文本 +function getCategoryLabel(category?: string): string { + const option = categoryOptions.find(o => o.value === category); + return option?.label || category || "未知"; +} + +// 获取状态标签类型 +function getStatusType( + status?: string +): "success" | "warning" | "info" | "primary" | "danger" { + switch (status) { + case "resolved": + case "closed": + return "success"; + case "mitigating": + return "warning"; + case "assigned": + return "primary"; + case "identified": + return "info"; + default: + return "info"; + } +} + +// 获取状态显示文本 +function getStatusLabel(status?: string): string { + const option = statusOptions.find(o => o.value === status); + return option?.label || status || "未知"; +} + +// 加载风险列表 +async function loadRiskList() { + loading.value = true; + try { + const res = await getRiskList({ + ...queryParams.value, + 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; + } + } catch (error) { + message("加载风险列表失败", { type: "error" }); + } finally { + loading.value = false; + } +} + +// 加载统计数据 +async function loadStatistics() { + try { + const res = await getRiskStatistics(); + const statsResponse = res.data as any; + if (statsResponse.code === 200 && statsResponse.data) { + statistics.value = statsResponse.data; + updateCharts(); + } + } catch (error) { + console.error("加载统计数据失败", error); + } +} + +// 初始化饼图 +function initPieChart() { + if (!pieChartRef.value) return; + pieChart = echarts.init(pieChartRef.value); + updatePieChart(); +} + +// 更新饼图 +function updatePieChart() { + if (!pieChart) return; + const data = [ + { + value: statistics.value.criticalCount || 0, + name: "高风险", + itemStyle: { color: "#f56c6c" } + }, + { + value: statistics.value.highCount || 0, + name: "中风险", + itemStyle: { color: "#e6a23c" } + }, + { + value: + (statistics.value.mediumCount || 0) + (statistics.value.lowCount || 0), + name: "低风险", + itemStyle: { color: "#67c23a" } + } + ]; + const option = { + tooltip: { + trigger: "item", + formatter: "{b}: {c} ({d}%)" + }, + legend: { + bottom: "5%", + left: "center", + itemWidth: 10, + itemHeight: 10, + textStyle: { fontSize: 12 } + }, + series: [ + { + name: "风险分布", + type: "pie", + radius: ["50%", "70%"], + center: ["50%", "45%"], + avoidLabelOverlap: false, + itemStyle: { + borderRadius: 6, + borderColor: "#fff", + borderWidth: 2 + }, + label: { + show: false + }, + emphasis: { + label: { + show: true, + fontSize: 14, + fontWeight: "bold" + } + }, + labelLine: { + show: false + }, + data + } + ] + }; + pieChart.setOption(option); +} + +// 初始化趋势图 +function initTrendChart() { + if (!trendChartRef.value) return; + trendChart = echarts.init(trendChartRef.value); + updateTrendChart(); +} + +// 更新趋势图 +function updateTrendChart() { + if (!trendChart) return; + const months = ["1月", "2月", "3月", "4月", "5月", "6月"]; + const option = { + tooltip: { + trigger: "axis", + axisPointer: { type: "shadow" } + }, + legend: { + data: ["高风险", "中风险", "低风险"], + right: 10, + top: 10, + itemWidth: 12, + itemHeight: 12 + }, + grid: { + left: "3%", + right: "4%", + bottom: "3%", + top: "15%", + containLabel: true + }, + xAxis: { + type: "category", + data: months, + axisLine: { lineStyle: { color: "#dcdfe6" } }, + axisLabel: { color: "#606266" } + }, + yAxis: { + type: "value", + axisLine: { show: false }, + splitLine: { lineStyle: { color: "#ebeef5" } }, + axisLabel: { color: "#606266" } + }, + series: [ + { + name: "高风险", + type: "bar", + stack: "total", + data: [5, 8, 6, 10, 12, 8], + itemStyle: { color: "#f56c6c", borderRadius: [0, 0, 4, 4] } + }, + { + name: "中风险", + type: "bar", + stack: "total", + data: [8, 12, 10, 15, 18, 16], + itemStyle: { color: "#e6a23c" } + }, + { + name: "低风险", + type: "bar", + stack: "total", + data: [10, 15, 12, 18, 20, 22], + itemStyle: { color: "#67c23a", borderRadius: [4, 4, 0, 0] } + } + ] + }; + trendChart.setOption(option); +} + +// 更新图表 +function updateCharts() { + updatePieChart(); + updateTrendChart(); +} + +// 搜索 +function onSearch() { + pagination.value.currentPage = 1; + loadRiskList(); +} + +// 重置 +function resetForm() { + queryParams.value = { + pageNum: 1, + pageSize: 10, + keyword: "", + category: "", + riskLevel: "", + status: "" + }; + onSearch(); +} + +// 分页大小变化 +function handleSizeChange(val: number) { + pagination.value.pageSize = val; + loadRiskList(); +} + +// 页码变化 +function handleCurrentChange(val: number) { + pagination.value.currentPage = val; + loadRiskList(); +} + +// 新建风险 +function handleCreate() { + message("新建风险功能开发中", { type: "info" }); +} + +// 查看风险详情 +function handleView(row: RiskVO) { + message(`查看风险: ${row.riskName}`, { type: "info" }); +} + +// 编辑风险 +function handleEdit(row: RiskVO) { + message(`编辑风险: ${row.riskName}`, { type: "info" }); +} + +// 删除风险 +async function handleDelete(row: RiskVO) { + if (!row.id) return; + try { + await deleteRisk(row.id); + message("删除成功", { type: "success" }); + loadRiskList(); + loadStatistics(); + } catch (error) { + message("删除失败", { type: "error" }); + } +} + +// 窗口大小变化时重新渲染图表 +function handleResize() { + pieChart?.resize(); + trendChart?.resize(); +} + +onMounted(() => { + loadRiskList(); + loadStatistics(); + initPieChart(); + initTrendChart(); + window.addEventListener("resize", handleResize); +}); + + + + + diff --git a/src/views/workorder-management/index.vue b/src/views/workorder-management/index.vue new file mode 100644 index 0000000..a146edc --- /dev/null +++ b/src/views/workorder-management/index.vue @@ -0,0 +1,862 @@ + + + + +