1
This commit is contained in:
		| @ -95,8 +95,8 @@ | ||||
|           </div> | ||||
|  | ||||
|           <div class="task-actions"> | ||||
|             <el-button type="text" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button> | ||||
|             <el-button type="primary" size="small" :class="task.actionClass" @click="handleAction(task)"> | ||||
|             <el-button type="text" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button> | ||||
|             <el-button type="primary" :class="task.actionClass" @click="handleAction(task)"> | ||||
|               {{ task.actionText }} | ||||
|             </el-button> | ||||
|           </div> | ||||
| @ -853,7 +853,18 @@ const handleInspection7 = () => { | ||||
|   align-items: center; | ||||
|   padding-top: 12px; | ||||
|   border-top: 1px solid #f0f2f5; | ||||
|   margin-top: 12px; | ||||
|   position: absolute; | ||||
|   bottom: 16px; | ||||
|   right: 16px; | ||||
|   left: 16px; | ||||
|   background-color: #fff; | ||||
|   padding: 12px 0 0 0; | ||||
|   z-index: 10; | ||||
| } | ||||
|  | ||||
| .task-actions .el-button { | ||||
|   border-radius: 16px; | ||||
|   padding: 6px 16px; | ||||
| } | ||||
|  | ||||
| .task-card::before { | ||||
|  | ||||
| @ -1,184 +1,209 @@ | ||||
| <template> | ||||
|   <div class="container"> | ||||
|     <!-- 导航栏 --> | ||||
|     <div class="navigation-tabs"> | ||||
|       <div class="nav-tab active" @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" @click="handleInspection6">工单管理</div> | ||||
|       <div class="nav-tab" @click="handleInspection7">运维组织</div> | ||||
|     </div> | ||||
|   <div> | ||||
|     <div class="box-container"> | ||||
|       <!-- 导航栏 --> | ||||
|       <div class="navigation-tabs"> | ||||
|         <div class="nav-tab active" @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" @click="handleInspection6">工单管理</div> | ||||
|         <div class="nav-tab" @click="handleInspection7">运维组织</div> | ||||
|       </div> | ||||
|  | ||||
|     <!-- 标题栏 --> | ||||
|     <div class="header"> | ||||
|       <TitleComponent title="运维待办事项" subtitle="管理每日、每周等的运维工作任务"></TitleComponent> | ||||
|     </div> | ||||
|       <!-- 标题栏 --> | ||||
|       <div class="header"> | ||||
|         <TitleComponent title="运维待办事项" subtitle="管理每日、每周等的运维工作任务"></TitleComponent> | ||||
|       </div> | ||||
|  | ||||
|     <div class="main-content"> | ||||
|       <!-- 左侧日历区域 --> | ||||
|       <div class="calendar-container"> | ||||
|         <div class="calendar-header"> | ||||
|           <div class="calendar-title">待办月视图</div> | ||||
|           <div class="calendar-controls"> | ||||
|             <!-- 年份月份选择 --> | ||||
|             <el-select v-model="selectedYear" placeholder="选择年份" size="small" style="width: 80px; margin-right: 5px"> | ||||
|               <el-option v-for="year in years" :key="year" :label="year.toString()" :value="year"></el-option> | ||||
|             </el-select> | ||||
|             <el-select v-model="selectedMonth" placeholder="选择月份" size="small" style="width: 80px; margin-right: 10px"> | ||||
|               <el-option v-for="month in 12" :key="month" :label="month.toString()" :value="month"></el-option> | ||||
|             </el-select> | ||||
|             <!-- 月份切换按钮 --> | ||||
|             <el-button type="text" icon="el-icon-arrow-left" @click="decreaseMonth"></el-button> | ||||
|             <el-button type="text" icon="el-icon-arrow-right" @click="increaseMonth"></el-button> | ||||
|             <el-button type="primary" size="small">添加</el-button> | ||||
|             <el-button type="primary" size="small" @click="goToToday">今日</el-button> | ||||
|             <el-button type="text" icon="el-icon-plus"></el-button> | ||||
|       <div class="main-content"> | ||||
|         <!-- 左侧日历区域 --> | ||||
|         <div class="calendar-container"> | ||||
|           <div class="calendar-header"> | ||||
|             <div class="calendar-title">待办月视图</div> | ||||
|             <div class="calendar-controls"> | ||||
|               <!-- 月份选择器 --> | ||||
|               <el-date-picker v-model="currentDate" type="month" placeholder="选择月份" style="width: 120px; margin-right: 15px" /> | ||||
|  | ||||
|               <el-button type="primary">添加</el-button> | ||||
|               <el-button type="primary" @click="goToToday">今日</el-button> | ||||
|               <el-button type="text" icon="el-icon-plus"></el-button> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|         <!-- 使用 Element Plus 的日历组件 --> | ||||
|         <el-calendar v-model="currentDate"> | ||||
|           <template #date-cell="{ date, data }"> | ||||
|             <div class="custom-date-cell" :class="getCellClass(data.day)"> | ||||
|               <div class="date-day">{{ data.day.split('-').slice(2).join('-') }}</div> | ||||
|               <div class="date-events"> | ||||
|                 <div v-for="event in getDayEvents(data.day)" :key="event.id" class="event-item" :class="'event-' + event.type"> | ||||
|                   <div class="event-title">{{ event.title }}</div> | ||||
|                   <div class="event-description">{{ event.description }}</div> | ||||
|           <!-- 使用 Element Plus 的日历组件 --> | ||||
|           <el-calendar v-model="currentDate"> | ||||
|             <template #date-cell="{ date, data }"> | ||||
|               <div class="custom-date-cell" :class="getCellClass(data.day)"> | ||||
|                 <div class="date-day">{{ data.day.split('-').slice(2).join('-') }}</div> | ||||
|                 <div class="date-events"> | ||||
|                   <div v-for="event in getDayEvents(data.day)" :key="event.id" class="event-item" :class="'event-' + event.type"> | ||||
|                     <div class="event-title">{{ event.title }}</div> | ||||
|                     <div class="event-description">{{ event.description }}</div> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-calendar> | ||||
|       </div> | ||||
|  | ||||
|       <!-- 右侧表单区域 --> | ||||
|       <div class="form-container"> | ||||
|         <div class="form-header"> | ||||
|           <h2>今日待办</h2> | ||||
|           <el-button type="primary" size="small" icon="el-icon-plus" @click="openAddTaskDialog">添加</el-button> | ||||
|             </template> | ||||
|           </el-calendar> | ||||
|         </div> | ||||
|  | ||||
|         <!-- 待办事项列表 --> | ||||
|         <div class="todo-list"> | ||||
|           <!-- 待办项1 - 常规维护 --> | ||||
|           <div class="todo-item"> | ||||
|             <div class="todo-color-indicator normal"></div> | ||||
|             <el-checkbox class="todo-checkbox"></el-checkbox> | ||||
|             <div class="todo-content"> | ||||
|               <div class="todo-main"> | ||||
|                 <div class="todo-title">服务器例行检查</div> | ||||
|                 <div class="todo-time">09:00-10:00 AM</div> | ||||
|         <!-- 右侧表单区域 --> | ||||
|         <div class="form-container"> | ||||
|           <div class="form-header"> | ||||
|             <h2>今日待办</h2> | ||||
|             <el-button type="primary" size="small" icon="el-icon-plus" @click="openAddTaskDialog">添加</el-button> | ||||
|           </div> | ||||
|  | ||||
|           <!-- 待办事项列表 --> | ||||
|           <div class="todo-list"> | ||||
|             <!-- 待办项1 - 常规维护 --> | ||||
|             <div class="todo-item"> | ||||
|               <div class="todo-color-indicator normal"></div> | ||||
|               <el-checkbox class="todo-checkbox"></el-checkbox> | ||||
|               <div class="todo-content"> | ||||
|                 <div class="todo-main"> | ||||
|                   <div class="todo-title">服务器例行检查</div> | ||||
|                   <div class="todo-time">09:00-10:00 AM</div> | ||||
|                 </div> | ||||
|                 <div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div> | ||||
|               </div> | ||||
|               <div class="todo-actions"> | ||||
|                 <el-button type="primary" size="small" icon="el-icon-check">编辑</el-button> | ||||
|                 <el-button type="danger" size="small" icon="el-icon-delete">删除</el-button> | ||||
|               </div> | ||||
|             </div> | ||||
|  | ||||
|             <!-- 待办项2 - 重要 --> | ||||
|             <div class="todo-item important"> | ||||
|               <div class="todo-color-indicator important"></div> | ||||
|               <el-checkbox class="todo-checkbox"></el-checkbox> | ||||
|               <div class="todo-content"> | ||||
|                 <div class="todo-main"> | ||||
|                   <div class="todo-title">数据库备份</div> | ||||
|                   <div class="todo-time">14:00-15:00 PM</div> | ||||
|                 </div> | ||||
|                 <div class="todo-description">主要数据库全备份,并验证备份文件完整性</div> | ||||
|               </div> | ||||
|               <div class="todo-actions"> | ||||
|                 <el-button type="primary" size="small" icon="el-icon-check">编辑</el-button> | ||||
|                 <el-button type="danger" size="small" icon="el-icon-delete">删除</el-button> | ||||
|               </div> | ||||
|             </div> | ||||
|  | ||||
|             <!-- 待办项3 - 紧急 --> | ||||
|             <div class="todo-item"> | ||||
|               <div class="todo-color-indicator urgent"></div> | ||||
|               <el-checkbox class="todo-checkbox"></el-checkbox> | ||||
|               <div class="todo-content"> | ||||
|                 <div class="todo-main"> | ||||
|                   <div class="todo-title">网络设备固件更新</div> | ||||
|                   <div class="todo-time">18:00-20:00 PM</div> | ||||
|                 </div> | ||||
|                 <div class="todo-description">更新核心交换机和防火墙固件,需安排在业务低峰期</div> | ||||
|               </div> | ||||
|               <div class="todo-actions"> | ||||
|                 <el-button type="primary" size="small" icon="el-icon-check">编辑</el-button> | ||||
|                 <el-button type="danger" size="small" icon="el-icon-delete">删除</el-button> | ||||
|               </div> | ||||
|             </div> | ||||
|  | ||||
|             <!-- 待办项4 - 常规维护 --> | ||||
|             <div class="todo-item"> | ||||
|               <div class="todo-color-indicator normal"></div> | ||||
|               <el-checkbox class="todo-checkbox"></el-checkbox> | ||||
|               <div class="todo-content"> | ||||
|                 <div class="todo-main"> | ||||
|                   <div class="todo-title">服务器例行检查</div> | ||||
|                   <div class="todo-time">08:00-09:00 AM</div> | ||||
|                 </div> | ||||
|                 <div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div> | ||||
|               </div> | ||||
|               <div class="todo-actions"> | ||||
|                 <el-button type="primary" size="small" icon="el-icon-check">编辑</el-button> | ||||
|                 <el-button type="danger" size="small" icon="el-icon-delete">删除</el-button> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="todo-item"> | ||||
|               <div class="todo-color-indicator normal"></div> | ||||
|               <el-checkbox class="todo-checkbox"></el-checkbox> | ||||
|               <div class="todo-content"> | ||||
|                 <div class="todo-main"> | ||||
|                   <div class="todo-title">服务器例行检查</div> | ||||
|                   <div class="todo-time">06:00-07:00 AM</div> | ||||
|                 </div> | ||||
|                 <div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div> | ||||
|               </div> | ||||
|               <div class="todo-actions"> | ||||
|                 <el-button type="primary" size="small" icon="el-icon-check">编辑</el-button> | ||||
|                 <el-button type="danger" size="small" icon="el-icon-delete">删除</el-button> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="todo-item"> | ||||
|               <div class="todo-color-indicator normal"></div> | ||||
|               <el-checkbox class="todo-checkbox"></el-checkbox> | ||||
|               <div class="todo-content"> | ||||
|                 <div class="todo-main"> | ||||
|                   <div class="todo-title">服务器例行检查</div> | ||||
|                   <div class="todo-time">06:00-07:00 AM</div> | ||||
|                 </div> | ||||
|                 <div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div> | ||||
|               </div> | ||||
|               <div class="todo-actions"> | ||||
|                 <el-button type="primary" size="small" icon="el-icon-check">编辑</el-button> | ||||
|                 <el-button type="danger" size="small" icon="el-icon-delete">删除</el-button> | ||||
|               </div> | ||||
|               <div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div> | ||||
|             </div> | ||||
|           </div> | ||||
|  | ||||
|           <!-- 待办项2 - 重要 --> | ||||
|           <div class="todo-item important"> | ||||
|             <div class="todo-color-indicator important"></div> | ||||
|             <el-checkbox class="todo-checkbox"></el-checkbox> | ||||
|             <div class="todo-content"> | ||||
|               <div class="todo-main"> | ||||
|                 <div class="todo-title">数据库备份</div> | ||||
|                 <div class="todo-time">14:00-15:00 PM</div> | ||||
|               </div> | ||||
|               <div class="todo-description">主要数据库全备份,并验证备份文件完整性</div> | ||||
|             </div> | ||||
|             <div class="todo-actions"> | ||||
|               <el-button type="text" icon="el-icon-edit"></el-button> | ||||
|               <el-button type="text" icon="el-icon-delete"></el-button> | ||||
|             </div> | ||||
|           <!-- 状态图例 - 标签形式 --> | ||||
|           <!-- 状态图例 - 标签形式 --> | ||||
|           <div class="status-legend"> | ||||
|             <span class="status-tag normal"><span class="color-block"></span>常规维护</span> | ||||
|             <span class="status-tag important"><span class="color-block"></span>重要</span> | ||||
|             <span class="status-tag urgent"><span class="color-block"></span>紧急</span> | ||||
|           </div> | ||||
|  | ||||
|           <!-- 待办项3 - 紧急 --> | ||||
|           <div class="todo-item"> | ||||
|             <div class="todo-color-indicator urgent"></div> | ||||
|             <el-checkbox class="todo-checkbox"></el-checkbox> | ||||
|             <div class="todo-content"> | ||||
|               <div class="todo-main"> | ||||
|                 <div class="todo-title">网络设备固件更新</div> | ||||
|                 <div class="todo-time">18:00-20:00 PM</div> | ||||
|               </div> | ||||
|               <div class="todo-description">更新核心交换机和防火墙固件,需安排在业务低峰期</div> | ||||
|             </div> | ||||
|           </div> | ||||
|  | ||||
|           <!-- 待办项4 - 常规维护 --> | ||||
|           <div class="todo-item"> | ||||
|             <div class="todo-color-indicator normal"></div> | ||||
|             <el-checkbox class="todo-checkbox"></el-checkbox> | ||||
|             <div class="todo-content"> | ||||
|               <div class="todo-main"> | ||||
|                 <div class="todo-title">服务器例行检查</div> | ||||
|                 <div class="todo-time">08:00-09:00 AM</div> | ||||
|               </div> | ||||
|               <div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div> | ||||
|             </div> | ||||
|           </div> | ||||
|  | ||||
|           <!-- 待办项5 - 常规维护 --> | ||||
|           <div class="todo-item"> | ||||
|             <div class="todo-color-indicator normal"></div> | ||||
|             <el-checkbox class="todo-checkbox"></el-checkbox> | ||||
|             <div class="todo-content"> | ||||
|               <div class="todo-main"> | ||||
|                 <div class="todo-title">服务器例行检查</div> | ||||
|                 <div class="todo-time">06:00-07:00 AM</div> | ||||
|               </div> | ||||
|               <div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         <!-- 状态图例 - 标签形式 --> | ||||
|         <div class="status-legend"> | ||||
|           <span class="status-tag normal">常规维护</span> | ||||
|           <span class="status-tag important">重要</span> | ||||
|           <span class="status-tag urgent">紧急</span> | ||||
|         </div> | ||||
|       </div> | ||||
|       <el-dialog v-model="dialogVisible" title="新增任务" width="480px" class="custom-dialog" :before-close="closeDialog"> | ||||
|         <el-form :model="taskForm" label-width="80px" class="task-form"> | ||||
|           <el-form-item label="任务名称" prop="name"> | ||||
|             <el-input v-model="taskForm.name" placeholder="输入任务名称" class="form-input"></el-input> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="任务描述" prop="description"> | ||||
|             <el-input v-model="taskForm.description" placeholder="输入任务描述" class="form-input"></el-input> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="时间" prop="timeRange"> | ||||
|             <el-date-picker | ||||
|               v-model="taskForm.timeRange" | ||||
|               type="datetimerange" | ||||
|               start-placeholder="开始时间" | ||||
|               end-placeholder="结束时间" | ||||
|               class="form-input" | ||||
|               style="width: 100%" | ||||
|             /> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="优先级" prop="priority"> | ||||
|             <el-select v-model="taskForm.priority" placeholder="选择优先级" class="form-input"> | ||||
|               <el-option label="常规项" value="常规项"></el-option> | ||||
|               <el-option label="重要" value="重要"></el-option> | ||||
|               <el-option label="紧急" value="紧急"></el-option> | ||||
|             </el-select> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="任务类型" prop="taskType"> | ||||
|             <el-select v-model="taskForm.taskType" placeholder="选择任务类型" class="form-input"> | ||||
|               <el-option label="常规维护" value="常规维护"></el-option> | ||||
|               <el-option label="安全巡检" value="安全巡检"></el-option> | ||||
|               <el-option label="系统升级" value="系统升级"></el-option> | ||||
|               <el-option label="数据备份" value="数据备份"></el-option> | ||||
|             </el-select> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|         <template #footer> | ||||
|           <el-button @click="closeDialog">取消</el-button> | ||||
|           <el-button type="primary" @click="saveTask">保存任务</el-button> | ||||
|         </template> | ||||
|       </el-dialog> | ||||
|     </div> | ||||
|     <el-dialog v-model="dialogVisible" title="新增任务" width="480px" class="custom-dialog" :before-close="closeDialog"> | ||||
|       <el-form :model="taskForm" label-width="80px" class="task-form"> | ||||
|         <el-form-item label="任务名称" prop="name"> | ||||
|           <el-input v-model="taskForm.name" placeholder="输入任务名称" class="form-input"></el-input> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="任务描述" prop="description"> | ||||
|           <el-input v-model="taskForm.description" placeholder="输入任务描述" class="form-input"></el-input> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="时间" prop="timeRange"> | ||||
|           <el-date-picker | ||||
|             v-model="taskForm.timeRange" | ||||
|             type="datetimerange" | ||||
|             start-placeholder="开始时间" | ||||
|             end-placeholder="结束时间" | ||||
|             class="form-input" | ||||
|             style="width: 100%" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="优先级" prop="priority"> | ||||
|           <el-select v-model="taskForm.priority" placeholder="选择优先级" class="form-input"> | ||||
|             <el-option label="常规项" value="常规项"></el-option> | ||||
|             <el-option label="重要" value="重要"></el-option> | ||||
|             <el-option label="紧急" value="紧急"></el-option> | ||||
|           </el-select> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="任务类型" prop="taskType"> | ||||
|           <el-select v-model="taskForm.taskType" placeholder="选择任务类型" class="form-input"> | ||||
|             <el-option label="常规维护" value="常规维护"></el-option> | ||||
|             <el-option label="安全巡检" value="安全巡检"></el-option> | ||||
|             <el-option label="系统升级" value="系统升级"></el-option> | ||||
|             <el-option label="数据备份" value="数据备份"></el-option> | ||||
|           </el-select> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|       <template #footer> | ||||
|         <el-button @click="closeDialog">取消</el-button> | ||||
|         <el-button type="primary" @click="saveTask">保存任务</el-button> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| @ -187,14 +212,14 @@ import { ref, computed, watch } from 'vue'; | ||||
| import router from '@/router'; | ||||
| import TitleComponent from '../demo/components/TitleComponent.vue'; | ||||
|  | ||||
| // 生成年份选项,生成2020-2029年的年份范围 | ||||
| const targetYear = 2025; | ||||
| const years = ref(Array.from({ length: 10 }, (_, index) => 2020 + index)); | ||||
| const selectedYear = ref(targetYear); | ||||
| const selectedMonth = ref(9); | ||||
| // 默认显示当前月份 | ||||
| const currentDate = ref(new Date()); | ||||
|  | ||||
| // 默认显示2025年9月 | ||||
| const currentDate = ref(new Date(targetYear, 8, 1)); | ||||
| // 为了保持兼容性,保留这些变量 | ||||
| const targetYear = 2025; | ||||
| const years = ref([]); | ||||
| const selectedYear = ref(currentDate.value.getFullYear()); | ||||
| const selectedMonth = ref(currentDate.value.getMonth() + 1); | ||||
|  | ||||
| // 减少月份 | ||||
| const decreaseMonth = () => { | ||||
| @ -258,15 +283,13 @@ const updateYearAndMonth = () => { | ||||
|   selectedMonth.value = currentDate.value.getMonth() + 1; | ||||
| }; | ||||
|  | ||||
| // 监听年份和月份变化,更新日历显示 | ||||
| watch([selectedYear, selectedMonth], ([newYear, newMonth]) => { | ||||
|   const date = new Date(currentDate.value); | ||||
|   date.setFullYear(newYear); | ||||
|   date.setMonth(newMonth - 1); | ||||
|   currentDate.value = date; | ||||
| // 监听日期变化,更新年份和月份 | ||||
| watch(currentDate, (newDate) => { | ||||
|   selectedYear.value = newDate.getFullYear(); | ||||
|   selectedMonth.value = newDate.getMonth() + 1; | ||||
| }); | ||||
|  | ||||
| // 初始化年份和月份选择器 | ||||
| // 初始化年份和月份 | ||||
| updateYearAndMonth(); | ||||
|  | ||||
| // 弹窗相关状态管理 | ||||
| @ -329,7 +352,8 @@ const handleInspection7 = () => { | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| .container { | ||||
| .box-container { | ||||
|   width: 100%; | ||||
|   padding: 20px; | ||||
|   background-color: #f5f7fa; | ||||
|   min-height: 100vh; | ||||
| @ -397,15 +421,18 @@ const handleInspection7 = () => { | ||||
| .main-content { | ||||
|   display: flex; | ||||
|   gap: 20px; | ||||
|   width: 100%; | ||||
| } | ||||
|  | ||||
| /* 日历区域样式 */ | ||||
| .calendar-container { | ||||
|   flex: 1; | ||||
|   min-width: 0; | ||||
|   background-color: #fff; | ||||
|   border-radius: 4px; | ||||
|   padding: 20px; | ||||
|   box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); | ||||
|   height: 100%; | ||||
| } | ||||
|  | ||||
| /* 自定义弹窗样式 */ | ||||
| @ -463,14 +490,13 @@ const handleInspection7 = () => { | ||||
| .el-select { | ||||
|   margin-right: 5px; | ||||
| } | ||||
|  | ||||
| /* 表单区域样式 */ | ||||
| .form-container { | ||||
|   width: 400px; | ||||
|   flex: 0 0 360px; /* 调整宽度以匹配设计图,更贴合右侧区域宽度 */ | ||||
|   background-color: #fff; | ||||
|   border-radius: 4px; | ||||
|   padding: 20px; | ||||
|   padding: 20px 20px 80px 20px; /* 增加底部内边距,为固定标签留出空间 */ | ||||
|   box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); | ||||
|   position: relative; /* 设置为相对定位,使内部绝对定位元素相对于此容器定位 */ | ||||
| } | ||||
|  | ||||
| .form-header { | ||||
| @ -494,7 +520,7 @@ const handleInspection7 = () => { | ||||
|   flex-direction: column; | ||||
|   gap: 10px; | ||||
|   margin-bottom: 20px; | ||||
|   max-height: 400px; | ||||
|   max-height: 480px; | ||||
|   overflow-y: auto; | ||||
| } | ||||
|  | ||||
| @ -507,6 +533,7 @@ const handleInspection7 = () => { | ||||
|   border-radius: 4px; | ||||
|   position: relative; | ||||
|   transition: all 0.3s ease; | ||||
|   overflow: hidden; | ||||
| } | ||||
|  | ||||
| /* 重要任务的背景色 */ | ||||
| @ -521,6 +548,8 @@ const handleInspection7 = () => { | ||||
|  | ||||
| .todo-content { | ||||
|   flex: 1; | ||||
|   position: relative; | ||||
|   transition: all 0.3s ease; | ||||
| } | ||||
|  | ||||
| .todo-main { | ||||
| @ -549,42 +578,75 @@ const handleInspection7 = () => { | ||||
|  | ||||
| .todo-actions { | ||||
|   position: absolute; | ||||
|   right: 10px; | ||||
|   bottom: 10px; | ||||
|   right: -120px; | ||||
|   top: 0; | ||||
|   bottom: 0; | ||||
|   display: flex; | ||||
|   gap: 5px; | ||||
|   opacity: 0; | ||||
|   transition: all 0.3s ease; | ||||
| } | ||||
|  | ||||
| .todo-actions .el-button { | ||||
|   height: 100%; | ||||
|   border-radius: 0; | ||||
|   border-right: 1px solid #fff; | ||||
| } | ||||
|  | ||||
| .todo-actions .el-button:last-child { | ||||
|   border-right: none; | ||||
| } | ||||
|  | ||||
| .todo-item:hover .todo-content { | ||||
|   transform: translateX(-120px); | ||||
| } | ||||
|  | ||||
| .todo-item:hover .todo-actions { | ||||
|   opacity: 1; | ||||
|   right: 0; | ||||
| } | ||||
|  | ||||
| .todo-actions .el-button { | ||||
|   padding: 4px 8px; | ||||
|   min-width: auto; | ||||
|   font-size: 12px; | ||||
| } | ||||
|  | ||||
| /* 状态图例 - 标签形式 */ | ||||
| .status-legend { | ||||
|   display: flex; | ||||
|   gap: 10px; | ||||
|   padding-top: 15px; | ||||
|   gap: 20px; | ||||
|   padding: 15px 0; | ||||
|   border-top: 1px solid #ebeef5; | ||||
|   justify-content: center; | ||||
|   width: 100%; | ||||
|   position: absolute; | ||||
|   bottom: 0; | ||||
|   left: 0; | ||||
|   right: 0; | ||||
|   background-color: #fff; | ||||
| } | ||||
|  | ||||
| .status-tag { | ||||
|   display: inline-block; | ||||
|   padding: 4px 12px; | ||||
|   border-radius: 16px; | ||||
|   font-size: 12px; | ||||
|   color: #fff; | ||||
|   display: inline-flex; | ||||
|   align-items: center; | ||||
|   gap: 5px; | ||||
|   font-size: 14px; | ||||
|   color: #303133; | ||||
| } | ||||
|  | ||||
| .status-tag.normal { | ||||
| .status-tag .color-block { | ||||
|   width: 12px; | ||||
|   height: 12px; | ||||
|   border-radius: 2px; | ||||
|   flex-shrink: 0; | ||||
| } | ||||
|  | ||||
| .status-tag.normal .color-block { | ||||
|   background-color: #52c41a; | ||||
| } | ||||
|  | ||||
| .status-tag.important { | ||||
| .status-tag.important .color-block { | ||||
|   background-color: #faad14; | ||||
| } | ||||
|  | ||||
| .status-tag.urgent { | ||||
| .status-tag.urgent .color-block { | ||||
|   background-color: #ff4d4f; | ||||
| } | ||||
|  | ||||
| @ -610,10 +672,12 @@ const handleInspection7 = () => { | ||||
|   background-color: #ff4d4f; | ||||
| } | ||||
|  | ||||
| /* 自定义日历单元格样式 */ | ||||
| .custom-date-cell { | ||||
| ::v-deep .custom-date-cell { | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   padding: 5px; | ||||
|   text-align: center; | ||||
|   box-sizing: border-box; /* 确保内边距不撑大元素 */ | ||||
| } | ||||
|  | ||||
| /* 系统升级事件样式 */ | ||||
| @ -648,15 +712,21 @@ const handleInspection7 = () => { | ||||
|   width: 100%; | ||||
| } | ||||
|  | ||||
| .el-calendar-table td { | ||||
| /* 穿透作用域,强制设置日历单元格为正方形 */ | ||||
| ::v-deep .el-calendar-table td { | ||||
|   padding: 2px; | ||||
|   vertical-align: top; | ||||
|   width: 120px; /* 强制宽度 */ | ||||
|   height: 120px; /* 强制高度(与宽度一致) */ | ||||
| } | ||||
|  | ||||
| .el-calendar-day { | ||||
|   height: 120px; | ||||
| ::v-deep .el-calendar-day { | ||||
|   padding: 0; /* 移除默认内边距 */ | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   border-radius: 4px; | ||||
|   overflow: hidden; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
| } | ||||
|  | ||||
| .date-day { | ||||
|  | ||||
| @ -112,8 +112,8 @@ | ||||
|           </div> | ||||
|  | ||||
|           <div class="task-actions"> | ||||
|             <el-button type="text" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button> | ||||
|             <el-button type="primary" size="small" :class="task.actionClass" @click="handleAction(task)"> | ||||
|             <el-button type="text" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button> | ||||
|             <el-button type="primary" :class="task.actionClass" @click="handleAction(task)"> | ||||
|               {{ task.actionText }} | ||||
|             </el-button> | ||||
|           </div> | ||||
| @ -701,10 +701,20 @@ const handleInspection7 = () => { | ||||
|   display: flex; | ||||
|   justify-content: flex-end; | ||||
|   align-items: center; | ||||
|   padding-top: 16px; | ||||
|   padding-top: 12px; | ||||
|   border-top: 1px solid #f0f2f5; | ||||
|   margin-top: auto; /* 自动推到最底部 */ | ||||
|   gap: 8px; | ||||
|   position: absolute; | ||||
|   bottom: 16px; | ||||
|   right: 16px; | ||||
|   left: 16px; | ||||
|   background-color: #fff; | ||||
|   padding: 12px 0 0 0; | ||||
|   z-index: 10; | ||||
| } | ||||
|  | ||||
| .task-actions .el-button { | ||||
|   border-radius: 16px; | ||||
|   padding: 6px 16px; | ||||
| } | ||||
|  | ||||
| .action-btn { | ||||
|  | ||||
| @ -16,7 +16,6 @@ | ||||
|       <TitleComponent title="运维组织模块" subtitle="实时监控人员状态、车辆状态和班组状态"></TitleComponent> | ||||
|  | ||||
|       <!-- 选项卡 --> | ||||
|       <!-- 选项卡和按钮组合 --> | ||||
|       <div class="tabs-wrapper"> | ||||
|         <div style="display: flex; align-items: center; gap: 10px"> | ||||
|           <el-button type="primary" @click="handleInspectionManagement1">人员状态</el-button> | ||||
| @ -31,58 +30,9 @@ | ||||
|         <div class="sidebar"> | ||||
|           <div class="stats-card"> | ||||
|             <h3 class="stats-title">人员数据总览</h3> | ||||
|             <!-- 使用ECharts饼图替换原有的环形图 --> | ||||
|             <div class="chart-container"> | ||||
|               <div class="gauge-chart"> | ||||
|                 <div class="doughnut-chart"> | ||||
|                   <!-- 动态镂空环形图 --> | ||||
|                   <svg width="200" height="200" viewBox="0 0 200 200"> | ||||
|                     <!-- 环形背景 --> | ||||
|                     <circle cx="100" cy="100" r="70" fill="none" stroke="#f0f2f5" stroke-width="12" class="background-circle" /> | ||||
|                     <!-- 在线可用部分 - 动态显示 --> | ||||
|                     <circle | ||||
|                       cx="100" | ||||
|                       cy="100" | ||||
|                       r="70" | ||||
|                       fill="none" | ||||
|                       stroke="#165dff" | ||||
|                       stroke-width="12" | ||||
|                       stroke-linecap="round" | ||||
|                       :stroke-dasharray="circumference" | ||||
|                       :stroke-dashoffset="onlineOffset" | ||||
|                       transform="rotate(-90 100 100)" | ||||
|                       class="progress-circle online-progress" | ||||
|                     /> | ||||
|                     <!-- 离线休息部分 - 动态显示 --> | ||||
|                     <circle | ||||
|                       cx="100" | ||||
|                       cy="100" | ||||
|                       r="70" | ||||
|                       fill="none" | ||||
|                       stroke="#40c9c6" | ||||
|                       stroke-width="12" | ||||
|                       stroke-linecap="round" | ||||
|                       :stroke-dasharray="circumference" | ||||
|                       :stroke-dashoffset="offlineOffset" | ||||
|                       transform="rotate(-90 100 100)" | ||||
|                       class="progress-circle offline-progress" | ||||
|                     /> | ||||
|                   </svg> | ||||
|                   <div class="gauge-text"> | ||||
|                     <div class="gauge-percentage">{{ onlineRate }}%</div> | ||||
|                     <div class="gauge-label">在线可用率</div> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </div> | ||||
|               <div class="chart-legend"> | ||||
|                 <div class="legend-item"> | ||||
|                   <span class="legend-color online"></span> | ||||
|                   <span class="legend-text">在线可用人数 ({{ availablePersonnel }})</span> | ||||
|                 </div> | ||||
|                 <div class="legend-item"> | ||||
|                   <span class="legend-color offline"></span> | ||||
|                   <span class="legend-text">离线休息人数 ({{ restingPersonnel }})</span> | ||||
|                 </div> | ||||
|               </div> | ||||
|               <div ref="personnelChart" class="personnel-chart"></div> | ||||
|             </div> | ||||
|  | ||||
|             <div class="stats-grid"> | ||||
| @ -112,30 +62,42 @@ | ||||
|  | ||||
|         <!-- 右侧人员列表区域,带滚动条 --> | ||||
|         <div class="main-content"> | ||||
|           <div class="scrollable-content"> | ||||
|             <div class="personnel-grid"> | ||||
|               <div v-for="(person, index) in personnelList" :key="index" class="person-card"> | ||||
|                 <div class="person-header"> | ||||
|                   <div class="avatar"> | ||||
|                     <img :src="person.avatar" alt="头像" class="avatar-img" /> | ||||
|                     <div class="status-indicator" :class="person.statusClass"></div> | ||||
|           <div class="scroll-wrapper"> | ||||
|             <!-- 固定的顶部空间,不随内容滚动 --> | ||||
|             <div class="fixed-top-space"></div> | ||||
|             <!-- 可滚动的内容区域 --> | ||||
|             <div class="scrollable-content"> | ||||
|               <div class="scrollable-inner"> | ||||
|                 <div class="personnel-grid"> | ||||
|                   <div v-for="(person, index) in personnelList" :key="index" class="person-card"> | ||||
|                     <div class="person-header"> | ||||
|                       <div class="avatar"> | ||||
|                         <img src="@/assets/images/attendanceperson.png" class="avatar-img" /> | ||||
|                         <div class="status-indicator" :class="person.statusClass"></div> | ||||
|                       </div> | ||||
|                       <div class="person-info"> | ||||
|                         <div class="person-name">{{ person.name }}</div> | ||||
|                         <div class="person-status">{{ person.statusText }}</div> | ||||
|                       </div> | ||||
|                     </div> | ||||
|                     <div class="person-details"> | ||||
|                       <div class="detail-row"> | ||||
|                         <div class="detail-item">工号: {{ person.id }}</div> | ||||
|                         <div class="detail-item">岗位: {{ person.position }}</div> | ||||
|                       </div> | ||||
|                       <div class="detail-row"> | ||||
|                         <div class="detail-item">班组: {{ person.team }}</div> | ||||
|                         <div class="detail-item">今日完成: {{ person.completedTasks }}单</div> | ||||
|                       </div> | ||||
|                       <div class="detail-row"> | ||||
|                         <div class="detail-item full-width">当前任务: {{ person.currentTask || '无' }}</div> | ||||
|                       </div> | ||||
|                     </div> | ||||
|                     <div class="person-actions"> | ||||
|                       <el-button type="text" @click="viewDetails(person)" size="small" class="detail-btn">详情</el-button> | ||||
|                       <el-button type="text" @click="assignTask(person)" size="small" class="assign-btn">指派</el-button> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                   <div class="person-info"> | ||||
|                     <div class="person-name">{{ person.name }}</div> | ||||
|                     <div class="person-status">{{ person.statusText }}</div> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <div class="person-details"> | ||||
|                   <div class="detail-item">工号: {{ person.id }}</div> | ||||
|                   <div class="detail-item">岗位: {{ person.position }}</div> | ||||
|                   <div class="detail-item">班组: {{ person.team }}</div> | ||||
|                   <div class="detail-item">今日完成: {{ person.completedTasks }}单</div> | ||||
|                   <div class="detail-item" v-if="person.currentTask">当前任务: {{ person.currentTask }}</div> | ||||
|                   <div class="detail-item" v-else>当前任务: 无</div> | ||||
|                 </div> | ||||
|                 <div class="person-actions"> | ||||
|                   <el-button type="text" @click="viewDetails(person)" size="small" class="detail-btn">详情</el-button> | ||||
|                   <el-button type="text" @click="assignTask(person)" size="small" class="assign-btn">指派</el-button> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
| @ -147,33 +109,32 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { ref, watch } from 'vue'; | ||||
| import { ref, watch, onMounted } from 'vue'; | ||||
| import router from '@/router'; | ||||
| import TitleComponent from '@/views/demo/components/TitleComponent.vue'; | ||||
| import * as echarts from 'echarts'; | ||||
|  | ||||
| // 激活的选项卡 | ||||
| const activeTab = ref('personnel'); | ||||
|  | ||||
| // 统计数据 | ||||
| // 统计数据(保持原有数据不变) | ||||
| const totalPersonnel = ref(36); | ||||
| const availablePersonnel = ref(18); | ||||
| const workingPersonnel = ref(12); | ||||
| const restingPersonnel = ref(6); | ||||
| const onlineRate = ref(82); | ||||
|  | ||||
| // 环形图相关计算 | ||||
| const radius = 70; | ||||
| const circumference = 2 * Math.PI * radius; | ||||
| const onlineOffset = ref(circumference - (onlineRate.value / 100) * circumference); | ||||
| const offlineOffset = ref(circumference - ((100 - onlineRate.value) / 100) * circumference); | ||||
| // 人员状态数据 - 使用原有数据结构 | ||||
| const personnelStatusData = { | ||||
|   '在线可用': availablePersonnel.value, | ||||
|   '离线休息': restingPersonnel.value | ||||
| }; | ||||
|  | ||||
| // 监听onlineRate变化,更新环形图 | ||||
| watch(onlineRate, (newRate) => { | ||||
|   onlineOffset.value = circumference - (newRate / 100) * circumference; | ||||
|   offlineOffset.value = circumference - ((100 - newRate) / 100) * circumference; | ||||
| }); | ||||
| // 初始化图表 | ||||
| const personnelChart = ref(null); | ||||
| let chartInstance = null; | ||||
|  | ||||
| // 人员列表数据 | ||||
| // 人员列表数据(保持不变) | ||||
| const personnelList = ref([ | ||||
|   { | ||||
|     id: 'EMP-2023-001', | ||||
| @ -276,10 +237,127 @@ const personnelList = ref([ | ||||
|   } | ||||
| ]); | ||||
|  | ||||
| // 初始化饼图 | ||||
| const initChart = () => { | ||||
|   if (chartInstance) { | ||||
|     chartInstance.dispose(); | ||||
|   } | ||||
|  | ||||
|   chartInstance = echarts.init(personnelChart.value); | ||||
|  | ||||
|   const names = Object.keys(personnelStatusData); | ||||
|   const values = Object.values(personnelStatusData).map((item) => Number(Number(item).toFixed(2))); | ||||
|   const sumValue = values.reduce((total, num) => total + num, 0); | ||||
|  | ||||
|   // 设置图表配置 - 美化饼图样式,保持原有数据 | ||||
|   const option = { | ||||
|     tooltip: { | ||||
|       trigger: 'item', | ||||
|       formatter: '{b}: {c}人 ({d}%)' | ||||
|     }, | ||||
|     legend: { | ||||
|       show: true, | ||||
|       orient: 'horizontal', | ||||
|       bottom: 10, | ||||
|       itemWidth: 12, | ||||
|       itemHeight: 12, | ||||
|       textStyle: { | ||||
|         color: '#606266', | ||||
|         fontSize: 14 | ||||
|       } | ||||
|     }, | ||||
|     series: [ | ||||
|       // 主饼图 | ||||
|       { | ||||
|         name: '人员状态', | ||||
|         type: 'pie', | ||||
|         radius: ['40%', '70%'], | ||||
|         center: ['50%', '50%'], | ||||
|         avoidLabelOverlap: false, | ||||
|         itemStyle: { | ||||
|           borderRadius: 4, | ||||
|           borderColor: '#fff', | ||||
|           borderWidth: 2, | ||||
|           shadowBlur: 6, | ||||
|           shadowColor: 'rgba(0, 0, 0, 0.1)' | ||||
|         }, | ||||
|         label: { | ||||
|           show: false, | ||||
|           position: 'outside', | ||||
|           formatter: '{d}%', | ||||
|           fontSize: 14, | ||||
|           fontWeight: 'bold', | ||||
|           color: '#303133', | ||||
|           lineHeight: 20 | ||||
|         }, | ||||
|         labelLine: { | ||||
|           show: true, | ||||
|           length: 15, | ||||
|           length2: 10, | ||||
|           lineStyle: { | ||||
|             width: 1 | ||||
|           } | ||||
|         }, | ||||
|         emphasis: { | ||||
|           scale: true, | ||||
|           scaleSize: 15 | ||||
|         }, | ||||
|         data: [ | ||||
|           { | ||||
|             value: availablePersonnel.value, | ||||
|             name: '在线可用人数', | ||||
|             itemStyle: { | ||||
|               color: '#165dff' | ||||
|             } | ||||
|           }, | ||||
|  | ||||
|           { | ||||
|             value: restingPersonnel.value, | ||||
|             name: '离线休息人数', | ||||
|             itemStyle: { | ||||
|               color: '#40c9c6' | ||||
|             }, | ||||
|             emphasis: { | ||||
|               itemStyle: { | ||||
|                 shadowBlur: 15, | ||||
|                 shadowColor: 'rgba(64, 201, 198, 0.4)' | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         ] | ||||
|       } | ||||
|     ] | ||||
|   }; | ||||
|  | ||||
|   chartInstance.setOption(option); | ||||
| }; | ||||
|  | ||||
| // 监听数据变化,更新图表 | ||||
| watch([availablePersonnel, workingPersonnel, restingPersonnel], () => { | ||||
|   // 更新人员状态数据 | ||||
|   personnelStatusData['在线可用'] = availablePersonnel.value; | ||||
|  | ||||
|   personnelStatusData['离线休息'] = restingPersonnel.value; | ||||
|  | ||||
|   // 重新初始化图表 | ||||
|   initChart(); | ||||
| }); | ||||
|  | ||||
| // 页面加载完成后初始化图表 | ||||
| onMounted(() => { | ||||
|   initChart(); | ||||
|  | ||||
|   // 监听窗口大小变化,调整图表尺寸 | ||||
|   window.addEventListener('resize', () => { | ||||
|     if (chartInstance) { | ||||
|       chartInstance.resize(); | ||||
|     } | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| // 选项卡点击事件 | ||||
| const handleTabClick = (tab) => { | ||||
|   console.log('切换到选项卡:', tab.name); | ||||
|   // 根据选择的选项卡加载不同数据 | ||||
|   if (tab.name === 'vehicles') { | ||||
|     // 加载车辆状态数据 | ||||
|   } else if (tab.name === 'teams') { | ||||
| @ -419,96 +497,9 @@ const handleInspectionManagement3 = () => { | ||||
|   padding: 10px 0; | ||||
| } | ||||
|  | ||||
| .gauge-chart { | ||||
|   width: 200px; | ||||
|   height: 200px; | ||||
|   position: relative; | ||||
| } | ||||
|  | ||||
| .doughnut-chart { | ||||
| .personnel-chart { | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   position: relative; | ||||
| } | ||||
|  | ||||
| .gauge-text { | ||||
|   position: absolute; | ||||
|   top: 50%; | ||||
|   left: 50%; | ||||
|   transform: translate(-50%, -50%); | ||||
|   text-align: center; | ||||
| } | ||||
|  | ||||
| .gauge-percentage { | ||||
|   font-size: 36px; | ||||
|   font-weight: 700; | ||||
|   color: #165dff; | ||||
|   line-height: 1; | ||||
| } | ||||
|  | ||||
| .gauge-label { | ||||
|   font-size: 15px; | ||||
|   color: #606266; | ||||
|   margin-top: 6px; | ||||
|   font-weight: 500; | ||||
| } | ||||
|  | ||||
| /* 环形图动画效果 */ | ||||
| .background-circle { | ||||
|   stroke: #f0f2f5; | ||||
| } | ||||
|  | ||||
| .progress-circle { | ||||
|   transition: stroke-dashoffset 1s ease-in-out; | ||||
| } | ||||
|  | ||||
| .online-progress { | ||||
|   stroke: #165dff; | ||||
|   filter: drop-shadow(0 0 6px rgba(22, 93, 255, 0.2)); | ||||
| } | ||||
|  | ||||
| .offline-progress { | ||||
|   stroke: #40c9c6; | ||||
|   filter: drop-shadow(0 0 6px rgba(64, 201, 198, 0.2)); | ||||
| } | ||||
|  | ||||
| /* 图例样式 */ | ||||
| .chart-legend { | ||||
|   margin-top: 16px; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   gap: 8px; | ||||
|   width: 100%; | ||||
| } | ||||
|  | ||||
| .legend-item { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   gap: 8px; | ||||
|   padding: 4px 0; | ||||
| } | ||||
|  | ||||
| .legend-color { | ||||
|   width: 12px; | ||||
|   height: 12px; | ||||
|   border-radius: 4px; | ||||
|   flex-shrink: 0; | ||||
| } | ||||
|  | ||||
| .legend-color.online { | ||||
|   background-color: #165dff; | ||||
|   box-shadow: 0 2px 4px rgba(22, 93, 255, 0.3); | ||||
| } | ||||
|  | ||||
| .legend-color.offline { | ||||
|   background-color: #40c9c6; | ||||
|   box-shadow: 0 2px 4px rgba(64, 201, 198, 0.3); | ||||
| } | ||||
|  | ||||
| .legend-text { | ||||
|   font-size: 13px; | ||||
|   color: #606266; | ||||
|   font-weight: 500; | ||||
|   height: 300px; | ||||
| } | ||||
|  | ||||
| /* 统计网格 */ | ||||
| @ -574,12 +565,50 @@ const handleInspectionManagement3 = () => { | ||||
|   border-radius: 12px; | ||||
|   box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06); | ||||
|   overflow: hidden; | ||||
|   padding: 0 28px 28px 28px; | ||||
| } | ||||
| /* 滚动包装器 */ | ||||
| .scroll-wrapper { | ||||
|   height: 100%; | ||||
|   position: relative; | ||||
| } | ||||
|  | ||||
| /* 固定的顶部空间,不随内容滚动 */ | ||||
| .fixed-top-space { | ||||
|   height: 40px; | ||||
|   flex-shrink: 0; | ||||
| } | ||||
|  | ||||
| /* 可滚动的内容区域 */ | ||||
| .scrollable-content { | ||||
|   max-height: calc(100vh - 340px); | ||||
|   overflow-y: auto; | ||||
|   padding: 28px; | ||||
|   max-height: calc(120vh - 340px - 40px); /* 减去顶部固定空间的高度 */ | ||||
|   overflow: auto; | ||||
|   scrollbar-width: thin; | ||||
|   scrollbar-color: rgba(150, 150, 150, 0.5) transparent; | ||||
| } | ||||
| /* 内容包装器 */ | ||||
| .content-wrapper { | ||||
|   padding: 0 28px 60px 28px; | ||||
| } | ||||
| /* Webkit浏览器自定义滚动条样式 */ | ||||
| .scrollable-content::-webkit-scrollbar { | ||||
|   width: 8px; | ||||
| } | ||||
|  | ||||
| .scrollable-content::-webkit-scrollbar-track { | ||||
|   background: transparent; | ||||
|   border-radius: 4px; | ||||
| } | ||||
|  | ||||
| .scrollable-content::-webkit-scrollbar-thumb { | ||||
|   background-color: rgba(150, 150, 150, 0.5); | ||||
|   border-radius: 4px; | ||||
|   border: 2px solid transparent; | ||||
|   background-clip: content-box; | ||||
| } | ||||
|  | ||||
| .scrollable-content::-webkit-scrollbar-thumb:hover { | ||||
|   background-color: rgba(150, 150, 150, 0.8); | ||||
| } | ||||
|  | ||||
| /* 增强内容区域标题样式 */ | ||||
| @ -595,17 +624,18 @@ const handleInspectionManagement3 = () => { | ||||
| /* 人员网格 */ | ||||
| .personnel-grid { | ||||
|   display: grid; | ||||
|   grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); | ||||
|   gap: 20px; | ||||
|   grid-template-columns: repeat(3, 1fr); | ||||
|   gap: 24px; | ||||
| } | ||||
|  | ||||
| .person-card { | ||||
|   border: 1px solid #f0f0f0; | ||||
|   border-radius: 12px; | ||||
|   padding: 20px; | ||||
|   border-radius: 8px; | ||||
|   padding: 16px; | ||||
|   transition: all 0.3s ease; | ||||
|   background-color: #ffffff; | ||||
|   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); | ||||
|   min-height: 220px; | ||||
| } | ||||
|  | ||||
| .person-card:hover { | ||||
| @ -617,14 +647,14 @@ const handleInspectionManagement3 = () => { | ||||
| .person-header { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   margin-bottom: 20px; | ||||
|   margin-bottom: 16px; | ||||
| } | ||||
|  | ||||
| .avatar { | ||||
|   position: relative; | ||||
|   width: 64px; | ||||
|   height: 64px; | ||||
|   margin-right: 16px; | ||||
|   width: 56px; | ||||
|   height: 56px; | ||||
|   margin-right: 12px; | ||||
|   flex-shrink: 0; | ||||
| } | ||||
|  | ||||
| @ -640,8 +670,8 @@ const handleInspectionManagement3 = () => { | ||||
|   position: absolute; | ||||
|   bottom: 0; | ||||
|   right: 0; | ||||
|   width: 18px; | ||||
|   height: 18px; | ||||
|   width: 16px; | ||||
|   height: 16px; | ||||
|   border-radius: 50%; | ||||
|   border: 3px solid #fff; | ||||
|   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | ||||
| @ -664,17 +694,17 @@ const handleInspectionManagement3 = () => { | ||||
| } | ||||
|  | ||||
| .person-name { | ||||
|   font-size: 18px; | ||||
|   font-size: 16px; | ||||
|   font-weight: 600; | ||||
|   color: #2c3e50; | ||||
|   margin-bottom: 6px; | ||||
|   margin-bottom: 4px; | ||||
|   line-height: 1.2; | ||||
| } | ||||
|  | ||||
| .person-status { | ||||
|   font-size: 13px; | ||||
|   padding: 3px 10px; | ||||
|   border-radius: 15px; | ||||
|   font-size: 12px; | ||||
|   padding: 2px 8px; | ||||
|   border-radius: 12px; | ||||
|   display: inline-block; | ||||
|   font-weight: 500; | ||||
| } | ||||
| @ -695,28 +725,52 @@ const handleInspectionManagement3 = () => { | ||||
| } | ||||
|  | ||||
| .person-details { | ||||
|   margin-bottom: 20px; | ||||
|   border-top: 1px dashed #f0f0f0; | ||||
|   padding-top: 16px; | ||||
|   margin-bottom: 16px; | ||||
|   border-top: none; | ||||
|   padding-top: 0; | ||||
| } | ||||
|  | ||||
| .detail-row { | ||||
|   display: flex; | ||||
|   margin-bottom: 8px; | ||||
|   border-bottom: 1px dotted #f0f0f0; | ||||
|   padding-bottom: 8px; | ||||
| } | ||||
|  | ||||
| .detail-row:last-child { | ||||
|   margin-bottom: 0; | ||||
|   border-bottom: none; | ||||
|   padding-bottom: 0; | ||||
| } | ||||
|  | ||||
| .detail-item { | ||||
|   font-size: 13px; | ||||
|   color: #606266; | ||||
|   margin-bottom: 10px; | ||||
|   line-height: 1.6; | ||||
|   flex: 1; | ||||
|   padding: 0 8px; | ||||
| } | ||||
|  | ||||
| .detail-item:first-child { | ||||
|   padding-left: 0; | ||||
| } | ||||
|  | ||||
| .detail-item:last-child { | ||||
|   margin-bottom: 0; | ||||
|   padding-right: 0; | ||||
| } | ||||
|  | ||||
| .detail-item.full-width { | ||||
|   flex: 1 0 100%; | ||||
|   padding: 0; | ||||
| } | ||||
|  | ||||
| .person-actions { | ||||
|   display: flex; | ||||
|   justify-content: flex-end; | ||||
|   gap: 12px; | ||||
|   border-top: 1px dashed #f0f0f0; | ||||
|   border-top: 1px solid #f0f0f0; | ||||
|   padding-top: 16px; | ||||
|   margin-top: 16px; | ||||
| } | ||||
|  | ||||
| /* 美化按钮样式 */ | ||||
| @ -862,5 +916,9 @@ const handleInspectionManagement3 = () => { | ||||
|   .personnel-grid { | ||||
|     grid-template-columns: 1fr; | ||||
|   } | ||||
|  | ||||
|   .personnel-chart { | ||||
|     height: 250px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|  | ||||
| @ -106,8 +106,8 @@ | ||||
|           </div> | ||||
|  | ||||
|           <div class="task-actions"> | ||||
|             <el-button type="text" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button> | ||||
|             <el-button type="primary" size="small" :class="task.actionClass" @click="handleAction(task)"> | ||||
|             <el-button type="text" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button> | ||||
|             <el-button type="primary" :class="task.actionClass" @click="handleAction(task)"> | ||||
|               {{ task.actionText }} | ||||
|             </el-button> | ||||
|           </div> | ||||
| @ -564,7 +564,7 @@ const handleInspection7 = () => { | ||||
|  | ||||
| .task-card { | ||||
|   background-color: #fff; | ||||
|   border-radius: 8px; | ||||
|   border-radius: 16px; | ||||
|   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05); | ||||
|   padding: 16px 16px 60px 16px; /* 底部留出更多空间给按钮 */ | ||||
|   transition: box-shadow 0.2s ease; | ||||
| @ -588,6 +588,11 @@ const handleInspection7 = () => { | ||||
|   z-index: 10; | ||||
| } | ||||
|  | ||||
| .task-actions .el-button { | ||||
|   border-radius: 16px; | ||||
|   padding: 6px 16px; | ||||
| } | ||||
|  | ||||
| .task-card::before { | ||||
|   content: ''; | ||||
|   position: absolute; | ||||
| @ -635,8 +640,8 @@ const handleInspection7 = () => { | ||||
| } | ||||
|  | ||||
| .task-status { | ||||
|   padding: 4px 10px; | ||||
|   border-radius: 6px; | ||||
|   padding: 4px 12px; | ||||
|   border-radius: 16px; | ||||
|   font-size: 12px; | ||||
|   font-weight: 500; | ||||
|   border: 1px solid transparent; | ||||
|  | ||||
| @ -55,7 +55,7 @@ | ||||
|         ></el-date-picker> | ||||
|       </div> | ||||
|       <div class="filter-actions"> | ||||
|         <el-button type="primary" class="search-btn">搜索</el-button> | ||||
|         <el-button type="primary" class="search-btn" @click="fetchDashboardData">搜索</el-button> | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
| @ -97,19 +97,19 @@ | ||||
|             <div class="grid grid-cols-2 md:grid-cols-4 gap-4"> | ||||
|               <div class="stat-card"> | ||||
|                 <p class="stat-label">本月完成巡检</p> | ||||
|                 <p class="stat-value">42</p> | ||||
|                 <p class="stat-value">{{ completedInspections }}</p> | ||||
|               </div> | ||||
|               <div class="stat-card"> | ||||
|                 <p class="stat-label">发现问题数</p> | ||||
|                 <p class="stat-value">7</p> | ||||
|                 <p class="stat-value">{{ totalProblems }}</p> | ||||
|               </div> | ||||
|               <div class="stat-card"> | ||||
|                 <p class="stat-label">已解决问题</p> | ||||
|                 <p class="stat-value">5</p> | ||||
|                 <p class="stat-value">{{ solvedProblems }}</p> | ||||
|               </div> | ||||
|               <div class="stat-card"> | ||||
|                 <p class="stat-label">平均完成时间</p> | ||||
|                 <p class="stat-value">45分钟</p> | ||||
|                 <p class="stat-value">{{ avgCompletionTime }}</p> | ||||
|               </div> | ||||
|             </div> | ||||
|  | ||||
| @ -117,56 +117,10 @@ | ||||
|  | ||||
|             <!-- 图表区域 --> | ||||
|             <div class="grid grid-cols-1 md:grid-cols-3 gap-6 py-4"> | ||||
|               <!-- 饼图 - 本月巡检完成情况 --> | ||||
|               <!-- 饼图 - 使用指定的ECharts配置 --> | ||||
|               <div class="md:col-span-1"> | ||||
|                 <p class="chart-title">本月完成巡检</p> | ||||
|                 <div class="relative w-32 h-32 mx-auto"> | ||||
|                   <!-- 饼图使用SVG绘制 - 显示本月巡检完成情况 --> | ||||
|                   <svg class="w-full h-full" viewBox="0 0 100 100"> | ||||
|                     <!-- 背景圆环 --> | ||||
|                     <circle cx="50" cy="50" r="45" fill="none" stroke="#f3f4f6" stroke-width="10" /> | ||||
|                     <!-- 已完成部分 (72%) --> | ||||
|                     <circle | ||||
|                       cx="50" | ||||
|                       cy="50" | ||||
|                       r="45" | ||||
|                       fill="none" | ||||
|                       stroke="#10b981" | ||||
|                       stroke-width="10" | ||||
|                       stroke-dasharray="282.74" | ||||
|                       stroke-dashoffset="113.1" | ||||
|                       transform="rotate(-90 50 50)" | ||||
|                     /> | ||||
|                     <!-- 未完成部分 (28%) --> | ||||
|                     <circle | ||||
|                       cx="50" | ||||
|                       cy="50" | ||||
|                       r="45" | ||||
|                       fill="none" | ||||
|                       stroke="#f97316" | ||||
|                       stroke-width="10" | ||||
|                       stroke-dasharray="113.1" | ||||
|                       stroke-dashoffset="0" | ||||
|                       transform="rotate(-90 50 50)" | ||||
|                     /> | ||||
|                   </svg> | ||||
|                   <!-- 饼图中心显示 --> | ||||
|                   <div class="absolute inset-0 flex flex-col items-center justify-center"> | ||||
|                     <p class="text-sm text-gray-500">已解决问题</p> | ||||
|                     <p class="text-lg font-bold text-gray-800">72%</p> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <!-- 饼图图例 --> | ||||
|                 <div class="mt-3 flex justify-center space-x-4"> | ||||
|                   <div class="flex items-center"> | ||||
|                     <div class="w-3 h-3 rounded-full bg-green-500 mr-1"></div> | ||||
|                     <span class="text-xs text-gray-600">已解决</span> | ||||
|                   </div> | ||||
|                   <div class="flex items-center"> | ||||
|                     <div class="w-3 h-3 rounded-full bg-orange-500 mr-1"></div> | ||||
|                     <span class="text-xs text-gray-600">未解决</span> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <p class="chart-title">进度指标对比</p> | ||||
|                 <div ref="pieChartRef" class="pie-chart-container"></div> | ||||
|               </div> | ||||
|  | ||||
|               <!-- 进度条 --> | ||||
| @ -175,28 +129,28 @@ | ||||
|                   <div> | ||||
|                     <div class="flex justify-between text-sm mb-1"> | ||||
|                       <span class="text-gray-600">完成率</span> | ||||
|                       <span class="font-medium text-gray-800">68%</span> | ||||
|                       <span class="font-medium text-gray-800">{{ completionRate }}%</span> | ||||
|                     </div> | ||||
|                     <div class="w-full bg-gray-200 rounded-full h-2"> | ||||
|                       <div class="bg-red-500 h-2 rounded-full" style="width: 68%"></div> | ||||
|                     <div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden"> | ||||
|                       <div class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: completionRate + '%' }"></div> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                   <div> | ||||
|                     <div class="flex justify-between text-sm mb-1"> | ||||
|                       <span class="text-gray-600">解决率</span> | ||||
|                       <span class="font-medium text-gray-800">72%</span> | ||||
|                       <span class="font-medium text-gray-800">{{ resolutionRate }}%</span> | ||||
|                     </div> | ||||
|                     <div class="w-full bg-gray-200 rounded-full h-2"> | ||||
|                       <div class="bg-green-500 h-2 rounded-full" style="width: 72%"></div> | ||||
|                     <div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden"> | ||||
|                       <div class="bg-red-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: resolutionRate + '%' }"></div> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                   <div> | ||||
|                     <div class="flex justify-between text-sm mb-1"> | ||||
|                       <span class="text-gray-600">及时率</span> | ||||
|                       <span class="font-medium text-gray-800">60%</span> | ||||
|                       <span class="font-medium text-gray-800">{{ timelinessRate }}%</span> | ||||
|                     </div> | ||||
|                     <div class="w-full bg-gray-200 rounded-full h-2"> | ||||
|                       <div class="bg-gray-500 h-2 rounded-full" style="width: 60%"></div> | ||||
|                     <div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden"> | ||||
|                       <div class="bg-green-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: timelinessRate + '%' }"></div> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                 </div> | ||||
| @ -212,46 +166,58 @@ | ||||
|                 <div> | ||||
|                   <div class="flex justify-between text-sm mb-1"> | ||||
|                     <span class="text-gray-600">温度异常率</span> | ||||
|                     <span class="text-gray-500">85%</span> | ||||
|                     <span class="text-gray-500">{{ problemTypes.temperature }}%</span> | ||||
|                   </div> | ||||
|                   <div class="w-full bg-gray-200 rounded-full h-2"> | ||||
|                     <div class="bg-blue-500 h-2 rounded-full" style="width: 85%"></div> | ||||
|                   <div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden"> | ||||
|                     <div | ||||
|                       class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out" | ||||
|                       :style="{ width: problemTypes.temperature + '%' }" | ||||
|                     ></div> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <div> | ||||
|                   <div class="flex justify-between text-sm mb-1"> | ||||
|                     <span class="text-gray-600">内存使用率</span> | ||||
|                     <span class="text-gray-500">62%</span> | ||||
|                     <span class="text-gray-500">{{ problemTypes.memory }}%</span> | ||||
|                   </div> | ||||
|                   <div class="w-full bg-gray-200 rounded-full h-2"> | ||||
|                     <div class="bg-blue-500 h-2 rounded-full" style="width: 62%"></div> | ||||
|                   <div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden"> | ||||
|                     <div | ||||
|                       class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out" | ||||
|                       :style="{ width: problemTypes.memory + '%' }" | ||||
|                     ></div> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <div> | ||||
|                   <div class="flex justify-between text-sm mb-1"> | ||||
|                     <span class="text-gray-600">CPU负载</span> | ||||
|                     <span class="text-gray-500">45%</span> | ||||
|                     <span class="text-gray-500">{{ problemTypes.cpu }}%</span> | ||||
|                   </div> | ||||
|                   <div class="w-full bg-gray-200 rounded-full h-2"> | ||||
|                     <div class="bg-blue-500 h-2 rounded-full" style="width: 45%"></div> | ||||
|                   <div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden"> | ||||
|                     <div class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: problemTypes.cpu + '%' }"></div> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <div> | ||||
|                   <div class="flex justify-between text-sm mb-1"> | ||||
|                     <span class="text-gray-600">响应时间</span> | ||||
|                     <span class="text-gray-500">30%</span> | ||||
|                     <span class="text-gray-500">{{ problemTypes.responseTime }}%</span> | ||||
|                   </div> | ||||
|                   <div class="w-full bg-gray-200 rounded-full h-2"> | ||||
|                     <div class="bg-blue-500 h-2 rounded-full" style="width: 30%"></div> | ||||
|                   <div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden"> | ||||
|                     <div | ||||
|                       class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out" | ||||
|                       :style="{ width: problemTypes.responseTime + '%' }" | ||||
|                     ></div> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <div> | ||||
|                   <div class="flex justify-between text-sm mb-1"> | ||||
|                     <span class="text-gray-600">磁盘空间状态</span> | ||||
|                     <span class="text-gray-500">15%</span> | ||||
|                     <span class="text-gray-500">{{ problemTypes.diskSpace }}%</span> | ||||
|                   </div> | ||||
|                   <div class="w-full bg-gray-200 rounded-full h-2"> | ||||
|                     <div class="bg-blue-500 h-2 rounded-full" style="width: 15%"></div> | ||||
|                   <div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden"> | ||||
|                     <div | ||||
|                       class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out" | ||||
|                       :style="{ width: problemTypes.diskSpace + '%' }" | ||||
|                     ></div> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </div> | ||||
| @ -271,7 +237,7 @@ | ||||
|           <div class="card-body flex-1 overflow-y-auto scrollbar-thin"> | ||||
|             <div class="inspection-results space-y-4"> | ||||
|               <!-- 结果1:正常 --> | ||||
|               <div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm"> | ||||
|               <div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm hover:shadow-md transition-shadow"> | ||||
|                 <div class="flex justify-between items-start mb-4"> | ||||
|                   <h3 class="text-lg font-medium text-gray-800">数据库性能巡检</h3> | ||||
|                   <span class="status-tag status-normal px-3 py-1 text-xs">正常</span> | ||||
| @ -308,7 +274,7 @@ | ||||
|               </div> | ||||
|  | ||||
|               <!-- 结果2:需关注 --> | ||||
|               <div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm"> | ||||
|               <div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm hover:shadow-md transition-shadow"> | ||||
|                 <div class="flex justify-between items-start mb-4"> | ||||
|                   <h3 class="text-lg font-medium text-gray-800">生产服务器日常巡检</h3> | ||||
|                   <span class="status-tag status-attention px-3 py-1 text-xs">需关注</span> | ||||
| @ -352,7 +318,7 @@ | ||||
|               </div> | ||||
|  | ||||
|               <!-- 结果3:有问题 --> | ||||
|               <div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm"> | ||||
|               <div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm hover:shadow-md transition-shadow"> | ||||
|                 <div class="flex justify-between items-start mb-4"> | ||||
|                   <h3 class="text-lg font-medium text-gray-800">网络设备安全巡检</h3> | ||||
|                   <span class="status-tag status-problem px-3 py-1 text-xs">有问题</span> | ||||
| @ -396,9 +362,10 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { ref } from 'vue'; | ||||
| import { ref, onMounted, computed, onUnmounted } from 'vue'; | ||||
| import router from '@/router'; | ||||
| import TitleComponent from '@/views/demo/components/TitleComponent.vue'; | ||||
| import * as echarts from 'echarts'; | ||||
|  | ||||
| // 筛选条件 | ||||
| const filterStatus = ref('all'); | ||||
| @ -408,13 +375,216 @@ const dateRange = ref([]); | ||||
| // 时间范围选择 | ||||
| const timeRange = ref('month'); // 默认选中"月" | ||||
|  | ||||
| // 进度指标数据 | ||||
| const completionRate = ref(68); // 完成率 | ||||
| const resolutionRate = ref(72); // 解决率 | ||||
| const timelinessRate = ref(60); // 及时率 | ||||
|  | ||||
| // 统计数据 | ||||
| const completedInspections = ref(42); | ||||
| const totalProblems = ref(7); | ||||
| const solvedProblems = ref(5); | ||||
| const avgCompletionTime = ref('45分钟'); | ||||
|  | ||||
| // 问题类型数据 | ||||
| const problemTypes = ref({ | ||||
|   temperature: 85, // 温度异常率 | ||||
|   memory: 62, // 内存使用率 | ||||
|   cpu: 45, // CPU负载 | ||||
|   responseTime: 30, // 响应时间 | ||||
|   diskSpace: 15 // 磁盘空间状态 | ||||
| }); | ||||
|  | ||||
| // ECharts 饼图相关 | ||||
| const pieChartRef = ref(null); | ||||
| let pieChart = null; | ||||
|  | ||||
| // 计算平均完成度 | ||||
| const averageRate = computed(() => (completionRate.value + resolutionRate.value + timelinessRate.value) / 3); | ||||
|  | ||||
| // 初始化饼图 - 使用指定的option配置 | ||||
| const initPieChart = () => { | ||||
|   // 确保DOM元素已存在 | ||||
|   if (!pieChartRef.value) return; | ||||
|  | ||||
|   // 销毁已存在的实例 | ||||
|   if (pieChart) { | ||||
|     pieChart.dispose(); | ||||
|   } | ||||
|  | ||||
|   // 创建新实例 | ||||
|   pieChart = echarts.init(pieChartRef.value); | ||||
|  | ||||
|   // 设置图表配置 - 使用指定的option | ||||
|   const option = { | ||||
|     tooltip: { | ||||
|       trigger: 'item' | ||||
|     }, | ||||
|     legend: { | ||||
|       top: '5%', | ||||
|       left: 'center' | ||||
|     }, | ||||
|     series: [ | ||||
|       { | ||||
|         name: '进度指标', | ||||
|         type: 'pie', | ||||
|         radius: ['40%', '70%'], | ||||
|         avoidLabelOverlap: false, | ||||
|         padAngle: 5, | ||||
|         itemStyle: { | ||||
|           borderRadius: 10 | ||||
|         }, | ||||
|         label: { | ||||
|           show: false, | ||||
|           position: 'center' | ||||
|         }, | ||||
|         emphasis: { | ||||
|           label: { | ||||
|             show: true, | ||||
|             fontSize: 40, | ||||
|             fontWeight: 'bold', | ||||
|             formatter: function (params) { | ||||
|               // 鼠标悬停时显示当前指标的百分比 | ||||
|               return params.value + '%'; | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         labelLine: { | ||||
|           show: false | ||||
|         }, | ||||
|         data: [ | ||||
|           { value: completionRate.value, name: '完成率', itemStyle: { color: '#5470c6' } }, | ||||
|           { value: resolutionRate.value, name: '解决率', itemStyle: { color: '#f56c6c' } }, | ||||
|           { value: timelinessRate.value, name: '及时率', itemStyle: { color: '#67c23a' } } | ||||
|         ] | ||||
|       } | ||||
|     ] | ||||
|   }; | ||||
|  | ||||
|   // 设置配置项 | ||||
|   pieChart.setOption(option); | ||||
|  | ||||
|   // 响应窗口大小变化 | ||||
|   const handleResize = () => { | ||||
|     if (pieChart) { | ||||
|       pieChart.resize(); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   window.addEventListener('resize', handleResize); | ||||
|  | ||||
|   // 组件卸载时移除事件监听 | ||||
|   onUnmounted(() => { | ||||
|     window.removeEventListener('resize', handleResize); | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| // 时间范围切换函数 | ||||
| const handleTimeRangeChange = (range) => { | ||||
|   timeRange.value = range; | ||||
|   // 在实际应用中,这里应该根据选择的时间范围重新获取数据 | ||||
|   console.log(`切换到${range}视图`); | ||||
|   fetchDashboardData(); // 切换时间范围时重新获取数据 | ||||
| }; | ||||
|  | ||||
| // 获取仪表盘数据(模拟) | ||||
| const fetchDashboardData = () => { | ||||
|   // 模拟加载状态 | ||||
|   completionRate.value = 0; | ||||
|   resolutionRate.value = 0; | ||||
|   timelinessRate.value = 0; | ||||
|  | ||||
|   // 模拟API请求延迟 | ||||
|   setTimeout(() => { | ||||
|     // 根据时间范围返回不同数据 | ||||
|     let mockData; | ||||
|     if (timeRange.value === 'month') { | ||||
|       mockData = { | ||||
|         completionRate: 68, | ||||
|         resolutionRate: 72, | ||||
|         timelinessRate: 60, | ||||
|         completedInspections: 42, | ||||
|         totalProblems: 7, | ||||
|         solvedProblems: 5, | ||||
|         avgCompletionTime: '45分钟', | ||||
|         problemTypes: { | ||||
|           temperature: 85, | ||||
|           memory: 62, | ||||
|           cpu: 45, | ||||
|           responseTime: 30, | ||||
|           diskSpace: 15 | ||||
|         } | ||||
|       }; | ||||
|     } else if (timeRange.value === 'week') { | ||||
|       mockData = { | ||||
|         completionRate: 75, | ||||
|         resolutionRate: 80, | ||||
|         timelinessRate: 65, | ||||
|         completedInspections: 12, | ||||
|         totalProblems: 2, | ||||
|         solvedProblems: 2, | ||||
|         avgCompletionTime: '35分钟', | ||||
|         problemTypes: { | ||||
|           temperature: 70, | ||||
|           memory: 55, | ||||
|           cpu: 40, | ||||
|           responseTime: 25, | ||||
|           diskSpace: 10 | ||||
|         } | ||||
|       }; | ||||
|     } else { | ||||
|       // day | ||||
|       mockData = { | ||||
|         completionRate: 90, | ||||
|         resolutionRate: 100, | ||||
|         timelinessRate: 95, | ||||
|         completedInspections: 2, | ||||
|         totalProblems: 0, | ||||
|         solvedProblems: 0, | ||||
|         avgCompletionTime: '25分钟', | ||||
|         problemTypes: { | ||||
|           temperature: 30, | ||||
|           memory: 45, | ||||
|           cpu: 25, | ||||
|           responseTime: 10, | ||||
|           diskSpace: 5 | ||||
|         } | ||||
|       }; | ||||
|     } | ||||
|  | ||||
|     // 应用筛选条件(这里仅做简单演示) | ||||
|     if (filterStatus.value === 'problem') { | ||||
|       mockData.totalProblems = Math.round(mockData.totalProblems * 1.5); | ||||
|       mockData.solvedProblems = Math.round(mockData.solvedProblems * 0.7); | ||||
|       mockData.resolutionRate = Math.round(mockData.resolutionRate * 0.8); | ||||
|     } | ||||
|  | ||||
|     // 更新数据 | ||||
|     completionRate.value = mockData.completionRate; | ||||
|     resolutionRate.value = mockData.resolutionRate; | ||||
|     timelinessRate.value = mockData.timelinessRate; | ||||
|     completedInspections.value = mockData.completedInspections; | ||||
|     totalProblems.value = mockData.totalProblems; | ||||
|     solvedProblems.value = mockData.solvedProblems; | ||||
|     avgCompletionTime.value = mockData.avgCompletionTime; | ||||
|     problemTypes.value = mockData.problemTypes; | ||||
|  | ||||
|     // 更新饼图 | ||||
|     initPieChart(); | ||||
|   }, 800); // 模拟网络延迟 | ||||
| }; | ||||
|  | ||||
| // 页面加载时获取数据 | ||||
| onMounted(() => { | ||||
|   fetchDashboardData(); | ||||
| }); | ||||
|  | ||||
| // 组件卸载时销毁图表实例 | ||||
| onUnmounted(() => { | ||||
|   if (pieChart) { | ||||
|     pieChart.dispose(); | ||||
|     pieChart = null; | ||||
|   } | ||||
| }); | ||||
|  | ||||
| // 导航方法 | ||||
| const handleInspection1 = () => { | ||||
|   router.push('/rili/rili'); | ||||
| @ -456,11 +626,12 @@ const handleInspectionManagement3 = () => { | ||||
|   min-height: 100vh; | ||||
| } | ||||
|  | ||||
| /* 头部容器 - 替换了固定gap的flex布局 */ | ||||
| /* 头部容器 */ | ||||
| .header-container { | ||||
|   display: flex; | ||||
|   justify-content: space-between; | ||||
|   align-items: center; | ||||
|   margin-bottom: 20px; | ||||
| } | ||||
|  | ||||
| .header-actions { | ||||
| @ -603,7 +774,7 @@ const handleInspectionManagement3 = () => { | ||||
| } | ||||
|  | ||||
| .card-body { | ||||
|   padding: 0 20px; | ||||
|   padding: 20px; | ||||
|   flex: 1; /* 内容区域占满剩余空间 */ | ||||
| } | ||||
|  | ||||
| @ -612,6 +783,14 @@ const handleInspectionManagement3 = () => { | ||||
|   background-color: #f5f7fa; | ||||
|   border-radius: 6px; | ||||
|   padding: 16px; | ||||
|   transition: | ||||
|     transform 0.3s ease, | ||||
|     box-shadow 0.3s ease; | ||||
| } | ||||
|  | ||||
| .stat-card:hover { | ||||
|   transform: translateY(-3px); | ||||
|   box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); | ||||
| } | ||||
|  | ||||
| .stat-label { | ||||
| @ -639,6 +818,14 @@ const handleInspectionManagement3 = () => { | ||||
|   font-size: 14px; | ||||
|   color: #606266; | ||||
|   margin: 0 0 8px 0; | ||||
|   text-align: center; | ||||
| } | ||||
|  | ||||
| /* 饼图容器 */ | ||||
| .pie-chart-container { | ||||
|   width: 100%; | ||||
|   height: 300px; | ||||
|   margin: 0 auto; | ||||
| } | ||||
|  | ||||
| /* 区域标题 */ | ||||
| @ -649,30 +836,6 @@ const handleInspectionManagement3 = () => { | ||||
|   margin: 0 0 12px 0; | ||||
| } | ||||
|  | ||||
| /* 记录列表样式 */ | ||||
| .record-list { | ||||
|   margin: 0; | ||||
|   padding: 0; | ||||
| } | ||||
|  | ||||
| .record-item { | ||||
|   padding: 16px 0; | ||||
| } | ||||
|  | ||||
| .record-title { | ||||
|   font-size: 14px; | ||||
|   font-weight: 500; | ||||
|   color: #303133; | ||||
|   margin: 0; | ||||
| } | ||||
|  | ||||
| .record-time, | ||||
| .record-type { | ||||
|   font-size: 12px; | ||||
|   color: #909399; | ||||
|   margin: 4px 0 0 0; | ||||
| } | ||||
|  | ||||
| /* 状态标签 */ | ||||
| .status-tag { | ||||
|   font-size: 12px; | ||||
| @ -698,18 +861,6 @@ const handleInspectionManagement3 = () => { | ||||
|   border: 1px solid #ffe3e0; | ||||
| } | ||||
|  | ||||
| /* 操作按钮 */ | ||||
| .action-btn { | ||||
|   color: #409eff; | ||||
|   font-size: 12px; | ||||
|   padding: 4px 8px; | ||||
| } | ||||
|  | ||||
| .action-btn:hover { | ||||
|   color: #66b1ff; | ||||
|   background-color: #ecf5ff; | ||||
| } | ||||
|  | ||||
| /* 滚动条样式优化 */ | ||||
| .scrollbar-thin { | ||||
|   scrollbar-width: thin; | ||||
| @ -750,4 +901,25 @@ const handleInspectionManagement3 = () => { | ||||
|     justify-content: flex-end; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @media (max-width: 768px) { | ||||
|   .grid-cols-2 { | ||||
|     grid-template-columns: 1fr; | ||||
|   } | ||||
|  | ||||
|   .md\:col-span-1, | ||||
|   .md\:col-span-2, | ||||
|   .md\:col-span-3 { | ||||
|     grid-column: span 1; | ||||
|   } | ||||
|  | ||||
|   .md\:grid-cols-4, | ||||
|   .md\:grid-cols-3 { | ||||
|     grid-template-columns: 1fr 1fr; | ||||
|   } | ||||
|  | ||||
|   .navigation-tabs { | ||||
|     justify-content: flex-start; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|  | ||||
| @ -106,8 +106,8 @@ | ||||
|           </div> | ||||
|  | ||||
|           <div class="task-actions"> | ||||
|             <el-button type="text" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button> | ||||
|             <el-button type="primary" size="small" :class="task.actionClass" @click="handleAction(task)"> | ||||
|             <el-button type="text" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button> | ||||
|             <el-button type="primary" :class="task.actionClass" @click="handleAction(task)"> | ||||
|               {{ task.actionText }} | ||||
|             </el-button> | ||||
|           </div> | ||||
| @ -588,6 +588,10 @@ const handleInspection7 = () => { | ||||
|   z-index: 10; | ||||
| } | ||||
|  | ||||
| .task-actions .el-button { | ||||
|   border-radius: 16px; | ||||
|   padding: 6px 16px; | ||||
| } | ||||
| .task-card::before { | ||||
|   content: ''; | ||||
|   position: absolute; | ||||
|  | ||||
| @ -22,7 +22,13 @@ | ||||
|       <div> | ||||
|         <div> | ||||
|           <span>租金</span> | ||||
|           <span>{{ proxy.formatPrice(detailInfo.rentSum) / 1000 }} 万元</span> | ||||
|           <span>{{ | ||||
|             detailInfo.rentSum && !isNaN(detailInfo.rentSum) | ||||
|               ? detailInfo.rentSum >= 10000 | ||||
|                 ? proxy.formatPrice(detailInfo.rentSum / 10000) + ' 万元' | ||||
|                 : proxy.formatPrice(detailInfo.rentSum) + ' 元' | ||||
|               : '0.00 元' | ||||
|           }}</span> | ||||
|         </div> | ||||
|         <el-icon :size="50" color="#3176ff"> | ||||
|           <Postcard /> | ||||
|  | ||||
| @ -115,11 +115,7 @@ | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="分包公司" align="center" prop="contractorName" /> | ||||
|         <el-table-column label="班组" align="center" prop="teamId"> | ||||
|           <template #default="scope"> | ||||
|             {{ getTeamName(scope.row.teamId) }} | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="班组" align="center" prop="teamName"> </el-table-column> | ||||
|         <el-table-column label="联系电话" align="center" prop="phone" min-width="120" /> | ||||
|         <el-table-column label="性别" align="center" prop="sex"> | ||||
|           <template #default="scope"> | ||||
|  | ||||
		Reference in New Issue
	
	Block a user