forked from ccsens_fe/tall-mui-3
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.
473 lines
13 KiB
473 lines
13 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 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 swiper" :key="sitem">
|
|
<view class="calendar-days">
|
|
<!-- 当前的 -->
|
|
<template v-if="sitem === 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 === '1'" :style="dotStyle"> </view>
|
|
</view>
|
|
</template>
|
|
<template v-else>
|
|
<!-- 下一个月/周 -->
|
|
<template v-if="current - sitem === 1 || 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>
|
|
import { mapState } from 'vuex';
|
|
import { gegerateDates, formatDate } from './generateDates.js';
|
|
|
|
export default {
|
|
props: {
|
|
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: () => {
|
|
return { background: '#FF0000' };
|
|
},
|
|
},
|
|
},
|
|
|
|
watch: {
|
|
dotList: function (newvalue) {
|
|
const days = this.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;
|
|
}
|
|
});
|
|
});
|
|
this.days = days;
|
|
},
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
weeks: ['日', '一', '二', '三', '四', '五', '六'], // 周
|
|
current: 1,
|
|
currentYear: '',
|
|
currentMonth: '',
|
|
currentDate: '',
|
|
days: [],
|
|
weekMode: false, // false -> 月 true -> 显示周
|
|
swiper: [0, 1, 2],
|
|
selectedDate: formatDate(new Date(), 'yyyy-MM-dd'), // 当前选中的日期
|
|
start: '',
|
|
end: '',
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
...mapState('project', ['dotList']),
|
|
sheight() {
|
|
// 根据年月判断有多少行
|
|
// 判断该月有多少天
|
|
let h = '35px';
|
|
if (!this.weekMode) {
|
|
const d = new Date(this.currentYear, this.currentMonth, 0);
|
|
const days = d.getDate(); // 判断本月有多少天
|
|
let 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;
|
|
},
|
|
|
|
// 当前日期 年月
|
|
timeStr() {
|
|
let str = '';
|
|
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
|
|
const y = d.getFullYear();
|
|
const m = d.getMonth() + 1 <= 9 ? `0${d.getMonth() + 1}` : d.getMonth() + 1;
|
|
str = `${y}年${m}月`;
|
|
return str;
|
|
},
|
|
|
|
// 上一周期的days书籍
|
|
predays() {
|
|
let pres = [];
|
|
if (this.weekMode) {
|
|
// 周模式
|
|
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
|
|
d.setDate(d.getDate() - 7);
|
|
pres = gegerateDates(d, 'week');
|
|
} else {
|
|
// 月模式
|
|
const d = new Date(this.currentYear, this.currentMonth - 2, 1);
|
|
pres = gegerateDates(d, 'month');
|
|
}
|
|
return pres;
|
|
},
|
|
|
|
// 下一周期的days书籍
|
|
nextdays() {
|
|
let nexts = [];
|
|
if (this.weekMode) {
|
|
// 周模式
|
|
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
|
|
d.setDate(d.getDate() + 7);
|
|
nexts = gegerateDates(d, 'week');
|
|
} else {
|
|
// 月模式
|
|
const d = new Date(this.currentYear, this.currentMonth, 1);
|
|
nexts = gegerateDates(d, 'month');
|
|
}
|
|
return nexts;
|
|
},
|
|
},
|
|
|
|
created() {
|
|
this.initDate();
|
|
this.start = this.$moment().startOf('month').valueOf();
|
|
this.end = this.$moment().endOf('month').valueOf();
|
|
},
|
|
|
|
methods: {
|
|
//
|
|
/**
|
|
* 滑动切换上下周期
|
|
* 根据前一个减去目前的值我们可以判断是下一个月/周还是上一个月/周
|
|
* current - pre === 1, -2 下一个月/周
|
|
* current - pre === -1, 2 上一个月或者上一周
|
|
*/
|
|
changeSwp(e) {
|
|
const pre = this.current;
|
|
const current = e.target.current;
|
|
this.current = current;
|
|
|
|
if (current - pre === 1 || current - pre === -2) {
|
|
// 下一个月 或 下一周
|
|
this.daysNext();
|
|
const arr = this.days.filter(s => s.show);
|
|
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
|
|
this.start = this.$moment(arr[0].fullDate).valueOf();
|
|
this.end = this.$moment(end).valueOf();
|
|
this.$emit('handleFindPoint', this.start, this.end);
|
|
} else {
|
|
// 上一个月 或 上一周
|
|
this.daysPre();
|
|
const arr = this.days.filter(s => s.show);
|
|
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
|
|
this.start = this.$moment(arr[0].fullDate).valueOf();
|
|
this.end = this.$moment(end).valueOf();
|
|
this.$emit('handleFindPoint', this.start, this.end);
|
|
}
|
|
},
|
|
|
|
// 初始化日历的方法
|
|
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;
|
|
// 派发事件,时间发生改变
|
|
let 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);
|
|
},
|
|
|
|
// 上一个
|
|
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);
|
|
}
|
|
},
|
|
|
|
// 下一个
|
|
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);
|
|
}
|
|
},
|
|
|
|
// 切换模式
|
|
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);
|
|
},
|
|
|
|
// 点击日期
|
|
clickItem(e) {
|
|
this.selectedDate = e.fullDate;
|
|
this.$emit('selected-change', e);
|
|
},
|
|
|
|
// 返回
|
|
goToday() {
|
|
const d = new Date();
|
|
this.initDate(d);
|
|
},
|
|
},
|
|
};
|
|
</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>
|
|
|