✨ feat(mes): 优化工单和任务管理功能,增强表单交互逻辑
调整工单表单和任务列表的展示,新增工单完成操作,优化表单数据处理逻辑,提升用户体验。pull/871/MERGE
parent
cfa787530e
commit
bc098e8999
|
|
@ -180,13 +180,37 @@ const props = defineProps<{
|
|||
|
||||
const { t } = useI18n()
|
||||
const message = useMessage()
|
||||
const getDefaultColor = () => props.colorCode || '#00AEF3'
|
||||
|
||||
// ==================== 列表 ====================
|
||||
const loading = ref(false)
|
||||
const list = ref<ProTaskVO[]>([])
|
||||
|
||||
/** 查询任务列表(按工单 + 路线 + 工序过滤) */
|
||||
// ==================== 表单弹窗 ====================
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = computed(() => {
|
||||
const titles: Record<string, string> = {
|
||||
create: '新增生产任务',
|
||||
update: '编辑生产任务',
|
||||
detail: '生产任务详情'
|
||||
}
|
||||
return titles[formType.value] || ''
|
||||
})
|
||||
const formLoading = ref(false)
|
||||
const formType = ref('')
|
||||
const isDetail = computed(() => formType.value === 'detail')
|
||||
const formData = ref<ProTaskVO>({} as unknown as ProTaskVO)
|
||||
const formRules = reactive({
|
||||
workstationId: [{ required: true, message: '工作站不能为空', trigger: 'change' }],
|
||||
quantity: [
|
||||
{ required: true, message: '排产数量不能为空', trigger: 'blur' },
|
||||
{ type: 'number', min: 0.01, message: '排产数量必须大于 0', trigger: 'blur' }
|
||||
],
|
||||
startTime: [{ required: true, message: '开始时间不能为空', trigger: 'change' }],
|
||||
duration: [{ required: true, message: '生产时长不能为空', trigger: 'blur' }]
|
||||
})
|
||||
const formRef = ref()
|
||||
|
||||
/** 查询任务列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
|
|
@ -203,87 +227,18 @@ const getList = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
/** 删除任务 */
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
await message.delConfirm()
|
||||
await ProTaskApi.deleteTask(id)
|
||||
message.success(t('common.delSuccess'))
|
||||
await getList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// ==================== 添加/编辑表单 ====================
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const formLoading = ref(false) // 表单的加载中
|
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改;detail - 详情
|
||||
const dialogTitle = computed(() => {
|
||||
const typeMap: Record<string, string> = {
|
||||
detail: '生产任务详情',
|
||||
create: '新增生产任务',
|
||||
update: '编辑生产任务'
|
||||
}
|
||||
return typeMap[formType.value] || ''
|
||||
})
|
||||
const formData = ref<ProTaskVO>({
|
||||
id: undefined,
|
||||
workOrderId: undefined,
|
||||
workstationId: undefined,
|
||||
routeId: undefined,
|
||||
processId: undefined,
|
||||
itemId: undefined,
|
||||
quantity: undefined,
|
||||
startTime: undefined,
|
||||
duration: 1,
|
||||
endTime: undefined,
|
||||
colorCode: undefined,
|
||||
status: undefined,
|
||||
remark: undefined
|
||||
} as unknown as ProTaskVO)
|
||||
const formRules = reactive({
|
||||
workstationId: [{ required: true, message: '工作站不能为空', trigger: 'change' }],
|
||||
quantity: [
|
||||
{ required: true, message: '排产数量不能为空', trigger: 'blur' },
|
||||
{ type: 'number', min: 0.01, message: '排产数量必须大于 0', trigger: 'blur' }
|
||||
],
|
||||
startTime: [{ required: true, message: '开始时间不能为空', trigger: 'change' }],
|
||||
duration: [{ required: true, message: '生产时长不能为空', trigger: 'blur' }]
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
const isDetail = computed(() => formType.value === 'detail')
|
||||
|
||||
/** 计算结束时间:开始时间 + 生产时长 * 8小时 */
|
||||
const handleDurationChange = () => {
|
||||
if (formData.value.startTime && formData.value.duration) {
|
||||
const start =
|
||||
typeof formData.value.startTime === 'number'
|
||||
? formData.value.startTime
|
||||
: new Date(formData.value.startTime).getTime()
|
||||
formData.value.endTime = start + formData.value.duration * 8 * 3600 * 1000
|
||||
}
|
||||
}
|
||||
|
||||
/** 监听开始时间变化也重新计算 */
|
||||
watch(
|
||||
() => formData.value.startTime,
|
||||
() => handleDurationChange()
|
||||
)
|
||||
|
||||
/** 打开表单弹窗 */
|
||||
const openForm = async (type: string, id?: number) => {
|
||||
dialogVisible.value = true
|
||||
formType.value = type
|
||||
resetForm()
|
||||
|
||||
if (type === 'create') {
|
||||
// 新增时预填工单信息
|
||||
formData.value.workOrderId = props.workOrderId!
|
||||
formData.value.routeId = props.routeId!
|
||||
formData.value.processId = props.processId!
|
||||
formData.value.itemId = props.itemId!
|
||||
formData.value.colorCode = getDefaultColor()
|
||||
formData.value.colorCode = props.colorCode || '#00AEF3'
|
||||
} else if (id) {
|
||||
// 编辑:加载任务数据
|
||||
formLoading.value = true
|
||||
try {
|
||||
formData.value = await ProTaskApi.getTask(id)
|
||||
|
|
@ -313,6 +268,27 @@ const submitForm = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
/** 删除任务 */
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
await message.delConfirm()
|
||||
await ProTaskApi.deleteTask(id)
|
||||
message.success(t('common.delSuccess'))
|
||||
await getList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 计算结束时间:开始时间 + 生产时长 × 8小时 */
|
||||
const handleDurationChange = () => {
|
||||
if (formData.value.startTime && formData.value.duration) {
|
||||
const start =
|
||||
typeof formData.value.startTime === 'number'
|
||||
? formData.value.startTime
|
||||
: new Date(formData.value.startTime).getTime()
|
||||
formData.value.endTime = start + formData.value.duration * 8 * 3600 * 1000
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
|
|
@ -333,6 +309,12 @@ const resetForm = () => {
|
|||
formRef.value?.resetFields()
|
||||
}
|
||||
|
||||
/** 监听开始时间变化重新计算结束时间 */
|
||||
watch(
|
||||
() => formData.value.startTime,
|
||||
() => handleDurationChange()
|
||||
)
|
||||
|
||||
/** 监听 processId 切换重新加载 */
|
||||
watch(
|
||||
() => props.processId,
|
||||
|
|
|
|||
|
|
@ -51,6 +51,18 @@
|
|||
<MdItemSelect v-model="formData.productId" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="规格型号" prop="productSpec">
|
||||
<el-input v-model="formData.productSpec" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="单位" prop="unitMeasureName">
|
||||
<el-input v-model="formData.unitMeasureName" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="工单数量" prop="quantity">
|
||||
<el-input-number
|
||||
|
|
@ -141,10 +153,18 @@
|
|||
:process-id="rp.processId"
|
||||
:item-id="formData.productId!"
|
||||
:color-code="rp.colorCode"
|
||||
:disabled="formType === 'detail'"
|
||||
:disabled="isReadonly"
|
||||
/>
|
||||
</el-card>
|
||||
<template #footer>
|
||||
<el-button
|
||||
v-if="formType === 'schedule'"
|
||||
@click="handleFinish"
|
||||
type="success"
|
||||
:disabled="formLoading"
|
||||
>
|
||||
完 成
|
||||
</el-button>
|
||||
<el-button @click="dialogVisible = false">关 闭</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
|
|
@ -161,6 +181,7 @@ import { MesProWorkOrderSourceTypeEnum, MesProWorkOrderTypeEnum } from '@/views/
|
|||
import ProTaskList from './ProTaskList.vue'
|
||||
|
||||
defineOptions({ name: 'WorkOrderForm2' })
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
|
|
@ -168,6 +189,7 @@ const dialogVisible = ref(false) // 弹窗的是否展示
|
|||
const dialogTitle = ref('') // 弹窗的标题
|
||||
const formLoading = ref(false) // 表单的加载中
|
||||
const formType = ref('') // 表单的类型:detail - 详情;schedule - 排产
|
||||
const isReadonly = computed(() => formType.value === 'detail') // 是否只读
|
||||
const formData = ref<any>({})
|
||||
const formRef = ref() // 表单 Ref
|
||||
|
||||
|
|
@ -178,8 +200,8 @@ const currentRouteId = ref(0) // 当前工艺路线编号
|
|||
/** 打开弹窗 */
|
||||
const open = async (type: string, id: number) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = type === 'schedule' ? '生产排产' : '工单详情'
|
||||
formType.value = type
|
||||
dialogTitle.value = { schedule: '生产排产', detail: '工单详情' }[type] || type
|
||||
formLoading.value = true
|
||||
formData.value = {}
|
||||
routeProcessList.value = []
|
||||
|
|
@ -197,6 +219,21 @@ const open = async (type: string, id: number) => {
|
|||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
|
||||
/** 完成工单 */
|
||||
const handleFinish = async () => {
|
||||
try {
|
||||
await message.confirm('确认要完成该工单吗?完成后工单下所有任务将标记为已完成。')
|
||||
formLoading.value = true
|
||||
await ProWorkOrderApi.finishWorkOrder(formData.value.id!)
|
||||
message.success('工单已完成')
|
||||
dialogVisible.value = false
|
||||
emit('success')
|
||||
} catch {
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 加载工艺路线工序列表 */
|
||||
const loadRouteProcesses = async (productId: number) => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@
|
|||
<dict-tag :type="DICT_TYPE.MES_PRO_WORK_ORDER_STATUS" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="160" fixed="right">
|
||||
<el-table-column label="操作" align="center" width="100" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-if="scope.row.status === MesProWorkOrderStatusEnum.CONFIRMED"
|
||||
|
|
@ -128,15 +128,6 @@
|
|||
>
|
||||
排产
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="scope.row.status === MesProWorkOrderStatusEnum.CONFIRMED"
|
||||
link
|
||||
type="success"
|
||||
@click="handleFinish(scope.row.id)"
|
||||
v-hasPermi="['mes:pro-task:update']"
|
||||
>
|
||||
完成
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
|
@ -149,7 +140,7 @@
|
|||
/>
|
||||
</ContentWrap>
|
||||
|
||||
<WorkOrderForm2 ref="formRef" />
|
||||
<WorkOrderForm2 ref="formRef" @success="getWorkOrderList" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
|
@ -166,10 +157,12 @@ import WorkOrderForm2 from './WorkOrderForm2.vue'
|
|||
|
||||
defineOptions({ name: 'MesProTask' })
|
||||
|
||||
const message = useMessage()
|
||||
const { push } = useRouter()
|
||||
|
||||
const loading = ref(true) // 列表加载状态
|
||||
const workOrderList = ref<ProWorkOrderVO[]>([]) // 工单列表数据
|
||||
const total = ref(0) // 总条数
|
||||
const ganttTasks = ref<any[]>([]) // 甘特图数据
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
|
|
@ -183,9 +176,7 @@ const queryParams = reactive({
|
|||
type: MesProWorkOrderTypeEnum.SELF // 固定筛选:只查询"自制"的工单
|
||||
})
|
||||
const queryFormRef = ref() // 搜索表单 ref
|
||||
|
||||
const ganttLoading = ref(false) // 甘特图加载状态
|
||||
const ganttTasks = ref<any[]>([]) // 甘特图数据
|
||||
const formRef = ref() // 表单弹窗 ref
|
||||
|
||||
/** 查询待排产工单列表(支持父子工单树形展示) */
|
||||
const getWorkOrderList = async () => {
|
||||
|
|
@ -199,50 +190,33 @@ const getWorkOrderList = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
/** 加载甘特图预览数据(查询所有任务,供甘特图组件渲染) */
|
||||
/** 加载甘特图预览数据 */
|
||||
const loadGanttPreview = async () => {
|
||||
ganttLoading.value = true
|
||||
try {
|
||||
ganttTasks.value = await ProTaskApi.getGanttTaskList(queryParams)
|
||||
} finally {
|
||||
ganttLoading.value = false
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 搜索 */
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getWorkOrderList()
|
||||
}
|
||||
|
||||
/** 重置 */
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
// 恢复固定筛选
|
||||
queryParams.status = MesProWorkOrderStatusEnum.CONFIRMED
|
||||
queryParams.type = MesProWorkOrderTypeEnum.SELF
|
||||
// 执行搜索
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 打开排产/详情对话框 */
|
||||
const formRef = ref()
|
||||
/** 打开排产/详情/完成对话框 */
|
||||
const openForm = (type: string, id: number) => {
|
||||
formRef.value.open(type, id)
|
||||
}
|
||||
|
||||
/** 完成工单 */
|
||||
const handleFinish = async (id: number) => {
|
||||
try {
|
||||
await message.confirm('确认要完成该工单吗?')
|
||||
await ProWorkOrderApi.finishWorkOrder(id)
|
||||
message.success('工单已完成')
|
||||
await getWorkOrderList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 打开甘特图编辑页面 */
|
||||
const { push } = useRouter()
|
||||
const openGanttEdit = () => {
|
||||
push({ name: 'MesProTaskGanttEdit' })
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue