diff --git a/src/api/erp/stock/check/index.ts b/src/api/erp/stock/check/index.ts index 9de3a893..79482fb9 100644 --- a/src/api/erp/stock/check/index.ts +++ b/src/api/erp/stock/check/index.ts @@ -6,9 +6,11 @@ export interface StockCheckVO { no: string // 盘点单号 checkTime: Date | string // 盘点时间 sourceType?: number | string // 生成来源类型:1-按库存,2-按产品 + categoryType?: number | string // 分类 totalCount: number // 合计数量 totalPrice: number // 合计金额,单位:元 status: number // 状态 + checkStatus?: number | string // 盘点状态:0-未盘点,1-已盘点 auditUserId?: number // 审核人编号 auditUserName?: string // 审核人名称 remark?: string // 备注 @@ -95,6 +97,16 @@ export const StockCheckApi = { }) }, + // 提交库存盘点单 + submitStockCheck: async (data: { id: number; auditUserId?: number; remark?: string }) => { + return await request.put({ url: `/erp/stock-check/submit`, data }) + }, + + // 审核库存盘点单 + auditStockCheck: async (data: { id: number; status: number; remark?: string }) => { + return await request.put({ url: `/erp/stock-check/audit`, data }) + }, + // 删除库存盘点单 deleteStockCheck: async (ids: number[]) => { return await request.delete({ diff --git a/src/api/erp/stock/pallet/index.ts b/src/api/erp/stock/pallet/index.ts new file mode 100644 index 00000000..2ce1c0ac --- /dev/null +++ b/src/api/erp/stock/pallet/index.ts @@ -0,0 +1,40 @@ +import request from '@/config/axios' + +export interface PalletVO { + id?: number + code?: string + isCode?: boolean + palletType?: number | string + specification?: string + ratedLoadWeight?: number | string + unit?: string + status?: number | string + warehouseId?: number | string + areaId?: number | string + planCode?: string + productId?: number | string + productCount?: number | string + qrcode?: string + purchaseDate?: string + useDate?: string + remark?: string + createTime?: string +} + +export const PalletApi = { + getPalletPage: async (params: any) => { + return await request.get({ url: `/erp/pallet/page`, params }) + }, + + createPallet: async (params: PalletVO) => { + return await request.post({ url: `/erp/pallet/create`, params }) + }, + + updatePallet: async (params: PalletVO) => { + return await request.put({ url: `/erp/pallet/update`, params }) + }, + + deletePallet: async (id: number) => { + return await request.delete({ url: `/erp/pallet/delete?id=` + id }) + } +} diff --git a/src/locales/en.ts b/src/locales/en.ts index 0d66d18f..b18a5a43 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -545,13 +545,25 @@ price: 'Amount', totalPrice: 'Total Price', sourceType: 'Source Type', + categoryType: 'Category', sourceTypeStock: 'By Stock', sourceTypeProduct: 'By Product', area: 'Area', checkItem: 'Check Item', stockCount: 'Stock Quantity', actualCount: 'Actual Count', + differenceCount: 'Difference', inventoryCheck: 'Check', + saveDraft: 'Save Draft', + checkStatus: 'Check Status', + checkStatusUnchecked: 'Unchecked', + checkStatusChecked: 'Checked', + submit: 'Submit', + submitRemark: 'Submit Remark', + auditRemark: 'Audit Remark', + auditUserName: 'Auditor', + auditApprove: 'Pass', + auditReject: 'Reject', materialCategory: 'Material Category', materialSubCategory: 'Material Subcategory', standard: 'Standard', @@ -569,20 +581,29 @@ placeholderCheckItem: 'Please select check item', placeholderProductBarCode: 'Please enter material code', placeholderProductName: 'Please enter material name', + placeholderAuditUser: 'Please select auditor', + placeholderSubmitRemark: 'Please enter submit remark', + placeholderAuditRemark: 'Please enter audit remark', placeholderCreator: 'Please select creator', placeholderStatus: 'Please select status', placeholderRemark: 'Please enter remark', placeholderCheckTime: 'Select check time', validatorCheckTimeRequired: 'Check time is required', validatorSourceTypeRequired: 'Please select source type', + validatorCategoryTypeRequired: 'Please select category', validatorSelectWarehouseFirst: 'Please select warehouse first', validatorSelectAreaFirst: 'Please select area first', validatorSelectProductFirst: 'Please select product first', validatorSelectCheckItem: 'Please select check item', + validatorAuditUserRequired: 'Please select auditor', + validatorCompleteCheckInfo: 'Please complete check information first', confirmApprove: 'Are you sure to approve this check order?', confirmReverseApprove: 'Are you sure to reverse approve this check order?', + submitSuccess: 'Submit success', approveSuccess: 'Approve success', reverseApproveSuccess: 'Reverse approve success', + auditApproveSuccess: 'Pass success', + auditRejectSuccess: 'Reject success', exportName: 'Check Order.xls', list: 'Check Product List', addItem: 'Add Check Product', @@ -693,6 +714,43 @@ validatorPackageQuantityRequired: 'Package quantity is required', validatorPalletPackageQuantityRequired: 'Pallet package quantity is required', validatorStatusRequired: 'Status is required' + }, + Pallet: { + code: 'Pallet Code', + palletType: 'Pallet Type', + specification: 'Specification', + ratedLoadWeight: 'Rated Load', + unit: 'Unit', + status: 'Pallet Status', + warehouseId: 'Warehouse', + areaId: 'Area', + planCode: 'Production Task No.', + productId: 'Product ID', + productCount: 'Product Quantity', + qrcode: 'QR Code', + viewQrcode: 'View QR Code', + purchaseDate: 'Purchase Date', + useDate: 'Use Date', + remark: 'Remark', + createTime: 'Create Time', + placeholderCode: 'Please enter pallet code', + placeholderPalletType: 'Please enter pallet type', + placeholderSpecification: 'Please select pallet specification', + placeholderRatedLoadWeight: 'Please enter rated load', + placeholderUnit: 'Please enter unit', + placeholderStatus: 'Please select pallet status', + placeholderWarehouseId: 'Please select warehouse', + placeholderAreaId: 'Please select area', + placeholderPlanCode: 'Please enter production task no.', + placeholderProductId: 'Please select product', + placeholderProductCount: 'Please enter product quantity', + placeholderQrcode: 'Please enter QR code URL', + placeholderPurchaseDate: 'Please select purchase date', + placeholderUseDate: 'Please select use date', + placeholderRemark: 'Please enter remark', + validatorCodeRequired: 'Pallet code is required', + validatorPalletTypeRequired: 'Pallet type is required', + validatorStatusRequired: 'Pallet status is required' } }, ErpPurchase: { diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 431118c7..600f308e 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -545,13 +545,25 @@ price: '金额', totalPrice: '合计金额', sourceType: '生成来源', + categoryType: '分类', sourceTypeStock: '按库存', sourceTypeProduct: '按产品', area: '库区', checkItem: '盘点项', stockCount: '库存数量', actualCount: '实盘数量', + differenceCount: '差异', inventoryCheck: '盘点', + saveDraft: '保存草稿', + checkStatus: '盘点状态', + checkStatusUnchecked: '未盘点', + checkStatusChecked: '已盘点', + submit: '提交', + submitRemark: '提交备注', + auditRemark: '审核备注', + auditUserName: '审核人', + auditApprove: '通过', + auditReject: '驳回', materialCategory: '物料大类', materialSubCategory: '物料小类', standard: '规格', @@ -569,20 +581,29 @@ placeholderCheckItem: '请选择盘点项', placeholderProductBarCode: '请输入物料编码', placeholderProductName: '请输入物料名称', + placeholderAuditUser: '请选择审核人', + placeholderSubmitRemark: '请输入提交备注', + placeholderAuditRemark: '请输入审核备注', placeholderCreator: '请选择创建人', placeholderStatus: '请选择状态', placeholderRemark: '请输入备注', placeholderCheckTime: '选择盘点时间', validatorCheckTimeRequired: '盘点时间不能为空', validatorSourceTypeRequired: '请选择生成来源', + validatorCategoryTypeRequired: '请选择分类', validatorSelectWarehouseFirst: '请先选择仓库', validatorSelectAreaFirst: '请先选择库区', validatorSelectProductFirst: '请先选择产品', validatorSelectCheckItem: '请选择盘点项', + validatorAuditUserRequired: '请选择审核人', + validatorCompleteCheckInfo: '请先完善盘点信息', confirmApprove: '确定审批该盘点单吗?', confirmReverseApprove: '确定反审批该盘点单吗?', + submitSuccess: '提交成功', approveSuccess: '审批成功', reverseApproveSuccess: '反审批成功', + auditApproveSuccess: '通过成功', + auditRejectSuccess: '驳回成功', exportName: '其它盘点单.xls', list: '盘点产品物料清单', addItem: '添加盘点产品', @@ -693,6 +714,43 @@ validatorPackageQuantityRequired: '每包数量不能为空', validatorPalletPackageQuantityRequired: '每托包数不能为空', validatorStatusRequired: '状态不能为空' + }, + Pallet: { + code: '托盘编码', + palletType: '托盘类型', + specification: '规格', + ratedLoadWeight: '额定载重', + unit: '单位', + status: '托盘状态', + warehouseId: '所属仓库', + areaId: '所属库区', + planCode: '生产任务单号', + productId: '产品编号', + productCount: '产品数量', + qrcode: '二维码', + viewQrcode: '查看二维码', + purchaseDate: '采购日期', + useDate: '启用日期', + remark: '备注', + createTime: '创建时间', + placeholderCode: '请输入托盘编码', + placeholderPalletType: '请输入托盘类型', + placeholderSpecification: '请选择托盘规格', + placeholderRatedLoadWeight: '请输入额定载重', + placeholderUnit: '请输入单位', + placeholderStatus: '请选择托盘状态', + placeholderWarehouseId: '请选择所属仓库', + placeholderAreaId: '请选择所属库区', + placeholderPlanCode: '请输入生产任务单号', + placeholderProductId: '请选择产品', + placeholderProductCount: '请输入产品数量', + placeholderQrcode: '请输入二维码地址', + placeholderPurchaseDate: '请选择采购日期', + placeholderUseDate: '请选择投入使用日期', + placeholderRemark: '请输入备注', + validatorCodeRequired: '托盘编码不能为空', + validatorPalletTypeRequired: '托盘类型不能为空', + validatorStatusRequired: '托盘状态不能为空' } }, ErpPurchase: { diff --git a/src/utils/dict.ts b/src/utils/dict.ts index 427a7797..1cf04976 100644 --- a/src/utils/dict.ts +++ b/src/utils/dict.ts @@ -233,6 +233,9 @@ export enum DICT_TYPE { WAREHOUSE_RECEIVING_STATUS = 'warehouse_receiving_status', // 入库状态 WAREHOUSE_OUTBOUND_STATUS = 'Warehouse_outbound_status', // 出库状态 WAREHOUSE_OUTBOUND_PURPOSE = 'warehouse_outbound_purpose', // 出库用途 + STORAGE_PALLET_TYPES = 'storage_pallet_types', // 仓储托盘类型 + STORAGE_PALLET_STATUS = 'storage_pallet_status', // 仓储托盘状态 + STORAGE_PALLET_SPECIFICATIONS = 'storage_pallet_specifications', // 仓储托盘规格 SUBMOLD_TYPE = 'submold_type', // 子模具类型 ERP_MAINTAIN_TYPE = 'maintain_type',// ERP 保养类型 diff --git a/src/views/erp/stock/checkExecution/components/StockCheckExecutionForm.vue b/src/views/erp/stock/checkExecution/components/StockCheckExecutionForm.vue index 520fc6a0..61c67499 100644 --- a/src/views/erp/stock/checkExecution/components/StockCheckExecutionForm.vue +++ b/src/views/erp/stock/checkExecution/components/StockCheckExecutionForm.vue @@ -14,7 +14,8 @@ :placeholder="t('ErpStock.Check.placeholderCheckTime')" class="!w-1/1" /> - + + {{ t('ErpStock.Check.sourceTypeStock') }} @@ -22,11 +23,25 @@ + + + + + {{ dict.label }} + + + + - + - + + + + - + @@ -257,6 +346,8 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { dateFormatter } from '@/utils/formatTime' import { StockCheckApi, type StockCheckVO } from '@/api/erp/stock/check' import { WarehouseApi, type WarehouseVO } from '@/api/erp/stock/warehouse' +import * as UserApi from '@/api/system/user' +import * as ConfigApi from '@/api/infra/config' import StockCheckExecutionForm from './components/StockCheckExecutionForm.vue' defineOptions({ name: 'ErpStockCheckExecution' }) @@ -269,8 +360,34 @@ const list = ref([]) const total = ref(0) const warehouseList = ref([]) const selectionList = ref([]) +const userList = ref([]) const queryFormRef = ref() const formRef = ref() +const submitFormRef = ref() +const submitDialogVisible = ref(false) +const submitLoading = ref(false) +const submitForm = reactive({ + id: undefined as number | undefined, + auditUserId: undefined as number | undefined, + remark: undefined as string | undefined +}) +const isAuditDisabled = ref(false) +const submitActionText = computed(() => + isAuditDisabled.value ? t('ErpStock.Check.inventoryCheck') : t('ErpStock.Check.submit') +) +const submitRules = computed(() => isAuditDisabled.value ? {} : { + auditUserId: [{ required: true, message: t('ErpStock.Check.validatorAuditUserRequired'), trigger: 'change' }] +}) +const auditDialogVisible = ref(false) +const auditLoading = ref(false) +const auditForm = reactive({ + id: undefined as number | undefined, + status: undefined as number | undefined, + remark: undefined as string | undefined +}) +const auditDialogTitle = computed(() => + auditForm.status === 20 ? t('ErpStock.Check.auditApprove') : t('ErpStock.Check.auditReject') +) const queryParams = reactive({ pageNo: 1, pageSize: 10, @@ -291,6 +408,16 @@ const getList = async () => { } } +const loadAuditConfig = async () => { + try { + const data = await ConfigApi.getConfigPage({ pageNo: 1, pageSize: 10, key: 'inventoryAudit' } as PageParam & { key: string }) + const auditConfig = data?.list?.find((item) => item?.key === 'inventoryAudit') + isAuditDisabled.value = auditConfig?.value === '0' + } catch { + isAuditDisabled.value = false + } +} + const handleQuery = () => { queryParams.pageNo = 1 getList() @@ -322,13 +449,89 @@ const handleSelectionChange = (rows: StockCheckVO[]) => { selectionList.value = rows } +const openSubmitDialog = (row: StockCheckVO) => { + const hasIncompleteItem = (row.items || []).some( + (item) => item.actualCount === undefined || item.actualCount === null || item.actualCount === '' + ) + if (hasIncompleteItem) { + message.warning(t('ErpStock.Check.validatorCompleteCheckInfo')) + return + } + submitForm.id = row.id + submitForm.auditUserId = row.auditUserId + submitForm.remark = undefined + submitDialogVisible.value = true + submitFormRef.value?.clearValidate() +} + +const handleSubmit = async () => { + if (!isAuditDisabled.value) { + await submitFormRef.value.validate() + } + if (!submitForm.id || (!isAuditDisabled.value && !submitForm.auditUserId)) { + return + } + submitLoading.value = true + try { + const data: { id: number; auditUserId?: number; remark?: string } = { + id: submitForm.id, + remark: submitForm.remark + } + if (!isAuditDisabled.value) { + data.auditUserId = submitForm.auditUserId + } + await StockCheckApi.submitStockCheck(data) + message.success(t('ErpStock.Check.submitSuccess')) + submitDialogVisible.value = false + await getList() + } finally { + submitLoading.value = false + } +} + +const openAuditDialog = (row: StockCheckVO, status: number) => { + auditForm.id = row.id + auditForm.status = status + auditForm.remark = undefined + auditDialogVisible.value = true +} + +const handleAudit = async () => { + if (!auditForm.id || !auditForm.status) { + return + } + auditLoading.value = true + try { + await StockCheckApi.auditStockCheck({ + id: auditForm.id, + status: auditForm.status, + remark: auditForm.remark + }) + message.success( + auditForm.status === 20 + ? t('ErpStock.Check.auditApproveSuccess') + : t('ErpStock.Check.auditRejectSuccess') + ) + auditDialogVisible.value = false + await getList() + } finally { + auditLoading.value = false + } +} + const getWarehouseNames = (row: StockCheckVO) => { const names = Array.from(new Set((row.items || []).map((item) => item.warehouseName).filter(Boolean))) return names.length ? names.join('、') : '-' } onMounted(async () => { - warehouseList.value = await WarehouseApi.getWarehouseSimpleList() + const [warehouses, users] = await Promise.all([ + WarehouseApi.getWarehouseSimpleList(), + UserApi.getSimpleUserList(), + loadAuditConfig() + ]) + warehouseList.value = warehouses || [] + userList.value = users || [] await getList() }) diff --git a/src/views/erp/stock/pallet/PalletForm.vue b/src/views/erp/stock/pallet/PalletForm.vue new file mode 100644 index 00000000..4519c6f3 --- /dev/null +++ b/src/views/erp/stock/pallet/PalletForm.vue @@ -0,0 +1,356 @@ + + + diff --git a/src/views/erp/stock/pallet/index.vue b/src/views/erp/stock/pallet/index.vue new file mode 100644 index 00000000..9a2f7c94 --- /dev/null +++ b/src/views/erp/stock/pallet/index.vue @@ -0,0 +1,311 @@ + + +