From db9e2e55ea8918f37ca9851295b15dbe5e770b8b Mon Sep 17 00:00:00 2001 From: dhr <2216804034@qq.com> Date: Mon, 29 Sep 2025 15:18:50 +0800 Subject: [PATCH] 0929 --- src/views/zhinengxunjian/qiangxiujilu.vue | 96 +++-- src/views/zhinengxunjian/zhixingjilu.vue | 475 ++++++++++++++++++++-- 2 files changed, 513 insertions(+), 58 deletions(-) diff --git a/src/views/zhinengxunjian/qiangxiujilu.vue b/src/views/zhinengxunjian/qiangxiujilu.vue index 160e252..a49d7ab 100644 --- a/src/views/zhinengxunjian/qiangxiujilu.vue +++ b/src/views/zhinengxunjian/qiangxiujilu.vue @@ -64,7 +64,9 @@

本月抢修总数

{{ isCardLoading ? '加载中...' : statisticsData.totalCount }}

-

较上月:{{ statisticsData.monthChange }}

+

+ 较上月{{ statisticsData.monthChangeClass === 'warning' ? '无增长' : ':' + statisticsData.monthChange }} +

本月抢修总数 @@ -75,7 +77,9 @@

平均抢修时长

{{ isCardLoading ? '加载中...' : statisticsData.avgDuration }}

-

较上月:{{ statisticsData.durationChange }}

+

+ 较上月{{ statisticsData.durationChangeClass === 'warning' ? '无增长' : ':' + statisticsData.durationChange }} +

平均抢修时长 @@ -97,7 +101,9 @@

按时完成率

{{ isCardLoading ? '加载中...' : statisticsData.completionRate }}

-

{{ statisticsData.rateChange }}

+

+ {{ statisticsData.rateChangeClass === 'warning' ? '较上月无增长' : statisticsData.rateChange }} +

按时完成率 @@ -586,15 +592,33 @@ const getStatisticsData = async () => { const res = await qiangxiuRecord({ projectId: 1 }); if (res && res.code === 200) { - // 更新统计卡片数据 + // API返回的实际数据在data字段中 + const data = res.data || {}; + + // 更新统计卡片数据 - 映射新的API返回字段 + // 解析百分比数据并添加判断逻辑 + const bxsPercent = parseFloat(data.bxsjszzzl) || 0; + const clscPercent = parseFloat(data.clscjszzzl) || 0; + const wclPercent = parseFloat(data.wcljszzzl) || 0; + + // 判断并设置变化率样式类 + const getChangeClass = (percent) => { + if (percent > 100) return 'up'; + if (percent < 100 && percent !== 0) return 'down'; + return 'warning'; // 等于100或0时显示为灰色(无变化) + }; + statisticsData.value = { - totalCount: res.totalCount || 0, - avgDuration: res.avgDuration || '0分钟', - pendingCount: res.pendingCount || 0, - completionRate: res.completionRate || '0%', - monthChange: res.monthChange || '+0%', - durationChange: res.durationChange || '-0分钟', - rateChange: res.rateChange || '+0%' + totalCount: data.byzbxs || 0, // 本月报修总数 + avgDuration: `${data.pjclsc || 0}分钟`, // 平均处理时长 + pendingCount: data.dclbx || 0, // 待处理报修 + completionRate: `${data.wcl || 0}%`, // 完成率 + monthChange: `${bxsPercent > 0 ? '+' : ''}${bxsPercent}%`, // 报修数较上月变化 + monthChangeClass: getChangeClass(bxsPercent), // 报修数变化率样式类 + durationChange: `${clscPercent > 0 ? '+' : '-'}${Math.abs(clscPercent)}分钟`, // 处理时长较上月变化 + durationChangeClass: getChangeClass(clscPercent), // 处理时长变化率样式类 + rateChange: `${wclPercent > 0 ? '+' : ''}${wclPercent}%`, // 完成率较上月变化 + rateChangeClass: getChangeClass(wclPercent) // 完成率变化率样式类 }; } else { ElMessage.error(`获取统计数据失败:${res?.msg || '未知错误'}`); @@ -1122,7 +1146,7 @@ const handleInspectionManagement2 = () => { } .stat-trend.warning { - color: #fa8c16; + color: #999; } .stat-icon { @@ -1210,39 +1234,53 @@ const handleInspectionManagement2 = () => { } .status-tag { - padding: 2px 8px; - border-radius: 4px; + padding: 4px 10px; + border-radius: 6px; font-size: 12px; + font-weight: 500; } -.status-tag.processing { +.status-processing { background-color: #fffbe6; - color: #faad14; - border: 1px solid #fff1b8; + color: #fa8c16; + border: 1px solid #ffe58f; } -.status-tag.completed { - background-color: #f0f9eb; +.status-completed { + background-color: #f6ffed; color: #52c41a; - border: 1px solid #e1f3d8; + border: 1px solid #b7eb8f; +} + +.status-pending { + background-color: #e6f7ff; + color: #1677ff; + border: 1px solid #91d5ff; } .priority-tag { - padding: 2px 8px; - border-radius: 4px; + padding: 4px 10px; + border-radius: 6px; font-size: 12px; + font-weight: 500; } -.priority-tag.urgent { - background-color: #ffebe6; +.priority-urgent { + background-color: #fff2f0; color: #ff4d4f; border: 1px solid #ffccc7; } -.priority-tag.normal { +.priority-normal { background-color: #e6f7ff; - color: #1890ff; - border: 1px solid #b3d8ff; + color: #1677ff; + border: 1px solid #91d5ff; +} + +.priority-fatal { + background-color: #fff2f0; + color: #ff4d4f; + border: 1px solid #ffccc7; } .detail-btn { @@ -1253,6 +1291,10 @@ const handleInspectionManagement2 = () => { color: #fa8c16; } +.evaluate-btn { + color: #52c41a; +} + /* 分页区域样式 */ .pagination-section { display: flex; diff --git a/src/views/zhinengxunjian/zhixingjilu.vue b/src/views/zhinengxunjian/zhixingjilu.vue index c58148a..d7185e3 100644 --- a/src/views/zhinengxunjian/zhixingjilu.vue +++ b/src/views/zhinengxunjian/zhixingjilu.vue @@ -83,26 +83,54 @@
- -
-
- - - + +
+ +
+ +
+ +
+ +
+
+
+
{{ step.code || index + 1 }}
+
+
+
+
+ + +
+
+
+
{{ step.code || index + 1 }}
+
{{ step.name }}
+
+
+
+ + {{ step.executor || (step.getOrderPersonVo && step.getOrderPersonVo.userName) || '待分配' }} +
+ +
+ + 预期目的:{{ step.intendedPurpose || '-' }} +
+
+
@@ -612,7 +640,8 @@ const updateCurrentTrackedOrder = () => { intendedTime: node.intendedTime, finishTime: node.finishTime, intendedPurpose: node.intendedPurpose || '-', - remark: node.remark || '' + remark: node.remark || '', + status: node.status || '' // 添加status字段 })); } else { // 如果nodes数组为空,创建一些默认的步骤数据 @@ -620,13 +649,12 @@ const updateCurrentTrackedOrder = () => { } // 设置当前激活步骤索引 - // 如果有实际的完成时间,我们可以基于此设置激活步骤 - // 否则默认设置为第一个步骤 + // 根据status字段判断,status='1'表示完成,status='2'表示未完成,status='3'表示失败 activeStepIndex.value = 0; // 检查是否有已完成的步骤,如果有,将激活步骤设置为最后一个已完成步骤的下一个 for (let i = trackingSteps.value.length - 1; i >= 0; i--) { - if (trackingSteps.value[i].finishTime) { + if (trackingSteps.value[i].status === '1') { activeStepIndex.value = Math.min(i + 1, trackingSteps.value.length - 1); break; } @@ -796,8 +824,10 @@ const refreshTrackingSteps = async () => { // 根据索引获取步骤状态 const getStatusByIndex = (index) => { + if (!currentTrackedWorkOrder.value) return 'wait'; + if (index < activeStepIndex.value) { - return 'success'; + return 'finish'; } else if (index === activeStepIndex.value) { return 'process'; } else { @@ -805,6 +835,101 @@ const getStatusByIndex = (index) => { } }; +// 试验记录页面步骤条状态判断 - 重点跟踪区域专用 +const getStepStatusClass = (index) => { + if (!currentTrackedWorkOrder.value) return 'pending'; + + const step = trackingSteps.value[index]; + if (step) { + // 优先根据status字段判断状态 + const status = step.status?.toString() || ''; + + if (status === '1') { + return 'completed'; // 完成状态 - 绿色 + } else if (status === '3') { + return 'delayed'; // 失败状态 - 红色 + } else if (status === '2') { + return 'pending'; // 未完成状态 - 灰色 + } + } + + // fallback到基于索引的判断逻辑 + if (index < activeStepIndex.value) { + return 'completed'; + } else if (index === activeStepIndex.value) { + return 'active'; + } else { + return 'pending'; + } +}; + +// 获取进度线状态 - 重点跟踪区域专用 +const getLineStatusClass = (index) => { + if (!currentTrackedWorkOrder.value) return 'pending'; + + // 进度线状态与前一个步骤状态保持一致 + const prevStepIndex = index; + const prevStep = trackingSteps.value[prevStepIndex]; + + if (prevStep) { + const status = prevStep.status?.toString() || ''; + + if (status === '1') { + return 'completed'; // 前一步骤已完成 - 绿色 + } else if (status === '3') { + return 'delayed'; // 前一步骤失败 - 红色 + } + } + + // fallback到基于索引的判断逻辑 + if (index < activeStepIndex.value) { + return 'completed'; + } else { + return 'pending'; + } +}; + +// 计算进度百分比 +const getProgressPercentage = () => { + if (!currentTrackedWorkOrder.value || trackingSteps.value.length === 0) return 0; + + // 优先使用API返回的progress字段值 + if (currentTrackedWorkOrder.value.progress) { + try { + // 将字符串类型的progress转换为数字 + const progressValue = parseFloat(currentTrackedWorkOrder.value.progress); + // 确保进度值在0-100之间 + return Math.min(Math.max(progressValue, 0), 100); + } catch (error) { + console.warn('解析progress字段失败,使用默认计算逻辑:', error); + // 解析失败时使用原有逻辑 + } + } + + // 计算已完成步骤数 + const completedSteps = trackingSteps.value.filter((step) => step.status === '1').length; + + // 如果没有已完成步骤,但有活跃步骤,则使用活跃步骤的位置 + if (completedSteps === 0 && activeStepIndex.value >= 0) { + return (activeStepIndex.value / trackingSteps.value.length) * 100; + } + + // 计算进度百分比 + const percentage = (completedSteps / trackingSteps.value.length) * 100; + + // 确保最大为100% + return Math.min(percentage, 100); +}; + +// 计算节点位置百分比 +const getNodePosition = (index) => { + if (!currentTrackedWorkOrder.value || trackingSteps.value.length <= 1) return 0; + + // 等距分布节点 + const position = (index / (trackingSteps.value.length - 1)) * 100; + return position; +}; + // 将状态码转换为可读的状态文本 const getStatusText = (statusCode) => { const statusMap = { @@ -1762,10 +1887,6 @@ const handleCloseDetailDialog = () => { transition: all 0.3s ease; } -.step-connector.connector-completed { - background: linear-gradient(to bottom, #52c41a, #73d13d); -} - /* 动画效果 */ @keyframes fadeInUp { from { @@ -3320,13 +3441,299 @@ const handleCloseDetailDialog = () => { position: relative; } +/* 重点跟踪区域进度条样式 */ +.tracking-progress-container { + padding: 20px; + background-color: #fff; +} + +/* 进度条包装器 */ +.progress-bar-wrapper { + position: relative; + height: 40px; + margin-bottom: 30px; + display: flex; + align-items: center; +} + +/* 进度条背景 */ +.progress-bar-background { + position: absolute; + top: 50%; + left: 0; + right: 0; + height: 6px; + background-color: #e5e7eb; + border-radius: 3px; + transform: translateY(-50%); +} + +/* 进度条填充 */ +.progress-bar-fill { + position: absolute; + top: 50%; + left: 0; + height: 6px; + background: linear-gradient(90deg, #00b42a, #95de64); + border-radius: 3px; + transition: width 0.6s ease; + transform: translateY(-50%); +} + +/* 进度条节点容器 */ +.progress-bar-nodes { + position: relative; + width: 100%; + height: 100%; +} + +/* 进度条节点 */ +.progress-node { + position: absolute; + top: 50%; + transform: translate(-50%, -50%); +} + +/* 节点圆圈 */ +.node-circle { + width: 36px; + height: 36px; + border-radius: 50%; + background-color: #fff; + border: 2px solid #e5e7eb; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + transition: all 0.3s ease; + z-index: 2; +} + +/* 节点图标/数字 */ +.node-icon { + font-size: 14px; + font-weight: 600; + color: #6b7280; +} + +/* 步骤信息卡片容器 */ +.progress-steps-info { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + gap: 12px; +} + +/* 单个步骤信息卡片 */ +.step-info-card { + flex: 1; + min-width: 160px; + max-width: 250px; + padding: 12px; + border-radius: 6px; + border: 1px solid #f0f0f0; + background-color: #fff; + transition: all 0.3s ease; +} + +/* 步骤卡片头部 */ +.step-header { + display: flex; + align-items: center; + margin-bottom: 8px; +} + +/* 步骤数字 */ +.step-info-card .step-number { + width: 20px; + height: 20px; + border-radius: 50%; + background-color: #e5e7eb; + color: #6b7280; + display: flex; + align-items: center; + justify-content: center; + font-size: 11px; + font-weight: 600; + margin-right: 6px; +} + +/* 步骤名称 */ +.step-name { + font-size: 16px; + font-weight: 600; + color: #1f2937; +} + +/* 步骤详情 */ +.step-details { + display: flex; + flex-direction: column; + gap: 8px; + font-size: 14px; +} + +.step-details > div { + display: flex; + align-items: center; + color: #6b7280; +} + +.step-details i { + margin-right: 6px; + font-size: 14px; +} + +/* 已完成状态样式 - 绿色 */ +.step-info-card.completed { + border-color: #00b42a; + background-color: #f6ffed; +} + +.step-info-card.completed .step-number { + background-color: #00b42a; + color: white; +} + +.progress-node.completed .node-circle { + border-color: #00b42a; + background-color: #fff; +} + +.progress-node.completed .node-icon { + background-color: #00b42a; + color: white; + border-radius: 50%; + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; +} + +/* 进行中状态样式 */ +.step-info-card.active { + border-color: #165dff; + background-color: #f0f7ff; + box-shadow: 0 4px 12px rgba(22, 93, 255, 0.1); +} + +.step-info-card.active .step-number { + background-color: #165dff; + color: white; +} + +.progress-node.active .node-circle { + border-color: #165dff; + background-color: #fff; + animation: pulse 2s infinite; +} + +.progress-node.active .node-icon { + background-color: #165dff; + color: white; + border-radius: 50%; + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; +} + +/* 待处理状态样式 */ +.step-info-card.pending { + border-color: #e5e7eb; + background-color: #fff; +} + +/* 失败/逾期状态样式 */ +.step-info-card.delayed { + border-color: #ff4d4f; + background-color: #fff2f0; +} + +.step-info-card.delayed .step-number { + background-color: #ff4d4f; + color: white; +} + +.progress-node.delayed .node-circle { + border-color: #ff4d4f; + background-color: #fff; +} + +.progress-node.delayed .node-icon { + background-color: #ff4d4f; + color: white; + border-radius: 50%; + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; +} + +/* 脉冲动画 */ +@keyframes pulse { + 0% { + box-shadow: 0 0 0 0 rgba(22, 93, 255, 0.4); + } + 70% { + box-shadow: 0 0 0 10px rgba(22, 93, 255, 0); + } + 100% { + box-shadow: 0 0 0 0 rgba(22, 93, 255, 0); + } +} + +.tracking-progress-timeline .progress-step.completed .step-number { + background-color: #00b42a; + color: white; +} + +.tracking-progress-timeline .progress-line.completed { + background-color: #00b42a; +} + +.tracking-progress-timeline .progress-step.delayed .step-number { + background-color: #dc2626; + color: white; +} + +.tracking-progress-timeline .progress-line.delayed { + background-color: #dc2626; +} + +.tracking-progress-timeline .step-name { + font-size: 14px; + font-weight: 500; + color: #1f2329; + margin-bottom: 8px; + text-align: center; +} + +.tracking-progress-timeline .step-info { + font-size: 12px; + color: #6b7280; + text-align: center; +} + +.tracking-progress-timeline .step-person-time { + margin-bottom: 4px; +} + +.tracking-progress-timeline .step-purpose { + margin-top: 4px; + line-height: 1.4; +} + .custom-step:hover { transform: translateY(-8px); filter: brightness(1.03); } -/* 步骤连接线 */ -.custom-step:not(:last-child)::after { +/* 步骤连接线 - 默认(进行中) */ +.custom-step:not(:last-child):not(.is-wait)::after { content: ''; position: absolute; top: 32px; @@ -3338,6 +3745,12 @@ const handleCloseDetailDialog = () => { box-shadow: 0 2px 8px rgba(22, 93, 255, 0.3); } +/* 已完成步骤连接线 */ +.custom-step.completed:not(:last-child)::after { + background: linear-gradient(90deg, #00b42a 0%, #95de64 100%); + box-shadow: 0 2px 8px rgba(0, 180, 42, 0.3); +} + /* 待处理步骤连接线 */ .custom-step.is-wait:not(:last-child)::after { background: linear-gradient(90deg, #dcdfe6 0%, #e4e7ed 100%);