feat(mes): 实现临时码预生成和补录功能
- 新增临时批次码和临时托盘码概念,支持预生成二维码
- 添加补录批次信息功能,将临时批次码转为正式批次号
- 实现托盘码绑定生产批次功能,生成正式托盘码
- 更新表单类型,增加fill类型用于临时码补录
- 修改二维码生成流程,分离预生成和正式录入步骤
- 增加扫码追溯对临时码的支持
- 更新表格列宽以适应新增的操作按钮
- 实现批量绑定批次功能
- 添加临时码状态标识和显示逻辑
| | |
| | | |
| | | /** çææ°æ®å
è¯·æ± */ |
| | | export interface GenerateParams { |
| | | batchId: number; // çäº§æ¹æ¬¡ç¼å· |
| | | count: number; // çæè¢æ° |
| | | remark?: string; // 夿³¨ |
| | | } |
| | | |
| | | export interface GenerateResult { |
| | | uuid?: string; |
| | | } |
| | | |
| | | export interface BindBatchParams { |
| | | batchId: number; |
| | | ids: number[]; |
| | | } |
| | | |
| | | /** ç»å®/è§£ç»æçè¯·æ± */ |
| | |
| | | |
| | | /** çæè¢ç æ°æ®å
ï¼è¿åçæç» UUIDï¼ */ |
| | | export function generateBagCodes(data: MesProBagCodeApi.GenerateParams) { |
| | | return requestClient.post<string>('/mes/pro/bag-code/generate', data); |
| | | return requestClient.post<MesProBagCodeApi.GenerateResult>( |
| | | '/mes/pro/bag-code/generate', |
| | | data, |
| | | ); |
| | | } |
| | | |
| | | /** å½å
¥çäº§æ¹æ¬¡ */ |
| | | export function bindBagCodeBatch(data: MesProBagCodeApi.BindBatchParams) { |
| | | return requestClient.put('/mes/pro/bag-code/bind-batch', data); |
| | | } |
| | | |
| | | /** å é¤è¢ç çæç» */ |
| | |
| | | /** çäº§æ¹æ¬¡ */ |
| | | export interface Batch { |
| | | id?: number; // ç¼å· |
| | | code?: string; // æ¹æ¬¡å·ï¼èªå¨çæï¼ |
| | | code?: string; // æ¹æ¬¡å·ï¼è¡¥å½æ£å¼ä¿¡æ¯åèªå¨çæï¼ |
| | | tempCode?: string; // ä¸´æ¶æ¹æ¬¡ç ï¼é¢çæäºç»´ç é¶æ®µä½¿ç¨ï¼æ«ç 追溯å
¼å®¹ï¼ |
| | | itemId?: number; // åç§ï¼äº§åç©æï¼ç¼å· |
| | | itemCode?: string; // åç§ç¼ç ï¼åç«¯æ¼æ¥ï¼ |
| | | itemName?: string; // åç§åç§°ï¼åç«¯æ¼æ¥ï¼ |
| | |
| | | /** çäº§æ¹æ¬¡æ«ç 追溯 */ |
| | | export interface BatchTrace { |
| | | id?: number; // çäº§æ¹æ¬¡ç¼å· |
| | | code?: string; // æ¹æ¬¡å·ï¼äºç»´ç å
å®¹ï¼ |
| | | code?: string; // æ¹æ¬¡å·ï¼è¡¥å½åçæ£å¼æ¹æ¬¡å·ï¼ |
| | | tempCode?: string; // ä¸´æ¶æ¹æ¬¡ç ï¼äºç»´ç å
å®¹ï¼æªè¡¥å½ä¿¡æ¯æ¶å±ç¤ºï¼ |
| | | status?: number; // æ¹æ¬¡ç¶æï¼åå
¸ mes_pro_batch_statusï¼ |
| | | produceDate?: string; // çäº§æ¥æ |
| | | lineCode?: string; // 产线ç¼ç |
| | |
| | | /** çäº§æ¹æ¬¡å页æ¥è¯¢åæ° */ |
| | | export interface PageParams extends PageParam { |
| | | code?: string; |
| | | tempCode?: string; |
| | | itemId?: number; |
| | | lineId?: number; |
| | | lineCode?: string; |
| | |
| | | status?: number; |
| | | produceDate?: string[]; |
| | | createTime?: string[]; |
| | | } |
| | | |
| | | /** é¢çææ¹æ¬¡äºç»´ç è¿å项 */ |
| | | export interface PreGenerateResult { |
| | | id: number; // çäº§æ¹æ¬¡ç¼å· |
| | | tempCode: string; // ä¸´æ¶æ¹æ¬¡ç ï¼äºç»´ç å
å®¹ï¼ |
| | | } |
| | | } |
| | | |
| | |
| | | ); |
| | | } |
| | | |
| | | /** é¢çææ¹æ¬¡ä¸´æ¶äºç»´ç ï¼ä»
çæä¸´æ¶æ¹æ¬¡ç ï¼ä¸å½å
¥ä¸å¡ä¿¡æ¯ï¼ */ |
| | | export function preGenerateBatch(data: { |
| | | count: number; |
| | | remark?: string; |
| | | }) { |
| | | return requestClient.post<MesProBatchApi.PreGenerateResult[]>( |
| | | '/mes/pro/batch/pre-generate', |
| | | data, |
| | | ); |
| | | } |
| | | |
| | | /** è¡¥å½æ¹æ¬¡æ£å¼ä¿¡æ¯ï¼çææ£å¼æ¹æ¬¡å·ï¼ */ |
| | | export function fillBatchInfo(data: MesProBatchApi.Batch) { |
| | | return requestClient.put('/mes/pro/batch/fill-info', data); |
| | | } |
| | | |
| | | /** æ°å¢çäº§æ¹æ¬¡ï¼èªå¨çææ¹æ¬¡å·ï¼ */ |
| | | export function createBatch(data: MesProBatchApi.Batch) { |
| | | return requestClient.post<number>('/mes/pro/batch/create', data); |
| | |
| | | /** æçç */ |
| | | export interface Pallet { |
| | | id?: number; // ç¼å· |
| | | code?: string; // æçç |
| | | code?: string; // æçç ï¼ç»å®æ¹æ¬¡åçæï¼ |
| | | tempCode?: string; // ä¸´æ¶æçç ï¼é¢çæäºç»´ç é¶æ®µä½¿ç¨ï¼æ«ç 追溯å
¼å®¹ï¼ |
| | | batchId?: number; // çäº§æ¹æ¬¡ç¼å· |
| | | batchCode?: string; // æ¹æ¬¡å· |
| | | palletNo?: number; // æ¹æ¬¡å
æçåºå· |
| | |
| | | /** æçç å页æ¥è¯¢åæ° */ |
| | | export interface PageParams extends PageParam { |
| | | code?: string; |
| | | tempCode?: string; |
| | | batchId?: number; |
| | | batchCode?: string; |
| | | status?: number; |
| | |
| | | /** æçç æ«ç 追溯 */ |
| | | export interface PalletTrace { |
| | | id?: number; // ç¼å· |
| | | code?: string; // æçç ï¼äºç»´ç å
å®¹ï¼ |
| | | code?: string; // æçç ï¼ç»å®æ¹æ¬¡åçæ£å¼æçç ï¼ |
| | | tempCode?: string; // ä¸´æ¶æçç ï¼äºç»´ç å
å®¹ï¼æªç»å®æ¹æ¬¡æ¶å±ç¤ºï¼ |
| | | palletNo?: number; // æ¹æ¬¡å
æçåºå· |
| | | capacity?: number; // å¯è£
è¢æ° |
| | | bagCount?: number; // å·²ç»å®è¢ç æ°é |
| | |
| | | capacity?: number; // å¯è£
è¢æ° |
| | | remark?: string; // 夿³¨ |
| | | } |
| | | |
| | | /** é¢çææçäºç»´ç è¿å项 */ |
| | | export interface PreGenerateResult { |
| | | id: number; // æçç ç¼å· |
| | | tempCode: string; // ä¸´æ¶æçç ï¼äºç»´ç å
å®¹ï¼ |
| | | } |
| | | } |
| | | |
| | | /** æ¹éçææçç ï¼è¿åçæçæçç¼å·åè¡¨ï¼ */ |
| | | export function batchCreatePallet(data: MesProPalletApi.BatchCreateParams) { |
| | | return requestClient.post<number[]>('/mes/pro/pallet/batch-create', data); |
| | | } |
| | | |
| | | /** é¢çææç临æ¶äºç»´ç ï¼ä¸ç»å®çäº§æ¹æ¬¡ï¼ */ |
| | | export function preGeneratePallet(data: { |
| | | count: number; |
| | | capacity?: number; |
| | | remark?: string; |
| | | }) { |
| | | return requestClient.post<MesProPalletApi.PreGenerateResult[]>( |
| | | '/mes/pro/pallet/pre-generate', |
| | | data, |
| | | ); |
| | | } |
| | | |
| | | /** æçç ç»å®çäº§æ¹æ¬¡ï¼çææ£å¼æçç ï¼ */ |
| | | export function bindPalletBatch(data: { ids: number[]; batchId: number }) { |
| | | return requestClient.put('/mes/pro/pallet/bind-batch', data); |
| | | } |
| | | |
| | | /** å 餿çç */ |
| | |
| | | export function exportPalletQr(batchId: number) { |
| | | return requestClient.download(`/mes/pro/pallet/export-qr?batchId=${batchId}`); |
| | | } |
| | | |
| | | /** ææçç ç¼å·å表æ¹é导åºäºç»´ç å¾ç ZIP */ |
| | | export function exportPalletQrByIds(ids: number[]) { |
| | | return requestClient.download('/mes/pro/pallet/export-qr-by-ids', { |
| | | method: 'POST', |
| | | data: { ids }, |
| | | }); |
| | | } |
| | |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 200, |
| | | width: 350, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | |
| | | exportBagCodeExcel, |
| | | exportBagQr, |
| | | getBagCodePage, |
| | | bindBagCodeBatch, |
| | | unbindBagCodePallet, |
| | | } from "#/api/mes/pro/bagCode"; |
| | | import { $t } from "#/locales"; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from "./data"; |
| | | import BindBatchModal from "./modules/bind-batch.vue"; |
| | | import BindPalletModal from "./modules/bind-pallet.vue"; |
| | | import GenerateModal from "./modules/generate-form.vue"; |
| | | import ReplaceModal from "./modules/replace-form.vue"; |
| | |
| | | |
| | | const [GenerateFormModal, generateFormModalApi] = useVbenModal({ |
| | | connectedComponent: GenerateModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [BindBatchFormModal, bindBatchFormModalApi] = useVbenModal({ |
| | | connectedComponent: BindBatchModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | |
| | | .open(); |
| | | } |
| | | |
| | | /** æ¹éå½å
¥çäº§æ¹æ¬¡ */ |
| | | function handleBindBatch() { |
| | | const records = getSelectedRecords(); |
| | | if (!records) return; |
| | | if (records.some((record) => record.status !== MesProBagCodeStatusEnum.GENERATED || record.batchId)) { |
| | | message.warning("è¯·éæ©æªå½å
¥æ¹æ¬¡ä¸ç¶æä¸ºå·²çæçè¢ç "); |
| | | return; |
| | | } |
| | | bindBatchFormModalApi.setData({ ids: records.map((record) => record.id!) }).open(); |
| | | } |
| | | |
| | | /** æ¹éç»å®æç */ |
| | | function handleBindPallet() { |
| | | const records = getSelectedRecords(); |
| | | if (!records) return; |
| | | if (records.some((record) => !record.batchId)) { |
| | | message.warning("请å
å½å
¥çäº§æ¹æ¬¡ï¼åç»å®æç"); |
| | | return; |
| | | } |
| | | const batchIds = new Set(records.map((record) => record.batchId)); |
| | | if (batchIds.size > 1) { |
| | | message.warning("è¯·éæ©å䏿¹æ¬¡ä¸çè¢ç è¿è¡ç»å®"); |
| | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <GenerateFormModal @success="handleRefresh" /> |
| | | <BindBatchFormModal @success="handleRefresh" /> |
| | | <BindPalletFormModal @success="handleRefresh" /> |
| | | <ReplaceFormModal @success="handleReplaceSuccess" /> |
| | | <QrTraceQueryModal /> |
| | |
| | | onClick: handleGenerate, |
| | | }, |
| | | { |
| | | label: 'å½å
¥æ¹æ¬¡', |
| | | type: 'primary', |
| | | auth: ['mes:pro-bag-code:update'], |
| | | onClick: handleBindBatch, |
| | | }, |
| | | { |
| | | label: 'ç»å®æç', |
| | | type: 'primary', |
| | | auth: ['mes:pro-bag-code:update'], |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VbenFormSchema } from "#/adapter/form"; |
| | | |
| | | import { useVbenModal } from "@vben/common-ui"; |
| | | import { MesProBatchStatusEnum } from "@vben/constants"; |
| | | import { message } from "ant-design-vue"; |
| | | |
| | | import { useVbenForm } from "#/adapter/form"; |
| | | import { bindBagCodeBatch } from "#/api/mes/pro/bagCode"; |
| | | import { getBatchSimpleList } from "#/api/mes/pro/batch"; |
| | | import { $t } from "#/locales"; |
| | | |
| | | defineOptions({ name: "MesProBagCodeBindBatch" }); |
| | | |
| | | interface ModalData { ids: number[] } |
| | | const emit = defineEmits(["success"]); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { componentProps: { class: "w-full" }, labelWidth: 100 }, |
| | | layout: "horizontal", schema: [], showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) return; |
| | | const data = modalApi.getData<ModalData>(); |
| | | const values = await formApi.getValues(); |
| | | modalApi.lock(); |
| | | try { |
| | | await bindBagCodeBatch({ batchId: values.batchId, ids: data.ids }); |
| | | message.success($t("ui.actionMessage.operationSuccess")); |
| | | emit("success"); |
| | | await modalApi.close(); |
| | | } finally { modalApi.unlock(); } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) return; |
| | | modalApi.lock(); |
| | | try { |
| | | const batches = await getBatchSimpleList(); |
| | | // ä»
å·²è¡¥å½æ£å¼ä¿¡æ¯ï¼æ¹æ¬¡å·é空ï¼ä¸ç产ä¸çæ¹æ¬¡å
许å½å
¥è¢ç |
| | | const options = batches |
| | | .filter( |
| | | (batch) => |
| | | batch.status === MesProBatchStatusEnum.PRODUCING && batch.code, |
| | | ) |
| | | .map((batch) => ({ label: batch.code!, value: batch.id! })); |
| | | const schema: VbenFormSchema[] = [{ |
| | | fieldName: "batchId", label: "çäº§æ¹æ¬¡", component: "Select", |
| | | componentProps: { options, optionFilterProp: "label", placeholder: "è¯·éæ©ç产ä¸çæ¹æ¬¡", showSearch: true }, |
| | | rules: "selectRequired", |
| | | }]; |
| | | await formApi.setState({ schema }); |
| | | } finally { modalApi.unlock(); } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal title="å½å
¥çäº§æ¹æ¬¡" class="w-2/5"><Form class="mx-4" /></Modal> |
| | | </template> |
| | |
| | | import type { MesProBagCodeApi } from "#/api/mes/pro/bagCode"; |
| | | |
| | | import { useVbenModal } from "@vben/common-ui"; |
| | | import { MesProBatchStatusEnum } from "@vben/constants"; |
| | | |
| | | import { message } from "ant-design-vue"; |
| | | |
| | | import { useVbenForm } from "#/adapter/form"; |
| | | import { generateBagCodes } from "#/api/mes/pro/bagCode"; |
| | | import { getBatchSimpleList } from "#/api/mes/pro/batch"; |
| | | |
| | | defineOptions({ name: "MesProBagCodeGenerateForm" }); |
| | | |
| | | const emit = defineEmits(["success"]); |
| | | |
| | | /** æå»ºè¡¨åï¼æ¹æ¬¡ä¸æé项ç±å¤é¨å 载注å
¥ï¼ */ |
| | | function buildSchema(batchOptions: { label: string; value: number }[]): VbenFormSchema[] { |
| | | function buildSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: "batchId", |
| | | label: "çäº§æ¹æ¬¡", |
| | | component: "Select", |
| | | componentProps: { |
| | | options: batchOptions, |
| | | optionFilterProp: "label", |
| | | placeholder: "è¯·éæ©ç产ä¸çæ¹æ¬¡", |
| | | showSearch: true, |
| | | }, |
| | | rules: "selectRequired", |
| | | }, |
| | | { |
| | | fieldName: "count", |
| | | label: "çæè¢æ°", |
| | |
| | | if (!isOpen) return; |
| | | modalApi.lock(); |
| | | try { |
| | | // ä»
ç产ä¸çæ¹æ¬¡å
许çæè¢ç |
| | | const batches = await getBatchSimpleList(); |
| | | const options = batches |
| | | .filter( |
| | | (batch) => batch.status === MesProBatchStatusEnum.PRODUCING |
| | | ) |
| | | .map((batch) => ({ |
| | | label: batch.code!, |
| | | value: batch.id!, |
| | | })); |
| | | await formApi.setState({ schema: buildSchema(options) }); |
| | | await formApi.setState({ schema: buildSchema() }); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | |
| | | import { UserSelect } from '#/views/system/user/components'; |
| | | import { getRangePickerDefaultProps } from '#/utils'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'detail' | 'update'; |
| | | /** 表åç±»åï¼fillï¼ä¸´æ¶æ¹æ¬¡ç è¡¥å½æ£å¼ä¿¡æ¯ï¼ */ |
| | | export type FormType = 'create' | 'detail' | 'update' | 'fill'; |
| | | |
| | | /** æ°å¢/ä¿®æ¹ç表å */ |
| | | export function useFormSchema(formType: FormType): VbenFormSchema[] { |
| | |
| | | component: 'Input', |
| | | componentProps: { |
| | | disabled: true, |
| | | placeholder: 'ä¿ååèªå¨çæ', |
| | | placeholder: 'è¡¥å½åèªå¨çæ', |
| | | }, |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => formType !== 'create', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'tempCode', |
| | | label: 'ä¸´æ¶æ¹æ¬¡ç ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | disabled: true, |
| | | placeholder: 'é¢çæäºç»´ç é¶æ®µä½¿ç¨ç临æ¶ç ', |
| | | }, |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => formType === 'fill', |
| | | }, |
| | | }, |
| | | { |
| | |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 300, |
| | | width: 350, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | |
| | | import { MesProBatchStatusEnum } from "@vben/constants"; |
| | | import { downloadFileFromBlobPart } from "@vben/utils"; |
| | | |
| | | import { Button, message } from "ant-design-vue"; |
| | | import { Button, message, Modal, Tag } from "ant-design-vue"; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from "#/adapter/vxe-table"; |
| | | import { |
| | |
| | | |
| | | import { useGridColumns, useGridFormSchema } from "./data"; |
| | | import Form from "./modules/form.vue"; |
| | | import PreGenerateModal from "./modules/pre-generate.vue"; |
| | | import QrTraceModal from "../components/qr-trace-modal.vue"; |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [PreGenerateModalApi, preGenerateModalApi] = useVbenModal({ |
| | | connectedComponent: PreGenerateModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | |
| | | qrTraceQueryModalApi.open(); |
| | | } |
| | | |
| | | /** æ¥çäºç»´ç ï¼è¡å
é¢å¡«ç å¼ï¼ */ |
| | | /** è·åæ¹æ¬¡æ¾ç¤ºç¨çç å¼ï¼æ£å¼æ¹æ¬¡å·ä¼å
ï¼å
¶æ¬¡ä¸´æ¶æ¹æ¬¡ç ï¼ */ |
| | | function getDisplayCode(row: MesProBatchApi.Batch) { |
| | | return row.code || row.tempCode || ""; |
| | | } |
| | | |
| | | /** æ¥çäºç»´ç ï¼è¡å
é¢å¡«ç å¼ï¼ä¸´æ¶æ¹æ¬¡ç¨ä¸´æ¶æ¹æ¬¡ç ï¼ */ |
| | | function handleViewQr(row: MesProBatchApi.Batch) { |
| | | qrTraceQueryModalApi.setData({ code: row.code }).open(); |
| | | qrTraceQueryModalApi.setData({ code: getDisplayCode(row) }).open(); |
| | | } |
| | | |
| | | /** æå°æ´å¥äºç»´ç ï¼æ¹æ¬¡å¾ + å
¨é¨æçå¾ ZIPï¼ */ |
| | | async function handlePrintQrSet(row: MesProBatchApi.Batch) { |
| | | const data = await exportBatchQr(row.id!); |
| | | downloadFileFromBlobPart({ |
| | | fileName: `æ¹æ¬¡äºç»´ç -${row.code}.zip`, |
| | | fileName: `æ¹æ¬¡äºç»´ç -${getDisplayCode(row)}.zip`, |
| | | source: data, |
| | | }); |
| | | } |
| | | |
| | | /** é¢çææ¹æ¬¡äºç»´ç æåï¼å±ç¤ºçæçä¸´æ¶æ¹æ¬¡ç */ |
| | | function handlePreGenerateSuccess(result: { id: number; tempCode: string }[]) { |
| | | Modal.success({ |
| | | title: "é¢çæä¸´æ¶æ¹æ¬¡ç æå", |
| | | content: result.map((item) => item.tempCode).join("\n"), |
| | | centered: true, |
| | | }); |
| | | } |
| | | |
| | | /** æ°å¢æ¹æ¬¡ */ |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: "create" }).open(); |
| | | } |
| | | |
| | | /** ä¸´æ¶æ¹æ¬¡è¡¥å½æ£å¼ä¿¡æ¯ */ |
| | | function handleFillInfo(row: MesProBatchApi.Batch) { |
| | | formModalApi.setData({ formType: "fill", id: row.id }).open(); |
| | | } |
| | | |
| | | /** é¢çææ¹æ¬¡äºç»´ç */ |
| | | function handlePreGenerate() { |
| | | preGenerateModalApi.open(); |
| | | } |
| | | |
| | | /** æ¥ç详æ
*/ |
| | |
| | | /** å 餿¹æ¬¡ */ |
| | | async function handleDelete(row: MesProBatchApi.Batch) { |
| | | await deleteBatch(row.id!); |
| | | message.success($t("ui.actionMessage.deleteSuccess", [row.code])); |
| | | message.success($t("ui.actionMessage.deleteSuccess", [getDisplayCode(row)])); |
| | | handleRefresh(); |
| | | } |
| | | |
| | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <PreGenerateModalApi @success="handlePreGenerateSuccess" /> |
| | | <QrTraceQueryModal /> |
| | | <Grid table-title="çäº§æ¹æ¬¡å表"> |
| | | <template #toolbar-tools> |
| | | <TableAction :actions="[ |
| | | { |
| | | label: 'é¢çæäºç»´ç ', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mes:pro-batch:create'], |
| | | onClick: handlePreGenerate, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.create', ['æ¹æ¬¡']), |
| | | type: 'primary', |
| | |
| | | </template> |
| | | <template #code="{ row }"> |
| | | <Button type="link" @click="handleDetail(row)"> |
| | | {{ row.code }} |
| | | {{ getDisplayCode(row) }} |
| | | </Button> |
| | | <Tag v-if="!row.code" color="warning">å¾
è¡¥å½</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction :actions="[ |
| | |
| | | onClick: handleViewQr.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'è¡¥å½ä¿¡æ¯', |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:pro-batch:update'], |
| | | ifShow: !row.code, |
| | | onClick: handleFillInfo.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:pro-batch:update'], |
| | | ifShow: |
| | | row.status === MesProBatchStatusEnum.DRAFT || |
| | | row.status === MesProBatchStatusEnum.PRODUCING, |
| | | (row.status === MesProBatchStatusEnum.DRAFT || |
| | | row.status === MesProBatchStatusEnum.PRODUCING) && |
| | | !!row.code, |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | row.status === MesProBatchStatusEnum.DRAFT || |
| | | row.status === MesProBatchStatusEnum.CANCELED, |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.code]), |
| | | title: $t('ui.actionMessage.deleteConfirm', [getDisplayCode(row)]), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | |
| | | { |
| | | label: 'å¼å§ç产', |
| | | auth: ['mes:pro-batch:update'], |
| | | ifShow: row.status === MesProBatchStatusEnum.DRAFT, |
| | | ifShow: row.status === MesProBatchStatusEnum.DRAFT && !!row.code, |
| | | popConfirm: { |
| | | title: '确认å¼å§çäº§è¯¥æ¹æ¬¡åï¼', |
| | | confirm: () => |
| | |
| | | |
| | | import { useVbenForm } from "#/adapter/form"; |
| | | import { TableAction, useVbenVxeGrid } from "#/adapter/vxe-table"; |
| | | import { createBatch, getBatch, updateBatch } from "#/api/mes/pro/batch"; |
| | | import { |
| | | createBatch, |
| | | fillBatchInfo, |
| | | getBatch, |
| | | updateBatch, |
| | | } from "#/api/mes/pro/batch"; |
| | | import { $t } from "#/locales"; |
| | | import { UserSelect } from "#/views/system/user/components"; |
| | | |
| | |
| | | const formData = ref<MesProBatchApi.Batch>(); |
| | | |
| | | const isEditable = computed(() => |
| | | ["create", "update"].includes(formType.value) |
| | | ["create", "update", "fill"].includes(formType.value) |
| | | ); |
| | | |
| | | const getTitle = computed(() => { |
| | |
| | | } |
| | | case "update": { |
| | | return $t("ui.actionTitle.edit", ["çäº§æ¹æ¬¡"]); |
| | | } |
| | | case "fill": { |
| | | return "è¡¥å½æ¹æ¬¡ä¿¡æ¯"; |
| | | } |
| | | default: { |
| | | return $t("ui.actionTitle.create", ["çäº§æ¹æ¬¡"]); |
| | |
| | | modalApi.lock(); |
| | | try { |
| | | const data = (await formApi.getValues()) as MesProBatchApi.Batch; |
| | | if (formData.value?.id) { |
| | | if (formType.value === "fill") { |
| | | await fillBatchInfo({ ...data, id: formData.value!.id, workers }); |
| | | } else if (formData.value?.id) { |
| | | await updateBatch({ ...data, id: formData.value.id, workers }); |
| | | } else { |
| | | await createBatch({ ...data, workers }); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VbenFormSchema } from "#/adapter/form"; |
| | | import type { MesProBatchApi } from "#/api/mes/pro/batch"; |
| | | |
| | | import { useVbenModal } from "@vben/common-ui"; |
| | | |
| | | import { message } from "ant-design-vue"; |
| | | |
| | | import { useVbenForm } from "#/adapter/form"; |
| | | import { preGenerateBatch } from "#/api/mes/pro/batch"; |
| | | |
| | | defineOptions({ name: "MesProBatchPreGenerate" }); |
| | | |
| | | const emit = defineEmits(["success"]); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: "w-full", |
| | | }, |
| | | labelWidth: 100, |
| | | }, |
| | | layout: "horizontal", |
| | | schema: [], |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) return; |
| | | modalApi.lock(); |
| | | try { |
| | | const values = await formApi.getValues(); |
| | | const result = await preGenerateBatch({ |
| | | count: values.count, |
| | | remark: values.remark, |
| | | }); |
| | | message.success(`å·²çæ ${result.length} ä¸ªä¸´æ¶æ¹æ¬¡ç `); |
| | | emit("success", result); |
| | | await modalApi.close(); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) return; |
| | | const schema: VbenFormSchema[] = [ |
| | | { |
| | | fieldName: "count", |
| | | label: "çæä¸ªæ°", |
| | | component: "InputNumber", |
| | | componentProps: { |
| | | class: "!w-full", |
| | | min: 1, |
| | | placeholder: "请è¾å
¥éè¦çæçæ¹æ¬¡ä¸ªæ°", |
| | | precision: 0, |
| | | }, |
| | | rules: "required", |
| | | }, |
| | | { |
| | | fieldName: "remark", |
| | | label: "夿³¨", |
| | | component: "Textarea", |
| | | componentProps: { |
| | | placeholder: "请è¾å
¥å¤æ³¨", |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | | formApi.setState({ schema }); |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal title="é¢çææ¹æ¬¡äºç»´ç " class="w-2/5"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| | |
| | | |
| | | const traceTypeLabel = ref(""); |
| | | |
| | | /** è¯å«äºç»´ç å
容类åï¼æ¹æ¬¡å· / æçç / è¢ç */ |
| | | /** è¯å«äºç»´ç å
容类åï¼æ¹æ¬¡å·ï¼å«ä¸´æ¶æ¹æ¬¡ç ï¼/ æçç ï¼å«ä¸´æ¶æçç ï¼/ è¢ç */ |
| | | function resolveCodeType(raw: string): TraceType | undefined { |
| | | const value = raw.trim().toUpperCase(); |
| | | if (/^PB-\d{8}$/.test(value)) { |
| | | return "batch"; |
| | | } |
| | | if (/^PL-\d{8}$/.test(value)) { |
| | | return "pallet"; |
| | | } |
| | | if (/^.*-P\d{2}$/.test(value)) { |
| | | return "pallet"; |
| | | } |
| | | if (/^.*-\d{4}$/.test(value)) { |
| | | if (/^BAG-\d{8}$/.test(value) || /^.*-\d{4}$/.test(value)) { |
| | | return "bag"; |
| | | } |
| | | return "batch"; |
| | |
| | | if (traceType.value === "pallet" && palletTrace.value) { |
| | | const d = palletTrace.value; |
| | | return [ |
| | | { label: "æçç ", value: d.code || "" }, |
| | | { label: "æçç ", value: d.code || d.tempCode || "" }, |
| | | { label: "æçåºå·", value: d.palletNo ? String(d.palletNo) : "" }, |
| | | { label: "æ¹æ¬¡å·", value: d.batchCode || "" }, |
| | | { label: "åç§", value: d.itemName || "" }, |
| | |
| | | if (batchTrace.value) { |
| | | const d = batchTrace.value; |
| | | return [ |
| | | { label: "æ¹æ¬¡å·", value: d.code || "" }, |
| | | { label: "æ¹æ¬¡å·", value: d.code || d.tempCode || "" }, |
| | | { label: "åç§", value: d.itemName || "" }, |
| | | { label: "è§æ ¼", value: d.itemSpecification || "" }, |
| | | { |
| | |
| | | schema: [ |
| | | { |
| | | field: "code", |
| | | label: "æçç ï¼äºç»´ç å
容ï¼", |
| | | label: "æçç ï¼æ£å¼æçç ï¼", |
| | | span: 2, |
| | | }, |
| | | { |
| | | field: "tempCode", |
| | | label: "ä¸´æ¶æçç ï¼æªç»å®æ¹æ¬¡ï¼", |
| | | span: 2, |
| | | }, |
| | | { |
| | |
| | | schema: [ |
| | | { |
| | | field: "code", |
| | | label: "æ¹æ¬¡å·ï¼äºç»´ç å
容ï¼", |
| | | label: "æ¹æ¬¡å·ï¼æ£å¼æ¹æ¬¡å·ï¼", |
| | | span: 2, |
| | | }, |
| | | { |
| | | field: "tempCode", |
| | | label: "ä¸´æ¶æ¹æ¬¡ç ï¼å¾
è¡¥å½ï¼", |
| | | span: 2, |
| | | }, |
| | | { |
| | |
| | | <p class="text-lg font-bold break-all">{{ currentCode }}</p> |
| | | <p class="mt-1 text-xs text-gray-500"> |
| | | ç ç±»åï¼{{ traceTypeLabel }} |
| | | <Tag |
| | | v-if="traceType === 'batch' && batchTrace && !batchTrace.code" |
| | | color="warning" |
| | | class="ml-2" |
| | | > |
| | | å¾
è¡¥å½ |
| | | </Tag> |
| | | <Tag |
| | | v-else-if=" |
| | | traceType === 'pallet' && palletTrace && !palletTrace.code |
| | | " |
| | | color="warning" |
| | | class="ml-2" |
| | | > |
| | | æªç»å®æ¹æ¬¡ |
| | | </Tag> |
| | | </p> |
| | | </div> |
| | | </div> |
| | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions<MesProPalletApi.Pallet>['columns'] { |
| | | return [ |
| | | { type: 'checkbox', width: 50 }, |
| | | { |
| | | field: 'code', |
| | | title: 'æçç ', |
| | | fixed: 'left', |
| | | minWidth: 210, |
| | | slots: { default: 'code' }, |
| | | }, |
| | | { |
| | | field: 'palletNo', |
| | |
| | | field: 'batchCode', |
| | | title: 'æ¹æ¬¡å·', |
| | | minWidth: 190, |
| | | slots: { default: 'batchCode' }, |
| | | }, |
| | | { |
| | | field: 'capacity', |
| | |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 200, |
| | | width: 350, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | |
| | | import { Page, useVbenModal } from "@vben/common-ui"; |
| | | import { downloadFileFromBlobPart } from "@vben/utils"; |
| | | |
| | | import { message } from "ant-design-vue"; |
| | | import { message, Modal, Tag } from "ant-design-vue"; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from "#/adapter/vxe-table"; |
| | | import { |
| | | deletePallet, |
| | | exportPalletExcel, |
| | | exportPalletQr, |
| | | exportPalletQrByIds, |
| | | getPalletPage, |
| | | } from "#/api/mes/pro/pallet"; |
| | | import { $t } from "#/locales"; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from "./data"; |
| | | import BindBatchModal from "./modules/bind-batch.vue"; |
| | | import GenerateModal from "./modules/generate-form.vue"; |
| | | import QrTraceModal from "../components/qr-trace-modal.vue"; |
| | | |
| | |
| | | |
| | | const [GenerateFormModal, generateFormModalApi] = useVbenModal({ |
| | | connectedComponent: GenerateModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [BindBatchFormModal, bindBatchFormModalApi] = useVbenModal({ |
| | | connectedComponent: BindBatchModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** æ¹éçææçç */ |
| | | /** æ¹éé¢çææçç */ |
| | | function handleCreate() { |
| | | generateFormModalApi.open(); |
| | | } |
| | | |
| | | /** é¢çææåï¼å±ç¤ºçæçä¸´æ¶æçç */ |
| | | function handlePreGenerateSuccess(result: { id: number; tempCode: string }[]) { |
| | | Modal.success({ |
| | | title: "é¢çæä¸´æ¶æçç æå", |
| | | content: result.map((item) => item.tempCode).join("\n"), |
| | | centered: true, |
| | | }); |
| | | } |
| | | |
| | | /** æ«ç 追溯 */ |
| | |
| | | qrTraceQueryModalApi.open(); |
| | | } |
| | | |
| | | /** æ¥çäºç»´ç ï¼è¡å
é¢å¡«ç å¼ï¼ */ |
| | | /** è·åæçæ¾ç¤ºç¨çç å¼ï¼æ£å¼æçç ä¼å
ï¼å
¶æ¬¡ä¸´æ¶æçç ï¼ */ |
| | | function getDisplayCode(row: MesProPalletApi.Pallet) { |
| | | return row.code || row.tempCode || ""; |
| | | } |
| | | |
| | | /** æ¥çäºç»´ç ï¼è¡å
é¢å¡«ç å¼ï¼ä¸´æ¶æçç¨ä¸´æ¶æçç ï¼ */ |
| | | function handleViewQr(row: MesProPalletApi.Pallet) { |
| | | qrTraceQueryModalApi.setData({ code: row.code }).open(); |
| | | qrTraceQueryModalApi.setData({ code: getDisplayCode(row) }).open(); |
| | | } |
| | | |
| | | /** è·åå¾éçä¸´æ¶æçè®°å½ */ |
| | | function getSelectedTempPallets(): MesProPalletApi.Pallet[] | undefined { |
| | | const records = [ |
| | | ...(gridApi.grid.getCheckboxReserveRecords?.() ?? []), |
| | | ...(gridApi.grid.getCheckboxRecords?.() ?? []), |
| | | ] as MesProPalletApi.Pallet[]; |
| | | const uniqueRecords = [ |
| | | ...new Map(records.map((record) => [record.id, record])).values(), |
| | | ]; |
| | | const tempRecords = uniqueRecords.filter((record) => !record.batchId); |
| | | if (uniqueRecords.length === 0) { |
| | | message.warning("请è³å°å¾é䏿¡æçç è®°å½"); |
| | | return undefined; |
| | | } |
| | | if (tempRecords.length === 0) { |
| | | message.warning("å¾éçè®°å½åå·²ç»å®æ¹æ¬¡ï¼æ éç»å®"); |
| | | return undefined; |
| | | } |
| | | return tempRecords; |
| | | } |
| | | |
| | | /** ç»å®æ¹æ¬¡ */ |
| | | function handleBindBatch() { |
| | | const records = getSelectedTempPallets(); |
| | | if (!records) return; |
| | | bindBatchFormModalApi |
| | | .setData({ ids: records.map((record) => record.id!) }) |
| | | .open(); |
| | | } |
| | | |
| | | /** 导åºäºç»´ç ZIPï¼æå½åæ¥è¯¢æ¡ä»¶çæ¹æ¬¡ï¼ */ |
| | |
| | | downloadFileFromBlobPart({ fileName: "æçç äºç»´ç .zip", source: data }); |
| | | } |
| | | |
| | | /** 导åºå个æçç äºç»´ç ZIPï¼æ¯ææªç»å®æ¹æ¬¡çä¸´æ¶æçï¼ */ |
| | | async function handleExportQrById(row: MesProPalletApi.Pallet) { |
| | | const data = await exportPalletQrByIds([row.id!]); |
| | | downloadFileFromBlobPart({ |
| | | fileName: `æçç äºç»´ç -${getDisplayCode(row)}.zip`, |
| | | source: data, |
| | | }); |
| | | } |
| | | |
| | | /** å 餿çç */ |
| | | async function handleDelete(row: MesProPalletApi.Pallet) { |
| | | await deletePallet(row.id!); |
| | | message.success($t("ui.actionMessage.deleteSuccess", [row.code])); |
| | | message.success($t("ui.actionMessage.deleteSuccess", [getDisplayCode(row)])); |
| | | handleRefresh(); |
| | | } |
| | | |
| | |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | checkboxConfig: { |
| | | highlight: true, |
| | | reserve: true, |
| | | }, |
| | | columns: useGridColumns(), |
| | | height: "auto", |
| | | keepSource: true, |
| | |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <GenerateFormModal @success="handleRefresh" /> |
| | | <GenerateFormModal @success="handlePreGenerateSuccess" /> |
| | | <BindBatchFormModal @success="handleRefresh" /> |
| | | <QrTraceQueryModal /> |
| | | <Grid table-title="æçç å表"> |
| | | <template #toolbar-tools> |
| | | <TableAction :actions="[ |
| | | { |
| | | label: 'æ¹éçæ', |
| | | label: 'é¢çæäºç»´ç ', |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mes:pro-pallet:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: 'ç»å®æ¹æ¬¡', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:pro-pallet:update'], |
| | | onClick: handleBindBatch, |
| | | }, |
| | | { |
| | | label: 'æ«ç 追溯', |
| | |
| | | }, |
| | | ]" /> |
| | | </template> |
| | | <template #code="{ row }"> |
| | | <span>{{ getDisplayCode(row) }}</span> |
| | | <Tag v-if="!row.code" color="warning">æªç»å®æ¹æ¬¡</Tag> |
| | | </template> |
| | | <template #batchCode="{ row }"> |
| | | <span v-if="row.batchCode">{{ row.batchCode }}</span> |
| | | <Tag v-else color="warning">æªç»å®æ¹æ¬¡</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction :actions="[ |
| | | { |
| | |
| | | onClick: handleViewQr.bind(null, row), |
| | | }, |
| | | { |
| | | label: '导åºäºç»´ç ', |
| | | type: 'link', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['mes:pro-pallet:export'], |
| | | onClick: handleExportQrById.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | |
| | | auth: ['mes:pro-pallet:delete'], |
| | | ifShow: !row.bagCount, |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.code]), |
| | | title: $t('ui.actionMessage.deleteConfirm', [getDisplayCode(row)]), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VbenFormSchema } from "#/adapter/form"; |
| | | |
| | | import { useVbenModal } from "@vben/common-ui"; |
| | | import { MesProBatchStatusEnum } from "@vben/constants"; |
| | | |
| | | import { message } from "ant-design-vue"; |
| | | |
| | | import { useVbenForm } from "#/adapter/form"; |
| | | import { getBatchSimpleList } from "#/api/mes/pro/batch"; |
| | | import { bindPalletBatch } from "#/api/mes/pro/pallet"; |
| | | import { $t } from "#/locales"; |
| | | |
| | | defineOptions({ name: "MesProPalletBindBatch" }); |
| | | |
| | | interface ModalData { |
| | | ids: number[]; |
| | | } |
| | | |
| | | const emit = defineEmits(["success"]); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: "w-full", |
| | | }, |
| | | labelWidth: 100, |
| | | }, |
| | | layout: "horizontal", |
| | | schema: [], |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) return; |
| | | const data = modalApi.getData<ModalData>(); |
| | | const values = await formApi.getValues(); |
| | | modalApi.lock(); |
| | | try { |
| | | await bindPalletBatch({ batchId: values.batchId, ids: data.ids }); |
| | | message.success($t("ui.actionMessage.operationSuccess")); |
| | | emit("success"); |
| | | await modalApi.close(); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) return; |
| | | modalApi.lock(); |
| | | try { |
| | | // ä»
å·²è¡¥å½æ£å¼ä¿¡æ¯ä¸ç产ä¸çæ¹æ¬¡å
许ç»å® |
| | | const batches = await getBatchSimpleList(); |
| | | const options = batches |
| | | .filter( |
| | | (batch) => |
| | | batch.status === MesProBatchStatusEnum.PRODUCING && batch.code, |
| | | ) |
| | | .map((batch) => ({ label: batch.code!, value: batch.id! })); |
| | | const schema: VbenFormSchema[] = [ |
| | | { |
| | | fieldName: "batchId", |
| | | label: "çäº§æ¹æ¬¡", |
| | | component: "Select", |
| | | componentProps: { |
| | | options, |
| | | optionFilterProp: "label", |
| | | placeholder: "è¯·éæ©å·²è¡¥å½ä¸ç产ä¸çæ¹æ¬¡", |
| | | showSearch: true, |
| | | }, |
| | | rules: "selectRequired", |
| | | }, |
| | | ]; |
| | | await formApi.setState({ schema }); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal title="æçç ç»å®çäº§æ¹æ¬¡" class="w-2/5"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| | |
| | | <script lang="ts" setup> |
| | | import type { VbenFormSchema } from "#/adapter/form"; |
| | | import type { MesProPalletApi } from "#/api/mes/pro/pallet"; |
| | | |
| | | import { useVbenModal } from "@vben/common-ui"; |
| | | import { MesProBatchStatusEnum } from "@vben/constants"; |
| | | |
| | | import { message } from "ant-design-vue"; |
| | | |
| | | import { useVbenForm } from "#/adapter/form"; |
| | | import { getBatchSimpleList } from "#/api/mes/pro/batch"; |
| | | import { batchCreatePallet } from "#/api/mes/pro/pallet"; |
| | | import { preGeneratePallet } from "#/api/mes/pro/pallet"; |
| | | |
| | | defineOptions({ name: "MesProPalletGenerateForm" }); |
| | | |
| | | const emit = defineEmits(["success"]); |
| | | |
| | | /** æå»ºè¡¨åï¼æ¹æ¬¡ä¸æé项ç±å¤é¨å 载注å
¥ï¼ */ |
| | | function buildSchema(batchOptions: { label: string; value: number }[]): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: "batchId", |
| | | label: "çäº§æ¹æ¬¡", |
| | | component: "Select", |
| | | componentProps: { |
| | | options: batchOptions, |
| | | optionFilterProp: "label", |
| | | placeholder: "è¯·éæ©ç产ä¸çæ¹æ¬¡", |
| | | showSearch: true, |
| | | }, |
| | | rules: "selectRequired", |
| | | }, |
| | | { |
| | | fieldName: "count", |
| | | label: "çææ°é", |
| | | component: "InputNumber", |
| | | componentProps: { |
| | | class: "!w-full", |
| | | min: 1, |
| | | placeholder: "请è¾å
¥éè¦çæçæçæ°é", |
| | | precision: 0, |
| | | }, |
| | | rules: "required", |
| | | }, |
| | | { |
| | | fieldName: "capacity", |
| | | label: "å¯è£
è¢æ°", |
| | | component: "InputNumber", |
| | | componentProps: { |
| | | class: "!w-full", |
| | | min: 1, |
| | | placeholder: "请è¾å
¥æ¯æçå¯è£
è¢æ°ï¼è¢/æçï¼", |
| | | precision: 0, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: "remark", |
| | | label: "夿³¨", |
| | | component: "Textarea", |
| | | componentProps: { |
| | | placeholder: "请è¾å
¥å¤æ³¨", |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | |
| | | if (!valid) return; |
| | | modalApi.lock(); |
| | | try { |
| | | const values = |
| | | (await formApi.getValues()) as MesProPalletApi.BatchCreateParams; |
| | | const ids = await batchCreatePallet(values); |
| | | message.success(`å·²æåçæ ${ids.length} 个æçç `); |
| | | emit("success"); |
| | | const values = await formApi.getValues(); |
| | | const result = await preGeneratePallet({ |
| | | count: values.count, |
| | | capacity: values.capacity, |
| | | remark: values.remark, |
| | | }); |
| | | message.success(`å·²çæ ${result.length} ä¸ªä¸´æ¶æçç `); |
| | | emit("success", result); |
| | | await modalApi.close(); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) return; |
| | | modalApi.lock(); |
| | | try { |
| | | // ä»
ç产ä¸çæ¹æ¬¡å
è®¸çææçç |
| | | const batches = await getBatchSimpleList(); |
| | | const options = batches |
| | | .filter( |
| | | (batch) => batch.status === MesProBatchStatusEnum.PRODUCING |
| | | ) |
| | | .map((batch) => ({ |
| | | label: batch.code!, |
| | | value: batch.id!, |
| | | })); |
| | | await formApi.setState({ schema: buildSchema(options) }); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | const schema: VbenFormSchema[] = [ |
| | | { |
| | | fieldName: "count", |
| | | label: "çææ°é", |
| | | component: "InputNumber", |
| | | componentProps: { |
| | | class: "!w-full", |
| | | min: 1, |
| | | placeholder: "请è¾å
¥éè¦çæçæçæ°é", |
| | | precision: 0, |
| | | }, |
| | | rules: "required", |
| | | }, |
| | | { |
| | | fieldName: "capacity", |
| | | label: "å¯è£
è¢æ°", |
| | | component: "InputNumber", |
| | | componentProps: { |
| | | class: "!w-full", |
| | | min: 1, |
| | | placeholder: "请è¾å
¥æ¯æçå¯è£
è¢æ°ï¼è¢/æçï¼", |
| | | precision: 0, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: "remark", |
| | | label: "夿³¨", |
| | | component: "Textarea", |
| | | componentProps: { |
| | | placeholder: "请è¾å
¥å¤æ³¨", |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | | formApi.setState({ schema }); |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal title="æ¹éçææçç " class="w-2/5"> |
| | | <Modal title="é¢çææçäºç»´ç " class="w-2/5"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| | | </template> |