From 57295febd254991c01eff2345ba293b89287689d Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 10 七月 2026 16:07:07 +0800
Subject: [PATCH] 银川 1.仓储物流页面开发、联调 2.项目配置修改

---
 src/api/mes/wm/arrivalnotice/index.ts                    |    7 
 src/api/mes/wm/returnvendor/index.ts                     |    1 
 src/router/routes/modules/mes.ts                         |   27 --
 src/views/wls/warehouse/area/index.vue                   |    2 
 src/api/mes/wm/itemreceipt/index.ts                      |   17 +
 .idea/mom-pro2-before.iml                                |    9 
 src/views/wls/arrivalnotice/data.ts                      |   24 ++
 vite.config.ts                                           |   34 ++
 src/views/wls/itemreceipt/index.vue                      |   46 +++
 src/views/wls/itemreceipt/modules/form.vue               |   32 ++
 src/views/wls/arrivalnotice/index.vue                    |   46 +++
 src/views/wls/barcode/components/detail.vue              |  139 ++++++++--
 src/views/wls/itemreceipt/modules/an-select-dialog.vue   |  129 ++++++++++
 src/views/wls/returnvendor/data.ts                       |   31 ++
 src/views/mes/md/vendor/components/select.vue            |   39 --
 src/views/wls/warehouse/index.vue                        |    4 
 src/views/wls/arrivalnotice/modules/po-select-dialog.vue |  123 ++++++++++
 src/views/wls/warehouse/location/index.vue               |    4 
 18 files changed, 608 insertions(+), 106 deletions(-)

diff --git a/.idea/mom-pro2-before.iml b/.idea/mom-pro2-before.iml
index c956989..f856ba1 100644
--- a/.idea/mom-pro2-before.iml
+++ b/.idea/mom-pro2-before.iml
@@ -1,7 +1,14 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <module type="WEB_MODULE" version="4">
   <component name="NewModuleRootManager">
-    <content url="file://$MODULE_DIR$" />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/node_modules" />
+      <excludeFolder url="file://$MODULE_DIR$/.pnpm" />
+      <excludeFolder url="file://$MODULE_DIR$/.vite" />
+      <excludeFolder url="file://$MODULE_DIR$/.cache" />
+      <excludeFolder url="file://$MODULE_DIR$/dist" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
   </component>
diff --git a/src/api/mes/wm/arrivalnotice/index.ts b/src/api/mes/wm/arrivalnotice/index.ts
index d664093..687c1a6 100644
--- a/src/api/mes/wm/arrivalnotice/index.ts
+++ b/src/api/mes/wm/arrivalnotice/index.ts
@@ -62,3 +62,10 @@
     params,
   });
 }
+
+/** 鏍规嵁閲囪喘璁㈠崟鐢熸垚鍒拌揣閫氱煡鍗� */
+export function generateArrivalNoticeFromPurchaseOrder(purchaseOrderId: number) {
+  return requestClient.post<number>(
+    `/mes/wm/arrival-notice/generate-from-purchase-order?purchaseOrderId=${purchaseOrderId}`,
+  );
+}
diff --git a/src/api/mes/wm/itemreceipt/index.ts b/src/api/mes/wm/itemreceipt/index.ts
index 24a4a61..e03b8cd 100644
--- a/src/api/mes/wm/itemreceipt/index.ts
+++ b/src/api/mes/wm/itemreceipt/index.ts
@@ -84,3 +84,20 @@
     params,
   });
 }
+
+/** 鏍规嵁鍒拌揣閫氱煡鍗曠敓鎴愰噰璐叆搴撳崟 */
+export function generateItemReceiptFromArrivalNotice(arrivalNoticeId: number) {
+  return requestClient.post<number>(
+    `/mes/wm/item-receipt/generate-from-arrival-notice?arrivalNoticeId=${arrivalNoticeId}`,
+  );
+}
+
+/** 鎻愪氦閲囪喘鍏ュ簱鍗曞鎵� */
+export function submitItemReceiptApproval(
+  id: number,
+  processDefinitionKey: string,
+) {
+  return requestClient.put(
+    `/mes/wm/item-receipt/submit-approval?id=${id}&processDefinitionKey=${processDefinitionKey}`,
+  );
+}
diff --git a/src/api/mes/wm/returnvendor/index.ts b/src/api/mes/wm/returnvendor/index.ts
index c721c52..3d35cb0 100644
--- a/src/api/mes/wm/returnvendor/index.ts
+++ b/src/api/mes/wm/returnvendor/index.ts
@@ -8,6 +8,7 @@
     id?: number; // 閫�璐у崟缂栧彿
     code?: string; // 閫�璐у崟缂栧彿
     name?: string; // 閫�璐у崟鍚嶇О
+    purchaseOrderId?: number; // 閲囪喘璁㈠崟缂栧彿
     purchaseOrderCode?: string; // 閲囪喘璁㈠崟鍙�
     vendorId?: number; // 渚涘簲鍟嗙紪鍙�
     vendorCode?: string; // 渚涘簲鍟嗙紪鐮�
diff --git a/src/router/routes/modules/mes.ts b/src/router/routes/modules/mes.ts
index 91aec0a..de6c512 100644
--- a/src/router/routes/modules/mes.ts
+++ b/src/router/routes/modules/mes.ts
@@ -12,33 +12,6 @@
     },
     children: [
       {
-        path: 'wm/warehouse/location',
-        name: 'MesWmLocation',
-        meta: {
-          title: '搴撳尯璁剧疆',
-          activePath: '/mes/wm/warehouse',
-        },
-        component: () => import('#/views/mes/wm/warehouse/location/index.vue'),
-      },
-      {
-        path: 'wm/warehouse/area',
-        name: 'MesWmArea',
-        meta: {
-          title: '搴撲綅璁剧疆',
-          activePath: '/mes/wm/warehouse',
-        },
-        component: () => import('#/views/mes/wm/warehouse/area/index.vue'),
-      },
-      {
-        path: 'wm/barcode/config',
-        name: 'MesWmBarcodeConfig',
-        meta: {
-          title: '鏉$爜閰嶇疆',
-          activePath: '/mes/wm/barcode',
-        },
-        component: () => import('#/views/mes/wm/barcode/config/index.vue'),
-      },
-      {
         path: 'pro/task/gantt-edit',
         name: 'MesProTaskGanttEdit',
         meta: {
diff --git a/src/views/mes/md/vendor/components/select.vue b/src/views/mes/md/vendor/components/select.vue
index 408972a..b824102 100644
--- a/src/views/mes/md/vendor/components/select.vue
+++ b/src/views/mes/md/vendor/components/select.vue
@@ -1,13 +1,11 @@
 <script lang="ts" setup>
 import type { MesMdVendorApi } from '#/api/mes/md/vendor';
 
-import { computed, ref, useAttrs, watch } from 'vue';
+import { computed, ref, useAttrs } from 'vue';
 
 import { IconifyIcon } from '../../../../../packages/icons/src';
 
 import { Input, Tooltip } from 'ant-design-vue';
-
-import { getVendor } from '#/api/mes/md/vendor';
 
 import MdVendorSelectDialog from './select-dialog.vue';
 
@@ -19,24 +17,26 @@
     disabled?: boolean;
     modelValue?: number;
     placeholder?: string;
+    vendorName?: string;
   }>(),
   {
     allowClear: true,
     disabled: false,
     modelValue: undefined,
     placeholder: '璇烽�夋嫨渚涘簲鍟�',
+    vendorName: undefined,
   },
 );
 const emit = defineEmits<{
   change: [item: MesMdVendorApi.Vendor | undefined];
   'update:modelValue': [value: number | undefined];
 }>();
-const attrs = useAttrs(); // 閫忎紶灞炴��
-const dialogRef = ref<InstanceType<typeof MdVendorSelectDialog>>(); // 渚涘簲鍟嗛�夋嫨寮圭獥
-const hovering = ref(false); // 鏄惁鎮仠
-const selectedItem = ref<MesMdVendorApi.Vendor>(); // 褰撳墠閫変腑渚涘簲鍟�
+const attrs = useAttrs();
+const dialogRef = ref<InstanceType<typeof MdVendorSelectDialog>>();
+const hovering = ref(false);
+const selectedItem = ref<MesMdVendorApi.Vendor>();
 
-const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 閫夋嫨鍣ㄥ睍绀哄悕绉�
+const displayLabel = computed(() => props.vendorName || selectedItem.value?.name || '');
 const showClear = computed(
   () =>
     props.allowClear &&
@@ -45,34 +45,12 @@
     props.modelValue !== null,
 );
 
-/** 鏍规嵁渚涘簲鍟嗙紪鍙峰洖鏄鹃�夋嫨鍣� */
-async function resolveItemById(id: number | undefined) {
-  if (!id) {
-    selectedItem.value = undefined;
-    return;
-  }
-  if (selectedItem.value?.id === id) {
-    return;
-  }
-  selectedItem.value = await getVendor(id);
-}
-
-watch(
-  () => props.modelValue,
-  (value) => {
-    resolveItemById(value);
-  },
-  { immediate: true },
-);
-
-/** 娓呯┖宸查�変緵搴斿晢 */
 function clearSelected() {
   selectedItem.value = undefined;
   emit('update:modelValue', undefined);
   emit('change', undefined);
 }
 
-/** 鎵撳紑渚涘簲鍟嗛�夋嫨寮圭獥 */
 function handleClick(event: MouseEvent) {
   if (props.disabled) {
     return;
@@ -89,7 +67,6 @@
   dialogRef.value?.open(selectedIds, { multiple: false });
 }
 
-/** 鍥炲~閫変腑鐨勪緵搴斿晢 */
 function handleSelected(rows: MesMdVendorApi.Vendor[]) {
   const item = rows[0];
   if (!item) {
diff --git a/src/views/wls/arrivalnotice/data.ts b/src/views/wls/arrivalnotice/data.ts
index bbed3bb..95b24b4 100644
--- a/src/views/wls/arrivalnotice/data.ts
+++ b/src/views/wls/arrivalnotice/data.ts
@@ -77,11 +77,26 @@
       rules: 'required',
     },
     {
+      fieldName: 'vendorName',
+      label: '',
+      component: 'Input',
+      dependencies: {
+        triggerFields: [''],
+        show: () => false,
+      },
+    },
+    {
       fieldName: 'purchaseOrderId',
       label: '閲囪喘璁㈠崟',
       component: markRaw(ErpPurchaseOrderSelect),
       componentProps: {
         placeholder: '璇烽�夋嫨閲囪喘璁㈠崟',
+        onChange: (item: any) => {
+          if (item?.supplierId && formApi) {
+            formApi.setFieldValue('vendorId', item.supplierId);
+            formApi.setFieldValue('vendorName', item.supplierName);
+          }
+        },
       },
     },
     {
@@ -90,6 +105,15 @@
       component: markRaw(MdVendorSelect),
       componentProps: {
         placeholder: '璇烽�夋嫨渚涘簲鍟�',
+        disabled: true,
+      },
+      dependencies: {
+        triggerFields: ['vendorName'],
+        componentProps: (values) => ({
+          placeholder: '璇烽�夋嫨渚涘簲鍟�',
+          disabled: true,
+          vendorName: values.vendorName as string,
+        }),
       },
       rules: 'selectRequired',
     },
diff --git a/src/views/wls/arrivalnotice/index.vue b/src/views/wls/arrivalnotice/index.vue
index df90182..15f292e 100644
--- a/src/views/wls/arrivalnotice/index.vue
+++ b/src/views/wls/arrivalnotice/index.vue
@@ -2,9 +2,9 @@
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { MesWmArrivalNoticeApi } from '#/api/mes/wm/arrivalnotice';
 
-import { Page, useVbenModal } from '../../../packages/effects/common-ui/src';
-import { MesWmArrivalNoticeStatusEnum } from '../../../packages/constants/src';
-import { downloadFileFromBlobPart } from '../../../packages/utils/src';
+import { Page, useVbenModal } from '@vben/common-ui';
+import { MesWmArrivalNoticeStatusEnum } from '@vben/constants';
+import { downloadFileFromBlobPart } from '@vben/utils';
 
 import { Button, message } from 'ant-design-vue';
 
@@ -12,15 +12,22 @@
 import {
   deleteArrivalNotice,
   exportArrivalNotice,
+  generateArrivalNoticeFromPurchaseOrder,
   getArrivalNoticePage,
 } from '#/api/mes/wm/arrivalnotice';
 import { $t } from '#/locales';
 
 import { useGridColumns, useGridFormSchema } from './data';
 import Form from './modules/form.vue';
+import PoSelectDialog from './modules/po-select-dialog.vue';
 
 const [FormModal, formModalApi] = useVbenModal({
   connectedComponent: Form,
+  destroyOnClose: true,
+});
+
+const [PoSelectModal, poSelectModalApi] = useVbenModal({
+  connectedComponent: PoSelectDialog,
   destroyOnClose: true,
 });
 
@@ -69,6 +76,28 @@
   message.info('璇峰墠寰�銆愪粨搴撶鐞� - 閲囪喘鍏ュ簱銆戜腑杩涜鍏ュ簱鎿嶄綔');
 }
 
+/** 浠庨噰璐鍗曠敓鎴愬埌璐ч�氱煡鍗� */
+async function handleGenerateFromPO() {
+  poSelectModalApi.open();
+}
+
+/** 閲囪喘璁㈠崟閫夋嫨鍥炶皟 */
+async function handlePurchaseOrderSelected(purchaseOrderId: number) {
+  const hideLoading = message.loading({
+    content: '姝e湪鐢熸垚鍒拌揣閫氱煡鍗�...',
+    duration: 0,
+  });
+  try {
+    const id = await generateArrivalNoticeFromPurchaseOrder(purchaseOrderId);
+    message.success('鍒拌揣閫氱煡鍗曠敓鎴愭垚鍔�');
+    // 璺宠浆鍒扮紪杈戦〉
+    formModalApi.setData({ formType: 'update', id }).open();
+    handleRefresh();
+  } finally {
+    hideLoading();
+  }
+}
+
 /** 瀵煎嚭琛ㄦ牸 */
 async function handleExport() {
   const data = await exportArrivalNotice(await gridApi.formApi.getValues());
@@ -107,7 +136,9 @@
 </script>
 
 <template>
-  <Page auto-content-height><FormModal @success="handleRefresh" />
+  <Page auto-content-height>
+    <FormModal @success="handleRefresh" />
+    <PoSelectModal @selected="handlePurchaseOrderSelected" />
 
     <Grid table-title="鍒拌揣閫氱煡鍗曞垪琛�">
       <template #toolbar-tools>
@@ -121,6 +152,13 @@
               onClick: handleCreate,
             },
             {
+              label: '浠庨噰璐鍗曠敓鎴�',
+              type: 'primary',
+              icon: ACTION_ICON.ADD,
+              auth: ['mes:wm-arrival-notice:create'],
+              onClick: handleGenerateFromPO,
+            },
+            {
               label: $t('ui.actionTitle.export'),
               type: 'primary',
               icon: ACTION_ICON.DOWNLOAD,
diff --git a/src/views/wls/arrivalnotice/modules/po-select-dialog.vue b/src/views/wls/arrivalnotice/modules/po-select-dialog.vue
new file mode 100644
index 0000000..6d6d492
--- /dev/null
+++ b/src/views/wls/arrivalnotice/modules/po-select-dialog.vue
@@ -0,0 +1,123 @@
+<script lang="ts" setup>
+import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+
+import { Page, useVbenModal } from '@vben/common-ui';
+
+import { message } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { getPurchaseOrderPage } from '#/api/erp/purchase/order';
+
+const emit = defineEmits<{
+  selected: [purchaseOrderId: number];
+}>();
+
+const [Grid, gridApi] = useVbenVxeGrid({
+  formOptions: {
+    schema: [
+      {
+        fieldName: 'no',
+        label: '璁㈠崟鍙�',
+        component: 'Input',
+        componentProps: {
+          allowClear: true,
+          placeholder: '璇疯緭鍏ヨ鍗曞彿',
+        },
+      },
+      {
+        fieldName: 'supplierName',
+        label: '渚涘簲鍟�',
+        component: 'Input',
+        componentProps: {
+          allowClear: true,
+          placeholder: '璇疯緭鍏ヤ緵搴斿晢鍚嶇О',
+        },
+      },
+    ],
+  },
+  gridOptions: {
+    columns: [
+      {
+        type: 'radio',
+        width: 60,
+      },
+      {
+        field: 'no',
+        title: '璁㈠崟鍙�',
+        minWidth: 160,
+      },
+      {
+        field: 'supplierName',
+        title: '渚涘簲鍟嗗悕绉�',
+        minWidth: 120,
+      },
+      {
+        field: 'orderTime',
+        title: '璁㈠崟鏃ユ湡',
+        width: 180,
+        formatter: 'formatDate',
+      },
+      {
+        field: 'totalPrice',
+        title: '鎬婚噾棰�',
+        width: 120,
+        formatter: 'formatMoney',
+      },
+      {
+        field: 'status',
+        title: '鐘舵��',
+        width: 100,
+        cellRender: {
+          name: 'CellDict',
+          props: { type: 'erp_purchase_order_status' },
+        },
+      },
+    ],
+    height: 'auto',
+    keepSource: true,
+    proxyConfig: {
+      ajax: {
+        query: async ({ page }, formValues) => {
+          return await getPurchaseOrderPage({
+            pageNo: page.currentPage,
+            pageSize: page.pageSize,
+            ...formValues,
+          });
+        },
+      },
+    },
+    rowConfig: {
+      keyField: 'id',
+      isHover: true,
+    },
+    toolbarConfig: {
+      refresh: true,
+      search: true,
+    },
+  } as VxeTableGridOptions<ErpPurchaseOrderApi.PurchaseOrder>,
+});
+
+const [Modal, modalApi] = useVbenModal({
+  async onConfirm() {
+    const selectedRows = gridApi.grid.getRadioRecord();
+    if (!selectedRows) {
+      message.warning('璇烽�夋嫨閲囪喘璁㈠崟');
+      return;
+    }
+    emit('selected', selectedRows.id);
+    await modalApi.close();
+  },
+  async onOpenChange(isOpen: boolean) {
+    if (isOpen) {
+      await gridApi.query();
+    }
+  },
+});
+</script>
+
+<template>
+  <Modal title="閫夋嫨閲囪喘璁㈠崟" class="w-2/3">
+    <Grid table-title="閲囪喘璁㈠崟鍒楄〃" />
+  </Modal>
+</template>
diff --git a/src/views/wls/barcode/components/detail.vue b/src/views/wls/barcode/components/detail.vue
index 17a9f37..c9abe98 100644
--- a/src/views/wls/barcode/components/detail.vue
+++ b/src/views/wls/barcode/components/detail.vue
@@ -24,6 +24,7 @@
   column: 1,
   schema: useBarcodeDetailSchema(),
   useCard: false,
+  labelStyle: { width: '80px', whiteSpace: 'nowrap' },
 });
 
 function openModal(row: Partial<MesWmBarcodeApi.Barcode>) {
@@ -98,11 +99,86 @@
     message.warning('鏉$爜鐢熸垚澶辫触锛屾棤娉曚笅杞�');
     return;
   }
-  const link = document.createElement('a');
-  link.href = base64;
-  link.download = `barcode_${barcodeData.value.bizCode || 'unknown'}_${Date.now()}.png`;
-  link.click();
-  message.success('涓嬭浇鎴愬姛');
+
+  const canvas = document.createElement('canvas');
+  const ctx = canvas.getContext('2d');
+  if (!ctx) {
+    message.error('Canvas 鍒濆鍖栧け璐�');
+    return;
+  }
+
+  const img = new Image();
+  img.onload = () => {
+    const padding = 20;
+    const infoX = img.width + padding * 2;
+    const infoWidth = 320;
+    canvas.width = infoX + infoWidth + padding;
+    canvas.height = Math.max(img.height + padding * 2, 360);
+
+    ctx.fillStyle = '#ffffff';
+    ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+    ctx.drawImage(img, padding, padding);
+
+    ctx.fillStyle = '#000000';
+    let y = padding + 10;
+    const lineHeight = 26;
+
+    // 鑾峰彇瀛楀吀鏂囨湰鐨勮緟鍔╁嚱鏁�
+    const getFormatText = (val?: number) => {
+      const map: Record<number, string> = { 1: 'QR_CODE', 2: 'CODE_128', 3: 'CODE_39', 4: 'EAN_13', 5: 'UPC_A' };
+      return map[val || 1] || 'QR_CODE';
+    };
+    const getBizTypeText = (val?: number) => {
+      const map: Record<number, string> = { 1: '浠撳簱', 2: '搴撳尯', 3: '搴撲綅', 4: '鐗╂枡', 5: '瀹㈡埛', 6: '渚涘簲鍟�', 7: '宸ュ崟', 8: '璁惧', 9: '宸ュ叿', 10: '浜哄憳', 11: '宸ヤ綔绔�', 12: '杞﹂棿', 13: '搴撳瓨', 14: '娴佽浆鍗�', 15: '瑁呯鍗�', 16: '鎵规' };
+      return map[val || 1] || '-';
+    };
+    const getStatusText = (val?: number) => val === 0 ? '绂佺敤' : '鍚敤';
+
+    const items = [
+      { label: '鏉$爜鏍煎紡', value: getFormatText(barcodeData.value.format) },
+      { label: '涓氬姟绫诲瀷', value: getBizTypeText(barcodeData.value.bizType) },
+      { label: '涓氬姟缂栫爜', value: barcodeData.value.bizCode },
+      { label: '涓氬姟鍚嶇О', value: barcodeData.value.bizName },
+      { label: '鏉$爜鍐呭', value: barcodeData.value.content },
+      { label: '鐘舵��', value: getStatusText(barcodeData.value.status) },
+    ];
+
+    items.forEach((item) => {
+      ctx.font = 'bold 13px Arial, sans-serif';
+      ctx.fillText(`${item.label}:`, infoX, y);
+      y += 18;
+      ctx.font = '13px Arial, sans-serif';
+      const text = item.value || '-';
+      // 澶勭悊闀挎枃鏈崲琛�
+      const maxWidth = infoWidth - 10;
+      if (ctx.measureText(text).width > maxWidth) {
+        let currentText = text;
+        while (currentText.length > 0) {
+          let line = '';
+          for (let i = 0; i < currentText.length; i++) {
+            const testLine = line + currentText[i];
+            if (ctx.measureText(testLine).width > maxWidth) break;
+            line = testLine;
+          }
+          ctx.fillText(line, infoX + 5, y);
+          y += 16;
+          currentText = currentText.slice(line.length);
+        }
+        y += 6;
+      } else {
+        ctx.fillText(text, infoX + 5, y);
+        y += lineHeight;
+      }
+    });
+
+    const link = document.createElement('a');
+    link.href = canvas.toDataURL('image/png');
+    link.download = `barcode_${barcodeData.value.bizCode || 'unknown'}_${Date.now()}.png`;
+    link.click();
+    message.success('涓嬭浇鎴愬姛');
+  };
+  img.src = base64;
 }
 
 async function handleGenerate() {
@@ -126,36 +202,35 @@
 </script>
 
 <template>
-  <Modal v-model:open="open" title="鏌ョ湅鏉$爜" width="500px">
+  <Modal v-model:open="open" title="鏌ョ湅鏉$爜" width="750px">
     <div>
-      <div
-        class="mb-5 flex min-h-50 items-center justify-center rounded bg-gray-100 p-5"
-      >
-        <div
-          v-if="barcodeData.content"
-          class="flex items-center justify-center"
-        >
-          <WlsBarcode
-            ref="barcodeRef"
-            :content="barcodeData.content"
-            :format="barcodeData.format"
-            :height="150"
-            :width="400"
-          />
+      <div class="mb-5 flex min-h-50 items-center rounded bg-gray-100 p-5">
+        <div v-if="barcodeData.content" class="flex w-full items-center gap-6">
+          <div class="flex-shrink-0">
+            <WlsBarcode
+              ref="barcodeRef"
+              :content="barcodeData.content"
+              :format="barcodeData.format"
+              :height="150"
+              :width="280"
+            />
+          </div>
+          <div class="flex-1">
+            <Descriptions :data="barcodeData">
+              <template #content>
+                <Tooltip :title="barcodeData.content">
+                  <span
+                    class="inline-block max-w-60 overflow-hidden text-ellipsis whitespace-nowrap"
+                  >
+                    {{ barcodeData.content }}
+                  </span>
+                </Tooltip>
+              </template>
+            </Descriptions>
+          </div>
         </div>
-        <Empty v-else description="鏆傛棤鏉$爜鏁版嵁" />
+        <Empty v-else description="鏆傛棤鏉$爜鏁版嵁" class="flex-1" />
       </div>
-      <Descriptions :data="barcodeData">
-        <template #content>
-          <Tooltip :title="barcodeData.content">
-            <span
-              class="inline-block max-w-75 overflow-hidden text-ellipsis whitespace-nowrap"
-            >
-              {{ barcodeData.content }}
-            </span>
-          </Tooltip>
-        </template>
-      </Descriptions>
     </div>
     <template #footer>
       <Button v-if="!barcodeData.content" @click="handleGenerate">
diff --git a/src/views/wls/itemreceipt/index.vue b/src/views/wls/itemreceipt/index.vue
index 9e3f25c..552e77a 100644
--- a/src/views/wls/itemreceipt/index.vue
+++ b/src/views/wls/itemreceipt/index.vue
@@ -2,9 +2,9 @@
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { MesWmItemReceiptApi } from '#/api/mes/wm/itemreceipt';
 
-import { Page, useVbenModal } from '../../../packages/effects/common-ui/src';
-import { MesWmItemReceiptStatusEnum } from '../../../packages/constants/src';
-import { downloadFileFromBlobPart } from '../../../packages/utils/src';
+import { Page, useVbenModal } from '@vben/common-ui';
+import { MesWmItemReceiptStatusEnum } from '@vben/constants';
+import { downloadFileFromBlobPart } from '@vben/utils';
 
 import { Button, message } from 'ant-design-vue';
 
@@ -13,15 +13,22 @@
   cancelItemReceipt,
   deleteItemReceipt,
   exportItemReceipt,
+  generateItemReceiptFromArrivalNotice,
   getItemReceiptPage,
 } from '#/api/mes/wm/itemreceipt';
 import { $t } from '#/locales';
 
 import { useGridColumns, useGridFormSchema } from './data';
 import Form from './modules/form.vue';
+import AnSelectDialog from './modules/an-select-dialog.vue';
 
 const [FormModal, formModalApi] = useVbenModal({
   connectedComponent: Form,
+  destroyOnClose: true,
+});
+
+const [AnSelectModal, anSelectModalApi] = useVbenModal({
+  connectedComponent: AnSelectDialog,
   destroyOnClose: true,
 });
 
@@ -77,6 +84,28 @@
   handleRefresh();
 }
 
+/** 浠庡埌璐ч�氱煡鐢熸垚閲囪喘鍏ュ簱鍗� */
+async function handleGenerateFromAN() {
+  anSelectModalApi.open();
+}
+
+/** 鍒拌揣閫氱煡閫夋嫨鍥炶皟 */
+async function handleArrivalNoticeSelected(arrivalNoticeId: number) {
+  const hideLoading = message.loading({
+    content: '姝e湪鐢熸垚閲囪喘鍏ュ簱鍗�...',
+    duration: 0,
+  });
+  try {
+    const id = await generateItemReceiptFromArrivalNotice(arrivalNoticeId);
+    message.success('閲囪喘鍏ュ簱鍗曠敓鎴愭垚鍔�');
+    // 璺宠浆鍒扮紪杈戦〉
+    formModalApi.setData({ formType: 'update', id }).open();
+    handleRefresh();
+  } finally {
+    hideLoading();
+  }
+}
+
 /** 瀵煎嚭琛ㄦ牸 */
 async function handleExport() {
   const data = await exportItemReceipt(await gridApi.formApi.getValues());
@@ -115,7 +144,9 @@
 </script>
 
 <template>
-  <Page auto-content-height><FormModal @success="handleRefresh" />
+  <Page auto-content-height>
+    <FormModal @success="handleRefresh" />
+    <AnSelectModal @selected="handleArrivalNoticeSelected" />
 
     <Grid table-title="閲囪喘鍏ュ簱鍗曞垪琛�">
       <template #toolbar-tools>
@@ -129,6 +160,13 @@
               onClick: handleCreate,
             },
             {
+              label: '浠庡埌璐ч�氱煡鐢熸垚',
+              type: 'primary',
+              icon: ACTION_ICON.ADD,
+              auth: ['mes:wm-item-receipt:create'],
+              onClick: handleGenerateFromAN,
+            },
+            {
               label: $t('ui.actionTitle.export'),
               type: 'primary',
               icon: ACTION_ICON.DOWNLOAD,
diff --git a/src/views/wls/itemreceipt/modules/an-select-dialog.vue b/src/views/wls/itemreceipt/modules/an-select-dialog.vue
new file mode 100644
index 0000000..eef4eef
--- /dev/null
+++ b/src/views/wls/itemreceipt/modules/an-select-dialog.vue
@@ -0,0 +1,129 @@
+<script lang="ts" setup>
+import type { MesWmArrivalNoticeApi } from '#/api/mes/wm/arrivalnotice';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+
+import { Page, useVbenModal } from '@vben/common-ui';
+import { MesWmArrivalNoticeStatusEnum } from '@vben/constants';
+
+import { message } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { getArrivalNoticePage } from '#/api/mes/wm/arrivalnotice';
+
+const emit = defineEmits<{
+  selected: [arrivalNoticeId: number];
+}>();
+
+const [Grid, gridApi] = useVbenVxeGrid({
+  formOptions: {
+    schema: [
+      {
+        fieldName: 'code',
+        label: '閫氱煡鍗曞彿',
+        component: 'Input',
+        componentProps: {
+          allowClear: true,
+          placeholder: '璇疯緭鍏ラ�氱煡鍗曞彿',
+        },
+      },
+      {
+        fieldName: 'vendorName',
+        label: '渚涘簲鍟�',
+        component: 'Input',
+        componentProps: {
+          allowClear: true,
+          placeholder: '璇疯緭鍏ヤ緵搴斿晢鍚嶇О',
+        },
+      },
+    ],
+  },
+  gridOptions: {
+    columns: [
+      {
+        type: 'radio',
+        width: 60,
+      },
+      {
+        field: 'code',
+        title: '閫氱煡鍗曞彿',
+        minWidth: 160,
+      },
+      {
+        field: 'name',
+        title: '閫氱煡鍗曞悕绉�',
+        minWidth: 150,
+      },
+      {
+        field: 'vendorName',
+        title: '渚涘簲鍟嗗悕绉�',
+        minWidth: 120,
+      },
+      {
+        field: 'purchaseOrderNo',
+        title: '閲囪喘璁㈠崟鍙�',
+        minWidth: 140,
+      },
+      {
+        field: 'arrivalDate',
+        title: '鍒拌揣鏃ユ湡',
+        width: 180,
+        formatter: 'formatDate',
+      },
+      {
+        field: 'status',
+        title: '鐘舵��',
+        width: 100,
+        cellRender: {
+          name: 'CellDict',
+          props: { type: 'mes_wm_arrival_notice_status' },
+        },
+      },
+    ],
+    height: 'auto',
+    keepSource: true,
+    proxyConfig: {
+      ajax: {
+        query: async ({ page }, formValues) => {
+          return await getArrivalNoticePage({
+            pageNo: page.currentPage,
+            pageSize: page.pageSize,
+            status: MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT,
+            ...formValues,
+          });
+        },
+      },
+    },
+    rowConfig: {
+      keyField: 'id',
+      isHover: true,
+    },
+    toolbarConfig: {
+      refresh: true,
+      search: true,
+    },
+  } as VxeTableGridOptions<MesWmArrivalNoticeApi.ArrivalNotice>,
+});
+
+const [Modal, modalApi] = useVbenModal({
+  async onConfirm() {
+    const selectedRows = gridApi.grid.getRadioRecord();
+    if (!selectedRows) {
+      message.warning('璇烽�夋嫨鍒拌揣閫氱煡鍗�');
+      return;
+    }
+    emit('selected', selectedRows.id);
+    await modalApi.close();
+  },
+  async onOpenChange(isOpen: boolean) {
+    if (isOpen) {
+      await gridApi.query();
+    }
+  },
+});
+</script>
+
+<template>
+  <Modal title="閫夋嫨鍒拌揣閫氱煡鍗�" class="w-2/3">
+    <Grid table-title="鍒拌揣閫氱煡鍗曞垪琛�" />
+  </Modal>
+</template>
diff --git a/src/views/wls/itemreceipt/modules/form.vue b/src/views/wls/itemreceipt/modules/form.vue
index a0fae09..6794cc1 100644
--- a/src/views/wls/itemreceipt/modules/form.vue
+++ b/src/views/wls/itemreceipt/modules/form.vue
@@ -5,8 +5,8 @@
 
 import { computed, ref } from 'vue';
 
-import { confirm, useVbenModal } from '../../../../packages/effects/common-ui/src';
-import { MesWmItemReceiptStatusEnum } from '../../../../packages/constants/src';
+import { confirm, useVbenModal } from '@vben/common-ui';
+import { MesWmItemReceiptStatusEnum } from '@vben/constants';
 
 import { Button, Divider, message, Popconfirm } from 'ant-design-vue';
 
@@ -17,6 +17,7 @@
   getItemReceipt,
   stockItemReceipt,
   submitItemReceipt,
+  submitItemReceiptApproval,
   updateItemReceipt,
 } from '#/api/mes/wm/itemreceipt';
 import { $t } from '#/locales';
@@ -37,6 +38,12 @@
 const canSubmit = computed(
   () =>
     // 鏄惁鍙彁浜�
+    formType.value === 'update' &&
+    formData.value?.status === MesWmItemReceiptStatusEnum.PREPARE,
+);
+const canSubmitApproval = computed(
+  () =>
+    // 鏄惁鍙彁浜ゅ鎵�
     formType.value === 'update' &&
     formData.value?.status === MesWmItemReceiptStatusEnum.PREPARE,
 );
@@ -118,6 +125,24 @@
   try {
     await finishItemReceipt(formData.value.id);
     message.success('鍏ュ簱鎴愬姛');
+    await modalApi.close();
+    emit('success');
+  } finally {
+    modalApi.unlock();
+  }
+}
+
+/** 鎻愪氦瀹℃壒 */
+async function handleSubmitApproval() {
+  if (!formData.value?.id) {
+    return;
+  }
+  modalApi.lock();
+  try {
+    // 浣跨敤榛樿娴佺▼key锛屽疄闄呴」鐩腑鍙兘闇�瑕佸脊绐楅�夋嫨
+    const processDefinitionKey = 'item_receipt_approval';
+    await submitItemReceiptApproval(formData.value.id, processDefinitionKey);
+    message.success('鎻愪氦瀹℃壒鎴愬姛');
     await modalApi.close();
     emit('success');
   } finally {
@@ -230,6 +255,9 @@
         >
           <Button type="primary">鎻愪氦</Button>
         </Popconfirm>
+        <Button v-if="canSubmitApproval" type="primary" @click="handleSubmitApproval">
+          鎻愪氦瀹℃壒
+        </Button>
         <Button v-if="isStock" type="primary" @click="confirmStock">
           鎵ц涓婃灦
         </Button>
diff --git a/src/views/wls/returnvendor/data.ts b/src/views/wls/returnvendor/data.ts
index 6844970..a0494ea 100644
--- a/src/views/wls/returnvendor/data.ts
+++ b/src/views/wls/returnvendor/data.ts
@@ -14,6 +14,7 @@
 import { generateAutoCode } from '#/api/mes/md/autocode/record';
 import { MdItemSelect } from '#/views/mes/md/item/components';
 import { MdVendorSelect } from '#/views/mes/md/vendor/components';
+import { ErpPurchaseOrderSelect } from '#/views/erp/purchase/order/components';
 import { WmBatchSelect } from '#/views/wls/batch/components';
 import { WmMaterialStockSelect } from '#/views/wls/materialstock/components';
 import {
@@ -87,11 +88,26 @@
       rules: 'required',
     },
     {
-      fieldName: 'purchaseOrderCode',
-      label: '閲囪喘璁㈠崟鍙�',
+      fieldName: 'vendorName',
+      label: '',
       component: 'Input',
+      dependencies: {
+        triggerFields: [''],
+        show: () => false,
+      },
+    },
+    {
+      fieldName: 'purchaseOrderId',
+      label: '閲囪喘璁㈠崟',
+      component: markRaw(ErpPurchaseOrderSelect),
       componentProps: {
-        placeholder: '璇疯緭鍏ラ噰璐鍗曞彿',
+        placeholder: '璇烽�夋嫨閲囪喘璁㈠崟',
+        onChange: (item: any) => {
+          if (item?.supplierId && formApi) {
+            formApi.setFieldValue('vendorId', item.supplierId);
+            formApi.setFieldValue('vendorName', item.supplierName);
+          }
+        },
       },
     },
     {
@@ -100,6 +116,15 @@
       component: markRaw(MdVendorSelect),
       componentProps: {
         placeholder: '璇烽�夋嫨渚涘簲鍟�',
+        disabled: true,
+      },
+      dependencies: {
+        triggerFields: ['vendorName'],
+        componentProps: (values) => ({
+          placeholder: '璇烽�夋嫨渚涘簲鍟�',
+          disabled: true,
+          vendorName: values.vendorName as string,
+        }),
       },
       rules: 'selectRequired',
     },
diff --git a/src/views/wls/warehouse/area/index.vue b/src/views/wls/warehouse/area/index.vue
index 64b6950..53ed2b7 100644
--- a/src/views/wls/warehouse/area/index.vue
+++ b/src/views/wls/warehouse/area/index.vue
@@ -22,6 +22,8 @@
 import { useGridColumns, useGridFormSchema } from './data';
 import Form from './modules/form.vue';
 
+defineOptions({ name: 'WlsArea' });
+
 const route = useRoute();
 
 const [FormModal, formModalApi] = useVbenModal({
diff --git a/src/views/wls/warehouse/index.vue b/src/views/wls/warehouse/index.vue
index 9edfabd..e02033c 100644
--- a/src/views/wls/warehouse/index.vue
+++ b/src/views/wls/warehouse/index.vue
@@ -18,6 +18,8 @@
 import { useGridColumns, useGridFormSchema } from './data';
 import Form from './modules/form.vue';
 
+defineOptions({ name: 'WlsWarehouse' });
+
 const router = useRouter();
 
 const [FormModal, formModalApi] = useVbenModal({
@@ -65,7 +67,7 @@
 /** 璺宠浆搴撳尯鍒楄〃 */
 function handleOpenLocation(row: MesWmWarehouseApi.Warehouse) {
   router.push({
-    name: 'WlsLocation',
+    path: '/wls/location',
     query: { warehouseId: String(row.id) },
   });
 }
diff --git a/src/views/wls/warehouse/location/index.vue b/src/views/wls/warehouse/location/index.vue
index 9de6261..e956665 100644
--- a/src/views/wls/warehouse/location/index.vue
+++ b/src/views/wls/warehouse/location/index.vue
@@ -22,6 +22,8 @@
 import { useGridColumns, useGridFormSchema } from './data';
 import Form from './modules/form.vue';
 
+defineOptions({ name: 'WlsLocation' });
+
 const route = useRoute();
 const router = useRouter();
 
@@ -99,7 +101,7 @@
 /** 璺宠浆搴撲綅鍒楄〃 */
 function handleOpenArea(row: MesWmWarehouseLocationApi.WarehouseLocation) {
   router.push({
-    name: 'WlsArea',
+    path: '/wls/area',
     query: { locationId: String(row.id) },
   });
 }
diff --git a/vite.config.ts b/vite.config.ts
index 22580b3..a38ba42 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -7,6 +7,40 @@
       oxc: {
         enable: false,
       },
+      optimizeDeps: {
+        include: [
+          "vue",
+          "vue-router",
+          "pinia",
+          "ant-design-vue",
+          "dayjs",
+          "@vueuse/core",
+          "axios",
+        ],
+        exclude: [
+          "dhtmlx-gantt",
+          "tinymce",
+          "bpmn-js",
+          "bpmn-js-properties-panel",
+          "video.js",
+        ],
+      },
+      build: {
+        rollupOptions: {
+          output: {
+            manualChunks: {
+              "vendor-vue": ["vue", "vue-router", "pinia"],
+              "vendor-ui": ["ant-design-vue", "@vueuse/core"],
+              "vendor-utils": ["dayjs", "axios", "@vee-validate/zod", "zod"],
+              "vendor-editor": [
+                "tinymce",
+                "@tinymce/tinymce-vue",
+                "@form-create/ant-design-vue",
+              ],
+            },
+          },
+        },
+      },
       server: {
         allowedHosts: true,
         watch: {

--
Gitblit v1.9.3