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