钱新宇 1 napja
szülő
commit
3a26c5ff2c

+ 60 - 0
traceCodePackages/traceabilityReport/pages/blacklist/index.vue

@@ -54,6 +54,10 @@
         </view>
       </view>
     </scroll-view>
+
+    <view class="footer-btn-area">
+      <button class="export-btn" @click="handleExport">导出至邮箱</button>
+    </view>
   </view>
 </template>
 
@@ -162,6 +166,29 @@ export default {
         url: `/traceCodePackages/traceabilityReport/pages/blacklist/detail/index?id=${item.id}&name=${encodeURIComponent(item.receiverName)}`,
       });
     },
+
+    handleExport() {
+      uni.showModal({
+        title: "导出至邮箱",
+        editable: true,
+        placeholderText: "请输入邮箱地址",
+        success: (res) => {
+          if (res.confirm) {
+            if (!res.content) {
+              uni.showToast({
+                title: "请输入邮箱",
+                icon: "none",
+              });
+              return;
+            }
+            uni.showToast({
+              title: "导出请求已发送",
+              icon: "success",
+            });
+          }
+        },
+      });
+    },
   },
 };
 </script>
@@ -313,4 +340,37 @@ export default {
     transform: rotate(360deg);
   }
 }
+
+.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);
+  position: fixed;
+  z-index: 10;
+  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;
+  height: 88rpx;
+  line-height: 88rpx;
+  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);
+}
+
+.export-btn::after {
+  border: none;
+}
 </style>

+ 254 - 9
traceCodePackages/traceabilityReport/pages/ganmaoling/index.vue

@@ -1,13 +1,65 @@
 <template>
-  <view class="detail-page">
+  <view class="detail-page" @click="closeProvinceDropdown">
     <view class="tip"
       >数据更新时间:{{
         formatDate(
           new Date().setDate(new Date().getDate() - 1),
           "YYYY-MM-DD",
         ) || "--"
-      }}</view
-    >
+      }}
+      <view
+        class="filter"
+        :style="{
+          position: 'relative',
+          zIndex: dropdownProvinceOpen ? 9 : 'auto',
+        }"
+      >
+        <view class="selector-wrap">
+          <view class="selector" @click.stop="toggleProvinceDropdown">
+            <text class="selector-text">{{
+              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"
@@ -20,7 +72,7 @@
       <view class="list-container">
         <view
           class="card-item"
-          v-for="(item, index) in rows"
+          v-for="(item, index) in displayRows"
           :key="index"
           @click="toDetail(item)"
         >
@@ -58,15 +110,19 @@
           />
         </view>
 
-        <view v-if="!loading && rows.length === 0" class="empty-data">
+        <view v-if="!loading && displayRows.length === 0" class="empty-data">
           <EmptyView text="无相关数据" />
         </view>
 
-        <view v-if="!hasMore && rows.length > 0" class="no-more">
+        <view v-if="!hasMore && displayRows.length > 0" class="no-more">
           <text>没有更多数据了</text>
         </view>
       </view>
     </scroll-view>
+
+    <view class="footer-btn-area">
+      <button class="export-btn" @click="handleExport">导出至邮箱</button>
+    </view>
   </view>
 </template>
 
@@ -75,6 +131,8 @@ import EmptyView from "../../../wigets/empty.vue";
 import request from "../../../request/index.js";
 import { formatDate } from "../../../utils/utils.js";
 
+const PROVINCES = ["北京市", "上海市", "广东省", "浙江省", "江苏省"];
+
 export default {
   components: {
     EmptyView,
@@ -88,8 +146,27 @@ export default {
       hasMore: true,
       pageNum: 1,
       pageSize: 20,
+      dropdownProvinceOpen: false,
+      provinceSearchText: "",
+      provinceList: ["", ...PROVINCES],
+      selectedProvince: "",
     };
   },
+  computed: {
+    displayRows() {
+      if (!this.selectedProvince) return this.rows;
+      return this.rows.filter(
+        (item) => item.receiverProvince === this.selectedProvince,
+      );
+    },
+    filteredProvinceList() {
+      const keyword = (this.provinceSearchText || "").trim();
+      if (!keyword) return this.provinceList;
+      return this.provinceList.filter((p) =>
+        (p || "全部省份").includes(keyword),
+      );
+    },
+  },
   created() {
     this.resetFetch();
   },
@@ -106,7 +183,6 @@ export default {
     generateFakeData() {
       const newRows = [];
       const levels = ["VIP", "二级", "三级"];
-      const provinces = ["北京市", "上海市", "广东省", "浙江省", "江苏省"];
       const natures = ["协议客户", "非协议客户"];
       const managers = ["张明华", "李建华", "王丽萍", "陈大文"];
 
@@ -122,7 +198,7 @@ export default {
         newRows.push({
           id: i,
           receiverName: `测试收货企业${i + 1}有限公司`,
-          receiverProvince: provinces[i % provinces.length],
+          receiverProvince: PROVINCES[i % PROVINCES.length],
           customerLevel: levels[i % levels.length],
           customerNature: natures[i % natures.length],
           manager: managers[i % managers.length],
@@ -132,6 +208,21 @@ export default {
       return newRows;
     },
 
+    toggleProvinceDropdown() {
+      this.dropdownProvinceOpen = !this.dropdownProvinceOpen;
+    },
+
+    closeProvinceDropdown() {
+      this.dropdownProvinceOpen = false;
+    },
+
+    selectProvince(province) {
+      this.selectedProvince = province || "";
+      this.dropdownProvinceOpen = false;
+    },
+
+    onProvinceSearch() {},
+
     async onRefresh() {
       this.isRefreshing = true;
       this.pageNum = 1;
@@ -176,6 +267,29 @@ export default {
         url: `/traceCodePackages/traceabilityReport/pages/ganmaoling/detail/index?id=${item.id}&name=${encodeURIComponent(item.receiverName)}`,
       });
     },
+
+    handleExport() {
+      uni.showModal({
+        title: "导出至邮箱",
+        editable: true,
+        placeholderText: "请输入邮箱地址",
+        success: (res) => {
+          if (res.confirm) {
+            if (!res.content) {
+              uni.showToast({
+                title: "请输入邮箱",
+                icon: "none",
+              });
+              return;
+            }
+            uni.showToast({
+              title: "导出请求已发送",
+              icon: "success",
+            });
+          }
+        },
+      });
+    },
   },
 };
 </script>
@@ -189,6 +303,104 @@ export default {
   background: #f3f6f9;
 }
 
+.filter {
+  background: #f3f6f9;
+  padding: 8rpx 24rpx 0;
+}
+
+.selector-wrap {
+  position: relative;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.selector {
+  position: relative;
+  display: flex;
+  align-items: center;
+  color: #2c69ff;
+  padding-right: 30rpx;
+}
+
+.selector-text {
+  font-size: 30rpx;
+  max-width: 240rpx;
+  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;
+}
+
+.selector-arrow.open {
+  bottom: 7rpx;
+  transform: rotate(225deg);
+}
+
+.dropdown {
+  position: absolute;
+  right: 0rpx;
+  top: 54rpx;
+  width: 310rpx;
+  max-height: 380rpx;
+  background: #fff;
+  border: 1rpx solid #eef0f4;
+  border-radius: 12rpx;
+  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
+  z-index: 93;
+  overflow: hidden;
+}
+
+.dropdown-search-bar {
+  padding: 10rpx;
+  border-bottom: 1rpx solid #f0f2f5;
+  background: #fff;
+  z-index: 94;
+}
+
+.dropdown-search-input {
+  width: 100%;
+  height: 60rpx;
+  background: #f5f7fa;
+  border-radius: 8rpx;
+  padding: 0 20rpx;
+  font-size: 28rpx;
+  box-sizing: border-box;
+}
+
+.dropdown-scroll-view {
+  flex: 1;
+  width: 100%;
+  max-height: 260rpx;
+  overflow-y: auto;
+}
+
+.dropdown-item {
+  padding: 16rpx 24rpx;
+  font-size: 28rpx;
+  color: #333;
+  text-wrap: wrap;
+}
+
+.dropdown-item + .dropdown-item {
+  border-top: 1rpx solid #f0f2f5;
+}
+
 .tip {
   font-size: 24rpx;
   color: #999;
@@ -205,7 +417,7 @@ export default {
 }
 
 .list-container {
-  padding-bottom: calc(50rpx + env(safe-area-inset-bottom));
+  padding-bottom: calc(200rpx + env(safe-area-inset-bottom));
 }
 
 .card-item {
@@ -335,4 +547,37 @@ export default {
     transform: rotate(360deg);
   }
 }
+
+.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);
+  position: fixed;
+  z-index: 10;
+  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;
+  height: 88rpx;
+  line-height: 88rpx;
+  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);
+}
+
+.export-btn::after {
+  border: none;
+}
 </style>