Files
hejiu/pages/index/index.vue
T
cg 81e7a3afa5 feat(event): 添加酒局报名审核功能并优化前端组件
- 新增 ApproveEvent API 接口用于审核报名用户
- 在 EventCard 组件中显示待审核状态(⏳ 待审核)
- 实现酒局发起人审核报名用户的完整流程
- 添加用户协议和隐私政策页面
- 优化 FeedCard 组件中的图片展示逻辑
- 修复连续打卡天数计算问题
- 更新 HaveADrink SDK 至 1.0.15 版本
2026-08-16 14:50:50 +08:00

905 lines
25 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="themeClass" class="page-container home">
<!-- 顶部问候 -->
<view class="greeting-bar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="greeting-left">
<text class="greeting-text">{{ greeting }},{{ userName }}</text>
<text class="greeting-sub">今晚喝一杯?</text>
</view>
</view>
<!-- 核心CTA - 首页最醒目位置 -->
<view class="hero-cta" @click="goRecord">
<view class="hero-cta-bg"></view>
<view class="hero-cta-content">
<text class="hero-cta-emoji">🍻</text>
<view class="hero-cta-text">
<text class="hero-cta-title">开始记录</text>
<text class="hero-cta-sub">记录今晚的酒局</text>
</view>
<text class="hero-cta-arrow">›</text>
</view>
</view>
<!-- 统计卡片 -->
<view class="stats-row">
<view class="stat-card card">
<text class="stat-value text-num text-amber">{{ stats.monthDrinkCount }}</text>
<text class="stat-label">本月饮酒</text>
</view>
<view class="stat-card card">
<text class="stat-value text-num">{{ stats.monthCups }}</text>
<text class="stat-label">标准杯</text>
</view>
<view class="stat-card card">
<text class="stat-value text-num text-amber">{{ stats.drankStreak }}</text>
<text class="stat-label">连喝天数</text>
</view>
<view class="stat-card card">
<text class="stat-value text-num text-mint">{{ stats.abstainStreak }}</text>
<text class="stat-label">戒酒天数</text>
</view>
</view>
<!-- 饮酒日历 -->
<view class="calendar-section card">
<DrinkCalendar
:year="calendarYear"
:month="calendarMonth"
:records="records"
@change-month="onMonthChange"
@select-date="onDateSelect"
/>
</view>
<!-- 本周摘要 -->
<view class="week-summary card">
<view class="week-header flex-between">
<text class="text-h3">本周摘要</text>
<text class="text-caption">{{ weekRange }}</text>
</view>
<view class="week-stats flex">
<view class="week-stat">
<text class="week-stat-value text-num">{{ stats.weekDrinkCount }}</text>
<text class="week-stat-label">次饮酒</text>
</view>
<view class="week-divider"></view>
<view class="week-stat">
<text class="week-stat-value text-num text-amber">{{ stats.weekCups }}</text>
<text class="week-stat-label">标准杯</text>
</view>
</view>
<view class="health-ref" v-if="stats.weekCups > 0">
<view class="health-bar-fill" :style="{ width: healthPercent + '%' }"></view>
<text class="health-text">
{{ stats.weekCups > 14 ? '本周超标了,注意休息' : '本周控制得不错' }}
</text>
</view>
</view>
<!-- 底部健康提示 -->
<view class="bottom-health-tip">
<text>过量饮酒有害健康 · 请理性记录</text>
</view>
<!-- 日期记录弹窗 -->
<view v-if="showDayDetail" class="day-overlay" @click="showDayDetail = false">
<view class="day-detail card-elevated" @click.stop>
<view class="day-detail-handle"></view>
<view class="day-detail-header flex-between">
<text class="day-detail-date text-h3">{{ selectedDate }}</text>
<text class="day-close btn-text" @click="showDayDetail = false">关闭</text>
</view>
<view v-if="selectedRecord">
<view v-if="selectedRecord.mode === 'drank'" class="day-record-info">
<view class="day-drinks">
<view v-for="(drink, i) in selectedRecord.drinks" :key="i" class="day-drink-item">
<view class="day-drink-row">
<view class="day-drink-name">
<image v-if="isIconPath(getCatIcon(drink.category))" :src="getCatIcon(drink.category)" class="day-drink-icon" mode="aspectFit"></image>
<text v-else>{{ getCatEmoji(drink.category) }}</text>
<text>{{ drink.brand }} {{ drink.product }}</text>
</view>
<text v-if="drink.customAmount != null" class="day-drink-amount text-num">{{ drink.customAmount }}{{ getUnitLabel(drink.customUnit) }}</text>
</view>
</view>
</view>
<view class="day-meta">
<view class="day-meta-chip day-feeling-chip">
<text class="day-feeling-text">{{ getFeelingName(selectedRecord.feeling) }}</text>
</view>
<view class="day-meta-chip day-cups-chip">
<text class="day-cups-num text-num">{{ selectedRecord.standardCupsTotal }}</text>
<text class="day-cups-unit">标准杯</text>
</view>
</view>
<view class="day-action-row">
<button class="btn-ghost day-action-btn" @click="editRecord">修改</button>
<button class="btn-ghost day-action-btn" @click="toggleToAbstain">改为未饮酒</button>
</view>
<button class="btn-danger day-delete-btn" @click="deleteRecord">删除记录</button>
</view>
<view v-else class="day-abstain">
<text class="day-abstain-emoji">🚫</text>
<text class="text-caption">今日未饮酒,好样的</text>
<button class="btn-ghost day-toggle-btn" @click="toggleToDrank">改为饮酒</button>
<button class="btn-danger day-delete-btn" @click="deleteRecord">删除记录</button>
</view>
</view>
<view v-else class="day-empty">
<text class="text-caption">当天无记录</text>
<button v-if="isSelectedToday" class="btn-primary day-record-btn" @click="goRecordToday">记录饮酒</button>
<button v-else class="btn-ghost day-record-btn" @click="backfillDate">补打卡饮酒</button>
<button class="btn-ghost day-abstain-btn" @click="markAbstain">未饮酒</button>
</view>
</view>
</view>
</view>
</template>
<script>
import DrinkCalendar from '../../components/DrinkCalendar.vue'
import client from '../../common/api'
import { GetCalendarReq, DeleteRecordReq, CreateRecordReq, GetRecordDetailReq } from 'HaveADrink'
import { getGreeting, formatDate, getWeekStart, getCatIcon, isIconPath, calcLocalStreak } from '../../common/utils'
import { FEELINGS, DRINK_CATEGORIES, DRINK_UNITS } from '../../common/constants'
import { savePendingInvite, handlePendingInvite } from '../../common/invite'
import themeMixin from '../../common/theme-mixin'
export default {
mixins: [themeMixin],
components: { DrinkCalendar },
data() {
const now = new Date()
const sysInfo = uni.getSystemInfoSync()
return {
statusBarHeight: sysInfo.statusBarHeight || 25,
calendarYear: now.getFullYear(),
calendarMonth: now.getMonth() + 1,
records: [],
stats: {},
greeting: '',
userName: '',
showDayDetail: false,
selectedDate: '',
selectedRecord: null
}
},
computed: {
weekRange() {
const weekStart = getWeekStart()
const weekEnd = new Date(weekStart)
weekEnd.setDate(weekEnd.getDate() + 6)
return `${formatDate(weekStart, 'MM/DD')} - ${formatDate(weekEnd, 'MM/DD')}`
},
healthPercent() {
// 建议每周不超过14标准杯
return Math.min((this.stats.weekCups / 14) * 100, 100)
},
isSelectedToday() {
return this.selectedDate === formatDate(new Date(), 'YYYY-MM-DD')
}
},
onLoad(options) {
// 分享邀请落地:携带 inviteCode 时暂存邀请,已登录则立即接受邀请
if (options && options.inviteCode) {
savePendingInvite(options.inviteCode, options.inviterNick)
if (uni.getStorageSync('is_logged_in') === 'true') {
handlePendingInvite()
}
}
},
onShow() {
// 首次启动跳转引导页
const isFirst = uni.getStorageSync('is_first_launch')
if (isFirst === 'true') {
uni.reLaunch({ url: '/pages/onboarding/onboarding' })
return
}
this.loadData()
},
onShareAppMessage() {
return {
title: '碰盏日记 - 让每一杯酒都有迹可循',
path: '/pages/index/index'
}
},
onShareTimeline() {
return {
title: '碰盏日记 - 让每一杯酒都有迹可循',
query: ''
}
},
methods: {
async loadData() {
this.greeting = getGreeting()
// 并行加载用户信息、统计概览、记录列表
try {
const [userResp, statsResp, recordsResp] = await Promise.allSettled([
client.GetUserProfile({}),
client.GetStatsOverview({}),
client.GetCalendar(new GetCalendarReq(this.calendarYear, this.calendarMonth))
])
// 用户信息
if (userResp.status === 'fulfilled' && userResp.value) {
const user = userResp.value
this.userName = user.nickname || '酒友'
} else {
this.userName = '酒友'
}
// 统计概览
if (statsResp.status === 'fulfilled' && statsResp.value) {
const s = statsResp.value.data || statsResp.value
this.stats = {
weekDrinkCount: s.weekDrinkCount || 0,
weekCups: s.weekCups || 0,
monthDrinkCount: s.monthDrinkCount || 0,
monthCups: s.monthCups || 0,
streak: s.streak || 0,
streakType: String(s.streakType || 'drank'),
totalDays: s.totalDays || 0,
totalRecords: s.totalRecords || 0,
totalCups: s.totalCups || 0,
favCategory: s.favCategory ? String(s.favCategory) : null,
categoryVariety: s.categoryVariety || 0
}
// 后端 streak 不区分饮酒/戒酒模式,拉取记录本地重算修正
this.refreshLocalStreak()
}
// 日历数据
if (recordsResp.status === 'fulfilled' && recordsResp.value) {
const calData = recordsResp.value.data || recordsResp.value
const days = calData.days || []
this.records = days.filter(d => d && d.hasRecord).map(d => ({
id: d.id || '',
date: d.date,
mode: String(d.mode),
standardCupsTotal: d.standardCupsTotal || 0,
drinks: (d.drinks || []).map(dr => ({
...dr,
category: String(dr.category),
customAmount: dr.customAmount,
customUnit: dr.customUnit ? String(dr.customUnit) : ''
})),
food: d.food ? { category: String(d.food.category), name: d.food.name || '' } : null,
feeling: d.feeling ? String(d.feeling) : null,
quote: d.quote || '',
visibility: d.visibility ? String(d.visibility) : 'friends'
}))
}
} catch (e) {
console.warn('加载首页数据失败:', e)
this.userName = '酒友'
}
},
onMonthChange({ year, month }) {
this.calendarYear = year
this.calendarMonth = month
// 切换月份时重新加载记录
this.loadRecordsForMonth(year, month)
},
/** 后端 streak 不区分饮酒/戒酒模式,拉取全部记录后本地重算连续天数 */
async refreshLocalStreak() {
try {
const resp = await client.GetRecords({ page: 1, pageSize: 100 })
const payload = resp.data || resp
const list = payload.list || []
if (!list.length) return
const { streak, streakType, drankStreak, abstainStreak } = calcLocalStreak(list)
this.stats.streak = streak
this.stats.streakType = streakType
this.stats.drankStreak = drankStreak
this.stats.abstainStreak = abstainStreak
} catch (e) {
console.warn('本地计算连续天数失败:', e)
}
},
async loadRecordsForMonth(year, month) {
try {
const resp = await client.GetCalendar(new GetCalendarReq(year, month))
const calData = resp.data || resp
const days = calData.days || []
this.records = days.filter(d => d && d.hasRecord).map(d => ({
id: d.id || '',
date: d.date,
mode: String(d.mode),
standardCupsTotal: d.standardCupsTotal || 0,
drinks: (d.drinks || []).map(dr => ({
...dr,
category: String(dr.category),
customAmount: dr.customAmount,
customUnit: dr.customUnit ? String(dr.customUnit) : ''
})),
food: d.food ? { category: String(d.food.category), name: d.food.name || '' } : null,
feeling: d.feeling ? String(d.feeling) : null,
quote: d.quote || '',
visibility: d.visibility ? String(d.visibility) : 'friends'
}))
} catch (e) {
console.warn('加载月度记录失败:', e)
}
},
async onDateSelect(dateStr) {
this.selectedDate = dateStr
const localRecord = this.records.find(r => r.date === dateStr) || null
// 如果有记录且有id,拉取完整详情(确保拿到 customAmount/customUnit 等全量字段)
if (localRecord && localRecord.id && localRecord.mode === 'drank') {
this.selectedRecord = localRecord // 先用本地数据展示
this.showDayDetail = true
try {
const resp = await client.GetRecordDetail(new GetRecordDetailReq(localRecord.id))
const rec = resp.data || resp
if (rec) {
this.selectedRecord = {
...localRecord,
...rec,
mode: String(rec.mode || localRecord.mode),
drinks: (rec.drinks || localRecord.drinks || []).map(d => ({
...d,
category: String(d.category),
customUnit: d.customUnit ? String(d.customUnit) : ''
})),
feeling: rec.feeling ? String(rec.feeling) : localRecord.feeling,
visibility: rec.visibility ? String(rec.visibility) : localRecord.visibility
}
}
} catch (e) {
console.warn('获取记录详情失败,使用本地数据:', e)
}
} else {
this.selectedRecord = localRecord
this.showDayDetail = true
}
},
getFeelingName(feelingId) {
const f = FEELINGS.find(f => f.id === feelingId)
return f ? `${f.emoji} ${f.name}` : ''
},
getCatEmoji(catId) {
const cat = DRINK_CATEGORIES.find(c => c.id === catId)
return cat ? cat.emoji : '🥃'
},
getCatIcon,
isIconPath,
getUnitLabel(unitId) {
if (!unitId) return ''
const u = DRINK_UNITS.find(u => u.id === unitId)
return u ? u.name : unitId
},
backfillDate() {
this.showDayDetail = false
uni.navigateTo({
url: `/pages/record/record?date=${this.selectedDate}&mode=backfill`
})
},
// 修改记录(跳转到记录页编辑)
editRecord() {
this.showDayDetail = false
uni.navigateTo({
url: `/pages/record/record?date=${this.selectedDate}&mode=edit`
})
},
// 改为未饮酒
toggleToAbstain() {
uni.showModal({
title: '确认修改',
content: '确定将这天改为未饮酒吗?饮酒记录将被清除。',
success: async (res) => {
if (!res.confirm) return
const recordId = this.selectedRecord && this.selectedRecord.id
try {
if (recordId) {
await client.DeleteRecord(new DeleteRecordReq(recordId))
}
uni.showToast({ title: '已修改', icon: 'success' })
this.showDayDetail = false
this.loadData()
} catch (e) {
console.warn('修改为未饮酒失败:', e)
uni.showToast({ title: '修改失败,请重试', icon: 'none' })
}
}
})
},
// 改为饮酒(跳转到补录页)
toggleToDrank() {
this.showDayDetail = false
uni.navigateTo({
url: `/pages/record/record?date=${this.selectedDate}&mode=backfill`
})
},
// 删除记录
deleteRecord() {
uni.showModal({
title: '确认删除',
content: `确定删除 ${this.selectedDate} 的记录吗?删除后不可恢复。`,
confirmColor: '#e85d3a',
success: async (res) => {
if (!res.confirm) return
const recordId = this.selectedRecord && this.selectedRecord.id
try {
if (recordId) {
await client.DeleteRecord(new DeleteRecordReq(recordId))
}
this.showDayDetail = false
uni.showToast({ title: '已删除', icon: 'success' })
// 重新加载统计和日历数据
this.loadData()
} catch (e) {
console.warn('删除记录失败:', e)
uni.showToast({ title: '删除失败,请重试', icon: 'none' })
}
}
})
},
goRecord() {
uni.navigateTo({ url: '/pages/record/record' })
},
goRecordToday() {
this.showDayDetail = false
uni.navigateTo({ url: '/pages/record/record' })
},
// 标记为未饮酒(直接创建 abstain 记录)
async markAbstain() {
const recordData = {
date: this.selectedDate,
mode: 'abstain',
drinks: [],
food: null,
feeling: null,
photos: [],
visibility: 'friends',
quote: ''
}
try {
uni.showLoading({ title: '保存中...' })
await client.CreateRecord(recordData)
uni.hideLoading()
this.showDayDetail = false
uni.showToast({ title: '已记录未饮酒', icon: 'success' })
this.loadData()
} catch (e) {
uni.hideLoading()
console.warn('标记未饮酒失败:', e)
uni.showToast({ title: (e && e.msg) || '保存失败,请重试', icon: 'none' })
}
},
}
}
</script>
<style lang="scss" scoped>
.home {
padding: $sp-md;
padding-top: 0;
}
.greeting-bar {
display: flex;
align-items: flex-start;
padding: $sp-md 0 $sp-sm;
}
.greeting-text {
display: block;
font-size:42rpx;
font-weight: $fw-bold;
color: $text-primary;
}
.greeting-sub {
display: block;
font-size: $fs-xs;
color: $text-secondary;
margin-top: 4rpx;
}
.calendar-section {
margin-bottom: $sp-md;
padding: $sp-md;
}
.stats-row {
display: flex;
gap: $sp-xs;
margin-bottom: $sp-md;
}
.stat-card {
flex: 1;
text-align: center;
padding: $sp-md $sp-xs;
}
.stat-value {
display: block;
font-size: $fs-xl;
color: $text-primary;
margin-bottom: 4rpx;
}
.stat-label {
font-size: $fs-xs;
color: $text-secondary;
}
.week-summary {
padding: $sp-md;
}
.week-header {
margin-bottom: $sp-sm;
}
.week-stats {
gap: 0;
}
.week-stat {
flex: 1;
text-align: center;
}
.week-stat-value {
display: block;
font-size: $fs-xl;
font-weight: $fw-bold;
color: $text-primary;
margin-bottom: 4rpx;
}
.week-stat-label {
font-size: $fs-sm;
color: $text-secondary;
}
.week-divider {
width: 2rpx;
background: var(--divider-color, rgba(255, 255, 255, 0.08));
margin: $sp-xs 0;
}
.health-ref {
margin-top: $sp-md;
position: relative;
height: 12rpx;
background: $bg-elevated;
border-radius: $radius-full;
overflow: hidden;
}
.health-bar-fill {
height: 100%;
border-radius: $radius-full;
background: linear-gradient(90deg, $mint, $amber);
transition: width $duration-slow $ease-out;
}
.health-text {
display: block;
font-size: $fs-xs;
color: $text-tertiary;
margin-top: $sp-xs;
}
/* 核心CTA - 首页英雄区域 */
.hero-cta {
position: relative;
margin-bottom: $sp-md;
border-radius: $radius-lg;
overflow: hidden;
padding: $sp-md $sp-lg;
cursor: pointer;
&:active {
transform: scale(0.98);
}
}
.hero-cta-bg {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, $amber-light, $amber, $amber-deep);
z-index: 0;
&::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, var(--btn-shimmer, rgba(255, 255, 255, 0.15)), transparent);
animation: shimmer 4s infinite;
}
}
@keyframes shimmer {
0% { left: -100%; }
100% { left: 100%; }
}
.hero-cta-content {
position: relative;
z-index: 1;
display: flex;
align-items: center;
gap: $sp-md;
}
.hero-cta-emoji {
font-size: 56rpx;
}
.hero-cta-text {
flex: 1;
}
.hero-cta-title {
display: block;
font-size: $fs-xl;
font-weight: $fw-black;
color: $text-on-amber;
letter-spacing: -1rpx;
}
.hero-cta-sub {
display: block;
font-size: $fs-xs;
color: rgba(11, 11, 20, 0.6);
margin-top: 4rpx;
}
.hero-cta-arrow {
font-size: 44rpx;
color: $text-on-amber;
opacity: 0.5;
font-weight: $fw-bold;
}
.bottom-health-tip {
text-align: center;
padding: $sp-sm 0;
font-size: $fs-xs;
color: $text-tertiary;
opacity: 0.4;
}
/* 日期弹窗 */
.day-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--overlay-mask, rgba(0, 0, 0, 0.6));
display: flex;
align-items: flex-end;
z-index: 100;
padding: $sp-lg;
animation: overlayIn 0.2s ease-out;
}
@keyframes overlayIn {
from { opacity: 0; }
to { opacity: 1; }
}
.day-detail {
position: relative;
width: 100%;
padding: $sp-md $sp-xl $sp-xl;
color: $text-primary;
border-radius: $radius-xl;
/* 背景层次:底部卡片色 + 顶部琥珀光晕,日夜主题自适应 */
background:
radial-gradient(120% 60% at 50% 0%, var(--amber-glow, rgba(232, 168, 56, 0.15)) 0%, transparent 60%),
linear-gradient(180deg, var(--bg-elevated, #28283E) 0%, var(--bg-card, #1A1A28) 55%);
border: 2rpx solid var(--border-faint, rgba(255, 255, 255, 0.08));
box-shadow: var(--shadow-lg);
animation: sheetIn 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes sheetIn {
from { opacity: 0; transform: translateY(48rpx); }
to { opacity: 1; transform: translateY(0); }
}
/* 顶部拖拽把手 */
.day-detail-handle {
width: 64rpx;
height: 8rpx;
border-radius: $radius-full;
background: var(--border-active, rgba(255, 255, 255, 0.12));
margin: 0 auto $sp-md;
}
.day-detail-header {
margin-bottom: $sp-lg;
}
.day-detail-date {
position: relative;
padding-left: $sp-md;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 6rpx;
height: 70%;
border-radius: $radius-full;
background: linear-gradient(180deg, var(--amber-light, #F5C563), var(--amber-deep, #C47F17));
}
}
.day-close {
padding: $sp-xs $sp-sm;
}
.day-drinks {
background: var(--bg-subtle, rgba(255, 255, 255, 0.03));
border-radius: $radius-md;
padding: $sp-xs $sp-md;
}
.day-drink-item {
padding: $sp-md 0;
font-size: $fs-base;
color: $text-primary;
border-bottom: 2rpx solid var(--border-micro, rgba(255, 255, 255, 0.05));
&:last-child {
border-bottom: none;
}
}
.day-drink-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.day-drink-name {
display: flex;
align-items: center;
gap: $sp-xs;
flex: 1;
min-width: 0;
}
.day-drink-icon {
width: 36rpx;
height: 36rpx;
flex-shrink: 0;
}
.day-drink-amount {
font-size: $fs-sm;
color: $text-secondary;
white-space: nowrap;
margin-left: $sp-sm;
}
.day-meta {
display: flex;
gap: $sp-sm;
margin-top: $sp-lg;
}
.day-meta-chip {
display: flex;
align-items: center;
gap: $sp-xs;
padding: $sp-sm $sp-md;
border-radius: $radius-full;
}
.day-feeling-chip {
background: var(--bg-hover, rgba(255, 255, 255, 0.08));
}
.day-feeling-text {
font-size: $fs-sm;
color: $text-secondary;
}
.day-cups-chip {
background: var(--amber-glow, rgba(232, 168, 56, 0.15));
border: 2rpx solid rgba(232, 168, 56, 0.25);
}
.day-cups-num {
font-size: $fs-lg;
font-weight: $fw-bold;
color: $amber;
}
.day-cups-unit {
font-size: $fs-xs;
color: $amber;
}
.day-abstain {
text-align: center;
padding: $sp-xl 0;
}
.day-abstain-emoji {
display: block;
font-size: $fs-hero;
margin-bottom: $sp-sm;
}
.day-empty {
text-align: center;
padding: $sp-xl 0;
.btn-ghost, .day-record-btn {
margin-top: $sp-lg;
width: 100%;
}
.day-abstain-btn {
color: $mint;
border-color: rgba(94, 198, 160, 0.35);
background: rgba(94, 198, 160, 0.08);
}
}
.day-action-row {
display: flex;
gap: $sp-sm;
margin-top: $sp-lg;
}
/* 修改:琥珀主操作 */
.day-action-btn {
flex: 1;
font-size: $fs-sm;
&:first-child {
color: $text-on-amber;
background: linear-gradient(135deg, var(--amber-light, #F5C563), var(--amber-deep, #C47F17));
border: none;
box-shadow: var(--shadow-amber);
}
/* 改为未饮酒:薄荷淡底 */
&:last-child {
color: $mint;
background: rgba(94, 198, 160, 0.08);
border: 2rpx solid rgba(94, 198, 160, 0.30);
}
}
.day-delete-btn {
margin-top: $sp-md;
width: 100%;
font-size: $fs-sm;
color: #E85D3A;
background: rgba(232, 93, 58, 0.06);
border: 2rpx solid rgba(232, 93, 58, 0.30);
&:active {
background: rgba(232, 93, 58, 0.14);
}
}
.day-toggle-btn {
margin-top: $sp-lg;
width: 100%;
font-size: $fs-sm;
color: $text-secondary;
border-color: var(--border-active, rgba(255, 255, 255, 0.12));
}
</style>