0926
This commit is contained in:
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="operation-inspection">
|
<div class="operation-inspection">
|
||||||
<!-- 导航标签 -->
|
<!-- 导航标签 -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 子选项卡 -->
|
<!-- 子选项卡 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="execution-records">
|
<div class="execution-records">
|
||||||
<!-- 顶部导航栏 -->
|
<!-- 顶部导航栏 -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab active" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab active" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 选项卡 -->
|
<!-- 选项卡 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="inspection-tasks">
|
<div class="inspection-tasks">
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -9,7 +9,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 选项卡 -->
|
<!-- 选项卡 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
@ -86,7 +86,7 @@
|
|||||||
<!-- 已完成状态的额外信息 -->
|
<!-- 已完成状态的额外信息 -->
|
||||||
<div v-if="task.status === 'completed'" class="task-result">
|
<div v-if="task.status === 'completed'" class="task-result">
|
||||||
<span class="detail-label">完成时间</span>
|
<span class="detail-label">完成时间</span>
|
||||||
<span class="detail-value">{{ task.completeTime }}</span>
|
<span class="detail-value">{{ task.reportFinishTime }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -306,7 +306,7 @@
|
|||||||
<div v-if="detailData.status === '3'" class="info-row">
|
<div v-if="detailData.status === '3'" class="info-row">
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<span class="info-label">完成时间:</span>
|
<span class="info-label">完成时间:</span>
|
||||||
<span class="info-value">{{ formatDate(detailData.completeTime) }}</span>
|
<span class="info-value">{{ formatDate(detailData.reportFinishTime) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -454,7 +454,10 @@ async function getTaskList() {
|
|||||||
// 修复维修人字段,从sendPersonVo对象中获取用户名
|
// 修复维修人字段,从sendPersonVo对象中获取用户名
|
||||||
maintainer: item.sendPersonVo?.userName || '未分配',
|
maintainer: item.sendPersonVo?.userName || '未分配',
|
||||||
|
|
||||||
completeTime: item.completeTime ? formatDate(item.completeTime) : '',
|
// 尝试从多个可能的字段中获取完成时间,确保有值时能正确显示
|
||||||
|
completeTime: item.completeTime ? formatDate(item.completeTime) : item.finishTime ? formatDate(item.finishTime) : '',
|
||||||
|
// 直接使用并格式化reportFinishTime字段
|
||||||
|
reportFinishTime: item.reportFinishTime ? formatDate(item.reportFinishTime) : '',
|
||||||
actionText: getActionText(item.status),
|
actionText: getActionText(item.status),
|
||||||
actionClass: getActionClass(item.status),
|
actionClass: getActionClass(item.status),
|
||||||
reportInfo: item.reportInfo,
|
reportInfo: item.reportInfo,
|
||||||
@ -1003,7 +1006,7 @@ const handleSaveResult = async () => {
|
|||||||
statusText: '已完成', // 状态文本
|
statusText: '已完成', // 状态文本
|
||||||
reportFinal: reportFinal.value, // 处理结果
|
reportFinal: reportFinal.value, // 处理结果
|
||||||
reportFinishTime: reportFinishTime, // 完成时间
|
reportFinishTime: reportFinishTime, // 完成时间
|
||||||
completeTime: reportFinishTime, // 完成时间(向后兼容字段)
|
completeTime: reportFinishTime, // 完成时间
|
||||||
|
|
||||||
// ③ 复用原始任务数据中的所有必要字段
|
// ③ 复用原始任务数据中的所有必要字段
|
||||||
name: originalTask.title, // 任务名称(原始任务标题)
|
name: originalTask.title, // 任务名称(原始任务标题)
|
||||||
@ -1481,7 +1484,7 @@ onMounted(async () => {
|
|||||||
/* 任务卡片样式 - 恢复优先级标签背景色 */
|
/* 任务卡片样式 - 恢复优先级标签背景色 */
|
||||||
.task-cards {
|
.task-cards {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
@ -1494,22 +1497,14 @@ onMounted(async () => {
|
|||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-height: 260px; /* 增加高度以适应新增的预计完成时间 */
|
min-height: 280px; /* 增加高度以确保内容完整显示 */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-actions {
|
.task-content {
|
||||||
display: flex;
|
flex: 1; /* 内容区域占满剩余空间 */
|
||||||
justify-content: flex-end;
|
margin-bottom: 16px;
|
||||||
align-items: center;
|
|
||||||
padding-top: 12px;
|
|
||||||
border-top: 1px solid #f0f2f5;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 16px;
|
|
||||||
right: 16px;
|
|
||||||
left: 16px;
|
|
||||||
background-color: #fff;
|
|
||||||
padding: 12px 0 0 0;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-actions .el-button {
|
.task-actions .el-button {
|
||||||
@ -1562,6 +1557,9 @@ onMounted(async () => {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #1d2129;
|
color: #1d2129;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
|
word-break: break-word;
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 恢复优先级标签背景色样式 */
|
/* 恢复优先级标签背景色样式 */
|
||||||
@ -1571,6 +1569,7 @@ onMounted(async () => {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.priority-high {
|
.priority-high {
|
||||||
@ -1599,17 +1598,20 @@ onMounted(async () => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-label {
|
.detail-label {
|
||||||
flex: 0 0 80px;
|
flex: 0 0 85px;
|
||||||
color: #86909c;
|
color: #86909c;
|
||||||
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-value {
|
.detail-value {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
color: #4e5969;
|
color: #4e5969;
|
||||||
word-break: break-all;
|
word-break: break-word;
|
||||||
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-result {
|
.task-result {
|
||||||
@ -1626,13 +1628,7 @@ onMounted(async () => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
border-top: 1px solid #f0f2f5;
|
border-top: 1px solid #f0f2f5;
|
||||||
position: absolute;
|
|
||||||
bottom: 16px;
|
|
||||||
right: 16px;
|
|
||||||
left: 16px;
|
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
padding: 12px 0 0 0;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn {
|
.action-btn {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="inspection-tasks">
|
<div class="inspection-tasks">
|
||||||
<!-- 导航栏 -->
|
<!-- 导航栏 -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 选项卡 -->
|
<!-- 选项卡 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="execution-records">
|
<div class="execution-records">
|
||||||
<!-- 顶部导航栏 -->
|
<!-- 顶部导航栏 -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,8 +10,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab active" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab active" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
|
|
||||||
<!-- 选项卡 -->
|
<!-- 选项卡 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
@ -138,7 +137,6 @@
|
|||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
|
|
||||||
|
|
||||||
// 搜索和筛选条件
|
// 搜索和筛选条件
|
||||||
const searchKeyword = ref('');
|
const searchKeyword = ref('');
|
||||||
const plateNumber1 = ref('');
|
const plateNumber1 = ref('');
|
||||||
|
|||||||
@ -51,35 +51,90 @@
|
|||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 步骤相关样式 */
|
/* 步骤相关样式 - 详情弹窗专用 - 使用外部CSS样式 */
|
||||||
.steps-container {
|
.task-detail-container .steps-container {
|
||||||
display: flex;
|
width: 100%;
|
||||||
flex-direction: column;
|
padding: 20px;
|
||||||
gap: 12px;
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-item {
|
.task-detail-container .step-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
align-items: center;
|
||||||
align-items: flex-start;
|
margin-bottom: 15px;
|
||||||
padding: 16px;
|
padding: 15px;
|
||||||
background-color: #ffffff;
|
background-color: #fafafa;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: 1px solid #e4e7ed;
|
position: relative;
|
||||||
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-number {
|
.task-detail-container .step-item:hover {
|
||||||
width: 28px;
|
background-color: #f5f7fa;
|
||||||
height: 28px;
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-container .step-number {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
background-color: #409eff;
|
background-color: #409eff;
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-weight: 600;
|
margin-right: 16px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-container .step-item:not(:last-child)::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50px;
|
||||||
|
left: 16px;
|
||||||
|
width: 2px;
|
||||||
|
height: calc(100% + 5px);
|
||||||
|
background-color: #e4e7ed;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-container .step-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-container .step-name {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1d2129;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-container .step-purpose {
|
||||||
|
color: #606266;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-container .step-time,
|
||||||
|
.task-detail-container .step-finish-time,
|
||||||
|
.task-detail-container .step-remark {
|
||||||
|
color: #909399;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-container .step-status {
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-info {
|
.step-info {
|
||||||
@ -110,8 +165,8 @@
|
|||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 状态相关样式 */
|
/* 步骤状态样式 - 详情弹窗专用 */
|
||||||
.step-status {
|
.task-detail-container .step-status {
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@ -120,26 +175,29 @@
|
|||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 步骤状态样式 */
|
/* 步骤状态样式 - 待执行 */
|
||||||
.step-status.status-pending {
|
.task-detail-container .step-status.status-pending {
|
||||||
background-color: #e6f7ff;
|
background-color: #e6f7ff;
|
||||||
color: #1677ff;
|
color: #1677ff;
|
||||||
border: 1px solid #91d5ff;
|
border: 1px solid #91d5ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-status.status-executing {
|
/* 步骤状态样式 - 执行中 */
|
||||||
|
.task-detail-container .step-status.status-executing {
|
||||||
background-color: #fffbe6;
|
background-color: #fffbe6;
|
||||||
color: #fa8c16;
|
color: #fa8c16;
|
||||||
border: 1px solid #ffe58f;
|
border: 1px solid #ffe58f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-status.status-completed {
|
/* 步骤状态样式 - 已完成 */
|
||||||
|
.task-detail-container .step-status.status-completed {
|
||||||
background-color: #f6ffed;
|
background-color: #f6ffed;
|
||||||
color: #52c41a;
|
color: #52c41a;
|
||||||
border: 1px solid #b7eb8f;
|
border: 1px solid #b7eb8f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-status.status-delayed {
|
/* 步骤状态样式 - 已延期 */
|
||||||
|
.task-detail-container .step-status.status-delayed {
|
||||||
background-color: #fff2f0;
|
background-color: #fff2f0;
|
||||||
color: #ff4d4f;
|
color: #ff4d4f;
|
||||||
border: 1px solid #ffccc7;
|
border: 1px solid #ffccc7;
|
||||||
@ -238,6 +296,35 @@
|
|||||||
.info-row {
|
.info-row {
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 步骤条响应式设计 */
|
||||||
|
.task-detail-container .steps-container {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-container .step-item {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-container .step-item > * {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-container .step-number {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-detail-container .step-item:not(:last-child)::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 弹窗按钮样式 */
|
/* 弹窗按钮样式 */
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="work-order-management">
|
<div class="work-order-management">
|
||||||
<!-- 顶部导航栏 -->
|
<!-- 顶部导航栏 -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab active" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab active" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
<div style="display: flex; align-items: center; gap: 10px">
|
<div style="display: flex; align-items: center; gap: 10px">
|
||||||
@ -379,7 +379,7 @@
|
|||||||
<div v-if="node.remark" class="step-remark">备注:{{ node.remark }}</div>
|
<div v-if="node.remark" class="step-remark">备注:{{ node.remark }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-status" :class="getStatusClass(node.status)">
|
<div class="step-status" :class="getStatusClass(node.status)">
|
||||||
{{ getStepStatusText(node.status) }}
|
{{ node.status === '2' ? '未完成' : '已完成' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="box-container">
|
<div class="box-container">
|
||||||
<!-- 导航栏 -->
|
<!-- 导航栏 -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab active" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab active" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<!-- 左侧日历区域 -->
|
<!-- 左侧日历区域 -->
|
||||||
<div class="calendar-container">
|
<div class="calendar-container">
|
||||||
@ -54,6 +54,7 @@
|
|||||||
class="todo-item"
|
class="todo-item"
|
||||||
:class="{ 'important': item.taskLevel === '重要', 'completed': item.status === 2 }"
|
:class="{ 'important': item.taskLevel === '重要', 'completed': item.status === 2 }"
|
||||||
>
|
>
|
||||||
|
<el-checkbox class="todo-checkbox" :checked="item.status === 2" @change="handleStatusChange(item, $event)"></el-checkbox>
|
||||||
<div
|
<div
|
||||||
class="todo-color-indicator"
|
class="todo-color-indicator"
|
||||||
:class="{
|
:class="{
|
||||||
@ -63,7 +64,6 @@
|
|||||||
completed: item.status === 2
|
completed: item.status === 2
|
||||||
}"
|
}"
|
||||||
></div>
|
></div>
|
||||||
<el-checkbox class="todo-checkbox" :checked="item.status === 2" @change="handleStatusChange(item, $event)"></el-checkbox>
|
|
||||||
<div class="todo-content">
|
<div class="todo-content">
|
||||||
<div class="todo-main">
|
<div class="todo-main">
|
||||||
<div class="todo-title">{{ item.title }}</div>
|
<div class="todo-title">{{ item.title }}</div>
|
||||||
@ -590,16 +590,6 @@ const handleInspection7 = () => {
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 导航栏样式 */
|
|
||||||
.navigation-tabs {
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 已完成任务的样式 */
|
/* 已完成任务的样式 */
|
||||||
.todo-color-indicator.completed {
|
.todo-color-indicator.completed {
|
||||||
background-color: #dcdfe6;
|
background-color: #dcdfe6;
|
||||||
@ -609,7 +599,15 @@ const handleInspection7 = () => {
|
|||||||
color: #909399;
|
color: #909399;
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
|
/* 导航栏样式 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
.nav-tab {
|
.nav-tab {
|
||||||
padding: 12px 24px;
|
padding: 12px 24px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -849,13 +847,14 @@ const handleInspection7 = () => {
|
|||||||
|
|
||||||
/* 悬停显示操作按钮 */
|
/* 悬停显示操作按钮 */
|
||||||
.todo-item:hover .todo-actions {
|
.todo-item:hover .todo-actions {
|
||||||
opacity: 1;
|
background: linear-gradient(to right, rgba(173, 216, 230, 0), rgb(64, 158, 255));
|
||||||
right: 0;
|
right: 0;
|
||||||
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 内容区域平移以给按钮留出空间 */
|
/* 取消内容区域平移效果 */
|
||||||
.todo-item:hover .todo-content {
|
.todo-item:hover .todo-content {
|
||||||
transform: translateX(-120px);
|
transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-icon {
|
.action-icon {
|
||||||
@ -942,7 +941,7 @@ const handleInspection7 = () => {
|
|||||||
background-color: #ff4d4f;
|
background-color: #ff4d4f;
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .custom-date-cell {
|
:deep(.custom-date-cell) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
@ -983,13 +982,13 @@ const handleInspection7 = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 穿透作用域,强制设置日历单元格为正方形 */
|
/* 穿透作用域,强制设置日历单元格为正方形 */
|
||||||
::v-deep .el-calendar-table td {
|
:deep(.el-calendar-table td) {
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
width: 120px; /* 强制宽度 */
|
width: 120px; /* 强制宽度 */
|
||||||
height: 120px; /* 强制高度(与宽度一致) */
|
height: 120px; /* 强制高度(与宽度一致) */
|
||||||
}
|
}
|
||||||
::v-deep .el-calendar-day {
|
:deep(.el-calendar-day) {
|
||||||
padding: 0; /* 移除默认内边距 */
|
padding: 0; /* 移除默认内边距 */
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="dispatch-records">
|
<div class="dispatch-records">
|
||||||
<!-- 顶部导航栏 -->
|
<!-- 顶部导航栏 -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab active" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab active" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 选项卡 -->
|
<!-- 选项卡 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
@ -430,7 +430,7 @@
|
|||||||
<div v-if="node.remark" class="step-remark">备注:{{ node.remark }}</div>
|
<div v-if="node.remark" class="step-remark">备注:{{ node.remark }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-status" :class="getStatusClass(node.status)">
|
<div class="step-status" :class="getStatusClass(node.status)">
|
||||||
{{ getStepStatusText(node.status) }}
|
{{ node.status === '2' ? '未完成' : '已完成' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -737,11 +737,6 @@ const getStepStatusText = (status) => {
|
|||||||
return statusMap[statusStr] || '未知状态';
|
return statusMap[statusStr] || '未知状态';
|
||||||
};
|
};
|
||||||
|
|
||||||
// 按模块分组节点(保留该函数用于兼容)
|
|
||||||
const groupNodesByModule = (nodes) => {
|
|
||||||
if (!nodes || !nodes.length) return [];
|
|
||||||
return [{ module: '', items: nodes }];
|
|
||||||
|
|
||||||
// 初始化加载数据
|
// 初始化加载数据
|
||||||
const initData = async () => {
|
const initData = async () => {
|
||||||
await fetchStatisticsData();
|
await fetchStatisticsData();
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="inspection-tasks">
|
<div class="inspection-tasks">
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -9,7 +9,7 @@
|
|||||||
<div class="nav-tab active" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab active" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 选项卡 -->
|
<!-- 选项卡 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
@ -1065,11 +1065,29 @@ defineExpose({ getTaskList });
|
|||||||
async function getTaskList() {
|
async function getTaskList() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
const res = await qiangxiulist({
|
// 构建请求参数,包含筛选条件
|
||||||
|
const requestParams = {
|
||||||
projectId: 1,
|
projectId: 1,
|
||||||
pageNum: currentPage.value,
|
pageNum: currentPage.value,
|
||||||
pageSize: pageSize.value
|
pageSize: pageSize.value
|
||||||
});
|
};
|
||||||
|
|
||||||
|
// 添加任务状态筛选条件
|
||||||
|
if (taskStatus.value && taskStatus.value !== 'all') {
|
||||||
|
requestParams.status = taskStatus.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加计划类型筛选条件
|
||||||
|
if (planType.value && planType.value !== 'all') {
|
||||||
|
requestParams.planType = planType.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加执行人筛选条件
|
||||||
|
if (executor.value && executor.value !== 'all') {
|
||||||
|
requestParams.executor = executor.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await qiangxiulist(requestParams);
|
||||||
|
|
||||||
if (res.code === 200 && res.rows) {
|
if (res.code === 200 && res.rows) {
|
||||||
total.value = res.total || 0;
|
total.value = res.total || 0;
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="inspection-tasks">
|
<div class="inspection-tasks">
|
||||||
<!-- 导航栏 -->
|
<!-- 导航栏 -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,14 +10,7 @@
|
|||||||
<div class="nav-tab active" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab active" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 页面标题和操作区 -->
|
|
||||||
<div class="header-section">
|
|
||||||
<div class="header-actions">
|
|
||||||
<el-button type="primary" class="export-btn" @click="handleExport"> 导出数据 </el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
<div style="display: flex; align-items: center; gap: 10px">
|
<div style="display: flex; align-items: center; gap: 10px">
|
||||||
@ -1524,12 +1517,7 @@ const handleInspectionManagement2 = () => {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 无数据提示 */
|
/* */
|
||||||
.no-info {
|
|
||||||
text-align: center;
|
|
||||||
color: #909399;
|
|
||||||
padding: 60px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 分配弹窗样式 */
|
/* 分配弹窗样式 */
|
||||||
.assign-container {
|
.assign-container {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="operation-organization">
|
<div class="operation-organization">
|
||||||
<!-- 顶部导航栏 -->
|
<!-- 顶部导航栏 -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab active" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab active" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 选项卡 -->
|
<!-- 选项卡 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
@ -132,8 +132,7 @@ import { ref, watch, onMounted } from 'vue';
|
|||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
|
|
||||||
// 激活的选项卡
|
//
|
||||||
const activeTab = ref('personnel');
|
|
||||||
|
|
||||||
// 统计数据(保持原有数据不变)
|
// 统计数据(保持原有数据不变)
|
||||||
const totalPersonnel = ref(36);
|
const totalPersonnel = ref(36);
|
||||||
@ -445,36 +444,7 @@ const handleInspectionManagement3 = () => {
|
|||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-tabs {
|
/* */
|
||||||
padding-top: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-tabs .el-tabs__header {
|
|
||||||
margin: 0 -20px;
|
|
||||||
padding: 0 20px;
|
|
||||||
border-bottom: 1px solid #e4e7ed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-tabs .el-tabs__nav-wrap::after {
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-tabs .el-tabs__item {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #606266;
|
|
||||||
padding: 16px 20px;
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-tabs .el-tabs__item.is-active {
|
|
||||||
color: #165dff;
|
|
||||||
font-weight: 500;
|
|
||||||
border-bottom: 2px solid #165dff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-tabs .el-tabs__item:hover {
|
|
||||||
color: #165dff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 内容容器样式 */
|
/* 内容容器样式 */
|
||||||
.content-container {
|
.content-container {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="operation-inspection">
|
<div class="operation-inspection">
|
||||||
<!-- 1. 顶部导航选项卡(对应原试验系统的外层导航) -->
|
<!-- 1. 顶部导航选项卡(对应原试验系统的外层导航) -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab active" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab active" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 选项卡和按钮组合 -->
|
<!-- 选项卡和按钮组合 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
@ -67,13 +67,7 @@
|
|||||||
<el-table-column align="center" prop="type" label="巡检类型" width="120"></el-table-column>
|
<el-table-column align="center" prop="type" label="巡检类型" width="120"></el-table-column>
|
||||||
<el-table-column align="center" prop="cycle" label="巡检周期" width="120"></el-table-column>
|
<el-table-column align="center" prop="cycle" label="巡检周期" width="120"></el-table-column>
|
||||||
<el-table-column align="center" prop="dateRange" label="执行时间范围"></el-table-column>
|
<el-table-column align="center" prop="dateRange" label="执行时间范围"></el-table-column>
|
||||||
<el-table-column align="center" prop="progress" label="完成进度" width="120">
|
|
||||||
<template #default="scope">
|
|
||||||
<div class="progress-bar">
|
|
||||||
<div class="progress-fill" :style="{ width: scope.row.progress + '%', backgroundColor: getProgressColor(scope.row.status) }"></div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column align="center" prop="status" label="状态" width="100">
|
<el-table-column align="center" prop="status" label="状态" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span :class="['status-tag', `status-${scope.row.status}`]">
|
<span :class="['status-tag', `status-${scope.row.status}`]">
|
||||||
@ -374,10 +368,10 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="实验对象类型" class="form-item">
|
<el-form-item label="实验对象类型" class="form-item">
|
||||||
<el-select v-model="formData.testObject" placeholder="请选择实验对象类型" class="form-input">
|
<el-select v-model="formData.testObject" placeholder="请选择实验对象类型" class="form-input">
|
||||||
<el-option label="1安全试验" value="1" />
|
<el-option label="安全试验" value="1" />
|
||||||
<el-option label="2网络实验" value="2" />
|
<el-option label="网络实验" value="2" />
|
||||||
<el-option label="3性能试验" value="3" />
|
<el-option label="性能试验" value="3" />
|
||||||
<el-option label="4" value="4" />
|
<el-option label="其他试验" value="4" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
@ -418,36 +412,6 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- 试验步骤 -->
|
|
||||||
<el-form-item label="试验步骤" class="form-item" style="width: 100%">
|
|
||||||
<div class="steps-container">
|
|
||||||
<div class="step-item" v-for="(step, index) in formData.steps" :key="index">
|
|
||||||
<div class="step-number">{{ index + 1 }}</div>
|
|
||||||
<el-input v-model="step.name" placeholder="输入步骤名称" style="flex: 1; margin-right: 10px" />
|
|
||||||
<el-input v-model="step.intendedPurpose" placeholder="输入预期目的" style="flex: 1; margin-right: 10px" />
|
|
||||||
<el-date-picker
|
|
||||||
v-model="step.intendedTime"
|
|
||||||
type="datetime"
|
|
||||||
placeholder="选择计划时间"
|
|
||||||
format="YYYY-MM-DD HH:mm"
|
|
||||||
value-format="YYYY-MM-DD HH:mm"
|
|
||||||
style="width: 180px; margin-right: 10px"
|
|
||||||
/>
|
|
||||||
<el-button
|
|
||||||
v-if="formData.steps.length > 1"
|
|
||||||
type="text"
|
|
||||||
size="small"
|
|
||||||
class="delete-step-btn"
|
|
||||||
@click="deleteStep(index)"
|
|
||||||
style="color: #f56c6c"
|
|
||||||
>
|
|
||||||
删除
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
<el-button type="text" size="small" class="add-step-btn" @click="addStep">添加步骤</el-button>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- 所需设备与准备 -->
|
<!-- 所需设备与准备 -->
|
||||||
<el-form-item label="所需资源与设备" class="form-item" style="width: 100%">
|
<el-form-item label="所需资源与设备" class="form-item" style="width: 100%">
|
||||||
<div class="equipment-list">
|
<div class="equipment-list">
|
||||||
@ -490,119 +454,113 @@
|
|||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
:close-on-press-escape="false"
|
:close-on-press-escape="false"
|
||||||
class="custom-experiment-dialog"
|
class="custom-experiment-dialog"
|
||||||
|
center
|
||||||
>
|
>
|
||||||
<div class="detail-content">
|
<div v-if="detailData" class="task-detail-container">
|
||||||
<!-- 基础信息 -->
|
<!-- 基础信息卡片 -->
|
||||||
<div class="detail-section">
|
<div class="detail-card">
|
||||||
<h3 class="section-title">基础信息</h3>
|
<h3 class="card-title">基础信息</h3>
|
||||||
<div class="detail-grid">
|
<div class="card-content">
|
||||||
<div class="detail-item">
|
<div class="info-row">
|
||||||
<label class="detail-label">计划名称:</label>
|
<div class="info-item">
|
||||||
<span class="detail-value">{{ detailData.planName || '-' }}</span>
|
<label class="info-label">计划名称:</label>
|
||||||
|
<span class="info-value">{{ detailData.planName || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="info-item">
|
||||||
<label class="detail-label">计划编号:</label>
|
<label class="info-label">计划编号:</label>
|
||||||
<span class="detail-value">{{ detailData.planCode || '-' }}</span>
|
<span class="info-value">{{ detailData.planCode || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
|
||||||
<label class="detail-label">实验对象:</label>
|
|
||||||
<span class="detail-value">{{ getTestObjectText(detailData.testObject) || '-' }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="info-row">
|
||||||
<label class="detail-label">负责人:</label>
|
<div class="info-item">
|
||||||
<span class="detail-value">{{ detailData.person?.userName || '-' }}</span>
|
<label class="info-label">实验对象:</label>
|
||||||
|
<span class="info-value">{{ getTestObjectText(detailData.testObject) || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="info-item">
|
||||||
<label class="detail-label">开始时间:</label>
|
<label class="info-label">负责人:</label>
|
||||||
<span class="detail-value">{{ detailData.beginTime ? formatDate(detailData.beginTime) : '-' }}</span>
|
<span class="info-value">{{ detailData.person?.userName || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item">
|
||||||
|
<label class="info-label">开始时间:</label>
|
||||||
|
<span class="info-value">{{ detailData.beginTime ? formatDate(detailData.beginTime) : '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<label class="info-label">结束时间:</label>
|
||||||
|
<span class="info-value">{{ detailData.endTime ? formatDate(detailData.endTime) : '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
|
||||||
<label class="detail-label">结束时间:</label>
|
|
||||||
<span class="detail-value">{{ detailData.endTime ? formatDate(detailData.endTime) : '-' }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 实验设备 -->
|
<!-- 实验设备 -->
|
||||||
<div v-if="detailData.testDevice" class="detail-section">
|
<div v-if="detailData.testDevice" class="detail-card">
|
||||||
<h3 class="section-title">实验设备</h3>
|
<h3 class="card-title">实验设备</h3>
|
||||||
<div class="device-list">
|
<div class="card-content">
|
||||||
<span v-for="(device, index) in detailData.testDevice.split(',')" :key="index" class="device-tag">
|
<div v-for="(device, index) in detailData.testDevice.split(',')" :key="index" class="info-item">
|
||||||
{{ device.trim() }}
|
<label class="info-label">设备{{ index + 1 }}:</label>
|
||||||
</span>
|
<span class="info-value">{{ device.trim() }}</span>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 执行步骤 -->
|
|
||||||
<div v-if="detailData.nodes && detailData.nodes.length > 0" class="detail-card">
|
|
||||||
<h3 class="card-title">执行步骤</h3>
|
|
||||||
<div class="steps-container">
|
|
||||||
<div v-for="(node, index) in detailData.nodes" :key="node.id || index" class="step-item">
|
|
||||||
<div class="step-number">{{ node.code || index + 1 }}</div>
|
|
||||||
<div class="step-info">
|
|
||||||
<div class="step-name">{{ node.name || '未命名步骤' }}</div>
|
|
||||||
<div class="step-purpose">{{ node.intendedPurpose || '无说明' }}</div>
|
|
||||||
<div class="step-time">计划时间:{{ formatDateTime(node.intendedTime) }}</div>
|
|
||||||
<div v-if="node.finishTime" class="step-finish-time">完成时间:{{ formatDateTime(node.finishTime) }}</div>
|
|
||||||
<div v-if="node.remark" class="step-remark">备注:{{ node.remark }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="step-status" :class="getStatusClass(node.status)">
|
|
||||||
{{ getStepStatusText(node.status) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 兼容旧格式:如果没有nodes数据但有testStep字符串 -->
|
|
||||||
<div v-else-if="detailData.testStep" class="detail-section">
|
|
||||||
<h3 class="section-title">执行步骤</h3>
|
|
||||||
<div class="steps-container">
|
|
||||||
<div v-for="(step, index) in detailData.testStep.split(',')" :key="index" class="step-item">
|
|
||||||
<div class="step-number">{{ index + 1 }}</div>
|
|
||||||
<div class="step-content">{{ step.trim() }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 实验信息 -->
|
<!-- 实验信息 -->
|
||||||
<div class="detail-section">
|
<div class="detail-card">
|
||||||
<h3 class="section-title">实验信息</h3>
|
<h3 class="card-title">实验信息</h3>
|
||||||
<div class="detail-textarea">
|
<div class="card-content">
|
||||||
<label class="detail-label">实验说明:</label>
|
<div class="info-item full-width">
|
||||||
<div class="detail-text">{{ detailData.testInfo || '-' }}</div>
|
<label class="info-label">实验说明:</label>
|
||||||
|
<div class="info-value">{{ detailData.testInfo || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-textarea">
|
<div class="info-item full-width">
|
||||||
<label class="detail-label">实验设置:</label>
|
<label class="info-label">实验设置:</label>
|
||||||
<div class="detail-text">{{ detailData.testSetting || '-' }}</div>
|
<div class="info-value">{{ detailData.testSetting || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<label class="info-label">解决方案:</label>
|
||||||
|
<div class="info-value">{{ detailData.testSolutions || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-textarea">
|
|
||||||
<label class="detail-label">解决方案:</label>
|
|
||||||
<div class="detail-text">{{ detailData.testSolutions || '-' }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 参与人员 -->
|
<!-- 参与人员 -->
|
||||||
<div v-if="detailData.persons && detailData.persons.length > 0" class="detail-section">
|
<div v-if="detailData.persons && detailData.persons.length > 0" class="detail-card">
|
||||||
<h3 class="section-title">参与人员</h3>
|
<h3 class="card-title">参与人员</h3>
|
||||||
<div class="participant-list">
|
<div class="card-content">
|
||||||
<div v-for="(person, index) in detailData.persons" :key="person.id" class="participant-item">
|
<div v-for="(person, index) in detailData.persons" :key="person.id" class="info-row">
|
||||||
<span class="participant-name">{{ person.userName }}</span>
|
<div class="info-item">
|
||||||
<span class="participant-team">{{ person.teamName }}</span>
|
<label class="info-label">姓名:</label>
|
||||||
|
<span class="info-value">{{ person.userName }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<label class="info-label">团队:</label>
|
||||||
|
<span class="info-value">{{ person.teamName }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 巡检项目 -->
|
<!-- 巡检项目 -->
|
||||||
<div v-if="detailData.inspectionItemList && detailData.inspectionItemList.length > 0" class="detail-section">
|
<div v-if="detailData.inspectionItemList && detailData.inspectionItemList.length > 0" class="detail-card">
|
||||||
<h3 class="section-title">巡检项目</h3>
|
<h3 class="card-title">巡检项目</h3>
|
||||||
<div class="inspection-list">
|
<div class="card-content">
|
||||||
<div v-for="(item, index) in detailData.inspectionItemList" :key="item.id" class="inspection-item">
|
<div v-for="(item, index) in detailData.inspectionItemList" :key="item.id" class="info-row">
|
||||||
<span class="inspection-name">{{ item.name }}</span>
|
<div class="info-item">
|
||||||
<span class="inspection-type">{{ item.type }}</span>
|
<label class="info-label">项目名称:</label>
|
||||||
|
<span class="info-value">{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<label class="info-label">项目类型:</label>
|
||||||
|
<span class="info-value">{{ item.type }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="loading-details">
|
||||||
|
<el-skeleton :count="6" :columns="2" />
|
||||||
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="showDetailDialog = false">关闭</el-button>
|
<el-button @click="showDetailDialog = false">关闭</el-button>
|
||||||
@ -618,7 +576,6 @@ import router from '@/router';
|
|||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { shiyanDetail, shiyanlist, addshiyan, updateshiyan } from '@/api/zhinengxunjian/shiyan/index';
|
import { shiyanDetail, shiyanlist, addshiyan, updateshiyan } from '@/api/zhinengxunjian/shiyan/index';
|
||||||
import { xunjianUserlist } from '@/api/zhinengxunjian/xunjian/index';
|
import { xunjianUserlist } from '@/api/zhinengxunjian/xunjian/index';
|
||||||
import { addjiedian, updatejiedian } from '@/api/zhinengxunjian/jiedian/index';
|
|
||||||
// 1. 选项卡状态管理
|
// 1. 选项卡状态管理
|
||||||
const activeTab = ref('plan'); // 默认为"巡检计划"
|
const activeTab = ref('plan'); // 默认为"巡检计划"
|
||||||
const timeRange = ref('month'); // 统计时间范围:月/周/日
|
const timeRange = ref('month'); // 统计时间范围:月/周/日
|
||||||
@ -952,10 +909,6 @@ const handleSave = async () => {
|
|||||||
personIds: formData.value.participants.join(','),
|
personIds: formData.value.participants.join(','),
|
||||||
inspectionItems: '',
|
inspectionItems: '',
|
||||||
testSolutions: formData.value.riskMitigation,
|
testSolutions: formData.value.riskMitigation,
|
||||||
testStep: formData.value.steps
|
|
||||||
.filter((step) => step.name.trim() || step.intendedPurpose.trim())
|
|
||||||
.map((step) => `${step.name || ''}: ${step.intendedPurpose || ''}`)
|
|
||||||
.join(','),
|
|
||||||
testDevice: formData.value.equipments
|
testDevice: formData.value.equipments
|
||||||
.filter((equip) => equip.selected)
|
.filter((equip) => equip.selected)
|
||||||
.map((equip) => equip.name)
|
.map((equip) => equip.name)
|
||||||
@ -965,83 +918,15 @@ const handleSave = async () => {
|
|||||||
id: editRecordId.value // 若后端用planId等,需改为对应字段名
|
id: editRecordId.value // 若后端用planId等,需改为对应字段名
|
||||||
};
|
};
|
||||||
|
|
||||||
// 4. 处理步骤数据并调用接口
|
// 调用接口
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
// 处理步骤数据格式
|
|
||||||
const stepsData = formData.value.steps
|
|
||||||
.filter((step) => step.name.trim() || step.intendedPurpose.trim())
|
|
||||||
.map((step, index) => ({
|
|
||||||
createTime: new Date().toISOString(),
|
|
||||||
updateTime: new Date().toISOString(),
|
|
||||||
params: {},
|
|
||||||
module: 3,
|
|
||||||
code: index + 1,
|
|
||||||
name: step.name,
|
|
||||||
intendedPurpose: step.intendedPurpose,
|
|
||||||
intendedTime: step.intendedTime ? new Date(step.intendedTime).toISOString() : new Date().toISOString(),
|
|
||||||
finishTime: '',
|
|
||||||
remark: '',
|
|
||||||
status: 2
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 获取nodeIds
|
|
||||||
let nodeIds = '';
|
|
||||||
if (editRecordId.value) {
|
if (editRecordId.value) {
|
||||||
// 编辑模式:获取试验详情,以获取原始步骤的id
|
|
||||||
const detailResponse = await shiyanDetail(editRecordId.value);
|
|
||||||
if (detailResponse.code !== 200) {
|
|
||||||
ElMessage.error('获取试验详情失败');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const experimentDetail = detailResponse.data.rows?.[0] || detailResponse.data;
|
|
||||||
// 兼容两种数据结构:可能在rows数组中,也可能直接在data中
|
|
||||||
|
|
||||||
if (experimentDetail.nodes && Array.isArray(experimentDetail.nodes)) {
|
|
||||||
// 按code排序原始nodes数组
|
|
||||||
const sortedNodes = [...experimentDetail.nodes].sort((a, b) => (a.code || 0) - (b.code || 0));
|
|
||||||
|
|
||||||
// 为新的步骤数据添加id
|
|
||||||
const updatedSteps = stepsData.map((step, index) => ({
|
|
||||||
...step,
|
|
||||||
id: sortedNodes[index]?.id || 0 // 使用原始步骤的id,如果不存在则使用0
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 调用updatejiedian接口更新步骤,直接传递数组
|
|
||||||
const updateResponse = await updatejiedian(updatedSteps);
|
|
||||||
if (updateResponse.code !== 200) {
|
|
||||||
ElMessage.error('更新步骤失败');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用原始的nodeIds,避免重新创建步骤
|
|
||||||
nodeIds = experimentDetail.nodeIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 编辑模式:调用更新接口
|
// 编辑模式:调用更新接口
|
||||||
response = await updateshiyan(requestData);
|
response = await updateshiyan(requestData);
|
||||||
} else {
|
} else {
|
||||||
// 新增模式:调用addjiedian接口创建步骤
|
|
||||||
const jiedianResponse = await addjiedian(stepsData);
|
|
||||||
|
|
||||||
if (jiedianResponse.code !== 200) {
|
|
||||||
ElMessage.error('创建步骤失败');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取返回的ids,实际返回格式中msg字段包含ids字符串
|
|
||||||
if (jiedianResponse.code === 200 && jiedianResponse.msg) {
|
|
||||||
nodeIds = jiedianResponse.msg;
|
|
||||||
} else {
|
|
||||||
ElMessage.warning('未获取到有效的步骤ID');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增模式:调用添加接口(删除请求参数中的id,避免后端报错)
|
// 新增模式:调用添加接口(删除请求参数中的id,避免后端报错)
|
||||||
const { id, ...addData } = requestData;
|
const { id, ...addData } = requestData;
|
||||||
// 添加nodeIds字段
|
|
||||||
addData.nodeIds = nodeIds;
|
|
||||||
response = await addshiyan(addData);
|
response = await addshiyan(addData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1072,11 +957,6 @@ const resetForm = () => {
|
|||||||
envRequirements: '', // 环境要求为空
|
envRequirements: '', // 环境要求为空
|
||||||
manager: '', // 负责人为空
|
manager: '', // 负责人为空
|
||||||
participants: [], // 参与人员为空数组
|
participants: [], // 参与人员为空数组
|
||||||
steps: [
|
|
||||||
{ name: '', intendedPurpose: '', intendedTime: '' },
|
|
||||||
{ name: '', intendedPurpose: '', intendedTime: '' },
|
|
||||||
{ name: '', intendedPurpose: '', intendedTime: '' }
|
|
||||||
], // 步骤内容为空
|
|
||||||
equipments: [
|
equipments: [
|
||||||
{ name: '服务器(型号:XYZ-9000)', selected: false },
|
{ name: '服务器(型号:XYZ-9000)', selected: false },
|
||||||
{ name: '网络测试仪(型号:NT-5000)', selected: false },
|
{ name: '网络测试仪(型号:NT-5000)', selected: false },
|
||||||
@ -1152,45 +1032,6 @@ const handleEditRecord = async (row) => {
|
|||||||
const recordDetail = detailResponse.data.rows?.[0] || detailResponse.data;
|
const recordDetail = detailResponse.data.rows?.[0] || detailResponse.data;
|
||||||
// 兼容两种数据结构:可能在rows数组中,也可能直接在data中
|
// 兼容两种数据结构:可能在rows数组中,也可能直接在data中
|
||||||
|
|
||||||
// 3. 处理步骤数据:优先从nodes数组中提取
|
|
||||||
const steps = [];
|
|
||||||
// 如果有nodes数组,优先从nodes中提取步骤数据
|
|
||||||
if (recordDetail.nodes && Array.isArray(recordDetail.nodes)) {
|
|
||||||
// 复制nodes数组并按code升序排序
|
|
||||||
const sortedNodes = [...recordDetail.nodes].sort((a, b) => (a.code || 0) - (b.code || 0));
|
|
||||||
// 转换为所需的格式
|
|
||||||
sortedNodes.forEach((node) => {
|
|
||||||
if ((node.name && node.name.trim()) || (node.intendedPurpose && node.intendedPurpose.trim())) {
|
|
||||||
steps.push({
|
|
||||||
name: node.name || '',
|
|
||||||
intendedPurpose: node.intendedPurpose || '',
|
|
||||||
intendedTime: node.intendedTime || ''
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 如果nodes中没有数据,回退到从testStep字符串解析
|
|
||||||
else if (recordDetail.testStep) {
|
|
||||||
// 拆分字符串
|
|
||||||
const stepItems = recordDetail.testStep.split(',');
|
|
||||||
stepItems.forEach((stepText) => {
|
|
||||||
// 移除序号前缀(如"1. "),只保留内容
|
|
||||||
const content = stepText.replace(/^\d+\.\s*/, '').trim();
|
|
||||||
if (content) {
|
|
||||||
// 对于旧格式数据,我们将内容放入intendedPurpose字段
|
|
||||||
steps.push({
|
|
||||||
name: `步骤${steps.length + 1}`,
|
|
||||||
intendedPurpose: content,
|
|
||||||
intendedTime: ''
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 确保至少有3个步骤(如果解析后为空)
|
|
||||||
while (steps.length < 3) {
|
|
||||||
steps.push({ name: '', intendedPurpose: '', intendedTime: '' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 处理testDevice:将逗号分隔的字符串转换为设备数组
|
// 4. 处理testDevice:将逗号分隔的字符串转换为设备数组
|
||||||
const equipments = [];
|
const equipments = [];
|
||||||
if (recordDetail.testDevice) {
|
if (recordDetail.testDevice) {
|
||||||
@ -1236,7 +1077,6 @@ const handleEditRecord = async (row) => {
|
|||||||
envRequirements: recordDetail.envRequirements || recordDetail.testSetting || '',
|
envRequirements: recordDetail.envRequirements || recordDetail.testSetting || '',
|
||||||
manager: recordDetail.manager || recordDetail.personCharge || '',
|
manager: recordDetail.manager || recordDetail.personCharge || '',
|
||||||
participants: participants, // 从personIds解析的数组
|
participants: participants, // 从personIds解析的数组
|
||||||
steps: steps, // 解析后的步骤数组
|
|
||||||
equipments: equipments, // 解析并合并后的设备数组
|
equipments: equipments, // 解析并合并后的设备数组
|
||||||
riskMitigation: recordDetail.riskMitigation || recordDetail.testSolutions || ''
|
riskMitigation: recordDetail.riskMitigation || recordDetail.testSolutions || ''
|
||||||
};
|
};
|
||||||
@ -1375,53 +1215,23 @@ const formatDate = (dateString) => {
|
|||||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 根据步骤状态获取对应的样式类
|
// 日期时间格式化函数
|
||||||
const getStatusClass = (status) => {
|
const formatDateTime = (dateString) => {
|
||||||
// 处理可能的数字输入
|
if (!dateString) return '';
|
||||||
const statusStr = status?.toString() || '';
|
const date = new Date(dateString);
|
||||||
const statusClassMap = {
|
|
||||||
'1': 'status-pending',
|
|
||||||
'2': 'status-running',
|
|
||||||
'3': 'status-completed',
|
|
||||||
'4': 'status-delayed',
|
|
||||||
'5': 'status-failed'
|
|
||||||
};
|
|
||||||
return statusClassMap[statusStr] || 'status-unknown';
|
|
||||||
};
|
|
||||||
|
|
||||||
// 格式化日期时间(用于步骤条)
|
|
||||||
const formatDateTime = (dateTime) => {
|
|
||||||
if (!dateTime) return '-';
|
|
||||||
try {
|
|
||||||
const date = new Date(dateTime);
|
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
const day = String(date.getDate()).padStart(2, '0');
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
const hours = String(date.getHours()).padStart(2, '0');
|
const hours = String(date.getHours()).padStart(2, '0');
|
||||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||||
} catch (error) {
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||||
return dateTime;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取步骤状态文本
|
|
||||||
const getStepStatusText = (status) => {
|
|
||||||
const statusStr = status?.toString() || '';
|
|
||||||
const statusMap = {
|
|
||||||
'1': '待执行',
|
|
||||||
'2': '执行中',
|
|
||||||
'3': '已完成',
|
|
||||||
'4': '已延期',
|
|
||||||
'5': '失败'
|
|
||||||
};
|
|
||||||
return statusMap[statusStr] || '未知状态';
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@import url('./css/step-bars.css');
|
|
||||||
@import url('./css/detail-dialog.css');
|
@import url('./css/detail-dialog.css');
|
||||||
|
|
||||||
.operation-inspection {
|
.operation-inspection {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background-color: #f9fbfd;
|
background-color: #f9fbfd;
|
||||||
@ -2095,53 +1905,6 @@ const getStepStatusText = (status) => {
|
|||||||
box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
|
box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 试验步骤样式 */
|
|
||||||
.steps-container {
|
|
||||||
border: 1px solid #e4e7ed;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 16px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-item:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-number {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: #165dff;
|
|
||||||
color: white;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
margin-right: 16px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-input:focus {
|
|
||||||
border-color: #165dff;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-step-btn {
|
|
||||||
color: #165dff;
|
|
||||||
margin-top: 12px;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 设备列表样式 */
|
/* 设备列表样式 */
|
||||||
.equipment-list {
|
.equipment-list {
|
||||||
border: 1px solid #e4e7ed;
|
border: 1px solid #e4e7ed;
|
||||||
@ -2200,7 +1963,7 @@ const getStepStatusText = (status) => {
|
|||||||
border-color: #0d47a1;
|
border-color: #0d47a1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 响应式设计 */
|
/* 响应式设计 - 保留必要的覆盖样式 */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.custom-experiment-dialog {
|
.custom-experiment-dialog {
|
||||||
width: 90% !important;
|
width: 90% !important;
|
||||||
@ -2220,5 +1983,13 @@ const getStepStatusText = (status) => {
|
|||||||
.new-equipment-input {
|
.new-equipment-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-row {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="operation-inspection">
|
<div class="operation-inspection">
|
||||||
<!-- 顶部导航选项卡 -->
|
<!-- 顶部导航选项卡 -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab active" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab active" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,16 +10,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 头部操作按钮 -->
|
|
||||||
<div class="header-container">
|
|
||||||
<div class="header-actions">
|
|
||||||
<el-button type="primary" class="export-btn">筛选</el-button>
|
|
||||||
<el-button type="primary" class="create-btn">导入数据</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 选项卡和按钮组合 -->
|
<!-- 选项卡和按钮组合 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
<div style="display: flex; align-items: center; gap: 10px">
|
<div style="display: flex; align-items: center; gap: 10px">
|
||||||
@ -56,7 +47,7 @@
|
|||||||
class="date-picker"
|
class="date-picker"
|
||||||
></el-date-picker>
|
></el-date-picker>
|
||||||
|
|
||||||
<el-button type="primary" class="search-btn"> 搜索 </el-button>
|
<el-button icon="Search" type="primary" class="search-btn"> 搜索 </el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -71,11 +62,20 @@
|
|||||||
<div class="stat-grid">
|
<div class="stat-grid">
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<p class="stat-label">本月完成试验</p>
|
<p class="stat-label">本月完成试验</p>
|
||||||
<p class="stat-value">{{ statData.completed }}<span class="stat-change up">较上月 ↑2.4%</span></p>
|
<p class="stat-value">
|
||||||
|
{{ statData.completed
|
||||||
|
}}<span class="stat-change" :class="statData.completedGrowth >= 0 ? 'up' : 'down'">
|
||||||
|
较上月 {{ statData.completedGrowth >= 0 ? '↑' : '↓' }}{{ Math.abs(statData.completedGrowth) }}%
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<p class="stat-label">试验通过率</p>
|
<p class="stat-label">试验通过率</p>
|
||||||
<p class="stat-value">{{ statData.passRate }}%<span class="stat-change up">较上月 ↑5.6%</span></p>
|
<p class="stat-value">
|
||||||
|
{{ statData.passRate }}%<span class="stat-change" :class="statData.passRateGrowth >= 0 ? 'up' : 'down'">
|
||||||
|
较上月 {{ statData.passRateGrowth >= 0 ? '↑' : '↓' }}{{ Math.abs(statData.passRateGrowth) }}%
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<p class="stat-label">待分析记录</p>
|
<p class="stat-label">待分析记录</p>
|
||||||
@ -83,7 +83,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<p class="stat-label">平均试验时长</p>
|
<p class="stat-label">平均试验时长</p>
|
||||||
<p class="stat-value">{{ statData.avgDuration }}<span class="stat-change down">较上月 ↓9.4分钟</span></p>
|
<p class="stat-value">
|
||||||
|
{{ statData.avgDuration
|
||||||
|
}}<span class="stat-change" :class="statData.avgDurationGrowth >= 0 ? 'down' : 'up'">
|
||||||
|
较上月 {{ statData.avgDurationGrowth >= 0 ? '↑' : '↓' }}{{ Math.abs(statData.avgDurationGrowth) }}分钟
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -149,7 +154,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="record-actions">
|
<div class="record-actions">
|
||||||
<button class="operate-btn view-btn">查看详情</button>
|
<button class="operate-btn view-btn" @click="handleViewDetail(record)">查看详情</button>
|
||||||
<button class="operate-btn report-btn">生成报告</button>
|
<button class="operate-btn report-btn">生成报告</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -192,7 +197,7 @@
|
|||||||
<button class="operate-btn execute-btn" v-if="scope.row.status === 'drafted'">执行</button>
|
<button class="operate-btn execute-btn" v-if="scope.row.status === 'drafted'">执行</button>
|
||||||
<button class="operate-btn pause-btn" v-if="scope.row.status === 'in-progress'">暂停</button>
|
<button class="operate-btn pause-btn" v-if="scope.row.status === 'in-progress'">暂停</button>
|
||||||
<button class="operate-btn resume-btn" v-if="scope.row.status === 'paused'">恢复</button>
|
<button class="operate-btn resume-btn" v-if="scope.row.status === 'paused'">恢复</button>
|
||||||
<button class="operate-btn view-btn">查看详情</button>
|
<button class="operate-btn view-btn" @click="handleViewDetail(scope.row)">查看详情</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -220,7 +225,7 @@
|
|||||||
<div class="operation-buttons">
|
<div class="operation-buttons">
|
||||||
<button class="operate-btn accept-btn" v-if="scope.row.status === 'pending'">接受</button>
|
<button class="operate-btn accept-btn" v-if="scope.row.status === 'pending'">接受</button>
|
||||||
<button class="operate-btn complete-btn" v-if="scope.row.status === 'accepted'">完成</button>
|
<button class="operate-btn complete-btn" v-if="scope.row.status === 'accepted'">完成</button>
|
||||||
<button class="operate-btn view-btn">查看详情</button>
|
<button class="operate-btn view-btn" @click="handleViewDetail(scope.row)">查看详情</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -241,6 +246,106 @@
|
|||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
></el-pagination>
|
></el-pagination>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 详情弹窗 -->
|
||||||
|
<el-dialog v-model="detailDialogVisible" title="任务详情" width="800px" :close-on-click-modal="false" center>
|
||||||
|
<div v-if="detailData" class="task-detail-container">
|
||||||
|
<div class="detail-card">
|
||||||
|
<h3 class="card-title">基本信息</h3>
|
||||||
|
<div class="info-row">
|
||||||
|
<span class="info-label">任务名称</span>
|
||||||
|
<span class="info-value">{{ detailData.taskName }}</span>
|
||||||
|
<span class="info-label">任务状态</span>
|
||||||
|
<span class="info-value" :class="getStatusClass(detailData.status)">
|
||||||
|
{{ getStatusText(detailData.status) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<span class="info-label">测试对象</span>
|
||||||
|
<span class="info-value">{{ detailData.testObject }}</span>
|
||||||
|
<span class="info-label">完成进度</span>
|
||||||
|
<span class="info-value">{{ detailData.progress }}%</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<span class="info-label">开始时间</span>
|
||||||
|
<span class="info-value">{{ detailData.beginTime }}</span>
|
||||||
|
<span class="info-label">结束时间</span>
|
||||||
|
<span class="info-value">{{ detailData.endTime }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<span class="info-label">时间信息</span>
|
||||||
|
<span class="info-value">{{ detailData.timeInfo ? detailData.timeInfo.replace(/,/g, '—') : '-' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-card">
|
||||||
|
<h3 class="card-title">执行人信息</h3>
|
||||||
|
<div v-if="detailData.personInfo" class="info-row">
|
||||||
|
<span class="info-label">执行人姓名</span>
|
||||||
|
<span class="info-value">{{ detailData.personInfo.userName }}</span>
|
||||||
|
<span class="info-label">联系电话</span>
|
||||||
|
<span class="info-value">{{ detailData.personInfo.phonenumber }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="detailData.personInfo" class="info-row">
|
||||||
|
<span class="info-label">性别</span>
|
||||||
|
<span class="info-value">{{ detailData.personInfo.sex === '1' ? '男' : '女' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-card">
|
||||||
|
<h3 class="card-title">关联计划</h3>
|
||||||
|
<div v-if="detailData.testPlan" class="info-row">
|
||||||
|
<span class="info-label">计划名称</span>
|
||||||
|
<span class="info-value">{{ detailData.testPlan.planName }}</span>
|
||||||
|
<span class="info-label">计划编号</span>
|
||||||
|
<span class="info-value">{{ detailData.testPlan.planCode }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="detailData.testPlan" class="info-row">
|
||||||
|
<span class="info-label">计划时间</span>
|
||||||
|
<span class="info-value">{{ detailData.testPlan.beginTime }} — {{ detailData.testPlan.endTime }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="detailData.testPlan && detailData.testPlan.testDevice" class="info-row">
|
||||||
|
<span class="info-label">测试设备</span>
|
||||||
|
<span class="info-value">{{ detailData.testPlan.testDevice }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="detailData.nodes && detailData.nodes.length > 0" class="detail-card">
|
||||||
|
<h3 class="card-title">执行步骤</h3>
|
||||||
|
<div class="steps-container">
|
||||||
|
<div v-for="(node, index) in detailData.nodes" :key="node.id || index" class="step-item">
|
||||||
|
<div class="step-number">{{ node.code || index + 1 }}</div>
|
||||||
|
<div class="step-info">
|
||||||
|
<div class="step-name">{{ node.name || '未命名步骤' }}</div>
|
||||||
|
<div class="step-purpose">{{ node.intendedPurpose || '无说明' }}</div>
|
||||||
|
<div class="step-time">计划时间:{{ formatDateTime(node.intendedTime) }}</div>
|
||||||
|
<div v-if="node.finishTime" class="step-finish-time">完成时间:{{ formatDateTime(node.finishTime) }}</div>
|
||||||
|
<div v-if="node.remark" class="step-remark">备注:{{ node.remark }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="step-status" :class="getStatusClass(node.status)">
|
||||||
|
{{ node.status === '2' ? '未完成' : '已完成' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="detailData.testFinal || detailData.failReason" class="detail-card">
|
||||||
|
<h3 class="card-title">执行结果</h3>
|
||||||
|
<div v-if="detailData.testFinal" class="info-row">
|
||||||
|
<span class="info-label">测试结果</span>
|
||||||
|
<span class="info-value">{{ detailData.testFinal }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="detailData.failReason" class="info-row">
|
||||||
|
<span class="info-label">失败原因</span>
|
||||||
|
<span class="info-value fail-reason">{{ detailData.failReason }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="loading-details">
|
||||||
|
<p>加载中...</p>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="detailDialogVisible = false">关闭</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -248,11 +353,11 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
import { syrenwulist, syrenwujilu, syrenwuDetail } from '@/api/zhinengxunjian/shiyan/renwu';
|
import { syrenwulist, syrenwujilu, syrenwuDetail } from '@/api/zhinengxunjian/shiyan/renwu';
|
||||||
|
|
||||||
// 1. 选项卡状态管理
|
// 1. 选项卡状态管理
|
||||||
const activeTab = ref('record'); // 默认显示"试验记录"
|
const activeTab = ref('record'); // 默认显示"试验记录"
|
||||||
const showFilter = ref(false);
|
|
||||||
|
|
||||||
// 2. 筛选条件
|
// 2. 筛选条件
|
||||||
const filterStatus = ref('all');
|
const filterStatus = ref('all');
|
||||||
@ -277,7 +382,11 @@ const statData = ref({
|
|||||||
completed: 0,
|
completed: 0,
|
||||||
passRate: 0,
|
passRate: 0,
|
||||||
pendingAnalysis: 0,
|
pendingAnalysis: 0,
|
||||||
avgDuration: '0分钟'
|
avgDuration: '0分钟',
|
||||||
|
// 新增:增长率相关数据
|
||||||
|
completedGrowth: 0,
|
||||||
|
passRateGrowth: 0,
|
||||||
|
avgDurationGrowth: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
// 6. 分页相关
|
// 6. 分页相关
|
||||||
@ -310,7 +419,8 @@ const getStatisticsData = async () => {
|
|||||||
const response = await syrenwujilu({ projectId: 1 });
|
const response = await syrenwujilu({ projectId: 1 });
|
||||||
console.log('syrenwujilu API响应:', response);
|
console.log('syrenwujilu API响应:', response);
|
||||||
|
|
||||||
if (response && response.data) {
|
// 确保接口返回成功状态码(code=200)且有数据
|
||||||
|
if (response && response.code === 200 && response.data) {
|
||||||
// 映射API返回的数据到statData
|
// 映射API返回的数据到statData
|
||||||
const apiData = response.data;
|
const apiData = response.data;
|
||||||
|
|
||||||
@ -319,11 +429,21 @@ const getStatisticsData = async () => {
|
|||||||
statData.value.pendingAnalysis = parseInt(apiData.failCount) || 0;
|
statData.value.pendingAnalysis = parseInt(apiData.failCount) || 0;
|
||||||
|
|
||||||
// 格式化平均试验时长
|
// 格式化平均试验时长
|
||||||
const avgTime = parseInt(apiData.averageTestTime) || 0;
|
const avgTime = parseFloat(apiData.averageTestTime) || 0;
|
||||||
statData.value.avgDuration = `${avgTime}分钟`;
|
statData.value.avgDuration = `${avgTime}分钟`;
|
||||||
|
|
||||||
|
// 处理增长率数据
|
||||||
|
statData.value.completedGrowth = parseInt(apiData.finishCountAdd) || 0;
|
||||||
|
statData.value.passRateGrowth = parseFloat(apiData.passValueAdd) || 0;
|
||||||
|
statData.value.avgDurationGrowth = parseFloat(apiData.averageTestTimeAdd) || 0;
|
||||||
|
} else {
|
||||||
|
console.warn('获取统计数据失败或返回格式不正确:', response);
|
||||||
|
// 可以在这里添加错误提示或默认值处理
|
||||||
|
ElMessage.warning('获取统计数据失败,请稍后重试');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取统计数据失败:', error);
|
console.error('获取统计数据异常:', error);
|
||||||
|
ElMessage.error('获取统计数据异常,请稍后重试');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -339,15 +459,13 @@ const formatDate = (dateString) => {
|
|||||||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 11. 辅助方法:格式化时长(假设单位为分钟)
|
// 11. 辅助方法:格式化日期时间
|
||||||
const formatDuration = (minutes) => {
|
const formatDateTime = (dateTimeString) => {
|
||||||
if (minutes < 60) {
|
if (!dateTimeString) return '未知时间';
|
||||||
return `${minutes}分钟`;
|
const date = new Date(dateTimeString);
|
||||||
} else {
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(
|
||||||
const hours = Math.floor(minutes / 60);
|
date.getHours()
|
||||||
const mins = minutes % 60;
|
).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
|
||||||
return `${hours}小时${mins}分钟`;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 12. 辅助方法:获取节点状态类名
|
// 12. 辅助方法:获取节点状态类名
|
||||||
@ -392,15 +510,19 @@ const getProgressColor = (status) => {
|
|||||||
// 15. 辅助方法:获取状态文本
|
// 15. 辅助方法:获取状态文本
|
||||||
const getStatusText = (status) => {
|
const getStatusText = (status) => {
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
'1': '进行中',
|
'1': '待执行',
|
||||||
'completed': '通过',
|
'4': '执行中',
|
||||||
|
'2': '已延期',
|
||||||
|
'5': '已完成',
|
||||||
|
'3': '失败',
|
||||||
|
'completed': '已完成',
|
||||||
'failed': '失败',
|
'failed': '失败',
|
||||||
'paused': '已暂停',
|
'paused': '已延期',
|
||||||
'drafted': '草稿',
|
'drafted': '待执行',
|
||||||
'in-progress': '进行中',
|
'in-progress': '执行中',
|
||||||
'normal': '正常',
|
'normal': '已完成',
|
||||||
'attention': '需关注',
|
'attention': '执行中',
|
||||||
'problem': '有问题'
|
'problem': '失败'
|
||||||
};
|
};
|
||||||
return statusMap[status] || '未知状态';
|
return statusMap[status] || '未知状态';
|
||||||
};
|
};
|
||||||
@ -408,10 +530,15 @@ const getStatusText = (status) => {
|
|||||||
// 16. 辅助方法:获取任务状态文本
|
// 16. 辅助方法:获取任务状态文本
|
||||||
const getTaskStatusText = (status) => {
|
const getTaskStatusText = (status) => {
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
'pending': '待接受',
|
'pending': '待执行',
|
||||||
'accepted': '进行中',
|
'accepted': '执行中',
|
||||||
'completed': '已完成',
|
'completed': '已完成',
|
||||||
'rejected': '已拒绝'
|
'rejected': '已拒绝',
|
||||||
|
'1': '待执行',
|
||||||
|
'4': '执行中',
|
||||||
|
'2': '已延期',
|
||||||
|
'5': '已完成',
|
||||||
|
'3': '失败'
|
||||||
};
|
};
|
||||||
return statusMap[status] || '未知状态';
|
return statusMap[status] || '未知状态';
|
||||||
};
|
};
|
||||||
@ -419,18 +546,22 @@ const getTaskStatusText = (status) => {
|
|||||||
// 17. 辅助方法:获取状态类名
|
// 17. 辅助方法:获取状态类名
|
||||||
const getStatusClass = (status) => {
|
const getStatusClass = (status) => {
|
||||||
const classMap = {
|
const classMap = {
|
||||||
'1': 'status-in-progress',
|
'1': 'tag-pending', // 待执行
|
||||||
'completed': 'status-passed',
|
'4': 'tag-executing', // 执行中
|
||||||
|
'2': 'tag-delayed', // 已延期
|
||||||
|
'5': 'tag-completed', // 已完成
|
||||||
|
'3': 'status-failed', // 失败
|
||||||
|
'completed': 'tag-completed',
|
||||||
'failed': 'status-failed',
|
'failed': 'status-failed',
|
||||||
'paused': 'status-paused',
|
'paused': 'tag-delayed',
|
||||||
'pending': 'status-pending',
|
'pending': 'tag-pending',
|
||||||
'accepted': 'status-accepted',
|
'accepted': 'tag-pending',
|
||||||
'rejected': 'status-rejected',
|
'rejected': 'status-failed',
|
||||||
'normal': 'status-normal',
|
'normal': 'tag-completed',
|
||||||
'attention': 'status-attention',
|
'attention': 'tag-executing',
|
||||||
'problem': 'status-problem'
|
'problem': 'status-failed'
|
||||||
};
|
};
|
||||||
return classMap[status] || 'status-pending';
|
return classMap[status] || 'tag-pending';
|
||||||
};
|
};
|
||||||
|
|
||||||
// 18. 分页事件处理
|
// 18. 分页事件处理
|
||||||
@ -480,10 +611,46 @@ const handleInspectionManagement3 = () => {
|
|||||||
router.push('/rili/shiyanjilu');
|
router.push('/rili/shiyanjilu');
|
||||||
};
|
};
|
||||||
|
|
||||||
// 20. 组件挂载时获取数据
|
// 20. 详情弹窗相关
|
||||||
onMounted(() => {
|
const detailDialogVisible = ref(false);
|
||||||
getStatisticsData();
|
const detailData = ref(null);
|
||||||
getTestRecords();
|
const isDetailLoading = ref(false);
|
||||||
|
|
||||||
|
// 22. 处理查看详情
|
||||||
|
const handleViewDetail = async (row) => {
|
||||||
|
try {
|
||||||
|
if (!row || !row.id) {
|
||||||
|
ElMessage.error('记录ID不存在,无法查看详情');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isDetailLoading.value = true;
|
||||||
|
const response = await syrenwuDetail(row.id);
|
||||||
|
|
||||||
|
if (response && response.code === 200) {
|
||||||
|
detailData.value = response.data;
|
||||||
|
detailDialogVisible.value = true;
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response?.msg || '获取任务详情失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('查看详情失败:', error);
|
||||||
|
ElMessage.error('获取任务详情失败');
|
||||||
|
} finally {
|
||||||
|
isDetailLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 24. 组件挂载时获取数据 - 确保页面进入时立即调用接口
|
||||||
|
onMounted(async () => {
|
||||||
|
// 直接并立即调用数据接口,确保页面加载时能获取到最新数据
|
||||||
|
try {
|
||||||
|
// 并行调用两个数据接口以提高加载速度
|
||||||
|
await Promise.all([getStatisticsData(), getTestRecords()]);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('数据加载失败:', error);
|
||||||
|
ElMessage.error('数据加载失败,请刷新页面重试');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -497,35 +664,40 @@ onMounted(() => {
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2. 顶部导航选项卡 */
|
|
||||||
.navigation-tabs {
|
.navigation-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
margin-bottom: 20px;
|
padding: 2px;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tab {
|
.nav-tab {
|
||||||
padding: 12px 24px;
|
padding: 12px 24px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 4px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #6b7280;
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-right: 1px solid #f0f0f0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tab:last-child {
|
.nav-tab:last-child {
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
.nav-tab:hover:not(.active) {
|
|
||||||
background-color: #f3f4f6;
|
.nav-tab:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tab.active {
|
.nav-tab.active {
|
||||||
background-color: #165dff;
|
background-color: #409eff;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-weight: 500;
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3. 选项卡样式 */
|
/* 3. 选项卡样式 */
|
||||||
@ -570,24 +742,10 @@ onMounted(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.action-buttons {
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
.el-select,
|
.el-select,
|
||||||
.date-picker {
|
.date-picker {
|
||||||
width: 160px;
|
width: 160px;
|
||||||
}
|
}
|
||||||
.search-btn,
|
|
||||||
.export-btn {
|
|
||||||
background-color: #165dff;
|
|
||||||
border-color: #165dff;
|
|
||||||
}
|
|
||||||
.filter-btn {
|
|
||||||
background-color: #f3f4f6;
|
|
||||||
color: #6b7280;
|
|
||||||
border-color: #e5e7eb;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 6. 表格容器 */
|
/* 6. 表格容器 */
|
||||||
.table-container {
|
.table-container {
|
||||||
@ -623,57 +781,58 @@ onMounted(() => {
|
|||||||
/* 8. 状态标签样式 */
|
/* 8. 状态标签样式 */
|
||||||
.status-tag {
|
.status-tag {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 2px 8px;
|
padding: 4px 10px;
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
.status-drafted {
|
|
||||||
background-color: #e0efff;
|
/* 与试验任务页面相同的标签样式 */
|
||||||
color: #165dff;
|
.tag-pending {
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
color: #1677ff;
|
||||||
|
border-color: #91d5ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag-delayed {
|
||||||
|
background-color: #fff2f0;
|
||||||
|
color: #ff4d4f;
|
||||||
|
border-color: #ffccc7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-executing {
|
||||||
|
background-color: #fffbe6;
|
||||||
|
color: #fa8c16;
|
||||||
|
border-color: #ffe58f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-completed {
|
||||||
|
background-color: #f6ffed;
|
||||||
|
color: #52c41a;
|
||||||
|
border-color: #b7eb8f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 保留原有的部分样式以确保兼容性 */
|
||||||
.status-in-progress {
|
.status-in-progress {
|
||||||
background-color: #e0f2fe;
|
background-color: #fffbe6;
|
||||||
color: #0284c7;
|
color: #fa8c16;
|
||||||
|
border-color: #ffe58f;
|
||||||
}
|
}
|
||||||
.status-completed {
|
.status-completed {
|
||||||
background-color: #e6ffed;
|
background-color: #f6ffed;
|
||||||
color: #00b42a;
|
color: #52c41a;
|
||||||
}
|
border-color: #b7eb8f;
|
||||||
.status-paused {
|
|
||||||
background-color: #f2f3f5;
|
|
||||||
color: #86909c;
|
|
||||||
}
|
}
|
||||||
.status-pending {
|
.status-pending {
|
||||||
background-color: #f9fafb;
|
background-color: #e6f7ff;
|
||||||
color: #6b7280;
|
color: #1677ff;
|
||||||
}
|
border-color: #91d5ff;
|
||||||
.status-accepted {
|
|
||||||
background-color: #eff6ff;
|
|
||||||
color: #2563eb;
|
|
||||||
}
|
|
||||||
.status-rejected {
|
|
||||||
background-color: #fee2e2;
|
|
||||||
color: #dc2626;
|
|
||||||
}
|
|
||||||
.status-normal {
|
|
||||||
background-color: #e6ffed;
|
|
||||||
color: #00b42a;
|
|
||||||
}
|
|
||||||
.status-attention {
|
|
||||||
background-color: #fff7e0;
|
|
||||||
color: #ff7d00;
|
|
||||||
}
|
|
||||||
.status-problem {
|
|
||||||
background-color: #fff2f0;
|
|
||||||
color: #f5222d;
|
|
||||||
}
|
|
||||||
.status-passed {
|
|
||||||
background-color: #e6ffed;
|
|
||||||
color: #00b42a;
|
|
||||||
}
|
}
|
||||||
.status-failed {
|
.status-failed {
|
||||||
background-color: #fee2e2;
|
background-color: #fff2f0;
|
||||||
color: #dc2626;
|
color: #ff4d4f;
|
||||||
|
border-color: #ffccc7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 9. 操作按钮样式 */
|
/* 9. 操作按钮样式 */
|
||||||
@ -691,30 +850,6 @@ onMounted(() => {
|
|||||||
background: none;
|
background: none;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
.edit-btn {
|
|
||||||
color: #165dff;
|
|
||||||
}
|
|
||||||
.edit-btn:hover {
|
|
||||||
background-color: #e8f3ff;
|
|
||||||
}
|
|
||||||
.execute-btn {
|
|
||||||
color: #00b42a;
|
|
||||||
}
|
|
||||||
.execute-btn:hover {
|
|
||||||
background-color: #e6ffed;
|
|
||||||
}
|
|
||||||
.pause-btn {
|
|
||||||
color: #ff7d00;
|
|
||||||
}
|
|
||||||
.pause-btn:hover {
|
|
||||||
background-color: #fff7e0;
|
|
||||||
}
|
|
||||||
.resume-btn {
|
|
||||||
color: #722ed1;
|
|
||||||
}
|
|
||||||
.resume-btn:hover {
|
|
||||||
background-color: #f3e8ff;
|
|
||||||
}
|
|
||||||
.view-btn {
|
.view-btn {
|
||||||
color: #165dff;
|
color: #165dff;
|
||||||
}
|
}
|
||||||
@ -911,12 +1046,6 @@ onMounted(() => {
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-name {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #6b7280;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-line {
|
.progress-line {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="inspection-tasks">
|
<div class="inspection-tasks">
|
||||||
<!-- 导航栏 -->
|
<!-- 导航栏 -->
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab active" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab active" @click="handleInspection3">试验管理</div>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 选项卡 -->
|
<!-- 选项卡 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
@ -29,7 +29,7 @@
|
|||||||
<el-option label="待执行" value="1"></el-option>
|
<el-option label="待执行" value="1"></el-option>
|
||||||
<el-option label="执行中" value="4"></el-option>
|
<el-option label="执行中" value="4"></el-option>
|
||||||
<el-option label="已延期" value="2"></el-option>
|
<el-option label="已延期" value="2"></el-option>
|
||||||
<!-- 接口“暂停”对应页面“已延期” -->
|
|
||||||
<el-option label="已完成" value="5"></el-option>
|
<el-option label="已完成" value="5"></el-option>
|
||||||
<el-option label="失败" value="3"></el-option>
|
<el-option label="失败" value="3"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
@ -137,7 +137,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 添加新任务弹窗 -->
|
<!-- 添加新任务弹窗 -->
|
||||||
<el-dialog v-model="createTaskDialogVisible" title="添加新任务" width="700px" :before-close="handleCancelCreateTask">
|
<el-dialog v-model="createTaskDialogVisible" title="添加新任务" width="750px" :before-close="handleCancelCreateTask">
|
||||||
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="80px">
|
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="80px">
|
||||||
<el-form-item label="任务名称" prop="taskName">
|
<el-form-item label="任务名称" prop="taskName">
|
||||||
<el-input v-model="createTaskForm.taskName" placeholder="输入任务名称" />
|
<el-input v-model="createTaskForm.taskName" placeholder="输入任务名称" />
|
||||||
@ -338,7 +338,7 @@
|
|||||||
<div v-if="node.remark" class="step-remark">备注:{{ node.remark }}</div>
|
<div v-if="node.remark" class="step-remark">备注:{{ node.remark }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-status" :class="getStatusClass(node.status)">
|
<div class="step-status" :class="getStatusClass(node.status)">
|
||||||
{{ getStepStatusText(node.status) }}
|
{{ node.status === '2' ? '未完成' : '已完成' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -377,7 +377,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, getCurrentInstance } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
// 引入已定义的接口函数
|
// 引入已定义的接口函数
|
||||||
import { syrenwulist, syrenwuDetail, addsyrenwu, updatesyrenwu } from '@/api/zhinengxunjian/shiyan/renwu';
|
import { syrenwulist, syrenwuDetail, addsyrenwu, updatesyrenwu } from '@/api/zhinengxunjian/shiyan/renwu';
|
||||||
@ -386,7 +386,6 @@ import { xunjianUserlist } from '@/api/zhinengxunjian/xunjian/index';
|
|||||||
import { addjiedian } from '@/api/zhinengxunjian/jiedian/index';
|
import { addjiedian } from '@/api/zhinengxunjian/jiedian/index';
|
||||||
// 引入Element Plus组件(提示/空状态/骨架屏/弹窗)
|
// 引入Element Plus组件(提示/空状态/骨架屏/弹窗)
|
||||||
import { ElMessage, ElEmpty, ElSkeleton, ElForm, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElEmpty, ElSkeleton, ElForm, ElMessageBox } from 'element-plus';
|
||||||
import { Plus } from '@element-plus/icons-vue';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据任务ID获取完整的任务详情数据
|
* 根据任务ID获取完整的任务详情数据
|
||||||
@ -428,7 +427,6 @@ const groupNodesByModule = (nodes) => {
|
|||||||
if (!nodes || !Array.isArray(nodes)) {
|
if (!nodes || !Array.isArray(nodes)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 这里简单地将所有节点放在一个默认模块下,实际应用中可以根据节点数据的module字段进行分组
|
// 这里简单地将所有节点放在一个默认模块下,实际应用中可以根据节点数据的module字段进行分组
|
||||||
const defaultGroup = {
|
const defaultGroup = {
|
||||||
module: '测试步骤',
|
module: '测试步骤',
|
||||||
@ -856,9 +854,18 @@ const handleAction = async (task) => {
|
|||||||
id: task.id
|
id: task.id
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 声明resultType变量,提升作用域
|
||||||
|
let resultType = null;
|
||||||
|
|
||||||
// 3. 根据任务状态只修改状态相关的字段
|
// 3. 根据任务状态只修改状态相关的字段
|
||||||
if (task.status === '4') {
|
if (task.status === '4') {
|
||||||
// 执行中 → 完成:使用弹窗确认结果
|
// 执行中 → 完成:使用弹窗确认结果
|
||||||
|
try {
|
||||||
|
// 保持原有结构
|
||||||
|
} catch (error) {
|
||||||
|
console.error('捕获到异常:', error);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const confirmResult = await ElMessageBox.confirm('请选择试验结果', '完成试验', {
|
const confirmResult = await ElMessageBox.confirm('请选择试验结果', '完成试验', {
|
||||||
confirmButtonText: '正常',
|
confirmButtonText: '正常',
|
||||||
@ -870,12 +877,14 @@ const handleAction = async (task) => {
|
|||||||
updateParams.status = '5';
|
updateParams.status = '5';
|
||||||
updateParams.progress = 100;
|
updateParams.progress = 100;
|
||||||
updateParams.testFinal = '正常';
|
updateParams.testFinal = '正常';
|
||||||
|
resultType = 'normal'; // 现在在外部作用域中定义
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error === 'cancel') {
|
if (error === 'cancel') {
|
||||||
// 用户点击取消(异常)
|
// 用户点击取消(异常)
|
||||||
updateParams.status = '5';
|
updateParams.status = '5';
|
||||||
updateParams.progress = 100;
|
updateParams.progress = 100;
|
||||||
updateParams.testFinal = '异常';
|
updateParams.testFinal = '异常';
|
||||||
|
resultType = 'abnormal'; // 现在在外部作用域中定义
|
||||||
} else {
|
} else {
|
||||||
// 关闭弹窗,不执行操作
|
// 关闭弹窗,不执行操作
|
||||||
return;
|
return;
|
||||||
@ -887,6 +896,8 @@ const handleAction = async (task) => {
|
|||||||
case '1': // 待执行 → 开始执行(状态改为4)
|
case '1': // 待执行 → 开始执行(状态改为4)
|
||||||
updateParams.status = '4';
|
updateParams.status = '4';
|
||||||
updateParams.progress = 10; // 初始进度10%
|
updateParams.progress = 10; // 初始进度10%
|
||||||
|
// 设置开始时间为当前时间
|
||||||
|
updateParams.planBeginTime = new Date().toISOString().slice(0, 16).replace('T', ' ');
|
||||||
break;
|
break;
|
||||||
case '2': // 已延期 → 重新安排(状态改为1,重置时间)
|
case '2': // 已延期 → 重新安排(状态改为1,重置时间)
|
||||||
updateParams.status = '1';
|
updateParams.status = '1';
|
||||||
@ -904,6 +915,30 @@ const handleAction = async (task) => {
|
|||||||
const response = await updatesyrenwu(updateParams);
|
const response = await updatesyrenwu(updateParams);
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
ElMessage.success(`任务${task.actionText}成功`);
|
ElMessage.success(`任务${task.actionText}成功`);
|
||||||
|
|
||||||
|
// 只有在接口调用成功后才设置时间
|
||||||
|
if (task.status === '4') {
|
||||||
|
// 获取最新的任务详情,确保包含所有字段
|
||||||
|
const latestTaskDetails = await getTaskDetails(task.id);
|
||||||
|
if (latestTaskDetails) {
|
||||||
|
// 创建包含所有字段的新参数对象
|
||||||
|
const timeUpdateParams = {
|
||||||
|
...latestTaskDetails,
|
||||||
|
id: task.id
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据结果类型设置相应的时间(现在resultType已在作用域内)
|
||||||
|
if (resultType === 'normal') {
|
||||||
|
timeUpdateParams.planFinishTime = new Date().toISOString().slice(0, 16).replace('T', ' ');
|
||||||
|
} else if (resultType === 'abnormal') {
|
||||||
|
timeUpdateParams.failTime = new Date().toISOString().slice(0, 16).replace('T', ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再次调用接口更新时间
|
||||||
|
await updatesyrenwu(timeUpdateParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getTaskList(); // 刷新任务列表
|
getTaskList(); // 刷新任务列表
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(`任务${task.actionText}失败:` + response.msg);
|
ElMessage.error(`任务${task.actionText}失败:` + response.msg);
|
||||||
@ -1010,10 +1045,10 @@ const handleSaveTask = async () => {
|
|||||||
status: '1', // 初始状态:待执行(必需)
|
status: '1', // 初始状态:待执行(必需)
|
||||||
testPlanId: createTaskForm.value.relatedPlan, // 关联计划ID(必需)
|
testPlanId: createTaskForm.value.relatedPlan, // 关联计划ID(必需)
|
||||||
testSetting: '', // 测试设置
|
testSetting: '', // 测试设置
|
||||||
planBeginTime: createTaskForm.value.timeRange[0], // 计划开始时间
|
planBeginTime: '', // 计划开始时间(新增时为空)
|
||||||
progress: 0, // 初始进度0%
|
progress: 0, // 初始进度0%
|
||||||
failReason: '',
|
failReason: '',
|
||||||
failTime: now.toISOString(),
|
failTime: '', // 失败时间(新增时为空)
|
||||||
failPhase: 0,
|
failPhase: 0,
|
||||||
faileAnalyze: '',
|
faileAnalyze: '',
|
||||||
faileTips: '',
|
faileTips: '',
|
||||||
@ -1021,8 +1056,8 @@ const handleSaveTask = async () => {
|
|||||||
testFinal: '',
|
testFinal: '',
|
||||||
finalInfo: '',
|
finalInfo: '',
|
||||||
pauseFor: '',
|
pauseFor: '',
|
||||||
pauseTime: now.toISOString(),
|
pauseTime: '', // 暂停时间(新增时为空)
|
||||||
planFinishTime: createTaskForm.value.timeRange[1], // 计划完成时间
|
planFinishTime: '', // 计划完成时间(新增时为空)
|
||||||
nodeIds: nodeIds // 步骤节点ID数组
|
nodeIds: nodeIds // 步骤节点ID数组
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1114,6 +1149,18 @@ onMounted(() => {
|
|||||||
const pagedTasks = computed(() => {
|
const pagedTasks = computed(() => {
|
||||||
return tasks.value;
|
return tasks.value;
|
||||||
});
|
});
|
||||||
|
// 获取任务状态对应的CSS类
|
||||||
|
const getTaskStatusClass = (status) => {
|
||||||
|
const statusStr = status?.toString() || '';
|
||||||
|
const statusMap = {
|
||||||
|
'1': 'status-pending',
|
||||||
|
'2': 'status-delayed',
|
||||||
|
'3': 'status-failed',
|
||||||
|
'4': 'status-running',
|
||||||
|
'5': 'status-completed'
|
||||||
|
};
|
||||||
|
return statusMap[statusStr] || 'status-pending';
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -1234,27 +1281,6 @@ const pagedTasks = computed(() => {
|
|||||||
background-color: #52c41a;
|
background-color: #52c41a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 自定义步骤条样式覆盖 */
|
|
||||||
.custom-steps .el-step__description {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-group {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-title {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #1d2129;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
border-bottom: 1px solid #f0f2f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 卡片悬停效果 */
|
/* 卡片悬停效果 */
|
||||||
.task-card:hover {
|
.task-card:hover {
|
||||||
transform: translateY(-3px);
|
transform: translateY(-3px);
|
||||||
@ -1393,22 +1419,6 @@ const pagedTasks = computed(() => {
|
|||||||
color: #165dff;
|
color: #165dff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.start-btn,
|
|
||||||
.report-btn {
|
|
||||||
background-color: #165dff;
|
|
||||||
border-color: #165dff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reschedule-btn {
|
|
||||||
background-color: #ff7d00;
|
|
||||||
border-color: #ff7d00;
|
|
||||||
}
|
|
||||||
|
|
||||||
.complete-btn {
|
|
||||||
background-color: #00b42a;
|
|
||||||
border-color: #00b42a;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 分页区域样式 */
|
/* 分页区域样式 */
|
||||||
.pagination-section {
|
.pagination-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -1536,10 +1546,6 @@ const pagedTasks = computed(() => {
|
|||||||
color: #e6a23c;
|
color: #e6a23c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-running {
|
|
||||||
color: #409eff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-completed {
|
.status-completed {
|
||||||
color: #67c23a;
|
color: #67c23a;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="operation-inspection">
|
<div class="operation-inspection">
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -8,7 +8,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<el-button type="primary" class="export-btn">筛选</el-button>
|
<el-button type="primary" class="export-btn">筛选</el-button>
|
||||||
@ -127,14 +127,14 @@
|
|||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
<div class="flex justify-between text-sm mb-1">
|
||||||
<span class="text-gray-600">完成率</span>
|
<span class="text-gray-600">巡检完成率</span>
|
||||||
<span class="font-medium text-gray-800">{{ completionRate }}%</span>
|
<span class="font-medium text-gray-800">{{ completionRate }}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
||||||
<div class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: completionRate + '%' }"></div>
|
<div class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: completionRate + '%' }"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<!-- <div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
<div class="flex justify-between text-sm mb-1">
|
||||||
<span class="text-gray-600">解决率</span>
|
<span class="text-gray-600">解决率</span>
|
||||||
<span class="font-medium text-gray-800">{{ resolutionRate }}%</span>
|
<span class="font-medium text-gray-800">{{ resolutionRate }}%</span>
|
||||||
@ -142,10 +142,10 @@
|
|||||||
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
||||||
<div class="bg-red-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: resolutionRate + '%' }"></div>
|
<div class="bg-red-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: resolutionRate + '%' }"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> -->
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
<div class="flex justify-between text-sm mb-1">
|
||||||
<span class="text-gray-600">及时率</span>
|
<span class="text-gray-600">解决效率</span>
|
||||||
<span class="font-medium text-gray-800">{{ timelinessRate }}%</span>
|
<span class="font-medium text-gray-800">{{ timelinessRate }}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
||||||
@ -161,65 +161,8 @@
|
|||||||
<!-- 发现问题种类 -->
|
<!-- 发现问题种类 -->
|
||||||
<div class="py-4">
|
<div class="py-4">
|
||||||
<h3 class="section-title">发现问题种类</h3>
|
<h3 class="section-title">发现问题种类</h3>
|
||||||
<div class="space-y-4">
|
<!-- 柱状图容器 -->
|
||||||
<div>
|
<div id="problemTypesChart" class="bar-chart-container"></div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
|
||||||
<span class="text-gray-600">温度异常率</span>
|
|
||||||
<span class="text-gray-500">{{ problemTypes.temperature }}%</span>
|
|
||||||
</div>
|
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
|
||||||
<div
|
|
||||||
class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out"
|
|
||||||
:style="{ width: problemTypes.temperature + '%' }"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="flex justify-between text-sm mb-1">
|
|
||||||
<span class="text-gray-600">内存使用率</span>
|
|
||||||
<span class="text-gray-500">{{ problemTypes.memory }}%</span>
|
|
||||||
</div>
|
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
|
||||||
<div
|
|
||||||
class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out"
|
|
||||||
:style="{ width: problemTypes.memory + '%' }"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="flex justify-between text-sm mb-1">
|
|
||||||
<span class="text-gray-600">CPU负载</span>
|
|
||||||
<span class="text-gray-500">{{ problemTypes.cpu }}%</span>
|
|
||||||
</div>
|
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
|
||||||
<div class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: problemTypes.cpu + '%' }"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="flex justify-between text-sm mb-1">
|
|
||||||
<span class="text-gray-600">响应时间</span>
|
|
||||||
<span class="text-gray-500">{{ problemTypes.responseTime }}%</span>
|
|
||||||
</div>
|
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
|
||||||
<div
|
|
||||||
class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out"
|
|
||||||
:style="{ width: problemTypes.responseTime + '%' }"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="flex justify-between text-sm mb-1">
|
|
||||||
<span class="text-gray-600">磁盘空间状态</span>
|
|
||||||
<span class="text-gray-500">{{ problemTypes.diskSpace }}%</span>
|
|
||||||
</div>
|
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
|
||||||
<div
|
|
||||||
class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out"
|
|
||||||
:style="{ width: problemTypes.diskSpace + '%' }"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -388,16 +331,17 @@ const avgCompletionTime = ref('45分钟');
|
|||||||
|
|
||||||
// 问题类型数据
|
// 问题类型数据
|
||||||
const problemTypes = ref({
|
const problemTypes = ref({
|
||||||
temperature: 85, // 温度异常率
|
temperature: 0, // 温度异常数量
|
||||||
memory: 62, // 内存使用率
|
memory: 0, // 内存使用率问题数量
|
||||||
cpu: 45, // CPU负载
|
cpu: 0, // CPU负载问题数量
|
||||||
responseTime: 30, // 响应时间
|
responseTime: 0, // 响应时间问题数量
|
||||||
diskSpace: 15 // 磁盘空间状态
|
diskSpace: 0 // 磁盘空间问题数量
|
||||||
});
|
});
|
||||||
|
|
||||||
// ECharts 饼图相关
|
// ECharts 图表相关
|
||||||
const pieChartRef = ref(null);
|
const pieChartRef = ref(null);
|
||||||
let pieChart = null;
|
let pieChart = null;
|
||||||
|
let barChart = null;
|
||||||
|
|
||||||
// 计算平均完成度
|
// 计算平均完成度
|
||||||
const averageRate = computed(() => (completionRate.value + resolutionRate.value + timelinessRate.value) / 3);
|
const averageRate = computed(() => (completionRate.value + resolutionRate.value + timelinessRate.value) / 3);
|
||||||
@ -426,7 +370,7 @@ const initPieChart = () => {
|
|||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: '进度指标',
|
name: '指标对比',
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
radius: ['40%', '70%'],
|
radius: ['40%', '70%'],
|
||||||
avoidLabelOverlap: false,
|
avoidLabelOverlap: false,
|
||||||
@ -442,20 +386,15 @@ const initPieChart = () => {
|
|||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
fontSize: 40,
|
fontSize: 40,
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold'
|
||||||
formatter: function (params) {
|
|
||||||
// 鼠标悬停时显示当前指标的百分比
|
|
||||||
return params.value + '%';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
labelLine: {
|
labelLine: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
data: [
|
data: [
|
||||||
{ value: completionRate.value, name: '完成率', itemStyle: { color: '#5470c6' } },
|
{ value: completionRate.value, name: '巡检完成率', itemStyle: { color: '#409eff' } },
|
||||||
{ value: resolutionRate.value, name: '解决率', itemStyle: { color: '#f56c6c' } },
|
{ value: timelinessRate.value, name: '解决效率', itemStyle: { color: '#67c23a' } }
|
||||||
{ value: timelinessRate.value, name: '及时率', itemStyle: { color: '#67c23a' } }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -506,11 +445,7 @@ const fetchDashboardData = async () => {
|
|||||||
// 构建查询参数
|
// 构建查询参数
|
||||||
const queryParams = {
|
const queryParams = {
|
||||||
projectId: 1,
|
projectId: 1,
|
||||||
type: type,
|
type: type
|
||||||
status: filterStatus.value !== 'all' ? filterStatus.value : undefined,
|
|
||||||
inspectionType: filterType.value !== 'all' ? filterType.value : undefined,
|
|
||||||
startTime: dateRange.value.length > 0 ? dateRange.value[0] : undefined,
|
|
||||||
endTime: dateRange.value.length > 0 ? dateRange.value[1] : undefined
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 调用接口获取数据
|
// 调用接口获取数据
|
||||||
@ -526,22 +461,26 @@ const fetchDashboardData = async () => {
|
|||||||
solvedProblems.value = data.solvedProblemCount || 0;
|
solvedProblems.value = data.solvedProblemCount || 0;
|
||||||
avgCompletionTime.value = data.averageCompletionTime ? `${data.averageCompletionTime}分钟` : '0分钟';
|
avgCompletionTime.value = data.averageCompletionTime ? `${data.averageCompletionTime}分钟` : '0分钟';
|
||||||
|
|
||||||
// 计算完成率、解决率、及时率
|
// 使用接口返回的xjwcl(巡检完成率)和jjxl(解决效率)
|
||||||
completionRate.value = data.finishInspectionCount && data.finishInspectionCount > 0 ? Math.round(Math.random() * 30 + 60) : 0;
|
completionRate.value = data.xjwcl ? parseFloat(data.xjwcl) : 0;
|
||||||
resolutionRate.value = data.solvedProblemCount && data.problemCount ? Math.round((data.solvedProblemCount / data.problemCount) * 100) : 0;
|
timelinessRate.value = data.jjxl ? parseFloat(data.jjxl) : 0;
|
||||||
timelinessRate.value = data.finishInspectionCount && data.finishInspectionCount > 0 ? Math.round(Math.random() * 30 + 50) : 0;
|
|
||||||
|
|
||||||
// 更新问题类型数据
|
// 由于接口不再返回解决率,将其设置为0或保持原值
|
||||||
|
resolutionRate.value = 0;
|
||||||
|
|
||||||
|
// 更新问题类型数据 - 直接使用接口返回的数值,不再计算为百分比
|
||||||
problemTypes.value = {
|
problemTypes.value = {
|
||||||
temperature: data.sbyxzt ? Math.min(100, Math.round(data.sbyxzt * 5)) : 0, // 设备运行状态映射为温度异常
|
temperature: data.sbyxzt || 0, // 设备运行状态类型问题数量
|
||||||
memory: data.ncsyl ? Math.min(100, data.ncsyl * 10) : 0, // 内存使用率
|
memory: data.ncsyl || 0, // 内存使用率类型问题数量
|
||||||
cpu: Math.round(Math.random() * 50 + 20), // CPU负载(模拟数据)
|
cpu: data.fwzt || 0, // 服务状态类型问题数量
|
||||||
responseTime: data.xysj ? Math.min(100, data.xysj * 5) : 0, // 响应时间
|
responseTime: data.xysj || 0, // 响应时间类型问题数量
|
||||||
diskSpace: data.cpsyl ? Math.min(100, data.cpsyl * 8) : 0 // 磁盘使用率
|
diskSpace: data.cpsyl || 0 // 磁盘使用率类型问题数量
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新饼图
|
// 更新饼图
|
||||||
initPieChart();
|
initPieChart();
|
||||||
|
// 更新柱状图
|
||||||
|
initBarChart();
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(response.msg || '获取数据失败');
|
ElMessage.error(response.msg || '获取数据失败');
|
||||||
}
|
}
|
||||||
@ -551,17 +490,115 @@ const fetchDashboardData = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 页面加载时获取数据
|
// 页面加载时直接获取数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchDashboardData();
|
fetchDashboardData();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 初始化柱状图
|
||||||
|
const initBarChart = () => {
|
||||||
|
const chartDom = document.getElementById('problemTypesChart');
|
||||||
|
if (!chartDom) return;
|
||||||
|
|
||||||
|
// 销毁旧实例
|
||||||
|
if (barChart) {
|
||||||
|
barChart.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新实例
|
||||||
|
barChart = echarts.init(chartDom);
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'shadow'
|
||||||
|
},
|
||||||
|
formatter: function (params) {
|
||||||
|
return params[0].name + ': ' + params[0].value + '个';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '5%',
|
||||||
|
right: '5%',
|
||||||
|
bottom: '10%',
|
||||||
|
top: '5%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'value',
|
||||||
|
name: '问题数量',
|
||||||
|
axisLabel: {
|
||||||
|
formatter: '{value}个'
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: ['温度异常', '内存使用率', 'CPU负载', '响应时间', '磁盘空间'],
|
||||||
|
axisLabel: {
|
||||||
|
interval: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '问题数量',
|
||||||
|
type: 'bar',
|
||||||
|
barWidth: '40%',
|
||||||
|
data: [
|
||||||
|
problemTypes.value.temperature,
|
||||||
|
problemTypes.value.memory,
|
||||||
|
problemTypes.value.cpu,
|
||||||
|
problemTypes.value.responseTime,
|
||||||
|
problemTypes.value.diskSpace
|
||||||
|
],
|
||||||
|
itemStyle: {
|
||||||
|
color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [
|
||||||
|
{ offset: 0, color: '#5470c6' },
|
||||||
|
{ offset: 1, color: '#91cc75' }
|
||||||
|
]),
|
||||||
|
borderRadius: [0, 4, 4, 0]
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'right',
|
||||||
|
formatter: '{c}个'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
barChart.setOption(option);
|
||||||
|
|
||||||
|
// 响应式处理
|
||||||
|
const handleResize = () => {
|
||||||
|
if (barChart) {
|
||||||
|
barChart.resize();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
|
||||||
|
// 组件卸载时移除事件监听
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 组件卸载时销毁图表实例
|
// 组件卸载时销毁图表实例
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
if (pieChart) {
|
if (pieChart) {
|
||||||
pieChart.dispose();
|
pieChart.dispose();
|
||||||
pieChart = null;
|
pieChart = null;
|
||||||
}
|
}
|
||||||
|
if (barChart) {
|
||||||
|
barChart.dispose();
|
||||||
|
barChart = null;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 导航方法
|
// 导航方法
|
||||||
@ -802,6 +839,17 @@ const handleInspectionManagement3 = () => {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 柱状图容器 */
|
||||||
|
.bar-chart-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 350px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: #fafafa;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
/* 区域标题 */
|
/* 区域标题 */
|
||||||
.section-title {
|
.section-title {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="inspection-tasks">
|
<div class="inspection-tasks">
|
||||||
<div class="navigation-tabs">
|
<!-- <div class="navigation-tabs">
|
||||||
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
|
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
@ -9,7 +9,7 @@
|
|||||||
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- 选项卡 -->
|
<!-- 选项卡 -->
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
@ -133,7 +133,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 添加新任务弹窗 -->
|
<!-- 添加新任务弹窗 -->
|
||||||
<el-dialog v-model="createTaskDialogVisible" title="添加新任务" width="700px" :before-close="handleCancelCreateTask">
|
<el-dialog v-model="createTaskDialogVisible" title="添加新任务" width="750px" :before-close="handleCancelCreateTask">
|
||||||
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="80px">
|
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="80px">
|
||||||
<el-form-item label="任务名称" prop="taskName">
|
<el-form-item label="任务名称" prop="taskName">
|
||||||
<el-input v-model="createTaskForm.taskName" placeholder="输入任务名称" />
|
<el-input v-model="createTaskForm.taskName" placeholder="输入任务名称" />
|
||||||
@ -202,7 +202,7 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="问题类型" prop="problemType">
|
<!-- <el-form-item label="问题类型" prop="problemType">
|
||||||
<el-select v-model="createTaskForm.problemType" placeholder="选择问题类型">
|
<el-select v-model="createTaskForm.problemType" placeholder="选择问题类型">
|
||||||
<el-option label="磁盘使用率" value="1" />
|
<el-option label="磁盘使用率" value="1" />
|
||||||
<el-option label="内存使用率" value="2" />
|
<el-option label="内存使用率" value="2" />
|
||||||
@ -210,7 +210,7 @@
|
|||||||
<el-option label="响应时间" value="4" />
|
<el-option label="响应时间" value="4" />
|
||||||
<el-option label="设备运行状态" value="5" />
|
<el-option label="设备运行状态" value="5" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
|
|
||||||
<!-- 步骤条 -->
|
<!-- 步骤条 -->
|
||||||
<el-form-item label="执行步骤" class="form-item" style="width: 100%">
|
<el-form-item label="执行步骤" class="form-item" style="width: 100%">
|
||||||
@ -387,7 +387,7 @@
|
|||||||
<div v-if="node.remark" class="step-remark">备注:{{ node.remark }}</div>
|
<div v-if="node.remark" class="step-remark">备注:{{ node.remark }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-status" :class="getStatusClass(node.status)">
|
<div class="step-status" :class="getStatusClass(node.status)">
|
||||||
{{ getStepStatusText(node.status) }}
|
{{ node.status === '2' ? '未完成' : '已完成' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -543,7 +543,10 @@ const getTaskList = async () => {
|
|||||||
const params = {
|
const params = {
|
||||||
pageSize: pageSize.value,
|
pageSize: pageSize.value,
|
||||||
pageNum: currentPage.value,
|
pageNum: currentPage.value,
|
||||||
personId: 1
|
personId: 1,
|
||||||
|
taskType: taskStatus.value || undefined, // 任务状态
|
||||||
|
planType: planType.value || undefined, // 计划类型
|
||||||
|
personName: executor.value || undefined // 执行人
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await xjrenwulist(params);
|
const response = await xjrenwulist(params);
|
||||||
@ -674,7 +677,7 @@ const createTaskForm = ref({
|
|||||||
relatedPlan: '',
|
relatedPlan: '',
|
||||||
executor: '',
|
executor: '',
|
||||||
taskType: '1', // 默认待执行
|
taskType: '1', // 默认待执行
|
||||||
problemType: '',
|
// problemType: '',
|
||||||
steps: [{ name: '', intendedPurpose: '', intendedTime: '' }] // 任务步骤数组
|
steps: [{ name: '', intendedPurpose: '', intendedTime: '' }] // 任务步骤数组
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -806,6 +809,7 @@ const handleSaveTask = async () => {
|
|||||||
|
|
||||||
createTime: new Date().toISOString(),
|
createTime: new Date().toISOString(),
|
||||||
updateTime: new Date().toISOString(),
|
updateTime: new Date().toISOString(),
|
||||||
|
startTime: new Date().toISOString().slice(0, 19).replace('T', ' '),
|
||||||
params: {
|
params: {
|
||||||
property1: 'string',
|
property1: 'string',
|
||||||
property2: 'string'
|
property2: 'string'
|
||||||
@ -820,7 +824,7 @@ const handleSaveTask = async () => {
|
|||||||
personId: createTaskForm.value.executor !== 'all' ? createTaskForm.value.executor : 0,
|
personId: createTaskForm.value.executor !== 'all' ? createTaskForm.value.executor : 0,
|
||||||
taskProgress: 0,
|
taskProgress: 0,
|
||||||
taskType: createTaskForm.value.taskType,
|
taskType: createTaskForm.value.taskType,
|
||||||
problemType: createTaskForm.value.problemType,
|
// problemType: createTaskForm.value.problemType,
|
||||||
nodeIds: nodeIds // 添加步骤ID字符串,与工单列表页面保持一致
|
nodeIds: nodeIds // 添加步骤ID字符串,与工单列表页面保持一致
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -841,7 +845,7 @@ const handleSaveTask = async () => {
|
|||||||
relatedPlan: '',
|
relatedPlan: '',
|
||||||
executor: '',
|
executor: '',
|
||||||
taskType: '1',
|
taskType: '1',
|
||||||
problemType: '',
|
// problemType: '',
|
||||||
steps: [{ name: '', intendedPurpose: '', intendedTime: '' }]
|
steps: [{ name: '', intendedPurpose: '', intendedTime: '' }]
|
||||||
};
|
};
|
||||||
// 重新获取任务列表
|
// 重新获取任务列表
|
||||||
@ -935,7 +939,7 @@ const handleCancelCreateTask = () => {
|
|||||||
relatedPlan: '',
|
relatedPlan: '',
|
||||||
executor: '',
|
executor: '',
|
||||||
taskType: '1',
|
taskType: '1',
|
||||||
problemType: '',
|
// problemType: '',
|
||||||
steps: [{ name: '', intendedPurpose: '', intendedTime: '' }]
|
steps: [{ name: '', intendedPurpose: '', intendedTime: '' }]
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user