Files
hejiu/components/DrinkCalendar.vue
T
cg f945ccf4c7 feat(app): 初始化喝酒了么小程序基础架构
- 添加项目配置文件(.editorconfig, .gitignore)
- 创建App.vue主应用文件,包含启动时Mock数据初始化
- 添加index.html和main.js应用入口文件
- 配置manifest.json应用基本信息和权限设置
- 设置pages.json页面路由和全局样式
- 添加uni.promisify.adaptor.js适配器文件
- 创建uni.scss设计令牌系统,定义琥珀夜光主题色彩
- 新增constants.js常量定义,包含酒类分类和品牌数据
2026-07-13 22:15:16 +08:00

198 lines
4.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="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-drank': getRecordMode(cell.date) === 'drank',
'cal-cell-abstain': getRecordMode(cell.date) === 'abstain'
}"
@click="cell.day && 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: {
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-lg;
}
.cal-nav {
width: 64rpx;
height: 64rpx;
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-sm;
}
.cal-weekday {
text-align: center;
font-size: $fs-xs;
color: $text-tertiary;
padding: $sp-xs 0;
}
.cal-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: $sp-xs;
}
.cal-cell {
aspect-ratio: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: $radius-md;
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) {
transform: scale(0.92);
}
}
.cal-day-num {
font-size: $fs-sm;
font-weight: $fw-medium;
color: $text-primary;
font-family: $font-num;
}
.cal-dot {
width: 10rpx;
height: 10rpx;
border-radius: $radius-full;
margin-top: $sp-xs;
&.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-drank {
background: rgba(232, 168, 56, 0.08);
}
.cal-cell-abstain {
background: rgba(94, 198, 160, 0.06);
}
</style>