From 5470429a79313630a7ddef601de1d89e7dada754 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期五, 22 五月 2026 09:14:12 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_NEW_pro' into dev-new_pro_OA

---
 src/views/financialManagement/receivable/invoiceApply.vue |  238 ++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 195 insertions(+), 43 deletions(-)

diff --git a/src/views/financialManagement/receivable/invoiceApply.vue b/src/views/financialManagement/receivable/invoiceApply.vue
index ac691bc..31b6345 100644
--- a/src/views/financialManagement/receivable/invoiceApply.vue
+++ b/src/views/financialManagement/receivable/invoiceApply.vue
@@ -72,7 +72,7 @@
           <el-button type="primary" link @click="edit(row)" v-if="isPendingStatus(row.status)">缂栬緫</el-button>
           <el-button type="danger" link @click="handleDelete(row)" v-if="isPendingStatus(row.status)">鍒犻櫎</el-button>
           <el-button type="success" link @click="handleAudit(row)" v-if="isPendingStatus(row.status)">瀹℃牳</el-button>
-          <!-- <el-button type="warning" link @click="handleInvoice(row)" v-if="isApprovedStatus(row.status)">寮�绁�</el-button> -->
+          <el-button type="primary" link @click="openFileDialog(row)" v-if="isApprovedStatus(row.status)">闄勪欢</el-button>
         </template>
       </PIMTable>
     </div>
@@ -119,25 +119,24 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="鍑哄簱鍗曞彿" prop="outboundBatchNos">
-              <el-select
-                v-model="form.outboundBatchNos"
-                multiple
-                collapse-tags
-                collapse-tags-tooltip
-                filterable
+              <el-input
+                :model-value="outboundBatchDisplayText"
                 placeholder="璇峰厛閫夋嫨瀹㈡埛"
-                style="width: 100%;"
-                :disabled="!form.customerId || isView"
-                :loading="outboundBatchLoading"
-                @change="handleOutboundBatchChange"
+                readonly
+                :disabled="!form.customerId || isEdit || isView"
+                class="outbound-batch-input"
+                @click="handleOutboundInputClick"
               >
-                <el-option
-                  v-for="item in outboundBatchOptions"
-                  :key="item.value"
-                  :label="item.label"
-                  :value="item.value"
-                />
-              </el-select>
+                <template v-if="!isEdit && !isView" #append>
+                  <el-button
+                    :disabled="!form.customerId"
+                    :loading="outboundBatchLoading"
+                    @click.stop="openOutboundSelectDialog"
+                  >
+                    閫夋嫨
+                  </el-button>
+                </template>
+              </el-input>
             </el-form-item>
           </el-col>
         </el-row>
@@ -171,9 +170,9 @@
           <el-col :span="12">
             <el-form-item label="鍙戠エ绫诲瀷" prop="invoiceType">
               <el-select v-model="form.invoiceType" placeholder="璇烽�夋嫨鍙戠エ绫诲瀷" style="width: 100%;" :disabled="isView">
-                <el-option label="澧炲�肩◣涓撶敤鍙戠エ" value="special" />
-                <el-option label="澧炲�肩◣鏅�氬彂绁�" value="normal" />
-                <el-option label="鐢靛瓙鍙戠エ" value="electronic" />
+                <el-option label="澧炲�肩◣涓撶敤鍙戠エ" value="澧炲�肩◣涓撶敤鍙戠エ" />
+                <el-option label="澧炲�肩◣鏅�氬彂绁�" value="澧炲�肩◣鏅�氬彂绁�" />
+                <el-option label="鐢靛瓙鍙戠エ" value="鐢靛瓙鍙戠エ" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -202,11 +201,58 @@
         <el-button @click="closeDialog">鍙栨秷</el-button>
       </template>
     </FormDialog>
+
+    <el-dialog
+      v-model="outboundSelectVisible"
+      title="閫夋嫨鍑哄簱鍗�"
+      width="1200px"
+      append-to-body
+      destroy-on-close
+      :close-on-click-modal="false"
+      @closed="handleOutboundDialogClosed"
+    >
+      <el-table
+        ref="outboundTableRef"
+        v-loading="outboundBatchLoading"
+        :data="outboundBatchList"
+        row-key="id"
+        border
+        stripe
+        max-height="480"
+        @selection-change="handleOutboundDialogSelectionChange"
+      >
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column prop="outboundBatches" label="鍑哄簱鍗曞彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="customerName" label="瀹㈡埛鍚嶇О" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="productName" label="浜у搧鍚嶇О" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="specificationModel" label="瑙勬牸鍨嬪彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="salesContractNo" label="閿�鍞悎鍚屽彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="shippingNo" label="鍙戣揣鍗曞彿" min-width="130" show-overflow-tooltip />
+        <el-table-column prop="shippingDate" label="鍙戣揣鏃ユ湡" width="110" align="center" />
+        <el-table-column prop="outboundAmount" label="鍑哄簱閲戦" width="110" align="right">
+          <template #default="{ row }">楼{{ formatMoney(row.outboundAmount) }}</template>
+        </el-table-column>
+        <el-table-column prop="taxRate" label="绋庣巼" width="80" align="center">
+          <template #default="{ row }">{{ row.taxRate }}%</template>
+        </el-table-column>
+      </el-table>
+      <template #footer>
+        <el-button type="primary" @click="confirmOutboundSelection">纭畾</el-button>
+        <el-button @click="outboundSelectVisible = false">鍙栨秷</el-button>
+      </template>
+    </el-dialog>
+
+    <FileList
+      v-if="fileDialogVisible"
+      v-model:visible="fileDialogVisible"
+      record-type="account_invoice_application"
+      :record-id="currentRecordId"
+    />
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+import { ref, reactive, computed, onMounted, nextTick, getCurrentInstance, defineAsyncComponent } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import FormDialog from "@/components/Dialog/FormDialog.vue";
 import { listCustomer } from "@/api/basicData/customer.js";
@@ -218,6 +264,8 @@
   updateAccountInvoiceApplication,
   deleteAccountInvoiceApplication,
 } from "@/api/financialManagement/invoiceApply.js";
+
+const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
 defineOptions({
   name: "寮�绁ㄧ敵璇�",
@@ -244,10 +292,10 @@
   { label: "瀹㈡埛鍚嶇О", prop: "customerName", width: "180" },
   { label: "寮�绁ㄩ噾棰�", prop: "amount", dataType: "slot", slot: "amount" },
   { label: "绋庣巼", prop: "taxRate", dataType: "slot", slot: "taxRate" },
-  { label: "鍙戠エ绫诲瀷", prop: "invoiceTypeLabel", width: "130" },
+  { label: "鍙戠エ绫诲瀷", prop: "invoiceType", width: "130" },
   { label: "鐢宠鏃ユ湡", prop: "applyDate", width: "120" },
   { label: "瀹℃牳鐘舵��", prop: "status", dataType: "slot", slot: "status", width: "110", align: "center" },
-  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "260", fixed: "right" },
+  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "300", fixed: "right" },
 ];
 
 const dataList = ref([]);
@@ -262,13 +310,18 @@
 
 const closeDialog = () => {
   dialogVisible.value = false;
+  outboundSelectVisible.value = false;
   isView.value = false;
   isEdit.value = false;
 };
 
 const customerList = ref([]);
+const outboundBatchList = ref([]);
 const outboundBatchOptions = ref([]);
 const outboundBatchLoading = ref(false);
+const outboundSelectVisible = ref(false);
+const outboundTableRef = ref(null);
+const dialogOutboundSelection = ref([]);
 
 const getCustomerList = () => {
   listCustomer({ current: -1, size: -1, type: 0 }).then((res) => {
@@ -302,9 +355,13 @@
   });
 };
 
+const isSameOutboundId = (a, b) => String(a) === String(b);
+
 const getSelectedOutboundOptions = () => {
   const selected = form.outboundBatchNos || [];
-  return outboundBatchOptions.value.filter((opt) => selected.includes(opt.value));
+  return outboundBatchOptions.value.filter((opt) =>
+    selected.some((id) => isSameOutboundId(id, opt.value))
+  );
 };
 
 /** 鏍¢獙鎵�閫夊嚭搴撳崟绋庣巼鏄惁涓�鑷达紝涓�鑷村垯鍥炲~ form.taxRate */
@@ -334,18 +391,89 @@
 const syncInvoiceAmount = () => {
   const selected = form.outboundBatchNos || [];
   const sum = outboundBatchOptions.value
-    .filter((opt) => selected.includes(opt.value))
+    .filter((opt) => selected.some((id) => isSameOutboundId(id, opt.value)))
     .reduce((acc, opt) => acc + (Number(opt.outboundAmount) || 0), 0);
   form.amount = sum > 0 ? Number(sum.toFixed(2)) : 0;
 };
 
-const handleOutboundBatchChange = () => {
+const getOutboundRowId = (row) => row?.id ?? row?.stockOutRecordId;
+
+const outboundBatchDisplayText = computed(() => {
+  if (isEdit.value || isView.value) {
+    return form.outboundBatches || "";
+  }
+  if (form.outboundBatches) return form.outboundBatches;
+  const ids = form.outboundBatchNos || [];
+  if (!ids.length) return "";
+  return outboundBatchOptions.value
+    .filter((opt) => ids.some((id) => isSameOutboundId(id, opt.value)))
+    .map((opt) => opt.label)
+    .join("銆�");
+});
+
+const handleOutboundInputClick = () => {
+  if (isEdit.value || isView.value) return;
+  openOutboundSelectDialog();
+};
+
+const restoreOutboundTableSelection = () => {
+  nextTick(() => {
+    const table = outboundTableRef.value;
+    if (!table) return;
+    table.clearSelection();
+    const selectedIds = new Set((form.outboundBatchNos || []).map((id) => String(id)));
+    outboundBatchList.value.forEach((row) => {
+      const rowId = getOutboundRowId(row);
+      if (rowId !== undefined && rowId !== null && selectedIds.has(String(rowId))) {
+        table.toggleRowSelection(row, true);
+      }
+    });
+  });
+};
+
+const openOutboundSelectDialog = () => {
+  if (!form.customerId || isEdit.value || isView.value) return;
+  outboundSelectVisible.value = true;
+  loadOutboundBatches(form.customerId, true).then(() => {
+    restoreOutboundTableSelection();
+  });
+};
+
+const handleOutboundDialogSelectionChange = (selection) => {
+  dialogOutboundSelection.value = selection;
+};
+
+const confirmOutboundSelection = () => {
+  if (dialogOutboundSelection.value.length === 0) {
+    ElMessage.warning("璇疯嚦灏戦�夋嫨涓�鏉″嚭搴撳崟");
+    return;
+  }
+  const prevIds = [...(form.outboundBatchNos || [])];
+  const prevBatches = form.outboundBatches;
+  form.outboundBatchNos = dialogOutboundSelection.value
+    .map((row) => getOutboundRowId(row))
+    .filter((id) => id !== undefined && id !== null);
+  form.outboundBatches = dialogOutboundSelection.value
+    .map((row) => row.outboundBatches ?? row.batchNo ?? row.shippingNo ?? "")
+    .filter(Boolean)
+    .join("銆�");
+  if (!checkTaxRateConsistency()) {
+    form.outboundBatchNos = prevIds;
+    form.outboundBatches = prevBatches;
+    return;
+  }
+  outboundSelectVisible.value = false;
   syncInvoiceAmount();
-  checkTaxRateConsistency();
+  formRef.value?.validateField("outboundBatchNos");
+};
+
+const handleOutboundDialogClosed = () => {
+  dialogOutboundSelection.value = [];
 };
 
 const loadOutboundBatches = (customerId, keepSelected = false) => {
   if (!customerId) {
+    outboundBatchList.value = [];
     outboundBatchOptions.value = [];
     if (!keepSelected) {
       form.outboundBatchNos = [];
@@ -358,12 +486,15 @@
     .then((res) => {
       if (res.code === 200) {
         const list = res.data?.records ?? res.data ?? [];
+        outboundBatchList.value = Array.isArray(list) ? list : [];
         outboundBatchOptions.value = normalizeOutboundBatchOptions(list);
       } else {
+        outboundBatchList.value = [];
         outboundBatchOptions.value = [];
       }
     })
     .catch(() => {
+      outboundBatchList.value = [];
       outboundBatchOptions.value = [];
     })
     .finally(() => {
@@ -377,6 +508,7 @@
 
 const handleCustomerChange = (customerId) => {
   form.outboundBatchNos = [];
+  form.outboundBatches = "";
   form.amount = 0;
   loadOutboundBatches(customerId);
 };
@@ -385,9 +517,10 @@
   applyCode: "",
   customerId: "",
   outboundBatchNos: [],
+  outboundBatches: "",
   amount: 0,
   taxRate: 13,
-  invoiceType: "special",
+  invoiceType: "澧炲�肩◣涓撶敤鍙戠エ",
   applyDate: "",
   content: "",
   remark: "",
@@ -400,12 +533,6 @@
   taxRate: [{ required: true, message: "璇烽�夋嫨绋庣巼", trigger: "change" }],
   invoiceType: [{ required: true, message: "璇烽�夋嫨鍙戠エ绫诲瀷", trigger: "change" }],
   applyDate: [{ required: true, message: "璇烽�夋嫨鐢宠鏃ユ湡", trigger: "change" }],
-};
-
-const INVOICE_TYPE_LABEL_MAP = {
-  special: "澧炲�肩◣涓撶敤鍙戠エ",
-  normal: "澧炲�肩◣鏅�氬彂绁�",
-  electronic: "鐢靛瓙鍙戠エ",
 };
 
 /** 瀹℃牳鐘舵�侊細0寰呭鏍� 1瀹℃牳閫氳繃 2瀹℃牳涓嶉�氳繃 */
@@ -421,8 +548,6 @@
   2: "danger",
 };
 
-const getInvoiceTypeLabel = (type) => INVOICE_TYPE_LABEL_MAP[type] || type || "";
-
 const normalizeStatus = (status) => {
   if (status === undefined || status === null || status === "") return status;
   const num = Number(status);
@@ -432,13 +557,32 @@
 const isPendingStatus = (status) => normalizeStatus(status) === 0;
 const isApprovedStatus = (status) => normalizeStatus(status) === 1;
 
+const fileDialogVisible = ref(false);
+const currentRecordId = ref(0);
+
+const openFileDialog = (row) => {
+  currentRecordId.value = row.id;
+  fileDialogVisible.value = true;
+};
+
+const formatOutboundBatches = (value) => {
+  if (value === undefined || value === null || value === "") return "";
+  if (Array.isArray(value)) return value.filter(Boolean).join("銆�");
+  return String(value)
+    .split(/[,锛宂/)
+    .map((s) => s.trim())
+    .filter(Boolean)
+    .join("銆�");
+};
+
 const normalizeTableRow = (row) => ({
   ...row,
   applyCode: row.invoiceApplicationNo ?? row.applyCode,
   amount: row.invoiceAmount ?? row.amount,
   content: row.invoiceContent ?? row.content,
   status: normalizeStatus(row.status ?? row.auditStatus),
-  invoiceTypeLabel: row.invoiceTypeLabel || getInvoiceTypeLabel(row.invoiceType),
+  stockOutRecordIds: row.stockOutRecordIds ?? row.stockOutRecordId ?? "",
+  outboundBatches: formatOutboundBatches(row.outboundBatches),
 });
 
 const appendFilterParams = (params) => {
@@ -553,14 +697,15 @@
 const fillFormFromRow = (row) => {
   const outboundBatchNos = Array.isArray(row.outboundBatchNos)
     ? row.outboundBatchNos
-    : parseStockOutRecordIds(row.stockOutRecordIds ?? row.outboundBatches);
+    : parseStockOutRecordIds(row.stockOutRecordIds ?? row.stockOutRecordId);
   Object.assign(form, {
     ...row,
     applyCode: row.applyCode ?? row.invoiceApplicationNo ?? "",
-    amount: row.amount ?? row.invoiceAmount,
+    amount: Number(row.amount ?? row.invoiceAmount ?? 0),
     content: row.content ?? row.invoiceContent,
     status: normalizeStatus(row.status ?? row.auditStatus),
     outboundBatchNos,
+    outboundBatches: formatOutboundBatches(row.outboundBatches),
   });
 };
 
@@ -572,13 +717,15 @@
     applyCode: "KP" + Date.now().toString().slice(-8),
     customerId: "",
     outboundBatchNos: [],
+    outboundBatches: "",
     amount: 0,
     taxRate: 13,
-    invoiceType: "special",
-    applyDate: new Date().toISOString().split('T')[0],
+    invoiceType: "澧炲�肩◣涓撶敤鍙戠エ",
+    applyDate: new Date().toISOString().split("T")[0],
     content: "",
     remark: "",
   });
+  outboundBatchList.value = [];
   outboundBatchOptions.value = [];
   dialogVisible.value = true;
 };
@@ -628,7 +775,6 @@
   dialogTitle.value = "鏌ョ湅寮�绁ㄧ敵璇�";
   fillFormFromRow(row);
   dialogVisible.value = true;
-  loadOutboundBatches(form.customerId, true);
 };
 
 const submitAudit = (row, status) => {
@@ -747,4 +893,10 @@
   color: #409eff;
   font-weight: bold;
 }
+
+.outbound-batch-input:not(.is-disabled) {
+  :deep(.el-input__wrapper) {
+    cursor: pointer;
+  }
+}
 </style>

--
Gitblit v1.9.3