1407 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page flex flex-col">
<!-- 固定搜索框 -->
<view class="fixed-search-box" style="background-color:#19367A;border-radius: 0rpx 0rpx 24rpx 24rpx;">
<view class="search-box">
<image
src="/static/Vector@1x.png"
class="search-icon"
:class="{'rotating': isSearching}"
mode="aspectFit">
</image>
<input
ref="searchInput"
type="text"
v-model="keyword"
placeholder="输入酒款名称,品牌名称,啤酒风格"
@confirm="handleConfirm"
@input="handleInput"
focus>
<text
v-if="keyword"
class="cuIcon-close clear-icon"
@tap="clearKeyword">
</text>
<view
class="searchs"
:class="{'loading': isSearching}"
@tap="search">
<uni-icons
type="search"
size="30"
color="#fff">
</uni-icons>
</view>
</view>
</view>
<!-- 内容区域 -->
<view class="content">
<!-- 搜索历史 -->
<template v-if="(!keyword || keyword.length < 2) && searchHistory.length > 0">
<view class="section-title">
<text class="title">搜索历史</text>
<view class="clear-btn" @tap="clearHistory">
<uni-icons type="trash" size="16" color="#999"></uni-icons>
<text>清空</text>
</view>
</view>
<view class="history-list">
<view
v-for="(item, index) in searchHistory"
:key="index"
class="history-tag"
@tap="useHistoryKeyword(item)">
{{item}}
</view>
</view>
</template>
<!-- 热门啤酒风格 -->
<template v-if="!keyword || keyword.length < 2">
<view class="section-title">
<text class="title">热门啤酒风格</text>
</view>
<view class="style-list">
<view
v-for="(item, index) in popularStyleList"
:key="index"
class="style-item"
@tap="searchByStyle(item)">
<view class="item-content">
<image
src="/static/bg/pc-1.png"
mode="aspectFit">
</image>
<view class="info">
<view class="title">{{ item.beerStyles }}</view>
<view class="sub">全系列{{item.popular}}款产品在售</view>
</view>
<image
src="/static/right-arrow.png"
class="arrow">
</image>
</view>
</view>
</view>
</template>
<!-- 搜索结果 -->
<template v-if="keyword && keyword.length >= 2">
<view class="tag-list">
<view
v-for="(tag, index) in searchTags"
:key="index"
class="text-sm tag"
:class="{'active-tag': curTag === index}"
@tap="changeTag(index)">
{{tag.name}}
</view>
</view>
<!-- 最佳匹配 -->
<template v-if="curTag === 0">
<scroll-view
v-if="commonBeer.length > 0 || commonBreweries.length > 0"
scroll-y="true"
class="my-brandSide"
@scrolltolower="loadMore">
<!-- 酒款列表 -->
<view
v-for="(item, index) in commonBeer"
:key="index"
class="brandSide-box"
@tap="toBeer(item)">
<view class="flex align-center justify-start">
<image
:src="item.cover"
class="beerCover"
mode="aspectFill"
lazy-load>
</image>
<view class="info">
<view class="title">{{ item.beerName }}</view>
<view class="desc">{{item.beerStyles}}</view>
<view class="brewery-info">
<image
:src="item.brandLogo || '/static/default-brewery.png'"
class="brewery-logo"
mode="aspectFill">
</image>
<text class="brewery-name">{{item.brandName}}</text>
</view>
</view>
</view>
<view class="rating">
{{ item.beerOverallRating || 0 }}
<text class="cuIcon-favorfill star"></text>
</view>
</view>
<!-- 酒厂列表 -->
<view
v-for="(item, index) in commonBreweries"
:key="index"
class="brandSide-box brewery-item"
@tap="toBrand(item)">
<view class="flex align-center justify-start">
<image
:src="item.brandLogo || '/static/default-brewery.png'"
class="logo"
mode="aspectFill"
lazy-load>
</image>
<view class="info">
<view class="title">{{ item.brandName }}</view>
<view class="desc">全系列{{item.productCount || 'XXX'}}款产品在售</view>
</view>
</view>
<view class="arrow-container">
<image
src="/static/right-arrow.png"
class="arrow"
mode="aspectFit">
</image>
</view>
</view>
<!-- 加载更多 -->
<view v-if="hasMore" class="loading-more">
<text>加载中...</text>
</view>
<!-- 添加引导提示 -->
<view v-if="!hasMore && (commonBeer.length > 0 || commonBreweries.length > 0)" class="guide-tip">
<text>没找到想要的酒款</text>
<view class="add-btn" @tap="toNewBeer">
<text>添加新酒款</text>
<uni-icons type="plus" size="12" color="#19367A"></uni-icons>
</view>
</view>
</scroll-view>
<!-- 空状态 -->
<view v-else class="empty-state">
<image
src="@/static/wenhao.png"
mode="aspectFit"
class="empty-image">
</image>
<view class="empty-content">
<view class="empty-text">
<text class="main-text">未找到相关酒款</text>
<text class="sub-text">换个关键词试试或者添加新酒款</text>
</view>
<view class="request-btn" @tap="toNewBeer">
<text>添加新酒款</text>
<uni-icons type="plus" size="16" color="#FFFFFF"></uni-icons>
</view>
</view>
</view>
</template>
<!-- 酒款列表 -->
<template v-if="curTag === 1">
<scroll-view
v-if="beers.length > 0"
scroll-y="true"
class="my-brandSide"
@scrolltolower="loadMore">
<view
v-for="(item, index) in beers"
:key="index"
class="brandSide-box"
@tap="toBeer(item)">
<view class="flex align-center justify-start">
<image
:src="item.cover"
class="beerCover"
mode="aspectFill"
lazy-load>
</image>
<view class="info">
<view class="title">{{ item.beerName }}</view>
<view class="desc">{{item.beerStyles}}</view>
<view class="brewery-info">
<image
:src="item.brandLogo || '/static/default-brewery.png'"
class="brewery-logo"
mode="aspectFill">
</image>
<text class="brewery-name">{{item.brandName}}</text>
</view>
</view>
</view>
<view class="rating">
{{ item.beerOverallRating || 0 }}
<text class="cuIcon-favorfill star"></text>
</view>
</view>
<!-- 加载更多 -->
<view v-if="hasMore" class="loading-more">
<text>加载中...</text>
</view>
<!-- 添加引导提示 -->
<view v-if="!hasMore && beers.length > 0" class="guide-tip">
<text>没找到想要的酒款</text>
<view class="add-btn" @tap="toNewBeer">
<text>添加新酒款</text>
<uni-icons type="plus" size="12" color="#19367A"></uni-icons>
</view>
</view>
</scroll-view>
<!-- 空状态 -->
<view v-else class="empty-state">
<image
src="@/static/wenhao.png"
mode="aspectFit"
class="empty-image">
</image>
<view class="empty-content">
<view class="empty-text">
<text class="main-text">未找到相关酒款</text>
<text class="sub-text">换个关键词试试或者添加新酒款</text>
</view>
<view class="request-btn" @tap="toNewBeer">
<text>添加新酒款</text>
<uni-icons type="plus" size="16" color="#FFFFFF"></uni-icons>
</view>
</view>
</view>
</template>
<!-- 厂牌列表 -->
<template v-if="curTag === 2">
<scroll-view
v-if="breweries.length > 0"
scroll-y="true"
class="my-brandSide brewery-list"
@scrolltolower="loadMore">
<view
v-for="(item, index) in breweries"
:key="index"
class="brandSide-box brewery-item"
@tap="toBrand(item)">
<view class="flex align-center justify-start">
<image
:src="item.brandLogo || '/static/default-brewery.png'"
class="logo"
mode="aspectFill"
lazy-load>
</image>
<view class="info">
<view class="title">{{ item.brandName }}</view>
<view class="desc">全系列{{item.productCount || 'XXX'}}款产品在售</view>
</view>
</view>
<view class="arrow-container">
<image
src="/static/right-arrow.png"
class="arrow"
mode="aspectFit">
</image>
</view>
</view>
<!-- 加载更多 -->
<view v-if="hasMore" class="loading-more">
<text>加载中...</text>
</view>
<!-- 添加引导提示 -->
<view v-if="!hasMore && breweries.length > 0" class="guide-tip">
<text>没找到想要的酒款</text>
<view class="add-btn" @tap="toNewBeer">
<text>添加新酒款</text>
<uni-icons type="plus" size="12" color="#19367A"></uni-icons>
</view>
</view>
</scroll-view>
<!-- 空状态 -->
<view v-else class="empty-state">
<image
src="@/static/wenhao.png"
mode="aspectFit"
class="empty-image">
</image>
<view class="empty-content">
<view class="empty-text">
<text class="main-text">未找到相关酒款</text>
<text class="sub-text">换个关键词试试或者添加新酒款</text>
</view>
<view class="request-btn" @tap="toNewBeer">
<text>添加新酒款</text>
<uni-icons type="plus" size="16" color="#FFFFFF"></uni-icons>
</view>
</view>
</view>
</template>
</template>
</view>
</view>
</template>
<script>
import {
commonSearch,
popularStyle,
getBeerByStyle,
searchByBreweriesApi,
getBeerList
} from "@/api/platform.js"
export default {
components: {
},
data() {
return {
keyword: '',
popularStyleList: [],
curTag: 0,
breweries: [], // 酒厂列表
beers: [], // 酒款列表
commonBeer:[],
commonBreweries:[],
searchHistory: [], // 搜索历史
isSearching: false, // 搜索状态
currentPage: 1, // 当前页码
pageSize: 10, // 每页数量
hasMore: false, // 是否有更多数据
timer: null, // 搜索防抖定时器
searchTags: [
{ name: '最佳匹配', type: 'all' },
{ name: '酒款', type: 'beer' },
{ name: '厂牌', type: 'brewery' }
]
};
},
onLoad() {
this.getPopularStyle()
this.loadSearchHistory()
// 监听键盘打开事件
uni.$on('openKeyboard', () => {
if (this.$refs.searchInput) {
this.$refs.searchInput.focus()
}
})
},
onUnload() {
// 移除事件监听
uni.$off('openKeyboard')
},
methods: {
// 加载搜索历史
loadSearchHistory() {
const history = uni.getStorageSync('searchHistory')
this.searchHistory = history ? JSON.parse(history) : []
},
// 保存搜索历史
saveSearchHistory(keyword) {
if (!keyword) return
let history = this.searchHistory
// 移除重复项
history = history.filter(item => item !== keyword)
// 添加到开头
history.unshift(keyword)
// 最多保存8条
history = history.slice(0, 8)
this.searchHistory = history
uni.setStorageSync('searchHistory', JSON.stringify(history))
},
// 清空搜索历史
clearHistory() {
this.searchHistory = []
uni.removeStorageSync('searchHistory')
},
// 使用历史搜索词
useHistoryKeyword(keyword) {
this.keyword = keyword
this.search()
},
// 清空搜索框
clearKeyword() {
this.keyword = '';
this.isSearching = false;
this.clearSearchResults();
},
// 输入框变化
handleInput(e) {
// 清除之前的定时器
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
// 如果输入长度小于2直接返回并清空搜索状态
if (!this.keyword || this.keyword.length < 2) {
this.isSearching = false;
return;
}
// 设置新的定时器只有当输入长度大于等于2时才触发搜索
this.timer = setTimeout(() => {
const trimmedKeyword = this.keyword.trim();
if (trimmedKeyword && trimmedKeyword.length >= 2) {
this.search();
}
}, 500);
},
// 输入确认(回车键)
handleConfirm() {
if (!this.keyword || this.keyword.length < 2) {
uni.showToast({
title: '请至少输入2个字符',
icon: 'none'
});
return;
}
this.search();
},
// 搜索
async search() {
if (!this.keyword || this.keyword.length < 2) {
this.isSearching = false;
return;
}
const trimmedKeyword = this.keyword.trim();
if (!trimmedKeyword || trimmedKeyword.length < 2) {
this.isSearching = false;
return;
}
this.isSearching = true;
this.currentPage = 1;
try {
// 保存搜索历史
this.saveSearchHistory(trimmedKeyword);
// 根据当前标签搜索
await this.searchByTag();
} catch (error) {
console.error('搜索失败:', error);
if (error.statusCode === 400) {
uni.showToast({
title: '搜索参数错误,请重试',
icon: 'none'
});
} else if (error.statusCode === 500) {
uni.showToast({
title: '服务器错误,请稍后重试',
icon: 'none'
});
} else {
uni.showToast({
title: '搜索失败,请检查网络连接',
icon: 'none'
});
}
this.clearSearchResults();
} finally {
this.isSearching = false;
}
},
// 清空搜索结果
clearSearchResults() {
this.commonBeer = [];
this.commonBreweries = [];
this.beers = [];
this.breweries = [];
this.hasMore = false;
},
// 根据标签搜索
async searchByTag() {
const tag = this.searchTags[this.curTag]
switch (tag.type) {
case 'all':
await this.searchAll()
break
case 'beer':
await this.searchBeers()
break
case 'brewery':
await this.searchBreweries()
break
}
},
// 搜索全部
async searchAll() {
try {
const res = await commonSearch(this.keyword.trim())
if (!res || res.code !== 200) {
throw new Error('搜索结果为空')
}
// 直接使用返回的数据结构
if (this.currentPage === 1) {
this.commonBeer = res.data.beers || []
this.commonBreweries = res.data.breweries || []
} else {
this.commonBeer = [...this.commonBeer, ...(res.data.beers || [])]
this.commonBreweries = [...this.commonBreweries, ...(res.data.breweries || [])]
}
// 根据返回的数据长度判断是否还有更多
this.hasMore = (res.data.beers?.length === this.pageSize) ||
(res.data.breweries?.length === this.pageSize)
} catch (error) {
console.error('搜索全部失败:', error)
throw error
}
},
// 搜索酒款
async searchBeers() {
try {
const keyword = this.keyword.trim()
const res = await getBeerList(keyword)
// 修复正确处理API返回的数据结构
if (!res || res.code !== 200) {
throw new Error('搜索结果为空')
}
// 获取rows数组
const beerList = res.rows || []
if (this.currentPage === 1) {
this.beers = beerList
} else {
this.beers = [...this.beers, ...beerList]
}
this.hasMore = beerList.length === this.pageSize
} catch (error) {
console.error('搜索酒款失败:', error)
throw error
}
},
// 搜索酒厂
async searchBreweries() {
try {
const keyword = this.keyword.trim()
const res = await searchByBreweriesApi(keyword)
// 修复正确处理API返回的数据结构
if (!res || res.code !== 200) {
throw new Error('搜索结果为空')
}
// 获取rows数组
const breweryList = res.rows || []
if (this.currentPage === 1) {
this.breweries = breweryList
} else {
this.breweries = [...this.breweries, ...breweryList]
}
this.hasMore = breweryList.length === this.pageSize
} catch (error) {
console.error('搜索酒厂失败:', error)
throw error
}
},
// 加载更多
loadMore() {
if (this.hasMore && !this.isSearching) {
this.currentPage++
this.search()
}
},
// 切换标签
async changeTag(index) {
if (this.curTag === index) return
this.curTag = index
this.currentPage = 1
await this.search()
},
// 获取热门风格
async getPopularStyle() {
try {
const res = await popularStyle()
this.popularStyleList = res.data || []
} catch (error) {
console.error('获取热门风格失败:', error)
}
},
// 点击热门风格
searchByStyle(item) {
uni.navigateTo({
url: '/pages/index/styleBeer?beerStyles=' + item.beerStyles
});
},
// 跳转酒厂详情
toBrand(item) {
uni.navigateTo({
url: '/pages/index/brandHome?breweryId=' + item.id
})
},
// 跳转酒款详情
toBeer(item) {
uni.navigateTo({
url: '/pages/index/review?beerId=' + item.id
})
},
// 返回
goBack() {
uni.navigateBack()
},
// 跳转到添加新酒款页面
toNewBeer() {
uni.navigateTo({
url: '/pagesActivity/newWine'
})
}
},
watch: {
keyword(newVal) {
// 只在关键词为空时清空结果
if (!newVal || newVal.trim().length === 0) {
this.commonBeer = []
this.commonBreweries = []
this.beers = []
this.breweries = []
}
},
}
}
</script>
<style lang="scss" scoped>
.page {
background: #FFF;
height: 100vh;
padding-top: 120rpx;
font-family: Roboto;
}
.fixed-search-box {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
}
.content {
padding: 0 38rpx;
animation: fadeIn 0.3s ease;
}
.search-box {
border-radius: 24rpx;
box-sizing: border-box;
height: 80rpx;
background-color: #FFF;
display: flex;
align-items: center;
margin: 20rpx 30rpx 20rpx 22rpx;
position: relative;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
.search-icon {
width: 32rpx;
height: 32rpx;
margin-left: 24rpx;
flex-shrink: 0;
&.rotating {
animation: rotate 1.2s linear infinite;
}
}
input {
flex: 1;
height: 100%;
font-size: 28rpx;
text-align: left;
padding: 0 20rpx;
}
.clear-icon {
padding: 0 20rpx;
color: #999;
}
.searchs {
background: #D42E78;
width: 80rpx;
height: 80rpx;
border-radius: 0 24rpx 24rpx 0;
display: flex;
justify-content: center;
align-items: center;
&.loading {
.uni-icons {
animation: rotate 1s linear infinite;
}
}
}
}
.section-title {
display: flex;
justify-content: space-between;
align-items: center;
margin: 36rpx 0 24rpx 0;
position: relative;
padding-left: 20rpx;
.title {
font-size: 28rpx;
font-weight: 600;
color: #030303;
position: relative;
&::before {
content: '';
position: absolute;
left: -20rpx;
top: 50%;
transform: translateY(-50%);
width: 6rpx;
height: 24rpx;
background: #D42E78;
border-radius: 3rpx;
}
}
.clear-btn {
display: flex;
align-items: center;
padding: 8rpx 16rpx;
border-radius: 20rpx;
background: #F7F8FA;
transition: all 0.3s ease;
text {
font-size: 24rpx;
color: #999;
margin-left: 8rpx;
}
&:active {
transform: scale(0.95);
opacity: 0.8;
}
}
}
.history-list {
margin: 0 22rpx;
background: #FEFEFE;
box-sizing: border-box;
padding: 0 12rpx;
display: flex;
flex-wrap: wrap;
}
.history-tag {
height: 64rpx;
background-color: #F9F9F9;
color: #606060;
border-radius: 32rpx;
padding: 0 24rpx;
margin: 0 16rpx 16rpx 0;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
transition: all 0.3s ease;
min-width: 80rpx;
&:active {
transform: scale(0.95);
opacity: 0.8;
}
}
.style-list {
margin: 0 22rpx;
background: #FEFEFE;
box-sizing: border-box;
padding-left: 12rpx;
}
.style-item {
position: relative;
padding: 20rpx;
border-radius: 16rpx;
margin-bottom: 32rpx;
transition: all 0.3s ease;
background: #FFF;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
&:active {
transform: scale(0.98);
background: #F7F8FA;
}
.item-content {
display: flex;
align-items: center;
image {
width: 62rpx;
height: 88rpx;
margin-right: 24rpx;
transition: all 0.3s ease;
&:active {
transform: scale(1.1);
}
}
.info {
flex: 1;
.title {
font-size: 28rpx;
font-weight: 600;
color: #0B0E26;
margin-bottom: 8rpx;
transition: all 0.3s ease;
&:active {
color: #D42E78;
}
}
.sub {
font-size: 24rpx;
color: #5E5F60;
transition: all 0.3s ease;
}
}
.arrow {
width: 48rpx;
height: 48rpx;
transition: all 0.3s ease;
&:active {
transform: translateX(4rpx);
}
}
}
}
.tag-list {
display: flex;
align-items: center;
padding: 20rpx 0;
margin-bottom: 10rpx;
border-bottom: 1rpx solid #F0F4F9;
overflow-x: auto;
white-space: nowrap;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
.tag {
background-color: #F7F8FA;
border-radius: 20rpx;
padding: 16rpx 32rpx;
margin-right: 40rpx;
color: #606060;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 4rpx;
background: #D42E78;
transition: all 0.3s ease;
}
&:active {
transform: scale(0.95);
opacity: 0.8;
}
&.active-tag {
background-color: #4E63E0;
font-weight: 600;
color: #FFFFFF;
&::after {
width: 40rpx;
}
}
}
}
.empty-state {
flex: 1;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80rpx 32rpx;
animation: fadeIn 0.5s ease;
.empty-image {
width: 280rpx;
height: 280rpx;
margin-bottom: 48rpx;
animation: float 3s ease-in-out infinite;
}
.empty-content {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
max-width: 600rpx;
}
.empty-text {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 48rpx;
text-align: center;
.main-text {
font-size: 36rpx;
color: #19367A;
font-weight: 600;
margin-bottom: 20rpx;
position: relative;
display: inline-block;
&::after {
content: '';
position: absolute;
bottom: -4rpx;
left: 50%;
transform: translateX(-50%);
width: 120%;
height: 8rpx;
background: rgba(25, 54, 122, 0.1);
border-radius: 4rpx;
}
}
.sub-text {
font-size: 28rpx;
color: #9C9BA6;
line-height: 1.6;
}
}
.request-btn {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
max-width: 400rpx;
height: 88rpx;
background: #19367A;
border-radius: 44rpx;
box-shadow: 0 8rpx 16rpx rgba(25, 54, 122, 0.15);
transition: all 0.3s ease;
text {
font-size: 28rpx;
color: #FFFFFF;
font-weight: 500;
margin-right: 12rpx;
}
&:active {
transform: scale(0.96) translateY(4rpx);
box-shadow: 0 4rpx 8rpx rgba(25, 54, 122, 0.1);
}
}
}
.my-brandSide {
padding: 28rpx 0rpx;
.brandSide-box {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 32rpx;
transition: all 0.3s ease;
border-radius: 16rpx;
margin-bottom: 24rpx;
background: #FFF;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
left: 0;
top: 0;
width: 6rpx;
height: 100%;
background: linear-gradient(to bottom, #D42E78, #4E63E0);
opacity: 0.8;
}
&:active {
transform: scale(0.98);
background: #F7F8FA;
}
.logo {
width: 88rpx;
height: 88rpx;
border-radius: 12rpx;
margin-right: 24rpx;
transition: all 0.3s ease;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.1);
border: 2rpx solid #F0F0F0;
&:active {
transform: scale(1.1);
}
}
.beerCover {
width: 88rpx;
height: 124rpx;
border-radius: 12rpx;
margin-right: 28rpx;
transition: all 0.3s ease;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.1);
border: 2rpx solid #F0F0F0;
&:active {
transform: scale(1.1);
}
}
.info {
flex: 1;
.title {
font-size: 30rpx;
font-weight: 600;
color: #19191B;
margin-bottom: 16rpx;
transition: all 0.3s ease;
position: relative;
display: inline-block;
&::after {
content: '';
position: absolute;
bottom: 4rpx;
left: 0;
width: 100%;
height: 6rpx;
background: linear-gradient(to right, rgba(212, 46, 120, 0.2), rgba(78, 99, 224, 0.2));
border-radius: 3rpx;
z-index: -1;
}
&:active {
color: #D42E78;
}
}
.desc {
font-size: 24rpx;
color: #9C9BA6;
transition: all 0.3s ease;
display: flex;
align-items: center;
&::before {
content: '';
display: inline-block;
width: 8rpx;
height: 8rpx;
background: #D42E78;
border-radius: 50%;
margin-right: 12rpx;
}
}
}
.rating {
padding: 10rpx 20rpx;
background: linear-gradient(135deg, #F7F8FA, #F0F0F0);
border-radius: 12rpx;
font-size: 24rpx;
color: #9C9BA6;
transition: all 0.3s ease;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
&:active {
transform: scale(0.95);
background: linear-gradient(135deg, #F0F0F0, #E8E8E8);
}
.star {
color: #FEE034;
margin-left: 10rpx;
animation: twinkle 1.5s ease-in-out infinite;
}
}
}
}
.brewery-list {
padding: 28rpx 0rpx;
}
.brewery-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 32rpx;
transition: all 0.3s ease;
border-radius: 16rpx;
margin-bottom: 24rpx;
background: #FFF;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
left: 0;
top: 0;
width: 6rpx;
height: 100%;
background: linear-gradient(to bottom, #4E63E0, #D42E78);
opacity: 0.8;
}
&:active {
transform: scale(0.98);
background: #F7F8FA;
}
.logo {
width: 100rpx;
height: 100rpx;
border-radius: 16rpx;
margin-right: 32rpx;
transition: all 0.3s ease;
object-fit: cover;
border: 2rpx solid #F0F0F0;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.1);
&:active {
transform: scale(1.1);
}
}
.info {
flex: 1;
.title {
font-size: 32rpx;
font-weight: 600;
color: #19191B;
margin-bottom: 12rpx;
transition: all 0.3s ease;
position: relative;
display: inline-block;
&::after {
content: '';
position: absolute;
bottom: 4rpx;
left: 0;
width: 100%;
height: 6rpx;
background: linear-gradient(to right, rgba(78, 99, 224, 0.2), rgba(212, 46, 120, 0.2));
border-radius: 3rpx;
z-index: -1;
}
&:active {
color: #D42E78;
}
}
.desc {
font-size: 26rpx;
color: #9C9BA6;
transition: all 0.3s ease;
display: flex;
align-items: center;
&::before {
content: '';
display: inline-block;
width: 8rpx;
height: 8rpx;
background: #4E63E0;
border-radius: 50%;
margin-right: 12rpx;
}
}
}
.arrow-container {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #F7F8FA, #F0F0F0);
border-radius: 50%;
transition: all 0.3s ease;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
&:active {
transform: scale(0.9);
background: linear-gradient(135deg, #F0F0F0, #E8E8E8);
}
.arrow {
width: 36rpx;
height: 36rpx;
transition: all 0.3s ease;
&:active {
transform: translateX(4rpx);
}
}
}
}
.guide-tip {
display: flex;
align-items: center;
justify-content: center;
padding: 32rpx 0;
margin-top: 20rpx;
text {
font-size: 24rpx;
color: #9C9BA6;
}
.add-btn {
display: flex;
align-items: center;
margin-left: 16rpx;
padding: 8rpx 20rpx;
background: rgba(25, 54, 122, 0.05);
border-radius: 24rpx;
transition: all 0.3s ease;
text {
font-size: 24rpx;
color: #19367A;
margin-right: 8rpx;
}
&:active {
transform: scale(0.95);
opacity: 0.8;
}
}
}
.brewery-info {
display: flex;
align-items: center;
margin-top: 12rpx;
.brewery-logo {
width: 32rpx;
height: 32rpx;
border-radius: 50%;
margin-right: 8rpx;
border: 1rpx solid rgba(240, 240, 240, 0.8);
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.05);
}
.brewery-name {
font-size: 24rpx;
color: #9C9BA6;
padding-left: 8rpx;
}
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes float {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-10rpx);
}
}
@keyframes twinkle {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
</style>