0917
This commit is contained in:
BIN
src/assets/images/attendanceperson.png
Normal file
BIN
src/assets/images/attendanceperson.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
BIN
src/assets/images/car.png
Normal file
BIN
src/assets/images/car.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 469 KiB |
772
src/views/zhinengxunjian/InspectionManagement.vue
Normal file
772
src/views/zhinengxunjian/InspectionManagement.vue
Normal file
@ -0,0 +1,772 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="operation-inspection">
|
||||||
|
<div class="navigation-tabs">
|
||||||
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
|
<div class="nav-tab active" @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>
|
||||||
|
<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>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement2">巡检任务</el-button>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement3">巡检记录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 筛选栏 -->
|
||||||
|
<div class="filter-bar">
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="planType" placeholder="计划类型" clearable>
|
||||||
|
<el-option label="全部类型" value="all"></el-option>
|
||||||
|
<el-option label="每日巡检" value="daily"></el-option>
|
||||||
|
<el-option label="每周巡检" value="weekly"></el-option>
|
||||||
|
<el-option label="每月巡检" value="monthly"></el-option>
|
||||||
|
<el-option label="每季度巡检" value="quarterly"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="status" placeholder="全部状态" clearable>
|
||||||
|
<el-option label="全部状态" value="all"></el-option>
|
||||||
|
<el-option label="启用中" value="enabled"></el-option>
|
||||||
|
<el-option label="已停用" value="disabled"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="inspectionObject" placeholder="巡检对象" clearable>
|
||||||
|
<el-option label="全部对象" value="all"></el-option>
|
||||||
|
<el-option label="服务器" value="server"></el-option>
|
||||||
|
<el-option label="网络设备" value="network"></el-option>
|
||||||
|
<el-option label="应用系统" value="application"></el-option>
|
||||||
|
<el-option label="基础设施" value="infrastructure"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-actions">
|
||||||
|
<el-button type="primary" class="search-btn">搜索</el-button>
|
||||||
|
<el-button type="primary" icon="el-icon-plus" class="create-btn" @click="handleCreate">手动创建计划</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 表格 -->
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<el-table :data="pagedTableData" stripe style="width: 100%" highlight-current-row class="custom-table">
|
||||||
|
<el-table-column align="center" prop="name" label="计划名称" style="width: 14.2%"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="type" label="类型" style="width: 14.2%"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="object" label="巡检对象" style="width: 14.2%"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="frequency" label="频率" style="width: 14.2%"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="status" label="状态" style="width: 14.2%">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="scope.row.status === 'enabled' ? 'success' : 'info'" class="status-tag">
|
||||||
|
{{ scope.row.status === 'enabled' ? '启用中' : '已停用' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" prop="responsible" label="负责人" style="width: 14.2%"></el-table-column>
|
||||||
|
<el-table-column align="center" label="操作" style="width: 14.2%" fixed="right">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button type="text" @click="handleEdit(scope.row)" size="small" class="action-btn">编辑</el-button>
|
||||||
|
<el-button type="text" @click="handleDetail(scope.row)" size="small" class="action-btn">详情</el-button>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
:disabled="scope.row.status === 'disabled'"
|
||||||
|
@click="handleEnable(scope.row)"
|
||||||
|
size="small"
|
||||||
|
class="action-btn"
|
||||||
|
:class="{ 'text-success': scope.row.status === 'disabled' }"
|
||||||
|
>
|
||||||
|
{{ scope.row.status === 'enabled' ? '停用' : '启用' }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
<!-- 分页区域 -->
|
||||||
|
<div class="pagination-section">
|
||||||
|
<div class="pagination-info">
|
||||||
|
显示第{{ (currentPage - 1) * pageSize + 1 }}到{{ Math.min(currentPage * pageSize, total) }}条,共有{{ total }}条记录
|
||||||
|
</div>
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<el-pagination
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
:current-page="currentPage"
|
||||||
|
:page-sizes="[10, 20, 30, 40]"
|
||||||
|
:page-size="pageSize"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:total="total"
|
||||||
|
background
|
||||||
|
>
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 创建计划弹窗 -->
|
||||||
|
<el-dialog v-model="dialogVisible" title="新建巡检计划" width="700px" class="create-plan-dialog" center :show-close="true">
|
||||||
|
<el-form :model="createForm" :rules="createFormRules" ref="createFormRef" label-width="150px" class="custom-form">
|
||||||
|
<el-form-item label="计划名称*" prop="planName" class="form-item-large">
|
||||||
|
<el-input v-model="createForm.planName" placeholder="请输入计划名称" class="custom-input" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<el-form-item label="计划类型*" prop="planType" class="form-item-half">
|
||||||
|
<el-select v-model="createForm.planType" placeholder="请选择计划类型" class="custom-select">
|
||||||
|
<el-option label="每日巡检" value="daily" />
|
||||||
|
<el-option label="每周巡检" value="weekly" />
|
||||||
|
<el-option label="每月巡检" value="monthly" />
|
||||||
|
<el-option label="每季度巡检" value="quarterly" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="巡检对象类型*" prop="objectType" class="form-item-half">
|
||||||
|
<el-select v-model="createForm.objectType" placeholder="请选择对象类型" class="custom-select">
|
||||||
|
<el-option label="服务器" value="server" />
|
||||||
|
<el-option label="网络设备" value="network" />
|
||||||
|
<el-option label="应用系统" value="application" />
|
||||||
|
<el-option label="基础设施" value="infrastructure" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<el-form-item label="开始日期*" prop="startDate" class="form-item-half">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="createForm.startDate"
|
||||||
|
type="date"
|
||||||
|
placeholder="选择日期"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
class="custom-date-picker"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="结束日期*" prop="endDate" class="form-item-half">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="createForm.endDate"
|
||||||
|
type="date"
|
||||||
|
placeholder="选择日期"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
class="custom-date-picker"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<el-form-item label="巡检频率*" class="form-item-large">
|
||||||
|
<div style="display: flex; align-items: center; gap: 20px">
|
||||||
|
<el-radio-group v-model="createForm.frequencyType" class="frequency-radio-group">
|
||||||
|
<el-radio label="daily">每天</el-radio>
|
||||||
|
<el-radio label="weekly">每周</el-radio>
|
||||||
|
<el-radio label="monthly">每月</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
|
||||||
|
<!-- 每周选择框 - 变小并排在单选框后面 -->
|
||||||
|
<el-select
|
||||||
|
v-if="createForm.frequencyType === 'weekly'"
|
||||||
|
v-model="createForm.weekday"
|
||||||
|
placeholder="选择周几"
|
||||||
|
class="custom-select-small"
|
||||||
|
style="width: 100px"
|
||||||
|
>
|
||||||
|
<el-option label="周一" value="1" />
|
||||||
|
<el-option label="周二" value="2" />
|
||||||
|
<el-option label="周三" value="3" />
|
||||||
|
<el-option label="周四" value="4" />
|
||||||
|
<el-option label="周五" value="5" />
|
||||||
|
<el-option label="周六" value="6" />
|
||||||
|
<el-option label="周日" value="0" />
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<!-- 每月选择框 - 变小并排在单选框后面 -->
|
||||||
|
<el-select
|
||||||
|
v-if="createForm.frequencyType === 'monthly'"
|
||||||
|
v-model="createForm.monthday"
|
||||||
|
placeholder="选择几号"
|
||||||
|
class="custom-select-small"
|
||||||
|
style="width: 100px"
|
||||||
|
>
|
||||||
|
<template v-for="day in 31" :key="day">
|
||||||
|
<el-option :label="day + '号'" :value="day" />
|
||||||
|
</template>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="form-row" s>
|
||||||
|
<el-form-item label="计划开始时间*" prop="startTime" class="form-item-half">
|
||||||
|
<el-time-picker v-model="createForm.startTime" placeholder="选择时间" format="HH:mm" value-format="HH:mm" class="custom-time-picker" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="预计时长(分钟)" class="form-item-half">
|
||||||
|
<el-input v-model.number="createForm.estimatedDuration" class="custom-input" />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item label="负责人*" prop="responsiblePerson" class="form-item-large">
|
||||||
|
<el-select v-model="createForm.responsiblePerson" placeholder="请选择负责人" class="custom-select">
|
||||||
|
<el-option label="张明" value="zhangming" />
|
||||||
|
<el-option label="李华" value="lihua" />
|
||||||
|
<el-option label="王强" value="wangqiang" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="巡检项*" class="form-item-large">
|
||||||
|
<el-checkbox-group v-model="createForm.inspectionItems" style="border: 0.1 solid black; padding: 5px">
|
||||||
|
<el-checkbox label="CPU使用率检查" />
|
||||||
|
<el-checkbox label="内存使用情况" />
|
||||||
|
<el-checkbox label="磁盘空间检查" />
|
||||||
|
<el-checkbox label="网络连接状态" />
|
||||||
|
<el-checkbox label="系统日志检查" />
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="备注说明" prop="remarks" class="form-item-large">
|
||||||
|
<el-input v-model="createForm.remarks" type="textarea" placeholder="请输入备注" rows="3" class="custom-textarea" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="cancelCreatePlan">取消</el-button>
|
||||||
|
<el-button type="primary" @click="submitCreatePlan">新增任务</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
// 表单引用
|
||||||
|
const createFormRef = ref(null);
|
||||||
|
import { ref, computed, reactive } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './TitleComponent.vue';
|
||||||
|
|
||||||
|
// 激活的选项卡
|
||||||
|
const activeTab = ref('plan');
|
||||||
|
// 计划类型
|
||||||
|
const planType = ref('all');
|
||||||
|
// 状态
|
||||||
|
const status = ref('all');
|
||||||
|
// 巡检对象
|
||||||
|
const inspectionObject = ref('all');
|
||||||
|
// 原始表格数据
|
||||||
|
const rawTableData = ref([
|
||||||
|
{
|
||||||
|
name: '生产服务器每日巡检 2025-05-14',
|
||||||
|
type: '每日巡检',
|
||||||
|
object: '服务器',
|
||||||
|
frequency: '每天8:30',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '张明'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '网络设备安全巡检 2025-04-15',
|
||||||
|
type: '每周巡检',
|
||||||
|
object: '网络设备',
|
||||||
|
frequency: '每天10:30',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '张明'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '数据库性能巡检 2025-03-03',
|
||||||
|
type: '每月巡检',
|
||||||
|
object: '应用系统',
|
||||||
|
frequency: '每月1日14:00',
|
||||||
|
status: 'disabled',
|
||||||
|
responsible: '张明'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '机房环境季度检查',
|
||||||
|
type: '每季度巡检',
|
||||||
|
object: '基础设备',
|
||||||
|
frequency: '每季度第一个月5号',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '张明'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '生产服务器每日巡检 2025-05-14',
|
||||||
|
type: '每日巡检',
|
||||||
|
object: '服务器',
|
||||||
|
frequency: '每天8:30',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '张明'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '生产服务器每日巡检 2025-05-14',
|
||||||
|
type: '每日巡检',
|
||||||
|
object: '服务器',
|
||||||
|
frequency: '每天8:30',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '张明'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '生产服务器每日巡检 2025-05-14',
|
||||||
|
type: '每日巡检',
|
||||||
|
object: '服务器',
|
||||||
|
frequency: '每天8:30',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '张明'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '生产服务器每日巡检 2025-05-14',
|
||||||
|
type: '每日巡检',
|
||||||
|
object: '服务器',
|
||||||
|
frequency: '每天8:30',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '张明'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '生产服务器每日巡检 2025-05-14',
|
||||||
|
type: '每日巡检',
|
||||||
|
object: '服务器',
|
||||||
|
frequency: '每天8:30',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '张明'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '生产服务器每日巡检 2025-05-14',
|
||||||
|
type: '每日巡检',
|
||||||
|
object: '服务器',
|
||||||
|
frequency: '每天8:30',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '张明'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '生产服务器每日巡检 2025-05-14',
|
||||||
|
type: '每日巡检',
|
||||||
|
object: '服务器',
|
||||||
|
frequency: '每天8:30',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '张明'
|
||||||
|
},
|
||||||
|
// 增加更多数据用于测试分页
|
||||||
|
{
|
||||||
|
name: '应用系统安全检查',
|
||||||
|
type: '每周巡检',
|
||||||
|
object: '应用系统',
|
||||||
|
frequency: '每周五16:00',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '李华'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '网络带宽监控',
|
||||||
|
type: '每日巡检',
|
||||||
|
object: '网络设备',
|
||||||
|
frequency: '每天12:00',
|
||||||
|
status: 'enabled',
|
||||||
|
responsible: '王强'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
// 当前页码
|
||||||
|
const currentPage = ref(1);
|
||||||
|
// 每页条数 - 与分页控件默认值保持一致
|
||||||
|
const pageSize = ref(10);
|
||||||
|
// 总条数 - 从原始数据计算得出
|
||||||
|
const total = ref(rawTableData.value.length);
|
||||||
|
|
||||||
|
// 计算属性:根据当前页码和每页条数获取分页后的数据
|
||||||
|
const pagedTableData = computed(() => {
|
||||||
|
const startIndex = (currentPage.value - 1) * pageSize.value;
|
||||||
|
const endIndex = startIndex + pageSize.value;
|
||||||
|
return rawTableData.value.slice(startIndex, endIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 每页条数改变
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pageSize.value = val;
|
||||||
|
currentPage.value = 1; // 重置到第一页
|
||||||
|
};
|
||||||
|
|
||||||
|
// 当前页码改变
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
currentPage.value = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 编辑
|
||||||
|
const handleEdit = (row) => {
|
||||||
|
console.log('编辑', row);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 详情
|
||||||
|
const handleDetail = (row) => {
|
||||||
|
console.log('详情', row);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 启用/停用
|
||||||
|
const handleEnable = (row) => {
|
||||||
|
row.status = row.status === 'enabled' ? 'disabled' : 'enabled';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选项卡切换
|
||||||
|
const handleTabChange = (newTab, oldTab) => {
|
||||||
|
// 可以在这里添加选项卡切换时的逻辑
|
||||||
|
console.log('选项卡切换:', newTab, oldTab);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建计划弹窗相关
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const createForm = reactive({
|
||||||
|
planName: '',
|
||||||
|
planType: '',
|
||||||
|
objectType: '',
|
||||||
|
startDate: '',
|
||||||
|
endDate: '',
|
||||||
|
frequencyType: 'daily',
|
||||||
|
frequencyValue: '',
|
||||||
|
weekday: '', // 存储周几
|
||||||
|
monthday: '', // 存储几号
|
||||||
|
startTime: '',
|
||||||
|
estimatedDuration: 60,
|
||||||
|
responsiblePerson: '',
|
||||||
|
inspectionItems: [],
|
||||||
|
remarks: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建计划表单验证规则
|
||||||
|
const createFormRules = computed(() => ({
|
||||||
|
planName: [{ required: true, message: '请输入计划名称', trigger: 'blur' }],
|
||||||
|
planType: [{ required: true, message: '请选择计划类型', trigger: 'change' }],
|
||||||
|
objectType: [{ required: true, message: '请选择对象类型', trigger: 'change' }],
|
||||||
|
startDate: [{ required: true, message: '请选择开始日期', trigger: 'change' }],
|
||||||
|
endDate: [{ required: true, message: '请选择结束日期', trigger: 'change' }],
|
||||||
|
startTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
|
||||||
|
responsiblePerson: [{ required: true, message: '请选择负责人', trigger: 'change' }],
|
||||||
|
weekday: createForm.frequencyType === 'weekly' ? [{ required: true, message: '请选择周几', trigger: 'change' }] : [],
|
||||||
|
monthday: createForm.frequencyType === 'monthly' ? [{ required: true, message: '请选择几号', trigger: 'change' }] : []
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 打开创建计划弹窗
|
||||||
|
const handleCreate = () => {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交创建计划
|
||||||
|
const submitCreatePlan = () => {
|
||||||
|
console.log('提交创建计划:', createForm);
|
||||||
|
// 这里可以添加实际的创建计划逻辑
|
||||||
|
dialogVisible.value = false;
|
||||||
|
// 重置表单
|
||||||
|
Object.keys(createForm).forEach((key) => {
|
||||||
|
if (Array.isArray(createForm[key])) {
|
||||||
|
createForm[key] = [];
|
||||||
|
} else if (key === 'estimatedDuration') {
|
||||||
|
createForm[key] = 60;
|
||||||
|
} else if (key === 'frequencyType') {
|
||||||
|
createForm[key] = 'daily';
|
||||||
|
} else {
|
||||||
|
createForm[key] = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消创建计划
|
||||||
|
const cancelCreatePlan = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
// 重置表单
|
||||||
|
Object.keys(createForm).forEach((key) => {
|
||||||
|
if (Array.isArray(createForm[key])) {
|
||||||
|
createForm[key] = [];
|
||||||
|
} else if (key === 'estimatedDuration') {
|
||||||
|
createForm[key] = 60;
|
||||||
|
} else if (key === 'frequencyType') {
|
||||||
|
createForm[key] = 'daily';
|
||||||
|
} else {
|
||||||
|
createForm[key] = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const handleInspection1 = () => {
|
||||||
|
router.push('/rili/rili');
|
||||||
|
};
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement1 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspectionManagement2 = () => {
|
||||||
|
router.push('/rili/xunjianrenwu');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement3 = () => {
|
||||||
|
router.push('/rili/xunjianjihua');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 样式保持不变 */
|
||||||
|
.operation-inspection {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标题区域样式 */
|
||||||
|
.title-section {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #909399;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选项卡样式 */
|
||||||
|
.tabs-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs {
|
||||||
|
border-bottom: none;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__header {
|
||||||
|
margin: 0 -20px 0 -20px;
|
||||||
|
padding: 0 20px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__nav-wrap::after {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
padding: 12px 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item.is-active {
|
||||||
|
color: #409eff;
|
||||||
|
border-bottom-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item:hover {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 筛选栏样式 */
|
||||||
|
.filter-bar {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select {
|
||||||
|
width: 150px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn,
|
||||||
|
.create-btn {
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表格样式 */
|
||||||
|
.table-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-table {
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-table th {
|
||||||
|
background-color: #fafafa;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #606266;
|
||||||
|
text-align: left;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-table td {
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-table tr:hover {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-table tr.current-row {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag {
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
color: #409eff;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:hover {
|
||||||
|
color: #66b1ff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分页区域样式 */
|
||||||
|
.pagination-section {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-info {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination__sizes {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination button {
|
||||||
|
min-width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination .el-pager li {
|
||||||
|
min-width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination .el-pager li.active {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
/* 导航栏样式 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.filter-bar {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: 0;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
29
src/views/zhinengxunjian/TitleComponent.vue
Normal file
29
src/views/zhinengxunjian/TitleComponent.vue
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<el-row style="padding: 0 20px;">
|
||||||
|
<el-col>
|
||||||
|
<div style="color: rgba(0, 30, 59, 1); font-family: 'Alibaba-PuHuiTi-Bold'; margin: 10px 0 0 0"
|
||||||
|
:style="{ fontSize: fontLevelMap[props.fontLevel] }">
|
||||||
|
{{ props.title }}
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col>
|
||||||
|
<p style="color: rgba(154, 154, 154, 1); font-size: 14px">
|
||||||
|
{{ props.subtitle }}
|
||||||
|
</p>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
title: String,
|
||||||
|
subtitle: String,
|
||||||
|
fontLevel: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const fontLevelMap = {
|
||||||
|
1: '24px',
|
||||||
|
2: '18px'
|
||||||
|
};
|
||||||
|
</script>
|
||||||
1031
src/views/zhinengxunjian/banzhuzhuangtai.vue
Normal file
1031
src/views/zhinengxunjian/banzhuzhuangtai.vue
Normal file
File diff suppressed because it is too large
Load Diff
1176
src/views/zhinengxunjian/baoxiuguanli.vue
Normal file
1176
src/views/zhinengxunjian/baoxiuguanli.vue
Normal file
File diff suppressed because it is too large
Load Diff
720
src/views/zhinengxunjian/baoxiujilu.vue
Normal file
720
src/views/zhinengxunjian/baoxiujilu.vue
Normal file
@ -0,0 +1,720 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="inspection-tasks">
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<div class="navigation-tabs">
|
||||||
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
|
<div class="nav-tab active" @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>
|
||||||
|
|
||||||
|
<!-- 页面标题 -->
|
||||||
|
<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>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement2">报修记录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选栏 -->
|
||||||
|
<div class="filter-bar">
|
||||||
|
<div class="filter-container">
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="taskStatus" placeholder="任务状态">
|
||||||
|
<el-option label="待执行" value="pending"></el-option>
|
||||||
|
<el-option label="处理中" value="processing"></el-option>
|
||||||
|
<el-option label="已完成" value="completed"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="priority" placeholder="优先级">
|
||||||
|
<el-option label="高优先级" value="high"></el-option>
|
||||||
|
<el-option label="中优先级" value="medium"></el-option>
|
||||||
|
<el-option label="低优先级" value="low"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="executor" placeholder="处理人员">
|
||||||
|
<el-option label="全部人员" value="all"></el-option>
|
||||||
|
<el-option label="李阳" value="liyang"></el-option>
|
||||||
|
<el-option label="张明" value="zhangming"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
type="datetimerange"
|
||||||
|
start-placeholder="开始时间"
|
||||||
|
end-placeholder="结束时间"
|
||||||
|
format="YYYY-MM-DD HH:mm"
|
||||||
|
value-format="YYYY-MM-DD HH:mm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="filter-actions">
|
||||||
|
<el-button type="primary" class="search-btn" @click="handleSearch"> 搜索 </el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 统计卡片区域 -->
|
||||||
|
<div class="statistics-container">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-info">
|
||||||
|
<p class="stat-label">本月报修数</p>
|
||||||
|
<p class="stat-value">24</p>
|
||||||
|
<p class="stat-trend up">较上月 +4.2%</p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-icon">
|
||||||
|
<i class="el-icon-file-text"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-info">
|
||||||
|
<p class="stat-label">平均处理时长</p>
|
||||||
|
<p class="stat-value">3.5小时</p>
|
||||||
|
<p class="stat-trend down">较上月 -0.6小时</p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-icon">
|
||||||
|
<i class="el-icon-clock"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-info">
|
||||||
|
<p class="stat-label">待处理报修</p>
|
||||||
|
<p class="stat-value">15</p>
|
||||||
|
<p class="stat-trend warning">需及时处理</p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-icon warning">
|
||||||
|
<i class="el-icon-alarm-clock"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-info">
|
||||||
|
<p class="stat-label">完成率</p>
|
||||||
|
<p class="stat-value">92%</p>
|
||||||
|
<p class="stat-trend up">较上月 +2.1%</p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-icon success">
|
||||||
|
<i class="el-icon-check-circle"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 报修记录表格 -->
|
||||||
|
<div class="table-container">
|
||||||
|
<el-table :data="filteredRecords" border style="width: 100%" class="record-table">
|
||||||
|
<el-table-column prop="reportNo" label="报修单号" width="140"></el-table-column>
|
||||||
|
<el-table-column prop="content" label="报修内容"></el-table-column>
|
||||||
|
<el-table-column prop="reporter" label="报修人" width="100"></el-table-column>
|
||||||
|
<el-table-column prop="reportTime" label="报修时间" width="160"></el-table-column>
|
||||||
|
<el-table-column prop="handler" label="处理人员" width="100"></el-table-column>
|
||||||
|
<el-table-column prop="status" label="处理状态" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<span :class="`status-tag ${scope.row.statusClass}`">{{ scope.row.status }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="handleTime" label="处理时间" width="160"></el-table-column>
|
||||||
|
<el-table-column prop="result" label="维修结果"></el-table-column>
|
||||||
|
<el-table-column label="操作" width="160">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button type="text" size="small" class="detail-btn" @click="handleDetail(scope.row)"> 详情 </el-button>
|
||||||
|
<el-button type="text" size="small" :class="scope.row.actionClass" @click="handleAction(scope.row)">
|
||||||
|
{{ scope.row.actionText }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页区域 -->
|
||||||
|
<div class="pagination-section">
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<el-pagination
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
:current-page="currentPage"
|
||||||
|
:page-sizes="[7, 15, 20, 30]"
|
||||||
|
:page-size="pageSize"
|
||||||
|
layout="prev, pager, next, jumper"
|
||||||
|
:total="total"
|
||||||
|
background
|
||||||
|
>
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './TitleComponent.vue';
|
||||||
|
|
||||||
|
// 筛选条件
|
||||||
|
const taskStatus = ref('');
|
||||||
|
const priority = ref('');
|
||||||
|
const executor = ref('');
|
||||||
|
const dateRange = ref([]);
|
||||||
|
|
||||||
|
// 分页相关
|
||||||
|
const currentPage = ref(3);
|
||||||
|
const pageSize = ref(7);
|
||||||
|
|
||||||
|
// 报修记录数据
|
||||||
|
const repairRecords = ref([
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-001',
|
||||||
|
content: '服务器A1电源故障',
|
||||||
|
reporter: '张明',
|
||||||
|
reportTime: '2025-06-20 08:30',
|
||||||
|
handler: '李阳',
|
||||||
|
status: '处理中',
|
||||||
|
statusClass: 'processing',
|
||||||
|
handleTime: '--',
|
||||||
|
result: '--',
|
||||||
|
actionText: '跟进',
|
||||||
|
actionClass: 'follow-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-002',
|
||||||
|
content: '测试软件授权过期',
|
||||||
|
reporter: '张明',
|
||||||
|
reportTime: '2025-06-20 09:15',
|
||||||
|
handler: '李阳',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
handleTime: '2025-06-21 14:30',
|
||||||
|
result: '已重新授权',
|
||||||
|
actionText: '评价',
|
||||||
|
actionClass: 'evaluate-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-003',
|
||||||
|
content: '打印机卡纸故障',
|
||||||
|
reporter: '张明',
|
||||||
|
reportTime: '2025-06-20 10:45',
|
||||||
|
handler: '李阳',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
handleTime: '2025-06-21 10:15',
|
||||||
|
result: '已清除卡纸,设备正常',
|
||||||
|
actionText: '评价',
|
||||||
|
actionClass: 'evaluate-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-004',
|
||||||
|
content: '网络交换机端口故障',
|
||||||
|
reporter: '张明',
|
||||||
|
reportTime: '2025-06-20 13:20',
|
||||||
|
handler: '李阳',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
handleTime: '2025-06-20 15:40',
|
||||||
|
result: '已更换端口',
|
||||||
|
actionText: '评价',
|
||||||
|
actionClass: 'evaluate-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-005',
|
||||||
|
content: '服务器A1电源故障',
|
||||||
|
reporter: '张明',
|
||||||
|
reportTime: '2025-06-20 14:50',
|
||||||
|
handler: '李阳',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
handleTime: '2025-06-21 09:30',
|
||||||
|
result: '已重新授权',
|
||||||
|
actionText: '评价',
|
||||||
|
actionClass: 'evaluate-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-006',
|
||||||
|
content: '机房空调温度异常',
|
||||||
|
reporter: '张明',
|
||||||
|
reportTime: '2025-06-20 16:10',
|
||||||
|
handler: '李阳',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
handleTime: '2025-06-20 17:25',
|
||||||
|
result: '已修复,温度正常',
|
||||||
|
actionText: '评价',
|
||||||
|
actionClass: 'evaluate-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-007',
|
||||||
|
content: '监控系统无法连接',
|
||||||
|
reporter: '张明',
|
||||||
|
reportTime: '2025-06-20 18:05',
|
||||||
|
handler: '李阳',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
handleTime: '2025-06-21 08:45',
|
||||||
|
result: '网络配置已重置',
|
||||||
|
actionText: '评价',
|
||||||
|
actionClass: 'evaluate-btn'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 总记录数
|
||||||
|
const total = ref(54);
|
||||||
|
|
||||||
|
// 筛选后的记录
|
||||||
|
const filteredRecords = computed(() => {
|
||||||
|
// 实际应用中这里会根据筛选条件过滤数据
|
||||||
|
return repairRecords.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {
|
||||||
|
currentPage.value = 1; // 重置到第一页
|
||||||
|
// 实际应用中这里会根据筛选条件过滤数据
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建任务弹窗相关
|
||||||
|
const createTaskDialogVisible = ref(false);
|
||||||
|
const createTaskForm = ref({
|
||||||
|
taskName: '',
|
||||||
|
repairContent: '',
|
||||||
|
timeRange: [],
|
||||||
|
priority: '',
|
||||||
|
handler: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const createTaskRules = {
|
||||||
|
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
|
||||||
|
repairContent: [{ required: true, message: '请输入报修内容', trigger: 'blur' }],
|
||||||
|
timeRange: [{ required: true, message: '请选择时间范围', trigger: 'change' }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存任务
|
||||||
|
const handleSaveTask = () => {
|
||||||
|
// 模拟保存任务逻辑
|
||||||
|
console.log('保存任务:', createTaskForm.value);
|
||||||
|
// 关闭弹窗
|
||||||
|
createTaskDialogVisible.value = false;
|
||||||
|
// 重置表单
|
||||||
|
createTaskForm.value = {
|
||||||
|
taskName: '',
|
||||||
|
repairContent: '',
|
||||||
|
timeRange: [],
|
||||||
|
priority: '',
|
||||||
|
handler: ''
|
||||||
|
};
|
||||||
|
// 这里可以添加成功提示和刷新任务列表的逻辑
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消创建任务
|
||||||
|
const handleCancelCreateTask = () => {
|
||||||
|
createTaskDialogVisible.value = false;
|
||||||
|
// 重置表单
|
||||||
|
createTaskForm.value = {
|
||||||
|
taskName: '',
|
||||||
|
repairContent: '',
|
||||||
|
timeRange: [],
|
||||||
|
priority: '',
|
||||||
|
handler: ''
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页事件
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pageSize.value = val;
|
||||||
|
currentPage.value = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
currentPage.value = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
const handleDetail = (record) => {
|
||||||
|
console.log('查看详情:', record);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理操作
|
||||||
|
const handleAction = (record) => {
|
||||||
|
console.log('执行操作:', record.actionText, record);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 导航事件
|
||||||
|
const handleInspectionManagement1 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspectionManagement2 = () => {
|
||||||
|
router.push('/rili/baoxiujilu');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspection1 = () => {
|
||||||
|
router.push('/rili/rili');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.inspection-tasks {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选项卡样式 */
|
||||||
|
.tabs-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 筛选栏样式 */
|
||||||
|
.filter-bar {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 16px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select,
|
||||||
|
.filter-bar .el-date-picker {
|
||||||
|
width: 180px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select .el-input__inner,
|
||||||
|
.filter-bar .el-date-picker .el-input__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
border-color: #dcdfe6;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select .el-input__inner:focus,
|
||||||
|
.filter-bar .el-date-picker .el-input__inner:focus {
|
||||||
|
border-color: #165dff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
background-color: #f2f3f5;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #f2f3f5;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn:hover {
|
||||||
|
background-color: #e5e6eb;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #e5e6eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-btn {
|
||||||
|
background-color: #165dff;
|
||||||
|
border-color: #165dff;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-btn:hover {
|
||||||
|
background-color: #0e42d2;
|
||||||
|
border-color: #0e42d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 统计卡片样式 */
|
||||||
|
.statistics-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #86909c;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d2129;
|
||||||
|
margin: 0 0 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend {
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend.up {
|
||||||
|
color: #00b42a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend.up::before {
|
||||||
|
content: '↑';
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend.down {
|
||||||
|
color: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend.down::before {
|
||||||
|
content: '↓';
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend.warning {
|
||||||
|
color: #fa8c16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #e8f3ff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #165dff;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon.warning {
|
||||||
|
background-color: #fff7e6;
|
||||||
|
color: #fa8c16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon.success {
|
||||||
|
background-color: #f6ffed;
|
||||||
|
color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表格样式 */
|
||||||
|
.table-container {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-table {
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-table th {
|
||||||
|
background-color: #f7f8fa;
|
||||||
|
color: #4e5969;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-table td {
|
||||||
|
color: #1d2129;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag.processing {
|
||||||
|
background-color: #fffbe6;
|
||||||
|
color: #faad14;
|
||||||
|
border: 1px solid #fff1b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag.completed {
|
||||||
|
background-color: #f0f9eb;
|
||||||
|
color: #52c41a;
|
||||||
|
border: 1px solid #e1f3d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-btn {
|
||||||
|
color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-btn {
|
||||||
|
color: #fa8c16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.evaluate-btn {
|
||||||
|
color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分页区域样式 */
|
||||||
|
.pagination-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination button,
|
||||||
|
.pagination-controls .el-pagination .el-pager li {
|
||||||
|
min-width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination .el-pager li.active {
|
||||||
|
background-color: #165dff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导航栏样式 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.statistics-container {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.inspection-tasks {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: 0;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select,
|
||||||
|
.filter-bar .el-date-picker {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics-container {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
739
src/views/zhinengxunjian/cheliangzhuangtai.vue
Normal file
739
src/views/zhinengxunjian/cheliangzhuangtai.vue
Normal file
@ -0,0 +1,739 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="execution-records">
|
||||||
|
<!-- 顶部导航栏 -->
|
||||||
|
<div class="navigation-tabs">
|
||||||
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection4">报修管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
|
<div class="nav-tab active" @click="handleInspection7">运维组织</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 页面标题 -->
|
||||||
|
<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>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement2">车辆状态</el-button>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement3">班组状态</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 搜索和筛选区 -->
|
||||||
|
<div class="search-filter">
|
||||||
|
<div class="search-container">
|
||||||
|
<!-- 左侧统计数据和车辆图片组合 -->
|
||||||
|
<div class="stats-and-image">
|
||||||
|
<div class="vehicle-stats">
|
||||||
|
<div class="stats-container">
|
||||||
|
<div class="vehicle-stats">
|
||||||
|
<!-- 总车辆数 -->
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-label">总车辆数</div>
|
||||||
|
<div class="stat-value">{{ totalVehicles }}</div>
|
||||||
|
<div class="stat-desc">所有运维车辆总数</div>
|
||||||
|
</div>
|
||||||
|
<!-- 可用车辆 -->
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-label">可用车辆</div>
|
||||||
|
<div class="stat-value">{{ availableVehicles }}</div>
|
||||||
|
<div class="stat-desc available">可立即调度</div>
|
||||||
|
</div>
|
||||||
|
<!-- 使用中 -->
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-label">使用中</div>
|
||||||
|
<div class="stat-value">{{ inUseVehicles }}</div>
|
||||||
|
<div class="stat-desc in-use">执行任务中</div>
|
||||||
|
</div>
|
||||||
|
<!-- 维修/保养 -->
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-label">维修/保养</div>
|
||||||
|
<div class="stat-value">{{ maintenanceVehicles }}</div>
|
||||||
|
<div class="stat-desc maintenance">预计2天后可用</div>
|
||||||
|
</div>
|
||||||
|
<img src="@/assets/images/car.png" class="img-car" alt="车辆图片" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧搜索区域 -->
|
||||||
|
<div class="search-integrated">
|
||||||
|
<div class="search-box">
|
||||||
|
<div class="search-label">搜索车牌号</div>
|
||||||
|
<div class="license-plate-input">
|
||||||
|
<span class="plate-prefix">京</span>
|
||||||
|
<span class="plate-dot">·</span>
|
||||||
|
<el-input v-model="plateNumber1" maxlength="1" class="plate-char"></el-input>
|
||||||
|
<el-input v-model="plateNumber2" maxlength="1" class="plate-char"></el-input>
|
||||||
|
<el-input v-model="plateNumber3" maxlength="1" class="plate-char"></el-input>
|
||||||
|
<el-input v-model="plateNumber4" maxlength="1" class="plate-char"></el-input>
|
||||||
|
<el-input v-model="plateNumber5" maxlength="1" class="plate-char"></el-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 车辆列表表格 -->
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<el-table :data="pagedTableData" stripe style="width: 100%" highlight-current-row class="custom-table">
|
||||||
|
<el-table-column align="center" prop="vehicleId" label="车辆编号" min-width="120"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="licensePlate" label="车牌号" min-width="120"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="vehicleType" label="车辆类型" min-width="120"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="team" label="所属班组" min-width="120"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="responsiblePerson" label="负责人" min-width="120"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="currentTask" label="当前任务" min-width="150"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="status" label="当前状态" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="getStatusTagType(scope.row.status)" class="status-tag">
|
||||||
|
{{ scope.row.status }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" prop="nextMaintenance" label="下次保养" min-width="120"></el-table-column>
|
||||||
|
<el-table-column align="center" label="操作" min-width="180" fixed="right">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button type="text" @click="handleViewDetails(scope.row)" size="small" class="action-btn">详情</el-button>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
@click="handleDispatch(scope.row)"
|
||||||
|
size="small"
|
||||||
|
class="action-btn dispatch-btn"
|
||||||
|
v-if="scope.row.status === '可用'"
|
||||||
|
>
|
||||||
|
调度
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页区域 -->
|
||||||
|
<div class="pagination-section">
|
||||||
|
<div class="pagination-info">
|
||||||
|
显示第{{ (currentPage - 1) * pageSize + 1 }}到{{ Math.min(currentPage * pageSize, total) }}条,共{{ total }}条记录
|
||||||
|
</div>
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<el-pagination
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
:current-page="currentPage"
|
||||||
|
:page-sizes="[10, 20, 30, 40]"
|
||||||
|
:page-size="pageSize"
|
||||||
|
layout="prev, pager, next, jumper"
|
||||||
|
:total="total"
|
||||||
|
background
|
||||||
|
>
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './TitleComponent.vue';
|
||||||
|
|
||||||
|
// 搜索和筛选条件
|
||||||
|
const searchKeyword = ref('');
|
||||||
|
const plateNumber1 = ref('');
|
||||||
|
const plateNumber2 = ref('');
|
||||||
|
const plateNumber3 = ref('');
|
||||||
|
const plateNumber4 = ref('');
|
||||||
|
const plateNumber5 = ref('');
|
||||||
|
|
||||||
|
// 车辆数据
|
||||||
|
const rawTableData = ref([
|
||||||
|
{
|
||||||
|
vehicleId: 'CAR-001',
|
||||||
|
licensePlate: '京A·12345',
|
||||||
|
vehicleType: '工具车',
|
||||||
|
team: '第一运维组',
|
||||||
|
responsiblePerson: '赵工',
|
||||||
|
currentTask: '无',
|
||||||
|
status: '可用',
|
||||||
|
nextMaintenance: '2023-07-15'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vehicleId: 'CAR-003',
|
||||||
|
licensePlate: '京B·67890',
|
||||||
|
vehicleType: '小型货车',
|
||||||
|
team: '第二运维组',
|
||||||
|
responsiblePerson: '赵工',
|
||||||
|
currentTask: 'WO-2023-0619-055',
|
||||||
|
status: '使用中',
|
||||||
|
nextMaintenance: '2023-08-20'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vehicleId: 'CAR-005',
|
||||||
|
licensePlate: '京C·24680',
|
||||||
|
vehicleType: '工程车',
|
||||||
|
team: '第一运维组',
|
||||||
|
responsiblePerson: '赵工',
|
||||||
|
currentTask: 'WO-2023-0618-054',
|
||||||
|
status: '使用中',
|
||||||
|
nextMaintenance: '2023-07-15'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vehicleId: 'CAR-007',
|
||||||
|
licensePlate: '京D·13579',
|
||||||
|
vehicleType: '面包车',
|
||||||
|
team: '第三运维组',
|
||||||
|
responsiblePerson: '赵工',
|
||||||
|
currentTask: '无',
|
||||||
|
status: '维修中',
|
||||||
|
nextMaintenance: '2023-07-15'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vehicleId: 'CAR-009',
|
||||||
|
licensePlate: '京E·12345',
|
||||||
|
vehicleType: '工具车',
|
||||||
|
team: '第一运维组',
|
||||||
|
responsiblePerson: '赵工',
|
||||||
|
currentTask: '无',
|
||||||
|
status: '可用',
|
||||||
|
nextMaintenance: '2023-07-15'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vehicleId: 'CAR-011',
|
||||||
|
licensePlate: '京F·12345',
|
||||||
|
vehicleType: '工具车',
|
||||||
|
team: '第一运维组',
|
||||||
|
responsiblePerson: '赵工',
|
||||||
|
currentTask: '无',
|
||||||
|
status: '可用',
|
||||||
|
nextMaintenance: '2023-07-15'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vehicleId: 'CAR-013',
|
||||||
|
licensePlate: '京G·12345',
|
||||||
|
vehicleType: '工具车',
|
||||||
|
team: '第一运维组',
|
||||||
|
responsiblePerson: '赵工',
|
||||||
|
currentTask: '无',
|
||||||
|
status: '可用',
|
||||||
|
nextMaintenance: '2023-07-15'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 分页相关
|
||||||
|
const currentPage = ref(1);
|
||||||
|
const pageSize = ref(10);
|
||||||
|
const total = ref(rawTableData.value.length);
|
||||||
|
|
||||||
|
// 统计数据
|
||||||
|
const totalVehicles = computed(() => rawTableData.value.length);
|
||||||
|
const availableVehicles = computed(() => rawTableData.value.filter((v) => v.status === '可用').length);
|
||||||
|
const inUseVehicles = computed(() => rawTableData.value.filter((v) => v.status === '使用中').length);
|
||||||
|
const maintenanceVehicles = computed(() => rawTableData.value.filter((v) => v.status === '维修中').length);
|
||||||
|
|
||||||
|
// 分页处理后的数据
|
||||||
|
const pagedTableData = computed(() => {
|
||||||
|
// 筛选逻辑
|
||||||
|
let filteredData = [...rawTableData.value];
|
||||||
|
|
||||||
|
// 搜索关键词筛选
|
||||||
|
if (searchKeyword.value) {
|
||||||
|
const keyword = searchKeyword.value.toLowerCase();
|
||||||
|
filteredData = filteredData.filter(
|
||||||
|
(item) =>
|
||||||
|
item.vehicleId.toLowerCase().includes(keyword) ||
|
||||||
|
item.licensePlate.toLowerCase().includes(keyword) ||
|
||||||
|
item.vehicleType.toLowerCase().includes(keyword)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 车牌号筛选
|
||||||
|
const plateNumber = plateNumber1.value + plateNumber2.value + plateNumber3.value + plateNumber4.value + plateNumber5.value;
|
||||||
|
if (plateNumber) {
|
||||||
|
filteredData = filteredData.filter((item) => item.licensePlate.replace(/[·\s]/g, '').includes(plateNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新总条数
|
||||||
|
total.value = filteredData.length;
|
||||||
|
|
||||||
|
// 分页处理
|
||||||
|
const startIndex = (currentPage.value - 1) * pageSize.value;
|
||||||
|
const endIndex = startIndex + pageSize.value;
|
||||||
|
return filteredData.slice(startIndex, endIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取状态标签样式
|
||||||
|
const getStatusTagType = (status) => {
|
||||||
|
const statusMap = {
|
||||||
|
'可用': 'success',
|
||||||
|
'使用中': 'primary',
|
||||||
|
'维修中': 'warning'
|
||||||
|
};
|
||||||
|
return statusMap[status] || 'default';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {
|
||||||
|
currentPage.value = 1; // 重置到第一页
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页事件
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pageSize.value = val;
|
||||||
|
currentPage.value = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
currentPage.value = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 操作按钮事件
|
||||||
|
const handleViewDetails = (row) => {
|
||||||
|
console.log('查看详情:', row);
|
||||||
|
// 实际应用中这里会跳转到详情页
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDispatch = (row) => {
|
||||||
|
console.log('调度车辆:', row);
|
||||||
|
// 实际应用中这里会打开调度表单
|
||||||
|
};
|
||||||
|
|
||||||
|
// 导航路由跳转
|
||||||
|
const handleInspection1 = () => {
|
||||||
|
router.push('/rili/rili');
|
||||||
|
};
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement1 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement2 = () => {
|
||||||
|
router.push('/rili/cheliangzhuangtai');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement3 = () => {
|
||||||
|
router.push('/rili/banzhuzhuangtai');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.execution-records {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选项卡样式 */
|
||||||
|
.tabs-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 搜索和筛选区样式 */
|
||||||
|
.search-filter {
|
||||||
|
border-radius: 12px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||||
|
overflow: hidden;
|
||||||
|
transition: box-shadow 0.3s ease;
|
||||||
|
background: linear-gradient(135deg, #f0f7ff 0%, #f5f7fa 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 24px 32px;
|
||||||
|
min-height: 140px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 统计数据和车辆图片组合容器 */
|
||||||
|
.stats-and-image {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 40px;
|
||||||
|
flex: 1;
|
||||||
|
max-width: calc(100% - 350px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 车辆统计区域 */
|
||||||
|
.vehicle-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 28px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 搜索区域 */
|
||||||
|
.search-integrated {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: 320px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
background-color: rgba(255, 255, 255, 0.95);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px 24px;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
flex: 1;
|
||||||
|
background-color: rgba(255, 255, 255, 0.95);
|
||||||
|
padding: 20px 28px;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
min-width: 160px;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item:hover {
|
||||||
|
transform: translateY(-5px) scale(1.02);
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
||||||
|
border-color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
line-height: 1.2;
|
||||||
|
letter-spacing: -0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-desc {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #606266;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
.stats-container {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
display: inline-block; /* 适应内容宽度 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.vehicle-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 40px; /* 统计项之间的间距 */
|
||||||
|
align-items: flex-start; /* 顶部对齐 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
text-align: center;
|
||||||
|
min-width: 120px; /* 保证每个项的最小宽度 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1f2937; /* 深色标题(与参考图一致) */
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1f2937; /* 深色数值(与参考图一致) */
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #6b7280; /* 浅灰色默认描述 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 不同状态的描述文字颜色 */
|
||||||
|
.stat-desc.available {
|
||||||
|
color: #059669; /* 绿色(可立即调度) */
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-desc.in-use {
|
||||||
|
color: #d97706; /* 橙色(执行任务中) */
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-desc.maintenance {
|
||||||
|
color: #dc2626; /* 红色(预计2天后可用) */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 车牌号输入样式 */
|
||||||
|
.license-plate-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 2px solid #e6e6e6;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-plate-input:hover {
|
||||||
|
border-color: #c0c4cc;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.plate-prefix {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
padding: 0 12px;
|
||||||
|
height: 42px;
|
||||||
|
line-height: 42px;
|
||||||
|
border-right: 1px solid #dcdfe6;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plate-dot {
|
||||||
|
padding: 0 6px;
|
||||||
|
height: 42px;
|
||||||
|
line-height: 42px;
|
||||||
|
color: #606266;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plate-char {
|
||||||
|
width: 32px !important;
|
||||||
|
height: 42px !important;
|
||||||
|
text-align: center;
|
||||||
|
border: none;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
background-color: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plate-char:focus {
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
color: #409eff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plate-char:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表格样式优化 */
|
||||||
|
.table-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 状态标签样式 */
|
||||||
|
.status-tag {
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 操作按钮样式优化 */
|
||||||
|
.action-btn {
|
||||||
|
color: #165dff;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
margin: 0 3px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:hover {
|
||||||
|
color: #094ab2;
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dispatch-btn {
|
||||||
|
color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dispatch-btn:hover {
|
||||||
|
color: #389e0d;
|
||||||
|
background-color: #f6ffed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分页区域样式 */
|
||||||
|
.pagination-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 16px 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-info {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination button,
|
||||||
|
.pagination-controls .el-pagination .el-pager li {
|
||||||
|
min-width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination .el-pager li.active {
|
||||||
|
background-color: #165dff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.img-car {
|
||||||
|
max-width: 350px;
|
||||||
|
max-height: 350px;
|
||||||
|
}
|
||||||
|
/* 导航栏样式 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.search-container {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-and-image {
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-integrated {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.stats-and-image {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vehicle-image-container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.execution-records {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-tabs {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
flex: 1 0 33%;
|
||||||
|
padding: 10px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vehicle-stats {
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
flex: 1 0 40%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-section {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1095
src/views/zhinengxunjian/gongdanliebiao.vue
Normal file
1095
src/views/zhinengxunjian/gongdanliebiao.vue
Normal file
File diff suppressed because it is too large
Load Diff
786
src/views/zhinengxunjian/index.vue
Normal file
786
src/views/zhinengxunjian/index.vue
Normal file
@ -0,0 +1,786 @@
|
|||||||
|
<template>
|
||||||
|
<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="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>
|
||||||
|
<!-- 使用 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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, watch } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './TitleComponent.vue';
|
||||||
|
|
||||||
|
// 默认显示当前月份
|
||||||
|
const currentDate = ref(new Date());
|
||||||
|
|
||||||
|
// 为了保持兼容性,保留这些变量
|
||||||
|
const targetYear = 2025;
|
||||||
|
const years = ref([]);
|
||||||
|
const selectedYear = ref(currentDate.value.getFullYear());
|
||||||
|
const selectedMonth = ref(currentDate.value.getMonth() + 1);
|
||||||
|
|
||||||
|
// 减少月份
|
||||||
|
const decreaseMonth = () => {
|
||||||
|
const date = new Date(currentDate.value);
|
||||||
|
date.setMonth(date.getMonth() - 1);
|
||||||
|
currentDate.value = date;
|
||||||
|
updateYearAndMonth();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 增加月份
|
||||||
|
const increaseMonth = () => {
|
||||||
|
const date = new Date(currentDate.value);
|
||||||
|
date.setMonth(date.getMonth() + 1);
|
||||||
|
currentDate.value = date;
|
||||||
|
updateYearAndMonth();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 回到今天
|
||||||
|
const goToToday = () => {
|
||||||
|
currentDate.value = new Date();
|
||||||
|
updateYearAndMonth();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 日历事件数据 - 2025年9月的随机事件
|
||||||
|
const calendarEvents = ref([
|
||||||
|
// 服务维护事件
|
||||||
|
{ id: 1, date: '2025-09-11', title: '服务维护', description: '维护公司内部服务器', type: 'service' },
|
||||||
|
{ id: 2, date: '2025-09-28', title: '服务维护', description: '先所有旧服务器部署新内存', type: 'service' },
|
||||||
|
|
||||||
|
// 数据库管理事件
|
||||||
|
{ id: 3, date: '2025-09-21', title: '数据库管理', description: '定期执行数据库优化', type: 'database' },
|
||||||
|
{ id: 4, date: '2025-09-30', title: '数据库管理', description: '大型数据库备份策略', type: 'database' },
|
||||||
|
|
||||||
|
// 网络维护事件
|
||||||
|
{ id: 5, date: '2025-09-05', title: '网络维护', description: '网络设备例行检查', type: 'network' },
|
||||||
|
{ id: 6, date: '2025-09-15', title: '网络维护', description: '更新网络安全策略', type: 'network' },
|
||||||
|
|
||||||
|
// 系统升级事件
|
||||||
|
{ id: 7, date: '2025-09-18', title: '系统升级', description: '核心系统版本升级', type: 'upgrade' },
|
||||||
|
{ id: 8, date: '2025-09-25', title: '系统升级', description: '应用服务升级部署', type: 'upgrade' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 获取指定日期的事件
|
||||||
|
const getDayEvents = (dateStr) => {
|
||||||
|
return calendarEvents.value.filter((event) => event.date === dateStr);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据事件类型获取单元格样式
|
||||||
|
const getCellClass = (date) => {
|
||||||
|
const events = getDayEvents(date);
|
||||||
|
if (events.length > 0) {
|
||||||
|
const eventType = events[0].type;
|
||||||
|
return `date-cell-${eventType}`;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 更新年份和月份选择器的值
|
||||||
|
const updateYearAndMonth = () => {
|
||||||
|
selectedYear.value = currentDate.value.getFullYear();
|
||||||
|
selectedMonth.value = currentDate.value.getMonth() + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听日期变化,更新年份和月份
|
||||||
|
watch(currentDate, (newDate) => {
|
||||||
|
selectedYear.value = newDate.getFullYear();
|
||||||
|
selectedMonth.value = newDate.getMonth() + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化年份和月份
|
||||||
|
updateYearAndMonth();
|
||||||
|
|
||||||
|
// 弹窗相关状态管理
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const taskForm = ref({
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
timeRange: '',
|
||||||
|
priority: '常规项',
|
||||||
|
taskType: '常规维护'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 打开添加任务弹窗
|
||||||
|
const openAddTaskDialog = () => {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭弹窗
|
||||||
|
const closeDialog = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存任务
|
||||||
|
const saveTask = () => {
|
||||||
|
// 这里可以添加表单验证和保存逻辑
|
||||||
|
console.log('保存任务:', taskForm.value);
|
||||||
|
// 重置表单
|
||||||
|
taskForm.value = {
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
timeRange: '',
|
||||||
|
priority: '常规项',
|
||||||
|
taskType: '常规维护'
|
||||||
|
};
|
||||||
|
// 关闭弹窗
|
||||||
|
closeDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspection1 = () => {
|
||||||
|
router.push('/rili/rili');
|
||||||
|
};
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.box-container {
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导航栏样式 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header p {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
margin: 5px 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自定义弹窗样式 */
|
||||||
|
.custom-dialog {
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-dialog .el-dialog__header {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
padding: 15px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-dialog .el-dialog__title {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-dialog .el-dialog__body {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保所有输入框长度相等 */
|
||||||
|
.task-form .form-input {
|
||||||
|
height: 30px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 时间选择器样式调整 */
|
||||||
|
.task-form .el-date-editor {
|
||||||
|
width: 100%;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.form-container {
|
||||||
|
flex: 0 0 360px; /* 调整宽度以匹配设计图,更贴合右侧区域宽度 */
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 20px 20px 80px 20px; /* 增加底部内边距,为固定标签留出空间 */
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
position: relative; /* 设置为相对定位,使内部绝对定位元素相对于此容器定位 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-header h2 {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
max-height: 480px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 12px 12px 12px 20px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
border-radius: 4px;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 重要任务的背景色 */
|
||||||
|
.todo-item.important {
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-checkbox {
|
||||||
|
margin-top: 2px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-content {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-main {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-time {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-description {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #606266;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-actions {
|
||||||
|
position: absolute;
|
||||||
|
right: -120px;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
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: 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-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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 .color-block {
|
||||||
|
background-color: #faad14;
|
||||||
|
}
|
||||||
|
.status-tag.urgent .color-block {
|
||||||
|
background-color: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-color-indicator {
|
||||||
|
width: 8px;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 0 4px 4px 0;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-color-indicator.normal {
|
||||||
|
background-color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-color-indicator.important {
|
||||||
|
background-color: #faad14;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-color-indicator.urgent {
|
||||||
|
background-color: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .custom-date-cell {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 5px;
|
||||||
|
text-align: center;
|
||||||
|
box-sizing: border-box; /* 确保内边距不撑大元素 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 系统升级事件样式 */
|
||||||
|
.event-upgrade {
|
||||||
|
background-color: #fff1f0;
|
||||||
|
color: #f5222d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 日期单元格背景色 - 按事件类型 */
|
||||||
|
.date-cell-service {
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-cell-database {
|
||||||
|
background-color: #f0f9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-cell-network {
|
||||||
|
background-color: #fffbe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-cell-upgrade {
|
||||||
|
background-color: #fff1f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 日历样式优化 */
|
||||||
|
.el-calendar {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-calendar-table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 穿透作用域,强制设置日历单元格为正方形 */
|
||||||
|
::v-deep .el-calendar-table td {
|
||||||
|
padding: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
width: 120px; /* 强制宽度 */
|
||||||
|
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 {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-events {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-item {
|
||||||
|
padding: 3px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-title {
|
||||||
|
font-weight: bold;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-description {
|
||||||
|
font-size: 11px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 服务维护事件样式 */
|
||||||
|
.event-service {
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 数据库管理事件样式 */
|
||||||
|
.event-database {
|
||||||
|
background-color: #f0f9ff;
|
||||||
|
color: #36cfc9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 网络维护事件样式 */
|
||||||
|
.event-network {
|
||||||
|
background-color: #fffbe6;
|
||||||
|
color: #faad14;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 系统升级事件样式 */
|
||||||
|
.event-upgrade {
|
||||||
|
background-color: #fff1f0;
|
||||||
|
color: #f5222d;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
814
src/views/zhinengxunjian/paidanjilu.vue
Normal file
814
src/views/zhinengxunjian/paidanjilu.vue
Normal file
@ -0,0 +1,814 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="dispatch-records">
|
||||||
|
<!-- 顶部导航栏 -->
|
||||||
|
<div class="navigation-tabs">
|
||||||
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection4">报修管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
|
<div class="nav-tab active" @click="handleInspection6">工单管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 页面标题 -->
|
||||||
|
<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>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement2">派单计划</el-button>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement3">执行计划</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选栏 -->
|
||||||
|
<div class="filter-bar">
|
||||||
|
<div class="filter-container">
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="dispatchStatus" placeholder="派单状态" clearable>
|
||||||
|
<el-option label="全部状态" value="all"></el-option>
|
||||||
|
<el-option label="已接收" value="received"></el-option>
|
||||||
|
<el-option label="处理中" value="processing"></el-option>
|
||||||
|
<el-option label="已完成" value="completed"></el-option>
|
||||||
|
<el-option label="已拒绝" value="rejected"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="executor" placeholder="执行人" clearable>
|
||||||
|
<el-option label="全部人员" value="all"></el-option>
|
||||||
|
<el-option label="张明" value="zhangming"></el-option>
|
||||||
|
<el-option label="李华" value="lihua"></el-option>
|
||||||
|
<el-option label="王强" value="wangqiang"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-date-picker v-model="dispatchDate" type="date" placeholder="派单日期" format="yyyy/MM/dd" value-format="yyyy/MM/dd"></el-date-picker>
|
||||||
|
</div>
|
||||||
|
<div class="filter-actions">
|
||||||
|
<el-button type="primary" class="search-btn" @click="handleSearch">搜索</el-button>
|
||||||
|
<el-button type="primary" class="create-btn" @click="handleExport">导出记录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 统计卡片 -->
|
||||||
|
<div class="statistics-cards">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-value">{{ totalDispatches }}</div>
|
||||||
|
<div class="stat-label">本月派单总数</div>
|
||||||
|
<div class="stat-trend">较上月 <span class="trend-up">↑ 12%</span></div>
|
||||||
|
<div class="stat-icon">
|
||||||
|
<i class="el-icon-document"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-value">{{ avgResponseTime }}</div>
|
||||||
|
<div class="stat-label">平均响应时间</div>
|
||||||
|
<div class="stat-trend">较上月 <span class="trend-down">↓ 5分钟</span></div>
|
||||||
|
<div class="stat-icon">
|
||||||
|
<i class="el-icon-clock"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-value">{{ pendingDispatches }}</div>
|
||||||
|
<div class="stat-label">待接收工单</div>
|
||||||
|
<div class="stat-trend">较昨日 <span class="trend-up">↑ 2</span></div>
|
||||||
|
<div class="stat-icon warning">
|
||||||
|
<i class="el-icon-warning"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-value">{{ completionRate }}</div>
|
||||||
|
<div class="stat-label">按时完成率</div>
|
||||||
|
<div class="stat-trend">较上月 <span class="trend-up">↑ 3%</span></div>
|
||||||
|
<div class="stat-icon success">
|
||||||
|
<i class="el-icon-check-circle"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 派单记录表格 -->
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<el-table :data="pagedTableData" stripe style="width: 100%" highlight-current-row class="custom-table">
|
||||||
|
<el-table-column align="center" prop="dispatchNo" label="派单号" min-width="120"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="orderNo" label="工单编号" min-width="120"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="taskType" label="工单类型" min-width="100"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="dispatcher" label="派单人" min-width="100"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="executor" label="接收人" min-width="100"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="dispatchTime" label="派单时间" min-width="140"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="status" label="派单状态" min-width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="getStatusTagType(scope.row.status)" class="status-tag">
|
||||||
|
{{ scope.row.status }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" prop="completionStatus" label="完成状态" min-width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="getCompletionTagType(scope.row.completionStatus)" class="completion-tag">
|
||||||
|
{{ scope.row.completionStatus }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="操作" min-width="180" fixed="right">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button type="text" @click="handleViewDetails(scope.row)" size="small" class="action-btn">详情</el-button>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
@click="handleViewReport(scope.row)"
|
||||||
|
size="small"
|
||||||
|
class="action-btn report-btn"
|
||||||
|
v-if="scope.row.completionStatus === '已完成'"
|
||||||
|
>
|
||||||
|
查看报告
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
@click="handleViewProgress(scope.row)"
|
||||||
|
size="small"
|
||||||
|
class="action-btn progress-btn"
|
||||||
|
v-else-if="scope.row.completionStatus === '进行中'"
|
||||||
|
>
|
||||||
|
查看进度
|
||||||
|
</el-button>
|
||||||
|
<el-button type="text" @click="handleTrack(scope.row)" size="small" class="action-btn track-btn" v-else> 跟踪 </el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页区域 -->
|
||||||
|
<div class="pagination-section">
|
||||||
|
<div class="pagination-info">
|
||||||
|
显示第{{ (currentPage - 1) * pageSize + 1 }}到{{ Math.min(currentPage * pageSize, total) }}条,共{{ total }}条记录
|
||||||
|
</div>
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<el-pagination
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
:current-page="currentPage"
|
||||||
|
:page-sizes="[10, 20, 30, 40]"
|
||||||
|
:page-size="pageSize"
|
||||||
|
layout="prev, pager, next, jumper"
|
||||||
|
:total="total"
|
||||||
|
background
|
||||||
|
>
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, reactive } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './TitleComponent.vue';
|
||||||
|
|
||||||
|
// 激活的选项卡,默认显示派单记录
|
||||||
|
const activeTab = ref('dispatch');
|
||||||
|
|
||||||
|
// 筛选条件
|
||||||
|
const dispatchStatus = ref('all');
|
||||||
|
const executor = ref('all');
|
||||||
|
const dispatchDate = ref('');
|
||||||
|
|
||||||
|
// 统计数据
|
||||||
|
const totalDispatches = ref(56);
|
||||||
|
const avgResponseTime = ref('42分钟');
|
||||||
|
const pendingDispatches = ref(7);
|
||||||
|
const completionRate = ref('92%');
|
||||||
|
|
||||||
|
// 派单记录数据
|
||||||
|
const rawTableData = ref([
|
||||||
|
{
|
||||||
|
dispatchNo: 'DP-2023-0619-089',
|
||||||
|
orderNo: 'WO-2023-0619-055',
|
||||||
|
taskType: '安全设备检查检测',
|
||||||
|
dispatcher: '张明',
|
||||||
|
executor: '李阳',
|
||||||
|
dispatchTime: '2023-06-19 13:50',
|
||||||
|
status: '已接收',
|
||||||
|
completionStatus: '未完成'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dispatchNo: 'DP-2023-0619-088',
|
||||||
|
orderNo: 'WO-2023-0618-054',
|
||||||
|
taskType: '新设备安装调试',
|
||||||
|
dispatcher: '张明',
|
||||||
|
executor: '李阳',
|
||||||
|
dispatchTime: '2023-06-19 13:30',
|
||||||
|
status: '已接收',
|
||||||
|
completionStatus: '进行中'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dispatchNo: 'DP-2023-0619-087',
|
||||||
|
orderNo: 'WO-2023-0617-053',
|
||||||
|
taskType: '系统升级改造',
|
||||||
|
dispatcher: '张明',
|
||||||
|
executor: '李阳',
|
||||||
|
dispatchTime: '2023-06-19 10:15',
|
||||||
|
status: '已接收',
|
||||||
|
completionStatus: '已完成'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dispatchNo: 'DP-2023-0619-086',
|
||||||
|
orderNo: 'WO-2023-0616-052',
|
||||||
|
taskType: '安全设备检查检测',
|
||||||
|
dispatcher: '张明',
|
||||||
|
executor: '李阳',
|
||||||
|
dispatchTime: '2023-06-19 09:40',
|
||||||
|
status: '已接收',
|
||||||
|
completionStatus: '未完成'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dispatchNo: 'DP-2023-0619-085',
|
||||||
|
orderNo: 'WO-2023-0615-051',
|
||||||
|
taskType: '安全设备检查检测',
|
||||||
|
dispatcher: '张明',
|
||||||
|
executor: '李阳',
|
||||||
|
dispatchTime: '2023-06-19 09:20',
|
||||||
|
status: '已接收',
|
||||||
|
completionStatus: '未完成'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dispatchNo: 'DP-2023-0619-084',
|
||||||
|
orderNo: 'WO-2023-0614-050',
|
||||||
|
taskType: '安全设备检查检测',
|
||||||
|
dispatcher: '张明',
|
||||||
|
executor: '李阳',
|
||||||
|
dispatchTime: '2023-06-19 09:10',
|
||||||
|
status: '已接收',
|
||||||
|
completionStatus: '未完成'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dispatchNo: 'DP-2023-0619-083',
|
||||||
|
orderNo: 'WO-2023-0613-049',
|
||||||
|
taskType: '安全设备检查检测',
|
||||||
|
dispatcher: '张明',
|
||||||
|
executor: '李阳',
|
||||||
|
dispatchTime: '2023-06-19 08:50',
|
||||||
|
status: '已接收',
|
||||||
|
completionStatus: '未完成'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 分页相关
|
||||||
|
const currentPage = ref(1);
|
||||||
|
const pageSize = ref(10);
|
||||||
|
const total = ref(rawTableData.value.length);
|
||||||
|
|
||||||
|
// 分页处理后的数据
|
||||||
|
const pagedTableData = computed(() => {
|
||||||
|
// 筛选逻辑
|
||||||
|
let filteredData = [...rawTableData.value];
|
||||||
|
|
||||||
|
if (dispatchStatus.value !== 'all') {
|
||||||
|
filteredData = filteredData.filter((item) => item.status === dispatchStatus.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (executor.value !== 'all') {
|
||||||
|
// 这里假设执行人的值与选项值对应
|
||||||
|
const executorMap = {
|
||||||
|
'zhangming': '张明',
|
||||||
|
'lihua': '李华',
|
||||||
|
'wangqiang': '王强'
|
||||||
|
};
|
||||||
|
filteredData = filteredData.filter((item) => item.executor === executorMap[executor.value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dispatchDate.value) {
|
||||||
|
filteredData = filteredData.filter((item) => item.dispatchTime.includes(dispatchDate.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新总条数
|
||||||
|
total.value = filteredData.length;
|
||||||
|
|
||||||
|
// 分页处理
|
||||||
|
const startIndex = (currentPage.value - 1) * pageSize.value;
|
||||||
|
const endIndex = startIndex + pageSize.value;
|
||||||
|
return filteredData.slice(startIndex, endIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取派单状态标签样式
|
||||||
|
const getStatusTagType = (status) => {
|
||||||
|
const statusMap = {
|
||||||
|
'已接收': 'primary',
|
||||||
|
'处理中': 'success',
|
||||||
|
'已完成': 'info',
|
||||||
|
'已拒绝': 'danger'
|
||||||
|
};
|
||||||
|
return statusMap[status] || 'default';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取完成状态标签样式
|
||||||
|
const getCompletionTagType = (status) => {
|
||||||
|
const statusMap = {
|
||||||
|
'未完成': 'warning',
|
||||||
|
'进行中': 'primary',
|
||||||
|
'已完成': 'success',
|
||||||
|
'已逾期': 'danger'
|
||||||
|
};
|
||||||
|
return statusMap[status] || 'default';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {
|
||||||
|
currentPage.value = 1; // 重置到第一页
|
||||||
|
};
|
||||||
|
|
||||||
|
// 导出记录
|
||||||
|
const handleExport = () => {
|
||||||
|
console.log('导出派单记录');
|
||||||
|
// 实际应用中这里会调用导出API
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页事件
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pageSize.value = val;
|
||||||
|
currentPage.value = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
currentPage.value = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选项卡点击
|
||||||
|
const handleTabClick = (tab) => {
|
||||||
|
console.log('切换到选项卡:', tab.name);
|
||||||
|
// 重置筛选条件和分页
|
||||||
|
dispatchStatus.value = 'all';
|
||||||
|
executor.value = 'all';
|
||||||
|
dispatchDate.value = '';
|
||||||
|
currentPage.value = 1;
|
||||||
|
|
||||||
|
// 如果切换到其他选项卡,导航到相应页面
|
||||||
|
if (tab.name === 'list') {
|
||||||
|
router.push('/rili/gongdanguanli');
|
||||||
|
} else if (tab.name === 'execution') {
|
||||||
|
router.push('/rili/execution-records');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 操作按钮事件
|
||||||
|
const handleViewDetails = (row) => {
|
||||||
|
console.log('查看派单详情:', row);
|
||||||
|
// 实际应用中这里会跳转到详情页
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleViewReport = (row) => {
|
||||||
|
console.log('查看报告:', row);
|
||||||
|
// 实际应用中这里会跳转到报告页面
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleViewProgress = (row) => {
|
||||||
|
console.log('查看进度:', row);
|
||||||
|
// 实际应用中这里会跳转到进度页面
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTrack = (row) => {
|
||||||
|
console.log('跟踪工单:', row);
|
||||||
|
// 实际应用中这里会跳转到跟踪页面或打开跟踪弹窗
|
||||||
|
};
|
||||||
|
|
||||||
|
// 导航路由跳转
|
||||||
|
const handleInspection1 = () => {
|
||||||
|
router.push('/rili/rili');
|
||||||
|
};
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanguanli');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement1 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspectionManagement2 = () => {
|
||||||
|
router.push('/rili/paidanjilu');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement3 = () => {
|
||||||
|
router.push('/rili/zhixingjilu');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.dispatch-records {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选项卡样式 */
|
||||||
|
.tabs-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs {
|
||||||
|
padding-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__header {
|
||||||
|
margin: 0 -20px;
|
||||||
|
padding: 0 20px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__nav-wrap::after {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
padding: 14px 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item.is-active {
|
||||||
|
color: #165dff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item:hover {
|
||||||
|
color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 筛选栏样式 */
|
||||||
|
.filter-bar {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 16px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select,
|
||||||
|
.filter-bar .el-date-picker {
|
||||||
|
width: 180px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select .el-input__inner,
|
||||||
|
.filter-bar .el-date-picker .el-input__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
border-color: #dcdfe6;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select .el-input__inner:focus,
|
||||||
|
.filter-bar .el-date-picker .el-input__inner:focus {
|
||||||
|
border-color: #165dff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
background-color: #f2f3f5;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #f2f3f5;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn:hover {
|
||||||
|
background-color: #e5e6eb;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #e5e6eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.export-btn {
|
||||||
|
color: #165dff;
|
||||||
|
border: 1px solid #165dff;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.export-btn:hover {
|
||||||
|
background-color: #e8f3ff;
|
||||||
|
color: #0e42d2;
|
||||||
|
border-color: #0e42d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 统计卡片样式 */
|
||||||
|
.statistics-cards {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d2129;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #86909c;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trend-up {
|
||||||
|
color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trend-down {
|
||||||
|
color: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #165dff;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon.warning {
|
||||||
|
background-color: #fff7e6;
|
||||||
|
color: #fa8c16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon.success {
|
||||||
|
background-color: #f6ffed;
|
||||||
|
color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表格样式 */
|
||||||
|
.table-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-table th {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #606266;
|
||||||
|
text-align: center;
|
||||||
|
padding: 12px 8px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-table td {
|
||||||
|
padding: 12px 8px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
color: #303133;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-table tr:hover {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-table tr.current-row {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag,
|
||||||
|
.completion-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 操作按钮样式 */
|
||||||
|
.action-btn {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: 0 2px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:hover {
|
||||||
|
background-color: #e8f3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-btn {
|
||||||
|
color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-btn:hover {
|
||||||
|
color: #389e0d;
|
||||||
|
background-color: #f6ffed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-btn {
|
||||||
|
color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-btn:hover {
|
||||||
|
color: #0e42d2;
|
||||||
|
background-color: #e8f3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.track-btn {
|
||||||
|
color: #fa8c16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.track-btn:hover {
|
||||||
|
color: #e67700;
|
||||||
|
background-color: #fff7e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分页区域样式 */
|
||||||
|
.pagination-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 16px 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-info {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination button,
|
||||||
|
.pagination-controls .el-pagination .el-pager li {
|
||||||
|
min-width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination .el-pager li.active {
|
||||||
|
background-color: #165dff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导航栏样式 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.filter-container {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: 0;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select,
|
||||||
|
.filter-bar .el-date-picker {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.create-btn {
|
||||||
|
background-color: #165dff;
|
||||||
|
border-color: #165dff;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-btn:hover {
|
||||||
|
background-color: #0e42d2;
|
||||||
|
border-color: #0e42d2;
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.dispatch-records {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-tabs {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
flex: 1 0 33%;
|
||||||
|
padding: 10px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics-cards {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-section {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.statistics-cards {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
922
src/views/zhinengxunjian/qiangxiuguanli.vue
Normal file
922
src/views/zhinengxunjian/qiangxiuguanli.vue
Normal file
@ -0,0 +1,922 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="inspection-tasks">
|
||||||
|
<div class="navigation-tabs">
|
||||||
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection4">报修管理</div>
|
||||||
|
<div class="nav-tab active" @click="handleInspection5">抢修管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
|
</div>
|
||||||
|
<!-- 页面标题 -->
|
||||||
|
<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>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement2">抢修记录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选栏 -->
|
||||||
|
<div class="filter-bar">
|
||||||
|
<div class="filter-container">
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="taskStatus" placeholder="任务状态">
|
||||||
|
<el-option label="待执行" value="pending"></el-option>
|
||||||
|
<el-option label="执行中" value="executing"></el-option>
|
||||||
|
<el-option label="已延期" value="delayed"></el-option>
|
||||||
|
<el-option label="已完成" value="completed"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="planType" placeholder="全部计划">
|
||||||
|
<el-option label="全部计划" value="all"></el-option>
|
||||||
|
<el-option label="每日巡检计划" value="daily"></el-option>
|
||||||
|
<el-option label="每周巡检计划" value="weekly"></el-option>
|
||||||
|
<el-option label="每月巡检计划" value="monthly"></el-option>
|
||||||
|
<el-option label="每季度巡检计划" value="quarterly"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="executor" placeholder="执行人">
|
||||||
|
<el-option label="全部人员" value="all"></el-option>
|
||||||
|
<el-option label="张明" value="zhangming"></el-option>
|
||||||
|
<el-option label="李华" value="lihua"></el-option>
|
||||||
|
<el-option label="王强" value="wangqiang"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-actions">
|
||||||
|
<el-button type="primary" class="search-btn" @click="handleSearch"> 搜索 </el-button>
|
||||||
|
<el-button type="primary" icon="el-icon-plus" class="create-btn" @click="handleCreateTask"> 手动创建任务 </el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 任务卡片列表 -->
|
||||||
|
<div class="task-cards">
|
||||||
|
<div class="task-card" v-for="(task, index) in pagedTasks" :key="index" :class="task.statusClass">
|
||||||
|
<!-- 顶部信息区域 -->
|
||||||
|
<div class="task-header">
|
||||||
|
<div class="task-title">
|
||||||
|
{{ task.title }}
|
||||||
|
</div>
|
||||||
|
<div class="task-type-tag" :class="getFaultTypeClass(task.faultType)">
|
||||||
|
{{ task.faultType }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 新增滚动内容容器 -->
|
||||||
|
<div class="task-content-scroll">
|
||||||
|
<div class="task-details">
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">报修时间</span>
|
||||||
|
<span class="detail-value">{{ task.reportTime }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">报修人</span>
|
||||||
|
<span class="detail-value">{{ task.reporter }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">维修人</span>
|
||||||
|
<span class="detail-value">{{ task.maintainer }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">预计完成</span>
|
||||||
|
<span class="detail-value">{{ task.expectedCompleteTime }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">状态</span>
|
||||||
|
<span class="detail-value">{{ task.statusText }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 已完成状态的额外信息 -->
|
||||||
|
<div v-if="task.status === 'completed'" class="task-result">
|
||||||
|
<span class="detail-label">完成时间</span>
|
||||||
|
<span class="detail-value">{{ task.completeTime }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 增加一些示例数据来演示滚动效果 -->
|
||||||
|
<div v-if="task.status === 'executing'" class="detail-item">
|
||||||
|
<span class="detail-label">开始时间</span>
|
||||||
|
<span class="detail-value">{{ task.startTime || '30分钟前' }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="task.status === 'executing'" class="detail-item">
|
||||||
|
<span class="detail-label">进度</span>
|
||||||
|
<span class="detail-value">{{ task.progress || '60%' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="task-actions">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页区域 -->
|
||||||
|
<div class="pagination-section">
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<el-pagination
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
:current-page="currentPage"
|
||||||
|
:page-sizes="[8, 12, 16, 20]"
|
||||||
|
:page-size="pageSize"
|
||||||
|
layout="prev, pager, next, jumper"
|
||||||
|
:total="total"
|
||||||
|
background
|
||||||
|
>
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 新建紧急抢修任务弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="createTaskDialogVisible"
|
||||||
|
title="创建紧急抢修任务"
|
||||||
|
width="800px"
|
||||||
|
:before-close="handleCancelCreateTask"
|
||||||
|
custom-class="beautiful-dialog"
|
||||||
|
center
|
||||||
|
>
|
||||||
|
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="100px" class="elegant-form">
|
||||||
|
<el-form-item label="抢修名称*" prop="repairName">
|
||||||
|
<el-input v-model="createTaskForm.repairName" placeholder="简要描述抢修内容" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="抢修类型*" prop="repairType">
|
||||||
|
<el-select v-model="createTaskForm.repairType" placeholder="请选择类型">
|
||||||
|
<el-option label="设备故障" value="device" />
|
||||||
|
<el-option label="软件故障" value="software" />
|
||||||
|
<el-option label="网络故障" value="network" />
|
||||||
|
<el-option label="环境问题" value="environment" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="紧急程度*" prop="priority">
|
||||||
|
<el-select v-model="createTaskForm.priority" placeholder="请选择紧急程度">
|
||||||
|
<el-option label="致命" value="fatal" />
|
||||||
|
<el-option label="紧急" value="urgent" />
|
||||||
|
<el-option label="较危险" value="dangerous" />
|
||||||
|
<el-option label="一般" value="normal" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-form-item label="故障描述*" prop="detailedDescription">
|
||||||
|
<el-input
|
||||||
|
v-model="createTaskForm.detailedDescription"
|
||||||
|
type="textarea"
|
||||||
|
:rows="4"
|
||||||
|
placeholder="详细描述故障现象、影响范围、潜在威胁等信息"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="故障位置*" prop="faultLocation">
|
||||||
|
<el-input v-model="createTaskForm.faultLocation" placeholder="例如:A区102" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="上传图片(可选)*">
|
||||||
|
<div class="upload-container">
|
||||||
|
<div class="upload-box">
|
||||||
|
<i class="el-icon-plus avatar-uploader-icon"></i>
|
||||||
|
<div class="upload-text">点击或拖拽图片至此处上传</div>
|
||||||
|
<div class="upload-hint">支持JPG、PNG格式,最多3张</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系人*" prop="contactPerson">
|
||||||
|
<el-input v-model="createTaskForm.contactPerson" placeholder="您的姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系电话*" prop="contactPhone">
|
||||||
|
<el-input v-model="createTaskForm.contactPhone" placeholder="您的联系电话" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-form-item label="是否需要立即现场支持*">
|
||||||
|
<div>
|
||||||
|
<el-radio v-model="createTaskForm.needSupport" label="yes">是,需要立即派人现场</el-radio>
|
||||||
|
<el-radio v-model="createTaskForm.needSupport" label="no">否,可远程指导或延后处理</el-radio>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="handleCancelCreateTask">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSaveTask">提交抢修计划</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './TitleComponent.vue';
|
||||||
|
|
||||||
|
// 激活的选项卡
|
||||||
|
const activeTab = ref('task');
|
||||||
|
|
||||||
|
// 根据故障类型获取对应的CSS类
|
||||||
|
const getFaultTypeClass = (faultType) => {
|
||||||
|
const typeMap = {
|
||||||
|
// 电力,设备故障为红色
|
||||||
|
'电力故障': 'electric',
|
||||||
|
'设备故障': 'equipment',
|
||||||
|
|
||||||
|
// 供水,设备损坏为黄色
|
||||||
|
'供水问题': 'water',
|
||||||
|
'设备损坏': 'damage',
|
||||||
|
|
||||||
|
// 其余默认使用基本样式(绿色)
|
||||||
|
'网络中断': '',
|
||||||
|
'制冷系统故障': '',
|
||||||
|
'安全问题': ''
|
||||||
|
};
|
||||||
|
return typeMap[faultType] || '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 筛选条件
|
||||||
|
const repairType = ref('all');
|
||||||
|
const taskStatus = ref('all');
|
||||||
|
const emergencyLevel = ref('all');
|
||||||
|
const planType = ref('all');
|
||||||
|
const executor = ref('all');
|
||||||
|
|
||||||
|
// 任务数据 - 添加了更多字段以展示滚动效果
|
||||||
|
const tasks = ref([
|
||||||
|
{
|
||||||
|
title: '主配电室短路故障',
|
||||||
|
status: 'executing',
|
||||||
|
statusText: '抢修中',
|
||||||
|
statusClass: 'status-high',
|
||||||
|
priority: '致命',
|
||||||
|
reportTime: '10分钟前',
|
||||||
|
reporter: '李阳',
|
||||||
|
maintainer: '张明',
|
||||||
|
expectedCompleteTime: '30分钟内',
|
||||||
|
faultType: '电力故障',
|
||||||
|
faultLocation: '地下一层主配电室',
|
||||||
|
startTime: '10分钟前',
|
||||||
|
progress: '40%',
|
||||||
|
remarks: '已切断该区域电源,正在排查短路点',
|
||||||
|
actionText: '实时跟进',
|
||||||
|
actionClass: 'follow-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '主配电室短路故障',
|
||||||
|
status: 'executing',
|
||||||
|
statusText: '抢修中',
|
||||||
|
statusClass: 'status-medium',
|
||||||
|
priority: '紧急',
|
||||||
|
reportTime: '45分钟前',
|
||||||
|
reporter: '李阳',
|
||||||
|
maintainer: '张明',
|
||||||
|
expectedCompleteTime: '1小时内',
|
||||||
|
faultType: '供水问题',
|
||||||
|
faultLocation: '三楼东侧卫生间',
|
||||||
|
startTime: '40分钟前',
|
||||||
|
progress: '70%',
|
||||||
|
remarks: '已找到漏水点,正在进行修复',
|
||||||
|
actionText: '实时跟进',
|
||||||
|
actionClass: 'follow-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '网络主干交换机故障',
|
||||||
|
status: 'completed',
|
||||||
|
statusText: '已完成',
|
||||||
|
statusClass: 'status-completed',
|
||||||
|
priority: '较危险',
|
||||||
|
reportTime: '1小时前',
|
||||||
|
reporter: '李阳',
|
||||||
|
maintainer: '张明',
|
||||||
|
expectedCompleteTime: '1小时内',
|
||||||
|
faultType: '网络中断',
|
||||||
|
faultLocation: '二楼机房',
|
||||||
|
completeTime: '2小时前',
|
||||||
|
remarks: '交换机电源模块故障,已更换备用模块',
|
||||||
|
actionText: '查看报告',
|
||||||
|
actionClass: 'view-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '安全出口指示牌损坏',
|
||||||
|
status: 'pending',
|
||||||
|
statusText: '待处理',
|
||||||
|
statusClass: 'status-medium',
|
||||||
|
priority: '较危险',
|
||||||
|
reportTime: '3小时前',
|
||||||
|
reporter: '李阳',
|
||||||
|
maintainer: '未分配',
|
||||||
|
expectedCompleteTime: '今天以内',
|
||||||
|
faultType: '设备损坏',
|
||||||
|
faultLocation: '一楼东侧安全通道',
|
||||||
|
remarks: '指示牌不亮,可能是线路问题',
|
||||||
|
actionText: '分配任务',
|
||||||
|
actionClass: 'assign-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '制冷系统主压缩机故障',
|
||||||
|
status: 'executing',
|
||||||
|
statusText: '抢修中',
|
||||||
|
statusClass: 'status-high',
|
||||||
|
priority: '致命',
|
||||||
|
reportTime: '1小时前',
|
||||||
|
reporter: '李阳',
|
||||||
|
maintainer: '张明',
|
||||||
|
expectedCompleteTime: '45分钟内',
|
||||||
|
faultType: '设备故障',
|
||||||
|
faultLocation: '楼顶制冷机房',
|
||||||
|
startTime: '50分钟前',
|
||||||
|
progress: '30%',
|
||||||
|
remarks: '压缩机无法启动,正在检查电路和 refrigerant 压力',
|
||||||
|
actionText: '实时跟进',
|
||||||
|
actionClass: 'follow-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '主配电室短路故障',
|
||||||
|
status: 'executing',
|
||||||
|
statusText: '抢修中',
|
||||||
|
statusClass: 'status-medium',
|
||||||
|
priority: '紧急',
|
||||||
|
reportTime: '45分钟前',
|
||||||
|
reporter: '李阳',
|
||||||
|
maintainer: '张明',
|
||||||
|
expectedCompleteTime: '1小时内',
|
||||||
|
faultType: '供水问题',
|
||||||
|
faultLocation: '地下室水泵房',
|
||||||
|
startTime: '40分钟前',
|
||||||
|
progress: '60%',
|
||||||
|
remarks: '水泵压力不足,正在更换滤网和检查管道',
|
||||||
|
actionText: '实时跟进',
|
||||||
|
actionClass: 'follow-btn'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 分页相关
|
||||||
|
const currentPage = ref(1);
|
||||||
|
const pageSize = ref(20);
|
||||||
|
const total = ref(6);
|
||||||
|
|
||||||
|
// 状态排序映射
|
||||||
|
const statusOrder = {
|
||||||
|
pending: 0, // 待处理
|
||||||
|
executing: 1, // 处理中
|
||||||
|
completed: 2 // 已完成
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页处理后的数据(含排序)
|
||||||
|
const pagedTasks = computed(() => {
|
||||||
|
// 先按状态排序
|
||||||
|
const sortedTasks = [...tasks.value].sort((a, b) => {
|
||||||
|
return statusOrder[a.status] - statusOrder[b.status];
|
||||||
|
});
|
||||||
|
|
||||||
|
// 再进行分页
|
||||||
|
const startIndex = (currentPage.value - 1) * pageSize.value;
|
||||||
|
const endIndex = startIndex + pageSize.value;
|
||||||
|
return sortedTasks.slice(startIndex, endIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {
|
||||||
|
currentPage.value = 1; // 重置到第一页
|
||||||
|
// 实际应用中这里会根据筛选条件过滤数据
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建紧急抢修任务弹窗相关
|
||||||
|
const createTaskDialogVisible = ref(false);
|
||||||
|
const createTaskForm = ref({
|
||||||
|
repairName: '',
|
||||||
|
repairType: '',
|
||||||
|
priority: '',
|
||||||
|
detailedDescription: '',
|
||||||
|
faultLocation: '',
|
||||||
|
contactPerson: '',
|
||||||
|
contactPhone: '',
|
||||||
|
needSupport: 'yes'
|
||||||
|
});
|
||||||
|
|
||||||
|
const createTaskRules = {
|
||||||
|
repairName: [{ required: true, message: '请输入抢修名称', trigger: 'blur' }],
|
||||||
|
repairType: [{ required: true, message: '请选择抢修类型', trigger: 'change' }],
|
||||||
|
priority: [{ required: true, message: '请选择紧急程度', trigger: 'change' }],
|
||||||
|
detailedDescription: [{ required: true, message: '请输入故障描述', trigger: 'blur' }],
|
||||||
|
faultLocation: [{ required: true, message: '请输入故障位置', trigger: 'blur' }],
|
||||||
|
contactPerson: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
|
||||||
|
contactPhone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建任务
|
||||||
|
const handleCreateTask = () => {
|
||||||
|
createTaskDialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交抢修计划
|
||||||
|
const handleSaveTask = () => {
|
||||||
|
// 模拟提交抢修计划逻辑
|
||||||
|
console.log('提交抢修计划:', createTaskForm.value);
|
||||||
|
// 关闭弹窗
|
||||||
|
createTaskDialogVisible.value = false;
|
||||||
|
// 重置表单
|
||||||
|
createTaskForm.value = {
|
||||||
|
repairName: '',
|
||||||
|
repairType: '',
|
||||||
|
priority: '',
|
||||||
|
detailedDescription: '',
|
||||||
|
faultLocation: '',
|
||||||
|
contactPerson: '',
|
||||||
|
contactPhone: '',
|
||||||
|
needSupport: 'yes'
|
||||||
|
};
|
||||||
|
// 这里可以添加成功提示和刷新任务列表的逻辑
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消创建紧急抢修任务
|
||||||
|
const handleCancelCreateTask = () => {
|
||||||
|
createTaskDialogVisible.value = false;
|
||||||
|
// 重置表单
|
||||||
|
createTaskForm.value = {
|
||||||
|
repairName: '',
|
||||||
|
repairType: '',
|
||||||
|
priority: '',
|
||||||
|
detailedDescription: '',
|
||||||
|
faultLocation: '',
|
||||||
|
contactPerson: '',
|
||||||
|
contactPhone: '',
|
||||||
|
needSupport: 'yes'
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页事件
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pageSize.value = val;
|
||||||
|
currentPage.value = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
currentPage.value = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查看任务详情
|
||||||
|
const handleView = (task) => {
|
||||||
|
console.log('查看任务详情:', task);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理选项卡点击
|
||||||
|
const handleTabClick = () => {
|
||||||
|
currentPage.value = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspectionManagement1 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspectionManagement2 = () => {
|
||||||
|
router.push('/rili/qiangxiujilu');
|
||||||
|
};
|
||||||
|
const handleInspection1 = () => {
|
||||||
|
router.push('/rili/rili');
|
||||||
|
};
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.inspection-tasks {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 任务卡片样式修改 - 增加滚动功能 */
|
||||||
|
.task-cards {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 16px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
/* 固定卡片高度 */
|
||||||
|
min-height: 280px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 顶部装饰条样式 */
|
||||||
|
.task-card.status-high::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card.status-medium::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card.status-low::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card.status-completed::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加滚动内容容器 */
|
||||||
|
.task-content-scroll {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 8px; /* 为滚动条预留空间 */
|
||||||
|
margin-bottom: 10px;
|
||||||
|
/* 限制最大高度,超出则显示滚动条 */
|
||||||
|
max-height: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条样式保持不变 */
|
||||||
|
.task-content-scroll::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-content-scroll::-webkit-scrollbar-track {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-content-scroll::-webkit-scrollbar-thumb {
|
||||||
|
background: #c1c1c1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-content-scroll::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #a8a8a8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1d2129;
|
||||||
|
line-height: 1.4;
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-type-tag {
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 不同故障类型的颜色 */
|
||||||
|
/* 电力,设备故障为红色 */
|
||||||
|
.task-type-tag.electric,
|
||||||
|
.task-type-tag.equipment {
|
||||||
|
background-color: #fff2f0;
|
||||||
|
color: #ff4d4f;
|
||||||
|
border-color: #ffccc7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 供水,设备损坏为黄色 */
|
||||||
|
.task-type-tag.water,
|
||||||
|
.task-type-tag.damage {
|
||||||
|
background-color: #fffbe6;
|
||||||
|
color: #fa8c16;
|
||||||
|
border-color: #ffe58f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 其余为绿色 */
|
||||||
|
.task-type-tag {
|
||||||
|
background-color: #f6ffed;
|
||||||
|
color: #52c41a;
|
||||||
|
border-color: #b7eb8f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-details {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-label {
|
||||||
|
flex: 0 0 70px;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-value {
|
||||||
|
flex: 1;
|
||||||
|
color: #4e5969;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-result {
|
||||||
|
display: flex;
|
||||||
|
margin: 8px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px dashed #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #f0f2f5;
|
||||||
|
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 {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 4px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-btn {
|
||||||
|
color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-btn:hover {
|
||||||
|
color: #0e42d2;
|
||||||
|
background-color: #e8f3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-btn {
|
||||||
|
background-color: #165dff;
|
||||||
|
border-color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-btn:hover {
|
||||||
|
background-color: #0e42d2;
|
||||||
|
border-color: #0e42d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assign-btn {
|
||||||
|
background-color: #ff7d00;
|
||||||
|
border-color: #ff7d00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assign-btn:hover {
|
||||||
|
background-color: #e86a00;
|
||||||
|
border-color: #e86a00;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 其他样式保持不变 */
|
||||||
|
.tabs-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 16px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select {
|
||||||
|
width: 180px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
background-color: #f2f3f5;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #f2f3f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-btn {
|
||||||
|
background-color: #165dff;
|
||||||
|
border-color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 上传图片区域样式 */
|
||||||
|
.upload-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-box {
|
||||||
|
border: 2px dashed #dcdfe6;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 40px 20px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-uploader-icon {
|
||||||
|
font-size: 40px;
|
||||||
|
color: #c0c4cc;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-hint {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 弹窗和表单样式保持不变 */
|
||||||
|
.beautiful-dialog {
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.elegant-form .el-form-item {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.task-cards {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.inspection-tasks {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: 0;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-cards {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
741
src/views/zhinengxunjian/qiangxiujilu.vue
Normal file
741
src/views/zhinengxunjian/qiangxiujilu.vue
Normal file
@ -0,0 +1,741 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="inspection-tasks">
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<div class="navigation-tabs">
|
||||||
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection4">报修管理</div>
|
||||||
|
<div class="nav-tab active" @click="handleInspection5">抢修管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection7">运维组织</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 页面标题和操作区 -->
|
||||||
|
<div class="header-section">
|
||||||
|
<TitleComponent title="抢修管理模块" subtitle="处理紧急抢修任务,跟踪抢修进度和记录"></TitleComponent>
|
||||||
|
<div class="header-actions">
|
||||||
|
<el-button class="filter-btn" @click="showFilter = !showFilter">
|
||||||
|
筛选
|
||||||
|
<i class="el-icon-arrow-down ml-1"></i>
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" class="export-btn" @click="handleExport"> 导出数据 </el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs-wrapper">
|
||||||
|
<div style="display: flex; align-items: center; gap: 10px">
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement1">抢修任务</el-button>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement2">抢修记录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选栏 (默认隐藏) -->
|
||||||
|
<div class="filter-bar" v-if="showFilter">
|
||||||
|
<div class="filter-container">
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="taskStatus" placeholder="任务状态">
|
||||||
|
<el-option label="待执行" value="pending"></el-option>
|
||||||
|
<el-option label="处理中" value="processing"></el-option>
|
||||||
|
<el-option label="已完成" value="completed"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="priority" placeholder="紧急程度">
|
||||||
|
<el-option label="紧急" value="urgent"></el-option>
|
||||||
|
<el-option label="常规" value="normal"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="executor" placeholder="抢修人员">
|
||||||
|
<el-option label="全部人员" value="all"></el-option>
|
||||||
|
<el-option label="李明" value="liming"></el-option>
|
||||||
|
<el-option label="王伟" value="wangwei"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
type="datetimerange"
|
||||||
|
start-placeholder="开始时间"
|
||||||
|
end-placeholder="结束时间"
|
||||||
|
format="YYYY-MM-DD HH:mm"
|
||||||
|
value-format="YYYY-MM-DD HH:mm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="filter-actions">
|
||||||
|
<el-button type="primary" class="search-btn" @click="handleSearch"> 搜索 </el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 统计卡片区域 -->
|
||||||
|
<div class="statistics-container">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-info">
|
||||||
|
<p class="stat-label">本月抢修总数</p>
|
||||||
|
<p class="stat-value">18</p>
|
||||||
|
<p class="stat-trend up">较上月 +8.7%</p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-icon">
|
||||||
|
<i class="el-icon-warning-outline"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-info">
|
||||||
|
<p class="stat-label">平均抢修时长</p>
|
||||||
|
<p class="stat-value">58分钟</p>
|
||||||
|
<p class="stat-trend down">较上月 -2.5分钟</p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-icon">
|
||||||
|
<i class="el-icon-clock"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-info">
|
||||||
|
<p class="stat-label">待处理抢修</p>
|
||||||
|
<p class="stat-value">3</p>
|
||||||
|
<p class="stat-trend warning">需要尽快处理</p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-icon warning">
|
||||||
|
<i class="el-icon-alarm"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-info">
|
||||||
|
<p class="stat-label">按时完成率</p>
|
||||||
|
<p class="stat-value">92%</p>
|
||||||
|
<p class="stat-trend up">较上月 +2.4%</p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-icon success">
|
||||||
|
<i class="el-icon-check-circle"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 抢修记录表格 -->
|
||||||
|
<div class="table-container">
|
||||||
|
<el-table :data="repairRecords" border style="width: 100%" class="record-table">
|
||||||
|
<el-table-column prop="reportNo" label="抢修单号" width="140"></el-table-column>
|
||||||
|
<el-table-column prop="content" label="抢修内容"></el-table-column>
|
||||||
|
<el-table-column prop="reporter" label="报修人" width="100"></el-table-column>
|
||||||
|
<el-table-column prop="reportTime" label="报修时间" width="160"></el-table-column>
|
||||||
|
<el-table-column prop="handler" label="抢修人员" width="100"></el-table-column>
|
||||||
|
<el-table-column prop="priority" label="紧急程度" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<span :class="`priority-tag ${scope.row.priorityClass}`">{{ scope.row.priority }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="status" label="处理状态" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<span :class="`status-tag ${scope.row.statusClass}`">{{ scope.row.status }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="duration" label="处理时长" width="100"></el-table-column>
|
||||||
|
<el-table-column label="操作" width="140">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button type="text" size="small" class="detail-btn" @click="handleDetail(scope.row)"> 详情 </el-button>
|
||||||
|
<el-button type="text" size="small" :class="scope.row.actionClass" @click="handleAction(scope.row)">
|
||||||
|
{{ scope.row.actionText }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页区域 -->
|
||||||
|
<div class="pagination-section">
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<el-pagination
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
:current-page="currentPage"
|
||||||
|
:page-sizes="[10, 20, 30, 50]"
|
||||||
|
:page-size="pageSize"
|
||||||
|
layout="prev, pager, next, jumper"
|
||||||
|
:total="total"
|
||||||
|
background
|
||||||
|
>
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './TitleComponent.vue';
|
||||||
|
|
||||||
|
// 筛选条件
|
||||||
|
const taskStatus = ref('');
|
||||||
|
const priority = ref('');
|
||||||
|
const executor = ref('');
|
||||||
|
const dateRange = ref([]);
|
||||||
|
const showFilter = ref(false);
|
||||||
|
|
||||||
|
// 分页相关
|
||||||
|
const currentPage = ref(3);
|
||||||
|
const pageSize = ref(10);
|
||||||
|
const total = ref(187);
|
||||||
|
|
||||||
|
// 抢修记录数据
|
||||||
|
const repairRecords = ref([
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-001',
|
||||||
|
content: '网络主干交换机故障AAAAAA',
|
||||||
|
reporter: '陈明',
|
||||||
|
reportTime: '2025-06-20 08:30',
|
||||||
|
handler: '李明',
|
||||||
|
priority: '紧急',
|
||||||
|
priorityClass: 'urgent',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
duration: '10分钟',
|
||||||
|
actionText: '详情',
|
||||||
|
actionClass: 'detail-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-002',
|
||||||
|
content: '实验室水管爆裂',
|
||||||
|
reporter: '陈明',
|
||||||
|
reportTime: '2025-06-20 08:30',
|
||||||
|
handler: '李明',
|
||||||
|
priority: '紧急',
|
||||||
|
priorityClass: 'urgent',
|
||||||
|
status: '抢修中',
|
||||||
|
statusClass: 'processing',
|
||||||
|
duration: '4分钟',
|
||||||
|
actionText: '查看',
|
||||||
|
actionClass: 'follow-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-003',
|
||||||
|
content: '主配电室线路故障',
|
||||||
|
reporter: '陈明',
|
||||||
|
reportTime: '2025-06-20 08:30',
|
||||||
|
handler: '李明',
|
||||||
|
priority: '紧急',
|
||||||
|
priorityClass: 'urgent',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
duration: '10分钟',
|
||||||
|
actionText: '详情',
|
||||||
|
actionClass: 'detail-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-004',
|
||||||
|
content: '网络主干交换机故障AAAAAA',
|
||||||
|
reporter: '陈明',
|
||||||
|
reportTime: '2025-06-20 08:30',
|
||||||
|
handler: '李明',
|
||||||
|
priority: '常规',
|
||||||
|
priorityClass: 'normal',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
duration: '10分钟',
|
||||||
|
actionText: '详情',
|
||||||
|
actionClass: 'detail-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-005',
|
||||||
|
content: '网络主干交换机故障AAAAAA',
|
||||||
|
reporter: '陈明',
|
||||||
|
reportTime: '2025-06-20 08:30',
|
||||||
|
handler: '李明',
|
||||||
|
priority: '紧急',
|
||||||
|
priorityClass: 'urgent',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
duration: '10分钟',
|
||||||
|
actionText: '详情',
|
||||||
|
actionClass: 'detail-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-006',
|
||||||
|
content: '网络主干交换机故障AAAAAA',
|
||||||
|
reporter: '陈明',
|
||||||
|
reportTime: '2025-06-20 08:30',
|
||||||
|
handler: '李明',
|
||||||
|
priority: '紧急',
|
||||||
|
priorityClass: 'urgent',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
duration: '10分钟',
|
||||||
|
actionText: '详情',
|
||||||
|
actionClass: 'detail-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reportNo: 'R-2025-0620-007',
|
||||||
|
content: '网络主干交换机故障AAAAAA',
|
||||||
|
reporter: '陈明',
|
||||||
|
reportTime: '2025-06-20 08:30',
|
||||||
|
handler: '李明',
|
||||||
|
priority: '紧急',
|
||||||
|
priorityClass: 'urgent',
|
||||||
|
status: '已完成',
|
||||||
|
statusClass: 'completed',
|
||||||
|
duration: '10分钟',
|
||||||
|
actionText: '详情',
|
||||||
|
actionClass: 'detail-btn'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {
|
||||||
|
currentPage.value = 1; // 重置到第一页
|
||||||
|
// 实际应用中这里会根据筛选条件过滤数据
|
||||||
|
};
|
||||||
|
|
||||||
|
// 导出数据
|
||||||
|
const handleExport = () => {
|
||||||
|
console.log('导出抢修记录数据');
|
||||||
|
// 实际应用中添加导出逻辑
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页事件
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pageSize.value = val;
|
||||||
|
currentPage.value = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
currentPage.value = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
const handleDetail = (record) => {
|
||||||
|
console.log('查看详情:', record);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理操作
|
||||||
|
const handleAction = (record) => {
|
||||||
|
console.log('执行操作:', record.actionText, record);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选项卡切换
|
||||||
|
const handleTaskTab = () => {
|
||||||
|
// 抢修任务选项卡逻辑
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRecordTab = () => {
|
||||||
|
router.push('/rili/qiangxiujiilu');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 导航事件
|
||||||
|
const handleInspection1 = () => {
|
||||||
|
router.push('/rili/rili');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspectionManagement1 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspectionManagement2 = () => {
|
||||||
|
router.push('/rili/qiangxiujilu');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.inspection-tasks {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 头部标题和操作区 */
|
||||||
|
.header-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.export-btn {
|
||||||
|
background-color: #165dff;
|
||||||
|
border-color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选项卡样式 */
|
||||||
|
.tabs-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 筛选栏样式 */
|
||||||
|
.filter-bar {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 16px 24px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select,
|
||||||
|
.filter-bar .el-date-picker {
|
||||||
|
width: 180px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select .el-input__inner,
|
||||||
|
.filter-bar .el-date-picker .el-input__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
border-color: #dcdfe6;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select .el-input__inner:focus,
|
||||||
|
.filter-bar .el-date-picker .el-input__inner:focus {
|
||||||
|
border-color: #165dff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
background-color: #f2f3f5;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #f2f3f5;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn:hover {
|
||||||
|
background-color: #e5e6eb;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #e5e6eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 统计卡片样式 */
|
||||||
|
.statistics-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #86909c;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d2129;
|
||||||
|
margin: 0 0 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend {
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend.up {
|
||||||
|
color: #00b42a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend.up::before {
|
||||||
|
content: '↑';
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend.down {
|
||||||
|
color: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend.down::before {
|
||||||
|
content: '↓';
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-trend.warning {
|
||||||
|
color: #fa8c16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #ffebe6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #ff4d4f;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon.warning {
|
||||||
|
background-color: #fff7e6;
|
||||||
|
color: #fa8c16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon.success {
|
||||||
|
background-color: #f6ffed;
|
||||||
|
color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表格样式 */
|
||||||
|
.table-container {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-table {
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-table th {
|
||||||
|
background-color: #f7f8fa;
|
||||||
|
color: #4e5969;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-table td {
|
||||||
|
color: #1d2129;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag.processing {
|
||||||
|
background-color: #fffbe6;
|
||||||
|
color: #faad14;
|
||||||
|
border: 1px solid #fff1b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag.completed {
|
||||||
|
background-color: #f0f9eb;
|
||||||
|
color: #52c41a;
|
||||||
|
border: 1px solid #e1f3d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.priority-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.priority-tag.urgent {
|
||||||
|
background-color: #ffebe6;
|
||||||
|
color: #ff4d4f;
|
||||||
|
border: 1px solid #ffccc7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.priority-tag.normal {
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
color: #1890ff;
|
||||||
|
border: 1px solid #b3d8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-btn {
|
||||||
|
color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-btn {
|
||||||
|
color: #fa8c16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分页区域样式 */
|
||||||
|
.pagination-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination button,
|
||||||
|
.pagination-controls .el-pagination .el-pager li {
|
||||||
|
min-width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination .el-pager li.active {
|
||||||
|
background-color: #165dff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导航栏样式 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.statistics-container {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.inspection-tasks {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-section {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: 0;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select,
|
||||||
|
.filter-bar .el-date-picker {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics-container {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
973
src/views/zhinengxunjian/renyuanzhuangtai.vue
Normal file
973
src/views/zhinengxunjian/renyuanzhuangtai.vue
Normal file
@ -0,0 +1,973 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="operation-organization">
|
||||||
|
<!-- 顶部导航栏 -->
|
||||||
|
<div class="navigation-tabs">
|
||||||
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection3">试验管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection4">报修管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection5">抢修管理</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection6">工单管理</div>
|
||||||
|
<div class="nav-tab active" @click="handleInspection7">运维组织</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 页面标题 -->
|
||||||
|
<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>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement2">车辆状态</el-button>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement3">班组状态</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 内容区域 -->
|
||||||
|
<div class="content-container">
|
||||||
|
<!-- 左侧数据概览区域 -->
|
||||||
|
<div class="sidebar">
|
||||||
|
<div class="stats-card">
|
||||||
|
<h3 class="stats-title">人员数据总览</h3>
|
||||||
|
<!-- 使用ECharts饼图替换原有的环形图 -->
|
||||||
|
<div class="chart-container">
|
||||||
|
<div ref="personnelChart" class="personnel-chart"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stats-grid">
|
||||||
|
<div class="stat-item total-personnel">
|
||||||
|
<div class="stat-icon">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M16 12C16 14.2091 14.2091 16 12 16C9.79086 16 8 14.2091 8 12C8 9.79086 9.79086 8 12 8C14.2091 8 16 9.79086 16 12Z"
|
||||||
|
stroke="#165dff"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2Z"
|
||||||
|
stroke="#165dff"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="stat-value">{{ totalPersonnel }}</div>
|
||||||
|
<div class="stat-label">总人数</div>
|
||||||
|
<div class="stat-change">+2人</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item available-personnel">
|
||||||
|
<div class="stat-icon">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M12 16V12M12 8H12.01M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12Z"
|
||||||
|
stroke="#19b949"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="stat-value">{{ availablePersonnel }}</div>
|
||||||
|
<div class="stat-label">在线可用</div>
|
||||||
|
<div class="stat-change">+2人</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-value">{{ workingPersonnel }}</div>
|
||||||
|
<div class="stat-label">工作中</div>
|
||||||
|
<div class="stat-change">+1人</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item resting-personnel">
|
||||||
|
<div class="stat-icon">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M7 13a4 4 0 1 0 0-8 4 4 0 0 0 0 8zm0 1a5 5 0 1 1 0-10 5 5 0 0 1 0 10z"
|
||||||
|
stroke="#909399"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M17 13a4 4 0 1 0 0-8 4 4 0 0 0 0 8zm0 1a5 5 0 1 1 0-10 5 5 0 0 1 0 10z"
|
||||||
|
stroke="#909399"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="stat-value">{{ restingPersonnel }}</div>
|
||||||
|
<div class="stat-label">离线休息</div>
|
||||||
|
<div class="stat-change">-1人</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧人员列表区域,带滚动条 -->
|
||||||
|
<div class="main-content">
|
||||||
|
<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" :class="person.statusClass">{{ 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)" class="detail-btn">详情</el-button>
|
||||||
|
<el-button type="text" @click="assignTask(person)" class="assign-btn">
|
||||||
|
{{ person.statusClass === 'online' ? '派单' : person.statusClass === 'working' ? '联系' : '留言' }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, onMounted } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './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 personnelStatusData = {
|
||||||
|
'在线可用': availablePersonnel.value,
|
||||||
|
'离线休息': restingPersonnel.value
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化图表
|
||||||
|
const personnelChart = ref(null);
|
||||||
|
let chartInstance = null;
|
||||||
|
|
||||||
|
// 人员列表数据(保持不变)
|
||||||
|
const personnelList = ref([
|
||||||
|
{
|
||||||
|
id: 'EMP-2023-001',
|
||||||
|
name: '张工',
|
||||||
|
position: '设备维护工程师',
|
||||||
|
team: '第一运维组',
|
||||||
|
statusText: '在线可用',
|
||||||
|
statusClass: 'online',
|
||||||
|
completedTasks: 2,
|
||||||
|
currentTask: '',
|
||||||
|
avatar: 'https://p9-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/937facf77da3466fafaf9ff8f0223333.png~tplv-a9rns2rl98-24:720:720.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'EMP-2023-006',
|
||||||
|
name: '李工',
|
||||||
|
position: '系统工程师',
|
||||||
|
team: '第三运维组',
|
||||||
|
statusText: '工作中',
|
||||||
|
statusClass: 'working',
|
||||||
|
completedTasks: 1,
|
||||||
|
currentTask: 'WO-2023-0619-055',
|
||||||
|
avatar: 'https://p3-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/63a989286b91488ca0c4a0141041ea41.png~tplv-a9rns2rl98-24:720:720.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'EMP-2023-015',
|
||||||
|
name: '刘工',
|
||||||
|
position: '安全检查工程师',
|
||||||
|
team: '第一运维组',
|
||||||
|
statusText: '工作中',
|
||||||
|
statusClass: 'working',
|
||||||
|
completedTasks: 0,
|
||||||
|
currentTask: 'WO-2023-0618-054',
|
||||||
|
avatar: 'https://p3-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/0a6cf54a4a1c4623b8365939c8d61adc.png~tplv-a9rns2rl98-24:720:720.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'EMP-2023-022',
|
||||||
|
name: '孙工',
|
||||||
|
position: '安装调试工程师',
|
||||||
|
team: '第三运维组',
|
||||||
|
statusText: '离线休息',
|
||||||
|
statusClass: 'offline',
|
||||||
|
completedTasks: 2,
|
||||||
|
currentTask: '',
|
||||||
|
avatar: 'https://p3-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/f3e766fffb5d4573945ef7501894c461.png~tplv-a9rns2rl98-24:720:720.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'EMP-2023-008',
|
||||||
|
name: '李工',
|
||||||
|
position: '系统工程师',
|
||||||
|
team: '第三运维组',
|
||||||
|
statusText: '工作中',
|
||||||
|
statusClass: 'working',
|
||||||
|
completedTasks: 1,
|
||||||
|
currentTask: 'WO-2023-0619-055',
|
||||||
|
avatar: 'https://p3-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/d315aa56eb894980bf090804594ccf13.png~tplv-a9rns2rl98-24:720:720.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'EMP-2023-016',
|
||||||
|
name: '刘工',
|
||||||
|
position: '安全检查工程师',
|
||||||
|
team: '第一运维组',
|
||||||
|
statusText: '工作中',
|
||||||
|
statusClass: 'working',
|
||||||
|
completedTasks: 0,
|
||||||
|
currentTask: 'WO-2023-0618-054',
|
||||||
|
avatar: 'https://p9-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/937facf77da3466fafaf9ff8f0223333.png~tplv-a9rns2rl98-24:720:720.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'EMP-2023-002',
|
||||||
|
name: '张工',
|
||||||
|
position: '设备维护工程师',
|
||||||
|
team: '第一运维组',
|
||||||
|
statusText: '在线可用',
|
||||||
|
statusClass: 'online',
|
||||||
|
completedTasks: 2,
|
||||||
|
currentTask: '',
|
||||||
|
avatar: 'https://p3-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/63a989286b91488ca0c4a0141041ea41.png~tplv-a9rns2rl98-24:720:720.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'EMP-2023-009',
|
||||||
|
name: '李工',
|
||||||
|
position: '系统工程师',
|
||||||
|
team: '第三运维组',
|
||||||
|
statusText: '工作中',
|
||||||
|
statusClass: 'working',
|
||||||
|
completedTasks: 1,
|
||||||
|
currentTask: 'WO-2023-0619-055',
|
||||||
|
avatar: 'https://p3-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/0a6cf54a4a1c4623b8365939c8d61adc.png~tplv-a9rns2rl98-24:720:720.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'EMP-2023-017',
|
||||||
|
name: '刘工',
|
||||||
|
position: '安全检查工程师',
|
||||||
|
team: '第一运维组',
|
||||||
|
statusText: '工作中',
|
||||||
|
statusClass: 'working',
|
||||||
|
completedTasks: 0,
|
||||||
|
currentTask: 'WO-2023-0618-054',
|
||||||
|
avatar: 'https://p3-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/f3e766fffb5d4573945ef7501894c461.png~tplv-a9rns2rl98-24:720:720.png'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 初始化饼图
|
||||||
|
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') {
|
||||||
|
// 加载班组状态数据
|
||||||
|
} else {
|
||||||
|
// 加载人员状态数据
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 人员卡片操作
|
||||||
|
const viewDetails = (person) => {
|
||||||
|
console.log('查看详情:', person);
|
||||||
|
// 跳转到人员详情页
|
||||||
|
};
|
||||||
|
|
||||||
|
const assignTask = (person) => {
|
||||||
|
console.log('指派任务给:', person);
|
||||||
|
// 打开任务指派对话框
|
||||||
|
};
|
||||||
|
|
||||||
|
// 导航路由跳转
|
||||||
|
const handleInspection1 = () => {
|
||||||
|
router.push('/rili/rili');
|
||||||
|
};
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement1 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement2 = () => {
|
||||||
|
router.push('/rili/cheliangzhuangtai');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement3 = () => {
|
||||||
|
router.push('/rili/banzhuzhuangtai');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.operation-organization {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选项卡样式 */
|
||||||
|
.tabs-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs {
|
||||||
|
padding-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__header {
|
||||||
|
margin: 0 -20px;
|
||||||
|
padding: 0 20px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__nav-wrap::after {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
padding: 16px 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item.is-active {
|
||||||
|
color: #165dff;
|
||||||
|
font-weight: 500;
|
||||||
|
border-bottom: 2px solid #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item:hover {
|
||||||
|
color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容容器样式 */
|
||||||
|
.content-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 左侧边栏样式 */
|
||||||
|
.sidebar {
|
||||||
|
width: 320px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-card {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
padding: 24px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2c3e50;
|
||||||
|
margin: 0 0 24px 0;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 图表容器 */
|
||||||
|
.chart-container {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.personnel-chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 统计网格 */
|
||||||
|
.stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
background-color: #f8fafc;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 16px 12px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item:hover {
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #606266;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-change {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #52c41a;
|
||||||
|
font-weight: 500;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-change::before {
|
||||||
|
content: '↗';
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-change {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 主内容区域 */
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
background-color: #fff;
|
||||||
|
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(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 增强内容区域标题样式 */
|
||||||
|
.main-content-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 2px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 人员网格 */
|
||||||
|
.personnel-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-card {
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
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 {
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
|
||||||
|
border-color: #e6f7ff;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
position: relative;
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
margin-right: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 2px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid #fff;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator.online {
|
||||||
|
background-color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator.working {
|
||||||
|
background-color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator.offline {
|
||||||
|
background-color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-name {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-status {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-status.online {
|
||||||
|
background-color: #cbfad6;
|
||||||
|
color: #19b949;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-status.working {
|
||||||
|
background-color: #fff7e6;
|
||||||
|
color: #fa8c16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-status.offline {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-details {
|
||||||
|
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;
|
||||||
|
line-height: 1.6;
|
||||||
|
flex: 1;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item:first-child {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item:last-child {
|
||||||
|
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 solid #f0f0f0;
|
||||||
|
padding-top: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 美化按钮样式 */
|
||||||
|
.detail-btn,
|
||||||
|
.assign-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 6px 16px;
|
||||||
|
border-radius: 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-btn {
|
||||||
|
color: #165dff;
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
border-color: #d6e4ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-btn:hover {
|
||||||
|
color: #094ab2;
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
border-color: #91bfff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assign-btn {
|
||||||
|
color: #fa8c16;
|
||||||
|
background-color: #fff9f0;
|
||||||
|
border-color: #ffe7ba;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assign-btn:hover {
|
||||||
|
color: #e67700;
|
||||||
|
background-color: #fff7e6;
|
||||||
|
border-color: #ffd591;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导航栏样式 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
padding: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
padding: 14px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:hover {
|
||||||
|
color: #165dff;
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active {
|
||||||
|
background: linear-gradient(135deg, #165dff 0%, #4080ff 100%);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 4px 12px rgba(22, 93, 255, 0.3);
|
||||||
|
border-right-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active:hover {
|
||||||
|
background: linear-gradient(135deg, #094ab2 0%, #3366cc 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条样式 */
|
||||||
|
.scrollable-content::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollable-content::-webkit-scrollbar-track {
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollable-content::-webkit-scrollbar-thumb {
|
||||||
|
background: #c0c4cc;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollable-content::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.content-container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollable-content {
|
||||||
|
max-height: 600px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.operation-organization {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-tabs {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
flex: 1 0 33%;
|
||||||
|
padding: 10px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.personnel-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.personnel-chart {
|
||||||
|
height: 250px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1587
src/views/zhinengxunjian/shiyanguanli.vue
Normal file
1587
src/views/zhinengxunjian/shiyanguanli.vue
Normal file
File diff suppressed because it is too large
Load Diff
969
src/views/zhinengxunjian/shiyanjilu.vue
Normal file
969
src/views/zhinengxunjian/shiyanjilu.vue
Normal file
@ -0,0 +1,969 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="operation-inspection">
|
||||||
|
<div class="navigation-tabs">
|
||||||
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
|
<div class="nav-tab active" @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-container">
|
||||||
|
<TitleComponent title="实验管理系统" subtitle="制定巡检计划,安排巡检任务,跟进巡检记录"></TitleComponent>
|
||||||
|
<div class="header-actions">
|
||||||
|
<el-button type="primary" class="export-btn">筛选</el-button>
|
||||||
|
<el-button type="primary" class="create-btn">导入数据</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 选项卡和按钮组合 -->
|
||||||
|
<div class="tabs-wrapper">
|
||||||
|
<div style="display: flex; align-items: center; gap: 10px">
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement1">实验计划</el-button>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement2">实验任务</el-button>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement3">实验记录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 4. 筛选和操作区域 -->
|
||||||
|
<div class="filter-and-actions">
|
||||||
|
<div class="filters">
|
||||||
|
<el-select v-model="filterStatus" placeholder="巡检状态" clearable>
|
||||||
|
<el-option label="全部状态" value="all"></el-option>
|
||||||
|
<el-option label="正常" value="normal"></el-option>
|
||||||
|
<el-option label="需关注" value="attention"></el-option>
|
||||||
|
<el-option label="有问题" value="problem"></el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<el-select v-model="filterType" placeholder="巡检类型" clearable>
|
||||||
|
<el-option label="全部类型" value="all"></el-option>
|
||||||
|
<el-option label="数据库" value="database"></el-option>
|
||||||
|
<el-option label="服务器" value="server"></el-option>
|
||||||
|
<el-option label="网络设备" value="network"></el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
class="date-picker"
|
||||||
|
></el-date-picker>
|
||||||
|
|
||||||
|
<el-button type="primary" class="search-btn"> 搜索 </el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 5. 主内容区 -->
|
||||||
|
<div class="content-container">
|
||||||
|
<!-- 5.3 巡检记录(根据图片调整) -->
|
||||||
|
<div v-if="activeTab === 'record'" class="record-container">
|
||||||
|
<h2 class="section-title">试验记录与报告</h2>
|
||||||
|
<p class="section-subtitle">截止至 {{ currentDate }}</p>
|
||||||
|
|
||||||
|
<!-- 统计卡片 -->
|
||||||
|
<div class="stat-grid">
|
||||||
|
<div class="stat-card">
|
||||||
|
<p class="stat-label">本月完成试验</p>
|
||||||
|
<p class="stat-value">{{ statData.completed }}<span class="stat-change up">较上月 ↑2.4%</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<p class="stat-label">试验通过率</p>
|
||||||
|
<p class="stat-value">{{ statData.passRate }}%<span class="stat-change up">较上月 ↑5.6%</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<p class="stat-label">待分析记录</p>
|
||||||
|
<p class="stat-value">{{ statData.pendingAnalysis }}<span class="stat-change warning">需要及时处理</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<p class="stat-label">平均试验时长</p>
|
||||||
|
<p class="stat-value">{{ statData.avgDuration }}<span class="stat-change down">较上月 ↓9.4分钟</span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 试验记录列表 -->
|
||||||
|
<div class="test-records">
|
||||||
|
<!-- 数据库性能巡检记录 -->
|
||||||
|
<div class="test-record-card passed">
|
||||||
|
<div class="record-header">
|
||||||
|
<h3 class="record-title">数据库性能巡检</h3>
|
||||||
|
<p class="record-date">
|
||||||
|
{{ testRecords[0].date }} <span class="record-time">耗时: {{ testRecords[0].duration }}</span>
|
||||||
|
</p>
|
||||||
|
<span class="status-tag status-passed">通过</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 试验进度 -->
|
||||||
|
<div class="test-progress">
|
||||||
|
<div class="progress-step active">
|
||||||
|
<div class="step-number">1</div>
|
||||||
|
<div class="step-name">准备环境</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-line active"></div>
|
||||||
|
<div class="progress-step active">
|
||||||
|
<div class="step-number">2</div>
|
||||||
|
<div class="step-name">50%负载</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-line active"></div>
|
||||||
|
<div class="progress-step active">
|
||||||
|
<div class="step-number">3</div>
|
||||||
|
<div class="step-name">80%负载</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-line active"></div>
|
||||||
|
<div class="progress-step active">
|
||||||
|
<div class="step-number">4</div>
|
||||||
|
<div class="step-name">100%负载</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 试验结果 -->
|
||||||
|
<div class="test-result">
|
||||||
|
<h4 class="result-title">试验结果</h4>
|
||||||
|
<p class="result-content">系统在100%负载下稳定运行1小时,CPU平均使用率92%,内存使用率88%,无崩溃或异常重启现象。</p>
|
||||||
|
<p class="result-details">
|
||||||
|
平均响应时间: {{ testRecords[0].responseTime }} | 错误率: {{ testRecords[0].errorRate }} | 温度值: {{ testRecords[0].temperature }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="record-actions">
|
||||||
|
<button class="operate-btn view-btn">查看详情</button>
|
||||||
|
<button class="operate-btn report-btn">生成报告</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 1000用户并发测试记录 -->
|
||||||
|
<div class="test-record-card failed">
|
||||||
|
<div class="record-header">
|
||||||
|
<h3 class="record-title">1000用户并发测试</h3>
|
||||||
|
<p class="record-date">
|
||||||
|
{{ testRecords[1].date }} <span class="record-time">耗时: {{ testRecords[1].duration }}</span>
|
||||||
|
</p>
|
||||||
|
<span class="status-tag status-failed">失败</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 试验进度 -->
|
||||||
|
<div class="test-progress">
|
||||||
|
<div class="progress-step active">
|
||||||
|
<div class="step-number">1</div>
|
||||||
|
<div class="step-name">准备环境</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-line active"></div>
|
||||||
|
<div class="progress-step active">
|
||||||
|
<div class="step-number">2</div>
|
||||||
|
<div class="step-name">300用户</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-line active"></div>
|
||||||
|
<div class="progress-step active">
|
||||||
|
<div class="step-number">3</div>
|
||||||
|
<div class="step-name">500用户</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-line failed"></div>
|
||||||
|
<div class="progress-step failed">
|
||||||
|
<div class="step-number">4</div>
|
||||||
|
<div class="step-name">800用户</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 失败原因分析 -->
|
||||||
|
<div class="test-result failure-analysis">
|
||||||
|
<h4 class="result-title">失败原因分析</h4>
|
||||||
|
<p class="result-content">当并发用户数达到780人时,数据库连接耗尽,新用户无法建立数据库连接,导致系统响应超时。</p>
|
||||||
|
|
||||||
|
<!-- 改进建议 -->
|
||||||
|
<div class="improvement-suggestion">
|
||||||
|
<i class="fas fa-lightbulb"></i>
|
||||||
|
<p>建议: 增加数据库连接池最大连接数,优化长连接超时时间,增加连接复用机制分析评估。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="record-actions">
|
||||||
|
<button class="operate-btn view-btn">查看详情</button>
|
||||||
|
<button class="operate-btn report-btn">生成报告</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 5.1 巡检计划表格 -->
|
||||||
|
<div v-if="activeTab === 'plan'" class="table-container">
|
||||||
|
<el-table :data="planTableData" border>
|
||||||
|
<el-table-column prop="name" label="计划名称" width="220">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="plan-name">{{ scope.row.name }}</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="type" label="巡检类型" width="120"></el-table-column>
|
||||||
|
<el-table-column prop="cycle" label="巡检周期" width="120"></el-table-column>
|
||||||
|
<el-table-column prop="dateRange" label="执行时间范围"></el-table-column>
|
||||||
|
<el-table-column prop="progress" label="完成进度" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="progress-bar">
|
||||||
|
<div class="progress-fill" :style="{ width: scope.row.progress + '%', backgroundColor: getProgressColor(scope.row.status) }"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="status" label="状态" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<span :class="['status-tag', `status-${scope.row.status}`]">
|
||||||
|
{{ getStatusText(scope.row.status) }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="responsible" label="负责人" width="120"></el-table-column>
|
||||||
|
<el-table-column label="操作" width="220">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="operation-buttons">
|
||||||
|
<button class="operate-btn edit-btn" v-if="['drafted', 'paused'].includes(scope.row.status)">编辑</button>
|
||||||
|
<button class="operate-btn execute-btn" v-if="scope.row.status === 'drafted'">执行</button>
|
||||||
|
<button class="operate-btn pause-btn" v-if="scope.row.status === 'in-progress'">暂停</button>
|
||||||
|
<button class="operate-btn resume-btn" v-if="scope.row.status === 'paused'">恢复</button>
|
||||||
|
<button class="operate-btn view-btn">查看详情</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 5.2 巡检任务表格 -->
|
||||||
|
<div v-if="activeTab === 'task'" class="table-container">
|
||||||
|
<el-table :data="taskTableData" border>
|
||||||
|
<el-table-column prop="name" label="任务名称" width="220"></el-table-column>
|
||||||
|
<el-table-column prop="planName" label="所属计划" width="180"></el-table-column>
|
||||||
|
<el-table-column prop="type" label="巡检类型" width="120"></el-table-column>
|
||||||
|
<el-table-column prop="target" label="巡检对象" width="150"></el-table-column>
|
||||||
|
<el-table-column prop="deadline" label="截止时间" width="160"></el-table-column>
|
||||||
|
<el-table-column prop="status" label="状态" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<span :class="['status-tag', `status-${scope.row.status}`]">
|
||||||
|
{{ getTaskStatusText(scope.row.status) }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="executor" label="执行人" width="120"></el-table-column>
|
||||||
|
<el-table-column label="操作" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="operation-buttons">
|
||||||
|
<button class="operate-btn accept-btn" v-if="scope.row.status === 'pending'">接受</button>
|
||||||
|
<button class="operate-btn complete-btn" v-if="scope.row.status === 'accepted'">完成</button>
|
||||||
|
<button class="operate-btn view-btn">查看详情</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 6. 分页 -->
|
||||||
|
<div class="pagination" v-if="activeTab !== 'record'">
|
||||||
|
<p class="total-records">显示1到{{ pageSize }}条,共{{ totalRecords }}条记录</p>
|
||||||
|
<el-pagination
|
||||||
|
layout="prev, pager, next, jumper, sizes"
|
||||||
|
:total="totalRecords"
|
||||||
|
v-model:current-page="currentPage"
|
||||||
|
v-model:page-size="pageSize"
|
||||||
|
:page-sizes="[20, 50, 100]"
|
||||||
|
@current-change="handlePageChange"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
></el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './TitleComponent.vue';
|
||||||
|
// 1. 选项卡状态管理
|
||||||
|
const activeTab = ref('record'); // 默认显示"巡检记录"
|
||||||
|
const showFilter = ref(false);
|
||||||
|
|
||||||
|
// 2. 筛选条件
|
||||||
|
const filterStatus = ref('all');
|
||||||
|
const filterType = ref('all');
|
||||||
|
const dateRange = ref([]);
|
||||||
|
|
||||||
|
// 4. 当前日期
|
||||||
|
const currentDate = computed(() => {
|
||||||
|
const date = new Date();
|
||||||
|
return `${date.getFullYear()}/${String(date.getMonth() + 1).padStart(2, '0')}/${String(date.getDate()).padStart(2, '0')} ${String(
|
||||||
|
date.getHours()
|
||||||
|
).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 5. 统计数据
|
||||||
|
const statData = ref({
|
||||||
|
completed: 12,
|
||||||
|
passRate: 83,
|
||||||
|
pendingAnalysis: 3,
|
||||||
|
avgDuration: '42分钟'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 6. 试验记录数据
|
||||||
|
const testRecords = ref([
|
||||||
|
{
|
||||||
|
date: '2025-06-15',
|
||||||
|
duration: '1小时45分钟',
|
||||||
|
responseTime: '1.2s',
|
||||||
|
errorRate: '0%',
|
||||||
|
temperature: '72°C'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2025-06-12',
|
||||||
|
duration: '2小时10分钟'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 9. 方法:切换顶部导航
|
||||||
|
const handleInspection1 = () => {
|
||||||
|
router.push('/rili/rili');
|
||||||
|
};
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement1 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement2 = () => {
|
||||||
|
router.push('/rili/shiyanrenwu');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement3 = () => {
|
||||||
|
router.push('/rili/shiyanjilu');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 1. 基础容器样式 */
|
||||||
|
.operation-inspection {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f9fbfd;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. 顶部导航选项卡 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.nav-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6b7280;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
.nav-tab:hover:not(.active) {
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
}
|
||||||
|
.nav-tab.active {
|
||||||
|
background-color: #165dff;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选项卡样式 */
|
||||||
|
.tabs-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 筛选栏样式 */
|
||||||
|
.filter-bar {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select,
|
||||||
|
.filter-bar .el-date-picker {
|
||||||
|
width: 150px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
/* 5. 筛选和操作区域 */
|
||||||
|
.filter-and-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 0 0 4px 4px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.filters {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.el-select,
|
||||||
|
.date-picker {
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
|
.search-btn,
|
||||||
|
.export-btn {
|
||||||
|
background-color: #165dff;
|
||||||
|
border-color: #165dff;
|
||||||
|
}
|
||||||
|
.filter-btn {
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
color: #6b7280;
|
||||||
|
border-color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 6. 表格容器 */
|
||||||
|
.table-container {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.el-table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.el-table th {
|
||||||
|
background-color: #f9fafb;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #4b5563;
|
||||||
|
}
|
||||||
|
.plan-name {
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 7. 进度条样式 */
|
||||||
|
.progress-bar {
|
||||||
|
height: 8px;
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.progress-fill {
|
||||||
|
height: 100%;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 8. 状态标签样式 */
|
||||||
|
.status-tag {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.status-drafted {
|
||||||
|
background-color: #e0efff;
|
||||||
|
color: #165dff;
|
||||||
|
}
|
||||||
|
.status-in-progress {
|
||||||
|
background-color: #e0f2fe;
|
||||||
|
color: #0284c7;
|
||||||
|
}
|
||||||
|
.status-completed {
|
||||||
|
background-color: #e6ffed;
|
||||||
|
color: #00b42a;
|
||||||
|
}
|
||||||
|
.status-paused {
|
||||||
|
background-color: #f2f3f5;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
.status-pending {
|
||||||
|
background-color: #f9fafb;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
.status-accepted {
|
||||||
|
background-color: #eff6ff;
|
||||||
|
color: #2563eb;
|
||||||
|
}
|
||||||
|
.status-rejected {
|
||||||
|
background-color: #fee2e2;
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
.status-normal {
|
||||||
|
background-color: #e6ffed;
|
||||||
|
color: #00b42a;
|
||||||
|
}
|
||||||
|
.status-attention {
|
||||||
|
background-color: #fff7e0;
|
||||||
|
color: #ff7d00;
|
||||||
|
}
|
||||||
|
.status-problem {
|
||||||
|
background-color: #fff2f0;
|
||||||
|
color: #f5222d;
|
||||||
|
}
|
||||||
|
.status-passed {
|
||||||
|
background-color: #e6ffed;
|
||||||
|
color: #00b42a;
|
||||||
|
}
|
||||||
|
.status-failed {
|
||||||
|
background-color: #fee2e2;
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 9. 操作按钮样式 */
|
||||||
|
.operation-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.operate-btn {
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.edit-btn {
|
||||||
|
color: #165dff;
|
||||||
|
}
|
||||||
|
.edit-btn:hover {
|
||||||
|
background-color: #e8f3ff;
|
||||||
|
}
|
||||||
|
.execute-btn {
|
||||||
|
color: #00b42a;
|
||||||
|
}
|
||||||
|
.execute-btn:hover {
|
||||||
|
background-color: #e6ffed;
|
||||||
|
}
|
||||||
|
.pause-btn {
|
||||||
|
color: #ff7d00;
|
||||||
|
}
|
||||||
|
.pause-btn:hover {
|
||||||
|
background-color: #fff7e0;
|
||||||
|
}
|
||||||
|
.resume-btn {
|
||||||
|
color: #722ed1;
|
||||||
|
}
|
||||||
|
.resume-btn:hover {
|
||||||
|
background-color: #f3e8ff;
|
||||||
|
}
|
||||||
|
.view-btn {
|
||||||
|
color: #165dff;
|
||||||
|
}
|
||||||
|
.view-btn:hover {
|
||||||
|
background-color: #e8f3ff;
|
||||||
|
}
|
||||||
|
.complete-btn {
|
||||||
|
color: #00b42a;
|
||||||
|
}
|
||||||
|
.complete-btn:hover {
|
||||||
|
background-color: #e6ffed;
|
||||||
|
}
|
||||||
|
.accept-btn {
|
||||||
|
color: #2563eb;
|
||||||
|
}
|
||||||
|
.accept-btn:hover {
|
||||||
|
background-color: #eff6ff;
|
||||||
|
}
|
||||||
|
.report-btn {
|
||||||
|
color: #ff7d00;
|
||||||
|
}
|
||||||
|
.report-btn:hover {
|
||||||
|
background-color: #fff7e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 10. 分页样式 */
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
.total-records {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6b7280;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.el-pagination {
|
||||||
|
--el-pagination-item-active-bg-color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 11. 记录页面样式 */
|
||||||
|
.record-container {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2329;
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6b7280;
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
/* 头部容器 - 替换了固定gap的flex布局 */
|
||||||
|
.header-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
/* 12. 统计卡片样式 */
|
||||||
|
.stat-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.stat-card {
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
border-left: 4px solid #165dff;
|
||||||
|
}
|
||||||
|
.stat-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6b7280;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
}
|
||||||
|
.stat-value {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2329;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.stat-change {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 1px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.stat-change.up {
|
||||||
|
background-color: #e6ffed;
|
||||||
|
color: #00b42a;
|
||||||
|
}
|
||||||
|
.stat-change.down {
|
||||||
|
background-color: #fff1f0;
|
||||||
|
color: #f5222d;
|
||||||
|
}
|
||||||
|
.stat-change.warning {
|
||||||
|
background-color: #fff7e0;
|
||||||
|
color: #ff7d00;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 13. 试验记录样式 */
|
||||||
|
.test-records {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-record-card {
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: box-shadow 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-record-card:hover {
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-record-card.passed {
|
||||||
|
border-left: 4px solid #00b42a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-record-card.failed {
|
||||||
|
border-left: 4px solid #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
border-bottom: 1px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1f2329;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-date {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6b7280;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-time {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #9ca3af;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 14. 试验进度样式 */
|
||||||
|
.test-progress {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-step {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-number {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #e5e7eb;
|
||||||
|
color: #6b7280;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-name {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #6b7280;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-line {
|
||||||
|
flex: 1;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-step.active .step-number {
|
||||||
|
background-color: #165dff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-step.active .step-name {
|
||||||
|
color: #165dff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-line.active {
|
||||||
|
background-color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-step.failed .step-number {
|
||||||
|
background-color: #dc2626;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-step.failed .step-name {
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-line.failed {
|
||||||
|
background-color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 15. 试验结果样式 */
|
||||||
|
.test-result {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-top: 1px solid #e5e7eb;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1f2329;
|
||||||
|
margin: 0 0 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-content {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #4b5563;
|
||||||
|
line-height: 1.5;
|
||||||
|
margin: 0 0 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-details {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6b7280;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.failure-analysis {
|
||||||
|
background-color: #fff5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.improvement-suggestion {
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
background-color: #fff8e6;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.improvement-suggestion i {
|
||||||
|
color: #ff7d00;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.improvement-suggestion p {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6b46c1;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 16. 记录操作按钮 */
|
||||||
|
.record-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
border-top: 1px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 17. 响应式适配 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.stat-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.stat-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-progress {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-step {
|
||||||
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-number {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-line {
|
||||||
|
width: 2px;
|
||||||
|
height: 30px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filters {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select,
|
||||||
|
.date-picker {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-tabs {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
912
src/views/zhinengxunjian/shiyanrenwu.vue
Normal file
912
src/views/zhinengxunjian/shiyanrenwu.vue
Normal file
@ -0,0 +1,912 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="inspection-tasks">
|
||||||
|
<div class="navigation-tabs">
|
||||||
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
|
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
|
||||||
|
<div class="nav-tab active" @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>
|
||||||
|
<!-- 页面标题 -->
|
||||||
|
<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>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement2">实验任务</el-button>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement3">实验记录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选栏 -->
|
||||||
|
<div class="filter-bar">
|
||||||
|
<div class="filter-container">
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="taskStatus" placeholder="任务状态">
|
||||||
|
<el-option label="待执行" value="pending"></el-option>
|
||||||
|
<el-option label="执行中" value="executing"></el-option>
|
||||||
|
<el-option label="已延期" value="delayed"></el-option>
|
||||||
|
<el-option label="已完成" value="completed"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="planType" placeholder="全部计划">
|
||||||
|
<el-option label="每日巡检计划" value="daily"></el-option>
|
||||||
|
<el-option label="每周巡检计划" value="weekly"></el-option>
|
||||||
|
<el-option label="每月巡检计划" value="monthly"></el-option>
|
||||||
|
<el-option label="每季度巡检计划" value="quarterly"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="executor" placeholder="执行人">
|
||||||
|
<el-option label="全部人员" value="all"></el-option>
|
||||||
|
<el-option label="张明" value="zhangming"></el-option>
|
||||||
|
<el-option label="李华" value="lihua"></el-option>
|
||||||
|
<el-option label="王强" value="wangqiang"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-actions">
|
||||||
|
<el-button type="primary" class="search-btn" @click="handleSearch"> 搜索 </el-button>
|
||||||
|
<el-button type="primary" icon="el-icon-plus" class="create-btn" @click="handleCreateTask"> 手动创建任务 </el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 任务卡片列表 -->
|
||||||
|
<div class="task-cards">
|
||||||
|
<div class="task-card" v-for="(task, index) in pagedTasks" :key="index">
|
||||||
|
<div class="task-header">
|
||||||
|
<div class="task-title">
|
||||||
|
{{ task.title }}
|
||||||
|
</div>
|
||||||
|
<div class="task-status" :class="task.statusClass">
|
||||||
|
{{ task.statusText }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="task-details">
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">计划时间</span>
|
||||||
|
<span class="detail-value">{{ task.planTime }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">巡检对象</span>
|
||||||
|
<span class="detail-value">{{ task.target }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">执行人</span>
|
||||||
|
<span class="detail-value">{{ task.executor }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">关联计划</span>
|
||||||
|
<span class="detail-value">{{ task.relatedPlan }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 特定状态的额外信息 -->
|
||||||
|
<div v-if="task.status === 'delayed'" class="delay-reason">
|
||||||
|
<span class="detail-label">延期原因</span>
|
||||||
|
<span class="detail-value">{{ task.delayReason }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="task.status === 'executing'" class="progress-container">
|
||||||
|
<span class="detail-label">完成进度</span>
|
||||||
|
<div class="progress-bar">
|
||||||
|
<el-progress :percentage="task.progress" stroke-width="6" :stroke-color="task.progressColor"></el-progress>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="task.status === 'completed'" class="task-result">
|
||||||
|
<span class="detail-label">结果</span>
|
||||||
|
<span class="detail-value" :class="task.resultClass">{{ task.result }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="task-actions">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页区域 -->
|
||||||
|
<div class="pagination-section">
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<el-pagination
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
:current-page="currentPage"
|
||||||
|
:page-sizes="[8, 12, 16, 20]"
|
||||||
|
:page-size="pageSize"
|
||||||
|
layout="prev, pager, next, jumper"
|
||||||
|
:total="total"
|
||||||
|
background
|
||||||
|
>
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 添加新任务弹窗 -->
|
||||||
|
<el-dialog v-model="createTaskDialogVisible" title="添加新任务" width="500px" :before-close="handleCancelCreateTask">
|
||||||
|
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="80px">
|
||||||
|
<el-form-item label="任务名称" prop="taskName">
|
||||||
|
<el-input v-model="createTaskForm.taskName" placeholder="输入任务名称" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="巡检对象" prop="inspectionTarget">
|
||||||
|
<el-input v-model="createTaskForm.inspectionTarget" placeholder="输入巡检内容" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="时间" prop="timeRange">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="createTaskForm.timeRange"
|
||||||
|
type="datetimerange"
|
||||||
|
start-placeholder="开始时间"
|
||||||
|
end-placeholder="结束时间"
|
||||||
|
format="YYYY-MM-DD HH:mm"
|
||||||
|
value-format="YYYY-MM-DD HH:mm"
|
||||||
|
placeholder="选择时间范围"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="关联计划">
|
||||||
|
<el-select v-model="createTaskForm.relatedPlan" placeholder="选择关联计划">
|
||||||
|
<el-option label="全部计划" value="all" />
|
||||||
|
<el-option label="每日巡检计划" value="daily" />
|
||||||
|
<el-option label="每周巡检计划" value="weekly" />
|
||||||
|
<el-option label="每月巡检计划" value="monthly" />
|
||||||
|
<el-option label="每季度巡检计划" value="quarterly" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="执行人">
|
||||||
|
<el-select v-model="createTaskForm.executor" placeholder="选择执行人">
|
||||||
|
<el-option label="全部人员" value="all" />
|
||||||
|
<el-option label="张明" value="zhangming" />
|
||||||
|
<el-option label="李华" value="lihua" />
|
||||||
|
<el-option label="王强" value="wangqiang" />
|
||||||
|
<el-option label="赵伟" value="zhaowei" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="handleCancelCreateTask">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSaveTask">保存任务</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './TitleComponent.vue';
|
||||||
|
|
||||||
|
// 激活的选项卡
|
||||||
|
const activeTab = ref('task');
|
||||||
|
|
||||||
|
// 筛选条件
|
||||||
|
const taskStatus = ref('');
|
||||||
|
const planType = ref('');
|
||||||
|
const executor = ref('');
|
||||||
|
|
||||||
|
// 任务数据
|
||||||
|
const tasks = ref([
|
||||||
|
{
|
||||||
|
title: '生产服务器日常巡检',
|
||||||
|
status: 'pending',
|
||||||
|
statusText: '待执行',
|
||||||
|
statusClass: 'status-pending',
|
||||||
|
planTime: '2025-06-16 08:30',
|
||||||
|
target: '生产服务器集群(12台)',
|
||||||
|
executor: '张明',
|
||||||
|
relatedPlan: '每日巡检计划',
|
||||||
|
actionText: '开始执行',
|
||||||
|
actionClass: 'start-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '机房环境检查',
|
||||||
|
status: 'delayed',
|
||||||
|
statusText: '已延期',
|
||||||
|
statusClass: 'status-delayed',
|
||||||
|
planTime: '2025-06-16 08:30',
|
||||||
|
target: '机房温度、湿度、电源',
|
||||||
|
executor: '李华',
|
||||||
|
relatedPlan: '每周巡检计划',
|
||||||
|
delayReason: '设备维修处理中',
|
||||||
|
actionText: '重新安排',
|
||||||
|
actionClass: 'reschedule-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '网络设备安全巡检',
|
||||||
|
status: 'executing',
|
||||||
|
statusText: '执行中',
|
||||||
|
statusClass: 'status-executing',
|
||||||
|
planTime: '2025-06-16 09:30',
|
||||||
|
target: '核心交换机、防火墙',
|
||||||
|
executor: '王强',
|
||||||
|
relatedPlan: '每周巡检计划',
|
||||||
|
progress: 60,
|
||||||
|
progressColor: '#FF7D00',
|
||||||
|
actionText: '完成',
|
||||||
|
actionClass: 'complete-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '数据库性能巡检',
|
||||||
|
status: 'completed',
|
||||||
|
statusText: '已完成',
|
||||||
|
statusClass: 'status-completed',
|
||||||
|
planTime: '2025-06-16 10:30',
|
||||||
|
target: '生产数据库集群(2组)',
|
||||||
|
executor: '赵伟',
|
||||||
|
relatedPlan: '每月巡检计划',
|
||||||
|
result: '正常',
|
||||||
|
resultClass: 'result-normal',
|
||||||
|
actionText: '查看报告',
|
||||||
|
actionClass: 'report-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '生产服务器日常巡检',
|
||||||
|
status: 'pending',
|
||||||
|
statusText: '待执行',
|
||||||
|
statusClass: 'status-pending',
|
||||||
|
planTime: '2025-06-16 13:30',
|
||||||
|
target: '生产服务器集群(12台)',
|
||||||
|
executor: '张明',
|
||||||
|
relatedPlan: '每日巡检计划',
|
||||||
|
actionText: '开始执行',
|
||||||
|
actionClass: 'start-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '机房环境检查',
|
||||||
|
status: 'delayed',
|
||||||
|
statusText: '已延期',
|
||||||
|
statusClass: 'status-delayed',
|
||||||
|
planTime: '2025-06-16 14:00',
|
||||||
|
target: '机房温度、湿度、电源',
|
||||||
|
executor: '李华',
|
||||||
|
relatedPlan: '每周巡检计划',
|
||||||
|
delayReason: '设备维修处理中',
|
||||||
|
actionText: '重新安排',
|
||||||
|
actionClass: 'reschedule-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '网络设备安全巡检',
|
||||||
|
status: 'executing',
|
||||||
|
statusText: '执行中',
|
||||||
|
statusClass: 'status-executing',
|
||||||
|
planTime: '2025-06-16 15:00',
|
||||||
|
target: '核心交换机、防火墙',
|
||||||
|
executor: '王强',
|
||||||
|
relatedPlan: '每周巡检计划',
|
||||||
|
progress: 35,
|
||||||
|
progressColor: '#FF7D00',
|
||||||
|
actionText: '完成',
|
||||||
|
actionClass: 'complete-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '数据库性能巡检',
|
||||||
|
status: 'completed',
|
||||||
|
statusText: '已完成',
|
||||||
|
statusClass: 'status-completed',
|
||||||
|
planTime: '2025-06-16 16:00',
|
||||||
|
target: '生产数据库集群(2组)',
|
||||||
|
executor: '赵伟',
|
||||||
|
relatedPlan: '每月巡检计划',
|
||||||
|
result: '正常',
|
||||||
|
resultClass: 'result-normal',
|
||||||
|
actionText: '查看报告',
|
||||||
|
actionClass: 'report-btn'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 分页相关
|
||||||
|
const currentPage = ref(1);
|
||||||
|
const pageSize = ref(8);
|
||||||
|
const total = ref(tasks.value.length);
|
||||||
|
|
||||||
|
// 状态排序映射
|
||||||
|
const statusOrder = {
|
||||||
|
pending: 0, // 待完成
|
||||||
|
delayed: 1, // 已延期
|
||||||
|
executing: 2, // 执行中
|
||||||
|
completed: 3 // 已完成
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页处理后的数据(含排序)
|
||||||
|
const pagedTasks = computed(() => {
|
||||||
|
// 先按状态排序
|
||||||
|
const sortedTasks = [...tasks.value].sort((a, b) => {
|
||||||
|
return statusOrder[a.status] - statusOrder[b.status];
|
||||||
|
});
|
||||||
|
|
||||||
|
// 再进行分页
|
||||||
|
const startIndex = (currentPage.value - 1) * pageSize.value;
|
||||||
|
const endIndex = startIndex + pageSize.value;
|
||||||
|
return sortedTasks.slice(startIndex, endIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {
|
||||||
|
currentPage.value = 1; // 重置到第一页
|
||||||
|
// 实际应用中这里会根据筛选条件过滤数据
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建任务弹窗相关
|
||||||
|
const createTaskDialogVisible = ref(false);
|
||||||
|
const createTaskForm = ref({
|
||||||
|
taskName: '',
|
||||||
|
inspectionTarget: '',
|
||||||
|
timeRange: [],
|
||||||
|
relatedPlan: 'all',
|
||||||
|
executor: 'all'
|
||||||
|
});
|
||||||
|
|
||||||
|
const createTaskRules = {
|
||||||
|
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
|
||||||
|
inspectionTarget: [{ required: true, message: '请输入巡检对象', trigger: 'blur' }],
|
||||||
|
timeRange: [{ required: true, message: '请选择时间范围', trigger: 'change' }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建任务
|
||||||
|
const handleCreateTask = () => {
|
||||||
|
createTaskDialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存任务
|
||||||
|
const handleSaveTask = () => {
|
||||||
|
// 模拟保存任务逻辑
|
||||||
|
console.log('保存任务:', createTaskForm.value);
|
||||||
|
// 关闭弹窗
|
||||||
|
createTaskDialogVisible.value = false;
|
||||||
|
// 重置表单
|
||||||
|
createTaskForm.value = {
|
||||||
|
taskName: '',
|
||||||
|
inspectionTarget: '',
|
||||||
|
timeRange: [],
|
||||||
|
relatedPlan: 'all',
|
||||||
|
executor: 'all'
|
||||||
|
};
|
||||||
|
// 这里可以添加成功提示和刷新任务列表的逻辑
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消创建任务
|
||||||
|
const handleCancelCreateTask = () => {
|
||||||
|
createTaskDialogVisible.value = false;
|
||||||
|
// 重置表单
|
||||||
|
createTaskForm.value = {
|
||||||
|
taskName: '',
|
||||||
|
inspectionTarget: '',
|
||||||
|
timeRange: [],
|
||||||
|
relatedPlan: 'all',
|
||||||
|
executor: 'all'
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页事件
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pageSize.value = val;
|
||||||
|
currentPage.value = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
currentPage.value = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查看任务详情
|
||||||
|
const handleView = (task) => {
|
||||||
|
console.log('查看任务详情:', task);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspectionManagement1 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement2 = () => {
|
||||||
|
router.push('/rili/shiyanrenwu');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement3 = () => {
|
||||||
|
router.push('/rili/shiyanjilu');
|
||||||
|
};
|
||||||
|
const handleInspection1 = () => {
|
||||||
|
router.push('/rili/rili');
|
||||||
|
};
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.inspection-tasks {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选项卡样式 */
|
||||||
|
.tabs-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs {
|
||||||
|
border-bottom: none;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__header {
|
||||||
|
margin: 0 -20px 0 -20px;
|
||||||
|
padding: 0 20px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__nav-wrap::after {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
padding: 12px 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item.is-active {
|
||||||
|
color: #409eff;
|
||||||
|
border-bottom-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item:hover {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
/* 筛选栏样式 */
|
||||||
|
.filter-bar {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 16px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select {
|
||||||
|
width: 180px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select .el-input__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
border-color: #dcdfe6;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select .el-input__inner:focus {
|
||||||
|
border-color: #165dff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
background-color: #f2f3f5;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #f2f3f5;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn:hover {
|
||||||
|
background-color: #e5e6eb;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #e5e6eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-btn {
|
||||||
|
background-color: #165dff;
|
||||||
|
border-color: #165dff;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-btn:hover {
|
||||||
|
background-color: #0e42d2;
|
||||||
|
border-color: #0e42d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 任务卡片样式 */
|
||||||
|
.task-cards {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card {
|
||||||
|
background-color: #fff;
|
||||||
|
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;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 280px; /* 确保有足够高度显示所有内容 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #f0f2f5;
|
||||||
|
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 {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card.status-pending::before {
|
||||||
|
background-color: #1677ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card.status-delayed::before {
|
||||||
|
background-color: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card.status-executing::before {
|
||||||
|
background-color: #fa8c16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card.status-completed::before {
|
||||||
|
background-color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1d2129;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-status {
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 待执行状态 - 蓝色 */
|
||||||
|
.status-pending {
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
color: #1677ff;
|
||||||
|
border-color: #91d5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 已延期状态 - 红色 */
|
||||||
|
.status-delayed {
|
||||||
|
background-color: #fff2f0;
|
||||||
|
color: #ff4d4f;
|
||||||
|
border-color: #ffccc7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 执行中状态 - 黄色 */
|
||||||
|
.status-executing {
|
||||||
|
background-color: #fffbe6;
|
||||||
|
color: #fa8c16;
|
||||||
|
border-color: #ffe58f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 已完成状态 - 绿色 */
|
||||||
|
.status-completed {
|
||||||
|
background-color: #f6ffed;
|
||||||
|
color: #52c41a;
|
||||||
|
border-color: #b7eb8f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-details {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-label {
|
||||||
|
flex: 0 0 80px;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-value {
|
||||||
|
flex: 1;
|
||||||
|
color: #4e5969;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delay-reason {
|
||||||
|
display: flex;
|
||||||
|
margin: 10px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px dashed #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 10px 0;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px dashed #f0f2f5;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
flex: 1;
|
||||||
|
padding-left: 80px;
|
||||||
|
margin-top: 4px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-result {
|
||||||
|
display: flex;
|
||||||
|
margin: 10px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px dashed #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-normal {
|
||||||
|
color: #00b42a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-abnormal {
|
||||||
|
color: #f53f3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #f0f2f5;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 16px;
|
||||||
|
right: 16px;
|
||||||
|
left: 16px;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 12px 0 0 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-btn {
|
||||||
|
color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-btn:hover {
|
||||||
|
color: #0e42d2;
|
||||||
|
background-color: #e8f3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-btn {
|
||||||
|
background-color: #165dff;
|
||||||
|
border-color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-btn:hover {
|
||||||
|
background-color: #0e42d2;
|
||||||
|
border-color: #0e42d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reschedule-btn {
|
||||||
|
background-color: #ff7d00;
|
||||||
|
border-color: #ff7d00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reschedule-btn:hover {
|
||||||
|
background-color: #e86a00;
|
||||||
|
border-color: #e86a00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.complete-btn {
|
||||||
|
background-color: #00b42a;
|
||||||
|
border-color: #00b42a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.complete-btn:hover {
|
||||||
|
background-color: #008718;
|
||||||
|
border-color: #008718;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-btn {
|
||||||
|
background-color: #86909c;
|
||||||
|
border-color: #86909c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-btn:hover {
|
||||||
|
background-color: #6b7785;
|
||||||
|
border-color: #6b7785;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分页区域样式 */
|
||||||
|
.pagination-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination button,
|
||||||
|
.pagination-controls .el-pagination .el-pager li {
|
||||||
|
min-width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination .el-pager li.active {
|
||||||
|
background-color: #165dff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.task-cards {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.inspection-tasks {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: 0;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-cards {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 导航栏样式 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
925
src/views/zhinengxunjian/xunjianjihua.vue
Normal file
925
src/views/zhinengxunjian/xunjianjihua.vue
Normal file
@ -0,0 +1,925 @@
|
|||||||
|
<template>
|
||||||
|
<div class="operation-inspection">
|
||||||
|
<div class="navigation-tabs">
|
||||||
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
|
<div class="nav-tab active" @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-container">
|
||||||
|
<TitleComponent title="运维巡检管理" subtitle="制定巡检计划,安排巡检任务,跟进巡检记录"></TitleComponent>
|
||||||
|
<div class="header-actions">
|
||||||
|
<el-button type="primary" class="export-btn">筛选</el-button>
|
||||||
|
<el-button type="primary" class="create-btn">导入数据</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 选项卡和按钮组合 -->
|
||||||
|
<div class="tabs-wrapper">
|
||||||
|
<div style="display: flex; align-items: center; gap: 10px">
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement1">巡检计划</el-button>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement2">巡检任务</el-button>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement3">巡检记录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选栏 -->
|
||||||
|
<div class="filter-bar">
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="filterStatus" placeholder="状态" clearable>
|
||||||
|
<el-option label="全部状态" value="all"></el-option>
|
||||||
|
<el-option label="正常" value="normal"></el-option>
|
||||||
|
<el-option label="需关注" value="attention"></el-option>
|
||||||
|
<el-option label="有问题" value="problem"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="filterType" placeholder="巡检类型" clearable>
|
||||||
|
<el-option label="全部类型" value="all"></el-option>
|
||||||
|
<el-option label="数据库" value="database"></el-option>
|
||||||
|
<el-option label="服务器" value="server"></el-option>
|
||||||
|
<el-option label="网络设备" value="network"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
></el-date-picker>
|
||||||
|
</div>
|
||||||
|
<div class="filter-actions">
|
||||||
|
<el-button type="primary" class="search-btn" @click="fetchDashboardData">搜索</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主内容区 - 使用flex确保等高 -->
|
||||||
|
<div class="main-content-container">
|
||||||
|
<!-- 左侧和中间内容区 -->
|
||||||
|
<div class="left-content">
|
||||||
|
<!-- 巡检记录与报告卡片 -->
|
||||||
|
<div class="content-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2 class="card-title">巡检记录与报告</h2>
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 text-sm rounded-md hover:bg-gray-200 transition"
|
||||||
|
:class="{ 'bg-gray-100 text-gray-700': timeRange === 'month', 'bg-white text-gray-500': timeRange !== 'month' }"
|
||||||
|
@click="handleTimeRangeChange('month')"
|
||||||
|
>
|
||||||
|
月
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 text-sm rounded-md hover:bg-gray-100 transition"
|
||||||
|
:class="{ 'bg-gray-100 text-gray-700': timeRange === 'week', 'bg-white text-gray-500': timeRange !== 'week' }"
|
||||||
|
@click="handleTimeRangeChange('week')"
|
||||||
|
>
|
||||||
|
周
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 text-sm rounded-md hover:bg-gray-100 transition"
|
||||||
|
:class="{ 'bg-gray-100 text-gray-700': timeRange === 'day', 'bg-white text-gray-500': timeRange !== 'day' }"
|
||||||
|
@click="handleTimeRangeChange('day')"
|
||||||
|
>
|
||||||
|
日
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 数据卡片 -->
|
||||||
|
<div class="card-body">
|
||||||
|
<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">{{ completedInspections }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<p class="stat-label">发现问题数</p>
|
||||||
|
<p class="stat-value">{{ totalProblems }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<p class="stat-label">已解决问题</p>
|
||||||
|
<p class="stat-value">{{ solvedProblems }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<p class="stat-label">平均完成时间</p>
|
||||||
|
<p class="stat-value">{{ avgCompletionTime }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
|
||||||
|
<!-- 图表区域 -->
|
||||||
|
<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 ref="pieChartRef" class="pie-chart-container"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 进度条 -->
|
||||||
|
<div class="md:col-span-2 flex flex-col justify-center">
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<div class="flex justify-between text-sm mb-1">
|
||||||
|
<span class="text-gray-600">完成率</span>
|
||||||
|
<span class="font-medium text-gray-800">{{ completionRate }}%</span>
|
||||||
|
</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">{{ resolutionRate }}%</span>
|
||||||
|
</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">{{ timelinessRate }}%</span>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
|
||||||
|
<!-- 发现问题种类 -->
|
||||||
|
<div class="py-4">
|
||||||
|
<h3 class="section-title">发现问题种类</h3>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<div class="flex justify-between text-sm mb-1">
|
||||||
|
<span class="text-gray-600">温度异常率</span>
|
||||||
|
<span class="text-gray-500">{{ problemTypes.temperature }}%</span>
|
||||||
|
</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">{{ problemTypes.memory }}%</span>
|
||||||
|
</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">{{ problemTypes.cpu }}%</span>
|
||||||
|
</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">{{ problemTypes.responseTime }}%</span>
|
||||||
|
</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">{{ problemTypes.diskSpace }}%</span>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧最近巡检结果 -->
|
||||||
|
<div class="right-content">
|
||||||
|
<div class="content-card h-full flex flex-col">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2 class="card-title">最近巡检结果</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 巡检结果列表 - 添加滚动样式 -->
|
||||||
|
<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 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>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-500 mb-3">2025-06-15 14:00-16:45 张明</p>
|
||||||
|
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">系统连接量</span>
|
||||||
|
<span class="text-sm font-medium">128</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">查询响应时间</span>
|
||||||
|
<span class="text-sm font-medium">平均0.3S</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">表空间使用率</span>
|
||||||
|
<span class="text-sm font-medium">75%</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">日志文件</span>
|
||||||
|
<span class="text-sm font-medium">正常轮转</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end gap-2">
|
||||||
|
<el-button size="small" class="text-sm border-gray-300 text-gray-600">查看详情</el-button>
|
||||||
|
<el-button type="primary" size="small" class="text-sm">生成报告</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 结果2:需关注 -->
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-500 mb-3">2025-06-15 14:00-16:45 张明</p>
|
||||||
|
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">CPU使用率</span>
|
||||||
|
<span class="text-sm font-medium">平均35%,峰值59%</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-exclamation-circle text-yellow-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">内存使用率</span>
|
||||||
|
<span class="text-sm font-medium">85%</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">磁盘空间</span>
|
||||||
|
<span class="text-sm font-medium">62%</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">服务状态</span>
|
||||||
|
<span class="text-sm font-medium">正常运行</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-yellow-50 border border-yellow-200 rounded-md p-3 mb-4">
|
||||||
|
<div class="flex items-start">
|
||||||
|
<i class="fas fa-info-circle text-yellow-500 mt-0.5 mr-2"></i>
|
||||||
|
<p class="text-xs text-yellow-800">已创建问题单 #PRB-2023061501,计划于今晚进行内存扩容</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end gap-2">
|
||||||
|
<el-button size="small" class="text-sm border-gray-300 text-gray-600">查看详情</el-button>
|
||||||
|
<el-button type="primary" size="small" class="text-sm">生成报告</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 结果3:有问题 -->
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-500 mb-3">2025-06-14 10:00-11:30 李华</p>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-2 mb-4">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-times-circle text-red-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">防火墙规则</span>
|
||||||
|
<span class="text-sm font-medium">部分规则异常</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-exclamation-circle text-yellow-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">安全补丁</span>
|
||||||
|
<span class="text-sm font-medium">需更新</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">访问控制</span>
|
||||||
|
<span class="text-sm font-medium">正常</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
|
||||||
|
<span class="text-xs text-gray-600 mb-1">流量监控</span>
|
||||||
|
<span class="text-sm font-medium">正常</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end gap-2">
|
||||||
|
<el-button size="small" class="text-sm border-gray-300 text-gray-600">查看详情</el-button>
|
||||||
|
<el-button type="primary" size="small" class="text-sm">生成报告</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, computed, onUnmounted } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './TitleComponent.vue';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
|
||||||
|
// 筛选条件
|
||||||
|
const filterStatus = ref('all');
|
||||||
|
const filterType = ref('all');
|
||||||
|
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;
|
||||||
|
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');
|
||||||
|
};
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement1 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement2 = () => {
|
||||||
|
router.push('/rili/xunjianrenwu');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement3 = () => {
|
||||||
|
router.push('/rili/xunjianjihua');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 主容器样式 */
|
||||||
|
.operation-inspection {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 头部容器 */
|
||||||
|
.header-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导航栏样式 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选项卡样式 */
|
||||||
|
.tabs-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 筛选栏样式 */
|
||||||
|
.filter-bar {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select,
|
||||||
|
.filter-bar .el-date-picker {
|
||||||
|
width: 150px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn,
|
||||||
|
.export-btn,
|
||||||
|
.create-btn {
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 主内容区 - 使用flex确保等高 */
|
||||||
|
.main-content-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
height: calc(100% - 20px);
|
||||||
|
min-height: 500px; /* 确保有最小高度 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-content {
|
||||||
|
flex: 2; /* 左侧占2/3宽度 */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-content {
|
||||||
|
flex: 1; /* 右侧占1/3宽度 */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容卡片样式 */
|
||||||
|
.content-card {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
overflow: hidden;
|
||||||
|
height: 100%; /* 卡片高度占满容器 */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
padding: 20px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: 20px;
|
||||||
|
flex: 1; /* 内容区域占满剩余空间 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 统计卡片样式 */
|
||||||
|
.stat-card {
|
||||||
|
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 {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分隔线 */
|
||||||
|
.divider {
|
||||||
|
height: 1px;
|
||||||
|
background-color: #e4e7ed;
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 图表标题 */
|
||||||
|
.chart-title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 饼图容器 */
|
||||||
|
.pie-chart-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 区域标题 */
|
||||||
|
.section-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0 0 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 状态标签 */
|
||||||
|
.status-tag {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-normal {
|
||||||
|
background-color: #f0f9eb;
|
||||||
|
color: #52c41a;
|
||||||
|
border: 1px solid #e1f3d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-attention {
|
||||||
|
background-color: #fffbe6;
|
||||||
|
color: #faad14;
|
||||||
|
border: 1px solid #fff1b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-problem {
|
||||||
|
background-color: #fff2f0;
|
||||||
|
color: #f5222d;
|
||||||
|
border: 1px solid #ffe3e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条样式优化 */
|
||||||
|
.scrollbar-thin {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: #d1d5db #f3f4f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-track {
|
||||||
|
background: #f3f4f6;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #d1d5db;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: #9ca3af;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.main-content-container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: 0;
|
||||||
|
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>
|
||||||
911
src/views/zhinengxunjian/xunjianrenwu.vue
Normal file
911
src/views/zhinengxunjian/xunjianrenwu.vue
Normal file
@ -0,0 +1,911 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="inspection-tasks">
|
||||||
|
<div class="navigation-tabs">
|
||||||
|
<div class="nav-tab" @click="handleInspection1">待办事项</div>
|
||||||
|
<div class="nav-tab active" @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>
|
||||||
|
<!-- 页面标题 -->
|
||||||
|
<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>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement2">巡检任务</el-button>
|
||||||
|
<el-button type="primary" @click="handleInspectionManagement3">巡检记录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选栏 -->
|
||||||
|
<div class="filter-bar">
|
||||||
|
<div class="filter-container">
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="taskStatus" placeholder="任务状态">
|
||||||
|
<el-option label="待执行" value="pending"></el-option>
|
||||||
|
<el-option label="执行中" value="executing"></el-option>
|
||||||
|
<el-option label="已延期" value="delayed"></el-option>
|
||||||
|
<el-option label="已完成" value="completed"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="planType" placeholder="全部计划">
|
||||||
|
<el-option label="每日巡检计划" value="daily"></el-option>
|
||||||
|
<el-option label="每周巡检计划" value="weekly"></el-option>
|
||||||
|
<el-option label="每月巡检计划" value="monthly"></el-option>
|
||||||
|
<el-option label="每季度巡检计划" value="quarterly"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-item">
|
||||||
|
<el-select v-model="executor" placeholder="执行人">
|
||||||
|
<el-option label="全部人员" value="all"></el-option>
|
||||||
|
<el-option label="张明" value="zhangming"></el-option>
|
||||||
|
<el-option label="李华" value="lihua"></el-option>
|
||||||
|
<el-option label="王强" value="wangqiang"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="filter-actions">
|
||||||
|
<el-button type="primary" class="search-btn">搜索</el-button>
|
||||||
|
<el-button type="primary" icon="el-icon-plus" class="create-btn" @click="handleCreateTask"> 手动创建任务 </el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 任务卡片列表 -->
|
||||||
|
<div class="task-cards">
|
||||||
|
<div class="task-card" v-for="(task, index) in pagedTasks" :key="index">
|
||||||
|
<div class="task-header">
|
||||||
|
<div class="task-title">
|
||||||
|
{{ task.title }}
|
||||||
|
</div>
|
||||||
|
<div class="task-status" :class="task.statusClass">
|
||||||
|
{{ task.statusText }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="task-details">
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">计划时间</span>
|
||||||
|
<span class="detail-value">{{ task.planTime }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">巡检对象</span>
|
||||||
|
<span class="detail-value">{{ task.target }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">执行人</span>
|
||||||
|
<span class="detail-value">{{ task.executor }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">关联计划</span>
|
||||||
|
<span class="detail-value">{{ task.relatedPlan }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 特定状态的额外信息 -->
|
||||||
|
<div v-if="task.status === 'delayed'" class="delay-reason">
|
||||||
|
<span class="detail-label">延期原因</span>
|
||||||
|
<span class="detail-value">{{ task.delayReason }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="task.status === 'executing'" class="progress-container">
|
||||||
|
<span class="detail-label">完成进度</span>
|
||||||
|
<div class="progress-bar">
|
||||||
|
<el-progress :percentage="task.progress" stroke-width="6" :stroke-color="task.progressColor"></el-progress>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="task.status === 'completed'" class="task-result">
|
||||||
|
<span class="detail-label">结果</span>
|
||||||
|
<span class="detail-value" :class="task.resultClass">{{ task.result }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="task-actions">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页区域 -->
|
||||||
|
<div class="pagination-section">
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<el-pagination
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
:current-page="currentPage"
|
||||||
|
:page-sizes="[8, 12, 16, 20]"
|
||||||
|
:page-size="pageSize"
|
||||||
|
layout="prev, pager, next, jumper"
|
||||||
|
:total="total"
|
||||||
|
background
|
||||||
|
>
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 添加新任务弹窗 -->
|
||||||
|
<el-dialog v-model="createTaskDialogVisible" title="添加新任务" width="500px" :before-close="handleCancelCreateTask">
|
||||||
|
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="80px">
|
||||||
|
<el-form-item label="任务名称" prop="taskName">
|
||||||
|
<el-input v-model="createTaskForm.taskName" placeholder="输入任务名称" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="巡检对象" prop="inspectionTarget">
|
||||||
|
<el-input v-model="createTaskForm.inspectionTarget" placeholder="输入巡检内容" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="时间" prop="timeRange">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="createTaskForm.timeRange"
|
||||||
|
type="datetimerange"
|
||||||
|
start-placeholder="开始时间"
|
||||||
|
end-placeholder="结束时间"
|
||||||
|
format="YYYY-MM-DD HH:mm"
|
||||||
|
value-format="YYYY-MM-DD HH:mm"
|
||||||
|
placeholder="选择时间范围"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="关联计划">
|
||||||
|
<el-select v-model="createTaskForm.relatedPlan" placeholder="选择关联计划">
|
||||||
|
<el-option label="全部计划" value="all" />
|
||||||
|
<el-option label="每日巡检计划" value="daily" />
|
||||||
|
<el-option label="每周巡检计划" value="weekly" />
|
||||||
|
<el-option label="每月巡检计划" value="monthly" />
|
||||||
|
<el-option label="每季度巡检计划" value="quarterly" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="执行人">
|
||||||
|
<el-select v-model="createTaskForm.executor" placeholder="选择执行人">
|
||||||
|
<el-option label="全部人员" value="all" />
|
||||||
|
<el-option label="张明" value="zhangming" />
|
||||||
|
<el-option label="李华" value="lihua" />
|
||||||
|
<el-option label="王强" value="wangqiang" />
|
||||||
|
<el-option label="赵伟" value="zhaowei" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="handleCancelCreateTask">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSaveTask">保存任务</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import router from '@/router';
|
||||||
|
import TitleComponent from './TitleComponent.vue';
|
||||||
|
|
||||||
|
// 激活的选项卡
|
||||||
|
const activeTab = ref('task');
|
||||||
|
|
||||||
|
// 筛选条件
|
||||||
|
const taskStatus = ref('');
|
||||||
|
const planType = ref('');
|
||||||
|
const executor = ref('');
|
||||||
|
|
||||||
|
// 任务数据
|
||||||
|
const tasks = ref([
|
||||||
|
{
|
||||||
|
title: '生产服务器日常巡检',
|
||||||
|
status: 'pending',
|
||||||
|
statusText: '待执行',
|
||||||
|
statusClass: 'status-pending',
|
||||||
|
planTime: '2025-06-16 08:30',
|
||||||
|
target: '生产服务器集群(12台)',
|
||||||
|
executor: '张明',
|
||||||
|
relatedPlan: '每日巡检计划',
|
||||||
|
actionText: '开始执行',
|
||||||
|
actionClass: 'start-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '机房环境检查',
|
||||||
|
status: 'delayed',
|
||||||
|
statusText: '已延期',
|
||||||
|
statusClass: 'status-delayed',
|
||||||
|
planTime: '2025-06-16 08:30',
|
||||||
|
target: '机房温度、湿度、电源',
|
||||||
|
executor: '李华',
|
||||||
|
relatedPlan: '每周巡检计划',
|
||||||
|
delayReason: '设备维修处理中',
|
||||||
|
actionText: '重新安排',
|
||||||
|
actionClass: 'reschedule-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '网络设备安全巡检',
|
||||||
|
status: 'executing',
|
||||||
|
statusText: '执行中',
|
||||||
|
statusClass: 'status-executing',
|
||||||
|
planTime: '2025-06-16 09:30',
|
||||||
|
target: '核心交换机、防火墙',
|
||||||
|
executor: '王强',
|
||||||
|
relatedPlan: '每周巡检计划',
|
||||||
|
progress: 60,
|
||||||
|
progressColor: '#FF7D00',
|
||||||
|
actionText: '完成',
|
||||||
|
actionClass: 'complete-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '数据库性能巡检',
|
||||||
|
status: 'completed',
|
||||||
|
statusText: '已完成',
|
||||||
|
statusClass: 'status-completed',
|
||||||
|
planTime: '2025-06-16 10:30',
|
||||||
|
target: '生产数据库集群(2组)',
|
||||||
|
executor: '赵伟',
|
||||||
|
relatedPlan: '每月巡检计划',
|
||||||
|
result: '正常',
|
||||||
|
resultClass: 'result-normal',
|
||||||
|
actionText: '查看报告',
|
||||||
|
actionClass: 'report-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '生产服务器日常巡检',
|
||||||
|
status: 'pending',
|
||||||
|
statusText: '待执行',
|
||||||
|
statusClass: 'status-pending',
|
||||||
|
planTime: '2025-06-16 13:30',
|
||||||
|
target: '生产服务器集群(12台)',
|
||||||
|
executor: '张明',
|
||||||
|
relatedPlan: '每日巡检计划',
|
||||||
|
actionText: '开始执行',
|
||||||
|
actionClass: 'start-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '机房环境检查',
|
||||||
|
status: 'delayed',
|
||||||
|
statusText: '已延期',
|
||||||
|
statusClass: 'status-delayed',
|
||||||
|
planTime: '2025-06-16 14:00',
|
||||||
|
target: '机房温度、湿度、电源',
|
||||||
|
executor: '李华',
|
||||||
|
relatedPlan: '每周巡检计划',
|
||||||
|
delayReason: '设备维修处理中',
|
||||||
|
actionText: '重新安排',
|
||||||
|
actionClass: 'reschedule-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '网络设备安全巡检',
|
||||||
|
status: 'executing',
|
||||||
|
statusText: '执行中',
|
||||||
|
statusClass: 'status-executing',
|
||||||
|
planTime: '2025-06-16 15:00',
|
||||||
|
target: '核心交换机、防火墙',
|
||||||
|
executor: '王强',
|
||||||
|
relatedPlan: '每周巡检计划',
|
||||||
|
progress: 35,
|
||||||
|
progressColor: '#FF7D00',
|
||||||
|
actionText: '完成',
|
||||||
|
actionClass: 'complete-btn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '数据库性能巡检',
|
||||||
|
status: 'completed',
|
||||||
|
statusText: '已完成',
|
||||||
|
statusClass: 'status-completed',
|
||||||
|
planTime: '2025-06-16 16:00',
|
||||||
|
target: '生产数据库集群(2组)',
|
||||||
|
executor: '赵伟',
|
||||||
|
relatedPlan: '每月巡检计划',
|
||||||
|
result: '正常',
|
||||||
|
resultClass: 'result-normal',
|
||||||
|
actionText: '查看报告',
|
||||||
|
actionClass: 'report-btn'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 分页相关
|
||||||
|
const currentPage = ref(1);
|
||||||
|
const pageSize = ref(8);
|
||||||
|
const total = ref(tasks.value.length);
|
||||||
|
|
||||||
|
// 状态排序映射
|
||||||
|
const statusOrder = {
|
||||||
|
pending: 0, // 待完成
|
||||||
|
delayed: 1, // 已延期
|
||||||
|
executing: 2, // 执行中
|
||||||
|
completed: 3 // 已完成
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页处理后的数据(含排序)
|
||||||
|
const pagedTasks = computed(() => {
|
||||||
|
// 先按状态排序
|
||||||
|
const sortedTasks = [...tasks.value].sort((a, b) => {
|
||||||
|
return statusOrder[a.status] - statusOrder[b.status];
|
||||||
|
});
|
||||||
|
|
||||||
|
// 再进行分页
|
||||||
|
const startIndex = (currentPage.value - 1) * pageSize.value;
|
||||||
|
const endIndex = startIndex + pageSize.value;
|
||||||
|
return sortedTasks.slice(startIndex, endIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {
|
||||||
|
currentPage.value = 1; // 重置到第一页
|
||||||
|
// 实际应用中这里会根据筛选条件过滤数据
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建任务弹窗相关
|
||||||
|
const createTaskDialogVisible = ref(false);
|
||||||
|
const createTaskForm = ref({
|
||||||
|
taskName: '',
|
||||||
|
inspectionTarget: '',
|
||||||
|
timeRange: [],
|
||||||
|
relatedPlan: 'all',
|
||||||
|
executor: 'all'
|
||||||
|
});
|
||||||
|
|
||||||
|
const createTaskRules = {
|
||||||
|
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
|
||||||
|
inspectionTarget: [{ required: true, message: '请输入巡检对象', trigger: 'blur' }],
|
||||||
|
timeRange: [{ required: true, message: '请选择时间范围', trigger: 'change' }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建任务
|
||||||
|
const handleCreateTask = () => {
|
||||||
|
createTaskDialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存任务
|
||||||
|
const handleSaveTask = () => {
|
||||||
|
// 模拟保存任务逻辑
|
||||||
|
console.log('保存任务:', createTaskForm.value);
|
||||||
|
// 关闭弹窗
|
||||||
|
createTaskDialogVisible.value = false;
|
||||||
|
// 重置表单
|
||||||
|
createTaskForm.value = {
|
||||||
|
taskName: '',
|
||||||
|
inspectionTarget: '',
|
||||||
|
timeRange: [],
|
||||||
|
relatedPlan: 'all',
|
||||||
|
executor: 'all'
|
||||||
|
};
|
||||||
|
// 这里可以添加成功提示和刷新任务列表的逻辑
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消创建任务
|
||||||
|
const handleCancelCreateTask = () => {
|
||||||
|
createTaskDialogVisible.value = false;
|
||||||
|
// 重置表单
|
||||||
|
createTaskForm.value = {
|
||||||
|
taskName: '',
|
||||||
|
inspectionTarget: '',
|
||||||
|
timeRange: [],
|
||||||
|
relatedPlan: 'all',
|
||||||
|
executor: 'all'
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页事件
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pageSize.value = val;
|
||||||
|
currentPage.value = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
currentPage.value = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查看任务详情
|
||||||
|
const handleView = (task) => {
|
||||||
|
console.log('查看任务详情:', task);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspectionManagement1 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInspectionManagement2 = () => {
|
||||||
|
router.push('/rili/xunjianrenwu');
|
||||||
|
};
|
||||||
|
const handleInspectionManagement3 = () => {
|
||||||
|
router.push('/rili/xunjianjihua');
|
||||||
|
};
|
||||||
|
const handleInspection1 = () => {
|
||||||
|
router.push('/rili/rili');
|
||||||
|
};
|
||||||
|
const handleInspection2 = () => {
|
||||||
|
router.push('/rili/InspectionManagement');
|
||||||
|
};
|
||||||
|
const handleInspection3 = () => {
|
||||||
|
router.push('/rili/shiyanguanli');
|
||||||
|
};
|
||||||
|
const handleInspection4 = () => {
|
||||||
|
router.push('/rili/baoxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection5 = () => {
|
||||||
|
router.push('/rili/qiangxiuguanli');
|
||||||
|
};
|
||||||
|
const handleInspection6 = () => {
|
||||||
|
router.push('/rili/gongdanliebiao');
|
||||||
|
};
|
||||||
|
const handleInspection7 = () => {
|
||||||
|
router.push('/rili/renyuanzhuangtai');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.inspection-tasks {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选项卡样式 */
|
||||||
|
.tabs-wrapper {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs {
|
||||||
|
border-bottom: none;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__header {
|
||||||
|
margin: 0 -20px 0 -20px;
|
||||||
|
padding: 0 20px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__nav-wrap::after {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
padding: 12px 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item.is-active {
|
||||||
|
color: #409eff;
|
||||||
|
border-bottom-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item:hover {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
/* 筛选栏样式 */
|
||||||
|
.filter-bar {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 16px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select {
|
||||||
|
width: 180px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select .el-input__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
border-color: #dcdfe6;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select .el-input__inner:focus {
|
||||||
|
border-color: #165dff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
background-color: #f2f3f5;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #f2f3f5;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn:hover {
|
||||||
|
background-color: #e5e6eb;
|
||||||
|
color: #303133;
|
||||||
|
border-color: #e5e6eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-btn {
|
||||||
|
background-color: #165dff;
|
||||||
|
border-color: #165dff;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-btn:hover {
|
||||||
|
background-color: #0e42d2;
|
||||||
|
border-color: #0e42d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 任务卡片样式 */
|
||||||
|
.task-cards {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 16px 16px 60px 16px; /* 底部留出更多空间给按钮 */
|
||||||
|
transition: box-shadow 0.2s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 280px; /* 确保有足够高度显示所有内容 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #f0f2f5;
|
||||||
|
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 {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card.status-pending::before {
|
||||||
|
background-color: #1677ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card.status-delayed::before {
|
||||||
|
background-color: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card.status-executing::before {
|
||||||
|
background-color: #fa8c16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card.status-completed::before {
|
||||||
|
background-color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-card:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1d2129;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-status {
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 待执行状态 - 蓝色 */
|
||||||
|
.status-pending {
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
color: #1677ff;
|
||||||
|
border-color: #91d5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 已延期状态 - 红色 */
|
||||||
|
.status-delayed {
|
||||||
|
background-color: #fff2f0;
|
||||||
|
color: #ff4d4f;
|
||||||
|
border-color: #ffccc7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 执行中状态 - 黄色 */
|
||||||
|
.status-executing {
|
||||||
|
background-color: #fffbe6;
|
||||||
|
color: #fa8c16;
|
||||||
|
border-color: #ffe58f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 已完成状态 - 绿色 */
|
||||||
|
.status-completed {
|
||||||
|
background-color: #f6ffed;
|
||||||
|
color: #52c41a;
|
||||||
|
border-color: #b7eb8f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-details {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-label {
|
||||||
|
flex: 0 0 80px;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-value {
|
||||||
|
flex: 1;
|
||||||
|
color: #4e5969;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delay-reason {
|
||||||
|
display: flex;
|
||||||
|
margin: 10px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px dashed #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 10px 0;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px dashed #f0f2f5;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
flex: 1;
|
||||||
|
padding-left: 80px;
|
||||||
|
margin-top: 4px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-result {
|
||||||
|
display: flex;
|
||||||
|
margin: 10px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px dashed #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-normal {
|
||||||
|
color: #00b42a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-abnormal {
|
||||||
|
color: #f53f3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #f0f2f5;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 16px;
|
||||||
|
right: 16px;
|
||||||
|
left: 16px;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 12px 0 0 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-btn {
|
||||||
|
color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-btn:hover {
|
||||||
|
color: #0e42d2;
|
||||||
|
background-color: #e8f3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-btn {
|
||||||
|
background-color: #165dff;
|
||||||
|
border-color: #165dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-btn:hover {
|
||||||
|
background-color: #0e42d2;
|
||||||
|
border-color: #0e42d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reschedule-btn {
|
||||||
|
background-color: #ff7d00;
|
||||||
|
border-color: #ff7d00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reschedule-btn:hover {
|
||||||
|
background-color: #e86a00;
|
||||||
|
border-color: #e86a00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.complete-btn {
|
||||||
|
background-color: #00b42a;
|
||||||
|
border-color: #00b42a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.complete-btn:hover {
|
||||||
|
background-color: #008718;
|
||||||
|
border-color: #008718;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-btn {
|
||||||
|
background-color: #86909c;
|
||||||
|
border-color: #86909c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-btn:hover {
|
||||||
|
background-color: #6b7785;
|
||||||
|
border-color: #6b7785;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分页区域样式 */
|
||||||
|
.pagination-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination button,
|
||||||
|
.pagination-controls .el-pagination .el-pager li {
|
||||||
|
min-width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls .el-pagination .el-pager li.active {
|
||||||
|
background-color: #165dff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.task-cards {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.inspection-tasks {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-actions {
|
||||||
|
margin-left: 0;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .el-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-cards {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 导航栏样式 */
|
||||||
|
.navigation-tabs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
border-right: 1px solid #f0f0f0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab.active {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tab {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1112
src/views/zhinengxunjian/zhixingjilu.vue
Normal file
1112
src/views/zhinengxunjian/zhixingjilu.vue
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user