Pārlūkot izejas kodu

feat:小程序优化

钱新宇 2 dienas atpakaļ
vecāks
revīzija
03a2f051ec

+ 1 - 1
manifest.json

@@ -1,6 +1,6 @@
 {
     "name" : "观星台小程序",
-    "appid" : "__UNI__3318F0E",
+    "appid" : "__UNI__1F2086E",
     "description" : "",
     "versionName" : "1.0.0",
     "versionCode" : "100",

BIN
traceCodePackages/static/images/report.png


BIN
traceCodePackages/static/images/scan.png


+ 78 - 35
traceCodePackages/traceabilityCodeQuery/pages/index.vue

@@ -1,63 +1,100 @@
 <template>
   <Water></Water>
   <view class="nav" :style="{ paddingTop: statusBarHeight + 'px' }">
-    <text class="nav-back" :style="{ top: statusBarHeight + 'px' }" @click="onBack"></text>
+    <text
+      class="nav-back"
+      :style="{ top: statusBarHeight + 'px' }"
+      @click="onBack"
+    ></text>
     <text class="nav-title">药品追溯码查询</text>
   </view>
-  <scroll-view class="page" :style="{
-    marginTop: statusBarHeight + 44 + 'px',
-    height: pageHeight + 'px',
-  }" @scrolltolower="onHistoryScrollToLower" scroll-y="true">
+  <view
+    class="page"
+    :style="{
+      marginTop: statusBarHeight + 44 + 'px',
+      height: pageHeight + 'px',
+    }"
+  >
     <view class="scan-tip" @click="handleScanTipClick">
       <uni-icons type="help" size="18" color="#2c69ff"></uni-icons>
-      <text :style="{ marginLeft: '5rpx', paddingBottom: '5rpx' }">可扫码生产企业及药品</text>
+      <text :style="{ marginLeft: '5rpx', paddingBottom: '5rpx' }"
+        >可扫码生产企业及药品</text
+      >
     </view>
     <view class="scan-card" @click="handleScan">
       <view class="scan-card-content">
-        <image src="../../static/images/camera.png" mode="scaleToFill" class="scan-icon" />
+        <image
+          src="../../static/images/camera.png"
+          mode="scaleToFill"
+          class="scan-icon"
+        />
         <text class="scan-text">扫码查询</text>
       </view>
     </view>
     <view class="hint">请扫描药品最小销售包装上的追溯码</view>
     <view class="input-wrap">
-      <input class="input" v-model="traceCode" maxlength="23" @input="onTraceInput" placeholder="请输入 20 位药品追溯码" />
+      <input
+        class="input"
+        v-model="traceCode"
+        maxlength="23"
+        @input="onTraceInput"
+        placeholder="请输入 20 位药品追溯码"
+      />
     </view>
-    <view class="count">已输入 {{ traceCode.replace(/\s+/g, "").length }}/20 位</view>
+    <view class="count"
+      >已输入 {{ traceCode.replace(/\s+/g, "").length }}/20 位</view
+    >
     <button class="query-btn" :class="{ disabled: !canQuery }" @click="onQuery">
       查询
     </button>
     <text class="tip">若扫码失败,可手动输入追溯码查询</text>
     <view class="section-title">扫码历史</view>
 
-    <view class="history-list" v-if="history.length != 0 && !loading">
-      <view class="history-item" v-for="item in history" :key="item.code" @click="onTapHistory(item)">
-        <view class="history-left">
-          <view class="history-title">{{ item.physicName }}</view>
-          <view class="history-sub">追溯码:{{ item.tracCode }}</view>
+    <scroll-view
+      class="history-scroll"
+      v-if="history.length != 0 && !loading"
+      scroll-y="true"
+      @scrolltolower="onHistoryScrollToLower"
+    >
+      <view class="history-list">
+        <view
+          class="history-item"
+          v-for="item in history"
+          :key="item.code"
+          @click="onTapHistory(item)"
+        >
+          <view class="history-left">
+            <view class="history-title">{{ item.physicName }}</view>
+            <view class="history-sub">追溯码:{{ item.tracCode }}</view>
+          </view>
+          <text class="arrow">›</text>
         </view>
-        <text class="arrow">›</text>
-      </view>
-      <view class="loading-row" v-if="history.length < totalCount">
-        <view class="loading-wrapper">
-          <image class="loading-icon" :src="loadingImg" />
+        <view class="loading-row" v-if="history.length < totalCount">
+          <view class="loading-wrapper">
+            <image class="loading-icon" :src="loadingImg" />
+          </view>
         </view>
       </view>
-    </view>
-    <view v-else-if="!loading" style="margin-top: 20rpx;">
+    </scroll-view>
+    <view v-else-if="!loading" style="margin-top: 20rpx">
       <Empty text="暂无扫码历史" />
     </view>
     <view class="loading-view" v-else>
-      <image class="loading-icon" src="../../static/images/loading.png" mode="scaleToFill"
-        :style="{ width: '50rpx', height: '50rpx' }" />
+      <image
+        class="loading-icon"
+        src="../../static/images/loading.png"
+        mode="scaleToFill"
+        :style="{ width: '50rpx', height: '50rpx' }"
+      />
     </view>
-  </scroll-view>
+  </view>
 </template>
 
 <script>
 import loadingImg from "../../static/images/loading.png";
 import Empty from "../../wigets/empty.vue";
 import Water from "@/components/water/water.vue";
-import request from '../../request/index.js'
+import request from "../../request/index.js";
 export default {
   components: {
     Empty,
@@ -77,10 +114,10 @@ export default {
     };
   },
   onShow() {
-    this.history = []
-    this.totalCount = 0
-    this.pageNum = 1
-    this.isLoading = false
+    this.history = [];
+    this.totalCount = 0;
+    this.pageNum = 1;
+    this.isLoading = false;
     this.getHistoryData();
   },
   onLoad() {
@@ -103,7 +140,7 @@ export default {
     onBack() {
       try {
         uni.navigateBack();
-      } catch (e) { }
+      } catch (e) {}
     },
     handleScanTipClick() {
       uni.navigateTo({
@@ -120,11 +157,11 @@ export default {
       this.traceCode = this.formatTraceCode(val);
     },
     getHistoryData() {
-      request('/bills/getScanHistory', {
+      request("/bills/getScanHistory", {
         pageNum: this.pageNum,
         pageSize: this.pageSize,
-        path: '/traceabilityCodeQuery/pages/index.vue',
-      }).then(res => {
+        path: "/traceabilityCodeQuery/pages/index.vue",
+      }).then((res) => {
         if (res.code == 200) {
           const { total, list } = res.data || {};
           this.totalCount = total || 0;
@@ -134,7 +171,7 @@ export default {
         }
         this.isLoading = false;
         this.loading = false;
-      })
+      });
     },
     handleScan() {
       uni.scanCode({
@@ -254,7 +291,7 @@ export default {
   padding: 0 55rpx;
   padding-bottom: env(safe-area-inset-bottom);
   background-color: rgb(243, 246, 249);
-  overflow-y: auto;
+  overflow: hidden;
 }
 
 .scan-card {
@@ -356,6 +393,12 @@ export default {
   width: 640rpx;
 }
 
+.history-scroll {
+  flex: 1;
+  height: 0;
+  width: 640rpx;
+}
+
 .history-item {
   background-color: #fff;
   border-radius: 16rpx;

+ 4 - 1
traceCodePackages/traceabilityCodeQuery/pages/scanRange/index.vue

@@ -8,7 +8,10 @@
       <view class="item" v-for="(item, i) in companyList" :key="i" @click="toggle(i)">
         <view class="item-header">
           <text class="item-title">{{ i + 1 }}.&nbsp;{{ item.entName || "" }}</text>
-          <view style="color: #2c69ff">{{ expanded[i] ? "收起" : "展开" }}</view>
+          <uni-icons type="down" size="22" color="#999" :style="{
+            transform: expanded[i] ? 'rotate(180deg)' : 'rotate(0deg)',
+            transition: 'transform 0.3s ease-in-out',
+          }"></uni-icons>
         </view>
         <scroll-view class="item-collapse" scroll-y="true" :style="{
           height: getCollapseHeight(i),

+ 102 - 37
traceCodePackages/traceabilityReport/pages/blacklist/detail/index.vue

@@ -1,45 +1,84 @@
 <template>
-  <!-- <Water></Water> -->
+  <Water></Water>
   <view class="nav" :style="{ paddingTop: statusBarHeight + 'px' }">
-    <text class="nav-back" :style="{ top: statusBarHeight + 'px' }" @click="onBack"></text>
+    <text
+      class="nav-back"
+      :style="{ top: statusBarHeight + 'px' }"
+      @click="onBack"
+    ></text>
     <view class="nav-title">{{ title }}</view>
   </view>
   <view class="page">
-    <view class="list-container" :style="{ paddingTop: statusBarHeight + 60 + 'px' }">
+    <view
+      class="header-card"
+      :style="{ paddingTop: statusBarHeight + 60 + 'px' }"
+    >
+      <view class="meta">
+        <view class="dot"></view>
+        <text class="meta-text">客户名称:{{ title }}</text>
+      </view>
+      <view class="meta">
+        <view class="dot"></view>
+        <text class="meta-text">信用代码:91370104771001730R</text>
+      </view>
+    </view>
+    <view
+      class="list-container"
+      :style="{ paddingTop: statusBarHeight - 30 + 'px' }"
+    >
       <view v-for="(prd, i) in products" :key="'prd-' + i">
-        <view class="section-title">感冒灵</view>
+        <view class="section-title">{{
+          i == 0 ? "感冒灵" : "复方氨酚颗粒"
+        }}</view>
+
         <view class="card product-card">
-          <view class="customer-row" v-for="(c, j) in prd.customers" :key="'cust-' + j">
-            <text class="customer-label">上游客户:</text>
-            <text class="customer-name" @click.stop="toggleCustomer(i, j)">{{
-              c.name
-              }}</text>
-            <text class="expand-tag" @click.stop="toggleCustomer(i, j)">{{
-              c.expanded ? "收起" : "展开"
-              }}</text>
-          </view>
-          <view class="table-card" v-for="(c, j) in prd.customers" :key="'tbl-' + j" v-show="c.expanded">
-            <scroll-view scroll-x="true" class="table-scroll">
-              <view class="blk-table">
-                <view class="blk-header">
-                  <view class="th col-region">货源片区</view>
-                  <view class="th col-qty">数量</view>
-                  <view class="th col-batch">批号</view>
-                  <view class="th col-sample">监管码样本(抽样)</view>
-                  <view class="th col-terminal">终端到达数量</view>
-                </view>
-                <view class="blk-body">
-                  <view class="blk-row" v-for="(row, idx) in c.details" :key="'row-' + idx">
-                    <view class="td col-region">{{ row.region }}</view>
-                    <view class="td col-qty">{{ row.quantity }}</view>
-                    <view class="td col-batch">{{ row.batchNo }}</view>
-                    <view class="td col-sample">{{ row.sample }}</view>
-                    <view class="td col-terminal">{{ row.arrivalQty }}</view>
+          <view v-for="(c, j) in prd.customers" :key="'cust-' + j">
+            <view class="customer-row" @click.stop="toggleCustomer(i, j)">
+              <view>
+                <text class="customer-label">上游客户:</text>
+                <text class="customer-name">{{ c.name }}</text>
+              </view>
+              <uni-icons
+                type="down"
+                size="22"
+                color="#999"
+                :style="{
+                  transform: c.expanded ? 'rotate(180deg)' : 'rotate(0deg)',
+                  transition: 'transform 0.3s ease-in-out',
+                }"
+              ></uni-icons>
+            </view>
+            <view class="table-card" v-show="c.expanded">
+              <scroll-view scroll-x="true" class="table-scroll">
+                <view class="blk-table">
+                  <view class="blk-header">
+                    <view class="th col-region">货源片区</view>
+                    <view class="th col-qty">数量</view>
+                    <view class="th col-batch">批号</view>
+                    <view class="th col-sample">监管码样本(抽样)</view>
+                    <view class="th col-terminal">终端到达数量</view>
+                  </view>
+                  <view class="blk-body">
+                    <view
+                      class="blk-row"
+                      v-for="(row, idx) in c.details"
+                      :key="'row-' + idx"
+                    >
+                      <view class="td col-region">{{ row.region }}</view>
+                      <view class="td col-qty">{{ row.quantity }}</view>
+                      <view class="td col-batch">{{ row.batchNo }}</view>
+                      <view class="td col-sample">{{ row.sample }}</view>
+                      <view class="td col-terminal">{{ row.arrivalQty }}</view>
+                    </view>
+                    <view
+                      v-if="!c.details || c.details.length === 0"
+                      class="empty-row"
+                      >暂无数据</view
+                    >
                   </view>
-                  <view v-if="!c.details || c.details.length === 0" class="empty-row">暂无数据</view>
                 </view>
-              </view>
-            </scroll-view>
+              </scroll-view>
+            </view>
           </view>
         </view>
       </view>
@@ -72,12 +111,11 @@ export default {
     onBack() {
       try {
         uni.navigateBack();
-      } catch (e) { }
+      } catch (e) {}
     },
     toggleCustomer(i, j) {
-      const expanded = this.products[i].customers[j].expanded;
-      this.products[i].customers.forEach((c) => (c.expanded = false));
-      this.$set(this.products[i].customers[j], "expanded", !expanded);
+      const cur = this.products[i].customers[j];
+      this.$set(this.products[i].customers[j], "expanded", !cur.expanded);
     },
     generateMockProducts(drugName) {
       const makeDetails = (n = 3) =>
@@ -110,6 +148,31 @@ export default {
 </script>
 
 <style scoped>
+.header-card {
+  background: #2c69ff;
+  border-bottom-left-radius: 32rpx;
+  border-bottom-right-radius: 32rpx;
+  padding: 36rpx;
+  color: #fff;
+}
+
+.meta {
+  display: flex;
+  align-items: center;
+  margin: 14rpx 0;
+}
+
+.dot {
+  width: 8rpx;
+  height: 8rpx;
+  border-radius: 50%;
+  background: #fff;
+  margin-right: 20rpx;
+}
+
+.meta-text {
+  font-size: 32rpx;
+}
 .nav {
   position: fixed;
   top: 0;
@@ -196,6 +259,8 @@ export default {
   align-items: center;
   padding: 12rpx 0;
   border-bottom: 1rpx solid #f0f0f0;
+  display: flex;
+  justify-content: space-between;
 }
 
 .customer-row:last-child {

+ 2 - 4
traceCodePackages/traceabilityReport/pages/blacklist/index.vue

@@ -26,7 +26,7 @@
         >
           <view class="left-info">
             <view class="row1-name">{{ item.receiverName }}</view>
-            <view class="row4-manager">{{ item.companyCode }}</view>
+            <view class="row4-manager">信用代码:{{ item.companyCode }}</view>
           </view>
         </view>
 
@@ -183,8 +183,6 @@ export default {
 
 .list-container {
   padding-bottom: calc(50rpx + env(safe-area-inset-bottom));
-  padding-left: 24rpx;
-  padding-right: 24rpx;
 }
 
 .card-item {
@@ -206,7 +204,7 @@ export default {
 .row1-name {
   font-size: 30rpx;
   font-weight: bold;
-  color: #333;
+  color: #1890ff;
   margin-bottom: 16rpx;
 }
 

+ 75 - 34
traceCodePackages/traceabilityReport/pages/customerScanningRate/detail/index.vue

@@ -1,16 +1,25 @@
 <template>
   <Water></Water>
   <view class="nav" :style="{ paddingTop: statusBarHeight + 'px' }">
-    <text class="nav-back" :style="{ top: statusBarHeight + 'px' }" @click="onBack"></text>
+    <text
+      class="nav-back"
+      :style="{ top: statusBarHeight + 'px' }"
+      @click="onBack"
+    ></text>
     <view class="nav-title">客户扫码率</view>
   </view>
   <view class="page" @click="closeDropdown">
-    <view class="header-card" :style="{ paddingTop: statusBarHeight + 60 + 'px' }">
+    <view
+      class="header-card"
+      :style="{ paddingTop: statusBarHeight + 60 + 'px' }"
+    >
       <view class="meta">
         <view class="dot"></view>
-        <text class="meta-text">等级:{{
-          scanType == 1 ? "VIP" : scanType == 2 ? "二级" : "三级"
-        }}客户</text>
+        <text class="meta-text"
+          >等级:{{
+            scanType == 1 ? "VIP" : scanType == 2 ? "二级" : "三级"
+          }}客户</text
+        >
       </view>
       <view class="meta">
         <view class="dot"></view>
@@ -18,27 +27,54 @@
       </view>
       <view class="meta">
         <view class="dot"></view>
-        <text class="meta-text">品种:{{ physicName || '全品种' }}</text>
+        <text class="meta-text">品种:{{ physicName || "全品种" }}</text>
       </view>
       <view class="meta">
         <view class="dot"></view>
         <text class="meta-text">时间区间:{{ dateRange }}</text>
       </view>
       <view class="selector-wrap" @click.stop>
-        <input class="selector-input" v-model="customerInput.customerName" placeholder="选择客户" @focus="openDropdown"
-          @input="onInputChange" />
-        <view class="selector-arrow" :class="{ open: dropdownOpen }" @click="toggleDropdown"></view>
+        <input
+          class="selector-input"
+          v-model="customerInput.customerName"
+          placeholder="选择客户"
+          @focus="openDropdown"
+          @input="onInputChange"
+        />
+        <view
+          class="selector-arrow"
+          :class="{ open: dropdownOpen }"
+          @click="toggleDropdown"
+        ></view>
         <view class="dropdown" v-show="dropdownOpen" @click.stop>
-          <scroll-view v-if="customers.length && !customerLoading" scroll-y :style="{ maxHeight: '300rpx' }"
-            lower-threshold="20" @scrolltolower="getCustomerInfo">
-            <view class="dropdown-item" v-for="(c, i) in customers" :key="i" @click="selectCustomer(c)">{{
-              c.customerName || "--" }}</view>
+          <scroll-view
+            v-if="customers.length && !customerLoading"
+            scroll-y
+            :style="{ maxHeight: '300rpx' }"
+            lower-threshold="20"
+            @scrolltolower="getCustomerInfo"
+          >
+            <view
+              class="dropdown-item"
+              v-for="(c, i) in customers"
+              :key="i"
+              @click="selectCustomer(c)"
+              >{{ c.customerName || "--" }}</view
+            >
             <view v-if="customerHasMore" class="customer-loading-wrap">
-              <image src="../../../../static/images/loading.png" mode="scaleToFill" class="loading-icon" />
+              <image
+                src="../../../../static/images/loading.png"
+                mode="scaleToFill"
+                class="loading-icon"
+              />
             </view>
           </scroll-view>
           <view v-else-if="customerLoading" class="customer-loading-wrap">
-            <image src="../../../../static/images/loading.png" mode="scaleToFill" class="loading-icon" />
+            <image
+              src="../../../../static/images/loading.png"
+              mode="scaleToFill"
+              class="loading-icon"
+            />
           </view>
           <view v-else class="dropdown-item">暂无数据</view>
         </view>
@@ -46,8 +82,16 @@
     </view>
 
     <view class="card">
-      <ScanRateTable :api="`/bills/getScanRateDetail`" :columns="columns" :tableBodyHeight="tableBodyHeight"
-        :showHeader="false" bodyFontColor="#000" summaryBold="true" tableType="customerDetail" :params="queryParams" />
+      <ScanRateTable
+        :api="`/bills/getScanRateDetail`"
+        :columns="columns"
+        :tableBodyHeight="tableBodyHeight"
+        :showHeader="false"
+        bodyFontColor="#000"
+        summaryBold="true"
+        tableType="customerDetail"
+        :params="queryParams"
+      />
     </view>
   </view>
 </template>
@@ -55,7 +99,7 @@
 <script>
 import ScanRateTable from "../wigets/ScanRateTable.vue";
 import Water from "@/components/water/water.vue";
-import request from '../../../../request/index.js'
+import request from "../../../../request/index.js";
 export default {
   components: {
     ScanRateTable,
@@ -77,7 +121,7 @@ export default {
       customerHasMore: true,
       customerLoading: false,
       customers: [],
-      customerInput: { customerName: '' },
+      customerInput: { customerName: "" },
       customerDebounceTimer: null,
       selectedCustomer: "",
       dropdownOpen: false,
@@ -97,21 +141,21 @@ export default {
           title: "出库扫码率",
           fixed: false,
           width: "",
-          unit: '%'
+          unit: "%",
         },
         {
           key: "inScanRate",
           title: "入库扫码率",
           fixed: false,
           width: "",
-          unit: '%'
+          unit: "%",
         },
         {
           key: "selfExaminationRate",
           title: "自验证率",
           fixed: false,
           width: "",
-          unit: '%'
+          unit: "%",
         },
       ],
     };
@@ -132,12 +176,9 @@ export default {
     this.getCustomerInfo();
   },
   watch: {
-    'customerInput.customerName': {
+    "customerInput.customerName": {
       handler(newVal, oldVal) {
-        if (
-          !newVal ||
-          newVal !== oldVal
-        ) {
+        if (!newVal || newVal !== oldVal) {
           if (this.customerDebounceTimer)
             clearTimeout(this.customerDebounceTimer);
           this.customerDebounceTimer = setTimeout(() => {
@@ -199,15 +240,15 @@ export default {
     getCustomerInfo() {
       if (!this.customerHasMore || this.customerLoading) return;
       this.customerLoading = true;
-      request('/customer/info/getCustomerInfo', {
+      request("/customer/info/getCustomerInfo", {
         customerName: this.customerInput?.customerName,
         name: this.physicName,
         pageNum: this.customerPage,
         pageSize: this.customerPageSize,
         customerLevel: this.customerLevel,
         provinceCode: this.regionCode,
-        path: '/traceabilityReport/pages/customerScanningRate/detail/index.vue',
-      }).then(res => {
+        path: "/traceabilityReport/pages/customerScanningRate/detail/index.vue",
+      }).then((res) => {
         if (res.code == 200) {
           const _data = res.data || {};
           this.customerTotal = _data.total;
@@ -229,8 +270,8 @@ export default {
         }
         setTimeout(() => {
           this.customerLoading = false;
-        }, 200)
-      })
+        }, 200);
+      });
     },
     openDropdown() {
       this.dropdownOpen = true;
@@ -253,7 +294,7 @@ export default {
     onBack() {
       try {
         uni.navigateBack();
-      } catch (e) { }
+      } catch (e) {}
     },
     onTableScrollToLower() {
       if (this.isLoading) return;
@@ -468,7 +509,7 @@ export default {
   color: #333;
 }
 
-.dropdown-item+.dropdown-item {
+.dropdown-item + .dropdown-item {
   border-top: 1rpx solid #f0f2f5;
 }
 

+ 265 - 116
traceCodePackages/traceabilityReport/pages/customerScanningRate/wigets/ScanRateTable.vue

@@ -1,66 +1,131 @@
 <template>
-  <view class="section" :style="{
-    position: 'relative',
-    zIndex: dropdownOpen || dropdownRegionOpen ? 9 : 'auto',
-  }">
+  <view
+    class="section"
+    :style="{
+      position: 'relative',
+      zIndex: dropdownOpen || dropdownRegionOpen ? 9 : 'auto',
+    }"
+  >
     <view v-if="showHeader" class="section-header">
       <text class="section-title">{{ title }}</text>
       <view :style="{ display: 'flex' }">
-        <view v-if="showSelector && tableType === 'variety'" class="selector-wrap">
+        <view
+          v-if="showSelector && tableType === 'variety'"
+          class="selector-wrap"
+        >
           <view class="selector" @click.stop="toggleDropdownRegion">
             <text class="selector-text">{{
               region?.regionCode ? region.regionName : "选择片区"
             }}</text>
-            <text class="selector-arrow" :class="{ open: dropdownRegionOpen }"></text>
+            <text
+              class="selector-arrow"
+              :class="{ open: dropdownRegionOpen }"
+            ></text>
           </view>
-          <view class="dropdown" v-show="dropdownRegionOpen" :style="dropdownDirection === 'top'
-            ? { top: 'auto', bottom: '48rpx' }
-            : {}
-            " @click.stop>
+          <view
+            class="dropdown"
+            v-show="dropdownRegionOpen"
+            :style="
+              dropdownDirection === 'top'
+                ? { top: 'auto', bottom: '48rpx' }
+                : {}
+            "
+            @click.stop
+          >
             <view class="dropdown-search-bar">
-              <input class="dropdown-search-input" v-model="regionSearchText" @input="onRegionSearch"
-                placeholder="搜索..." />
+              <input
+                class="dropdown-search-input"
+                v-model="regionSearchText"
+                @input="onRegionSearch"
+                placeholder="搜索..."
+              />
             </view>
-            <scroll-view scroll-y="true" class="dropdown-scroll-view" lower-threshold="80"
-              @scrolltolower="loadMoreRegions">
-              <view class="dropdown-item" v-for="(p, i) in regionList" :key="p.regionCode || i" :style="p.regionCode === region?.regionCode || (!region?.regionCode && i == 0)
-                ? {
-                  backgroundColor: '#2c69ff',
-                  color: '#fff',
-                }
-                : {}
-                " @click.stop="selectProduct('region', p)">{{ p.regionName || p }}</view>
-              <view v-if="regionList.length === 0" class="dropdown-item" style="text-align: center; color: #999;">暂无数据
+            <scroll-view
+              scroll-y="true"
+              class="dropdown-scroll-view"
+              lower-threshold="80"
+              @scrolltolower="loadMoreRegions"
+            >
+              <view
+                class="dropdown-item"
+                v-for="(p, i) in regionList"
+                :key="p.regionCode || i"
+                :style="
+                  p.regionCode === region?.regionCode ||
+                  (!region?.regionCode && i == 0)
+                    ? {
+                        backgroundColor: '#2c69ff',
+                        color: '#fff',
+                      }
+                    : {}
+                "
+                @click.stop="selectProduct('region', p)"
+                >{{ p.regionName || p }}</view
+              >
+              <view
+                v-if="regionList.length === 0"
+                class="dropdown-item"
+                style="text-align: center; color: #999"
+                >暂无数据
               </view>
             </scroll-view>
           </view>
         </view>
         <view v-if="showSelector" class="selector-wrap">
           <view class="selector" @click.stop="toggleDropdown">
-            <text class="selector-text">{{ product?.drugEntBaseInfoId ? product.physicName : '选择品种' }}</text>
+            <text class="selector-text">{{
+              product?.drugEntBaseInfoId ? product.physicName : "选择品种"
+            }}</text>
             <text class="selector-arrow" :class="{ open: dropdownOpen }"></text>
           </view>
-          <view class="dropdown" v-show="dropdownOpen" :style="dropdownDirection === 'top'
-            ? {
-              top: 'auto',
-              bottom: '48rpx',
-            }
-            : {}
-            " @click.stop>
-            <view class="dropdown-search-bar">
-              <input class="dropdown-search-input" v-model="productSearchText" @input="onProductSearch"
-                placeholder="搜索..." />
-            </view>
-            <scroll-view scroll-y="true" class="dropdown-scroll-view" lower-threshold="80"
-              @scrolltolower="loadMoreProducts">
-              <view class="dropdown-item" v-for="(p, i) in productList" :key="p.drugEntBaseInfoId || i" :style="p.drugEntBaseInfoId === product?.drugEntBaseInfoId || (!product?.drugEntBaseInfoId && i == 0)
+          <view
+            class="dropdown"
+            v-show="dropdownOpen"
+            :style="
+              dropdownDirection === 'top'
                 ? {
-                  backgroundColor: '#2c69ff',
-                  color: '#fff',
-                }
+                    top: 'auto',
+                    bottom: '48rpx',
+                  }
                 : {}
-                " @click.stop="selectProduct('product', p)">{{ p.physicName }}</view>
-              <view v-if="productList.length === 0" class="dropdown-item" style="text-align: center; color: #999;">暂无数据
+            "
+            @click.stop
+          >
+            <view class="dropdown-search-bar">
+              <input
+                class="dropdown-search-input"
+                v-model="productSearchText"
+                @input="onProductSearch"
+                placeholder="搜索..."
+              />
+            </view>
+            <scroll-view
+              scroll-y="true"
+              class="dropdown-scroll-view"
+              lower-threshold="80"
+              @scrolltolower="loadMoreProducts"
+            >
+              <view
+                class="dropdown-item"
+                v-for="(p, i) in productList"
+                :key="p.drugEntBaseInfoId || i"
+                :style="
+                  p.drugEntBaseInfoId === product?.drugEntBaseInfoId ||
+                  (!product?.drugEntBaseInfoId && i == 0)
+                    ? {
+                        backgroundColor: '#2c69ff',
+                        color: '#fff',
+                      }
+                    : {}
+                "
+                @click.stop="selectProduct('product', p)"
+                >{{ p.physicName }}</view
+              >
+              <view
+                v-if="productList.length === 0"
+                class="dropdown-item"
+                style="text-align: center; color: #999"
+                >暂无数据
               </view>
             </scroll-view>
           </view>
@@ -68,31 +133,64 @@
       </view>
     </view>
 
-    <view class="table-scroll-x" :style="{
-      height: (tableHeightAuto || list.length < 7) ? 'auto' : tableBodyHeight + 80 + 'rpx',
-      maxHeight: tableHeightAuto,
-    }">
-      <scroll-view class="no-scrollbar" :style="{ height: '100%' }" scroll-x="true" scroll-y="true" enhanced
-        :show-scrollbar="false" @scrolltolower="onScrollToLower">
+    <view
+      class="table-scroll-x"
+      :style="{
+        height:
+          tableHeightAuto || list.length < 7
+            ? 'auto'
+            : tableBodyHeight + 80 + 'rpx',
+        maxHeight: tableHeightAuto,
+      }"
+    >
+      <scroll-view
+        class="no-scrollbar"
+        :style="{ height: '100%' }"
+        scroll-x="true"
+        scroll-y="true"
+        enhanced
+        :show-scrollbar="false"
+        @scrolltolower="onScrollToLower"
+      >
         <view class="card" :style="{ width: tableWidth }">
-          <view class="table-header" :style="{
-            position: 'sticky',
-            top: '0',
-            zIndex: 10,
-            fontWeight: headerBold ? 'bold' : 'normal',
-          }">
-            <view v-for="(col, ci) in columnList" :key="getUid()" class="cell" :style="{
-              ...headerCellStyle(ci, col),
-            }">
-              <view v-if="isPlainTitle(col.title)" :style="{
-                display: 'flex',
-                alignItems: 'center',
-                position: 'relative',
-              }">
+          <view
+            class="table-header"
+            :style="{
+              position: 'sticky',
+              top: '0',
+              zIndex: 10,
+              fontWeight: headerBold ? 'bold' : 'normal',
+            }"
+          >
+            <view
+              v-for="(col, ci) in columnList"
+              :key="getUid()"
+              class="cell"
+              :style="{
+                ...headerCellStyle(ci, col),
+              }"
+            >
+              <view
+                v-if="isPlainTitle(col.title)"
+                :style="{
+                  display: 'flex',
+                  alignItems: 'center',
+                  position: 'relative',
+                }"
+              >
                 <text>{{ col.title }}</text>
-                <uni-icons v-if="col.tooltip" type="help" size="16" color="#2c69ff"
-                  @tap.stop.prevent="toggleHeaderTooltip(ci)"></uni-icons>
-                <view v-if="headerTooltip[ci]" class="header-tooltip-wrap" @click.stop>
+                <uni-icons
+                  v-if="col.tooltip"
+                  type="help"
+                  size="16"
+                  color="#2c69ff"
+                  @tap.stop.prevent="toggleHeaderTooltip(ci)"
+                ></uni-icons>
+                <view
+                  v-if="headerTooltip[ci]"
+                  class="header-tooltip-wrap"
+                  @click.stop
+                >
                   <view class="header-tooltip">{{ col.tooltip }}</view>
                   <view class="header-tooltip-arrow"></view>
                 </view>
@@ -103,50 +201,84 @@
           <view v-if="!loading && list && list.length > 0" class="table-body">
             <template>
               <view class="row" v-for="(item, i) in list" :key="getUid()">
-                <view v-for="(col, ci) in columnList" :key="getUid()" class="cell"
-                  :class="{ underline: col.underline, striped: striped && (i + 1) % 2 === 0 }"
-                  :style="bodyCellStyle(ci, col)" @click="handleClick(item, col)">{{ renderCell(item, col) }}</view>
+                <view
+                  v-for="(col, ci) in columnList"
+                  :key="getUid()"
+                  class="cell"
+                  :class="{
+                    underline: col.underline,
+                    striped: striped && (i + 1) % 2 === 0,
+                  }"
+                  :style="bodyCellStyle(ci, col)"
+                  @click="handleClick(item, col)"
+                  >{{ renderCell(item, col) }}</view
+                >
               </view>
               <view class="row loading-row" v-if="hasmore">
                 <view class="loading-wrapper">
                   <image class="loading-icon" :src="loadingImg" />
                 </view>
               </view>
-              <view class="row" v-if="showSummary" :style="{
-                position: 'sticky',
-                bottom: '0',
-                zIndex: 5,
-                backgroundColor: '#fff',
-                borderTop: '1rpx solid #eef0f4',
-                color: summaryFontColor,
-              }">
-                <view v-for="(col, ci) in columnList" :key="getUid()" class="cell" :style="{
-                  ...bodyCellStyle(ci, col),
-                  fontWeight: summaryBold ? 'bold' : 'normal',
-                }">{{ getSummary(col, ci) }}</view>
+              <view
+                class="row"
+                v-if="showSummary"
+                :style="{
+                  position: 'sticky',
+                  bottom: '0',
+                  zIndex: 5,
+                  backgroundColor: '#fff',
+                  borderTop: '1rpx solid #eef0f4',
+                  color: summaryFontColor,
+                }"
+              >
+                <view
+                  v-for="(col, ci) in columnList"
+                  :key="getUid()"
+                  class="cell"
+                  :style="{
+                    ...bodyCellStyle(ci, col),
+                    fontWeight: summaryBold ? 'bold' : 'normal',
+                  }"
+                  >{{ getSummary(col, ci) }}</view
+                >
               </view>
             </template>
           </view>
         </view>
-        <view v-if="loading" class="no-data-placeholder" :style="{ height: 'auto' }">
+        <view
+          v-if="loading"
+          class="no-data-placeholder"
+          :style="{ height: 'auto' }"
+        >
           <view class="row loading-row">
             <view class="loading-wrapper">
               <image class="loading-icon" :src="loadingImg" />
             </view>
           </view>
         </view>
-        <view v-if="!loading && (!list || list.length === 0)" class="no-data-placeholder">
+        <view
+          v-if="!loading && (!list || list.length === 0)"
+          class="no-data-placeholder"
+        >
           <EmptyView />
         </view>
       </scroll-view>
-      <view v-if="loading" class="no-data" :style="{ height: 'auto', top: cellHeight }">
+      <view
+        v-if="loading"
+        class="no-data"
+        :style="{ height: 'auto', top: cellHeight }"
+      >
         <view class="row loading-row">
           <view class="loading-wrapper">
             <image class="loading-icon" :src="loadingImg" />
           </view>
         </view>
       </view>
-      <view v-if="!loading && (!list || list.length === 0)" class="no-data" :style="{ top: cellHeight }">
+      <view
+        v-if="!loading && (!list || list.length === 0)"
+        class="no-data"
+        :style="{ top: cellHeight }"
+      >
         <EmptyView />
       </view>
     </view>
@@ -157,7 +289,7 @@
 import EmptyView from "../../../../wigets/empty.vue";
 import loadingImg from "../../../../static/images/loading.png";
 import { getUid } from "../../../../utils/utils.js";
-import request from '../../../../request/index.js'
+import request from "../../../../request/index.js";
 import Select from "../../../../wigets/select.vue";
 export default {
   name: "ScanRateTable",
@@ -185,17 +317,17 @@ export default {
         {
           key: "totalInRate",
           title: "入库扫码率",
-          unit: '%'
+          unit: "%",
         },
         {
           key: "totalOutRate",
           title: "出库扫码率",
-          unit: '%'
+          unit: "%",
         },
         {
           key: "totalSelfExaminationRate",
           title: "自验证率",
-          unit: '%'
+          unit: "%",
         },
       ],
     },
@@ -253,7 +385,7 @@ export default {
           width: "",
           tooltip:
             "客户出库扫码量(与下游入库单中相同的追溯码)/下游企业入库扫码量",
-          unit: '%'
+          unit: "%",
         },
         {
           key: "inScanRate",
@@ -262,7 +394,7 @@ export default {
           width: "",
           tooltip:
             "客户入库扫码量(与上游出库单中相同的追溯码)/上游企业出库扫码量",
-          unit: '%'
+          unit: "%",
         },
         {
           key: "selfExaminationRate",
@@ -270,7 +402,7 @@ export default {
           fixed: false,
           width: "",
           tooltip: "客户出库扫码量(与入库单中相同的追溯码)/入库扫码量",
-          unit: '%'
+          unit: "%",
         },
       ],
     },
@@ -291,8 +423,8 @@ export default {
       tablePageSize: 10,
       summaryData: [],
       headerTooltip: {},
-      regionSearchText: '',
-      productSearchText: '',
+      regionSearchText: "",
+      productSearchText: "",
       regionList: [],
       productList: [],
     };
@@ -301,34 +433,43 @@ export default {
     filteredRegions() {
       if (!this.regionSearchText) return this.regions;
       const lower = this.regionSearchText.toLowerCase();
-      return this.regions.filter(r => (r.regionName || r.name || r || '').toString().toLowerCase().indexOf(lower) > -1);
+      return this.regions.filter(
+        (r) =>
+          (r.regionName || r.name || r || "")
+            .toString()
+            .toLowerCase()
+            .indexOf(lower) > -1,
+      );
     },
     filteredProducts() {
       if (!this.productSearchText) return this.products;
       const lower = this.productSearchText.toLowerCase();
-      return this.products.filter(p => (p.physicName || '').toLowerCase().indexOf(lower) > -1);
+      return this.products.filter(
+        (p) => (p.physicName || "").toLowerCase().indexOf(lower) > -1,
+      );
     },
     tableBodyHeight() {
       return 6 * 80;
     },
     columnList() {
       if (this.params) {
-        const type = this.params?.type
-        if (type === '1' || type === '2') return this.columns.filter(i => i.key !== 'selfExaminationRate');
+        const type = this.params?.type;
+        if (type === "1" || type === "2")
+          return this.columns.filter((i) => i.key !== "selfExaminationRate");
       }
-      return this.columns
-    }
+      return this.columns;
+    },
   },
   watch: {
     dropdownRegionOpen(val) {
       if (val) {
-        this.regionSearchText = '';
+        this.regionSearchText = "";
         this.initRegionList();
       }
     },
     dropdownOpen(val) {
       if (val) {
-        this.productSearchText = '';
+        this.productSearchText = "";
         this.initProductList();
       }
     },
@@ -343,7 +484,11 @@ export default {
     },
     params: {
       handler(newVal, oldVal) {
-        if (newVal !== oldVal && JSON.stringify(newVal) === JSON.stringify(oldVal)) return;
+        if (
+          newVal !== oldVal &&
+          JSON.stringify(newVal) === JSON.stringify(oldVal)
+        )
+          return;
         this.resetFetch();
       },
       deep: true,
@@ -385,9 +530,10 @@ export default {
   },
   methods: {
     renderCell(item, col) {
-      if (!item[col.key]) return '--';
+      if (!item[col.key]) return "--";
       const reg = /rate/i;
-      if (reg.test(col.key)) return (Math.floor(Number(item[col.key])) + (col.unit || ''));
+      if (reg.test(col.key))
+        return Math.floor(Number(item[col.key])) + (col.unit || "");
       return item[col.key];
     },
     initRegionList() {
@@ -417,7 +563,7 @@ export default {
     getUid,
     getSummary(col, ci) {
       if (ci == 0) return "合计";
-      return Math.floor(Number(this.summaryData[ci])) + (col.unit || '');
+      return Math.floor(Number(this.summaryData[ci])) + (col.unit || "");
     },
     closeAllTooltip() {
       this.headerTooltip = {};
@@ -494,7 +640,7 @@ export default {
     //   return res;
     // },
     onScrollToLower(e) {
-      if (e?.detail?.direction === 'right') return
+      if (e?.detail?.direction === "right") return;
       // if (!Array.isArray(this.list)) this.list = [];
       // if (this.list.length - 1 >= this.totalCount) return;
       // if (this.isLoading) return;
@@ -531,13 +677,15 @@ export default {
         if (this.fetchLoading) return;
         this.fetchLoading = true;
         request(this.api, {
-          drugEntBaseInfoId: this.product ? (this.product?.drugEntBaseInfoId || '') : '',
-          regionCode: this.region ? (this.region?.regionCode || '') : '',
+          drugEntBaseInfoId: this.product
+            ? this.product?.drugEntBaseInfoId || ""
+            : "",
+          regionCode: this.region ? this.region?.regionCode || "" : "",
           pageNum: this.tablePage,
           pageSize: this.tablePageSize,
-          path: 'customerScanningRate/wigets/ScanRateTable.vue',
+          path: "customerScanningRate/wigets/ScanRateTable.vue",
           ...(this.params || {}),
-        }).then(res => {
+        }).then((res) => {
           if (res.code == 200) {
             const _data = res.data || {};
             let pageInfo = _data || {};
@@ -582,7 +730,7 @@ export default {
           }
           this.fetchLoading = false;
           this.loading = false;
-        })
+        });
       }, delay);
     },
     headerCellStyle(ci, col) {
@@ -607,7 +755,7 @@ export default {
     bodyCellStyle(ci, col) {
       const base = this.cellBaseStyle(ci, col);
       // base.lineHeight = this.cellHeight;
-      base.padding = '12rpx'
+      base.padding = "12rpx";
       base.fontSize = this.bodyFontSize;
       if (this.bodyFontColor) {
         base.color = this.bodyFontColor;
@@ -651,7 +799,7 @@ export default {
         .replace(/<\/\s*view\s*>/g, "</div>");
       html = html.replace(
         /:style=\"\{\s*textAlign:\s*'center'\s*\}\"/g,
-        'style="text-align:center;"'
+        'style="text-align:center;"',
       );
       return html;
     },
@@ -669,9 +817,9 @@ export default {
           "&regionName=" +
           encodeURIComponent(data.regionName) +
           "&drugEntBaseInfoId=" +
-          (data.druGentBaseInfoId || '') +
+          (data.druGentBaseInfoId || "") +
           "&physicName=" +
-          encodeURIComponent(data.name || '') +
+          encodeURIComponent(data.name || "") +
           "&scanType=" +
           this.scanType +
           (this.params.type ? "&type=" + this.params.type : ""),
@@ -802,7 +950,7 @@ export default {
   text-wrap: wrap;
 }
 
-.dropdown-item+.dropdown-item {
+.dropdown-item + .dropdown-item {
   border-top: 1rpx solid #f0f2f5;
 }
 
@@ -897,6 +1045,7 @@ export default {
 
 .underline {
   text-decoration: underline;
+  color: #2c69ff;
 }
 
 /* hide scrollbars for H5/App while preserving scroll behavior */

+ 229 - 208
traceCodePackages/traceabilityReport/pages/ganmaoling/detail/index.vue

@@ -1,306 +1,327 @@
 <template>
-	<Water></Water>
-	<view class="nav" :style="{ paddingTop: statusBarHeight + 'px' }">
-		<text class="nav-back" :style="{ top: statusBarHeight + 'px' }" @click="onBack"></text>
-		<view class="nav-title">{{ title }}</view>
-	</view>
-	<view class="page">
-		<view class="header-card" :style="{ paddingTop: statusBarHeight + 60 + 'px' }">
-			<view class="meta">
-				<view class="dot"></view>
-				<text class="meta-text">所在省份:{{ regionName }}</text>
-			</view>
-			<view class="meta">
-				<view class="dot"></view>
-				<text class="meta-text">客户等级:{{
-					scanType == 1 ? "VIP" : scanType == 2 ? "二级" : "三级"
-				}}客户</text>
-			</view>
-			<view class="meta">
-				<view class="dot"></view>
-				<text class="meta-text">客户性质:{{ customerType || '--' }}</text>
-			</view>
-			<view class="meta">
-				<view class="dot"></view>
-				<text class="meta-text">责任经理:{{ managerName || '--' }}</text>
-			</view>
-			<view class="meta">
-				<view class="dot"></view>
-				<text class="meta-text">累计预警次数:{{ warningCount || warningCount == 0 ? warningCount : '--' }}</text>
-			</view>
-		</view>
+  <Water></Water>
+  <view class="nav" :style="{ paddingTop: statusBarHeight + 'px' }">
+    <text
+      class="nav-back"
+      :style="{ top: statusBarHeight + 'px' }"
+      @click="onBack"
+    ></text>
+    <view class="nav-title">{{ title }}</view>
+  </view>
+  <view class="page">
+    <view
+      class="header-card"
+      :style="{ paddingTop: statusBarHeight + 60 + 'px' }"
+    >
+      <view class="meta">
+        <view class="dot"></view>
+        <text class="meta-text">所在省份:{{ regionName }}</text>
+      </view>
+      <view class="meta">
+        <view class="dot"></view>
+        <text class="meta-text"
+          >客户等级:{{
+            scanType == 1 ? "VIP" : scanType == 2 ? "二级" : "三级"
+          }}客户</text
+        >
+      </view>
+      <view class="meta">
+        <view class="dot"></view>
+        <text class="meta-text">客户性质:{{ customerType || "--" }}</text>
+      </view>
+      <view class="meta">
+        <view class="dot"></view>
+        <text class="meta-text">责任经理:{{ managerName || "--" }}</text>
+      </view>
+      <view class="meta">
+        <view class="dot"></view>
+        <text class="meta-text"
+          >累计预警次数:{{
+            warningCount || warningCount == 0 ? warningCount : "--"
+          }}</text
+        >
+      </view>
+    </view>
 
-		<view class="section-title">流转信息</view>
+    <view class="section-title">流转信息</view>
 
-		<view class="card table-card">
-			<scroll-view scroll-x="true" class="table-scroll">
-				<view class="flow-table">
-					<view class="flow-header">
-						<view class="th col-time">单据时间</view>
-						<view class="th col-type">单据类型</view>
-						<view class="th col-product">产品名称</view>
-						<view class="th col-batch">批号</view>
-						<view class="th col-source">货源地</view>
-						<view class="th col-qty">数量</view>
-						<view class="th col-chain">链路</view>
-					</view>
-					<view class="flow-body">
-						<view class="flow-row" v-for="(item, index) in flowList" :key="index">
-							<view class="td col-time">{{ item.billTime }}</view>
-							<view class="td col-type">{{ item.billType }}</view>
-							<view class="td col-product">{{ item.productName }}</view>
-							<view class="td-group">
-								<view class="sub-row" v-for="(sub, sIdx) in item.items" :key="sIdx">
-									<view class="td col-batch">{{ sub.batchNo }}</view>
-									<view class="td col-source">{{ sub.source }}</view>
-									<view class="td col-qty">{{ sub.quantity }}</view>
-								</view>
-							</view>
-							<view class="td col-chain">{{ item.chain }}</view>
-						</view>
-					</view>
-				</view>
-			</scroll-view>
-		</view>
-	</view>
+    <view class="card table-card">
+      <scroll-view scroll-x="true" class="table-scroll">
+        <view class="flow-table">
+          <view class="flow-header">
+            <view class="th col-time">单据时间</view>
+            <view class="th col-type">单据类型</view>
+            <view class="th col-product">产品名称</view>
+            <view class="th col-batch">批号</view>
+            <view class="th col-source">货源地</view>
+            <view class="th col-qty">数量</view>
+            <view class="th col-chain">链路</view>
+          </view>
+          <view class="flow-body">
+            <view
+              class="flow-row"
+              v-for="(item, index) in flowList"
+              :key="index"
+            >
+              <view class="td col-time">{{ item.billTime }}</view>
+              <view class="td col-type">{{ item.billType }}</view>
+              <view class="td col-product">{{ item.productName }}</view>
+              <view class="td-group">
+                <view
+                  class="sub-row"
+                  v-for="(sub, sIdx) in item.items"
+                  :key="sIdx"
+                >
+                  <view class="td col-batch">{{ sub.batchNo }}</view>
+                  <view class="td col-source">{{ sub.source }}</view>
+                  <view class="td col-qty">{{ sub.quantity }}</view>
+                </view>
+              </view>
+              <view class="td col-chain">{{ item.chain }}</view>
+            </view>
+          </view>
+        </view>
+      </scroll-view>
+    </view>
+  </view>
 </template>
 
 <script>
 import Water from "@/components/water/water.vue";
 export default {
-	components: {
-		Water,
-	},
-	data() {
-		return {
-			title: '',
-			managerName: '夜神月',
-			warningCount: 0,
-			scanType: "",
-			statusBarHeight: 20,
-			regionName: "广东",
-			customerType: "协议客户",
-			flowList: [
-				{
-					billTime: '2023-01-01 12:00',
-					billType: '销售出库',
-					productName: '感冒灵颗粒',
-					items: [
-						{ batchNo: 'A20230101', source: '广州工厂', quantity: '1000' },
-						{ batchNo: 'A20230102', source: '深圳工厂', quantity: '500' }
-					],
-					chain: '经销商A -> 药店B'
-				},
-				{
-					billTime: '2023-01-02 14:30',
-					billType: '调拨入库',
-					productName: '三九胃泰',
-					items: [
-						{ batchNo: 'B20230105', source: '北京仓库', quantity: '200' },
-						{ batchNo: 'B20230106', source: '上海仓库', quantity: '300' },
-						{ batchNo: 'B20230107', source: '武汉仓库', quantity: '150' }
-					],
-					chain: '总仓 -> 分仓'
-				}
-			]
-		}
-	},
-	onLoad(options) {
-		const info = uni.getSystemInfoSync();
-		this.statusBarHeight = info.statusBarHeight || 20;
-		this.title =
-			options && options.name ? decodeURIComponent(options.name) : "报表详情";
-	},
-	methods: {
-		onBack() {
-			try {
-				uni.navigateBack();
-			} catch (e) { }
-		},
-	},
-}
+  components: {
+    Water,
+  },
+  data() {
+    return {
+      title: "",
+      managerName: "夜神月",
+      warningCount: 0,
+      scanType: "",
+      statusBarHeight: 20,
+      regionName: "广东",
+      customerType: "协议客户",
+      flowList: [
+        {
+          billTime: "2023-01-01 12:00",
+          billType: "销售出库",
+          productName: "感冒灵颗粒",
+          items: [
+            { batchNo: "A20230101", source: "广州工厂", quantity: "1000" },
+            { batchNo: "A20230102", source: "深圳工厂", quantity: "500" },
+          ],
+          chain: "经销商A -> 药店B",
+        },
+        {
+          billTime: "2023-01-02 14:30",
+          billType: "调拨入库",
+          productName: "三九胃泰",
+          items: [
+            { batchNo: "B20230105", source: "北京仓库", quantity: "200" },
+            { batchNo: "B20230106", source: "上海仓库", quantity: "300" },
+            { batchNo: "B20230107", source: "武汉仓库", quantity: "150" },
+          ],
+          chain: "总仓 -> 分仓",
+        },
+      ],
+    };
+  },
+  onLoad(options) {
+    const info = uni.getSystemInfoSync();
+    this.statusBarHeight = info.statusBarHeight || 20;
+    this.title =
+      options && options.name ? decodeURIComponent(options.name) : "报表详情";
+  },
+  methods: {
+    onBack() {
+      try {
+        uni.navigateBack();
+      } catch (e) {}
+    },
+  },
+};
 </script>
 <style scoped>
 .nav {
-	position: fixed;
-	top: 0;
-	left: 0;
-	right: 0;
-	height: 44px;
-	background-color: #2c69ff;
-	display: flex;
-	align-items: center;
-	justify-content: center;
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 44px;
+  background-color: #2c69ff;
+  display: flex;
+  align-items: center;
+  justify-content: center;
 }
 
 .nav-title {
-	font-size: 36rpx;
-	color: #fff;
-	font-weight: 700;
+  font-size: 36rpx;
+  color: #fff;
+  font-weight: 700;
 }
 
 .nav-back {
-	position: absolute;
-	left: 40rpx;
-	top: 12rpx;
-	width: 20rpx;
-	height: 20rpx;
-	color: #fff;
-	border-left: 3rpx solid #fff;
-	border-bottom: 3rpx solid #fff;
-	transform: rotate(45deg) translateY(56rpx);
-	margin-left: 40rpx;
-	margin-top: -6rpx;
+  position: absolute;
+  left: 40rpx;
+  top: 12rpx;
+  width: 20rpx;
+  height: 20rpx;
+  color: #fff;
+  border-left: 3rpx solid #fff;
+  border-bottom: 3rpx solid #fff;
+  transform: rotate(45deg) translateY(56rpx);
+  margin-left: 40rpx;
+  margin-top: -6rpx;
 }
 
 .page {
-	height: 100vh;
+  height: 100vh;
 }
 
 .card {
-	margin: 24rpx;
-	background: #fff;
-	border-radius: 16rpx;
-	font-size: 32rpx;
+  margin: 24rpx;
+  background: #fff;
+  border-radius: 16rpx;
+  font-size: 32rpx;
 }
 
 .header-card {
-	background: #2c69ff;
-	border-bottom-left-radius: 32rpx;
-	border-bottom-right-radius: 32rpx;
-	padding: 36rpx;
-	color: #fff;
+  background: #2c69ff;
+  border-bottom-left-radius: 32rpx;
+  border-bottom-right-radius: 32rpx;
+  padding: 36rpx;
+  color: #fff;
 }
 
 .meta {
-	display: flex;
-	align-items: center;
-	margin: 14rpx 0;
+  display: flex;
+  align-items: center;
+  margin: 14rpx 0;
 }
 
 .dot {
-	width: 8rpx;
-	height: 8rpx;
-	border-radius: 50%;
-	background: #fff;
-	margin-right: 20rpx;
+  width: 8rpx;
+  height: 8rpx;
+  border-radius: 50%;
+  background: #fff;
+  margin-right: 20rpx;
 }
 
 .meta-text {
-	font-size: 32rpx;
+  font-size: 32rpx;
 }
 
 .section-title {
-	position: relative;
-	font-size: 32rpx;
-	font-weight: bold;
-	color: #333;
-	margin: 30rpx 30rpx 20rpx;
+  position: relative;
+  font-size: 32rpx;
+  font-weight: bold;
+  color: #333;
+  margin: 30rpx 30rpx 20rpx;
 }
 
 .section-title::after {
-	content: "";
-	position: absolute;
-	left: -20rpx;
-	bottom: 8rpx;
-	width: 8rpx;
-	height: 50%;
-	background: #2c69ff;
-	border-radius: 10px;
+  content: "";
+  position: absolute;
+  left: -20rpx;
+  bottom: 8rpx;
+  width: 8rpx;
+  height: 50%;
+  background: #2c69ff;
+  border-radius: 10px;
 }
 
 .table-card {
-	padding: 0;
-	overflow: hidden;
+  padding: 0;
+  overflow: hidden;
 }
 
 .table-scroll {
-	width: 100%;
+  width: 100%;
 }
 
 .flow-table {
-	min-width: 1300rpx;
-	border-top: 1rpx solid #eee;
-	border-left: 1rpx solid #eee;
+  min-width: 1300rpx;
+  border-top: 1rpx solid #eee;
+  border-left: 1rpx solid #eee;
 }
 
 .flow-header {
-	display: flex;
-	background: #f5f7fa;
-	font-size: 26rpx;
-	font-weight: bold;
-	color: #333;
+  display: flex;
+  background: #f5f7fa;
+  font-size: 26rpx;
+  font-weight: bold;
+  color: #333;
 }
 
 .flow-body {
-	font-size: 26rpx;
-	color: #666;
+  font-size: 26rpx;
+  color: #666;
 }
 
 .flow-row {
-	display: flex;
-	border-bottom: 1rpx solid #eee;
+  display: flex;
+  border-bottom: 1rpx solid #eee;
 }
 
 .th,
 .td {
-	padding: 16rpx 10rpx;
-	border-right: 1rpx solid #eee;
-	display: flex;
-	align-items: center;
-	justify-content: center;
-	text-align: center;
-	word-break: break-all;
-	box-sizing: border-box;
-	flex-shrink: 0;
+  padding: 16rpx 10rpx;
+  border-right: 1rpx solid #eee;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  text-align: center;
+  word-break: break-all;
+  box-sizing: border-box;
+  flex-shrink: 0;
 }
 
 .th {
-	border-bottom: 1rpx solid #eee;
+  border-bottom: 1rpx solid #eee;
 }
 
 .col-time {
-	width: 220rpx;
+  width: 220rpx;
 }
 
 .col-type {
-	width: 160rpx;
+  width: 160rpx;
 }
 
 .col-product {
-	width: 200rpx;
+  width: 200rpx;
 }
 
 .col-batch {
-	width: 180rpx;
+  width: 180rpx;
 }
 
 .col-source {
-	width: 180rpx;
+  width: 180rpx;
 }
 
 .col-qty {
-	width: 120rpx;
+  width: 120rpx;
 }
 
 .col-chain {
-	width: 240rpx;
+  width: 240rpx;
 }
 
 .td-group {
-	display: flex;
-	flex-direction: column;
-	width: 480rpx;
-	flex-shrink: 0;
+  display: flex;
+  flex-direction: column;
+  width: 480rpx;
+  flex-shrink: 0;
 }
 
 .sub-row {
-	display: flex;
-	flex: 1;
-	border-bottom: 1rpx solid #eee;
+  display: flex;
+  flex: 1;
+  border-bottom: 1rpx solid #eee;
 }
 
 .sub-row:last-child {
-	border-bottom: none;
+  border-bottom: none;
 }
 </style>

+ 44 - 21
traceCodePackages/traceabilityReport/pages/ganmaoling/index.vue

@@ -1,27 +1,46 @@
 <template>
   <view class="detail-page">
-    <view class="tip">数据更新时间:{{
-      formatDate(
-        new Date().setDate(new Date().getDate() - 1),
-        "YYYY-MM-DD",
-      ) || "--"
-    }}</view>
-
-    <scroll-view class="list-scroll" scroll-y="true" refresher-enabled :refresher-triggered="isRefreshing"
-      @refresherrefresh="onRefresh" @scrolltolower="onLoadMore">
+    <view class="tip"
+      >数据更新时间:{{
+        formatDate(
+          new Date().setDate(new Date().getDate() - 1),
+          "YYYY-MM-DD",
+        ) || "--"
+      }}</view
+    >
+
+    <scroll-view
+      class="list-scroll"
+      scroll-y="true"
+      refresher-enabled
+      :refresher-triggered="isRefreshing"
+      @refresherrefresh="onRefresh"
+      @scrolltolower="onLoadMore"
+    >
       <view class="list-container">
-        <view class="card-item" v-for="(item, index) in rows" :key="index" @click="toDetail(item)">
+        <view
+          class="card-item"
+          v-for="(item, index) in rows"
+          :key="index"
+          @click="toDetail(item)"
+        >
           <view class="left-info">
-            <view class="row1-name">{{ item.receiverName }}
-            </view>
-            <view class="row2-info">
-              <text class="province">{{ item.receiverProvince }}</text>
-              <text class="level-tag" :class="getLevelClass(item.customerLevel)">
+            <view class="row1-name"
+              >{{ item.receiverName }}
+              <text
+                class="level-tag"
+                :class="getLevelClass(item.customerLevel)"
+              >
                 {{ item.customerLevel }}
+              </text></view
+            >
+            <view class="row2-info">
+              <text class="province"
+                >客户省份:{{ item.receiverProvince }}
               </text>
             </view>
-            <view class="row3-nature">{{ item.customerNature }}</view>
-            <view class="row4-manager">{{ item.manager }}</view>
+            <view class="row3-nature">客户性质:{{ item.customerNature }}</view>
+            <view class="row4-manager">责任经理:{{ item.manager }}</view>
           </view>
 
           <view class="right-info">
@@ -30,7 +49,10 @@
         </view>
 
         <view class="loading-more" v-if="loading">
-          <image class="loading-icon" src="../../../static/images/loading.png" />
+          <image
+            class="loading-icon"
+            src="../../../static/images/loading.png"
+          />
         </view>
 
         <view v-if="!loading && rows.length === 0" class="empty-data">
@@ -181,8 +203,6 @@ export default {
 
 .list-container {
   padding-bottom: calc(50rpx + env(safe-area-inset-bottom));
-  padding-left: 24rpx;
-  padding-right: 24rpx;
 }
 
 .card-item {
@@ -205,8 +225,11 @@ export default {
 .row1-name {
   font-size: 30rpx;
   font-weight: bold;
-  color: #333;
+  color: #1890ff;
   margin-bottom: 16rpx;
+  display: flex;
+  align-items: center;
+  gap: 20rpx;
 }
 
 .row2-info {

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 548 - 204
traceCodePackages/traceabilityReport/pages/reportExport/index.vue


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels