feat(mes): 优化工艺路线管理功能,调整状态处理逻辑

移除工艺路线状态的必填验证,调整状态字段为可选。更新状态切换逻辑,增强用户交互体验,确保状态操作的可用性和提示信息的准确性。
pull/871/MERGE
YunaiV 2026-04-04 16:42:26 +08:00
parent 375d5a2236
commit cfa787530e
6 changed files with 89 additions and 115 deletions

View File

@ -6,7 +6,7 @@ export interface ProRouteVO {
code: string // 工艺路线编码 code: string // 工艺路线编码
name: string // 工艺路线名称 name: string // 工艺路线名称
description?: string // 工艺路线说明 description?: string // 工艺路线说明
status: number // 状态 status?: number // 状态
remark?: string // 备注 remark?: string // 备注
createTime?: Date // 创建时间 createTime?: Date // 创建时间
} }

View File

@ -10,7 +10,7 @@
:disabled="isDetail" :disabled="isDetail"
> >
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="8"> <el-col :span="12">
<el-form-item label="编码" prop="code"> <el-form-item label="编码" prop="code">
<el-input v-model="formData.code" placeholder="请输入编码" :disabled="isHeaderReadonly"> <el-input v-model="formData.code" placeholder="请输入编码" :disabled="isHeaderReadonly">
<template #append> <template #append>
@ -19,7 +19,7 @@
</el-input> </el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="12">
<el-form-item label="名称" prop="name"> <el-form-item label="名称" prop="name">
<el-input <el-input
v-model="formData.name" v-model="formData.name"
@ -28,19 +28,6 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8">
<el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status" :disabled="isHeaderReadonly">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row> </el-row>
<el-form-item label="说明" prop="description"> <el-form-item label="说明" prop="description">
<el-input <el-input
@ -61,7 +48,6 @@
</el-form-item> </el-form-item>
<!-- 编辑/启用/详情时展示 Tab --> <!-- 编辑/启用/详情时展示 Tab -->
<template v-if="formData.id"> <template v-if="formData.id">
<el-divider content-position="left">详细信息</el-divider>
<el-tabs v-model="activeTab"> <el-tabs v-model="activeTab">
<el-tab-pane label="组成工序" name="process"> <el-tab-pane label="组成工序" name="process">
<RouteProcessList :routeId="formData.id" :form-type="formType" /> <RouteProcessList :routeId="formData.id" :form-type="formType" />
@ -73,20 +59,10 @@
</template> </template>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button <el-button v-if="isEditable" type="primary" @click="submitForm" :disabled="formLoading">
v-if="isEditable"
type="primary"
@click="submitForm"
:disabled="formLoading"
>
</el-button> </el-button>
<el-button <el-button v-if="isEnable" type="success" @click="handleEnable" :disabled="formLoading">
v-if="isEnable"
type="success"
@click="handleEnable"
:disabled="formLoading"
>
确认启用 确认启用
</el-button> </el-button>
<el-button @click="dialogVisible = false"> </el-button> <el-button @click="dialogVisible = false"> </el-button>
@ -95,10 +71,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
import { generateRandomStr } from '@/utils'
import { ProRouteApi, ProRouteVO } from '@/api/mes/pro/route' import { ProRouteApi, ProRouteVO } from '@/api/mes/pro/route'
import { AutoCodeRecordApi } from '@/api/mes/md/autocode/record'
import { MesAutoCodeRuleCode } from '@/views/mes/utils/constants'
import RouteProcessList from './RouteProcessList.vue' import RouteProcessList from './RouteProcessList.vue'
import RouteProductList from './RouteProductList.vue' import RouteProductList from './RouteProductList.vue'
@ -128,21 +104,17 @@ const formData = ref<ProRouteVO>({
code: '', code: '',
name: '', name: '',
description: '', description: '',
status: CommonStatusEnum.ENABLE,
remark: '' remark: ''
}) })
const formRules = reactive({ const formRules = reactive({
code: [{ required: true, message: '编码不能为空', trigger: 'blur' }], code: [{ required: true, message: '编码不能为空', trigger: 'blur' }],
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }], name: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
// TODO @AIsave
status: [{ required: true, message: '状态不能为空', trigger: 'change' }]
}) })
const formRef = ref() // Ref const formRef = ref() // Ref
/** 生成编码 */ /** 生成编码 */
const generateCode = () => { const generateCode = async () => {
// TODO @AImysql formData.value.code = await AutoCodeRecordApi.generateAutoCode(MesAutoCodeRuleCode.PRO_ROUTE_CODE)
formData.value.code = 'ROUTE' + generateRandomStr(8)
} }
/** 打开弹窗 */ /** 打开弹窗 */
@ -173,7 +145,6 @@ const submitForm = async () => {
message.success('新增成功') message.success('新增成功')
// //
formData.value.id = res formData.value.id = res
formData.value.status = CommonStatusEnum.DISABLE
formType.value = 'update' formType.value = 'update'
} else { } else {
await ProRouteApi.updateRoute(data) await ProRouteApi.updateRoute(data)
@ -188,7 +159,9 @@ const submitForm = async () => {
/** 确认启用 */ /** 确认启用 */
const handleEnable = async () => { const handleEnable = async () => {
try { try {
await message.confirm('确认启用"' + formData.value.name + '"工艺路线吗?启用前请确认工序和产品 BOM 配置完整。') await message.confirm(
'确认启用"' + formData.value.name + '"工艺路线吗?启用前请确认工序和产品 BOM 配置完整。'
)
formLoading.value = true formLoading.value = true
await ProRouteApi.updateRouteStatus(formData.value.id!, CommonStatusEnum.ENABLE) await ProRouteApi.updateRouteStatus(formData.value.id!, CommonStatusEnum.ENABLE)
message.success('启用成功') message.success('启用成功')
@ -207,7 +180,6 @@ const resetForm = () => {
code: '', code: '',
name: '', name: '',
description: '', description: '',
status: CommonStatusEnum.ENABLE,
remark: '' remark: ''
} }
formRef.value?.resetFields() formRef.value?.resetFields()

View File

@ -52,17 +52,10 @@
</el-table-column> </el-table-column>
<el-table-column label="甘特图颜色" align="center" prop="colorCode" width="100"> <el-table-column label="甘特图颜色" align="center" prop="colorCode" width="100">
<template #default="scope"> <template #default="scope">
<div <div v-if="scope.row.colorCode" class="flex items-center justify-center gap-4px">
v-if="scope.row.colorCode"
style="display: flex; align-items: center; justify-content: center; gap: 4px"
>
<div <div
:style="{ :style="{ backgroundColor: scope.row.colorCode }"
backgroundColor: scope.row.colorCode, class="w-16px h-16px rounded-4px"
width: '16px',
height: '16px',
borderRadius: '4px'
}"
></div> ></div>
<span>{{ scope.row.colorCode }}</span> <span>{{ scope.row.colorCode }}</span>
</div> </div>
@ -78,7 +71,7 @@
<!-- 表单弹窗添加/修改 --> <!-- 表单弹窗添加/修改 -->
<Dialog :title="formTitle" v-model="formVisible" width="960px"> <Dialog :title="formTitle" v-model="formVisible" width="960px">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="130px"> <el-form ref="formRef" :model="formData" :rules="formRules" label-width="140px">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="序号" prop="sort"> <el-form-item label="序号" prop="sort">
@ -113,8 +106,7 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="甘特图颜色" prop="colorCode"> <el-form-item label="甘特图颜色" prop="colorCode">
<!-- TODO @AIunocss --> <div class="flex items-center gap-8px">
<div style="display: flex; align-items: center; gap: 8px">
<el-color-picker v-model="formData.colorCode" /> <el-color-picker v-model="formData.colorCode" />
<span v-if="formData.colorCode">{{ formData.colorCode }}</span> <span v-if="formData.colorCode">{{ formData.colorCode }}</span>
</div> </div>
@ -200,8 +192,9 @@ const formData = ref<any>({}) // 表单数据
const formRules = reactive({ const formRules = reactive({
sort: [{ required: true, message: '序号不能为空', trigger: 'blur' }], sort: [{ required: true, message: '序号不能为空', trigger: 'blur' }],
processId: [{ required: true, message: '工序不能为空', trigger: 'change' }], processId: [{ required: true, message: '工序不能为空', trigger: 'change' }],
linkType: [{ required: true, message: '工序关系不能为空', trigger: 'change' }] linkType: [{ required: true, message: '工序关系不能为空', trigger: 'change' }],
// TODO @AIkeyFlagcheckFlag keyFlag: [{ required: true, message: '是否关键工序不能为空', trigger: 'change' }],
checkFlag: [{ required: true, message: '是否需要质检确认不能为空', trigger: 'change' }]
}) })
const formRef = ref() // Ref const formRef = ref() // Ref

View File

@ -13,7 +13,6 @@
<el-table-column label="产品物料名称" align="center" prop="itemName" width="150" /> <el-table-column label="产品物料名称" align="center" prop="itemName" width="150" />
<el-table-column label="规格型号" align="center" prop="specification" width="150" /> <el-table-column label="规格型号" align="center" prop="specification" width="150" />
<el-table-column label="单位" align="center" prop="unitName" width="80" /> <el-table-column label="单位" align="center" prop="unitName" width="80" />
<!-- TODO @AI对齐的话生产数量生产用时生产单位是不是不需要这些字段 -->
<el-table-column label="生产数量" align="center" prop="quantity" width="100" /> <el-table-column label="生产数量" align="center" prop="quantity" width="100" />
<el-table-column label="生产用时" align="center" width="120"> <el-table-column label="生产用时" align="center" width="120">
<template #default="scope"> <template #default="scope">
@ -35,26 +34,31 @@
<!-- 表单弹窗添加/修改 --> <!-- 表单弹窗添加/修改 -->
<Dialog :title="formTitle" v-model="formVisible" width="960px"> <Dialog :title="formTitle" v-model="formVisible" width="960px">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px"> <el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
<el-form-item label="产品" prop="itemId">
<MdItemSelect v-model="formData.itemId" />
</el-form-item>
<el-form-item label="生产数量" prop="quantity">
<el-input-number v-model="formData.quantity" :min="1" controls-position="right" />
</el-form-item>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="14"> <el-col :span="12">
<el-form-item label="产品" prop="itemId">
<MdItemSelect v-model="formData.itemId" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="生产数量" prop="quantity">
<el-input-number v-model="formData.quantity" :min="1" controls-position="right" class="!w-1/1" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="生产用时" prop="productionTime"> <el-form-item label="生产用时" prop="productionTime">
<el-input-number <el-input-number
v-model="formData.productionTime" v-model="formData.productionTime"
:min="0" :min="0"
:precision="2" :precision="2"
controls-position="right" controls-position="right"
class="!w-1/1"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="12">
<el-form-item label="时间单位" prop="timeUnitType"> <el-form-item label="时间单位" prop="timeUnitType">
<el-select v-model="formData.timeUnitType" placeholder="请选择"> <el-select v-model="formData.timeUnitType" placeholder="请选择" class="!w-1/1">
<el-option <el-option
v-for="dict in getStrDictOptions(DICT_TYPE.MES_TIME_UNIT_TYPE)" v-for="dict in getStrDictOptions(DICT_TYPE.MES_TIME_UNIT_TYPE)"
:key="dict.value" :key="dict.value"

View File

@ -73,10 +73,15 @@
</el-table-column> </el-table-column>
<el-table-column label="路线名称" align="center" prop="name" min-width="200" /> <el-table-column label="路线名称" align="center" prop="name" min-width="200" />
<el-table-column label="路线说明" align="center" prop="description" min-width="200" /> <el-table-column label="路线说明" align="center" prop="description" min-width="200" />
<!-- TODO @AI改成 el-switch 形式 -->
<el-table-column label="状态" align="center" prop="status" min-width="100"> <el-table-column label="状态" align="center" prop="status" min-width="100">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> <el-switch
v-model="scope.row.status"
:active-value="0"
:inactive-value="1"
@change="handleStatusChange(scope.row)"
:disabled="!checkPermi(['mes:pro-route:update'])"
/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="备注" align="center" prop="remark" min-width="120" /> <el-table-column label="备注" align="center" prop="remark" min-width="120" />
@ -89,45 +94,40 @@
/> />
<el-table-column label="操作" align="center" width="220" fixed="right"> <el-table-column label="操作" align="center" width="220" fixed="right">
<template #default="scope"> <template #default="scope">
<!-- 停用状态编辑启用删除 --> <el-tooltip
<!-- TODO @AI禁用不可编辑删除时有个 tooltip disable 这样不要直接隐藏 --> :disabled="scope.row.status === CommonStatusEnum.DISABLE"
<el-button content="仅停用状态,才可以操作"
link placement="top"
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['mes:pro-route:update']"
v-if="scope.row.status === CommonStatusEnum.DISABLE"
> >
编辑 <span class="inline-block cursor-not-allowed">
</el-button> <el-button
<el-button link
link type="primary"
type="success" @click="openForm('update', scope.row.id)"
@click="openForm('enable', scope.row.id)" v-hasPermi="['mes:pro-route:update']"
v-hasPermi="['mes:pro-route:update']" :disabled="scope.row.status !== CommonStatusEnum.DISABLE"
v-if="scope.row.status === CommonStatusEnum.DISABLE" >
编辑
</el-button>
</span>
</el-tooltip>
<el-tooltip
:disabled="scope.row.status === CommonStatusEnum.DISABLE"
content="仅停用状态,才可以操作"
placement="top"
> >
启用 <span class="inline-block cursor-not-allowed">
</el-button> <el-button
<el-button link
link type="danger"
type="danger" @click="handleDelete(scope.row.id)"
@click="handleDelete(scope.row.id)" v-hasPermi="['mes:pro-route:delete']"
v-hasPermi="['mes:pro-route:delete']" :disabled="scope.row.status !== CommonStatusEnum.DISABLE"
v-if="scope.row.status === CommonStatusEnum.DISABLE" >
> 删除
删除 </el-button>
</el-button> </span>
<!-- 启用状态禁用 --> </el-tooltip>
<el-button
link
type="warning"
@click="handleDisable(scope.row)"
v-hasPermi="['mes:pro-route:update']"
v-if="scope.row.status === CommonStatusEnum.ENABLE"
>
禁用
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -148,6 +148,7 @@
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime' import { dateFormatter } from '@/utils/formatTime'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
import { checkPermi } from '@/utils/permission'
import download from '@/utils/download' import download from '@/utils/download'
import { ProRouteApi, ProRouteVO } from '@/api/mes/pro/route' import { ProRouteApi, ProRouteVO } from '@/api/mes/pro/route'
import RouteForm from './RouteForm.vue' import RouteForm from './RouteForm.vue'
@ -195,21 +196,24 @@ const resetQuery = () => {
handleQuery() handleQuery()
} }
/** 状态开关操作 */
const handleStatusChange = async (row: ProRouteVO) => {
try {
const text = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用'
await message.confirm('确认要“' + text + '”“' + row.name + '”工艺路线吗?')
await ProRouteApi.updateRouteStatus(row.id!, row.status!)
await getList()
} catch {
row.status =
row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE
}
}
/** 添加/修改操作 */ /** 添加/修改操作 */
const openForm = (type: string, id?: number) => { const openForm = (type: string, id?: number) => {
formRef.value.open(type, id) formRef.value.open(type, id)
} }
/** 禁用按钮操作 */
const handleDisable = async (row: ProRouteVO) => {
try {
await message.confirm('确认要停用"' + row.name + '"工艺路线吗?')
await ProRouteApi.updateRouteStatus(row.id!, CommonStatusEnum.DISABLE)
message.success('停用成功')
await getList()
} catch {}
}
/** 删除按钮操作 */ /** 删除按钮操作 */
const handleDelete = async (id: number) => { const handleDelete = async (id: number) => {
try { try {

View File

@ -455,6 +455,7 @@ export const MesAutoCodeRuleCode = {
DV_SUBJECT_CODE: 'DV_SUBJECT_CODE', // 点检保养项目编码 DV_SUBJECT_CODE: 'DV_SUBJECT_CODE', // 点检保养项目编码
DV_REPAIR_CODE: 'DV_REPAIR_CODE', // 维修单编码 DV_REPAIR_CODE: 'DV_REPAIR_CODE', // 维修单编码
PRO_PROCESS_CODE: 'PRO_PROCESS_CODE', // 工序编码 PRO_PROCESS_CODE: 'PRO_PROCESS_CODE', // 工序编码
PRO_ROUTE_CODE: 'PRO_ROUTE_CODE', // 工艺路线编码
PRO_WORK_ORDER_CODE: 'PRO_WORK_ORDER_CODE' // 生产工单编码 PRO_WORK_ORDER_CODE: 'PRO_WORK_ORDER_CODE' // 生产工单编码
} as const } as const