Files
hejiu/components/DrinkCard.vue
T
cg 145976f221 refactor(components): 重构饮酒卡片组件并优化日历交互体验
- 移除DrinkCard组件中的模板切换功能和多种布局模式
- 简化DrinkCard组件结构,统一使用琥珀流光样式
- 添加未来日期禁用功能,防止用户选择未来日期
- 优化卡片样式为现代化深色主题设计
- 调整日历单元格点击交互逻辑,过滤未来日期
- 更新Canvas导出尺寸适配新卡片高度
- 优化照片网格布局算法,支持响应式排列
- 简化页面操作按钮,移除冗余功能入口
- 移除情感状态显示,专注核心饮酒记录功能
2026-07-15 23:12:13 +08:00

272 lines
6.0 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) }}·{{ drink.standardCups }}</text>
</view>
<view v-if="record.food" class="drink-row">
<text class="drink-name">🍲 {{ getFoodName() }}</text>
<text class="drink-detail"></text>
</view>
</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 } 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) : '🥃'
}
},
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, #1A1510 0%, #0D0B08 100%);
border: 2rpx solid rgba(232, 168, 56, 0.15);
box-shadow: 0 24rpx 80rpx rgba(0, 0, 0, 0.5), 0 0 60rpx rgba(232, 168, 56, 0.06);
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;
}
/* 分割线 */
.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 rgba(232, 168, 56, 0.15);
background: rgba(255, 255, 255, 0.03);
}
</style>