Browse Source

feat(订单表单): 添加物料明细上传功能并优化导入逻辑

yz 1 month ago
parent
commit
d23205a098

+ 81 - 2
src/components/order-form/material-detail-mixin.js

@@ -22,7 +22,7 @@ import {
   MaterialDetailDataSource
 } from '@/constants/order'
 import { MATERIAL_DETAIL_EVENTS, DIALOG_EVENTS } from './events'
-import { getMaterialFullList, downloadSalesOrderTemplate } from '@/api/order/sales-order'
+import { getMaterialFullList, downloadSalesOrderTemplate, importSalesOrderById } from '@/api/order/sales-order'
 import { getBrandStockList } from '@/api/forecast/brand-stock'
 import {
   formatAmount,
@@ -186,7 +186,13 @@ export default {
        * 模板下载加载状态
        * @type {boolean}
        */
-      templateLoading: false
+      templateLoading: false,
+
+      /**
+       * 模板上传加载状态
+       * @type {boolean}
+       */
+      uploadLoading: false
     }
   },
 
@@ -618,6 +624,79 @@ export default {
     },
 
     /**
+     * 触发上传选择
+     * @returns {void}
+     * @this {MaterialDetailTableComponent & Vue}
+     */
+    handleUploadClick() {
+      if (this.uploadLoading) {
+        return
+      }
+      const input = this.$refs.materialUploadInput
+      if (input && typeof input.click === 'function') {
+        input.click()
+      }
+    },
+
+    /**
+     * 处理上传文件选择
+     * @param {Event} event - 文件选择事件
+     * @returns {void}
+     * @this {MaterialDetailTableComponent & Vue}
+     */
+    handleUploadFileChange(event) {
+      const input = event?.target
+      const file = input?.files?.[0]
+      if (!file) {
+        return
+      }
+      this.uploadSalesOrderFile(file).finally(() => {
+        if (input) {
+          input.value = ''
+        }
+      })
+    },
+
+    /**
+     * 上传销售订单明细 Excel
+     * @param {File} file - Excel 文件
+     * @returns {Promise<void>}
+     * @this {MaterialDetailTableComponent & Vue}
+     */
+    async uploadSalesOrderFile(file) {
+      if (!this.orderId) {
+        this.$message && this.$message.warning('请先保存订单获取订单ID后再上传')
+        return
+      }
+
+      const filename = file?.name || ''
+      if (!/\.(xls|xlsx)$/i.test(filename)) {
+        this.$message && this.$message.error('请上传 .xls 或 .xlsx 格式文件')
+        return
+      }
+
+      try {
+        this.uploadLoading = true
+        const response = await importSalesOrderById(this.orderId, file)
+        const success = response?.data?.success
+        const data = response?.data?.data
+        const message = response?.data?.msg || response?.data?.message
+        if (success && Array.isArray(data)) {
+          this.$emit(MATERIAL_DETAIL_EVENTS.MATERIAL_IMPORT, data)
+          this.$emit(MATERIAL_DETAIL_EVENTS.REFRESH)
+          this.$message && this.$message.success(message || `成功导入 ${data.length} 条物料明细`)
+        } else {
+          this.$message && this.$message.error(message || '上传失败,请检查模板内容')
+        }
+      } catch (error) {
+        console.error('上传模板失败:', error)
+        this.$message && this.$message.error('上传失败,请稍后重试')
+      } finally {
+        this.uploadLoading = false
+      }
+    },
+
+    /**
      * 准备物料明细数据
      * @description 将选中的物料数据转换为物料明细表所需的格式
      * @param {import('./types').MaterialOption} material - 物料数据(来自getMaterialFullList API)

+ 16 - 0
src/components/order-form/material-detail-table.vue

@@ -59,6 +59,22 @@
             下载模板
           </el-button>
           <el-button
+            type="primary"
+            icon="el-icon-upload"
+            size="small"
+            :loading="uploadLoading"
+            @click="handleUploadClick"
+          >
+            上传
+          </el-button>
+          <input
+            ref="materialUploadInput"
+            type="file"
+            accept=".xls,.xlsx"
+            style="display: none;"
+            @change="handleUploadFileChange"
+          />
+          <el-button
             v-if="editMode && selectedRows.length > 0"
             type="danger"
             icon="el-icon-delete"

+ 2 - 2
src/components/order-form/order-form-mixin.js

@@ -1551,8 +1551,8 @@ export default {
           return formatted
         })
 
-        // 添加到物料明细列表
-        this.materialDetails.push(...formattedMaterials)
+        // 替换物料明细列表为导入结果
+        this.materialDetails = formattedMaterials
 
         this.$message.success(`成功导入 ${importedMaterials.length} 条物料明细`)
       } catch (error) {