Bladeren bron

refactor(订单表单): 重构物料明细表格的编辑逻辑和格式化函数

yz 1 maand geleden
bovenliggende
commit
6c140cf7f8
1 gewijzigde bestanden met toevoegingen van 101 en 98 verwijderingen
  1. 101 98
      src/components/order-form/material-detail-table.vue

+ 101 - 98
src/components/order-form/material-detail-table.vue

@@ -41,18 +41,18 @@
       >
         <!-- 可用数量自定义模板 -->
         <template slot="availableQuantity" slot-scope="scope">
-          <span>{{ formatQuantity(scope.row.availableQuantity) }}</span>
+          <span>{{ formatFloatNumber(scope.row.availableQuantity) }}</span>
         </template>
 
         <!-- 确认数量自定义模板 -->
         <template slot="confirmQuantity" slot-scope="scope">
-          <span>{{ formatQuantity(scope.row.confirmQuantity) }}</span>
+          <span>{{ formatFloatNumber(scope.row.confirmQuantity) }}</span>
         </template>
 
         <!-- 单价自定义模板 -->
         <template slot="unitPrice" slot-scope="scope">
           <el-input
-            v-if="editMode"
+            v-if="editMode && isRowEditable(scope.row)"
             v-model="scope.row.unitPrice"
             size="mini"
             style="width: 100%"
@@ -65,7 +65,7 @@
         <!-- 订单数量自定义模板 -->
         <template slot="orderQuantity" slot-scope="scope">
           <el-input
-            v-if="editMode"
+            v-if="editMode && isRowEditable(scope.row)"
             v-model="scope.row.orderQuantity"
             size="mini"
             style="width: 100%"
@@ -79,7 +79,7 @@
         <!-- 税率自定义模板 -->
         <template slot="taxRate" slot-scope="scope">
           <el-input
-            v-if="editMode"
+            v-if="editMode && isRowEditable(scope.row)"
             v-model="scope.row.taxRate"
             size="mini"
             style="width: 100%"
@@ -87,13 +87,13 @@
             @input="validateFloatInput($event, scope.row, 'taxRate', 0, 100)"
             @blur="validateAndFormatFloatOnBlur(scope.row, 'taxRate', 0, 100); handleTaxRateChange(scope.row, scope.$index)"
           />
-          <span v-else>{{ formatQuantity(scope.row.taxRate) }}%</span>
+          <span v-else>{{ formatTaxRate(scope.row.taxRate, false) }}%</span>
         </template>
 
         <!-- 税额自定义模板 -->
         <template slot="taxAmount" slot-scope="scope">
           <el-input
-            v-if="editMode"
+            v-if="editMode && isRowEditable(scope.row)"
             v-model="scope.row.taxAmount"
             size="mini"
             style="width: 100%"
@@ -107,7 +107,7 @@
         <!-- 总金额自定义模板 -->
         <template slot="totalAmount" slot-scope="scope">
           <el-input
-            v-if="editMode"
+            v-if="editMode && isRowEditable(scope.row)"
             v-model="scope.row.totalAmount"
             size="mini"
             style="width: 100%"
@@ -170,11 +170,7 @@ import {
   getMaterialDetailStatusColor
 } from './constants'
 import MaterialImportDialog from './material-import-dialog.vue'
-import { 
-  formatAmount as legacyFormatAmount, 
-  formatQuantity as legacyFormatQuantity 
-} from './utils'
-import { 
+import {
   formatAmount,
   formatFloatNumber,
   formatIntegerNumber,
@@ -366,19 +362,19 @@ export default {
         if (value === '' || value === '-') {
           return
         }
-        
+
         // 移除所有非数字字符(除了负号)
         let cleanValue = value.replace(/[^-\d]/g, '')
-        
+
         // 确保负号只能在开头
         if (cleanValue.indexOf('-') > 0) {
           cleanValue = cleanValue.replace(/-/g, '')
         }
-        
+
         // 如果有值,转换为整数
         if (cleanValue !== '' && cleanValue !== '-') {
           const numValue = parseInt(cleanValue, 10)
-          
+
           // 检查范围
           if (numValue < min) {
             row[field] = min
@@ -389,7 +385,7 @@ export default {
           }
         }
       },
-      
+
       /**
        * 验证浮点数输入(输入时验证)
        * @param {string} value - 输入值
@@ -404,61 +400,77 @@ export default {
           row[field] = value
           return
         }
-        
+
         // 移除无效字符,只保留数字、小数点和负号
         let cleanValue = value.replace(/[^-\d.]/g, '')
-        
+
         // 确保负号只能在开头
         if (cleanValue.indexOf('-') > 0) {
           cleanValue = cleanValue.replace(/-/g, '')
         }
-        
+
         // 确保只有一个小数点
         const parts = cleanValue.split('.')
         if (parts.length > 2) {
           cleanValue = parts[0] + '.' + parts.slice(1).join('')
         }
-        
+
         // 限制小数位数为2位(但允许继续输入)
         if (parts.length === 2 && parts[1].length > 2) {
           cleanValue = parts[0] + '.' + parts[1].substring(0, 2)
         }
-        
+
         // 更新字段值,但不进行范围检查(留到blur时处理)
         row[field] = cleanValue
       },
 
       /**
-       * 验证并格式化浮点数(失焦时验证)
-       * @param {Object} row - 当前行数据
-       * @param {string} field - 字段名
-       * @param {number} min - 最小值
-       * @param {number} max - 最大值
-       * @param {number} precision - 小数位数,默认2位
-       */
-      validateAndFormatFloatOnBlur(row, field, min = 0, max = 999999.99, precision = 2) {
-        const value = row[field]
-        
-        // 如果是空值或无效输入,设置为最小值
-        if (value === '' || value === '.' || value === '-' || value === '-.' || isNaN(parseFloat(value))) {
-          row[field] = min
-          return
-        }
-        
-        const numValue = parseFloat(value)
-        
-        // 范围检查
-        if (numValue < min) {
-          row[field] = min
-        } else if (numValue > max) {
-          row[field] = max
-        } else {
-          // 格式化为指定小数位数
-          const multiplier = Math.pow(10, precision)
-          const roundedValue = Math.round(numValue * multiplier) / multiplier
-          row[field] = roundedValue
-        }
-      },
+     * 验证并格式化浮点数(失焦时验证)
+     * @param {Object} row - 当前行数据
+     * @param {string} field - 字段名
+     * @param {number} min - 最小值
+     * @param {number} max - 最大值
+     * @param {number} precision - 小数位数,默认2位
+     */
+    validateAndFormatFloatOnBlur(row, field, min = 0, max = 999999.99, precision = 2) {
+      const value = row[field]
+
+      // 如果是空值或无效输入,设置为最小值
+      if (value === '' || value === '.' || value === '-' || value === '-.' || isNaN(parseFloat(value))) {
+        row[field] = min
+        return
+      }
+
+      const numValue = parseFloat(value)
+
+      // 范围检查
+      if (numValue < min) {
+        row[field] = min
+      } else if (numValue > max) {
+        row[field] = max
+      } else {
+        // 格式化为指定小数位数
+        const multiplier = Math.pow(10, precision)
+        const roundedValue = Math.round(numValue * multiplier) / multiplier
+        row[field] = roundedValue
+      }
+    },
+
+    /**
+     * 判断行是否可编辑
+     * @description 根据数据来源判断物料明细行是否允许编辑,远程数据(订单ID获取)不可编辑
+     * @param {MaterialDetailRecord} row - 物料明细行数据
+     * @returns {boolean} 是否可编辑,true表示可编辑,false表示不可编辑
+     */
+    isRowEditable(row) {
+      // 如果没有数据来源信息,默认可编辑
+      if (!row || !row.dataSource) {
+        return true
+      }
+
+      // 只有导入的物料可以编辑,远程数据(订单ID获取)不可编辑
+      return row.dataSource === MaterialDetailDataSource.IMPORTED
+    },
 
     /**
      * 处理导入物料按钮点击事件
@@ -526,44 +538,37 @@ export default {
     },
 
     /**
-     * 格式化金额显示
-     * @description 格式化金额为带货币符号的字符串,保留2位小数
-     * @param {number|string|null|undefined} amount - 金额数值
-     * @returns {string} 格式化后的金额字符串
+     * 格式化浮点数显示
+     * @description 格式化浮点数为4位小数的字符串
+     * @param {number|string|null|undefined} value - 数值
+     * @returns {string} 格式化后的字符串
      */
-    formatAmount(amount) {
-      return formatAmount(amount, true)
+    formatFloatNumber(value) {
+      return formatFloatNumber(value)
     },
-    
-    /**
-     * 格式化数量显示
-     * @description 格式化数量为4位浮点型字符串
-     * @param {number|string|null|undefined} quantity - 数量数值
-     * @param {boolean} [isInteger=false] - 是否为整数类型
-     * @returns {string} 格式化后的数量字符串
-     */
-    formatQuantity(quantity, isInteger = false) {
-      return isInteger ? formatIntegerNumber(quantity) : formatFloatNumber(quantity)
-    },
-    
+
     /**
-     * 格式化单价显示
-     * @description 格式化单价为4位浮点型字符串
-     * @param {number|string|null|undefined} price - 单价数值
-     * @returns {string} 格式化后的单价字符串
+     * 格式化金额显示
+     * @description 格式化金额为带货币符号的字符串
+     * @param {number|string|null|undefined} amount - 金额数值
+     * @param {boolean} withSymbol - 是否显示货币符号
+     * @returns {string} 格式化后的金额字符串
      */
-    formatUnitPrice(price) {
-      return formatUnitPrice(price)
+    formatAmount(amount, withSymbol = true) {
+      return formatAmount(amount, withSymbol)
     },
-    
+
+    formatUnitPrice,
+    formatTaxRate,
+
     /**
-     * 格式化税率显示
-     * @description 格式化税率为百分比字符串
-     * @param {number|string|null|undefined} rate - 税率数值
-     * @returns {string} 格式化后的税率字符串
+     * 格式化整数显示
+     * @description 格式化整数为字符串
+     * @param {number|string|null|undefined} value - 整数数值
+     * @returns {string} 格式化后的整数字符串
      */
-    formatTaxRate(rate) {
-      return formatTaxRate(rate, true)
+    formatIntegerNumber(value) {
+      return formatIntegerNumber(value)
     },
 
     /**
@@ -647,13 +652,13 @@ export default {
       try {
         // 执行自动计算
         const calculatedRow = this.calculateAmounts(row)
-        
+
         // 触发更新事件,传递计算后的数据
         this.$emit('material-update', { row: calculatedRow, index })
-        
+
         // 完成编辑
         done(calculatedRow)
-        
+
         this.$message.success('物料明细更新成功')
       } catch (error) {
         this.$message.error('更新失败:' + error.message)
@@ -753,10 +758,10 @@ export default {
       // 如果编辑的是影响计算的字段,执行自动计算
       if (['orderQuantity', 'unitPrice', 'taxRate'].includes(prop)) {
         const calculatedRow = this.calculateAmounts(row)
-        
+
         // 更新行数据
         Object.assign(row, calculatedRow)
-        
+
         // 触发更新事件
         this.$emit('material-update', { row: calculatedRow, index: this.getCurrentRowIndex(row) })
       }
@@ -770,29 +775,27 @@ export default {
      */
     calculateAmounts(row) {
       const calculatedRow = { ...row }
-      
+
       // 验证并获取数值
       const quantityValidation = validateNumber(calculatedRow.orderQuantity)
       const priceValidation = validateNumber(calculatedRow.unitPrice)
       const rateValidation = validateNumber(calculatedRow.taxRate)
-      
+
       const orderQuantity = quantityValidation.isValid ? Math.round(quantityValidation.value) : 0
       const unitPrice = priceValidation.isValid ? priceValidation.value : 0
       const taxRate = rateValidation.isValid ? rateValidation.value : 0
-      
+
       // 使用精确计算:订单数量 * 单价
       const totalAmount = preciseMultiply(orderQuantity, unitPrice)
       calculatedRow.totalAmount = preciseRound(totalAmount, 2)
-      
+
       // 使用精确计算:总金额 * 税率 / 100
       const taxAmount = preciseMultiply(totalAmount, preciseDivide(taxRate, 100))
       calculatedRow.taxAmount = preciseRound(taxAmount, 2)
-      
+
       return calculatedRow
     },
 
-
-
     /**
      * 计算税额
      * @description 根据总金额和税率计算税额,使用精确计算避免浮点数精度问题
@@ -802,11 +805,11 @@ export default {
     calculateTaxAmount(row) {
       const amountValidation = validateNumber(row.totalAmount)
       const rateValidation = validateNumber(row.taxRate)
-      
+
       if (amountValidation.isValid && rateValidation.isValid) {
         const totalAmount = amountValidation.value
         const taxRate = rateValidation.value
-        
+
         // 使用精确计算:总金额 * 税率 / 100
         const taxAmount = preciseMultiply(totalAmount, preciseDivide(taxRate, 100))
         row.taxAmount = preciseRound(taxAmount, 2)