Files
maintenance_system/src/views/zhinengxunjian/paidanjilu.vue
2025-09-18 19:56:24 +08:00

825 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<div>
<div class="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">
<img src="@/assets/images/paidan.png" alt="时间" class="stat-img" />
</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">
<img src="@/assets/images/shijian.png" alt="时间" class="stat-img" />
</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">
<img src="@/assets/images/gongdan.png" alt="工单" class="stat-img" />
</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">
<img src="@/assets/images/wancheng.png" alt="完成" class="stat-img" />
</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)" class="action-btn">详情</el-button>
<el-button
type="text"
@click="handleViewReport(scope.row)"
class="action-btn report-btn"
v-if="scope.row.completionStatus === '已完成'"
>
查看报告
</el-button>
<el-button
type="text"
@click="handleViewProgress(scope.row)"
class="action-btn progress-btn"
v-else-if="scope.row.completionStatus === '进行中'"
>
查看进度
</el-button>
<el-button type="text" @click="handleTrack(scope.row)" class="action-btn track-btn" v-else> 跟踪 </el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页区域 -->
<div class="pagination-section">
<div class="pagination-info">
显示第{{ (currentPage - 1) * pageSize + 1 }}{{ Math.min(currentPage * pageSize, total) }}{{ total }}条记录
</div>
<div class="pagination-controls">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[10, 20, 30, 40]"
:page-size="pageSize"
layout="prev, pager, next, jumper"
:total="total"
background
>
</el-pagination>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, reactive } from 'vue';
import router from '@/router';
import TitleComponent from './TitleComponent.vue';
// 激活的选项卡,默认显示派单记录
const activeTab = ref('dispatch');
// 筛选条件
const dispatchStatus = ref('all');
const executor = ref('all');
const dispatchDate = ref('');
// 统计数据
const totalDispatches = ref(56);
const avgResponseTime = ref('42分钟');
const pendingDispatches = ref(7);
const completionRate = ref('92%');
// 派单记录数据
const rawTableData = ref([
{
dispatchNo: 'DP-2023-0619-089',
orderNo: 'WO-2023-0619-055',
taskType: '安全设备检查检测',
dispatcher: '张明',
executor: '李阳',
dispatchTime: '2023-06-19 13:50',
status: '已接收',
completionStatus: '未完成'
},
{
dispatchNo: 'DP-2023-0619-088',
orderNo: 'WO-2023-0618-054',
taskType: '新设备安装调试',
dispatcher: '张明',
executor: '李阳',
dispatchTime: '2023-06-19 13:30',
status: '已接收',
completionStatus: '进行中'
},
{
dispatchNo: 'DP-2023-0619-087',
orderNo: 'WO-2023-0617-053',
taskType: '系统升级改造',
dispatcher: '张明',
executor: '李阳',
dispatchTime: '2023-06-19 10:15',
status: '已接收',
completionStatus: '已完成'
},
{
dispatchNo: 'DP-2023-0619-086',
orderNo: 'WO-2023-0616-052',
taskType: '安全设备检查检测',
dispatcher: '张明',
executor: '李阳',
dispatchTime: '2023-06-19 09:40',
status: '已接收',
completionStatus: '未完成'
},
{
dispatchNo: 'DP-2023-0619-085',
orderNo: 'WO-2023-0615-051',
taskType: '安全设备检查检测',
dispatcher: '张明',
executor: '李阳',
dispatchTime: '2023-06-19 09:20',
status: '已接收',
completionStatus: '未完成'
},
{
dispatchNo: 'DP-2023-0619-084',
orderNo: 'WO-2023-0614-050',
taskType: '安全设备检查检测',
dispatcher: '张明',
executor: '李阳',
dispatchTime: '2023-06-19 09:10',
status: '已接收',
completionStatus: '未完成'
},
{
dispatchNo: 'DP-2023-0619-083',
orderNo: 'WO-2023-0613-049',
taskType: '安全设备检查检测',
dispatcher: '张明',
executor: '李阳',
dispatchTime: '2023-06-19 08:50',
status: '已接收',
completionStatus: '未完成'
}
]);
// 分页相关
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(rawTableData.value.length);
// 分页处理后的数据
const pagedTableData = computed(() => {
// 筛选逻辑
let filteredData = [...rawTableData.value];
if (dispatchStatus.value !== 'all') {
filteredData = filteredData.filter((item) => item.status === dispatchStatus.value);
}
if (executor.value !== 'all') {
// 这里假设执行人的值与选项值对应
const executorMap = {
'zhangming': '张明',
'lihua': '李华',
'wangqiang': '王强'
};
filteredData = filteredData.filter((item) => item.executor === executorMap[executor.value]);
}
if (dispatchDate.value) {
filteredData = filteredData.filter((item) => item.dispatchTime.includes(dispatchDate.value));
}
// 更新总条数
total.value = filteredData.length;
// 分页处理
const startIndex = (currentPage.value - 1) * pageSize.value;
const endIndex = startIndex + pageSize.value;
return filteredData.slice(startIndex, endIndex);
});
// 获取派单状态标签样式
const getStatusTagType = (status) => {
const statusMap = {
'已接收': 'primary',
'处理中': 'success',
'已完成': 'info',
'已拒绝': 'danger'
};
return statusMap[status] || 'default';
};
// 获取完成状态标签样式
const getCompletionTagType = (status) => {
const statusMap = {
'未完成': 'warning',
'进行中': 'primary',
'已完成': 'success',
'已逾期': 'danger'
};
return statusMap[status] || 'default';
};
// 搜索处理
const handleSearch = () => {
currentPage.value = 1; // 重置到第一页
};
// 导出记录
const handleExport = () => {
console.log('导出派单记录');
// 实际应用中这里会调用导出API
};
// 分页事件
const handleSizeChange = (val) => {
pageSize.value = val;
currentPage.value = 1;
};
const handleCurrentChange = (val) => {
currentPage.value = val;
};
// 选项卡点击
const handleTabClick = (tab) => {
console.log('切换到选项卡:', tab.name);
// 重置筛选条件和分页
dispatchStatus.value = 'all';
executor.value = 'all';
dispatchDate.value = '';
currentPage.value = 1;
// 如果切换到其他选项卡,导航到相应页面
if (tab.name === 'list') {
router.push('/rili/gongdanguanli');
} else if (tab.name === 'execution') {
router.push('/rili/execution-records');
}
};
// 操作按钮事件
const handleViewDetails = (row) => {
console.log('查看派单详情:', row);
// 实际应用中这里会跳转到详情页
};
const handleViewReport = (row) => {
console.log('查看报告:', row);
// 实际应用中这里会跳转到报告页面
};
const handleViewProgress = (row) => {
console.log('查看进度:', row);
// 实际应用中这里会跳转到进度页面
};
const handleTrack = (row) => {
console.log('跟踪工单:', row);
// 实际应用中这里会跳转到跟踪页面或打开跟踪弹窗
};
// 导航路由跳转
const handleInspection1 = () => {
router.push('/rili/rili');
};
const handleInspection2 = () => {
router.push('/rili/InspectionManagement');
};
const handleInspection3 = () => {
router.push('/rili/shiyanguanli');
};
const handleInspection4 = () => {
router.push('/rili/baoxiuguanli');
};
const handleInspection5 = () => {
router.push('/rili/qiangxiuguanli');
};
const handleInspection6 = () => {
router.push('/rili/gongdanguanli');
};
const handleInspection7 = () => {
router.push('/rili/renyuanzhuangtai');
};
const handleInspectionManagement1 = () => {
router.push('/rili/gongdanliebiao');
};
const handleInspectionManagement2 = () => {
router.push('/rili/paidanjilu');
};
const handleInspectionManagement3 = () => {
router.push('/rili/zhixingjilu');
};
</script>
<style scoped>
.dispatch-records {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
/* 选项卡样式 */
.tabs-wrapper {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.custom-tabs {
padding-top: 1px;
}
.custom-tabs .el-tabs__header {
margin: 0 -20px;
padding: 0 20px;
border-bottom: 1px solid #e4e7ed;
}
.custom-tabs .el-tabs__nav-wrap::after {
height: 0;
}
.custom-tabs .el-tabs__item {
font-size: 14px;
color: #606266;
padding: 14px 20px;
margin-right: 20px;
}
.custom-tabs .el-tabs__item.is-active {
color: #165dff;
font-weight: 500;
}
.custom-tabs .el-tabs__item:hover {
color: #165dff;
}
/* 筛选栏样式 */
.filter-bar {
background-color: #fff;
border-radius: 8px;
margin-bottom: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
padding: 16px 24px;
}
.filter-container {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
width: 100%;
}
.filter-item {
flex-shrink: 0;
}
.filter-bar .el-select,
.filter-bar .el-date-picker {
width: 180px;
height: 36px;
}
.filter-bar .el-select .el-input__inner,
.filter-bar .el-date-picker .el-input__inner {
border-radius: 4px;
border-color: #dcdfe6;
transition: all 0.2s ease;
}
.filter-bar .el-select .el-input__inner:focus,
.filter-bar .el-date-picker .el-input__inner:focus {
border-color: #165dff;
box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
}
.filter-actions {
margin-left: auto;
display: flex;
gap: 12px;
flex-shrink: 0;
}
.search-btn {
background-color: #f2f3f5;
color: #303133;
border-color: #f2f3f5;
transition: all 0.2s ease;
}
.search-btn:hover {
background-color: #e5e6eb;
color: #303133;
border-color: #e5e6eb;
}
.export-btn {
color: #165dff;
border: 1px solid #165dff;
transition: all 0.2s ease;
}
.export-btn:hover {
background-color: #e8f3ff;
color: #0e42d2;
border-color: #0e42d2;
}
/* 统计卡片样式 */
.statistics-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
.stat-card {
background-color: #fff;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
position: relative;
overflow: hidden;
transition: all 0.3s ease;
}
.stat-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}
.stat-value {
font-size: 28px;
font-weight: 600;
color: #1d2129;
margin-bottom: 8px;
line-height: 1.2;
}
.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: 24px;
right: 24px;
width: 50px;
height: 50px;
border-radius: 12px;
background-color: #f0f7ff;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.stat-icon:hover {
transform: scale(1.05);
}
/* 统计卡片图片样式 */
.stat-img {
width: 35px;
height: 35px;
object-fit: contain;
transition: all 0.3s ease;
}
.stat-icon:hover .stat-img {
transform: scale(1.1);
}
/* 表格样式 */
.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>