Просмотр исходного кода

pms 瑞恒日报 任务计划进度 实际进度

zhangcl 3 недель назад
Родитель
Сommit
34dfcedfbc

+ 5 - 0
src/api/pms/iotrhdailyreport/index.ts

@@ -40,6 +40,11 @@ export const IotRhDailyReportApi = {
     return await request.get({ url: `/pms/iot-rh-daily-report/page`, params })
   },
 
+  // 查询项目任务实际进度列表
+  taskActualProgress: async (params: any) => {
+    return await request.get({ url: `/pms/iot-rh-daily-report/taskActualProgress`, params })
+  },
+
   // 查询瑞恒日报详情
   getIotRhDailyReport: async (id: number) => {
     return await request.get({ url: `/pms/iot-rh-daily-report/get?id=` + id })

+ 124 - 59
src/views/pms/iotprojectinfo/index.vue

@@ -241,19 +241,44 @@
   </ContentWrap>
 
   <!-- Timeline 时间线 Dialog - 已修改为 el-steps -->
-  <el-dialog v-model="timelineDialogVisible" :title="`任务进度 - ${currentTaskRow ? currentTaskRow.wellName : ''}`" :width="dialogWidth">
-    <div v-if="stepsData.length > 0">
-      <el-steps direction="horizontal" :active="currentStepIndex" finish-status="success">
-        <el-step
-          v-for="(step, index) in stepsData"
-          :key="index"
-          :title="step.title"
-          :description="step.description"
-          :status="step.status"
-        />
-      </el-steps>
+  <el-dialog v-model="timelineDialogVisible"
+             :title="`任务进度 - ${currentTaskRow ? currentTaskRow.wellName : ''}`"
+             :width="dialogWidth">
+    <div class="progress-container">
+      <!-- 计划进度 -->
+      <div class="progress-section">
+        <h3 class="progress-title">计划进度</h3>
+        <div v-if="stepsData.length > 0">
+          <el-steps direction="horizontal" :active="currentStepIndex" finish-status="success">
+            <el-step
+              v-for="(step, index) in stepsData"
+              :key="index"
+              :title="step.title"
+              :description="step.description"
+              :status="step.status"
+            />
+          </el-steps>
+        </div>
+        <el-empty v-else description="暂无计划进度数据" :image-size="80" />
+      </div>
+
+      <!-- 实际进度 -->
+      <div class="progress-section">
+        <h3 class="progress-title">实际进度</h3>
+        <div v-if="actualStepsData.length > 0">
+          <el-steps direction="horizontal" :active="actualStepsData.length - 1" finish-status="success">
+            <el-step
+              v-for="(step, index) in actualStepsData"
+              :key="index"
+              :title="step.title"
+              :description="step.description"
+              :status="step.status"
+            />
+          </el-steps>
+        </div>
+        <el-empty v-else description="暂无实际进度数据" :image-size="80" />
+      </div>
     </div>
-    <el-empty v-else description="暂无进度数据" :image-size="100" />
     <template #footer>
       <span class="dialog-footer">
         <el-button @click="timelineDialogVisible = false">关闭</el-button>
@@ -275,6 +300,7 @@ import * as UserApi from "@/api/system/user"; // 引入用户API
 import * as DeptApi from "@/api/system/dept"; // 引入部门API
 import { handleTree } from "@/utils/tree"; // 引入树形处理工具
 import { IotProjectTaskScheduleApi } from '@/api/pms/iotprojecttaskschedule'
+import { IotRhDailyReportApi } from '@/api/pms/iotrhdailyreport'
 import dayjs from 'dayjs' // 引入 dayjs 用于时间格式化
 import { ref, reactive, onMounted, computed, nextTick, watch } from 'vue'
 
@@ -298,6 +324,7 @@ const timelineDialogVisible = ref(false) // 控制时间线弹窗显示
 const currentTaskRow = ref<any>(null) // 当前选中的任务行数据
 
 const stepsData = ref<Array<{title: string, description?: string, status?: string}>>([]) // 步骤数据
+const actualStepsData = ref<Array<{title: string, description?: string, status?: string}>>([]) // 实际步骤数据
 const currentStepIndex = ref(0) // 当前步骤索引
 
 // 表格引用
@@ -570,13 +597,16 @@ const getDeptNames = (deptIds) => {
 
 // 添加计算属性计算对话框宽度
 const dialogWidth = computed(() => {
-  if (stepsData.value.length === 0) return '700px';
+  // if (stepsData.value.length === 0) return '700px';
 
   // 根据步骤数量计算宽度,每个步骤大约需要 200px
-  const baseWidth = stepsData.value.length * 200;
+  const baseWidth = Math.max(
+    stepsData.value.length * 200,
+    actualStepsData.value.length * 200
+  );
 
   // 限制最小和最大宽度
-  const minWidth = 400;
+  const minWidth = 900;
   const maxWidth = window.innerWidth * 0.9; // 最大为视口宽度的90%
 
   // 应用限制
@@ -693,6 +723,7 @@ const openTimelineDialog = async (row: any) => {
   currentTaskRow.value = row
   timelineDialogVisible.value = true
   stepsData.value = [] // 清空旧数据
+  actualStepsData.value = [] // 清空实际进度数据
   currentStepIndex.value = -1 // 初始化为-1,不选中任何步骤
 
   try {
@@ -701,73 +732,57 @@ const openTimelineDialog = async (row: any) => {
       await getTaskScheduleDictOptions()
     }
 
-    // 获取时间线数据
-    const params = { taskId: row.id } // 假设根据 taskId 获取
+    // 获取计划进度数据
+    const params = { taskId: row.id }
     const response = await IotProjectTaskScheduleApi.getIotProjectTaskSchedules(params)
 
+    // 获取实际进度数据
+    const actualProgress = await IotRhDailyReportApi.taskActualProgress(params)
+
+    // 处理计划进度数据
     if (response && response.length > 0) {
-      // 处理数据:转换时间戳、匹配字典label
       const sortedSchedules = response.sort((a, b) => a.status - b.status);
-
-      // 生成步骤数据
       stepsData.value = sortedSchedules.map((item: any) => {
-        // 格式化时间戳 (假设 startTime 是毫秒时间戳)
         const formattedTimestamp = item.startTime ? dayjs(item.startTime).format('YYYY-MM-DD HH:mm') : '时间未设置'
-
-        // 查找 status 对应的字典 label
         const dictItem = taskScheduleDictOptions.value.find(dict => dict.value === item.status)
         const statusLabel = dictItem ? dictItem.label : `未知状态 (${item.status})`
 
         return {
           title: `${formattedTimestamp} ${statusLabel}`,
-          description: '', // 初始为空
-          status: undefined // 初始状态为任何特殊状态
+          description: '',
+          status: undefined
         }
       })
+    } else {
+      stepsData.value = []
+    }
 
-      // 只有当任务有明确状态时才计算当前步骤
-      if (row.status !== null && row.status !== undefined && row.status !== '') {
-        const currentStatus = row.status;
-        let activeIndex = -1;
-
-        // 找到第一个状态大于当前任务状态的计划,当前步骤就是前一个
-        for (let i = 0; i < sortedSchedules.length; i++) {
-          if (currentStatus < sortedSchedules[i].status) {
-            activeIndex = i - 0.5; // 中间状态
-            break;
-          } else if (currentStatus === sortedSchedules[i].status) {
-            activeIndex = i; // 正好在这个节点上
-            break;
-          }
-        }
-
-        // 如果当前状态大于所有计划进度状态,则显示最后一步已完成
-        if (activeIndex === -1 && sortedSchedules.length > 0) {
-          if (currentStatus > sortedSchedules[sortedSchedules.length - 1].status) {
-            activeIndex = sortedSchedules.length;
-          } else {
-            activeIndex = sortedSchedules.length - 1;
-          }
-        }
+    // 处理实际进度数据
+    if (actualProgress && actualProgress.length > 0) {
+      const sortedActualProgress = actualProgress.sort((a, b) =>
+        (a.constructionStartDate || 0) - (b.constructionStartDate || 0)
+      );
 
-        currentStepIndex.value = Math.max(0, activeIndex);
+      actualStepsData.value = sortedActualProgress.map((item: any) => {
+        const formattedTimestamp = item.constructionStartDate ?
+          dayjs(item.constructionStartDate).format('YYYY-MM-DD HH:mm') : '时间未设置'
+        const dictItem = taskScheduleDictOptions.value.find(dict => dict.value === item.constructionStatus)
+        const statusLabel = dictItem ? dictItem.label : `未知状态 (${item.constructionStatus})`
 
-        // 更新步骤数据,设置当前步骤的描述和状态
-        if (currentStepIndex.value >= 0 && currentStepIndex.value < stepsData.value.length) {
-          stepsData.value = stepsData.value.map((step, index) => ({
-            ...step,
-            description: index === currentStepIndex.value ? '当前进度' : '',
-            status: index === currentStepIndex.value ? 'process' : undefined
-          }))
+        return {
+          title: `${formattedTimestamp} ${statusLabel}`,
+          description: '',
+          status: undefined
         }
-      }
+      })
     } else {
-      stepsData.value = []
+      actualStepsData.value = []
     }
   } catch (error) {
     console.error('获取任务进度时间线失败:', error)
     message.error('获取任务进度失败')
     stepsData.value = []
+    actualStepsData.value = []
   }
 }
 
@@ -978,4 +993,54 @@ watch(list, () => {
   text-overflow: clip !important;
 }
 
+/* 进度展示容器样式 */
+.progress-container {
+  display: flex;
+  flex-direction: column;
+  gap: 24px;
+}
+
+.progress-section {
+  border: 1px solid #e6e6e6;
+  border-radius: 8px;
+  padding: 16px;
+  background-color: #fafafa;
+}
+
+.progress-section:first-child {
+  border-color: #409eff;
+  background-color: #f0f7ff;
+}
+
+.progress-section:last-child {
+  border-color: #67c23a;
+  background-color: #f0f9eb;
+}
+
+.progress-title {
+  margin: 0 0 16px 0;
+  font-size: 16px;
+  font-weight: bold;
+  color: #606266;
+}
+
+.progress-section:first-child .progress-title {
+  color: #409eff;
+}
+
+.progress-section:last-child .progress-title {
+  color: #67c23a;
+}
+
+/* 调整空状态显示 */
+:deep(.progress-section .el-empty) {
+  padding: 20px 0;
+}
+
+:deep(.progress-section .el-empty__description) {
+  margin-top: 8px;
+  color: #909399;
+  font-size: 14px;
+}
+
 </style>

+ 2 - 2
src/views/pms/iotrhdailyreport/index.vue

@@ -70,7 +70,7 @@
           label="日期"
           align="center"
           prop="createTime"
-          :formatter="dateFormatter"
+          :formatter="dateFormatter2"
           :width="columnWidths.createTime"
         />
         <el-table-column label="施工队伍" align="center" prop="deptName" :width="columnWidths.deptName"/>
@@ -150,7 +150,7 @@
 </template>
 
 <script setup lang="ts">
-import { dateFormatter } from '@/utils/formatTime'
+import {dateFormatter, dateFormatter2} from '@/utils/formatTime'
 import download from '@/utils/download'
 import { IotRhDailyReportApi, IotRhDailyReportVO } from '@/api/pms/iotrhdailyreport'
 import IotRhDailyReportForm from './IotRhDailyReportForm.vue'