From 1c1af9b0fc10778ae5ac13cc68fd4030affbcfe1 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 09 九月 2026 10:59:53 +0800
Subject: [PATCH] feat(wm): 新增SN码管理和设备入库功能

---
 src/views/wls/sn/index.vue |  298 +++++++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 228 insertions(+), 70 deletions(-)

diff --git a/src/views/wls/sn/index.vue b/src/views/wls/sn/index.vue
index c881303..f1c5572 100644
--- a/src/views/wls/sn/index.vue
+++ b/src/views/wls/sn/index.vue
@@ -2,10 +2,12 @@
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { MesWmSnApi } from '#/api/mes/wm/sn';
 
+import { ref } from 'vue';
+
 import { Page, useVbenModal } from '@vben/common-ui';
 import { downloadFileFromBlobPart } from '@vben/utils';
 
-import { message } from 'ant-design-vue';
+import { message, Tabs, Tag } from 'ant-design-vue';
 
 import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
 import {
@@ -13,12 +15,28 @@
   exportSnDetailExcel,
   exportSnGroupExcel,
   getSnGroupPage,
+  getSnInStockPage,
 } from '#/api/mes/wm/sn';
 import { $t } from '#/locales';
 
-import { useGridColumns, useGridFormSchema } from './data';
+import {
+  useGridColumns,
+  useGridFormSchema,
+  useInStockGridColumns,
+  useInStockGridFormSchema,
+} from './data';
+import {
+  formatWmLocation,
+  getWmLocationMaps,
+  type WmLocationMaps,
+} from './location-maps';
 import Detail from './modules/detail.vue';
 import Form from './modules/form.vue';
+import InStockModal from './modules/in-stock-modal.vue';
+import OutStockModal from './modules/out-stock-modal.vue';
+import SnDetailModal from './modules/sn-detail-modal.vue';
+
+const activeKey = ref('group');
 
 const [FormModal, formModalApi] = useVbenModal({
   connectedComponent: Form,
@@ -30,9 +48,25 @@
   destroyOnClose: true,
 });
 
-/** 鍒锋柊琛ㄦ牸 */
+const [InStockModalRef, inStockModalApi] = useVbenModal({
+  connectedComponent: InStockModal,
+  destroyOnClose: true,
+});
+
+const [OutStockModalRef, outStockModalApi] = useVbenModal({
+  connectedComponent: OutStockModal,
+  destroyOnClose: true,
+});
+
+const snDetailModalRef = ref<InstanceType<typeof SnDetailModal>>();
+
+/** 鍒锋柊褰撳墠椤电 */
 function handleRefresh() {
-  gridApi.query();
+  if (activeKey.value === 'group') {
+    gridApi.query();
+  } else {
+    inStockGridApi.query();
+  }
 }
 
 /** 鐢熸垚 SN 鐮� */
@@ -74,6 +108,34 @@
   }
 }
 
+/** 鍏ュ簱鐧昏 */
+function handleInStock() {
+  inStockModalApi.open();
+}
+
+/** 鍑哄簱鏍搁攢 */
+function handleOutStock() {
+  outStockModalApi.open();
+}
+
+/** 鏌ョ湅鍗曚欢璇︽儏 */
+function handleSnDetail(row: MesWmSnApi.Sn) {
+  snDetailModalRef.value?.open(row.code);
+}
+
+/** 鍦ㄥ簱鍗曚欢鍒楄〃浣嶇疆鍚嶇О鏄犲皠锛堟噿鍔犺浇锛岄娆¤闂椂鍒濆鍖栵級 */
+const locationMapsRef = ref<Awaited<ReturnType<typeof getWmLocationMaps>>>();
+const EMPTY_MAPS: WmLocationMaps = {
+  warehouseNameMap: {},
+  locationNameMap: {},
+  areaNameMap: {},
+};
+async function ensureLocationMaps() {
+  if (!locationMapsRef.value) {
+    locationMapsRef.value = await getWmLocationMaps();
+  }
+}
+
 const [Grid, gridApi] = useVbenVxeGrid({
   formOptions: {
     schema: useGridFormSchema(),
@@ -103,75 +165,171 @@
     },
   } as VxeTableGridOptions<MesWmSnApi.SnGroup>,
 });
+
+const [InStockGrid, inStockGridApi] = useVbenVxeGrid({
+  formOptions: {
+    schema: useInStockGridFormSchema(),
+  },
+  gridOptions: {
+    columns: useInStockGridColumns(),
+    height: 'auto',
+    keepSource: true,
+    proxyConfig: {
+      ajax: {
+        query: async ({ page }, formValues) => {
+          return await getSnInStockPage({
+            pageNo: page.currentPage,
+            pageSize: page.pageSize,
+            ...formValues,
+          });
+        },
+      },
+    },
+    rowConfig: {
+      keyField: 'id',
+      isHover: true,
+    },
+    toolbarConfig: {
+      refresh: true,
+      search: true,
+    },
+  } as VxeTableGridOptions<MesWmSnApi.Sn>,
+});
+
+// 棣栨鎸傝浇鏃堕鐑綅缃悕绉版槧灏勶紝渚涘垪琛ㄥ睍绀�
+void ensureLocationMaps();
 </script>
 
 <template>
-  <Page auto-content-height><FormModal @success="handleRefresh" />
+  <Page auto-content-height>
+    <FormModal @success="handleRefresh" />
     <DetailModal />
+    <InStockModalRef @success="handleRefresh" />
+    <OutStockModalRef @success="handleRefresh" />
+    <SnDetailModal ref="snDetailModalRef" />
 
-    <Grid table-title="SN 鐮佸垪琛�">
-      <template #toolbar-tools>
-        <TableAction
-          :actions="[
-            {
-              label: '鐢熸垚 SN 鐮�',
-              type: 'primary',
-              icon: ACTION_ICON.ADD,
-              auth: ['mes:wm-sn:create'],
-              onClick: handleCreate,
-            },
-            {
-              label: $t('ui.actionTitle.export'),
-              type: 'primary',
-              icon: ACTION_ICON.DOWNLOAD,
-              auth: ['mes:wm-sn:export'],
-              onClick: handleExport,
-            },
-          ]"
-        />
-      </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',
-              auth: ['mes:wm-sn:export'],
-              onClick: handleExportDetail.bind(null, row),
-            },
-            {
-              label: $t('common.delete'),
-              type: 'link',
-              danger: true,
-              auth: ['mes:wm-sn:delete'],
-              popConfirm: {
-                title: $t('ui.actionMessage.deleteConfirm', [
-                  row.batchCode || row.itemName,
-                ]),
-                confirm: handleDelete.bind(null, row),
-              },
-            },
-          ]"
-        />
-      </template>
-    </Grid>
+    <Tabs v-model:active-key="activeKey" class="px-4 pt-1" type="card">
+      <Tabs.TabPane key="group" tab="SN 鐮佸垎缁�">
+        <Grid table-title="SN 鐮佸垪琛�">
+          <template #toolbar-tools>
+            <TableAction
+              :actions="[
+                {
+                  label: '鐢熸垚 SN 鐮�',
+                  type: 'primary',
+                  icon: ACTION_ICON.ADD,
+                  auth: ['mes:wm-sn:create'],
+                  onClick: handleCreate,
+                },
+                {
+                  label: $t('ui.actionTitle.export'),
+                  type: 'primary',
+                  icon: ACTION_ICON.DOWNLOAD,
+                  auth: ['mes:wm-sn:export'],
+                  onClick: handleExport,
+                },
+              ]"
+            />
+          </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',
+                  auth: ['mes:wm-sn:export'],
+                  onClick: handleExportDetail.bind(null, row),
+                },
+                {
+                  label: $t('common.delete'),
+                  type: 'link',
+                  danger: true,
+                  auth: ['mes:wm-sn:delete'],
+                  popConfirm: {
+                    title: $t('ui.actionMessage.deleteConfirm', [
+                      row.batchCode || row.itemName,
+                    ]),
+                    confirm: handleDelete.bind(null, row),
+                  },
+                },
+              ]"
+            />
+          </template>
+        </Grid>
+      </Tabs.TabPane>
+      <Tabs.TabPane key="in-stock" tab="鍦ㄥ簱鍗曚欢">
+        <InStockGrid table-title="SN 鍗曚欢鐘舵�佸垪琛�">
+          <template #toolbar-tools>
+            <TableAction
+              :actions="[
+                {
+                  label: '鍏ュ簱鐧昏',
+                  type: 'primary',
+                  icon: ACTION_ICON.ADD,
+                  auth: ['mes:wm-sn:update'],
+                  onClick: handleInStock,
+                },
+                {
+                  label: '鍑哄簱鏍搁攢',
+                  type: 'primary',
+                  danger: true,
+                  icon: ACTION_ICON.DELETE,
+                  auth: ['mes:wm-sn:update'],
+                  onClick: handleOutStock,
+                },
+              ]"
+            />
+          </template>
+          <template #status="{ row }">
+            <Tag :color="row.status === 1 ? 'green' : 'orange'">
+              {{ row.status === 1 ? '鍦ㄥ簱' : '宸插嚭搴�' }}
+            </Tag>
+          </template>
+          <template #locations="{ row }">
+            <span v-if="row.status === 1">
+              {{
+                formatWmLocation(
+                  locationMapsRef ?? EMPTY_MAPS,
+                  row.warehouseId,
+                  row.locationId,
+                  row.areaId,
+                )
+              }}
+            </span>
+            <span v-else>-</span>
+          </template>
+          <template #actions="{ row }">
+            <TableAction
+              :actions="[
+                {
+                  label: '璇︽儏',
+                  type: 'link',
+                  auth: ['mes:wm-sn:query'],
+                  onClick: handleSnDetail.bind(null, row),
+                },
+              ]"
+            />
+          </template>
+        </InStockGrid>
+      </Tabs.TabPane>
+    </Tabs>
   </Page>
-</template>
+</template>
\ No newline at end of file

--
Gitblit v1.9.3