Pārlūkot izejas kodu

fix: 添加款项子类型选择,优化表单布局和输入逻辑

xieyong 6 dienas atpakaļ
vecāks
revīzija
d48c241196
1 mainītis faili ar 187 papildinājumiem un 97 dzēšanām
  1. 187 97
      src/BIZComponents/paymentCollectionPlan/Index.vue

+ 187 - 97
src/BIZComponents/paymentCollectionPlan/Index.vue

@@ -11,24 +11,28 @@
       <!-- 表头工具栏 -->
       <template v-slot:toolbar>
         <div class="headbox">
-            <div>
-              <el-button
-                size="small"
-                type="primary"
-                icon="el-icon-plus"
-                class="ele-btn-icon"
-                @click="handlAdd"
-                v-if="showAddBtn"
-              >
-                新增
-              </el-button>
-            </div>
-
-            <div class="pricebox">
-                <span class="amount">比例合计:{{ allRatio }}%</span>
-                <span class="amount">计划{{ menu === 'purchase' ? '付款' : '收款' }}金额合计:{{ allPrice }}元</span>
-
-                <!-- <el-form-item
+          <div>
+            <el-button
+              size="small"
+              type="primary"
+              icon="el-icon-plus"
+              class="ele-btn-icon"
+              @click="handlAdd"
+              v-if="showAddBtn"
+            >
+              新增
+            </el-button>
+          </div>
+
+          <div class="pricebox">
+            <span class="amount">比例合计:{{ allRatio }}%</span>
+            <span class="amount"
+              >计划{{ menu === 'purchase' ? '付款' : '收款' }}金额合计:{{
+                allPrice
+              }}元</span
+            >
+
+            <!-- <el-form-item
                     style="width: 300px"
                     label="优惠后总金额:"
                     prop="discountTotalPrice"
@@ -51,13 +55,13 @@
                     <template slot="append">元</template>
                     </el-input>
                 </el-form-item> -->
-            </div>
+          </div>
         </div>
       </template>
 
       <template v-slot:headerIssueNumber="{ column }">
         <span class="is-required">{{ column.label }}</span>
-      </template> 
+      </template>
 
       <template v-slot:headerType="{ column }">
         <span class="is-required">{{ column.label }}</span>
@@ -80,8 +84,7 @@
           <el-input
             v-model="scope.row.moneyName"
             placeholder="请输入"
-            :disabled="type=='view'"
-
+            :disabled="type == 'view'"
           ></el-input>
         </el-form-item>
       </template>
@@ -102,7 +105,7 @@
           <el-input
             v-model="scope.row.ratio"
             placeholder="请输入"
-            :disabled="type=='view'"
+            :disabled="type == 'view'"
             @input="(val) => ratioInput(val, scope.$index)"
           >
             <template slot="append">%</template>
@@ -123,7 +126,7 @@
             v-model="scope.row.type"
             placeholder="请选择"
             style="width: 100%"
-            :disabled="type=='view'"
+            :disabled="type == 'view'"
             @change="(val) => typeChange(val, scope.$index)"
           >
             <el-option
@@ -136,6 +139,29 @@
           </el-select>
         </el-form-item>
       </template>
+      <template v-slot:subType="scope">
+        <el-form-item
+          v-if="scope.row.type == 1"
+          style="margin-bottom: 20px"
+          :prop="'datasource.' + scope.$index + '.subType'"
+        >
+          <el-select
+            v-model="scope.row.subType"
+            placeholder="请选择款项子类型"
+            style="width: 100%"
+            :disabled="type == 'view'"
+            @change="(val) => subTypeChange(val, scope.$index)"
+          >
+            <el-option
+              v-for="item in subTypeOp"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+      </template>
       <template v-slot:headerRatio="{ column }">
         <span class="is-required">{{ column.label }}</span>
       </template>
@@ -154,16 +180,16 @@
             trigger: 'change'
           }"
         >
-            <el-input
-                type="number"
-                :min="0"
-                disabled
-                v-model="scope.row.price"
-                style="width: 100%"
-                placeholder="请输入"
-            >
-                <template slot="append">元</template>
-            </el-input>
+          <el-input
+            type="number"
+            :min="0"
+            disabled
+            v-model="scope.row.price"
+            style="width: 100%"
+            placeholder="请输入"
+          >
+            <template slot="append">元</template>
+          </el-input>
         </el-form-item>
       </template>
       <template v-slot:deadLine="scope">
@@ -198,7 +224,7 @@
             v-model="scope.row.remark"
             type="textarea"
             placeholder="请输入"
-            :disabled="type=='view'"
+            :disabled="type == 'view'"
           ></el-input>
         </el-form-item>
       </template>
@@ -273,7 +299,9 @@
       showAddBtn() {
         // console.log('showAddBtn~~~~', this.type, this.info);
         // console.log('showAddBtn!!!!',!['1', '2'].includes(this.info.settlementMode) || this.type != 'view');
-        return !(['1', '2'].includes(this.info?.settlementMode)) && this.type != 'view' 
+        return (
+          !['1', '2'].includes(this.info?.settlementMode) && this.type != 'view'
+        );
       },
       columns() {
         return [
@@ -300,12 +328,21 @@
             headerSlot: 'headerType',
             align: 'center'
           },
+          {
+            width: 150,
+            prop: 'subType',
+            label: '款项子类型',
+            slot: 'subType',
+            align: 'center',
+            // 没有任何一行的 type 为预付款(value=1)时,整列隐藏
+            show: this.showSubTypeColumn
+          },
           {
             prop: 'moneyName',
             label: '款项名称',
             slot: 'moneyName',
             // headerSlot: 'headerMoneyName',
-            align: 'center',
+            align: 'center'
             // width: 170
           },
           {
@@ -321,7 +358,7 @@
             prop: 'price',
             label: this.menu === 'purchase' ? '计划付款金额' : '计划收款金额',
             slot: 'price',
-            align: 'center',
+            align: 'center'
             // headerSlot: 'headerPrice',
           },
 
@@ -352,12 +389,30 @@
         ];
       },
       allRatio() {
-        return formatPrice(this.form.datasource.reduce((acc, cur) => acc + Number(cur.ratio), 0));
+        return formatPrice(
+          this.form.datasource.reduce((acc, cur) => acc + Number(cur.ratio), 0)
+        );
       },
       allPrice() {
         // 使用分进行计算,避免浮点数精度问题
-        return formatPrice(this.form.datasource.reduce((acc, cur) => acc + Math.round(Number(cur.price) * 100), 0) / 100);
+        return formatPrice(
+          this.form.datasource.reduce(
+            (acc, cur) => acc + Math.round(Number(cur.price) * 100),
+            0
+          ) / 100
+        );
       },
+      // 任何一行款项类型是『预付款』(value=1) 时才显示子类型列
+      showSubTypeColumn() {
+        return this.form.datasource.some((item) => item.type == 1);
+      },
+      subTypeOp() {
+        return [
+          { value: 'PREPAY', label: '预付款' },
+          { value: 'ADVANCE', label: '预收款' },
+          { value: 'DEPOSIT', label: '定金' }
+        ];
+      }
     },
     watch: {
       discountAmount(newval) {
@@ -391,7 +446,11 @@
       typeChange(val, index = null) {
         // console.log(val, index, '55555');
         if (val) {
-          this.$set(this.form.datasource[index], 'typeName', this.paymentTypeOp.find(item => item.value === val).label);
+          this.$set(
+            this.form.datasource[index],
+            'typeName',
+            this.paymentTypeOp.find((item) => item.value === val).label
+          );
         }
       },
       //输入比例更新金额
@@ -453,11 +512,11 @@
         if (this.isLoadingFromApi) {
           return;
         }
-        
+
         // 创建一个新的数组,避免直接修改原数组
         let newData = JSON.parse(JSON.stringify(this.form.datasource));
         console.log('newData after copy:', newData);
-        
+
         // 先根据比例计算所有价格
         for (let i = 0; i < newData.length; i++) {
           const r = newData[i];
@@ -472,29 +531,56 @@
             };
           }
         }
-        
+
         // 验证并调整最后一行价格,确保总和等于优惠后的总金额
         // 使用分进行计算,避免浮点数精度问题
-        const allPriceSum = newData.reduce((acc, cur) => acc + Math.round(Number(cur.price || 0) * 100), 0) / 100;
+        const allPriceSum =
+          newData.reduce(
+            (acc, cur) => acc + Math.round(Number(cur.price || 0) * 100),
+            0
+          ) / 100;
         const discountAmount = Number(this.discountAmount);
         // 直接计算比例总和,避免字符串转换问题
-        const allRatio = newData.reduce((acc, cur) => acc + Number(cur.ratio || 0), 0);
-        
-        console.log('allPriceSum:', allPriceSum, 'discountAmount:', discountAmount, 'allRatio:', allRatio);
-        
+        const allRatio = newData.reduce(
+          (acc, cur) => acc + Number(cur.ratio || 0),
+          0
+        );
+
+        console.log(
+          'allPriceSum:',
+          allPriceSum,
+          'discountAmount:',
+          discountAmount,
+          'allRatio:',
+          allRatio
+        );
+
         // 检查是否所有数据都有price且比例合计为100%
-        const allHavePrice = newData.every(item => item.price != null && item.price !== '');
-        
+        const allHavePrice = newData.every(
+          (item) => item.price != null && item.price !== ''
+        );
+
         console.log('allHavePrice:', allHavePrice);
-        
-        if (allHavePrice && Math.abs(allRatio - 100) < 0.01 && Math.abs(allPriceSum - discountAmount) >= 0.01) {
+
+        if (
+          allHavePrice &&
+          Math.abs(allRatio - 100) < 0.01 &&
+          Math.abs(allPriceSum - discountAmount) >= 0.01
+        ) {
           // 调整最后一行的价格
           if (newData.length > 0) {
             const lastIndex = newData.length - 1;
             // 使用分进行计算,避免浮点数精度问题
-            const otherPriceSum = newData.slice(0, lastIndex).reduce((acc, cur) => acc + Math.round(Number(cur.price || 0) * 100), 0) / 100;
+            const otherPriceSum =
+              newData
+                .slice(0, lastIndex)
+                .reduce(
+                  (acc, cur) => acc + Math.round(Number(cur.price || 0) * 100),
+                  0
+                ) / 100;
             // 计算最后一行应该有的价格
-            const lastPrice = Math.round((discountAmount - otherPriceSum) * 100) / 100;
+            const lastPrice =
+              Math.round((discountAmount - otherPriceSum) * 100) / 100;
             newData[lastIndex] = {
               ...newData[lastIndex],
               price: formatPrice(lastPrice)
@@ -502,9 +588,9 @@
             console.log('adjusted last item price:', lastPrice);
           }
         }
-        
+
         console.log('newData before update:', newData);
-        
+
         // 确保更新this.form.datasource,触发Vue的响应式更新
         this.form.datasource = newData;
         console.log('after update, datasource:', this.form.datasource);
@@ -544,21 +630,22 @@
       },
       defaultList(method, issueNumber, dateRange) {
         // console.log('method, issueNumber', method, issueNumber, dateRange);
-        const tempList = []
-        if(dateRange) {
+        const tempList = [];
+        if (dateRange) {
           this.setDefaultList(dateRange, issueNumber);
-          return
+          return;
         }
-        if(method == 3) {
+        if (method == 3) {
           let params = ['预付款', '交货款'];
-          for(let i = 0; i < issueNumber; i++) {
+          for (let i = 0; i < issueNumber; i++) {
             let item = JSON.parse(JSON.stringify(this.defaultForm));
-              item.moneyName = i < params.length ? params[i] : '';
-              item.type = i < params.length ? this.paymentTypeOp[i].value : '';
-              item.typeName = i < params.length ? this.paymentTypeOp[i].label : '';
-              item.key = i + 1;
-              item.issueNumber = i + 1;
-              tempList.push(item);
+            item.moneyName = i < params.length ? params[i] : '';
+            item.type = i < params.length ? this.paymentTypeOp[i].value : '';
+            item.typeName =
+              i < params.length ? this.paymentTypeOp[i].label : '';
+            item.key = i + 1;
+            item.issueNumber = i + 1;
+            tempList.push(item);
           }
           // params.forEach((item, index) => {
           //     let i = JSON.parse(JSON.stringify(this.defaultForm));
@@ -577,9 +664,9 @@
           //     i.issueNumber = index + 1;
           //     tempList.push(i);
           // });
-          for(let i = 0; i < issueNumber; i++) {
+          for (let i = 0; i < issueNumber; i++) {
             let item = JSON.parse(JSON.stringify(this.defaultForm));
-            if(issueNumber == 1) {
+            if (issueNumber == 1) {
               item.moneyName = '';
               item.type = 2;
               item.typeName = '交货款';
@@ -613,26 +700,27 @@
         const startDate = new Date(date[0]);
         const endDate = new Date(date[1]);
         // 计算毫秒差并转换为天数,使用Math.ceil确保结果为整数
-        const days = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24)) + 1;
+        const days =
+          Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24)) + 1;
         console.log('包含两头的天数:', days);
 
         // 生成包括头尾在内的所有日期
         const allDates = [];
         const current = new Date(startDate);
-        
+
         // 遍历从开始日期到结束日期的所有天数
         while (current <= endDate) {
           // 格式化日期为YYYY-MM-dd
           const year = current.getFullYear();
           const month = current.getMonth() + 1; // 月份从0开始,需要+1
           const day = current.getDate();
-          
+
           const formattedMonth = String(month).padStart(2, '0');
           const formattedDay = String(day).padStart(2, '0');
           const formattedDateStr = `${year}-${formattedMonth}-${formattedDay}`;
-          
+
           allDates.push(formattedDateStr);
-          
+
           // 移动到下一天
           current.setDate(current.getDate() + 1);
         }
@@ -644,27 +732,29 @@
         const parseMonthDate = (dateStr) => {
           return dateStr instanceof Date ? dateStr : new Date(dateStr + '-01');
         };
-        
+
         const start = parseMonthDate(date[0]);
         const end = parseMonthDate(date[1]);
-        
+
         // 先生成所有月份的日期数组
         const allMonthDates = [];
         const currentDate = new Date(start);
-        
+
         // 遍历从开始月份到结束月份的所有月份
         while (currentDate <= end) {
           const year = currentDate.getFullYear();
           const month = currentDate.getMonth() + 1; // 月份从0开始,需要+1
           const receiptDate = day;
-          
+
           // 格式化日期为YYYY-MM-dd
           const formattedMonth = String(month).padStart(2, '0');
           const formattedDate = String(receiptDate).padStart(2, '0');
-          const deadLine = receiptDate ? `${year}-${formattedMonth}-${formattedDate}` : '';
-          
+          const deadLine = receiptDate
+            ? `${year}-${formattedMonth}-${formattedDate}`
+            : '';
+
           allMonthDates.push(deadLine);
-          
+
           // 使用Date对象的setMonth方法正确移动到下一个月(自动处理年份变化)
           currentDate.setMonth(currentDate.getMonth() + 1);
         }
@@ -677,13 +767,13 @@
         // 计算基本比例
         const basicRatio = 100 / tempPeriod;
         let totalRatio = 0;
-        
+
         // 保存原有数据
         const existingData = [...this.form.datasource];
-        
+
         // 生成付款计划列表项
         const tempList = [];
-        
+
         // 根据传入的period参数生成付款计划
         for (let i = 0; i < tempPeriod; i++) {
           let item = JSON.parse(JSON.stringify(this.defaultForm));
@@ -694,7 +784,7 @@
           // } else {
           //   item = JSON.parse(JSON.stringify(this.defaultForm));
           // }
-          
+
           // 获取日期:如果i小于日期数组长度则使用对应日期,否则设为空
           const deadLine = i < dateRange.length ? dateRange[i] : '';
           const ratio = parseFloat(basicRatio.toFixed(2));
@@ -706,7 +796,7 @@
           tempList.push(item);
           // totalRatio += ratio;
         }
-        
+
         // 调整最后一项的比例,确保总和为100
         // if (tempList.length > 0) {
         //   const difference = 100 - totalRatio;
@@ -714,7 +804,7 @@
         //     tempList[tempList.length - 1].ratio = parseFloat((tempList[tempList.length - 1].ratio + difference).toFixed(2));
         //   }
         // }
-        
+
         console.log('付款计划列表:~~', tempList);
         // this.$set(this.form, 'datasource', tempList);
         console.log('付款计划列表:', this.form.datasource);
@@ -752,7 +842,7 @@
           }
           callback(valid);
         });
-      },
+      }
     }
   };
 </script>
@@ -774,12 +864,12 @@
   }
 
   .pricebox {
-      display: flex;
-      justify-content: flex-start;
-      align-items: center;
-      font-weight: bold;
-    }
-    :deep(.el-input-group__append) {
-      padding: 0;
-    }
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+    font-weight: bold;
+  }
+  :deep(.el-input-group__append) {
+    padding: 0;
+  }
 </style>