Bladeren bron

feat:update

钱新宇 2 weken geleden
bovenliggende
commit
c8c35ee4d7

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

@@ -13,21 +13,18 @@
         </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 class="filter-tabs">
+          <view class="tab-item" v-for="(tab, index) in timeFilters" :key="index"
+            :class="{ active: currentFilter === tab.value }" @click="switchFilter(tab.value)">
+            {{ tab.label }}
+          </view>
         </view>
 
         <view class="filter-wrap">
           <view class="selector" @click.stop="toggleProvinceDropdown">
             <text class="selector-text">{{
               selectedProvince || "全部省份"
-              }}</text>
+            }}</text>
             <text class="selector-arrow" :class="{ open: dropdownProvinceOpen }"></text>
           </view>
         </view>
@@ -72,9 +69,9 @@
     </scroll-view>
 
     <view class="footer-btn-area">
-      <button class="action-btn history-btn" @click="handleHistory">
+      <!-- <button class="action-btn history-btn" @click="handleHistory">
         历史记录
-      </button>
+      </button> -->
       <button class="action-btn export-btn" @click="handleExport">
         导出至邮箱
       </button>
@@ -159,6 +156,13 @@ export default {
         email: "",
       },
       emailError: false,
+      currentFilter: "1",
+      timeFilters: [
+        { label: "昨日", value: "1" },
+        { label: "近7天", value: "7" },
+        { label: "近15天", value: "15" },
+        { label: "近30天", value: "30" },
+      ],
     };
   },
   created() {
@@ -181,18 +185,31 @@ export default {
       });
     },
 
+    switchFilter(value) {
+      if (this.currentFilter === value) return;
+      this.currentFilter = value;
+      this.resetFetch();
+    },
+
     fetchList() {
       if (this.loading) return;
       this.loading = true;
 
-      const yesterday = new Date();
-      yesterday.setDate(yesterday.getDate() - 1);
-      const dateStr = this.formatDate(yesterday, "YYYY-MM-DD");
+      const days = parseInt(this.currentFilter);
+      const toDate = new Date();
+      toDate.setDate(toDate.getDate() - 1);
+
+      const fromDate = new Date(toDate);
+      if (days > 1) {
+        fromDate.setDate(toDate.getDate() - (days - 1));
+      }
 
+      const fromDateStr = this.formatDate(fromDate, "YYYY-MM-DD");
+      const toDateStr = this.formatDate(toDate, "YYYY-MM-DD");
 
       request("/blacklist-report/get-export-company-data", {
-        fromDate: dateStr,
-        toDate: dateStr,
+        fromDate: fromDateStr,
+        toDate: toDateStr,
         path: "traceabilityReport/pages/blacklist/index.vue",
       }).then((res) => {
         if (res.code == 200) {
@@ -319,7 +336,7 @@ export default {
 /* Header Section */
 .header-section {
   background: linear-gradient(135deg, #2b32b2 0%, #1488cc 100%);
-  padding: 40rpx 40rpx 80rpx;
+  padding: 40rpx 40rpx 40rpx;
   /* Extra padding at bottom for overlap effect */
   position: relative;
   z-index: 20;
@@ -336,7 +353,7 @@ export default {
   align-items: center;
   position: relative;
   z-index: 2;
-  margin-bottom: 24rpx;
+  margin-bottom: 40rpx;
 }
 
 .title-group {
@@ -396,6 +413,30 @@ export default {
   font-size: 20rpx;
 }
 
+/* Filter Tabs */
+.filter-tabs {
+  display: flex;
+  background: rgba(255, 255, 255, 0.2);
+  border-radius: 30rpx;
+  padding: 4rpx;
+  margin-right: 20rpx;
+}
+
+.tab-item {
+  padding: 8rpx 24rpx;
+  font-size: 24rpx;
+  color: rgba(255, 255, 255, 0.8);
+  border-radius: 26rpx;
+  transition: all 0.3s;
+}
+
+.tab-item.active {
+  background: #fff;
+  color: #1890ff;
+  font-weight: 600;
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
+}
+
 /* Filter Styles */
 .filter-wrap {
   position: relative;
@@ -527,7 +568,7 @@ export default {
   padding: 0 24rpx;
   /* Remove vertical padding from scroll container */
   box-sizing: border-box;
-  margin-top: -50rpx;
+  margin-top: -20rpx;
   /* Negative margin to pull list up */
   position: relative;
   z-index: 21;

+ 194 - 42
traceCodePackages/traceabilityReport/pages/ganmaoling/index.vue

@@ -18,21 +18,18 @@
       </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 class="filter-tabs">
+          <view class="tab-item" v-for="(tab, index) in timeFilters" :key="index"
+            :class="{ active: currentFilter === tab.value }" @click="switchFilter(tab.value)">
+            {{ tab.label }}
+          </view>
         </view>
 
         <view class="filter-wrap">
           <view class="selector" @click.stop="toggleProvinceDropdown">
             <text class="selector-text">{{
               selectedProvince || "全部省份"
-            }}</text>
+              }}</text>
             <text class="selector-arrow" :class="{ open: dropdownProvinceOpen }"></text>
           </view>
         </view>
@@ -43,33 +40,45 @@
     <scroll-view class="list-scroll" scroll-y="true" refresher-enabled :refresher-triggered="isRefreshing"
       @refresherrefresh="onRefresh">
       <view class="list-container">
-        <view class="card-item" v-for="(item, index) in rows" :key="index" @click="toDetail(item)">
-          <view class="card-header">
-            <view class="header-left">
-              <text class="index-num">{{ index + 1 }}</text>
-              <text class="company-name">{{ item.customerName }}</text>
-              <text class="level-tag" :class="getLevelClass(item.customerLevel)">
-                {{ item.customerLevel }}
-              </text>
-            </view>
-            <view class="header-right">
-              <text class="alert-count">{{ item.totalWarningAmount }}次预警</text>
-            </view>
+        <view class="date-group" v-for="group in groupedRows" :key="group.date">
+          <view class="group-header" @click="toggleGroup(group)">
+            <view class="checkbox group-checkbox" :class="{ checked: isGroupChecked(group) }"></view>
+            <text class="group-date">{{ group.date }}</text>
           </view>
 
-          <view class="card-body">
-            <view class="info-grid">
-              <view class="info-item">
-                <text class="label">省份</text>
-                <text class="value">{{ item.customerProvinceName ?? '--' }}</text>
-              </view>
-              <view class="info-item">
-                <text class="label">责任人</text>
-                <text class="value">{{ item.responsibleManager }}</text>
+          <view class="card-item" v-for="(item, index) in group.list" :key="index" @click="toDetail(item)">
+            <view class="checkbox item-checkbox" :class="{ checked: item.checked }" @click.stop="toggleItem(item)">
+            </view>
+
+            <view class="card-content">
+              <view class="card-header">
+                <view class="header-left">
+                  <text class="index-num">{{ index + 1 }}</text>
+                  <text class="company-name">{{ item.customerName }}</text>
+                  <text class="level-tag" :class="getLevelClass(item.customerLevel)">
+                    {{ item.customerLevel }}
+                  </text>
+                </view>
+                <view class="header-right">
+                  <text class="alert-count">{{ item.totalWarningAmount }}次预警</text>
+                </view>
               </view>
-              <view class="info-item">
-                <text class="label">性质</text>
-                <text class="value">{{ item.customerCategory }}</text>
+
+              <view class="card-body">
+                <view class="info-grid">
+                  <view class="info-item">
+                    <text class="label">省份</text>
+                    <text class="value">{{ item.customerProvinceName ?? '--' }}</text>
+                  </view>
+                  <view class="info-item">
+                    <text class="label">责任人</text>
+                    <text class="value">{{ item.responsibleManager }}</text>
+                  </view>
+                  <view class="info-item">
+                    <text class="label">性质</text>
+                    <text class="value">{{ item.customerCategory }}</text>
+                  </view>
+                </view>
               </view>
             </view>
           </view>
@@ -83,9 +92,9 @@
 
     <!-- 底部按钮区 -->
     <view class="footer-btn-area">
-      <button class="action-btn history-btn" @click="handleHistory">
+      <!-- <button class="action-btn history-btn" @click="handleHistory">
         历史记录
-      </button>
+      </button> -->
       <button class="action-btn export-btn" @click="handleExport">
         导出至邮箱
       </button>
@@ -166,6 +175,13 @@ export default {
         email: "",
       },
       emailError: false,
+      currentFilter: "1",
+      timeFilters: [
+        { label: "昨日", value: "1" },
+        { label: "近7天", value: "7" },
+        { label: "近15天", value: "15" },
+        { label: "近30天", value: "30" },
+      ],
     };
   },
   created() {
@@ -195,19 +211,25 @@ export default {
       return "tag-default";
     },
 
+    switchFilter(value) {
+      if (this.currentFilter === value) return;
+      this.currentFilter = value;
+      this.resetFetch();
+    },
+
     fetchList() {
       if (this.loading) return;
       this.loading = true;
 
       request(
-        `/report/ganmaoling/list?days=1`,
+        `/report/ganmaoling/list?days=${this.currentFilter}`,
         {
           path: "traceabilityReport/pages/ganmaoling/index.vue",
         },
         "get",
       ).then((res) => {
         if (res.code == 200) {
-          this.allRows = res.data || [];
+          this.allRows = (res.data || []).map(item => ({ ...item, checked: false }));
           this.applyFilter();
         }
         this.loading = false;
@@ -307,12 +329,46 @@ export default {
     },
 
     handleHistory() {
-      uni.navigateTo({
-        url: "/traceCodePackages/traceabilityReport/pages/ganmaoling/history/index",
+      // uni.navigateTo({
+      //   url: "/traceCodePackages/traceabilityReport/pages/ganmaoling/history/index",
+      // });
+    },
+
+    toggleItem(item) {
+      item.checked = !item.checked;
+    },
+
+    toggleGroup(group) {
+      const allChecked = this.isGroupChecked(group);
+      group.list.forEach(item => {
+        item.checked = !allChecked;
       });
     },
+
+    isGroupChecked(group) {
+      if (!group || !group.list || group.list.length === 0) return false;
+      return group.list.every(item => item.checked);
+    },
   },
   computed: {
+    groupedRows() {
+      const groups = {};
+      this.rows.forEach((item) => {
+        const fullTime = item.updatedTime || "";
+        const date = fullTime.split(" ")[0] || fullTime.split("T")[0] || "未知日期";
+        if (!groups[date]) {
+          groups[date] = [];
+        }
+        groups[date].push(item);
+      });
+      // Sort by date descending
+      return Object.keys(groups)
+        .sort((a, b) => new Date(b.replace(/-/g, "/")) - new Date(a.replace(/-/g, "/")))
+        .map((date) => ({
+          date,
+          list: groups[date],
+        }));
+    },
     filteredProvinceList() {
       if (!this.provinceSearchText) {
         return this.provinceList;
@@ -432,6 +488,30 @@ export default {
   font-size: 20rpx;
 }
 
+/* Filter Tabs */
+.filter-tabs {
+  display: flex;
+  background: rgba(255, 255, 255, 0.2);
+  border-radius: 30rpx;
+  padding: 4rpx;
+  margin-right: 20rpx;
+}
+
+.tab-item {
+  padding: 8rpx 24rpx;
+  font-size: 24rpx;
+  color: rgba(255, 255, 255, 0.8);
+  border-radius: 26rpx;
+  transition: all 0.3s;
+}
+
+.tab-item.active {
+  background: #fff;
+  color: #1890ff;
+  font-weight: 600;
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
+}
+
 /* Filter Styles */
 .filter-wrap {
   position: relative;
@@ -541,7 +621,7 @@ export default {
   height: 0;
   padding: 0 24rpx;
   box-sizing: border-box;
-  margin-top: -50rpx;
+  margin-top: -20rpx;
   /* Overlap effect */
   position: relative;
   z-index: 2;
@@ -553,13 +633,85 @@ export default {
   padding-bottom: calc(200rpx + env(safe-area-inset-bottom));
 }
 
+.date-group {
+  margin-bottom: 24rpx;
+}
+
+.group-header {
+  display: flex;
+  align-items: flex-start;
+  padding: 24rpx 30rpx;
+  background: #e6f7ff;
+  border-radius: 20rpx;
+  margin-bottom: 20rpx;
+  box-shadow: 0 4rpx 12rpx rgba(24, 144, 255, 0.1);
+}
+
+.group-date {
+  font-size: 32rpx;
+  font-weight: bold;
+  color: #1890ff;
+  margin-left: 20rpx;
+  line-height: 44rpx;
+  /* Match checkbox height for alignment */
+}
+
+.checkbox {
+  width: 44rpx;
+  height: 44rpx;
+  border: 3rpx solid #d9d9d9;
+  border-radius: 8rpx;
+  flex-shrink: 0;
+  position: relative;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  box-sizing: border-box;
+  margin-top: 0;
+  /* Reset margin */
+  background: #fff;
+}
+
+.checkbox.checked {
+  background: #1890ff;
+  border-color: #1890ff;
+  box-shadow: 0 4rpx 10rpx rgba(24, 144, 255, 0.3);
+}
+
+.checkbox.checked::after {
+  content: '';
+  position: absolute;
+  left: 14rpx;
+  top: 8rpx;
+  width: 10rpx;
+  height: 20rpx;
+  border: 4rpx solid #fff;
+  border-top: 0;
+  border-left: 0;
+  transform: rotate(45deg);
+}
+
 .card-item {
   background: #fff;
   border-radius: 20rpx;
   padding: 30rpx;
   margin-bottom: 24rpx;
-  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.05);
-  transition: transform 0.2s;
+  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04);
+  transition: all 0.2s;
+  display: flex;
+  align-items: flex-start;
+  /* Align to top */
+}
+
+.item-checkbox {
+  margin-right: 24rpx;
+  margin-top: 6rpx;
+  /* Align with first line of text */
+}
+
+.card-content {
+  flex: 1;
+  overflow: hidden;
+  display: flex;
+  flex-direction: column;
 }
 
 .card-item:active {