feat(@vben/web-antdv-next): add MES SN detail view

- add SN detail API and row type

- add SN detail modal with barcode action

- add clickable SN count and detail action in SN list
pull/369/head
XuZhiqiang 2026-06-20 23:55:07 +08:00
parent 9f611f89fc
commit 29d943ae03
4 changed files with 202 additions and 1 deletions

View File

@ -17,6 +17,21 @@ export namespace MesWmSnApi {
createTime?: Date; // 生成时间
}
/** MES SN 码明细 */
export interface Sn {
id?: number; // 编号
uuid?: string; // 批次 UUID
code?: string; // SN 码
itemId?: number; // 物料编号
itemCode?: string; // 物料编码
itemName?: string; // 物料名称
specification?: string; // 规格型号
unitName?: string; // 单位名称
batchCode?: string; // 批次号
workOrderId?: number; // 生产工单编号
createTime?: Date; // 生成时间
}
/** MES SN 码生成参数 */
export interface SnGenerate {
itemId?: number; // 物料编号
@ -48,6 +63,13 @@ export function getSnGroupPage(params: MesWmSnApi.PageParams) {
);
}
/** 查询批次 SN 码明细列表 */
export function getSnListByUuid(uuid: string) {
return requestClient.get<MesWmSnApi.Sn[]>('/mes/wm/sn/list-by-uuid', {
params: { uuid },
});
}
/** 批量删除 SN 码(按批次 UUID */
export function deleteSnBatch(uuid: string) {
return requestClient.delete('/mes/wm/sn/delete-batch', {

View File

@ -117,6 +117,7 @@ export function useGridColumns(): VxeTableGridOptions<MesWmSnApi.SnGroup>['colum
field: 'count',
title: 'SN 码数量',
width: 100,
slots: { default: 'count' },
},
{
field: 'createTime',
@ -126,7 +127,55 @@ export function useGridColumns(): VxeTableGridOptions<MesWmSnApi.SnGroup>['colum
},
{
title: '操作',
width: 180,
width: 240,
fixed: 'right',
slots: { default: 'actions' },
},
];
}
/** SN 码明细弹窗的字段 */
export function useDetailGridColumns(): VxeTableGridOptions<MesWmSnApi.Sn>['columns'] {
return [
{
field: 'code',
title: 'SN 码',
minWidth: 180,
},
{
field: 'itemCode',
title: '物料编码',
minWidth: 120,
},
{
field: 'itemName',
title: '物料名称',
minWidth: 150,
},
{
field: 'specification',
title: '规格型号',
minWidth: 120,
},
{
field: 'unitName',
title: '单位',
width: 80,
},
{
field: 'batchCode',
title: '批次号',
minWidth: 120,
},
{
field: 'createTime',
title: '生成时间',
width: 180,
formatter: 'formatDateTime',
},
{
title: '操作',
width: 100,
fixed: 'right',
slots: { default: 'actions' },
},

View File

@ -17,6 +17,7 @@ import {
import { $t } from '#/locales';
import { useGridColumns, useGridFormSchema } from './data';
import Detail from './modules/detail.vue';
import Form from './modules/form.vue';
const [FormModal, formModalApi] = useVbenModal({
@ -24,6 +25,11 @@ const [FormModal, formModalApi] = useVbenModal({
destroyOnClose: true,
});
const [DetailModal, detailModalApi] = useVbenModal({
connectedComponent: Detail,
destroyOnClose: true,
});
/** 刷新表格 */
function handleRefresh() {
gridApi.query();
@ -46,6 +52,11 @@ async function handleExportDetail(row: MesWmSnApi.SnGroup) {
downloadFileFromBlobPart({ fileName: 'SN码明细.xls', source: data });
}
/** 查看 SN 码明细 */
function handleDetail(row: MesWmSnApi.SnGroup) {
detailModalApi.setData(row).open();
}
/** 删除 SN 码批次 */
async function handleDelete(row: MesWmSnApi.SnGroup) {
const hideLoading = message.loading({
@ -104,6 +115,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
</template>
<FormModal @success="handleRefresh" />
<DetailModal />
<Grid table-title="SN ">
<template #toolbar-tools>
@ -126,9 +138,27 @@ const [Grid, gridApi] = useVbenVxeGrid({
]"
/>
</template>
<template #count="{ row }">
<TableAction
:actions="[
{
label: `${row.count ?? 0}`,
type: 'link',
auth: ['mes:wm-sn:query'],
onClick: handleDetail.bind(null, row),
},
]"
/>
</template>
<template #actions="{ row }">
<TableAction
:actions="[
{
label: '查看明细',
type: 'link',
auth: ['mes:wm-sn:query'],
onClick: handleDetail.bind(null, row),
},
{
label: '导出明细',
type: 'link',

View File

@ -0,0 +1,100 @@
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesWmSnApi } from '#/api/mes/wm/sn';
import { nextTick, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { BarcodeBizTypeEnum } from '@vben/constants';
import { message } from 'antdv-next';
import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { getSnListByUuid } from '#/api/mes/wm/sn';
import { BarcodeDetail } from '#/views/mes/wm/barcode/components';
import { useDetailGridColumns } from '../data';
defineOptions({ name: 'MesWmSnDetail' });
const barcodeDetailRef = ref<InstanceType<typeof BarcodeDetail>>();
/** 查看 SN 码条码 */
function handleBarcode(row: MesWmSnApi.Sn) {
if (!row.id) {
message.warning('缺少 SN 码编号,无法查看条码');
return;
}
barcodeDetailRef.value?.openByBusiness(
row.id,
BarcodeBizTypeEnum.SN,
row.code,
row.itemName || row.code,
);
}
/** 加载 SN 码明细 */
async function loadDetail(row?: MesWmSnApi.SnGroup) {
if (!row?.uuid) {
await gridApi.grid?.loadData([]);
return;
}
gridApi.setLoading(true);
try {
const list = await getSnListByUuid(row.uuid);
await gridApi.grid?.loadData(list);
} finally {
gridApi.setLoading(false);
}
}
const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: {
columns: useDetailGridColumns(),
height: 520,
pagerConfig: {
enabled: false,
},
rowConfig: {
keyField: 'id',
isHover: true,
},
toolbarConfig: {
enabled: false,
},
} as VxeTableGridOptions<MesWmSnApi.Sn>,
});
const [Modal, modalApi] = useVbenModal({
showCancelButton: false,
showConfirmButton: false,
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
await gridApi.grid?.loadData([]);
return;
}
await nextTick();
await loadDetail(modalApi.getData<MesWmSnApi.SnGroup>());
},
});
</script>
<template>
<Modal class="w-3/5" title="SN 码明细">
<Grid class="mx-4">
<template #actions="{ row }">
<TableAction
:actions="[
{
label: '条码',
type: 'link',
auth: ['mes:wm-sn:query'],
onClick: handleBarcode.bind(null, row),
},
]"
/>
</template>
</Grid>
<BarcodeDetail ref="barcodeDetailRef" />
</Modal>
</template>