Files
hejiu/components/DrinkCalendar.vue
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

216 lines
4.5 KiB
Vue
Raw Permalink 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;
color: $text-primary;
}
.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: var(--amber-glow, rgba(232, 168, 56, 0.15));
}
.cal-cell-abstain {
background: rgba(94, 198, 160, 0.06);
}
</style>