From 04102f7237efefa744090ed7c25f7b5d0807b679 Mon Sep 17 00:00:00 2001
From: quanwei <419654421@qq.com>
Date: Thu, 05 Feb 2026 18:11:57 +0800
Subject: [PATCH] 完成运营中心提现和运营中心权限管理

---
 shop_vue/src/views/page/page/diy/model/GroupBuy.vue |  484 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 481 insertions(+), 3 deletions(-)

diff --git a/shop_vue/src/views/page/page/diy/model/GroupBuy.vue b/shop_vue/src/views/page/page/diy/model/GroupBuy.vue
index 1351525..5a978e5 100644
--- a/shop_vue/src/views/page/page/diy/model/GroupBuy.vue
+++ b/shop_vue/src/views/page/page/diy/model/GroupBuy.vue
@@ -6,7 +6,96 @@
     -->
   <div @click.stop="$parent.$parent.onEditer(index)" class="drag optional" :class="{selected: index === selectedIndex}">
     <div class="supplier" :style="{background: item.style.background}">
-      <div class="supplier-time" v-for="(supplier, index) in item.data" :key="index">
+      <!-- 筛选栏 -->
+      <div class="supplier-set" v-if="item.params.is_sort||(item.params.category==0&&item.params.is_category)||item.params.is_filter" >
+        <div class="filter-item" v-if="item.params.is_sort" >
+          <span class="filter-text">{{ sortOptions[currentSort] ? sortOptions[currentSort].text : '智能排序' }}</span>
+          <span class="filter-icon" :class="{ 'rotate': showSortDropdown }">▼</span>
+        </div>
+        <div class="filter-item" v-if="item.params.category==0&&item.params.is_category" >
+          <span class="filter-text">{{ categoryOptions[currentCategory] ? categoryOptions[currentCategory].name : '分类' }}</span>
+          <span class="filter-icon" :class="{ 'rotate': showCategoryDropdown }">▼</span>
+        </div>
+        <div class="filter-item" v-if="item.params.is_filter" >
+          <span class="filter-text">筛选</span>
+          <span class="filter-badge" v-if="hasActiveFilters">●</span>
+        </div>
+      </div>
+
+      <!-- 排序下拉面板 -->
+      <div class="sort-dropdown" v-if="showSortDropdown" @click.stop>
+        <div class="sort-option" v-for="(option, idx) in sortOptions" :key="idx" @click.stop="selectSort(idx)">
+          <span class="sort-option-text" :class="{ 'active': currentSort === idx }">{{ option.text }}</span>
+          <span class="sort-option-check" v-if="currentSort === idx">✓</span>
+        </div>
+      </div>
+
+      <!-- 分类下拉面板 -->
+      <div class="category-dropdown" v-if="showCategoryDropdown" @click.stop>
+        <div class="sort-option" v-for="(option, idx) in categoryOptions" :key="idx" @click.stop="selectCategory(idx)">
+          <span class="sort-option-text" :class="{ 'active': currentCategory === idx }">{{ option.name }}</span>
+          <span class="sort-option-check" v-if="currentCategory === idx">✓</span>
+        </div>
+      </div>
+
+      <!-- 遮罩层 -->
+      <div class="mask" v-if="showSortDropdown || showCategoryDropdown || showFilterPanel" @click.stop="closeAllDropdowns"></div>
+
+      <!-- 筛选面板 -->
+      <div class="filter-panel" v-if="showFilterPanel" @click.stop>
+        <div class="filter-panel-header">
+          <span class="filter-panel-title">筛选</span>
+          <span class="filter-reset" @click="resetFilters">重置</span>
+        </div>
+
+        <div class="filter-section">
+          <div class="filter-section-title">距离范围</div>
+          <div class="filter-tags">
+            <div class="filter-tag" v-for="(distItem, idx) in distanceOptions" :key="idx"
+              :class="{ 'active': selectedDistance === idx }" @click.stop="selectDistance(idx)">
+              {{ distItem.label }}
+            </div>
+          </div>
+        </div>
+
+        <div class="filter-section">
+          <div class="filter-section-title">人均价格</div>
+          <div class="filter-tags">
+            <div class="filter-tag" v-for="(priceItem, idx) in priceOptions" :key="idx"
+              :class="{ 'active': selectedPrice === idx }" @click.stop="selectPrice(idx)">
+              {{ priceItem.label }}
+            </div>
+          </div>
+        </div>
+
+        <div class="filter-section">
+          <div class="filter-section-title">服务评分</div>
+          <div class="filter-tags">
+            <div class="filter-tag" v-for="(scoreItem, idx) in scoreOptions" :key="idx"
+              :class="{ 'active': selectedScore === idx }" @click.stop="selectScore(idx)">
+              {{ scoreItem.label }}
+            </div>
+          </div>
+        </div>
+
+        <div class="filter-section">
+          <div class="filter-section-title">优惠类型</div>
+          <div class="filter-tags">
+            <div class="filter-tag" :class="{ 'active': showCouponOnly }" @click.stop="toggleCouponOnly">
+              仅看有券
+            </div>
+            <div class="filter-tag" :class="{ 'active': showTopRanked }" @click.stop="toggleTopRanked">
+              好评榜前10
+            </div>
+          </div>
+        </div>
+
+        <div class="filter-panel-footer">
+          <div class="filter-confirm-btn" @click.stop="applyFilters">确定</div>
+        </div>
+      </div>
+
+      <div class="supplier-time" v-for="(supplier, idx) in filteredData" :key="idx">
         <div class="supplier-data">
           <div class="supplier-name">
             商户名称
@@ -51,6 +140,12 @@
           </div>
         </div>
       </div>
+
+      <!-- 空状态 -->
+      <div class="empty-state" v-if="filteredData.length === 0">
+        <span class="empty-text">暂无符合条件的商户</span>
+      </div>
+
       <div class="btn-edit-del">
         <div class="btn-del" @click.stop="$parent.$parent.onDeleleItem(index)">删除</div>
       </div>
@@ -61,13 +156,180 @@
 <script>
 export default {
   data() {
-    return {};
+    return {
+      showSortDropdown: false,
+      showCategoryDropdown: false,
+      showFilterPanel: false,
+      currentSort: 0,
+      currentCategory: 0,
+      selectedDistance: -1,
+      selectedPrice: -1,
+      selectedScore: -1,
+      showCouponOnly: false,
+      showTopRanked: false,
+      sortOptions: [],
+      categoryOptions: [],
+      distanceOptions: [],
+      priceOptions: [],
+      scoreOptions: []
+    };
   },
   created() {
     console.log(this.item)
   },
   props: ['item', 'index', 'selectedIndex'],
-  methods: {}
+  computed: {
+    filteredData() {
+      let data = [...(this.item.data || [])];
+
+      // 分类筛选
+      if (this.categoryOptions[this.currentCategory] && this.categoryOptions[this.currentCategory].category_id > 0) {
+        const categoryId = this.categoryOptions[this.currentCategory].category_id;
+        data = data.filter(supplier => supplier.category_id === categoryId);
+      }
+
+      // 筛选条件
+      data = data.filter(supplier => {
+        // 距离筛选
+        if (this.selectedDistance >= 0) {
+          const distance = this.parseDistance(supplier.distance);
+          if (distance > this.distanceOptions[this.selectedDistance].value) {
+            return false;
+          }
+        }
+
+        // 价格筛选
+        if (this.selectedPrice >= 0) {
+          const price = supplier.average_price || 0;
+          const range = this.priceOptions[this.selectedPrice].value;
+          if (range.max === -1) {
+            if (price < range.min) return false;
+          } else {
+            if (price < range.min || price >= range.max) return false;
+          }
+        }
+
+        // 评分筛选
+        if (this.selectedScore >= 0) {
+          const score = parseFloat(supplier.server_score) || 0;
+          if (score < this.scoreOptions[this.selectedScore].value) {
+            return false;
+          }
+        }
+
+        // 仅看有券
+        if (this.showCouponOnly && (!supplier.max_reduce_price || supplier.max_reduce_price <= 0)) {
+          return false;
+        }
+
+        // 好评榜前10
+        if (this.showTopRanked && (!supplier.ranking || supplier.ranking > 10)) {
+          return false;
+        }
+
+        return true;
+      });
+
+      // 排序
+      const sortType = this.sortOptions[this.currentSort] ? this.sortOptions[this.currentSort].value : 'smart';
+      data.sort((a, b) => {
+        switch (sortType) {
+          case 'distance':
+            return this.parseDistance(a.distance) - this.parseDistance(b.distance);
+          case 'score':
+            return parseFloat(b.server_score) - parseFloat(a.server_score);
+          case 'price_low':
+            return (a.average_price || 0) - (b.average_price || 0);
+          case 'price_high':
+            return (b.average_price || 0) - (a.average_price || 0);
+          default:
+            return 0;
+        }
+      });
+
+      return data;
+    },
+    hasActiveFilters() {
+      return this.currentCategory > 0 ||
+             this.selectedDistance >= 0 ||
+             this.selectedPrice >= 0 ||
+             this.selectedScore >= 0 ||
+             this.showCouponOnly ||
+             this.showTopRanked;
+    }
+  },
+  methods: {
+    // 获取筛选条件
+    getFilterCondition() {
+      this.$http.get('/supplier/index/getGroupBuyCondition').then(res => {
+        this.sortOptions = res.data.sortOptions || [];
+        this.categoryOptions = res.data.category || [];
+        this.distanceOptions = res.data.distanceOptions || [];
+        this.priceOptions = res.data.priceOptions || [];
+        this.scoreOptions = res.data.scoreOptions || [];
+      }).catch(err => {
+        console.error('获取筛选条件失败', err);
+      });
+    },
+    toggleSort() {
+      this.showSortDropdown = !this.showSortDropdown;
+      this.showCategoryDropdown = false;
+      this.showFilterPanel = false;
+    },
+    toggleCategory() {
+      this.showCategoryDropdown = !this.showCategoryDropdown;
+      this.showSortDropdown = false;
+      this.showFilterPanel = false;
+    },
+    toggleFilter() {
+      this.showFilterPanel = !this.showFilterPanel;
+      this.showSortDropdown = false;
+      this.showCategoryDropdown = false;
+    },
+    closeAllDropdowns() {
+      this.showSortDropdown = false;
+      this.showCategoryDropdown = false;
+      this.showFilterPanel = false;
+    },
+    selectCategory(index) {
+      this.currentCategory = index;
+      this.showCategoryDropdown = false;
+    },
+    selectSort(index) {
+      this.currentSort = index;
+      this.showSortDropdown = false;
+    },
+    selectDistance(index) {
+      this.selectedDistance = this.selectedDistance === index ? -1 : index;
+    },
+    selectPrice(index) {
+      this.selectedPrice = this.selectedPrice === index ? -1 : index;
+    },
+    selectScore(index) {
+      this.selectedScore = this.selectedScore === index ? -1 : index;
+    },
+    toggleCouponOnly() {
+      this.showCouponOnly = !this.showCouponOnly;
+    },
+    toggleTopRanked() {
+      this.showTopRanked = !this.showTopRanked;
+    },
+    resetFilters() {
+      this.selectedDistance = -1;
+      this.selectedPrice = -1;
+      this.selectedScore = -1;
+      this.showCouponOnly = false;
+      this.showTopRanked = false;
+    },
+    applyFilters() {
+      this.showFilterPanel = false;
+    },
+    parseDistance(distanceStr) {
+      if (!distanceStr) return 99999;
+      const match = distanceStr.match(/(\d+\.?\d*)/);
+      return match ? parseFloat(match[1]) : 99999;
+    }
+  }
 };
 </script>
 
@@ -75,6 +337,222 @@
 .supplier{
   padding: 12px;
 }
+
+/* 筛选栏 */
+.supplier-set{
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 10px;
+}
+
+.filter-item {
+  display: flex;
+  align-items: center;
+  gap: 5px;
+  padding: 6px 12px;
+  background: #f8f8f8;
+  border-radius: 15px;
+  font-size: 14px;
+  color: #333;
+  cursor: pointer;
+  border-left: none;
+  width: auto;
+  text-align: center;
+}
+
+.filter-text {
+  font-size: 14px;
+  color: #333;
+}
+
+.filter-icon {
+  font-size: 10px;
+  color: #999;
+  transition: transform 0.3s;
+}
+
+.filter-icon.rotate {
+  transform: rotate(180deg);
+}
+
+.filter-badge {
+  width: 8px;
+  height: 8px;
+  background: #c73a4e;
+  border-radius: 50%;
+  font-size: 0;
+}
+
+/* 排序下拉面板 */
+.sort-dropdown,
+.category-dropdown {
+  position: absolute;
+  top: 60px;
+  z-index: 200;
+  width: 150px;
+  background: #ffffff;
+  border-radius: 8px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  overflow: hidden;
+}
+
+.sort-dropdown {
+  left: 12px;
+}
+
+.category-dropdown {
+  left: 172px;
+}
+
+.sort-option {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 12px 15px;
+  border-bottom: 1px solid #f5f5f5;
+  cursor: pointer;
+}
+
+.sort-option:last-child {
+  border-bottom: none;
+}
+
+.sort-option:hover {
+  background: #f8f8f8;
+}
+
+.sort-option-text {
+  font-size: 14px;
+  color: #333;
+}
+
+.sort-option-text.active {
+  color: #c73a4e;
+  font-weight: bold;
+}
+
+.sort-option-check {
+  color: #c73a4e;
+  font-size: 14px;
+  font-weight: bold;
+}
+
+/* 遮罩层 */
+.mask {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  z-index: 150;
+}
+
+/* 筛选面板 */
+.filter-panel {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  z-index: 200;
+  background: #ffffff;
+  border-radius: 16px 16px 0 0;
+  max-height: 400px;
+  overflow-y: auto;
+}
+
+.filter-panel-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px 12px;
+  border-bottom: 1px solid #f5f5f5;
+}
+
+.filter-panel-title {
+  font-size: 16px;
+  font-weight: bold;
+  color: #333;
+}
+
+.filter-reset {
+  font-size: 14px;
+  color: #999;
+  cursor: pointer;
+}
+
+.filter-section {
+  padding: 15px 12px;
+  border-bottom: 1px solid #f5f5f5;
+}
+
+.filter-section-title {
+  font-size: 14px;
+  font-weight: bold;
+  color: #333;
+  margin-bottom: 10px;
+}
+
+.filter-tags {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+
+.filter-tag {
+  padding: 8px 16px;
+  background: #f8f8f8;
+  border-radius: 4px;
+  font-size: 13px;
+  color: #666;
+  white-space: nowrap;
+  cursor: pointer;
+}
+
+.filter-tag.active {
+  background: #fff5f6;
+  color: #c73a4e;
+  border: 1px solid #c73a4e;
+}
+
+.filter-panel-footer {
+  padding: 12px;
+  border-top: 1px solid #f5f5f5;
+}
+
+.filter-confirm-btn {
+  width: 100%;
+  height: 44px;
+  background: linear-gradient(to right, #c73a4e, #e74c3c);
+  border-radius: 22px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #ffffff;
+  font-size: 16px;
+  font-weight: bold;
+  cursor: pointer;
+}
+
+.filter-confirm-btn:hover {
+  opacity: 0.9;
+}
+
+/* 空状态 */
+.empty-state {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  padding: 50px 0;
+}
+
+.empty-text {
+  font-size: 14px;
+  color: #999;
+}
 .supplier-time{
   background: #ffff;
   margin-bottom: 10px;

--
Gitblit v1.9.2