Files
WarehouseClient/src/views/Path/PathSchedule.vue

707 lines
18 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 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>