From 8b1b73b297451d87e2ebf8c1bcb05c64f108127c Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 30 七月 2026 13:36:35 +0800
Subject: [PATCH] 银川 1.销售退货选择销售订单逻辑修改

---
 src/views/erp/sale/order/components/select.vue        |    8 
 src/api/erp/sale/order/index.ts                       |    1 
 src/views/mes/md/item/components/select-dialog.vue    |   15 +
 src/views/mes/pro/workorder/modules/form.vue          |   48 +++--
 src/views/wls/returnsales/modules/line-list.vue       |    4 
 src/views/erp/sale/return/modules/item-form.vue       |   75 +++++++++
 src/views/erp/sale/return/modules/form.vue            |  138 +++++++++++++----
 src/views/wls/returnsales/modules/form.vue            |   32 +++
 src/views/wls/returnsales/modules/line-form.vue       |   37 ++++
 src/views/erp/sale/order/components/select-dialog.vue |    5 
 src/views/mes/md/item/components/select.vue           |    7 
 src/views/wls/returnsales/data.ts                     |   54 ++++++
 12 files changed, 358 insertions(+), 66 deletions(-)

diff --git a/src/api/erp/sale/order/index.ts b/src/api/erp/sale/order/index.ts
index 7e42f11..5468cab 100644
--- a/src/api/erp/sale/order/index.ts
+++ b/src/api/erp/sale/order/index.ts
@@ -55,6 +55,7 @@
     stockCount?: number; // 搴撳瓨鏁伴噺锛堟樉绀哄瓧娈碉級
     needProduction?: number; // 鏄惁闇�瑕佺敓浜э細0-涓嶉渶瑕侊紝1-闇�瑕�
     mpsId?: number; // MPS缂栧彿
+    batchCode?: string; // 鎵规鍙�
   }
 }
 
diff --git a/src/views/erp/sale/order/components/select-dialog.vue b/src/views/erp/sale/order/components/select-dialog.vue
index 9a1dfe1..8c8980e 100644
--- a/src/views/erp/sale/order/components/select-dialog.vue
+++ b/src/views/erp/sale/order/components/select-dialog.vue
@@ -17,6 +17,7 @@
 
 const open = ref(false);
 const multiple = ref(true);
+const outStatus = ref<number | undefined>(undefined);
 const status = ref<number | undefined>(undefined);
 const selectedRows = ref<ErpSaleOrderApi.SaleOrder[]>([]);
 const preSelectedIds = ref<number[]>([]);
@@ -117,6 +118,7 @@
           return await getSaleOrderPage({
             pageNo: page.currentPage,
             pageSize: page.pageSize,
+            outStatus: outStatus.value,
             status: status.value,
             ...formValues,
           });
@@ -149,10 +151,11 @@
 /** 鎵撳紑閿�鍞鍗曢�夋嫨寮圭獥 */
 async function openModal(
   selectedIds?: number[],
-  options?: { multiple?: boolean; status?: number },
+  options?: { multiple?: boolean; outStatus?: number; status?: number },
 ) {
   open.value = true;
   multiple.value = options?.multiple ?? true;
+  outStatus.value = options?.outStatus;
   status.value = options?.status;
   preSelectedIds.value = selectedIds || [];
   await nextTick();
diff --git a/src/views/erp/sale/order/components/select.vue b/src/views/erp/sale/order/components/select.vue
index 12652d0..a81843d 100644
--- a/src/views/erp/sale/order/components/select.vue
+++ b/src/views/erp/sale/order/components/select.vue
@@ -18,6 +18,7 @@
     allowClear?: boolean;
     disabled?: boolean;
     modelValue?: number;
+    outStatus?: number;
     placeholder?: string;
     status?: number;
   }>(),
@@ -25,6 +26,7 @@
     allowClear: true,
     disabled: false,
     modelValue: undefined,
+    outStatus: undefined,
     placeholder: '璇烽�夋嫨閿�鍞鍗�',
     status: undefined,
   },
@@ -84,7 +86,11 @@
   const selectedIds = (
     props.modelValue === null ? [] : [props.modelValue]
   ) as number[];
-  dialogRef.value?.open(selectedIds, { multiple: false, status: props.status });
+  dialogRef.value?.open(selectedIds, {
+    multiple: false,
+    outStatus: props.outStatus,
+    status: props.status,
+  });
 }
 
 function handleSelected(rows: ErpSaleOrderApi.SaleOrder[]) {
diff --git a/src/views/erp/sale/return/modules/form.vue b/src/views/erp/sale/return/modules/form.vue
index 7611a0c..64d7dd5 100644
--- a/src/views/erp/sale/return/modules/form.vue
+++ b/src/views/erp/sale/return/modules/form.vue
@@ -13,6 +13,7 @@
 
 import { useVbenForm } from '#/adapter/form';
 import { getAccountSimpleList } from '#/api/erp/finance/account';
+import { getSaleOrderItemListByOrderId, getSaleOrderPage } from '#/api/erp/sale/order';
 import {
   createSaleReturn,
   getSaleReturn,
@@ -48,6 +49,7 @@
 });
 const formType = ref<FormType>('create'); // 琛ㄥ崟绫诲瀷锛�'create' | 'edit' | 'detail'
 const itemFormRef = ref<InstanceType<typeof ItemForm>>();
+const orderItems = ref<ErpSaleOrderApi.SaleOrderItem[]>([]);
 
 const getTitle = computed(() => {
   if (formType.value === 'create') {
@@ -113,7 +115,7 @@
 }
 
 /** 閫夋嫨閿�鍞鍗� */
-function handleUpdateOrder(order: ErpSaleOrderApi.SaleOrder) {
+async function handleUpdateOrder(order: ErpSaleOrderApi.SaleOrder) {
   formData.value = {
     ...formData.value,
     orderId: order.id,
@@ -123,16 +125,34 @@
     remark: order.remark!,
     discountPercent: order.discountPercent!,
   };
-  // 灏嗚鍗曢」璁剧疆鍒伴��璐у崟椤�
-  order.items!.forEach((item: any) => {
-    item.totalCount = item.count;
-    item.count = item.totalCount - item.returnCount;
-    item.orderItemId = item.id;
-    item.id = undefined;
-  });
-  formData.value.items = order.items!.filter(
-    (item) => item.count && item.count > 0,
-  ) as ErpSaleReturnApi.SaleReturnItem[];
+  // 鍔犺浇鍏宠仈閿�鍞鍗曠殑鐗╂枡鍒楄〃
+  const items = await getSaleOrderItemListByOrderId(order.id!);
+  orderItems.value = items;
+  // 灏嗚鍗曢」杞崲涓洪��璐у崟椤癸紙浠呬繚鐣欏彲閫�璐ф暟閲� > 0 鐨勯」锛�
+  const returnItems: ErpSaleReturnApi.SaleReturnItem[] = [];
+  for (const item of items) {
+    const returnCount = (item as { returnCount?: number }).returnCount ?? 0;
+    const remainingCount = (item.count ?? 0) - returnCount;
+    if (remainingCount <= 0) continue;
+
+    returnItems.push({
+      orderItemId: item.id,
+      productId: item.productId,
+      productName: item.productName || '',
+      productPrice: item.productPrice || 0,
+      productUnitId: item.productUnitId,
+      productUnitName: item.productUnitName,
+      productBarCode: item.productBarCode,
+      totalCount: item.count,
+      count: remainingCount,
+      taxPercent: item.taxPercent || 0,
+      remark: item.remark || '',
+      totalProductPrice: 0,
+      taxPrice: 0,
+      totalPrice: 0,
+    });
+  }
+  formData.value.items = returnItems;
   formApi.setValues(formData.value, false);
 }
 
@@ -171,14 +191,72 @@
   async onOpenChange(isOpen: boolean) {
     if (!isOpen) {
       formData.value = {} as ErpSaleReturnApi.SaleReturn;
+      orderItems.value = [];
       return;
     }
-    // 鍔犺浇鏁版嵁
-    const data = modalApi.getData<{ formType: FormType; id?: number }>();
-    formType.value = data.formType;
+    const modalData = modalApi.getData<{ formType: FormType; id?: number }>();
+    formType.value = modalData.formType;
+
+    // 缂栬緫/璇︽儏妯″紡锛氬厛鍔犺浇鏁版嵁锛屽啀鏇存柊 schema锛岀‘淇濇覆鏌撴椂 orderNo 宸插氨缁�
+    if (modalData?.id) {
+      modalApi.lock();
+      try {
+        const apiData = await getSaleReturn(modalData.id);
+        const raw = apiData as Record<string, unknown>;
+
+        // 鎻愬彇璁㈠崟鍙凤紙灏濊瘯澶氱鍙兘鐨勫瓧娈靛悕 / 宓屽缁撴瀯锛�
+        const getOrderNo = (): string => {
+          if (raw.orderNo) return raw.orderNo as string;
+          if (raw.salesOrderCode) return raw.salesOrderCode as string;
+          if (raw.salesOrderNo) return raw.salesOrderNo as string;
+          const so = raw.salesOrder as Record<string, unknown> | undefined;
+          if (so?.no) return so.no as string;
+          const o = raw.order as Record<string, unknown> | undefined;
+          if (o?.no) return o.no as string;
+          return '';
+        };
+
+        // 鎻愬彇璁㈠崟ID锛堝皾璇曞绉嶅彲鑳界殑瀛楁鍚� / 宓屽缁撴瀯锛�
+        const getOrderId = (): number | undefined => {
+          if (raw.orderId) return raw.orderId as number;
+          if (raw.salesOrderId) return raw.salesOrderId as number;
+          const so = raw.salesOrder as Record<string, unknown> | undefined;
+          if (so?.id) return so.id as number;
+          const o = raw.order as Record<string, unknown> | undefined;
+          if (o?.id) return o.id as number;
+          return undefined;
+        };
+
+        let orderNo = getOrderNo();
+        let orderId = getOrderId();
+
+        // 濡傛灉鏈夎鍗曞彿浣嗘病鏈夎鍗旾D锛岄�氳繃璁㈠崟鍙峰弽鏌ヨ鍗旾D
+        if (orderNo && !orderId) {
+          const orderPage = await getSaleOrderPage({
+            pageNo: 1,
+            pageSize: 1,
+            no: orderNo,
+          } as Record<string, unknown> as never);
+          const list = (orderPage as Record<string, unknown>)?.list as Array<Record<string, unknown>> | undefined;
+          if (list?.length) {
+            orderId = list[0].id as number;
+          }
+        }
+
+        formData.value = { ...apiData, orderNo, orderId };
+        if (orderId) {
+          orderItems.value = await getSaleOrderItemListByOrderId(orderId);
+        }
+      } finally {
+        modalApi.unlock();
+      }
+    }
+
+    // 鏁版嵁灏辩华鍚庡啀鏇存柊 schema 鍜岃缃〃鍗曞��
     formApi.setDisabled(formType.value === 'detail');
     formApi.updateSchema(useFormSchema(formType.value));
-    if (!data || !data.id) {
+
+    if (!modalData?.id) {
       // 鏂板鏃讹紝榛樿閫変腑璐︽埛
       const accountList = await getAccountSimpleList();
       const defaultAccount = accountList.find((item) => item.defaultStatus);
@@ -187,23 +265,17 @@
       }
       return;
     }
-    modalApi.lock();
-    try {
-      formData.value = await getSaleReturn(data.id);
-      // 璁剧疆鍒� values
-      await formApi.setValues(formData.value, false);
-      if (formData.value?.attachmentList?.length) {
-        const blobIds = formData.value.attachmentList.map((item) => ({
-          uid: String(item.id),
-          name: item.name || '',
-          url: item.url || '',
-          status: 'done',
-          id: item.id,
-        }));
-        await formApi.setFieldValue('blobIds', blobIds);
-      }
-    } finally {
-      modalApi.unlock();
+
+    await formApi.setValues(formData.value, false);
+    if (formData.value?.attachmentList?.length) {
+      const blobIds = formData.value.attachmentList.map((item) => ({
+        uid: String(item.id),
+        name: item.name || '',
+        url: item.url || '',
+        status: 'done',
+        id: item.id,
+      }));
+      await formApi.setFieldValue('blobIds', blobIds);
     }
   },
 });
@@ -224,6 +296,7 @@
           :disabled="formType === 'detail'"
           :discount-percent="formData?.discountPercent ?? 0"
           :other-price="formData?.otherPrice ?? 0"
+          :order-items="orderItems"
           @update:items="handleUpdateItems"
           @update:discount-price="handleUpdateDiscountPrice"
           @update:other-price="handleUpdateOtherPrice"
@@ -232,6 +305,7 @@
       </template>
       <template #orderNo>
         <SaleOrderSelect
+          :key="formData?.orderNo ?? 'empty'"
           :order-no="formData?.orderNo"
           @update:order="handleUpdateOrder"
         />
diff --git a/src/views/erp/sale/return/modules/item-form.vue b/src/views/erp/sale/return/modules/item-form.vue
index af30c83..04cb817 100644
--- a/src/views/erp/sale/return/modules/item-form.vue
+++ b/src/views/erp/sale/return/modules/item-form.vue
@@ -1,5 +1,6 @@
 <script lang="ts" setup>
 import type { MdmItemApi } from '#/api/mdm/item';
+import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
 import type { ErpSaleReturnApi } from '#/api/erp/sale/return';
 
 import { computed, nextTick, onMounted, ref, watch } from 'vue';
@@ -24,6 +25,7 @@
   disabled?: boolean;
   discountPercent?: number;
   otherPrice?: number;
+  orderItems?: ErpSaleOrderApi.SaleOrderItem[];
 }
 
 const props = withDefaults(defineProps<Props>(), {
@@ -31,6 +33,7 @@
   disabled: false,
   discountPercent: 0,
   otherPrice: 0,
+  orderItems: () => [],
 });
 
 const emit = defineEmits([
@@ -141,6 +144,57 @@
   emit('update:items', [...tableData.value]);
 }
 
+/** 澶勭悊鏂板鐗╂枡琛� */
+function handleAdd() {
+  const newRow: ErpSaleReturnApi.SaleReturnItem = {
+    seq: Date.now(),
+    productId: undefined,
+    productName: '',
+    productPrice: 0,
+    productUnitId: undefined,
+    productUnitName: '',
+    count: 0,
+    totalProductPrice: 0,
+    taxPercent: 0,
+    taxPrice: 0,
+    totalPrice: 0,
+    remark: '',
+  };
+  tableData.value.push(newRow);
+  emit('update:items', [...tableData.value]);
+}
+
+/** 澶勭悊浜у搧鍙樻洿锛氫紭鍏堜粠鍏宠仈璁㈠崟鐗╂枡涓~鍏咃紝鍏滃簳浠庡叏閮ㄧ墿鏂欎腑鏌ユ壘 */
+function handleProductChange(row: ErpSaleReturnApi.SaleReturnItem) {
+  // 浼樺厛浠庡叧鑱旇鍗曠殑鐗╂枡涓煡鎵�
+  const orderItem = props.orderItems.find(
+    (item) => item.productId === row.productId,
+  );
+  if (orderItem) {
+    row.productName = orderItem.productName;
+    row.productPrice = orderItem.productPrice ?? 0;
+    row.productUnitId = orderItem.productUnitId;
+    row.productUnitName = orderItem.productUnitName;
+    row.productBarCode = orderItem.productBarCode;
+    row.taxPercent = orderItem.taxPercent ?? 0;
+    row.count = row.count || 1;
+    handleRowChange(row);
+    return;
+  }
+  // 鍏滃簳锛氫粠鍏ㄩ儴鐗╂枡涓煡鎵�
+  const product = productOptions.value.find((item) => item.id === row.productId);
+  if (product) {
+    row.productName = product.name || '';
+    row.productPrice = product.salesPrice ?? 0;
+    row.productUnitId = product.unitMeasureId;
+    row.productUnitName = product.unitMeasureName;
+    row.productBarCode = product.barCode;
+    row.taxPercent = 0;
+    row.count = row.count || 1;
+    handleRowChange(row);
+  }
+}
+
 /** 澶勭悊浠撳簱鍙樻洿 */
 async function handleWarehouseChange(row: ErpSaleReturnApi.SaleReturnItem) {
   const stockCount = await getWarehouseStockCount({
@@ -177,6 +231,9 @@
   for (let i = 0; i < tableData.value.length; i++) {
     const item = tableData.value[i];
     if (item) {
+      if (!item.productId) {
+        throw new Error(`绗� ${i + 1} 琛岋細浜у搧涓嶈兘涓虹┖`);
+      }
       if (!item.warehouseId) {
         throw new Error(`绗� ${i + 1} 琛岋細浠撳簱涓嶈兘涓虹┖`);
       }
@@ -215,13 +272,14 @@
     </template>
     <template #productId="{ row }">
       <Select
-        disabled
+        :disabled="disabled"
         v-model:value="row.productId"
-        :options="productOptions"
-        :field-names="{ label: 'name', value: 'id' }"
+        :options="orderItems?.length ? orderItems : productOptions"
+        :field-names="orderItems?.length ? { label: 'productName', value: 'productId' } : { label: 'name', value: 'id' }"
         class="w-full"
         placeholder="璇烽�夋嫨浜у搧"
         show-search
+        @change="handleProductChange(row)"
       />
     </template>
     <template #count="{ row }">
@@ -291,6 +349,17 @@
           </div>
         </div>
       </div>
+      <TableAction
+        v-if="!disabled"
+        class="mt-2 flex justify-center"
+        :actions="[
+          {
+            label: '娣诲姞閫�璐т骇鍝�',
+            type: 'default',
+            onClick: handleAdd,
+          },
+        ]"
+      />
     </template>
   </Grid>
 </template>
diff --git a/src/views/mes/md/item/components/select-dialog.vue b/src/views/mes/md/item/components/select-dialog.vue
index a7ed8b8..d377f66 100644
--- a/src/views/mes/md/item/components/select-dialog.vue
+++ b/src/views/mes/md/item/components/select-dialog.vue
@@ -26,6 +26,7 @@
   const selectedRows = ref<MesMdItemApi.Item[]>([]); // 宸查�夌墿鏂欏垪琛�
   const selectedItemTypeId = ref<number>(); // 褰撳墠绛涢�夊垎绫荤紪鍙�
   const preSelectedIds = ref<number[]>([]); // 棰勯�夌墿鏂欑紪鍙峰垪琛�
+  const productIds = ref<number[]>([]); // 闄愬畾鍙�夌殑鐗╂枡缂栧彿鍒楄〃锛堜负绌哄垯涓嶉檺鍒讹級
   const typeTreeRef = ref<InstanceType<typeof MdItemTypeTree>>(); // 鐗╂枡鍒嗙被鏍�
 
   /** 鑾峰彇褰撳墠琛ㄦ牸鏁版嵁 */
@@ -130,13 +131,20 @@
       proxyConfig: {
         ajax: {
           query: async ({ page }, formValues) => {
-            return await getItemPage({
+            const params: Record<string, unknown> = {
               pageNo: page.currentPage,
               pageSize: page.pageSize,
               ...formValues,
               itemTypeId: selectedItemTypeId.value,
               status: CommonStatusEnum.ENABLE,
-            });
+            };
+            // 闄愬畾鍙�夌墿鏂欒寖鍥�
+            if (productIds.value.length > 0) {
+              params.pageSize = 1000;
+              params.ids = productIds.value.join(',');
+            }
+            const result = await getItemPage(params as never);
+            return result;
           },
         },
       },
@@ -173,11 +181,12 @@
   /** 鎵撳紑鐗╂枡閫夋嫨寮圭獥 */
   async function openModal(
     selectedIds?: number[],
-    options?: { multiple?: boolean }
+    options?: { multiple?: boolean; productIds?: number[] }
   ) {
     open.value = true;
     multiple.value = options?.multiple ?? true;
     preSelectedIds.value = selectedIds || [];
+    productIds.value = options?.productIds || [];
     await nextTick();
     gridApi.setGridOptions({
       columns: useItemSelectGridColumns(multiple.value),
diff --git a/src/views/mes/md/item/components/select.vue b/src/views/mes/md/item/components/select.vue
index e5ffb2b..d157aff 100644
--- a/src/views/mes/md/item/components/select.vue
+++ b/src/views/mes/md/item/components/select.vue
@@ -19,12 +19,14 @@
     disabled?: boolean;
     modelValue?: number;
     placeholder?: string;
+    productIds?: number[];
   }>(),
   {
     allowClear: true,
     disabled: false,
     modelValue: undefined,
     placeholder: '璇烽�夋嫨浜у搧鐗╂枡',
+    productIds: () => [],
   },
 );
 const emit = defineEmits<{
@@ -86,7 +88,10 @@
   const selectedIds = (
     props.modelValue === null ? [] : [props.modelValue]
   ) as number[];
-  dialogRef.value?.open(selectedIds, { multiple: false });
+  dialogRef.value?.open(selectedIds, {
+    multiple: false,
+    productIds: props.productIds,
+  });
 }
 
 /** 鍥炲~閫変腑鐨勭墿鏂� */
diff --git a/src/views/mes/pro/workorder/modules/form.vue b/src/views/mes/pro/workorder/modules/form.vue
index c998ef8..1181216 100644
--- a/src/views/mes/pro/workorder/modules/form.vue
+++ b/src/views/mes/pro/workorder/modules/form.vue
@@ -99,19 +99,17 @@
   });
 
   /** 閲嶆柊鎸傝浇 schema 骞舵寜琛ㄥ崟鎬佹帶鍒跺簳閮ㄦ寜閽� */
+  const mainActionText = computed(() => {
+    if (isConfirm.value) return '纭';
+    if (isFinish.value) return '瀹屾垚';
+    return '鎻愪氦';
+  });
+
+  const showMainBtn = computed(() => isEditable.value || isConfirm.value || isFinish.value);
+
   function applySchema() {
     formApi.setState({ schema: useFormSchema(formType.value, formApi) });
-    const showBtn = isEditable.value || isConfirm.value || isFinish.value;
-    modalApi.setState({
-      showConfirmButton: showBtn,
-      confirmText: isConfirm.value || canConfirm.value
-        ? '纭'
-        : isFinish.value
-          ? '瀹屾垚'
-          : isCreateMode.value
-            ? '鏂板'
-            : '淇濆瓨',
-    });
+    modalApi.setState({ showCancelButton: false, showConfirmButton: false });
   }
 
   /** 浠呬繚瀛橈紙涓嶆敼鍙樼姸鎬侊級 */
@@ -353,14 +351,26 @@
       </Tabs>
     </template>
     <template #prepend-footer>
-      <Button v-if="canConfirm"
-              @click="handleSave">
-        淇濆瓨
-      </Button>
-      <Button v-if="formType === 'detail' && formData?.id"
-              @click="handleBarcode">
-        鏌ョ湅鏉$爜
-      </Button>
+      <div class="flex flex-auto items-center">
+        <Button v-if="showMainBtn"
+                type="primary"
+                @click="modalApi.onConfirm()">
+          {{ mainActionText }}
+        </Button>
+      </div>
+    </template>
+    <template #append-footer>
+      <div class="flex gap-2">
+        <Button v-if="canConfirm"
+                @click="handleSave">
+          淇濆瓨淇敼
+        </Button>
+        <Button v-if="formType === 'detail' && formData?.id"
+                @click="handleBarcode">
+          鏌ョ湅鏉$爜
+        </Button>
+        <Button @click="modalApi.close()">鍙栨秷</Button>
+      </div>
     </template>
   </Modal>
   <BarcodeDetail ref="barcodeDetailRef" />
diff --git a/src/views/wls/returnsales/data.ts b/src/views/wls/returnsales/data.ts
index fadbd4a..9b61d3c 100644
--- a/src/views/wls/returnsales/data.ts
+++ b/src/views/wls/returnsales/data.ts
@@ -1,3 +1,4 @@
+import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
 import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { MesWmReturnSalesApi } from '#/api/mes/wm/returnsales';
@@ -35,6 +36,7 @@
 export function useFormSchema(
   formType: FormType,
   formApi?: VbenFormApi,
+  onOrderChange?: (item: Record<string, unknown> | undefined) => void,
 ): VbenFormSchema[] {
   return [
     {
@@ -100,6 +102,7 @@
       label: '閿�鍞鍗曞彿',
       component: markRaw(ErpSaleOrderSelect),
       componentProps: {
+        outStatus: 3,
         placeholder: '璇烽�夋嫨閿�鍞鍗�',
         onChange: (item: any) => {
           if (formApi) {
@@ -108,6 +111,7 @@
               formApi.setFieldValue('clientId', item.customerId);
             }
           }
+          onOrderChange?.(item);
         },
       },
       rules: 'selectRequired',
@@ -342,15 +346,31 @@
 export function useLineFormSchema(
   clientId?: number,
   salesOrderCode?: string,
+  items?: ErpSaleOrderApi.SaleOrderItem[],
+  onItemChange?: (item: ErpSaleOrderApi.SaleOrderItem | undefined) => void,
 ): VbenFormSchema[] {
+  const hasItems = items && items.length > 0;
   return [
     {
       fieldName: 'itemId',
       label: '鐗╂枡',
-      component: markRaw(MdItemSelect),
-      componentProps: {
-        placeholder: '璇烽�夋嫨鐗╂枡',
-      },
+      component: hasItems ? 'Select' : markRaw(MdItemSelect),
+      componentProps: hasItems
+        ? {
+            placeholder: '璇烽�夋嫨鐗╂枡',
+            options: items.map((item) => ({
+              label: `${item.productName || ''}锛�${item.productBarCode || ''}锛塦,
+              value: item.productId,
+            })),
+            onChange: (value: number | undefined) => {
+              const selected = items.find((i) => i.productId === value);
+              onItemChange?.(selected);
+            },
+          }
+        : {
+            placeholder: '璇烽�夋嫨鐗╂枡',
+            productIds: [],
+          },
       rules: 'selectRequired',
     },
     {
@@ -363,6 +383,30 @@
         placeholder: '璇疯緭鍏ラ��璐ф暟閲�',
         precision: 2,
       },
+      dependencies: {
+        triggerFields: ['itemId'],
+        componentProps: (values) => {
+          const selected = items?.find((i) => i.productId === values.itemId);
+          return {
+            class: '!w-full',
+            max: selected?.count ?? undefined,
+            min: 0,
+            placeholder: '璇疯緭鍏ラ��璐ф暟閲�',
+            precision: 2,
+          };
+        },
+        rules: (values) => {
+          const selected = items?.find((i) => i.productId === values.itemId);
+          const max = selected?.count;
+          if (max !== undefined && max !== null) {
+            return z
+              .number({ message: '璇疯緭鍏ラ��璐ф暟閲�' })
+              .min(0)
+              .max(max, `鍙��璐ф暟閲忎笉鑳借秴杩� ${max}`);
+          }
+          return z.number({ message: '璇疯緭鍏ラ��璐ф暟閲�' }).min(0);
+        },
+      },
       rules: 'required',
     },
     {
@@ -371,6 +415,7 @@
       component: markRaw(WmBatchSelect),
       componentProps: {
         clientId,
+        disabled: true,
         placeholder: '璇烽�夋嫨鎵规',
         salesOrderCode,
       },
@@ -378,6 +423,7 @@
         triggerFields: ['itemId'],
         componentProps: (values) => ({
           clientId,
+          disabled: true,
           itemId: values.itemId,
           placeholder: '璇烽�夋嫨鎵规',
           salesOrderCode,
diff --git a/src/views/wls/returnsales/modules/form.vue b/src/views/wls/returnsales/modules/form.vue
index 3cae020..2f57364 100644
--- a/src/views/wls/returnsales/modules/form.vue
+++ b/src/views/wls/returnsales/modules/form.vue
@@ -19,6 +19,9 @@
   submitReturnSales,
   updateReturnSales,
 } from '#/api/mes/wm/returnsales';
+import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
+
+import { getSaleOrder, getSaleOrderPage } from '#/api/erp/sale/order';
 import { $t } from '#/locales';
 
 import { useFormSchema } from '../data';
@@ -28,6 +31,7 @@
 const formType = ref<FormType>('create');
 const formData = ref<MesWmReturnSalesApi.ReturnSales>();
 const originalSnapshot = ref(''); // 琛ㄥ崟鍘熷鏁版嵁蹇収锛岀敤浜庢彁浜ゆ椂璺宠繃鏈彉鏇寸殑淇濆瓨璇锋眰
+const saleOrderItems = ref<ErpSaleOrderApi.SaleOrderItem[]>([]); // 褰撳墠閿�鍞鍗曠殑鐗╂枡琛�
 const isEditable = computed(() =>
   // 鏄惁涓虹紪杈戞ā寮忥紙鍙繚瀛橈級
   ['create', 'update'].includes(formType.value),
@@ -169,13 +173,38 @@
     // 鍔犺浇鏁版嵁
     const data = modalApi.getData<{ formType: FormType; id?: number }>();
     formType.value = data.formType;
-    formApi.setState({ schema: useFormSchema(formType.value, formApi) });
+    formApi.setState({
+      schema: useFormSchema(formType.value, formApi, (item) => {
+        if (item?.id) {
+          getSaleOrder(item.id as number).then((order) => {
+            saleOrderItems.value = (order as ErpSaleOrderApi.SaleOrder)?.items || [];
+          });
+        } else {
+          saleOrderItems.value = [];
+        }
+      }),
+    });
     formApi.setDisabled(!isEditable.value);
     modalApi.setState({ showConfirmButton: isEditable.value });
     if (data?.id) {
       modalApi.lock();
       try {
         formData.value = await getReturnSales(data.id);
+        // 閫氳繃閿�鍞鍗曞彿鍙嶆煡璁㈠崟ID锛岀‘淇� ErpSaleOrderSelect 鑳芥纭洖鏄�
+        if (formData.value?.salesOrderCode && !formData.value.saleOrderId) {
+          const orderPage = await getSaleOrderPage({
+            pageNo: 1,
+            pageSize: 1,
+            no: formData.value.salesOrderCode,
+          } as Record<string, unknown> as never);
+          const list = (orderPage as Record<string, unknown>)?.list as Array<Record<string, unknown>> | undefined;
+          if (list?.length) {
+            const orderId = list[0].id as number;
+            (formData.value as Record<string, unknown>).saleOrderId = orderId;
+            const order = await getSaleOrder(orderId);
+            saleOrderItems.value = order?.items || [];
+          }
+        }
         // 璁剧疆鍒� values
         await formApi.setValues(formData.value);
       } finally {
@@ -198,6 +227,7 @@
           :client-id="formData.clientId"
           :form-type="formType"
           :return-id="formData.id"
+          :sale-order-items="saleOrderItems"
           :sales-order-code="formData.salesOrderCode"
         />
       </div>
diff --git a/src/views/wls/returnsales/modules/line-form.vue b/src/views/wls/returnsales/modules/line-form.vue
index 0736b8b..06adfaf 100644
--- a/src/views/wls/returnsales/modules/line-form.vue
+++ b/src/views/wls/returnsales/modules/line-form.vue
@@ -1,4 +1,5 @@
 <script lang="ts" setup>
+import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
 import type { MesWmReturnSalesLineApi } from '#/api/mes/wm/returnsales/line';
 
 import { computed, ref } from 'vue';
@@ -8,6 +9,7 @@
 import { message } from 'ant-design-vue';
 
 import { useVbenForm } from '#/adapter/form';
+import { getBatchPage } from '#/api/mes/wm/batch';
 import {
   createReturnSalesLine,
   getReturnSalesLine,
@@ -20,6 +22,7 @@
 const emit = defineEmits(['success']);
 const formData = ref<MesWmReturnSalesLineApi.ReturnSalesLine>();
 const returnId = ref<number>(); // 鎵�灞為��璐у崟缂栧彿
+const maxQuantity = ref<number>(); // 褰撳墠閫変腑鐗╂枡鍙��璐х殑鏈�澶ф暟閲�
 
 const getTitle = computed(() => {
   return formData.value?.id
@@ -73,12 +76,38 @@
     const data = modalApi.getData<{
       clientId?: number;
       id?: number;
+      items?: ErpSaleOrderApi.SaleOrderItem[];
       returnId: number;
       salesOrderCode?: string;
     }>();
     returnId.value = data.returnId;
+    maxQuantity.value = undefined;
     formApi.setState({
-      schema: useLineFormSchema(data.clientId, data.salesOrderCode),
+      schema: useLineFormSchema(
+        data.clientId,
+        data.salesOrderCode,
+        data.items || [],
+        async (item) => {
+          maxQuantity.value = item?.count;
+          // 閲嶇疆鎵规
+          await formApi.setFieldValue('batchId', undefined);
+          if (item?.batchCode) {
+            try {
+              const batchPage = await getBatchPage({
+                code: item.batchCode,
+                pageNo: 1,
+                pageSize: 1,
+              });
+              const batchList = batchPage?.list;
+              if (batchList?.length) {
+                await formApi.setFieldValue('batchId', batchList[0].id);
+              }
+            } catch {
+              // 鏌ヨ澶辫触鏃跺拷鐣�
+            }
+          }
+        },
+      ),
     });
     if (!data.id) {
       return;
@@ -98,5 +127,11 @@
 <template>
   <Modal :title="getTitle" class="w-3/5">
     <Form class="mx-4" />
+    <div
+      v-if="maxQuantity !== undefined"
+      class="mx-4 mt-2 text-sm text-blue-600"
+    >
+      褰撳墠鐗╂枡鍙��璐ф暟閲忥細<span class="font-bold">{{ maxQuantity }}</span>
+    </div>
   </Modal>
 </template>
diff --git a/src/views/wls/returnsales/modules/line-list.vue b/src/views/wls/returnsales/modules/line-list.vue
index d1ab690..9c635e2 100644
--- a/src/views/wls/returnsales/modules/line-list.vue
+++ b/src/views/wls/returnsales/modules/line-list.vue
@@ -1,6 +1,7 @@
 <script lang="ts" setup>
 import type { FormType } from '../data';
 
+import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { MesWmReturnSalesDetailApi } from '#/api/mes/wm/returnsales/detail';
 import type { MesWmReturnSalesLineApi } from '#/api/mes/wm/returnsales/line';
@@ -29,6 +30,7 @@
   clientId?: number;
   formType: FormType;
   returnId: number;
+  saleOrderItems?: ErpSaleOrderApi.SaleOrderItem[];
   salesOrderCode?: string;
 }>();
 
@@ -64,6 +66,7 @@
   lineFormModalApi
     .setData({
       clientId: props.clientId,
+      items: props.saleOrderItems,
       returnId: props.returnId,
       salesOrderCode: props.salesOrderCode,
     })
@@ -76,6 +79,7 @@
     .setData({
       clientId: props.clientId,
       id: row.id,
+      items: props.saleOrderItems,
       returnId: props.returnId,
       salesOrderCode: props.salesOrderCode,
     })

--
Gitblit v1.9.3