Files
maintenance_system/src/views/zhinengxunjian/qiangxiuguanli.vue
2025-09-26 20:32:14 +08:00

2008 lines
53 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<div>
<div class="inspection-tasks">
<!-- <div class="navigation-tabs">
<div class="nav-tab" @click="handleInspection1">待办事项</div>
<div class="nav-tab" @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="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" icon="Search" class="search-btn" @click="handleSearch"> 搜索 </el-button>
<el-button type="primary" 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.leftLineClass">
<div class="task-header">
<div class="task-title">
{{ task.title }}
</div>
<!-- 恢复优先级标签背景色样式 -->
<div class="task-status" :class="task.priorityClass">
{{ task.priority }}
</div>
</div>
<div class="task-details">
<div class="detail-item">
<span class="detail-label">报修时间</span>
<span class="detail-value">{{ task.createTime }}</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.statusText }}</span>
</div>
<div class="detail-item">
<span class="detail-label">期望处理时间</span>
<span class="detail-label">{{ task.expectedTime || '——' }}</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>
<div class="task-actions">
<el-button type="text" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button>
<el-button type="primary" :class="task.actionClass" @click="handleAction(task)">
{{ task.actionText }}
</el-button>
</div>
</div>
</div>
<!-- 分页区域 -->
<div class="pagination-section">
<div class="pagination-controls">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[8, 12, 16, 20]"
:page-size="pageSize"
layout="prev, pager, next, jumper"
:total="total"
background
>
</el-pagination>
</div>
</div>
<!-- 新建紧急抢修任务弹窗 -->
<el-dialog
v-model="createTaskDialogVisible"
title="创建紧急抢修任务"
width="800px"
:before-close="handleCancelCreateTask"
custom-class="beautiful-dialog"
center
>
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="100px" class="elegant-form">
<el-form-item label="抢修名称*" prop="repairName">
<el-input v-model="createTaskForm.repairName" placeholder="简要描述抢修内容" />
</el-form-item>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="抢修类型*" prop="repairType">
<el-select v-model="createTaskForm.repairType" placeholder="请选择类型">
<el-option label="电力故障" value="electric" />
<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="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="expectedTime">
<el-date-picker
v-model="createTaskForm.expectedTime"
type="datetime"
:min-date="new Date()"
placeholder="选择预计完成时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
@change="validateTime"
style="width: 100%"
/>
</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="上传图片(可选)*">
<image-upload v-model="createTaskForm.file" />
<div v-if="createTaskForm.fileList && createTaskForm.fileList.length > 0" class="upload-tip">
<span style="color: #1989fa">已选择{{ createTaskForm.fileList.length }}张图片将在提交时上传</span>
</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>
<!-- 任务详情弹窗 -->
<el-dialog
v-model="detailDialogVisible"
title="抢修任务详情"
width="800px"
:before-close="handleCloseDetailDialog"
class="custom-experiment-dialog"
>
<div v-if="detailData" class="task-detail-container">
<!-- 加载状态骨架屏 -->
<div v-if="isDetailLoading" class="skeleton-loading">
<div class="skeleton-card">
<div class="skeleton-header"></div>
<div class="skeleton-content">
<div class="skeleton-row"></div>
<div class="skeleton-row"></div>
<div class="skeleton-row"></div>
</div>
</div>
<div class="skeleton-card">
<div class="skeleton-header"></div>
<div class="skeleton-content">
<div class="skeleton-row"></div>
<div class="skeleton-row"></div>
</div>
</div>
<div class="skeleton-card">
<div class="skeleton-header"></div>
<div class="skeleton-content">
<div class="skeleton-row"></div>
<div class="skeleton-row"></div>
</div>
</div>
</div>
<!-- 任务基本信息卡片 -->
<div class="detail-card">
<h3 class="card-title">任务基本信息</h3>
<div class="card-content">
<div class="info-row">
<div class="info-item">
<span class="info-label">任务ID</span>
<span class="info-value">{{ detailData.id || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">任务名称</span>
<span class="info-value">{{ detailData.name || '未命名' }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<span class="info-label">任务状态</span>
<span class="info-value">{{ getStatusText(detailData.status) }}</span>
</div>
<div class="info-item">
<span class="info-label">任务等级</span>
<span class="info-value">{{ getPriorityText(detailData.level) }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<span class="info-label">任务类型</span>
<span class="info-value">{{ getFaultTypeText(detailData.type) }}</span>
</div>
<div class="info-item">
<span class="info-label">创建时间</span>
<span class="info-value">{{ formatDate(detailData.createTime) }}</span>
</div>
</div>
</div>
</div>
<!-- 报修人信息卡片 -->
<div class="detail-card">
<h3 class="card-title">报修人信息</h3>
<div class="card-content">
<div class="info-row">
<div class="info-item">
<span class="info-label">报修人</span>
<span class="info-value">{{ detailData.reportName || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">联系电话</span>
<span class="info-value">{{ detailData.reportPhone || '-' }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<span class="info-label">维修人</span>
<span class="info-value">{{ detailData.sendPersonVo?.userName || '-' }}</span>
</div>
</div>
</div>
</div>
<div class="detail-card">
<h3 class="card-title">报修详情</h3>
<div class="card-content">
<div class="info-row">
<div class="info-item full-width">
<span class="info-label">故障位置</span>
<span class="info-value">{{ detailData.position || '-' }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item full-width">
<span class="info-label">详细描述</span>
<span class="info-value">{{ detailData.reportInfo || '-' }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<span class="info-label">期望处理时间</span>
<span class="info-value">{{ detailData.expectedTime || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">现场支持</span>
<span class="info-value">{{ detailData.support || '-' }}</span>
</div>
</div>
<!-- 已完成状态的额外信息 -->
<div v-if="detailData.status === '3'" class="info-row">
<div class="info-item">
<span class="info-label">完成时间</span>
<span class="info-value">{{ formatDate(detailData.reportFinishTime) }}</span>
</div>
</div>
</div>
</div>
<!-- 故障图片 -->
<div v-if="detailData.fileUrl && detailData.fileUrl.length > 0" class="detail-card">
<h3 class="card-title">故障图片</h3>
<div class="card-content">
<div class="images-container">
<!-- 将逗号分隔的URL字符串拆分为数组并循环展示 -->
<div v-for="(url, index) in splitImageUrls(detailData.fileUrl)" :key="index" class="image-item">
<img
:src="url"
:alt="`故障图片 ${index + 1}`"
class="detail-image"
@error="handleImageError($event, index)"
style="max-width: 100%; max-height: 200px; border-radius: 4px"
/>
</div>
</div>
</div>
</div>
</div>
<div v-else class="loading-state">
<i class="el-icon-loading el-icon--loading"></i>
<span>加载中...</span>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseDetailDialog">关闭</el-button>
</span>
</template>
</el-dialog>
</div>
<!-- 处理结果输入弹窗 -->
<el-dialog v-model="resultDialogVisible" title="处理结果输入" class="beautiful-dialog">
<div class="result-dialog-content">
<el-form ref="resultFormRef" :model="{ reportFinal: reportFinal }" :rules="resultFormRules" label-width="80px">
<el-form-item label="处理结果" prop="reportFinal">
<el-input v-model="reportFinal" type="textarea" :rows="6" placeholder="请输入处理结果详情" />
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="resultDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSaveResult">保存</el-button>
</div>
</template>
</el-dialog>
<!-- 分配任务弹窗 -->
<el-dialog title="分配抢修任务" v-model="assignDialogVisible" width="400px" :before-close="handleCloseAssign">
<el-form ref="assignTaskFormRef" :model="assignTaskForm" :rules="assignTaskRules" label-width="100px">
<el-form-item label="维修人员" prop="sendPerson">
<el-select v-model="assignTaskForm.sendPerson" placeholder="请选择维修人" :loading="loadingUsers">
<el-option v-for="user in usersList" :key="user.id" :label="user.name" :value="user.id" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseAssign">取消</el-button>
<el-button type="primary" @click="handleSubmitAssign">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import router from '@/router';
import { ElMessage } from 'element-plus';
import { qiangxiuDetail, qiangxiulist, addqiangxiu, updateqiangxiu } from '@/api/zhinengxunjian/qiangxiu';
import { xunjianUserlist } from '@/api/zhinengxunjian/xunjian';
const taskStatus = ref('all');
const planType = ref('all');
const executor = ref('all');
// 任务数据 - 添加了更多字段以展示滚动效果
const tasks = ref([]);
// 分页相关
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; // 重置到第一页
getTaskList(); // 调用接口获取数据
};
// 创建紧急抢修任务弹窗相关
const createTaskDialogVisible = ref(false);
const createTaskFormRef = ref(null); // 表单引用
// 用户列表(维修人)
const createTaskForm = ref({
repairName: '',
repairType: '',
priority: '',
detailedDescription: '',
faultLocation: '',
contactPerson: '',
contactPhone: '',
needSupport: 'yes',
file: '', // 上传的文件列表
expectedTime: '' // 预计完成时间
});
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' }],
expectedTime: [{ required: true, message: '请选择预计完成时间', trigger: 'change' }]
};
// 映射抢修类型到接口要求的数字1电力2设备3供水4网络5设施
const mapRepairType = (type) => {
const typeMap = {
'electric': '1', // 电力故障 -> 1
'device': '2', // 设备故障 -> 2
'software': '3', // 软件故障 -> 3
'network': '4', // 网络故障 -> 4
'environment': '5' // 环境问题 -> 5
};
return typeMap[type] || '2'; // 默认返回设备故障
};
// 映射优先级到接口要求的数字1常规2紧急3致命
const mapPriorityLevel = (priority) => {
const priorityMap = {
'normal': '1', // 一般 -> 1
'urgent': '2', // 紧急 -> 2
'fatal': '3' // 致命 -> 3
};
return priorityMap[priority] || '1'; // 默认返回常规
};
// 创建任务
const handleCreateTask = async () => {
createTaskDialogVisible.value = true;
// 打开弹窗时获取用户列表
await getUsersList();
};
const isSubmitting = ref(false); // 防止重复提交的状态标记
// 重置创建表单
const resetCreateForm = () => {
createTaskForm.value = {
repairName: '',
repairType: '',
priority: '',
detailedDescription: '',
faultLocation: '',
contactPerson: '',
contactPhone: '',
needSupport: 'yes',
file: '',
sendPerson: '',
expectedTime: ''
};
if (createTaskFormRef.value) {
createTaskFormRef.value.resetFields();
}
};
// 提交抢修计划
const handleSaveTask = async () => {
// 防止重复提交
if (!createTaskFormRef.value || isSubmitting.value) return;
try {
// 设置提交状态为true
isSubmitting.value = true;
// 先验证表单
await createTaskFormRef.value.validate();
// 构造提交数据
const submitData = {
// 必填项目ID
projectId: 1,
// 默认状态为待处理
status: '1',
// 任务名称
name: createTaskForm.value.repairName,
// 任务类型转换为数字1电力2设备3供水4网络5设施
type: mapRepairType(createTaskForm.value.repairType),
// 任务等级转换为数字1常规2紧急3致命
level: mapPriorityLevel(createTaskForm.value.priority),
// 故障描述
reportInfo: createTaskForm.value.detailedDescription,
// 故障位置
position: createTaskForm.value.faultLocation,
// 文件ID
fileId: createTaskForm.value.file,
// 报修人姓名
reportName: createTaskForm.value.contactPerson,
// 报修人电话
reportPhone: createTaskForm.value.contactPhone,
// 现场支持需求
support: createTaskForm.value.needSupport === 'yes' ? '是' : '否',
// 指派维修人
sendPerson: createTaskForm.value.sendPerson,
// 预计完成时间
expectedTime: createTaskForm.value.expectedTime
};
// 调用接口提交数据
const res = await addqiangxiu(submitData);
// 检查接口返回是否成功
if (res && res.code === 200) {
// 显示成功提示
ElMessage.success('抢修任务创建成功');
// 关闭弹窗
createTaskDialogVisible.value = false;
// 重置表单
resetCreateForm();
// 刷新任务列表
getTaskList();
} else {
ElMessage.error(`创建失败:${res?.msg || '未知错误'}`);
}
} catch (error) {
// 错误处理
if (error instanceof Error) {
ElMessage.error(`操作失败:${error.message}`);
} else if (error === false) {
// 表单验证失败,不做处理
} else {
ElMessage.error('操作失败:未知错误');
}
console.error('创建抢修任务失败:', error);
} finally {
// 无论成功失败,都重置提交状态
isSubmitting.value = false;
}
};
// 取消创建紧急抢修任务
const handleCancelCreateTask = () => {
createTaskDialogVisible.value = false;
// 重置表单
createTaskForm.value = {
repairName: '',
repairType: '',
priority: '',
detailedDescription: '',
faultLocation: '',
contactPerson: '',
contactPhone: '',
needSupport: 'yes',
file: '',
sendPerson: '',
expectedTime: ''
};
};
// 分页事件
const handleSizeChange = (val) => {
pageSize.value = val;
currentPage.value = 1;
};
const handleCurrentChange = (val) => {
currentPage.value = val;
};
// 详情弹窗相关
const detailDialogVisible = ref(false);
const detailData = ref(null);
const isDetailLoading = ref(false);
// 关闭详情弹窗
const handleCloseDetailDialog = () => {
detailDialogVisible.value = false;
detailData.value = null;
};
// 拆分图片URL字符串为数组
const splitImageUrls = (urlString) => {
if (!urlString) return [];
// 拆分并过滤空字符串(处理可能的首尾逗号或连续逗号)
return urlString.split(',').filter((url) => url.trim().length > 0);
};
// 处理图片加载失败
const handleImageError = (event, index) => {
// 可以设置一个默认图片占位符
event.target.src = '';
console.error(`图片加载失败: 索引 ${index}`);
};
// 查看任务详情
const handleView = async (task) => {
if (!task || !task.id) {
ElMessage.warning('任务ID不存在请刷新页面重试');
return;
}
detailDialogVisible.value = true;
isDetailLoading.value = true;
try {
// 调用接口获取详情数据
const res = await qiangxiuDetail(task.id);
if (res.code === 200 && res.data) {
detailData.value = res.data;
} else {
ElMessage.error(`获取详情失败:${res?.msg || '未知错误'}`);
}
} catch (error) {
console.error('获取任务详情异常:', error);
ElMessage.error('获取详情失败,请稍后重试');
} finally {
isDetailLoading.value = false;
}
};
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');
};
// 加载状态
const loading = ref(false);
// 分配任务弹窗相关
const assignDialogVisible = ref(false);
const assignTaskForm = ref({ taskId: '', sendPerson: '', expectedTime: '' });
const usersList = ref([]);
const loadingUsers = ref(false);
const assignTaskRules = {
sendPerson: [{ required: true, message: '请选择维修人', trigger: 'change' }],
expectedTime: [{ required: true, message: '请选择预计完成时间', trigger: 'change' }]
};
const assignTaskFormRef = ref(null);
// 结果输入弹窗相关状态
const resultDialogVisible = ref(false);
const currentTaskId = ref('');
const reportFinal = ref('');
// 处理结果表单验证规则
const resultFormRules = {
reportFinal: [
{
required: true,
message: '请输入处理结果',
trigger: 'blur'
},
{
min: 5,
max: 500,
message: '处理结果长度在 5 到 500 个字符之间',
trigger: 'blur'
}
]
};
// 表单引用
const resultFormRef = ref(null);
// 获取用户列表
const getUsersList = async () => {
loadingUsers.value = true;
try {
const res = await xunjianUserlist();
if (res.code === 200 && res.rows && Array.isArray(res.rows)) {
usersList.value = res.rows.map((user) => ({ id: String(user.userId || ''), name: user.userName || '未知用户' }));
} else {
usersList.value = [];
ElMessage.error('获取用户列表失败');
}
} catch (error) {
console.error('获取用户列表异常:', error);
ElMessage.error('获取用户列表失败');
usersList.value = [];
} finally {
loadingUsers.value = false;
}
};
// 处理任务操作按钮点击事件
const handleAction = async (task) => {
try {
if (!task || !task.id) {
ElMessage.warning('任务ID不存在请刷新页面重试');
console.error('任务缺少有效id任务数据', task);
return;
}
// 点击分配按钮:打开分配弹窗
if (task.actionText === '分配') {
// 重置表单并设置任务ID
assignTaskForm.value = { taskId: task.id, sendPerson: '' };
assignDialogVisible.value = true;
// 打开弹窗时获取用户列表
if (usersList.value.length === 0) {
await getUsersList();
}
if (usersList.value.length === 0) {
ElMessage.error('无可用维修人员,请先配置维修人员信息');
assignDialogVisible.value = false;
}
}
// 点击跟进按钮:原有逻辑
else if (task.actionText === '跟进') {
resultDialogVisible.value = true;
currentTaskId.value = task.id;
}
// 其他操作(如评价)
else {
console.log('其他操作:', task.actionText);
}
} catch (error) {
console.error('任务操作失败:', error, '当前任务数据:', task);
ElMessage.error('操作失败,请联系技术支持');
}
};
// 提交分配任务
const handleSubmitAssign = async () => {
if (!assignTaskFormRef.value) return;
try {
await assignTaskFormRef.value.validate();
// 找到原始任务数据
const originalTask = tasks.value.find((t) => t.id === assignTaskForm.value.taskId);
if (!originalTask) {
ElMessage.warning('未找到任务完整数据,请刷新重试');
return;
}
// 找到选中的维修人员
const selectedUser = usersList.value.find((u) => u.id === assignTaskForm.value.sendPerson);
if (!selectedUser) {
ElMessage.error('未找到选中的维修人员');
return;
}
// 构造完整的更新参数
const updateData = {
id: assignTaskForm.value.taskId,
status: '2', // 处理中状态
sendPerson: selectedUser.id,
sendPersonName: selectedUser.name,
sendPersonVo: {
id: selectedUser.id,
userName: selectedUser.name
},
// 包含后端所需的其他必要字段
name: originalTask.title,
type: originalTask.type || '1',
level: mapPriorityLevel(originalTask.level), // 传入实际的level值1常规、2紧急、3致命
reportName: originalTask.reporter,
reportPhone: originalTask.reportPhone || '',
position: originalTask.position || '',
reportInfo: originalTask.reportInfo || '',
projectId: 1,
// 使用用户选择的预计完成时间
expectedTime: assignTaskForm.value.expectedTime || originalTask.expectedTime,
// 确保support字段处理一致
support: originalTask.needSupport || ''
};
// 调用接口更新
const res = await updateqiangxiu(updateData);
if (res.code === 200) {
ElMessage.success(`任务已分配给【${selectedUser.name}】,状态更新为处理中`);
assignDialogVisible.value = false;
getTaskList(); // 刷新列表
} else {
const errorMsg = res.msg || '未知错误';
console.error(`任务分配失败:${errorMsg},请求参数:`, updateData);
ElMessage.error(`分配失败:${errorMsg}`);
}
} catch (error) {
if (error instanceof Error) {
ElMessage.error(`操作失败:${error.message}`);
} else if (error !== false) {
ElMessage.error('操作失败:未知错误');
}
}
};
// 关闭分配弹窗
const handleCloseAssign = () => {
assignDialogVisible.value = false;
if (assignTaskFormRef.value) {
assignTaskFormRef.value.clearValidate();
}
};
// 保存结果
const handleSaveResult = async () => {
try {
if (!currentTaskId.value) {
ElMessage.warning('任务ID不存在');
return;
}
if (!reportFinal.value.trim()) {
ElMessage.warning('请输入处理结果');
return;
}
// 1. 查找当前任务的完整数据
const originalTask = tasks.value.find((t) => t.id === currentTaskId.value);
if (!originalTask) {
ElMessage.warning('未找到任务完整数据,请刷新重试');
console.error('未找到任务完整数据任务ID', currentTaskId.value);
return;
}
// 2. 生成当前时间作为完成时间
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const completeTime = `${year}-${month}-${day} ${hours}:${minutes}`;
// 3. 构造更新参数,确保包含所有必要字段
const updateData = {
id: currentTaskId.value,
status: '3', // 已完成状态
reportFinishTime: completeTime,
reportFinal: reportFinal.value,
expectedTime: originalTask.expectedTime,
position: originalTask.position || '',
name: originalTask.title,
type: originalTask.type || '1',
level: mapPriorityLevel(originalTask.level),
reportName: originalTask.reporter,
reportPhone: originalTask.reportPhone || '',
reportInfo: originalTask.reportInfo || '',
projectId: 1,
support: originalTask.needSupport || '',
// 维修人员信息
sendPerson: originalTask.sendPersonVo?.id || '',
sendPersonName: originalTask.sendPersonVo?.userName || '',
sendPersonVo: originalTask.sendPersonVo || {}
};
// 4. 调用接口更新
const res = await updateqiangxiu(updateData);
if (res.code === 200) {
ElMessage.success('处理结果保存成功');
resultDialogVisible.value = false;
reportFinal.value = '';
getTaskList(); // 刷新列表
} else {
const errorMsg = res.msg || '未知错误';
console.error(`保存结果失败:${errorMsg},请求参数:`, updateData);
ElMessage.error(`保存失败:${errorMsg}`);
}
} catch (error) {
console.error('保存处理结果失败:', error);
ElMessage.error('保存失败,请联系技术支持');
}
};
// 状态映射辅助函数
function mapStatusToKey(status) {
const statusMap = {
'1': 'pending', // 待处理
'2': 'executing', // 处理中
'3': 'completed' // 已完成
};
return statusMap[status] || 'pending';
}
// 获取状态文本
function getStatusText(status) {
const statusMap = {
'1': '待处理',
'2': '处理中',
'3': '已完成'
};
return statusMap[status] || '未知状态';
}
// 获取左侧状态线样式类
function getLeftLineClass(status, level) {
if (status === '3') return 'left-line-completed';
const levelMap = {
'1': 'left-line-low',
'2': 'left-line-medium',
'3': 'left-line-high'
};
return levelMap[level] || 'left-line-low';
}
// 获取优先级样式
function getPriorityClass(level) {
const levelMap = {
'1': 'priority-low',
'2': 'priority-medium',
'3': 'priority-high'
};
return levelMap[level] || 'priority-low';
}
// 获取优先级文本
function getPriorityText(level) {
const levelMap = {
'1': '低优先级',
'2': '中优先级',
'3': '高优先级'
};
return levelMap[level] || '普通优先级';
}
// 获取操作按钮文本
function getActionText(status) {
const actionMap = {
'1': '分配',
'2': '跟进',
'3': '评价'
};
return actionMap[status] || '查看';
}
// 获取操作按钮样式类
function getActionClass(status) {
const actionMap = {
'1': 'assign-btn',
'2': 'follow-btn',
'3': 'evaluate-btn'
};
return actionMap[status] || 'view-btn';
}
// 格式化日期时间
function formatDate(date) {
if (!date) return '';
const d = new Date(date);
if (isNaN(d.getTime())) return '';
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
const hours = String(d.getHours()).padStart(2, '0');
const minutes = String(d.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
}
// 获取抢修任务列表
defineExpose({ getTaskList });
async function getTaskList() {
loading.value = true;
try {
// 构建请求参数,包含筛选条件
const requestParams = {
projectId: 1,
pageNum: currentPage.value,
pageSize: pageSize.value
};
// 添加任务状态筛选条件
if (taskStatus.value && taskStatus.value !== 'all') {
requestParams.status = taskStatus.value;
}
// 添加计划类型筛选条件
if (planType.value && planType.value !== 'all') {
requestParams.planType = planType.value;
}
// 添加执行人筛选条件
if (executor.value && executor.value !== 'all') {
requestParams.executor = executor.value;
}
const res = await qiangxiulist(requestParams);
if (res.code === 200 && res.rows) {
total.value = res.total || 0;
// 将API返回的数据转换为前端显示所需的格式
tasks.value = res.rows.map((item) => ({
id: item.id,
title: item.name || '未命名抢修任务',
status: mapStatusToKey(item.status),
statusText: getStatusText(item.status),
leftLineClass: getLeftLineClass(item.status, item.level),
priorityClass: getPriorityClass(item.level),
priority: getPriorityText(item.level),
// 修复报修时间字段名使用与模板一致的createTime
createTime: formatDate(item.createTime),
// 修复报修人字段使用reportName
reporter: item.reportName || '未知报修人',
// 修复维修人字段从sendPersonVo对象中获取用户名
maintainer: item.sendPersonVo?.userName || '未分配',
completeTime: item.reportFinishTime ? formatDate(item.reportFinishTime) : '',
actionText: getActionText(item.status),
actionClass: getActionClass(item.status),
reportInfo: item.reportInfo,
position: item.position,
fileUrl: item.fileUrl,
reportPhone: item.reportPhone || '',
type: item.type || '',
// 保留原始数据用于详情查看
sendPersonVo: item.sendPersonVo,
faultType: getFaultTypeText(item.type),
// 保留expectedTime字段用于任务修改
expectedTime: item.expectedTime || '',
// 添加needSupport字段确保从API返回数据中获取实际值
needSupport: item.support || ''
}));
} else {
tasks.value = [];
total.value = 0;
console.error('获取抢修任务列表失败:', res.msg);
}
} catch (error) {
console.error('获取抢修任务列表异常:', error);
tasks.value = [];
total.value = 0;
} finally {
loading.value = false;
}
}
// 根据类型获取故障类型文本
function getFaultTypeText(type) {
const typeMap = {
'1': '电力故障',
'2': '设备故障',
'3': '供水问题',
'4': '网络故障',
'5': '设施故障'
};
return typeMap[type] || '其他故障';
}
// 初始化时调用接口获取数据
setTimeout(() => {
getTaskList();
}, 0);
</script>
<style scoped>
.inspection-tasks {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
/* 任务卡片样式 - 恢复优先级标签背景色 */
.task-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.task-card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
padding: 16px;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
min-height: 260px; /* 增加高度以适应新增的预计完成时间 */
}
/* 左侧状态线基础样式 */
.task-card::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
}
/* 详情弹窗样式 - 与保修管理页面保持一致 */
.custom-experiment-dialog .el-dialog__body {
max-height: 60vh;
overflow-y: auto;
padding: 24px;
}
.task-detail-container {
padding: 10px 0;
}
/* 详情卡片样式 */
.detail-card {
background-color: #fff;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
border: 1px solid #f0f2f5;
}
.card-title {
font-size: 16px;
font-weight: 600;
color: #1d2129;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 2px solid #409eff;
}
.card-content {
padding: 0 4px;
}
/* 信息行和信息项样式 */
.info-row {
display: flex;
margin-bottom: 16px;
flex-wrap: wrap;
}
.info-item {
flex: 0 0 50%;
margin-bottom: 12px;
display: flex;
align-items: flex-start;
}
.info-item.full-width {
flex: 0 0 100%;
}
.info-label {
font-weight: 500;
color: #86909c;
margin-right: 8px;
min-width: 80px;
flex-shrink: 0;
}
.info-value {
color: #4e5969;
flex: 1;
word-break: break-all;
font-size: 14px;
}
/* 图片容器样式 */
.images-container {
display: flex;
flex-wrap: wrap;
gap: 16px;
margin-top: 12px;
padding: 10px;
background-color: #f9f9f9;
border-radius: 8px;
}
/* 单个图片项样式 */
.image-item {
flex: 0 0 auto;
width: 200px; /* 固定宽度 */
height: 160px; /* 固定高度 */
border-radius: 6px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: transform 0.3s ease;
}
.image-item:hover {
transform: scale(1.03);
}
/* 图片样式 */
.detail-image {
width: 100%;
height: 100%;
object-fit: cover; /* 保持比例填充容器 */
display: block;
border-radius: 4px;
transition: transform 0.3s ease;
}
.detail-image:hover {
transform: scale(1.02);
}
/* 图片加载失败样式 */
.detail-image[src=''] {
background-color: #f0f0f0;
display: flex;
}
/* 骨架屏样式 */
.skeleton-loading {
display: flex;
flex-direction: column;
gap: 16px;
}
.skeleton-card {
background-color: #f5f5f5;
border-radius: 8px;
padding: 16px;
}
.skeleton-header {
height: 20px;
width: 30%;
background-color: #e0e0e0;
border-radius: 4px;
margin-bottom: 12px;
}
.skeleton-content {
display: flex;
flex-direction: column;
gap: 8px;
}
.skeleton-row {
height: 16px;
background-color: #e0e0e0;
border-radius: 4px;
}
/* 无数据提示 */
.no-info {
text-align: center;
color: #909399;
padding: 60px 20px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.custom-experiment-dialog {
width: 95% !important;
}
.info-item {
flex: 0 0 100%;
}
}
/* 加载状态 */
.loading-state {
display: flex;
align-items: center;
justify-content: center;
padding: 40px 0;
color: #909399;
}
.loading-state .el-icon {
margin-right: 8px;
}
/* 动画效果 */
@keyframes skeleton-loading {
0% {
opacity: 0.6;
}
50% {
opacity: 1;
}
100% {
opacity: 0.6;
}
}
/* 响应式设计 */
@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;
}
.custom-experiment-dialog {
width: 95% !important;
}
.info-item {
flex: 0 0 100%;
}
.image-item {
flex: 0 0 100%;
max-width: 100%;
}
}
/* 美化按钮样式 */
.dialog-footer .el-button {
min-width: 80px;
height: 36px;
border-radius: 6px;
font-size: 14px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
margin: 0 8px;
}
.dialog-footer .el-button--primary {
background-color: #409eff;
border-color: #409eff;
color: #fff;
font-weight: 500;
}
.dialog-footer .el-button--primary:hover {
background-color: #66b1ff;
border-color: #66b1ff;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
}
.dialog-footer .el-button--default {
background-color: #fff;
border-color: #dcdfe6;
color: #606266;
}
.dialog-footer .el-button--default:hover {
background-color: #f5f7fa;
border-color: #c6e2ff;
color: #409eff;
transform: translateY(-1px);
}
/* 分页区域样式 */
.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;
}
/* 左侧状态线颜色样式 */
.left-line-pending::before {
background-color: #1890ff;
}
.left-line-executing::before {
background-color: #fa8c16;
}
.left-line-completed::before {
background-color: #52c41a;
}
/* 优先级状态线颜色样式 - 与getLeftLineClass函数返回类名匹配 */
.left-line-low::before {
background-color: #1677ff;
}
.left-line-medium::before {
background-color: #fa8c16;
}
.left-line-high::before {
background-color: #ff4d4f;
}
.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;
}
.priority-high {
background-color: #ffebee;
border: 1px solid #f44336;
color: #f44336;
}
.priority-medium {
background-color: #fff8e1;
border: 1px solid #ffc107;
color: #ffc107;
}
.priority-low {
background-color: #e8f5e9;
border: 1px solid #4caf50;
color: #4caf50;
}
.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;
}
.task-result {
display: flex;
margin: 10px 0;
font-size: 13px;
padding-top: 8px;
border-top: 1px dashed #f0f2f5;
}
.task-actions {
display: flex;
justify-content: flex-end;
align-items: center;
padding-top: 12px;
border-top: 1px solid #f0f2f5;
position: absolute;
bottom: 16px;
right: 16px;
left: 16px;
background-color: #fff;
padding: 12px 0 0 0;
z-index: 10;
}
.action-btn {
font-size: 13px;
padding: 4px 10px;
}
.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;
}
.evaluate-btn {
background-color: #00b42a;
border-color: #00b42a;
}
.evaluate-btn:hover {
background-color: #008718;
border-color: #008718;
}
.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-card[data-v-2668390e]::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
}
.task-details {
margin-bottom: 16px;
}
.detail-item {
display: flex;
margin-bottom: 8px;
font-size: 12px;
line-height: 1.5;
}
.detail-label {
flex: 0 0 70px;
color: #86909c;
}
.detail-value {
flex: 1;
color: #4e5969;
word-break: break-all;
}
.task-result {
display: flex;
margin: 8px 0;
font-size: 12px;
padding-top: 8px;
border-top: 1px dashed #f0f2f5;
}
.task-actions {
display: flex;
justify-content: flex-end;
align-items: center;
padding-top: 12px;
border-top: 1px solid #f0f2f5;
position: absolute;
bottom: 16px;
right: 16px;
left: 16px;
background-color: #fff;
padding: 12px 0 0 0;
z-index: 10;
}
.task-actions .el-button {
border-radius: 16px;
padding: 6px 16px;
}
.action-btn {
font-size: 12px;
padding: 4px 12px;
}
.view-btn {
color: #165dff;
}
.view-btn:hover {
color: #0e42d2;
background-color: #e8f3ff;
}
.follow-btn {
background-color: #165dff;
border-color: #165dff;
}
.follow-btn:hover {
background-color: #0e42d2;
border-color: #0e42d2;
}
.assign-btn {
background-color: #ff7d00;
border-color: #ff7d00;
}
.assign-btn:hover {
background-color: #e86a00;
border-color: #e86a00;
}
/* 其他样式保持不变 */
.tabs-wrapper {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.filter-bar {
background-color: #fff;
border-radius: 8px;
margin-bottom: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
padding: 16px 24px;
}
.filter-container {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
width: 100%;
}
.filter-item {
flex-shrink: 0;
}
.filter-bar .el-select {
width: 180px;
height: 36px;
}
.filter-actions {
margin-left: auto;
display: flex;
gap: 12px;
flex-shrink: 0;
}
.search-btn,
.create-btn {
height: 36px;
border-radius: 4px;
}
.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>