Files
maintenance_system/src/views/zhinengxunjian/shiyanrenwu.vue
2025-09-17 20:03:00 +08:00

801 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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" :class="task.cardClass">
<div class="task-header">
<div class="task-title">
{{ task.title }}
</div>
<div class="task-status" :class="task.tagClass">
<!-- 标签专用类名控制标签样式 -->
{{ 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: '待执行',
cardClass: 'card-pending', // 卡片专用类(控制阴影和左侧线)
tagClass: 'tag-pending', // 标签专用类(控制标签样式)
planTime: '2025-06-16 08:30',
target: '生产服务器集群(12台)',
executor: '张明',
relatedPlan: '每日巡检计划',
actionText: '开始执行',
actionClass: 'start-btn'
},
{
title: '机房环境检查',
status: 'delayed',
statusText: '已延期',
cardClass: 'card-delayed',
tagClass: 'tag-delayed',
planTime: '2025-06-16 08:30',
target: '机房温度、湿度、电源',
executor: '李华',
relatedPlan: '每周巡检计划',
delayReason: '设备维修处理中',
actionText: '重新安排',
actionClass: 'reschedule-btn'
},
{
title: '网络设备安全巡检',
status: 'executing',
statusText: '执行中',
cardClass: 'card-executing',
tagClass: 'tag-executing',
planTime: '2025-06-16 09:30',
target: '核心交换机、防火墙',
executor: '王强',
relatedPlan: '每周巡检计划',
progress: 60,
progressColor: '#FF7D00',
actionText: '完成',
actionClass: 'complete-btn'
},
{
title: '数据库性能巡检',
status: 'completed',
statusText: '已完成',
cardClass: 'card-completed',
tagClass: 'tag-completed',
planTime: '2025-06-16 10:30',
target: '生产数据库集群(2组)',
executor: '赵伟',
relatedPlan: '每月巡检计划',
result: '正常',
resultClass: 'result-normal',
actionText: '查看报告',
actionClass: 'report-btn'
},
{
title: '生产服务器日常巡检',
status: 'pending',
statusText: '待执行',
cardClass: 'card-pending',
tagClass: 'tag-pending',
planTime: '2025-06-16 13:30',
target: '生产服务器集群(12台)',
executor: '张明',
relatedPlan: '每日巡检计划',
actionText: '开始执行',
actionClass: 'start-btn'
},
{
title: '机房环境检查',
status: 'delayed',
statusText: '已延期',
cardClass: 'card-delayed',
tagClass: 'tag-delayed',
planTime: '2025-06-16 14:00',
target: '机房温度、湿度、电源',
executor: '李华',
relatedPlan: '每周巡检计划',
delayReason: '设备维修处理中',
actionText: '重新安排',
actionClass: 'reschedule-btn'
},
{
title: '网络设备安全巡检',
status: 'executing',
statusText: '执行中',
cardClass: 'card-executing',
tagClass: 'tag-executing',
planTime: '2025-06-16 15:00',
target: '核心交换机、防火墙',
executor: '王强',
relatedPlan: '每周巡检计划',
progress: 35,
progressColor: '#FF7D00',
actionText: '完成',
actionClass: 'complete-btn'
},
{
title: '数据库性能巡检',
status: 'completed',
statusText: '已完成',
cardClass: 'card-completed',
tagClass: 'tag-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);
}
/* 筛选栏样式 */
.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: 10px;
}
.search-btn {
background-color: #f2f3f5;
color: #303133;
border-color: #f2f3f5;
transition: all 0.2s ease;
}
.create-btn {
background-color: #165dff;
border-color: #165dff;
transition: all 0.2s ease;
}
/* 任务卡片样式 */
.task-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.task-card {
background-color: #fff; /* 确保卡片背景始终为白色 */
border-radius: 8px;
padding: 16px 16px 60px 24px; /* 左侧留空间给状态线 */
position: relative;
overflow: hidden;
min-height: 280px;
transition: all 0.3s ease;
}
/* 卡片左侧状态竖线 - 仅用于左侧标识 */
.task-card::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 6px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.05);
}
/* 卡片阴影样式 - 与状态关联但不影响背景色 */
.card-pending {
box-shadow: 0 4px 16px rgba(22, 119, 255, 0.15);
}
.card-delayed {
box-shadow: 0 4px 16px rgba(255, 77, 79, 0.15);
}
.card-executing {
box-shadow: 0 4px 16px rgba(250, 140, 22, 0.15);
}
.card-completed {
box-shadow: 0 4px 16px rgba(82, 196, 26, 0.15);
}
/* 左侧状态线颜色 */
.card-pending::before {
background-color: #1677ff;
}
.card-delayed::before {
background-color: #ff4d4f;
}
.card-executing::before {
background-color: #fa8c16;
}
.card-completed::before {
background-color: #52c41a;
}
/* 卡片悬停效果 */
.task-card:hover {
transform: translateY(-3px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1), 0 4px 16px rgba(0, 0, 0, 0.05);
}
.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;
}
.tag-pending {
background-color: #e6f7ff;
color: #1677ff;
border-color: #91d5ff;
}
.tag-delayed {
background-color: #fff2f0;
color: #ff4d4f;
border-color: #ffccc7;
}
.tag-executing {
background-color: #fffbe6;
color: #fa8c16;
border-color: #ffe58f;
}
.tag-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;
}
.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;
}
.start-btn {
background-color: #165dff;
border-color: #165dff;
}
.reschedule-btn {
background-color: #ff7d00;
border-color: #ff7d00;
}
.complete-btn {
background-color: #00b42a;
border-color: #00b42a;
}
.report-btn {
background-color: #86909c;
border-color: #86909c;
}
/* 分页区域样式 */
.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);
}
/* 响应式设计 */
@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;
}
.task-cards {
grid-template-columns: 1fr;
}
}
</style>