h5
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

445 lines
12 KiB

<template>
<view class="zzx-calendar">
<view class="calendar-heander">{{ timeStr }}</view>
<!-- 星期几标题 -->
<view class="calendar-weeks">
<view class="calendar-week" :class="{ 'text-red-500': week === '六' || week === '日' }" v-for="(week, index) in data.weeks" :key="index">{{ week }}</view>
</view>
<view class="calendar-content">
<swiper
class="calendar-swiper"
:style="{
width: '100%',
height: sheight,
}"
:indicator-dots="false"
:autoplay="false"
:duration="duration"
:current="current"
@change="changeSwp"
:circular="true"
>
<swiper-item class="calendar-item" v-for="sitem in data.swiper" :key="sitem">
<view class="calendar-days">
<!-- 当前的 -->
<template v-if="sitem === data.current">
<view class="calendar-day" v-for="(item, index) in days" :key="index" :class="{ 'day-hidden': !item.show }" @click="clickItem(item)">
<view class="date" :class="[item.isToday ? todayClass : '', item.fullDate === selectedDate ? checkedClass : '']">{{ item.time.getDate() }}</view>
<view class="dot-show" v-if="item.info === '0'" :style="dotStyle"></view>
</view>
</template>
<template v-else>
<!-- 下一个月/ -->
<template v-if="data.current - sitem === 1 || data.current - sitem === -2">
<view
class="calendar-day"
v-for="(item, index) in predays"
:key="index"
:class="{
'day-hidden': !item.show,
}"
>
<view class="date" :class="[item.isToday ? todayClass : '']">{{ item.time.getDate() }}</view>
</view>
</template>
<!-- 上一个月/周 -->
<template v-else>
<view
class="calendar-day"
v-for="(item, index) in nextdays"
:key="index"
:class="{
'day-hidden': !item.show,
}"
>
<view class="date" :class="[item.isToday ? todayClass : '']">{{ item.time.getDate() }}</view>
</view>
</template>
</template>
</view>
</swiper-item>
</swiper>
<!-- <view class="mode-change" @click="changeMode">
<view :class="weekMode ? 'mode-arrow-bottom' : 'mode-arrow-top'"> </view>
</view> -->
</view>
<view class="flex justify-center u-font-18" style="color: #3b82f6" @click="goToday">今日</view>
</view>
</template>
<script setup>
import { reactive, computed, watch, defineProps, defineEmits } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import { gegerateDates, formatDate } from './generateDates.js';
defineProps({
duration: { type: Number, default: 500 },
// 是否返回今日
showBack: { type: Boolean, default: false },
// 今日的自定义样式class
todayClass: { type: String, default: 'is-today' },
// 选中日期的样式class
checkedClass: { type: String, default: 'is-checked' },
// 打点日期的自定义样式
dotStyle: {
type: Object,
default: () => ({ background: '#4ade80' }),
},
});
const emit = defineEmits(['handleFindPoint', 'handleFindPoint']);
const data = reactive({
weeks: ['日', '一', '二', '三', '四', '五', '六'], // 周
current: 1,
currentYear: '',
currentMonth: '',
currentDate: '',
days: [],
weekMode: false, // false -> 月 true -> 显示周
swiper: [0, 1, 2],
selectedDate: formatDate(new Date(), 'yyyy-MM-dd'), // 当前选中的日期
start: dayjs()
.startOf('month')
.valueOf(),
end: dayjs()
.endOf('month')
.valueOf(),
});
const store = useStore();
const dotList = computed(() => store.state.project.dotList);
const sheight = computed(() => {
// 根据年月判断有多少行
// 判断该月有多少天
let h = '35px';
if (!data.weekMode) {
const d = new Date(data.currentYear, data.currentMonth, 0);
const days = d.getDate(); // 判断本月有多少天
const day = new Date(d.setDate(1)).getDay();
// if (day === 0) {
// day = 7;
// }
const pre = 8 - day;
const rows = Math.ceil((days - pre) / 7) + 1;
h = `${35 * rows}px`;
}
return h;
});
// 当前日期 年月
const timeStr = computed(() => {
let str = '';
const d = new Date(data.currentYear, data.currentMonth - 1, data.currentDate);
const y = d.getFullYear();
const m = d.getMonth() + 1 <= 9 ? `0${d.getMonth() + 1}` : d.getMonth() + 1;
str = `${y}${m}`;
return str;
});
// 上一周期的days书籍
const predays = computed(() => {
let pres = [];
if (data.weekMode) {
// 周模式
const d = new Date(data.currentYear, data.currentMonth - 1, data.currentDate);
d.setDate(d.getDate() - 7);
pres = gegerateDates(d, 'week');
} else {
// 月模式
const d = new Date(data.currentYear, data.currentMonth - 2, 1);
pres = gegerateDates(d, 'month');
}
return pres;
});
// 下一周期的days书籍
const nextdays = computed(() => {
let nexts = [];
if (data.weekMode) {
// 周模式
const d = new Date(data.currentYear, data.currentMonth - 1, data.currentDate);
d.setDate(d.getDate() + 7);
nexts = gegerateDates(d, 'week');
} else {
// 月模式
const d = new Date(data.currentYear, data.currentMonth, 1);
nexts = gegerateDates(d, 'month');
}
return nexts;
});
watch(dotList, newValue => {
// 直接监听
const days = data.days.slice(0);
const index = days.findIndex(day => day.show);
days.forEach((day, i) => {
newValue.forEach((item, j) => {
if (i - index === j) {
day.info = item;
}
});
});
data.days = days;
});
// 上一个
const daysPre = () => {
// if (this.weekMode) {
// const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
// d.setDate(d.getDate() - 7);
// this.initDate(d);
// } else {
// const d = new Date(this.currentYear, this.currentMonth - 2, 1);
// this.initDate(d);
// }
};
// 下一个
const daysNext = () => {
// if (this.weekMode) {
// const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
// d.setDate(d.getDate() + 7);
// this.initDate(d);
// } else {
// const d = new Date(this.currentYear, this.currentMonth, 1);
// this.initDate(d);
// }
};
/**
* 滑动切换上下周期
* 根据前一个减去目前的值我们可以判断是下一个月/周还是上一个月/周
* current - pre === 1, -2 下一个月/周
* current - pre === -1, 2 上一个月或者上一周
*/
const changeSwp = e => {
const pre = data.current;
const { current } = e.target;
data.current = current;
if (current - pre === 1 || current - pre === -2) {
// 下一个月 或 下一周
daysNext();
const arr = data.days.filter(s => s.show);
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
data.start = dayjs(arr[0].fullDate).valueOf();
data.end = dayjs(end).valueOf();
emit('handleFindPoint', this.start, this.end);
} else {
// 上一个月 或 上一周
daysPre();
const arr = data.days.filter(s => s.show);
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
data.start = dayjs(arr[0].fullDate).valueOf();
data.end = dayjs(end).valueOf();
emit('handleFindPoint', this.start, this.end);
}
};
// 初始化日历的方法
const initDate = cur => {
// let date = '';
// if (cur) {
// date = new Date(cur);
// } else {
// date = new Date();
// }
// this.currentDate = date.getDate(); // 今日几号
// this.currentYear = date.getFullYear(); // 当前年份
// this.currentMonth = date.getMonth() + 1; // 当前月份
// this.currentWeek = date.getDay() === 0 ? 7 : date.getDay(); // 1...6,0 星期几
// // const nowY = new Date().getFullYear(); // 当前年份
// // const nowM = new Date().getMonth() + 1;
// // const nowD = new Date().getDate(); // 今日日期 几号
// // const nowW = new Date().getDay();
// // this.selectedDate = formatDate(new Date(), 'yyyy-MM-dd')
// this.days = [];
// let days = [];
// if (this.weekMode) {
// days = gegerateDates(date, 'week');
// // this.selectedDate = days[0].fullDate;
// } else {
// days = gegerateDates(date, 'month');
// // const sel = new Date(this.selectedDate.replace('-', '/').replace('-', '/'));
// // const isMonth = sel.getFullYear() === this.currentYear && (sel.getMonth() + 1) === this.currentMonth;
// // if(!isMonth) {
// // this.selectedDate = formatDate(new Date(this.currentYear, this.currentMonth-1,1), 'yyyy-MM-dd')
// // }
// }
// // 设置小红点
// days.forEach((day, i) => {
// this.dotList.forEach((item, j) => {
// if (i === j) {
// day.info = item;
// }
// });
// });
// this.days = days;
// // 派发事件,时间发生改变
// const obj = {
// start: '',
// end: '',
// };
// if (this.weekMode) {
// obj.start = this.days[0].time;
// obj.end = this.days[6].time;
// } else {
// const start = new Date(this.currentYear, this.currentMonth - 1, 1);
// const end = new Date(this.currentYear, this.currentMonth, 0);
// obj.start = start;
// obj.end = end;
// }
// this.$emit('days-change', obj);
};
// 切换模式
const changeMode = () => {
// const premode = this.weekMode;
// let isweek = false;
// if (premode) {
// isweek = !!this.days.find((item) => item.fullDate === this.selectedDate);
// }
// this.weekMode = !this.weekMode;
// let d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
// const sel = new Date(this.selectedDate.replace('-', '/').replace('-', '/'));
// const isMonth = sel.getFullYear() === this.currentYear && sel.getMonth() + 1 === this.currentMonth;
// if ((this.selectedDate && isMonth) || isweek) {
// d = new Date(this.selectedDate.replace('-', '/').replace('-', '/'));
// }
// this.initDate(d);
};
// 点击日期
const clickItem = e => {
// this.selectedDate = e.fullDate;
// this.$emit('selected-change', e);
};
// 返回
const goToday = () => {
// const d = new Date();
// this.initDate(d);
};
initDate();
</script>
<style lang="scss" scoped>
.zzx-calendar {
width: 100%;
height: auto;
background-color: #fff;
padding-bottom: 10px;
.calendar-heander {
text-align: center;
padding: 16px 0;
position: relative;
font-size: 15px;
}
.calendar-weeks {
width: 100%;
display: flex;
flex-flow: row nowrap;
margin-bottom: 10px;
justify-content: center;
align-items: center;
font-size: 12px;
color: #9ca3af;
font-weight: bold;
.calendar-week {
width: calc(100% / 7);
height: 100%;
text-align: center;
}
}
swiper {
width: 100%;
height: 60upx;
}
.calendar-content {
min-height: 30px;
}
.calendar-swiper {
min-height: 35px;
transition: height ease-out 0.3s;
}
.calendar-item {
margin: 0;
padding: 0;
height: 100%;
}
.calendar-days {
display: flex;
flex-flow: row wrap;
width: 100%;
height: 100%;
overflow: hidden;
font-size: 14px;
.calendar-day {
width: calc(100% / 7);
height: 35px;
text-align: center;
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
align-items: center;
position: relative;
}
}
.day-hidden {
visibility: hidden;
}
.mode-change {
display: flex;
justify-content: center;
margin-top: 5px;
.mode-arrow-top {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 5px solid #ff6633;
}
.mode-arrow-bottom {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 5px solid #ff6633;
}
}
.is-today {
background: #ffffff;
border: 1upx solid #ff6633;
border-radius: 50%;
color: #ff6633;
}
.is-checked {
background: #ff6633;
color: #ffffff;
}
.date {
width: 25px;
height: 25px;
line-height: 25px;
margin: 0 auto;
border-radius: 25px;
}
.dot-show {
width: 6px;
height: 6px;
// background: red;
border-radius: 5px;
position: absolute;
top: 2px;
right: 10px;
}
}
</style>