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

215 lines
4.4 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="calendar">
<!-- 月份导航 -->
<view class="cal-header">
<view class="cal-nav" @click="prevMonth">
<text class="cal-nav-arrow"></text>
</view>
<text class="cal-title">{{ year }}{{ month }}</text>
<view class="cal-nav" @click="nextMonth">
<text class="cal-nav-arrow"></text>
</view>
</view>
<!-- 星期头 -->
<view class="cal-weekdays">
<text v-for="day in weekLabels" :key="day" class="cal-weekday">{{ day }}</text>
</view>
<!-- 日期网格 -->
<view class="cal-grid">
<view
v-for="(cell, index) in calendarDays"
:key="index"
class="cal-cell"
:class="{
'cal-cell-empty': !cell.day,
'cal-cell-today': cell.isToday,
'cal-cell-future': cell.day && isFuture(cell.date),
'cal-cell-drank': getRecordMode(cell.date) === 'drank',
'cal-cell-abstain': getRecordMode(cell.date) === 'abstain'
}"
@click="cell.day && !isFuture(cell.date) && onSelectDate(cell.date)"
>
<text v-if="cell.day" class="cal-day-num">{{ cell.day }}</text>
<view v-if="getRecordMode(cell.date) === 'drank'" class="cal-dot cal-dot-drank"></view>
<view v-if="getRecordMode(cell.date) === 'abstain'" class="cal-dot cal-dot-abstain"></view>
</view>
</view>
</view>
</template>
<script>
import { getCalendarDays } from '../common/utils'
export default {
props: {
year: Number,
month: Number,
records: {
type: Array,
default: () => []
}
},
data() {
return {
weekLabels: ['一', '二', '三', '四', '五', '六', '日']
}
},
computed: {
calendarDays() {
return getCalendarDays(this.year, this.month)
}
},
methods: {
isFuture(date) {
if (!date) return false
const today = new Date()
today.setHours(0, 0, 0, 0)
const d = new Date(date.replace(/-/g, '/'))
return d > today
},
getRecordMode(date) {
if (!date) return null
const record = this.records.find(r => r.date === date)
return record ? record.mode : null
},
prevMonth() {
let y = this.year
let m = this.month - 1
if (m < 1) { y--; m = 12 }
this.$emit('change-month', { year: y, month: m })
},
nextMonth() {
let y = this.year
let m = this.month + 1
if (m > 12) { y++; m = 1 }
this.$emit('change-month', { year: y, month: m })
},
onSelectDate(date) {
this.$emit('select-date', date)
}
}
}
</script>
<style lang="scss" scoped>
.calendar {
width: 100%;
}
.cal-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: $sp-sm;
}
.cal-nav {
width: 56rpx;
height: 56rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: $radius-full;
background: $bg-elevated;
}
.cal-nav-arrow {
font-size: $fs-xl;
color: $text-secondary;
font-weight: $fw-bold;
line-height: 1;
}
.cal-title {
font-size: $fs-lg;
font-weight: $fw-bold;
font-family: $font-num;
}
.cal-weekdays {
display: grid;
grid-template-columns: repeat(7, 1fr);
margin-bottom: $sp-xs;
}
.cal-weekday {
text-align: center;
font-size: $fs-xs;
color: $text-tertiary;
padding: 4rpx 0;
}
.cal-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 4rpx;
}
.cal-cell {
aspect-ratio: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: $radius-sm;
position: relative;
transition: all $duration-fast $ease-out;
&.cal-cell-empty {
background: transparent;
}
&.cal-cell-today {
border: 2rpx solid $amber;
}
&:active:not(.cal-cell-empty):not(.cal-cell-future) {
transform: scale(0.92);
}
}
.cal-day-num {
font-size: $fs-xs;
font-weight: $fw-medium;
color: $text-primary;
font-family: $font-num;
}
.cal-dot {
width: 8rpx;
height: 8rpx;
border-radius: $radius-full;
margin-top: 4rpx;
&.cal-dot-drank {
background: $amber;
box-shadow: 0 0 12rpx rgba(232, 168, 56, 0.5);
}
&.cal-dot-abstain {
background: $mint;
box-shadow: 0 0 12rpx rgba(94, 198, 160, 0.3);
}
}
/* 未来日期置灰 */
.cal-cell-future {
opacity: 0.3;
}
.cal-cell-future .cal-day-num {
color: $text-tertiary;
}
/* 饮酒日高亮背景 */
.cal-cell-drank {
background: rgba(232, 168, 56, 0.08);
}
.cal-cell-abstain {
background: rgba(94, 198, 160, 0.06);
}
</style>