1
This commit is contained in:
@ -95,8 +95,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="task-actions">
|
<div class="task-actions">
|
||||||
<el-button type="text" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button>
|
<el-button type="text" 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="primary" :class="task.actionClass" @click="handleAction(task)">
|
||||||
{{ task.actionText }}
|
{{ task.actionText }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -853,7 +853,18 @@ const handleInspection7 = () => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
border-top: 1px solid #f0f2f5;
|
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 {
|
.task-card::before {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div>
|
||||||
|
<div class="box-container">
|
||||||
<!-- 导航栏 -->
|
<!-- 导航栏 -->
|
||||||
<div class="navigation-tabs">
|
<div class="navigation-tabs">
|
||||||
<div class="nav-tab active" @click="handleInspection1">待办事项</div>
|
<div class="nav-tab active" @click="handleInspection1">待办事项</div>
|
||||||
@ -22,18 +23,11 @@
|
|||||||
<div class="calendar-header">
|
<div class="calendar-header">
|
||||||
<div class="calendar-title">待办月视图</div>
|
<div class="calendar-title">待办月视图</div>
|
||||||
<div class="calendar-controls">
|
<div class="calendar-controls">
|
||||||
<!-- 年份月份选择 -->
|
<!-- 月份选择器 -->
|
||||||
<el-select v-model="selectedYear" placeholder="选择年份" size="small" style="width: 80px; margin-right: 5px">
|
<el-date-picker v-model="currentDate" type="month" placeholder="选择月份" style="width: 120px; margin-right: 15px" />
|
||||||
<el-option v-for="year in years" :key="year" :label="year.toString()" :value="year"></el-option>
|
|
||||||
</el-select>
|
<el-button type="primary">添加</el-button>
|
||||||
<el-select v-model="selectedMonth" placeholder="选择月份" size="small" style="width: 80px; margin-right: 10px">
|
<el-button type="primary" @click="goToToday">今日</el-button>
|
||||||
<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>
|
<el-button type="text" icon="el-icon-plus"></el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -73,6 +67,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div>
|
<div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div>
|
||||||
</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>
|
||||||
|
|
||||||
<!-- 待办项2 - 重要 -->
|
<!-- 待办项2 - 重要 -->
|
||||||
@ -87,8 +85,8 @@
|
|||||||
<div class="todo-description">主要数据库全备份,并验证备份文件完整性</div>
|
<div class="todo-description">主要数据库全备份,并验证备份文件完整性</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="todo-actions">
|
<div class="todo-actions">
|
||||||
<el-button type="text" icon="el-icon-edit"></el-button>
|
<el-button type="primary" size="small" icon="el-icon-check">编辑</el-button>
|
||||||
<el-button type="text" icon="el-icon-delete"></el-button>
|
<el-button type="danger" size="small" icon="el-icon-delete">删除</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -103,6 +101,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="todo-description">更新核心交换机和防火墙固件,需安排在业务低峰期</div>
|
<div class="todo-description">更新核心交换机和防火墙固件,需安排在业务低峰期</div>
|
||||||
</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>
|
||||||
|
|
||||||
<!-- 待办项4 - 常规维护 -->
|
<!-- 待办项4 - 常规维护 -->
|
||||||
@ -116,9 +118,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div>
|
<div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div>
|
||||||
</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>
|
||||||
|
|
||||||
<!-- 待办项5 - 常规维护 -->
|
|
||||||
<div class="todo-item">
|
<div class="todo-item">
|
||||||
<div class="todo-color-indicator normal"></div>
|
<div class="todo-color-indicator normal"></div>
|
||||||
<el-checkbox class="todo-checkbox"></el-checkbox>
|
<el-checkbox class="todo-checkbox"></el-checkbox>
|
||||||
@ -129,14 +133,34 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div>
|
<div class="todo-description">检查所有生产服务器的CPU、内存、磁盘使用率,确保正常运行</div>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 状态图例 - 标签形式 -->
|
||||||
<!-- 状态图例 - 标签形式 -->
|
<!-- 状态图例 - 标签形式 -->
|
||||||
<div class="status-legend">
|
<div class="status-legend">
|
||||||
<span class="status-tag normal">常规维护</span>
|
<span class="status-tag normal"><span class="color-block"></span>常规维护</span>
|
||||||
<span class="status-tag important">重要</span>
|
<span class="status-tag important"><span class="color-block"></span>重要</span>
|
||||||
<span class="status-tag urgent">紧急</span>
|
<span class="status-tag urgent"><span class="color-block"></span>紧急</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -180,6 +204,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -187,14 +212,14 @@ import { ref, computed, watch } from 'vue';
|
|||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import TitleComponent from '../demo/components/TitleComponent.vue';
|
import TitleComponent from '../demo/components/TitleComponent.vue';
|
||||||
|
|
||||||
// 生成年份选项,生成2020-2029年的年份范围
|
// 默认显示当前月份
|
||||||
const targetYear = 2025;
|
const currentDate = ref(new Date());
|
||||||
const years = ref(Array.from({ length: 10 }, (_, index) => 2020 + index));
|
|
||||||
const selectedYear = ref(targetYear);
|
|
||||||
const selectedMonth = ref(9);
|
|
||||||
|
|
||||||
// 默认显示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 = () => {
|
const decreaseMonth = () => {
|
||||||
@ -258,15 +283,13 @@ const updateYearAndMonth = () => {
|
|||||||
selectedMonth.value = currentDate.value.getMonth() + 1;
|
selectedMonth.value = currentDate.value.getMonth() + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 监听年份和月份变化,更新日历显示
|
// 监听日期变化,更新年份和月份
|
||||||
watch([selectedYear, selectedMonth], ([newYear, newMonth]) => {
|
watch(currentDate, (newDate) => {
|
||||||
const date = new Date(currentDate.value);
|
selectedYear.value = newDate.getFullYear();
|
||||||
date.setFullYear(newYear);
|
selectedMonth.value = newDate.getMonth() + 1;
|
||||||
date.setMonth(newMonth - 1);
|
|
||||||
currentDate.value = date;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 初始化年份和月份选择器
|
// 初始化年份和月份
|
||||||
updateYearAndMonth();
|
updateYearAndMonth();
|
||||||
|
|
||||||
// 弹窗相关状态管理
|
// 弹窗相关状态管理
|
||||||
@ -329,7 +352,8 @@ const handleInspection7 = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.container {
|
.box-container {
|
||||||
|
width: 100%;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
@ -397,15 +421,18 @@ const handleInspection7 = () => {
|
|||||||
.main-content {
|
.main-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 日历区域样式 */
|
/* 日历区域样式 */
|
||||||
.calendar-container {
|
.calendar-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 自定义弹窗样式 */
|
/* 自定义弹窗样式 */
|
||||||
@ -463,14 +490,13 @@ const handleInspection7 = () => {
|
|||||||
.el-select {
|
.el-select {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 表单区域样式 */
|
|
||||||
.form-container {
|
.form-container {
|
||||||
width: 400px;
|
flex: 0 0 360px; /* 调整宽度以匹配设计图,更贴合右侧区域宽度 */
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 20px;
|
padding: 20px 20px 80px 20px; /* 增加底部内边距,为固定标签留出空间 */
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
position: relative; /* 设置为相对定位,使内部绝对定位元素相对于此容器定位 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-header {
|
.form-header {
|
||||||
@ -494,7 +520,7 @@ const handleInspection7 = () => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
max-height: 400px;
|
max-height: 480px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,6 +533,7 @@ const handleInspection7 = () => {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 重要任务的背景色 */
|
/* 重要任务的背景色 */
|
||||||
@ -521,6 +548,8 @@ const handleInspection7 = () => {
|
|||||||
|
|
||||||
.todo-content {
|
.todo-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo-main {
|
.todo-main {
|
||||||
@ -549,42 +578,75 @@ const handleInspection7 = () => {
|
|||||||
|
|
||||||
.todo-actions {
|
.todo-actions {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 10px;
|
right: -120px;
|
||||||
bottom: 10px;
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
display: flex;
|
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 {
|
.todo-actions .el-button {
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 状态图例 - 标签形式 */
|
|
||||||
.status-legend {
|
.status-legend {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 20px;
|
||||||
padding-top: 15px;
|
padding: 15px 0;
|
||||||
border-top: 1px solid #ebeef5;
|
border-top: 1px solid #ebeef5;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-tag {
|
.status-tag {
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
padding: 4px 12px;
|
align-items: center;
|
||||||
border-radius: 16px;
|
gap: 5px;
|
||||||
font-size: 12px;
|
font-size: 14px;
|
||||||
color: #fff;
|
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;
|
background-color: #52c41a;
|
||||||
}
|
}
|
||||||
|
.status-tag.important .color-block {
|
||||||
.status-tag.important {
|
|
||||||
background-color: #faad14;
|
background-color: #faad14;
|
||||||
}
|
}
|
||||||
|
.status-tag.urgent .color-block {
|
||||||
.status-tag.urgent {
|
|
||||||
background-color: #ff4d4f;
|
background-color: #ff4d4f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,10 +672,12 @@ const handleInspection7 = () => {
|
|||||||
background-color: #ff4d4f;
|
background-color: #ff4d4f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 自定义日历单元格样式 */
|
::v-deep .custom-date-cell {
|
||||||
.custom-date-cell {
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
box-sizing: border-box; /* 确保内边距不撑大元素 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 系统升级事件样式 */
|
/* 系统升级事件样式 */
|
||||||
@ -648,15 +712,21 @@ const handleInspection7 = () => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-calendar-table td {
|
/* 穿透作用域,强制设置日历单元格为正方形 */
|
||||||
|
::v-deep .el-calendar-table td {
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
width: 120px; /* 强制宽度 */
|
||||||
|
height: 120px; /* 强制高度(与宽度一致) */
|
||||||
}
|
}
|
||||||
|
::v-deep .el-calendar-day {
|
||||||
.el-calendar-day {
|
padding: 0; /* 移除默认内边距 */
|
||||||
height: 120px;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-day {
|
.date-day {
|
||||||
|
|||||||
@ -112,8 +112,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="task-actions">
|
<div class="task-actions">
|
||||||
<el-button type="text" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button>
|
<el-button type="text" 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="primary" :class="task.actionClass" @click="handleAction(task)">
|
||||||
{{ task.actionText }}
|
{{ task.actionText }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -701,10 +701,20 @@ const handleInspection7 = () => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-top: 16px;
|
padding-top: 12px;
|
||||||
border-top: 1px solid #f0f2f5;
|
border-top: 1px solid #f0f2f5;
|
||||||
margin-top: auto; /* 自动推到最底部 */
|
position: absolute;
|
||||||
gap: 8px;
|
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 {
|
.action-btn {
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
<TitleComponent title="运维组织模块" subtitle="实时监控人员状态、车辆状态和班组状态"></TitleComponent>
|
<TitleComponent title="运维组织模块" subtitle="实时监控人员状态、车辆状态和班组状态"></TitleComponent>
|
||||||
|
|
||||||
<!-- 选项卡 -->
|
<!-- 选项卡 -->
|
||||||
<!-- 选项卡和按钮组合 -->
|
|
||||||
<div class="tabs-wrapper">
|
<div class="tabs-wrapper">
|
||||||
<div style="display: flex; align-items: center; gap: 10px">
|
<div style="display: flex; align-items: center; gap: 10px">
|
||||||
<el-button type="primary" @click="handleInspectionManagement1">人员状态</el-button>
|
<el-button type="primary" @click="handleInspectionManagement1">人员状态</el-button>
|
||||||
@ -31,58 +30,9 @@
|
|||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
<div class="stats-card">
|
<div class="stats-card">
|
||||||
<h3 class="stats-title">人员数据总览</h3>
|
<h3 class="stats-title">人员数据总览</h3>
|
||||||
|
<!-- 使用ECharts饼图替换原有的环形图 -->
|
||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<div class="gauge-chart">
|
<div ref="personnelChart" class="personnel-chart"></div>
|
||||||
<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>
|
</div>
|
||||||
|
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
@ -112,12 +62,17 @@
|
|||||||
|
|
||||||
<!-- 右侧人员列表区域,带滚动条 -->
|
<!-- 右侧人员列表区域,带滚动条 -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
|
<div class="scroll-wrapper">
|
||||||
|
<!-- 固定的顶部空间,不随内容滚动 -->
|
||||||
|
<div class="fixed-top-space"></div>
|
||||||
|
<!-- 可滚动的内容区域 -->
|
||||||
<div class="scrollable-content">
|
<div class="scrollable-content">
|
||||||
|
<div class="scrollable-inner">
|
||||||
<div class="personnel-grid">
|
<div class="personnel-grid">
|
||||||
<div v-for="(person, index) in personnelList" :key="index" class="person-card">
|
<div v-for="(person, index) in personnelList" :key="index" class="person-card">
|
||||||
<div class="person-header">
|
<div class="person-header">
|
||||||
<div class="avatar">
|
<div class="avatar">
|
||||||
<img :src="person.avatar" alt="头像" class="avatar-img" />
|
<img src="@/assets/images/attendanceperson.png" class="avatar-img" />
|
||||||
<div class="status-indicator" :class="person.statusClass"></div>
|
<div class="status-indicator" :class="person.statusClass"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="person-info">
|
<div class="person-info">
|
||||||
@ -126,12 +81,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="person-details">
|
<div class="person-details">
|
||||||
|
<div class="detail-row">
|
||||||
<div class="detail-item">工号: {{ person.id }}</div>
|
<div class="detail-item">工号: {{ person.id }}</div>
|
||||||
<div class="detail-item">岗位: {{ person.position }}</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.team }}</div>
|
||||||
<div class="detail-item">今日完成: {{ person.completedTasks }}单</div>
|
<div class="detail-item">今日完成: {{ person.completedTasks }}单</div>
|
||||||
<div class="detail-item" v-if="person.currentTask">当前任务: {{ person.currentTask }}</div>
|
</div>
|
||||||
<div class="detail-item" v-else>当前任务: 无</div>
|
<div class="detail-row">
|
||||||
|
<div class="detail-item full-width">当前任务: {{ person.currentTask || '无' }}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="person-actions">
|
<div class="person-actions">
|
||||||
<el-button type="text" @click="viewDetails(person)" size="small" class="detail-btn">详情</el-button>
|
<el-button type="text" @click="viewDetails(person)" size="small" class="detail-btn">详情</el-button>
|
||||||
@ -144,36 +104,37 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from 'vue';
|
import { ref, watch, onMounted } from 'vue';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
|
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
|
||||||
// 激活的选项卡
|
// 激活的选项卡
|
||||||
const activeTab = ref('personnel');
|
const activeTab = ref('personnel');
|
||||||
|
|
||||||
// 统计数据
|
// 统计数据(保持原有数据不变)
|
||||||
const totalPersonnel = ref(36);
|
const totalPersonnel = ref(36);
|
||||||
const availablePersonnel = ref(18);
|
const availablePersonnel = ref(18);
|
||||||
const workingPersonnel = ref(12);
|
const workingPersonnel = ref(12);
|
||||||
const restingPersonnel = ref(6);
|
const restingPersonnel = ref(6);
|
||||||
const onlineRate = ref(82);
|
const onlineRate = ref(82);
|
||||||
|
|
||||||
// 环形图相关计算
|
// 人员状态数据 - 使用原有数据结构
|
||||||
const radius = 70;
|
const personnelStatusData = {
|
||||||
const circumference = 2 * Math.PI * radius;
|
'在线可用': availablePersonnel.value,
|
||||||
const onlineOffset = ref(circumference - (onlineRate.value / 100) * circumference);
|
'离线休息': restingPersonnel.value
|
||||||
const offlineOffset = ref(circumference - ((100 - onlineRate.value) / 100) * circumference);
|
};
|
||||||
|
|
||||||
// 监听onlineRate变化,更新环形图
|
// 初始化图表
|
||||||
watch(onlineRate, (newRate) => {
|
const personnelChart = ref(null);
|
||||||
onlineOffset.value = circumference - (newRate / 100) * circumference;
|
let chartInstance = null;
|
||||||
offlineOffset.value = circumference - ((100 - newRate) / 100) * circumference;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 人员列表数据
|
// 人员列表数据(保持不变)
|
||||||
const personnelList = ref([
|
const personnelList = ref([
|
||||||
{
|
{
|
||||||
id: 'EMP-2023-001',
|
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) => {
|
const handleTabClick = (tab) => {
|
||||||
console.log('切换到选项卡:', tab.name);
|
console.log('切换到选项卡:', tab.name);
|
||||||
// 根据选择的选项卡加载不同数据
|
|
||||||
if (tab.name === 'vehicles') {
|
if (tab.name === 'vehicles') {
|
||||||
// 加载车辆状态数据
|
// 加载车辆状态数据
|
||||||
} else if (tab.name === 'teams') {
|
} else if (tab.name === 'teams') {
|
||||||
@ -419,96 +497,9 @@ const handleInspectionManagement3 = () => {
|
|||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gauge-chart {
|
.personnel-chart {
|
||||||
width: 200px;
|
|
||||||
height: 200px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doughnut-chart {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 300px;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 统计网格 */
|
/* 统计网格 */
|
||||||
@ -574,12 +565,50 @@ const handleInspectionManagement3 = () => {
|
|||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
padding: 0 28px 28px 28px;
|
||||||
|
}
|
||||||
|
/* 滚动包装器 */
|
||||||
|
.scroll-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 固定的顶部空间,不随内容滚动 */
|
||||||
|
.fixed-top-space {
|
||||||
|
height: 40px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 可滚动的内容区域 */
|
||||||
.scrollable-content {
|
.scrollable-content {
|
||||||
max-height: calc(100vh - 340px);
|
max-height: calc(120vh - 340px - 40px); /* 减去顶部固定空间的高度 */
|
||||||
overflow-y: auto;
|
overflow: auto;
|
||||||
padding: 28px;
|
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 {
|
.personnel-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
grid-template-columns: repeat(3, 1fr);
|
||||||
gap: 20px;
|
gap: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.person-card {
|
.person-card {
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid #f0f0f0;
|
||||||
border-radius: 12px;
|
border-radius: 8px;
|
||||||
padding: 20px;
|
padding: 16px;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||||
|
min-height: 220px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.person-card:hover {
|
.person-card:hover {
|
||||||
@ -617,14 +647,14 @@ const handleInspectionManagement3 = () => {
|
|||||||
.person-header {
|
.person-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 64px;
|
width: 56px;
|
||||||
height: 64px;
|
height: 56px;
|
||||||
margin-right: 16px;
|
margin-right: 12px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,8 +670,8 @@ const handleInspectionManagement3 = () => {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 18px;
|
width: 16px;
|
||||||
height: 18px;
|
height: 16px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border: 3px solid #fff;
|
border: 3px solid #fff;
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
@ -664,17 +694,17 @@ const handleInspectionManagement3 = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.person-name {
|
.person-name {
|
||||||
font-size: 18px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #2c3e50;
|
color: #2c3e50;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 4px;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.person-status {
|
.person-status {
|
||||||
font-size: 13px;
|
font-size: 12px;
|
||||||
padding: 3px 10px;
|
padding: 2px 8px;
|
||||||
border-radius: 15px;
|
border-radius: 12px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
@ -695,28 +725,52 @@ const handleInspectionManagement3 = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.person-details {
|
.person-details {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 16px;
|
||||||
border-top: 1px dashed #f0f0f0;
|
border-top: none;
|
||||||
padding-top: 16px;
|
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 {
|
.detail-item {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #606266;
|
color: #606266;
|
||||||
margin-bottom: 10px;
|
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
|
flex: 1;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item:first-child {
|
||||||
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-item:last-child {
|
.detail-item:last-child {
|
||||||
margin-bottom: 0;
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item.full-width {
|
||||||
|
flex: 1 0 100%;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.person-actions {
|
.person-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
border-top: 1px dashed #f0f0f0;
|
border-top: 1px solid #f0f0f0;
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 美化按钮样式 */
|
/* 美化按钮样式 */
|
||||||
@ -862,5 +916,9 @@ const handleInspectionManagement3 = () => {
|
|||||||
.personnel-grid {
|
.personnel-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.personnel-chart {
|
||||||
|
height: 250px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -106,8 +106,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="task-actions">
|
<div class="task-actions">
|
||||||
<el-button type="text" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button>
|
<el-button type="text" 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="primary" :class="task.actionClass" @click="handleAction(task)">
|
||||||
{{ task.actionText }}
|
{{ task.actionText }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -564,7 +564,7 @@ const handleInspection7 = () => {
|
|||||||
|
|
||||||
.task-card {
|
.task-card {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-radius: 8px;
|
border-radius: 16px;
|
||||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
padding: 16px 16px 60px 16px; /* 底部留出更多空间给按钮 */
|
padding: 16px 16px 60px 16px; /* 底部留出更多空间给按钮 */
|
||||||
transition: box-shadow 0.2s ease;
|
transition: box-shadow 0.2s ease;
|
||||||
@ -588,6 +588,11 @@ const handleInspection7 = () => {
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.task-actions .el-button {
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 6px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.task-card::before {
|
.task-card::before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -635,8 +640,8 @@ const handleInspection7 = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.task-status {
|
.task-status {
|
||||||
padding: 4px 10px;
|
padding: 4px 12px;
|
||||||
border-radius: 6px;
|
border-radius: 16px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
|
|||||||
@ -55,7 +55,7 @@
|
|||||||
></el-date-picker>
|
></el-date-picker>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-actions">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -97,19 +97,19 @@
|
|||||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<p class="stat-label">本月完成巡检</p>
|
<p class="stat-label">本月完成巡检</p>
|
||||||
<p class="stat-value">42</p>
|
<p class="stat-value">{{ completedInspections }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<p class="stat-label">发现问题数</p>
|
<p class="stat-label">发现问题数</p>
|
||||||
<p class="stat-value">7</p>
|
<p class="stat-value">{{ totalProblems }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<p class="stat-label">已解决问题</p>
|
<p class="stat-label">已解决问题</p>
|
||||||
<p class="stat-value">5</p>
|
<p class="stat-value">{{ solvedProblems }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<p class="stat-label">平均完成时间</p>
|
<p class="stat-label">平均完成时间</p>
|
||||||
<p class="stat-value">45分钟</p>
|
<p class="stat-value">{{ avgCompletionTime }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -117,56 +117,10 @@
|
|||||||
|
|
||||||
<!-- 图表区域 -->
|
<!-- 图表区域 -->
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 py-4">
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 py-4">
|
||||||
<!-- 饼图 - 本月巡检完成情况 -->
|
<!-- 饼图 - 使用指定的ECharts配置 -->
|
||||||
<div class="md:col-span-1">
|
<div class="md:col-span-1">
|
||||||
<p class="chart-title">本月完成巡检</p>
|
<p class="chart-title">进度指标对比</p>
|
||||||
<div class="relative w-32 h-32 mx-auto">
|
<div ref="pieChartRef" class="pie-chart-container"></div>
|
||||||
<!-- 饼图使用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>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 进度条 -->
|
<!-- 进度条 -->
|
||||||
@ -175,28 +129,28 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
<div class="flex justify-between text-sm mb-1">
|
||||||
<span class="text-gray-600">完成率</span>
|
<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>
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2">
|
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
||||||
<div class="bg-red-500 h-2 rounded-full" style="width: 68%"></div>
|
<div class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: completionRate + '%' }"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
<div class="flex justify-between text-sm mb-1">
|
||||||
<span class="text-gray-600">解决率</span>
|
<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>
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2">
|
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
||||||
<div class="bg-green-500 h-2 rounded-full" style="width: 72%"></div>
|
<div class="bg-red-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: resolutionRate + '%' }"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
<div class="flex justify-between text-sm mb-1">
|
||||||
<span class="text-gray-600">及时率</span>
|
<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>
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2">
|
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
||||||
<div class="bg-gray-500 h-2 rounded-full" style="width: 60%"></div>
|
<div class="bg-green-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: timelinessRate + '%' }"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -212,46 +166,58 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
<div class="flex justify-between text-sm mb-1">
|
||||||
<span class="text-gray-600">温度异常率</span>
|
<span class="text-gray-600">温度异常率</span>
|
||||||
<span class="text-gray-500">85%</span>
|
<span class="text-gray-500">{{ problemTypes.temperature }}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2">
|
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
||||||
<div class="bg-blue-500 h-2 rounded-full" style="width: 85%"></div>
|
<div
|
||||||
|
class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out"
|
||||||
|
:style="{ width: problemTypes.temperature + '%' }"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
<div class="flex justify-between text-sm mb-1">
|
||||||
<span class="text-gray-600">内存使用率</span>
|
<span class="text-gray-600">内存使用率</span>
|
||||||
<span class="text-gray-500">62%</span>
|
<span class="text-gray-500">{{ problemTypes.memory }}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2">
|
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
||||||
<div class="bg-blue-500 h-2 rounded-full" style="width: 62%"></div>
|
<div
|
||||||
|
class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out"
|
||||||
|
:style="{ width: problemTypes.memory + '%' }"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
<div class="flex justify-between text-sm mb-1">
|
||||||
<span class="text-gray-600">CPU负载</span>
|
<span class="text-gray-600">CPU负载</span>
|
||||||
<span class="text-gray-500">45%</span>
|
<span class="text-gray-500">{{ problemTypes.cpu }}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2">
|
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
||||||
<div class="bg-blue-500 h-2 rounded-full" style="width: 45%"></div>
|
<div class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out" :style="{ width: problemTypes.cpu + '%' }"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
<div class="flex justify-between text-sm mb-1">
|
||||||
<span class="text-gray-600">响应时间</span>
|
<span class="text-gray-600">响应时间</span>
|
||||||
<span class="text-gray-500">30%</span>
|
<span class="text-gray-500">{{ problemTypes.responseTime }}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2">
|
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
||||||
<div class="bg-blue-500 h-2 rounded-full" style="width: 30%"></div>
|
<div
|
||||||
|
class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out"
|
||||||
|
:style="{ width: problemTypes.responseTime + '%' }"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-sm mb-1">
|
<div class="flex justify-between text-sm mb-1">
|
||||||
<span class="text-gray-600">磁盘空间状态</span>
|
<span class="text-gray-600">磁盘空间状态</span>
|
||||||
<span class="text-gray-500">15%</span>
|
<span class="text-gray-500">{{ problemTypes.diskSpace }}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2">
|
<div class="w-full bg-gray-200 rounded-full h-2 overflow-hidden">
|
||||||
<div class="bg-blue-500 h-2 rounded-full" style="width: 15%"></div>
|
<div
|
||||||
|
class="bg-blue-500 h-2 rounded-full transition-all duration-1500 ease-out"
|
||||||
|
:style="{ width: problemTypes.diskSpace + '%' }"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -271,7 +237,7 @@
|
|||||||
<div class="card-body flex-1 overflow-y-auto scrollbar-thin">
|
<div class="card-body flex-1 overflow-y-auto scrollbar-thin">
|
||||||
<div class="inspection-results space-y-4">
|
<div class="inspection-results space-y-4">
|
||||||
<!-- 结果1:正常 -->
|
<!-- 结果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">
|
<div class="flex justify-between items-start mb-4">
|
||||||
<h3 class="text-lg font-medium text-gray-800">数据库性能巡检</h3>
|
<h3 class="text-lg font-medium text-gray-800">数据库性能巡检</h3>
|
||||||
<span class="status-tag status-normal px-3 py-1 text-xs">正常</span>
|
<span class="status-tag status-normal px-3 py-1 text-xs">正常</span>
|
||||||
@ -308,7 +274,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 结果2:需关注 -->
|
<!-- 结果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">
|
<div class="flex justify-between items-start mb-4">
|
||||||
<h3 class="text-lg font-medium text-gray-800">生产服务器日常巡检</h3>
|
<h3 class="text-lg font-medium text-gray-800">生产服务器日常巡检</h3>
|
||||||
<span class="status-tag status-attention px-3 py-1 text-xs">需关注</span>
|
<span class="status-tag status-attention px-3 py-1 text-xs">需关注</span>
|
||||||
@ -352,7 +318,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 结果3:有问题 -->
|
<!-- 结果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">
|
<div class="flex justify-between items-start mb-4">
|
||||||
<h3 class="text-lg font-medium text-gray-800">网络设备安全巡检</h3>
|
<h3 class="text-lg font-medium text-gray-800">网络设备安全巡检</h3>
|
||||||
<span class="status-tag status-problem px-3 py-1 text-xs">有问题</span>
|
<span class="status-tag status-problem px-3 py-1 text-xs">有问题</span>
|
||||||
@ -396,9 +362,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref, onMounted, computed, onUnmounted } from 'vue';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
|
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
|
||||||
// 筛选条件
|
// 筛选条件
|
||||||
const filterStatus = ref('all');
|
const filterStatus = ref('all');
|
||||||
@ -408,13 +375,216 @@ const dateRange = ref([]);
|
|||||||
// 时间范围选择
|
// 时间范围选择
|
||||||
const timeRange = ref('month'); // 默认选中"月"
|
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) => {
|
const handleTimeRangeChange = (range) => {
|
||||||
timeRange.value = range;
|
timeRange.value = range;
|
||||||
// 在实际应用中,这里应该根据选择的时间范围重新获取数据
|
fetchDashboardData(); // 切换时间范围时重新获取数据
|
||||||
console.log(`切换到${range}视图`);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取仪表盘数据(模拟)
|
||||||
|
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 = () => {
|
const handleInspection1 = () => {
|
||||||
router.push('/rili/rili');
|
router.push('/rili/rili');
|
||||||
@ -456,11 +626,12 @@ const handleInspectionManagement3 = () => {
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 头部容器 - 替换了固定gap的flex布局 */
|
/* 头部容器 */
|
||||||
.header-container {
|
.header-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-actions {
|
.header-actions {
|
||||||
@ -603,7 +774,7 @@ const handleInspectionManagement3 = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.card-body {
|
.card-body {
|
||||||
padding: 0 20px;
|
padding: 20px;
|
||||||
flex: 1; /* 内容区域占满剩余空间 */
|
flex: 1; /* 内容区域占满剩余空间 */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,6 +783,14 @@ const handleInspectionManagement3 = () => {
|
|||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 16px;
|
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 {
|
.stat-label {
|
||||||
@ -639,6 +818,14 @@ const handleInspectionManagement3 = () => {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #606266;
|
color: #606266;
|
||||||
margin: 0 0 8px 0;
|
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;
|
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 {
|
.status-tag {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@ -698,18 +861,6 @@ const handleInspectionManagement3 = () => {
|
|||||||
border: 1px solid #ffe3e0;
|
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-thin {
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
@ -750,4 +901,25 @@ const handleInspectionManagement3 = () => {
|
|||||||
justify-content: flex-end;
|
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>
|
</style>
|
||||||
|
|||||||
@ -106,8 +106,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="task-actions">
|
<div class="task-actions">
|
||||||
<el-button type="text" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button>
|
<el-button type="text" 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="primary" :class="task.actionClass" @click="handleAction(task)">
|
||||||
{{ task.actionText }}
|
{{ task.actionText }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -588,6 +588,10 @@ const handleInspection7 = () => {
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.task-actions .el-button {
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 6px 16px;
|
||||||
|
}
|
||||||
.task-card::before {
|
.task-card::before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@ -22,7 +22,13 @@
|
|||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<span>租金</span>
|
<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>
|
</div>
|
||||||
<el-icon :size="50" color="#3176ff">
|
<el-icon :size="50" color="#3176ff">
|
||||||
<Postcard />
|
<Postcard />
|
||||||
|
|||||||
@ -115,11 +115,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="分包公司" align="center" prop="contractorName" />
|
<el-table-column label="分包公司" align="center" prop="contractorName" />
|
||||||
<el-table-column label="班组" align="center" prop="teamId">
|
<el-table-column label="班组" align="center" prop="teamName"> </el-table-column>
|
||||||
<template #default="scope">
|
|
||||||
{{ getTeamName(scope.row.teamId) }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="联系电话" align="center" prop="phone" min-width="120" />
|
<el-table-column label="联系电话" align="center" prop="phone" min-width="120" />
|
||||||
<el-table-column label="性别" align="center" prop="sex">
|
<el-table-column label="性别" align="center" prop="sex">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
|||||||
Reference in New Issue
Block a user