feat:盘点执行/托盘管理模块

main
黄伟杰 1 month ago
parent a536ee7603
commit 68c61dbf81

@ -26,8 +26,8 @@ export const PalletApi = {
return await request.get({ url: `/erp/pallet/page`, params }) return await request.get({ url: `/erp/pallet/page`, params })
}, },
createPallet: async (params: PalletVO) => { createPallet: async (data: PalletVO) => {
return await request.post({ url: `/erp/pallet/create`, params }) return await request.post({ url: `/erp/pallet/create`, data })
}, },
updatePallet: async (params: PalletVO) => { updatePallet: async (params: PalletVO) => {

@ -597,6 +597,7 @@
validatorSelectCheckItem: 'Please select check item', validatorSelectCheckItem: 'Please select check item',
validatorAuditUserRequired: 'Please select auditor', validatorAuditUserRequired: 'Please select auditor',
validatorCompleteCheckInfo: 'Please complete check information first', validatorCompleteCheckInfo: 'Please complete check information first',
confirmActualCountZero: ' actual count is 0. Confirm submit?',
confirmApprove: 'Are you sure to approve this check order?', confirmApprove: 'Are you sure to approve this check order?',
confirmReverseApprove: 'Are you sure to reverse approve this check order?', confirmReverseApprove: 'Are you sure to reverse approve this check order?',
submitSuccess: 'Submit success', submitSuccess: 'Submit success',
@ -729,13 +730,18 @@
productCount: 'Product Quantity', productCount: 'Product Quantity',
qrcode: 'QR Code', qrcode: 'QR Code',
viewQrcode: 'View QR Code', viewQrcode: 'View QR Code',
qrcodeEmpty: 'No QR code',
qrcodeRefreshConfirm: 'Confirm to refresh this pallet QR code?',
purchaseDate: 'Purchase Date', purchaseDate: 'Purchase Date',
useDate: 'Use Date', useDate: 'Use Date',
remark: 'Remark', remark: 'Remark',
createTime: 'Create Time', createTime: 'Create Time',
placeholderCode: 'Please enter pallet code', placeholderCode: 'Please enter pallet code',
placeholderPalletType: 'Please enter pallet type', placeholderPalletType: 'Please enter pallet type',
placeholderSpecification: 'Please select pallet specification', placeholderSpecification: 'Please enter pallet specification',
placeholderLength: 'Length',
placeholderWidth: 'Width',
placeholderHeight: 'Height',
placeholderRatedLoadWeight: 'Please enter rated load', placeholderRatedLoadWeight: 'Please enter rated load',
placeholderUnit: 'Please enter unit', placeholderUnit: 'Please enter unit',
placeholderStatus: 'Please select pallet status', placeholderStatus: 'Please select pallet status',
@ -744,7 +750,6 @@
placeholderPlanCode: 'Please enter production task no.', placeholderPlanCode: 'Please enter production task no.',
placeholderProductId: 'Please select product', placeholderProductId: 'Please select product',
placeholderProductCount: 'Please enter product quantity', placeholderProductCount: 'Please enter product quantity',
placeholderQrcode: 'Please enter QR code URL',
placeholderPurchaseDate: 'Please select purchase date', placeholderPurchaseDate: 'Please select purchase date',
placeholderUseDate: 'Please select use date', placeholderUseDate: 'Please select use date',
placeholderRemark: 'Please enter remark', placeholderRemark: 'Please enter remark',

@ -597,6 +597,7 @@
validatorSelectCheckItem: '请选择盘点项', validatorSelectCheckItem: '请选择盘点项',
validatorAuditUserRequired: '请选择审核人', validatorAuditUserRequired: '请选择审核人',
validatorCompleteCheckInfo: '请先完善盘点信息', validatorCompleteCheckInfo: '请先完善盘点信息',
confirmActualCountZero: '实盘数量为0确认提交吗',
confirmApprove: '确定审批该盘点单吗?', confirmApprove: '确定审批该盘点单吗?',
confirmReverseApprove: '确定反审批该盘点单吗?', confirmReverseApprove: '确定反审批该盘点单吗?',
submitSuccess: '提交成功', submitSuccess: '提交成功',
@ -729,13 +730,18 @@
productCount: '产品数量', productCount: '产品数量',
qrcode: '二维码', qrcode: '二维码',
viewQrcode: '查看二维码', viewQrcode: '查看二维码',
qrcodeEmpty: '暂无二维码',
qrcodeRefreshConfirm: '确认刷新该托盘二维码吗?',
purchaseDate: '采购日期', purchaseDate: '采购日期',
useDate: '启用日期', useDate: '启用日期',
remark: '备注', remark: '备注',
createTime: '创建时间', createTime: '创建时间',
placeholderCode: '请输入托盘编码', placeholderCode: '请输入托盘编码',
placeholderPalletType: '请输入托盘类型', placeholderPalletType: '请输入托盘类型',
placeholderSpecification: '请选择托盘规格', placeholderSpecification: '请输入托盘规格',
placeholderLength: '长',
placeholderWidth: '宽',
placeholderHeight: '高',
placeholderRatedLoadWeight: '请输入额定载重', placeholderRatedLoadWeight: '请输入额定载重',
placeholderUnit: '请输入单位', placeholderUnit: '请输入单位',
placeholderStatus: '请选择托盘状态', placeholderStatus: '请选择托盘状态',
@ -744,7 +750,6 @@
placeholderPlanCode: '请输入生产任务单号', placeholderPlanCode: '请输入生产任务单号',
placeholderProductId: '请选择产品', placeholderProductId: '请选择产品',
placeholderProductCount: '请输入产品数量', placeholderProductCount: '请输入产品数量',
placeholderQrcode: '请输入二维码地址',
placeholderPurchaseDate: '请选择采购日期', placeholderPurchaseDate: '请选择采购日期',
placeholderUseDate: '请选择投入使用日期', placeholderUseDate: '请选择投入使用日期',
placeholderRemark: '请输入备注', placeholderRemark: '请输入备注',

@ -235,7 +235,6 @@ export enum DICT_TYPE {
WAREHOUSE_OUTBOUND_PURPOSE = 'warehouse_outbound_purpose', // 出库用途 WAREHOUSE_OUTBOUND_PURPOSE = 'warehouse_outbound_purpose', // 出库用途
STORAGE_PALLET_TYPES = 'storage_pallet_types', // 仓储托盘类型 STORAGE_PALLET_TYPES = 'storage_pallet_types', // 仓储托盘类型
STORAGE_PALLET_STATUS = 'storage_pallet_status', // 仓储托盘状态 STORAGE_PALLET_STATUS = 'storage_pallet_status', // 仓储托盘状态
STORAGE_PALLET_SPECIFICATIONS = 'storage_pallet_specifications', // 仓储托盘规格
SUBMOLD_TYPE = 'submold_type', // 子模具类型 SUBMOLD_TYPE = 'submold_type', // 子模具类型
ERP_MAINTAIN_TYPE = 'maintain_type',// ERP 保养类型 ERP_MAINTAIN_TYPE = 'maintain_type',// ERP 保养类型

@ -354,6 +354,8 @@ const isActualCountEmpty = (value: unknown) => value === undefined || value ===
const hasIncompleteActualCount = computed(() => const hasIncompleteActualCount = computed(() =>
(formData.value.items || []).some((item) => isActualCountEmpty(item.actualCount)) (formData.value.items || []).some((item) => isActualCountEmpty(item.actualCount))
) )
const getCheckItemName = (item: StockCheckItemVO) =>
item.productBarCode || item.productName || `${t('ErpStock.Check.checkItem')}${item.id ? `-${item.id}` : ''}`
const selectedWarehouses = ref<WarehouseVO[]>([]) const selectedWarehouses = ref<WarehouseVO[]>([])
const selectedAreas = ref<WarehouseAreaVO[]>([]) const selectedAreas = ref<WarehouseAreaVO[]>([])
@ -811,6 +813,13 @@ const submitForm = async (checkStatus?: 0 | 1) => {
message.warning(t('ErpStock.Check.validatorCompleteCheckInfo')) message.warning(t('ErpStock.Check.validatorCompleteCheckInfo'))
return return
} }
if (checkStatus === 1) {
const zeroCountItems = (formData.value.items || []).filter((item) => Number(item.actualCount) === 0)
if (zeroCountItems.length > 0) {
const itemNames = zeroCountItems.map((item) => getCheckItemName(item)).join('、')
await message.confirm(`${itemNames}${t('ErpStock.Check.confirmActualCountZero')}`)
}
}
if (isInventoryCheck.value) { if (isInventoryCheck.value) {
formData.value.checkStatus = checkStatus formData.value.checkStatus = checkStatus
formData.value.items.forEach((item) => { formData.value.items.forEach((item) => {

@ -46,19 +46,31 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('ErpStock.Pallet.specification')" prop="specification"> <el-form-item :label="t('ErpStock.Pallet.specification')" prop="specification">
<el-select <div class="pallet-spec-input">
v-model="formData.specification" <el-input-number
:placeholder="t('ErpStock.Pallet.placeholderSpecification')" v-model="specificationParts.length"
clearable :min="0"
class="!w-1/1" :precision="0"
> :controls="false"
<el-option :placeholder="t('ErpStock.Pallet.placeholderLength')"
v-for="dict in getStrDictOptions(DICT_TYPE.STORAGE_PALLET_SPECIFICATIONS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/> />
</el-select> <span>x</span>
<el-input-number
v-model="specificationParts.width"
:min="0"
:precision="0"
:controls="false"
:placeholder="t('ErpStock.Pallet.placeholderWidth')"
/>
<span>x</span>
<el-input-number
v-model="specificationParts.height"
:min="0"
:precision="0"
:controls="false"
:placeholder="t('ErpStock.Pallet.placeholderHeight')"
/>
</div>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@ -95,37 +107,20 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('ErpStock.Pallet.warehouseId')" prop="warehouseId"> <el-form-item :label="t('ErpStock.Pallet.warehouseId')" prop="warehouseId">
<el-select <el-input :model-value="selectedWarehouseText" readonly :placeholder="t('ErpStock.Pallet.placeholderWarehouseId')">
v-model="formData.warehouseId" <template #append>
:placeholder="t('ErpStock.Pallet.placeholderWarehouseId')" <el-button @click="openWarehouseDialog">{{ t('common.select') }}</el-button>
clearable </template>
class="!w-1/1" </el-input>
@change="handleWarehouseChange"
>
<el-option
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('ErpStock.Pallet.areaId')" prop="areaId"> <el-form-item :label="t('ErpStock.Pallet.areaId')" prop="areaId">
<el-select <el-input :model-value="selectedAreaText" readonly :placeholder="t('ErpStock.Pallet.placeholderAreaId')">
v-model="formData.areaId" <template #append>
:placeholder="t('ErpStock.Pallet.placeholderAreaId')" <el-button @click="openAreaDialog">{{ t('common.select') }}</el-button>
clearable </template>
class="!w-1/1" </el-input>
>
<el-option
v-for="item in filteredAreaList"
:key="item.id"
:label="item.areaName"
:value="item.id"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@ -184,9 +179,19 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col v-if="formType === 'update'" :span="24">
<el-form-item :label="t('ErpStock.Pallet.qrcode')" prop="qrcode"> <el-form-item :label="t('ErpStock.Pallet.qrcode')" prop="qrcode">
<el-input v-model="formData.qrcode" :placeholder="t('ErpStock.Pallet.placeholderQrcode')" /> <QrcodeActionCard
:image-url="formData.qrcode"
:print-id="formData.id"
:print-title="`${formData.code || t('ErpStock.Pallet.code')}二维码打印预览`"
:empty-text="t('ErpStock.Pallet.qrcodeEmpty')"
:refresh-url="getQrcodeRefreshUrl()"
:refresh-disabled="!formData.id || !formData.code"
:refresh-confirm-text="t('ErpStock.Pallet.qrcodeRefreshConfirm')"
:print-data="buildPrintData()"
@refresh-success="handleQrcodeRefreshSuccess"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
@ -205,14 +210,156 @@
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button> <el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template> </template>
</Dialog> </Dialog>
<Dialog :title="t('ErpStock.Check.selectWarehouseDialogTitle')" v-model="warehouseDialogVisible" width="1000px">
<el-form :model="warehouseQueryParams" :inline="true" label-width="auto" class="-mb-15px">
<el-form-item :label="t('ErpStock.Warehouse.name')">
<el-input
v-model="warehouseQueryParams.name"
clearable
:placeholder="t('ErpStock.Warehouse.placeholderName')"
class="!w-240px"
@keyup.enter="handleWarehouseQuery"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleWarehouseQuery">
<Icon icon="ep:search" class="mr-5px" />{{ t('common.query') }}
</el-button>
<el-button @click="resetWarehouseQuery">
<Icon icon="ep:refresh" class="mr-5px" />{{ t('common.reset') }}
</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="warehouseLoading"
:data="warehouseTableList"
row-key="id"
highlight-current-row
@row-click="handleWarehouseRowClick"
>
<el-table-column align="center" width="55">
<template #default="scope">
<el-radio
:model-value="warehouseSelection?.id"
:value="scope.row.id"
@change="handleWarehouseRowClick(scope.row)"
/>
</template>
</el-table-column>
<el-table-column :label="t('ErpStock.Warehouse.name')" align="center" prop="name" min-width="160" sortable />
<el-table-column :label="t('ErpStock.Warehouse.categoryType')" align="center" prop="categoryType" min-width="120">
<template #default="scope">
<dict-tag :type="DICT_TYPE.MATERIAL_CLASSIFICATION_TYPE" :value="scope.row.categoryType" />
</template>
</el-table-column>
<el-table-column :label="t('ErpStock.Warehouse.address')" align="center" prop="address" min-width="180" show-overflow-tooltip />
<el-table-column :label="t('ErpStock.Warehouse.principal')" align="center" prop="principal" min-width="110" />
<el-table-column :label="t('ErpStock.Warehouse.status')" align="center" prop="status" min-width="100" 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.Warehouse.createTime')" align="center" prop="createTime" :formatter="dateFormatter" min-width="180" sortable />
</el-table>
<div class="pallet-dialog-pagination">
<Pagination
:total="warehouseTotal"
v-model:page="warehouseQueryParams.pageNo"
v-model:limit="warehouseQueryParams.pageSize"
@pagination="getWarehouseTableList"
/>
</div>
<template #footer>
<el-button type="primary" @click="confirmWarehouseSelection">{{ t('common.ok') }}</el-button>
<el-button @click="warehouseDialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
<Dialog :title="t('ErpStock.Check.selectAreaDialogTitle')" v-model="areaDialogVisible" width="1000px">
<el-form :model="areaQueryParams" :inline="true" label-width="auto" class="-mb-15px">
<el-form-item :label="t('ErpStock.WarehouseArea.areaCode')">
<el-input
v-model="areaQueryParams.areaCode"
clearable
:placeholder="t('ErpStock.WarehouseArea.placeholderAreaCode')"
class="!w-240px"
@keyup.enter="handleAreaQuery"
/>
</el-form-item>
<el-form-item :label="t('ErpStock.WarehouseArea.areaName')">
<el-input
v-model="areaQueryParams.areaName"
clearable
:placeholder="t('ErpStock.WarehouseArea.placeholderAreaName')"
class="!w-240px"
@keyup.enter="handleAreaQuery"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleAreaQuery">
<Icon icon="ep:search" class="mr-5px" />{{ t('common.query') }}
</el-button>
<el-button @click="resetAreaQuery">
<Icon icon="ep:refresh" class="mr-5px" />{{ t('common.reset') }}
</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="areaLoading"
:data="areaTableList"
row-key="id"
highlight-current-row
@row-click="handleAreaRowClick"
>
<el-table-column align="center" width="55">
<template #default="scope">
<el-radio
:model-value="areaSelection?.id"
:value="scope.row.id"
@change="handleAreaRowClick(scope.row)"
/>
</template>
</el-table-column>
<el-table-column :label="t('ErpStock.WarehouseArea.warehouseId')" align="center" prop="warehouseId" min-width="140" sortable>
<template #default="scope">
{{ getWarehouseName(scope.row.warehouseId) }}
</template>
</el-table-column>
<el-table-column :label="t('ErpStock.WarehouseArea.areaCode')" align="center" prop="areaCode" min-width="130" sortable />
<el-table-column :label="t('ErpStock.WarehouseArea.areaName')" align="center" prop="areaName" min-width="130" sortable />
<el-table-column :label="t('ErpStock.WarehouseArea.areaSize')" align="center" prop="areaSize" min-width="100" />
<el-table-column :label="t('ErpStock.WarehouseArea.description')" align="center" prop="description" min-width="160" show-overflow-tooltip />
<el-table-column :label="t('ErpStock.WarehouseArea.status')" align="center" prop="status" min-width="100" 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.WarehouseArea.createTime')" align="center" prop="createTime" :formatter="dateFormatter" min-width="180" sortable />
</el-table>
<div class="pallet-dialog-pagination">
<Pagination
:total="areaTotal"
v-model:page="areaQueryParams.pageNo"
v-model:limit="areaQueryParams.pageSize"
@pagination="getAreaTableList"
/>
</div>
<template #footer>
<el-button type="primary" @click="confirmAreaSelection">{{ t('common.ok') }}</el-button>
<el-button @click="areaDialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { PalletApi, PalletVO } from '@/api/erp/stock/pallet' import { PalletApi, PalletVO } from '@/api/erp/stock/pallet'
import { WarehouseApi } from '@/api/erp/stock/warehouse' import { dateFormatter } from '@/utils/formatTime'
import { WarehouseAreaApi } from '@/api/erp/stock/warehousearea' import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
import { WarehouseAreaApi, WarehouseAreaVO } from '@/api/erp/stock/warehousearea'
import { ProductApi, ProductVO } from '@/api/erp/product/product' import { ProductApi, ProductVO } from '@/api/erp/product/product'
import QrcodeActionCard from '@/components/QrcodeActionCard/index.vue'
defineOptions({ name: 'PalletForm' }) defineOptions({ name: 'PalletForm' })
@ -224,9 +371,34 @@ const dialogTitle = ref('')
const formLoading = ref(false) const formLoading = ref(false)
const formType = ref('') const formType = ref('')
const formRef = ref() const formRef = ref()
const warehouseList = ref<any[]>([]) const warehouseOptions = ref<WarehouseVO[]>([])
const areaList = ref<any[]>([]) const areaOptions = ref<WarehouseAreaVO[]>([])
const productList = ref<ProductVO[]>([]) const productList = ref<ProductVO[]>([])
const selectedWarehouse = ref<WarehouseVO | undefined>()
const selectedArea = ref<WarehouseAreaVO | undefined>()
const warehouseDialogVisible = ref(false)
const warehouseLoading = ref(false)
const warehouseTableList = ref<WarehouseVO[]>([])
const warehouseTotal = ref(0)
const warehouseSelection = ref<WarehouseVO | undefined>()
const warehouseQueryParams = reactive({
pageNo: 1,
pageSize: 10,
name: undefined as string | undefined
})
const areaDialogVisible = ref(false)
const areaLoading = ref(false)
const areaTableList = ref<WarehouseAreaVO[]>([])
const areaTotal = ref(0)
const areaSelection = ref<WarehouseAreaVO | undefined>()
const areaQueryParams = reactive({
pageNo: 1,
pageSize: 10,
areaCode: undefined as string | undefined,
areaName: undefined as string | undefined
})
const formData = ref<PalletVO>({ const formData = ref<PalletVO>({
code: undefined, code: undefined,
@ -246,12 +418,15 @@ const formData = ref<PalletVO>({
useDate: undefined, useDate: undefined,
remark: undefined remark: undefined
}) })
const specificationParts = reactive({
const filteredAreaList = computed(() => { length: undefined as number | undefined,
if (!formData.value.warehouseId) return areaList.value width: undefined as number | undefined,
return areaList.value.filter((item) => item.warehouseId === formData.value.warehouseId) height: undefined as number | undefined
}) })
const selectedWarehouseText = computed(() => selectedWarehouse.value?.name ?? '')
const selectedAreaText = computed(() => selectedArea.value?.areaName ?? '')
const validateCode = (_rule, value, callback) => { const validateCode = (_rule, value, callback) => {
if (Boolean(formData.value.isCode)) { if (Boolean(formData.value.isCode)) {
callback() callback()
@ -275,12 +450,14 @@ const open = async (type: string, row?: PalletVO) => {
dialogTitle.value = t('action.' + type) dialogTitle.value = t('action.' + type)
formType.value = type formType.value = type
resetForm() resetForm()
await Promise.all([getWarehouseList(), getAreaList(), getProductList()]) await Promise.all([getWarehouseOptions(), getAreaOptions(), getProductList()])
if (type === 'update' && row) { if (type === 'update' && row) {
formData.value = { formData.value = {
...row, ...row,
isCode: false isCode: false
} }
parseSpecification(row.specification)
await hydrateSelectedWarehouseArea()
} }
} }
defineExpose({ open }) defineExpose({ open })
@ -291,6 +468,8 @@ const submitForm = async () => {
formLoading.value = true formLoading.value = true
try { try {
const data = { ...formData.value } const data = { ...formData.value }
delete data.qrcode
data.specification = buildSpecification()
if (data.isCode) { if (data.isCode) {
data.code = undefined data.code = undefined
} }
@ -308,21 +487,173 @@ const submitForm = async () => {
} }
} }
const getWarehouseList = async () => { const getWarehouseOptions = async () => {
warehouseList.value = await WarehouseApi.getWarehouseSimpleList() warehouseOptions.value = await WarehouseApi.getWarehouseSimpleList()
} }
const getAreaList = async () => { const getAreaOptions = async () => {
const data = await WarehouseAreaApi.getWarehouseAreaPage({ pageNo: 1, pageSize: 100 }) const data = await WarehouseAreaApi.getWarehouseAreaPage({ pageNo: 1, pageSize: 100 })
areaList.value = data.list ?? [] areaOptions.value = data.list ?? []
} }
const getProductList = async () => { const getProductList = async () => {
productList.value = await ProductApi.getProductSimpleList() productList.value = await ProductApi.getProductSimpleList()
} }
const handleWarehouseChange = () => { const buildPrintData = () => {
return {
id: formData.value.id,
code: formData.value.code,
palletType: formData.value.palletType,
specification: buildSpecification() || formData.value.specification,
warehouseId: formData.value.warehouseId,
areaId: formData.value.areaId,
qrcodeUrl: formData.value.qrcode
}
}
const getQrcodeRefreshUrl = () => {
if (!formData.value.id || !formData.value.code) return ''
return `/erp/pallet/regenerate-code?id=${formData.value.id}&code=${encodeURIComponent(String(formData.value.code))}`
}
const handleQrcodeRefreshSuccess = (data: any) => {
const qrcode = data?.qrcode ?? data?.qrcodeUrl
if (qrcode) {
formData.value.qrcode = qrcode
}
}
const parseSpecification = (value?: string) => {
const [length, width, height] = String(value || '')
.split(/[xX×*]/)
.map((item) => Number(item.trim()))
specificationParts.length = Number.isFinite(length) ? length : undefined
specificationParts.width = Number.isFinite(width) ? width : undefined
specificationParts.height = Number.isFinite(height) ? height : undefined
}
const buildSpecification = () => {
const { length, width, height } = specificationParts
const isEmpty = (value?: number | null) => value === undefined || value === null
if (isEmpty(length) && isEmpty(width) && isEmpty(height)) {
return undefined
}
return `${length ?? ''}x${width ?? ''}x${height ?? ''}`
}
const hydrateSelectedWarehouseArea = async () => {
selectedWarehouse.value = warehouseOptions.value.find((item) => item.id === formData.value.warehouseId)
selectedArea.value = areaOptions.value.find((item) => item.id === formData.value.areaId)
if (!selectedArea.value && formData.value.warehouseId && formData.value.areaId) {
const data = await WarehouseAreaApi.getWarehouseAreaPage({
pageNo: 1,
pageSize: 100,
warehouseId: formData.value.warehouseId
})
const areas = data?.list ?? []
areaOptions.value = areas
selectedArea.value = areas.find((item) => item.id === formData.value.areaId)
}
}
const getWarehouseName = (warehouseId?: number) => {
return warehouseOptions.value.find((item) => item.id === warehouseId)?.name ?? '-'
}
const clearAreaSelection = () => {
formData.value.areaId = undefined formData.value.areaId = undefined
selectedArea.value = undefined
}
const getWarehouseTableList = async () => {
warehouseLoading.value = true
try {
const data = await WarehouseApi.getWarehousePage(warehouseQueryParams)
warehouseTableList.value = data?.list ?? []
warehouseTotal.value = data?.total ?? 0
} finally {
warehouseLoading.value = false
}
}
const openWarehouseDialog = async () => {
warehouseDialogVisible.value = true
warehouseSelection.value = selectedWarehouse.value
await getWarehouseTableList()
}
const handleWarehouseQuery = () => {
warehouseQueryParams.pageNo = 1
getWarehouseTableList()
}
const resetWarehouseQuery = () => {
warehouseQueryParams.pageNo = 1
warehouseQueryParams.name = undefined
getWarehouseTableList()
}
const handleWarehouseRowClick = (row: WarehouseVO) => {
warehouseSelection.value = row
}
const confirmWarehouseSelection = () => {
if (!warehouseSelection.value) return
const oldWarehouseId = formData.value.warehouseId
selectedWarehouse.value = warehouseSelection.value
formData.value.warehouseId = warehouseSelection.value.id
if (oldWarehouseId !== formData.value.warehouseId) {
clearAreaSelection()
}
warehouseDialogVisible.value = false
}
const getAreaTableList = async () => {
areaLoading.value = true
try {
const data = await WarehouseAreaApi.getWarehouseAreaPage({
...areaQueryParams,
warehouseId: formData.value.warehouseId
})
areaTableList.value = data?.list ?? []
areaTotal.value = data?.total ?? 0
} finally {
areaLoading.value = false
}
}
const openAreaDialog = async () => {
if (!formData.value.warehouseId) {
message.warning(t('ErpStock.Check.validatorSelectWarehouseFirst'))
return
}
areaDialogVisible.value = true
areaSelection.value = selectedArea.value
await getAreaTableList()
}
const handleAreaQuery = () => {
areaQueryParams.pageNo = 1
getAreaTableList()
}
const resetAreaQuery = () => {
areaQueryParams.pageNo = 1
areaQueryParams.areaCode = undefined
areaQueryParams.areaName = undefined
getAreaTableList()
}
const handleAreaRowClick = (row: WarehouseAreaVO) => {
areaSelection.value = row
}
const confirmAreaSelection = () => {
if (!areaSelection.value) return
selectedArea.value = areaSelection.value
formData.value.areaId = areaSelection.value.id
areaDialogVisible.value = false
} }
const handleCodeAutoChange = (value: boolean) => { const handleCodeAutoChange = (value: boolean) => {
@ -351,6 +682,35 @@ const resetForm = () => {
useDate: undefined, useDate: undefined,
remark: undefined remark: undefined
} }
specificationParts.length = undefined
specificationParts.width = undefined
specificationParts.height = undefined
selectedWarehouse.value = undefined
selectedArea.value = undefined
formRef.value?.resetFields() formRef.value?.resetFields()
} }
</script> </script>
<style scoped lang="scss">
.pallet-dialog-pagination {
display: flex;
justify-content: flex-end;
padding: 16px 0 8px;
}
.pallet-spec-input {
display: grid;
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr);
align-items: center;
gap: 8px;
width: 100%;
:deep(.el-input-number) {
width: 100%;
}
span {
color: var(--el-text-color-secondary);
}
}
</style>

@ -1,90 +1,39 @@
<template> <template>
<ContentWrap> <ContentWrap>
<el-form <el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="auto">
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="auto"
>
<el-form-item :label="t('ErpStock.Pallet.code')" prop="code"> <el-form-item :label="t('ErpStock.Pallet.code')" prop="code">
<el-input <el-input v-model="queryParams.code" :placeholder="t('ErpStock.Pallet.placeholderCode')" clearable
v-model="queryParams.code" @keyup.enter="handleQuery" class="!w-240px" />
:placeholder="t('ErpStock.Pallet.placeholderCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item> </el-form-item>
<el-form-item :label="t('ErpStock.Pallet.palletType')" prop="palletType"> <el-form-item :label="t('ErpStock.Pallet.palletType')" prop="palletType">
<el-select <el-select v-model="queryParams.palletType" :placeholder="t('ErpStock.Pallet.placeholderPalletType')" clearable
v-model="queryParams.palletType" class="!w-240px">
:placeholder="t('ErpStock.Pallet.placeholderPalletType')" <el-option v-for="dict in getIntDictOptions(DICT_TYPE.STORAGE_PALLET_TYPES)" :key="dict.value"
clearable :label="dict.label" :value="dict.value" />
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.STORAGE_PALLET_TYPES)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('ErpStock.Pallet.status')" prop="status"> <el-form-item :label="t('ErpStock.Pallet.status')" prop="status">
<el-select <el-select v-model="queryParams.status" :placeholder="t('ErpStock.Pallet.placeholderStatus')" clearable
v-model="queryParams.status" class="!w-240px">
:placeholder="t('ErpStock.Pallet.placeholderStatus')" <el-option v-for="dict in getIntDictOptions(DICT_TYPE.STORAGE_PALLET_STATUS)" :key="dict.value"
clearable :label="dict.label" :value="dict.value" />
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.STORAGE_PALLET_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('ErpStock.Pallet.warehouseId')" prop="warehouseId" v-show="showAllFilters"> <el-form-item :label="t('ErpStock.Pallet.warehouseId')" prop="warehouseId" v-show="showAllFilters">
<el-select <el-select v-model="queryParams.warehouseId" :placeholder="t('ErpStock.Pallet.placeholderWarehouseId')"
v-model="queryParams.warehouseId" clearable class="!w-240px" @change="handleWarehouseChange">
:placeholder="t('ErpStock.Pallet.placeholderWarehouseId')" <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
clearable
class="!w-240px"
@change="handleWarehouseChange"
>
<el-option
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('ErpStock.Pallet.areaId')" prop="areaId" v-show="showAllFilters"> <el-form-item :label="t('ErpStock.Pallet.areaId')" prop="areaId" v-show="showAllFilters">
<el-select <el-select v-model="queryParams.areaId" :placeholder="t('ErpStock.Pallet.placeholderAreaId')" clearable
v-model="queryParams.areaId" class="!w-240px">
:placeholder="t('ErpStock.Pallet.placeholderAreaId')" <el-option v-for="item in filteredAreaList" :key="item.id" :label="item.areaName" :value="item.id" />
clearable
class="!w-240px"
>
<el-option
v-for="item in filteredAreaList"
:key="item.id"
:label="item.areaName"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('ErpStock.Pallet.planCode')" prop="planCode" v-show="showAllFilters"> <el-form-item :label="t('ErpStock.Pallet.planCode')" prop="planCode" v-show="showAllFilters">
<el-input <el-input v-model="queryParams.planCode" :placeholder="t('ErpStock.Pallet.placeholderPlanCode')" clearable
v-model="queryParams.planCode" @keyup.enter="handleQuery" class="!w-240px" />
:placeholder="t('ErpStock.Pallet.placeholderPlanCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item> </el-form-item>
<el-form-item v-if="filterCount > 3"> <el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters"> <el-button type="text" class="text-primary" @click="toggleFilters">
@ -94,14 +43,13 @@
</el-button> </el-button>
</el-form-item> </el-form-item>
<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="handleQuery">
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reset') }}</el-button> <Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}
<el-button </el-button>
type="primary" <el-button @click="resetQuery">
plain <Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reset') }}
@click="openForm('create')" </el-button>
v-hasPermi="['erp:pallet:create']" <el-button type="primary" plain @click="openForm('create')" v-hasPermi="['erp:pallet:create']">
>
<Icon icon="ep:plus" class="mr-5px" /> {{ t('action.add') }} <Icon icon="ep:plus" class="mr-5px" /> {{ t('action.add') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
@ -109,24 +57,15 @@
</ContentWrap> </ContentWrap>
<ContentWrap> <ContentWrap>
<el-table <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id">
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
>
<el-table-column :label="t('ErpStock.Pallet.code')" align="center" prop="code" min-width="150" sortable /> <el-table-column :label="t('ErpStock.Pallet.code')" align="center" prop="code" min-width="150" sortable />
<el-table-column :label="t('ErpStock.Pallet.palletType')" align="center" prop="palletType" min-width="100"> <el-table-column :label="t('ErpStock.Pallet.palletType')" align="center" prop="palletType" min-width="100">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.STORAGE_PALLET_TYPES" :value="scope.row.palletType" /> <dict-tag :type="DICT_TYPE.STORAGE_PALLET_TYPES" :value="scope.row.palletType" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('ErpStock.Pallet.specification')" align="center" prop="specification" min-width="140"> <el-table-column :label="t('ErpStock.Pallet.specification')" align="center" prop="specification"
<template #default="scope"> min-width="140" />
<dict-tag :type="DICT_TYPE.STORAGE_PALLET_SPECIFICATIONS" :value="scope.row.specification" />
</template>
</el-table-column>
<el-table-column :label="t('ErpStock.Pallet.ratedLoadWeight')" align="center" min-width="120"> <el-table-column :label="t('ErpStock.Pallet.ratedLoadWeight')" align="center" min-width="120">
<template #default="scope"> <template #default="scope">
{{ formatWeight(scope.row) }} {{ formatWeight(scope.row) }}
@ -150,52 +89,25 @@
<el-table-column :label="t('ErpStock.Pallet.planCode')" align="center" prop="planCode" min-width="160" /> <el-table-column :label="t('ErpStock.Pallet.planCode')" align="center" prop="planCode" min-width="160" />
<el-table-column :label="t('ErpStock.Pallet.productId')" align="center" prop="productId" min-width="100" /> <el-table-column :label="t('ErpStock.Pallet.productId')" align="center" prop="productId" min-width="100" />
<el-table-column :label="t('ErpStock.Pallet.productCount')" align="center" prop="productCount" min-width="100" /> <el-table-column :label="t('ErpStock.Pallet.productCount')" align="center" prop="productCount" min-width="100" />
<el-table-column :label="t('ErpStock.Pallet.qrcode')" align="center" prop="qrcode" min-width="120">
<template #default="scope">
<el-link v-if="scope.row.qrcode" :href="scope.row.qrcode" target="_blank" type="primary">
{{ t('ErpStock.Pallet.viewQrcode') }}
</el-link>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column :label="t('ErpStock.Pallet.purchaseDate')" align="center" prop="purchaseDate" min-width="120" /> <el-table-column :label="t('ErpStock.Pallet.purchaseDate')" align="center" prop="purchaseDate" min-width="120" />
<el-table-column :label="t('ErpStock.Pallet.useDate')" align="center" prop="useDate" min-width="120" /> <el-table-column :label="t('ErpStock.Pallet.useDate')" align="center" prop="useDate" min-width="120" />
<el-table-column :label="t('ErpStock.Pallet.remark')" align="center" prop="remark" min-width="160" /> <el-table-column :label="t('ErpStock.Pallet.remark')" align="center" prop="remark" min-width="160" />
<el-table-column <el-table-column :label="t('ErpStock.Pallet.createTime')" align="center" prop="createTime"
:label="t('ErpStock.Pallet.createTime')" :formatter="dateFormatter" width="180px" sortable />
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
sortable
/>
<el-table-column :label="t('common.operate')" align="center" width="150px"> <el-table-column :label="t('common.operate')" align="center" width="150px">
<template #default="scope"> <template #default="scope">
<el-button <el-button link type="primary" @click="openForm('update', scope.row)" v-hasPermi="['erp:pallet:update']">
link
type="primary"
@click="openForm('update', scope.row)"
v-hasPermi="['erp:pallet:update']"
>
{{ t('action.edit') }} {{ t('action.edit') }}
</el-button> </el-button>
<el-button <el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['erp:pallet:delete']">
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['erp:pallet:delete']"
>
{{ t('action.del') }} {{ t('action.del') }}
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<Pagination <Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
:total="total" @pagination="getList" />
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap> </ContentWrap>
<PalletForm ref="formRef" @success="getList" /> <PalletForm ref="formRef" @success="getList" />
@ -300,7 +212,7 @@ const handleDelete = async (id: number) => {
await PalletApi.deletePallet(id) await PalletApi.deletePallet(id)
message.success(t('common.delSuccess')) message.success(t('common.delSuccess'))
await getList() await getList()
} catch {} } catch { }
} }
onMounted(() => { onMounted(() => {

Loading…
Cancel
Save