Forráskód Böngészése

feat:优化更新

钱新宇 1 hónapja
szülő
commit
eea3c5893f

+ 2 - 2
pages.json

@@ -86,7 +86,7 @@
         {
           "path": "traceabilityReport/pages/blacklist/history/index",
           "style": {
-            "navigationBarTitleText": "历史记录"
+            "navigationBarTitleText": "黑名单企业监控历史记录"
           }
         },
         {
@@ -99,7 +99,7 @@
         {
           "path": "traceabilityReport/pages/ganmaoling/history/index",
           "style": {
-            "navigationBarTitleText": "历史记录"
+            "navigationBarTitleText": "感冒灵大批量跨区域历史记录"
           }
         }
       ]

+ 16 - 50
traceCodePackages/traceabilityCodeQuery/pages/index.vue

@@ -1,68 +1,38 @@
 <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>
-  <view
-    class="page"
-    :style="{
-      marginTop: statusBarHeight + 44 + 'px',
-      height: pageHeight + 'px',
-    }"
-  >
+  <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>
 
-    <scroll-view
-      class="history-scroll"
-      v-if="history.length != 0 && !loading"
-      scroll-y="true"
-      @scrolltolower="onHistoryScrollToLower"
-    >
+    <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-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>
@@ -80,12 +50,8 @@
       <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>
   </view>
 </template>
@@ -140,7 +106,7 @@ export default {
     onBack() {
       try {
         uni.navigateBack();
-      } catch (e) {}
+      } catch (e) { }
     },
     handleScanTipClick() {
       uni.navigateTo({
@@ -196,7 +162,7 @@ export default {
             });
           } else {
             uni.showToast({
-              title: "扫码成功,点击查询查看详情",
+              title: "扫码成功",
               icon: "none",
               duration: 2000,
             });

+ 1 - 1
traceCodePackages/traceabilityReport/pages/blacklist/history/index.vue

@@ -78,7 +78,7 @@
           backgroundColor: '#ebf3fb',
           height: '80rpx',
           paddingLeft: '20rpx',
-        }" placeholder="请填写邮箱" @input="emailError = false">
+        }" placeholder="请填写邮箱" @input="emailError = false" disabled>
           <template #suffix>
             <view style="margin-right: 20rpx; color: #666">@999.com.cn</view>
           </template>

+ 1 - 1
traceCodePackages/traceabilityReport/pages/blacklist/index.vue

@@ -96,7 +96,7 @@
           backgroundColor: '#ebf3fb',
           height: '80rpx',
           paddingLeft: '20rpx',
-        }" placeholder="请填写邮箱" @input="emailError = false">
+        }" placeholder="请填写邮箱" @input="emailError = false" disabled>
           <template #suffix>
             <view style="margin-right: 20rpx; color: #666">@999.com.cn</view>
           </template>

+ 38 - 70
traceCodePackages/traceabilityReport/pages/customerScanningRate/detail/index.vue

@@ -1,25 +1,16 @@
 <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>
@@ -34,47 +25,20 @@
         <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>
@@ -82,16 +46,9 @@
     </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"
+        :pageSize="20" :showHeader="false" summaryBold="true" tableType="customerDetail" :params="queryParams"
+        :summaryFontColor="'#2c69ff'" />
     </view>
   </view>
 </template>
@@ -116,7 +73,7 @@ export default {
       regionName: "",
       physicName: "",
       customerPage: 1,
-      customerPageSize: 10,
+      customerPageSize: 20,
       customerTotal: null,
       customerHasMore: true,
       customerLoading: false,
@@ -128,6 +85,7 @@ export default {
       totalCount: 30,
       isLoading: false,
       list: [],
+      windowHeight: 0,
       columns: [
         {
           key: "custemerName",
@@ -137,19 +95,20 @@ export default {
           width: "",
         },
         {
-          key: "outScanRate",
-          title: "库扫码率",
+          key: "inScanRate",
+          title: "库扫码率",
           fixed: false,
           width: "",
           unit: "%",
         },
         {
-          key: "inScanRate",
-          title: "库扫码率",
+          key: "outScanRate",
+          title: "库扫码率",
           fixed: false,
           width: "",
           unit: "%",
         },
+
         {
           key: "selfExaminationRate",
           title: "自验证率",
@@ -163,6 +122,7 @@ export default {
   onLoad(options) {
     const info = uni.getSystemInfoSync();
     this.statusBarHeight = info.statusBarHeight || 20;
+    this.windowHeight = info.windowHeight;
     // this.list = this.genRows(Math.min(10, this.totalCount));
 
     this.rangeType = options.type || 1;
@@ -232,9 +192,17 @@ export default {
       };
     },
     tableBodyHeight() {
-      const rowHeight = 76; // rpx
-      if (this.totalCount >= 9) return `${rowHeight * 8.5}rpx`;
-      return "auto";
+      // const rowHeight = 76; // rpx
+      // if (this.totalCount >= 9) return `${rowHeight * 8.5}rpx`;
+      // return "auto";
+      const info = uni.getSystemInfoSync();
+      const pixelRatio = 750 / info.windowWidth;
+      const windowHeightRpx = this.windowHeight * pixelRatio;
+      // Header card approx height: (statusBar + 60)px + content(approx 356rpx)
+      const topPx = this.statusBarHeight + 60;
+      const topRpx = topPx * pixelRatio + 356 + 24 + 24; // + margins
+      const headerHeight = 80; // Table header
+      return windowHeightRpx - topRpx - headerHeight - 20; // -20 safety
     },
   },
   methods: {
@@ -295,7 +263,7 @@ export default {
     onBack() {
       try {
         uni.navigateBack();
-      } catch (e) {}
+      } catch (e) { }
     },
     onTableScrollToLower() {
       if (this.isLoading) return;
@@ -510,7 +478,7 @@ export default {
   color: #333;
 }
 
-.dropdown-item + .dropdown-item {
+.dropdown-item+.dropdown-item {
   border-top: 1rpx solid #f0f2f5;
 }
 

+ 1 - 1
traceCodePackages/traceabilityReport/pages/customerScanningRate/index.vue

@@ -49,7 +49,7 @@ export default {
   },
   data() {
     return {
-      activeRange: 1,
+      activeRange: 4,
       varietyColumns: [
         {
           key: "physicName",

+ 108 - 222
traceCodePackages/traceabilityReport/pages/customerScanningRate/wigets/ScanRateTable.vue

@@ -1,72 +1,37 @@
 <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>
@@ -78,54 +43,28 @@
             }}</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" 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="搜索..."
-              />
+              <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"
-                >暂无数据
+            <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>
@@ -133,64 +72,34 @@
       </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>
@@ -201,84 +110,51 @@
           <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>
@@ -368,6 +244,14 @@ export default {
       type: Boolean,
       default: false,
     },
+    pageSize: {
+      type: Number,
+      default: 10,
+    },
+    tableBodyHeight: {
+      type: Number,
+      default: 0,
+    },
     columns: {
       type: Array,
       default: () => [
@@ -379,23 +263,24 @@ export default {
           width: "",
         },
         {
-          key: "outScanRate",
-          title: "库扫码率",
+          key: "inScanRate",
+          title: "库扫码率",
           fixed: false,
           width: "",
           tooltip:
-            "客户出库扫码量(与下游入库单中相同的追溯码)/下游企业入库扫码量",
+            "客户入库扫码量(与上游出库单中相同的追溯码)/上游企业出库扫码量",
           unit: "%",
         },
         {
-          key: "inScanRate",
-          title: "库扫码率",
+          key: "outScanRate",
+          title: "库扫码率",
           fixed: false,
           width: "",
           tooltip:
-            "客户入库扫码量(与上游出库单中相同的追溯码)/上游企业出库扫码量",
+            "客户出库扫码量(与下游入库单中相同的追溯码)/下游企业入库扫码量",
           unit: "%",
         },
+
         {
           key: "selfExaminationRate",
           title: "自验证率",
@@ -420,7 +305,7 @@ export default {
       product: null,
       region: null,
       tablePage: 1,
-      tablePageSize: 10,
+      tablePageSize: this.pageSize,
       summaryData: [],
       headerTooltip: {},
       regionSearchText: "",
@@ -448,7 +333,8 @@ export default {
         (p) => (p.physicName || "").toLowerCase().indexOf(lower) > -1,
       );
     },
-    tableBodyHeight() {
+    _tableBodyHeight() {
+      if (this.tableBodyHeight) return this.tableBodyHeight;
       return 6 * 80;
     },
     columnList() {
@@ -952,7 +838,7 @@ export default {
   text-wrap: wrap;
 }
 
-.dropdown-item + .dropdown-item {
+.dropdown-item+.dropdown-item {
   border-top: 1rpx solid #f0f2f5;
 }
 

+ 3 - 3
traceCodePackages/traceabilityReport/pages/ganmaoling/history/index.vue

@@ -47,11 +47,11 @@
                 </view>
                 <view class="info-item">
                   <text class="label">性质</text>
-                  <text class="value">{{ item.responsibleManager }}</text>
+                  <text class="value">{{ item.customerCategory }}</text>
                 </view>
                 <view class="info-item">
                   <text class="label">责任人</text>
-                  <text class="value">{{ item.customerCategory }}</text>
+                  <text class="value">{{ item.responsibleManager }}</text>
                 </view>
               </view>
             </view>
@@ -86,7 +86,7 @@
           backgroundColor: '#ebf3fb',
           height: '80rpx',
           paddingLeft: '20rpx',
-        }" placeholder="请填写邮箱" @input="emailError = false">
+        }" placeholder="请填写邮箱" @input="emailError = false" disabled>
           <template #suffix>
             <view style="margin-right: 20rpx; color: #666">@999.com.cn</view>
           </template>

+ 2 - 2
traceCodePackages/traceabilityReport/pages/ganmaoling/index.vue

@@ -32,7 +32,7 @@
           <view class="selector" @click.stop="toggleProvinceDropdown">
             <text class="selector-text">{{
               selectedProvince || "全部省份"
-              }}</text>
+            }}</text>
             <text class="selector-arrow" :class="{ open: dropdownProvinceOpen }"></text>
           </view>
         </view>
@@ -107,7 +107,7 @@
           backgroundColor: '#ebf3fb',
           height: '80rpx',
           paddingLeft: '20rpx',
-        }" placeholder="请填写邮箱" @input="emailError = false">
+        }" placeholder="请填写邮箱" @input="emailError = false" disabled>
           <template #suffix>
             <view style="margin-right: 20rpx; color: #666">@999.com.cn</view>
           </template>

+ 3 - 3
traceCodePackages/traceabilityReport/pages/index.vue

@@ -4,13 +4,13 @@
     <view class="tabs-container">
       <view class="tabs">
         <view v-if="hasScanFunction" class="tab" :class="{ active: activeTab === 'scan' }" @click="activeTab = 'scan'">
-          扫码率</view>
-        <view v-if="hasReportFunction" class="tab" :class="{ active: activeTab === 'export' }"
-          @click="activeTab = 'export'">报表导出</view>
+          扫码质量</view>
         <view v-if="hasBlacklistFunction" class="tab" :class="{ active: activeTab === 'blacklist' }"
           @click="activeTab = 'blacklist'">黑名单汇总</view>
         <view v-if="hasGanmaolingFunction" class="tab" :class="{ active: activeTab === 'ganmaoling' }"
           @click="activeTab = 'ganmaoling'">感冒灵大批量</view>
+        <view v-if="hasReportFunction" class="tab" :class="{ active: activeTab === 'export' }"
+          @click="activeTab = 'export'">购销分析</view>
       </view>
     </view>
     <view class="content" v-if="activeTab === 'scan' && hasScanFunction">

+ 266 - 207
traceCodePackages/traceabilityReport/pages/reportExport/detail/index.vue

@@ -7,46 +7,60 @@
         {{ t.label }}
       </view>
     </view>
-    <view class="card" :style="{ height: tableBodyHeight + 'rpx' }">
-      <scroll-view class="grid-scroll" scroll-y="true" scroll-x="true" :show-scrollbar="false" :style="{
-        maxHeight: tableBodyHeight + 'rpx',
-        opacity: category == 1 ? 1 : 0,
-      }" enhanced @scrolltolower="onTableScrollToLower">
-        <view :style="{
-          width: '2500rpx',
-        }">
-          <view class="grid-header">
-            <text class="hcell hcell-sticky-left">查询企业名称</text>
-            <text class="hcell">出库方企业名称</text>
-            <text class="hcell">产品名称</text>
-            <text class="hcell">规格</text>
-            <text class="hcell">批号</text>
-            <text class="hcell">货源地区</text>
-            <text class="hcell">货源数量</text>
-            <text class="hcell">终端到达数量</text>
-            <text class="hcell">出库时间</text>
-            <text class="hcell">追溯码抽样</text>
-            <!-- <text class="hcell">链路</text> -->
-          </view>
-          <view v-if="!loading && rows.length > 0" class="grid-body">
-            <view v-for="(row, idx) in rows" :key="idx + '-' + (row.produceBatchNo || '')" class="grow">
-              <view v-if="row.flags.enterpriseName" class="gcell gcol-1 gspan" :class="['sticky-left']"
-                :style="{ gridRowEnd: 'span ' + row.spans.enterpriseName }">{{ row.enterpriseName }}</view>
-              <view v-if="row.flags.fromEntName" class="gcell gcol-2 gspan"
-                :style="{ gridRowEnd: 'span ' + row.spans.fromEntName }">{{ row.fromEntName }}</view>
-              <view v-if="row.flags.physicName" class="gcell gcol-3 gspan"
-                :style="{ gridRowEnd: 'span ' + row.spans.physicName }">{{ row.physicName }}</view>
-              <view v-if="row.flags.spec" class="gcell gcol-4 gspan" :style="{ gridRowEnd: 'span ' + row.spans.spec }">
-                {{ row.spec }}</view>
-              <view class="gcell gcol-5">{{ row.produceBatchNo }}</view>
-              <view class="gcell gcol-6">{{ row.fromRegionName }}</view>
-              <view class="gcell gcol-7">{{ row.fromQuantity }}</view>
-              <view class="gcell gcol-8">{{ row.toQuantity }}</view>
-              <view class="gcell gcol-9">{{ row.billTime }}</view>
-              <view class="gcell gcol-10">{{ row.tracCode }}</view>
-              <!-- <view class="gcell gcol-11">{{ row.batchTraceLink }}</view> -->
+    <view class="grid-scroll">
+      <scroll-view v-show="category == 1" scroll-y class="grid-scroll-view" @scrolltolower="onTableScrollToLower">
+        <view>
+          <view v-if="!loading && rows.length > 0" class="card-list">
+            <view class="company-card" v-for="(company, cIdx) in rows" :key="cIdx">
+              <view class="company-header" @click="toggleExpand(company)">
+                <view class="company-title">
+                  <text class="company-name">{{ company.name }}</text>
+                  <view class="company-products" v-if="company.products && company.products.length">
+                    <text class="company-product-item" v-for="(prod, pIdx) in company.products" :key="pIdx">
+                      {{ prod.name }} {{ prod.spec }}
+                    </text>
+                  </view>
+                  <!-- <text class="company-total">总数量:{{ company.totalQty }}</text> -->
+                </view>
+                <uni-icons :type="company.expanded ? 'up' : 'down'" size="20" color="#999"></uni-icons>
+              </view>
+              <view v-if="company.expanded" class="company-body">
+                <view class="exporter-section" v-for="(exp, eIdx) in company.exporters" :key="eIdx">
+                  <view class="exporter-title" @click="toggleSubExpand(exp)">
+                    <text>{{ category == 1 ? '出库方' : '入库方' }}:{{ exp.name }}</text>
+                    <uni-icons :type="exp.expanded ? 'up' : 'down'" size="16" color="#666"></uni-icons>
+                  </view>
+                  <view v-if="exp.expanded" class="product-group" v-for="(pg, pIdx) in exp.products" :key="pIdx">
+                    <!-- Product Header Removed as requested, info is now in company header -->
+                    <!-- <view class="product-header">
+                      <text class="product-name">{{ pg.name }}</text>
+                      <text class="product-spec">{{ pg.spec }}</text>
+                    </view> -->
+                    <scroll-view scroll-x class="batch-scroll">
+                      <view class="batch-table">
+                        <view class="batch-header-row">
+                          <text class="th-cell col-batch">批号</text>
+                          <text class="th-cell col-region">货源地区</text>
+                          <text class="th-cell col-qty">货源数量</text>
+                          <text class="th-cell col-qty">终端到达数量</text>
+                          <text class="th-cell col-time">出库时间</text>
+                          <text class="th-cell col-code">追溯码抽样</text>
+                        </view>
+                        <view class="batch-row" v-for="(batch, bIdx) in pg.batches" :key="bIdx">
+                          <text class="td-cell col-batch">{{ batch.produceBatchNo }}</text>
+                          <text class="td-cell col-region">{{ batch.regionName }}</text>
+                          <text class="td-cell col-qty">{{ batch.fromQty }}</text>
+                          <text class="td-cell col-qty">{{ batch.toQty }}</text>
+                          <text class="td-cell col-time">{{ batch.billTime }}</text>
+                          <text class="td-cell col-code">{{ batch.tracCode }}</text>
+                        </view>
+                      </view>
+                    </scroll-view>
+                  </view>
+                </view>
+              </view>
             </view>
-            <view class="gcell gcell-full loading-row" v-if="hasMore">
+            <view class="loading-row" v-if="hasMore">
               <view class="loading-wrapper">
                 <image class="loading-icon" src="../../../../static/images/loading.png" />
               </view>
@@ -54,50 +68,59 @@
           </view>
         </view>
       </scroll-view>
-      <scroll-view class="grid-scroll" scroll-y="true" scroll-x="true" :show-scrollbar="false" :style="{
-        maxHeight: tableBodyHeight + 'rpx',
-        opacity: category == 2 ? 1 : 0,
-        position: 'absolute',
-        top: '0',
-        left: '0',
-        zIndex: category == 2 ? '92' : '-1',
-      }" enhanced @scrolltolower="onTableScrollToLower">
-        <view :style="{
-          width: '2500rpx',
-        }">
-          <view class="grid-header">
-            <text class="hcell hcell-sticky-left">查询企业名称</text>
-            <text class="hcell">入库方企业名称</text>
-            <text class="hcell">产品名称</text>
-            <text class="hcell">规格</text>
-            <text class="hcell">批号</text>
-            <text class="hcell">货源地区</text>
-            <text class="hcell">货源数量</text>
-            <text class="hcell">终端到达数量</text>
-            <text class="hcell">入库时间</text>
-            <text class="hcell">追溯码抽样</text>
-            <!-- <text class="hcell">链路</text> -->
-          </view>
-
-          <view v-if="!_loading && _rows.length > 0" class="grid-body">
-            <view v-for="(row, idx) in _rows" :key="idx + '-' + (row.produceBatchNo || '')" class="grow">
-              <view v-if="row.flags.enterpriseName" class="gcell gcol-1 gspan" :class="['sticky-left']"
-                :style="{ gridRowEnd: 'span ' + row.spans.enterpriseName }">{{ row.enterpriseName }}</view>
-              <view v-if="row.flags.fromEntName" class="gcell gcol-2 gspan"
-                :style="{ gridRowEnd: 'span ' + row.spans.fromEntName }">{{ row.fromEntName }}</view>
-              <view v-if="row.flags.physicName" class="gcell gcol-3 gspan"
-                :style="{ gridRowEnd: 'span ' + row.spans.physicName }">{{ row.physicName }}</view>
-              <view v-if="row.flags.spec" class="gcell gcol-4 gspan" :style="{ gridRowEnd: 'span ' + row.spans.spec }">
-                {{ row.spec }}</view>
-              <view class="gcell gcol-5">{{ row.produceBatchNo }}</view>
-              <view class="gcell gcol-6">{{ row.fromRegionName }}</view>
-              <view class="gcell gcol-7">{{ row.fromQuantity }}</view>
-              <view class="gcell gcol-8">{{ row.toQuantity }}</view>
-              <view class="gcell gcol-9">{{ row.billTime }}</view>
-              <view class="gcell gcol-10">{{ row.tracCode }}</view>
-              <!-- <view class="gcell gcol-11">{{ row.batchTraceLink }}</view> -->
+      <scroll-view v-show="category == 2" class="grid-scroll" scroll-y="true" scroll-x="true" :show-scrollbar="false"
+        enhanced @scrolltolower="onTableScrollToLower">
+        <view>
+          <view v-if="!_loading && _rows.length > 0" class="card-list">
+            <view class="company-card" v-for="(company, cIdx) in _rows" :key="cIdx">
+              <view class="company-header" @click="toggleExpand(company)">
+                <view class="company-title">
+                  <text class="company-name">{{ company.name }}</text>
+                  <view class="company-products" v-if="company.products && company.products.length">
+                    <text class="company-product-item" v-for="(prod, pIdx) in company.products" :key="pIdx">
+                      {{ prod.name }} {{ prod.spec }}
+                    </text>
+                  </view>
+                  <!-- <text class="company-total">总数量:{{ company.totalQty }}</text> -->
+                </view>
+                <uni-icons :type="company.expanded ? 'up' : 'down'" size="20" color="#999"></uni-icons>
+              </view>
+              <view v-if="company.expanded" class="company-body">
+                <view class="exporter-section" v-for="(exp, eIdx) in company.exporters" :key="eIdx">
+                  <view class="exporter-title" @click="toggleSubExpand(exp)">
+                    <text>{{ category == 1 ? '出库方' : '入库方' }}:{{ exp.name }}</text>
+                    <uni-icons :type="exp.expanded ? 'up' : 'down'" size="16" color="#666"></uni-icons>
+                  </view>
+                  <view v-if="exp.expanded" class="product-group" v-for="(pg, pIdx) in exp.products" :key="pIdx">
+                    <!-- <view class="product-header">
+                      <text class="product-name">{{ pg.name }}</text>
+                      <text class="product-spec">{{ pg.spec }}</text>
+                    </view> -->
+                    <scroll-view scroll-x class="batch-scroll">
+                      <view class="batch-table">
+                        <view class="batch-header-row">
+                          <text class="th-cell col-batch">批号</text>
+                          <text class="th-cell col-region">货源地区</text>
+                          <text class="th-cell col-qty">货源数量</text>
+                          <text class="th-cell col-qty">终端到达数量</text>
+                          <text class="th-cell col-time">入库时间</text>
+                          <text class="th-cell col-code">追溯码抽样</text>
+                        </view>
+                        <view class="batch-row" v-for="(batch, bIdx) in pg.batches" :key="bIdx">
+                          <text class="td-cell col-batch">{{ batch.produceBatchNo }}</text>
+                          <text class="td-cell col-region">{{ batch.regionName }}</text>
+                          <text class="td-cell col-qty">{{ batch.fromQty }}</text>
+                          <text class="td-cell col-qty">{{ batch.toQty }}</text>
+                          <text class="td-cell col-time">{{ batch.billTime }}</text>
+                          <text class="td-cell col-code">{{ batch.tracCode }}</text>
+                        </view>
+                      </view>
+                    </scroll-view>
+                  </view>
+                </view>
+              </view>
             </view>
-            <view class="gcell gcell-full loading-row" v-if="_hasMore">
+            <view class="loading-row" v-if="_hasMore">
               <view class="loading-wrapper">
                 <image class="loading-icon" src="../../../../static/images/loading.png" />
               </view>
@@ -327,63 +350,68 @@ export default {
       node.leafCount = sum;
       return sum;
     },
-    buildRows(data) {
+    processData(list) {
       const res = [];
-      (data || []).forEach((companyNode) => {
-        const cLeaves = this.computeLeafCount(companyNode);
-        let companyStarted = false;
-        (companyNode.enterpriseList || []).forEach((expNode) => {
-          const eLeaves = this.computeLeafCount(expNode);
-          let exporterStarted = false;
-          const groups = {};
-          const specGroups = {};
-          (expNode.enterpriseList || []).forEach((item) => {
-            const key = item.physicName || "";
-            if (!groups[key]) groups[key] = [];
-            groups[key].push(item);
-            if (!specGroups[key]) specGroups[key] = [];
-            specGroups[key].push(item.pkgSpec || "");
-          });
-          Object.keys(groups).forEach((prodName) => {
-            const group = groups[prodName];
-            let productStarted = false;
-            group.forEach((batch) => {
-              const { minBillTime, maxBillTime } = batch;
-              const billTime = `${formatDate(minBillTime, "YYYY-MM-DD")}——${formatDate(maxBillTime, "YYYY-MM-DD")}`;
-              res.push({
-                enterpriseName: companyNode.enterpriseName,
-                fromEntName: expNode.fromEntName,
-                physicName: prodName,
-                spec: batch.pkgSpec || "",
-                produceBatchNo: batch.produceBatchNo,
-                fromRegionName: batch.regionName,
-                fromQuantity: batch.fromQty,
-                toQuantity: batch.toQty,
-                billTime,
-                tracCode: batch.tracCode,
-                batchTraceLink: batch.batchTraceLink,
-                spans: {
-                  enterpriseName: companyStarted ? 0 : cLeaves,
-                  fromEntName: exporterStarted ? 0 : eLeaves,
-                  physicName: productStarted ? 0 : group.length,
-                  spec: productStarted ? 0 : group.length,
-                },
-                flags: {
-                  enterpriseName: !companyStarted,
-                  fromEntName: !exporterStarted,
-                  physicName: !productStarted,
-                  spec: !productStarted,
-                },
-              });
-              companyStarted = true;
-              exporterStarted = true;
-              productStarted = true;
+      if (!list || !list.length) return res;
+      list.forEach((company) => {
+        const companyNode = {
+          name: company.enterpriseName,
+          totalQty: 0,
+          expanded: false, // Default collapsed
+          exporters: [],
+          products: [], // Collect unique products here
+        };
+        const uniqueProducts = {};
+
+        (company.enterpriseList || []).forEach((exp) => {
+          const expNode = {
+            name: exp.fromEntName,
+            expanded: false, // Default collapsed
+            products: [],
+          };
+          const productGroups = {};
+          (exp.enterpriseList || []).forEach((item) => {
+            const key = (item.physicName || "") + "|" + (item.pkgSpec || "");
+            // Collect global unique products for the company header
+            if (!uniqueProducts[key]) {
+              uniqueProducts[key] = {
+                name: item.physicName,
+                spec: item.pkgSpec || "",
+              };
+            }
+
+            if (!productGroups[key]) {
+              productGroups[key] = {
+                name: item.physicName,
+                spec: item.pkgSpec || "",
+                batches: [],
+              };
+            }
+            const { minBillTime, maxBillTime } = item;
+            const billTime = `${formatDate(minBillTime, "YYYY-MM-DD")}——${formatDate(maxBillTime, "YYYY-MM-DD")}`;
+            const qty = Number(item.toQty) || 0;
+            companyNode.totalQty += qty;
+            productGroups[key].batches.push({
+              ...item,
+              billTime,
             });
           });
+          Object.values(productGroups).forEach((pg) => {
+            expNode.products.push(pg);
+          });
+          companyNode.exporters.push(expNode);
         });
+        companyNode.products = Object.values(uniqueProducts);
+        res.push(companyNode);
       });
       return res;
     },
+    toggleExpand(item) {
+      this.$set(item, "expanded", !item.expanded);
+    },
+    toggleSubExpand(item) {
+      this.$set(item, "expanded", !item.expanded);
+    },
     onTableScrollToLower(e) {
       if (e?.detail?.direction === "right") return;
       // if (this.isLoading) return;
@@ -433,7 +461,7 @@ export default {
             this[obj.totalCount] = total || 0;
             let _list = [];
             if (Array.isArray(list)) {
-              _list = this.buildRows(list);
+              _list = this.processData(list);
             }
             this[obj.rows] = [...this[obj.rows], ..._list];
             if (this[obj.rows].length < this[obj.totalCount]) {
@@ -509,135 +537,166 @@ export default {
   overflow: hidden;
 }
 
-.grid-header {
-  position: sticky;
-  top: 0;
-  z-index: 10;
-  display: grid;
-  grid-template-columns: 340rpx 300rpx 220rpx 220rpx 220rpx 220rpx 220rpx 220rpx 340rpx 200rpx;
+/* New Card Styles */
+.card-list {
+  padding: 24rpx;
+  background: #f5f7fa;
+  min-height: 100vh;
 }
 
-.grid-header .hcell {
-  background: #eaf2ff;
-  font-weight: bold;
-  color: #2c69ff;
+.company-card {
+  background: #fff;
+  border-radius: 16rpx;
+  margin-bottom: 24rpx;
+  overflow: hidden;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
 }
 
-.hcell {
-  height: 76rpx;
+.company-header {
+  padding: 24rpx 30rpx;
+  background: #fff;
   display: flex;
+  justify-content: space-between;
   align-items: center;
-  justify-content: center;
+  border-bottom: 1rpx solid #f0f0f0;
 }
 
-.hcell:last-child {
-  border-right: none;
+.company-title {
+  display: flex;
+  flex-direction: column;
 }
 
-.hcell-sticky-left {
-  position: sticky;
-  left: 0;
-  z-index: 11;
+.company-name {
+  font-size: 32rpx;
+  font-weight: bold;
+  color: #333;
+  margin-bottom: 8rpx;
 }
 
-.grid-scroll {
-  border-radius: 16rpx;
-  margin-top: 8rpx;
-  overflow: hidden;
+.company-products {
+  margin-bottom: 8rpx;
+}
+
+.company-product-item {
+  font-size: 26rpx;
+  color: #666;
+  margin-right: 16rpx;
+  display: inline-block;
+}
+
+.company-total {
+  font-size: 24rpx;
+  color: #999;
 }
 
-.grid-body {
+.company-body {
   background: #fff;
-  display: grid;
-  grid-template-columns: 340rpx 300rpx 220rpx 220rpx 220rpx 220rpx 220rpx 220rpx 340rpx 200rpx;
-  grid-auto-rows: auto;
+  padding: 0 24rpx 24rpx;
 }
 
-.grow {
-  display: contents;
+.exporter-section {
+  margin-top: 24rpx;
+  border: 1rpx solid #eef0f4;
+  border-radius: 12rpx;
+  overflow: hidden;
 }
 
-.gcell {
+.exporter-title {
+  background: #f8f9fb;
+  padding: 16rpx 24rpx;
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #333;
   display: flex;
+  justify-content: space-between;
   align-items: center;
-  justify-content: center;
   border-bottom: 1rpx solid #eef0f4;
-  border-right: 1rpx solid #eef0f4;
-  background: #fff;
-  color: #333;
-  padding: 0 20rpx;
-  text-align: center;
-  line-height: 50rpx;
-  word-break: break-all;
 }
 
-.gcell:last-child {
-  border-right: none;
+.product-group {
+  padding: 0;
 }
 
-.gcell.gcell-full {
-  grid-column: 1 / -1;
-  background: transparent;
-  border: none;
+.product-header {
+  padding: 16rpx 24rpx;
+  display: flex;
+  justify-content: space-between;
+  font-size: 26rpx;
+  color: #666;
+  border-bottom: 1rpx solid #f0f0f0;
 }
 
-.gspan {
-  background: #fff;
+.batch-scroll {
+  width: 100%;
 }
 
-.gcol-1 {
-  grid-column: 1;
+.batch-table {
+  min-width: 1300rpx;
 }
 
-.gcol-2 {
-  grid-column: 2;
+.batch-header-row {
+  display: flex;
+  background: #f7f9fc;
+  color: #2c69ff;
 }
 
-.gcol-3 {
-  grid-column: 3;
+.batch-row {
+  display: flex;
+  border-bottom: 1rpx solid #f0f0f0;
 }
 
-.gcol-4 {
-  grid-column: 4;
+.batch-row:nth-child(even) {
+  background-color: #f7f9fc;
 }
 
-.gcol-5 {
-  grid-column: 5;
+.batch-row:last-child {
+  border-bottom: none;
 }
 
-.gcol-6 {
-  grid-column: 6;
+.th-cell {
+  padding: 16rpx 10rpx;
+  font-size: 24rpx;
+  text-align: center;
+  flex-shrink: 0;
+  font-weight: 600;
 }
 
-.gcol-7 {
-  grid-column: 7;
+.td-cell {
+  padding: 16rpx 10rpx;
+  font-size: 24rpx;
+  color: #333;
+  text-align: center;
+  flex-shrink: 0;
+  word-break: break-all;
+  display: flex;
+  align-items: center;
+  justify-content: center;
 }
 
-.gcol-8 {
-  grid-column: 8;
+.col-batch {
+  width: 220rpx;
 }
 
-.gcol-9 {
-  grid-column: 9;
+.col-region {
+  width: 180rpx;
 }
 
-.gcol-10 {
-  grid-column: 10;
+.col-qty {
+  width: 140rpx;
 }
 
-.gcol-11 {
-  grid-column: 11;
+.col-time {
+  width: 280rpx;
 }
 
-.sticky-left {
-  position: sticky;
-  left: 0;
-  z-index: 9;
-  background: #fff;
+.col-code {
+  width: 240rpx;
 }
 
 .loading-row {
-  justify-content: flex-start;
+  padding: 24rpx;
+  display: flex;
+  justify-content: center;
 }
 
 .loading-wrapper {

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 223 - 564
traceCodePackages/traceabilityReport/pages/reportExport/index.vue


Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott