| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | <template> | 
					
						
							|  |  |  |  |   <div> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |     <div class="dispatch-records"> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |       <!-- 顶部导航栏 --> | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |       <!-- <div class="navigation-tabs"> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |         <div class="nav-tab" @click="handleInspection1">待办事项</div> | 
					
						
							|  |  |  |  |         <div class="nav-tab" @click="handleInspection2">巡检管理</div> | 
					
						
							|  |  |  |  |         <div class="nav-tab" @click="handleInspection3">试验管理</div> | 
					
						
							|  |  |  |  |         <div class="nav-tab" @click="handleInspection4">报修管理</div> | 
					
						
							|  |  |  |  |         <div class="nav-tab" @click="handleInspection5">抢修管理</div> | 
					
						
							|  |  |  |  |         <div class="nav-tab active" @click="handleInspection6">工单管理</div> | 
					
						
							|  |  |  |  |         <div class="nav-tab" @click="handleInspection7">运维组织</div> | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |       </div> --> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |       <!-- 选项卡 --> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |       <div class="tabs-wrapper"> | 
					
						
							|  |  |  |  |         <div style="display: flex; align-items: center; gap: 10px"> | 
					
						
							|  |  |  |  |           <el-button type="primary" @click="handleInspectionManagement1">工单列表</el-button> | 
					
						
							|  |  |  |  |           <el-button type="primary" @click="handleInspectionManagement2">派单计划</el-button> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |           <el-button type="primary" @click="handleInspectionManagement3">执行计划</el-button> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |         </div> | 
					
						
							|  |  |  |  |       </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |       <!-- 筛选栏 --> | 
					
						
							|  |  |  |  |       <div class="filter-bar"> | 
					
						
							|  |  |  |  |         <div class="filter-container"> | 
					
						
							| 
									
										
										
										
											2025-09-29 17:17:42 +08:00
										 |  |  |  |           <div class="filter-item"> | 
					
						
							|  |  |  |  |             <el-input v-model="keyword" placeholder="关键字(标题/描述/创建人)" clearable @keyup.enter="handleSearch" /> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |           <div class="filter-item"> | 
					
						
							|  |  |  |  |             <el-select v-model="workOrderType" placeholder="工单类型" clearable> | 
					
						
							|  |  |  |  |               <el-option label="全部类型" value="all"></el-option> | 
					
						
							|  |  |  |  |               <el-option label="维护保养" value="maintenance"></el-option> | 
					
						
							|  |  |  |  |               <el-option label="检查检测" value="inspection"></el-option> | 
					
						
							|  |  |  |  |               <el-option label="安装调试" value="installation"></el-option> | 
					
						
							|  |  |  |  |               <el-option label="升级改造" value="upgrade"></el-option> | 
					
						
							|  |  |  |  |             </el-select> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  |           <div class="filter-item"> | 
					
						
							|  |  |  |  |             <el-select v-model="workOrderStatus" placeholder="全部状态" clearable> | 
					
						
							|  |  |  |  |               <el-option label="全部状态" value="all"></el-option> | 
					
						
							|  |  |  |  |               <el-option label="待派单" value="accepted"></el-option> | 
					
						
							|  |  |  |  |               <el-option label="待处理" value="pending"></el-option> | 
					
						
							|  |  |  |  |               <el-option label="执行中" value="executing"></el-option> | 
					
						
							|  |  |  |  |               <el-option label="已完成" value="completed"></el-option> | 
					
						
							|  |  |  |  |             </el-select> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  |           <div class="filter-item"> | 
					
						
							|  |  |  |  |             <el-select v-model="priority" placeholder="全部优先级" clearable> | 
					
						
							|  |  |  |  |               <el-option label="全部优先级" value="all"></el-option> | 
					
						
							|  |  |  |  |               <el-option label="高" value="high"></el-option> | 
					
						
							|  |  |  |  |               <el-option label="中" value="medium"></el-option> | 
					
						
							|  |  |  |  |               <el-option label="低" value="low"></el-option> | 
					
						
							|  |  |  |  |             </el-select> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  |           <div class="filter-item"> | 
					
						
							|  |  |  |  |             <el-date-picker v-model="createDate" type="date" placeholder="创建日期" value-format="yyyy/MM/dd"></el-date-picker> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  |           <div class="filter-actions"> | 
					
						
							|  |  |  |  |             <el-button type="primary" icon="Search" class="search-btn" @click="handleSearch">搜索</el-button> | 
					
						
							| 
									
										
										
										
											2025-09-29 17:17:42 +08:00
										 |  |  |  |             <el-button icon="Refresh" class="create-btn" @click="resetFilters">重置</el-button> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |           </div> | 
					
						
							|  |  |  |  |         </div> | 
					
						
							|  |  |  |  |       </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       <!-- 重点跟踪区域 --> | 
					
						
							|  |  |  |  |       <div class="tracking-section"> | 
					
						
							|  |  |  |  |         <div class="tracking-header"> | 
					
						
							|  |  |  |  |           <h3>重点跟踪</h3> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |           <div class="tracking-tag executing" v-if="currentTrackedWorkOrder"> | 
					
						
							|  |  |  |  |             {{ getStatusText(currentTrackedWorkOrder.status) }} | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  |           <div class="tracking-tag" v-else>暂无工单</div> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |         </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         <div class="tracking-card"> | 
					
						
							|  |  |  |  |           <div class="tracking-title"> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |             <div class="tracking-main-info" v-if="currentTrackedWorkOrder"> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |               <div class="task-info"> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |                 <span class="task-type">工单名: {{ currentTrackedWorkOrder.title || '未命名工单' }} </span> | 
					
						
							|  |  |  |  |                 <span class="work-order-no"> 工单编号: {{ currentTrackedWorkOrder.id || '-' }} </span> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |               </div> | 
					
						
							|  |  |  |  |               <div class="time-range"> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |                 <span>创建时间:{{ formatDateTime(currentTrackedWorkOrder.createTime) }}</span> | 
					
						
							|  |  |  |  |                 <span v-if="currentTrackedWorkOrder.endTime">至 {{ formatDateTime(currentTrackedWorkOrder.endTime) }}</span> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |               </div> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 15:18:50 +08:00
										 |  |  |  |           <!-- 进度条设计 --> | 
					
						
							|  |  |  |  |           <div class="tracking-progress-container" v-if="currentTrackedWorkOrder"> | 
					
						
							|  |  |  |  |             <!-- 进度条整体容器 --> | 
					
						
							|  |  |  |  |             <div class="progress-bar-wrapper"> | 
					
						
							|  |  |  |  |               <!-- 进度条背景 --> | 
					
						
							|  |  |  |  |               <div class="progress-bar-background"></div> | 
					
						
							|  |  |  |  |               <!-- 进度条填充 --> | 
					
						
							|  |  |  |  |               <div class="progress-bar-fill" :style="{ width: getProgressPercentage() + '%' }"></div> | 
					
						
							|  |  |  |  |               <!-- 进度条节点 --> | 
					
						
							|  |  |  |  |               <div class="progress-bar-nodes"> | 
					
						
							|  |  |  |  |                 <div | 
					
						
							|  |  |  |  |                   v-for="(step, index) in trackingSteps" | 
					
						
							|  |  |  |  |                   :key="step.id" | 
					
						
							|  |  |  |  |                   class="progress-node" | 
					
						
							|  |  |  |  |                   :class="getStepStatusClass(index)" | 
					
						
							|  |  |  |  |                   :style="{ left: getNodePosition(index) + '%' }" | 
					
						
							|  |  |  |  |                 > | 
					
						
							|  |  |  |  |                   <div class="node-circle"> | 
					
						
							|  |  |  |  |                     <div class="node-icon">{{ step.code || index + 1 }}</div> | 
					
						
							|  |  |  |  |                   </div> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |               </div> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             <!-- 步骤信息显示 --> | 
					
						
							|  |  |  |  |             <div class="progress-steps-info"> | 
					
						
							|  |  |  |  |               <div v-for="(step, index) in trackingSteps" :key="step.id" class="step-info-card" :class="getStepStatusClass(index)"> | 
					
						
							|  |  |  |  |                 <div class="step-header"> | 
					
						
							|  |  |  |  |                   <div class="step-number">{{ step.code || index + 1 }}</div> | 
					
						
							|  |  |  |  |                   <div class="step-name">{{ step.name }}</div> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |                 <div class="step-details"> | 
					
						
							|  |  |  |  |                   <div class="step-person"> | 
					
						
							|  |  |  |  |                     <i class="el-icon-user"></i> | 
					
						
							|  |  |  |  |                     {{ step.executor || (step.getOrderPersonVo && step.getOrderPersonVo.userName) || '待分配' }} | 
					
						
							|  |  |  |  |                   </div> | 
					
						
							|  |  |  |  |                   <template v-if="step.intendedTime"> | 
					
						
							|  |  |  |  |                     <div class="step-time"> | 
					
						
							|  |  |  |  |                       <i class="el-icon-time"></i> | 
					
						
							|  |  |  |  |                       预期时间:{{ formatDateTime(step.intendedTime) }} | 
					
						
							|  |  |  |  |                     </div> | 
					
						
							|  |  |  |  |                   </template> | 
					
						
							|  |  |  |  |                   <div class="step-purpose"> | 
					
						
							|  |  |  |  |                     <i class="el-icon-document"></i> | 
					
						
							|  |  |  |  |                     预期目的:{{ step.intendedPurpose || '-' }} | 
					
						
							|  |  |  |  |                   </div> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |               </div> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           <!-- 步骤条分页控件 --> | 
					
						
							|  |  |  |  |           <div class="steps-pagination" v-if="trackedWorkOrders.length > 1"> | 
					
						
							|  |  |  |  |             <el-pagination | 
					
						
							|  |  |  |  |               background | 
					
						
							|  |  |  |  |               :current-page="currentTrackPage" | 
					
						
							|  |  |  |  |               :page-size="trackPageSize" | 
					
						
							|  |  |  |  |               layout="prev, pager, next" | 
					
						
							|  |  |  |  |               :total="trackedWorkOrders.length" | 
					
						
							|  |  |  |  |               @current-change="handleTrackPageChange" | 
					
						
							|  |  |  |  |             /> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |           </div> | 
					
						
							|  |  |  |  |         </div> | 
					
						
							|  |  |  |  |       </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |       <!-- 工单表格 --> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |       <div class="table-wrapper"> | 
					
						
							|  |  |  |  |         <el-table :data="pagedTableData" stripe style="width: 100%" highlight-current-row class="custom-table"> | 
					
						
							|  |  |  |  |           <el-table-column align="center" prop="orderNo" label="工单编号" min-width="120"></el-table-column> | 
					
						
							|  |  |  |  |           <el-table-column align="center" prop="description" label="工单描述" min-width="150"></el-table-column> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |           <el-table-column align="center" prop="type" label="类型" min-width="100"> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |             <template #default="scope"> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |               <el-tag :type="getTypeTagType(scope.row.type)" class="type-tag"> | 
					
						
							|  |  |  |  |                 {{ scope.row.type }} | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |               </el-tag> | 
					
						
							|  |  |  |  |             </template> | 
					
						
							|  |  |  |  |           </el-table-column> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |           <el-table-column align="center" prop="priority" label="优先级" min-width="100"> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |             <template #default="scope"> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |               <el-tag :type="getPriorityTagType(scope.row.priority)" class="priority-tag"> | 
					
						
							|  |  |  |  |                 {{ scope.row.priority }} | 
					
						
							|  |  |  |  |               </el-tag> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |             </template> | 
					
						
							|  |  |  |  |           </el-table-column> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |           <el-table-column align="center" prop="creator" label="创建人" min-width="100"></el-table-column> | 
					
						
							| 
									
										
										
										
											2025-09-28 20:12:49 +08:00
										 |  |  |  |           <el-table-column align="center" prop="progress" label="工单进度" min-width="100"> | 
					
						
							|  |  |  |  |             <template #default="scope"> | 
					
						
							|  |  |  |  |               <el-progress :percentage="parseFloat(scope.row.progress) || 0" show-text /> | 
					
						
							|  |  |  |  |             </template> | 
					
						
							|  |  |  |  |           </el-table-column> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |           <el-table-column align="center" prop="createTime" label="创建时间" min-width="140"></el-table-column> | 
					
						
							|  |  |  |  |           <el-table-column align="center" prop="deadline" label="截止时间" min-width="140"></el-table-column> | 
					
						
							|  |  |  |  |           <el-table-column align="center" prop="status" label="状态" min-width="100"> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |             <template #default="scope"> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |               <el-tag :type="getStatusTagType(scope.row.status)" class="status-tag"> | 
					
						
							|  |  |  |  |                 {{ scope.row.status }} | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |               </el-tag> | 
					
						
							|  |  |  |  |             </template> | 
					
						
							|  |  |  |  |           </el-table-column> | 
					
						
							|  |  |  |  |           <el-table-column align="center" label="操作" min-width="180" fixed="right"> | 
					
						
							|  |  |  |  |             <template #default="scope"> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |               <!-- 已接单状态 --> | 
					
						
							|  |  |  |  |               <template v-if="scope.row.status === '已接单'"> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleFollow(scope.row)" class="action-btn">跟踪</el-button> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleCancel(scope.row)" class="action-btn cancel-btn">删除</el-button> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleViewDetail(scope.row)" class="action-btn">详情</el-button> | 
					
						
							|  |  |  |  |               </template> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |               <!-- 已派单状态 --> | 
					
						
							|  |  |  |  |               <template v-else-if="scope.row.status === '已派单'"> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleSetTrack(scope.row)" class="action-btn"> | 
					
						
							|  |  |  |  |                   {{ scope.row.point === '1' ? '取消跟踪' : '跟踪' }} | 
					
						
							|  |  |  |  |                 </el-button> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleViewDetail(scope.row)" class="action-btn">详情</el-button> | 
					
						
							|  |  |  |  |               </template> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |               <!-- 待派单状态 --> | 
					
						
							|  |  |  |  |               <template v-else-if="scope.row.status === '待派单'"> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleAssign(scope.row)" class="action-btn">派单</el-button> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleEdit(scope.row)" class="action-btn">编辑</el-button> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleViewDetail(scope.row)" class="action-btn">详情</el-button> | 
					
						
							|  |  |  |  |               </template> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |               <!-- 执行中状态 --> | 
					
						
							|  |  |  |  |               <template v-else-if="scope.row.status === '执行中'"> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleCommunicate(scope.row)" class="action-btn">沟通</el-button> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleViewProgress(scope.row)" class="action-btn">查看进度</el-button> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleViewDetail(scope.row)" class="action-btn">详情</el-button> | 
					
						
							|  |  |  |  |               </template> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |               <!-- 已完成状态 --> | 
					
						
							|  |  |  |  |               <template v-else-if="scope.row.status === '已完成'"> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleArchive(scope.row)" class="action-btn">归档</el-button> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleViewDetail(scope.row)" class="action-btn">详情</el-button> | 
					
						
							|  |  |  |  |               </template> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |               <!-- 默认显示 --> | 
					
						
							|  |  |  |  |               <template v-else> | 
					
						
							|  |  |  |  |                 <el-button type="text" @click="handleViewDetail(scope.row)" class="action-btn">查看详情</el-button> | 
					
						
							|  |  |  |  |               </template> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |             </template> | 
					
						
							|  |  |  |  |           </el-table-column> | 
					
						
							|  |  |  |  |         </el-table> | 
					
						
							|  |  |  |  |       </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       <!-- 分页区域 --> | 
					
						
							|  |  |  |  |       <div class="pagination-section"> | 
					
						
							|  |  |  |  |         <div class="pagination-info"> | 
					
						
							|  |  |  |  |           显示第{{ (currentPage - 1) * pageSize + 1 }}到{{ Math.min(currentPage * pageSize, total) }}条,共{{ total }}条记录 | 
					
						
							|  |  |  |  |         </div> | 
					
						
							|  |  |  |  |         <div class="pagination-controls"> | 
					
						
							|  |  |  |  |           <el-pagination | 
					
						
							|  |  |  |  |             @size-change="handleSizeChange" | 
					
						
							|  |  |  |  |             @current-change="handleCurrentChange" | 
					
						
							|  |  |  |  |             :current-page="currentPage" | 
					
						
							|  |  |  |  |             :page-sizes="[10, 20, 30, 40]" | 
					
						
							|  |  |  |  |             :page-size="pageSize" | 
					
						
							|  |  |  |  |             layout="prev, pager, next, jumper" | 
					
						
							|  |  |  |  |             :total="total" | 
					
						
							|  |  |  |  |             background | 
					
						
							|  |  |  |  |           > | 
					
						
							|  |  |  |  |           </el-pagination> | 
					
						
							|  |  |  |  |         </div> | 
					
						
							|  |  |  |  |       </div> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       <!-- 编辑工单弹窗 --> | 
					
						
							|  |  |  |  |       <el-dialog v-model="createDialogVisible" title="编辑工单" width="900px" class="create-dialog" center> | 
					
						
							|  |  |  |  |         <el-form :model="createForm" :rules="createFormRules" ref="createFormRef" label-width="120px" class="custom-form"> | 
					
						
							|  |  |  |  |           <el-form-item label="工单标题*" prop="title"> | 
					
						
							|  |  |  |  |             <el-input v-model="createForm.title" placeholder="请输入工单标题" /> | 
					
						
							|  |  |  |  |           </el-form-item> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           <el-row :gutter="20"> | 
					
						
							|  |  |  |  |             <el-col :span="8"> | 
					
						
							|  |  |  |  |               <el-form-item label="工单类型*" prop="type"> | 
					
						
							|  |  |  |  |                 <el-select v-model="createForm.type" placeholder="请选择类型"> | 
					
						
							|  |  |  |  |                   <el-option label="维护保养" value="维护保养" /> | 
					
						
							|  |  |  |  |                   <el-option label="检查检测" value="检查检测" /> | 
					
						
							|  |  |  |  |                   <el-option label="安装调试" value="安装调试" /> | 
					
						
							|  |  |  |  |                   <el-option label="升级改造" value="升级改造" /> | 
					
						
							|  |  |  |  |                 </el-select> | 
					
						
							|  |  |  |  |               </el-form-item> | 
					
						
							|  |  |  |  |             </el-col> | 
					
						
							|  |  |  |  |             <el-col :span="8"> | 
					
						
							|  |  |  |  |               <el-form-item label="优先级*" prop="priority"> | 
					
						
							|  |  |  |  |                 <el-select v-model="createForm.priority" placeholder="请选择优先级"> | 
					
						
							|  |  |  |  |                   <el-option label="高" value="高" /> | 
					
						
							|  |  |  |  |                   <el-option label="中" value="中" /> | 
					
						
							|  |  |  |  |                   <el-option label="低" value="低" /> | 
					
						
							|  |  |  |  |                 </el-select> | 
					
						
							|  |  |  |  |               </el-form-item> | 
					
						
							|  |  |  |  |             </el-col> | 
					
						
							|  |  |  |  |             <el-col :span="8"> | 
					
						
							|  |  |  |  |               <el-form-item label="截止时间*" prop="deadline"> | 
					
						
							|  |  |  |  |                 <el-date-picker v-model="createForm.deadline" type="date" placeholder="请选择日期" value-format="YYYY-MM-DD" /> | 
					
						
							|  |  |  |  |               </el-form-item> | 
					
						
							|  |  |  |  |             </el-col> | 
					
						
							|  |  |  |  |           </el-row> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           <el-form-item label="工单描述*" prop="description"> | 
					
						
							|  |  |  |  |             <el-input v-model="createForm.description" type="textarea" :rows="3" placeholder="请详细描述工单内容、要求和注意事项等信息" /> | 
					
						
							|  |  |  |  |           </el-form-item> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           <el-row :gutter="20"> | 
					
						
							|  |  |  |  |             <el-col :span="12"> | 
					
						
							|  |  |  |  |               <el-form-item label="执行地点*" prop="location"> | 
					
						
							|  |  |  |  |                 <el-input v-model="createForm.location" placeholder="请填写执行地点" /> | 
					
						
							|  |  |  |  |               </el-form-item> | 
					
						
							|  |  |  |  |             </el-col> | 
					
						
							|  |  |  |  |             <el-col :span="12"> | 
					
						
							|  |  |  |  |               <el-form-item label="相关设备/系统"> | 
					
						
							|  |  |  |  |                 <el-input v-model="createForm.relatedEquipment" placeholder="请输入相关设备或系统名称" /> | 
					
						
							|  |  |  |  |               </el-form-item> | 
					
						
							|  |  |  |  |             </el-col> | 
					
						
							|  |  |  |  |           </el-row> | 
					
						
							|  |  |  |  |           <el-form-item label="工单步骤" class="form-item" style="width: 100%"> | 
					
						
							|  |  |  |  |             <div class="steps-container"> | 
					
						
							|  |  |  |  |               <div class="step-item" v-for="(step, index) in createForm.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="createForm.steps.length > 1" type="text" class="delete-step-btn" @click="deleteStep(index)" style="color: #f56c6c"> | 
					
						
							|  |  |  |  |                   删除 | 
					
						
							|  |  |  |  |                 </el-button> | 
					
						
							|  |  |  |  |               </div> | 
					
						
							|  |  |  |  |               <el-button type="text" class="add-step-btn" @click="addStep">添加步骤</el-button> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </el-form-item> | 
					
						
							|  |  |  |  |           <el-form-item label="上传图片(可选)" width="100%" prop="file"> | 
					
						
							|  |  |  |  |             <image-upload v-model="createForm.file" /> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             <div v-if="createForm.fileList && createForm.fileList.length > 0" class="upload-tip"> | 
					
						
							|  |  |  |  |               <span style="color: #1989fa">已选择{{ createForm.fileList.length }}张图片,将在提交时上传</span> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </el-form-item> | 
					
						
							|  |  |  |  |           <el-form-item label="工单描述"> | 
					
						
							|  |  |  |  |             <el-input v-model="createForm.resultDescription" type="textarea" :rows="3" placeholder="请描述该工单完成后预期达成的成果" /> | 
					
						
							|  |  |  |  |           </el-form-item> | 
					
						
							|  |  |  |  |         </el-form> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         <template #footer> | 
					
						
							|  |  |  |  |           <span class="dialog-footer"> | 
					
						
							|  |  |  |  |             <el-button @click="cancelCreate">取消</el-button> | 
					
						
							|  |  |  |  |             <el-button type="primary" @click="submitCreate">提交修改</el-button> | 
					
						
							|  |  |  |  |           </span> | 
					
						
							|  |  |  |  |         </template> | 
					
						
							|  |  |  |  |       </el-dialog> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       <!-- 工单详情弹窗 --> | 
					
						
							|  |  |  |  |       <el-dialog | 
					
						
							|  |  |  |  |         v-model="detailDialogVisible" | 
					
						
							|  |  |  |  |         title="工单详情" | 
					
						
							|  |  |  |  |         width="800px" | 
					
						
							|  |  |  |  |         :before-close="handleCloseDetailDialog" | 
					
						
							|  |  |  |  |         class="custom-experiment-dialog" | 
					
						
							|  |  |  |  |       > | 
					
						
							|  |  |  |  |         <div v-if="isDetailLoading" class="skeleton-loading"> | 
					
						
							|  |  |  |  |           <div class="skeleton-card"> | 
					
						
							|  |  |  |  |             <div class="skeleton-header"></div> | 
					
						
							|  |  |  |  |             <div class="skeleton-content"> | 
					
						
							|  |  |  |  |               <div class="skeleton-row"></div> | 
					
						
							|  |  |  |  |               <div class="skeleton-row"></div> | 
					
						
							|  |  |  |  |               <div class="skeleton-row"></div> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  |           <div class="skeleton-card"> | 
					
						
							|  |  |  |  |             <div class="skeleton-header"></div> | 
					
						
							|  |  |  |  |             <div class="skeleton-content"> | 
					
						
							|  |  |  |  |               <div class="skeleton-row"></div> | 
					
						
							|  |  |  |  |               <div class="skeleton-row"></div> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  |           <div class="skeleton-card"> | 
					
						
							|  |  |  |  |             <div class="skeleton-header"></div> | 
					
						
							|  |  |  |  |             <div class="skeleton-content"> | 
					
						
							|  |  |  |  |               <div class="skeleton-row"></div> | 
					
						
							|  |  |  |  |               <div class="skeleton-row"></div> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  |         </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         <div v-else-if="detailData" class="task-detail-container"> | 
					
						
							|  |  |  |  |           <!-- 基础信息区 --> | 
					
						
							|  |  |  |  |           <div class="detail-card"> | 
					
						
							|  |  |  |  |             <h3 class="card-title">基础信息</h3> | 
					
						
							|  |  |  |  |             <div class="card-content"> | 
					
						
							|  |  |  |  |               <div class="info-row"> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">工单编号:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value">WO-{{ detailData.id }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">工单标题:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value">{{ detailData.title }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |               </div> | 
					
						
							|  |  |  |  |               <div class="info-row"> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">工单类型:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value">{{ mapCodeToType(detailData.type) }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">优先级:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value task-status priority-{{ mapPriorityToClass(detailData.level) }}">{{ | 
					
						
							|  |  |  |  |                     mapCodeToPriority(detailData.level) | 
					
						
							|  |  |  |  |                   }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |               </div> | 
					
						
							|  |  |  |  |               <div class="info-row"> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">创建人:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value">{{ detailData.sendOrderPersonVo?.userName || '-' }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">创建时间:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value">{{ detailData.createTime ? formatDate(detailData.createTime) : '-' }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |               </div> | 
					
						
							|  |  |  |  |               <div class="info-row"> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">执行人:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value">{{ detailData.getOrderPersonVo?.userName || '-' }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">接单时间:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value">{{ detailData.getOrderTime ? formatDate(detailData.getOrderTime) : '-' }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |               </div> | 
					
						
							|  |  |  |  |               <div class="info-row"> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">截止时间:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value">{{ detailData.endTime ? formatDate(detailData.endTime) : '-' }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">完成时间:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value">{{ detailData.finishiOrderTime ? formatDate(detailData.finishiOrderTime) : '-' }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |               </div> | 
					
						
							|  |  |  |  |               <div class="info-row"> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">执行地点:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value">{{ detailData.position || '-' }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |                 <div class="info-item"> | 
					
						
							|  |  |  |  |                   <span class="info-label">相关设备:</span> | 
					
						
							|  |  |  |  |                   <span class="info-value">{{ detailData.device || '-' }}</span> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |               </div> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           <!-- 工单描述 --> | 
					
						
							|  |  |  |  |           <div class="detail-card"> | 
					
						
							|  |  |  |  |             <h3 class="card-title">工单描述</h3> | 
					
						
							|  |  |  |  |             <div class="card-content"> | 
					
						
							|  |  |  |  |               <div class="description-content"> | 
					
						
							|  |  |  |  |                 {{ detailData.info || '无描述信息' }} | 
					
						
							|  |  |  |  |               </div> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           <!-- 步骤条 --> | 
					
						
							|  |  |  |  |           <div v-if="detailData.nodes && detailData.nodes.length > 0" class="detail-card"> | 
					
						
							|  |  |  |  |             <h3 class="card-title">执行步骤</h3> | 
					
						
							|  |  |  |  |             <div class="steps-container"> | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |               <div | 
					
						
							|  |  |  |  |                 v-for="(node, index) in detailData.nodes" | 
					
						
							|  |  |  |  |                 :key="node.id || index" | 
					
						
							|  |  |  |  |                 class="step-item" | 
					
						
							|  |  |  |  |                 :class="{ 'last-item': index === detailData.nodes.length - 1 }" | 
					
						
							|  |  |  |  |               > | 
					
						
							|  |  |  |  |                 <div class="step-number" :class="getStatusClass(node.status)">{{ node.code || index + 1 }}</div> | 
					
						
							|  |  |  |  |                 <div class="step-content"> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |                   <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)"> | 
					
						
							| 
									
										
										
										
											2025-09-29 19:56:24 +08:00
										 |  |  |  |                   {{ node.status === '2' ? '未执行' : node.status === '3' ? '失败' : '已完成' }} | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |                 </div> | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |                 <!-- 连接线 --> | 
					
						
							|  |  |  |  |                 <div v-if="index < detailData.nodes.length - 1" class="step-connector" :class="{ 'connector-completed': node.status !== '2' }"></div> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |               </div> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           <!-- 图片展示区 --> | 
					
						
							|  |  |  |  |           <div v-if="detailData.fileUrl" class="detail-card"> | 
					
						
							|  |  |  |  |             <h3 class="card-title">故障图片</h3> | 
					
						
							|  |  |  |  |             <div class="card-content"> | 
					
						
							|  |  |  |  |               <div class="images-container"> | 
					
						
							|  |  |  |  |                 <!-- 将逗号分隔的URL字符串拆分为数组并循环展示 --> | 
					
						
							|  |  |  |  |                 <div v-for="(url, index) in splitImageUrls(detailData.fileUrl)" :key="index" class="image-item"> | 
					
						
							|  |  |  |  |                   <img | 
					
						
							|  |  |  |  |                     :src="url" | 
					
						
							|  |  |  |  |                     :alt="`故障图片 ${index + 1}`" | 
					
						
							|  |  |  |  |                     class="detail-image" | 
					
						
							|  |  |  |  |                     @error="handleImageError($event, index)" | 
					
						
							|  |  |  |  |                     style="max-width: 100%; max-height: 200px; border-radius: 4px" | 
					
						
							|  |  |  |  |                   /> | 
					
						
							|  |  |  |  |                 </div> | 
					
						
							|  |  |  |  |               </div> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           <!-- 工单结果 --> | 
					
						
							|  |  |  |  |           <div v-if="detailData.orderResult" class="detail-card"> | 
					
						
							|  |  |  |  |             <h3 class="card-title">工单结果</h3> | 
					
						
							|  |  |  |  |             <div class="card-content"> | 
					
						
							|  |  |  |  |               <div class="result-content"> | 
					
						
							|  |  |  |  |                 {{ detailData.orderResult }} | 
					
						
							|  |  |  |  |               </div> | 
					
						
							|  |  |  |  |             </div> | 
					
						
							|  |  |  |  |           </div> | 
					
						
							|  |  |  |  |         </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         <div v-else class="empty-state"> | 
					
						
							|  |  |  |  |           <p>暂无工单详情数据</p> | 
					
						
							|  |  |  |  |         </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         <template #footer> | 
					
						
							|  |  |  |  |           <span class="dialog-footer"> | 
					
						
							|  |  |  |  |             <el-button @click="closeDetailDialog">关闭</el-button> | 
					
						
							|  |  |  |  |           </span> | 
					
						
							|  |  |  |  |         </template> | 
					
						
							|  |  |  |  |       </el-dialog> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |     </div> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     <!-- 派单弹窗 --> | 
					
						
							|  |  |  |  |     <el-dialog v-model="assignDialogVisible" title="派单" width="400px" :before-close="cancelAssign"> | 
					
						
							|  |  |  |  |       <div class="assign-dialog-content"> | 
					
						
							|  |  |  |  |         <div class="form-group"> | 
					
						
							|  |  |  |  |           <label class="form-label">选择执行人:</label> | 
					
						
							|  |  |  |  |           <el-select v-model="selectedExecutor" placeholder="请选择执行人" style="width: 100%" :loading="loadingUsers" filterable> | 
					
						
							|  |  |  |  |             <el-option v-for="item in executors" :key="item.userId" :label="item.userName" :value="item.userId" /> | 
					
						
							|  |  |  |  |           </el-select> | 
					
						
							|  |  |  |  |         </div> | 
					
						
							|  |  |  |  |       </div> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       <template #footer> | 
					
						
							|  |  |  |  |         <div class="dialog-footer"> | 
					
						
							|  |  |  |  |           <el-button @click="cancelAssign">取消</el-button> | 
					
						
							|  |  |  |  |           <el-button type="primary" @click="confirmAssign" :loading="assignLoading">确定</el-button> | 
					
						
							|  |  |  |  |         </div> | 
					
						
							|  |  |  |  |       </template> | 
					
						
							|  |  |  |  |     </el-dialog> | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   </div> | 
					
						
							|  |  |  |  | </template> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | <script setup> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | import { ref, computed, reactive } from 'vue'; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | import router from '@/router'; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | import { gongdanlist, updategongdan, gongdanDetail } from '@/api/zhinengxunjian/gongdan/index'; | 
					
						
							|  |  |  |  | import { updatejiedian } from '@/api/zhinengxunjian/jiedian'; | 
					
						
							|  |  |  |  | import { xunjianUserlist } from '@/api/zhinengxunjian/xunjian'; | 
					
						
							|  |  |  |  | import ImageUpload from '@/components/ImageUpload/index.vue'; | 
					
						
							|  |  |  |  | import { ElMessageBox, ElMessage } from 'element-plus'; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 筛选条件
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:17:42 +08:00
										 |  |  |  | const keyword = ref(''); | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | const workOrderType = ref('all'); | 
					
						
							|  |  |  |  | const workOrderStatus = ref('all'); | 
					
						
							|  |  |  |  | const priority = ref('all'); | 
					
						
							|  |  |  |  | const createDate = ref(''); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 工单数据
 | 
					
						
							|  |  |  |  | const rawTableData = ref([]); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // 分页相关
 | 
					
						
							|  |  |  |  | const currentPage = ref(1); | 
					
						
							|  |  |  |  | const pageSize = ref(10); | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | const total = ref(0); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 获取工单列表数据
 | 
					
						
							|  |  |  |  | const fetchWorkOrderList = async () => { | 
					
						
							|  |  |  |  |   try { | 
					
						
							|  |  |  |  |     const params = { | 
					
						
							|  |  |  |  |       projectId: 1, | 
					
						
							|  |  |  |  |       pageNum: currentPage.value, | 
					
						
							|  |  |  |  |       pageSize: pageSize.value | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     const response = await gongdanlist(params); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (response.code === 200 && response.rows) { | 
					
						
							|  |  |  |  |       // 处理返回的数据,转换为表格需要的格式
 | 
					
						
							|  |  |  |  |       rawTableData.value = response.rows.map((item) => ({ | 
					
						
							|  |  |  |  |         id: item.id, | 
					
						
							|  |  |  |  |         projectId: item.projectId, | 
					
						
							|  |  |  |  |         orderNo: `WO-${item.id}`, // 生成工单编号
 | 
					
						
							|  |  |  |  |         title: item.title || '', | 
					
						
							|  |  |  |  |         description: item.info || '', | 
					
						
							|  |  |  |  |         type: mapCodeToType(item.type), | 
					
						
							|  |  |  |  |         priority: mapCodeToPriority(item.level), | 
					
						
							|  |  |  |  |         creator: item.sendOrderPersonVo?.userName || '', | 
					
						
							|  |  |  |  |         createTime: item.createTime ? formatDate(item.createTime) : item.sendOrderTime ? formatDate(item.sendOrderTime) : '', | 
					
						
							|  |  |  |  |         deadline: item.endTime ? formatDate(item.endTime) : '', | 
					
						
							|  |  |  |  |         status: mapCodeToStatus(item.status), | 
					
						
							|  |  |  |  |         executor: item.getOrderPersonVo?.userName || '', | 
					
						
							|  |  |  |  |         getOrderTime: item.getOrderTime ? formatDate(item.getOrderTime) : '', | 
					
						
							|  |  |  |  |         finishiOrderTime: item.finishiOrderTime ? formatDate(item.finishiOrderTime) : '', | 
					
						
							|  |  |  |  |         position: item.position || '', | 
					
						
							| 
									
										
										
										
											2025-09-28 20:12:49 +08:00
										 |  |  |  |         device: item.device || '', | 
					
						
							|  |  |  |  |         progress: item.progress // 添加进度字段
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |       })); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       // 更新总条数
 | 
					
						
							|  |  |  |  |       total.value = response.total || 0; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       // 处理跟踪步骤数据
 | 
					
						
							|  |  |  |  |       processTrackingSteps(response.rows); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } catch (error) { | 
					
						
							|  |  |  |  |     console.error('获取工单列表失败:', error); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 处理工单列表数据,提取需要跟踪的步骤
 | 
					
						
							|  |  |  |  | const processTrackingSteps = (workOrders) => { | 
					
						
							|  |  |  |  |   // 收集所有point为1的工单(根据新的数据结构)
 | 
					
						
							|  |  |  |  |   trackedWorkOrders.value = workOrders.filter((order) => order.point === '1'); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   // 更新当前显示的工单
 | 
					
						
							|  |  |  |  |   updateCurrentTrackedOrder(); | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 更新当前显示的跟踪工单
 | 
					
						
							|  |  |  |  | const updateCurrentTrackedOrder = () => { | 
					
						
							|  |  |  |  |   // 获取当前页应该显示的工单
 | 
					
						
							|  |  |  |  |   const currentWorkOrder = trackedWorkOrders.value[currentTrackPage.value - 1]; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (currentWorkOrder) { | 
					
						
							|  |  |  |  |     currentTrackedWorkOrder.value = currentWorkOrder; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 检查是否有nodes数据,如果有则处理
 | 
					
						
							|  |  |  |  |     if (currentWorkOrder.nodes && Array.isArray(currentWorkOrder.nodes) && currentWorkOrder.nodes.length > 0) { | 
					
						
							|  |  |  |  |       // 按code排序nodes数组
 | 
					
						
							|  |  |  |  |       const sortedNodes = [...currentWorkOrder.nodes].sort((a, b) => (a.code || 0) - (b.code || 0)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       // 设置跟踪步骤数据,确保每个节点有必要的字段
 | 
					
						
							|  |  |  |  |       trackingSteps.value = sortedNodes.map((node) => ({ | 
					
						
							|  |  |  |  |         id: node.id, | 
					
						
							|  |  |  |  |         name: node.name, | 
					
						
							|  |  |  |  |         code: node.code, | 
					
						
							|  |  |  |  |         executor: currentWorkOrder.sendOrderPersonVo?.userName || currentWorkOrder.getOrderPersonVo?.userName || '待分配', | 
					
						
							|  |  |  |  |         intendedTime: node.intendedTime, | 
					
						
							|  |  |  |  |         finishTime: node.finishTime, | 
					
						
							|  |  |  |  |         intendedPurpose: node.intendedPurpose || '-', | 
					
						
							| 
									
										
										
										
											2025-09-29 15:18:50 +08:00
										 |  |  |  |         remark: node.remark || '', | 
					
						
							|  |  |  |  |         status: node.status || '' // 添加status字段
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |       })); | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       // 如果nodes数组为空,创建一些默认的步骤数据
 | 
					
						
							|  |  |  |  |       trackingSteps.value = []; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 设置当前激活步骤索引
 | 
					
						
							| 
									
										
										
										
											2025-09-29 15:18:50 +08:00
										 |  |  |  |     // 根据status字段判断,status='1'表示完成,status='2'表示未完成,status='3'表示失败
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |     activeStepIndex.value = 0; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 检查是否有已完成的步骤,如果有,将激活步骤设置为最后一个已完成步骤的下一个
 | 
					
						
							|  |  |  |  |     for (let i = trackingSteps.value.length - 1; i >= 0; i--) { | 
					
						
							| 
									
										
										
										
											2025-09-29 15:18:50 +08:00
										 |  |  |  |       if (trackingSteps.value[i].status === '1') { | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |         activeStepIndex.value = Math.min(i + 1, trackingSteps.value.length - 1); | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 显示重点跟踪工单信息
 | 
					
						
							|  |  |  |  |     console.log('重点跟踪工单:', { | 
					
						
							|  |  |  |  |       title: currentWorkOrder.title, | 
					
						
							|  |  |  |  |       orderNo: currentWorkOrder.id, | 
					
						
							|  |  |  |  |       startTime: currentWorkOrder.createTime, | 
					
						
							|  |  |  |  |       endTime: currentWorkOrder.endTime, | 
					
						
							|  |  |  |  |       status: currentWorkOrder.status | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |   } else { | 
					
						
							|  |  |  |  |     // 如果没有找到point为1的工单,设置默认步骤数据
 | 
					
						
							|  |  |  |  |     trackingSteps.value = [ | 
					
						
							|  |  |  |  |       { | 
					
						
							|  |  |  |  |         id: 'no-point-1', | 
					
						
							|  |  |  |  |         name: '暂无重点跟踪工单', | 
					
						
							|  |  |  |  |         code: 1, | 
					
						
							|  |  |  |  |         executor: '系统', | 
					
						
							|  |  |  |  |         finishTime: new Date().toISOString(), | 
					
						
							|  |  |  |  |         intendedPurpose: '请在工单列表中设置重点跟踪工单', | 
					
						
							|  |  |  |  |         remark: '' | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     ]; | 
					
						
							|  |  |  |  |     activeStepIndex.value = 0; | 
					
						
							|  |  |  |  |     currentTrackedWorkOrder.value = null; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 步骤条分页切换
 | 
					
						
							|  |  |  |  | const handleTrackPageChange = (page) => { | 
					
						
							|  |  |  |  |   currentTrackPage.value = page; | 
					
						
							|  |  |  |  |   updateCurrentTrackedOrder(); | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 类型映射函数 - 页面类型转接口code
 | 
					
						
							|  |  |  |  | const mapTypeToCode = (type) => { | 
					
						
							|  |  |  |  |   const typeMap = { | 
					
						
							|  |  |  |  |     '维护保养': 1, | 
					
						
							|  |  |  |  |     '检查检测': 2, | 
					
						
							|  |  |  |  |     '安装调试': 3, | 
					
						
							|  |  |  |  |     '升级改造': 4 | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  |   return typeMap[type] || null; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 类型映射函数 - 接口code转页面类型
 | 
					
						
							|  |  |  |  | const mapCodeToType = (code) => { | 
					
						
							|  |  |  |  |   // 确保code是字符串类型以匹配映射表
 | 
					
						
							|  |  |  |  |   const codeStr = typeof code === 'number' ? code.toString() : code; | 
					
						
							|  |  |  |  |   const typeMap = { | 
					
						
							|  |  |  |  |     '1': '维护保养', | 
					
						
							|  |  |  |  |     '2': '检查检测', | 
					
						
							|  |  |  |  |     '3': '安装调试', | 
					
						
							|  |  |  |  |     '4': '升级改造' | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  |   return typeMap[codeStr] || code; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 状态映射函数 - 页面状态转接口code
 | 
					
						
							|  |  |  |  | const mapStatusToCode = (status) => { | 
					
						
							|  |  |  |  |   const statusMap = { | 
					
						
							|  |  |  |  |     '待派单': 1, | 
					
						
							|  |  |  |  |     '已派单': 2, | 
					
						
							|  |  |  |  |     '执行中': 3, | 
					
						
							|  |  |  |  |     '已完成': 4 | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  |   return statusMap[status] || null; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 状态映射函数 - 接口code转页面状态
 | 
					
						
							|  |  |  |  | const mapCodeToStatus = (code) => { | 
					
						
							|  |  |  |  |   // 确保code是字符串类型以匹配映射表
 | 
					
						
							|  |  |  |  |   const codeStr = typeof code === 'number' ? code.toString() : code; | 
					
						
							|  |  |  |  |   const statusMap = { | 
					
						
							|  |  |  |  |     '1': '待派单', | 
					
						
							|  |  |  |  |     '2': '已派单', | 
					
						
							|  |  |  |  |     '3': '执行中', | 
					
						
							|  |  |  |  |     '4': '已完成' | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  |   return statusMap[codeStr] || code; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 优先级映射函数 - 页面优先级转接口code
 | 
					
						
							|  |  |  |  | const mapPriorityToCode = (priority) => { | 
					
						
							|  |  |  |  |   const priorityMap = { | 
					
						
							|  |  |  |  |     '高': 3, | 
					
						
							|  |  |  |  |     '中': 2, | 
					
						
							|  |  |  |  |     '低': 1 | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  |   return priorityMap[priority] || null; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 优先级映射函数 - 接口code转页面优先级
 | 
					
						
							|  |  |  |  | const mapCodeToPriority = (code) => { | 
					
						
							|  |  |  |  |   // 确保code是字符串类型以匹配映射表
 | 
					
						
							|  |  |  |  |   const codeStr = typeof code === 'number' ? code.toString() : code; | 
					
						
							|  |  |  |  |   const priorityMap = { | 
					
						
							|  |  |  |  |     '1': '低', | 
					
						
							|  |  |  |  |     '2': '中', | 
					
						
							|  |  |  |  |     '3': '高' | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  |   return priorityMap[codeStr] || code; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 日期格式化函数 - 支持datetime格式
 | 
					
						
							|  |  |  |  | const formatDate = (dateString) => { | 
					
						
							|  |  |  |  |   if (!dateString) return ''; | 
					
						
							|  |  |  |  |   const date = new Date(dateString); | 
					
						
							|  |  |  |  |   const year = date.getFullYear(); | 
					
						
							|  |  |  |  |   const month = String(date.getMonth() + 1).padStart(2, '0'); | 
					
						
							|  |  |  |  |   const day = String(date.getDate()).padStart(2, '0'); | 
					
						
							|  |  |  |  |   const hours = String(date.getHours()).padStart(2, '0'); | 
					
						
							|  |  |  |  |   const minutes = String(date.getMinutes()).padStart(2, '0'); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   // 返回与datetime选择器value-format一致的格式
 | 
					
						
							|  |  |  |  |   return `${year}/${month}/${day} ${hours}:${minutes}`; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 时间格式化函数 - 用于步骤条的时间显示
 | 
					
						
							|  |  |  |  | // const formatDateTime = (dateString) => {
 | 
					
						
							|  |  |  |  | //   if (!dateString) return '';
 | 
					
						
							|  |  |  |  | //   const date = new Date(dateString);
 | 
					
						
							|  |  |  |  | //   const year = date.getFullYear();
 | 
					
						
							|  |  |  |  | //   const month = String(date.getMonth() + 1).padStart(2, '0');
 | 
					
						
							|  |  |  |  | //   const day = String(date.getDate()).padStart(2, '0');
 | 
					
						
							|  |  |  |  | //   const hours = String(date.getHours()).padStart(2, '0');
 | 
					
						
							|  |  |  |  | //   const minutes = String(date.getMinutes()).padStart(2, '0');
 | 
					
						
							|  |  |  |  | //   const seconds = String(date.getSeconds()).padStart(2, '0');
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | //   return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
 | 
					
						
							|  |  |  |  | // };
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 步骤条相关状态
 | 
					
						
							|  |  |  |  | const trackingSteps = ref([]); // 跟踪步骤数据
 | 
					
						
							|  |  |  |  | const activeStepIndex = ref(0); // 当前激活的步骤索引
 | 
					
						
							|  |  |  |  | const currentTrackedWorkOrder = ref(null); // 当前重点跟踪的工单信息
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 步骤条分页相关状态
 | 
					
						
							|  |  |  |  | const trackedWorkOrders = ref([]); // 所有重点跟踪工单列表
 | 
					
						
							|  |  |  |  | const currentTrackPage = ref(1); // 当前步骤条分页
 | 
					
						
							|  |  |  |  | const trackPageSize = ref(1); // 每页显示的步骤条数量(默认为1)
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 刷新步骤条数据
 | 
					
						
							|  |  |  |  | const refreshTrackingSteps = async () => { | 
					
						
							|  |  |  |  |   try { | 
					
						
							|  |  |  |  |     // 调用gongdanlist接口获取最新数据
 | 
					
						
							|  |  |  |  |     const params = { | 
					
						
							|  |  |  |  |       projectId: 1, | 
					
						
							|  |  |  |  |       pageNum: 1, | 
					
						
							|  |  |  |  |       point: 1, // 根据新的数据结构,查找point为2的工单
 | 
					
						
							|  |  |  |  |       pageSize: 100 // 获取足够多的数据以确保找到point为2的工单
 | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     const response = await gongdanlist(params); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (response.code === 200 && response.rows) { | 
					
						
							|  |  |  |  |       // 处理返回的数据,提取步骤信息
 | 
					
						
							|  |  |  |  |       processTrackingSteps(response.rows); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } catch (error) { | 
					
						
							|  |  |  |  |     console.error('刷新步骤条数据失败:', error); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 根据索引获取步骤状态
 | 
					
						
							|  |  |  |  | const getStatusByIndex = (index) => { | 
					
						
							| 
									
										
										
										
											2025-09-29 15:18:50 +08:00
										 |  |  |  |   if (!currentTrackedWorkOrder.value) return 'wait'; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   if (index < activeStepIndex.value) { | 
					
						
							| 
									
										
										
										
											2025-09-29 15:18:50 +08:00
										 |  |  |  |     return 'finish'; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   } else if (index === activeStepIndex.value) { | 
					
						
							|  |  |  |  |     return 'process'; | 
					
						
							|  |  |  |  |   } else { | 
					
						
							|  |  |  |  |     return 'wait'; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 15:18:50 +08:00
										 |  |  |  | // 试验记录页面步骤条状态判断 - 重点跟踪区域专用
 | 
					
						
							|  |  |  |  | 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; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | // 将状态码转换为可读的状态文本
 | 
					
						
							|  |  |  |  | const getStatusText = (statusCode) => { | 
					
						
							|  |  |  |  |   const statusMap = { | 
					
						
							|  |  |  |  |     '1': '待处理', | 
					
						
							|  |  |  |  |     '2': '待派单', | 
					
						
							|  |  |  |  |     '3': '执行中', | 
					
						
							|  |  |  |  |     '4': '已完成', | 
					
						
							|  |  |  |  |     '5': '已取消' | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   // 确保statusCode是字符串类型以匹配映射表
 | 
					
						
							|  |  |  |  |   const statusStr = typeof statusCode === 'number' ? statusCode.toString() : statusCode; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return statusMap[statusStr] || '未知状态'; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 初始化加载数据
 | 
					
						
							|  |  |  |  | const initData = async () => { | 
					
						
							|  |  |  |  |   await fetchWorkOrderList(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   // 额外调用一次专门刷新步骤条数据的函数,确保获取到最新的point为1的数据
 | 
					
						
							|  |  |  |  |   await refreshTrackingSteps(); | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | initData(); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // 分页处理后的数据
 | 
					
						
							|  |  |  |  | const pagedTableData = computed(() => { | 
					
						
							|  |  |  |  |   // 筛选逻辑
 | 
					
						
							|  |  |  |  |   let filteredData = [...rawTableData.value]; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:17:42 +08:00
										 |  |  |  |   if (keyword.value && keyword.value.trim()) { | 
					
						
							|  |  |  |  |     const kw = keyword.value.trim(); | 
					
						
							|  |  |  |  |     filteredData = filteredData.filter((item) => { | 
					
						
							|  |  |  |  |       return ( | 
					
						
							|  |  |  |  |         (item.title && item.title.includes(kw)) || | 
					
						
							|  |  |  |  |         (item.description && item.description.includes(kw)) || | 
					
						
							|  |  |  |  |         (item.creator && item.creator.includes(kw)) || | 
					
						
							|  |  |  |  |         (item.orderNo && item.orderNo.includes(kw)) | 
					
						
							|  |  |  |  |       ); | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   if (workOrderType.value !== 'all') { | 
					
						
							|  |  |  |  |     // 转换筛选条件为显示文本进行匹配
 | 
					
						
							|  |  |  |  |     let typeText = ''; | 
					
						
							|  |  |  |  |     switch (workOrderType.value) { | 
					
						
							|  |  |  |  |       case 'maintenance': | 
					
						
							|  |  |  |  |         typeText = '维护保养'; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case 'inspection': | 
					
						
							|  |  |  |  |         typeText = '检查检测'; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case 'installation': | 
					
						
							|  |  |  |  |         typeText = '安装调试'; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case 'upgrade': | 
					
						
							|  |  |  |  |         typeText = '升级改造'; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     filteredData = filteredData.filter((item) => item.type === typeText); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   if (workOrderStatus.value !== 'all') { | 
					
						
							|  |  |  |  |     // 转换筛选条件为显示文本进行匹配
 | 
					
						
							|  |  |  |  |     let statusText = ''; | 
					
						
							|  |  |  |  |     switch (workOrderStatus.value) { | 
					
						
							|  |  |  |  |       case 'accepted': | 
					
						
							|  |  |  |  |         statusText = '已接单'; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case 'pending': | 
					
						
							|  |  |  |  |         statusText = '待处理'; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case 'executing': | 
					
						
							|  |  |  |  |         statusText = '执行中'; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case 'completed': | 
					
						
							|  |  |  |  |         statusText = '已完成'; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     filteredData = filteredData.filter((item) => item.status === statusText); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   if (priority.value !== 'all') { | 
					
						
							|  |  |  |  |     // 转换筛选条件为显示文本进行匹配
 | 
					
						
							|  |  |  |  |     let priorityText = ''; | 
					
						
							|  |  |  |  |     switch (priority.value) { | 
					
						
							|  |  |  |  |       case 'high': | 
					
						
							|  |  |  |  |         priorityText = '高'; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case 'medium': | 
					
						
							|  |  |  |  |         priorityText = '中'; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case 'low': | 
					
						
							|  |  |  |  |         priorityText = '低'; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     filteredData = filteredData.filter((item) => item.priority === priorityText); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   if (createDate.value) { | 
					
						
							|  |  |  |  |     filteredData = filteredData.filter((item) => item.createTime.includes(createDate.value)); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   // 更新总条数
 | 
					
						
							|  |  |  |  |   total.value = filteredData.length; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   // 分页处理
 | 
					
						
							|  |  |  |  |   const startIndex = (currentPage.value - 1) * pageSize.value; | 
					
						
							|  |  |  |  |   const endIndex = startIndex + pageSize.value; | 
					
						
							|  |  |  |  |   return filteredData.slice(startIndex, endIndex); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | // 获取类型标签样式
 | 
					
						
							|  |  |  |  | const getTypeTagType = (type) => { | 
					
						
							|  |  |  |  |   const typeMap = { | 
					
						
							|  |  |  |  |     // 维护保养为红色
 | 
					
						
							|  |  |  |  |     '维护保养': 'danger', | 
					
						
							|  |  |  |  |     // 检查检测为绿色
 | 
					
						
							|  |  |  |  |     '检查检测': 'success', | 
					
						
							|  |  |  |  |     // 安装调试为黄色
 | 
					
						
							|  |  |  |  |     '安装调试': 'warning', | 
					
						
							|  |  |  |  |     // 升级改造为绿色
 | 
					
						
							|  |  |  |  |     '升级改造': 'success' | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  |   return typeMap[type] || 'default'; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 获取优先级标签样式
 | 
					
						
							|  |  |  |  | const getPriorityTagType = (priority) => { | 
					
						
							|  |  |  |  |   const priorityMap = { | 
					
						
							|  |  |  |  |     '高': 'danger', | 
					
						
							|  |  |  |  |     '中': 'warning', | 
					
						
							|  |  |  |  |     '低': 'info' | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  |   return priorityMap[priority] || 'default'; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | // 获取状态标签样式
 | 
					
						
							|  |  |  |  | const getStatusTagType = (status) => { | 
					
						
							|  |  |  |  |   const statusMap = { | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |     '已接单': 'primary', | 
					
						
							|  |  |  |  |     '待处理': 'warning', | 
					
						
							|  |  |  |  |     '待派单': 'warning', | 
					
						
							|  |  |  |  |     '执行中': 'success', | 
					
						
							|  |  |  |  |     '已完成': 'info' | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   }; | 
					
						
							|  |  |  |  |   return statusMap[status] || 'default'; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | // 根据步骤状态获取对应的样式类
 | 
					
						
							|  |  |  |  | const getStatusClass = (status) => { | 
					
						
							|  |  |  |  |   // 处理可能的数字输入
 | 
					
						
							|  |  |  |  |   const statusStr = status?.toString() || ''; | 
					
						
							|  |  |  |  |   const statusClassMap = { | 
					
						
							| 
									
										
										
										
											2025-09-29 19:56:24 +08:00
										 |  |  |  |     '1': 'status-pending', // 待执行 - 蓝色
 | 
					
						
							|  |  |  |  |     '2': 'status-unknown', // 未执行 - 灰色
 | 
					
						
							|  |  |  |  |     '3': 'status-failed', // 失败 - 红色
 | 
					
						
							|  |  |  |  |     '4': 'status-completed' // 已完成 - 绿色
 | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   return statusClassMap[statusStr] || 'status-unknown'; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 格式化日期时间(用于步骤条)
 | 
					
						
							|  |  |  |  | const formatDateTime = (dateTime) => { | 
					
						
							|  |  |  |  |   if (!dateTime) return '-'; | 
					
						
							|  |  |  |  |   try { | 
					
						
							|  |  |  |  |     const date = new Date(dateTime); | 
					
						
							|  |  |  |  |     const year = date.getFullYear(); | 
					
						
							|  |  |  |  |     const month = String(date.getMonth() + 1).padStart(2, '0'); | 
					
						
							|  |  |  |  |     const day = String(date.getDate()).padStart(2, '0'); | 
					
						
							|  |  |  |  |     const hours = String(date.getHours()).padStart(2, '0'); | 
					
						
							|  |  |  |  |     const minutes = String(date.getMinutes()).padStart(2, '0'); | 
					
						
							|  |  |  |  |     return `${year}-${month}-${day} ${hours}:${minutes}`; | 
					
						
							|  |  |  |  |   } catch (error) { | 
					
						
							|  |  |  |  |     return dateTime; | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | // 获取步骤状态文本
 | 
					
						
							|  |  |  |  | const getStepStatusText = (status) => { | 
					
						
							|  |  |  |  |   const statusStr = status?.toString() || ''; | 
					
						
							|  |  |  |  |   const statusMap = { | 
					
						
							|  |  |  |  |     '1': '待执行', | 
					
						
							|  |  |  |  |     '2': '执行中', | 
					
						
							|  |  |  |  |     '3': '已完成', | 
					
						
							|  |  |  |  |     '4': '已延期' | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  |   return statusMap[statusStr] || '未知状态'; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 搜索处理
 | 
					
						
							|  |  |  |  | const handleSearch = () => { | 
					
						
							|  |  |  |  |   currentPage.value = 1; // 重置到第一页
 | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:17:42 +08:00
										 |  |  |  | // 重置筛选
 | 
					
						
							|  |  |  |  | const resetFilters = () => { | 
					
						
							|  |  |  |  |   keyword.value = ''; | 
					
						
							|  |  |  |  |   workOrderType.value = 'all'; | 
					
						
							|  |  |  |  |   workOrderStatus.value = 'all'; | 
					
						
							|  |  |  |  |   priority.value = 'all'; | 
					
						
							|  |  |  |  |   createDate.value = ''; | 
					
						
							|  |  |  |  |   currentPage.value = 1; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | // 分页事件
 | 
					
						
							|  |  |  |  | const handleSizeChange = (val) => { | 
					
						
							|  |  |  |  |   pageSize.value = val; | 
					
						
							|  |  |  |  |   currentPage.value = 1; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const handleCurrentChange = (val) => { | 
					
						
							|  |  |  |  |   currentPage.value = val; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 操作按钮事件
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | const handleViewDetail = async (row) => { | 
					
						
							|  |  |  |  |   try { | 
					
						
							|  |  |  |  |     isDetailLoading.value = true; | 
					
						
							|  |  |  |  |     const response = await gongdanDetail(row.id); | 
					
						
							|  |  |  |  |     if (response.code === 200 && response.data) { | 
					
						
							|  |  |  |  |       detailData.value = response.data; | 
					
						
							|  |  |  |  |       detailDialogVisible.value = true; | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       ElMessageBox.alert('获取工单详情失败', '提示', { | 
					
						
							|  |  |  |  |         confirmButtonText: '确定', | 
					
						
							|  |  |  |  |         type: 'error' | 
					
						
							|  |  |  |  |       }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } catch (error) { | 
					
						
							|  |  |  |  |     console.error('获取工单详情错误:', error); | 
					
						
							|  |  |  |  |     ElMessageBox.alert('获取工单详情时发生错误', '错误', { | 
					
						
							|  |  |  |  |       confirmButtonText: '确定', | 
					
						
							|  |  |  |  |       type: 'error' | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |   } finally { | 
					
						
							|  |  |  |  |     isDetailLoading.value = false; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 关闭详情弹窗
 | 
					
						
							|  |  |  |  | const closeDetailDialog = () => { | 
					
						
							|  |  |  |  |   detailDialogVisible.value = false; | 
					
						
							|  |  |  |  |   detailData.value = null; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 详情弹窗相关
 | 
					
						
							|  |  |  |  | const detailDialogVisible = ref(false); | 
					
						
							|  |  |  |  | const detailData = ref(null); | 
					
						
							|  |  |  |  | const isDetailLoading = ref(false); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 分割图片URL
 | 
					
						
							|  |  |  |  | const splitImageUrls = (fileUrl) => { | 
					
						
							|  |  |  |  |   if (!fileUrl) return []; | 
					
						
							|  |  |  |  |   return fileUrl.split(',').filter((url) => url.trim()); | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 处理图片加载错误
 | 
					
						
							|  |  |  |  | const handleImageError = (event, index) => { | 
					
						
							|  |  |  |  |   event.target.src = '@/assets/images/error-image.png'; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 根据module分组nodes
 | 
					
						
							|  |  |  |  | const groupNodesByModule = (nodes) => { | 
					
						
							|  |  |  |  |   if (!nodes || !Array.isArray(nodes)) return []; | 
					
						
							|  |  |  |  |   const moduleMap = new Map(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   nodes.forEach((node) => { | 
					
						
							|  |  |  |  |     const module = node.module || '默认模块'; | 
					
						
							|  |  |  |  |     if (!moduleMap.has(module)) { | 
					
						
							|  |  |  |  |       moduleMap.set(module, []); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     moduleMap.get(module).push(node); | 
					
						
							|  |  |  |  |   }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   // 转换为数组并排序
 | 
					
						
							|  |  |  |  |   return Array.from(moduleMap.entries()).map(([module, items]) => ({ | 
					
						
							|  |  |  |  |     module, | 
					
						
							|  |  |  |  |     items: items.sort((a, b) => (a.code || 0) - (b.code || 0)) | 
					
						
							|  |  |  |  |   })); | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const handleCancel = (row) => { | 
					
						
							|  |  |  |  |   console.log('取消工单:', row); | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const handleCommunicate = (row) => { | 
					
						
							|  |  |  |  |   console.log('沟通:', row); | 
					
						
							|  |  |  |  |   // 这里可以实现沟通功能,例如打开沟通弹窗或跳转到沟通页面
 | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const handleArchive = (row) => { | 
					
						
							|  |  |  |  |   console.log('归档:', row); | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 派单弹窗相关状态
 | 
					
						
							|  |  |  |  | const assignDialogVisible = ref(false); | 
					
						
							|  |  |  |  | const assignLoading = ref(false); | 
					
						
							|  |  |  |  | const currentTaskId = ref(''); | 
					
						
							|  |  |  |  | const currentTaskInfo = ref(null); // 存储当前工单的完整信息
 | 
					
						
							|  |  |  |  | const selectedExecutor = ref(''); | 
					
						
							|  |  |  |  | const executors = ref([]); | 
					
						
							|  |  |  |  | const loadingUsers = ref(false); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 派单功能
 | 
					
						
							|  |  |  |  | const handleAssign = async (row) => { | 
					
						
							|  |  |  |  |   console.log('派单:', row); | 
					
						
							|  |  |  |  |   currentTaskId.value = row.id; | 
					
						
							|  |  |  |  |   currentTaskInfo.value = row; // 保存完整的工单信息
 | 
					
						
							|  |  |  |  |   selectedExecutor.value = ''; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   try { | 
					
						
							|  |  |  |  |     // 调用xunjianUserlist接口获取用户列表
 | 
					
						
							|  |  |  |  |     loadingUsers.value = true; | 
					
						
							|  |  |  |  |     const res = await xunjianUserlist(); | 
					
						
							|  |  |  |  |     if (res && res.code === 200 && res.rows && Array.isArray(res.rows)) { | 
					
						
							|  |  |  |  |       // 过滤有效用户并格式化数据
 | 
					
						
							|  |  |  |  |       executors.value = res.rows | 
					
						
							|  |  |  |  |         .filter((user) => user.userId && user.userName) | 
					
						
							|  |  |  |  |         .map((user) => ({ | 
					
						
							|  |  |  |  |           userId: user.userId.toString(), | 
					
						
							|  |  |  |  |           userName: user.userName | 
					
						
							|  |  |  |  |         })); | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       ElMessage.error('获取用户列表失败'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } catch (error) { | 
					
						
							|  |  |  |  |     console.error('获取用户列表异常:', error); | 
					
						
							|  |  |  |  |     ElMessage.error('获取用户列表失败,请稍后重试'); | 
					
						
							|  |  |  |  |   } finally { | 
					
						
							|  |  |  |  |     loadingUsers.value = false; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   // 打开派单弹窗
 | 
					
						
							|  |  |  |  |   assignDialogVisible.value = true; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 确认派单
 | 
					
						
							|  |  |  |  | const confirmAssign = async () => { | 
					
						
							|  |  |  |  |   if (!selectedExecutor.value) { | 
					
						
							|  |  |  |  |     ElMessage.warning('请选择执行人'); | 
					
						
							|  |  |  |  |     return; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   try { | 
					
						
							|  |  |  |  |     assignLoading.value = true; | 
					
						
							|  |  |  |  |     // 调用updategongdan接口来执行派单操作
 | 
					
						
							|  |  |  |  |     // 从执行人列表中查找选中的执行人信息
 | 
					
						
							|  |  |  |  |     const selectedExecutorInfo = executors.value.find((item) => item.userId === selectedExecutor.value); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 先获取完整的工单详情
 | 
					
						
							|  |  |  |  |     const detailResponse = await gongdanDetail(currentTaskId.value); | 
					
						
							|  |  |  |  |     if (detailResponse.code !== 200) { | 
					
						
							|  |  |  |  |       ElMessage.error('获取工单详情失败'); | 
					
						
							|  |  |  |  |       return; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 获取完整的工单数据
 | 
					
						
							|  |  |  |  |     const workOrderDetail = detailResponse.data; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 在完整工单数据基础上进行修改
 | 
					
						
							|  |  |  |  |     const updateData = { | 
					
						
							|  |  |  |  |       ...workOrderDetail, | 
					
						
							|  |  |  |  |       // 状态更新为已派单(根据系统状态映射,2表示已派单)
 | 
					
						
							|  |  |  |  |       status: 2, | 
					
						
							|  |  |  |  |       // 设置执行人ID
 | 
					
						
							|  |  |  |  |       handler: selectedExecutor.value, | 
					
						
							|  |  |  |  |       // 设置执行人姓名
 | 
					
						
							|  |  |  |  |       handlerName: selectedExecutorInfo?.userName || '', | 
					
						
							|  |  |  |  |       // 设置派单人ID
 | 
					
						
							|  |  |  |  |       getOrderPerson: selectedExecutor.value, | 
					
						
							|  |  |  |  |       sendPerson: selectedExecutor.value, | 
					
						
							|  |  |  |  |       // 设置派单人Vo对象(包含id和userName)
 | 
					
						
							|  |  |  |  |       getOrderPersonVo: selectedExecutorInfo | 
					
						
							|  |  |  |  |         ? { | 
					
						
							|  |  |  |  |             id: selectedExecutor.value, | 
					
						
							|  |  |  |  |             userName: selectedExecutorInfo.userName | 
					
						
							|  |  |  |  |           } | 
					
						
							|  |  |  |  |         : null, | 
					
						
							|  |  |  |  |       // 更新时间
 | 
					
						
							|  |  |  |  |       updateTime: new Date().toISOString(), | 
					
						
							|  |  |  |  |       // 设置派单时间
 | 
					
						
							|  |  |  |  |       sendOrderTime: new Date().toISOString(), | 
					
						
							|  |  |  |  |       // 确保类型字段正确
 | 
					
						
							|  |  |  |  |       type: workOrderDetail.type || 1 | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     const response = await updategongdan(updateData); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (response.code === 200) { | 
					
						
							|  |  |  |  |       ElMessage.success('派单成功'); | 
					
						
							|  |  |  |  |       assignDialogVisible.value = false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       // 刷新工单列表以显示更新后的状态
 | 
					
						
							|  |  |  |  |       fetchWorkOrderList(); | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       ElMessage.error(response.msg || '派单失败'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } catch (error) { | 
					
						
							|  |  |  |  |     console.error('派单异常:', error); | 
					
						
							|  |  |  |  |     ElMessage.error('派单失败,请稍后重试'); | 
					
						
							|  |  |  |  |   } finally { | 
					
						
							|  |  |  |  |     assignLoading.value = false; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 取消派单
 | 
					
						
							|  |  |  |  | const cancelAssign = () => { | 
					
						
							|  |  |  |  |   assignDialogVisible.value = false; | 
					
						
							|  |  |  |  |   selectedExecutor.value = ''; | 
					
						
							|  |  |  |  |   currentTaskId.value = ''; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 跟踪功能 - 已接单状态
 | 
					
						
							|  |  |  |  | const handleFollow = (row) => { | 
					
						
							|  |  |  |  |   console.log('跟踪:', row); | 
					
						
							|  |  |  |  |   // 实现跟踪功能
 | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 设置跟踪功能 - 已派单状态
 | 
					
						
							|  |  |  |  | const handleSetTrack = async (row) => { | 
					
						
							|  |  |  |  |   try { | 
					
						
							|  |  |  |  |     // 获取当前point值,默认为2(不跟踪)
 | 
					
						
							|  |  |  |  |     const currentPoint = row.point || '2'; | 
					
						
							|  |  |  |  |     // 确定新的point值和操作类型
 | 
					
						
							|  |  |  |  |     const newPoint = currentPoint === '1' ? '2' : '1'; | 
					
						
							|  |  |  |  |     const operationText = currentPoint === '1' ? '取消跟踪' : '设置跟踪'; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 弹出确认对话框
 | 
					
						
							|  |  |  |  |     await ElMessageBox.confirm(`确定要${operationText}该工单吗?`, '提示', { | 
					
						
							|  |  |  |  |       confirmButtonText: '确定', | 
					
						
							|  |  |  |  |       cancelButtonText: '取消', | 
					
						
							|  |  |  |  |       type: 'warning' | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 获取完整的工单详情
 | 
					
						
							|  |  |  |  |     const detailResponse = await gongdanDetail(row.id); | 
					
						
							|  |  |  |  |     if (detailResponse.code !== 200) { | 
					
						
							|  |  |  |  |       ElMessage.error('获取工单详情失败'); | 
					
						
							|  |  |  |  |       return; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 获取完整的工单数据
 | 
					
						
							|  |  |  |  |     const workOrderDetail = detailResponse.data; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 在完整工单数据基础上进行修改
 | 
					
						
							|  |  |  |  |     const updateData = { | 
					
						
							|  |  |  |  |       ...workOrderDetail, | 
					
						
							|  |  |  |  |       // 切换point值:1表示跟踪,2表示不跟踪
 | 
					
						
							|  |  |  |  |       point: newPoint, | 
					
						
							|  |  |  |  |       // 更新时间
 | 
					
						
							|  |  |  |  |       updateTime: new Date().toISOString() | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     const response = await updategongdan(updateData); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (response.code === 200) { | 
					
						
							|  |  |  |  |       ElMessage.success(`${operationText}成功`); | 
					
						
							|  |  |  |  |       // 刷新工单列表以显示更新后的状态
 | 
					
						
							|  |  |  |  |       fetchWorkOrderList(); | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       ElMessage.error(response.msg || `${operationText}失败`); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } catch (error) { | 
					
						
							|  |  |  |  |     if (error === 'cancel') { | 
					
						
							|  |  |  |  |       // 用户取消操作,不做处理
 | 
					
						
							|  |  |  |  |       return; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     console.error('设置跟踪异常:', error); | 
					
						
							|  |  |  |  |     ElMessage.error('设置跟踪失败,请稍后重试'); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 编辑工单
 | 
					
						
							|  |  |  |  | const handleEdit = async (row) => { | 
					
						
							|  |  |  |  |   console.log('编辑工单:', row); | 
					
						
							|  |  |  |  |   try { | 
					
						
							|  |  |  |  |     // 获取工单详情
 | 
					
						
							|  |  |  |  |     const detailResponse = await gongdanDetail(row.id); | 
					
						
							|  |  |  |  |     if (detailResponse.code !== 200) { | 
					
						
							|  |  |  |  |       ElMessage.error('获取工单详情失败'); | 
					
						
							|  |  |  |  |       return; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     const workOrderDetail = detailResponse.data; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 填充表单数据
 | 
					
						
							|  |  |  |  |     createForm.title = workOrderDetail.title || ''; | 
					
						
							|  |  |  |  |     createForm.type = mapCodeToType(workOrderDetail.type) || '维护保养'; | 
					
						
							|  |  |  |  |     createForm.priority = mapCodeToPriority(workOrderDetail.level) || '低'; | 
					
						
							|  |  |  |  |     createForm.deadline = workOrderDetail.endTime ? formatDate(workOrderDetail.endTime) : ''; | 
					
						
							|  |  |  |  |     createForm.description = workOrderDetail.info || ''; | 
					
						
							|  |  |  |  |     createForm.location = workOrderDetail.position || ''; | 
					
						
							|  |  |  |  |     createForm.relatedEquipment = workOrderDetail.device || ''; | 
					
						
							|  |  |  |  |     createForm.file = workOrderDetail.fileId || ''; | 
					
						
							|  |  |  |  |     createForm.resultDescription = workOrderDetail.results || ''; | 
					
						
							|  |  |  |  |     createForm.needAssignee = !!workOrderDetail.executor; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-28 20:12:49 +08:00
										 |  |  |  |     // 根据工单状态设置进度
 | 
					
						
							|  |  |  |  |     // 1: 待派单, 2: 已派单, 3: 执行中, 4: 已完成, 5: 已拒绝
 | 
					
						
							|  |  |  |  |     switch (workOrderDetail.status) { | 
					
						
							|  |  |  |  |       case '1': | 
					
						
							|  |  |  |  |         createForm.progress = 0; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case '2': | 
					
						
							|  |  |  |  |         createForm.progress = 25; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case '3': | 
					
						
							|  |  |  |  |         createForm.progress = 50; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case '4': | 
					
						
							|  |  |  |  |         createForm.progress = 100; | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       default: | 
					
						
							|  |  |  |  |         createForm.progress = 0; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |     // 填充步骤数据:从nodes数组中提取并按code排序
 | 
					
						
							|  |  |  |  |     if (workOrderDetail.nodes && Array.isArray(workOrderDetail.nodes)) { | 
					
						
							|  |  |  |  |       // 复制nodes数组并按code升序排序
 | 
					
						
							|  |  |  |  |       const sortedNodes = [...workOrderDetail.nodes].sort((a, b) => (a.code || 0) - (b.code || 0)); | 
					
						
							|  |  |  |  |       // 转换为createForm.steps所需的格式
 | 
					
						
							|  |  |  |  |       createForm.steps = sortedNodes.map((node) => ({ | 
					
						
							|  |  |  |  |         name: node.name || '', | 
					
						
							|  |  |  |  |         intendedPurpose: node.intendedPurpose || '', | 
					
						
							|  |  |  |  |         intendedTime: node.intendedTime ? formatDate(node.intendedTime, 'YYYY-MM-DD HH:mm') : '' | 
					
						
							|  |  |  |  |       })); | 
					
						
							|  |  |  |  |       // 确保至少有一个空步骤
 | 
					
						
							|  |  |  |  |       if (createForm.steps.length === 0) { | 
					
						
							|  |  |  |  |         createForm.steps = [{ name: '', intendedPurpose: '', intendedTime: '' }]; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       // 如果没有nodes数据,重置为默认的一个空步骤
 | 
					
						
							|  |  |  |  |       createForm.steps = [{ name: '', intendedPurpose: '', intendedTime: '' }]; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 存储当前编辑的工单ID,用于区分是创建还是编辑操作
 | 
					
						
							|  |  |  |  |     editingWorkOrderId.value = row.id; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 保存原始创建时间
 | 
					
						
							|  |  |  |  |     originalCreateTime.value = workOrderDetail.createTime || ''; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 打开新增工单的弹窗
 | 
					
						
							|  |  |  |  |     createDialogVisible.value = true; | 
					
						
							|  |  |  |  |   } catch (error) { | 
					
						
							|  |  |  |  |     console.error('打开编辑工单弹窗过程中发生错误:', error); | 
					
						
							|  |  |  |  |     ElMessage.error('打开编辑工单弹窗失败'); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 编辑状态下的工单ID
 | 
					
						
							|  |  |  |  | const editingWorkOrderId = ref(''); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 保存原始创建时间(编辑工单时使用)
 | 
					
						
							|  |  |  |  | const originalCreateTime = ref(''); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 查看工单进度
 | 
					
						
							|  |  |  |  | const handleViewProgress = (row) => { | 
					
						
							|  |  |  |  |   console.log('查看工单进度:', row); | 
					
						
							|  |  |  |  |   // 实现查看进度功能
 | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | // 编辑工单弹窗相关
 | 
					
						
							|  |  |  |  | const createDialogVisible = ref(false); | 
					
						
							|  |  |  |  | const createFormRef = ref(null); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const createForm = reactive({ | 
					
						
							|  |  |  |  |   title: '', | 
					
						
							|  |  |  |  |   type: '', | 
					
						
							|  |  |  |  |   priority: '', | 
					
						
							|  |  |  |  |   deadline: '', | 
					
						
							|  |  |  |  |   description: '', | 
					
						
							|  |  |  |  |   location: '', | 
					
						
							|  |  |  |  |   relatedEquipment: '', | 
					
						
							|  |  |  |  |   steps: [{ name: '', intendedPurpose: '', intendedTime: '' }], // 工单步骤数组
 | 
					
						
							|  |  |  |  |   file: '', | 
					
						
							|  |  |  |  |   fileList: [], | 
					
						
							|  |  |  |  |   resultDescription: '', | 
					
						
							| 
									
										
										
										
											2025-09-28 20:12:49 +08:00
										 |  |  |  |   needAssignee: 'false', | 
					
						
							|  |  |  |  |   progress: 0 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const createFormRules = { | 
					
						
							|  |  |  |  |   title: [{ required: true, message: '请输入工单标题', trigger: 'blur' }], | 
					
						
							|  |  |  |  |   type: [{ required: true, message: '请选择工单类型', trigger: 'change' }], | 
					
						
							|  |  |  |  |   priority: [{ required: true, message: '请选择优先级', trigger: 'change' }], | 
					
						
							|  |  |  |  |   deadline: [{ required: true, message: '请选择截止时间', trigger: 'change' }], | 
					
						
							|  |  |  |  |   description: [{ required: true, message: '请输入工单描述', trigger: 'blur' }], | 
					
						
							|  |  |  |  |   location: [{ required: true, message: '请输入执行地点', trigger: 'blur' }], | 
					
						
							|  |  |  |  |   needAssignee: [{ required: true, message: '请选择是否需要指定执行人', trigger: 'change' }] | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 添加试验步骤
 | 
					
						
							|  |  |  |  | const addStep = () => { | 
					
						
							|  |  |  |  |   createForm.steps.push({ name: '', intendedPurpose: '', intendedTime: '' }); | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 删除试验步骤
 | 
					
						
							|  |  |  |  | const deleteStep = (index) => { | 
					
						
							|  |  |  |  |   // 确保至少保留一个步骤
 | 
					
						
							|  |  |  |  |   if (createForm.steps.length <= 1) { | 
					
						
							|  |  |  |  |     ElMessage.warning('至少需要保留一个步骤'); | 
					
						
							|  |  |  |  |     return; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   createForm.steps.splice(index, 1); | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 提交编辑工单
 | 
					
						
							|  |  |  |  | const submitCreate = async () => { | 
					
						
							|  |  |  |  |   // 表单验证
 | 
					
						
							|  |  |  |  |   if (!createFormRef.value) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   try { | 
					
						
							|  |  |  |  |     await createFormRef.value.validate(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 准备步骤数据
 | 
					
						
							|  |  |  |  |     const stepsData = createForm.steps | 
					
						
							|  |  |  |  |       .filter((step) => step.name.trim() && step.intendedPurpose.trim()) | 
					
						
							|  |  |  |  |       .map((step, index) => ({ | 
					
						
							|  |  |  |  |         createTime: new Date().toISOString(), | 
					
						
							|  |  |  |  |         updateTime: new Date().toISOString(), | 
					
						
							|  |  |  |  |         params: {}, | 
					
						
							|  |  |  |  |         module: 1, | 
					
						
							|  |  |  |  |         code: index + 1, | 
					
						
							|  |  |  |  |         name: step.name, | 
					
						
							|  |  |  |  |         intendedPurpose: step.intendedPurpose, | 
					
						
							|  |  |  |  |         intendedTime: step.intendedTime ? new Date(step.intendedTime).toISOString() : new Date().toISOString(), | 
					
						
							|  |  |  |  |         finishTime: '', | 
					
						
							|  |  |  |  |         remark: '', | 
					
						
							|  |  |  |  |         status: 1 // 使用数字值而不是字符串,确保状态字段不为空
 | 
					
						
							|  |  |  |  |       })); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 编辑模式下,需要为每个步骤添加id,并调用updatejiedian接口
 | 
					
						
							|  |  |  |  |     let nodeIds = ''; | 
					
						
							|  |  |  |  |     if (editingWorkOrderId.value) { | 
					
						
							|  |  |  |  |       // 获取工单详情,以获取原始步骤的id
 | 
					
						
							|  |  |  |  |       const detailResponse = await gongdanDetail(editingWorkOrderId.value); | 
					
						
							|  |  |  |  |       if (detailResponse.code !== 200) { | 
					
						
							|  |  |  |  |         ElMessage.error('获取工单详情失败'); | 
					
						
							|  |  |  |  |         return; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       const workOrderDetail = detailResponse.data; | 
					
						
							|  |  |  |  |       if (workOrderDetail.nodes && Array.isArray(workOrderDetail.nodes)) { | 
					
						
							|  |  |  |  |         // 按code排序原始nodes数组
 | 
					
						
							|  |  |  |  |         const sortedNodes = [...workOrderDetail.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 = workOrderDetail.nodeIds; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       // 创建模式下,调用addjiedian接口,直接传递数组
 | 
					
						
							|  |  |  |  |       const jiedianResponse = await addjiedian(stepsData); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (jiedianResponse.code !== 200) { | 
					
						
							|  |  |  |  |         ElMessage.error('创建步骤失败'); | 
					
						
							|  |  |  |  |         return; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       // 获取返回的ids,实际返回格式中msg字段包含ids字符串,data为null
 | 
					
						
							|  |  |  |  |       if (jiedianResponse.code === 200 && jiedianResponse.msg) { | 
					
						
							|  |  |  |  |         nodeIds = jiedianResponse.msg; | 
					
						
							|  |  |  |  |       } else { | 
					
						
							|  |  |  |  |         ElMessage.warning('未获取到有效的步骤ID'); | 
					
						
							|  |  |  |  |         return; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 准备工单数据
 | 
					
						
							|  |  |  |  |     const workOrderData = { | 
					
						
							|  |  |  |  |       // 编辑模式下使用原始创建时间
 | 
					
						
							|  |  |  |  |       createTime: originalCreateTime.value, | 
					
						
							|  |  |  |  |       updateTime: new Date().toISOString(), | 
					
						
							|  |  |  |  |       params: {}, | 
					
						
							|  |  |  |  |       module: 1, | 
					
						
							|  |  |  |  |       projectId: 1, | 
					
						
							|  |  |  |  |       title: createForm.title, | 
					
						
							|  |  |  |  |       type: mapTypeToCode(createForm.type), | 
					
						
							|  |  |  |  |       level: mapPriorityToCode(createForm.priority), | 
					
						
							|  |  |  |  |       endTime: createForm.deadline ? new Date(createForm.deadline).toISOString() : '', | 
					
						
							|  |  |  |  |       info: createForm.description, | 
					
						
							|  |  |  |  |       position: createForm.location, | 
					
						
							|  |  |  |  |       device: createForm.relatedEquipment || '', | 
					
						
							|  |  |  |  |       fileId: createForm.file ? createForm.file : '', | 
					
						
							|  |  |  |  |       nodeIds: nodeIds, | 
					
						
							|  |  |  |  |       results: createForm.resultDescription || '', | 
					
						
							|  |  |  |  |       status: 1, // 待派单 1待派单2已派单3执行中4已完成
 | 
					
						
							|  |  |  |  |       sendOrderTime: '', // 只有在派单并选择人员后才赋值
 | 
					
						
							|  |  |  |  |       getOrderTime: '', | 
					
						
							|  |  |  |  |       finishiOrderTime: '', | 
					
						
							|  |  |  |  |       orderResult: '', // 验收结果1通过2需整改
 | 
					
						
							|  |  |  |  |       point: '2', // 默认不跟踪(2表示不跟踪,1表示跟踪)
 | 
					
						
							|  |  |  |  |       createDept: '', | 
					
						
							|  |  |  |  |       createBy: '', | 
					
						
							|  |  |  |  |       handlerDept: '', | 
					
						
							|  |  |  |  |       handler: '', | 
					
						
							| 
									
										
										
										
											2025-09-28 20:12:49 +08:00
										 |  |  |  |       handlerName: '', | 
					
						
							|  |  |  |  |       progress: createForm.progress || 0 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 编辑操作:调用updategongdan接口
 | 
					
						
							|  |  |  |  |     const updateData = { | 
					
						
							|  |  |  |  |       ...workOrderData, | 
					
						
							|  |  |  |  |       id: editingWorkOrderId.value | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  |     const response = await updategongdan(updateData); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (response.code === 200) { | 
					
						
							|  |  |  |  |       ElMessage.success('工单编辑成功'); | 
					
						
							|  |  |  |  |       createDialogVisible.value = false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       // 重置表单
 | 
					
						
							|  |  |  |  |       Object.keys(createForm).forEach((key) => { | 
					
						
							|  |  |  |  |         if (key === 'steps') { | 
					
						
							|  |  |  |  |           createForm[key] = [{ name: '', intendedPurpose: '', intendedTime: '' }]; | 
					
						
							|  |  |  |  |         } else if (key === 'fileList') { | 
					
						
							|  |  |  |  |           createForm[key] = []; | 
					
						
							| 
									
										
										
										
											2025-09-28 20:12:49 +08:00
										 |  |  |  |         } else if (key === 'progress') { | 
					
						
							|  |  |  |  |           createForm[key] = 0; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |         } else { | 
					
						
							|  |  |  |  |           createForm[key] = ''; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |       }); | 
					
						
							|  |  |  |  |       createForm.needAssignee = 'false'; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       // 重置编辑状态
 | 
					
						
							|  |  |  |  |       editingWorkOrderId.value = ''; | 
					
						
							|  |  |  |  |       originalCreateTime.value = ''; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       // 刷新工单列表
 | 
					
						
							|  |  |  |  |       fetchWorkOrderList(); | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       ElMessage.error('工单编辑失败'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } catch (error) { | 
					
						
							|  |  |  |  |     console.error('编辑工单过程中发生错误:', error); | 
					
						
							|  |  |  |  |     ElMessage.error(`编辑工单过程中发生错误: ${error.message || '未知错误'}`); | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | // 取消编辑工单
 | 
					
						
							|  |  |  |  | const cancelCreate = () => { | 
					
						
							|  |  |  |  |   createDialogVisible.value = false; | 
					
						
							|  |  |  |  |   // 重置表单
 | 
					
						
							|  |  |  |  |   Object.keys(createForm).forEach((key) => { | 
					
						
							|  |  |  |  |     if (key === 'steps') { | 
					
						
							|  |  |  |  |       createForm[key] = [{ name: '', intendedPurpose: '', intendedTime: '' }]; | 
					
						
							|  |  |  |  |     } else if (key === 'fileList') { | 
					
						
							|  |  |  |  |       createForm[key] = []; | 
					
						
							| 
									
										
										
										
											2025-09-28 20:12:49 +08:00
										 |  |  |  |     } else if (key === 'progress') { | 
					
						
							|  |  |  |  |       createForm[key] = 0; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |     } else { | 
					
						
							|  |  |  |  |       createForm[key] = ''; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   }); | 
					
						
							|  |  |  |  |   createForm.needAssignee = 'false'; | 
					
						
							|  |  |  |  |   editingWorkOrderId.value = ''; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 导航路由跳转
 | 
					
						
							|  |  |  |  | const handleInspection1 = () => { | 
					
						
							| 
									
										
										
										
											2025-09-28 18:54:52 +08:00
										 |  |  |  |   router.push('/znxj/rili'); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | const handleInspection2 = () => { | 
					
						
							| 
									
										
										
										
											2025-09-28 18:54:52 +08:00
										 |  |  |  |   router.push('/znxj/xjgl/InspectionManagement'); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | const handleInspection3 = () => { | 
					
						
							| 
									
										
										
										
											2025-09-28 18:54:52 +08:00
										 |  |  |  |   router.push('/znxj/sygl/shiyanguanli'); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | const handleInspection4 = () => { | 
					
						
							| 
									
										
										
										
											2025-09-28 18:54:52 +08:00
										 |  |  |  |   router.push('/znxj/bxgl/baoxiuguanli'); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | const handleInspection5 = () => { | 
					
						
							| 
									
										
										
										
											2025-09-28 18:54:52 +08:00
										 |  |  |  |   router.push('/znxj/qxgl/qiangxiuguanli'); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | const handleInspection6 = () => { | 
					
						
							| 
									
										
										
										
											2025-09-28 18:54:52 +08:00
										 |  |  |  |   router.push('/znxj/gdgl/gongdanliebiao'); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | const handleInspection7 = () => { | 
					
						
							| 
									
										
										
										
											2025-09-28 18:54:52 +08:00
										 |  |  |  |   router.push('/znxj/ywzz/renyuanzhuangtai'); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | const handleInspectionManagement1 = () => { | 
					
						
							| 
									
										
										
										
											2025-09-28 18:54:52 +08:00
										 |  |  |  |   router.push('/znxj/gdgl/gongdanliebiao'); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | const handleInspectionManagement2 = () => { | 
					
						
							| 
									
										
										
										
											2025-09-28 18:54:52 +08:00
										 |  |  |  |   router.push('/znxj/gdgl/paidanjilu'); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | const handleInspectionManagement3 = () => { | 
					
						
							| 
									
										
										
										
											2025-09-28 18:54:52 +08:00
										 |  |  |  |   router.push('/znxj/gdgl/zhixingjilu'); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | }; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // 关闭详情弹窗
 | 
					
						
							|  |  |  |  | const handleCloseDetailDialog = () => { | 
					
						
							|  |  |  |  |   detailDialogVisible.value = false; | 
					
						
							|  |  |  |  | }; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | </script> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | <style scoped> | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | @import url('./css/detail-dialog.css'); | 
					
						
							|  |  |  |  | @import url('./css/step-bars.css'); | 
					
						
							|  |  |  |  | .dispatch-records { | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   padding: 20px; | 
					
						
							|  |  |  |  |   background-color: #f5f7fa; | 
					
						
							|  |  |  |  |   min-height: 100vh; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | /* 美化后的步骤条样式 */ | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | .steps-container { | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   padding: 24px; | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #f8faff 0%, #f0f7ff 100%); | 
					
						
							|  |  |  |  |   border-radius: 12px; | 
					
						
							|  |  |  |  |   box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05); | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .steps-container::before { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: 0; | 
					
						
							|  |  |  |  |   left: 0; | 
					
						
							|  |  |  |  |   right: 0; | 
					
						
							|  |  |  |  |   height: 4px; | 
					
						
							|  |  |  |  |   background: linear-gradient(90deg, #165dff, #409eff, #69c0ff); | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-item { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: flex-start; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   margin-bottom: 32px; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   padding-bottom: 32px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-item:last-child { | 
					
						
							|  |  |  |  |   margin-bottom: 0; | 
					
						
							|  |  |  |  |   padding-bottom: 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-item:not(:last-child)::after { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   left: 16px; | 
					
						
							|  |  |  |  |   top: 40px; | 
					
						
							|  |  |  |  |   bottom: 0; | 
					
						
							|  |  |  |  |   width: 2px; | 
					
						
							|  |  |  |  |   background-color: #e4e7ed; | 
					
						
							|  |  |  |  |   z-index: 0; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-number { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   width: 40px; | 
					
						
							|  |  |  |  |   height: 40px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   background-color: #409eff; | 
					
						
							|  |  |  |  |   color: white; | 
					
						
							|  |  |  |  |   border-radius: 50%; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   margin-right: 20px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   flex-shrink: 0; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   font-weight: bold; | 
					
						
							|  |  |  |  |   font-size: 16px; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3); | 
					
						
							|  |  |  |  |   z-index: 1; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .step-number:hover { | 
					
						
							|  |  |  |  |   transform: scale(1.1); | 
					
						
							|  |  |  |  |   box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4); | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .step-number.completed { | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #52c41a, #73d13d); | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 8px rgba(82, 196, 26, 0.3); | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .step-number.pending { | 
					
						
							|  |  |  |  |   background-color: #f0f2f5; | 
					
						
							|  |  |  |  |   color: #909399; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .step-content { | 
					
						
							|  |  |  |  |   width: 200px; | 
					
						
							|  |  |  |  |   flex: 1; | 
					
						
							|  |  |  |  |   background-color: white; | 
					
						
							|  |  |  |  |   padding: 16px 20px; | 
					
						
							|  |  |  |  |   border-radius: 8px; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   z-index: 1; | 
					
						
							|  |  |  |  |   align-self: center; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .step-content:hover { | 
					
						
							|  |  |  |  |   box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); | 
					
						
							|  |  |  |  |   transform: translateY(-2px); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .step-name { | 
					
						
							|  |  |  |  |   font-size: 16px; | 
					
						
							|  |  |  |  |   font-weight: 600; | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							|  |  |  |  |   margin-bottom: 8px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .step-purpose { | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   color: #606266; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   margin-bottom: 8px; | 
					
						
							|  |  |  |  |   line-height: 1.5; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-time, | 
					
						
							|  |  |  |  | .step-finish-time { | 
					
						
							|  |  |  |  |   font-size: 13px; | 
					
						
							|  |  |  |  |   color: #909399; | 
					
						
							|  |  |  |  |   margin-bottom: 4px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .step-remark { | 
					
						
							|  |  |  |  |   font-size: 13px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   color: #165dff; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   margin-top: 8px; | 
					
						
							|  |  |  |  |   padding-top: 8px; | 
					
						
							|  |  |  |  |   border-top: 1px solid #e4e7ed; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-status { | 
					
						
							|  |  |  |  |   margin-left: 20px; | 
					
						
							|  |  |  |  |   padding: 8px 16px; | 
					
						
							|  |  |  |  |   border-radius: 20px; | 
					
						
							|  |  |  |  |   font-size: 13px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   font-weight: 500; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   flex-shrink: 0; | 
					
						
							|  |  |  |  |   align-self: center; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .step-status.completed { | 
					
						
							|  |  |  |  |   background-color: #f0f9ff; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   color: #165dff; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .step-status.pending { | 
					
						
							|  |  |  |  |   background-color: #fdf6ec; | 
					
						
							|  |  |  |  |   color: #fa8c16; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 步骤连接线 */ | 
					
						
							|  |  |  |  | .step-connector { | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   left: 16px; | 
					
						
							|  |  |  |  |   top: 40px; | 
					
						
							|  |  |  |  |   bottom: 0; | 
					
						
							|  |  |  |  |   width: 2px; | 
					
						
							|  |  |  |  |   background-color: #e4e7ed; | 
					
						
							|  |  |  |  |   z-index: 0; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 动画效果 */ | 
					
						
							|  |  |  |  | @keyframes fadeInUp { | 
					
						
							|  |  |  |  |   from { | 
					
						
							|  |  |  |  |     opacity: 0; | 
					
						
							|  |  |  |  |     transform: translateY(20px); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   to { | 
					
						
							|  |  |  |  |     opacity: 1; | 
					
						
							|  |  |  |  |     transform: translateY(0); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-item { | 
					
						
							|  |  |  |  |   animation: fadeInUp 0.5s ease-out; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-item:nth-child(1) { | 
					
						
							|  |  |  |  |   animation-delay: 0.1s; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | .step-item:nth-child(2) { | 
					
						
							|  |  |  |  |   animation-delay: 0.2s; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | .step-item:nth-child(3) { | 
					
						
							|  |  |  |  |   animation-delay: 0.3s; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | .step-item:nth-child(4) { | 
					
						
							|  |  |  |  |   animation-delay: 0.4s; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | .step-item:nth-child(5) { | 
					
						
							|  |  |  |  |   animation-delay: 0.5s; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .add-step-btn { | 
					
						
							|  |  |  |  |   margin-top: 10px; | 
					
						
							|  |  |  |  |   color: #409eff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .add-step-btn:hover { | 
					
						
							|  |  |  |  |   color: #66b1ff; | 
					
						
							|  |  |  |  |   background-color: #ecf5ff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .delete-step-btn { | 
					
						
							|  |  |  |  |   margin-top: 5px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 选项卡样式 */ | 
					
						
							|  |  |  |  | .tabs-wrapper { | 
					
						
							|  |  |  |  |   background-color: #fff; | 
					
						
							|  |  |  |  |   padding: 20px; | 
					
						
							|  |  |  |  |   border-radius: 8px; | 
					
						
							|  |  |  |  |   margin-bottom: 16px; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 筛选栏样式 */ | 
					
						
							|  |  |  |  | .filter-bar { | 
					
						
							|  |  |  |  |   background-color: #fff; | 
					
						
							|  |  |  |  |   border-radius: 8px; | 
					
						
							|  |  |  |  |   margin-bottom: 24px; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   padding: 16px 24px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | .filter-container { | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   display: flex; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   align-items: center; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   flex-wrap: wrap; | 
					
						
							|  |  |  |  |   gap: 16px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   width: 100%; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .filter-item { | 
					
						
							|  |  |  |  |   flex-shrink: 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | .filter-bar .el-select, | 
					
						
							|  |  |  |  | .filter-bar .el-date-picker { | 
					
						
							|  |  |  |  |   width: 180px; | 
					
						
							|  |  |  |  |   height: 36px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .filter-bar .el-select .el-input__inner, | 
					
						
							|  |  |  |  | .filter-bar .el-date-picker .el-input__inner { | 
					
						
							|  |  |  |  |   border-radius: 4px; | 
					
						
							|  |  |  |  |   border-color: #dcdfe6; | 
					
						
							|  |  |  |  |   transition: all 0.2s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .filter-bar .el-select .el-input__inner:focus, | 
					
						
							|  |  |  |  | .filter-bar .el-date-picker .el-input__inner:focus { | 
					
						
							|  |  |  |  |   border-color: #165dff; | 
					
						
							|  |  |  |  |   box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .filter-actions { | 
					
						
							|  |  |  |  |   margin-left: auto; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   gap: 12px; | 
					
						
							|  |  |  |  |   flex-shrink: 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .search-btn, | 
					
						
							|  |  |  |  | .create-btn { | 
					
						
							|  |  |  |  |   height: 36px; | 
					
						
							|  |  |  |  |   border-radius: 4px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 统计卡片样式 */ | 
					
						
							|  |  |  |  | .statistics-cards { | 
					
						
							|  |  |  |  |   display: grid; | 
					
						
							|  |  |  |  |   grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | 
					
						
							|  |  |  |  |   gap: 16px; | 
					
						
							|  |  |  |  |   margin-bottom: 24px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .stat-card { | 
					
						
							|  |  |  |  |   background-color: #fff; | 
					
						
							|  |  |  |  |   border-radius: 12px; | 
					
						
							|  |  |  |  |   padding: 24px; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05); | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .stat-card:hover { | 
					
						
							|  |  |  |  |   transform: translateY(-2px); | 
					
						
							|  |  |  |  |   box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .stat-value { | 
					
						
							|  |  |  |  |   font-size: 28px; | 
					
						
							|  |  |  |  |   font-weight: 600; | 
					
						
							|  |  |  |  |   color: #1d2129; | 
					
						
							|  |  |  |  |   margin-bottom: 8px; | 
					
						
							|  |  |  |  |   line-height: 1.2; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .stat-label { | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   color: #86909c; | 
					
						
							|  |  |  |  |   margin-bottom: 8px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .stat-trend { | 
					
						
							|  |  |  |  |   font-size: 12px; | 
					
						
							|  |  |  |  |   color: #86909c; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .trend-up { | 
					
						
							|  |  |  |  |   color: #52c41a; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .trend-down { | 
					
						
							|  |  |  |  |   color: #ff4d4f; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .stat-icon { | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: 24px; | 
					
						
							|  |  |  |  |   right: 24px; | 
					
						
							|  |  |  |  |   width: 50px; | 
					
						
							|  |  |  |  |   height: 50px; | 
					
						
							|  |  |  |  |   border-radius: 12px; | 
					
						
							|  |  |  |  |   background-color: #f0f7ff; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .stat-icon:hover { | 
					
						
							|  |  |  |  |   transform: scale(1.05); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 统计卡片图片样式 */ | 
					
						
							|  |  |  |  | .stat-img { | 
					
						
							|  |  |  |  |   width: 35px; | 
					
						
							|  |  |  |  |   height: 35px; | 
					
						
							|  |  |  |  |   object-fit: contain; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .stat-icon:hover .stat-img { | 
					
						
							|  |  |  |  |   transform: scale(1.1); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 表格样式 */ | 
					
						
							|  |  |  |  | .table-wrapper { | 
					
						
							|  |  |  |  |   background-color: #fff; | 
					
						
							|  |  |  |  |   border-radius: 8px; | 
					
						
							|  |  |  |  |   margin-bottom: 24px; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05); | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-table { | 
					
						
							|  |  |  |  |   border-collapse: collapse; | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-table th { | 
					
						
							|  |  |  |  |   background-color: #f5f7fa; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  |   color: #606266; | 
					
						
							|  |  |  |  |   text-align: center; | 
					
						
							|  |  |  |  |   padding: 12px 8px; | 
					
						
							|  |  |  |  |   border-bottom: 1px solid #e4e7ed; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-table td { | 
					
						
							|  |  |  |  |   padding: 12px 8px; | 
					
						
							|  |  |  |  |   border-bottom: 1px solid #e4e7ed; | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							|  |  |  |  |   text-align: center; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-table tr:hover { | 
					
						
							|  |  |  |  |   background-color: #f5f7fa; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-table tr.current-row { | 
					
						
							|  |  |  |  |   background-color: #ecf5ff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .type-tag, | 
					
						
							|  |  |  |  | .priority-tag, | 
					
						
							|  |  |  |  | .status-tag, | 
					
						
							|  |  |  |  | .tracking-tag { | 
					
						
							|  |  |  |  |   padding: 4px 10px; | 
					
						
							|  |  |  |  |   border-radius: 6px; | 
					
						
							|  |  |  |  |   font-size: 12px; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  |   display: inline-flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   gap: 4px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 跟踪标签样式 */ | 
					
						
							|  |  |  |  | .tracking-tag.executing { | 
					
						
							|  |  |  |  |   background-color: #e6f7ff; | 
					
						
							|  |  |  |  |   color: #1890ff; | 
					
						
							|  |  |  |  |   border: 1px solid #91d5ff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 操作按钮样式 */ | 
					
						
							|  |  |  |  | .action-btn { | 
					
						
							|  |  |  |  |   color: #165dff; | 
					
						
							|  |  |  |  |   font-size: 12px; | 
					
						
							|  |  |  |  |   padding: 4px 8px; | 
					
						
							|  |  |  |  |   margin: 0 2px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .action-btn:hover { | 
					
						
							|  |  |  |  |   color: #0e42d2; | 
					
						
							|  |  |  |  |   background-color: #e8f3ff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .cancel-btn { | 
					
						
							|  |  |  |  |   color: #f56c6c; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .cancel-btn:hover { | 
					
						
							|  |  |  |  |   color: #e64340; | 
					
						
							|  |  |  |  |   background-color: #fff2f0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 分页区域样式 */ | 
					
						
							|  |  |  |  | .pagination-section { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   justify-content: space-between; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   background-color: #fff; | 
					
						
							|  |  |  |  |   padding: 16px 24px; | 
					
						
							|  |  |  |  |   border-radius: 8px; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .pagination-info { | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   color: #606266; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .pagination-controls .el-pagination { | 
					
						
							|  |  |  |  |   margin: 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .pagination-controls .el-pagination button, | 
					
						
							|  |  |  |  | .pagination-controls .el-pagination .el-pager li { | 
					
						
							|  |  |  |  |   min-width: 36px; | 
					
						
							|  |  |  |  |   height: 36px; | 
					
						
							|  |  |  |  |   line-height: 36px; | 
					
						
							|  |  |  |  |   border-radius: 4px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .pagination-controls .el-pagination .el-pager li.active { | 
					
						
							|  |  |  |  |   background-color: #165dff; | 
					
						
							|  |  |  |  |   color: #fff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 导航栏样式 */ | 
					
						
							| 
									
										
										
										
											2025-09-29 17:17:42 +08:00
										 |  |  |  | /* 导航栏相关样式移除(对应模板已注释) */ | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 弹窗样式 */ | 
					
						
							|  |  |  |  | .create-dialog { | 
					
						
							|  |  |  |  |   border-radius: 12px; | 
					
						
							|  |  |  |  |   box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15); | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .create-dialog .el-dialog__header { | 
					
						
							|  |  |  |  |   padding: 20px 24px; | 
					
						
							|  |  |  |  |   border-bottom: 1px solid #f0f0f0; | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #f8f9ff 0%, #f0f2ff 100%); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .create-dialog .el-dialog__title { | 
					
						
							|  |  |  |  |   font-size: 18px; | 
					
						
							|  |  |  |  |   font-weight: 600; | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							|  |  |  |  |   letter-spacing: 0.5px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .create-dialog .el-dialog__body { | 
					
						
							|  |  |  |  |   padding: 24px; | 
					
						
							|  |  |  |  |   background-color: #ffffff; | 
					
						
							|  |  |  |  |   max-height: 70vh; | 
					
						
							|  |  |  |  |   overflow-y: auto; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-form .el-form-item { | 
					
						
							|  |  |  |  |   margin-bottom: 20px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-form .el-form-item__label { | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  |   padding: 10px 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 表单元素美化 */ | 
					
						
							|  |  |  |  | .custom-form .el-input__inner, | 
					
						
							|  |  |  |  | .custom-form .el-select .el-input__inner, | 
					
						
							|  |  |  |  | .custom-form .el-date-picker .el-input__inner { | 
					
						
							|  |  |  |  |   border-radius: 6px; | 
					
						
							|  |  |  |  |   border-color: #dcdfe6; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  |   height: 40px; | 
					
						
							|  |  |  |  |   padding: 0 15px; | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   background-color: #fff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-form .el-input__inner:hover, | 
					
						
							|  |  |  |  | .custom-form .el-select .el-input__inner:hover, | 
					
						
							|  |  |  |  | .custom-form .el-date-picker .el-input__inner:hover { | 
					
						
							|  |  |  |  |   border-color: #c0c4cc; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-form .el-input__inner:focus, | 
					
						
							|  |  |  |  | .custom-form .el-select .el-input__inner:focus, | 
					
						
							|  |  |  |  | .custom-form .el-date-picker .el-input__inner:focus { | 
					
						
							|  |  |  |  |   border-color: #165dff; | 
					
						
							|  |  |  |  |   box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 文本域美化 */ | 
					
						
							|  |  |  |  | .custom-form .el-textarea__inner { | 
					
						
							|  |  |  |  |   border-radius: 6px; | 
					
						
							|  |  |  |  |   border-color: #dcdfe6; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  |   padding: 10px 15px; | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   resize: vertical; | 
					
						
							|  |  |  |  |   min-height: 100px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-form .el-textarea__inner:hover { | 
					
						
							|  |  |  |  |   border-color: #c0c4cc; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-form .el-textarea__inner:focus { | 
					
						
							|  |  |  |  |   border-color: #165dff; | 
					
						
							|  |  |  |  |   box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 单选按钮美化 */ | 
					
						
							|  |  |  |  | .custom-form .el-radio-group { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   gap: 20px; | 
					
						
							|  |  |  |  |   padding: 5px 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-form .el-radio { | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-form .el-radio__label { | 
					
						
							|  |  |  |  |   padding-left: 8px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 弹窗按钮美化 */ | 
					
						
							|  |  |  |  | .create-dialog .dialog-footer { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   justify-content: flex-end; | 
					
						
							|  |  |  |  |   gap: 12px; | 
					
						
							|  |  |  |  |   padding: 16px 24px; | 
					
						
							|  |  |  |  |   background-color: #fafafa; | 
					
						
							|  |  |  |  |   border-top: 1px solid #f0f0f0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .create-dialog .dialog-footer .el-button { | 
					
						
							|  |  |  |  |   padding: 10px 24px; | 
					
						
							|  |  |  |  |   border-radius: 6px; | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  |   height: 40px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .create-dialog .dialog-footer .el-button:first-child { | 
					
						
							|  |  |  |  |   background-color: #f5f7fa; | 
					
						
							|  |  |  |  |   color: #606266; | 
					
						
							|  |  |  |  |   border-color: #f5f7fa; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .create-dialog .dialog-footer .el-button:first-child:hover { | 
					
						
							|  |  |  |  |   background-color: #e6e8eb; | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							|  |  |  |  |   border-color: #e6e8eb; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .create-dialog .dialog-footer .el-button:nth-child(2) { | 
					
						
							|  |  |  |  |   background-color: #f5f7fa; | 
					
						
							|  |  |  |  |   color: #606266; | 
					
						
							|  |  |  |  |   border-color: #dcdfe6; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .create-dialog .dialog-footer .el-button:nth-child(2):hover { | 
					
						
							|  |  |  |  |   background-color: #e6e8eb; | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							|  |  |  |  |   border-color: #c0c4cc; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .create-dialog .dialog-footer .el-button:last-child { | 
					
						
							|  |  |  |  |   background-color: #165dff; | 
					
						
							|  |  |  |  |   border-color: #165dff; | 
					
						
							|  |  |  |  |   color: #fff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .create-dialog .dialog-footer .el-button:last-child:hover { | 
					
						
							|  |  |  |  |   background-color: #0e42d2; | 
					
						
							|  |  |  |  |   border-color: #0e42d2; | 
					
						
							|  |  |  |  |   transform: translateY(-1px); | 
					
						
							|  |  |  |  |   box-shadow: 0 4px 12px rgba(22, 93, 255, 0.3); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 表单验证反馈 */ | 
					
						
							|  |  |  |  | .custom-form .el-form-item.is-error .el-input__inner, | 
					
						
							|  |  |  |  | .custom-form .el-form-item.is-error .el-select .el-input__inner { | 
					
						
							|  |  |  |  |   border-color: #f56c6c; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-form .el-form-item.is-error .el-input__inner:focus, | 
					
						
							|  |  |  |  | .custom-form .el-form-item.is-error .el-select .el-input__inner:focus { | 
					
						
							|  |  |  |  |   border-color: #f56c6c; | 
					
						
							|  |  |  |  |   box-shadow: 0 0 0 2px rgba(245, 108, 108, 0.1); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 详情弹窗样式 - 与工单列表页面保持一致 */ | 
					
						
							|  |  |  |  | .custom-experiment-dialog .el-dialog__body { | 
					
						
							|  |  |  |  |   max-height: 60vh; | 
					
						
							|  |  |  |  |   overflow-y: auto; | 
					
						
							|  |  |  |  |   padding: 24px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .task-detail-container { | 
					
						
							|  |  |  |  |   padding: 10px 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 详情卡片样式 */ | 
					
						
							|  |  |  |  | .detail-card { | 
					
						
							|  |  |  |  |   background-color: #fff; | 
					
						
							|  |  |  |  |   border-radius: 8px; | 
					
						
							|  |  |  |  |   padding: 20px; | 
					
						
							|  |  |  |  |   margin-bottom: 20px; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05); | 
					
						
							|  |  |  |  |   border: 1px solid #f0f2f5; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .card-title { | 
					
						
							|  |  |  |  |   font-size: 16px; | 
					
						
							|  |  |  |  |   font-weight: 600; | 
					
						
							|  |  |  |  |   color: #1d2129; | 
					
						
							|  |  |  |  |   margin-bottom: 16px; | 
					
						
							|  |  |  |  |   padding-bottom: 12px; | 
					
						
							|  |  |  |  |   border-bottom: 2px solid #409eff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .card-content { | 
					
						
							|  |  |  |  |   padding: 0 4px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 信息行和信息项样式 */ | 
					
						
							|  |  |  |  | .info-row { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   margin-bottom: 16px; | 
					
						
							|  |  |  |  |   flex-wrap: wrap; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .info-item { | 
					
						
							|  |  |  |  |   flex: 0 0 50%; | 
					
						
							|  |  |  |  |   margin-bottom: 12px; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: flex-start; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .info-item.full-width { | 
					
						
							|  |  |  |  |   flex: 0 0 100%; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .info-label { | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  |   color: #86909c; | 
					
						
							|  |  |  |  |   margin-right: 8px; | 
					
						
							|  |  |  |  |   min-width: 80px; | 
					
						
							|  |  |  |  |   flex-shrink: 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .info-value { | 
					
						
							|  |  |  |  |   color: #4e5969; | 
					
						
							|  |  |  |  |   flex: 1; | 
					
						
							|  |  |  |  |   word-break: break-all; | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 骨架屏样式 */ | 
					
						
							|  |  |  |  | .skeleton-loading { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   flex-direction: column; | 
					
						
							|  |  |  |  |   gap: 16px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .skeleton-card { | 
					
						
							|  |  |  |  |   background-color: #f5f5f5; | 
					
						
							|  |  |  |  |   border-radius: 8px; | 
					
						
							|  |  |  |  |   padding: 16px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .skeleton-header { | 
					
						
							|  |  |  |  |   height: 20px; | 
					
						
							|  |  |  |  |   width: 30%; | 
					
						
							|  |  |  |  |   background-color: #e0e0e0; | 
					
						
							|  |  |  |  |   border-radius: 4px; | 
					
						
							|  |  |  |  |   margin-bottom: 12px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .skeleton-content { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   flex-direction: column; | 
					
						
							|  |  |  |  |   gap: 8px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .skeleton-row { | 
					
						
							|  |  |  |  |   height: 16px; | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   background-color: #e0e0e0; | 
					
						
							|  |  |  |  |   border-radius: 4px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 优先级标签样式 */ | 
					
						
							|  |  |  |  | .task-status { | 
					
						
							|  |  |  |  |   padding: 4px 10px; | 
					
						
							|  |  |  |  |   border-radius: 6px; | 
					
						
							|  |  |  |  |   font-size: 12px; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  |   border: 1px solid transparent; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .priority-high { | 
					
						
							|  |  |  |  |   background-color: #fff2f0; | 
					
						
							|  |  |  |  |   color: #ff4d4f; | 
					
						
							|  |  |  |  |   border-color: #ffccc7; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .priority-medium { | 
					
						
							|  |  |  |  |   background-color: #fffbe6; | 
					
						
							|  |  |  |  |   color: #fa8c16; | 
					
						
							|  |  |  |  |   border-color: #ffe58f; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .priority-low { | 
					
						
							|  |  |  |  |   background-color: #e6f7ff; | 
					
						
							|  |  |  |  |   color: #1890ff; | 
					
						
							|  |  |  |  |   border-color: #91d5ff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .description-content, | 
					
						
							|  |  |  |  | .result-content { | 
					
						
							|  |  |  |  |   padding: 12px; | 
					
						
							|  |  |  |  |   background-color: #f9f9f9; | 
					
						
							|  |  |  |  |   border-radius: 4px; | 
					
						
							|  |  |  |  |   line-height: 1.6; | 
					
						
							|  |  |  |  |   color: #4e5969; | 
					
						
							|  |  |  |  |   font-size: 13px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .steps-container { | 
					
						
							|  |  |  |  |   padding: 16px; | 
					
						
							|  |  |  |  |   background-color: #fafafa; | 
					
						
							|  |  |  |  |   border-radius: 4px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .module-group { | 
					
						
							|  |  |  |  |   margin-bottom: 24px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .module-title { | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   font-weight: bold; | 
					
						
							|  |  |  |  |   margin-bottom: 12px; | 
					
						
							|  |  |  |  |   color: #333; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 多图片展示容器样式 */ | 
					
						
							|  |  |  |  | .images-container { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   flex-wrap: wrap; | 
					
						
							|  |  |  |  |   gap: 16px; | 
					
						
							|  |  |  |  |   margin-top: 12px; | 
					
						
							|  |  |  |  |   padding: 10px; | 
					
						
							|  |  |  |  |   background-color: #f9f9f9; | 
					
						
							|  |  |  |  |   border-radius: 8px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 单个图片项样式 */ | 
					
						
							|  |  |  |  | .image-item { | 
					
						
							|  |  |  |  |   flex: 0 0 auto; | 
					
						
							|  |  |  |  |   width: 200px; /* 固定宽度 */ | 
					
						
							|  |  |  |  |   height: 160px; /* 固定高度 */ | 
					
						
							|  |  |  |  |   border-radius: 6px; | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); | 
					
						
							|  |  |  |  |   transition: transform 0.3s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .image-item:hover { | 
					
						
							|  |  |  |  |   transform: scale(1.03); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 图片样式 */ | 
					
						
							|  |  |  |  | .detail-image { | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   height: 100%; | 
					
						
							|  |  |  |  |   object-fit: cover; /* 保持比例填充容器 */ | 
					
						
							|  |  |  |  |   display: block; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 图片加载失败样式 */ | 
					
						
							|  |  |  |  | .detail-image[src=''] { | 
					
						
							|  |  |  |  |   background-color: #f0f0f0; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							|  |  |  |  |   color: #999; | 
					
						
							|  |  |  |  |   font-size: 12px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | /* 重点跟踪区域样式 */ | 
					
						
							|  |  |  |  | .tracking-section { | 
					
						
							|  |  |  |  |   background-color: #fff; | 
					
						
							|  |  |  |  |   border-radius: 8px; | 
					
						
							|  |  |  |  |   margin-bottom: 24px; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05); | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  |   padding-bottom: 20px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 进度时间线容器 - 铺满居中显示 */ | 
					
						
							|  |  |  |  | .progress-timeline-container { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   min-height: 300px; | 
					
						
							|  |  |  |  |   padding: 20px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 进度时间线 */ | 
					
						
							|  |  |  |  | .progress-timeline { | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   margin: 0 auto; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 步骤条分页样式 */ | 
					
						
							|  |  |  |  | .steps-pagination { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   justify-content: right; | 
					
						
							|  |  |  |  |   margin-top: 20px; | 
					
						
							|  |  |  |  |   padding: 0 20px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .steps-pagination .el-pagination { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 步骤条居中优化 */ | 
					
						
							|  |  |  |  | .custom-steps { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 优化步骤条布局 */ | 
					
						
							|  |  |  |  | .el-steps--horizontal { | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   display: flex; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   justify-content: center; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 步骤内容居中显示 */ | 
					
						
							|  |  |  |  | .el-step { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   flex-direction: column; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   text-align: center; | 
					
						
							|  |  |  |  |   min-width: 250px; | 
					
						
							|  |  |  |  |   flex: 1; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-header { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   justify-content: space-between; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   padding: 16px 24px; | 
					
						
							|  |  |  |  |   border-bottom: 1px solid #f0f0f0; | 
					
						
							|  |  |  |  |   background-color: #f5f7fa; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-header h3 { | 
					
						
							|  |  |  |  |   font-size: 16px; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							|  |  |  |  |   margin: 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-tag { | 
					
						
							|  |  |  |  |   margin-left: 12px; | 
					
						
							|  |  |  |  |   background-color: #e6f7ff; | 
					
						
							|  |  |  |  |   color: #1890ff; | 
					
						
							|  |  |  |  |   padding: 2px 8px; | 
					
						
							|  |  |  |  |   border-radius: 4px; | 
					
						
							|  |  |  |  |   font-size: 12px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-card { | 
					
						
							|  |  |  |  |   padding: 24px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-title { | 
					
						
							|  |  |  |  |   margin-bottom: 24px; | 
					
						
							|  |  |  |  |   padding-bottom: 16px; | 
					
						
							|  |  |  |  |   border-bottom: 1px solid #f0f0f0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .task-type { | 
					
						
							|  |  |  |  |   display: inline-block; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							|  |  |  |  |   margin-right: 24px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .work-order-no, | 
					
						
							|  |  |  |  | .time-range { | 
					
						
							|  |  |  |  |   display: inline-block; | 
					
						
							|  |  |  |  |   color: #606266; | 
					
						
							|  |  |  |  |   margin-right: 24px; | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 动画效果 */ | 
					
						
							| 
									
										
										
										
											2025-09-29 17:17:42 +08:00
										 |  |  |  | /* 重复的 pulse 动画移除(下方已存在统一定义) */ | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-steps { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   padding: 20px 10px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   position: relative; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   background: #fff; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | /* 步骤标题样式 - 简洁大气 */ | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | .el-step__title { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   font-size: 16px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   font-weight: 600; | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   padding: 0 5px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | /* 步骤描述样式 - 简化布局 */ | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | .el-step__description { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   font-size: 13px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   color: #606266; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   line-height: 1.5; | 
					
						
							|  |  |  |  |   margin-top: 8px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   width: auto !important; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   max-width: 220px; | 
					
						
							|  |  |  |  |   padding: 6px 0; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | /* 当前步骤样式 - 突出重点 */ | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | .el-step__title.is-process { | 
					
						
							|  |  |  |  |   color: #165dff; | 
					
						
							|  |  |  |  |   font-weight: 700; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__icon.is-process { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   background: #165dff; | 
					
						
							|  |  |  |  |   border: 2px solid #e6f7ff; | 
					
						
							|  |  |  |  |   box-shadow: 0 0 0 4px rgba(22, 93, 255, 0.1); | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__icon.is-process .el-icon { | 
					
						
							|  |  |  |  |   color: #fff; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   font-size: 16px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | /* 已完成步骤样式 - 简洁明了 */ | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | .el-step__title.is-finish { | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   font-weight: 500; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__icon.is-finish { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   background: #52c41a; | 
					
						
							|  |  |  |  |   border: 2px solid #f6ffed; | 
					
						
							|  |  |  |  |   box-shadow: 0 0 0 4px rgba(82, 196, 26, 0.1); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__icon.is-finish .el-icon { | 
					
						
							|  |  |  |  |   color: #fff; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   font-size: 16px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | /* 待处理步骤样式 - 简约风格 */ | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | .el-step__icon.is-wait { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   background-color: #f5f7fa; | 
					
						
							|  |  |  |  |   border: 2px solid #e4e7ed; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__icon.is-wait:hover { | 
					
						
							|  |  |  |  |   background-color: #e6f7ff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__icon.is-wait .el-icon { | 
					
						
							|  |  |  |  |   color: #909399; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   font-size: 16px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | /* 连接线样式 - 简化设计 */ | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | .el-step__line { | 
					
						
							|  |  |  |  |   top: 50%; | 
					
						
							|  |  |  |  |   transform: translateY(-50%); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__line-inner { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   height: 4px; | 
					
						
							|  |  |  |  |   border-radius: 2px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | /* 连接线状态颜色 */ | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | .el-step__line.is-finish .el-step__line-inner { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   background: #52c41a; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__line.is-process .el-step__line-inner { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   background: #165dff; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__line.is-wait .el-step__line-inner { | 
					
						
							|  |  |  |  |   background-color: #e4e7ed; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | /* 图标样式标准化 */ | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | .el-step__icon { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   width: 36px; | 
					
						
							|  |  |  |  |   height: 36px; | 
					
						
							|  |  |  |  |   line-height: 32px; | 
					
						
							|  |  |  |  |   font-size: 16px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   border-radius: 50%; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 成功状态的图标 */ | 
					
						
							|  |  |  |  | .el-step__icon.is-success { | 
					
						
							|  |  |  |  |   background-color: #67c23a; | 
					
						
							|  |  |  |  |   color: white; | 
					
						
							|  |  |  |  |   box-shadow: 0 0 0 4px rgba(103, 194, 58, 0.1); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 进行中状态的图标 */ | 
					
						
							|  |  |  |  | .el-step__icon.is-process { | 
					
						
							|  |  |  |  |   background-color: #409eff; | 
					
						
							|  |  |  |  |   color: white; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   box-shadow: 0 0 0 4px rgba(64, 158, 255, 0.1); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 等待状态的图标 */ | 
					
						
							|  |  |  |  | .el-step__icon.is-wait { | 
					
						
							|  |  |  |  |   background-color: #f5f7fa; | 
					
						
							|  |  |  |  |   border-color: #e4e7ed; | 
					
						
							|  |  |  |  |   color: #c0c4cc; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 横向步骤条样式优化 */ | 
					
						
							|  |  |  |  | .el-steps--horizontal { | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | .el-steps--horizontal .el-step { | 
					
						
							|  |  |  |  |   padding-bottom: 0; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   min-height: 140px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   flex: 1; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   max-width: 280px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   flex-direction: column; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   text-align: center; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 等待状态标题 */ | 
					
						
							|  |  |  |  | .el-step__title.is-wait { | 
					
						
							|  |  |  |  |   color: #c0c4cc; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 描述样式增强 */ | 
					
						
							|  |  |  |  | .custom-steps .el-step__description, | 
					
						
							|  |  |  |  | .custom-steps .step-description { | 
					
						
							|  |  |  |  |   white-space: normal; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   font-size: 14px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   color: #606266; | 
					
						
							|  |  |  |  |   line-height: 1.6; | 
					
						
							|  |  |  |  |   padding: 12px 16px; | 
					
						
							|  |  |  |  |   background-color: #fafafa; | 
					
						
							|  |  |  |  |   border-radius: 8px; | 
					
						
							|  |  |  |  |   border-left: 4px solid transparent; | 
					
						
							|  |  |  |  |   min-height: 60px; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   width: 300px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   max-width: 300px; | 
					
						
							|  |  |  |  |   margin: 0 auto; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 成功状态描述 */ | 
					
						
							|  |  |  |  | .el-step__description.is-success, | 
					
						
							|  |  |  |  | .step-description.is-success { | 
					
						
							|  |  |  |  |   border-left-color: #67c23a; | 
					
						
							|  |  |  |  |   background-color: #f0f9eb; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 进行中状态描述 */ | 
					
						
							|  |  |  |  | .el-step__description.is-process, | 
					
						
							|  |  |  |  | .step-description.is-process { | 
					
						
							|  |  |  |  |   border-left-color: #409eff; | 
					
						
							|  |  |  |  |   background-color: #ecf5ff; | 
					
						
							|  |  |  |  |   box-shadow: 0 4px 12px rgba(64, 158, 255, 0.1); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 等待状态描述 */ | 
					
						
							|  |  |  |  | .el-step__description.is-wait, | 
					
						
							|  |  |  |  | .step-description.is-wait { | 
					
						
							|  |  |  |  |   border-left-color: #e4e7ed; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 步骤详情样式 */ | 
					
						
							|  |  |  |  | .step-person-time { | 
					
						
							|  |  |  |  |   font-size: 13px; | 
					
						
							|  |  |  |  |   color: #909399; | 
					
						
							|  |  |  |  |   margin-bottom: 8px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | .step-content { | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   color: #606266; | 
					
						
							|  |  |  |  |   line-height: 1.5; | 
					
						
							|  |  |  |  |   margin-bottom: 6px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | .step-remark { | 
					
						
							|  |  |  |  |   font-size: 12px; | 
					
						
							|  |  |  |  |   color: #909399; | 
					
						
							|  |  |  |  |   padding: 6px 10px; | 
					
						
							|  |  |  |  |   background-color: #f5f7fa; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   border-radius: 4px; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   margin-top: 6px; | 
					
						
							|  |  |  |  |   border-left: 3px solid #dcdfe6; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 悬浮效果增强 */ | 
					
						
							|  |  |  |  | .el-step:hover { | 
					
						
							|  |  |  |  |   transform: translateY(-3px); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | .el-step:hover .el-step__title { | 
					
						
							|  |  |  |  |   color: #409eff; | 
					
						
							|  |  |  |  |   transform: translateY(-2px); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | .el-step:hover .el-step__description { | 
					
						
							|  |  |  |  |   transform: translateY(-2px); | 
					
						
							|  |  |  |  |   box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | .el-step:hover .el-step__icon.is-process { | 
					
						
							|  |  |  |  |   transform: scale(1.1); | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 动画效果增强 */ | 
					
						
							|  |  |  |  | @keyframes float { | 
					
						
							|  |  |  |  |   0%, | 
					
						
							|  |  |  |  |   100% { | 
					
						
							|  |  |  |  |     transform: translateY(0) scale(1.05); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   50% { | 
					
						
							|  |  |  |  |     transform: translateY(-6px) scale(1.05); | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | @keyframes shimmer { | 
					
						
							|  |  |  |  |   0% { | 
					
						
							|  |  |  |  |     transform: translateX(-100%); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   100% { | 
					
						
							|  |  |  |  |     transform: translateX(250%); | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | @keyframes pulse { | 
					
						
							|  |  |  |  |   0% { | 
					
						
							|  |  |  |  |     box-shadow: 0 0 0 0 rgba(64, 158, 255, 0.4); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   70% { | 
					
						
							|  |  |  |  |     box-shadow: 0 0 0 10px rgba(64, 158, 255, 0); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   100% { | 
					
						
							|  |  |  |  |     box-shadow: 0 0 0 0 rgba(64, 158, 255, 0); | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | @keyframes successPulse { | 
					
						
							|  |  |  |  |   0% { | 
					
						
							|  |  |  |  |     transform: scale(0.8); | 
					
						
							|  |  |  |  |     opacity: 0; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   50% { | 
					
						
							|  |  |  |  |     transform: scale(1.1); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   100% { | 
					
						
							|  |  |  |  |     transform: scale(1); | 
					
						
							|  |  |  |  |     opacity: 1; | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | @keyframes fadeIn { | 
					
						
							|  |  |  |  |   from { | 
					
						
							|  |  |  |  |     opacity: 0; | 
					
						
							|  |  |  |  |     transform: translateY(10px); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   to { | 
					
						
							|  |  |  |  |     opacity: 1; | 
					
						
							|  |  |  |  |     transform: translateY(0); | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 步骤条容器样式 */ | 
					
						
							|  |  |  |  | .progress-timeline { | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   padding: 24px 0; | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); | 
					
						
							|  |  |  |  |   border-radius: 12px; | 
					
						
							|  |  |  |  |   margin-top: 16px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 自定义步骤条样式增强 */ | 
					
						
							|  |  |  |  | .custom-steps { | 
					
						
							|  |  |  |  |   --el-steps-process-text-color: #409eff; | 
					
						
							|  |  |  |  |   --el-steps-process-border-color: #409eff; | 
					
						
							|  |  |  |  |   --el-steps-process-bg-color: #409eff; | 
					
						
							|  |  |  |  |   --el-steps-success-text-color: #67c23a; | 
					
						
							|  |  |  |  |   --el-steps-success-border-color: #67c23a; | 
					
						
							|  |  |  |  |   --el-steps-success-bg-color: #67c23a; | 
					
						
							|  |  |  |  |   --el-steps-wait-text-color: #c0c4cc; | 
					
						
							|  |  |  |  |   --el-steps-wait-border-color: #c0c4cc; | 
					
						
							|  |  |  |  |   --el-steps-wait-bg-color: #c0c4cc; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .empty-state { | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   display: flex; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   justify-content: center; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   align-items: center; | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   padding: 60px 0; | 
					
						
							|  |  |  |  |   color: #999; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | /* 派单弹窗样式 */ | 
					
						
							|  |  |  |  | .assign-dialog-content { | 
					
						
							|  |  |  |  |   padding: 10px 0; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | .form-group { | 
					
						
							|  |  |  |  |   margin-bottom: 15px; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  | .form-label { | 
					
						
							|  |  |  |  |   display: block; | 
					
						
							|  |  |  |  |   margin-bottom: 8px; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |   color: #606266; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 响应式设计 */ | 
					
						
							|  |  |  |  | @media (max-width: 1200px) { | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   .filter-container { | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |     flex-direction: column; | 
					
						
							|  |  |  |  |     align-items: stretch; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   .filter-actions { | 
					
						
							|  |  |  |  |     margin-left: 0; | 
					
						
							|  |  |  |  |     justify-content: flex-end; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   .filter-bar .el-select, | 
					
						
							|  |  |  |  |   .filter-bar .el-date-picker { | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |     width: 100%; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | @media (max-width: 768px) { | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   .dispatch-records { | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  |     padding: 10px; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   .navigation-tabs { | 
					
						
							|  |  |  |  |     flex-wrap: wrap; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   .nav-tab { | 
					
						
							|  |  |  |  |     flex: 1 0 33%; | 
					
						
							|  |  |  |  |     padding: 10px 0; | 
					
						
							|  |  |  |  |     font-size: 12px; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   .pagination-section { | 
					
						
							|  |  |  |  |     flex-direction: column; | 
					
						
							|  |  |  |  |     align-items: flex-start; | 
					
						
							|  |  |  |  |     gap: 10px; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-25 20:03:08 +08:00
										 |  |  |  |   .detail-item { | 
					
						
							|  |  |  |  |     flex: 0 0 100%; | 
					
						
							|  |  |  |  |     padding-right: 0; | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .custom-steps { | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #f8faff, #f0f7ff); | 
					
						
							|  |  |  |  |   padding: 40px 20px; | 
					
						
							|  |  |  |  |   border-radius: 16px; | 
					
						
							|  |  |  |  |   box-shadow: 0 8px 30px rgba(0, 0, 0, 0.06); | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-09-29 17:17:42 +08:00
										 |  |  |  | /* 去重:自定义步骤条顶部装饰在下方统一块中定义 */ | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 重点跟踪区域样式 */ | 
					
						
							|  |  |  |  | .tracking-section { | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%); | 
					
						
							|  |  |  |  |   border-radius: 20px; | 
					
						
							|  |  |  |  |   margin-bottom: 30px; | 
					
						
							|  |  |  |  |   box-shadow: 0 8px 24px rgba(0, 0, 0, 0.05); | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  |   transition: transform 0.3s ease, box-shadow 0.3s ease; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   border: 1px solid #f0f5ff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-section::before { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: -50%; | 
					
						
							|  |  |  |  |   right: -50%; | 
					
						
							|  |  |  |  |   width: 300px; | 
					
						
							|  |  |  |  |   height: 300px; | 
					
						
							|  |  |  |  |   background: radial-gradient(circle, rgba(22, 93, 255, 0.03) 0%, rgba(22, 93, 255, 0) 70%); | 
					
						
							|  |  |  |  |   border-radius: 50%; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-section:hover { | 
					
						
							|  |  |  |  |   transform: translateY(-5px); | 
					
						
							|  |  |  |  |   box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); | 
					
						
							|  |  |  |  |   border-color: #e6f0ff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 跟踪头部样式 */ | 
					
						
							|  |  |  |  | .tracking-header { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   justify-content: space-between; | 
					
						
							|  |  |  |  |   padding: 24px 32px; | 
					
						
							|  |  |  |  |   border-bottom: 1px solid #f0f2f5; | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #f8f9ff 0%, #f0f2ff 100%); | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 头部装饰效果 */ | 
					
						
							|  |  |  |  | .tracking-header::before { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: -100px; | 
					
						
							|  |  |  |  |   right: -100px; | 
					
						
							|  |  |  |  |   width: 400px; | 
					
						
							|  |  |  |  |   height: 400px; | 
					
						
							|  |  |  |  |   background: radial-gradient(circle, rgba(22, 93, 255, 0.08) 0%, rgba(22, 93, 255, 0) 70%); | 
					
						
							|  |  |  |  |   border-radius: 50%; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-header::after { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   bottom: -50px; | 
					
						
							|  |  |  |  |   left: -50px; | 
					
						
							|  |  |  |  |   width: 200px; | 
					
						
							|  |  |  |  |   height: 200px; | 
					
						
							|  |  |  |  |   background: radial-gradient(circle, rgba(22, 93, 255, 0.03) 0%, rgba(22, 93, 255, 0) 70%); | 
					
						
							|  |  |  |  |   border-radius: 50%; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-header h3 { | 
					
						
							|  |  |  |  |   font-size: 20px; | 
					
						
							|  |  |  |  |   font-weight: 700; | 
					
						
							|  |  |  |  |   color: #1d2129; | 
					
						
							|  |  |  |  |   margin: 0; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   z-index: 1; | 
					
						
							|  |  |  |  |   letter-spacing: -0.2px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 标题图标装饰 */ | 
					
						
							|  |  |  |  | .tracking-header h3::before { | 
					
						
							|  |  |  |  |   content: '📊'; | 
					
						
							|  |  |  |  |   margin-right: 12px; | 
					
						
							|  |  |  |  |   font-size: 24px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-tag { | 
					
						
							|  |  |  |  |   margin-left: 12px; | 
					
						
							|  |  |  |  |   background-color: #e6f7ff; | 
					
						
							|  |  |  |  |   color: #1890ff; | 
					
						
							|  |  |  |  |   padding: 4px 12px; | 
					
						
							|  |  |  |  |   border-radius: 16px; | 
					
						
							|  |  |  |  |   font-size: 12px; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   gap: 4px; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-tag::before { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   width: 6px; | 
					
						
							|  |  |  |  |   height: 6px; | 
					
						
							|  |  |  |  |   border-radius: 50%; | 
					
						
							|  |  |  |  |   background-color: #1890ff; | 
					
						
							|  |  |  |  |   animation: pulse 2s infinite; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | @keyframes pulse { | 
					
						
							|  |  |  |  |   0% { | 
					
						
							|  |  |  |  |     box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.4); | 
					
						
							|  |  |  |  |     opacity: 1; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   70% { | 
					
						
							|  |  |  |  |     box-shadow: 0 0 0 10px rgba(24, 144, 255, 0); | 
					
						
							|  |  |  |  |     opacity: 0; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   100% { | 
					
						
							|  |  |  |  |     box-shadow: 0 0 0 0 rgba(24, 144, 255, 0); | 
					
						
							|  |  |  |  |     opacity: 0; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 跟踪内容卡片 */ | 
					
						
							|  |  |  |  | .tracking-card { | 
					
						
							|  |  |  |  |   padding: 32px; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #ffffff 0%, #fcfdff 100%); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 工单标题信息 */ | 
					
						
							|  |  |  |  | .tracking-title { | 
					
						
							|  |  |  |  |   margin-bottom: 32px; | 
					
						
							|  |  |  |  |   padding-bottom: 18px; | 
					
						
							|  |  |  |  |   border-bottom: 2px solid #f0f2f5; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   flex-wrap: wrap; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   gap: 24px; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .tracking-title::after { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   bottom: -2px; | 
					
						
							|  |  |  |  |   left: 0; | 
					
						
							|  |  |  |  |   width: 80px; | 
					
						
							|  |  |  |  |   height: 2px; | 
					
						
							|  |  |  |  |   background: linear-gradient(90deg, #165dff, #69c0ff); | 
					
						
							|  |  |  |  |   box-shadow: 0 0 10px rgba(22, 93, 255, 0.2); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .task-type { | 
					
						
							|  |  |  |  |   font-size: 18px; | 
					
						
							|  |  |  |  |   font-weight: 600; | 
					
						
							|  |  |  |  |   color: #1d2129; | 
					
						
							|  |  |  |  |   padding-right: 16px; | 
					
						
							|  |  |  |  |   border-right: 1px solid #e5e6eb; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .work-order-no, | 
					
						
							|  |  |  |  | .time-range { | 
					
						
							|  |  |  |  |   color: #606266; | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   gap: 6px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .work-order-no::before, | 
					
						
							|  |  |  |  | .time-range::before { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   width: 4px; | 
					
						
							|  |  |  |  |   height: 4px; | 
					
						
							|  |  |  |  |   border-radius: 50%; | 
					
						
							|  |  |  |  |   background-color: #c9cdd4; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 进度时间线容器 */ | 
					
						
							|  |  |  |  | .progress-timeline-container { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   padding: 10px 0 30px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .progress-timeline { | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   max-width: 1400px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 自定义步骤条样式 */ | 
					
						
							|  |  |  |  | .custom-steps { | 
					
						
							|  |  |  |  |   --el-steps-process-text-color: #165dff; | 
					
						
							|  |  |  |  |   --el-steps-process-border-color: #165dff; | 
					
						
							|  |  |  |  |   --el-steps-process-bg-color: #165dff; | 
					
						
							|  |  |  |  |   --el-steps-success-text-color: #52c41a; | 
					
						
							|  |  |  |  |   --el-steps-success-border-color: #52c41a; | 
					
						
							|  |  |  |  |   --el-steps-success-bg-color: #52c41a; | 
					
						
							|  |  |  |  |   --el-steps-wait-text-color: #86909c; | 
					
						
							|  |  |  |  |   --el-steps-wait-border-color: #dcdfe6; | 
					
						
							|  |  |  |  |   --el-steps-wait-bg-color: #f2f3f5; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #f8faff 0%, #f0f7ff 100%); | 
					
						
							|  |  |  |  |   padding: 50px 30px 80px; | 
					
						
							|  |  |  |  |   border-radius: 24px; | 
					
						
							|  |  |  |  |   box-shadow: 0 12px 40px rgba(0, 0, 0, 0.08); | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  |   border: 1px solid #e6f0ff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 顶部装饰条 */ | 
					
						
							| 
									
										
										
										
											2025-09-29 17:17:42 +08:00
										 |  |  |  | /* 去重:自定义步骤条顶部装饰重复定义移除 */ | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 背景装饰 */ | 
					
						
							|  |  |  |  | .custom-steps::after { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   bottom: 0; | 
					
						
							|  |  |  |  |   left: 50%; | 
					
						
							|  |  |  |  |   transform: translateX(-50%); | 
					
						
							|  |  |  |  |   width: 400px; | 
					
						
							|  |  |  |  |   height: 400px; | 
					
						
							|  |  |  |  |   background: radial-gradient(circle, rgba(22, 93, 255, 0.05) 0%, rgba(22, 93, 255, 0) 70%); | 
					
						
							|  |  |  |  |   border-radius: 50%; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 左侧装饰 */ | 
					
						
							| 
									
										
										
										
											2025-09-29 17:17:42 +08:00
										 |  |  |  | /* 去重:重复 before 装饰定义移除 */ | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 右侧装饰 */ | 
					
						
							| 
									
										
										
										
											2025-09-29 17:17:42 +08:00
										 |  |  |  | /* 去重:重复 before 装饰定义移除 */ | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 左侧装饰球 */ | 
					
						
							|  |  |  |  | .custom-steps::before { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: 0; | 
					
						
							|  |  |  |  |   left: 0; | 
					
						
							|  |  |  |  |   right: 0; | 
					
						
							|  |  |  |  |   height: 6px; | 
					
						
							|  |  |  |  |   background: linear-gradient(90deg, #165dff, #409eff, #69c0ff); | 
					
						
							|  |  |  |  |   border-radius: 6px 6px 0 0; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 12px rgba(22, 93, 255, 0.2); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 右侧装饰球 */ | 
					
						
							|  |  |  |  | .custom-steps::before { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: 0; | 
					
						
							|  |  |  |  |   left: 0; | 
					
						
							|  |  |  |  |   right: 0; | 
					
						
							|  |  |  |  |   height: 6px; | 
					
						
							|  |  |  |  |   background: linear-gradient(90deg, #165dff, #409eff, #69c0ff); | 
					
						
							|  |  |  |  |   border-radius: 6px 6px 0 0; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 12px rgba(22, 93, 255, 0.2); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 单个步骤样式 */ | 
					
						
							|  |  |  |  | .custom-step { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   flex-direction: column; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   text-align: center; | 
					
						
							|  |  |  |  |   min-width: 220px; | 
					
						
							|  |  |  |  |   max-width: 280px; | 
					
						
							|  |  |  |  |   flex: 1; | 
					
						
							|  |  |  |  |   padding: 0 20px; | 
					
						
							|  |  |  |  |   transition: transform 0.3s ease, filter 0.3s ease, box-shadow 0.3s ease; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 15:18:50 +08:00
										 |  |  |  | /* 重点跟踪区域进度条样式 */ | 
					
						
							|  |  |  |  | .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; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | .custom-step:hover { | 
					
						
							|  |  |  |  |   transform: translateY(-8px); | 
					
						
							|  |  |  |  |   filter: brightness(1.03); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 15:18:50 +08:00
										 |  |  |  | /* 步骤连接线 - 默认(进行中) */ | 
					
						
							|  |  |  |  | .custom-step:not(:last-child):not(.is-wait)::after { | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: 32px; | 
					
						
							|  |  |  |  |   right: -20px; | 
					
						
							|  |  |  |  |   width: 40px; | 
					
						
							|  |  |  |  |   height: 3px; | 
					
						
							|  |  |  |  |   background: linear-gradient(90deg, #165dff 0%, #69c0ff 100%); | 
					
						
							|  |  |  |  |   z-index: 1; | 
					
						
							|  |  |  |  |   box-shadow: 0 2px 8px rgba(22, 93, 255, 0.3); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 15:18:50 +08:00
										 |  |  |  | /* 已完成步骤连接线 */ | 
					
						
							|  |  |  |  | .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); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 20:32:14 +08:00
										 |  |  |  | /* 待处理步骤连接线 */ | 
					
						
							|  |  |  |  | .custom-step.is-wait:not(:last-child)::after { | 
					
						
							|  |  |  |  |   background: linear-gradient(90deg, #dcdfe6 0%, #e4e7ed 100%); | 
					
						
							|  |  |  |  |   box-shadow: none; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 步骤节点容器 */ | 
					
						
							|  |  |  |  | .el-step__head { | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   z-index: 2; | 
					
						
							|  |  |  |  |   transition: transform 0.3s ease, box-shadow 0.3s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-step:hover .el-step__head { | 
					
						
							|  |  |  |  |   transform: scale(1.1); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 当前步骤节点增强 */ | 
					
						
							|  |  |  |  | .el-step__head.is-process { | 
					
						
							|  |  |  |  |   box-shadow: 0 0 20px rgba(22, 93, 255, 0.3); | 
					
						
							|  |  |  |  |   animation: glowProcess 2s ease-in-out infinite alternate; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | @keyframes glowProcess { | 
					
						
							|  |  |  |  |   from { | 
					
						
							|  |  |  |  |     box-shadow: 0 0 20px rgba(22, 93, 255, 0.3); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   to { | 
					
						
							|  |  |  |  |     box-shadow: 0 0 30px rgba(22, 93, 255, 0.5); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 已完成步骤节点增强 */ | 
					
						
							|  |  |  |  | .el-step__head.is-finish { | 
					
						
							|  |  |  |  |   box-shadow: 0 0 15px rgba(82, 196, 26, 0.25); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 步骤标题样式 */ | 
					
						
							|  |  |  |  | .el-step__title { | 
					
						
							|  |  |  |  |   font-size: 18px; | 
					
						
							|  |  |  |  |   font-weight: 600; | 
					
						
							|  |  |  |  |   color: #303133; | 
					
						
							|  |  |  |  |   margin-bottom: 20px; | 
					
						
							|  |  |  |  |   padding: 0 10px; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   letter-spacing: -0.2px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 步骤标题装饰 */ | 
					
						
							|  |  |  |  | .el-step__title::after { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   bottom: -6px; | 
					
						
							|  |  |  |  |   left: 50%; | 
					
						
							|  |  |  |  |   transform: translateX(-50%); | 
					
						
							|  |  |  |  |   width: 0; | 
					
						
							|  |  |  |  |   height: 3px; | 
					
						
							|  |  |  |  |   background: linear-gradient(90deg, #165dff, #69c0ff); | 
					
						
							|  |  |  |  |   border-radius: 2px; | 
					
						
							|  |  |  |  |   transition: width 0.3s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .custom-step:hover .el-step__title::after { | 
					
						
							|  |  |  |  |   width: 70%; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 当前步骤标题 */ | 
					
						
							|  |  |  |  | .el-step__title.is-process { | 
					
						
							|  |  |  |  |   color: #165dff; | 
					
						
							|  |  |  |  |   font-weight: 700; | 
					
						
							|  |  |  |  |   text-shadow: 0 2px 8px rgba(22, 93, 255, 0.15); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__title.is-process::after { | 
					
						
							|  |  |  |  |   width: 60%; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 已完成步骤标题 */ | 
					
						
							|  |  |  |  | .el-step__title.is-finish { | 
					
						
							|  |  |  |  |   color: #52c41a; | 
					
						
							|  |  |  |  |   font-weight: 600; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__title.is-finish::after { | 
					
						
							|  |  |  |  |   background: linear-gradient(90deg, #52c41a, #95de64); | 
					
						
							|  |  |  |  |   width: 40%; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 待处理步骤标题 */ | 
					
						
							|  |  |  |  | .el-step__title.is-wait { | 
					
						
							|  |  |  |  |   color: #86909c; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .el-step__title.is-wait::after { | 
					
						
							|  |  |  |  |   background: linear-gradient(90deg, #dcdfe6, #e4e7ed); | 
					
						
							|  |  |  |  |   width: 0%; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 步骤描述容器 */ | 
					
						
							|  |  |  |  | .step-description { | 
					
						
							|  |  |  |  |   white-space: normal; | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   color: #606266; | 
					
						
							|  |  |  |  |   line-height: 1.65; | 
					
						
							|  |  |  |  |   padding: 24px 28px; | 
					
						
							|  |  |  |  |   background-color: #ffffff; | 
					
						
							|  |  |  |  |   border-radius: 16px; | 
					
						
							|  |  |  |  |   min-height: 130px; | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   box-shadow: 0 8px 24px rgba(0, 0, 0, 0.05); | 
					
						
							|  |  |  |  |   transition: all 0.3s ease, transform 0.3s ease; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   overflow: hidden; | 
					
						
							|  |  |  |  |   border: 1px solid transparent; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-description:hover { | 
					
						
							|  |  |  |  |   transform: translateY(-5px); | 
					
						
							|  |  |  |  |   box-shadow: 0 12px 32px rgba(0, 0, 0, 0.08); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 步骤描述装饰 */ | 
					
						
							|  |  |  |  | .step-description::before { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: 0; | 
					
						
							|  |  |  |  |   left: 0; | 
					
						
							|  |  |  |  |   width: 6px; | 
					
						
							|  |  |  |  |   height: 100%; | 
					
						
							|  |  |  |  |   border-radius: 6px 0 0 6px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 进度条装饰 */ | 
					
						
							|  |  |  |  | .step-description::after { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   bottom: 0; | 
					
						
							|  |  |  |  |   left: 0; | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   height: 4px; | 
					
						
							|  |  |  |  |   background: linear-gradient(90deg, rgba(0, 0, 0, 0.03) 0%, rgba(0, 0, 0, 0) 100%); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 卡片背景装饰 */ | 
					
						
							|  |  |  |  | .step-description::before { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: 0; | 
					
						
							|  |  |  |  |   left: 0; | 
					
						
							|  |  |  |  |   width: 6px; | 
					
						
							|  |  |  |  |   height: 100%; | 
					
						
							|  |  |  |  |   border-radius: 6px 0 0 6px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 右上角装饰 */ | 
					
						
							|  |  |  |  | .step-description::before { | 
					
						
							|  |  |  |  |   content: ''; | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: 0; | 
					
						
							|  |  |  |  |   right: 0; | 
					
						
							|  |  |  |  |   width: 80px; | 
					
						
							|  |  |  |  |   height: 80px; | 
					
						
							|  |  |  |  |   background: radial-gradient(circle, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0) 70%); | 
					
						
							|  |  |  |  |   border-radius: 50%; | 
					
						
							|  |  |  |  |   transform: translate(30%, -30%); | 
					
						
							|  |  |  |  |   z-index: 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 进行中步骤描述 */ | 
					
						
							|  |  |  |  | .step-description.is-process { | 
					
						
							|  |  |  |  |   border: 1px solid #e6f7ff; | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #ffffff 0%, #f0f7ff 100%); | 
					
						
							|  |  |  |  |   box-shadow: 0 8px 24px rgba(22, 93, 255, 0.08); | 
					
						
							|  |  |  |  |   animation: subtlePulse 4s ease-in-out infinite; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-description.is-process::before { | 
					
						
							|  |  |  |  |   background: linear-gradient(180deg, #165dff, #69c0ff); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 已完成步骤描述 */ | 
					
						
							|  |  |  |  | .step-description.is-finish { | 
					
						
							|  |  |  |  |   border: 1px solid #f0f9eb; | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #ffffff 0%, #f6ffed 100%); | 
					
						
							|  |  |  |  |   box-shadow: 0 8px 24px rgba(82, 196, 26, 0.08); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-description.is-finish::before { | 
					
						
							|  |  |  |  |   background: linear-gradient(180deg, #52c41a, #95de64); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 待处理步骤描述 */ | 
					
						
							|  |  |  |  | .step-description.is-wait { | 
					
						
							|  |  |  |  |   border: 1px solid #f2f3f5; | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #ffffff 0%, #fafafa 100%); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-description.is-wait::before { | 
					
						
							|  |  |  |  |   background: linear-gradient(180deg, #dcdfe6, #e4e7ed); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 微妙的脉冲动画 */ | 
					
						
							|  |  |  |  | @keyframes subtlePulse { | 
					
						
							|  |  |  |  |   0%, | 
					
						
							|  |  |  |  |   100% { | 
					
						
							|  |  |  |  |     box-shadow: 0 8px 24px rgba(22, 93, 255, 0.08); | 
					
						
							|  |  |  |  |     transform: scale(1); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   50% { | 
					
						
							|  |  |  |  |     box-shadow: 0 10px 28px rgba(22, 93, 255, 0.12); | 
					
						
							|  |  |  |  |     transform: scale(1.01); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 步骤详情样式 */ | 
					
						
							|  |  |  |  | .step-person-time { | 
					
						
							|  |  |  |  |   font-size: 13px; | 
					
						
							|  |  |  |  |   color: #1d2129; | 
					
						
							|  |  |  |  |   margin-bottom: 12px; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   gap: 6px; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   z-index: 1; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-person-time::before { | 
					
						
							|  |  |  |  |   content: '👤'; | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-content { | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   color: #4e5969; | 
					
						
							|  |  |  |  |   line-height: 1.6; | 
					
						
							|  |  |  |  |   margin-bottom: 12px; | 
					
						
							|  |  |  |  |   padding-bottom: 10px; | 
					
						
							|  |  |  |  |   border-bottom: 1px dashed #e5e6eb; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   z-index: 1; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-time, | 
					
						
							|  |  |  |  | .step-finish-time { | 
					
						
							|  |  |  |  |   font-size: 13px; | 
					
						
							|  |  |  |  |   color: #86909c; | 
					
						
							|  |  |  |  |   margin-bottom: 6px; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   gap: 6px; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   z-index: 1; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-time::before { | 
					
						
							|  |  |  |  |   content: '📅'; | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-finish-time::before { | 
					
						
							|  |  |  |  |   content: '✓'; | 
					
						
							|  |  |  |  |   color: #52c41a; | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  |   font-weight: bold; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-remark { | 
					
						
							|  |  |  |  |   font-size: 13px; | 
					
						
							|  |  |  |  |   color: #fa541c; | 
					
						
							|  |  |  |  |   margin-top: 10px; | 
					
						
							|  |  |  |  |   padding-top: 10px; | 
					
						
							|  |  |  |  |   border-top: 1px dashed #fff2e8; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   gap: 6px; | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							|  |  |  |  |   z-index: 1; | 
					
						
							|  |  |  |  |   background: linear-gradient(180deg, rgba(250, 84, 28, 0.03) 0%, rgba(250, 84, 28, 0) 100%); | 
					
						
							|  |  |  |  |   padding: 10px 0 0 0; | 
					
						
							|  |  |  |  |   margin: 10px -24px 0 -24px; | 
					
						
							|  |  |  |  |   padding-left: 24px; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .step-remark::before { | 
					
						
							|  |  |  |  |   content: '💬'; | 
					
						
							|  |  |  |  |   font-size: 14px; | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-09-17 15:53:38 +08:00
										 |  |  |  | </style> |