feat(game): 新增酒桌小游戏功能并优化图标显示
- 添加了完整的酒桌小游戏页面,包含数字炸弹、猜拳大战、骰子大话和命运转盘四个游戏 - 实现了成就徽章组件的图标路径判断逻辑,支持图片和文字图标的动态切换 - 更新了饮酒分类常量中的白酒图标为酒杯样式,并修改成就图标为SVG路径 - 重构了动态卡片组件中的分类表情符号显示方式,支持SVG图标渲染 - 添加了游戏页面的路由配置和完整的交互功能实现
This commit is contained in:
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// 酒类分类
|
// 酒类分类
|
||||||
export const DRINK_CATEGORIES = [
|
export const DRINK_CATEGORIES = [
|
||||||
{ id: 'baijiu', name: '白酒', emoji: '⚱️', icon: '/static/icons/baijiu.svg', defaultDegree: 52 },
|
{ id: 'baijiu', name: '白酒', emoji: '🥃', icon: '/static/icons/baijiu.svg', defaultDegree: 52 },
|
||||||
{ id: 'beer', name: '啤酒', emoji: '🍺', defaultDegree: 5 },
|
{ id: 'beer', name: '啤酒', emoji: '🍺', defaultDegree: 5 },
|
||||||
{ id: 'wine', name: '红酒', emoji: '🍷', defaultDegree: 13 },
|
{ id: 'wine', name: '红酒', emoji: '🍷', defaultDegree: 13 },
|
||||||
{ id: 'whisky', name: '洋酒', emoji: '🥂', defaultDegree: 40 },
|
{ id: 'whisky', name: '洋酒', emoji: '🥂', defaultDegree: 40 },
|
||||||
@@ -176,7 +176,7 @@ export const ACHIEVEMENTS = [
|
|||||||
id: 'baijiu_master',
|
id: 'baijiu_master',
|
||||||
name: '白酒达人',
|
name: '白酒达人',
|
||||||
desc: '白酒累计打卡20次',
|
desc: '白酒累计打卡20次',
|
||||||
icon: '⚱️',
|
icon: '/static/icons/baijiu.svg',
|
||||||
condition: { type: 'category_records', category: 'baijiu', value: 20 }
|
condition: { type: 'category_records', category: 'baijiu', value: 20 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
@click="$emit('click')"
|
@click="$emit('click')"
|
||||||
>
|
>
|
||||||
<view class="badge-icon-wrap">
|
<view class="badge-icon-wrap">
|
||||||
<text class="badge-icon">{{ achievement.icon }}</text>
|
<image v-if="isIconPath(achievement.icon)" :src="achievement.icon" class="badge-icon-img" mode="aspectFit"></image>
|
||||||
|
<text v-else class="badge-icon">{{ achievement.icon }}</text>
|
||||||
<view v-if="!achievement.unlocked" class="badge-lock">
|
<view v-if="!achievement.unlocked" class="badge-lock">
|
||||||
<text class="badge-lock-icon">🔒</text>
|
<text class="badge-lock-icon">🔒</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -15,11 +16,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { isIconPath } from '../common/utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
achievement: { type: Object, required: true }
|
achievement: { type: Object, required: true }
|
||||||
},
|
},
|
||||||
emits: ['click']
|
emits: ['click'],
|
||||||
|
methods: { isIconPath }
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -74,6 +78,11 @@ export default {
|
|||||||
font-size: 48rpx;
|
font-size: 48rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge-icon-img {
|
||||||
|
width: 52rpx;
|
||||||
|
height: 52rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.badge-lock {
|
.badge-lock {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -4rpx;
|
bottom: -4rpx;
|
||||||
|
|||||||
+12
-5
@@ -20,7 +20,8 @@
|
|||||||
<!-- 饮酒标签 -->
|
<!-- 饮酒标签 -->
|
||||||
<view class="feed-drinks" v-if="feed.drinks && feed.drinks.length">
|
<view class="feed-drinks" v-if="feed.drinks && feed.drinks.length">
|
||||||
<view class="feed-drink-tag" v-for="(d, i) in feed.drinks" :key="i">
|
<view class="feed-drink-tag" v-for="(d, i) in feed.drinks" :key="i">
|
||||||
<text class="feed-drink-emoji">{{ categoryEmoji(d.category) }}</text>
|
<image v-if="isIconPath(getCatIcon(d.category))" :src="getCatIcon(d.category)" class="feed-drink-icon-img" mode="aspectFit"></image>
|
||||||
|
<text v-else class="feed-drink-emoji">{{ getCatIcon(d.category) }}</text>
|
||||||
<text class="feed-drink-name">{{ d.name }} {{ d.amount }}</text>
|
<text class="feed-drink-name">{{ d.name }} {{ d.amount }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -60,16 +61,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { getCatIcon, isIconPath } from '../common/utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FeedCard',
|
name: 'FeedCard',
|
||||||
props: {
|
props: {
|
||||||
feed: { type: Object, default: () => ({}) }
|
feed: { type: Object, default: () => ({}) }
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
categoryEmoji(cat) {
|
getCatIcon,
|
||||||
const map = { baijiu: '🏺', beer: '🍺', wine: '🍷', whisky: '🥃', huangjiu: '🫖', sake: '🍶', fruit: '🍹', cocktail: '🍸' }
|
isIconPath,
|
||||||
return map[cat] || '🍻'
|
|
||||||
},
|
|
||||||
feelingLabel(f) {
|
feelingLabel(f) {
|
||||||
const map = { sober: '😌 清醒', buzzed: '😊 微醺', tipsy: '😄 小醉', drunk: '🥴 喝多了' }
|
const map = { sober: '😌 清醒', buzzed: '😊 微醺', tipsy: '😄 小醉', drunk: '🥴 喝多了' }
|
||||||
return map[f] || '🍻 喝了点'
|
return map[f] || '🍻 喝了点'
|
||||||
@@ -163,6 +164,12 @@ export default {
|
|||||||
font-size: $fs-sm;
|
font-size: $fs-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.feed-drink-icon-img {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.feed-drink-name {
|
.feed-drink-name {
|
||||||
font-size: $fs-xs;
|
font-size: $fs-xs;
|
||||||
color: $text-secondary;
|
color: $text-secondary;
|
||||||
|
|||||||
@@ -90,6 +90,13 @@
|
|||||||
"navigationStyle": "custom",
|
"navigationStyle": "custom",
|
||||||
"navigationBarTitleText": ""
|
"navigationBarTitleText": ""
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/games/games",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTitleText": ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -142,6 +142,10 @@ export default {
|
|||||||
uni.showToast({ title: '请先同意用户协议和隐私政策', icon: 'none', duration: 2000 })
|
uni.showToast({ title: '请先同意用户协议和隐私政策', icon: 'none', duration: 2000 })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (!this.nickname.trim()) {
|
||||||
|
uni.showToast({ title: '请先填写昵称', icon: 'none', duration: 2000 })
|
||||||
|
return
|
||||||
|
}
|
||||||
this.loginLoading = true
|
this.loginLoading = true
|
||||||
try {
|
try {
|
||||||
// 1. 获取微信登录 code
|
// 1. 获取微信登录 code
|
||||||
|
|||||||
+43
-12
@@ -78,7 +78,8 @@
|
|||||||
<view class="persona-glow"></view>
|
<view class="persona-glow"></view>
|
||||||
<view class="persona-content">
|
<view class="persona-content">
|
||||||
<view class="persona-header">
|
<view class="persona-header">
|
||||||
<text class="persona-emoji">{{ personaEmoji }}</text>
|
<image v-if="isIconPath(personaEmoji)" :src="personaEmoji" class="persona-icon-img" mode="aspectFit"></image>
|
||||||
|
<text v-else class="persona-emoji">{{ personaEmoji }}</text>
|
||||||
<view class="persona-text">
|
<view class="persona-text">
|
||||||
<text class="persona-title">{{ personaTitle }}</text>
|
<text class="persona-title">{{ personaTitle }}</text>
|
||||||
<text class="persona-desc">{{ personaDesc }}</text>
|
<text class="persona-desc">{{ personaDesc }}</text>
|
||||||
@@ -118,17 +119,17 @@
|
|||||||
|
|
||||||
<!-- 操作入口 -->
|
<!-- 操作入口 -->
|
||||||
<view class="actions-section">
|
<view class="actions-section">
|
||||||
<!-- 酒友圈 -->
|
<!-- 酒桌小游戏 -->
|
||||||
<view class="action-card" @click="goCircle">
|
<view class="action-card" @click="goGames">
|
||||||
<view class="action-icon-wrap action-icon-circle">
|
<view class="action-icon-wrap action-icon-games">
|
||||||
<text class="action-icon">🍻</text>
|
<text class="action-icon">🎲</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="action-text">
|
<view class="action-text">
|
||||||
<view class="action-title-row">
|
<view class="action-title-row">
|
||||||
<text class="action-title">酒友圈</text>
|
<text class="action-title">酒桌小游戏</text>
|
||||||
<view class="action-new-tag">NEW</view>
|
<view class="action-hot-tag">HOT</view>
|
||||||
</view>
|
</view>
|
||||||
<text class="action-desc">看看酒友们今晚都在喝什么</text>
|
<text class="action-desc">数字炸弹·猜拳·骰子·转盘,今晚谁喝?</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="action-arrow">›</text>
|
<text class="action-arrow">›</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -148,7 +149,8 @@
|
|||||||
<view v-if="showDetail" class="detail-overlay" @click="showDetail = false">
|
<view v-if="showDetail" class="detail-overlay" @click="showDetail = false">
|
||||||
<view class="detail-card" @click.stop>
|
<view class="detail-card" @click.stop>
|
||||||
<view class="detail-icon-ring" :class="detailAchievement.unlocked ? 'ring-unlocked' : 'ring-locked'">
|
<view class="detail-icon-ring" :class="detailAchievement.unlocked ? 'ring-unlocked' : 'ring-locked'">
|
||||||
<text class="detail-emoji">{{ detailAchievement.icon }}</text>
|
<image v-if="isIconPath(detailAchievement.icon)" :src="detailAchievement.icon" class="detail-icon-img" mode="aspectFit"></image>
|
||||||
|
<text v-else class="detail-emoji">{{ detailAchievement.icon }}</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="detail-name">{{ detailAchievement.name }}</text>
|
<text class="detail-name">{{ detailAchievement.name }}</text>
|
||||||
<text class="detail-desc">{{ detailAchievement.desc }}</text>
|
<text class="detail-desc">{{ detailAchievement.desc }}</text>
|
||||||
@@ -164,7 +166,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import AchievementBadge from '../../components/AchievementBadge.vue'
|
import AchievementBadge from '../../components/AchievementBadge.vue'
|
||||||
import client, { clearAuth } from '../../common/api'
|
import client, { clearAuth } from '../../common/api'
|
||||||
import { checkAchievements } from '../../common/utils'
|
import { checkAchievements, getCatIcon, isIconPath } from '../../common/utils'
|
||||||
import { ACHIEVEMENTS, DRINK_CATEGORIES } from '../../common/constants'
|
import { ACHIEVEMENTS, DRINK_CATEGORIES } from '../../common/constants'
|
||||||
import themeMixin from '../../common/theme-mixin'
|
import themeMixin from '../../common/theme-mixin'
|
||||||
|
|
||||||
@@ -217,8 +219,8 @@ export default {
|
|||||||
},
|
},
|
||||||
personaEmoji() {
|
personaEmoji() {
|
||||||
const fav = this.stats.favCategory
|
const fav = this.stats.favCategory
|
||||||
const map = { baijiu: '⚱️', beer: '🍺', wine: '🍷', whisky: '🥂', huangjiu: '🫖', sake: '🍶', fruit: '🍹', cocktail: '🍸' }
|
if (fav) return getCatIcon(fav)
|
||||||
return map[fav] || '🍻'
|
return '🍻'
|
||||||
},
|
},
|
||||||
personaTitle() {
|
personaTitle() {
|
||||||
const fav = this.stats.favCategory
|
const fav = this.stats.favCategory
|
||||||
@@ -261,6 +263,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
isIconPath,
|
||||||
// 构建分享名片的 query 参数(携带公开档案数据)
|
// 构建分享名片的 query 参数(携带公开档案数据)
|
||||||
buildShareQuery() {
|
buildShareQuery() {
|
||||||
const parts = [`nick=${encodeURIComponent(this.user.nickname || '酒友')}`]
|
const parts = [`nick=${encodeURIComponent(this.user.nickname || '酒友')}`]
|
||||||
@@ -351,6 +354,9 @@ export default {
|
|||||||
goCircle() {
|
goCircle() {
|
||||||
uni.switchTab({ url: '/pages/circle/circle' })
|
uni.switchTab({ url: '/pages/circle/circle' })
|
||||||
},
|
},
|
||||||
|
goGames() {
|
||||||
|
uni.navigateTo({ url: '/pages/games/games' })
|
||||||
|
},
|
||||||
goHome() {
|
goHome() {
|
||||||
uni.switchTab({ url: '/pages/index/index' })
|
uni.switchTab({ url: '/pages/index/index' })
|
||||||
},
|
},
|
||||||
@@ -541,6 +547,7 @@ export default {
|
|||||||
background: rgba(232,168,56,0.10);
|
background: rgba(232,168,56,0.10);
|
||||||
border: 1rpx solid rgba(232,168,56,0.20);
|
border: 1rpx solid rgba(232,168,56,0.20);
|
||||||
border-radius: $radius-full;
|
border-radius: $radius-full;
|
||||||
|
margin-left: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-level-text {
|
.hero-level-text {
|
||||||
@@ -720,6 +727,12 @@ export default {
|
|||||||
font-size: 56rpx;
|
font-size: 56rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.persona-icon-img {
|
||||||
|
width: 64rpx;
|
||||||
|
height: 64rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.persona-text {
|
.persona-text {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -838,6 +851,10 @@ export default {
|
|||||||
background: rgba(139,133,184,0.12);
|
background: rgba(139,133,184,0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-icon-games {
|
||||||
|
background: rgba(232,168,56,0.12);
|
||||||
|
}
|
||||||
|
|
||||||
.action-icon-timeline {
|
.action-icon-timeline {
|
||||||
background: rgba(94,198,160,0.12);
|
background: rgba(94,198,160,0.12);
|
||||||
}
|
}
|
||||||
@@ -872,6 +889,15 @@ export default {
|
|||||||
border-radius: $radius-full;
|
border-radius: $radius-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-hot-tag {
|
||||||
|
font-size: 18rpx;
|
||||||
|
font-weight: $fw-bold;
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(135deg, $coral, #e04848);
|
||||||
|
padding: 2rpx 10rpx;
|
||||||
|
border-radius: $radius-full;
|
||||||
|
}
|
||||||
|
|
||||||
.action-desc {
|
.action-desc {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: $fs-xs;
|
font-size: $fs-xs;
|
||||||
@@ -955,6 +981,11 @@ export default {
|
|||||||
font-size: 64rpx;
|
font-size: 64rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.detail-icon-img {
|
||||||
|
width: 72rpx;
|
||||||
|
height: 72rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.detail-name {
|
.detail-name {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: $fs-xl;
|
font-size: $fs-xl;
|
||||||
|
|||||||
Reference in New Issue
Block a user