Compare commits

...

2 Commits

7 changed files with 480 additions and 120 deletions

View File

@ -8,16 +8,33 @@ let showModal = false
const publicApis = [ const publicApis = [
'/beer/list', // 啤酒列表 '/beer/list', // 啤酒列表
'/beer/detail', // 啤酒详情 '/beer/detail', // 啤酒详情
'/beer/favor/status', // 收藏状态
'/beer/review/score', // 评分
'/beer/review/list', // 评价列表
'/activity/list', // 活动列表 '/activity/list', // 活动列表
'/activity/detail', // 活动详情 '/activity/detail', // 活动详情
'/bar/detail', // 酒吧详情 '/bar/detail', // 酒吧详情
'/bar/list', // 酒吧列表 '/bar/list', // 酒吧列表
'/common/', // 公共接口 '/common/', // 公共接口
'/bar/brewery/getBeerInfo', // 获取酒款信息
'/bar/brewery/getReviewList', // 获取酒评列表
'/bar/brewery/getReviewScoreList', // 获取酒评评分列表
'/bar/brewery/getActivities', // 获取活动列表
'/bar/brewery/getActivityInfo', // 获取活动详情
'/bar/brewery/getBreweryInfo', // 获取品牌详情
] ]
// 检查是否是公开API // 检查是否是公开API
const isPublicApi = (url) => { 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) => { export default (params) => {
@ -56,7 +73,7 @@ export default (params) => {
showModal = true showModal = true
uni.showModal({ uni.showModal({
title: "提示", title: "提示",
content: "身份已过期,请重新登录", content: res.data.msg || "身份已过期,请重新登录",
showCancel: false, showCancel: false,
success() { success() {
showModal = false showModal = false
@ -66,11 +83,14 @@ export default (params) => {
}, },
}); });
} else { } else {
// 对于公开接口的401错误不显示错误提示
if (!isPublicApi(url)) {
uni.showToast({ uni.showToast({
title: res.data.msg || '请求失败', title: res.data.msg || '请求失败',
icon: 'none', icon: 'none',
duration: 3000, duration: 3000,
}) })
}
reject(res.data) reject(res.data)
} }

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", "network": "all",
"packages": ["pagesActivity","pagesCoin","pagesMy"] "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="tabs-content">
<view <view
class="tab-item" class="tab-item"
:class="{'active-tag': queryForm.orderBy == 'create_time'}" :class="{'active-tag': queryForm.orderType == 'latest'}"
@click="changeOrder('create_time')" @click="changeOrder('latest')"
>最新发布</view> >最新发布</view>
<view <view
class="tab-item" class="tab-item"
:class="{'active-tag': queryForm.orderBy == 'popularity'}" :class="{'active-tag': queryForm.orderType == 'popularity'}"
@click="changeOrder('popularity')" @click="changeOrder('popularity')"
>人气排名</view> >人气排名</view>
<view class="brand-filter" :class="{ active: isFilterActive }" @click="showBrandFilter"> <view class="brand-filter" :class="{ active: selectedBrand !== null }" @click="showBrandFilter">
<text>筛选品牌</text> <text>筛选品牌</text>
<image :src="'/static/icons/filter.svg'" mode="aspectFit" class="filter-icon"></image> <image :src="'/static/icons/filter.svg'" mode="aspectFit" class="filter-icon"></image>
</view> </view>
@ -64,6 +64,8 @@
</scroll-view> </scroll-view>
</view> </view>
<loginPopup ref="loginRef"></loginPopup> <loginPopup ref="loginRef"></loginPopup>
<!-- 品牌筛选组件 -->
<brand-filter ref="brandFilterRef" @confirm="onBrandFilterConfirm"></brand-filter>
</view> </view>
</view> </view>
</template> </template>
@ -72,36 +74,96 @@
import { import {
getActivities getActivities
} from '@/api/bar.js' } from '@/api/bar.js'
import loginPopup from '@/components/loginPopup.vue'; import loginPopup from '@/components/loginPopup.vue'
import brandFilter from '@/components/brandFilter.vue'
export default { export default {
components: { components: {
loginPopup loginPopup,
brandFilter
}, },
data() { data() {
return { return {
activeList: [], // activeList: [], //
loading: false, loading: false,
isRefreshing: false, // isRefreshing: false,
queryForm: { queryForm: {
pageNum: 1, pageNum: 1,
pageSize: 5, pageSize: 5,
orderBy: 'create_time' // orderType: 'latest',
}, },
total: 0, total: 0,
isFilterActive: false // isFilterActive: false,
userLocation: null,
isLocationReady: false, //
originalList: [], //
selectedBrand: null, // ID
}; };
}, },
onLoad() { onLoad() {
// //
this.getActivitiesFun() this.getActivitiesFun();
//
this.getUserLocation();
}, },
methods: { 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) { changeOrder(type) {
if (this.queryForm.orderBy === key) return; //
this.queryForm.orderBy = key; if (this.queryForm.orderType === type) return;
//
this.queryForm.orderType = type;
//
this.queryForm.pageNum = 1; this.queryForm.pageNum = 1;
this.activeList = []; this.activeList = [];
//
this.getActivitiesFun(); this.getActivitiesFun();
}, },
@ -115,35 +177,75 @@
// //
toDetail(item) { toDetail(item) {
if (!uni.getStorageSync('token')) {
this.$refs.loginRef.open()
return
}
uni.navigateTo({ uni.navigateTo({
url: "/pagesActivity/activityDetail?id=" + item.id url: "/pagesActivity/activityDetail?id=" + item.id
}) });
},
//
toReview(it) {
uni.navigateTo({
url: "/pages/index/review?beerId=" + it.id
});
}, },
// //
getActivitiesFun() { getActivitiesFun() {
this.loading = true; 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; this.total = res.total;
if(res.rows && res.rows.length > 0) { if(res.rows && res.rows.length > 0) {
let arr = res.rows.map(it => { let arr = res.rows.map(it => {
it.remainingDays = this.getRemainingDays(it.endDate); it.remainingDays = this.getRemainingDays(it.endDate);
return it; 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) { if (this.queryForm.pageNum === 1) {
this.activeList = arr; this.activeList = arr;
} else { } else {
//
this.activeList = [...this.activeList, ...arr]; this.activeList = [...this.activeList, ...arr];
} }
} else {
if (this.queryForm.pageNum === 1) {
this.activeList = [];
this.originalList = [];
}
} }
this.loading = false; this.loading = false;
}).catch(err => { }).catch(err => {
console.error('获取活动列表失败:', err);
this.loading = false; this.loading = false;
}); });
}, },
@ -159,8 +261,25 @@
// //
showBrandFilter() { 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 = []; this.activeList = [];
// //
getActivities(this.queryForm).then(res => { this.getActivitiesFun();
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;
});
} }
} }
} }

View File

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

View File

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

View File

@ -216,6 +216,31 @@
return 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) { if (this.currentStep < 3) {
this.currentStep++ this.currentStep++
} }