Files
hejiu/components/DrinkCard.vue
T
cg 860136bceb feat(theme): 实现日夜主题自动切换功能
- 添加日夜主题CSS变量定义,支持琥珀夜光和暖白琥珀两种风格
- 实现主题切换逻辑,根据时间自动切换白天(light)和夜间(dark)主题
- 在App.vue中集成主题初始化和token恢复功能
- 更新全局样式类应用主题颜色变量,包括卡片、文本、边框等
- 创建主题混入(mixin)供各页面使用,确保主题同步更新
- 实现导航栏和TabBar主题动态切换,提升用户体验
- 添加API服务层封装HaveADrink SDK,统一处理认证和请求
- 优化DrinkCard组件显示饮酒感受信息,丰富打卡记录展示
- 更新项目依赖配置,集成新的API客户端库
2026-07-16 22:47:38 +08:00

294 lines
6.7 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="card-root">
<!-- 顶部日期 -->
<view class="card-header">
<text class="header-date">{{ record.date }}</text>
</view>
<!-- 照片区域 -->
<view v-if="photos.length > 0" class="card-photos">
<!-- 1张: 大图 -->
<view v-if="photos.length === 1" class="photo-single">
<image :src="photos[0]" mode="aspectFill"></image>
</view>
<!-- 2-6: 网格 -->
<view v-else class="photo-grid">
<view
v-for="(photo, i) in photos"
:key="i"
class="photo-cell"
:class="{ 'photo-span': i === 0 && photos.length % 2 !== 0 }"
>
<image :src="photo" mode="aspectFill"></image>
</view>
</view>
</view>
<!-- 无照片: emoji -->
<view v-else class="card-hero">
<view class="hero-emoji-wrap">
<text class="hero-emoji">{{ mainEmoji }}</text>
</view>
</view>
<!-- 酒水清单 -->
<view class="drink-list">
<view v-for="(drink, i) in record.drinks" :key="i" class="drink-row">
<text class="drink-name">{{ getCatEmoji(drink.category) }} {{ drink.brand }}</text>
<text class="drink-detail">{{ formatAmount(drink) }}</text>
</view>
<view v-if="record.food" class="drink-row">
<text class="drink-name">🍲 {{ getFoodName() }}</text>
<text class="drink-detail"></text>
</view>
</view>
<!-- 饮酒感受 -->
<view v-if="feelingLabel" class="feeling-row">
<text class="feeling-text">{{ feelingLabel }}</text>
</view>
<!-- 分割线 -->
<view class="divider"></view>
<!-- 喝后心得酒言酒语 -->
<view class="card-footer">
<text class="footer-label">喝后心得</text>
<text class="footer-quote">"{{ quote }}"</text>
</view>
<!-- 品牌 + 二维码 -->
<view class="card-brand">
<view class="brand-info">
<text class="brand-text">🍻 喝了么</text>
<text class="brand-slogan">记录每一杯的故事</text>
</view>
<view class="brand-qr"></view>
</view>
</view>
</template>
<script>
import { DRINK_CATEGORIES, FOOD_CATEGORIES, DRINK_QUOTES, FEELINGS } from '../common/constants'
const UNIT_NAMES = { ml: 'ml', liang: '两', bottle: '瓶', cup: '杯', can: '听', shot: 'shot' }
export default {
props: {
record: { type: Object, required: true }
},
data() {
return {
quote: DRINK_QUOTES[Math.floor(Math.random() * DRINK_QUOTES.length)]
}
},
computed: {
photos() {
return (this.record && this.record.photos) || []
},
mainEmoji() {
const first = (this.record.drinks || [])[0]
return first ? this.getCatEmoji(first.category) : '🥃'
},
feelingLabel() {
const f = FEELINGS.find(fe => fe.id === this.record.feeling)
return f ? `${f.emoji} ${f.name}` : ''
}
},
methods: {
getCatEmoji(catId) {
const cat = DRINK_CATEGORIES.find(c => c.id === catId)
return cat ? cat.emoji : '🥃'
},
getFoodName() {
const food = FOOD_CATEGORIES.find(f => f.id === this.record.food?.category)
if (!food) return this.record.food?.name || '美食'
return this.record.food.name ? `${food.name}·${this.record.food.name}` : food.name
},
formatAmount(drink) {
const unitName = UNIT_NAMES[drink.unit] || drink.unit
return `${drink.amount}${unitName}`
}
}
}
</script>
<style lang="scss" scoped>
.card-root {
position: relative;
width: 620rpx;
border-radius: 32rpx;
overflow: hidden;
background: linear-gradient(170deg, var(--card-gradient-start, #1A1510) 0%, var(--card-gradient-end, #0D0B08) 100%);
border: 2rpx solid var(--border-subtle, rgba(255, 255, 255, 0.10));
box-shadow: var(--shadow-lg, 0 16rpx 48rpx rgba(0, 0, 0, 0.45)), 0 0 60rpx var(--amber-glow, rgba(232, 168, 56, 0.15));
display: flex;
flex-direction: column;
}
/* 顶部 */
.card-header {
padding: $sp-lg $sp-xl 0;
}
.header-date {
font-size: $fs-sm;
color: $text-tertiary;
font-family: $font-num;
letter-spacing: 4rpx;
}
/* 照片区域 */
.card-photos {
padding: $sp-lg $sp-xl 0;
}
/* 1张:大图 */
.photo-single {
width: 100%;
height: 340rpx;
border-radius: $radius-lg;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
/* 2-6张:网格 */
.photo-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: $sp-sm;
}
.photo-cell {
aspect-ratio: 1;
border-radius: $radius-md;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
/* 奇数张时第一张占满两列 */
.photo-span {
grid-column: span 2;
aspect-ratio: 16 / 9;
}
/* emoji占位 */
.card-hero {
display: flex;
justify-content: center;
align-items: center;
padding: $sp-xl $sp-xl $sp-lg;
}
.hero-emoji-wrap {
width: 200rpx;
height: 200rpx;
border-radius: $radius-full;
background: rgba(232, 168, 56, 0.08);
display: flex;
align-items: center;
justify-content: center;
}
.hero-emoji {
font-size: 100rpx;
line-height: 1;
}
/* 酒水清单 */
.drink-list {
padding: 0 $sp-xl;
display: flex;
flex-direction: column;
gap: $sp-md;
}
.drink-row {
display: flex;
align-items: baseline;
justify-content: space-between;
}
.drink-name {
font-size: $fs-base;
color: $text-primary;
font-weight: $fw-medium;
flex-shrink: 0;
}
.drink-detail {
font-size: $fs-sm;
color: $amber;
font-family: $font-num;
font-weight: $fw-bold;
flex-shrink: 0;
margin-left: $sp-md;
}
/* 饮酒感受 */
.feeling-row {
padding: $sp-sm $sp-xl 0;
display: flex;
align-items: center;
}
.feeling-text {
font-size: $fs-base;
color: $amber;
font-weight: $fw-medium;
letter-spacing: 2rpx;
}
/* 分割线 */
.divider {
margin: $sp-lg $sp-xl;
height: 2rpx;
background: linear-gradient(90deg, transparent, rgba(232, 168, 56, 0.15), transparent);
}
/* 底部 */
.card-footer {
padding: 0 $sp-xl;
display: flex;
flex-direction: column;
gap: $sp-sm;
}
.footer-label {
font-size: $fs-xs;
color: $text-tertiary;
letter-spacing: 2rpx;
}
.footer-quote {
font-size: $fs-sm;
color: $text-secondary;
line-height: $lh-loose;
font-style: italic;
}
/* 品牌 + 二维码 */
.card-brand {
padding: $sp-lg $sp-xl $sp-xl;
display: flex;
align-items: center;
justify-content: space-between;
}
.brand-info {
display: flex;
flex-direction: column;
gap: 4rpx;
}
.brand-text {
font-size: $fs-sm;
color: $text-tertiary;
font-weight: $fw-bold;
letter-spacing: 2rpx;
}
.brand-slogan {
font-size: $fs-xs;
color: $text-tertiary;
}
.brand-qr {
width: 80rpx;
height: 80rpx;
border-radius: $radius-sm;
border: 2rpx solid var(--border-subtle, rgba(255, 255, 255, 0.10));
background: var(--bg-subtle, rgba(255, 255, 255, 0.03));
}
</style>