From 00e6928c50d58ed93fef75454d4f2ef0110d89e9 Mon Sep 17 00:00:00 2001
From: 吴羡 <16976746+Xian-TT3@user.noreply.gitee.com>
Date: 星期五, 30 十月 2026 16:32:17 +0800
Subject: [PATCH] feat(cnas,business): 客户满意度模板化表单与年度汇总导出、费用统计增强、路由加载自愈

---
 src/views/business/costStatistics/index.vue |  156 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 146 insertions(+), 10 deletions(-)

diff --git a/src/views/business/costStatistics/index.vue b/src/views/business/costStatistics/index.vue
index 19a9e4f..fac168e 100644
--- a/src/views/business/costStatistics/index.vue
+++ b/src/views/business/costStatistics/index.vue
@@ -4,6 +4,12 @@
     <div class="search">
       <div>
         <el-form :model="entity" ref="entity" size="small" :inline="true">
+          <el-form-item label="閫佹牱鏃堕棿">
+            <el-date-picker v-model="monthRange" type="monthrange" size="small"
+                            value-format="YYYY-MM" range-separator="鑷�"
+                            start-placeholder="寮�濮嬫湀浠�" end-placeholder="缁撴潫鏈堜唤"
+                            style="width: 240px" @change="refreshTable()"></el-date-picker>
+          </el-form-item>
           <el-form-item label="濮旀墭缂栧彿" prop="entrustCode">
             <el-input size="small" placeholder="璇疯緭鍏�" clearable v-model="entity.entrustCode"
                       @keyup.enter="refreshTable()"></el-input>
@@ -29,8 +35,31 @@
     </div>
     <div>
       <lims-table :tableData="tableData" :column="column"
-                  :height="'calc(100vh - 250px)'" @pagination="pagination"
-                  :page="page" :tableLoading="tableLoading"></lims-table>
+                  :height="'calc(100vh - 300px)'" @pagination="pagination"
+                  :isSelection="true" :handleSelectionChange="handleSelectionChange"
+                  :page="page" :tableLoading="tableLoading">
+        <template #isDiscount="{ row }">
+          <el-select v-model="row.isDiscount" size="small" style="width: 80px"
+                     @change="handleDiscountChange(row)">
+            <el-option label="鏃�" :value="0"></el-option>
+            <el-option label="鏈�" :value="1"></el-option>
+          </el-select>
+        </template>
+        <template #discountAmount="{ row }">
+          <el-input-number v-model="row.discountAmount" size="small" style="width: 100%"
+                           :controls="false" :precision="2" :min="0"
+                           :disabled="row.isDiscount !== 1"
+                           placeholder="璇疯緭鍏�" @change="handleAmountChange(row)"></el-input-number>
+        </template>
+        <template #feeRemark="{ row }">
+          <el-input v-model="row.feeRemark" size="small" maxlength="500"
+                    @change="handleFeeRemarkChange(row)"></el-input>
+        </template>
+      </lims-table>
+    </div>
+    <div class="sum-bar">
+      <span>宸插嬀閫� <b class="sum-count">{{ selectedRows.length }}</b> 鏉�</span>
+      <span>鎬婚噾棰濓細<b class="sum-amount">楼{{ selectedTotal }}</b></span>
     </div>
     <viewInfoDia ref="viewInfoDia" v-if="viewInfoDia"></viewInfoDia>
   </div>
@@ -39,8 +68,9 @@
 <script>
 import limsTable from "@/components/Table/lims-table.vue";
 import viewInfoDia from "./components/viewInfoDia.vue";
-import {selectRatesPage} from "@/api/business/insOrderRates";
+import {selectRatesPage, updateOrderFee} from "@/api/business/insOrderRates";
 import {selectCustomPageList} from "@/api/system/customer";
+import { ElMessage } from "element-plus";
 
 export default {
   components: {limsTable,viewInfoDia},
@@ -50,10 +80,11 @@
         sample: null,
         company: null,
       },
+      monthRange: [],
       tableData: [],
       tableLoading: false,
       column: [
-        { label: '涓嬪崟鏃堕棿', prop: 'createTime', width: 150 },
+        { label: '閫佹牱鏃堕棿', prop: 'sampleDate', width: 120 },
         { label: '濮旀墭缂栧彿', prop: 'entrustCode', width: 160 },
         { label: '鏍峰搧鍚嶇О', prop: 'sample', width: 160 },
         { label: '濮旀墭鍗曚綅', prop: 'company' },
@@ -84,8 +115,28 @@
           },
         },
         { label: '濮旀墭浜�', prop: 'prepareUser' },
-        { label: '鐢熶骇鍗曚綅', prop: 'production' },
-        { label: '鎬讳环', prop: 'totalPrice' },
+        { label: '鎬讳环', prop: 'totalPrice', width: 110 },
+        {
+          label: '鏄惁浼樻儬',
+          prop: 'isDiscount',
+          width: 100,
+          dataType: 'slot',
+          slot: 'isDiscount'
+        },
+        {
+          label: '浼樻儬鍚庨噾棰�',
+          prop: 'discountAmount',
+          width: 130,
+          dataType: 'slot',
+          slot: 'discountAmount'
+        },
+        {
+          label: '澶囨敞',
+          prop: 'feeRemark',
+          minWidth: 160,
+          dataType: 'slot',
+          slot: 'feeRemark'
+        },
         {
           dataType: "action",
           fixed: "right",
@@ -107,7 +158,19 @@
         current: 1
       },
       companyOptions: [],
-      viewInfoDia: false
+      viewInfoDia: false,
+      selectedRows: []
+    }
+  },
+  computed: {
+    // 鍕鹃�夊悎璁★細鏈変紭鎯犱笖濉簡浼樻儬鍚庨噾棰濈殑鎸変紭鎯犲悗閲戦绠楋紝鍚﹀垯鎸夋�讳环绠�
+    selectedTotal() {
+      const total = this.selectedRows.reduce((sum, row) => {
+        const useDiscount = row.isDiscount === 1 && row.discountAmount !== null && row.discountAmount !== undefined
+        const amount = Number(useDiscount ? row.discountAmount : row.totalPrice)
+        return sum + (isFinite(amount) ? amount : 0)
+      }, 0)
+      return total.toFixed(2)
     }
   },
   mounted() {
@@ -117,10 +180,15 @@
   methods :{
     refreshTable() {
       this.tableLoading = true
-      selectRatesPage({ ...this.page, ...this.entity }).then(res => {
+      const [startMonth, endMonth] = this.monthRange || []
+      selectRatesPage({ ...this.page, ...this.entity, startMonth, endMonth }).then(res => {
         this.tableLoading = false
-        this.tableData = res.data.records
+        this.tableData = (res.data.records || []).map(item => {
+          item.isDiscount = item.isDiscount === 1 ? 1 : 0
+          return item
+        })
         this.page.total = res.data.total
+        this.selectedRows = []
       }).catch(err => {
         this.tableLoading = false
       })
@@ -128,6 +196,7 @@
     // 閲嶇疆
     refresh() {
       this.resetForm('entity')
+      this.monthRange = []
       this.refreshTable()
     },
     // 鏌ヨ濮旀墭鍗曚綅涓嬫媺妗嗘暟鎹�
@@ -152,6 +221,53 @@
       this.page.size = page.limit
       this.refreshTable()
     },
+    // 鍕鹃�夎鍙樺寲
+    handleSelectionChange(selection) {
+      this.selectedRows = selection
+    },
+    // 鍒囨崲鏄惁浼樻儬
+    handleDiscountChange(row) {
+      if (row.isDiscount === 1) {
+        // 閫夆�滄湁鈥濇椂甯﹀嚭鎬讳环锛岀敤鎴峰啀鏀规垚瀹為檯浼樻儬鍚庨噾棰�
+        if (row.discountAmount === null || row.discountAmount === undefined || row.discountAmount === '') {
+          row.discountAmount = this.amountOf(row.totalPrice)
+        }
+      } else {
+        row.discountAmount = null
+      }
+      this.saveFee(row)
+    },
+    // 浼樻儬鍚庨噾棰濇敼瀹屼繚瀛�
+    handleAmountChange(row) {
+      if (row.isDiscount !== 1) {
+        row.discountAmount = null
+        return
+      }
+      if (row.discountAmount === null || row.discountAmount === undefined || row.discountAmount === '') {
+        ElMessage.warning('鏈変紭鎯犳椂璇峰~鍐欎紭鎯犲悗閲戦')
+        return
+      }
+      this.saveFee(row)
+    },
+    // 澶囨敞鏀瑰畬淇濆瓨
+    handleFeeRemarkChange(row) {
+      this.saveFee(row)
+    },
+    amountOf(value) {
+      const num = Number(value)
+      if (!isFinite(num)) return 0
+      return Math.round(num * 100) / 100
+    },
+    saveFee(row) {
+      updateOrderFee({
+        id: row.id,
+        isDiscount: row.isDiscount,
+        discountAmount: row.isDiscount === 1 ? row.discountAmount : null,
+        feeRemark: row.feeRemark || null
+      }).catch(() => {
+        this.refreshTable()
+      })
+    },
     // 鏌ョ湅璇︽儏
     openDia (row) {
       this.viewInfoDia = true
@@ -164,8 +280,28 @@
 </script>
 <style scoped>
 .search {
-  height: 46px;
+  min-height: 46px;
   display: flex;
   justify-content: space-between;
 }
+.sum-bar {
+  position: sticky;
+  bottom: 0;
+  z-index: 10;
+  display: flex;
+  justify-content: flex-end;
+  gap: 24px;
+  margin-top: 8px;
+  padding: 10px 16px;
+  background: #fff;
+  border-top: 1px solid var(--el-border-color-light);
+  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.06);
+}
+.sum-count {
+  color: var(--el-color-primary);
+}
+.sum-amount {
+  color: var(--el-color-danger);
+  font-size: 16px;
+}
 </style>

--
Gitblit v1.9.3