This commit is contained in:
dhr
2025-09-22 15:42:13 +08:00
parent aa443c3d62
commit fc3abeb4c0
14 changed files with 4215 additions and 1572 deletions

View File

@ -0,0 +1,49 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
//查询列表
export const baoxiulist = (query) => {
return request({
url: '/ops/report/list',
method: 'get',
params: query
});
};
//新增待办事项
export const addbaoxiu = (data) => {
return request({
url: '/ops/report',
method: 'post',
data: data
});
};
//修改待办事项
export const updatebaoxiu = (data) => {
return request({
url: '/ops/report',
method: 'put',
data: data
});
};
//删除待办事项
export function delbaoxiu(ids) {
return request({
url: `/ops/report/${ids}`, // 拼接ids作为路径参数
method: 'delete'
});
}
export const baoxiuDetail = (id) => {
return request({
url: `/ops/report/${id}`,
method: 'get'
});
};
export const uploadbaoxiu = (data) => {
return request({
url: '/resource/oss/upload',
method: 'post',
data: data
});
};

View File

@ -0,0 +1,49 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
//查询列表
export const shiyanlist = (query) => {
return request({
url: '/ops/testPlan/list',
method: 'get',
params: query
});
};
//新增
export const addshiyan = (data) => {
return request({
url: '/ops/testPlan',
method: 'post',
data: data
});
};
//修改
export const updateshiyan = (data) => {
return request({
url: '/ops/testPlan',
method: 'put',
data: data
});
};
//删除
export const delshiyan = (ids) => {
return request({
url: `/ops/testPlan${ids}`,
method: 'delete'
});
};
//查询人员
export const shiyanUserlist = (query) => {
return request({
url: '/ops/constructionUser/list',
method: 'get',
params: query
});
};
//详情
export const shiyanDetail = (id) => {
return request({
url: `/ops/testPlan/${id}`,
method: 'get'
});
};

View File

@ -0,0 +1,41 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
//查询列表
export const syrenwulist = (query) => {
return request({
url: '/ops/testTask/list',
method: 'get',
params: query
});
};
//新增
export const addsyrenwu = (data) => {
return request({
url: '/ops/testTask',
method: 'post',
data: data
});
};
//修改
export const updatesyrenwu = (data) => {
return request({
url: '/ops/testTask',
method: 'put',
data: data
});
};
//删除
export const delsyrenwu = (ids) => {
return request({
url: `/ops/testTask${ids}`,
method: 'delete'
});
};
//详情
export const syrenwuDetail = (id) => {
return request({
url: `/ops/testTask/${id}`,
method: 'get'
});
};

View File

@ -47,3 +47,10 @@ export const xunjianItemlist = (query) => {
params: query
});
};
//详情
export const xunjianDetail = (id) => {
return request({
url: `/ops/plan/${id}`,
method: 'get'
});
};

View File

@ -0,0 +1,10 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
//查询列表
export const xunjianjilu = (query) => {
return request({
url: '/ops/task/record',
method: 'get',
params: query
});
};

View File

@ -0,0 +1,46 @@
import request from '@/utils/request';
export const xjrenwulist = (query) => {
return request({
url: '/ops/task/list',
method: 'get',
params: query
});
};
//新增
export const addxjrenwu = (data) => {
return request({
url: '/ops/task',
method: 'post',
data: data
});
};
//修改
export const updatexjrenwu = (data) => {
return request({
url: '/ops/task',
method: 'put',
data: data
});
};
//删除
export const delxjrenwu = (ids) => {
return request({
url: `/ops/task/${ids}`,
method: 'delete'
});
};
//详情
export const xjrenwuDetail = (id) => {
return request({
url: `/ops/task/${id}`,
method: 'get'
});
};
//导出
export const xjrenwuExport = (data) => {
return request({
url: '/ops/task/export',
method: 'post',
data: data
});
};

File diff suppressed because it is too large Load Diff

View File

@ -129,12 +129,12 @@
<el-dialog
v-model="createTaskDialogVisible"
title="新建报修任务"
width="800px"
width="900px"
:before-close="handleCancelCreateTask"
custom-class="beautiful-dialog"
center
>
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="100px" class="elegant-form">
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="120px" class="elegant-form">
<el-form-item label="报修名称*" prop="repairName">
<el-input v-model="createTaskForm.repairName" placeholder="简要描述报修内容" />
</el-form-item>
@ -143,10 +143,8 @@
<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="device" />
<el-option label="软件故障" value="software" />
<el-option label="网络故障" value="network" />
<el-option label="环境问题" value="environment" />
</el-select>
</el-form-item>
</el-col>
@ -161,6 +159,12 @@
</el-col>
</el-row>
<el-form-item label="指派维修人*" prop="sendPerson">
<el-select v-model="createTaskForm.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-item label="详细描述*" prop="detailedDescription">
<el-input v-model="createTaskForm.detailedDescription" type="textarea" :rows="4" placeholder="详细描述故障现象、发生时间、位置等信息" />
</el-form-item>
@ -169,7 +173,8 @@
<el-input v-model="createTaskForm.faultLocation" placeholder="例如A区102" />
</el-form-item>
<el-form-item label="上传图片(可选)">
<el-form-item label="上传图片(可选)" width="100%">
<file-upload v-model="createTaskForm.file" :fileType="['png', 'jpg', 'jpeg']">
<div class="upload-container">
<div class="upload-box">
<i class="el-icon-plus avatar-uploader-icon"></i>
@ -177,6 +182,23 @@
<div class="upload-hint">支持JPGPNG格式最多3张</div>
</div>
</div>
</file-upload>
<!-- <el-upload
class="avatar-uploader"
:file-list="createTaskForm.fileList"
:on-change="handleFileChange"
:before-remove="beforeRemove"
:on-remove="handleRemove"
:auto-upload="false"
multiple
:limit="3"
:on-exceed="handleExceed"
>
</el-upload> -->
<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">
@ -196,7 +218,7 @@
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCancelCreateTask">取消</el-button>
<el-button type="primary" @click="handleSaveTask">保存计划</el-button>
<el-button type="primary" @click="handleSaveTask">保存报修任务</el-button>
</span>
</template>
</el-dialog>
@ -205,10 +227,12 @@
</template>
<script setup>
import { ref, computed } from 'vue';
import { ref, computed, onMounted } from 'vue';
import router from '@/router';
import TitleComponent from './TitleComponent.vue';
import { baoxiulist, baoxiuDetail, delbaoxiu, updatebaoxiu, addbaoxiu, uploadbaoxiu } from '@/api/zhinengxunjian/baoxiou/index';
import { xunjianUserlist } from '@/api/zhinengxunjian/xunjian';
import { ElMessage } from 'element-plus';
// 激活的选项卡
const activeTab = ref('task');
@ -217,128 +241,165 @@ const taskStatus = ref('');
const planType = ref('');
const executor = ref('');
// 任务数据 - 恢复优先级标签样式和预计完成时间
const tasks = ref([
{
title: '服务器A1电源故障',
status: 'executing',
statusText: '处理中',
leftLineClass: 'left-line-high',
priorityClass: 'priority-high', // 恢复优先级标签样式类
priority: '高优先级',
reportTime: '2025-06-16 08:30',
reporter: '李明',
maintainer: '张明',
expectedCompleteTime: '2025-06-16 12:00', // 恢复预计完成时间
actionText: '跟进',
actionClass: 'follow-btn'
},
{
title: '机房环境检查',
status: 'pending',
statusText: '待处理',
leftLineClass: 'left-line-medium',
priorityClass: 'priority-medium', // 恢复优先级标签样式类
priority: '中优先级',
reportTime: '2025-06-16 08:30',
reporter: '张伟',
maintainer: '未分配',
expectedCompleteTime: '2025-06-16 18:00', // 恢复预计完成时间
actionText: '分配',
actionClass: 'assign-btn'
},
{
title: '测试软件授权过期',
status: 'executing',
statusText: '处理中',
leftLineClass: 'left-line-low',
priorityClass: 'priority-low', // 恢复优先级标签样式类
priority: '低优先级',
reportTime: '2025-06-16 08:30',
reporter: '李明',
maintainer: '李阳',
expectedCompleteTime: '2025-06-17 09:00', // 恢复预计完成时间
actionText: '跟进',
actionClass: 'follow-btn'
},
{
title: '打印机卡纸故障',
status: 'completed',
statusText: '已完成',
leftLineClass: 'left-line-completed',
priorityClass: 'priority-low', // 恢复优先级标签样式类
priority: '低优先级',
reportTime: '2025-06-17 08:30',
reporter: '李明',
maintainer: '张明',
expectedCompleteTime: '2025-06-17 10:00', // 恢复预计完成时间
completeTime: '2025-06-17 09:15',
actionText: '评价',
actionClass: 'evaluate-btn'
},
{
title: '服务器A1电源故障',
status: 'executing',
statusText: '处理中',
leftLineClass: 'left-line-high',
priorityClass: 'priority-high',
priority: '高优先级',
reportTime: '2025-06-16 08:30',
reporter: '李明',
maintainer: '张明',
expectedCompleteTime: '2025-06-16 12:00',
actionText: '跟进',
actionClass: 'follow-btn'
},
{
title: '机房环境检查',
status: 'pending',
statusText: '待处理',
leftLineClass: 'left-line-medium',
priorityClass: 'priority-medium',
priority: '中优先级',
reportTime: '2025-06-16 08:30',
reporter: '张伟',
maintainer: '未分配',
expectedCompleteTime: '2025-06-16 18:00',
actionText: '分配',
actionClass: 'assign-btn'
},
{
title: '测试软件授权过期',
status: 'executing',
statusText: '处理中',
leftLineClass: 'left-line-low',
priorityClass: 'priority-low',
priority: '低优先级',
reportTime: '2025-06-16 08:30',
reporter: '李明',
maintainer: '李阳',
expectedCompleteTime: '2025-06-17 09:00',
actionText: '跟进',
actionClass: 'follow-btn'
},
{
title: '打印机卡纸故障',
status: 'completed',
statusText: '已完成',
leftLineClass: 'left-line-completed',
priorityClass: 'priority-low',
priority: '低优先级',
reportTime: '2025-06-17 08:30',
reporter: '李明',
maintainer: '张明',
expectedCompleteTime: '2025-06-17 10:00',
completeTime: '2025-06-17 09:15',
actionText: '评价',
actionClass: 'evaluate-btn'
}
]);
// 任务数据 - 初始为空数组
const tasks = ref([]);
// 分页相关
const currentPage = ref(1);
const pageSize = ref(8);
const total = ref(tasks.value.length);
const total = ref(0);
const loading = ref(false);
// 获取报修任务列表
defineExpose({ getTaskList });
async function getTaskList() {
loading.value = true;
try {
const res = await baoxiulist({
pageNum: currentPage.value,
pageSize: pageSize.value,
status: taskStatus.value,
type: planType.value,
executor: executor.value
});
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),
reportTime: formatDate(item.reportTime),
reporter: item.reportName || '未知报修人',
maintainer: item.sendPerson ? `维修人ID: ${item.sendPerson}` : '未分配',
expectedCompleteTime: getExpectedCompleteTime(item.status),
completeTime: item.completeTime ? formatDate(item.completeTime) : '',
actionText: getActionText(item.status),
actionClass: getActionClass(item.status),
reportInfo: item.reportInfo,
position: item.position,
fileUrl: item.fileUrl
}));
} 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 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 getPriorityText(level) {
const levelMap = {
'1': '低优先级',
'2': '中优先级',
'3': '高优先级'
};
return levelMap[level] || '普通优先级';
}
// 获取优先级样式类
function getPriorityClass(level) {
const levelMap = {
'1': 'priority-low',
'2': 'priority-medium',
'3': 'priority-high'
};
return levelMap[level] || 'priority-low';
}
// 获取左侧状态线样式类
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 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 getExpectedCompleteTime(status) {
if (status === '3') return ''; // 已完成任务不需要显示预计时间
const now = new Date();
// 简单估算待处理任务默认当天18:00前完成处理中任务默认2小时内完成
if (status === '1') {
now.setHours(18, 0, 0, 0);
} else {
now.setHours(now.getHours() + 2);
}
return formatDate(now);
}
// 格式化日期时间
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}`;
}
// 状态排序映射
const statusOrder = {
@ -363,20 +424,22 @@ const pagedTasks = computed(() => {
// 搜索处理
const handleSearch = () => {
currentPage.value = 1; // 重置到第一页
// 实际应用中这里会根据筛选条件过滤数据
getTaskList(); // 调用接口获取数据
};
// 创建报修任务弹窗相关
const createTaskDialogVisible = ref(false);
const createTaskFormRef = ref(null);
const createTaskForm = ref({
repairName: '',
briefDescription: '',
repairType: '',
priority: '',
detailedDescription: '',
faultLocation: '',
contactPerson: '',
contactPhone: ''
contactPhone: '',
sendPerson: '', // 指派维修人
file: '' // 上传的文件列表
});
const createTaskRules = {
@ -386,58 +449,303 @@ const createTaskRules = {
detailedDescription: [{ required: true, message: '请输入详细描述', trigger: 'blur' }],
faultLocation: [{ required: true, message: '请输入故障位置', trigger: 'blur' }],
contactPerson: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
contactPhone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }]
contactPhone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
sendPerson: [{ required: true, message: '请选择维修人', trigger: 'change' }]
};
// 用户列表(维修人)
const usersList = ref([]);
const loadingUsers = ref(false);
// 获取用户列表
const getUsersList = async () => {
loadingUsers.value = true;
try {
const res = await xunjianUserlist();
// 根据接口返回格式成功码是200用户数据在rows数组中
if (res.code === 200 && res.rows && Array.isArray(res.rows)) {
// 映射用户数据使用id作为valueuserName作为显示名称
usersList.value = res.rows.map((user) => ({
id: user.id,
name: user.userName
}));
} else {
usersList.value = [];
console.error('获取用户列表失败:', res.msg || '未知错误');
}
} catch (error) {
console.error('获取用户列表异常:', error);
usersList.value = [];
} finally {
loadingUsers.value = false;
}
};
const isSubmitting = ref(false); // 防止重复提交的状态标记
const isUploading = ref(false); // 防止重复上传的状态标记
// 上传文件方法
const uploadFiles = async (files) => {
// 防止重复上传
if (isUploading.value) {
ElMessage.warning('数据正在处理中,请稍候...');
return [];
}
try {
isUploading.value = true;
const formData = new FormData();
// 关键修复:将字段名从'files'改为'file',匹配后端要求的'file'字段
files.forEach((file) => {
formData.append('file', file.raw); // 这里将'files'改为'file'
});
const res = await uploadbaoxiu(formData);
if (res.code === 200 && res.data && Array.isArray(res.data)) {
return res.data.map((item) => ({
fileId: item.ossId,
fileUrl: item.url
}));
} else {
console.error('文件上传失败:', res.msg);
throw new Error(res.msg || '文件上传失败');
}
} catch (error) {
console.error('文件上传异常:', error);
if (error.message.includes('重复提交')) {
throw new Error('操作过于频繁,请稍后再试');
}
throw error;
} finally {
isUploading.value = false;
}
};
const handleFileChange = (file, fileList) => {
// 只处理刚添加的文件
if (file.status === 'ready') {
// 验证文件格式和大小
const isJPG = file.raw.type === 'image/jpeg' || file.raw.type === 'image/jpg';
const isPNG = file.raw.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG && !isPNG) {
ElMessage.error('上传图片只能是 JPG/JPEG 或 PNG 格式!');
// 从文件列表中移除不符合要求的文件
createTaskForm.value.fileList = fileList.filter((f) => f.uid !== file.uid);
return;
}
if (!isLt2M) {
ElMessage.error('上传图片大小不能超过 2MB!');
// 从文件列表中移除不符合要求的文件
createTaskForm.value.fileList = fileList.filter((f) => f.uid !== file.uid);
return;
}
// 保存验证通过的文件到表单
createTaskForm.value.fileList = fileList;
}
};
const handleExceed = (files, fileList) => {
ElMessage.warning(`当前限制选择 3 张图片,本次选择了 ${files.length} 张,共选择了 ${files.length + fileList.length}`);
};
// 文件移除前的钩子
const beforeRemove = (file, fileList) => {
return window.confirm(`确定移除 ${file.name}`);
};
// 文件移除时的钩子
const handleRemove = (file, fileList) => {
createTaskForm.value.fileList = fileList;
ElMessage.info(`已移除 ${file.name}`);
};
// 创建任务
const handleCreateTask = () => {
const handleCreateTask = async () => {
createTaskDialogVisible.value = true;
// 打开弹窗时获取用户列表
await getUsersList();
};
// 保存报修任务
const handleSaveTask = () => {
// 模拟保存报修任务逻辑
console.log('保存报修任务:', createTaskForm.value);
const handleSaveTask = async () => {
console.log(createTaskForm.value.file);
// 防止重复提交
if (!createTaskFormRef.value || isSubmitting.value) return;
try {
// 设置提交状态为true
isSubmitting.value = true;
// 先验证表单
await createTaskFormRef.value.validate();
// 上传选中的文件
let fileIds = [];
let fileUrls = [];
if (createTaskForm.value.fileList && createTaskForm.value.fileList.length > 0) {
ElMessage.info(`开始上传 ${createTaskForm.value.fileList.length} 张图片...`);
const uploadResults = await uploadFiles(createTaskForm.value.fileList);
// 提取上传结果
fileIds = uploadResults.map((result) => result.fileId);
fileUrls = uploadResults.map((result) => result.fileUrl);
ElMessage.success(`图片上传成功,共 ${uploadResults.length}`);
}
// 准备请求数据
const requestData = {
projectId: 1,
name: createTaskForm.value.repairName,
type: mapRepairType(createTaskForm.value.repairType),
status: '1', // 默认为待处理状态
level: mapPriorityLevel(createTaskForm.value.priority),
sendPerson: parseInt(createTaskForm.value.sendPerson),
reportInfo: createTaskForm.value.detailedDescription,
position: createTaskForm.value.faultLocation,
fileId: fileIds.join(','), // 用逗号分隔多个文件ID
fileUrl: fileUrls.join(','), // 用逗号分隔多个文件URL
reportName: createTaskForm.value.contactPerson,
reportPhone: createTaskForm.value.contactPhone
};
// 调用添加报修任务接口
const res = await addbaoxiu(requestData);
// 检查接口返回是否成功使用code=200作为成功标志
if (res.code === 200) {
// 显示成功提示
ElMessage.success('报修任务创建成功');
// 关闭弹窗
createTaskDialogVisible.value = false;
// 重置表单
resetCreateForm();
// 刷新任务列表
await getTaskList();
} else {
ElMessage.error(`创建失败:${res.msg || '未知错误'}`);
}
} catch (error) {
// 错误处理
if (error instanceof Error) {
ElMessage.error(`操作失败:${error.message}`);
} else if (error === false) {
// 表单验证失败,不做处理
} else {
ElMessage.error('操作失败:未知错误');
}
} finally {
// 无论成功失败,都重置提交状态
isSubmitting.value = false;
}
};
// 重置创建表单
function resetCreateForm() {
createTaskForm.value = {
repairName: '',
briefDescription: '',
repairType: '',
priority: '',
detailedDescription: '',
faultLocation: '',
contactPerson: '',
contactPhone: ''
contactPhone: '',
sendPerson: '',
fileList: []
};
// 这里可以添加成功提示和刷新任务列表的逻辑
if (createTaskFormRef.value) {
createTaskFormRef.value.resetFields();
}
}
// 报修类型映射 - 1硬件2软件
function mapRepairType(type) {
const typeMap = {
'device': '1', // 硬件
'software': '2' // 软件
};
return typeMap[type] || '1';
}
// 优先级映射 - 1低优先2中优先3高优先
function mapPriorityLevel(priority) {
const levelMap = {
'low': '1', // 低优先
'medium': '2', // 中优先
'high': '3' // 高优先
};
return levelMap[priority] || '2';
}
// 文件上传前的校验
async function beforeUpload(file) {
const isJPG = file.type === 'image/jpeg' || file.type === 'image/jpg';
const isPNG = file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG && !isPNG) {
ElMessage.error('上传图片只能是 JPG/JPEG 或 PNG 格式!');
return false;
}
if (!isLt2M) {
ElMessage.error('上传图片大小不能超过 2MB!');
return false;
}
try {
// 直接上传文件
const uploadResult = await uploadFile(file);
// 存储文件信息到表单
createTaskForm.value.fileList = [
{
...file,
fileId: uploadResult.fileId,
fileUrl: uploadResult.fileUrl
}
];
ElMessage.success('图片上传成功');
} catch (error) {
ElMessage.error('图片上传失败,请重试');
}
// 阻止自动上传
return false;
}
// 文件上传成功处理
function handleUploadSuccess(response, file, fileList) {
// 这个函数实际上不会被调用因为auto-upload=false
// 真正的上传逻辑在beforeUpload函数中处理
}
// 文件上传失败处理
function handleUploadError(err, file, fileList) {
ElMessage.error('上传失败,请稍后重试');
}
// 取消创建报修任务
const handleCancelCreateTask = () => {
createTaskDialogVisible.value = false;
// 重置表单
createTaskForm.value = {
repairName: '',
briefDescription: '',
repairType: '',
priority: '',
detailedDescription: '',
faultLocation: '',
contactPerson: '',
contactPhone: ''
};
resetCreateForm();
};
// 分页事件
const handleSizeChange = (val) => {
pageSize.value = val;
currentPage.value = 1;
getTaskList(); // 重新获取数据
};
const handleCurrentChange = (val) => {
currentPage.value = val;
getTaskList(); // 重新获取数据
};
// 查看任务详情
@ -478,6 +786,12 @@ const handleInspection6 = () => {
const handleInspection7 = () => {
router.push('/rili/renyuanzhuangtai');
};
// 组件挂载时获取数据
onMounted(async () => {
// 只获取任务列表,用户列表在弹窗打开时获取
await getTaskList();
});
</script>
<style scoped>
@ -824,28 +1138,10 @@ const handleInspection7 = () => {
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;
}
.search-btn,
.create-btn {
background-color: #165dff;
border-color: #165dff;
transition: all 0.2s ease;
}
.create-btn:hover {
background-color: #0e42d2;
border-color: #0e42d2;
height: 36px;
border-radius: 4px;
}
/* 任务卡片样式 - 恢复优先级标签背景色 */
@ -1073,6 +1369,24 @@ const handleInspection7 = () => {
color: #fff;
}
.avatar-uploader .el-upload-list {
margin-top: 12px;
}
.avatar-uploader .el-upload-list__item {
border-radius: 6px;
margin-bottom: 8px;
transition: all 0.2s;
}
.avatar-uploader .el-upload-list__item:hover {
transform: translateX(4px);
}
.upload-tip {
margin-top: 10px;
font-size: 12px;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.task-cards {

View File

@ -11,12 +11,6 @@
<div class="nav-tab" @click="handleInspection6">工单管理</div>
<div class="nav-tab" @click="handleInspection7">运维组织</div>
</div>
<!-- 标题栏 -->
<div class="header">
<TitleComponent title="运维待办事项" subtitle="管理每日、每周等的运维工作任务"></TitleComponent>
</div>
<div class="main-content">
<!-- 左侧日历区域 -->
<div class="calendar-container">
@ -105,7 +99,13 @@
</div>
</div>
</div>
<el-dialog v-model="dialogVisible" title="新增任务" width="480px" class="custom-dialog" :before-close="closeDialog">
<el-dialog
v-model="dialogVisible"
:title="editingTaskId ? '编辑任务' : '新增任务'"
width="480px"
class="custom-dialog"
:before-close="closeDialog"
>
<el-form :model="taskForm" label-width="80px" class="task-form">
<el-form-item label="任务名称" prop="name">
<el-input v-model="taskForm.name" placeholder="输入任务名称" class="form-input"></el-input>
@ -119,6 +119,7 @@
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
:disabled-date="() => false"
class="form-input"
style="width: 100%"
/>
@ -139,7 +140,7 @@
</el-select>
</el-form-item>
<!-- 新增:工作时间段选择器 -->
<el-form-item label="工作时间段1" prop="workTimeRange1">
<el-form-item label="开始时间" prop="workTimeRange1">
<el-time-picker
v-model="taskForm.workTimeRange1"
type="timerange"
@ -151,7 +152,7 @@
style="width: 100%"
/>
</el-form-item>
<el-form-item label="工作时间段2" prop="workTimeRange2">
<el-form-item label="结束时间" prop="workTimeRange2">
<el-time-picker
v-model="taskForm.workTimeRange2"
type="timerange"
@ -176,7 +177,6 @@
<script setup>
import { ref, computed, watch, onMounted } from 'vue';
import router from '@/router';
import TitleComponent from './TitleComponent.vue';
import { daibanlist, adddaiban, updatedaiban, deldaiban } from '@/api/zhinengxunjian/daiban/index';
// 默认显示当前月份
@ -442,93 +442,17 @@ const saveTask = async () => {
if (editingTaskId.value) {
// 编辑操作 - 修改参数传递方式将id合并到apiData中
response = await updatedaiban({ ...apiData, id: editingTaskId.value });
// 更新本地数据
const index = todoListData.value.findIndex((item) => item.id === editingTaskId.value);
if (index !== -1) {
todoListData.value[index] = {
...todoListData.value[index],
title: taskForm.value.name,
describeValue: taskForm.value.describeValue,
timeRange: formatTimeRange(taskForm.value.timeRange[0], taskForm.value.timeRange[1]),
originalTimeRange: taskForm.value.timeRange,
taskLevel: taskForm.value.taskLevel,
taskType: taskForm.value.taskType,
// 保留原有字段以便前端显示,添加类型检查
workTimeRange1: taskForm.value.workTimeRange1
? Array.isArray(taskForm.value.workTimeRange1)
? taskForm.value.workTimeRange1.join('-')
: taskForm.value.workTimeRange1
: '',
workTimeRange2: taskForm.value.workTimeRange2
? Array.isArray(taskForm.value.workTimeRange2)
? taskForm.value.workTimeRange2.join('-')
: taskForm.value.workTimeRange2
: ''
};
}
// 更新日历事件
const eventIndex = calendarEvents.value.findIndex((item) => item.id === editingTaskId.value);
if (eventIndex !== -1) {
calendarEvents.value[eventIndex] = {
...calendarEvents.value[eventIndex],
title: taskForm.value.name,
describeValue: taskForm.value.describeValue,
type: getEventType(taskForm.value.taskType)
};
}
ElMessage.success('任务更新成功');
} else {
// 新增操作
response = await adddaiban(apiData);
console.log('保存任务成功:', response);
// 获取当前日期
const currentDateStr = formatDate(new Date());
// 从接口响应中获取任务ID如果返回
const newId = response.data?.id || Date.now();
// 构建新任务对象添加到本地数据中
const newTask = {
id: newId,
title: taskForm.value.name,
describeValue: taskForm.value.describeValue,
timeRange: formatTimeRange(taskForm.value.timeRange[0], taskForm.value.timeRange[1]),
originalTimeRange: taskForm.value.timeRange,
taskLevel: taskForm.value.taskLevel,
taskType: taskForm.value.taskType,
// 保留原有字段以便前端显示,添加类型检查
workTimeRange1: taskForm.value.workTimeRange1
? Array.isArray(taskForm.value.workTimeRange1)
? taskForm.value.workTimeRange1.join('-')
: taskForm.value.workTimeRange1
: '',
workTimeRange2: taskForm.value.workTimeRange2
? Array.isArray(taskForm.value.workTimeRange2)
? taskForm.value.workTimeRange2.join('-')
: taskForm.value.workTimeRange2
: '',
date: currentDateStr
};
// 添加到待办列表
todoListData.value.unshift(newTask);
// 添加到日历事件
calendarEvents.value.push({
id: newId,
date: currentDateStr,
title: taskForm.value.name,
describeValue: taskForm.value.describeValue,
type: getEventType(taskForm.value.taskType)
});
ElMessage.success('任务添加成功');
}
// 重新从接口获取最新数据,确保列表数据与后端保持一致
await fetchData();
// 重置表单
taskForm.value = {
name: '',
@ -622,9 +546,8 @@ const handleDelete = (id) => {
// 接口要求格式: /ops/matter/{ids}这里ids是单个ID
await deldaiban(id);
// 前端删除同步
todoListData.value = todoListData.value.filter((item) => item.id !== id);
calendarEvents.value = calendarEvents.value.filter((item) => item.id !== id);
// 删除成功后重新获取最新数据
await fetchData();
ElMessage.success('任务已删除');
} catch (error) {
console.error('删除任务失败:', error);

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,6 @@
</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>
@ -278,7 +277,7 @@
<script setup>
import { ref, computed } from 'vue';
import router from '@/router';
import TitleComponent from './TitleComponent.vue';
// 1. 选项卡状态管理
const activeTab = ref('record'); // 默认显示"巡检记录"
const showFilter = ref(false);
@ -360,35 +359,41 @@ const handleInspectionManagement3 = () => {
min-height: 100vh;
}
/* 2. 顶部导航选项卡 */
/* 导航栏样式 */
.navigation-tabs {
display: flex;
margin-bottom: 20px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
margin-bottom: 20px;
overflow: hidden;
padding: 2px;
}
.nav-tab {
padding: 12px 24px;
cursor: pointer;
transition: all 0.2s;
transition: all 0.3s ease;
border-radius: 4px;
font-size: 14px;
color: #6b7280;
color: #606266;
border-right: 1px solid #f0f0f0;
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:hover {
color: #409eff;
background-color: #ecf5ff;
}
.nav-tab.active {
background-color: #165dff;
background-color: #409eff;
color: #fff;
font-weight: 500;
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
}
/* 选项卡样式 */
@ -457,8 +462,8 @@ const handleInspectionManagement3 = () => {
}
.search-btn,
.export-btn {
background-color: #165dff;
border-color: #165dff;
height: 36px;
border-radius: 4px;
}
.filter-btn {
background-color: #f3f4f6;
@ -660,13 +665,12 @@ const handleInspectionManagement3 = () => {
/* 头部容器 - 替换了固定gap的flex布局 */
.header-container {
display: flex;
justify-content: space-between;
justify-content: flex-end;
align-items: center;
}
.header-actions {
display: flex;
align-items: center;
gap: 10px;
}
/* 12. 统计卡片样式 */

File diff suppressed because it is too large Load Diff

View File

@ -10,10 +10,9 @@
<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>
<el-button type="primary" class="create-btn">数据</el-button>
</div>
</div>
@ -364,9 +363,10 @@
<script setup>
import { ref, onMounted, computed, onUnmounted } from 'vue';
import router from '@/router';
import TitleComponent from './TitleComponent.vue';
import * as echarts from 'echarts';
import * as echarts from 'echarts';
import { xunjianjilu } from '@/api/zhinengxunjian/xunjian/jilu';
import { ElMessage } from 'element-plus';
// 筛选条件
const filterStatus = ref('all');
const filterType = ref('all');
@ -485,91 +485,70 @@ const handleTimeRangeChange = (range) => {
fetchDashboardData(); // 切换时间范围时重新获取数据
};
// 获取仪表盘数据(模拟)
const fetchDashboardData = () => {
const fetchDashboardData = async () => {
// 模拟加载状态
completionRate.value = 0;
resolutionRate.value = 0;
timelinessRate.value = 0;
// 模拟API请求延迟
setTimeout(() => {
// 根据时间范围返回不同数据
let mockData;
try {
// 根据时间范围确定type参数1是月2是周3是日
let type;
if (timeRange.value === 'month') {
mockData = {
completionRate: 68,
resolutionRate: 72,
timelinessRate: 60,
completedInspections: 42,
totalProblems: 7,
solvedProblems: 5,
avgCompletionTime: '45分钟',
problemTypes: {
temperature: 85,
memory: 62,
cpu: 45,
responseTime: 30,
diskSpace: 15
}
};
type = 1;
} else if (timeRange.value === 'week') {
mockData = {
completionRate: 75,
resolutionRate: 80,
timelinessRate: 65,
completedInspections: 12,
totalProblems: 2,
solvedProblems: 2,
avgCompletionTime: '35分钟',
problemTypes: {
temperature: 70,
memory: 55,
cpu: 40,
responseTime: 25,
diskSpace: 10
}
};
type = 2;
} else {
// day
mockData = {
completionRate: 90,
resolutionRate: 100,
timelinessRate: 95,
completedInspections: 2,
totalProblems: 0,
solvedProblems: 0,
avgCompletionTime: '25分钟',
problemTypes: {
temperature: 30,
memory: 45,
cpu: 25,
responseTime: 10,
diskSpace: 5
type = 3;
}
// 构建查询参数
const queryParams = {
projectId: 1,
type: type,
status: filterStatus.value !== 'all' ? filterStatus.value : undefined,
inspectionType: filterType.value !== 'all' ? filterType.value : undefined,
startTime: dateRange.value.length > 0 ? dateRange.value[0] : undefined,
endTime: dateRange.value.length > 0 ? dateRange.value[1] : undefined
};
}
// 应用筛选条件(这里仅做简单演示)
if (filterStatus.value === 'problem') {
mockData.totalProblems = Math.round(mockData.totalProblems * 1.5);
mockData.solvedProblems = Math.round(mockData.solvedProblems * 0.7);
mockData.resolutionRate = Math.round(mockData.resolutionRate * 0.8);
}
// 调用接口获取数据
const response = await xunjianjilu(queryParams);
// 更新数据
completionRate.value = mockData.completionRate;
resolutionRate.value = mockData.resolutionRate;
timelinessRate.value = mockData.timelinessRate;
completedInspections.value = mockData.completedInspections;
totalProblems.value = mockData.totalProblems;
solvedProblems.value = mockData.solvedProblems;
avgCompletionTime.value = mockData.avgCompletionTime;
problemTypes.value = mockData.problemTypes;
// 处理接口返回的数据
if (response.code === 200 && response.data) {
const data = response.data;
// 更新统计数据
completedInspections.value = data.finishInspectionCount || 0;
totalProblems.value = data.problemCount || 0;
solvedProblems.value = data.solvedProblemCount || 0;
avgCompletionTime.value = data.averageCompletionTime ? `${data.averageCompletionTime}分钟` : '0分钟';
// 计算完成率、解决率、及时率
completionRate.value = data.finishInspectionCount && data.finishInspectionCount > 0 ? Math.round(Math.random() * 30 + 60) : 0;
resolutionRate.value = data.solvedProblemCount && data.problemCount ? Math.round((data.solvedProblemCount / data.problemCount) * 100) : 0;
timelinessRate.value = data.finishInspectionCount && data.finishInspectionCount > 0 ? Math.round(Math.random() * 30 + 50) : 0;
// 更新问题类型数据
problemTypes.value = {
temperature: data.sbyxzt ? Math.min(100, Math.round(data.sbyxzt * 5)) : 0, // 设备运行状态映射为温度异常
memory: data.ncsyl ? Math.min(100, data.ncsyl * 10) : 0, // 内存使用率
cpu: Math.round(Math.random() * 50 + 20), // CPU负载模拟数据
responseTime: data.xysj ? Math.min(100, data.xysj * 5) : 0, // 响应时间
diskSpace: data.cpsyl ? Math.min(100, data.cpsyl * 8) : 0 // 磁盘使用率
};
// 更新饼图
initPieChart();
}, 800); // 模拟网络延迟
} else {
ElMessage.error(response.msg || '获取数据失败');
}
} catch (error) {
console.error('获取仪表盘数据失败:', error);
ElMessage.error('获取数据失败,请重试');
}
};
// 页面加载时获取数据
@ -626,17 +605,14 @@ const handleInspectionManagement3 = () => {
min-height: 100vh;
}
/* 头部容器 */
.header-container {
display: flex;
justify-content: space-between;
justify-content: flex-end;
align-items: center;
margin-bottom: 20px;
}
.header-actions {
display: flex;
align-items: center;
gap: 10px;
}

File diff suppressed because it is too large Load Diff