فهرست منبع

feat:更新

钱新宇 12 ساعت پیش
والد
کامیت
0fd7b5505b

+ 1 - 1
package.json

@@ -24,4 +24,4 @@
         "dependencies": [],
         "encrypt": []
     }
-}
+}

+ 1 - 1
project.config.json

@@ -20,6 +20,6 @@
     "ignore": [],
     "include": []
   },
-  "appid": "wxc6266b2eeba52ee1",
+  "appid": "wx67fb4805c6d1ddd1",
   "editorSetting": {}
 }

+ 264 - 107
traceCodePackages/traceabilityReport/pages/blacklist/index.vue

@@ -1,13 +1,32 @@
 <template>
   <view class="detail-page">
-    <view class="tip"
-      >数据更新时间:{{
-        formatDate(
-          new Date().setDate(new Date().getDate() - 1),
-          "YYYY-MM-DD",
-        ) || "--"
-      }}</view
-    >
+    <!-- 顶部状态栏 -->
+    <view class="header-section">
+      <view class="header-content">
+        <view class="title-group">
+          <text class="main-title">黑名单企业库</text>
+          <text class="sub-title">实时监控异常经营企业</text>
+        </view>
+        <view class="stat-box">
+          <text class="stat-num">{{ totalCount }}</text>
+          <text class="stat-unit">家</text>
+        </view>
+      </view>
+      <view class="update-tip">
+        <text class="tip-icon">🕒</text>
+        <text
+          >数据更新时间:{{
+            formatDate(
+              new Date().setDate(new Date().getDate() - 1),
+              "YYYY-MM-DD",
+            ) || "--"
+          }}</text
+        >
+      </view>
+      <!-- 背景装饰 -->
+      <view class="header-circle circle-1"></view>
+      <view class="header-circle circle-2"></view>
+    </view>
 
     <scroll-view
       class="list-scroll"
@@ -24,16 +43,30 @@
           :key="index"
           @click="toDetail(item)"
         >
-          <view class="left-info">
-            <view class="row1-name">
-              <text style="text-decoration: underline"
-                >{{ index + 1 }}.{{ item.receiverName }}</text
-              >
+          <view class="card-header">
+            <view class="header-left">
+              <text class="index-num">{{ index + 1 }}</text>
+              <text class="company-name">{{ item.receiverName }}</text>
+            </view>
+            <view class="header-right">
+              <text class="status-tag">黑名单</text>
             </view>
-            <view class="row4-manager">信用代码:{{ item.companyCode }}</view>
-            <view class="row3-nature">
-              <text class="province">省份:{{ item.receiverProvince }}</text>
-              <text class="province">性质:{{ item.customerNature }}</text>
+          </view>
+
+          <view class="card-body">
+            <view class="code-row">
+              <text class="label">信用代码:</text>
+              <text class="value code-text">{{ item.companyCode }}</text>
+            </view>
+            <view class="info-grid">
+              <view class="info-item">
+                <text class="label">省份</text>
+                <text class="value">{{ item.receiverProvince }}</text>
+              </view>
+              <view class="info-item">
+                <text class="label">性质</text>
+                <text class="value">{{ item.customerNature }}</text>
+              </view>
             </view>
           </view>
         </view>
@@ -43,6 +76,7 @@
             class="loading-icon"
             src="../../../static/images/loading.png"
           />
+          <text class="loading-text">加载中...</text>
         </view>
 
         <view v-if="!loading && rows.length === 0" class="empty-data">
@@ -56,7 +90,9 @@
     </scroll-view>
 
     <view class="footer-btn-area">
-      <button class="export-btn" @click="handleExport">导出至邮箱</button>
+      <button class="action-btn export-btn" @click="handleExport">
+        导出至邮箱
+      </button>
     </view>
   </view>
 </template>
@@ -66,6 +102,9 @@ import EmptyView from "../../../wigets/empty.vue";
 import request from "../../../request/index.js";
 import { formatDate } from "../../../utils/utils.js";
 
+const PROVINCES = ["北京市", "上海市", "广东省", "浙江省", "江苏省"];
+const NATURES = ["协议客户", "非协议客户", "商业客户", "终端客户"];
+
 export default {
   components: {
     EmptyView,
@@ -87,16 +126,9 @@ export default {
   methods: {
     formatDate,
 
-    getLevelClass(level) {
-      if (level === "VIP") return "tag-vip";
-      if (level === "二级") return "tag-l2";
-      if (level === "三级") return "tag-l3";
-      return "tag-default";
-    },
-
     generateFakeData() {
       const newRows = [];
-      const provinces = [
+      const codes = [
         "91370104771001730R",
         "91420105783155681H",
         "91330110MA2CCJE32Y",
@@ -116,7 +148,9 @@ export default {
         newRows.push({
           id: i,
           receiverName: `测试收货企业${i + 1}有限公司`,
-          companyCode: provinces[i % provinces.length],
+          companyCode: codes[i % codes.length],
+          receiverProvince: PROVINCES[i % PROVINCES.length],
+          customerNature: NATURES[i % NATURES.length],
         });
       }
       return newRows;
@@ -199,137 +233,256 @@ export default {
   flex-direction: column;
   height: calc(100vh - 116rpx - env(safe-area-inset-bottom));
   box-sizing: border-box;
-  background: #f3f6f9;
+  background: #f5f7fa;
 }
 
-.tip {
+/* Header Section */
+.header-section {
+  background: linear-gradient(135deg, #2b32b2 0%, #1488cc 100%);
+  padding: 40rpx 40rpx 80rpx; /* Extra padding at bottom for overlap effect */
+  position: relative;
+  z-index: 20;
+  color: #fff;
+  border-bottom-left-radius: 40rpx;
+  border-bottom-right-radius: 40rpx;
+  overflow: hidden;
+  box-shadow: 0 10rpx 30rpx rgba(20, 136, 204, 0.2);
+}
+
+.header-content {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  position: relative;
+  z-index: 2;
+  margin-bottom: 24rpx;
+}
+
+.title-group {
+  display: flex;
+  flex-direction: column;
+}
+
+.main-title {
+  font-size: 40rpx;
+  font-weight: bold;
+  margin-bottom: 8rpx;
+  letter-spacing: 2rpx;
+}
+
+.sub-title {
   font-size: 24rpx;
-  color: #999;
-  padding: 24rpx;
-  background: #f3f6f9;
+  opacity: 0.8;
 }
 
+.stat-box {
+  display: flex;
+  align-items: baseline;
+}
+
+.stat-num {
+  font-size: 56rpx;
+  font-weight: bold;
+  margin-right: 8rpx;
+  font-family: "DINAlternate-Bold", sans-serif;
+}
+
+.stat-unit {
+  font-size: 24rpx;
+  opacity: 0.8;
+}
+
+.update-tip {
+  display: inline-flex;
+  align-items: center;
+  background: rgba(255, 255, 255, 0.15);
+  padding: 8rpx 20rpx;
+  border-radius: 30rpx;
+  font-size: 22rpx;
+  backdrop-filter: blur(10px);
+  position: relative;
+  z-index: 2;
+}
+
+.tip-icon {
+  margin-right: 8rpx;
+  font-size: 20rpx;
+}
+
+/* Header Decor Circles */
+.header-circle {
+  position: absolute;
+  border-radius: 50%;
+  background: rgba(255, 255, 255, 0.05);
+}
+
+.circle-1 {
+  width: 300rpx;
+  height: 300rpx;
+  top: -100rpx;
+  right: -50rpx;
+}
+
+.circle-2 {
+  width: 200rpx;
+  height: 200rpx;
+  bottom: -50rpx;
+  left: -50rpx;
+}
+
+/* List Scroll */
 .list-scroll {
   flex: 1;
-  height: 0; /* Important for flex expansion */
-  padding: 0 24rpx;
+  height: 0;
+  padding: 0 24rpx; /* Remove vertical padding from scroll container */
   box-sizing: border-box;
+  margin-top: -50rpx; /* Negative margin to pull list up */
+  position: relative;
+  z-index: 21;
 }
 
 .list-container {
-  padding-bottom: calc(50rpx + env(safe-area-inset-bottom));
+  padding-top: 10rpx;
+  padding-bottom: calc(200rpx + env(safe-area-inset-bottom));
 }
 
 .card-item {
-  display: flex;
-  justify-content: space-between;
-  align-items: flex-start; /* Align top */
   background: #fff;
-  border-radius: 16rpx;
+  border-radius: 20rpx;
   padding: 30rpx;
-  margin-bottom: 20rpx;
-  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
+  margin-bottom: 24rpx;
+  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.05);
+  transition: transform 0.2s;
 }
 
-.left-info {
-  flex: 1;
-  margin-right: 20rpx;
+.card-item:active {
+  transform: scale(0.99);
 }
 
-.row1-name {
-  font-size: 30rpx;
-  font-weight: bold;
-  color: #1890ff;
-  margin-bottom: 16rpx;
-  text-decoration: underline;
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  margin-bottom: 24rpx;
 }
 
-.row2-info {
+.header-left {
+  flex: 1;
   display: flex;
   align-items: center;
-  margin-bottom: 12rpx;
+  margin-right: 20rpx;
 }
 
-.province {
-  font-size: 26rpx;
-  color: #666;
-  margin-right: 20rpx;
+.index-num {
+  font-size: 24rpx;
+  color: #999;
+  margin-right: 12rpx;
+  font-family: monospace;
 }
 
-.level-tag {
-  font-size: 22rpx;
-  padding: 4rpx 12rpx;
-  border-radius: 6rpx;
-  background: #f0f0f0;
-  color: #666;
+.company-name {
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+  line-height: 1.4;
 }
 
-.tag-vip {
-  background: #e6f7ff;
-  color: #1890ff;
+.header-right {
+  flex-shrink: 0;
 }
 
-.tag-l2 {
-  background: #f6ffed;
-  color: #52c41a;
+.status-tag {
+  font-size: 20rpx;
+  padding: 6rpx 16rpx;
+  border-radius: 20rpx;
+  background: #fff1f0;
+  color: #ff4d4f;
+  font-weight: 600;
+  border: 1rpx solid rgba(255, 77, 79, 0.2);
 }
 
-.tag-l3 {
-  background: #fff7e6;
-  color: #fa8c16;
+.card-body {
+  background: #f9fbfd;
+  border-radius: 12rpx;
+  padding: 24rpx;
 }
 
-.row3-nature {
-  font-size: 26rpx;
-  color: #666;
-  margin-bottom: 12rpx;
+.code-row {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20rpx;
+  padding-bottom: 20rpx;
+  border-bottom: 1rpx solid #edf0f5;
 }
 
-.row4-manager {
-  font-size: 26rpx;
-  color: #666;
+.code-row:last-child {
+  margin-bottom: 0;
+  padding-bottom: 0;
+  border-bottom: none;
 }
 
-.right-info {
+.code-text {
+  font-family: monospace;
+  color: #333 !important;
+  font-weight: 600 !important;
+  letter-spacing: 1rpx;
+}
+
+.info-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 24rpx;
+}
+
+.info-item {
   display: flex;
   align-items: center;
-  align-self: center; /* Center vertically relative to card */
+  width: 45%;
 }
 
-.alert-count {
-  background: #fff2f0;
-  color: #ff4d4f;
+.info-item .label,
+.code-row .label {
   font-size: 24rpx;
-  padding: 8rpx 20rpx;
-  border-radius: 30rpx;
-  font-weight: bold;
+  color: #999;
+  margin-right: 12rpx;
 }
 
+.info-item .value,
+.code-row .value {
+  font-size: 26rpx;
+  color: #666;
+  font-weight: 500;
+}
+
+/* Loading & Footer */
 .loading-more {
   display: flex;
   justify-content: center;
   align-items: center;
-  padding: 20rpx 0;
+  padding: 30rpx 0;
+}
+
+.loading-text {
+  font-size: 24rpx;
+  color: #999;
 }
 
 .loading-icon {
   width: 32rpx;
   height: 32rpx;
-  margin-right: 10rpx;
+  margin-right: 12rpx;
   animation: spin 1s linear infinite;
 }
 
 .empty-data {
-  display: flex;
-  justify-content: center;
-  padding-top: 100rpx;
+  padding-top: 120rpx;
 }
 
 .no-more {
   text-align: center;
-  color: #999;
+  color: #ccc;
   font-size: 24rpx;
-  padding: 20rpx 0;
+  padding: 30rpx 0;
 }
 
 @keyframes spin {
@@ -344,33 +497,37 @@ export default {
 .footer-btn-area {
   padding: 24rpx 32rpx calc(24rpx + env(safe-area-inset-bottom));
   background: #fff;
-  box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.05);
+  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
   position: fixed;
-  z-index: 10;
+  z-index: 100;
   bottom: 0;
   width: 100%;
   box-sizing: border-box;
 }
 
-.export-btn {
-  background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
-  color: #fff;
-  border-radius: 44rpx;
-  font-size: 32rpx;
-  font-weight: 500;
+.action-btn {
+  width: 100%;
   height: 88rpx;
   line-height: 88rpx;
+  border-radius: 44rpx;
+  font-size: 30rpx;
+  font-weight: 600;
+  text-align: center;
   border: none;
-  box-shadow: 0 6rpx 16rpx rgba(24, 144, 255, 0.35);
   transition: all 0.3s;
 }
 
-.export-btn:active {
-  transform: scale(0.98);
-  box-shadow: 0 2rpx 8rpx rgba(24, 144, 255, 0.35);
+.action-btn::after {
+  border: none;
 }
 
-.export-btn::after {
-  border: none;
+.action-btn:active {
+  transform: scale(0.96);
+}
+
+.export-btn {
+  background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
+  color: #fff;
+  box-shadow: 0 6rpx 16rpx rgba(24, 144, 255, 0.35);
 }
 </style>

+ 4 - 4
traceCodePackages/traceabilityReport/pages/customerScanningRate/wigets/ScanRateTable.vue

@@ -315,13 +315,13 @@ export default {
       type: Array,
       default: () => [
         {
-          key: "totalInRate",
-          title: "库扫码率",
+          key: "totalOutRate",
+          title: "库扫码率",
           unit: "%",
         },
         {
-          key: "totalOutRate",
-          title: "库扫码率",
+          key: "totalInRate",
+          title: "库扫码率",
           unit: "%",
         },
         {

+ 369 - 200
traceCodePackages/traceabilityReport/pages/ganmaoling/index.vue

@@ -1,66 +1,49 @@
 <template>
   <view class="detail-page" @click="closeProvinceDropdown">
-    <view class="tip"
-      >数据更新时间:{{
-        formatDate(
-          new Date().setDate(new Date().getDate() - 1),
-          "YYYY-MM-DD",
-        ) || "--"
-      }}
-      <view
-        class="filter"
-        :style="{
-          position: 'relative',
-          zIndex: dropdownProvinceOpen ? 9 : 'auto',
-        }"
-      >
-        <view class="selector-wrap">
+    <!-- 背景层 -->
+    <view class="header-bg"></view>
+
+    <!-- 顶部内容层 -->
+    <view class="header-section">
+      <view class="header-content">
+        <view class="title-group">
+          <text class="main-title">感冒灵颗粒</text>
+          <text class="sub-title">药品流向实时追踪</text>
+        </view>
+        <view class="stat-box">
+          <text class="stat-num">{{ totalCount }}</text>
+          <text class="stat-unit">家</text>
+        </view>
+      </view>
+
+      <view class="header-toolbar">
+        <view class="update-tip">
+          <text class="tip-icon">🕒</text>
+          <text
+            >更新:{{
+              formatDate(
+                new Date().setDate(new Date().getDate() - 1),
+                "YYYY-MM-DD",
+              ) || "--"
+            }}</text
+          >
+        </view>
+
+        <view class="filter-wrap">
           <view class="selector" @click.stop="toggleProvinceDropdown">
             <text class="selector-text">{{
-              selectedProvince ? selectedProvince : "全部省份"
+              selectedProvince || "全部省份"
             }}</text>
             <text
               class="selector-arrow"
               :class="{ open: dropdownProvinceOpen }"
             ></text>
           </view>
-          <view class="dropdown" v-show="dropdownProvinceOpen" @click.stop>
-            <view class="dropdown-search-bar">
-              <input
-                class="dropdown-search-input"
-                v-model="provinceSearchText"
-                @input="onProvinceSearch"
-                placeholder="搜索省份..."
-              />
-            </view>
-            <scroll-view scroll-y="true" class="dropdown-scroll-view">
-              <view
-                class="dropdown-item"
-                v-for="(p, i) in filteredProvinceList"
-                :key="p || i"
-                :style="
-                  p === selectedProvince || (!selectedProvince && i === 0)
-                    ? {
-                        backgroundColor: '#2c69ff',
-                        color: '#fff',
-                      }
-                    : {}
-                "
-                @click.stop="selectProvince(p)"
-                >{{ p || "全部省份" }}</view
-              >
-              <view
-                v-if="filteredProvinceList.length === 0"
-                class="dropdown-item"
-                style="text-align: center; color: #999"
-                >暂无数据</view
-              >
-            </scroll-view>
-          </view>
         </view>
       </view>
     </view>
 
+    <!-- 列表区域 -->
     <scroll-view
       class="list-scroll"
       scroll-y="true"
@@ -76,29 +59,36 @@
           :key="index"
           @click="toDetail(item)"
         >
-          <view class="left-info">
-            <view class="row1-name">
-              <view style="display: flex; align-items: center; gap: 10rpx">
-                <text style="text-decoration: underline"
-                  >{{ index + 1 }}.{{ item.receiverName }}</text
-                >
-                <text
-                  class="level-tag"
-                  :class="getLevelClass(item.customerLevel)"
-                >
-                  {{ item.customerLevel }}
-                </text>
-              </view>
-              <view class="right-info">
-                <text class="alert-count">{{ item.alertCount }}次预警</text>
-              </view></view
-            >
-            <view class="row2-info">
-              <text class="province">省份:{{ item.receiverProvince }} </text>
+          <view class="card-header">
+            <view class="header-left">
+              <text class="index-num">{{ index + 1 }}</text>
+              <text class="company-name">{{ item.receiverName }}</text>
+              <text
+                class="level-tag"
+                :class="getLevelClass(item.customerLevel)"
+              >
+                {{ item.customerLevel }}
+              </text>
             </view>
-            <view class="row3-nature">
-              <text class="province">责任人:{{ item.manager }}</text>
-              <text class="province">性质:{{ item.customerNature }}</text>
+            <view class="header-right">
+              <text class="alert-count">{{ item.alertCount }}次预警</text>
+            </view>
+          </view>
+
+          <view class="card-body">
+            <view class="info-grid">
+              <view class="info-item">
+                <text class="label">省份</text>
+                <text class="value">{{ item.receiverProvince }}</text>
+              </view>
+              <view class="info-item">
+                <text class="label">责任人</text>
+                <text class="value">{{ item.manager }}</text>
+              </view>
+              <view class="info-item">
+                <text class="label">性质</text>
+                <text class="value">{{ item.customerNature }}</text>
+              </view>
             </view>
           </view>
         </view>
@@ -108,6 +98,7 @@
             class="loading-icon"
             src="../../../static/images/loading.png"
           />
+          <text class="loading-text">加载中...</text>
         </view>
 
         <view v-if="!loading && displayRows.length === 0" class="empty-data">
@@ -120,8 +111,50 @@
       </view>
     </scroll-view>
 
+    <!-- 独立的下拉菜单层 -->
+    <view class="dropdown-layer" v-if="dropdownProvinceOpen" @click.stop>
+      <view class="dropdown">
+        <view class="dropdown-search-bar">
+          <input
+            class="dropdown-search-input"
+            v-model="provinceSearchText"
+            @input="onProvinceSearch"
+            placeholder="搜索省份..."
+            placeholder-style="color: #999"
+          />
+        </view>
+        <scroll-view scroll-y="true" class="dropdown-scroll-view">
+          <view
+            class="dropdown-item"
+            v-for="(p, i) in filteredProvinceList"
+            :key="p || i"
+            :class="{
+              active: p === selectedProvince || (!selectedProvince && i === 0),
+            }"
+            @click.stop="selectProvince(p)"
+          >
+            {{ p || "全部省份" }}
+            <text
+              v-if="p === selectedProvince || (!selectedProvince && i === 0)"
+              class="check-mark"
+              >✓</text
+            >
+          </view>
+          <view v-if="filteredProvinceList.length === 0" class="dropdown-empty"
+            >暂无数据</view
+          >
+        </scroll-view>
+      </view>
+    </view>
+
+    <!-- 底部按钮区 -->
     <view class="footer-btn-area">
-      <button class="export-btn" @click="handleExport">导出至邮箱</button>
+      <button class="action-btn history-btn" @click="handleHistory">
+        历史记录
+      </button>
+      <button class="action-btn export-btn" @click="handleExport">
+        导出至邮箱
+      </button>
     </view>
   </view>
 </template>
@@ -290,6 +323,13 @@ export default {
         },
       });
     },
+
+    handleHistory() {
+      uni.showToast({
+        title: "历史记录功能开发中",
+        icon: "none",
+      });
+    },
   },
 };
 </script>
@@ -300,249 +340,365 @@ export default {
   flex-direction: column;
   height: calc(100vh - 116rpx - env(safe-area-inset-bottom));
   box-sizing: border-box;
-  background: #f3f6f9;
+  background: #f5f7fa;
+  position: relative;
 }
 
-.filter {
-  background: #f3f6f9;
-  padding: 8rpx 24rpx 0;
+/* Header Background Layer */
+.header-bg {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 320rpx; /* Fixed height for background */
+  background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
+  border-bottom-left-radius: 40rpx;
+  border-bottom-right-radius: 40rpx;
+  z-index: 1;
+  box-shadow: 0 10rpx 30rpx rgba(24, 144, 255, 0.2);
 }
 
-.selector-wrap {
+/* Header Content Layer */
+.header-section {
+  padding: 40rpx 40rpx 80rpx;
   position: relative;
+  z-index: 3; /* Above List */
+  color: #fff;
+  /* Transparent background to allow overlap effect */
+}
+
+.header-content {
   display: flex;
-  justify-content: flex-end;
+  justify-content: space-between;
+  align-items: center;
+  position: relative;
+  z-index: 2;
+  margin-bottom: 24rpx;
 }
 
-.selector {
+.title-group {
+  display: flex;
+  flex-direction: column;
+}
+
+.main-title {
+  font-size: 40rpx;
+  font-weight: bold;
+  margin-bottom: 8rpx;
+  letter-spacing: 2rpx;
+}
+
+.sub-title {
+  font-size: 24rpx;
+  opacity: 0.8;
+}
+
+.stat-box {
+  display: flex;
+  align-items: baseline;
+}
+
+.stat-num {
+  font-size: 56rpx;
+  font-weight: bold;
+  margin-right: 8rpx;
+  font-family: "DINAlternate-Bold", sans-serif;
+}
+
+.stat-unit {
+  font-size: 24rpx;
+  opacity: 0.8;
+}
+
+.header-toolbar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
   position: relative;
+  z-index: 3;
+}
+
+.update-tip {
+  display: inline-flex;
+  align-items: center;
+  background: rgba(255, 255, 255, 0.15);
+  padding: 8rpx 20rpx;
+  border-radius: 30rpx;
+  font-size: 22rpx;
+  backdrop-filter: blur(10px);
+}
+
+.tip-icon {
+  margin-right: 8rpx;
+  font-size: 20rpx;
+}
+
+/* Filter Styles */
+.filter-wrap {
+  position: relative;
+}
+
+.selector {
   display: flex;
   align-items: center;
-  color: #2c69ff;
-  padding-right: 30rpx;
+  color: #fff;
+  font-size: 26rpx;
+  font-weight: 500;
+  padding: 8rpx 20rpx;
+  background: rgba(255, 255, 255, 0.2);
+  border-radius: 30rpx;
+  border: 1rpx solid rgba(255, 255, 255, 0.3);
 }
 
 .selector-text {
-  font-size: 30rpx;
-  max-width: 240rpx;
+  max-width: 200rpx;
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  display: inline-block;
 }
 
 .selector-arrow {
-  position: absolute;
-  right: 0rpx;
-  bottom: 14rpx;
-  font-size: 30rpx;
-  display: inline-block;
-  width: 15rpx;
-  height: 15rpx;
-  border: 5rpx solid #2c69ff;
-  border-top: none;
-  border-left: none;
-  transform-origin: 50% 50%;
-  transform: rotate(45deg);
-  transition: transform 0.2s;
+  margin-left: 10rpx;
+  width: 0;
+  height: 0;
+  border-left: 8rpx solid transparent;
+  border-right: 8rpx solid transparent;
+  border-top: 10rpx solid #fff;
+  transition: transform 0.3s;
 }
 
 .selector-arrow.open {
-  bottom: 7rpx;
-  transform: rotate(225deg);
+  transform: rotate(180deg);
 }
 
-.dropdown {
+/* Dropdown Layer (Absolute on top of everything) */
+.dropdown-layer {
   position: absolute;
-  right: 0rpx;
-  top: 54rpx;
-  width: 310rpx;
-  max-height: 380rpx;
+  top: 220rpx; /* Adjust based on header layout */
+  right: 40rpx;
+  z-index: 999;
+}
+
+.dropdown {
+  width: 360rpx;
   background: #fff;
-  border: 1rpx solid #eef0f4;
   border-radius: 12rpx;
-  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
-  z-index: 93;
+  box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.15);
   overflow: hidden;
 }
 
 .dropdown-search-bar {
-  padding: 10rpx;
-  border-bottom: 1rpx solid #f0f2f5;
-  background: #fff;
-  z-index: 94;
+  padding: 16rpx;
+  border-bottom: 1rpx solid #f0f0f0;
 }
 
 .dropdown-search-input {
-  width: 100%;
-  height: 60rpx;
   background: #f5f7fa;
-  border-radius: 8rpx;
-  padding: 0 20rpx;
-  font-size: 28rpx;
-  box-sizing: border-box;
+  height: 64rpx;
+  border-radius: 32rpx;
+  padding: 0 24rpx;
+  font-size: 26rpx;
 }
 
 .dropdown-scroll-view {
-  flex: 1;
-  width: 100%;
-  max-height: 260rpx;
-  overflow-y: auto;
+  max-height: 400rpx;
 }
 
 .dropdown-item {
-  padding: 16rpx 24rpx;
+  padding: 20rpx 30rpx;
   font-size: 28rpx;
   color: #333;
-  text-wrap: wrap;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  transition: background 0.2s;
 }
 
-.dropdown-item + .dropdown-item {
-  border-top: 1rpx solid #f0f2f5;
+.dropdown-item:active {
+  background: #f5f7fa;
 }
 
-.tip {
+.dropdown-item.active {
+  color: #1890ff;
+  font-weight: 500;
+  background: #e6f7ff;
+}
+
+.check-mark {
   font-size: 24rpx;
+}
+
+.dropdown-empty {
+  padding: 40rpx;
+  text-align: center;
   color: #999;
-  padding: 24rpx;
-  background: #f3f6f9;
+  font-size: 26rpx;
 }
 
+/* List Section */
 .list-scroll {
   flex: 1;
   height: 0;
-  /* Important for flex expansion */
   padding: 0 24rpx;
   box-sizing: border-box;
+  margin-top: -50rpx; /* Overlap effect */
+  position: relative;
+  z-index: 2; /* Between bg and header content */
 }
 
 .list-container {
+  padding-top: 10rpx;
   padding-bottom: calc(200rpx + env(safe-area-inset-bottom));
 }
 
 .card-item {
-  display: flex;
-  justify-content: space-between;
-  /* Align top */
   background: #fff;
-  border-radius: 16rpx;
+  border-radius: 20rpx;
   padding: 30rpx;
-  margin-bottom: 20rpx;
-  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
+  margin-bottom: 24rpx;
+  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.05);
+  transition: transform 0.2s;
 }
 
-.left-info {
-  flex: 1;
+.card-item:active {
+  transform: scale(0.99);
 }
 
-.row1-name {
-  font-size: 30rpx;
-  font-weight: bold;
-  color: #1890ff;
-  margin-bottom: 16rpx;
+.card-header {
   display: flex;
-  align-items: center;
   justify-content: space-between;
-  gap: 20rpx;
+  align-items: flex-start;
+  margin-bottom: 24rpx;
 }
 
-.row2-info {
+.header-left {
+  flex: 1;
   display: flex;
   align-items: center;
-  margin-bottom: 12rpx;
+  flex-wrap: wrap;
+  margin-right: 20rpx;
+  gap: 12rpx;
 }
 
-.province {
-  font-size: 26rpx;
-  color: #666;
-  margin-right: 20rpx;
+.index-num {
+  font-size: 24rpx;
+  color: #999;
+  font-family: monospace;
+}
+
+.company-name {
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+  line-height: 1.4;
 }
 
 .level-tag {
-  font-size: 22rpx;
+  font-size: 20rpx;
   padding: 4rpx 12rpx;
-  border-radius: 6rpx;
-  background: #f0f0f0;
-  color: #666;
+  border-radius: 8rpx;
+  white-space: nowrap;
+  line-height: 1.2;
+}
+
+.header-right {
+  flex-shrink: 0;
 }
 
 .tag-vip {
-  background: #e6f7ff;
-  color: #1890ff;
+  background: linear-gradient(135deg, #e6f7ff, #bae7ff);
+  color: #096dd9;
 }
 
 .tag-l2 {
-  background: #f6ffed;
-  color: #52c41a;
+  background: linear-gradient(135deg, #f6ffed, #d9f7be);
+  color: #389e0d;
 }
 
 .tag-l3 {
-  background: #fff7e6;
-  color: #fa8c16;
+  background: linear-gradient(135deg, #fff7e6, #ffe7ba);
+  color: #d46b08;
 }
 
-.row3-nature {
-  font-size: 26rpx;
-  color: #666;
-  margin-bottom: 12rpx;
-  display: flex;
-  align-items: center;
-  gap: 20rpx;
+.tag-default {
+  background: #f5f5f5;
+  color: #999;
 }
 
-.row4-manager {
-  font-size: 26rpx;
-  color: #666;
+.card-body {
+  background: #f9fbfd;
+  border-radius: 12rpx;
+  padding: 24rpx;
+}
+
+.info-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 24rpx;
 }
 
-.right-info {
+.info-item {
   display: flex;
   align-items: center;
-  align-self: center;
-  /* Center vertically relative to card */
+  min-width: 45%;
+}
+
+.info-item .label {
+  font-size: 24rpx;
+  color: #999;
+  margin-right: 12rpx;
+}
+
+.info-item .value {
+  font-size: 26rpx;
+  color: #666;
+  font-weight: 500;
 }
 
 .alert-count {
-  background: #fff2f0;
+  font-size: 22rpx;
   color: #ff4d4f;
-  font-size: 24rpx;
-  padding: 8rpx 20rpx;
-  border-radius: 30rpx;
-  font-weight: bold;
+  background: rgba(255, 77, 79, 0.1);
+  padding: 6rpx 16rpx;
+  border-radius: 20rpx;
+  font-weight: 600;
 }
 
+/* Loading & Footer */
 .loading-more {
   display: flex;
   justify-content: center;
   align-items: center;
-  padding: 20rpx 0;
+  padding: 30rpx 0;
+}
+
+.loading-text {
+  font-size: 24rpx;
+  color: #999;
 }
 
 .loading-icon {
   width: 32rpx;
   height: 32rpx;
-  margin-right: 10rpx;
+  margin-right: 12rpx;
   animation: spin 1s linear infinite;
 }
 
 .empty-data {
-  display: flex;
-  justify-content: center;
-  padding-top: 100rpx;
+  padding-top: 120rpx;
 }
 
 .no-more {
   text-align: center;
-  color: #999;
+  color: #ccc;
   font-size: 24rpx;
-  padding: 20rpx 0;
+  padding: 30rpx 0;
 }
 
 @keyframes spin {
   from {
     transform: rotate(0deg);
   }
-
   to {
     transform: rotate(360deg);
   }
@@ -551,33 +707,46 @@ export default {
 .footer-btn-area {
   padding: 24rpx 32rpx calc(24rpx + env(safe-area-inset-bottom));
   background: #fff;
-  box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.05);
+  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
   position: fixed;
-  z-index: 10;
+  z-index: 100;
   bottom: 0;
   width: 100%;
   box-sizing: border-box;
+  display: flex;
+  gap: 24rpx;
 }
 
-.export-btn {
-  background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
-  color: #fff;
-  border-radius: 44rpx;
-  font-size: 32rpx;
-  font-weight: 500;
+.action-btn {
+  flex: 1;
   height: 88rpx;
   line-height: 88rpx;
+  border-radius: 44rpx;
+  font-size: 30rpx;
+  font-weight: 600;
+  text-align: center;
   border: none;
-  box-shadow: 0 6rpx 16rpx rgba(24, 144, 255, 0.35);
   transition: all 0.3s;
 }
 
-.export-btn:active {
-  transform: scale(0.98);
-  box-shadow: 0 2rpx 8rpx rgba(24, 144, 255, 0.35);
+.action-btn::after {
+  border: none;
 }
 
-.export-btn::after {
-  border: none;
+.action-btn:active {
+  transform: scale(0.96);
+}
+
+.history-btn {
+  background: #fff;
+  color: #1890ff;
+  border: 2rpx solid #1890ff;
+  box-shadow: 0 4rpx 12rpx rgba(24, 144, 255, 0.1);
+}
+
+.export-btn {
+  background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
+  color: #fff;
+  box-shadow: 0 6rpx 16rpx rgba(24, 144, 255, 0.35);
 }
 </style>

+ 45 - 13
traceCodePackages/traceabilityReport/pages/reportExport/index.vue

@@ -84,18 +84,24 @@
           >规格:{{ item.pkgSpec || "" }}</view
         >
         <view class="report-export-item-row"
-          >时间:{{ formatDate(item.beginTime) }}--{{
+          >时间:{{ formatDate(item.beginTime) }}{{
             formatDate(item.endTime)
           }}</view
         >
+        <!-- <view
+          class="report-export-item-row"
+          style="color: red"
+          v-if="item.remark !== ''"
+          >任务失败:{{ item.remark || "" }}</view
+        > -->
         <view v-if="item.status == 2" class="report-export-progress-wrap">
           <view class="report-export-progress">
             <view
               class="report-export-progress-fill"
-              :style="{ width: item.progress || 0 + '%' }"
+              :style="{ width: `${item.progress || 10}%` }"
             ></view>
             <text class="report-export-progress-text">{{
-              item.progress || 0
+              item.progress || 10
             }}</text>
           </view>
         </view>
@@ -384,6 +390,21 @@
               />
             </view>
           </view>
+          <view class="report-export-create-modal-row">
+            <text class="report-export-create-modal-label"
+              >其它客户信用代码</text
+            >
+            <view class="report-export-create-modal-inputwrap">
+              <input
+                class="report-export-dropdown-search-input"
+                v-model="form.otherCustomerCode"
+                placeholder="请填写其他客户信用代码(请依照其他客户填写顺序多个客户用半角逗号隔开)"
+                placeholder-class="report-export-dropdown-other-customer-input"
+                :disabled="modalType === 'read'"
+                :style="{ color: '#666', padding: 0, border: 'none' }"
+              />
+            </view>
+          </view>
           <view class="report-export-create-modal-row">
             <text class="report-export-create-modal-label">品种</text>
             <view
@@ -544,7 +565,11 @@
         >
           <view
             class="report-export-create-modal-btn"
-            :style="{ flex: '0 0 40%' }"
+            :style="
+              currentItem.status !== '2'
+                ? { flex: '0 0 40%' }
+                : { flex: '0 0 100%' }
+            "
             @click.stop="closeCreate"
             >关闭</view
           >
@@ -552,6 +577,7 @@
             class="report-export-create-modal-btn"
             :style="{ background: 'red', flex: '0 0 40%' }"
             @click.stop="confirmDelete"
+            v-if="currentItem.status !== '2'"
             >删除</view
           >
         </view>
@@ -673,7 +699,7 @@
     <view
       class="report-export-create-modal report-export-create-email-modal"
       :class="{ 'report-export-create-modal--open': emailModalOpen }"
-      :style="{ transform: 'translateY(1000%)' }"
+      v-if="emailModalOpen"
     >
       <view class="report-export-create-modal-title">
         <text>发送至邮箱</text>
@@ -780,6 +806,7 @@ export default {
         customer: [],
         product: { physicName: "" },
         otherCustomer: "",
+        otherCustomerCode: "",
       },
       dateRange: [],
       computeTimer: null,
@@ -844,7 +871,7 @@ export default {
   },
   created() {
     const userInfo = uni.getStorageSync("userInfo");
-    const staffEmail = userInfo?.staffEmail || "";
+    const staffEmail = userInfo?.ldap || "";
     this.emailForm.email = staffEmail.split("@")[0];
     console.log("reportExport\index.vue,storage,userInfo", userInfo);
     this.initList();
@@ -914,11 +941,11 @@ export default {
           name = otherCustomer;
         }
       }
-      const arr = name.split(",");
+      const arr = name?.split(",");
       if (arr.length == 0) return "--";
       return arr.length == 1
         ? arr[0].trim()
-        : `${arr[0].trim()}等${arr.length}个公司`;
+        : `${arr[0].trim()}等${arr.length - 1}家公司`;
     },
     formatDate(date) {
       return formatDate({ date }, "YYYY-MM-DD");
@@ -1024,8 +1051,10 @@ export default {
         } else if (this.modalType == "read") {
           this.taskTitle = "查看任务";
         }
-        const cNames = item.customerName.split(",");
-        const cCodes = (item.customerId || "").split(",");
+        const cNames = item.customerName ? item.customerName.split(",") : [];
+        const cCodes = item.customerId
+          ? String(item.customerId).split(",")
+          : [];
         const regionCode = item.regionCode || item.provinceCode || "";
         let regionName = item.regionName || item.provinceName || "";
         if (!regionName && regionCode && Array.isArray(this.options.region)) {
@@ -1063,6 +1092,7 @@ export default {
           },
           pkgSpec: item?.pkgSpec || "",
           otherCustomer: item?.otherCustomer || "",
+          otherCustomerCode: item?.otherCustomerCode || "",
         };
         if (item.physicName) {
           this.getGuigeList(item.physicName);
@@ -1152,7 +1182,7 @@ export default {
       uni.navigateTo({
         url: `/traceCodePackages/traceabilityReport/pages/reportExport/detail/index?id=${
           item.id
-        }&title=${encodeURIComponent(this.getCustomerName(item.customerName))}`,
+        }&title=${encodeURIComponent(this.getCustomerName(item))}`,
       });
     },
     onSearch() {
@@ -1173,6 +1203,7 @@ export default {
         customer: [],
         product: { physicName: "" },
         otherCustomer: "",
+        otherCustomerCode: "",
       };
       this.searchForm = {
         region: "",
@@ -1222,6 +1253,7 @@ export default {
         customerId,
         customerName,
         otherCustomer: this.form?.otherCustomer || "",
+        otherCustomerCode: this.form?.otherCustomerCode || "",
         drugEntBaseInfoId: this.form?.product?.drugEntBaseInfoId || "",
         pkgSpec: this.form?.pkgSpec || "",
         physicName: this.form?.product?.physicName || "",
@@ -2186,8 +2218,8 @@ export default {
 }
 
 .report-export-create-email-modal {
-  transform: translateY(200%);
-  height: auto;
+  /* transform: translateY(200%); */
+  height: 420rpx;
   top: 30%;
   bottom: auto;
   border-radius: 16rpx;