feat: 首页日历组件

This commit is contained in:
杨航
2026-01-12 10:08:59 +08:00
parent 4356a102f5
commit ae8c658351
3 changed files with 256 additions and 0 deletions
+180
View File
@@ -0,0 +1,180 @@
<template>
<view class="calendar-box">
<view class="year-box">{{nowDayObj.y}}{{nowDayObj.M}}</view>
<view class="day-box">
<view v-for="item in weekDayLabel" :class="['day-item label-name']">
<view class="item-box">{{item}}</view>
</view>
<view v-for="(item, index) in dateList" :class="['day-item',
activeDateShow === item ?'active-item':'',
todayWeek > index ?'is-pass':'',
tipDateList.includes(item)?'is-tip':''
]">
<view class="item-box" @click="chooseDate(item)">
{{
nowDayStr === item ?'':
item.split('-')[2]
}}
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref,
onMounted,
computed
} from 'vue'
import {
onShow
} from '@dcloudio/uni-app'
const emit = defineEmits(['update:modelValue'])
const props = defineProps({
modelValue: {
default: String,
default: ''
},
tipDateList: {
default: Array,
default: [
// '2026-01-15'
]
}
})
const activeDate = computed({
get: () => props.modelValue,
set: (val) => {
emit('update:modelValue', val)
emit('change', val)
activeDateShow.value = val
}
})
const activeDateShow = ref(1)
const chooseDate = (item) => {
activeDate.value = item
}
const nowDate = ref(new Date())
const nowDayStr = computed(() => {
return formatDate(nowDate.value, 'yyyy-MM-dd') || ''
})
const nowDayObj = computed(() => {
let _arr = nowDayStr.value.split(['-'])
if (_arr.length >= 2) {
return {
y: _arr[0],
M: _arr[1],
}
} else {
return {
y: '',
M: ''
}
}
})
const formatDate = (date, format) => {
const map = {
"M": date.getMonth() + 1, // 月份
"d": date.getDate(), // 日
"y": date.getFullYear(), // 年
"w": date.getDay(), // 星期
};
return format.replace(/([yMdw])\1*/g, function(key) {
return ('00' + map[key.charAt(0)]).slice(-key.length);
});
}
const weekDayLabel = ['日', '一', '二', '三', '四', '五', '六']
const getOtherDayInfo = (date, num) => {
let _lastDay = new Date(date.getTime() + num * 60 * 60 * 24 * 1000)
return formatDate(_lastDay, 'yyyy-MM-dd')
}
const todayWeek = ref(-1)
const dateList = computed(() => {
if (!nowDate.value || (todayWeek.value < 0)) {
return []
}
let _arr = []
for (let i = 0; i < 14; i++) {
let _num = i - todayWeek.value
_arr.push(getOtherDayInfo(nowDate.value, _num))
}
return _arr
})
onMounted(() => {
nowDate.value = new Date()
activeDate.value = formatDate(nowDate.value, 'yyyy-MM-dd')
todayWeek.value = nowDate.value.getDay()
})
</script>
<style lang="scss" scoped>
$day-width: 54rpx;
.year-box{
height: 50rpx;
line-height: 50rpx;
margin-bottom: 12rpx;
text-align: center;
font-size: 29rpx;
}
.day-box {
width: 100%;
overflow: hidden;
.day-item {
width: calc(100% / 7);
height: $day-width;
// background-color: #ccc;
line-height: $day-width;
font-size: 26rpx;
float: left;
margin-bottom: 20rpx;
position: relative;
&.active-item .item-box {
background-color: #06f;
color: #fff;
font-size: 29rpx;
}
&.label-name{
color: #999;
height: 50rpx;
line-height: 50rpx;
}
&.is-pass {
color: #999
}
&.is-tip{
&::after{
content: '';
width: 8rpx;
height: 8rpx;
display: block;
overflow: hidden;
background-color: #06f;
border-radius: 50%;
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
}
.item-box {
width: $day-width;
height: 100%;
text-align: center;
border-radius: calc( $day-width/2);
background-color: #fff;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
}
</style>
+73
View File
@@ -0,0 +1,73 @@
<template>
<view class="module_title_div" >
<view class="icon icon_1">
<!-- <image class="img" :src="icon"></image> -->
</view>
<view class="text font_pf">待办事项</view>
</view>
<view class="cont-box">
<calendarCom @change="changeDate"/>
{{activeDate}}
</view>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import calendarCom from './calendar.vue'
const activeDate = ref('')
const changeDate = (date) => {
console.log('date: '+date)
}
</script>
<style lang="scss" scoped>
$bg-margin-left: 30rpx;
.module_title_div {
display: flex;
margin: 30rpx $bg-margin-left;
align-items: center;
.icon {
margin-right: 6rpx;
}
.icon_1 {
.img {
width: 31rpx;
height: 36rpx;
}
}
.icon_2 {
margin-top: 10rpx;
.img {
width: 38rpx;
height: 38rpx;
}
}
.icon_3 {
// margin-top: 10rpx;
.img {
width: 38rpx;
height: 31rpx;
}
}
.title {
font-size: 34rpx;
color: #323e57;
font-weight: 700;
line-height: 46rpx;
text-align: left;
}
}
.cont-box{
margin: 0 $bg-margin-left;
background-color: #fff;
border-radius: 22rpx;
padding: 20rpx;
}
</style>
+3
View File
@@ -156,6 +156,7 @@
<classScroll :ref="(el) => (classScrollRef[0] = el)" name="hot_class"></classScroll>
<classScroll :ref="(el) => (classScrollRef[1] = el)" name="recommend_class"></classScroll>
<classScroll :ref="(el) => (classScrollRef[2] = el)" name="new_class"></classScroll>
<toDoCom></toDoCom>
<view class="bottom_line">
<uv-divider text="我是有底线的" lineColor="#9cB0DC" :hairline="true"></uv-divider>
</view>
@@ -184,6 +185,8 @@
import badge from '@/components/points-and-badge/badge';
import points from '@/components/points-and-badge/points';
import usePointsAndBadge from '@/components/points-and-badge/usePointsAndBadge';
import toDoCom from './components/todo.vue'
const { initCheckInStatus, checkInRef, checkInFun, startLotteryFun, holidayRef } = useCheckIn();
const { handlePointsBadgePopup, badgeRef, pointsRef } = usePointsAndBadge();
const scrollTop = ref(0);