更新:更多活动页面的排序,筛选逻辑,其他页面的游客权限判定

This commit is contained in:
davy 2025-04-03 02:20:07 +08:00
parent ce08b6819b
commit 4466afd8a1
7 changed files with 465 additions and 114 deletions

View File

@ -19,11 +19,22 @@ const publicApis = [
'/bar/brewery/getBeerInfo', // 获取酒款信息
'/bar/brewery/getReviewList', // 获取酒评列表
'/bar/brewery/getReviewScoreList', // 获取酒评评分列表
'/bar/brewery/getActivities', // 获取活动列表
'/bar/brewery/getActivityInfo', // 获取活动详情
'/bar/brewery/getBreweryInfo', // 获取品牌详情
]
// 检查是否是公开API
const isPublicApi = (url) => {
return publicApis.some(api => url.includes(api))
// 使用更精确的匹配方式
return publicApis.some(api => {
// 如果是完整路径匹配
if (api.includes('/')) {
return url.includes(api);
}
// 如果是通配符匹配
return url.split('/').includes(api);
});
}
export default (params) => {

244
components/brandFilter.vue Normal file
View File

@ -0,0 +1,244 @@
<template>
<view class="brand-filter-popup" v-if="show">
<view class="mask" @click="close"></view>
<view class="content">
<view class="page-content">
<!-- 标题区域 -->
<view class="section">
<view class="section-title">
筛选品牌
<view class="close-btn" @click="close">
<text class="cuIcon-close"></text>
</view>
</view>
</view>
<!-- 品牌列表区域 -->
<view class="section brand-list-section">
<scroll-view scroll-y="true" class="brand-list">
<!-- 全部选项 -->
<view class="brand-item" @tap="selectAll">
<view class="item-content" :class="{'selected': isAllSelected}">
<text>全部</text>
</view>
</view>
<!-- 品牌列表 -->
<view class="brand-item"
v-for="(item, index) in brandList"
:key="index"
@tap="selectBrand(item)">
<view class="item-content" :class="{'selected': selectedBrand === item.id}">
<text class="brand-name">{{item.name}}</text>
</view>
</view>
</scroll-view>
</view>
<!-- 底部按钮 -->
<view class="button-group">
<view class="reset-btn" @click="reset">重置</view>
<view class="save-btn" @click="confirm">确定</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'brand-filter',
data() {
return {
show: false,
brandList: [],
selectedBrand: null,
isAllSelected: true
}
},
methods: {
open() {
this.show = true;
},
close() {
this.show = false;
},
selectAll() {
this.isAllSelected = true;
this.selectedBrand = null;
this.$emit('confirm', {
id: null,
name: '全部'
});
this.close();
},
selectBrand(brand) {
this.selectedBrand = brand.id;
this.isAllSelected = false;
this.$emit('confirm', {
id: brand.id,
name: brand.name
});
this.close();
},
reset() {
this.selectAll();
},
confirm() {
this.$emit('confirm', {
id: this.selectedBrand,
name: this.selectedBrand ? this.brandList.find(b => b.id === this.selectedBrand)?.name : '全部'
});
this.close();
},
//
extractBrandsFromList(listData) {
if (!Array.isArray(listData) || listData.length === 0) {
return;
}
// 使Set
const brandSet = new Set();
const brands = [];
listData.forEach(item => {
if (item.breweryId && !brandSet.has(item.breweryId)) {
brandSet.add(item.breweryId);
brands.push({
id: item.breweryId,
name: item.breweryName || '未知品牌'
});
}
});
//
this.brandList = brands.sort((a, b) => a.name.localeCompare(b.name));
}
}
}
</script>
<style lang="scss" scoped>
.brand-filter-popup {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 999;
.mask {
position: absolute;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.4);
}
.content {
position: absolute;
bottom: 0;
width: 100%;
background: #F7F7F7;
border-radius: 32rpx 32rpx 0 0;
.page-content {
padding: 24rpx 32rpx;
.section {
background: #FFFFFF;
border-radius: 16rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.section-title {
font-size: 32rpx;
font-weight: 600;
padding: 32rpx;
color: #333333;
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
&::after {
content: '';
position: absolute;
left: 32rpx;
bottom: 0;
width: 48rpx;
height: 4rpx;
background: #19367A;
border-radius: 2rpx;
}
.close-btn {
font-size: 36rpx;
color: #999999;
padding: 10rpx;
}
}
}
.brand-list-section {
.brand-list {
max-height: 60vh;
padding: 24rpx;
.brand-item {
margin-bottom: 24rpx;
.item-content {
padding: 24rpx;
background: #F7F7F7;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s;
&.selected {
background: rgba(25, 54, 122, 0.05);
border: 2rpx solid #19367A;
}
.brand-name {
font-size: 28rpx;
color: #333333;
text-align: center;
}
}
}
}
}
.button-group {
display: flex;
justify-content: space-between;
gap: 24rpx;
.reset-btn, .save-btn {
flex: 1;
height: 88rpx;
border-radius: 44rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
font-weight: 500;
}
.reset-btn {
background: #F7F7F7;
color: #666666;
border: 2rpx solid #E5E5E5;
}
.save-btn {
background: #19367A;
color: #FFFFFF;
}
}
}
}
}
</style>

View File

@ -406,6 +406,12 @@
"network": "all",
"packages": ["pagesActivity","pagesCoin","pagesMy"]
}
}
},
"easycom": {
"autoscan": true,
"custom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue",
"^brand-filter": "@/components/brandFilter.vue"
}
}
}

View File

@ -6,15 +6,15 @@
<view class="tabs-content">
<view
class="tab-item"
:class="{'active-tag': queryForm.orderBy == 'create_time'}"
@click="changeOrder('create_time')"
:class="{'active-tag': queryForm.orderType == 'latest'}"
@click="changeOrder('latest')"
>最新发布</view>
<view
class="tab-item"
:class="{'active-tag': queryForm.orderBy == 'popularity'}"
:class="{'active-tag': queryForm.orderType == 'popularity'}"
@click="changeOrder('popularity')"
>人气排名</view>
<view class="brand-filter" :class="{ active: isFilterActive }" @click="showBrandFilter">
<view class="brand-filter" :class="{ active: selectedBrand !== null }" @click="showBrandFilter">
<text>筛选品牌</text>
<image :src="'/static/icons/filter.svg'" mode="aspectFit" class="filter-icon"></image>
</view>
@ -64,6 +64,8 @@
</scroll-view>
</view>
<loginPopup ref="loginRef"></loginPopup>
<!-- 品牌筛选组件 -->
<brand-filter ref="brandFilterRef" @confirm="onBrandFilterConfirm"></brand-filter>
</view>
</view>
</template>
@ -72,36 +74,96 @@
import {
getActivities
} from '@/api/bar.js'
import loginPopup from '@/components/loginPopup.vue';
import loginPopup from '@/components/loginPopup.vue'
import brandFilter from '@/components/brandFilter.vue'
export default {
components: {
loginPopup
loginPopup,
brandFilter
},
data() {
return {
activeList: [], //
loading: false,
isRefreshing: false, //
isRefreshing: false,
queryForm: {
pageNum: 1,
pageSize: 5,
orderBy: 'create_time' //
orderType: 'latest',
},
total: 0,
isFilterActive: false //
isFilterActive: false,
userLocation: null,
isLocationReady: false, //
originalList: [], //
selectedBrand: null, // ID
};
},
onLoad() {
//
this.getActivitiesFun()
//
this.getActivitiesFun();
//
this.getUserLocation();
},
methods: {
//
getUserLocation() {
uni.getLocation({
type: 'gcj02',
success: (res) => {
this.userLocation = {
latitude: res.latitude,
longitude: res.longitude
};
this.isLocationReady = true;
//
this.filterListByLocation();
},
fail: (err) => {
console.error('获取位置失败:', err);
this.isLocationReady = true;
uni.showToast({
title: '未获取到位置信息,将显示所有活动',
icon: 'none',
duration: 2000
});
}
});
},
//
filterListByLocation() {
if (this.originalList.length > 0) {
this.activeList = this.originalList.filter(item => this.isActivityInUserCity(item.city));
}
},
//
isActivityInUserCity(activityCity) {
if (!this.userLocation) return false;
try {
const cityList = JSON.parse(activityCity);
//
return true; // true
} catch (e) {
return false;
}
},
//
changeOrder(key) {
if (this.queryForm.orderBy === key) return;
this.queryForm.orderBy = key;
changeOrder(type) {
//
if (this.queryForm.orderType === type) return;
//
this.queryForm.orderType = type;
//
this.queryForm.pageNum = 1;
this.activeList = [];
//
this.getActivitiesFun();
},
@ -115,35 +177,75 @@
//
toDetail(item) {
if (!uni.getStorageSync('token')) {
this.$refs.loginRef.open()
return
}
uni.navigateTo({
url: "/pagesActivity/activityDetail?id=" + item.id
})
});
},
//
toReview(it) {
uni.navigateTo({
url: "/pages/index/review?beerId=" + it.id
});
},
//
getActivitiesFun() {
this.loading = true;
getActivities(this.queryForm).then(res => {
const params = {
pageNum: this.queryForm.pageNum,
pageSize: this.queryForm.pageSize
};
//
if (this.selectedBrand) {
params.breweryId = this.selectedBrand;
} else {
//
params.orderBy = this.queryForm.orderType === 'latest' ? 'start_date' : 'popularity';
params.order = 'desc';
}
getActivities(params).then(res => {
this.total = res.total;
if(res.rows && res.rows.length > 0) {
let arr = res.rows.map(it => {
it.remainingDays = this.getRemainingDays(it.endDate);
return it;
});
//
// (2,3)(4)(0)
arr = arr.filter(item => item.stage === 1);
//
if (this.selectedBrand) {
arr = arr.filter(item => item.breweryId === this.selectedBrand);
}
//
this.originalList = arr;
//
if (this.isLocationReady && this.userLocation) {
arr = arr.filter(item => this.isActivityInUserCity(item.city));
}
//
if (this.queryForm.pageNum === 1) {
this.activeList = arr;
} else {
//
this.activeList = [...this.activeList, ...arr];
}
} else {
if (this.queryForm.pageNum === 1) {
this.activeList = [];
this.originalList = [];
}
}
this.loading = false;
}).catch(err => {
console.error('获取活动列表失败:', err);
this.loading = false;
});
},
@ -159,8 +261,25 @@
//
showBrandFilter() {
this.isFilterActive = !this.isFilterActive;
//
//
if (!this.originalList || this.originalList.length === 0) {
this.queryForm.pageNum = 1;
this.getActivitiesFun().then(() => {
this.$refs.brandFilterRef.extractBrandsFromList(this.originalList);
this.$refs.brandFilterRef.open();
});
} else {
this.$refs.brandFilterRef.extractBrandsFromList(this.originalList);
this.$refs.brandFilterRef.open();
}
},
//
onBrandFilterConfirm(result) {
this.selectedBrand = result.id;
this.queryForm.pageNum = 1;
this.activeList = [];
this.getActivitiesFun();
},
//
@ -171,19 +290,7 @@
this.activeList = [];
//
getActivities(this.queryForm).then(res => {
this.total = res.total;
if(res.rows && res.rows.length > 0) {
let arr = res.rows.map(it => {
it.remainingDays = this.getRemainingDays(it.endDate);
return it;
});
this.activeList = arr;
}
this.isRefreshing = false;
}).catch(err => {
this.isRefreshing = false;
});
this.getActivitiesFun();
}
}
}

View File

@ -110,7 +110,7 @@
</view>
</view>
<view class="cu-load" style="height: 88rpx;"></view>
<view class="more-btn-box" @click="moreClick">
<view class="more-btn-box" @click="moreHotActivity">
<view class="more-btn">更多热门活动招募</view>
</view>
</scroll-view>
@ -296,10 +296,6 @@
})
},
toGo(key) {
//
const token = uni.getStorageSync('token')
const userInfo = uni.getStorageSync('userInfo')
switch (key) {
case 1: //
uni.navigateTo({
@ -307,80 +303,29 @@
})
break;
case 2: //
if (!token || !userInfo) {
this.$refs.loginRef.open()
return
}
if (!userInfo.barId) {
uni.showModal({
title: '提示',
content: '您还未认证门店,请先完成认证',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
return
}
uni.navigateTo({
url: "/pagesActivity/winelist"
})
break;
case 3: //
if (!token || !userInfo) {
this.$refs.loginRef.open()
return
}
if (!userInfo.barId) {
uni.showModal({
title: '提示',
content: '您还未认证门店,请先完成认证',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
return
}
uni.navigateTo({
url: "/pagesCoin/beerCoin"
})
break;
case 4: //
if (!token || !userInfo) {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
if (!userInfo.barId) {
uni.showModal({
title: '提示',
content: '您还未认证门店,请先完成认证',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
return
}
uni.navigateTo({
url: '/pagesMy/myAttention'
})
break;
}
},
moreClick() {
//
moreHotActivity() {
uni.navigateTo({
url: "/pages/activityList/activityList"
})

View File

@ -267,13 +267,15 @@
isFavor: false, //
};
},
onLoad({
beerId
}) {
onLoad({beerId}) {
this.beerId = beerId
this.queryForm.beerId = beerId
this.getBeerInfoFun()
this.getBeerFavorStatusFun() //
//
const token = uni.getStorageSync('token')
if (token) {
this.getBeerFavorStatusFun()
}
},
onShow() {
console.log('show')
@ -281,7 +283,9 @@
this.queryForm.pageNum = 1
this.getReviewListFun()
this.getReviewScoreListFun()
if (uni.getStorageSync('token')) {
//
const token = uni.getStorageSync('token')
if (token) {
this.getMyReviewInfoFun()
}
//
@ -298,6 +302,11 @@
},
//
getBeerFavorStatusFun() {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
getBeerFavorStatus(this.beerId).then(res => {
if(res.data) {
this.isFavor = true
@ -349,13 +358,19 @@
},
//
getMyReviewInfoFun() {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
getMyReviewInfo(this.beerId).then(res => {
this.myReviewInfo = res.data
})
},
//
toWrite() {
if (!uni.getStorageSync('token')) {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
@ -378,7 +393,8 @@
},
//
favorBeerFun(status) {
if (!uni.getStorageSync('token')) {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
@ -403,7 +419,8 @@
},
//
handleLike(item) {
if (!uni.getStorageSync('token')) {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
@ -425,16 +442,12 @@
})
item.reviewLike = false
}
// this.reviewList = []
// this.queryForm.pageNum = 1
// this.getReviewListFun()
})
},
//
toWinelist() {
if (!uni.getStorageSync('token')) {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}

View File

@ -216,6 +216,31 @@
return
}
//
const token = uni.getStorageSync('token')
const isAuth = uni.getStorageSync('isAuth')
if (!token) {
this.$refs.loginRef.open()
return
}
if (!isAuth) {
uni.showModal({
title: '提示',
content: '您还未认证门店,请先完成认证',
confirmText: '去认证',
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pagesActivity/barAuth'
})
}
}
})
return
}
if (this.currentStep < 3) {
this.currentStep++
}