吉安感知网项目-前端
shuishen
2026-01-31 f07efb36894070d4cfcb77ec27ffd017da0bdf54
applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue
@@ -10,22 +10,42 @@
   >
      <div class="content" style="display: flex">
         <div class="processBox" v-if="dialogMode !== 'add' && processList.length">
            <el-timeline class="gd-timeline">
               <el-timeline-item
                  v-for="(activity, index) in processList"
                  :key="index"
                  :icon="Check"
                  :type="index === processList.length - 1 ? 'success' : 'info'"
                  :color="activity.color"
                  :hollow="activity.hollow"
                  :timestamp="activity.createTime"
               >
                  <div class="item-content">
                     <div>{{ activity.operator }}</div>
                     <div class="flowName">{{ activity.flowName }}</div>
            <div class="timeline-wrapper">
               <div v-for="(stage, stageIndex) in processList" :key="stageIndex" class="stage-group">
                  <!-- 大节点 Stage Node -->
                  <div class="stage-node">
                     <div class="stage-icon" :class="{ reached: stage.reached }">
                        <el-icon v-if="stage.reached"><Check /></el-icon>
                        <span v-else class="stage-index">{{ stageIndex + 1 }}</span>
                     </div>
                     <span class="stage-name">{{ stage.stageName }}</span>
                  </div>
               </el-timeline-item>
            </el-timeline>
                  <!-- 小节点 Child Nodes -->
                  <div class="child-list" v-if="stage.child && stage.child.length">
                     <template v-for="(child, childIndex) in stage.child.filter(c => c.reached)">
                        <div v-if="child.reached" :key="childIndex" class="child-node">
                           <div class="child-left">
                              <span class="child-status">{{ child.statusName }}</span>
                           </div>
                           <div class="child-dot"></div>
                           <div class="child-right">
                              <span class="child-operator">{{ child.operator || '-' }}</span>
                              <span class="child-time">{{ child.createTime || '-' }}</span>
                           </div>
                        </div>
                     </template>
                  </div>
                  <!-- 连接线 -->
                  <div
                     class="connector-line"
                     v-if="stageIndex < processList.length - 1"
                     :class="{ reached: stage.reached }"
                  ></div>
               </div>
            </div>
         </div>
         <div class="leftBox">
            <div v-if="dialogReadonly">
@@ -57,6 +77,7 @@
               </el-row>
               <div class="detail-title" :style="{ marginTop: pxToRem(20) }">已选设备</div>
               <el-table class="setHeight gd-dialog-table" ref="deviceTableRef" :data="deviceList" row-key="id">
                  <el-table-column type="index" label="序号" />
                  <el-table-column prop="nickname" label="设备名称" />
                  <el-table-column prop="deviceName" label="设备型号" />
                  <el-table-column prop="devicePayload" label="设备负载" />
@@ -67,7 +88,7 @@
                     <el-table-column prop="patrolTaskName" show-overflow-tooltip label="巡查任务名称" />
                     <el-table-column prop="patrolTaskType" show-overflow-tooltip label="巡查任务类型">
                        <template v-slot="{ row }">
                           {{ getDictLabel(row.patrolTaskType, dictObj.patrolTaskType) }}
                           {{ getDictLabel(row.patrolTaskType, dictObj.workOrderType) }}
                        </template>
                     </el-table-column>
                     <el-table-column prop="taskStatus" show-overflow-tooltip label="任务状态">
@@ -90,6 +111,7 @@
               :disabled="dialogReadonly"
               label-width="90px"
            >
               <div class="detail-title">工单详情</div>
               <el-row>
                  <el-col :span="12">
                     <el-form-item label="工单名称" prop="workOrderName">
@@ -161,7 +183,10 @@
                  </el-col>
               </el-row>
            </el-form>
            <div class="detail-title" :style="{ marginTop: pxToRem(20) }">工单执行范围</div>
            <div class="detail-title" :style="{ marginTop: pxToRem(20) }">
               <span class="required-star" v-if="!dialogReadonly">*</span>
               工单执行范围
            </div>
            <CommonCesiumMap
               ref="mapRef"
               class="gd-cesium"
@@ -175,11 +200,17 @@
            />
         </div>
         <div class="rightBox" v-if="!dialogReadonly">
            <div class="detail-title">推荐设备</div>
            <div class="detail-title">
               <span class="required-star" v-if="!dialogReadonly">*</span>
               推荐设备
            </div>
            <el-table
               :empty-text="(formData.deviceLoadDemand && pointList.length) ? '暂无数据' : '请先选择设备需求并在地图上绘制工单范围'"
               class="separateTable"
               :empty-text="
                  formData.deviceLoadDemand && pointList.length ? '暂无数据' : '请先选择设备需求并在地图上绘制工单范围'
               "
               ref="deviceTableRef"
               :data="(formData.deviceLoadDemand && pointList.length) ? deviceList : []"
               :data="formData.deviceLoadDemand && pointList.length ? deviceList : []"
               row-key="id"
               @selection-change="handleDeviceSelectionChange"
            >
@@ -192,12 +223,8 @@
      </div>
      <template #footer>
         <el-button
            v-if="['11', '21', '23','31', '60'].includes(gdStatus)"
            @click="viewDescription"
            color="#F2F3F5"
         >
            {{ gdStatusObj[gdStatus].reason }}
         <el-button v-if="['11', '21', '23', '31', '60'].includes(gdStatus)" @click="viewDescription" color="#F2F3F5">
            {{ gdStatusObj[gdStatus]?.reason }}
         </el-button>
         <template v-if="!suddenlyEdit">
@@ -211,7 +238,7 @@
            <el-button
               color="#4C34FF"
               @click="requestModification"
               v-if="['20'].includes(gdStatus) && permission.order_applyNegotiation"
               v-if="['20'].includes(gdStatus) && permission.order_applyEdit"
            >
               申请修改
            </el-button>
@@ -238,7 +265,7 @@
         </template>
         <template v-if="permission.order_controlCancel">
            <el-button v-if="gdStatus === '21'" @click="statusChange(6)" color="#F2F3F5">驳回</el-button>
            <el-button v-if="gdStatus === '21'" @click="statusChange(5)" color="#4C34FF">同意</el-button>
            <el-button v-if="gdStatus === '21'" @click="statusChange(5)" color="#4C34FF">通过</el-button>
         </template>
         <el-button v-if="gdStatus === '30' && permission.order_applyNegotiation" @click="addDescription" color="#4C34FF">
            协商修改
@@ -325,14 +352,15 @@
const hasPatrolTaskList = computed(() => ['30', '40', '50', '60'].includes(String(formData.value.workOrderStatus)))
const gdStatusObj = {
   '10': { reason: '驳回原因', operationType: '2' },
   '11': { reason: '驳回原因' },
   '20': { reason: '取消原因', operationType: '3' },
   '10': { reason: '拒单原因', operationType: '2', title: '拒绝接单' },
   '11': { reason: '拒单原因' },
   '20': { reason: '原因', operationType: '3', title: '申请取消' },
   '21': { reason: '取消原因' },
   '23': { reason: '取消原因' },
   '30': { reason: '协商修改原因', operationType: '9' },
   '31': { reason: '协商修改原因' },
   '30': { reason: '修改原因', operationType: '9', title: '协商修改' },
   '31': { reason: '修改原因' },
   '40': { reason: '' },
   '50': { reason: '情况说明', operationType: '11' },
   '50': { reason: '情况说明', operationType: '11', title: '结算' },
   '60': { reason: '情况说明' },
}
@@ -386,6 +414,7 @@
         row: formData.value,
         type: gdStatusObj[gdStatus.value].operationType,
         formLabel: gdStatusObj[gdStatus.value].reason,
         title: gdStatusObj[gdStatus.value]?.title || '新增',
      })
   })
}
@@ -635,14 +664,14 @@
</script>
<style lang="scss" scoped>
.el-table{
.separateTable {
   height: 0;
   flex: 1;
   :deep(){
      .el-scrollbar__view{
   :deep() {
      .el-scrollbar__view {
         height: 100%;
      }
      .el-table__empty-text{
      .el-table__empty-text {
         line-height: normal;
      }
   }
@@ -678,18 +707,148 @@
   }
   .processBox {
      padding: 24px 0;
      padding: 24px 16px;
      width: 312px;
      border: 1px solid #e4e4e4;
      border-radius: 8px;
      overflow: auto;
      background: #fff;
      .item-content {
      .timeline-wrapper {
         padding-left: 100px;
         position: relative;
         .flowName {
            width: 80px;
      }
      .stage-group {
         position: relative;
      }
      // 大节点 - Stage Node
      .stage-node {
         display: flex;
         align-items: center;
         gap: 12px;
         margin-bottom: 8px;
         .stage-icon {
            width: 28px;
            height: 28px;
            border-radius: 50%;
            background: #e0e0e0;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #fff;
            font-size: 14px;
            font-weight: 600;
            flex-shrink: 0;
            position: relative;
            z-index: 2;
            &.reached {
               background: #1a1a2e;
            }
            .el-icon {
               font-size: 16px;
            }
            .stage-index {
               font-size: 12px;
            }
         }
         .stage-name {
            width: 70px;
            text-align: right;
            position: absolute;
            left: -120px;
            top: 0px;
            left: -80px;
            font-family: Roboto, Roboto;
            font-weight: bold;
            font-size: 16px;
            color: rgba(0,0,0,0.85);
         }
      }
      // 小节点 - Child Nodes
      .child-list {
         position: relative;
         left: -52px;
      }
      .child-node {
         display: flex;
         align-items: flex-start;
         position: relative;
         &:last-child::before {
            bottom: 50%;
         }
         .child-left {
            width: 100px;
            flex-shrink: 0;
            text-align: right;
            padding-right: 20px;
            font-family: Source Han Sans CN, Source Han Sans CN;
            font-weight: 400;
            font-size: 14px;
            color: rgba(0,0,0,0.85);
            .child-status {
               white-space: nowrap;
            }
         }
         .child-dot {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background: #1a1a2e;
            flex-shrink: 0;
            position: relative;
            z-index: 2;
            margin-top: 4px;
         }
         .child-right {
            flex: 1;
            padding-left: 12px;
            display: flex;
            flex-direction: column;
            gap: 2px;
            .child-operator {
               font-family: Source Han Sans CN, Source Han Sans CN;
               font-weight: 400;
               font-size: 14px;
               color: rgba(0,0,0,0.85);
            }
            .child-time {
               white-space: nowrap;
               font-family: Source Han Sans CN, Source Han Sans CN;
               font-weight: 400;
               font-size: 14px;
               color: rgba(0,0,0,0.45);
            }
         }
      }
      // 连接线
      .connector-line {
         position: absolute;
         left: 13px;
         width: 2px;
         height: 100%;
         background: #e0e0e0;
         top: 28px;
         z-index: 1;
         &.reached {
            background: #1a1a2e;
         }
      }
   }
@@ -700,4 +859,9 @@
   height: 200px;
   line-height: 200px;
}
.required-star {
   color: #f56c6c;
   margin-right: 4px;
}
</style>