| | |
| | | import { Page, useVbenModal } from "@vben/common-ui"; |
| | | import { downloadFileFromBlobPart } from "@vben/utils"; |
| | | |
| | | import { message } from "ant-design-vue"; |
| | | import { Button, message, Modal, Tag } from "ant-design-vue"; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from "#/adapter/vxe-table"; |
| | | import { |
| | | deletePallet, |
| | | exportPalletExcel, |
| | | exportPalletQr, |
| | | exportPalletQrByIds, |
| | | exportPalletBusinessQr, |
| | | generatePalletBusinessCodes, |
| | | getPalletPage, |
| | | } from "#/api/mes/pro/pallet"; |
| | | import { IconifyIcon } from "@vben/icons"; |
| | | 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"; |
| | | import BusinessQrModal from "../components/business-qr.vue"; |
| | | |
| | | defineOptions({ name: "MesProPallet" }); |
| | | |
| | | const [GenerateFormModal, generateFormModalApi] = useVbenModal({ |
| | | connectedComponent: GenerateModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [BindBatchFormModal, bindBatchFormModalApi] = useVbenModal({ |
| | | connectedComponent: BindBatchModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | |
| | | }); |
| | | |
| | | /** 刷新表格 */ |
| | | const [BusinessQrViewModal, businessQrApi] = useVbenModal({ connectedComponent: BusinessQrModal, destroyOnClose: true }); |
| | | function handleBusinessQr(row: MesProPalletApi.Pallet) { |
| | | businessQrApi.setData({ code: row.businessCode }).open(); |
| | | } |
| | | function getBusinessIds() { |
| | | const records = [...(gridApi.grid.getCheckboxReserveRecords?.() || []), ...(gridApi.grid.getCheckboxRecords?.() || [])] as MesProPalletApi.Pallet[]; |
| | | const ids = [...new Set(records.map(row => row.id).filter((id): id is number => id != null))]; |
| | | if (!ids.length || ids.length > 200) { message.warning('请勾选 1 至 200 条托盘记录'); return; } |
| | | if (records.some(row => row.status === 20)) { message.warning('已作废托盘不可操作业务码'); return; } |
| | | return ids; |
| | | } |
| | | async function handleGenerateBusiness() { |
| | | const ids = getBusinessIds(); if (!ids) return; |
| | | const count = await generatePalletBusinessCodes(ids); |
| | | message.success(`已补生成 ${count} 份业务码,已有码值保持不变`); handleRefresh(); |
| | | } |
| | | async function handleExportBusiness() { |
| | | const ids = getBusinessIds(); if (!ids) return; |
| | | const data = await exportPalletBusinessQr(ids); |
| | | downloadFileFromBlobPart({ fileName: '托盘业务二维码.zip', source: data }); |
| | | } |
| | | |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** 批量生成托盘码 */ |
| | | /** 批量预生成托盘码 */ |
| | | function handleCreate() { |
| | | generateFormModalApi.open(); |
| | | } |
| | | |
| | | /** 预生成成功:刷新列表并展示生成的临时托盘码 */ |
| | | function handlePreGenerateSuccess(result: { id: number; tempCode: string }[]) { |
| | | handleRefresh(); |
| | | 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 /> |
| | | <BusinessQrViewModal /> |
| | | <Grid table-title="托盘码列表"> |
| | | <template #table-title><span class="text-[1rem] font-bold" style="white-space:nowrap">托盘码列表</span></template> |
| | | <template #toolbar-tools> |
| | | <TableAction :actions="[ |
| | | { |
| | | label: '批量生成', |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mes:pro-pallet:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: '扫码追溯', |
| | | icon: ACTION_ICON.SEARCH, |
| | | auth: ['mes:pro-pallet:query'], |
| | | onClick: handleTrace, |
| | | }, |
| | | { |
| | | label: '导出二维码', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['mes:pro-pallet:export'], |
| | | onClick: handleExportQr, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['mes:pro-pallet:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | ]" /> |
| | | <div class="mes-code-toolbar"> |
| | | <TableAction :actions="[{ label: '预生成二维码', type: 'primary', icon: ACTION_ICON.ADD, auth: ['mes:pro-pallet:create'], onClick: handleCreate }, |
| | | { label: '绑定批次', auth: ['mes:pro-pallet:update'], onClick: handleBindBatch }, |
| | | { label: '扫码追溯', icon: ACTION_ICON.SEARCH, auth: ['mes:pro-pallet:query'], onClick: handleTrace }]" /> |
| | | <TableAction :dropdown-trigger="['click']" :drop-down-actions="[{ label: '追溯二维码(按批次)', auth: ['mes:pro-pallet:export'], onClick: handleExportQr }, |
| | | { label: '业务二维码(选中记录)', auth: ['mes:pro-pallet:export'], onClick: handleExportBusiness }, |
| | | { label: 'Excel 数据', auth: ['mes:pro-pallet:export'], onClick: handleExport }]"> |
| | | <template #more><Button>导出 <IconifyIcon icon="lucide:chevron-down" /></Button></template> |
| | | </TableAction> |
| | | <TableAction :dropdown-trigger="['click']" :drop-down-actions="[{ label: '补生成业务码(选中记录)', auth: ['mes:pro-pallet:create'], onClick: handleGenerateBusiness }]"> |
| | | <template #more><Button>更多操作 <IconifyIcon icon="lucide:chevron-down" /></Button></template> |
| | | </TableAction> |
| | | </div> |
| | | </template> |
| | | <template #code="{ row }"> |
| | | <span>{{ getDisplayCode(row) }}</span> |
| | | <Tag v-if="!row.code" color="warning">未绑定批次</Tag> |
| | | <Tag v-if="row.autoGenerated" color="processing">自动生成</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="[ |
| | | { |
| | | label: '查看二维码', |
| | | label: '追溯二维码', |
| | | type: 'link', |
| | | auth: ['mes:pro-pallet:query'], |
| | | onClick: handleViewQr.bind(null, row), |
| | | }, |
| | | { label: '业务二维码', type: 'link', auth: ['mes:pro-pallet:query'], ifShow: !!row.businessCode, onClick: handleBusinessQr.bind(null, row) }, |
| | | { |
| | | label: '导出二维码', |
| | | type: 'link', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['mes:pro-pallet:export'], |
| | | onClick: handleExportQrById.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | |
| | | 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), |
| | | }, |
| | | }, |
| | |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| | | |
| | | <style scoped> |
| | | .mes-code-toolbar { display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px; } |
| | | .mes-code-toolbar :deep(.ant-btn) { white-space:nowrap; } |
| | | .mes-code-toolbar :deep(.ant-btn > .iconify) { display:inline-block;width:14px;height:14px;vertical-align:middle; } |
| | | </style> |