707 lines
18 KiB
Vue
707 lines
18 KiB
Vue
<template>
|
||
<div class="p-4">
|
||
<h2 class="text-xl font-bold text-blue-400 mb-4">巡检计划管理</h2>
|
||
|
||
<!-- 工具栏 -->
|
||
<div class="flex justify-between items-center mb-4">
|
||
<div class="flex gap-4">
|
||
<el-button type="primary" @click="handleAddSchedule" icon="Plus">新增计划</el-button>
|
||
<el-button @click="handleRefresh" icon="Refresh">刷新</el-button>
|
||
</div>
|
||
|
||
<!-- 搜索框 -->
|
||
<el-input
|
||
v-model="searchKeyword"
|
||
placeholder="搜索计划标题"
|
||
prefix-icon="Search"
|
||
style="width: 240px"
|
||
@input="handleSearch"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 计划列表表格 -->
|
||
<el-table
|
||
v-loading="loading"
|
||
:data="scheduleList"
|
||
style="width: 100%"
|
||
@row-click="handleRowClick"
|
||
@selection-change="handleSelectionChange"
|
||
>
|
||
<el-table-column type="selection" width="55" />
|
||
<el-table-column prop="PatrolDay" label="巡检周期" width="100" align="center">
|
||
<template #default="scope">
|
||
{{ getDayOfWeek(scope.row.PatrolDay) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="PatrolTitle" label="计划标题" min-width="200" />
|
||
<el-table-column prop="PatrolStartTime" label="开始时间" width="120" align="center" />
|
||
<el-table-column prop="PatrolEndTime" label="结束时间" width="120" align="center" />
|
||
<el-table-column prop="PatrolPersons" label="巡检人员" min-width="200" align="center">
|
||
<template #default="scope">
|
||
<div v-for="person in scope.row.PatrolPersons" :key="person.id" class="text-sm">
|
||
{{ person.name }}
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="PatrolPathName" label="巡检路线" min-width="180" />
|
||
<el-table-column label="操作" width="150" align="center">
|
||
<template #default="scope">
|
||
<div class="flex gap-2 justify-center">
|
||
<el-button
|
||
size="small"
|
||
@click="handleEdit(scope.row)"
|
||
icon="Edit"
|
||
>编辑</el-button>
|
||
<el-button
|
||
size="small"
|
||
type="danger"
|
||
@click="handleDelete(scope.row)"
|
||
icon="Delete"
|
||
>删除</el-button>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 分页 -->
|
||
<div class="flex justify-end mt-4">
|
||
<el-pagination
|
||
v-model:current-page="currentPage"
|
||
v-model:page-size="pageSize"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
:total="total"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 计划编辑对话框 -->
|
||
<el-dialog
|
||
v-model="dialogVisible"
|
||
:title="isEdit ? '编辑巡检计划' : '新增巡检计划'"
|
||
width="70%"
|
||
max-width="900px"
|
||
destroy-on-close
|
||
@closed="handleClose"
|
||
>
|
||
<!-- 表单容器 -->
|
||
<el-form
|
||
ref="scheduleFormRef"
|
||
:model="scheduleForm"
|
||
label-width="120px"
|
||
:rules="formRules"
|
||
>
|
||
<!-- 第一行:周期和标题 -->
|
||
<div class="grid grid-cols-1 gap-4 mb-4">
|
||
<el-form-item label="每周第几天" prop="PatrolDay">
|
||
<el-input-number
|
||
v-model="scheduleForm.PatrolDay"
|
||
:min="1"
|
||
:max="7"
|
||
placeholder="请输入1-7"
|
||
:step-strictly="true"
|
||
>
|
||
<template #append>
|
||
<el-select v-model="scheduleForm.PatrolDay" placeholder="选择星期">
|
||
<el-option label="周一" :value="1" />
|
||
<el-option label="周二" :value="2" />
|
||
<el-option label="周三" :value="3" />
|
||
<el-option label="周四" :value="4" />
|
||
<el-option label="周五" :value="5" />
|
||
<el-option label="周六" :value="6" />
|
||
<el-option label="周日" :value="7" />
|
||
</el-select>
|
||
</template>
|
||
</el-input-number>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="标题" prop="PatrolTitle">
|
||
<el-input
|
||
v-model="scheduleForm.PatrolTitle"
|
||
placeholder="请输入计划标题"
|
||
maxlength="50"
|
||
show-word-limit
|
||
/>
|
||
</el-form-item>
|
||
</div>
|
||
|
||
<!-- 第二行:开始时间和结束时间 -->
|
||
<div class="grid grid-cols-1 gap-4 mb-4">
|
||
<el-form-item label="巡检开始时间" prop="PatrolStartTime">
|
||
<el-time-picker
|
||
v-model="scheduleForm.PatrolStartTime"
|
||
type="time"
|
||
placeholder="选择开始时间"
|
||
value-format="HH:mm"
|
||
/>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="巡检结束时间" prop="PatrolEndTime">
|
||
<el-time-picker
|
||
v-model="scheduleForm.PatrolEndTime"
|
||
type="time"
|
||
placeholder="选择结束时间"
|
||
value-format="HH:mm"
|
||
/>
|
||
</el-form-item>
|
||
</div>
|
||
|
||
<!-- 第三行:第一位和第二位巡检人员 -->
|
||
<div class="grid grid-cols-1 gap-4 mb-4">
|
||
<el-form-item label="第一位巡检人员" prop="UserId1">
|
||
<el-select
|
||
v-model="scheduleForm.UserId1"
|
||
placeholder="选择巡检人员"
|
||
style="width: 100%"
|
||
>
|
||
<el-option
|
||
v-for="user in userList"
|
||
:key="user.value"
|
||
:label="user.label"
|
||
:value="user.value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="第二位巡检人员" prop="UserId2">
|
||
<el-select
|
||
v-model="scheduleForm.UserId2"
|
||
placeholder="选择巡检人员"
|
||
style="width: 100%"
|
||
>
|
||
<el-option
|
||
v-for="user in userList"
|
||
:key="user.value"
|
||
:label="user.label"
|
||
:value="user.value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</div>
|
||
|
||
<!-- 第四行:第三位巡检人员和巡检路线 -->
|
||
<div class="grid grid-cols-1 gap-4">
|
||
<el-form-item label="第三位巡检人员" prop="UserId3">
|
||
<el-select
|
||
v-model="scheduleForm.UserId3"
|
||
placeholder="选择巡检人员"
|
||
style="width: 100%"
|
||
>
|
||
<el-option
|
||
v-for="user in userList"
|
||
:key="user.value"
|
||
:label="user.label"
|
||
:value="user.value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="巡检路线" prop="PatrolPathId">
|
||
<el-select
|
||
v-model="scheduleForm.PatrolPathId"
|
||
placeholder="选择巡检路线"
|
||
style="width: 100%"
|
||
>
|
||
<el-option
|
||
v-for="path in pathList"
|
||
:key="path.value"
|
||
:label="path.label"
|
||
:value="path.value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</div>
|
||
</el-form>
|
||
|
||
<!-- 对话框底部按钮 -->
|
||
<template #footer>
|
||
<span class="dialog-footer">
|
||
<el-button @click="dialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="handleSave">保存</el-button>
|
||
</span>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
/**
|
||
* 巡检计划管理组件
|
||
* 用于管理巡检计划信息,包含计划的周期、时间、人员和路线配置
|
||
*/
|
||
import { ref, reactive, computed, onMounted } from 'vue'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
|
||
// 响应式数据
|
||
const loading = ref(false)
|
||
const scheduleList = ref([])
|
||
const currentPage = ref(1)
|
||
const pageSize = ref(10)
|
||
const total = ref(0)
|
||
const searchKeyword = ref('')
|
||
|
||
// 编辑对话框相关
|
||
const dialogVisible = ref(false)
|
||
const isEdit = ref(false)
|
||
const scheduleFormRef = ref()
|
||
const scheduleForm = reactive({
|
||
PatrolDay: null,
|
||
PatrolTitle: '',
|
||
PatrolStartTime: '',
|
||
PatrolEndTime: '',
|
||
UserId1: '',
|
||
UserId2: '',
|
||
UserId3: '',
|
||
PatrolPathId: ''
|
||
})
|
||
|
||
// 表单验证规则
|
||
const formRules = {
|
||
PatrolDay: [
|
||
{ required: true, message: '请输入每周第几天', trigger: 'blur' },
|
||
{ type: 'number', min: 1, max: 7, message: '请输入1-7之间的数字', trigger: 'blur' }
|
||
],
|
||
PatrolTitle: [
|
||
{ required: true, message: '请输入计划标题', trigger: 'blur' }
|
||
],
|
||
PatrolStartTime: [
|
||
{ required: true, message: '请选择巡检开始时间', trigger: 'blur' }
|
||
],
|
||
PatrolEndTime: [
|
||
{ required: true, message: '请选择巡检结束时间', trigger: 'blur' }
|
||
],
|
||
UserId1: [
|
||
{ required: true, message: '请选择第一位巡检人员', trigger: 'blur' }
|
||
],
|
||
PatrolPathId: [
|
||
{ required: true, message: '请选择巡检路线', trigger: 'blur' }
|
||
]
|
||
}
|
||
|
||
// 人员列表和路线列表(模拟数据)
|
||
const userList = ref([
|
||
{ label: '张三', value: '1' },
|
||
{ label: '李四', value: '2' },
|
||
{ label: '王五', value: '3' },
|
||
{ label: '赵六', value: '4' },
|
||
{ label: '钱七', value: '5' }
|
||
])
|
||
|
||
const pathList = ref([
|
||
{ label: '生产线A巡检路线', value: '1' },
|
||
{ label: '生产线B巡检路线', value: '2' },
|
||
{ label: '仓库巡检路线', value: '3' },
|
||
{ label: '办公区巡检路线', value: '4' }
|
||
])
|
||
|
||
// 获取星期几的中文名称
|
||
const getDayOfWeek = (day: number): string => {
|
||
const days = ['', '周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||
return days[day] || ''
|
||
}
|
||
|
||
// 初始化数据
|
||
const initData = () => {
|
||
loading.value = true
|
||
// 模拟数据获取
|
||
setTimeout(() => {
|
||
scheduleList.value = [
|
||
{
|
||
id: 1,
|
||
PatrolDay: 1,
|
||
PatrolTitle: '周一生产线A例行巡检',
|
||
PatrolStartTime: '09:00',
|
||
PatrolEndTime: '10:30',
|
||
UserId1: '1',
|
||
UserId2: '2',
|
||
UserId3: '3',
|
||
PatrolPathId: '1',
|
||
PatrolPersons: [
|
||
{ id: '1', name: '张三' },
|
||
{ id: '2', name: '李四' },
|
||
{ id: '3', name: '王五' }
|
||
],
|
||
PatrolPathName: '生产线A巡检路线'
|
||
},
|
||
{
|
||
id: 2,
|
||
PatrolDay: 3,
|
||
PatrolTitle: '周三仓库安全巡检',
|
||
PatrolStartTime: '14:00',
|
||
PatrolEndTime: '15:30',
|
||
UserId1: '2',
|
||
UserId2: '',
|
||
UserId3: '',
|
||
PatrolPathId: '3',
|
||
PatrolPersons: [
|
||
{ id: '2', name: '李四' }
|
||
],
|
||
PatrolPathName: '仓库巡检路线'
|
||
},
|
||
{
|
||
id: 3,
|
||
PatrolDay: 5,
|
||
PatrolTitle: '周五办公区环境巡检',
|
||
PatrolStartTime: '15:00',
|
||
PatrolEndTime: '16:00',
|
||
UserId1: '3',
|
||
UserId2: '4',
|
||
UserId3: '',
|
||
PatrolPathId: '4',
|
||
PatrolPersons: [
|
||
{ id: '3', name: '王五' },
|
||
{ id: '4', name: '赵六' }
|
||
],
|
||
PatrolPathName: '办公区巡检路线'
|
||
}
|
||
]
|
||
total.value = scheduleList.value.length
|
||
loading.value = false
|
||
}, 500)
|
||
}
|
||
|
||
// 处理新增计划
|
||
const handleAddSchedule = () => {
|
||
isEdit.value = false
|
||
// 重置表单
|
||
Object.keys(scheduleForm).forEach(key => {
|
||
scheduleForm[key] = ''
|
||
})
|
||
scheduleForm.PatrolDay = null
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
// 处理编辑计划
|
||
const handleEdit = (row: any) => {
|
||
isEdit.value = true
|
||
// 填充表单数据
|
||
Object.keys(scheduleForm).forEach(key => {
|
||
if (key in row) {
|
||
scheduleForm[key] = row[key]
|
||
}
|
||
})
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
// 处理删除计划
|
||
const handleDelete = async (row: any) => {
|
||
try {
|
||
await ElMessageBox.confirm(
|
||
`确定要删除计划「${row.PatrolTitle}」吗?`,
|
||
'确认删除',
|
||
{
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}
|
||
)
|
||
// 模拟删除操作
|
||
loading.value = true
|
||
setTimeout(() => {
|
||
const index = scheduleList.value.findIndex(item => item.id === row.id)
|
||
if (index > -1) {
|
||
scheduleList.value.splice(index, 1)
|
||
total.value = scheduleList.value.length
|
||
ElMessage.success('删除成功')
|
||
}
|
||
loading.value = false
|
||
}, 300)
|
||
} catch {
|
||
// 取消删除
|
||
}
|
||
}
|
||
|
||
// 保存计划
|
||
const handleSave = async () => {
|
||
if (!scheduleFormRef.value) return
|
||
|
||
try {
|
||
await scheduleFormRef.value.validate()
|
||
|
||
// 构建人员信息
|
||
const personIds = [scheduleForm.UserId1, scheduleForm.UserId2, scheduleForm.UserId3].filter(id => id)
|
||
const PatrolPersons = personIds.map(id => {
|
||
const user = userList.value.find(u => u.value === id)
|
||
return { id, name: user?.label || '' }
|
||
})
|
||
|
||
// 获取路线名称
|
||
const path = pathList.value.find(p => p.value === scheduleForm.PatrolPathId)
|
||
|
||
// 保存数据
|
||
loading.value = true
|
||
setTimeout(() => {
|
||
if (isEdit.value) {
|
||
// 编辑模式
|
||
const index = scheduleList.value.findIndex(item => item.id === scheduleForm.id)
|
||
if (index > -1) {
|
||
scheduleList.value[index] = {
|
||
...scheduleForm,
|
||
PatrolPersons,
|
||
PatrolPathName: path?.label || ''
|
||
}
|
||
}
|
||
} else {
|
||
// 新增模式
|
||
const newSchedule = {
|
||
id: Date.now(), // 模拟生成ID
|
||
...scheduleForm,
|
||
PatrolPersons,
|
||
PatrolPathName: path?.label || ''
|
||
}
|
||
scheduleList.value.unshift(newSchedule)
|
||
total.value = scheduleList.value.length
|
||
}
|
||
|
||
ElMessage.success(isEdit.value ? '修改成功' : '新增成功')
|
||
dialogVisible.value = false
|
||
loading.value = false
|
||
}, 300)
|
||
} catch (error) {
|
||
// 表单验证失败
|
||
}
|
||
}
|
||
|
||
// 处理搜索
|
||
const handleSearch = () => {
|
||
// 这里可以根据关键词过滤数据
|
||
// 目前简单处理,实际项目中可能需要重新请求数据
|
||
}
|
||
|
||
// 处理刷新
|
||
const handleRefresh = () => {
|
||
searchKeyword.value = ''
|
||
currentPage.value = 1
|
||
initData()
|
||
}
|
||
|
||
// 分页处理
|
||
const handleSizeChange = (size: number) => {
|
||
pageSize.value = size
|
||
}
|
||
|
||
const handleCurrentChange = (current: number) => {
|
||
currentPage.value = current
|
||
}
|
||
|
||
// 处理行点击
|
||
const handleRowClick = (row: any) => {
|
||
// 可以在这里实现行点击后的操作
|
||
}
|
||
|
||
// 处理选择变化
|
||
const handleSelectionChange = (selection: any[]) => {
|
||
// 可以在这里处理选中的数据
|
||
}
|
||
|
||
// 处理对话框关闭
|
||
const handleClose = () => {
|
||
if (scheduleFormRef.value) {
|
||
scheduleFormRef.value.resetFields()
|
||
}
|
||
}
|
||
|
||
// 组件挂载时初始化数据
|
||
onMounted(() => {
|
||
initData()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
/**
|
||
* 巡检计划管理组件样式
|
||
*/
|
||
.dialog-footer {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 12px;
|
||
}
|
||
|
||
/* 标题样式 */
|
||
.text-xl {
|
||
font-size: 20px;
|
||
}
|
||
|
||
.text-lg {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.font-bold {
|
||
font-weight: 700;
|
||
}
|
||
|
||
.font-medium {
|
||
font-weight: 500;
|
||
}
|
||
|
||
.text-blue-400 {
|
||
color: #69b1ff;
|
||
}
|
||
|
||
.text-blue-300 {
|
||
color: #91d5ff;
|
||
}
|
||
|
||
.text-blue-200 {
|
||
color: #b6dfff;
|
||
}
|
||
|
||
/* 间距样式 */
|
||
.mb-4 {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.mb-6 {
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.mt-4 {
|
||
margin-top: 16px;
|
||
}
|
||
|
||
/* 网格布局 */
|
||
.grid {
|
||
display: grid;
|
||
}
|
||
|
||
.grid-cols-1 {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.grid-cols-2 {
|
||
grid-template-columns: 1fr 1fr;
|
||
}
|
||
|
||
.gap-4 {
|
||
gap: 16px;
|
||
}
|
||
|
||
/* 对话框样式 */
|
||
:deep(.el-dialog) {
|
||
background-color: rgba(0, 58, 97, 0.4) !important; /* 空军蓝,透明度40% */
|
||
backdrop-filter: blur(8px); /* 高斯模糊效果 */
|
||
border: 1px solid rgba(104, 201, 255, 0.3);
|
||
}
|
||
|
||
:deep(.el-dialog__header) {
|
||
background-color: rgba(0, 58, 97, 0.6) !important;
|
||
border-bottom: 1px solid rgba(104, 201, 255, 0.3);
|
||
}
|
||
|
||
:deep(.el-dialog__title) {
|
||
color: #91d5ff !important;
|
||
font-weight: 600;
|
||
}
|
||
|
||
:deep(.el-dialog__footer) {
|
||
background-color: rgba(0, 58, 97, 0.6) !important;
|
||
border-top: 1px solid rgba(104, 201, 255, 0.3);
|
||
padding-bottom: 20px;
|
||
}
|
||
|
||
/* 表单样式 */
|
||
:deep(.el-form) {
|
||
background: transparent !important;
|
||
}
|
||
|
||
:deep(.el-form-item__label) {
|
||
color: #68c9ff !important;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 输入框样式 */
|
||
:deep(.el-input__wrapper) {
|
||
background: rgba(255, 255, 255, 0.05) !important;
|
||
border-color: #68c9ff !important;
|
||
}
|
||
|
||
:deep(.el-input__inner) {
|
||
color: #b6dfff !important;
|
||
background: transparent !important;
|
||
}
|
||
|
||
/* 表格样式 */
|
||
:deep(.el-table) {
|
||
background: rgba(12, 43, 77, 0.7) !important;
|
||
border: 1px solid #68c9ff;
|
||
backdrop-filter: blur(5px);
|
||
}
|
||
|
||
:deep(.el-table__header-wrapper th) {
|
||
background: rgba(20, 60, 110, 0.8) !important;
|
||
color: #68c9ff !important;
|
||
border-bottom: 1px solid #68c9ff !important;
|
||
}
|
||
|
||
:deep(.el-table__body-wrapper tr) {
|
||
background: transparent !important;
|
||
}
|
||
|
||
:deep(.el-table__body-wrapper tr:nth-child(even)) {
|
||
background: rgba(20, 60, 110, 0.3) !important;
|
||
}
|
||
|
||
:deep(.el-table__body-wrapper tr:hover) {
|
||
background: rgba(104, 201, 255, 0.2) !important;
|
||
}
|
||
|
||
:deep(.el-table__body-wrapper td) {
|
||
color: #b6dfff !important;
|
||
border-bottom: 1px solid rgba(104, 201, 255, 0.3) !important;
|
||
}
|
||
|
||
/* 选择器样式 */
|
||
:deep(.el-select) {
|
||
width: 100%;
|
||
}
|
||
|
||
:deep(.el-select__wrapper) {
|
||
background: rgba(255, 255, 255, 0.05) !important;
|
||
border-color: #68c9ff !important;
|
||
}
|
||
|
||
:deep(.el-select__placeholder) {
|
||
color: #68c9ff !important;
|
||
}
|
||
|
||
:deep(.el-select__input) {
|
||
color: #b6dfff !important;
|
||
}
|
||
|
||
:deep(.el-select-dropdown) {
|
||
background: rgba(12, 43, 77, 0.95) !important;
|
||
border: 1px solid #68c9ff !important;
|
||
}
|
||
|
||
:deep(.el-select-dropdown__item) {
|
||
color: #b6dfff !important;
|
||
}
|
||
|
||
:deep(.el-select-dropdown__item:hover) {
|
||
background: rgba(104, 201, 255, 0.2) !important;
|
||
}
|
||
|
||
/* 时间选择器样式 */
|
||
:deep(.el-time-picker) {
|
||
width: 100%;
|
||
}
|
||
|
||
:deep(.el-time-panel) {
|
||
background: rgba(12, 43, 77, 0.95) !important;
|
||
border: 1px solid #68c9ff !important;
|
||
}
|
||
|
||
:deep(.el-time-spinner__item) {
|
||
color: #b6dfff !important;
|
||
}
|
||
|
||
:deep(.el-time-spinner__item:hover:not(.disabled)) {
|
||
background: rgba(104, 201, 255, 0.2) !important;
|
||
}
|
||
|
||
:deep(.el-time-spinner__item.active:not(.disabled)) {
|
||
color: #68c9ff !important;
|
||
background: rgba(104, 201, 255, 0.3) !important;
|
||
}
|
||
</style> |