This commit is contained in:
tcy
2025-09-15 10:06:05 +08:00
30 changed files with 12953 additions and 134 deletions

View File

@ -7,11 +7,11 @@ VITE_APP_ENV = 'development'
# 开发环境
# VITE_APP_BASE_API = 'http://192.168.110.180:8899'
# 李陈杰 209
VITE_APP_BASE_API = 'http://192.168.110.209:8899'
VITE_APP_BASE_API = 'http://192.168.110.180:8899'
# 李陈杰 209
VITE_APP_BASE_API = 'http://192.168.110.209:8899'
# 曾涛
# VITE_APP_BASE_API = 'http://192.168.110.209:8899'
# 曾涛
# VITE_APP_BASE_API = 'http://192.168.110.149:8899'
# 罗成
# VITE_APP_BASE_API = 'http://192.168.110.188:8899'
# 朱银

Binary file not shown.

Binary file not shown.

View File

@ -186,7 +186,7 @@ export const dowloadConstructionUserTemplate = (query: ConstructionUserTemplateF
*/
export const delConstructionUserMember = (data: ConstructionUserMembeForm) => {
return request({
url: '/contractor/projectTeamMember/',
url: '/project/projectTeamMember/',
method: 'delete',
data
});

View File

@ -170,6 +170,7 @@ async function getVersionNums(isSheet = true) {
state.loading.versions = true;
state.error = null;
console.log('🚀 ~ handleSheetName ~ currentProject.value?.id:', currentProject.value?.id);
const res = await obtainAllVersionNumbers({
projectId: currentProject.value?.id,
workOrderType: state.work_order_type,
@ -375,6 +376,16 @@ const downloadTemplate = (type) => {
alert('下载失败,请重试');
}
};
const resetState = () => {
state.tableData = [];
state.options = [];
state.sheets = [];
state.queryForm.versions = '';
state.queryForm.sheet = '';
state.versionsData = {};
state.error = null;
isExpandAll.value = true;
};
onMounted(async () => {
await getVersionNums();
});
@ -382,6 +393,8 @@ onMounted(async () => {
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
resetState();
state.queryForm.projectId = nid;
getVersionNums();
}
);

View File

@ -4,10 +4,11 @@
<div class="navigation-tabs">
<div class="nav-tab" @click="handleInspection1">待办事项</div>
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</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>
@ -486,6 +487,21 @@ const handleInspection1 = () => {
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');
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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 '@/views/demo/components/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>

View File

@ -0,0 +1,700 @@
<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="stat-item total">
<div class="stat-value">{{ totalVehicles }}</div>
<div class="stat-label">总车辆数</div>
<div class="stat-desc">所有运维车辆总数</div>
</div>
<div class="stat-item available">
<div class="stat-value">{{ availableVehicles }}</div>
<div class="stat-label">可用车辆</div>
<div class="stat-desc">可立即调度</div>
</div>
<div class="stat-item in-use">
<div class="stat-value">{{ inUseVehicles }}</div>
<div class="stat-label">使用中</div>
<div class="stat-desc">执行任务中</div>
</div>
<div class="stat-item maintenance">
<div class="stat-value">{{ maintenanceVehicles }}</div>
<div class="stat-label">维修/保养</div>
<div class="stat-desc">预计2天后可使用</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 '@/views/demo/components/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 {
background-color: rgba(255, 255, 255, 0.95);
border-radius: 12px;
padding: 20px 28px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
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;
}
.stat-item.total .stat-value {
color: #303133;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.stat-item.available .stat-value {
color: #52c41a;
text-shadow: 0 2px 4px rgba(82, 196, 26, 0.2);
}
.stat-item.in-use .stat-value {
color: #fa8c16;
text-shadow: 0 2px 4px rgba(250, 140, 22, 0.2);
}
.stat-item.maintenance .stat-value {
color: #faad14;
text-shadow: 0 2px 4px rgba(250, 173, 20, 0.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;
}
/* 导航栏样式 */
.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;
gap: 16px;
}
.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;
gap: 20px;
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>

File diff suppressed because it is too large Load Diff

View File

@ -4,10 +4,11 @@
<div class="navigation-tabs">
<div class="nav-tab active" @click="handleInspection1">待办事项</div>
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</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>
<!-- 标题栏 -->
@ -310,6 +311,21 @@ const handleInspection1 = () => {
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>

View 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 '@/views/demo/components/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>

View 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" @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" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button>
<el-button type="primary" size="small" :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">支持JPGPNG格式最多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 '@/views/demo/components/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: 16px;
border-top: 1px solid #f0f2f5;
margin-top: auto; /* 自动推到最底部 */
gap: 8px;
}
.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>

View 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 '@/views/demo/components/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>

View File

@ -0,0 +1,866 @@
<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>
<div class="chart-container">
<div class="gauge-chart">
<div class="doughnut-chart">
<!-- 动态镂空环形图 -->
<svg width="200" height="200" viewBox="0 0 200 200">
<!-- 环形背景 -->
<circle cx="100" cy="100" r="70" fill="none" stroke="#f0f2f5" stroke-width="12" class="background-circle" />
<!-- 在线可用部分 - 动态显示 -->
<circle
cx="100"
cy="100"
r="70"
fill="none"
stroke="#165dff"
stroke-width="12"
stroke-linecap="round"
:stroke-dasharray="circumference"
:stroke-dashoffset="onlineOffset"
transform="rotate(-90 100 100)"
class="progress-circle online-progress"
/>
<!-- 离线休息部分 - 动态显示 -->
<circle
cx="100"
cy="100"
r="70"
fill="none"
stroke="#40c9c6"
stroke-width="12"
stroke-linecap="round"
:stroke-dasharray="circumference"
:stroke-dashoffset="offlineOffset"
transform="rotate(-90 100 100)"
class="progress-circle offline-progress"
/>
</svg>
<div class="gauge-text">
<div class="gauge-percentage">{{ onlineRate }}%</div>
<div class="gauge-label">在线可用率</div>
</div>
</div>
</div>
<div class="chart-legend">
<div class="legend-item">
<span class="legend-color online"></span>
<span class="legend-text">在线可用人数 ({{ availablePersonnel }})</span>
</div>
<div class="legend-item">
<span class="legend-color offline"></span>
<span class="legend-text">离线休息人数 ({{ restingPersonnel }})</span>
</div>
</div>
</div>
<div class="stats-grid">
<div class="stat-item">
<div class="stat-value">{{ totalPersonnel }}</div>
<div class="stat-label">总人数</div>
<div class="stat-change">+2</div>
</div>
<div class="stat-item">
<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">
<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="scrollable-content">
<div class="personnel-grid">
<div v-for="(person, index) in personnelList" :key="index" class="person-card">
<div class="person-header">
<div class="avatar">
<img :src="person.avatar" alt="头像" class="avatar-img" />
<div class="status-indicator" :class="person.statusClass"></div>
</div>
<div class="person-info">
<div class="person-name">{{ person.name }}</div>
<div class="person-status">{{ person.statusText }}</div>
</div>
</div>
<div class="person-details">
<div class="detail-item">工号: {{ person.id }}</div>
<div class="detail-item">岗位: {{ person.position }}</div>
<div class="detail-item">班组: {{ person.team }}</div>
<div class="detail-item">今日完成: {{ person.completedTasks }}</div>
<div class="detail-item" v-if="person.currentTask">当前任务: {{ person.currentTask }}</div>
<div class="detail-item" v-else>当前任务: </div>
</div>
<div class="person-actions">
<el-button type="text" @click="viewDetails(person)" size="small" class="detail-btn">详情</el-button>
<el-button type="text" @click="assignTask(person)" size="small" class="assign-btn">指派</el-button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, watch } from 'vue';
import router from '@/router';
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
// 激活的选项卡
const activeTab = ref('personnel');
// 统计数据
const totalPersonnel = ref(36);
const availablePersonnel = ref(18);
const workingPersonnel = ref(12);
const restingPersonnel = ref(6);
const onlineRate = ref(82);
// 环形图相关计算
const radius = 70;
const circumference = 2 * Math.PI * radius;
const onlineOffset = ref(circumference - (onlineRate.value / 100) * circumference);
const offlineOffset = ref(circumference - ((100 - onlineRate.value) / 100) * circumference);
// 监听onlineRate变化更新环形图
watch(onlineRate, (newRate) => {
onlineOffset.value = circumference - (newRate / 100) * circumference;
offlineOffset.value = circumference - ((100 - newRate) / 100) * circumference;
});
// 人员列表数据
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 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;
}
.gauge-chart {
width: 200px;
height: 200px;
position: relative;
}
.doughnut-chart {
width: 100%;
height: 100%;
position: relative;
}
.gauge-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.gauge-percentage {
font-size: 36px;
font-weight: 700;
color: #165dff;
line-height: 1;
}
.gauge-label {
font-size: 15px;
color: #606266;
margin-top: 6px;
font-weight: 500;
}
/* 环形图动画效果 */
.background-circle {
stroke: #f0f2f5;
}
.progress-circle {
transition: stroke-dashoffset 1s ease-in-out;
}
.online-progress {
stroke: #165dff;
filter: drop-shadow(0 0 6px rgba(22, 93, 255, 0.2));
}
.offline-progress {
stroke: #40c9c6;
filter: drop-shadow(0 0 6px rgba(64, 201, 198, 0.2));
}
/* 图例样式 */
.chart-legend {
margin-top: 16px;
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
}
.legend-color {
width: 12px;
height: 12px;
border-radius: 4px;
flex-shrink: 0;
}
.legend-color.online {
background-color: #165dff;
box-shadow: 0 2px 4px rgba(22, 93, 255, 0.3);
}
.legend-color.offline {
background-color: #40c9c6;
box-shadow: 0 2px 4px rgba(64, 201, 198, 0.3);
}
.legend-text {
font-size: 13px;
color: #606266;
font-weight: 500;
}
/* 统计网格 */
.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;
}
.scrollable-content {
max-height: calc(100vh - 340px);
overflow-y: auto;
padding: 28px;
}
/* 增强内容区域标题样式 */
.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(auto-fill, minmax(280px, 1fr));
gap: 20px;
}
.person-card {
border: 1px solid #f0f0f0;
border-radius: 12px;
padding: 20px;
transition: all 0.3s ease;
background-color: #ffffff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.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: 20px;
}
.avatar {
position: relative;
width: 64px;
height: 64px;
margin-right: 16px;
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: 18px;
height: 18px;
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: 18px;
font-weight: 600;
color: #2c3e50;
margin-bottom: 6px;
line-height: 1.2;
}
.person-status {
font-size: 13px;
padding: 3px 10px;
border-radius: 15px;
display: inline-block;
font-weight: 500;
}
.person-status.online {
background-color: #f6ffed;
color: #52c41a;
}
.person-status.working {
background-color: #e8f3ff;
color: #165dff;
}
.person-status.offline {
background-color: #f5f5f5;
color: #909399;
}
.person-details {
margin-bottom: 20px;
border-top: 1px dashed #f0f0f0;
padding-top: 16px;
}
.detail-item {
font-size: 13px;
color: #606266;
margin-bottom: 10px;
line-height: 1.6;
}
.detail-item:last-child {
margin-bottom: 0;
}
.person-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
border-top: 1px dashed #f0f0f0;
padding-top: 16px;
}
/* 美化按钮样式 */
.detail-btn,
.assign-btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 6px 16px;
border-radius: 6px;
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;
}
}
</style>

File diff suppressed because it is too large Load Diff

View 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 '@/views/demo/components/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>

View File

@ -0,0 +1,907 @@
<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" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button>
<el-button type="primary" size="small" :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 '@/views/demo/components/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: 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-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>

View File

@ -3,14 +3,15 @@
<div class="navigation-tabs">
<div class="nav-tab" @click="handleInspection1">待办事项</div>
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</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 style="display: flex; align-items: center; gap: 1200px">
<div class="header-container">
<TitleComponent title="运维巡检管理" subtitle="制定巡检计划,安排巡检任务,跟进巡检记录"></TitleComponent>
<div style="display: flex; align-items: center; gap: 10px">
<div class="header-actions">
<el-button type="primary" class="export-btn">筛选</el-button>
<el-button type="primary" class="create-btn">导入数据</el-button>
</div>
@ -58,10 +59,10 @@
</div>
</div>
<!-- 主内容区 -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6" style="grid-auto-rows: 1fr">
<!-- 主内容区 - 使用flex确保等高 -->
<div class="main-content-container">
<!-- 左侧和中间内容区 -->
<div class="lg:col-span-2 space-y-6">
<div class="left-content">
<!-- 巡检记录与报告卡片 -->
<div class="content-card">
<div class="card-header">
@ -260,14 +261,14 @@
</div>
<!-- 右侧最近巡检结果 -->
<div class="lg:col-span-1" style="display: flex; flex-direction: column; height: 100%">
<div class="content-card" style="flex: 1; display: flex; flex-direction: column">
<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" style="flex: 1; overflow-y: auto">
<!-- 巡检结果列表 - 添加滚动样式 -->
<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">
@ -281,7 +282,7 @@
<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<500</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>
@ -421,6 +422,21 @@ const handleInspection1 = () => {
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');
};
@ -440,6 +456,19 @@ const handleInspectionManagement3 = () => {
min-height: 100vh;
}
/* 头部容器 - 替换了固定gap的flex布局 */
.header-container {
display: flex;
justify-content: space-between;
align-items: center;
}
.header-actions {
display: flex;
align-items: center;
gap: 10px;
}
/* 导航栏样式 */
.navigation-tabs {
display: flex;
@ -527,12 +556,35 @@ const handleInspectionManagement3 = () => {
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 {
@ -552,6 +604,7 @@ const handleInspectionManagement3 = () => {
.card-body {
padding: 0 20px;
flex: 1; /* 内容区域占满剩余空间 */
}
/* 统计卡片样式 */
@ -657,8 +710,36 @@ const handleInspectionManagement3 = () => {
background-color: #ecf5ff;
}
/* 滚动条样式优化 */
.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;

View File

@ -4,10 +4,11 @@
<div class="navigation-tabs">
<div class="nav-tab" @click="handleInspection1">待办事项</div>
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</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>
@ -49,7 +50,7 @@
</el-select>
</div>
<div class="filter-actions">
<el-button type="primary" class="search-btn" @click="handleSearch"> <i class="el-icon-search mr-1"></i>搜索 </el-button>
<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>
@ -422,6 +423,21 @@ const handleInspection1 = () => {
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/运维组织');
};
</script>
<style scoped>
@ -511,8 +527,7 @@ const handleInspection2 = () => {
.filter-actions {
margin-left: auto;
display: flex;
gap: 12px;
flex-shrink: 0;
gap: 10px;
}
.search-btn {

File diff suppressed because it is too large Load Diff

View File

@ -421,6 +421,7 @@ const handleDetail = async (row?: PurchaseDocVO) => {
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
planList.value = [];
purchaseDocFormRef.value?.resetFields();
form.value.projectId = currentProject.value?.id;
};
@ -494,7 +495,7 @@ const submitForm = () => {
purchaseDocFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
form.value.associationList = selectPlanList.value;
form.value.associationList = JSON.parse(JSON.stringify(selectPlanList.value));
form.value.associationList.forEach((item: any) => {
item.planId = item.id;
delete item.id;

View File

@ -1,14 +1,12 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="请选择项目:" prop="pid" label-width="100">
<el-select v-model="queryParams.projectId" placeholder="请选择" @change="handleChange" clearable>
<el-option v-for="item in matrixOptions" :key="item.projectId" :label="item.name"
:value="item.projectId" />
<el-option v-for="item in matrixOptions" :key="item.projectId" :label="item.name" :value="item.projectId" />
</el-select>
</el-form-item>
<el-form-item label="请选择方阵:" prop="pid" label-width="100" v-if="relevancyStructure == '2'">
@ -23,14 +21,23 @@
<el-tabs type="border-card" v-model="activeTab" @tab-click="handleTabClick">
<el-tab-pane :label="item.name" v-for="item in tabList" :key="item.id" :name="item.id"></el-tab-pane>
<el-card shadow="never">
<el-table ref="progressCategoryTableRef" v-loading="loading" :data="progressCategoryList" row-key="id"
:default-expand-all="isExpandAll" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
v-if="isExpand" border>
<el-table
ref="progressCategoryTableRef"
v-loading="loading"
:data="progressCategoryList"
row-key="id"
:default-expand-all="isExpandAll"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
v-if="isExpand"
border
>
<el-table-column label="" width="50" type="expand">
<template #header>
<el-icon class="cursor-pointer text-4! transform-rotate-z--90 transition-all-300"
<el-icon
class="cursor-pointer text-4! transform-rotate-z--90 transition-all-300"
:class="!isExpandAll ? 'transform-rotate-z--90' : 'transform-rotate-z-90'"
@click="handleToggleExpandAll">
@click="handleToggleExpandAll"
>
<Expand />
</el-icon>
</template>
@ -40,86 +47,9 @@
<el-table-column label="名称" align="center" prop="name" width="170">
<template #default="{ row }">
<el-tooltip :content="row.remark" placement="top" effect="dark" v-if="row.remark">
<span class="flex items-center justify-center"><i
class="iconfont icon-wenhao mr-0.5 text-3.5! text-#999"></i>{{ row.name }}</span>
</el-tooltip>
<span v-else>{{ row.name }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" width="100">
<template #default="{ row }">
<dict-tag :options="progress_status" :value="row.status" />
</template>
</el-table-column>
<el-table-column label="是否延期" align="center" prop="isDelay" width="100">
<template #default="{ row }">
<el-tag :type="row.isDelay == '1' ? 'danger' : 'primary'">{{ row.isDelay == '1' ? '是' : '否'
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="计量方式" align="center" prop="unitType" width="100">
<template #default="{ row }">
<dict-tag :options="progress_unit_type" :value="row.unitType" />
</template>
</el-table-column>
<el-table-column label="总量" align="center" prop="total" width="100" />
<el-table-column label="总进度" align="center" prop="projectId">
<template #default="{ row }">
<el-progress :text-inside="true" :stroke-width="20" :percentage="row.completedPercentage"
status="success" />
</template>
</el-table-column>
<el-table-column label="计划总量" align="center" prop="planTotal" width="100" />
<el-table-column label="计划中" align="center" prop="projectId">
<template #default="{ row }">
<el-progress :text-inside="true" :stroke-width="20" :percentage="row.planTotalPercentage" />
</template>
</el-table-column>
<el-table-column label="对比" align="center" prop="unitType" width="100">
<template #default="{ row }">
{{ row.completed + '/' + row.total }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template #default="scope">
<el-button type="warning" icon="Download" link size="small" v-if="scope.row.name === '光伏板'"
@click="openDialog(scope.row, 'importTableStatus', '上传表格')"
v-hasPermi="['progress:progressCategory:add']">
导入表格
</el-button>
<el-button type="success" icon="Plus" link size="small" @click="planRef.openDialog(scope.row)"
v-hasPermi="['progress:progressCategory:add']">
计划
</el-button>
<el-button type="primary" icon="Plus" link size="small" @click="handleDayAdd(scope.row)"
v-hasPermi="['progress:progressCategory:add']">
日报
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</template>
</el-table-column>
<el-table-column label="名称" align="center" prop="name" width="150" />
<el-table-column label="状态" align="center" prop="status" width="100">
<template #default="{ row }">
<dict-tag :options="progress_status" :value="row.status" />
</template>
</el-table-column>
<el-table-column label="总进度" align="center" prop="projectId">
<template #default="{ row }">
<el-progress :text-inside="true" :stroke-width="20" :percentage="row.completedPercentage"
status="success" />
</template>
</el-table-column>
</el-table>
<el-table ref="progressCategoryTableRef" v-loading="loading" :data="progressCategoryList" v-else border>
<el-table-column label="名称" align="center" prop="name" width="170">
<template #default="{ row }">
<el-tooltip :content="row.remark" placement="top" effect="dark" v-if="row.remark">
<span class="flex items-center justify-center"><i
class="iconfont icon-wenhao mr-0.5 text-3.5! text-#999"></i>{{ row.name }}</span>
<span class="flex items-center justify-center"
><i class="iconfont icon-wenhao mr-0.5 text-3.5! text-#999"></i>{{ row.name }}</span
>
</el-tooltip>
<span v-else>{{ row.name }}</span>
</template>
@ -142,8 +72,7 @@
<el-table-column label="总量" align="center" prop="total" width="100" />
<el-table-column label="总进度" align="center" prop="projectId">
<template #default="{ row }">
<el-progress :text-inside="true" :stroke-width="20" :percentage="row.completedPercentage"
status="success" />
<el-progress :text-inside="true" :stroke-width="20" :percentage="row.completedPercentage" status="success" />
</template>
</el-table-column>
<el-table-column label="计划总量" align="center" prop="planTotal" width="100" />
@ -159,17 +88,120 @@
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template #default="scope">
<el-button type="warning" icon="Download" link size="small" v-if="scope.row.name === '光伏板'"
<el-button
type="warning"
icon="Download"
link
size="small"
v-if="scope.row.name === '光伏板'"
@click="openDialog(scope.row, 'importTableStatus', '上传表格')"
v-hasPermi="['progress:progressCategory:add']">
v-hasPermi="['progress:progressCategory:add']"
>
导入表格
</el-button>
<el-button type="success" icon="Plus" link size="small" @click="planRef.openDialog(scope.row)"
v-hasPermi="['progress:progressCategory:add']">
<el-button
type="success"
icon="Plus"
link
size="small"
@click="planRef.openDialog(scope.row)"
v-hasPermi="['progress:progressCategory:add']"
>
计划
</el-button>
<el-button type="primary" icon="Plus" link size="small" @click="handleDayAdd(scope.row)"
v-hasPermi="['progress:progressCategory:add']">
<el-button
type="primary"
icon="Plus"
link
size="small"
@click="handleDayAdd(scope.row)"
v-hasPermi="['progress:progressCategory:add']"
>
日报
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</template>
</el-table-column>
<el-table-column label="名称" align="center" prop="name" width="150" />
<el-table-column label="状态" align="center" prop="status" width="100">
<template #default="{ row }">
<dict-tag :options="progress_status" :value="row.status" />
</template>
</el-table-column>
<el-table-column label="总进度" align="center" prop="projectId">
<template #default="{ row }">
<el-progress :text-inside="true" :stroke-width="20" :percentage="row.completedPercentage" status="success" />
</template>
</el-table-column>
</el-table>
<el-table ref="progressCategoryTableRef" v-loading="loading" :data="progressCategoryList" v-else border>
<el-table-column label="名称" align="center" prop="name" width="170">
<template #default="{ row }">
<el-tooltip :content="row.remark" placement="top" effect="dark" v-if="row.remark">
<span class="flex items-center justify-center"><i class="iconfont icon-wenhao mr-0.5 text-3.5! text-#999"></i>{{ row.name }}</span>
</el-tooltip>
<span v-else>{{ row.name }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" width="100">
<template #default="{ row }">
<dict-tag :options="progress_status" :value="row.status" />
</template>
</el-table-column>
<el-table-column label="是否延期" align="center" prop="isDelay" width="100">
<template #default="{ row }">
<el-tag :type="row.isDelay == '1' ? 'danger' : 'primary'">{{ row.isDelay == '1' ? '是' : '否' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="计量方式" align="center" prop="unitType" width="100">
<template #default="{ row }">
<dict-tag :options="progress_unit_type" :value="row.unitType" />
</template>
</el-table-column>
<el-table-column label="总量" align="center" prop="total" width="100" />
<el-table-column label="总进度" align="center" prop="projectId">
<template #default="{ row }">
<el-progress :text-inside="true" :stroke-width="20" :percentage="row.completedPercentage" status="success" />
</template>
</el-table-column>
<el-table-column label="计划总量" align="center" prop="planTotal" width="100" />
<el-table-column label="计划中" align="center" prop="projectId">
<template #default="{ row }">
<el-progress :text-inside="true" :stroke-width="20" :percentage="row.planTotalPercentage" />
</template>
</el-table-column>
<el-table-column label="对比" align="center" prop="unitType" width="100">
<template #default="{ row }">
{{ row.completed + '/' + row.total }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template #default="scope">
<el-button
type="warning"
icon="Download"
link
size="small"
v-if="scope.row.name === '光伏板'"
@click="openDialog(scope.row, 'importTableStatus', '上传表格')"
v-hasPermi="['progress:progressCategory:add']"
>
导入表格
</el-button>
<el-button
type="success"
icon="Plus"
link
size="small"
@click="planRef.openDialog(scope.row)"
v-hasPermi="['progress:progressCategory:add']"
>
计划
</el-button>
<el-button type="primary" icon="Plus" link size="small" @click="handleDayAdd(scope.row)" v-hasPermi="['progress:progressCategory:add']">
日报
</el-button>
</template>
@ -180,8 +212,7 @@
<!-- 导入数据对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.importDataStatus" width="500px" append-to-body>
<file-upload class="pl-20 pt" v-model="dialog.file" :limit="20" :file-size="50"
:file-type="['shp', 'shx', 'dbf']" />
<file-upload class="pl-20 pt" v-model="dialog.file" :limit="20" :file-size="50" :file-type="['shp', 'shx', 'dbf']" />
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
@ -291,6 +322,9 @@ const getList = async () => {
const res = await getProjectSquare(currentProject.value?.id);
if (!res.data || res.data.length === 0) {
proxy?.$modal.msgWarning('当前项目下没有方阵,请先创建方阵');
tabList.value = [];
progressCategoryList.value = [];
return;
} else {
let matrixList = res.data.map((item) => {
return {
@ -367,6 +401,8 @@ const reset = () => {
const resetMatrix = () => {
matrixValue.value = undefined;
queryParams.value.matrixId = undefined;
queryParams.value.projectId = undefined;
relevancyStructure.value = '1';
matrixOptions.value = [];
};
@ -385,9 +421,13 @@ const handleChange = (value: number) => {
const handleDayAdd = (row: ProgressCategoryVO) => {
if (row.unitType === '2') {
dailyRef.value.openDialog(row);
} else {
if (!row.workType) {
dailyRef.value.openDialog(row);
} else {
dailyRateRef.value.openDialog(row);
}
}
};
/** 导入按钮操作 */
@ -463,8 +503,6 @@ onMounted(() => {
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
queryParams.value.projectId = nid;
form.value.projectId = nid;
resetMatrix();
getList();
}

View File

@ -1,14 +1,12 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="请选择项目:" prop="pid" label-width="100">
<el-select v-model="queryParams.projectId" placeholder="请选择" @change="handleChange" clearable>
<el-option v-for="item in matrixOptions" :key="item.projectId" :label="item.name"
:value="item.projectId" />
<el-option v-for="item in matrixOptions" :key="item.projectId" :label="item.name" :value="item.projectId" />
</el-select>
</el-form-item>
<el-form-item label="请选择方阵:" prop="pid" label-width="100" v-if="relevancyStructure == '2'">
@ -24,13 +22,18 @@
<el-tab-pane :label="item.name" v-for="item in tabList" :key="item.id" :name="item.id"></el-tab-pane>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8" style="display: flex; align-items: center;">
<el-row :gutter="10" class="mb8" style="display: flex; align-items: center">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
</el-col>
<el-col :span="1.5">
<file-upload upload-url="/progress/progressCategory/import" v-model="file" :limit="1"
:file-type="['xls', 'xlsx']" :on-upload-success="handleSuccess">
<file-upload
upload-url="/progress/progressCategory/import"
v-model="file"
:limit="1"
:file-type="['xls', 'xlsx']"
:on-upload-success="handleSuccess"
>
<el-button type="primary" plain icon="upload">导入</el-button>
</file-upload>
</el-col>
@ -69,12 +72,17 @@
</div>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table ref="progressCategoryTableRef" v-loading="loading" :data="progressCategoryList" row-key="id"
:default-expand-all="isExpandAll" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
max-height="550">
<el-table
ref="progressCategoryTableRef"
v-loading="loading"
:data="progressCategoryList"
row-key="id"
:default-expand-all="isExpandAll"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
max-height="550"
>
<!-- <el-table-column label="父类别id" prop="parentId" /> -->
<el-table-column label="类别名称" prop="name" width="230" />
<el-table-column label="计量方式" align="center" prop="unitType">
@ -123,12 +131,10 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<div>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['progress:progressCategory:edit']">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['progress:progressCategory:edit']">
修改
</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['progress:progressCategory:remove']">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['progress:progressCategory:remove']">
删除
</el-button>
</div>
@ -142,9 +148,14 @@
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="progressCategoryFormRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="父类别" prop="parentId" v-if="!form.id">
<el-tree-select v-model="form.parentId" :data="progressCategoryOptions"
:props="{ value: 'id', label: 'name', children: 'children' }" value-key="id" placeholder="请选择父类别"
check-strictly />
<el-tree-select
v-model="form.parentId"
:data="progressCategoryOptions"
:props="{ value: 'id', label: 'name', children: 'children' }"
value-key="id"
placeholder="请选择父类别"
check-strictly
/>
</el-form-item>
<el-form-item label="计量方式" prop="unitType" v-if="!form.workType && form.unitType != '0'">
<el-select v-model="form.unitType" placeholder="请选择关联数据">
@ -167,7 +178,7 @@
<el-input v-model="form.total" placeholder="请输入数量" />
</el-form-item>
<el-form-item label="关联数据" prop="workType" v-if="!form.id && form.unitType != '0'">
<el-select v-model="form.workType" placeholder="请选择关联数据">
<el-select v-model="form.workType" placeholder="请选择关联数据" clearable>
<el-option v-for="dict in progress_work_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
@ -244,7 +255,7 @@ const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const tempData = ref([])
const tempData = ref([]);
const initFormData: ProgressCategoryForm = {
id: undefined,
parentId: undefined,
@ -312,16 +323,16 @@ const { queryParams, form, rules } = toRefs(data);
const matrixIdList = ref([]);
const ownerOutputSum = computed(() => {
let sum = 0;
tempData.value.forEach(item => {
tempData.value.forEach((item) => {
sum += Number(item.ownerOutputValue);
})
return proxy.formatPrice(sum) ?? 0;
});
return proxy.formatPrice(sum);
});
const constructionOutputSum = computed(() => {
let sum = 0;
tempData.value.forEach(item => {
tempData.value.forEach((item) => {
sum += Number(item.constructionOutputValue);
})
});
return proxy.formatPrice(sum);
});
/** 查询分项工程单价列表 */
@ -329,12 +340,14 @@ const getList = async () => {
if (!queryParams.value.projectId) {
const res = await getProjectSquare(currentProject.value?.id);
if (res.data.length === 0) {
proxy?.$modal.msgWarning('当前项目下没有方阵,请先创建方阵');
matrixOptions.value = [];
queryParams.value.projectId = '';
form.value.projectId = '';
// proxy?.$modal.msgWarning('当前项目下没有方阵,请先创建方阵');
// matrixOptions.value = [];
// queryParams.value.projectId = '';
// form.value.projectId = '';
progressCategoryList.value = [];
tabList.value = [];
activeTab.value = '';
// activeTab.value = '';
return;
} else {
let matrixList = res.data.map((item) => {
return {
@ -512,6 +525,7 @@ const resetMatrix = () => {
matrixValue.value = undefined;
queryParams.value.matrixId = undefined;
queryParams.value.projectId = undefined;
relevancyStructure.value = '1';
matrixOptions.value = [];
};
@ -658,7 +672,11 @@ onUnmounted(() => {
font-size: 20px;
font-weight: 700;
color: #262626;
font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
font-family:
'SF Pro Display',
-apple-system,
BlinkMacSystemFont,
sans-serif;
letter-spacing: -0.5px;
line-height: 1.2;
text-align: center;

View File

@ -21,8 +21,8 @@
<el-date-picker
clearable
v-model="queryParams.clockDate"
type="date"
value-format="YYYY-MM-DD"
type="month"
value-format="YYYY-MM"
placeholder="请选择打卡日期"
@change="selectDate"
/>
@ -338,19 +338,22 @@ const handleViewPlayCard = async (data: any) => {
/** 查询考勤列表 */
const getList = async () => {
loading.value = true;
try {
const res = await listAttendance(queryParams.value);
attendanceList.value = res.rows;
total.value = res.total;
} finally {
loading.value = false;
}
};
/** 查询近两周考勤列表 */
const getListTwoWeek = async () => {
loading.value = true;
// const res = await listAttendanceTwoWeek(queryParams.value);
// attendanceTwoWeekList.value = res.data;
// echartsOption.value = { ...option(attendanceTwoWeekList.value) };
// commandstatsIntance.value.setOption(echartsOption.value);
const res = await listAttendanceTwoWeek(queryParams.value);
attendanceTwoWeekList.value = res.data;
echartsOption.value = { ...option(attendanceTwoWeekList.value) };
commandstatsIntance.value.setOption(echartsOption.value);
};
/** 取消按钮 */

View File

@ -116,12 +116,15 @@
</el-dialog>
<!-- 上传退场记录 -->
<el-dialog title="员工离场" v-model="memberStatus" width="30%">
<el-form :model="memberForm" ref="memberFormRef" :rules="memberRules" label-width="100px" :inline="false">
<el-form :model="memberForm" ref="memberFormRef" :rules="memberRules" label-width="120px" :inline="false">
<el-form-item label="用户名">
<el-input v-model="memberForm.userName" disabled></el-input>
</el-form-item>
<el-form-item label="退场文件">
<file-upload v-model="memberForm.filePath" :limit="10" :is-show-tip="false" :file-size="50" />
<el-form-item label="工资发放凭证">
<file-upload v-model="memberForm.salaryVoucherFile" :limit="10" :is-show-tip="false" :file-size="50" />
</el-form-item>
<el-form-item label="工资结算确认书">
<file-upload v-model="memberForm.salaryConfirmationFile" :limit="10" :is-show-tip="false" :file-size="50" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="memberForm.remark" placeholder="请输入备注" type="textarea"></el-input>
@ -163,9 +166,10 @@ const memberStatus = ref(false);
interface Props {
projectTeamVo: ProjectTeamVO;
}
const memberForm = reactive<ConstructionUserMembeForm>({
const memberForm = reactive<any>({
id: undefined,
filePath: undefined,
salaryConfirmationFile: undefined,
salaryVoucherFile: undefined,
remark: undefined,
userName: undefined
});
@ -328,8 +332,9 @@ const submitMemberForm = async () => {
const handleExit = async (row?: ProjectTeamMemberVO) => {
const _ids = row?.id || ids.value;
memberForm.userName = row?.memberName;
console.log('🚀 ~ handleDelete ~ row:', row);
memberForm.id = row?.id;
memberForm.salaryVoucherFile = '';
memberForm.salaryConfirmationFile = '';
memberStatus.value = true;
};

View File

@ -103,7 +103,7 @@
</template>
<script setup name="ProjectTeam" lang="ts">
import { addProjectTeam, delProjectTeam, getProjectTeam, listProjectTeam, updateProjectTeam,getProjectTeamClockIn } from '@/api/project/projectTeam';
import { addProjectTeam, delProjectTeam, getProjectTeam, listProjectTeam, updateProjectTeam, getProjectTeamClockIn } from '@/api/project/projectTeam';
import { ProjectTeamForm, ProjectTeamQuery, ProjectTeamVO } from '@/api/project/projectTeam/types';
import { useUserStoreHook } from '@/store/modules/user';
import UserListDialog from '@/views/project/projectTeam/component/UserListDialog.vue';
@ -182,13 +182,12 @@ const getList = async () => {
};
/** 获取该项目的打开范围 "*/
const getClockIn = async () => {
if(currentProject.value?.id){
const res = await getProjectTeamClockIn({projectId:currentProject.value?.id});
projectTeamRangeList.value = res.rows
if (currentProject.value?.id) {
const res = await getProjectTeamClockIn({ projectId: currentProject.value?.id });
projectTeamRangeList.value = res.rows;
}
};
/** 取消按钮 */
const cancel = () => {
reset();
@ -288,6 +287,7 @@ const listeningProject = watch(
queryParams.value.projectId = nid;
form.value.projectId = nid;
getList();
getClockIn();
}
);

View File

@ -113,15 +113,7 @@
<!-- <el-button type="primary" link icon="Edit" @click="handleSave(scope.row)" v-hasPermi="['tender:segmentedIndicatorPlanning:edit']"
>信息
</el-button> -->
<el-button
type="primary"
link
icon="View"
@click="handleDetail(scope.row)"
:disabled="scope.row.bidStatus == 1"
v-hasPermi="['tender:biddingPlan:getMore']"
>详情</el-button
>
<el-button type="primary" link icon="View" @click="handleDetail(scope.row)" v-hasPermi="['tender:biddingPlan:getMore']">详情</el-button>
<el-button
type="primary"

View File

@ -549,6 +549,8 @@ const splitBackEndStrToForm = (resData: any) => {
};
/** 审核过程按钮操作 */
const handleAudit = async (row) => {
if(!row.fileId)return proxy?.$modal.msgError('用户资料未上传');
proxy.$tab.closePage(proxy.$route);
proxy.$router.push({
path: `/approval/supplierInput/indexEdit`,