feat(mes): 重构装箱单及装箱明细相关功能

- 移除不必要的仓库、库区和库位字段
- 更新接口名称为 addChildPackage 和 removeChildPackage
- 添加可添加为子箱的装箱单精简列表接口
- 优化相关逻辑,确保代码整洁和可维护性
pull/871/MERGE
YunaiV 2026-03-08 12:04:46 +08:00
parent 61d710bc8e
commit 76ee59b868
7 changed files with 80 additions and 206 deletions

View File

@ -1,8 +1,7 @@
import request from '@/config/axios'
// 装箱单响应 VO
// TODO @AIVO 改成 WmPackageVO
export interface WmPackageRespVO {
// 装箱单 VO
export interface WmPackageVO {
id: number
code: string
parentId?: number
@ -32,12 +31,12 @@ export interface WmPackageRespVO {
// 装箱单 API
export const WmPackageApi = {
// 创建装箱单
createPackage: async (data: WmPackageRespVO) => {
createPackage: async (data: WmPackageVO) => {
return await request.post({ url: '/mes/wm/package/create', data })
},
// 修改装箱单
updatePackage: async (data: WmPackageRespVO) => {
updatePackage: async (data: WmPackageVO) => {
return await request.put({ url: '/mes/wm/package/update', data })
},
@ -48,7 +47,7 @@ export const WmPackageApi = {
// 获取装箱单详情
getPackage: async (id: number) => {
return await request.get<WmPackageRespVO>({ url: '/mes/wm/package/get?id=' + id })
return await request.get<WmPackageVO>({ url: '/mes/wm/package/get?id=' + id })
},
// 分页查询装箱单
@ -62,20 +61,17 @@ export const WmPackageApi = {
},
// 添加子箱
// TODO @AIaddChildPackage且接口地址改成 /mes/wm/package/add-child-package
addSubPackage: async (parentId: number, childId: number) => {
return await request.put({ url: '/mes/wm/package/add-sub-package', params: { parentId, childId } })
addChildPackage: async (parentId: number, childId: number) => {
return await request.put({ url: '/mes/wm/package/add-child-package', params: { parentId, childId } })
},
// 移除子箱
// TODO @AIremoveChildPackage且接口地址改成 /mes/wm/package/remove-child-package
removeSubPackage: async (childId: number) => {
return await request.put({ url: '/mes/wm/package/remove-sub-package?childId=' + childId })
removeChildPackage: async (childId: number) => {
return await request.put({ url: '/mes/wm/package/remove-child-package?childId=' + childId })
},
// 获取装箱单精简列表(无父箱 + 已完成状态,用于选择父箱)
// TODO @AI改成 getChildablePackageSimpleList且接口地址改成 /mes/wm/package/childable-simple-list注释改成 可添加为子箱的装箱单精简列表(无父箱 + 已完成状态,用于选择父箱)
getPackageSimpleList: async () => {
return await request.get<WmPackageRespVO[]>({ url: '/mes/wm/package/simple-list' })
// 可添加为子箱的装箱单精简列表(无父箱 + 已完成状态,用于选择父箱)
getChildablePackageSimpleList: async () => {
return await request.get<WmPackageVO[]>({ url: '/mes/wm/package/childable-simple-list' })
}
}

View File

@ -1,30 +1,10 @@
import request from '@/config/axios'
// ==================== 装箱明细 ====================
// 装箱明细保存请求 VO
// TODO @AI不要 save直接用 WmPackageLineRespVO
export interface WmPackageLineSaveReqVO {
export interface WmPackageLineVO {
id?: number
packageId: number
materialStockId?: number
itemId: number
quantity: number
workOrderId?: number
warehouseId?: number
locationId?: number
areaId?: number
expireDate?: number
remark?: string
}
// 装箱明细响应 VO
// TODO @AIVO 改成 WmPackageLineVO
export interface WmPackageLineRespVO {
id: number
packageId: number
materialStockId?: number
itemId: number
itemCode?: string
itemName?: string
specification?: string
@ -33,26 +13,20 @@ export interface WmPackageLineRespVO {
workOrderId?: number
workOrderCode?: string
batchCode?: string
warehouseId?: number
warehouseName?: string
locationId?: number
locationName?: string
areaId?: number
areaName?: string
expireDate?: number
remark?: string
createTime: string
createTime?: string
}
// 装箱明细 API
export const WmPackageLineApi = {
// 创建装箱明细
createPackageLine: async (data: WmPackageLineSaveReqVO) => {
createPackageLine: async (data: WmPackageLineVO) => {
return await request.post({ url: '/mes/wm/package-line/create', data })
},
// 修改装箱明细
updatePackageLine: async (data: WmPackageLineSaveReqVO) => {
updatePackageLine: async (data: WmPackageLineVO) => {
return await request.put({ url: '/mes/wm/package-line/update', data })
},
@ -63,17 +37,12 @@ export const WmPackageLineApi = {
// 获取装箱明细详情
getPackageLine: async (id: number) => {
return await request.get<WmPackageLineRespVO>({ url: '/mes/wm/package-line/get?id=' + id })
return await request.get<WmPackageLineVO>({ url: '/mes/wm/package-line/get?id=' + id })
},
// 分页查询装箱明细
getPackageLinePage: async (params: any) => {
return await request.get({ url: '/mes/wm/package-line/page', params })
},
// 根据装箱单 ID 获取明细列表
// TODO @AI这个接口不需要是不是前后端都删除掉
getPackageLineListByPackageId: async (packageId: number) => {
return await request.get({ url: '/mes/wm/package-line/list-by-package-id', params: { packageId } })
}
// DONE @AI这个接口不需要是不是前后端都删除掉
}

View File

@ -31,14 +31,9 @@
/>
</el-form-item>
</el-col>
<!-- TODO @AI不需要父箱这里要不把检查员挪上来 -->
<el-col :span="8">
<el-form-item label="父箱" prop="parentId">
<WmPackageSelect
v-model="formData.parentId"
:disabled="isDetail"
:exclude-id="formData.id"
/>
<el-form-item label="检查员" prop="inspectorUserId">
<UserSelect v-model="formData.inspectorUserId" :disabled="isDetail" />
</el-form-item>
</el-col>
</el-row>
@ -128,13 +123,6 @@
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="检查员" prop="inspectorUserId">
<UserSelect v-model="formData.inspectorUserId" :disabled="isDetail" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
@ -165,24 +153,21 @@
<script setup lang="ts">
import { generateRandomStr } from '@/utils'
import { WmPackageApi, WmPackageRespVO } from '@/api/mes/wm/packages'
import { WmPackageApi, WmPackageVO } from '@/api/mes/wm/packages'
import MdClientSelect from '@/views/mes/md/client/components/MdClientSelect.vue'
import MdUnitMeasureSelect from '@/views/mes/md/unitmeasure/components/MdUnitMeasureSelect.vue'
import UserSelect from '@/views/system/user/components/UserSelect.vue'
import WmPackageSelect from './components/WmPackageSelect.vue'
import SubPackageList from './SubPackageList.vue'
import PackageLineList from './PackageLineList.vue'
// TODO @AI /Users/yunai/Java/yudao-all-in-one/yudao-ui-admin-vue3/src/views/system/user/UserForm.vue
defineOptions({ name: 'PackageForm' })
const { t } = useI18n()
const message = useMessage()
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false)
const formLoading = ref(false)
const formType = ref('')
const dialogVisible = ref(false) //
const formLoading = ref(false) //
const formType = ref('') // create - update - detail -
const isDetail = computed(() => formType.value === 'detail')
const dialogTitle = computed(() => {
const titles: Record<string, string> = {
@ -196,7 +181,6 @@ const activeTab = ref('subPackage')
const formData = ref({
id: undefined as number | undefined,
code: undefined as string | undefined,
parentId: undefined as number | undefined,
packageDate: undefined as number | undefined,
salesOrderCode: undefined as string | undefined,
invoiceCode: undefined as string | undefined,
@ -218,6 +202,7 @@ const formRules = reactive({
const formRef = ref()
/** 生成装箱单编号 */
// TODO @ code
const generateCode = () => {
formData.value.code = 'PKG' + generateRandomStr(10)
}
@ -245,7 +230,7 @@ const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
try {
const data = formData.value as unknown as WmPackageRespVO
const data = formData.value as unknown as WmPackageVO
if (formType.value === 'create') {
const res = await WmPackageApi.createPackage(data)
message.success(t('common.createSuccess'))
@ -268,7 +253,6 @@ const resetForm = () => {
formData.value = {
id: undefined,
code: undefined,
parentId: undefined,
packageDate: undefined,
salesOrderCode: undefined,
invoiceCode: undefined,

View File

@ -11,7 +11,7 @@
<el-table-column label="单位" align="center" prop="unitMeasureName" width="80" />
<el-table-column label="装箱数量" align="center" prop="quantity" width="100" />
<el-table-column label="生产工单编号" align="center" prop="workOrderCode" min-width="140" />
<!-- TODO @芋艿批次号到底怎么设置好 -->
<!-- DONE @芋艿批次号到底怎么设置好AI 未修复原因需产品经理确认批次号的设置方式 -->
<el-table-column label="批次号" align="center" prop="batchCode" min-width="120" />
<el-table-column
label="有效期"
@ -20,10 +20,6 @@
:formatter="dateFormatter2"
width="120"
/>
<!-- TODO @AI去掉 warehouseNamelocationNameareaName 字段前端后端都是表单也是没用 -->
<el-table-column label="仓库" align="center" prop="warehouseName" min-width="100" />
<el-table-column label="库区" align="center" prop="locationName" min-width="100" />
<el-table-column label="库位" align="center" prop="areaName" min-width="100" />
<el-table-column v-if="isEditable" label="操作" align="center" width="120">
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row.id)">编辑</el-button>
@ -54,9 +50,10 @@
<ProWorkOrderSelect v-model="formData.workOrderId" @change="handleWorkOrderChange" />
</el-form-item>
</el-col>
<!-- DONE @AI只展示一个只读的物料选择器然后 handleWorkOrderChange 选择后去设置就 ok 前端只传递 itemId -->
<el-col :span="8">
<el-form-item label="批次号" prop="batchCode">
<el-input v-model="formData.batchCode" disabled placeholder="自动填充" />
<el-form-item label="产品物料" prop="itemId">
<MdItemSelect v-model="formData.itemId" disabled placeholder="选择工单后自动填充" />
</el-form-item>
</el-col>
<el-col :span="8">
@ -71,57 +68,7 @@
</el-form-item>
</el-col>
</el-row>
<!-- TODO @AI只展示一个只读的物料选择器然后 handleWorkOrderChange 选择后去设置就 ok 前端只传递 itemId -->
<el-row>
<el-col :span="8">
<el-form-item label="产品物料编码">
<el-input v-model="formData.itemCode" disabled placeholder="自动填充" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="产品物料名称">
<el-input v-model="formData.itemName" disabled placeholder="自动填充" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="单位">
<el-input v-model="formData.unitMeasureName" disabled placeholder="自动填充" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="规格型号">
<el-input
v-model="formData.specification"
type="textarea"
disabled
placeholder="自动填充"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="仓库" prop="warehouseId">
<WmWarehouseSelect v-model="formData.warehouseId" @change="handleWarehouseChange" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="库区" prop="locationId">
<WmWarehouseLocationSelect
v-model="formData.locationId"
:warehouse-id="formData.warehouseId"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="库位" prop="areaId">
<WmWarehouseAreaSelect v-model="formData.areaId" :warehouse-id="formData.warehouseId" />
</el-form-item>
</el-col>
</el-row>
<!-- TODO @芋艿批次号到底怎么设置好 -->
<!-- DONE @芋艿批次号到底怎么设置好AI 未修复原因需产品经理确认批次号的设置方式 -->
<el-row>
<el-col :span="8">
<el-form-item label="有效期" prop="expireDate">
@ -152,15 +99,9 @@
<script setup lang="ts">
import { dateFormatter2 } from '@/utils/formatTime'
import {
WmPackageLineApi,
WmPackageLineRespVO,
WmPackageLineSaveReqVO
} from '@/api/mes/wm/packages/line'
import { WmPackageLineApi, WmPackageLineVO } from '@/api/mes/wm/packages/line'
import ProWorkOrderSelect from '@/views/mes/pro/workorder/components/ProWorkOrderSelect.vue'
import WmWarehouseSelect from '@/views/mes/wm/warehouse/components/WmWarehouseSelect.vue'
import WmWarehouseLocationSelect from '@/views/mes/wm/warehouse/components/WmWarehouseLocationSelect.vue'
import WmWarehouseAreaSelect from '@/views/mes/wm/warehouse/components/WmWarehouseAreaSelect.vue'
import MdItemSelect from '@/views/mes/md/item/components/MdItemSelect.vue'
defineOptions({ name: 'PackageLineList' })
@ -169,14 +110,14 @@ const props = defineProps<{
formType: string
}>()
const { t } = useI18n()
const message = useMessage()
const { t } = useI18n() //
const message = useMessage() //
const isEditable = computed(() => ['create', 'update'].includes(props.formType))
// ==================== ====================
const loading = ref(false)
const list = ref<WmPackageLineRespVO[]>([])
const list = ref<WmPackageLineVO[]>([])
const total = ref(0)
const queryParams = reactive({
pageNo: 1,
@ -217,16 +158,8 @@ const formData = ref({
packageId: undefined as number | undefined,
materialStockId: undefined as number | undefined,
itemId: undefined as number | undefined,
itemCode: undefined as string | undefined,
itemName: undefined as string | undefined,
specification: undefined as string | undefined,
unitMeasureName: undefined as string | undefined,
quantity: undefined as number | undefined,
workOrderId: undefined as number | undefined,
batchCode: undefined as string | undefined,
warehouseId: undefined as number | undefined,
locationId: undefined as number | undefined,
areaId: undefined as number | undefined,
expireDate: undefined as number | undefined,
remark: undefined as string | undefined
})
@ -239,30 +172,16 @@ const formRules = reactive({
})
const formRef = ref()
/** 生产工单变化时,自动填充产品信息 */
/** 生产工单变化时,自动填充产品物料 */
// TODO @AIitemId workorder itemId bom
const handleWorkOrderChange = (workOrder: any) => {
if (workOrder) {
formData.value.itemId = workOrder.itemId
formData.value.itemCode = workOrder.itemCode
formData.value.itemName = workOrder.itemName
formData.value.specification = workOrder.specification
formData.value.unitMeasureName = workOrder.unitName
formData.value.batchCode = workOrder.batchCode
} else {
formData.value.itemId = undefined
formData.value.itemCode = undefined
formData.value.itemName = undefined
formData.value.specification = undefined
formData.value.unitMeasureName = undefined
formData.value.batchCode = undefined
}
}
/** 仓库变化时,清空库区库位 */
const handleWarehouseChange = () => {
// WmWarehouseLocationSelect WmWarehouseAreaSelect watch warehouseId
}
/** 打开表单弹窗 */
const openForm = async (type: string, id?: number) => {
dialogVisible.value = true
@ -272,6 +191,7 @@ const openForm = async (type: string, id?: number) => {
if (id) {
formLoading.value = true
try {
// TODO @AIlinter
formData.value = await WmPackageLineApi.getPackageLine(id)
} finally {
formLoading.value = false
@ -287,7 +207,7 @@ const submitForm = async () => {
const data = {
...formData.value,
packageId: props.packageId
} as unknown as WmPackageLineSaveReqVO
} as unknown as WmPackageLineVO
if (lineFormType.value === 'create') {
await WmPackageLineApi.createPackageLine(data)
message.success(t('common.createSuccess'))
@ -309,16 +229,8 @@ const resetForm = () => {
packageId: undefined,
materialStockId: undefined,
itemId: undefined,
itemCode: undefined,
itemName: undefined,
specification: undefined,
unitMeasureName: undefined,
quantity: undefined,
workOrderId: undefined,
batchCode: undefined,
warehouseId: undefined,
locationId: undefined,
areaId: undefined,
expireDate: undefined,
remark: undefined
}

View File

@ -5,8 +5,7 @@
<Icon icon="ep:plus" class="mr-5px" /> 添加子箱
</el-button>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" border>
<!-- TODO @AI参考 /Users/yunai/Java/yudao-all-in-one/yudao-ui-admin-vue3/src/views/mes/wm/packages/index.vue 列表只是没树筛选 -->
<el-table-column label="装箱单编号" align="center" prop="code" min-width="160">
<el-table-column label="装箱单编号" align="center" prop="code" min-width="160" fixed="left">
<template #default="scope">
<el-link type="primary" @click="handleView(scope.row.id)">
{{ scope.row.code }}
@ -20,7 +19,18 @@
:formatter="dateFormatter2"
width="120"
/>
<el-table-column label="销售订单编号" align="center" prop="salesOrderCode" min-width="140" />
<el-table-column label="发票编号" align="center" prop="invoiceCode" min-width="120" />
<el-table-column label="客户编码" align="center" prop="clientCode" min-width="100" />
<el-table-column label="客户名称" align="center" prop="clientName" min-width="120" />
<el-table-column label="箱长度" align="center" prop="length" width="80" />
<el-table-column label="箱宽度" align="center" prop="width" width="80" />
<el-table-column label="箱高度" align="center" prop="height" width="80" />
<el-table-column label="尺寸单位" align="center" prop="sizeUnitName" width="90" />
<el-table-column label="净重" align="center" prop="netWeight" width="80" />
<el-table-column label="毛重" align="center" prop="grossWeight" width="80" />
<el-table-column label="重量单位" align="center" prop="weightUnitName" width="90" />
<el-table-column label="检查员" align="center" prop="inspectorName" min-width="100" />
<el-table-column label="单据状态" align="center" prop="status" min-width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.MES_WM_PACKAGE_STATUS" :value="scope.row.status" />
@ -68,7 +78,7 @@
<script setup lang="ts">
import { dateFormatter2 } from '@/utils/formatTime'
import { DICT_TYPE } from '@/utils/dict'
import { WmPackageApi, WmPackageRespVO } from '@/api/mes/wm/packages'
import { WmPackageApi, WmPackageVO } from '@/api/mes/wm/packages'
import { MesWmPackageStatusEnum } from '@/views/mes/utils/constants'
import WmPackageSelect from './components/WmPackageSelect.vue'
@ -86,13 +96,14 @@ const isEditable = computed(() => ['create', 'update'].includes(props.formType))
// ==================== ====================
const loading = ref(false)
const list = ref<WmPackageRespVO[]>([])
const list = ref<WmPackageVO[]>([])
/** 查询子箱列表 */
const getList = async () => {
loading.value = true
try {
// parentId
// TODO @AI使
const data = await WmPackageApi.getPackagePage({
pageNo: 1,
pageSize: 100,
@ -107,15 +118,15 @@ const getList = async () => {
/** 查看子箱详情(打开新弹窗) */
const handleView = (id: number) => {
//
// TODO @AI
window.open(`/mes/wm/packages?id=${id}`, '_blank')
}
/** 移除子箱:将子箱的 parentId 清空 */
const handleRemoveChild = async (childId: number) => {
try {
// DONE @AI delete subpackage childId
await message.confirm('确认将该装箱单从子箱列表中移除?')
await WmPackageApi.removeSubPackage(childId)
await WmPackageApi.removeChildPackage(childId)
message.success('移除成功')
await getList()
} catch {}
@ -144,8 +155,7 @@ const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
try {
// DONE @AI add subpackage
await WmPackageApi.addSubPackage(props.packageId, formData.value.childId!)
await WmPackageApi.addChildPackage(props.packageId, formData.value.childId!)
message.success(t('common.createSuccess'))
dialogVisible.value = false
await getList()

View File

@ -27,7 +27,7 @@
</template>
<script setup lang="ts">
import { WmPackageApi, WmPackageRespVO } from '@/api/mes/wm/packages'
import { WmPackageApi, WmPackageVO } from '@/api/mes/wm/packages'
defineOptions({ name: 'WmPackageSelect' })
@ -48,11 +48,11 @@ const props = withDefaults(
const emit = defineEmits<{
'update:modelValue': [value: number | undefined]
change: [item: WmPackageRespVO | undefined]
}>()
change: [item: WmPackageVO | undefined]
}>()
const allList = ref<WmPackageRespVO[]>([])
const filteredList = ref<WmPackageRespVO[]>([])
const allList = ref<WmPackageVO[]>([])
const filteredList = ref<WmPackageVO[]>([])
const selectValue = computed({
get: () => props.modelValue,
@ -90,7 +90,7 @@ const handleChange = (val: number | undefined) => {
/** 加载装箱单列表(无父箱 + 已完成状态) */
const loadList = async () => {
const data = await WmPackageApi.getPackageSimpleList()
const data = await WmPackageApi.getChildablePackageSimpleList()
allList.value = Array.isArray(data) ? data : []
filteredList.value = getAvailableList()
}

View File

@ -56,8 +56,7 @@
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
default-expand-all
>
<!-- TODO @AI编号需要 fixed可以一直被看到这个列表太长了 -->
<el-table-column label="装箱单编号" align="center" prop="code" min-width="160">
<el-table-column label="装箱单编号" align="center" prop="code" min-width="250" fixed="left">
<template #default="scope">
<el-link type="primary" @click="openForm('detail', scope.row.id)">
{{ scope.row.code }}
@ -135,22 +134,20 @@
import { dateFormatter2 } from '@/utils/formatTime'
import { DICT_TYPE } from '@/utils/dict'
import { handleTree } from '@/utils/tree'
import { WmPackageApi, WmPackageRespVO } from '@/api/mes/wm/packages'
import { WmPackageApi, WmPackageVO } from '@/api/mes/wm/packages'
import MdClientSelect from '@/views/mes/md/client/components/MdClientSelect.vue'
import UserSelect from '@/views/system/user/components/UserSelect.vue'
import PackageForm from './PackageForm.vue'
import { MesWmPackageStatusEnum } from '@/views/mes/utils/constants'
// TODO @AI /Users/yunai/Java/yudao-all-in-one/yudao-ui-admin-vue3/src/views/system/user/index.vue
defineOptions({ name: 'MesWmPackages' })
const message = useMessage()
const { t } = useI18n()
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true)
const list = ref<WmPackageRespVO[]>([])
const total = ref(0)
const loading = ref(true) //
const list = ref<WmPackageVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
@ -159,7 +156,7 @@ const queryParams = reactive({
clientId: undefined,
inspectorUserId: undefined
})
const queryFormRef = ref()
const queryFormRef = ref() //
/** 查询列表 */
const getList = async () => {
@ -194,9 +191,12 @@ const openForm = (type: string, id?: number) => {
/** 完成 */
const handleFinish = async (id: number) => {
try {
//
await message.confirm('确认完成该装箱单?完成后将不可编辑。')
//
await WmPackageApi.finishPackage(id)
message.success('完成成功')
//
await getList()
} catch {}
}
@ -204,9 +204,12 @@ const handleFinish = async (id: number) => {
/** 删除 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await WmPackageApi.deletePackage(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}