Merge remote-tracking branch 'origin/main'

main^2
liutao 10 hours ago
commit 13019bca0a

@ -0,0 +1,42 @@
import request from '@/config/axios'
// ERP 包装方案 VO
export interface PackagingSchemeVO {
id: number // 包装方案编号
code: string // 方案编码
name: string // 方案名称
packageQuantity: number // 每包数量(件)
palletPackageQuantity: number // 每托包数(包)
palletTotalQuantity: number // 每托总数量(件)
remark: string // 备注
status: number // 状态
createTime: string // 创建时间
}
// ERP 包装方案 API
export const PackagingSchemeApi = {
// 查询包装方案分页
getPackagingSchemePage: async (params: any) => {
return await request.get({ url: `/erp/packaging-scheme/page`, params })
},
// 查询包装方案详情
getPackagingScheme: async (id: number) => {
return await request.get({ url: `/erp/packaging-scheme/get?id=` + id })
},
// 新增包装方案
createPackagingScheme: async (data: PackagingSchemeVO) => {
return await request.post({ url: `/erp/packaging-scheme/create`, data })
},
// 修改包装方案
updatePackagingScheme: async (data: PackagingSchemeVO) => {
return await request.put({ url: `/erp/packaging-scheme/update`, data })
},
// 删除包装方案
deletePackagingScheme: async (id: number) => {
return await request.delete({ url: `/erp/packaging-scheme/delete?id=` + id })
}
}

@ -1,49 +1,49 @@
import request from '@/config/axios'
// 模具管理-领模申请 VO
export interface MoldGetVO {
id: number // ID
orderId: number // 领模单号
code: string // 模具编码
name: string // 模具名称
state: string // 状态
person: string // 领模人
deviceId: number // 设备id
deviceName: string // 设备名称
getTime: Date // 领取时间
principal: string // 库管员
remark: string // 备注
}
// 模具管理-领模申请 API
export const MoldGetApi = {
// 查询模具管理-领模申请分页
getMoldGetPage: async (params: any) => {
return await request.get({ url: `/mes/mold-get/page`, params })
},
// 查询模具管理-领模申请详情
getMoldGet: async (id: number) => {
return await request.get({ url: `/mes/mold-get/get?id=` + id })
},
// 新增模具管理-领模申请
createMoldGet: async (data: MoldGetVO) => {
return await request.post({ url: `/mes/mold-get/create`, data })
},
// 修改模具管理-领模申请
updateMoldGet: async (data: MoldGetVO) => {
return await request.put({ url: `/mes/mold-get/update`, data })
},
// 删除模具管理-领模申请
deleteMoldGet: async (id: number) => {
return await request.delete({ url: `/mes/mold-get/delete?id=` + id })
},
// 导出模具管理-领模申请 Excel
exportMoldGet: async (params) => {
return await request.download({ url: `/mes/mold-get/export-excel`, params })
},
}
import request from '@/config/axios'
// 模具管理-领模申请 VO
export interface MoldGetVO {
id: number // ID
orderId: number // 领模单号
code: string // 模具编码
name: string // 模具名称
state: string // 状态
person: string // 领模人
deviceId: number // 设备id
deviceName: string // 设备名称
getTime: Date // 领取时间
principal: string // 库管员
remark: string // 备注
}
// 模具管理-领模申请 API
export const MoldGetApi = {
// 查询模具管理-领模申请分页
getMoldGetPage: async (params: any) => {
return await request.get({ url: `/mes/mold-get/page`, params })
},
// 查询模具管理-领模申请详情
getMoldGet: async (id: number) => {
return await request.get({ url: `/mes/mold-get/get?id=` + id })
},
// 新增模具管理-领模申请
createMoldGet: async (data: MoldGetVO) => {
return await request.post({ url: `/mes/mold-get/create`, data })
},
// 修改模具管理-领模申请
updateMoldGet: async (data: MoldGetVO) => {
return await request.put({ url: `/mes/mold-get/update`, data })
},
// 删除模具管理-领模申请
deleteMoldGet: async (id: number) => {
return await request.delete({ url: `/mes/mold-get/delete?id=` + id })
},
// 导出模具管理-领模申请 Excel
exportMoldGet: async (params) => {
return await request.download({ url: `/mes/mold-get/export-excel`, params })
},
}

@ -1,47 +1,47 @@
import request from '@/config/axios'
// 模具管理-模具入库 VO
export interface MoldReturnVO {
id: number // ID
orderId: number // 领模单号
code: string // 模具编码
name: string // 模具名称
state: string // 状态
person: string // 归还人
returnTime: Date // 入库时间
principal: string // 库管员
remark: string // 备注
}
// 模具管理-模具入库 API
export const MoldReturnApi = {
// 查询模具管理-模具入库分页
getMoldReturnPage: async (params: any) => {
return await request.get({ url: `/mes/mold-return/page`, params })
},
// 查询模具管理-模具入库详情
getMoldReturn: async (id: number) => {
return await request.get({ url: `/mes/mold-return/get?id=` + id })
},
// 新增模具管理-模具入库
createMoldReturn: async (data: MoldReturnVO) => {
return await request.post({ url: `/mes/mold-return/create`, data })
},
// 修改模具管理-模具入库
updateMoldReturn: async (data: MoldReturnVO) => {
return await request.put({ url: `/mes/mold-return/update`, data })
},
// 删除模具管理-模具入库
deleteMoldReturn: async (id: number) => {
return await request.delete({ url: `/mes/mold-return/delete?id=` + id })
},
// 导出模具管理-模具入库 Excel
exportMoldReturn: async (params) => {
return await request.download({ url: `/mes/mold-return/export-excel`, params })
},
}
import request from '@/config/axios'
// 模具管理-模具入库 VO
export interface MoldReturnVO {
id: number // ID
orderId: number // 领模单号
code: string // 模具编码
name: string // 模具名称
state: string // 状态
person: string // 归还人
returnTime: Date // 入库时间
principal: string // 库管员
remark: string // 备注
}
// 模具管理-模具入库 API
export const MoldReturnApi = {
// 查询模具管理-模具入库分页
getMoldReturnPage: async (params: any) => {
return await request.get({ url: `/mes/mold-return/page`, params })
},
// 查询模具管理-模具入库详情
getMoldReturn: async (id: number) => {
return await request.get({ url: `/mes/mold-return/get?id=` + id })
},
// 新增模具管理-模具入库
createMoldReturn: async (data: MoldReturnVO) => {
return await request.post({ url: `/mes/mold-return/create`, data })
},
// 修改模具管理-模具入库
updateMoldReturn: async (data: MoldReturnVO) => {
return await request.put({ url: `/mes/mold-return/update`, data })
},
// 删除模具管理-模具入库
deleteMoldReturn: async (id: number) => {
return await request.delete({ url: `/mes/mold-return/delete?id=` + id })
},
// 导出模具管理-模具入库 Excel
exportMoldReturn: async (params) => {
return await request.download({ url: `/mes/mold-return/export-excel`, params })
},
}

@ -541,6 +541,38 @@ export default {
validatorFromWarehouseRequired: 'From warehouse is required',
validatorToWarehouseRequired: 'To warehouse is required'
}
},
PackagingScheme: {
code: 'Scheme Code',
name: 'Scheme Name',
packageQuantity: 'Package Quantity (pcs)',
palletPackageQuantity: 'Pallet Package Quantity (bags)',
palletTotalQuantity: 'Pallet Total Quantity (pcs)',
remark: 'Remark',
status: 'Status',
createTime: 'Create Time',
placeholderCode: 'Please enter scheme code',
placeholderName: 'Please enter scheme name',
placeholderPackageQuantity: 'Please enter package quantity',
placeholderPalletPackageQuantity: 'Please enter pallet package quantity',
placeholderPalletTotalQuantity: 'Please enter pallet total quantity',
placeholderRemark: 'Please enter remark',
placeholderStatus: 'Please select status',
validatorNameRequired: 'Scheme name is required',
validatorCodeRequired: 'Scheme code is required',
validatorPackageQuantityRequired: 'Package quantity is required',
validatorPalletPackageQuantityRequired: 'Pallet package quantity is required',
validatorStatusRequired: 'Status is required'
}
},
ErpPurchase: {
Supplier: {
name: 'Supplier Name',
contact: 'Contact',
mobile: 'Mobile',
telephone: 'Telephone',
placeholderName: 'Please enter supplier name',
placeholderMobile: 'Please enter mobile'
}
},
lock: {
@ -1501,6 +1533,7 @@ export default {
projectForm: 'Project Form',
startDate: 'Start Date',
endDate: 'End Date',
planEndDate: 'Plan End Date',
cronExpression: 'Cron Expression',
enabled: 'Enabled',
creatorName: 'Creator',
@ -2063,6 +2096,20 @@ export default {
validatorCategoryTypeRequired: 'Type can not be empty',
validatorUnitRequired: 'Unit id can not be empty',
validatorStatusRequired: 'Product status can not be empty',
dialogPackagingSchemeLabel: 'Packaging Scheme',
dialogPackagingSchemeTitle: 'Select Packaging Scheme',
dialogPackagingSchemePlaceholder: 'Please select packaging scheme',
dialogDefaultStatusLabel: 'Default Scheme',
validatorPackagingSchemeRequired: 'Packaging scheme is required',
dialogSupplierLabel: 'Supplier',
dialogSupplierTitle: 'Select Supplier',
dialogSupplierPlaceholder: 'Please select supplier',
validatorSupplierRequired: 'Supplier is required',
dialogFragileFlagLabel: 'Fragile',
dialogSparePartLevelLabel: 'Spare Part Level',
dialogPurchaseCycleLabel: 'Purchase Cycle (Days)',
dialogBrandLabel: 'Brand',
dialogBrandPlaceholder: 'Please enter brand',
categoryTree: 'Category Tree',
addCategory: 'Add Category',
refreshTree: 'Refresh'
@ -2548,7 +2595,18 @@ export default {
replaceNetRemark: 'Remark',
placeholderReplaceNetRemark: 'Please input remark',
moldInfo: 'Mold Info',
maintainInfo: 'Maintain Info'
maintainInfo: 'Maintain Info',
inspectionResult: 'Inspection Result',
index: 'Index',
inspectionItemName: 'Inspection Item Name',
inspectionMethod: 'Inspection Method',
judgmentCriteria: 'Judgment Criteria',
pendingInspection: 'Pending',
pass: 'Pass',
notPass: 'Not Pass',
inputValue: 'Input Value',
noInspectionItems: 'No Inspection Items',
pleaseSelectProjectForm: 'Please Select Project Form'
},
MoldBrandDetail: {

@ -541,6 +541,38 @@ export default {
validatorFromWarehouseRequired: '调出仓库不能为空',
validatorToWarehouseRequired: '调入仓库不能为空'
}
},
PackagingScheme: {
code: '方案编码',
name: '方案名称',
packageQuantity: '每包数量(件)',
palletPackageQuantity: '每托包数(包)',
palletTotalQuantity: '每托总数量(件)',
remark: '备注',
status: '状态',
createTime: '创建时间',
placeholderCode: '请输入方案编码',
placeholderName: '请输入方案名称',
placeholderPackageQuantity: '请输入每包数量',
placeholderPalletPackageQuantity: '请输入每托包数',
placeholderPalletTotalQuantity: '请输入每托总数量',
placeholderRemark: '请输入备注',
placeholderStatus: '请选择状态',
validatorNameRequired: '方案名称不能为空',
validatorCodeRequired: '方案编码不能为空',
validatorPackageQuantityRequired: '每包数量不能为空',
validatorPalletPackageQuantityRequired: '每托包数不能为空',
validatorStatusRequired: '状态不能为空'
}
},
ErpPurchase: {
Supplier: {
name: '供应商名称',
contact: '联系人',
mobile: '手机号码',
telephone: '联系电话',
placeholderName: '请输入供应商名称',
placeholderMobile: '请输入手机号码'
}
},
lock: {
@ -1498,6 +1530,7 @@ export default {
projectForm: '项目表单',
startDate: '开始日期',
endDate: '结束日期',
planEndDate: '计划结束时间',
cronExpression: 'cron 表达式',
enabled: '启用',
creatorName: '创建人',
@ -2045,7 +2078,18 @@ export default {
replaceNetRemark: '备注',
placeholderReplaceNetRemark: '请输入备注',
moldInfo: '模具信息',
maintainInfo: '维护信息'
maintainInfo: '维护信息',
inspectionResult: '检验结果',
index: '序号',
inspectionItemName: '检验项名称',
inspectionMethod: '检验方式',
judgmentCriteria: '判定基准',
pendingInspection: '待检测',
pass: '通过',
notPass: '不通过',
inputValue: '输入值',
noInspectionItems: '暂无检验项',
pleaseSelectProjectForm: '请选择项目表单'
},
MoldBrandDetail: {
@ -3216,6 +3260,20 @@ export default {
validatorCategoryTypeRequired: '类型不能为空',
validatorUnitRequired: '单位编号不能为空',
validatorStatusRequired: '产品状态不能为空',
dialogPackagingSchemeLabel: '包装方案',
dialogPackagingSchemeTitle: '选择包装方案',
dialogPackagingSchemePlaceholder: '请选择包装方案',
dialogDefaultStatusLabel: '是否默认方案',
validatorPackagingSchemeRequired: '包装方案不能为空',
dialogSupplierLabel: '供应商',
dialogSupplierTitle: '选择供应商',
dialogSupplierPlaceholder: '请选择供应商',
validatorSupplierRequired: '供应商不能为空',
dialogFragileFlagLabel: '是否易损件',
dialogSparePartLevelLabel: '备件等级',
dialogPurchaseCycleLabel: '采购周期(天)',
dialogBrandLabel: '品牌',
dialogBrandPlaceholder: '请输入品牌',
categoryTree: '产品分类树',
addCategory: '新增分类',
refreshTree: '刷新'

@ -236,6 +236,7 @@ export enum DICT_TYPE {
ERP_AUTOCODE_CYCLEMETHOD = "erp_autocode_cyclemethod",
ERP_AUTOCODE_PARTTYPE = "erp_autocode_parttype",
MATERIAL_CLASSIFICATION_TYPE = 'material_classification_type',
SPARE_PARTS_LEVEL = 'spare_parts_level',
// ========== MES - 生产管理模块 ==========

@ -75,20 +75,127 @@
<!-- 点检/保养表单 -->
<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"
<div class="mold-maintain-inspect-layout">
<div class="mold-maintain-inspect-layout__form">
<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>
</div>
<el-divider content-position="left">{{ t('MoldManagement.MoldBrandPage.inspectionResult') }}</el-divider>
<div class="mold-maintain-ticket-results">
<div class="mold-maintain-ticket-results__header">
<el-button
type="primary"
link
:disabled="!ticketResultList.length"
@click="handleTicketResultEditToggle"
>
<Icon :icon="ticketResultEditable ? 'ep:lock' : 'ep:edit-pen'" class="mr-4px" />
{{ ticketResultEditable ? t('common.cancel') : t('action.edit') }}
</el-button>
</div>
<el-table
:data="ticketResultPageData"
:stripe="true"
:show-overflow-tooltip="true"
size="small"
max-height="420"
row-key="id"
>
<el-table-column type="index" :label="t('MoldManagement.MoldBrandPage.index')" align="center" width="58" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.inspectionItemName')" align="center" prop="inspectionItemName" min-width="140" />
<el-table-column label="检验方式" align="center" prop="inspectionMethod" min-width="120">
<template #default="scope">
<dict-tag type="Inspection_method" :value="scope.row.inspectionMethod" />
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.judgmentCriteria')" align="center" prop="judgmentCriteria" min-width="140" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.inspectionResult')" align="center" prop="inspectionResult" width="100">
<template #default="scope">
<el-tag v-if="String(scope.row.inspectionResult) === '0'" type="info">{{ t('MoldManagement.MoldBrandPage.pendingInspection') }}</el-tag>
<el-tag v-else-if="String(scope.row.inspectionResult) === '1'" type="success">{{ t('MoldManagement.MoldBrandPage.pass') }}</el-tag>
<el-tag v-else-if="String(scope.row.inspectionResult) === '2'" type="danger">{{ t('MoldManagement.MoldBrandPage.notPass') }}</el-tag>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.image')" align="center" prop="images" width="110">
<template #default="scope">
<UploadImg
v-if="ticketResultEditable"
v-model="scope.row.images"
:drag="false"
:show-btn-text="false"
width="56px"
height="56px"
/>
<el-image
v-else-if="scope.row.images"
:src="parseFirstImage(scope.row.images)"
:preview-src-list="parseImages(scope.row.images)"
preview-teleported
fit="cover"
style="width: 56px; height: 56px"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column :label="t('EquipmentManagement.DvSubject.valueType')" align="center" prop="valueType" width="100">
<template #default="scope">
<dict-tag type="value_types" :value="scope.row.valueType" />
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.inputValue')" align="center" min-width="150">
<template #default="scope">
<el-input
v-if="String(scope.row.valueType) === '0' || String(scope.row.valueType) === '2'"
v-model="scope.row.textInput"
:disabled="!ticketResultEditable"
clearable
:placeholder="t('common.inputText')"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.remark')" align="center" prop="remark" min-width="100">
<template #default="scope">
<el-input v-model="scope.row.remark" :disabled="!ticketResultEditable" clearable :placeholder="t('common.inputText')" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" fixed="right">
<template #default="scope">
<el-radio-group v-if="ticketResultEditable" v-model="scope.row.inspectionResult">
<el-radio :label="'1'">通过</el-radio>
<el-radio :label="'2'">不通过</el-radio>
</el-radio-group>
<span v-else>-</span>
</template>
</el-table-column>
</el-table>
<Pagination
v-if="ticketResultList.length"
:total="ticketResultList.length"
v-model:page="ticketResultPageNo"
:limit="ticketResultPageSize"
@pagination="handleTicketResultPageChange"
/>
<el-empty
v-if="!ticketResultList.length"
:description="selectedProjectFormId ? t('MoldManagement.MoldBrandPage.noInspectionItems') : t('MoldManagement.MoldBrandPage.pleaseSelectProjectForm')"
:image-size="80"
/>
<el-button @click="openProjectFormDialog">{{ t('common.select') }}</el-button>
</div>
</el-form-item>
</div>
</template>
<!-- 维修表单 -->
@ -505,6 +612,32 @@ const selectedProjectFormId = ref<string>('') // 已确认选中的 id
const selectedProjectFormName = ref<string>('') //
const subjectListMap = ref<Record<string, any[]>>({})
const subjectLoadingMap = ref<Record<string, boolean>>({})
const ticketResultList = ref<any[]>([])
const ticketResultEditable = ref(false)
const ticketResultBackup = ref<any[] | null>(null)
const handleTicketResultEditToggle = () => {
if (ticketResultEditable.value) {
//
if (ticketResultBackup.value) {
ticketResultList.value = JSON.parse(JSON.stringify(ticketResultBackup.value))
ticketResultBackup.value = null
}
ticketResultEditable.value = false
} else {
//
ticketResultBackup.value = JSON.parse(JSON.stringify(ticketResultList.value))
ticketResultEditable.value = true
}
}
const ticketResultPageNo = ref(1)
const ticketResultPageSize = 5
const ticketResultPageData = computed(() => {
const start = (ticketResultPageNo.value - 1) * ticketResultPageSize
return ticketResultList.value.slice(start, start + ticketResultPageSize)
})
const handleTicketResultPageChange = () => {
// computed
}
const projectFormPageParams = reactive({
pageNo: 1,
@ -541,11 +674,18 @@ const handleProjectFormRadioChange = (row: any) => {
tempSelectedProjectForm.value = row
}
const confirmProjectFormSelection = () => {
const confirmProjectFormSelection = async () => {
if (!tempSelectedProjectForm.value) return
selectedProjectFormId.value = String(tempSelectedProjectForm.value.id)
selectedProjectFormName.value = tempSelectedProjectForm.value.planName ?? String(tempSelectedProjectForm.value.id)
taskFormData.projectForm = selectedProjectFormId.value
if (Array.isArray(tempSelectedProjectForm.value.subjectList)) {
subjectListMap.value[selectedProjectFormId.value] = tempSelectedProjectForm.value.subjectList
} else {
await ensureSubjectListLoaded(selectedProjectFormId.value)
}
setTicketResultList(subjectListMap.value[selectedProjectFormId.value] ?? [])
ticketResultEditable.value = false
projectFormDialogVisible.value = false
}
@ -563,6 +703,36 @@ const ensureSubjectListLoaded = async (planId: number | string) => {
}
}
const setTicketResultList = (subjectList: any[]) => {
ticketResultList.value = (subjectList ?? []).map((item: any, index: number) => ({
id: item.id,
subjectId: item.id,
inspectionItemName: item.subjectName ?? item.inspectionItemName ?? '',
inspectionMethod: item.inspectionMethod ?? '',
judgmentCriteria: item.judgmentCriteria ?? item.subjectStandard ?? '',
valueType: item.valueType ?? '',
textInput: item.textInput ?? '',
inspectionResult: item.inspectionResult ?? '0',
images: item.images ?? '',
remark: item.remark ?? '',
sort: index + 1
}))
ticketResultPageNo.value = 1
}
const parseImages = (value: any): string[] => {
if (!value) return []
if (Array.isArray(value)) return value.map(String).filter(Boolean)
return String(value)
.split(',')
.map((v) => v.trim())
.filter(Boolean)
}
const parseFirstImage = (value: any): string => {
return parseImages(value)[0] || ''
}
const handleProjectFormExpandChange = async (row: any, expandedRows: any[]) => {
const isExpanded = expandedRows.some((r) => String(r.id) === String(row.id))
if (!isExpanded) return
@ -649,7 +819,8 @@ const submitForm = async () => {
name: taskFormData.name,
taskType: String(taskFormData.taskType),
moldList: props.mold?.id ? String(props.mold.id) : undefined,
projectForm: taskFormData.projectForm
projectForm: taskFormData.projectForm,
ticketResultsList: ticketResultList.value.map((item: any) => ({ ...item }))
})
message.success(t('common.createSuccess'))
//
@ -657,6 +828,8 @@ const submitForm = async () => {
taskFormData.projectForm = ''
selectedProjectFormId.value = ''
selectedProjectFormName.value = ''
ticketResultList.value = []
ticketResultEditable.value = false
} else if (isRepair.value) {
//
const payload: any = {
@ -847,6 +1020,46 @@ defineExpose({ open })
white-space: nowrap;
}
.mold-maintain-inspect-layout {
display: flex;
flex-direction: column;
gap: 20px;
align-items: stretch;
}
.mold-maintain-inspect-layout__form {
min-width: 0;
}
.mold-maintain-ticket-results {
min-width: 0;
padding: 14px;
border: 1px solid var(--el-border-color-lighter);
border-radius: 8px;
background: #fafafa;
}
.mold-maintain-ticket-results__header {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
margin-bottom: 12px;
}
.mold-maintain-ticket-results__title {
font-size: 14px;
font-weight: 600;
color: var(--el-text-color-primary);
}
.mold-maintain-ticket-results :deep(.el-upload) {
margin: 0 auto;
}
@media (max-width: 1400px) {
}
.mold-maintain-page__form-actions {
display: flex;
justify-content: flex-end;

@ -110,6 +110,61 @@
/>
</el-form-item>
</el-col>
<el-col v-if="formData.categoryType === 1" :span="12">
<el-form-item :label="t('FactoryModeling.ProductInformation.dialogPackagingSchemeLabel')" prop="packagingSchemes">
<el-input
:model-value="displayPackagingSchemeText"
readonly
clearable
:placeholder="t('FactoryModeling.ProductInformation.dialogPackagingSchemePlaceholder')"
@click="openPackagingSchemeDialog"
@clear="handlePackagingSchemeClear"
/>
</el-form-item>
</el-col>
<el-col v-if="formData.categoryType === 2 || formData.categoryType === 3" :span="12">
<el-form-item :label="t('FactoryModeling.ProductInformation.dialogSupplierLabel')" prop="suppliers">
<el-input
:model-value="displaySupplierText"
readonly
clearable
:placeholder="t('FactoryModeling.ProductInformation.dialogSupplierPlaceholder')"
@click="openSupplierDialog"
@clear="handleSupplierClear"
/>
</el-form-item>
</el-col>
<el-col v-if="formData.categoryType === 3" :span="8">
<el-form-item :label="t('FactoryModeling.ProductInformation.dialogSparePartLevelLabel')" prop="sparePartLevel">
<el-radio-group v-model="formData.sparePartLevel">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.SPARE_PARTS_LEVEL)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col v-if="formData.categoryType === 3" :span="8">
<el-form-item :label="t('FactoryModeling.ProductInformation.dialogFragileFlagLabel')" prop="fragileFlag">
<el-radio-group v-model="formData.fragileFlag">
<el-radio :label="1">{{ t('common.yes') }}</el-radio>
<el-radio :label="0">{{ t('common.no') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col v-if="formData.categoryType === 3" :span="8">
<el-form-item :label="t('FactoryModeling.ProductInformation.dialogPurchaseCycleLabel')" prop="purchaseCycle">
<el-input-number v-model="formData.purchaseCycle" :min="0" :precision="0" class="!w-1/1" />
</el-form-item>
</el-col>
<el-col v-if="formData.categoryType === 3" :span="8">
<el-form-item :label="t('FactoryModeling.ProductInformation.dialogBrandLabel')" prop="brand">
<el-input v-model="formData.brand" :placeholder="t('FactoryModeling.ProductInformation.dialogBrandPlaceholder')" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="t('FactoryModeling.ProductInformation.dialogStatusLabel')" prop="status">
<el-radio-group v-model="formData.status">
@ -204,6 +259,99 @@
</el-form>
</template>
</TableSelectDialog>
<Dialog :title="t('FactoryModeling.ProductInformation.dialogPackagingSchemeTitle')" v-model="packagingSchemeDialogVisible" :appendToBody="true" width="1200">
<el-form ref="searchPackagingSchemeFormRef" :model="searchPackagingSchemeParams" :inline="true" class="-mb-15px">
<el-form-item :label="t('ErpStock.PackagingScheme.code')" prop="code">
<el-input v-model="searchPackagingSchemeParams.code" :placeholder="t('ErpStock.PackagingScheme.placeholderCode')" clearable />
</el-form-item>
<el-form-item :label="t('ErpStock.PackagingScheme.name')" prop="name">
<el-input v-model="searchPackagingSchemeParams.name" :placeholder="t('ErpStock.PackagingScheme.placeholderName')" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handlePackagingSchemeSearch">{{ t('FactoryModeling.ProductInformation.searchButtonText') }}</el-button>
<el-button @click="resetPackagingSchemeSearch">{{ t('FactoryModeling.ProductInformation.resetButtonText') }}</el-button>
</el-form-item>
</el-form>
<el-table
ref="packagingSchemeTableRef"
v-loading="packagingSchemeDialogLoading"
:data="packagingSchemeDialogList"
:row-key="(row) => row.id"
:show-overflow-tooltip="true"
:stripe="true"
@selection-change="handlePackagingSchemeSelectionChange"
>
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column :label="t('ErpStock.PackagingScheme.code')" prop="code" minWidth="160" />
<el-table-column :label="t('ErpStock.PackagingScheme.name')" prop="name" minWidth="160" />
<el-table-column :label="t('ErpStock.PackagingScheme.packageQuantity')" prop="packageQuantity" minWidth="120" />
<el-table-column :label="t('ErpStock.PackagingScheme.palletPackageQuantity')" prop="palletPackageQuantity" minWidth="120" />
<el-table-column :label="t('ErpStock.PackagingScheme.palletTotalQuantity')" prop="palletTotalQuantity" minWidth="120" />
<el-table-column :label="t('FactoryModeling.ProductInformation.dialogDefaultStatusLabel')" width="130" align="center">
<template #default="{ row }">
<el-radio v-model="packagingSchemeDefaultId" :label="row.id">&nbsp;</el-radio>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-15px">
<Pagination
v-model:page="packagingSchemeDialogPageNo"
v-model:limit="packagingSchemeDialogPageSize"
:total="packagingSchemeDialogTotal"
@pagination="getPackagingSchemeDialogList"
/>
</div>
<template #footer>
<el-button type="primary" @click="confirmPackagingSchemeSelect">{{ t('common.ok') }}</el-button>
<el-button @click="packagingSchemeDialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
<Dialog :title="t('FactoryModeling.ProductInformation.dialogSupplierTitle')" v-model="supplierDialogVisible" :appendToBody="true" width="1000">
<el-form ref="searchSupplierFormRef" :model="searchSupplierParams" :inline="true" class="-mb-15px">
<el-form-item :label="t('ErpPurchase.Supplier.name')" prop="name">
<el-input v-model="searchSupplierParams.name" :placeholder="t('ErpPurchase.Supplier.placeholderName')" clearable />
</el-form-item>
<el-form-item :label="t('ErpPurchase.Supplier.mobile')" prop="mobile">
<el-input v-model="searchSupplierParams.mobile" :placeholder="t('ErpPurchase.Supplier.placeholderMobile')" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSupplierSearch">{{ t('FactoryModeling.ProductInformation.searchButtonText') }}</el-button>
<el-button @click="resetSupplierSearch">{{ t('FactoryModeling.ProductInformation.resetButtonText') }}</el-button>
</el-form-item>
</el-form>
<el-table
ref="supplierTableRef"
v-loading="supplierDialogLoading"
:data="supplierDialogList"
:row-key="(row) => row.id"
:show-overflow-tooltip="true"
:stripe="true"
@selection-change="handleSupplierSelectionChange"
>
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column :label="t('ErpPurchase.Supplier.name')" prop="name" minWidth="160" />
<el-table-column :label="t('ErpPurchase.Supplier.contact')" prop="contact" minWidth="100" />
<el-table-column :label="t('ErpPurchase.Supplier.mobile')" prop="mobile" minWidth="120" />
<el-table-column :label="t('ErpPurchase.Supplier.telephone')" prop="telephone" minWidth="120" />
<el-table-column :label="t('FactoryModeling.ProductInformation.dialogDefaultStatusLabel')" width="130" align="center">
<template #default="{ row }">
<el-radio v-model="supplierDefaultId" :label="row.id">&nbsp;</el-radio>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-15px">
<Pagination
v-model:page="supplierDialogPageNo"
v-model:limit="supplierDialogPageSize"
:total="supplierDialogTotal"
@pagination="getSupplierDialogList"
/>
</div>
<template #footer>
<el-button type="primary" @click="confirmSupplierSelect">{{ t('common.ok') }}</el-button>
<el-button @click="supplierDialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { ProductApi, ProductVO } from '@/api/erp/product/product'
@ -213,6 +361,8 @@ import QrcodeActionCard from '@/components/QrcodeActionCard/index.vue'
import TableSelectDialog from '@/components/TableSelectDialog/TableSelectDialog.vue'
import { DeviceLedgerApi } from '@/api/mes/deviceledger'
import { MoldBrandApi } from '@/api/erp/mold'
import { PackagingSchemeApi } from '@/api/erp/stock/packagingScheme'
import { SupplierApi } from '@/api/erp/purchase/supplier'
import { CommonStatusEnum } from '@/utils/constants'
import { defaultProps, handleTree } from '@/utils/tree'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
@ -279,7 +429,13 @@ const formData = ref({
minPrice: undefined,
safetyNumber: undefined,
devices: [] as { id: number; name: string }[],
molds: [] as { id: number; name: string }[]
molds: [] as { id: number; name: string }[],
packagingSchemes: [] as { packagingSchemeId: number | undefined; defaultStatus: number }[],
suppliers: [] as { supplierId: number | undefined; defaultStatus: number }[],
fragileFlag: undefined as number | undefined,
purchaseCycle: undefined as number | undefined,
brand: undefined as string | undefined,
sparePartLevel: undefined as number | undefined
})
const selectedDeviceRows = ref<any[]>([])
const selectedMoldRows = ref<any[]>([])
@ -445,17 +601,252 @@ const validateBarCode = (_rule, value, callback) => {
}
callback()
}
const validatePackagingSchemes = (_rule, value, callback) => {
if (formData.value.categoryType !== 1) {
callback()
return
}
if (!value || !value.length) {
callback(new Error(t('FactoryModeling.ProductInformation.validatorPackagingSchemeRequired')))
return
}
if (value.some((item: any) => !item.packagingSchemeId)) {
callback(new Error(t('FactoryModeling.ProductInformation.validatorPackagingSchemeRequired')))
return
}
callback()
}
const validateSuppliers = (_rule, value, callback) => {
if (formData.value.categoryType !== 2 && formData.value.categoryType !== 3) {
callback()
return
}
if (!value || !value.length) {
callback(new Error(t('FactoryModeling.ProductInformation.validatorSupplierRequired')))
return
}
if (value.some((item: any) => !item.supplierId)) {
callback(new Error(t('FactoryModeling.ProductInformation.validatorSupplierRequired')))
return
}
callback()
}
//
const packagingSchemeDialogVisible = ref(false)
const packagingSchemeDialogLoading = ref(false)
const packagingSchemeDialogList = ref<any[]>([])
const packagingSchemeDialogTotal = ref(0)
const packagingSchemeDialogPageNo = ref(1)
const packagingSchemeDialogPageSize = ref(10)
const packagingSchemeTableRef = ref()
const packagingSchemeSelectedRows = ref<any[]>([])
const packagingSchemeDefaultId = ref<number | undefined>(undefined)
const searchPackagingSchemeParams = reactive({ code: undefined, name: undefined })
const searchPackagingSchemeFormRef = ref()
const getPackagingSchemeDialogList = async () => {
packagingSchemeDialogLoading.value = true
try {
const data = await PackagingSchemeApi.getPackagingSchemePage({
pageNo: packagingSchemeDialogPageNo.value,
pageSize: packagingSchemeDialogPageSize.value,
status: 0,
...searchPackagingSchemeParams
})
packagingSchemeDialogList.value = data.list || []
packagingSchemeDialogTotal.value = data.total || 0
} finally {
packagingSchemeDialogLoading.value = false
}
}
const handlePackagingSchemeSelectionChange = (selection: any[]) => {
packagingSchemeSelectedRows.value = selection
}
const displayPackagingSchemeText = computed(() => {
if (!formData.value.packagingSchemes?.length) return ''
return formData.value.packagingSchemes
.map((item) => {
const scheme = packagingSchemeList.value.find((s) => s.id === item.packagingSchemeId)
return scheme?.name || ''
})
.filter(Boolean)
.join('、')
})
const openPackagingSchemeDialog = async () => {
packagingSchemeDialogVisible.value = true
packagingSchemeDialogPageNo.value = 1
searchPackagingSchemeParams.code = undefined
searchPackagingSchemeParams.name = undefined
packagingSchemeSelectedRows.value = []
// ID
const defaultItem = formData.value.packagingSchemes?.find((item) => item.defaultStatus === 1)
packagingSchemeDefaultId.value = defaultItem?.packagingSchemeId ?? undefined
await getPackagingSchemeDialogList()
//
await nextTick()
if (formData.value.packagingSchemes?.length && packagingSchemeTableRef.value) {
packagingSchemeTableRef.value.clearSelection()
const selectedIds = formData.value.packagingSchemes.map((item) => item.packagingSchemeId)
packagingSchemeDialogList.value.forEach((row) => {
if (selectedIds.includes(row.id)) {
packagingSchemeTableRef.value?.toggleRowSelection(row, true)
}
})
}
}
const confirmPackagingSchemeSelect = () => {
if (!packagingSchemeSelectedRows.value.length) {
message.warning(t('FactoryModeling.ProductInformation.validatorPackagingSchemeRequired'))
return
}
formData.value.packagingSchemes = packagingSchemeSelectedRows.value.map((row) => ({
packagingSchemeId: row.id,
defaultStatus: row.id === packagingSchemeDefaultId.value ? 1 : 0
}))
//
if (!packagingSchemeDefaultId.value && formData.value.packagingSchemes.length > 0) {
formData.value.packagingSchemes[0].defaultStatus = 1
}
//
packagingSchemeSelectedRows.value.forEach((row) => {
if (!packagingSchemeList.value.find((s) => s.id === row.id)) {
packagingSchemeList.value.push(row)
}
})
packagingSchemeDialogVisible.value = false
}
const handlePackagingSchemeClear = () => {
formData.value.packagingSchemes = []
}
const handlePackagingSchemeSearch = () => {
packagingSchemeDialogPageNo.value = 1
getPackagingSchemeDialogList()
}
const resetPackagingSchemeSearch = () => {
searchPackagingSchemeFormRef.value?.resetFields()
handlePackagingSchemeSearch()
}
//
const supplierDialogVisible = ref(false)
const supplierDialogLoading = ref(false)
const supplierDialogList = ref<any[]>([])
const supplierDialogTotal = ref(0)
const supplierDialogPageNo = ref(1)
const supplierDialogPageSize = ref(10)
const supplierTableRef = ref()
const supplierSelectedRows = ref<any[]>([])
const supplierDefaultId = ref<number | undefined>(undefined)
const searchSupplierParams = reactive({ name: undefined, mobile: undefined })
const searchSupplierFormRef = ref()
const getSupplierDialogList = async () => {
supplierDialogLoading.value = true
try {
const data = await SupplierApi.getSupplierPage({
pageNo: supplierDialogPageNo.value,
pageSize: supplierDialogPageSize.value,
status: 0,
...searchSupplierParams
})
supplierDialogList.value = data.list || []
supplierDialogTotal.value = data.total || 0
} finally {
supplierDialogLoading.value = false
}
}
const handleSupplierSelectionChange = (selection: any[]) => {
supplierSelectedRows.value = selection
}
const displaySupplierText = computed(() => {
if (!formData.value.suppliers?.length) return ''
return formData.value.suppliers
.map((item) => {
const supplier = supplierList.value.find((s) => s.id === item.supplierId)
return supplier?.name || ''
})
.filter(Boolean)
.join('、')
})
const openSupplierDialog = async () => {
supplierDialogVisible.value = true
supplierDialogPageNo.value = 1
searchSupplierParams.name = undefined
searchSupplierParams.mobile = undefined
supplierSelectedRows.value = []
const defaultItem = formData.value.suppliers?.find((item) => item.defaultStatus === 1)
supplierDefaultId.value = defaultItem?.supplierId ?? undefined
await getSupplierDialogList()
//
await nextTick()
if (formData.value.suppliers?.length && supplierTableRef.value) {
supplierTableRef.value.clearSelection()
const selectedIds = formData.value.suppliers.map((item) => item.supplierId)
supplierDialogList.value.forEach((row) => {
if (selectedIds.includes(row.id)) {
supplierTableRef.value?.toggleRowSelection(row, true)
}
})
}
}
const confirmSupplierSelect = () => {
if (!supplierSelectedRows.value.length) {
message.warning(t('FactoryModeling.ProductInformation.validatorSupplierRequired'))
return
}
formData.value.suppliers = supplierSelectedRows.value.map((row) => ({
supplierId: row.id,
defaultStatus: row.id === supplierDefaultId.value ? 1 : 0
}))
if (!supplierDefaultId.value && formData.value.suppliers.length > 0) {
formData.value.suppliers[0].defaultStatus = 1
}
supplierSelectedRows.value.forEach((row) => {
if (!supplierList.value.find((s) => s.id === row.id)) {
supplierList.value.push(row)
}
})
supplierDialogVisible.value = false
}
const handleSupplierClear = () => {
formData.value.suppliers = []
}
const handleSupplierSearch = () => {
supplierDialogPageNo.value = 1
getSupplierDialogList()
}
const resetSupplierSearch = () => {
searchSupplierFormRef.value?.resetFields()
handleSupplierSearch()
}
const formRules = reactive({
categoryType: [{ required: true, message: t('FactoryModeling.ProductInformation.validatorCategoryTypeRequired'), trigger: 'change' }],
name: [{ required: true, message: t('FactoryModeling.ProductInformation.validatorNameRequired'), trigger: 'blur' }],
barCode: [{ validator: validateBarCode, trigger: ['blur', 'change'] }],
categoryId: [{ required: true, message: t('FactoryModeling.ProductInformation.validatorCategoryRequired'), trigger: 'blur' }],
unitId: [{ required: true, message: t('FactoryModeling.ProductInformation.validatorUnitRequired'), trigger: 'blur' }],
status: [{ required: true, message: t('FactoryModeling.ProductInformation.validatorStatusRequired'), trigger: 'blur' }]
status: [{ required: true, message: t('FactoryModeling.ProductInformation.validatorStatusRequired'), trigger: 'blur' }],
packagingSchemes: [{ validator: validatePackagingSchemes, trigger: 'change' }],
suppliers: [{ validator: validateSuppliers, trigger: 'change' }]
})
const formRef = ref()
const categoryList = ref<ProductCategoryVO[]>([])
const unitList = ref<ProductUnitVO[]>([])
const packagingSchemeList = ref<any[]>([])
const supplierList = ref<any[]>([])
let openRequestId = 0
@ -494,8 +885,11 @@ const open = async (type: string, id?: number) => {
...formData.value,
...productData,
templateJson: parsedTemplateJson,
sparePartLevel: productData.sparePartLevel != null ? Number(productData.sparePartLevel) : undefined,
devices,
molds
molds,
packagingSchemes: (productData as any).packagingSchemes || [],
suppliers: (productData as any).suppliers || []
}
selectedDeviceRows.value = toDeviceRows(devices)
selectedMoldRows.value = toMoldRows(molds)
@ -506,6 +900,12 @@ const open = async (type: string, id?: number) => {
const categoryData = await ProductCategoryApi.getProductCategorySimpleList(formData.value.categoryType)
categoryList.value = handleTree(categoryData, 'id', 'parentId')
unitList.value = await ProductUnitApi.getProductUnitSimpleList()
//
const schemeData = await PackagingSchemeApi.getPackagingSchemePage({ pageNo: 1, pageSize: 100, status: 0 })
packagingSchemeList.value = schemeData.list || []
//
const supplierData = await SupplierApi.getSupplierPage({ pageNo: 1, pageSize: 100, status: 0 })
supplierList.value = supplierData.list || []
}
defineExpose({ open })
@ -530,6 +930,12 @@ const handleCodeAutoChange = (value: boolean) => {
const handleCategoryTypeChange = async () => {
formData.value.categoryId = undefined
formData.value.packagingSchemes = []
formData.value.suppliers = []
formData.value.fragileFlag = undefined
formData.value.purchaseCycle = undefined
formData.value.brand = undefined
formData.value.sparePartLevel = undefined
const categoryData = await ProductCategoryApi.getProductCategorySimpleList(formData.value.categoryType)
categoryList.value = handleTree(categoryData, 'id', 'parentId')
}
@ -611,7 +1017,13 @@ const resetForm = () => {
salePrice: undefined,
minPrice: undefined,
devices: [],
molds: []
molds: [],
packagingSchemes: [],
suppliers: [],
fragileFlag: undefined,
purchaseCycle: undefined,
brand: undefined,
sparePartLevel: undefined
}
selectedDeviceRows.value = []
selectedMoldRows.value = []

@ -0,0 +1,193 @@
<!-- ERP 包装方案表单 -->
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="140px"
v-loading="formLoading"
>
<el-form-item :label="t('ErpStock.PackagingScheme.code')" prop="code">
<el-row :gutter="20" style="width: 100%">
<el-col :xs="18" :sm="18" :md="16" :lg="14" :xl="10">
<el-input v-model="formData.code"
:placeholder="t('ErpStock.PackagingScheme.placeholderCode')"
:disabled="Boolean(formData.isCode) || formType === 'update'" />
</el-col>
<el-col :xs="24" :sm="6" :md="4" :lg="3" :xl="2">
<el-switch v-model="formData.isCode" :disabled="formType === 'update'"
@change="handleCodeAutoChange" />
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="t('ErpStock.PackagingScheme.name')" prop="name">
<el-input v-model="formData.name" :placeholder="t('ErpStock.PackagingScheme.placeholderName')" />
</el-form-item>
<el-form-item :label="t('ErpStock.PackagingScheme.packageQuantity')" prop="packageQuantity">
<el-input-number
v-model="formData.packageQuantity"
:placeholder="t('ErpStock.PackagingScheme.placeholderPackageQuantity')"
:min="0"
:precision="0"
class="!w-1/1"
/>
</el-form-item>
<el-form-item :label="t('ErpStock.PackagingScheme.palletPackageQuantity')" prop="palletPackageQuantity">
<el-input-number
v-model="formData.palletPackageQuantity"
:placeholder="t('ErpStock.PackagingScheme.placeholderPalletPackageQuantity')"
:min="0"
:precision="0"
class="!w-1/1"
/>
</el-form-item>
<el-form-item :label="t('ErpStock.PackagingScheme.palletTotalQuantity')">
<el-input-number
:model-value="palletTotalQuantity"
disabled
class="!w-1/1"
/>
</el-form-item>
<el-form-item :label="t('ErpStock.PackagingScheme.remark')" prop="remark">
<el-input type="textarea" v-model="formData.remark" :placeholder="t('ErpStock.PackagingScheme.placeholderRemark')" />
</el-form-item>
<el-form-item :label="t('ErpStock.PackagingScheme.status')" prop="status">
<el-radio-group v-model="formData.status">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { PackagingSchemeApi, PackagingSchemeVO } from '@/api/erp/stock/packagingScheme'
import { CommonStatusEnum } from '@/utils/constants'
/** ERP 包装方案表单 */
defineOptions({ name: 'PackagingSolutionForm' })
const { t } = useI18n()
const message = useMessage()
const dialogVisible = ref(false)
const dialogTitle = ref('')
const formLoading = ref(false)
const formType = ref('')
/** 每托总数量 = 每包数量 × 每托包数 */
const palletTotalQuantity = computed(() => {
const qty = formData.value.packageQuantity ?? 0
const pallet = formData.value.palletPackageQuantity ?? 0
return qty * pallet
})
const formData = ref({
id: undefined,
code: undefined,
isCode: true,
name: undefined,
packageQuantity: undefined,
palletPackageQuantity: undefined,
palletTotalQuantity: undefined,
remark: undefined,
status: CommonStatusEnum.ENABLE
})
const validateCode = (_rule, value, callback) => {
if (Boolean(formData.value.isCode)) {
callback()
return
}
if (value === undefined || value === null || String(value).trim() === '') {
callback(new Error(t('ErpStock.PackagingScheme.validatorCodeRequired')))
return
}
callback()
}
const formRules = reactive({
code: [{ validator: validateCode, trigger: ['blur', 'change'] }],
name: [{ required: true, message: t('ErpStock.PackagingScheme.validatorNameRequired'), trigger: 'blur' }],
packageQuantity: [{ required: true, message: t('ErpStock.PackagingScheme.validatorPackageQuantityRequired'), trigger: 'blur' }],
palletPackageQuantity: [{ required: true, message: t('ErpStock.PackagingScheme.validatorPalletPackageQuantityRequired'), trigger: 'blur' }],
status: [{ required: true, message: t('ErpStock.PackagingScheme.validatorStatusRequired'), trigger: 'blur' }]
})
const formRef = ref()
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
const data = await PackagingSchemeApi.getPackagingScheme(id)
formData.value = {
...data,
isCode: (data as any)?.isCode ?? false
}
} finally {
formLoading.value = false
}
}
}
defineExpose({ open })
/** 提交表单 */
const emit = defineEmits(['success'])
const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
try {
const data = { ...formData.value, palletTotalQuantity: palletTotalQuantity.value } as unknown as PackagingSchemeVO
if (formType.value === 'create') {
await PackagingSchemeApi.createPackagingScheme(data)
message.success(t('common.createSuccess'))
} else {
await PackagingSchemeApi.updatePackagingScheme(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
emit('success')
} finally {
formLoading.value = false
}
}
/** 自动编码开关切换 */
const handleCodeAutoChange = (value: boolean) => {
if (value) {
formData.value.code = undefined
}
formRef.value?.clearValidate('code')
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
code: undefined,
isCode: true,
name: undefined,
packageQuantity: undefined,
palletPackageQuantity: undefined,
palletTotalQuantity: undefined,
remark: undefined,
status: CommonStatusEnum.ENABLE
}
formRef.value?.resetFields()
}
</script>

@ -0,0 +1,189 @@
<!-- ERP 包装方案列表 -->
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="auto"
>
<el-form-item :label="t('ErpStock.PackagingScheme.code')" prop="code">
<el-input
v-model="queryParams.code"
:placeholder="t('ErpStock.PackagingScheme.placeholderCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('ErpStock.PackagingScheme.name')" prop="name">
<el-input
v-model="queryParams.name"
:placeholder="t('ErpStock.PackagingScheme.placeholderName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('ErpStock.PackagingScheme.status')" prop="status">
<el-select
v-model="queryParams.status"
:placeholder="t('ErpStock.PackagingScheme.placeholderStatus')"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reset') }}</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['erp:packaging-scheme:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> {{ t('action.add') }}
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
>
<el-table-column :label="t('ErpStock.PackagingScheme.code')" align="center" prop="code" sortable />
<el-table-column :label="t('ErpStock.PackagingScheme.name')" align="center" prop="name" sortable />
<el-table-column :label="t('ErpStock.PackagingScheme.packageQuantity')" align="center" prop="packageQuantity" />
<el-table-column :label="t('ErpStock.PackagingScheme.palletPackageQuantity')" align="center" prop="palletPackageQuantity" />
<el-table-column :label="t('ErpStock.PackagingScheme.palletTotalQuantity')" align="center" prop="palletTotalQuantity" />
<el-table-column :label="t('ErpStock.PackagingScheme.remark')" align="center" prop="remark" />
<el-table-column :label="t('ErpStock.PackagingScheme.status')" align="center" prop="status" sortable>
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column
:label="t('ErpStock.PackagingScheme.createTime')"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
sortable
/>
<el-table-column :label="t('common.operate')" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['erp:packaging-scheme:update']"
>
{{ t('action.edit') }}
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['erp:packaging-scheme:delete']"
>
{{ t('action.del') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<PackagingSolutionForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import { PackagingSchemeApi, PackagingSchemeVO } from '@/api/erp/stock/packagingScheme'
import PackagingSolutionForm from './PackagingSolutionForm.vue'
/** ERP 包装方案列表 */
defineOptions({ name: 'ErpPackagingScheme' })
const message = useMessage()
const { t } = useI18n()
const loading = ref(true)
const list = ref<PackagingSchemeVO[]>([])
const total = ref(0)
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
code: undefined,
name: undefined,
status: undefined
})
const queryFormRef = ref()
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await PackagingSchemeApi.getPackagingSchemePage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
await message.delConfirm()
await PackagingSchemeApi.deletePackagingScheme(id)
message.success(t('common.delSuccess'))
await getList()
} catch {}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

@ -93,7 +93,13 @@
<ContentWrap>
<el-tabs v-model="subTabsName" class="-mt-15px -mb-10px">
<el-tab-pane :label="t('MoldManagement.MoldGet.moldGroupListTitle')" name="item">
<el-table :data="formData.items || []" :stripe="true" :show-overflow-tooltip="true" row-key="id">
<StockOutItemFormComp
v-if="!disabled"
ref="itemFormRef"
:items="formData.items"
:disabled="disabled"
/>
<el-table v-else :data="formData.items || []" :stripe="true" :show-overflow-tooltip="true" row-key="id">
<el-table-column type="expand" width="48">
<template #default="{ row: itemRow }">
<div class="p-12px">
@ -144,7 +150,7 @@
</template>
<script setup lang="ts">
import { StockOutApi, StockOutVO } from '@/api/erp/stock/out'
import {DICT_TYPE, getBoolDictOptions, getStrDictOptions} from "@/utils/dict";
import { DICT_TYPE } from '@/utils/dict'
import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer'
import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
@ -155,11 +161,40 @@ const { t } = useI18n() // 国际化
const message = useMessage() //
const warehouseList = ref<WarehouseVO[]>([]) //
interface MoldGetItem {
id?: number
moldSetId?: number
productId?: number
warehouseId?: number
moldSetName?: string
productBarCode?: string
count?: number
remark?: string
moldList?: any[]
[key: string]: any
}
interface MoldGetFormData {
id?: number
no?: string
customerId?: number
outTime?: number | string
remark?: string
outType?: string
fileUrl: string
items: MoldGetItem[]
warehouseId?: number
[key: string]: any
}
const StockOutItemFormComp = defineAsyncComponent(() => import('./components/StockOutItemForm.vue') as any)
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update - detail -
const formData = ref({
const formData = ref<MoldGetFormData>({
id: undefined,
no: undefined,
customerId: undefined,
outTime: undefined,
remark: undefined,
@ -190,6 +225,7 @@ const options = [
]
/** 子表的表单 */
const subTabsName = ref('item')
const itemFormRef = ref()
const ensureWarehouseId = () => {
if (formData.value.warehouseId !== undefined && formData.value.warehouseId !== null) return
@ -199,6 +235,32 @@ const ensureWarehouseId = () => {
const getTodayTimestamp = () => new Date().setHours(0, 0, 0, 0)
const getSelectedItemRows = (): any[] => {
const selectedRows = itemFormRef.value?.selectedRows
if (Array.isArray(selectedRows)) return selectedRows
if (Array.isArray(selectedRows?.value)) return selectedRows.value
return []
}
const buildSubmitItems = (rows: any[]): MoldGetItem[] => {
const existingItemMap = new Map(
(formData.value.items || []).map((item) => [item.productId ?? item.id, item])
)
return rows.map((row: any) => {
const existing = existingItemMap.get(row.id) || {}
return {
...existing,
moldSetId: existing.moldSetId ?? row.id,
productId: row.id,
warehouseId: formData.value.warehouseId,
moldSetName: existing.moldSetName ?? row.name,
productBarCode: existing.productBarCode ?? row.code,
count: existing.count ?? row.childMoldCount ?? 1
}
})
}
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogTitle.value = t('action.' + type)
@ -234,6 +296,12 @@ const emit = defineEmits(['success', 'closed']) // 定义 success 和 closed 事
const submitForm = async () => {
//
await formRef.value.validate()
const selectedRows = getSelectedItemRows()
if (!selectedRows.length) {
message.warning('请选择模具组')
return
}
formData.value.items = buildSubmitItems(selectedRows)
//
formLoading.value = true
try {
@ -258,12 +326,13 @@ const resetForm = () => {
formRef.value?.resetFields()
formData.value = {
id: undefined,
no: undefined,
customerId: undefined,
outTime: getTodayTimestamp(),
remark: undefined,
fileUrl: undefined,
fileUrl: '',
items: [],
outType: "模具出库",
outType: '模具出库',
warehouseId: undefined
}
}

@ -93,7 +93,13 @@
<ContentWrap>
<el-tabs v-model="subTabsName" class="-mt-15px -mb-10px">
<el-tab-pane :label="t('MoldManagement.MoldReturn.moldGroupListTitle')" name="item">
<el-table :data="formData.items || []" :stripe="true" :show-overflow-tooltip="true" row-key="id">
<StockInItemFormComp
v-if="!disabled"
ref="itemFormRef"
:items="formData.items"
:disabled="disabled"
/>
<el-table v-else :data="formData.items || []" :stripe="true" :show-overflow-tooltip="true" row-key="id">
<el-table-column type="expand" width="48">
<template #default="{ row: itemRow }">
<div class="p-12px">
@ -155,11 +161,40 @@ const { t } = useI18n() // 国际化
const message = useMessage() //
const warehouseList = ref<WarehouseVO[]>([]) //
interface MoldReturnItem {
id?: number
moldSetId?: number
productId?: number
warehouseId?: number
moldSetName?: string
productBarCode?: string
count?: number
remark?: string
moldList?: any[]
[key: string]: any
}
interface MoldReturnFormData {
id?: number
no?: string
customerId?: number
inTime?: number | string
remark?: string
inType?: string
fileUrl: string
items: MoldReturnItem[]
warehouseId?: number
[key: string]: any
}
const StockInItemFormComp = defineAsyncComponent(() => import('./components/StockInItemForm.vue') as any)
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update - detail -
const formData = ref({
const formData = ref<MoldReturnFormData>({
id: undefined,
no: undefined,
customerId: undefined,
inTime: undefined,
remark: undefined,
@ -190,6 +225,7 @@ const options = [
]
/** 子表的表单 */
const subTabsName = ref('item')
const itemFormRef = ref()
const ensureWarehouseId = () => {
if (formData.value.warehouseId !== undefined && formData.value.warehouseId !== null) return
@ -199,6 +235,32 @@ const ensureWarehouseId = () => {
const getTodayTimestamp = () => new Date().setHours(0, 0, 0, 0)
const getSelectedItemRows = (): any[] => {
const selectedRows = itemFormRef.value?.selectedRows
if (Array.isArray(selectedRows)) return selectedRows
if (Array.isArray(selectedRows?.value)) return selectedRows.value
return []
}
const buildSubmitItems = (rows: any[]): MoldReturnItem[] => {
const existingItemMap = new Map(
(formData.value.items || []).map((item) => [item.productId ?? item.id, item])
)
return rows.map((row: any) => {
const existing = existingItemMap.get(row.id) || {}
return {
...existing,
moldSetId: existing.moldSetId ?? row.id,
productId: row.id,
warehouseId: formData.value.warehouseId,
moldSetName: existing.moldSetName ?? row.name,
productBarCode: existing.productBarCode ?? row.code,
count: existing.count ?? row.childMoldCount ?? 1
}
})
}
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogTitle.value = t('action.' + type)
@ -234,10 +296,16 @@ const emit = defineEmits(['success', 'closed']) // 定义 success 和 closed 事
const submitForm = async () => {
//
await formRef.value.validate()
const selectedRows = getSelectedItemRows()
if (!selectedRows.length) {
message.warning('请选择模具组')
return
}
formData.value.items = buildSubmitItems(selectedRows)
//
formLoading.value = true
try {
const data = formData.value as unknown as StockInVO
const data = formData.value as unknown as StockInVO
if (formType.value === 'create') {
await StockInApi.createStockIn(data)
message.success(t('common.createSuccess'))
@ -258,12 +326,13 @@ const resetForm = () => {
formRef.value?.resetFields()
formData.value = {
id: undefined,
no: undefined,
customerId: undefined,
inTime: getTodayTimestamp(),
remark: undefined,
fileUrl: undefined,
fileUrl: '',
items: [],
inType: "模具入库",
inType: '模具入库',
warehouseId: undefined
}
}

@ -34,17 +34,16 @@
<el-option v-for="item in planOptions" :key="String(item.id)" :label="item.planName" :value="String(item.id)" />
</el-select>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.TaskManagement.dateRange')" prop="dateRange">
<el-form-item :label="t('EquipmentManagement.TaskManagement.planEndDate')" prop="endDate">
<el-date-picker
v-model="formData.dateRange"
v-model="formData.endDate"
value-format="YYYY-MM-DD"
type="daterange"
:start-placeholder="t('EquipmentManagement.TaskManagement.placeholderStartDate')"
:end-placeholder="t('EquipmentManagement.TaskManagement.placeholderEndDate')"
type="date"
:placeholder="t('EquipmentManagement.TaskManagement.placeholderEndDate')"
class="!w-320px"
/>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.TaskManagement.cronExpression')" prop="cronExpression">
<!-- <el-form-item :label="t('EquipmentManagement.TaskManagement.cronExpression')" prop="cronExpression">
<template #label>
<Tooltip
title="Cron 表达式"
@ -52,7 +51,7 @@
/>
</template>
<crontab v-model="formData.cronExpression" />
</el-form-item>
</el-form-item> -->
<el-form-item :label="t('EquipmentManagement.TaskManagement.operableUsers')" prop="operableUsers">
<el-select
v-model="formData.operableUsers"
@ -145,7 +144,7 @@ const formData = ref({
taskType: undefined as number | undefined,
moldList: [] as string[],
projectForm: [] as string[],
dateRange: [] as string[],
endDate: undefined as string | undefined,
cronExpression: undefined as string | undefined,
operableUsers: [] as string[],
enabled: true as boolean
@ -157,7 +156,7 @@ const formRules = reactive({
enabled: [{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderEnabled'), trigger: 'change' }],
moldList: [{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderDeviceList'), trigger: 'change' }],
projectForm: [{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderProjectForm'), trigger: 'change' }],
dateRange: [{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderDateRange'), trigger: 'change' }]
endDate: [{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderEndDate'), trigger: 'change' }]
})
const resetForm = () => {
@ -167,7 +166,7 @@ const resetForm = () => {
taskType: undefined,
moldList: [],
projectForm: [],
dateRange: [],
endDate: undefined,
cronExpression: undefined,
operableUsers: [],
enabled: true
@ -198,7 +197,7 @@ const open = async (type: string, row?: TaskManagementVO) => {
.map((id) => String(id))
formData.value.projectForm = mappedIds
}
formData.value.dateRange = [row.startDate, row.endDate].filter(Boolean) as string[]
formData.value.endDate = row.endDate || undefined
formData.value.cronExpression = row.cronExpression
formData.value.operableUsers = parseIdsValue((row as any).operableUsers)
if (typeof row.enabled === 'boolean') {
@ -219,15 +218,13 @@ const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
try {
const [startDate, endDate] = Array.isArray(formData.value.dateRange) ? formData.value.dateRange : []
const payload: TaskManagementVO = {
id: formData.value.id,
name: formData.value.name,
taskType: formData.value.taskType,
moldList: toCommaSeparatedIds((formData.value as any).moldList),
projectForm: toCommaSeparatedIds((formData.value as any).projectForm),
startDate: startDate || undefined,
endDate: endDate || undefined,
endDate: formData.value.endDate || undefined,
cronExpression: formData.value.cronExpression,
operableUsers: toCommaSeparatedIds((formData.value as any).operableUsers),
enabled: formData.value.enabled

@ -84,9 +84,9 @@
</template>
</el-table-column>
<el-table-column :label="t('EquipmentManagement.TaskManagement.projectForm')" align="center" prop="projectFormName" min-width="140" sortable />
<el-table-column :label="t('EquipmentManagement.TaskManagement.startDate')" align="center" prop="startDate" :formatter="dateFormatter2" width="120" sortable />
<el-table-column :label="t('EquipmentManagement.TaskManagement.endDate')" align="center" prop="endDate" :formatter="dateFormatter2" width="120" sortable />
<el-table-column :label="t('EquipmentManagement.TaskManagement.cronExpression')" align="center" prop="cronExpression" min-width="180" />
<!-- <el-table-column :label="t('EquipmentManagement.TaskManagement.startDate')" align="center" prop="startDate" :formatter="dateFormatter2" width="120" sortable /> -->
<el-table-column :label="t('EquipmentManagement.TaskManagement.planEndDate')" align="center" prop="endDate" :formatter="dateFormatter2" width="150" sortable />
<!-- <el-table-column :label="t('EquipmentManagement.TaskManagement.cronExpression')" align="center" prop="cronExpression" min-width="180" /> -->
<el-table-column :label="t('EquipmentManagement.TaskManagement.enabled')" align="center" prop="enabled" width="90">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />

@ -53,7 +53,11 @@ v-else-if="scope.row.images" :src="parseFirstImage(scope.row.images)"
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.TicketResultDialog.remark')" align="center" prop="remark" min-width="180" />
<el-table-column :label="t('MoldManagement.TicketResultDialog.remark')" align="center" prop="remark" min-width="180">
<template #default="scope">
<el-input v-model="scope.row.remark" clearable :placeholder="t('common.inputText')" />
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.TicketResultDialog.operate')" align="center" min-width="220" fixed="right">
<template #default="scope">
<el-radio-group v-if="String(scope.row.inspectionResult) === '0'" v-model="decisionMap[String(scope.row.id)]">

Loading…
Cancel
Save