Merge remote-tracking branch 'origin/main'

main
liutao 1 week ago
commit f62a08eaae

@ -8,8 +8,8 @@ VITE_DEV=true
# 线上环境
# VITE_BASE_URL='https://besure.ngsk.tech:7001'
# 本地联调
VITE_BASE_URL='http://192.168.5.106:48081'
# VITE_BASE_URL='http://192.168.5.164:48081'
VITE_BASE_URL='http://192.168.5.160:48081'
# VITE_BASE_URL='http://192.168.43.233:48081'
# VITE_BASE_URL='http://192.168.5.5:48081'

@ -0,0 +1,121 @@
style产品物料信息-新增/编辑-编码输入框大小调整
feat仓库信息-添加详情弹框
feat库区信息/库位信息-新增页面
style任务单排产-排产甘特图样式优化
style甘特图菜单样式调整
style甘特图适配中英文
Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web
style生产报表页面适配中英文
style出库单据-默认展示tabs修改
style生产报表-质检信息字段调整
style任务单排产-create-batch接口添加领料人/是否计算损耗入参
style生产计划/任务单排产生产报表-进度条样式修改
style生产计划-检验明细添加分页
feat生产报表-质检信息对接
feat甘特图菜单页添加刷新按钮
style任务单排产-进度条样式修改
feat甘特图菜单页-添加排产看板
style生产计划-检验按钮保存后刷新列表
style检验记录-新增/编辑-生产计划选项框调整
style检验记录-编辑添加显示判断
style检验模板-新增/编辑-检验方案添加productId传参
style任务单排产-任务单明细-是否计算损耗字段
style检验模板-编辑回显
style任务单排产-任务单明细-新增计划添加领料人、是否完成质检字段
style生产报表-报工信息-添加日期筛选条件
style生产报表-列表添加刷新按钮
style生产报表-基础信息-查看产品信息字段修改
feat生产计划-已开工-检验按钮逻辑修改
style修复甘特图保存后弹框报错
style生产投料-数量不填的默认为0
style产品物料信息-设备-所属车间字段更改
feat检验模板-添加关联产品
style产品物料信息-关联设备选项接口添加deviceStatus=0入参
style产品物料信息-状态字段位置更改
style任务制单-技术要求、备注样式修改
style任务制单-明细-编辑-打包数量字段自动填充
style产品物料信息-去掉字段:采购价格、最低价格、销售价格
style产品BOM-产品BOM明细-单位自动带入
style生产计划-添加“所有”tabs
style甘特图菜单添加设备筛选框
style排产甘特图日期调整
feat菜单甘特图页面/一键排查-甘特图拆开两个组件
style排产弹框-任务单汇总明细-未计划数为0的不能勾选
style排产弹框适配中英文
style检验记录-新增添加单号自动生成
style产品BOM-产品筛选框接口更改
style任务单排产-排产弹框样式调整
style任务制单-父列表项的status值为2,7,8,9,10时子列表不展示编辑和删除按钮
Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web
style任务单排产-生产进度条样式修改
feat添加生产报表页面
style生产计划-暂停状态操作栏添加开工按钮
Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web
style厂区结构-关联采集设备字段回显
feat待入库-入库按钮添加仓库选择
style厂区结构-新增/编辑-关联采集设备选项接口更换
feat甘特图添加颜色区分
feat添加报工记录页面
style甘特图菜单页添加每日报工平均值、数据采集产能字段
style甘特图显示样式优化
style任务单排产-新增-计划开始、计划结束、最晚开工时间添加时分秒
style任务制单-新增-交货日期不能选往日
style任务单排产-添加生产进度条
style任务制单-tabs项更换
style任务单排产-新增计划-数量值添加校验(不能大于未计划数量)
style甘特图tooltip隐藏逻辑优化
Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web
style修改任务单排产-新增计划及生产计划详情字段
style任务制单-任务单明细-新增按钮显示逻辑修改
style任务单排产-tabs更换
style任务单排产-未计划为0的不显示新增计划按钮
style任务制单-任务单明细-新增按钮显示逻辑修改
style生产计划-报工后刷新报工记录列表
style生产计划-详情弹框字段与排产的新增计划弹框字段同步
style生产投料-新增-生产计划status值修改
style删除甘特图菜单无用代码
feat甘特图组件封装
style生产计划列表添加任务编码
style产品BOM-编辑-bomDetails集合里不传createTime字段
Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web
style排产甘特图样式优化
style排产弹框-添加是否跳过节假日switch
style排产甘特图样式调整
style检验记录-编辑-ticketType回显
style检验记录-生产计划传参修改
style任务单排产-关联设备保存后刷新列表
feat排产弹框-新增设备名称列/关联设备按钮
feat生产计划-添加已开工tabs
style任务单排产-新增计划-计划开始时间不能晚于结束时间
style设备台账-是否排产勾选后展示额定产能、每日报工平均值、数据采集产能
Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web
style处理设备台账代码合并问题
Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web
style甘特图查询时间默认本月
feat新增甘特图页面
style任务单排产-排产弹框-复选框逻辑优化
style任务单排产-甘特图样式修改
style任务单排产-一键排查接口字段调整
style任务单排产字段调整
style甘特图样式修改
style任务单排产-新增计划-taskDetailId传参调整
style产品物料信息-新增/编辑-设备列表添加已排产过滤
style排产接口入参添加产品编码
feat甘特图弹框抽离组件
style任务单排产-甘特图保存字段调整
style生产计划-甘特图样式修改
feat添加甘特图预览
style设备台账-新增/编辑-是否排产字段修改
style产品物料信息-阻止表单原生事件
style设备台账-是否排产字段修改
feat任务单排产-列表表头调整、排产弹框对接
style表管理-计算规则添加文案提示
feat采集设备-点位规则添加四则运算规则
style采集设备-添加新增产量按钮
style任务单排产-新增计划刷新列表
Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web
style任务单排产-列表添加“是否完成排产”列
style产品BOM-新增-清除单位默认值
feat任务制单-添加是否急单字段
feat产品管理-产品物料信息-产品分类时添加关联设备、关联模具字段
feat设备台账-添加是否排产、额定产能字段状态改成switch切换

@ -173,6 +173,17 @@ export const MoldBrandApi = {
// 获得模具产品
getMoldBrandProduct: async (id: number) => {
return await request.get({ url: `/erp/mold-brand/mold-brand-product/get?id=` + id })
},
// ==================== 压网记录 ====================
// 新增压网记录
createPressureNetRecord: async (data: any) => {
return await request.post({ url: `/erp/mold-pressure-net-record/create`, data })
},
// 查询压网记录分页
getPressureNetRecordPage: async (params: any) => {
return await request.get({ url: `/erp/mold-pressure-net-record/page`, params })
}
}

@ -4,10 +4,12 @@ import request from '@/config/axios'
export interface MoldOperateVO {
id: number // ID
operateType: string // 操作类型
moldId: number | string // 关联模具id(上模/下模剩余模具,支持逗号分隔)
moldId: number // 关联模具id
deviceId: number // 关联设备id
lineId: number // 产线
operateTime: string // 操作时间
operatorId: number // 操作人
remark: string // 备注
lowerMoldId?: number | string // 下模的模具id
}
// 模具上下模 API

@ -62,6 +62,10 @@ export const MoldRepairApi = {
return await request.get({ url: `/mes/mold-repair/getRepairListByMoldId`, params })
},
getMoldRepairList: async (params: any) => {
return await request.get({ url: `/mes/mold-repair/list`, params })
},
exportRepairExcel: async (params: { moldId: number; startTime?: string; endTime?: string }) => {
return await request.download({ url: `/mes/mold-repair/export-repair-excel`, params })
}

@ -29,6 +29,11 @@ export const TaskManagementApi = {
return await request.post({ url: `/mes/mold-task-management/createMoldTicket`, params: { id } })
},
// 直接创建模具任务工单(点检/保养)
createMoldTicketDirect: async (data: any) => {
return await request.post({ url: `/mes/mold-task-management/createMoldTicketDirect`, data })
},
createTaskManagement: async (data: TaskManagementVO) => {
return await request.post({ url: `/mes/mold-task-management/create`, data })
},

@ -16,6 +16,7 @@ export default {
ok: 'OK',
save: 'Save',
cancel: 'Cancel',
select: 'Select',
close: 'Close',
reload: 'Reload current',
success: 'Success',
@ -2325,16 +2326,16 @@ export default {
nextMonth: 'next month',
work: 'work',
rest: 'rest',
searchDateStartPlaceholder: '开始日期',
searchDateEndPlaceholder: '结束日期',
searchTypeLabel: '类型',
searchTypePlaceholder: '请选择类型',
searchRemarkLabel: '备注',
searchRemarkPlaceholder: '请输入备注',
searchButtonText: '搜索',
resetButtonText: '重置',
addButtonText: '新增',
exportButtonText: '导出'
searchDateStartPlaceholder: 'Start date',
searchDateEndPlaceholder: 'End date',
searchTypeLabel: 'Type',
searchTypePlaceholder: 'Please select type',
searchRemarkLabel: 'Remark',
searchRemarkPlaceholder: 'Please input remark',
searchButtonText: 'Search',
resetButtonText: 'Reset',
addButtonText: 'Add',
exportButtonText: 'Export'
},
EsopFile: {
@ -2461,7 +2462,8 @@ export default {
version: 'Version',
status: 'Status',
currentDevice: 'Current Device',
moldSize: 'Sub Mold Count',
moldSize: 'Cavity Number',
childMoldCount: 'Sub Mold Count',
createTime: 'Create Time',
operate: 'Operate',
detail: 'Detail',
@ -2485,6 +2487,8 @@ export default {
back: 'Back',
moldCode: 'Mold Code',
moldName: 'Mold Name',
moldGroupCode: 'Mold Group Code',
moldGroupName: 'Mold Group Name',
lastChangeTime: 'Last Change Time',
targetLine: 'Target Line',
lineName: 'Line Name',
@ -2515,10 +2519,29 @@ export default {
uninstallDown: 'Down Mold',
noRecords: 'No operation records',
qrcodeDialogTitle: 'Mold QR Code',
qrcodeTitle: 'Mold QR Code',
qrcodePrintTitle: '{name} Code Print Preview',
qrcodeEmpty: 'No QR code',
qrcodeLoadError: 'QR code load failed',
qrcodeRefreshConfirm: 'Confirm to refresh this mold QR code?'
qrcodeRefreshConfirm: 'Confirm to refresh this mold QR code?',
// 维护操作
maintain: 'Maintain',
maintainType: 'Maintain Type',
placeholderMaintainType: 'Please select maintain type',
maintainTypeInspect: 'Inspect',
maintainTypeMaintain: 'Maintain',
maintainTypeRepair: 'Repair',
maintainTypeReplaceNet: 'Replace Net',
subMold: 'Sub Mold',
placeholderSubMold: 'Please select sub mold',
pressureNetTime: 'Pressure Net Time',
placeholderPressureNetTime: 'Please select pressure net time',
validatorSubMoldRequired: 'Please select sub mold',
validatorPressureNetTimeRequired: 'Please select pressure net time',
replaceNetRemark: 'Remark',
placeholderReplaceNetRemark: 'Please input remark',
moldInfo: 'Mold Info',
maintainInfo: 'Maintain Info'
},
MoldBrandDetail: {
@ -2537,7 +2560,7 @@ export default {
productName: 'Product Model',
version: 'Version',
lifeStatus: 'Life Status',
childMoldCount: 'Sub Mold Count',
childMoldCount: 'Cavity Count',
tabMolds: 'Sub Molds',
tabInspection: 'Inspection Records',
tabRepair: 'Repair Records',
@ -2559,11 +2582,27 @@ export default {
repairResult: 'Repair Result',
finishDate: 'Finish Date',
totalItems: '{count} items in total',
repairCode: 'Repair Code',
repairName: 'Repair Order',
moldCode: 'Mold Code',
repairStatus: 'Status',
repairStatusPending: 'Pending',
repairStatusDone: 'Completed',
repairResultPending: 'Pending Repair',
repairResultOk: 'Pass',
repairResultNg: 'Fail',
placeholderRepairCode: 'Please enter repair code',
selectRepairStatus: 'Please select status',
requireDate: 'Require Date',
finishDate: 'Finish Date',
acceptUser: 'Repair User',
maintainMethod: 'Maintenance Method',
maintainTime: 'Maintenance Time',
mold: 'Mold',
selectMold: 'Select Mold',
remarkPlaceholder: 'Remark',
operateType: 'Operation Type',
selectOperateType: 'Please select operation type',
moldName: 'Mold Name',
deviceName: 'Device',
creatorName: 'Operator',
@ -2624,6 +2663,14 @@ export default {
installLocation: 'Install Location',
material: 'Material',
quantity: 'Quantity',
pressureNetInfo: 'Pressure Net Info',
lastReplace: 'Last Replace',
usedDays: 'Used',
days: 'days',
remark: 'Remark',
pressureNetRecord: 'Pressure Net Record',
pressureNetTime: 'Pressure Net Time',
createTime: 'Create Time',
operate: 'Operate',
edit: 'Edit',
delete: 'Delete',
@ -2816,11 +2863,14 @@ export default {
selectDeleteTip: 'Please select data to delete',
exportFilename: 'MoldInspectionPlan.xls',
validatorPlanNameRequired: 'Plan name can not be empty',
validatorPlanTypeRequired: 'Plan type can not be empty'
validatorPlanTypeRequired: 'Plan type can not be empty',
validatorSubjectIdsRequired: 'Related items can not be empty'
},
MoldRepair: {
moduleName: 'Mold Repair',
basicInfo: 'Basic Information',
faultInfo: 'Fault Information',
repairCode: 'Repair Order No',
repairName: 'Repair Order',
mold: 'Mold',
@ -2987,6 +3037,9 @@ export default {
device: 'Device',
deviceName: 'Device Name',
remark: 'Remark',
productionLine: 'Production Line',
operateTime: 'Operation Time',
operatorName: 'Operator',
creatorName: 'Operator',
createTime: 'Operation Time',
operate: 'Operate',
@ -3000,6 +3053,9 @@ export default {
placeholderMold: 'Please select mold',
placeholderLowerMold: 'Please select lower mold',
placeholderRemark: 'Please input remark',
placeholderProductionLine: 'Please select production line',
placeholderOperateTime: 'Please select operation time',
placeholderOperatorName: 'Please input operator',
placeholderCreateTimeStart: 'Start Date',
placeholderCreateTimeEnd: 'End Date',
placeholderDevice: 'Please select device',
@ -3007,6 +3063,7 @@ export default {
reset: 'Reset',
validatorOperateTypeRequired: 'Operation type can not be empty',
validatorDeviceRequired: 'Device can not be empty',
validatorProductionLineRequired: 'Production line can not be empty',
validatorMoldRequired: 'Mold can not be empty',
validatorLowerMoldRequired: 'Lower mold can not be empty',
alertNeedRemoveMoldFirst: 'Please remove the mold from this device first!',

@ -16,6 +16,7 @@ export default {
ok: '确定',
save: '保存',
cancel: '取消',
select: '选择',
close: '关闭',
reload: '重新加载',
success: '成功',
@ -1960,7 +1961,8 @@ export default {
version: '版本',
status: '状态',
currentDevice: '当前设备',
moldSize: '子模数',
moldSize: '模穴数',
childMoldCount: '子模数',
createTime: '创建时间',
operate: '操作',
detail: '详情',
@ -1985,6 +1987,8 @@ export default {
back: '返回',
moldCode: '模具编码',
moldName: '模具名称',
moldGroupCode: '模具组编码',
moldGroupName: '模具组名称',
lastChangeTime: '上次更换时间',
targetLine: '目标产线',
lineName: '产线名称',
@ -2015,10 +2019,29 @@ export default {
uninstallDown: '下模',
noRecords: '暂无操作记录',
qrcodeDialogTitle: '模具二维码',
qrcodeTitle: '模具二维码',
qrcodePrintTitle: '{name}码打印预览',
qrcodeEmpty: '暂无二维码',
qrcodeLoadError: '二维码加载失败',
qrcodeRefreshConfirm: '确认刷新该模具二维码吗?'
qrcodeRefreshConfirm: '确认刷新该模具二维码吗?',
// 维护操作
maintain: '维护',
maintainType: '维护类型',
placeholderMaintainType: '请选择维护类型',
maintainTypeInspect: '点检',
maintainTypeMaintain: '保养',
maintainTypeRepair: '维修',
maintainTypeReplaceNet: '更换压网',
subMold: '子模具',
placeholderSubMold: '请选择子模具',
pressureNetTime: '压网时间',
placeholderPressureNetTime: '请选择压网时间',
validatorSubMoldRequired: '请选择子模具',
validatorPressureNetTimeRequired: '请选择压网时间',
replaceNetRemark: '备注',
placeholderReplaceNetRemark: '请输入备注',
moldInfo: '模具信息',
maintainInfo: '维护信息'
},
MoldBrandDetail: {
@ -2037,7 +2060,7 @@ export default {
productName: '产品型号',
version: '版本',
lifeStatus: '寿命状态',
childMoldCount: '模数量',
childMoldCount: '数量',
// tabs
tabMolds: '子模具',
tabInspection: '点检记录',
@ -2063,6 +2086,20 @@ export default {
repairResult: '维修结果',
finishDate: '完成日期',
totalItems: '共{count}条',
repairCode: '维修单号',
repairName: '维修单',
moldCode: '模具编码',
repairStatus: '单据状态',
repairStatusPending: '待处理',
repairStatusDone: '已完成',
repairResultPending: '待维修',
repairResultOk: '通过',
repairResultNg: '不通过',
placeholderRepairCode: '请输入维修单号',
selectRepairStatus: '请选择单据状态',
requireDate: '报修日期',
finishDate: '完成日期',
acceptUser: '接修人',
// 保养
maintainMethod: '保养方式',
maintainTime: '保养时间',
@ -2070,6 +2107,8 @@ export default {
mold: '模具',
selectMold: '选择模具',
remarkPlaceholder: '备注',
operateType: '操作类型',
selectOperateType: '请选择操作类型',
moldName: '模具名称',
deviceName: '设备',
creatorName: '操作人',
@ -2131,6 +2170,14 @@ export default {
installLocation: '安装位置',
material: '材质',
quantity: '数量',
pressureNetInfo: '压网信息',
lastReplace: '上次更换',
usedDays: '已使用',
days: '天',
remark: '备注',
pressureNetRecord: '压网记录',
pressureNetTime: '压网时间',
createTime: '创建时间',
operate: '操作',
edit: '编辑',
delete: '删除',
@ -2323,11 +2370,14 @@ export default {
selectDeleteTip: '请选择需要删除的数据',
exportFilename: '模具检验模板.xls',
validatorPlanNameRequired: '模板名称不能为空',
validatorPlanTypeRequired: '模板类型不能为空'
validatorPlanTypeRequired: '模板类型不能为空',
validatorSubjectIdsRequired: '关联项目不能为空'
},
MoldRepair: {
moduleName: '维修单',
basicInfo: '基本信息',
faultInfo: '故障信息',
repairCode: '维修单号',
repairName: '维修单',
mold: '模具',
@ -2494,6 +2544,9 @@ export default {
device: '设备',
deviceName: '设备名称',
remark: '备注',
productionLine: '产线',
operateTime: '操作时间',
operatorName: '操作人',
creatorName: '操作人',
createTime: '操作时间',
operate: '操作',
@ -2507,6 +2560,9 @@ export default {
placeholderMold: '请选择模具',
placeholderLowerMold: '请选择下模模具',
placeholderRemark: '请输入备注',
placeholderProductionLine: '请选择产线',
placeholderOperateTime: '请选择操作时间',
placeholderOperatorName: '请输入操作人',
placeholderCreateTimeStart: '开始日期',
placeholderCreateTimeEnd: '结束日期',
placeholderDevice: '请选择设备',
@ -2514,6 +2570,7 @@ export default {
reset: '重置',
validatorOperateTypeRequired: '操作类型不能为空',
validatorDeviceRequired: '关联设备不能为空',
validatorProductionLineRequired: '产线不能为空',
validatorMoldRequired: '关联模具不能为空',
validatorLowerMoldRequired: '下模模具不能为空',
alertNeedRemoveMoldFirst: '请先将该设备上的模具换下!',

@ -22,8 +22,8 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="t('MoldManagement.MoldBrandFormPage.productName')" prop="productId">
<el-select v-model="formData.productId" filterable clearable :placeholder="t('MoldManagement.MoldBrandFormPage.placeholderProduct')" class="w-1/1" @change="handleProductChange">
<el-form-item :label="t('MoldManagement.MoldBrandFormPage.productName')" prop="productIds">
<el-select v-model="formData.productIds" multiple filterable clearable :placeholder="t('MoldManagement.MoldBrandFormPage.placeholderProduct')" class="w-1/1" @change="handleProductChange">
<el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
@ -153,7 +153,7 @@ const formRules = reactive({
code: [{ validator: validateCode, trigger: 'blur' }],
name: [{ required: true, message: t('MoldManagement.MoldBrandFormPage.validatorNameRequired'), trigger: 'blur' }],
moldType: [{ required: true, message: t('MoldManagement.MoldBrandFormPage.validatorNameRequired'), trigger: 'blur' }],
productId: [{ required: true, message: t('MoldManagement.MoldBrandFormPage.validatorProductRequired'), trigger: 'change' }],
productIds: [{ required: true, message: t('MoldManagement.MoldBrandFormPage.validatorProductRequired'), trigger: 'change' }],
moldSize: [{ required: true, message: t('MoldManagement.MoldBrandFormPage.validatorMoldSizeRequired'), trigger: 'blur' }],
isEnable: [{ required: true, message: t('MoldManagement.MoldBrandFormPage.validatorIsEnableRequired'), trigger: 'change' }]
})
@ -181,10 +181,11 @@ const resetForm = () => {
formRef.value?.resetFields()
}
const handleProductChange = (value?: number) => {
const current = productList.value.find((item) => item.id === value)
formData.value.productName = current?.name || ''
formData.value.productIds = value ? [value] : []
const handleProductChange = (value?: number[] | number) => {
const ids = Array.isArray(value) ? value : value ? [value] : []
formData.value.productIds = ids
const names = productList.value.filter((item) => ids.includes(item.id)).map((p) => p.name)
formData.value.productName = names.join(',')
}
const open = async (type: string, id?: number) => {
@ -193,7 +194,7 @@ const open = async (type: string, id?: number) => {
formType.value = type
resetForm()
await dictStore.setDictMap()
productList.value = await ProductApi.getMesProductSimpleList()
productList.value = await ProductApi.getMesProductSimpleList({ categoryType: 1 })
if (!id) return
formLoading.value = true
try {
@ -220,16 +221,12 @@ const emit = defineEmits(['success'])
const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
try {
handleProductChange(formData.value.productId)
try {
handleProductChange(formData.value.productIds)
const payload: MoldBrandVO = {
...formData.value,
version: addVersionPrefix(formData.value.version),
productIds: Array.isArray(formData.value.productIds)
? formData.value.productIds
: formData.value.productId
? [formData.value.productId]
: [],
productIds: Array.isArray(formData.value.productIds) ? formData.value.productIds : [],
isEnable: Boolean(formData.value.isEnable)
}
if (formType.value === 'create') {

@ -1,13 +1,26 @@
<template>
<ContentWrap>
<el-form :model="queryParams" ref="queryFormRef" :inline="true" class="-mb-15px">
<el-form-item :label="t('MoldManagement.MoldListPage.code')" prop="code"><el-input v-model="queryParams.code" :placeholder="t('MoldManagement.MoldListPage.placeholderCode')" clearable @keyup.enter="handleQuery" class="!w-200px" /></el-form-item>
<el-form-item :label="t('MoldManagement.MoldListPage.name')" prop="name"><el-input v-model="queryParams.name" :placeholder="t('MoldManagement.MoldListPage.placeholderName')" clearable @keyup.enter="handleQuery" class="!w-200px" /></el-form-item>
<el-form-item :label="t('MoldManagement.MoldListPage.code')" prop="code"><el-input v-model="queryParams.code"
:placeholder="t('MoldManagement.MoldListPage.placeholderCode')" clearable @keyup.enter="handleQuery"
class="!w-200px" /></el-form-item>
<el-form-item :label="t('MoldManagement.MoldListPage.name')" prop="name"><el-input v-model="queryParams.name"
:placeholder="t('MoldManagement.MoldListPage.placeholderName')" clearable @keyup.enter="handleQuery"
class="!w-200px" /></el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('MoldManagement.MoldListPage.query') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('MoldManagement.MoldListPage.reset') }}</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['erp:mold-brand:create']"><Icon icon="ep:plus" class="mr-5px" /> {{ t('MoldManagement.MoldListPage.addSubMold') }}</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading" v-hasPermi="['erp:mold-brand:export']"><Icon icon="ep:download" class="mr-5px" /> {{ t('MoldManagement.MoldListPage.export') }}</el-button>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('MoldManagement.MoldListPage.query') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('MoldManagement.MoldListPage.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['erp:mold-brand:create']">
<Icon icon="ep:plus" class="mr-5px" /> {{ t('MoldManagement.MoldListPage.addSubMold') }}
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['erp:mold-brand:export']">
<Icon icon="ep:download" class="mr-5px" /> {{ t('MoldManagement.MoldListPage.export') }}
</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
@ -20,7 +33,8 @@
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldListPage.installLocation')" min-width="140">
<template #default="scope">
{{ scope.row.installLocation || scope.row.installPosition || scope.row.currentPosition || scope.row.machineName || '-' }}
{{ scope.row.installLocation || scope.row.installPosition || scope.row.currentPosition ||
scope.row.machineName || '-' }}
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldListPage.material')" min-width="120">
@ -33,21 +47,56 @@
{{ scope.row.quantity || scope.row.count || 1 }}
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldListPage.operate')" fixed="right" width="160">
<el-table-column :label="t('MoldManagement.MoldListPage.pressureNetInfo')" min-width="180">
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row.id)">{{ t('MoldManagement.MoldListPage.edit') }}</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)">{{ t('MoldManagement.MoldListPage.delete') }}</el-button>
<div>{{ t('MoldManagement.MoldListPage.lastReplace') }}{{ scope.row.pressureNetTime }}</div>
<div>{{ t('MoldManagement.MoldListPage.usedDays') }}{{ scope.row.pressureNetDays }}{{
t('MoldManagement.MoldListPage.days') }}</div>
<div v-if="scope.row.remark">{{ t('MoldManagement.MoldListPage.remark') }}{{ scope.row.remark }}</div>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldListPage.operate')" fixed="right" width="220">
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row.id)">{{
t('MoldManagement.MoldListPage.edit') }}</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)">{{ t('MoldManagement.MoldListPage.delete')
}}</el-button>
<el-button link type="warning" @click="openPressureNetRecord(scope.row.id)">{{
t('MoldManagement.MoldListPage.pressureNetRecord') }}</el-button>
</template>
</el-table-column>
</el-table>
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize" @pagination="getList" />
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
<MoldForm ref="formRef" @success="getList" />
<!-- 压网记录弹框 -->
<Dialog v-model="pressureNetDialogVisible" :title="t('MoldManagement.MoldListPage.pressureNetRecord')" width="700px">
<div class="pressure-net-dialog-content">
<el-table v-loading="pressureNetLoading" :data="pressureNetRecordList" :stripe="true"
:show-overflow-tooltip="true">
<el-table-column :label="t('MoldManagement.MoldListPage.subMoldName')" prop="moldName" min-width="120" />
<el-table-column :label="t('MoldManagement.MoldListPage.pressureNetTime')" prop="pressureNetTime"
min-width="160" :formatter="dateFormatter" />
<el-table-column :label="t('MoldManagement.MoldListPage.createTime')" prop="createTime" min-width="160"
:formatter="dateFormatter" />
<el-table-column :label="t('MoldManagement.MoldListPage.remark')" prop="remark" min-width="160">
<template #default="scope">
{{ scope.row.remark || '-' }}
</template>
</el-table-column>
</el-table>
<Pagination :total="pressureNetTotal" v-model:page="pressureNetPageParams.pageNo"
v-model:limit="pressureNetPageParams.pageSize" @pagination="getPressureNetRecordList" />
</div>
</Dialog>
<MoldRecordForm ref="recordFormRef" @success="getList" />
</template>
<script setup lang="ts">
import { defineAsyncComponent, nextTick } from 'vue'
import download from '@/utils/download'
import { dateFormatter } from '@/utils/formatTime'
import { DICT_TYPE } from '@/utils/dict'
import { MoldBrandApi } from '@/api/erp/mold'
@ -166,4 +215,40 @@ const openRecordForm = (type: string, id?: number, brandId?: number) => {
recordFormRef.value.open(type, id, brandId)
}
/** 压网记录弹框 */
const pressureNetDialogVisible = ref(false)
const pressureNetLoading = ref(false)
const pressureNetRecordList = ref<any[]>([])
const pressureNetTotal = ref(0)
const pressureNetPageParams = reactive({
pageNo: 1,
pageSize: 10,
moldId: undefined as number | undefined
})
const openPressureNetRecord = (moldId: number) => {
pressureNetPageParams.moldId = moldId
pressureNetPageParams.pageNo = 1
pressureNetDialogVisible.value = true
getPressureNetRecordList()
}
const getPressureNetRecordList = async () => {
pressureNetLoading.value = true
try {
const data = await MoldBrandApi.getPressureNetRecordPage(pressureNetPageParams)
pressureNetRecordList.value = data.list ?? []
pressureNetTotal.value = data.total ?? 0
} finally {
pressureNetLoading.value = false
}
}
</script>
<style lang="scss" scoped>
.pressure-net-dialog-content {
max-height: 500px;
overflow-y: auto;
padding: 10px;
}
</style>

@ -0,0 +1,955 @@
<template>
<div class="mold-maintain-page">
<div class="mold-maintain-page__header">
<el-button @click="emit('back')">
<Icon icon="ep:arrow-left" class="mr-5px" /> {{ t('MoldManagement.MoldBrandPage.back') }}
</el-button>
</div>
<div class="mold-maintain-page__body">
<!-- 左侧模具信息区域 -->
<div class="mold-maintain-page__sidebar" v-if="mold">
<div class="mold-maintain-page__info-card">
<div class="mold-maintain-page__info-header">
<span class="mold-maintain-page__info-num">1</span>
<span class="mold-maintain-page__info-title">{{ t('MoldManagement.MoldBrandPage.moldInfo') }}</span>
</div>
<div class="mold-maintain-page__info-image-wrap">
<el-image v-if="getImageList(mold.images).length" :src="getImageList(mold.images)[0]"
fit="cover" class="mold-maintain-page__info-image" />
<el-empty v-else :description="t('MoldManagement.MoldBrandDetail.noImage')" />
</div>
<div class="mold-maintain-page__info-item">
<span class="mold-maintain-page__info-label">{{ t('MoldManagement.MoldBrandPage.moldGroupCode') }}</span>
<span class="mold-maintain-page__info-value">{{ mold.code }}</span>
</div>
<div class="mold-maintain-page__info-item">
<span class="mold-maintain-page__info-label">{{ t('MoldManagement.MoldBrandPage.moldGroupName') }}</span>
<span class="mold-maintain-page__info-value">{{ mold.name }}</span>
</div>
<div class="mold-maintain-page__info-item">
<span class="mold-maintain-page__info-label">{{ t('MoldManagement.MoldBrandPage.productName') }}</span>
<span class="mold-maintain-page__info-value">{{ mold.productName }}</span>
</div>
<div class="mold-maintain-page__info-item">
<span class="mold-maintain-page__info-label">{{ t('MoldManagement.MoldBrandPage.moldSize') }}</span>
<span class="mold-maintain-page__info-value">{{ mold.moldSize }}</span>
</div>
<div class="mold-maintain-page__info-item">
<span class="mold-maintain-page__info-label">{{ t('MoldManagement.MoldBrandPage.status') }}</span>
<dict-tag :type="DICT_TYPE.ERP_MOLD_STATUS" :value="mold.status" />
</div>
<div class="mold-maintain-page__info-item">
<span class="mold-maintain-page__info-label">{{ t('MoldManagement.MoldBrandPage.currentDevice') }}</span>
<span class="mold-maintain-page__info-value">{{ mold.currentDevice || '-' }}</span>
</div>
</div>
</div>
<!-- 右侧表单区域 -->
<div class="mold-maintain-page__form">
<div class="mold-maintain-page__form-header">
<span class="mold-maintain-page__info-num">2</span>
<span class="mold-maintain-page__info-title">{{ t('MoldManagement.MoldBrandPage.maintainInfo') }}</span>
</div>
<el-form ref="maintainFormRef" :model="formModel" :rules="formRules" label-width="100px">
<!-- 维护类型 -->
<el-form-item :label="t('MoldManagement.MoldBrandPage.maintainType')" prop="maintainType">
<div class="mold-maintain-type-card">
<div
v-for="type in maintainTypes"
:key="type.value"
class="mold-maintain-type-card__item"
:class="{ 'is-active': maintainFormData.maintainType === type.value }"
@click="selectMaintainType(type.value)"
>
<div class="mold-maintain-type-card__icon">
<el-icon :size="26">
<component :is="type.icon" />
</el-icon>
</div>
<span class="mold-maintain-type-card__label">{{ type.label }}</span>
</div>
</div>
</el-form-item>
<!-- 点检/保养表单 -->
<template v-if="isInspectOrMaintain">
<el-form-item :label="t('EquipmentManagement.TaskManagement.name')" prop="name">
<el-input v-model="taskFormData.name" :placeholder="t('EquipmentManagement.TaskManagement.placeholderName')" />
</el-form-item>
<el-form-item :label="t('EquipmentManagement.TaskManagement.projectForm')" prop="projectForm">
<div class="flex items-center gap-2 w-full">
<el-input
v-model="projectFormDisplayText"
readonly
:placeholder="t('EquipmentManagement.TaskManagement.placeholderProjectForm')"
class="flex-1"
/>
<el-button @click="openProjectFormDialog">{{ t('common.select') }}</el-button>
</div>
</el-form-item>
</template>
<!-- 维修表单 -->
<template v-if="isRepair">
<section class="dv-repair-section">
<div class="dv-repair-section__title">{{ t('MoldManagement.MoldRepair.basicInfo') }}</div>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="t('MoldManagement.MoldRepair.repairCode')" prop="repairCode">
<div class="dv-repair-code-row">
<el-input
:disabled="repairCodeDisabled"
v-model="repairFormData.repairCode"
:placeholder="t('common.code')"
/>
<el-switch
v-model="repairFormData.isCode"
/>
</div>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('MoldManagement.MoldRepair.repairName')" prop="repairName">
<el-input
v-model="repairFormData.repairName"
:placeholder="t('MoldManagement.MoldRepair.placeholderRepairName')"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('MoldManagement.MoldRepair.requireDate')" prop="requireDate">
<el-date-picker
v-model="repairFormData.requireDate"
type="date"
value-format="x"
:placeholder="t('MoldManagement.MoldRepair.placeholderRequireDate')"
class="!w-full"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="t('MoldManagement.MoldRepair.repairUser')" prop="acceptedBy">
<el-select
v-model="repairFormData.acceptedBy" filterable clearable
:placeholder="t('MoldManagement.MoldRepair.placeholderAcceptUser')"
class="!w-full">
<el-option v-for="item in users" :key="String(item.id)" :label="item.nickname" :value="String(item.id)" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('MoldManagement.MoldRepair.confirmUser')" prop="confirmBy">
<el-select
v-model="repairFormData.confirmBy" filterable clearable
:placeholder="t('MoldManagement.MoldRepair.placeholderConfirmUser')"
class="!w-full">
<el-option v-for="item in users" :key="String(item.id)" :label="item.nickname" :value="String(item.id)" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="t('MoldManagement.MoldRepair.faultLevel')" prop="faultLevel">
<el-radio-group v-model="repairFormData.faultLevel">
<el-radio
v-for="dict in failureLevelOptions"
:key="String(dict.value)"
:label="String(dict.value)"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('MoldManagement.MoldRepair.isShutdown')" prop="shutdown">
<el-radio-group v-model="repairFormData.shutdown">
<el-radio :label="true">{{ t('common.yes') }}</el-radio>
<el-radio :label="false">{{ t('common.no') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</section>
<section class="dv-repair-section">
<div class="dv-repair-section__title">{{ t('MoldManagement.MoldRepair.faultInfo') }}</div>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item :label="t('MoldManagement.MoldRepair.faultPhenomenon')" prop="faultPhenomenon">
<el-input
v-model="repairFormData.faultPhenomenon"
:placeholder="t('MoldManagement.MoldRepair.placeholderFaultPhenomenon')"
/>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldRepair.faultDescription')" prop="faultDescription">
<el-input
v-model="repairFormData.faultDescription"
type="textarea"
:rows="4"
:placeholder="t('MoldManagement.MoldRepair.placeholderFaultDescription')"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item :label="t('MoldManagement.MoldRepair.faultImages')">
<UploadImgs
v-model="faultImagesValue"
:limit="9"
width="120px"
height="120px"
class="dv-repair-upload"
/>
</el-form-item>
</el-col>
</el-row>
</section>
<section class="dv-repair-section">
<div class="dv-repair-section__title">{{ t('MoldManagement.MoldRepair.remark') }}</div>
<el-form-item prop="remark" label-width="0">
<el-input
v-model="repairFormData.remark"
type="textarea"
:rows="3"
maxlength="300"
show-word-limit
:placeholder="t('MoldManagement.MoldRepair.placeholderRemark')"
/>
</el-form-item>
</section>
</template>
<!-- 更换压网表单 -->
<template v-if="isReplaceNet">
<section class="dv-repair-section">
<div class="dv-repair-section__title">{{ t('MoldManagement.MoldBrandPage.maintainTypeReplaceNet') }}</div>
<el-form-item :label="t('MoldManagement.MoldBrandPage.subMold')" prop="moldId">
<el-select
v-model="replaceNetFormData.moldId"
filterable
clearable
:loading="subMoldLoading"
:placeholder="t('MoldManagement.MoldBrandPage.placeholderSubMold')"
class="!w-full"
@change="handleSubMoldChange"
>
<el-option
v-for="item in subMoldList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandPage.pressureNetTime')" prop="pressureNetTime">
<el-date-picker
v-model="replaceNetFormData.pressureNetTime"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('MoldManagement.MoldBrandPage.placeholderPressureNetTime')"
class="!w-full"
:disabled-date="(date: Date) => date.getTime() > Date.now()"
/>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandPage.replaceNetRemark')" prop="replaceNetRemark">
<el-input
v-model="replaceNetFormData.remark"
type="textarea"
:rows="3"
maxlength="300"
show-word-limit
:placeholder="t('MoldManagement.MoldBrandPage.placeholderReplaceNetRemark')"
/>
</el-form-item>
</section>
</template>
</el-form>
<div class="mold-maintain-page__form-actions">
<el-button @click="emit('back')">{{ t('MoldManagement.MoldBrandPage.cancel') }}</el-button>
<el-button type="primary" @click="submitForm" :loading="submitLoading">{{ t('MoldManagement.MoldBrandPage.submit') }}</el-button>
</div>
</div>
</div>
<!-- 项目表单选择弹框 -->
<Dialog v-model="projectFormDialogVisible" :title="t('EquipmentManagement.TaskManagement.projectForm')" width="1200px">
<div class="project-form-dialog-content">
<el-table
ref="projectFormTableRef"
v-loading="projectFormLoading"
:data="projectFormList"
row-key="id"
@expand-change="handleProjectFormExpandChange"
>
<el-table-column width="55" align="center">
<template #default="scope">
<el-radio
v-model="tempSelectedProjectFormId"
:value="String(scope.row.id)"
@change="handleProjectFormRadioChange(scope.row)"
/>
</template>
</el-table-column>
<el-table-column type="expand" width="48">
<template #default="scope">
<div class="p-12px">
<el-table
v-loading="subjectLoadingMap[String(scope.row.id)]"
:data="subjectListMap[String(scope.row.id)] ?? []"
:stripe="true"
:show-overflow-tooltip="true"
size="small"
>
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.index')" align="center" width="80">
<template #default="s2">
{{ s2.$index + 1 }}
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.subjectCode')" align="center" prop="subjectCode" />
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.subjectName')" align="center" prop="subjectName" />
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.inspectionMethod')" align="center" prop="inspectionMethod" width="120" />
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.judgmentCriteria')" align="center" prop="judgmentCriteria" />
</el-table>
</div>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.index')" align="center" width="80">
<template #default="scope">
{{ (projectFormPageParams.pageNo - 1) * projectFormPageParams.pageSize + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.planName')" prop="planName" min-width="160" />
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.planType')" width="110">
<template #default="scope">
<el-tag effect="light" :type="scope.row.planType === 1 ? 'success' : 'primary'" size="small">
{{ scope.row.planType === 1 ? t('MoldManagement.MoldInspectionPlan.planTypeMaintain') : t('MoldManagement.MoldInspectionPlan.planTypeInspect') }}
</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.description')" prop="description" min-width="200" />
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.creatorName')" prop="creatorName" width="140" />
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.createTime')" prop="createTime" :formatter="dateFormatter" width="180" />
<el-table-column :label="t('MoldManagement.MoldInspectionPlan.updateTime')" prop="updateTime" :formatter="dateFormatter" width="180" />
</el-table>
<Pagination
:total="projectFormTotal"
v-model:page="projectFormPageParams.pageNo"
v-model:limit="projectFormPageParams.pageSize"
@pagination="loadProjectFormList"
/>
</div>
<template #footer>
<el-button @click="projectFormDialogVisible = false">{{ t('common.cancel') }}</el-button>
<el-button type="primary" @click="confirmProjectFormSelection">{{ t('common.ok') }}</el-button>
</template>
</Dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { EditPen, RefreshRight, Search, Tools } from '@element-plus/icons-vue'
import { MoldBrandApi, type MoldBrandVO } from '@/api/erp/mold'
import { DeviceLedgerApi, type DeviceLedgerVO } from '@/api/mes/deviceledger'
import { TaskManagementApi } from '@/api/mold/taskManagement'
import { MoldRepairApi, type MoldRepairVO } from '@/api/mold/moldrepair'
import { PlanMaintenanceApi } from '@/api/mold/planmaintenance'
import { getSimpleUserList, type UserVO } from '@/api/system/user'
import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
defineOptions({ name: 'MoldMaintainView' })
const props = defineProps<{
mold: MoldBrandVO | null
deviceOptions: DeviceLedgerVO[]
}>()
const emit = defineEmits<{
(e: 'back'): void
(e: 'success'): void
}>()
const { t } = useI18n()
const message = useMessage()
const submitLoading = ref(false)
const maintainFormRef = ref()
//
const formRules = reactive({
maintainType: [{ required: true, message: t('MoldManagement.MoldBrandPage.placeholderMaintainType'), trigger: 'change' }],
// /
name: [{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderName'), trigger: 'blur' }],
taskType: [{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderTaskType'), trigger: 'change' }],
projectForm: [{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderProjectForm') }],
//
repairName: [{ required: true, message: t('MoldManagement.MoldRepair.validatorRepairNameRequired'), trigger: 'blur' }],
requireDate: [{ required: true, message: t('MoldManagement.MoldRepair.validatorRequireDateRequired'), trigger: 'change' }],
faultLevel: [{ required: true, message: t('MoldManagement.MoldRepair.validatorFaultLevelRequired'), trigger: 'blur' }],
shutdown: [{ required: true, message: t('MoldManagement.MoldRepair.validatorIsShutdownRequired'), trigger: 'blur' }],
faultPhenomenon: [{ required: true, message: t('MoldManagement.MoldRepair.validatorFaultPhenomenonRequired'), trigger: 'blur' }],
//
moldId: [{ required: true, message: t('MoldManagement.MoldBrandPage.validatorSubMoldRequired'), trigger: 'blur' }],
pressureNetTime: [{ required: true, message: t('MoldManagement.MoldBrandPage.validatorPressureNetTimeRequired'), trigger: 'blur' }],
})
// el-form
const formModel = computed(() => ({
maintainType: maintainFormData.maintainType,
name: taskFormData.name,
taskType: taskFormData.taskType,
projectForm: taskFormData.projectForm,
repairName: repairFormData.repairName,
requireDate: repairFormData.requireDate,
faultLevel: repairFormData.faultLevel,
shutdown: repairFormData.shutdown,
faultPhenomenon: repairFormData.faultPhenomenon,
moldId: replaceNetFormData.moldId,
pressureNetTime: replaceNetFormData.pressureNetTime,
}))
//
const maintainFormData = reactive({
maintainType: 1 as number
})
// /
const taskFormData = reactive({
name: undefined as string | undefined,
taskType: 1 as number,
projectForm: '' as string
})
//
const repairFormData = reactive({
repairCode: undefined as string | undefined,
repairName: undefined as string | undefined,
requireDate: undefined as string | undefined,
acceptedBy: undefined as string | undefined,
confirmBy: undefined as string | undefined,
faultLevel: undefined as string | undefined,
shutdown: undefined as boolean | undefined,
faultPhenomenon: undefined as string | undefined,
faultDescription: undefined as string | undefined,
faultImages: '' as string,
remark: undefined as string | undefined,
isCode: true as boolean
})
//
const replaceNetFormData = reactive({
moldId: undefined as number | undefined,
moldName: undefined as string | undefined,
pressureNetTime: undefined as string | undefined,
remark: undefined as string | undefined
})
//
const subMoldList = ref<any[]>([])
const subMoldLoading = ref(false)
const loadSubMoldList = async () => {
if (!props.mold?.id) return
subMoldLoading.value = true
try {
const data = await MoldBrandApi.getMoldList({ brandId: props.mold.id })
subMoldList.value = data ?? []
} finally {
subMoldLoading.value = false
}
}
const handleSubMoldChange = (moldId: number) => {
const selected = subMoldList.value.find((item: any) => item.id === moldId)
replaceNetFormData.moldName = selected?.name ?? ''
}
//
const isInspectOrMaintain = computed(() => [1, 2].includes(maintainFormData.maintainType ?? 0))
const isRepair = computed(() => maintainFormData.maintainType === 3)
const isReplaceNet = computed(() => maintainFormData.maintainType === 4)
const repairCodeDisabled = computed(() => repairFormData.isCode === true)
const failureLevelOptions = computed(() => getStrDictOptions(DICT_TYPE.FAILURE_LEVEL))
//
const maintainTypes = computed(() => [
{ value: 1, label: t('MoldManagement.MoldBrandPage.maintainTypeInspect'), icon: Search },
{ value: 2, label: t('MoldManagement.MoldBrandPage.maintainTypeMaintain'), icon: Tools },
{ value: 3, label: t('MoldManagement.MoldBrandPage.maintainTypeRepair'), icon: EditPen },
{ value: 4, label: t('MoldManagement.MoldBrandPage.maintainTypeReplaceNet'), icon: RefreshRight }
])
// 使 select
const planOptions = ref<{ id: number | string; planName: string }[]>([])
const users = ref<UserVO[]>([])
//
const projectFormDialogVisible = ref(false)
const projectFormLoading = ref(false)
const projectFormList = ref<any[]>([])
const projectFormTotal = ref(0)
const projectFormTableRef = ref()
const tempSelectedProjectForm = ref<any>(null) //
const tempSelectedProjectFormId = ref<string>('') // radio id
const selectedProjectFormId = ref<string>('') // id
const selectedProjectFormName = ref<string>('') //
const subjectListMap = ref<Record<string, any[]>>({})
const subjectLoadingMap = ref<Record<string, boolean>>({})
const projectFormPageParams = reactive({
pageNo: 1,
pageSize: 10
})
const projectFormDisplayText = computed(() => {
return selectedProjectFormName.value || ''
})
const loadProjectFormList = async () => {
projectFormLoading.value = true
try {
const res = await PlanMaintenanceApi.getPlanMaintenancePage({
pageNo: projectFormPageParams.pageNo,
pageSize: projectFormPageParams.pageSize
})
projectFormList.value = res?.list ?? []
projectFormTotal.value = res?.total ?? 0
} finally {
projectFormLoading.value = false
}
}
const openProjectFormDialog = async () => {
projectFormPageParams.pageNo = 1
tempSelectedProjectForm.value = null
tempSelectedProjectFormId.value = selectedProjectFormId.value || ''
projectFormDialogVisible.value = true
await loadProjectFormList()
}
const handleProjectFormRadioChange = (row: any) => {
tempSelectedProjectForm.value = row
}
const confirmProjectFormSelection = () => {
if (!tempSelectedProjectForm.value) return
selectedProjectFormId.value = String(tempSelectedProjectForm.value.id)
selectedProjectFormName.value = tempSelectedProjectForm.value.planName ?? String(tempSelectedProjectForm.value.id)
taskFormData.projectForm = selectedProjectFormId.value
projectFormDialogVisible.value = false
}
const ensureSubjectListLoaded = async (planId: number | string) => {
const key = String(planId)
if (!key) return
if (subjectListMap.value[key]) return
subjectLoadingMap.value[key] = true
try {
const res = await PlanMaintenanceApi.getSubjectList(planId)
const data = Array.isArray(res) ? res : res?.list ?? res ?? []
subjectListMap.value[key] = (data ?? [])
} finally {
subjectLoadingMap.value[key] = false
}
}
const handleProjectFormExpandChange = async (row: any, expandedRows: any[]) => {
const isExpanded = expandedRows.some((r) => String(r.id) === String(row.id))
if (!isExpanded) return
if (row?.id === undefined || row?.id === null || row?.id === '') return
await ensureSubjectListLoaded(row.id)
}
const ensureUsersLoaded = async () => {
if (users.value.length) return
users.value = (await getSimpleUserList()) ?? []
}
const normalizeUserId = (value: any) => {
if (value === undefined || value === null || value === '') return undefined
const str = String(value)
if (/^\d+$/.test(str)) return str
const matched = users.value.find((u) => u.nickname === str)
return matched ? String(matched.id) : str
}
const splitImageValue = (value: unknown) => {
if (Array.isArray(value)) return value.map((item) => String(item).trim()).filter(Boolean)
if (typeof value !== 'string') return []
return value
.split(',')
.map((item) => item.trim())
.filter(Boolean)
}
const normalizeImageString = (value: unknown) => splitImageValue(value).join(',')
const faultImagesValue = computed<string[]>({
get: () => splitImageValue(repairFormData.faultImages),
set: (value) => { repairFormData.faultImages = value.join(',') }
})
const getImageList = (images?: string) => {
if (!images) return []
return String(images)
.split(',')
.map((item) => item.trim())
.filter(Boolean)
}
const initOptions = async () => {
const [planRes, userRes] = await Promise.all([
PlanMaintenanceApi.getPlanMaintenancePage({}),
getSimpleUserList()
])
planOptions.value = (planRes?.list ?? []) as { id: number | string; planName: string }[]
users.value = userRes ?? []
}
const handleMaintainTypeChange = () => {
// taskType
if (isInspectOrMaintain.value) {
taskFormData.taskType = maintainFormData.maintainType
}
}
const selectMaintainType = async (type: number) => {
maintainFormData.maintainType = type
handleMaintainTypeChange()
//
await initOptions()
//
if (type === 4) {
await loadSubMoldList()
}
}
const submitForm = async () => {
//
try {
await maintainFormRef.value?.validate()
} catch {
return
}
submitLoading.value = true
try {
if (isInspectOrMaintain.value) {
// /
await TaskManagementApi.createMoldTicketDirect({
name: taskFormData.name,
taskType: String(taskFormData.taskType),
moldList: props.mold?.id ? String(props.mold.id) : undefined,
projectForm: taskFormData.projectForm
})
message.success(t('common.createSuccess'))
//
taskFormData.name = undefined
taskFormData.projectForm = ''
selectedProjectFormId.value = ''
selectedProjectFormName.value = ''
} else if (isRepair.value) {
//
const payload: any = {
repairCode: repairFormData.isCode ? undefined : repairFormData.repairCode,
repairName: repairFormData.repairName,
moldId: props.mold?.id,
moldCode: props.mold?.code ?? '',
moldName: props.mold?.name ?? '',
machinerySpec: '',
requireDate: repairFormData.requireDate,
repairResult: '',
repairStatus: '',
acceptedBy: normalizeUserId(repairFormData.acceptedBy),
confirmBy: normalizeUserId(repairFormData.confirmBy),
faultLevel: repairFormData.faultLevel,
shutdown: repairFormData.shutdown,
faultPhenomenon: repairFormData.faultPhenomenon,
faultDescription: repairFormData.faultDescription,
faultImages: normalizeImageString(repairFormData.faultImages),
isCode: repairFormData.isCode,
repairedImages: '',
remark: repairFormData.remark
}
await MoldRepairApi.createMoldRepair(payload)
message.success(t('common.createSuccess'))
//
maintainFormRef.value?.clearValidate()
repairFormData.repairCode = undefined
repairFormData.repairName = undefined
repairFormData.requireDate = undefined
repairFormData.acceptedBy = undefined
repairFormData.confirmBy = undefined
repairFormData.faultLevel = undefined
repairFormData.shutdown = undefined
repairFormData.faultPhenomenon = undefined
repairFormData.faultDescription = undefined
repairFormData.faultImages = ''
repairFormData.remark = undefined
repairFormData.isCode = true
} else if (isReplaceNet.value) {
//
await MoldBrandApi.createPressureNetRecord({
moldBrandId: props.mold?.id,
moldBrandName: props.mold?.name ?? '',
moldId: replaceNetFormData.moldId,
moldName: replaceNetFormData.moldName ?? '',
pressureNetTime: replaceNetFormData.pressureNetTime,
remark: replaceNetFormData.remark
})
message.success(t('common.createSuccess'))
//
replaceNetFormData.moldId = undefined
replaceNetFormData.moldName = undefined
replaceNetFormData.pressureNetTime = undefined
replaceNetFormData.remark = undefined
await nextTick()
maintainFormRef.value?.clearValidate()
}
emit('success')
} catch (error) {
console.error(t('MoldManagement.MoldBrandPage.submitFailed'), error)
} finally {
submitLoading.value = false
}
}
const open = async () => {
maintainFormData.maintainType = 1
await initOptions()
}
defineExpose({ open })
</script>
<style scoped>
.mold-maintain-page__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.mold-maintain-page__info-card {
display: flex;
flex-direction: column;
gap: 16px;
padding: 20px;
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
flex: 1;
}
.mold-maintain-page__info-header,
.mold-maintain-page__form-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 4px;
}
.mold-maintain-page__info-num {
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
border-radius: 50%;
background: var(--el-color-primary);
color: #fff;
font-size: 12px;
font-weight: 600;
flex-shrink: 0;
}
.mold-maintain-page__info-title {
font-size: 15px;
font-weight: 600;
color: var(--el-text-color-primary);
}
.mold-maintain-page__info-image-wrap {
display: flex;
justify-content: left;
}
.mold-maintain-page__info-image {
width: 120px;
height: 120px;
border-radius: 8px;
border: 1px solid var(--el-border-color-lighter);
}
.mold-maintain-page__info-empty {
width: 120px;
height: 120px;
border-radius: 8px;
border: 1px dashed var(--el-border-color-lighter);
}
.mold-maintain-page__info-item {
display: flex;
align-items: center;
gap: 8px;
}
.mold-maintain-page__info-label {
color: var(--el-text-color-secondary);
font-size: 13px;
white-space: nowrap;
flex-shrink: 0;
width: 90px;
text-align: left;
}
.mold-maintain-page__info-value {
color: var(--el-text-color-primary);
font-size: 14px;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
text-align: left;
}
.mold-maintain-page__body {
display: flex;
gap: 20px;
align-items: stretch;
}
.mold-maintain-page__sidebar {
width: 20vw;
flex-shrink: 0;
display: flex;
}
.mold-maintain-page__form {
flex: 1;
background: #fff;
border-radius: 12px;
padding: 24px 32px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}
:deep(.el-form-item__label) {
white-space: nowrap;
}
.mold-maintain-page__form-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 24px;
padding-top: 16px;
border-top: 1px solid var(--el-border-color-lighter);
}
.dv-repair-section {
margin-bottom: 20px;
padding: 16px;
background: #f8f9fa;
border-radius: 8px;
}
.dv-repair-section__title {
font-size: 14px;
font-weight: 600;
color: #303133;
margin-bottom: 16px;
padding-left: 8px;
border-left: 3px solid #409eff;
}
.dv-repair-label {
display: inline-flex;
gap: 4px;
align-items: center;
&.is-required::before {
color: var(--el-color-danger);
content: '*';
}
}
.dv-repair-code-row {
display: flex;
gap: 10px;
align-items: center;
}
/* 维护类型卡片样式 */
.mold-maintain-type-card {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.mold-maintain-type-card__item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100px;
height: 100px;
border-radius: 12px;
border: 2px solid var(--el-border-color-lighter);
cursor: pointer;
transition: all 0.25s ease;
background: #fff;
&:hover {
border-color: var(--el-color-primary);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
&.is-active {
border-color: var(--el-color-primary);
background: rgba(64, 158, 255, 0.06);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.2);
}
}
.mold-maintain-type-card__icon {
width: 44px;
height: 44px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: var(--el-color-primary);
background: var(--el-color-primary-light-9);
transition: transform 0.25s ease;
.mold-maintain-type-card__item:hover & {
transform: scale(1.1);
}
}
.mold-maintain-type-card__label {
font-size: 14px;
color: var(--el-text-color-primary);
font-weight: 500;
}
.mold-maintain-type-card__item.is-active .mold-maintain-type-card__label {
color: var(--el-color-primary);
}
.project-form-dialog-content {
max-height: 500px;
overflow-y: auto;
}
</style>

@ -0,0 +1,352 @@
<template>
<div class="mold-operate-page">
<div class="mold-operate-page__header">
<el-button @click="emit('back')">
<Icon icon="ep:arrow-left" class="mr-5px" /> {{ t('MoldManagement.MoldBrandPage.back') }}
</el-button>
</div>
<!-- 模具信息卡片 -->
<div class="mold-operate-page__info-card" v-if="mold">
<el-image v-if="getImageList(mold.images).length" :src="getImageList(mold.images)[0]"
fit="cover" class="mold-operate-page__info-image" />
<div class="mold-operate-page__info-empty" v-else></div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.moldCode') }}</span>
<span class="mold-operate-page__info-value">{{ mold.code }}</span>
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.moldName') }}</span>
<span class="mold-operate-page__info-value">{{ mold.name }}</span>
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.productName') }}</span>
<span class="mold-operate-page__info-value">{{ mold.productName }}</span>
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.moldSize') }}</span>
<span class="mold-operate-page__info-value">{{ mold.moldSize }}</span>
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.status') }}</span>
<dict-tag :type="DICT_TYPE.ERP_MOLD_STATUS" :value="mold.status" />
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.currentDevice') }}</span>
<span class="mold-operate-page__info-value">{{ mold.currentDevice || '-' }}</span>
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.lastChangeTime') }}</span>
<span class="mold-operate-page__info-value">{{ mold.lastChangeTime ?
dateFormatter(mold.lastChangeTime) : '-' }}</span>
</div>
</div>
<div class="mold-operate-page__body">
<!-- 左侧表单 -->
<div class="mold-operate-page__form">
<el-form ref="operateFormRef" :model="operateFormData" :rules="operateFormRules" label-width="100px">
<el-form-item :label="t('MoldManagement.MoldBrandPage.targetLine')" prop="lineId">
<el-select v-model="operateFormData.lineId" filterable clearable
:placeholder="t('MoldManagement.MoldBrandPage.placeholderTargetLine')" class="!w-full">
<el-option v-for="line in lineOptions" :key="line.id" :label="line.name" :value="String(line.id)" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandPage.targetDevice')" prop="deviceId">
<el-select v-model="operateFormData.deviceId" filterable clearable
:placeholder="t('MoldManagement.MoldBrandPage.placeholderTargetDevice')" class="!w-full">
<el-option v-for="device in deviceOptions" :key="device.id"
:label="`${device.deviceName}${device.deviceCode}`" :value="device.id" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandPage.operateTime')" prop="operateTime">
<el-date-picker v-model="operateFormData.operateTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('MoldManagement.MoldBrandPage.placeholderOperateTime')" class="!w-full" />
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandPage.operator')" prop="operatorId">
<el-select v-model="operateFormData.operatorId" filterable clearable
:placeholder="t('MoldManagement.MoldBrandPage.placeholderOperator')" class="!w-full">
<el-option v-for="item in operatorOptions" :key="String(item.id)" :label="item.nickname"
:value="String(item.id)" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandPage.remark')" prop="remark">
<el-input v-model="operateFormData.remark"
:placeholder="t('MoldManagement.MoldBrandPage.placeholderRemark')" type="textarea" :rows="3" />
</el-form-item>
</el-form>
<div class="mold-operate-page__form-actions">
<el-button @click="emit('back')">{{ t('MoldManagement.MoldBrandPage.cancel') }}</el-button>
<el-button type="primary" @click="submitOperateForm" :loading="operateLoading">{{
t('MoldManagement.MoldBrandPage.submit') }}</el-button>
</div>
</div>
<!-- 右侧记录列表 -->
<div class="mold-operate-page__history">
<div class="mold-operate-page__history-header">
<span class="mold-operate-page__history-title">{{ t('MoldManagement.MoldBrandPage.recentRecords')
}}</span>
</div>
<el-table :data="recentOperateList" :stripe="true" :show-overflow-tooltip="true" v-loading="recentLoading">
<el-table-column :label="t('MoldManagement.MoldBrandPage.operateType')">
<template #default="scope">
<span :class="scope.row.operateType === '1' ? 'text-primary' : 'text-success'">
{{ scope.row.operateType === '1' ? t('MoldManagement.MoldBrandPage.installUp') :
t('MoldManagement.MoldBrandPage.uninstallDown') }}
</span>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.moldName')" prop="moldName" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.lineName')" prop="lineName" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.operateTime')" prop="createTime" width="160"
:formatter="dateFormatter" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.operator')" prop="operatorName" width="100" />
</el-table>
<el-empty v-if="!recentOperateList.length" :description="t('MoldManagement.MoldBrandPage.noRecords')" />
<Pagination :total="recentTotal" v-model:page="recentPageNo" v-model:limit="recentPageSize"
@pagination="fetchRecentOperateList" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { MoldBrandApi, type MoldBrandVO } from '@/api/erp/mold'
import { DeviceLedgerApi, type DeviceLedgerVO } from '@/api/mes/deviceledger'
import { MoldOperateApi, type MoldOperateVO } from '@/api/mes/moldoperate'
import { OrganizationApi, type OrganizationVO } from '@/api/mes/organization'
import { getSimpleUserList, type UserVO } from '@/api/system/user'
import { DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
defineOptions({ name: 'MoldOperateView' })
const props = defineProps<{
mold: MoldBrandVO | null
type: number // 1: , 2:
deviceOptions: DeviceLedgerVO[]
}>()
const emit = defineEmits<{
(e: 'back'): void
(e: 'success'): void
}>()
const { t } = useI18n()
const message = useMessage()
const operateLoading = ref(false)
const operateFormRef = ref()
//
const operateFormData = reactive({
lineId: undefined as string | undefined,
deviceId: undefined as number | undefined,
operateTime: undefined as string | undefined,
operatorId: undefined as string | undefined,
remark: undefined as string | undefined
})
//
const operateFormRules = reactive({
lineId: [{ required: true, message: t('MoldManagement.MoldBrandPage.validatorTargetLineRequired'), trigger: 'blur' }],
deviceId: [{ required: true, message: t('MoldManagement.MoldBrandPage.validatorTargetDeviceRequired'), trigger: 'blur' }],
operateTime: [{ required: true, message: t('MoldManagement.MoldBrandPage.validatorOperateTimeRequired'), trigger: 'blur' }],
operatorId: [{ required: true, message: t('MoldManagement.MoldBrandPage.validatorOperatorRequired'), trigger: 'blur' }]
})
//
const lineOptions = ref<OrganizationVO[]>([])
const operatorOptions = ref<UserVO[]>([])
//
const recentOperateList = ref<MoldOperateVO[]>([])
const recentPageNo = ref(1)
const recentPageSize = ref(5)
const recentTotal = ref(0)
const recentLoading = ref(false)
const getImageList = (images?: string) => {
if (!images) return []
return String(images)
.split(',')
.map((item) => item.trim())
.filter(Boolean)
}
const initOperateOptions = async () => {
try {
const data = await OrganizationApi.getOrganizationList()
lineOptions.value = Array.isArray(data) ? data : []
} catch {
lineOptions.value = []
}
try {
operatorOptions.value = (await getSimpleUserList()) ?? []
} catch {
operatorOptions.value = []
}
}
const fetchRecentOperateList = async () => {
if (!props.mold?.id) return
recentLoading.value = true
try {
const data = await MoldOperateApi.getMoldOperatePage({
pageNo: recentPageNo.value,
pageSize: recentPageSize.value,
moldId: props.mold.id
})
recentOperateList.value = data?.list ?? []
recentTotal.value = data?.total ?? 0
} catch {
recentOperateList.value = []
recentTotal.value = 0
} finally {
recentLoading.value = false
}
}
const submitOperateForm = async () => {
if (!operateFormRef.value) return
try {
await operateFormRef.value.validate()
operateLoading.value = true
const submitData = {
operateType: props.type,
moldId: props.mold?.id,
lineId: operateFormData.lineId,
deviceId: operateFormData.deviceId,
remark: operateFormData.remark,
operateTime: operateFormData.operateTime,
operatorId: operateFormData.operatorId
}
await MoldOperateApi.createMoldOperate(submitData)
message.success(props.type === 1 ? t('MoldManagement.MoldBrandPage.moldUpSuccess') : t('MoldManagement.MoldBrandPage.moldDownSuccess'))
fetchRecentOperateList()
emit('success')
} catch (error) {
console.error(t('MoldManagement.MoldBrandPage.submitFailed'), error)
} finally {
operateLoading.value = false
}
}
/** 对外暴露 open 方法,用于初始化 */
const open = async () => {
operateFormData.lineId = undefined
operateFormData.deviceId = undefined
operateFormData.operateTime = undefined
operateFormData.operatorId = undefined
operateFormData.remark = undefined
await initOperateOptions()
recentPageNo.value = 1
await fetchRecentOperateList()
}
defineExpose({ open })
</script>
<style scoped>
.mold-operate-page__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.mold-operate-page__info-card {
display: flex;
align-items: center;
gap: 24px;
padding: 20px;
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
margin-bottom: 20px;
}
.mold-operate-page__info-image {
width: 80px;
height: 80px;
border-radius: 8px;
border: 1px solid var(--el-border-color-lighter);
flex-shrink: 0;
}
.mold-operate-page__info-empty {
width: 80px;
height: 80px;
border-radius: 8px;
border: 1px dashed var(--el-border-color-lighter);
flex-shrink: 0;
}
.mold-operate-page__info-item {
flex: 1;
min-width: 0;
}
.mold-operate-page__info-label {
display: block;
color: var(--el-text-color-secondary);
font-size: 12px;
margin-bottom: 4px;
}
.mold-operate-page__info-value {
display: block;
color: var(--el-text-color-primary);
font-size: 14px;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mold-operate-page__body {
display: flex;
gap: 20px;
}
.mold-operate-page__form {
flex: 1;
background: #fff;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}
.mold-operate-page__form-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 24px;
padding-top: 16px;
border-top: 1px solid var(--el-border-color-lighter);
}
.mold-operate-page__history {
width: 30vw;
background: #fff;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
max-height: 500px;
overflow-y: auto;
}
.mold-operate-page__history-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.mold-operate-page__history-title {
font-size: 16px;
font-weight: 600;
color: var(--el-text-color-primary);
}
</style>

@ -119,6 +119,17 @@
<el-tab-pane :label="t('MoldManagement.MoldBrandDetail.tabRepair')" name="repair">
<div v-loading="repairLoading">
<el-form :inline="true" class="device-ledger-tab-toolbar">
<el-form-item :label="t('MoldManagement.MoldBrandDetail.repairCode')">
<el-input v-model="repairQueryCode" :placeholder="t('MoldManagement.MoldBrandDetail.placeholderRepairCode')" clearable
@keyup.enter="handleQueryRepair" class="!w-200px" />
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandDetail.repairStatus')">
<el-select v-model="repairQueryStatus" :placeholder="t('MoldManagement.MoldBrandDetail.selectRepairStatus')"
clearable class="!w-150px">
<el-option :label="t('MoldManagement.MoldBrandDetail.repairStatusPending')" value="0" />
<el-option :label="t('MoldManagement.MoldBrandDetail.repairStatusDone')" value="1" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandDetail.time')">
<el-date-picker v-model="repairDateRange" type="daterange" value-format="YYYY-MM-DD HH:mm:ss"
:start-placeholder="t('MoldManagement.MoldBrandDetail.startTime')" :end-placeholder="t('MoldManagement.MoldBrandDetail.endTime')" :range-separator="t('MoldManagement.MoldBrandDetail.to')" :unlink-panels="true"
@ -131,41 +142,36 @@
@click="handleExportRepair">{{ t('MoldManagement.MoldBrandDetail.export') }}</el-button>
</el-form-item>
</el-form>
<el-empty v-if="!repairGroups.length" />
<el-empty v-if="!repairList.length" />
<el-collapse v-else v-model="repairActiveNames" class="device-ledger-repair-collapse">
<el-collapse-item v-for="group in repairGroups" :key="group.key" :name="group.key">
<el-collapse-item v-for="row in repairList" :key="row.id ?? row.repairCode" :name="String(row.id ?? row.repairCode)">
<template #title>
<div class="device-ledger-repair-title">
<span class="device-ledger-repair-name">{{ group.name }}</span>
<span class="device-ledger-repair-meta">{{ t('MoldManagement.MoldBrandDetail.totalItems', { count: group.items.length }) }}</span>
<span class="device-ledger-repair-name">{{ row.repairCode ?? '-' }}</span>
</div>
</template>
<div class="device-ledger-history-items">
<div v-for="row in group.items" :key="String(row.id ?? row.subjectId ?? row.subjectCode)"
class="device-ledger-history-item">
<div class="device-ledger-history-item-head">
<el-tag type="info" effect="light">{{ row.subjectCode ?? '-' }}</el-tag>
<span class="device-ledger-history-item-text">{{ row.subjectName ?? '-' }}</span>
</div>
<div class="device-ledger-history-item">
<div class="device-ledger-history-item-body">
<div class="device-ledger-history-item-row"><span
class="device-ledger-history-item-label">{{ t('MoldManagement.MoldBrandDetail.projectContent') }}</span><span
class="device-ledger-history-item-value">{{ row.subjectContent ?? '-' }}</span></div>
class="device-ledger-history-item-label">{{ t('MoldManagement.MoldBrandDetail.moldCode') }}</span><span
class="device-ledger-history-item-value">{{ row.moldCode ?? '-' }}</span></div>
<div class="device-ledger-history-item-row"><span
class="device-ledger-history-item-label">{{ t('MoldManagement.MoldBrandDetail.repairResult') }}</span><span
class="device-ledger-history-item-label">{{ t('MoldManagement.MoldBrandDetail.repairStatus') }}</span><span
class="device-ledger-history-item-value"><el-tag
:type="getResultTagType(row.result ?? row.repairResult)">{{
getResultLabel(row.repairResult ??
row.result) }}</el-tag></span></div>
:type="getRepairStatusTagType(row.status)">{{
getRepairStatusLabel(row.status) }}</el-tag></span></div>
<div class="device-ledger-history-item-row"><span
class="device-ledger-history-item-label">{{ t('MoldManagement.MoldBrandDetail.finishDate') }}</span><span
class="device-ledger-history-item-value">{{
String(formatHistoryTime(row.finishDate)).split(' ')[0]
}}</span></div>
class="device-ledger-history-item-label">{{ t('EquipmentManagement.DvRepair.repairStatus') }}</span><span
class="device-ledger-history-item-value"><el-tag
:type="getRepairResultTagType(row.repairStatus)">{{
getRepairResultLabel(row.repairStatus) }}</el-tag></span></div>
<div class="device-ledger-history-item-row"><span
class="device-ledger-history-item-label">{{ t('MoldManagement.MoldBrandDetail.remark') }}</span><span
class="device-ledger-history-item-value">{{
row.remark ?? '-' }}</span></div>
class="device-ledger-history-item-label">{{ t('MoldManagement.MoldBrandDetail.requireDate') }}</span><span
class="device-ledger-history-item-value">{{ formatHistoryTime(row.requireDate) }}</span></div>
<div class="device-ledger-history-item-row"><span
class="device-ledger-history-item-label">{{ t('MoldManagement.MoldBrandDetail.finishDate') }}</span><span
class="device-ledger-history-item-value">{{ formatHistoryTime(row.finishDate) }}</span></div>
</div>
</div>
</div>
@ -231,11 +237,13 @@
<el-tab-pane :label="t('MoldManagement.MoldBrandDetail.tabInstall')" name="install">
<div v-loading="installLoading">
<el-form :inline="true" class="device-ledger-tab-toolbar">
<el-form-item :label="t('MoldManagement.MoldBrandDetail.mold')"><el-select v-model="installMoldId" filterable clearable :placeholder="t('MoldManagement.MoldBrandDetail.selectMold')"
class="!w-200px"><el-option v-for="item in childMolds" :key="item.id" :label="item.name"
:value="item.id" /></el-select></el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandDetail.remark')"><el-input v-model="installRemark" :placeholder="t('MoldManagement.MoldBrandDetail.remarkPlaceholder')" clearable
@keyup.enter="handleQueryInstall" /></el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandDetail.operateType')">
<el-select v-model="installOperateType" :placeholder="t('MoldManagement.MoldBrandDetail.selectOperateType')"
clearable class="!w-150px">
<el-option :label="t('MoldManagement.MoldBrandDetail.moldUp')" value="1" />
<el-option :label="t('MoldManagement.MoldBrandDetail.moldDown')" value="2" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandDetail.time')">
<el-date-picker v-model="installDateRange" type="daterange" value-format="YYYY-MM-DD HH:mm:ss"
:start-placeholder="t('MoldManagement.MoldBrandDetail.startTime')" :end-placeholder="t('MoldManagement.MoldBrandDetail.endTime')" :range-separator="t('MoldManagement.MoldBrandDetail.to')" :unlink-panels="true" />
@ -248,11 +256,18 @@
<el-table :data="installRecords" :stripe="true" :show-overflow-tooltip="true">
<el-table-column :label="t('MoldManagement.MoldBrandDetail.moldName')" prop="moldName" min-width="150" sortable />
<el-table-column :label="t('MoldManagement.MoldBrandDetail.deviceName')" prop="deviceName" min-width="120" sortable />
<el-table-column :label="t('MoldManagement.MoldBrandDetail.operateType')" prop="operateType" min-width="100" align="center">
<template #default="scope">
<span v-if="scope.row.operateType === 1 || scope.row.operateType === '1'">{{ t('MoldManagement.MoldBrandDetail.moldUp') }}</span>
<span v-else-if="scope.row.operateType === 2 || scope.row.operateType === '2'">{{ t('MoldManagement.MoldBrandDetail.moldDown') }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandDetail.creatorName')" prop="creatorName" min-width="100" sortable />
<el-table-column :label="t('MoldManagement.MoldBrandDetail.remark')" prop="remark" min-width="140" />
<el-table-column :label="t('MoldManagement.MoldBrandDetail.createTime')" prop="createTime" min-width="180" sortable>
<el-table-column :label="t('MoldManagement.MoldBrandDetail.createTime')" prop="createTime" min-width="180" sortable>
<template #default="scope">{{ formatHistoryTime(scope.row.createTime) }}</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandDetail.remark')" prop="remark" min-width="140" />
</el-table>
<el-empty v-if="!installRecords.length" :description="t('MoldManagement.MoldBrandDetail.noInstallRecords')" />
<Pagination :total="installTotal" v-model:page="installPageNo" v-model:limit="installPageSize"
@ -294,6 +309,8 @@ const loadedTabs = ref<Set<string>>(new Set(['molds']))
const inspectionHistory = ref<any[]>([])
const maintainHistory = ref<any[]>([])
const repairList = ref<any[]>([])
const repairQueryCode = ref<string | undefined>()
const repairQueryStatus = ref<string | undefined>()
const installRecords = ref<any[]>([])
const installTotal = ref(0)
const installPageNo = ref(1)
@ -301,6 +318,8 @@ const installPageSize = ref(10)
const installMoldId = ref<number | undefined>()
const installRemark = ref<string | undefined>()
const installDateRange = ref<string[] | undefined>()
const installOperateType = ref<string | undefined>()
const moldList = ref<any[]>([])
const repairActiveNames = ref<string[]>([])
const inspectionDateRange = ref<string[] | undefined>()
const maintainDateRange = ref<string[] | undefined>()
@ -369,6 +388,36 @@ const getResultTagType = (value: any) => {
return 'info'
}
const getRepairStatusLabel = (value: any) => {
const v = value === '' || value === null || value === undefined ? undefined : String(value)
if (v === '0') return t('MoldManagement.MoldBrandDetail.repairStatusPending')
if (v === '1') return t('MoldManagement.MoldBrandDetail.repairStatusDone')
return '-'
}
const getRepairStatusTagType = (value: any) => {
const v = value === '' || value === null || value === undefined ? undefined : String(value)
if (v === '1') return 'success'
if (v === '0') return 'warning'
return 'info'
}
const getRepairResultLabel = (value: any) => {
const v = value === '' || value === null || value === undefined ? undefined : String(value)
if (v === '0') return t('MoldManagement.MoldBrandDetail.repairResultPending')
if (v === '1') return t('MoldManagement.MoldBrandDetail.repairResultOk')
if (v === '2') return t('MoldManagement.MoldBrandDetail.repairResultNg')
return '-'
}
const getRepairResultTagType = (value: any) => {
const v = value === '' || value === null || value === undefined ? undefined : String(value)
if (v === '1') return 'success'
if (v === '2') return 'danger'
if (v === '0') return 'info'
return 'info'
}
type HistoryStepItem = {
key: string
name: string
@ -434,18 +483,6 @@ const maintainStepGroups = computed(() =>
})
)
const repairGroups = computed(() => {
const groupsMap = new Map<string, { key: string; name: string; items: any[] }>()
for (const row of repairList.value ?? []) {
const key = String(row.repairCode ?? row.repairId ?? row.subjectName ?? '-')
if (!groupsMap.has(key)) {
groupsMap.set(key, { key, name: String(row.repairName ?? row.repairCode ?? key), items: [] })
}
groupsMap.get(key)!.items.push(row)
}
return Array.from(groupsMap.values())
})
const getQrcodeRefreshUrl = () => {
if (!detailData.value?.id || !detailData.value?.code) return ''
return `/erp/mold-brand/regenerate-code?id=${detailData.value.id}&code=${encodeURIComponent(String(detailData.value.code))}`
@ -546,13 +583,14 @@ const fetchRepairHistory = async () => {
repairLoading.value = true
try {
const params: any = { moldId: brandId.value }
if (repairQueryCode.value) params.repairCode = repairQueryCode.value
if (repairQueryStatus.value) params.status = repairQueryStatus.value
if (repairDateRange.value && repairDateRange.value.length === 2) {
params.startTime = repairDateRange.value[0]
params.endTime = repairDateRange.value[1]
params.requireDate = [repairDateRange.value[0], repairDateRange.value[1]]
}
const data = await MoldRepairApi.getRepairListByMoldId(params)
const data = await MoldRepairApi.getMoldRepairList(params)
repairList.value = Array.isArray(data) ? data : []
repairActiveNames.value = repairGroups.value.map((item) => item.key)
repairActiveNames.value = repairList.value.map((row: any) => String(row.id ?? row.repairCode))
} finally {
repairLoading.value = false
}
@ -562,9 +600,10 @@ const fetchInstallRecords = async () => {
if (!brandId.value) return
installLoading.value = true
try {
const params: any = { pageNo: installPageNo.value, pageSize: installPageSize.value, brandId: brandId.value }
if (installMoldId.value) params.moldId = installMoldId.value
moldList.value = await MoldBrandApi.getBrandList()
const params: any = { pageNo: installPageNo.value, pageSize: installPageSize.value, moldId: brandId.value }
if (installRemark.value) params.remark = installRemark.value
if (installOperateType.value) params.operateType = installOperateType.value
if (installDateRange.value && installDateRange.value.length === 2) {
params.createTime = [installDateRange.value[0], installDateRange.value[1]]
}
@ -584,6 +623,7 @@ const handleQueryInstall = () => {
const handleResetInstall = () => {
installMoldId.value = undefined
installRemark.value = undefined
installOperateType.value = undefined
installDateRange.value = undefined
installPageNo.value = 1
fetchInstallRecords()
@ -624,6 +664,8 @@ const handleQueryRepair = async () => {
}
const handleResetRepair = async () => {
repairQueryCode.value = undefined
repairQueryStatus.value = undefined
repairDateRange.value = undefined
await fetchRepairHistory()
}
@ -707,6 +749,12 @@ onMounted(() => {
background: #fff;
}
.mold-brand-detail__qr-card {
display: flex;
flex-direction: column;
align-items: center;
}
.mold-brand-detail__image {
width: 100%;
height: 280px;

@ -1,15 +1,10 @@
<template>
<ContentWrap>
<!-- 列表视图 -->
<template v-if="!operateFormVisible">
<!-- 列表 -->
<template v-if="!operateFormVisible && !maintainFormVisible">
<div class="mold-brand-page__header">
<div
v-for="card in statusCards"
:key="card.key"
class="mold-brand-page__stat"
:class="{ 'is-active': currentStatusKey === card.key }"
@click="changeStatus(card.key, card.status)"
>
<div v-for="card in statusCards" :key="card.key" class="mold-brand-page__stat"
:class="{ 'is-active': currentStatusKey === card.key }" @click="changeStatus(card.key, card.status)">
<div class="mold-brand-page__stat-title">{{ card.label }}</div>
<div class="mold-brand-page__stat-value">{{ card.value }}</div>
</div>
@ -17,37 +12,27 @@
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="-mb-15px mt-16px">
<el-form-item prop="keyword">
<el-input
v-model="queryParams.keyword"
:placeholder="t('MoldManagement.MoldBrandPage.placeholderKeyword')"
clearable
class="!w-240px"
@keyup.enter="handleQuery"
/>
<el-input v-model="queryParams.keyword" :placeholder="t('MoldManagement.MoldBrandPage.placeholderKeyword')"
clearable class="!w-240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item prop="status">
<el-select v-model="queryParams.status" :placeholder="t('MoldManagement.MoldBrandPage.placeholderStatus')" clearable class="!w-180px">
<el-option
v-for="dict in statusOptions"
:key="dict.value"
:label="dict.label"
:value="Number(dict.value)"
/>
<el-select v-model="queryParams.status" :placeholder="t('MoldManagement.MoldBrandPage.placeholderStatus')"
clearable class="!w-180px">
<el-option v-for="dict in statusOptions" :key="dict.value" :label="dict.label"
:value="Number(dict.value)" />
</el-select>
</el-form-item>
<el-form-item prop="productId">
<el-select v-model="queryParams.productId" :placeholder="t('MoldManagement.MoldBrandPage.placeholderProduct')" clearable filterable class="!w-180px">
<el-form-item prop="productIds">
<el-select v-model="queryParams.productIds" multiple :placeholder="t('MoldManagement.MoldBrandPage.placeholderProduct')"
clearable filterable class="!w-180px">
<el-option v-for="product in productOptions" :key="product.id" :label="product.name" :value="product.id" />
</el-select>
</el-form-item>
<el-form-item prop="currentDevice">
<el-select v-model="queryParams.currentDevice" :placeholder="t('MoldManagement.MoldBrandPage.placeholderDevice')" clearable filterable class="!w-180px">
<el-option
v-for="device in deviceOptions"
:key="device.id"
:label="`${device.deviceName}${device.deviceCode}`"
:value="device.deviceName"
/>
<el-select v-model="queryParams.currentDevice"
:placeholder="t('MoldManagement.MoldBrandPage.placeholderDevice')" clearable filterable class="!w-180px">
<el-option v-for="device in deviceOptions" :key="device.id"
:label="`${device.deviceName}${device.deviceCode}`" :value="device.deviceName" />
</el-select>
</el-form-item>
<el-form-item>
@ -56,27 +41,28 @@
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['erp:mold-brand:create']">
<Icon icon="ep:plus" class="mr-5px" /> {{ t('MoldManagement.MoldBrandPage.add') }}
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading" v-hasPermi="['erp:mold-brand:export']">
<el-button type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['erp:mold-brand:export']">
<Icon icon="ep:download" class="mr-5px" /> {{ t('MoldManagement.MoldBrandPage.export') }}
</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id" style="margin-top: 16px;">
<el-table-column :label="t('MoldManagement.MoldBrandPage.image')" align="center" width="92">
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id"
style="margin-top: 16px;">
<el-table-column :label="t('MoldManagement.MoldBrandPage.image')" align="center" width="120">
<template #default="scope">
<el-image
v-if="getImageList(scope.row.images).length"
:src="getImageList(scope.row.images)[0]"
:preview-src-list="getImageList(scope.row.images)"
fit="cover"
preview-teleported
class="mold-brand-page__thumb"
/>
<el-image v-if="getImageList(scope.row.images).length" :src="getImageList(scope.row.images)[0]"
:preview-src-list="getImageList(scope.row.images)" fit="cover" preview-teleported
class="mold-brand-page__thumb" />
<span v-else class="mold-brand-page__empty">-</span>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.code')" prop="code" min-width="150" sortable />
<el-table-column :label="t('MoldManagement.MoldBrandPage.code')" prop="code" min-width="150" sortable>
<template #default="scope">
<span class="mold-brand-page__code-link" @click="previewQrcode(scope.row)">{{ scope.row.code }}</span>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.name')" prop="name" min-width="160" sortable />
<el-table-column :label="t('MoldManagement.MoldBrandPage.productName')" prop="productName" min-width="140" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.version')" prop="version" width="100" />
@ -87,157 +73,74 @@
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.currentDevice')" min-width="140">
<template #default="scope">
{{ scope.row.currentDevice || scope.row.machineName || '-' }}
{{ scope.row.deviceName }}
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.moldSize')" prop="moldSize" width="90" align="center" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.createTime')" prop="createTime" :formatter="dateFormatter" width="160" sortable />
<el-table-column :label="t('MoldManagement.MoldBrandPage.operate')" fixed="right" width="310">
<el-table-column :label="t('MoldManagement.MoldBrandPage.moldSize')" prop="moldSize" width="90"
align="center" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.childMoldCount')" prop="childMoldCount" width="90"
align="center" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.createTime')" prop="createTime"
:formatter="dateFormatter" width="160" sortable />
<el-table-column :label="t('MoldManagement.MoldBrandPage.operate')" fixed="right" width="310" align="center">
<template #default="scope">
<el-button link type="primary" @click="openDetail(scope.row.id)">{{ t('MoldManagement.MoldBrandPage.detail') }}</el-button>
<el-button link type="primary" @click="openOperateForm(1, scope.row)" v-if="scope.row.status === 1">{{ t('MoldManagement.MoldBrandPage.moldUp') }}</el-button>
<el-button link type="primary" @click="openOperateForm(2, scope.row)" v-if="scope.row.status === 0">{{ t('MoldManagement.MoldBrandPage.moldDown') }}</el-button>
<el-button link type="warning" @click="handleReservedAction(t('MoldManagement.MoldBrandPage.repair'))">{{ t('MoldManagement.MoldBrandPage.repair') }}</el-button>
<el-button link type="primary" @click="previewQrcode(scope.row)">{{ t('MoldManagement.MoldBrandPage.qrcode') }}</el-button>
<el-button link type="primary" @click="openForm('update', scope.row.id)" v-hasPermi="['erp:mold-brand:update']">{{ t('MoldManagement.MoldBrandPage.edit') }}</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['erp:mold-brand:delete']">{{ t('MoldManagement.MoldBrandPage.delete') }}</el-button>
<el-button link type="primary" @click="openDetail(scope.row.id)">{{ t('MoldManagement.MoldBrandPage.detail')
}}</el-button>
<el-button link type="primary" @click="openOperateForm(1, scope.row)" v-if="scope.row.status === 1">{{
t('MoldManagement.MoldBrandPage.moldUp') }}</el-button>
<el-button link type="primary" @click="openOperateForm(2, scope.row)" v-if="scope.row.status === 0">{{
t('MoldManagement.MoldBrandPage.moldDown') }}</el-button>
<el-button link type="warning" @click="openMaintainForm(scope.row)">{{
t('MoldManagement.MoldBrandPage.maintain') }}</el-button>
<el-button link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['erp:mold-brand:update']">{{ t('MoldManagement.MoldBrandPage.edit') }}</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['erp:mold-brand:delete']">{{
t('MoldManagement.MoldBrandPage.delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</template>
<!-- 上下模操作表单视图 -->
<template v-else>
<div class="mold-operate-page">
<div class="mold-operate-page__header">
<el-button @click="closeOperateForm"><Icon icon="ep:arrow-left" class="mr-5px" /> {{ t('MoldManagement.MoldBrandPage.back') }}</el-button>
</div>
<!-- 模具信息卡片 -->
<div class="mold-operate-page__info-card" v-if="currentMold">
<el-image
v-if="getImageList(currentMold.images).length"
:src="getImageList(currentMold.images)[0]"
fit="cover"
class="mold-operate-page__info-image"
/>
<div class="mold-operate-page__info-empty" v-else></div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.moldCode') }}</span>
<span class="mold-operate-page__info-value">{{ currentMold.code }}</span>
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.moldName') }}</span>
<span class="mold-operate-page__info-value">{{ currentMold.name }}</span>
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.productName') }}</span>
<span class="mold-operate-page__info-value">{{ currentMold.productName }}</span>
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.moldSize') }}</span>
<span class="mold-operate-page__info-value">{{ currentMold.moldSize }}</span>
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.status') }}</span>
<dict-tag :type="DICT_TYPE.ERP_MOLD_STATUS" :value="currentMold.status" />
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.currentDevice') }}</span>
<span class="mold-operate-page__info-value">{{ currentMold.currentDevice || '-' }}</span>
</div>
<div class="mold-operate-page__info-item">
<span class="mold-operate-page__info-label">{{ t('MoldManagement.MoldBrandPage.lastChangeTime') }}</span>
<span class="mold-operate-page__info-value">{{ currentMold.lastChangeTime ? dateFormatter(currentMold.lastChangeTime) : '-' }}</span>
</div>
</div>
<template v-else-if="operateFormVisible">
<MoldOperateViewComp
ref="moldOperateViewRef"
:mold="currentMold"
:type="operateType"
:device-options="deviceOptions"
@back="closeOperateForm"
@success="onOperateSuccess"
/>
</template>
<div class="mold-operate-page__body">
<!-- 左侧表单 -->
<div class="mold-operate-page__form">
<el-form ref="operateFormRef" :model="operateFormData" :rules="operateFormRules" label-width="100px">
<el-form-item :label="t('MoldManagement.MoldBrandPage.targetLine')" prop="lineId">
<el-select v-model="operateFormData.lineId" filterable clearable :placeholder="t('MoldManagement.MoldBrandPage.placeholderTargetLine')" class="!w-full">
<el-option v-for="line in lineOptions" :key="line.id" :label="line.name" :value="String(line.id)" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandPage.targetDevice')" prop="deviceId">
<el-select v-model="operateFormData.deviceId" filterable clearable :placeholder="t('MoldManagement.MoldBrandPage.placeholderTargetDevice')" class="!w-full">
<el-option v-for="device in deviceOptions" :key="device.id" :label="`${device.deviceName}${device.deviceCode}`" :value="device.id" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandPage.operateTime')" prop="operateTime">
<el-date-picker v-model="operateFormData.operateTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" :placeholder="t('MoldManagement.MoldBrandPage.placeholderOperateTime')" class="!w-full" />
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandPage.operator')" prop="operatorId">
<el-select v-model="operateFormData.operatorId" filterable clearable :placeholder="t('MoldManagement.MoldBrandPage.placeholderOperator')" class="!w-full">
<el-option v-for="item in operatorOptions" :key="String(item.id)" :label="item.nickname" :value="String(item.id)" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldBrandPage.remark')" prop="remark">
<el-input v-model="operateFormData.remark" :placeholder="t('MoldManagement.MoldBrandPage.placeholderRemark')" type="textarea" :rows="3" />
</el-form-item>
</el-form>
<div class="mold-operate-page__form-actions">
<el-button @click="closeOperateForm">{{ t('MoldManagement.MoldBrandPage.cancel') }}</el-button>
<el-button type="primary" @click="submitOperateForm" :loading="operateLoading">{{ t('MoldManagement.MoldBrandPage.submit') }}</el-button>
</div>
</div>
<!-- 右侧记录列表 -->
<div class="mold-operate-page__history">
<div class="mold-operate-page__history-header">
<span class="mold-operate-page__history-title">{{ t('MoldManagement.MoldBrandPage.recentRecords') }}</span>
</div>
<el-table :data="recentOperateList" :stripe="true" :show-overflow-tooltip="true" v-loading="recentLoading">
<el-table-column :label="t('MoldManagement.MoldBrandPage.operateType')">
<template #default="scope">
<span :class="scope.row.operateType === '1' ? 'text-primary' : 'text-success'">
{{ scope.row.operateType === '1' ? t('MoldManagement.MoldBrandPage.installUp') : t('MoldManagement.MoldBrandPage.uninstallDown') }}
</span>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.moldName')" prop="moldName" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.lineName')" prop="lineName" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.operateTime')" prop="createTime" width="160" :formatter="dateFormatter" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.operator')" prop="operatorName" width="100" />
</el-table>
<el-empty v-if="!recentOperateList.length" :description="t('MoldManagement.MoldBrandPage.noRecords')" />
<Pagination
:total="recentTotal"
v-model:page="recentPageNo"
v-model:limit="recentPageSize"
@pagination="fetchRecentOperateList"
/>
</div>
</div>
</div>
<!-- 维护操作表单视图 -->
<template v-else-if="maintainFormVisible">
<MoldMaintainViewComp
ref="moldMaintainViewRef"
:mold="currentMold"
:device-options="deviceOptions"
@back="closeMaintainForm"
@success="onMaintainSuccess"
/>
</template>
</ContentWrap>
<Dialog v-model="qrcodeVisible" :title="t('MoldManagement.MoldBrandPage.qrcodeDialogTitle')" width="360px">
<QrcodeActionCard
:image-url="currentQrcodeRow?.qrCodeUrl"
:print-id="currentQrcodeRow?.id"
:print-template-type="4"
:print-title="t('MoldManagement.MoldBrandPage.qrcodePrintTitle', { name: currentQrcodeRow?.name || t('MoldManagement.MoldBrandPage.mold') })"
:print-paper-width="80"
:print-paper-height="80"
:print-max-width="220"
:empty-text="t('MoldManagement.MoldBrandPage.qrcodeEmpty')"
:error-text="t('MoldManagement.MoldBrandPage.qrcodeLoadError')"
:refresh-url="getQrcodeRefreshUrl()"
:refresh-disabled="!currentQrcodeRow?.id || !currentQrcodeRow?.code"
:refresh-confirm-text="t('MoldManagement.MoldBrandPage.qrcodeRefreshConfirm')"
@refresh-success="handleQrcodeRefreshSuccess"
/>
<div class="mold-brand-page__qr-card">
<div class="mold-brand-page__qr-title">{{ t('MoldManagement.MoldBrandPage.qrcodeTitle') }}</div>
<QrcodeActionCard :image-url="currentQrcodeRow?.qrCodeUrl" :print-id="currentQrcodeRow?.id" :print-template-type="4"
:print-title="t('MoldManagement.MoldBrandPage.qrcodePrintTitle', { name: currentQrcodeRow?.name || t('MoldManagement.MoldBrandPage.mold') })"
:print-paper-width="80" :print-paper-height="80" :print-max-width="220"
:empty-text="t('MoldManagement.MoldBrandPage.qrcodeEmpty')"
:error-text="t('MoldManagement.MoldBrandPage.qrcodeLoadError')" :refresh-url="getQrcodeRefreshUrl()"
:refresh-disabled="!currentQrcodeRow?.id || !currentQrcodeRow?.code"
:refresh-confirm-text="t('MoldManagement.MoldBrandPage.qrcodeRefreshConfirm')"
@refresh-success="handleQrcodeRefreshSuccess" />
<div class="mold-brand-page__qr-code">{{ currentQrcodeRow?.code || '-' }}</div>
</div>
</Dialog>
<component :is="MoldBrandFormComp" ref="formRef" @success="getList" />
@ -248,9 +151,6 @@ import { defineAsyncComponent } from 'vue'
import { ProductApi, type ProductVO } from '@/api/erp/product/product'
import { MoldBrandApi, type MoldBrandVO } from '@/api/erp/mold'
import { DeviceLedgerApi, type DeviceLedgerVO } from '@/api/mes/deviceledger'
import { MoldOperateApi, type MoldOperateVO } from '@/api/mes/moldoperate'
import { OrganizationApi, type OrganizationVO } from '@/api/mes/organization'
import { getSimpleUserList, type UserVO } from '@/api/system/user'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
@ -285,7 +185,7 @@ const queryParams = reactive({
keyword: undefined as string | undefined,
code: undefined as string | undefined,
name: undefined as string | undefined,
productId: undefined as number | undefined,
productIds: [] as number[],
productName: undefined as string | undefined,
status: undefined as number | undefined,
currentDevice: undefined as string | undefined,
@ -294,39 +194,18 @@ const queryParams = reactive({
const queryFormRef = ref()
const formRef = ref()
const MoldBrandFormComp = defineAsyncComponent(() => import('./MoldBrandForm.vue') as any)
const MoldOperateViewComp = defineAsyncComponent(() => import('./components/MoldOperateView.vue') as any)
const MoldMaintainViewComp = defineAsyncComponent(() => import('./components/MoldMaintainView.vue') as any)
//
const operateFormVisible = ref(false)
const operateType = ref(1) // 1: , 2:
const currentMold = ref<MoldBrandVO | null>(null)
const operateLoading = ref(false)
const operateFormRef = ref()
const recentOperateList = ref<MoldOperateVO[]>([])
const recentPageNo = ref(1)
const recentPageSize = ref(5)
const recentTotal = ref(0)
const recentLoading = ref(false)
//
const operateFormData = reactive({
lineId: undefined as string | undefined,
deviceId: undefined as number | undefined,
operateTime: undefined as string | undefined,
operatorId: undefined as string | undefined,
remark: undefined as string | undefined
})
const moldOperateViewRef = ref()
//
const operateFormRules = reactive({
lineId: [{ required: true, message: t('MoldManagement.MoldBrandPage.validatorTargetLineRequired'), trigger: 'blur' }],
deviceId: [{ required: true, message: t('MoldManagement.MoldBrandPage.validatorTargetDeviceRequired'), trigger: 'blur' }],
operateTime: [{ required: true, message: t('MoldManagement.MoldBrandPage.validatorOperateTimeRequired'), trigger: 'blur' }],
operatorId: [{ required: true, message: t('MoldManagement.MoldBrandPage.validatorOperatorRequired'), trigger: 'blur' }]
})
//
const lineOptions = ref<OrganizationVO[]>([])
const operatorOptions = ref<UserVO[]>([])
//
const maintainFormVisible = ref(false)
const moldMaintainViewRef = ref()
const statusCards = computed(() => [
{ key: 'all', label: t('MoldManagement.MoldBrandPage.all'), value: counters.allCount, status: undefined },
@ -365,8 +244,8 @@ const getList = async () => {
loading.value = true
try {
parseKeyword()
const product = productOptions.value.find((item) => item.id === queryParams.productId)
queryParams.productName = product?.name
const selected = productOptions.value.filter((item) => (queryParams.productIds || []).includes(item.id))
queryParams.productName = selected.map((p) => p.name).join(',')
const data = await MoldBrandApi.getMoldBrandPage({
...queryParams,
currentDevice: queryParams.currentDevice
@ -386,6 +265,8 @@ const resetQuery = () => {
queryFormRef.value?.resetFields()
currentStatusKey.value = 'all'
queryParams.status = undefined
queryParams.productIds = []
queryParams.productName = undefined
handleQuery()
}
@ -405,7 +286,7 @@ const handleDelete = async (id: number) => {
await MoldBrandApi.deleteMoldBrand(id)
message.success(t('common.delSuccess'))
await getList()
} catch {}
} catch { }
}
const handleExport = async () => {
@ -454,20 +335,8 @@ const openOperateForm = async (type: number, row: MoldBrandVO) => {
operateType.value = type
currentMold.value = row
operateFormVisible.value = true
//
operateFormData.lineId = undefined
operateFormData.deviceId = undefined
operateFormData.operateTime = undefined
operateFormData.operatorId = undefined
operateFormData.remark = undefined
//
await initOperateOptions()
//
recentPageNo.value = 1
await fetchRecentOperateList()
await nextTick()
moldOperateViewRef.value?.open()
}
const closeOperateForm = () => {
@ -475,74 +344,25 @@ const closeOperateForm = () => {
currentMold.value = null
}
const initOperateOptions = async () => {
// 线
try {
const data = await OrganizationApi.getOrganizationList()
lineOptions.value = Array.isArray(data) ? data : []
} catch {
lineOptions.value = []
}
//
try {
operatorOptions.value = (await getSimpleUserList()) ?? []
} catch {
operatorOptions.value = []
}
const onOperateSuccess = () => {
//
}
const fetchRecentOperateList = async () => {
if (!currentMold.value?.id) return
//
const openMaintainForm = async (row: MoldBrandVO) => {
currentMold.value = row
maintainFormVisible.value = true
await nextTick()
moldMaintainViewRef.value?.open()
}
recentLoading.value = true
try {
const data = await MoldOperateApi.getMoldOperatePage({
pageNo: recentPageNo.value,
pageSize: recentPageSize.value,
moldId: currentMold.value.id
})
recentOperateList.value = data?.list ?? []
recentTotal.value = data?.total ?? 0
} catch {
recentOperateList.value = []
recentTotal.value = 0
} finally {
recentLoading.value = false
}
const closeMaintainForm = () => {
maintainFormVisible.value = false
currentMold.value = null
}
const submitOperateForm = async () => {
if (!operateFormRef.value) return
try {
await operateFormRef.value.validate()
operateLoading.value = true
const submitData = {
operateType: operateType.value,
moldId: currentMold.value?.id,
lineId: operateFormData.lineId,
deviceId: operateFormData.deviceId,
remark: operateFormData.remark,
operateTime: operateFormData.operateTime,
operatorId: operateFormData.operatorId
}
await MoldOperateApi.createMoldOperate(submitData)
message.success(operateType.value === 1 ? t('MoldManagement.MoldBrandPage.moldUpSuccess') : t('MoldManagement.MoldBrandPage.moldDownSuccess'))
//
// closeOperateForm()
// await getList()
fetchRecentOperateList()
} catch (error) {
console.error(t('MoldManagement.MoldBrandPage.submitFailed'), error)
} finally {
operateLoading.value = false
}
const onMaintainSuccess = () => {
//
}
onMounted(async () => {
@ -606,9 +426,26 @@ onMounted(async () => {
}
.mold-brand-page__empty {
display: inline-flex;
align-items: center;
justify-content: center;
width: 56px;
height: 56px;
border-radius: 8px;
border: 1px solid var(--el-border-color-lighter);
color: var(--el-text-color-placeholder);
}
.mold-brand-page__code-link {
color: var(--el-color-primary);
cursor: pointer;
text-decoration: underline;
}
.mold-brand-page__code-link:hover {
color: var(--el-color-primary-light-3);
}
.mold-brand-page__qrcode-wrap {
display: flex;
justify-content: center;
@ -619,111 +456,27 @@ onMounted(async () => {
height: 220px;
}
/* 上下模操作页面样式 */
.mold-operate-page__header {
.mold-brand-page__qr-card {
display: flex;
justify-content: space-between;
flex-direction: column;
align-items: center;
margin-bottom: 20px;
}
.mold-operate-page__tabs {
display: flex;
gap: 8px;
}
.mold-operate-page__info-card {
display: flex;
align-items: center;
gap: 24px;
padding: 20px;
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
margin-bottom: 20px;
}
.mold-operate-page__info-image {
width: 80px;
height: 80px;
border-radius: 8px;
padding: 16px;
border: 1px solid var(--el-border-color-lighter);
flex-shrink: 0;
}
.mold-operate-page__info-empty {
width: 80px;
height: 80px;
border-radius: 8px;
border: 1px dashed var(--el-border-color-lighter);
flex-shrink: 0;
}
.mold-operate-page__info-item {
flex: 1;
min-width: 0;
}
.mold-operate-page__info-label {
display: block;
color: var(--el-text-color-secondary);
font-size: 12px;
margin-bottom: 4px;
}
.mold-operate-page__info-value {
display: block;
color: var(--el-text-color-primary);
font-size: 14px;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mold-operate-page__body {
display: flex;
gap: 20px;
}
.mold-operate-page__form {
flex: 1;
background: #fff;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}
.mold-operate-page__form-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 24px;
padding-top: 16px;
border-top: 1px solid var(--el-border-color-lighter);
}
.mold-operate-page__history {
width: 30vw;
border-radius: 16px;
background: #fff;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
max-height: 500px;
overflow-y: auto;
}
.mold-operate-page__history-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
.mold-brand-page__qr-title {
margin-bottom: 12px;
color: var(--el-text-color-primary);
font-weight: 600;
text-align: center;
}
.mold-operate-page__history-title {
font-size: 16px;
.mold-brand-page__qr-code {
margin-top: 12px;
text-align: center;
font-weight: 600;
color: var(--el-text-color-primary);
}
@media (max-width: 1200px) {

@ -211,31 +211,31 @@ const submitForm = async () => {
.map((it: any) => [Number(it.productId ?? it.id), it])
)
const selectedProductIds = (itemFormRef.value.selectedRows ?? [])
.map((it: any) => it?.id)
.filter((id: any) => id !== undefined && id !== null)
.map((id: any) => Number(id))
.filter((id: any) => !Number.isNaN(id))
const selectedRows = (itemFormRef.value.selectedRows ?? [])
formData.value.items = selectedProductIds.map((productId) => {
const existing = existingByProductId.get(productId)
if (existing) {
formData.value.items = selectedRows
.filter((it: any) => it && it.productId !== undefined && it.productId !== null)
.map((row: any) => {
const productId = Number(row.productId)
const existing = existingByProductId.get(productId)
if (existing) {
return {
id: row.id,
warehouseId: formData.value.warehouseId,
productId,
productPrice: existing.productPrice ?? 0,
count: existing.count ?? 1,
remark: existing.remark ?? null
}
}
return {
id: existing.id,
id: row.id,
warehouseId: formData.value.warehouseId,
productId,
productPrice: existing.productPrice ?? 0,
count: existing.count ?? 1,
remark: existing.remark ?? null
productPrice: 0,
count: 1
}
}
return {
warehouseId: formData.value.warehouseId,
productId,
productPrice: 0,
count: 1
}
})
})
const data = formData.value as unknown as StockOutVO
if (formType.value === 'create') {
await StockOutApi.createStockOut(data)

@ -3,14 +3,14 @@
<div class="device-ledger-right">
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item :label="t('MoldManagement.Mold.code')" prop="code">
<el-form-item :label="t('MoldManagement.MoldBrandPage.code')" prop="code">
<el-input
v-model="queryParams.code" :placeholder="t('MoldManagement.Mold.code')" clearable @keyup.enter="handleQuery"
v-model="queryParams.code" :placeholder="t('MoldManagement.MoldBrandPage.code')" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item :label="t('MoldManagement.Mold.name')" prop="name">
<el-form-item :label="t('MoldManagement.MoldBrandPage.name')" prop="name">
<el-input
v-model="queryParams.name" :placeholder="t('MoldManagement.Mold.name')" clearable @keyup.enter="handleQuery"
v-model="queryParams.name" :placeholder="t('MoldManagement.MoldBrandPage.name')" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item>
@ -24,25 +24,59 @@ v-model="queryParams.name" :placeholder="t('MoldManagement.Mold.name')" clearabl
</el-form>
</ContentWrap>
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" @selection-change="handleSelectionChange" ref="tableRef" :row-key="row => row.id">
<el-table-column width="30" type="selection" />
<el-table-column :label="t('MoldManagement.Mold.code')" align="center" prop="code" sortable />
<el-table-column :label="t('MoldManagement.Mold.name')" align="left" prop="name" sortable />
<el-table-column :label="t('MoldManagement.Mold.useTime')" align="center" prop="useTime" sortable />
<el-table-column :label="t('MoldManagement.Mold.status')" align="center" prop="status" sortable>
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_MOLD_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.Mold.machineName')" align="center" prop="machineName" sortable />
<el-table-column :label="t('MoldManagement.Mold.remark')" align="center" prop="remark" />
<el-table-column :label="t('MoldManagement.Mold.isEnable')" align="center" prop="isEnable">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.isEnable" />
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.Mold.createTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180px" sortable />
</el-table>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"
@selection-change="handleSelectionChange" ref="tableRef" :row-key="row => row.id"
@expand-change="handleExpandChange">
<el-table-column width="30" type="selection" />
<el-table-column type="expand">
<template #default="scope">
<div style="padding: 0 48px">
<el-table v-loading="expandLoadingMap[scope.row.id]" :data="expandDataMap[scope.row.id] || []"
:stripe="true" :show-overflow-tooltip="true" size="small">
<el-table-column :label="t('MoldManagement.MoldListPage.subMoldName')" prop="name" min-width="160" />
<el-table-column :label="t('MoldManagement.MoldListPage.type')" min-width="120">
<template #default="subScope">
<dict-tag :type="DICT_TYPE.SUBMOLD_TYPE" :value="subScope.row.type" />
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldListPage.installLocation')" min-width="140">
<template #default="subScope">
{{ subScope.row.installLocation || subScope.row.installPosition || subScope.row.currentPosition || subScope.row.machineName || '-' }}
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldListPage.material')" min-width="120">
<template #default="subScope">
{{ subScope.row.material || '-' }}
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldListPage.quantity')" width="90" align="center">
<template #default="subScope">
{{ subScope.row.quantity || subScope.row.count || 1 }}
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.code')" prop="code" min-width="150" sortable />
<el-table-column :label="t('MoldManagement.MoldBrandPage.name')" prop="name" min-width="160" sortable />
<el-table-column :label="t('MoldManagement.MoldBrandPage.productName')" prop="productName" min-width="140" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.version')" prop="version" width="100" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.status')" prop="status" width="100" align="center">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_MOLD_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.currentDevice')" min-width="140">
<template #default="scope">
{{ scope.row.deviceName }}
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.moldSize')" prop="moldSize" width="90"
align="center" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.childMoldCount')" prop="childMoldCount" width="90"
align="center" />
</el-table>
<Pagination
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
@ -64,8 +98,7 @@ v-model="queryParams.name" :placeholder="t('MoldManagement.Mold.name')" clearabl
<script setup lang="ts">
import { DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import { MoldBrandApi, MoldVO } from '@/api/erp/mold'
import { MoldBrandApi, MoldBrandVO } from '@/api/erp/mold'
import { useDictStoreWithOut } from '@/store/modules/dict'
const props = defineProps<{
@ -77,37 +110,37 @@ const message = useMessage() // 消息弹窗
const { t } = useI18n() //
const loading = ref(false) //
const list = ref<MoldVO[]>([]) //
const list = ref<MoldBrandVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
code: undefined,
name: undefined,
brand: undefined,
})
const queryFormRef = ref() //
const dictStore = useDictStoreWithOut()
const dictReady = ref(false)
//
const expandLoadingMap = ref<Record<number, boolean>>({})
const expandDataMap = ref<Record<number, any[]>>({})
/** 查询列表 */
const getList = async () => {
loading.value = true
ignoreSelectionChange.value = true
try {
const data = await MoldBrandApi.getMoldPage({
const data = await MoldBrandApi.getMoldBrandPage({
pageNo: queryParams.pageNo,
pageSize: queryParams.pageSize,
code: queryParams.code,
name: queryParams.name,
brandId: queryParams.brand,
statuss: [1]
})
list.value = data.list
total.value = data.total
const pageResult = data?.pageResult ?? data ?? {}
list.value = pageResult.list ?? []
total.value = pageResult.total ?? 0
} finally {
loading.value = false
await nextTick()
@ -115,6 +148,30 @@ const getList = async () => {
}
}
/** 展开行 - 加载子模具列表 */
const handleExpandChange = async (row: MoldBrandVO, expandedRows: MoldBrandVO[]) => {
if (!expandedRows.some((r) => r.id === row.id)) {
//
delete expandDataMap.value[row.id]
return
}
if (expandDataMap.value[row.id]) {
//
return
}
expandLoadingMap.value[row.id] = true
try {
const data = await MoldBrandApi.getMoldPage({
pageNo: 1,
pageSize: 100,
brandId: row.id,
})
expandDataMap.value[row.id] = data.list || []
} finally {
expandLoadingMap.value[row.id] = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
@ -188,7 +245,7 @@ const handleSelectionChange = (rows: any[]) => {
const validate = async (): Promise<boolean> => {
if (!tableRef.value) return false
try {
await tableRef.value.validate()
return true
@ -196,7 +253,7 @@ const validate = async (): Promise<boolean> => {
return false
}
}
defineExpose({ validate,selectedRows: selectedRows })
defineExpose({ validate, selectedRows: selectedRows })
/** 初始化 **/
onMounted(async () => {
@ -204,7 +261,6 @@ onMounted(async () => {
dictReady.value = true
getList()
})
</script>
<style scoped>
@ -213,146 +269,8 @@ onMounted(async () => {
gap: 12px;
}
.device-ledger-left {
width: 280px;
flex: 0 0 auto;
}
.device-ledger-right {
flex: 1;
min-width: 0;
}
.device-ledger-detail-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.device-ledger-detail-title {
font-size: 14px;
font-weight: 600;
}
.device-ledger-history-steps {
padding: 8px 8px 0;
}
.device-ledger-history-title {
display: flex;
align-items: center;
gap: 10px;
font-size: 13px;
}
.device-ledger-history-time {
font-weight: 600;
}
.device-ledger-history-operator {
color: var(--el-text-color-secondary);
}
.device-ledger-tab-toolbar {
margin-bottom: 8px;
text-align: right;
}
.device-ledger-history-items {
display: flex;
flex-direction: column;
gap: 6px;
margin-top: 8px;
}
.device-ledger-history-item {
display: flex;
padding: 10px;
background: var(--el-fill-color-blank);
border: 1px solid var(--el-border-color-lighter);
border-radius: 8px;
flex-direction: column;
gap: 8px;
}
.device-ledger-history-item-head {
display: flex;
align-items: center;
gap: 10px;
}
.device-ledger-history-item-body {
display: flex;
flex-direction: column;
gap: 6px;
width: 100%;
}
.device-ledger-history-item-row {
display: flex;
gap: 10px;
}
.device-ledger-history-item-label {
width: 70px;
flex: 0 0 70px;
color: var(--el-text-color-secondary);
}
.device-ledger-history-item-value {
flex: 1;
color: var(--el-text-color-regular);
word-break: break-word;
}
.device-ledger-history-item-images {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 4px;
}
.device-ledger-history-item-image {
width: 76px;
height: 76px;
overflow: hidden;
border-radius: 6px;
}
.device-ledger-history-image-error {
display: flex;
width: 100%;
height: 100%;
font-size: 12px;
color: var(--el-text-color-secondary);
background: var(--el-fill-color);
align-items: center;
justify-content: center;
}
.device-ledger-repair-collapse {
padding: 8px 8px 0;
}
.device-ledger-repair-title {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
.device-ledger-repair-name {
font-weight: 600;
color: var(--el-text-color-primary);
}
.device-ledger-repair-meta {
font-size: 12px;
color: var(--el-text-color-secondary);
}
.device-ledger-history-item-text {
color: var(--el-text-color-regular);
}
</style>

@ -409,7 +409,7 @@ onMounted(async () => {
await getList()
//
// productList.value = await ProductApi.getProductSimpleList()
moldList.value = await MoldBrandApi.getMoldAllList()
moldList.value = await MoldBrandApi.getBrandList()
warehouseList.value = await WarehouseApi.getWarehouseSimpleList()
customerList.value = await CustomerApi.getCustomerSimpleList()
userList.value = await UserApi.getSimpleUserList()

@ -14,37 +14,11 @@
</el-radio-group>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.device')" prop="deviceId" v-if="formData.operateType != null">
<!-- <el-select
v-model="formData.deviceId"
filterable
clearable
:loading="deviceLoading"
:placeholder="t('MoldManagement.MoldOperate.placeholderDevice')"
class="!w-full"
@change="deviceChange(formData.deviceId)"
>
<el-option v-for="opt in deviceOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>-->
<el-input :model-value="displayItemDevice" readonly clearable class="device-ledger-selection-input"
:placeholder="t('MoldManagement.MoldOperate.placeholderDevice')"
@click="openCriticalComponentDialog" />
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.mold')" prop="moldId" v-if="formData.operateType == '1'">
<!-- <el-select
v-model="formData.moldId"
multiple
clearable
filterable
:placeholder="t('MoldManagement.MoldOperate.placeholderMold')"
class="!w-full"
>
<el-option
v-for="item in moldList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>-->
<el-form-item :label="t('MoldManagement.MoldOperate.mold')" prop="moldId" v-if="formData.operateType != null">
<el-input
:model-value="moldDisplayText"
:placeholder="t('MoldManagement.MoldOperate.placeholderMold')"
@ -52,25 +26,23 @@
@click="openMoldSelectDialog"
/>
</el-form-item>
<el-form-item
v-if="formData.operateType == '2' && formData.deviceId"
:label="t('MoldManagement.MoldOperate.lowerMold')"
prop="lowerMoldId"
>
<el-select
v-model="formData.lowerMoldId"
multiple
clearable
filterable
:placeholder="t('MoldManagement.MoldOperate.placeholderLowerMold')"
<el-form-item :label="t('MoldManagement.MoldOperate.productionLine')" prop="lineId">
<el-select v-model="formData.lineId" filterable clearable :placeholder="t('MoldManagement.MoldOperate.placeholderProductionLine')" class="!w-full">
<el-option v-for="line in lineOptions" :key="line.id" :label="line.name" :value="line.id" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.operateTime')" prop="operateTime">
<el-date-picker
v-model="formData.operateTime"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('MoldManagement.MoldOperate.placeholderOperateTime')"
class="!w-full"
>
<el-option
v-for="item in lowerMoldList"
:key="item.id"
:label="item.name || item.moldName || `ID:${item.id}`"
:value="item.id"
/>
/>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.operatorName')" prop="operatorId">
<el-select v-model="formData.operatorId" filterable clearable :placeholder="t('MoldManagement.MoldOperate.placeholderOperatorName')" class="!w-full">
<el-option v-for="item in operatorOptions" :key="item.id" :label="item.nickname" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.remark')" prop="remark">
@ -89,6 +61,7 @@
:columns="deviceColumns"
:fetch-api="fetchDeviceLedgerPage"
row-key="id"
selection-type="single"
@confirm="handleDeviceSelectConfirm"
:query-params="mergedQueryParams"
>
@ -113,8 +86,9 @@
ref="moldSelectDialogRef"
title="选择模具"
:columns="moldColumns"
:fetch-api="MoldBrandApi.getMoldPage"
:fetch-api="fetchMoldBrandPage"
row-key="id"
selection-type="single"
@confirm="handleMoldSelectConfirm"
:query-params="mergedMoldQueryParams"
>
@ -139,6 +113,8 @@
import { MoldOperateApi } from '@/api/mes/moldoperate'
import { MoldBrandApi, MoldVO } from '@/api/erp/mold'
import { DeviceLedgerApi, DeviceLedgerVO } from '@/api/mes/deviceledger'
import { OrganizationApi, OrganizationVO } from '@/api/mes/organization'
import { getSimpleUserList, type UserVO } from '@/api/system/user'
import TableSelectDialog from '@/components/TableSelectDialog/TableSelectDialog.vue'
/** 模具上下模 表单 */
@ -146,29 +122,24 @@ defineOptions({ name: 'MoldOperateForm' })
const { t } = useI18n() //
const message = useMessage() //
const moldList = ref<MoldVO[]>([]) //
const lowerMoldList = ref<any[]>([]) //
const deviceLoading = ref(false)
const deviceOptions = ref<{ label: string; value: number; raw?: DeviceLedgerVO }[]>([])
const deviceOptionsLoaded = ref(false)
const lineOptions = ref<OrganizationVO[]>([])
const operatorOptions = ref<UserVO[]>([])
const initializingOperateType = ref(false)
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
type SelectIdValue = string | number | number[] | undefined
type NamedSelection = { id: number; name: string }
type MoldOperateFormData = {
id: number | undefined
operateType: string | number | undefined
moldId: SelectIdValue
deviceId: string | undefined
moldId: number | undefined
deviceId: number | undefined
lineId: number | undefined
operateTime: string | undefined
operatorId: number | undefined
remark: string | undefined
lowerMoldId: SelectIdValue
devices?: NamedSelection[]
molds?: NamedSelection[]
}
const formData = ref<MoldOperateFormData>({
@ -176,29 +147,18 @@ const formData = ref<MoldOperateFormData>({
operateType: undefined,
moldId: undefined,
deviceId: undefined,
lineId: undefined,
operateTime: undefined,
operatorId: undefined,
remark: undefined,
lowerMoldId: undefined,
})
const normalizeIdList = (value: SelectIdValue) => {
if (Array.isArray(value)) {
return value.map((item) => Number(item)).filter((item) => Number.isFinite(item))
}
if (value === undefined || value === null || value === '') {
return []
}
return String(value)
.split(',')
.map((item) => Number(item))
.filter((item) => Number.isFinite(item))
}
const validateMoldId = (_rule: any, value: any, callback: (error?: Error) => void) => {
if (String(formData.value.operateType) !== '1') {
if (formData.value.operateType == null) {
callback()
return
}
const hasValue = Array.isArray(value) ? value.length > 0 : value !== undefined && value !== null && value !== ''
const hasValue = value !== undefined && value !== null && value !== ''
if (!hasValue) {
callback(new Error(t('MoldManagement.MoldOperate.validatorMoldRequired')))
} else {
@ -206,24 +166,11 @@ const validateMoldId = (_rule: any, value: any, callback: (error?: Error) => voi
}
}
const validateLowerMoldId = (_rule: any, value: any, callback: (error?: Error) => void) => {
if (String(formData.value.operateType) !== '2') {
callback()
return
}
const hasValue = Array.isArray(value) ? value.length > 0 : value !== undefined && value !== null && value !== ''
if (!hasValue) {
callback(new Error(t('MoldManagement.MoldOperate.validatorLowerMoldRequired')))
} else {
callback()
}
}
const formRules = reactive({
operateType: [{ required: true, message: t('MoldManagement.MoldOperate.validatorOperateTypeRequired'), trigger: 'blur' }],
deviceId: [{ required: true, message: t('MoldManagement.MoldOperate.validatorDeviceRequired'), trigger: 'change' }],
lineId: [{ required: true, message: t('MoldManagement.MoldOperate.validatorProductionLineRequired'), trigger: 'change' }],
moldId: [{ required: true, validator: validateMoldId, trigger: 'change' }],
lowerMoldId: [{ required: true, validator: validateLowerMoldId, trigger: 'change' }],
})
const formRef = ref() // Ref
@ -234,7 +181,13 @@ const open = async (type: string, id?: number) => {
formType.value = type
resetForm()
initSelectedItems()
await ensureDeviceOptionsLoaded()
//
if (type === 'create') {
const now = new Date()
const pad = (n: number) => String(n).padStart(2, '0')
formData.value.operateTime = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`
}
await ensureLineOptionsLoaded()
//
if (id) {
formLoading.value = true
@ -244,24 +197,12 @@ const open = async (type: string, id?: number) => {
formData.value = {
...formData.value,
...data,
lowerMoldId: (data as any).lowerMoldId,
}
ids.value = normalizeIdList(formData.value.deviceId)
//
if (String(formData.value.operateType) === '1') {
if (typeof formData.value.moldId === 'string') {
const parts = formData.value.moldId.split(',').map((v: string) => Number(v)).filter((v) => !Number.isNaN(v))
formData.value.moldId = parts as any
}
moldIds.value = normalizeIdList(formData.value.moldId)
await loadUpMoldList()
} else if (String(formData.value.operateType) === '2') {
const rawLower = (formData.value as any).lowerMoldId
if (typeof rawLower === 'string') {
const parts = rawLower.split(',').map((v: string) => Number(v)).filter((v) => !Number.isNaN(v))
;(formData.value as any).lowerMoldId = parts
}
await loadLowerMoldList()
if (formData.value.deviceId != null) {
ids.value = [Number(formData.value.deviceId)].filter((v) => Number.isFinite(v))
}
if (formData.value.moldId != null) {
moldIds.value = [Number(formData.value.moldId)].filter((v) => Number.isFinite(v))
}
} finally {
initializingOperateType.value = false
@ -320,25 +261,12 @@ const submitForm = async () => {
id: raw.id,
operateType: raw.operateType,
deviceId: raw.deviceId,
moldId: raw.moldId,
lineId: raw.lineId,
operateTime: raw.operateTime,
operatorId: raw.operatorId,
remark: raw.remark,
}
if (String(raw.operateType) === '1') {
const ids = Array.isArray(raw.moldId) ? raw.moldId : raw.moldId != null ? [raw.moldId] : []
submitData.moldId = ids.map((v: any) => v).join(',')
} else if (String(raw.operateType) === '2') {
const allIds = lowerMoldList.value
.map((item: any) => item?.id)
.filter((id: any) => id !== undefined && id !== null)
const lowerIds = Array.isArray(raw.lowerMoldId)
? raw.lowerMoldId
: raw.lowerMoldId != null
? [raw.lowerMoldId]
: []
submitData.lowerMoldId = lowerIds.map((v: any) => v).join(',')
const lowerIdSet = new Set(lowerIds.map((v: any) => String(v)))
const remainIds = allIds.filter((id: any) => !lowerIdSet.has(String(id)))
submitData.moldId = remainIds.join(',')
}
// 3.
if (formType.value === 'create') {
@ -361,40 +289,26 @@ const submitForm = async () => {
}
}
const ensureDeviceOptionsLoaded = async () => {
if (deviceOptionsLoaded.value) return
deviceLoading.value = true
const ensureLineOptionsLoaded = async () => {
if (lineOptions.value.length) return
try {
const data = await DeviceLedgerApi.getDeviceLedgerPage({})
const rows = (data?.list ?? []) as DeviceLedgerVO[]
deviceOptions.value = rows
.filter((r) => typeof r?.id === 'number')
.map((r) => ({ label: `${r.deviceCode ?? ''} ${r.deviceName ?? ''}`.trim(), value: r.id, raw: r }))
deviceOptionsLoaded.value = true
} finally {
deviceLoading.value = false
const data = await OrganizationApi.getOrganizationList()
lineOptions.value = Array.isArray(data) ? data : []
} catch {
lineOptions.value = []
}
try {
operatorOptions.value = (await getSimpleUserList()) ?? []
} catch {
operatorOptions.value = []
}
}
//
const deviceChange = async (deviceId:number) => {
if (String(formData.value.operateType) === '2' && deviceId) {
await loadLowerMoldList()
formData.value.lowerMoldId = undefined as any
}
}
const loadUpMoldList = async () => {
moldList.value = await MoldBrandApi.getInTransitMoldAllList()
}
const loadLowerMoldList = async () => {
if (!formData.value.deviceId) {
lowerMoldList.value = []
return
formData.value.moldId = undefined as any
}
const list = await MoldOperateApi.getLowerMoldList(formData.value.deviceId)
lowerMoldList.value = Array.isArray(list) ? list : []
}
watch(
@ -405,17 +319,13 @@ watch(
}
formData.value.deviceId = undefined as any
formData.value.moldId = undefined as any
formData.value.lowerMoldId = undefined as any
moldList.value = []
lowerMoldList.value = []
ids.value = []
moldIds.value = []
selectedDeviceRows.value = []
selectedMoldRows.value = []
if (!val) {
return
}
if (String(val) === '1') {
await loadUpMoldList()
} else if (String(val) === '2') {
await loadLowerMoldList()
}
}
)
@ -426,8 +336,10 @@ const resetForm = () => {
operateType: undefined,
moldId: undefined,
deviceId: undefined,
lineId: undefined,
operateTime: undefined,
operatorId: undefined,
remark: undefined,
lowerMoldId: undefined,
}
selectedDeviceRows.value = []
selectedMoldRows.value = []
@ -445,7 +357,7 @@ const deviceColumns = [
const moldColumns = [
{ label: '模具编码', prop: 'code', minWidth: 140 },
{ label: '模具名称', prop: 'name', minWidth: 160 },
{ label: '模具型号', prop: 'brandName', minWidth: 140 },
{ label: '版本', prop: 'version', minWidth: 100 },
{ label: '状态', prop: 'status', minWidth: 100 }
]
@ -455,41 +367,41 @@ const fetchDeviceLedgerPage = (params: Record<string, any>) => {
isScheduled: 1
})
}
const fetchMoldBrandPage = async (params: Record<string, any>) => {
const data = await MoldBrandApi.getMoldBrandPage(params)
const pageResult = data?.pageResult ?? data ?? {}
return { list: pageResult.list ?? [], total: pageResult.total ?? 0 }
}
const selectedDeviceRows = ref<any[]>([])
const selectedMoldRows = ref<any[]>([])
const handleDeviceSelectConfirm = (payload: { ids: (number | string)[]; rows: any[] }) => {
formData.value.devices = payload.rows
.map((item) => {
const id = Number(item.id)
if (!Number.isFinite(id)) return undefined
return {
id,
name: item.deviceName || item.name || item.code || `设备ID:${id}`
}
})
.filter((item): item is { id: number; name: string } => Boolean(item))
selectedDeviceRows.value = payload.rows
formData.value.deviceId = payload.ids.join(',')
ids.value = payload.ids.map((id) => Number(id))
const row = payload.rows[0]
if (row) {
selectedDeviceRows.value = [row]
formData.value.deviceId = Number(row.id)
ids.value = [Number(row.id)]
} else {
selectedDeviceRows.value = []
formData.value.deviceId = undefined
ids.value = []
}
nextTick(() => {
formRef.value?.clearValidate?.('deviceId')
})
}
const handleMoldSelectConfirm = (payload: { ids: (number | string)[]; rows: any[] }) => {
formData.value.molds = payload.rows
.map((item) => {
const id = Number(item.id)
if (!Number.isFinite(id)) return undefined
return {
id,
name: item.name || item.code || `模具ID:${id}`
}
})
.filter((item): item is { id: number; name: string } => Boolean(item))
selectedMoldRows.value = payload.rows
formData.value.moldId = payload.ids.map((id) => Number(id))
moldIds.value = payload.ids.map((id) => Number(id))
const row = payload.rows[0]
if (row) {
selectedMoldRows.value = [row]
formData.value.moldId = Number(row.id)
moldIds.value = [Number(row.id)]
} else {
selectedMoldRows.value = []
formData.value.moldId = undefined
moldIds.value = []
}
nextTick(() => {
formRef.value?.clearValidate?.('moldId')
})
@ -527,7 +439,10 @@ const resetMoldSearch = () => {
const moldSelectDialogRef = ref<InstanceType<typeof TableSelectDialog> | null>(null)
// 2.
const mergedQueryParams = computed(() => ({ ...searchParams }))
const mergedMoldQueryParams = computed(() => ({ ...searchMoldParams }))
const mergedMoldQueryParams = computed(() => {
const status = String(formData.value.operateType) === '1' ? 1 : String(formData.value.operateType) === '2' ? 0 : undefined
return { ...searchMoldParams, ...(status !== undefined ? { status } : {}) }
})
const ids = ref<number[]>([])
const moldIds= ref<number[]>([])
const itemList = ref<DeviceLedgerVO[]>([])
@ -539,55 +454,43 @@ const total = ref(0)
const queryFormRef = ref()
const loading = ref(true)
const displayItemDevice = computed( () => {
if (!ids.value.length)return ''
if (formData.value.deviceId == null) return ''
if (selectedDeviceRows.value.length) {
return selectedDeviceRows.value
.map((item) => item.deviceName || item.name || item.deviceCode || '')
.filter((name) => name)
.join(',')
const row = selectedDeviceRows.value[0]
return row.deviceName || row.name || row.deviceCode || ''
}
if (!itemList.value.length) {
return formData.value.deviceId ? String(formData.value.deviceId) : ''
return String(formData.value.deviceId)
}
const map = new Map(itemList.value.map((item) => [item.id, item.deviceName]))
const names = ids.value
.map((id) => map.get(id))
.filter((name) => name)
return names.join(',')
return map.get(formData.value.deviceId) || ''
})
const moldDisplayText = computed(() => {
if (!moldIds.value.length)return ''
if (formData.value.moldId == null) return ''
if (selectedMoldRows.value.length) {
return selectedMoldRows.value
.map((item) => item.name || item.code || '')
.filter((name) => name)
.join(',')
const row = selectedMoldRows.value[0]
return row.name || row.code || ''
}
if (!moldItemList.value.length) {
return formData.value.moldId ? String(formData.value.moldId) : ''
return String(formData.value.moldId)
}
const map = new Map(moldItemList.value.map((item) => [item.id, item.name]))
const names = moldIds.value
.map((id) => map.get(id))
.filter((name) => name)
return names.join(',')
return map.get(formData.value.moldId) || ''
})
const openCriticalComponentDialog = async () => {
searchParams.deviceCode=''
searchParams.deviceName=''
searchMoldParams.code=''
searchMoldParams.name=''
const rows = selectedDeviceRows.value.map((item) => ({ ...item, id: Number(item.id) }))
deviceSelectDialogRef.value?.open(rows)
ids.value = normalizeIdList(formData.value.deviceId)
}
const openMoldSelectDialog = () => {
searchMoldParams.code=''
searchMoldParams.name=''
const rows = selectedMoldRows.value.map((item) => ({ ...item, id: Number(item.id) }))
moldIds.value = normalizeIdList(formData.value.moldId)
moldSelectDialogRef.value?.open(rows)
}
const toDeviceRows = (split: any) => {

@ -89,6 +89,7 @@
<!-- <el-table-column label="操作类型" align="center" prop="operateType" sortable /> -->
<el-table-column :label="t('MoldManagement.MoldOperate.moldName')" align="center" prop="moldName" width="500px" sortable />
<el-table-column :label="t('MoldManagement.MoldOperate.deviceName')" align="center" prop="deviceName" sortable />
<el-table-column :label="t('MoldManagement.MoldOperate.productionLine')" align="center" prop="lineId" sortable />
<el-table-column :label="t('MoldManagement.MoldOperate.creatorName')" align="center" prop="creatorName" sortable />
<el-table-column :label="t('MoldManagement.MoldOperate.remark')" align="center" prop="remark" />
<el-table-column

@ -210,31 +210,31 @@ const submitForm = async () => {
.map((it: any) => [Number(it.productId ?? it.id), it])
)
const selectedProductIds = (itemFormRef.value.selectedRows ?? [])
.map((it: any) => it?.id)
.filter((id: any) => id !== undefined && id !== null)
.map((id: any) => Number(id))
.filter((id: any) => !Number.isNaN(id))
const selectedRows = (itemFormRef.value.selectedRows ?? [])
formData.value.items = selectedProductIds.map((productId) => {
const existing = existingByProductId.get(productId)
if (existing) {
formData.value.items = selectedRows
.filter((it: any) => it && it.productId !== undefined && it.productId !== null)
.map((row: any) => {
const productId = Number(row.productId)
const existing = existingByProductId.get(productId)
if (existing) {
return {
id: row.id,
warehouseId: formData.value.warehouseId,
productId,
productPrice: existing.productPrice ?? 0,
count: existing.count ?? 1,
remark: existing.remark ?? null
}
}
return {
id: existing.id,
id: row.id,
warehouseId: formData.value.warehouseId,
productId,
productPrice: existing.productPrice ?? 0,
count: existing.count ?? 1,
remark: existing.remark ?? null
productPrice: 0,
count: 1
}
}
return {
warehouseId: formData.value.warehouseId,
productId,
productPrice: 0,
count: 1
}
})
})
const data = formData.value as unknown as StockInVO
if (formType.value === 'create') {
await StockInApi.createStockIn(data)

@ -3,14 +3,14 @@
<div class="device-ledger-right">
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item :label="t('MoldManagement.Mold.code')" prop="code">
<el-form-item :label="t('MoldManagement.MoldBrandPage.code')" prop="code">
<el-input
v-model="queryParams.code" :placeholder="t('MoldManagement.Mold.code')" clearable @keyup.enter="handleQuery"
v-model="queryParams.code" :placeholder="t('MoldManagement.MoldBrandPage.code')" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item :label="t('MoldManagement.Mold.name')" prop="name">
<el-form-item :label="t('MoldManagement.MoldBrandPage.name')" prop="name">
<el-input
v-model="queryParams.name" :placeholder="t('MoldManagement.Mold.name')" clearable @keyup.enter="handleQuery"
v-model="queryParams.name" :placeholder="t('MoldManagement.MoldBrandPage.name')" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item>
@ -24,25 +24,59 @@ v-model="queryParams.name" :placeholder="t('MoldManagement.Mold.name')" clearabl
</el-form>
</ContentWrap>
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" @selection-change="handleSelectionChange" ref="tableRef" :row-key="row => row.id">
<el-table-column width="30" type="selection" />
<el-table-column :label="t('MoldManagement.Mold.code')" align="center" prop="code" sortable />
<el-table-column :label="t('MoldManagement.Mold.name')" align="left" prop="name" sortable />
<el-table-column :label="t('MoldManagement.Mold.useTime')" align="center" prop="useTime" sortable />
<el-table-column :label="t('MoldManagement.Mold.status')" align="center" prop="status" sortable>
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_MOLD_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.Mold.machineName')" align="center" prop="machineName" sortable />
<el-table-column :label="t('MoldManagement.Mold.remark')" align="center" prop="remark" />
<el-table-column :label="t('MoldManagement.Mold.isEnable')" align="center" prop="isEnable">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.isEnable" />
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.Mold.createTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180px" sortable />
</el-table>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"
@selection-change="handleSelectionChange" ref="tableRef" :row-key="row => row.id"
@expand-change="handleExpandChange">
<el-table-column width="30" type="selection" />
<el-table-column type="expand">
<template #default="scope">
<div style="padding: 0 48px">
<el-table v-loading="expandLoadingMap[scope.row.id]" :data="expandDataMap[scope.row.id] || []"
:stripe="true" :show-overflow-tooltip="true" size="small">
<el-table-column :label="t('MoldManagement.MoldListPage.subMoldName')" prop="name" min-width="160" />
<el-table-column :label="t('MoldManagement.MoldListPage.type')" min-width="120">
<template #default="subScope">
<dict-tag :type="DICT_TYPE.SUBMOLD_TYPE" :value="subScope.row.type" />
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldListPage.installLocation')" min-width="140">
<template #default="subScope">
{{ subScope.row.installLocation || subScope.row.installPosition || subScope.row.currentPosition || subScope.row.machineName || '-' }}
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldListPage.material')" min-width="120">
<template #default="subScope">
{{ subScope.row.material || '-' }}
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldListPage.quantity')" width="90" align="center">
<template #default="subScope">
{{ subScope.row.quantity || subScope.row.count || 1 }}
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.code')" prop="code" min-width="150" sortable />
<el-table-column :label="t('MoldManagement.MoldBrandPage.name')" prop="name" min-width="160" sortable />
<el-table-column :label="t('MoldManagement.MoldBrandPage.productName')" prop="productName" min-width="140" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.version')" prop="version" width="100" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.status')" prop="status" width="100" align="center">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_MOLD_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.currentDevice')" min-width="140">
<template #default="scope">
{{ scope.row.deviceName }}
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.moldSize')" prop="moldSize" width="90"
align="center" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.childMoldCount')" prop="childMoldCount" width="90"
align="center" />
</el-table>
<Pagination
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
@ -64,8 +98,7 @@ v-model="queryParams.name" :placeholder="t('MoldManagement.Mold.name')" clearabl
<script setup lang="ts">
import { DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import { MoldBrandApi, MoldVO } from '@/api/erp/mold'
import { MoldBrandApi, MoldBrandVO } from '@/api/erp/mold'
import { useDictStoreWithOut } from '@/store/modules/dict'
@ -78,37 +111,37 @@ const message = useMessage() // 消息弹窗
const { t } = useI18n() //
const loading = ref(false) //
const list = ref<MoldVO[]>([]) //
const list = ref<MoldBrandVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
code: undefined,
name: undefined,
brand: undefined,
})
const queryFormRef = ref() //
const dictStore = useDictStoreWithOut()
const dictReady = ref(false)
//
const expandLoadingMap = ref<Record<number, boolean>>({})
const expandDataMap = ref<Record<number, any[]>>({})
/** 查询列表 */
const getList = async () => {
loading.value = true
ignoreSelectionChange.value = true
try {
const data = await MoldBrandApi.getMoldPage({
const data = await MoldBrandApi.getMoldBrandPage({
pageNo: queryParams.pageNo,
pageSize: queryParams.pageSize,
code: queryParams.code,
name: queryParams.name,
brandId: queryParams.brand,
statuss: [3,0]
})
list.value = data.list
total.value = data.total
const pageResult = data?.pageResult ?? data ?? {}
list.value = pageResult.list ?? []
total.value = pageResult.total ?? 0
} finally {
loading.value = false
await nextTick()
@ -116,6 +149,30 @@ const getList = async () => {
}
}
/** 展开行 - 加载子模具列表 */
const handleExpandChange = async (row: MoldBrandVO, expandedRows: MoldBrandVO[]) => {
if (!expandedRows.some((r) => r.id === row.id)) {
//
delete expandDataMap.value[row.id]
return
}
if (expandDataMap.value[row.id]) {
//
return
}
expandLoadingMap.value[row.id] = true
try {
const data = await MoldBrandApi.getMoldPage({
pageNo: 1,
pageSize: 100,
brandId: row.id,
})
expandDataMap.value[row.id] = data.list || []
} finally {
expandLoadingMap.value[row.id] = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
@ -189,7 +246,7 @@ const handleSelectionChange = (rows: any[]) => {
const validate = async (): Promise<boolean> => {
if (!tableRef.value) return false
try {
await tableRef.value.validate()
return true
@ -197,7 +254,7 @@ const validate = async (): Promise<boolean> => {
return false
}
}
defineExpose({ validate,selectedRows: selectedRows })
defineExpose({ validate, selectedRows: selectedRows })
/** 初始化 **/
onMounted(async () => {
@ -205,7 +262,6 @@ onMounted(async () => {
dictReady.value = true
getList()
})
</script>
<style scoped>
@ -214,146 +270,8 @@ onMounted(async () => {
gap: 12px;
}
.device-ledger-left {
width: 280px;
flex: 0 0 auto;
}
.device-ledger-right {
flex: 1;
min-width: 0;
}
.device-ledger-detail-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.device-ledger-detail-title {
font-size: 14px;
font-weight: 600;
}
.device-ledger-history-steps {
padding: 8px 8px 0;
}
.device-ledger-history-title {
display: flex;
align-items: center;
gap: 10px;
font-size: 13px;
}
.device-ledger-history-time {
font-weight: 600;
}
.device-ledger-history-operator {
color: var(--el-text-color-secondary);
}
.device-ledger-tab-toolbar {
margin-bottom: 8px;
text-align: right;
}
.device-ledger-history-items {
display: flex;
flex-direction: column;
gap: 6px;
margin-top: 8px;
}
.device-ledger-history-item {
display: flex;
padding: 10px;
background: var(--el-fill-color-blank);
border: 1px solid var(--el-border-color-lighter);
border-radius: 8px;
flex-direction: column;
gap: 8px;
}
.device-ledger-history-item-head {
display: flex;
align-items: center;
gap: 10px;
}
.device-ledger-history-item-body {
display: flex;
flex-direction: column;
gap: 6px;
width: 100%;
}
.device-ledger-history-item-row {
display: flex;
gap: 10px;
}
.device-ledger-history-item-label {
width: 70px;
flex: 0 0 70px;
color: var(--el-text-color-secondary);
}
.device-ledger-history-item-value {
flex: 1;
color: var(--el-text-color-regular);
word-break: break-word;
}
.device-ledger-history-item-images {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 4px;
}
.device-ledger-history-item-image {
width: 76px;
height: 76px;
overflow: hidden;
border-radius: 6px;
}
.device-ledger-history-image-error {
display: flex;
width: 100%;
height: 100%;
font-size: 12px;
color: var(--el-text-color-secondary);
background: var(--el-fill-color);
align-items: center;
justify-content: center;
}
.device-ledger-repair-collapse {
padding: 8px 8px 0;
}
.device-ledger-repair-title {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
.device-ledger-repair-name {
font-weight: 600;
color: var(--el-text-color-primary);
}
.device-ledger-repair-meta {
font-size: 12px;
color: var(--el-text-color-secondary);
}
.device-ledger-history-item-text {
color: var(--el-text-color-regular);
}
</style>

@ -405,7 +405,7 @@ onMounted(async () => {
await getList()
//
// productList.value = await ProductApi.getProductSimpleList()
moldList.value = await MoldBrandApi.getMoldAllList()
moldList.value = await MoldBrandApi.getBrandList()
warehouseList.value = await WarehouseApi.getWarehouseSimpleList()
customerList.value = await CustomerApi.getCustomerSimpleList()
userList.value = await UserApi.getSimpleUserList()

@ -239,6 +239,13 @@ const formRules = reactive<FormRules>({
message: t('MoldManagement.MoldInspectionPlan.validatorPlanTypeRequired'),
trigger: 'change'
}
],
subjectIds: [
{
required: true,
message: t('MoldManagement.MoldInspectionPlan.validatorSubjectIdsRequired'),
trigger: 'change'
}
]
})
const formRef = ref()
@ -277,7 +284,7 @@ const submitForm = async () => {
planName: formData.value.planName,
planType: formData.value.planType,
description: formData.value.description,
subjectIdS: formData.value.subjectIds?.length ? formData.value.subjectIds.join(',') : undefined
subjectIdS: formData.value.subjectIds ? String(formData.value.subjectIds) : undefined
}
if (formType.value === 'create') {
await PlanMaintenanceApi.createPlanMaintenance(data)

Loading…
Cancel
Save