<template>
<u-popup
class="popup"
:maskCloseAble="maskCloseAble"
mode="bottom"
:popup="false"
v-model="value"
length="auto"
:safeAreaInsetBottom="safeAreaInsetBottom"
@close="close"
:z-index="uZIndex"
:border-radius="borderRadius"
:closeable="closeable"
>
<view class="u-calendar">
<view class="u-calendar__header">
<view class="u-calendar__header__text" v-if="!$slots['tooltip']">{{toolTip}}</view>
<slot v-else name="tooltip" />
</view>
<view class="u-calendar__action u-flex u-row-center">
<view class="u-calendar__action__icon">
<u-icon
v-if="changeYear"
name="arrow-left-double"
:color="yearArrowColor"
@click="changeYearHandler(0)"
></u-icon>
</view>
<view class="u-calendar__action__icon">
<u-icon
v-if="changeMonth"
name="arrow-left"
:color="monthArrowColor"
@click="changeMonthHandler(0)"
></u-icon>
</view>
<view class="u-calendar__action__text">{{ showTitle }}</view>
<view class="u-calendar__action__icon">
<u-icon
v-if="changeMonth"
name="arrow-right"
:color="monthArrowColor"
@click="changeMonthHandler(1)"
></u-icon>
</view>
<view class="u-calendar__action__icon">
<u-icon
v-if="changeYear"
name="arrow-right-double"
:color="yearArrowColor"
@click="changeYearHandler(1)"
></u-icon>
</view>
</view>
<view class="u-calendar__week-day">
<view
class="u-calendar__week-day__text"
v-for="(item, index) in weekDayZh"
:key="index"
>{{item}}</view>
</view>
<view class="u-calendar__content">
<block v-for="(item, index) in weekdayArr" :key="index">
<view class="u-calendar__content__item"></view>
</block>
<view
class="u-calendar__content__item"
:class="{
'u-hover-class':openDisAbled(year,month,index+1),
'u-calendar__content--start-date': (mode == 'range' && startDate==`${year}-${month}-${index+1}`) || mode== 'date',
'u-calendar__content--end-date':(mode== 'range' && endDate==`${year}-${month}-${index+1}`) || mode == 'date'
}"
:style="{backgroundColor: getColor(index,1)}"
v-for="(item, index) in daysArr"
:key="index"
@tap="dateClick(index)"
>
<view class="u-calendar__content__item__inner" :style="{color: getColor(index,2)}">
<view>{{ index + 1 }}</view>
</view>
<view
class="u-calendar__content__item__tips"
:style="{color:activeColor}"
v-if="mode== 'range' && startDate==`${year}-${month}-${index+1}` && startDate!=endDate"
>{{startText}}</view>
<view
class="u-calendar__content__item__tips"
:style="{color:activeColor}"
v-if="mode== 'range' && endDate==`${year}-${month}-${index+1}`"
>{{endText}}</view>
</view>
<view class="u-calendar__content__bg-month">{{month}}</view>
</view>
<view class="u-calendar__bottom">
<view class="u-calendar__bottom__choose">
<text>{{mode == 'date' ? activeDate : startDate}}</text>
<text v-if="endDate">{{i18nMsg.base.calendarMoudle.to}}{{endDate}}</text>
</view>
<view class="u-calendar__bottom__btn">
<u-button :type="btnType" shape="circle" size="default" @click="btnFix(false)">{{i18nMsg.base.calendarMoudle.ensure}}</u-button>
</view>
</view>
</view>
</u-popup>
</template>
<script>
import i18n from '@autel/mobile-base-library/lib/i18n'
const i18nMsg=i18n.messages[i18n.locale];
export default {
name: 'u-calendar',
props: {
safeAreaInsetBottom: {
type: Boolean,
default: false
},
maskCloseAble: {
type: Boolean,
default: true
},
value: {
type: Boolean,
default: false
},
zIndex: {
type: [String, Number],
default: 0
},
changeYear: {
type: Boolean,
default: true
},
changeMonth: {
type: Boolean,
default: true
},
mode: {
type: String,
default: 'date'
},
maxYear: {
type: [Number, String],
default: 2050
},
minYear: {
type: [Number, String],
default: 1950
},
minDate: {
type: [Number, String],
default: '1950-01-01'
},
maxDate: {
type: [Number, String],
default: ''
},
borderRadius: {
type: [String, Number],
default: 20
},
monthArrowColor: {
type: String,
default: '#606266'
},
yearArrowColor: {
type: String,
default: '#909399'
},
color: {
type: String,
default: '#303133'
},
activeBgColor: {
type: String,
default: '#2979ff'
},
activeColor: {
type: String,
default: '#ffffff'
},
rangeBgColor: {
type: String,
default: 'rgba(41,121,255,0.13)'
},
rangeColor: {
type: String,
default: '#2979ff'
},
startText: {
type: String,
default: '开始'
},
endText: {
type: String,
default: '结束'
},
btnType: {
type: String,
default: 'primary'
},
isActiveCurrent: {
type: Boolean,
default: true
},
isChange: {
type: Boolean,
default: false
},
closeable: {
type: Boolean,
default: true
},
toolTip: {
type: String,
default: '选择日期'
}
},
data() {
return {
weekday: 1,
weekdayArr: [],
days: 0,
daysArr: [],
showTitle: '',
i18nMsg:i18nMsg,
year: 2020,
month: 0,
day: 0,
startYear: 0,
startMonth: 0,
startDay: 0,
endYear: 0,
endMonth: 0,
endDay: 0,
today: '',
activeDate: '',
startDate: '',
endDate: '',
isStart: true,
min: null,
max: null,
weekDayZh: [i18nMsg.base.calendarMoudle.day7, i18nMsg.base.calendarMoudle.day1,
i18nMsg.base.calendarMoudle.day2, i18nMsg.base.calendarMoudle.day3,i18nMsg.base.calendarMoudle.day4, i18nMsg.base.calendarMoudle.day5, i18nMsg.base.calendarMoudle.day6]
}
},
computed: {
dataChange() {
return `${this.mode}-${this.minDate}-${this.maxDate}`
},
uZIndex() {
return this.zIndex ? this.zIndex : this.$u.zIndex.popup
}
},
watch: {
dataChange(val) {
this.init()
}
},
created() {
this.init()
},
methods: {
getColor(index, type) {
let color = type == 1 ? '' : this.color
let day = index + 1
let date = `${this.year}-${this.month}-${day}`
let timestamp = new Date(date.replace(/\-/g, '/')).getTime()
let start = this.startDate.replace(/\-/g, '/')
let end = this.endDate.replace(/\-/g, '/')
if (
(this.isActiveCurrent && this.activeDate == date) ||
this.startDate == date ||
this.endDate == date
) {
color = type == 1 ? this.activeBgColor : this.activeColor
} else if (
this.endDate &&
timestamp > new Date(start).getTime() &&
timestamp < new Date(end).getTime()
) {
color = type == 1 ? this.rangeBgColor : this.rangeColor
}
return color
},
init() {
let now = new Date()
this.year = now.getFullYear()
this.month = now.getMonth() + 1
this.day = now.getDate()
this.today = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`
this.activeDate = this.today
this.min = this.initDate(this.minDate)
this.max = this.initDate(this.maxDate || this.today)
this.startDate = ''
this.startYear = 0
this.startMonth = 0
this.startDay = 0
this.endYear = 0
this.endMonth = 0
this.endDay = 0
this.endDate = ''
this.isStart = true
this.changeData()
},
initDate(date) {
let fdate = date.split('-')
return {
year: Number(fdate[0] || 1920),
month: Number(fdate[1] || 1),
day: Number(fdate[2] || 1)
}
},
openDisAbled: function(year, month, day) {
let bool = true
let date = `${year}/${month}/${day}`
let min = `${this.min.year}/${this.min.month}/${this.min.day}`
let max = `${this.max.year}/${this.max.month}/${this.max.day}`
let timestamp = new Date(date).getTime()
if (
timestamp >= new Date(min).getTime() &&
timestamp <= new Date(max).getTime()
) {
bool = false
}
return bool
},
generateArray: function(start, end) {
return Array.from(new Array(end + 1).keys()).slice(start)
},
formatNum: function(num) {
return num < 10 ? '0' + num : num + ''
},
getMonthDay(year, month) {
let days = new Date(year, month, 0).getDate()
return days
},
getWeekday(year, month) {
let date = new Date(`${year}/${month}/01 00:00:00`)
return date.getDay()
},
checkRange(year) {
let overstep = false
if (year < this.minYear || year > this.maxYear) {
uni.showToast({
title: i18nMsg.base.calendarMoudle.overday+"~",
icon: 'none'
})
overstep = true
}
return overstep
},
changeMonthHandler(isAdd) {
if (isAdd) {
let month = this.month + 1
let year = month > 12 ? this.year + 1 : this.year
if (!this.checkRange(year)) {
this.month = month > 12 ? 1 : month
this.year = year
this.changeData()
}
} else {
let month = this.month - 1
let year = month < 1 ? this.year - 1 : this.year
if (!this.checkRange(year)) {
this.month = month < 1 ? 12 : month
this.year = year
this.changeData()
}
}
},
changeYearHandler(isAdd) {
let year = isAdd ? this.year + 1 : this.year - 1
if (!this.checkRange(year)) {
this.year = year
this.changeData()
}
},
changeData() {
this.days = this.getMonthDay(this.year, this.month)
this.daysArr = this.generateArray(1, this.days)
this.weekday = this.getWeekday(this.year, this.month)
this.weekdayArr = this.generateArray(1, this.weekday)
this.showTitle = `${this.year}/${this.month}`
if (this.isChange && this.mode == 'date') {
this.btnFix(true)
}
},
dateClick: function(day) {
day += 1
if (!this.openDisAbled(this.year, this.month, day)) {
this.day = day
let date = `${this.year}-${this.month}-${day}`
if (this.mode == 'date') {
this.activeDate = date
} else {
let compare =
new Date(date.replace(/\-/g, '/')).getTime() <
new Date(this.startDate.replace(/\-/g, '/')).getTime()
if (this.isStart || compare) {
this.startDate = date
this.startYear = this.year
this.startMonth = this.month
this.startDay = this.day
this.endYear = 0
this.endMonth = 0
this.endDay = 0
this.endDate = ''
this.activeDate = ''
this.isStart = false
} else {
this.endDate = date
this.endYear = this.year
this.endMonth = this.month
this.endDay = this.day
this.isStart = true
}
}
}
},
close() {
this.$emit('input', false)
},
getWeekText(date) {
date = new Date(`${date.replace(/\-/g, '/')} 00:00:00`)
let week = date.getDay()
return '星期' + ['日', '一', '二', '三', '四', '五', '六'][week]
},
btnFix(show) {
if (!show) {
this.close()
}
if (this.mode == 'date') {
let arr = this.activeDate.split('-')
let year = this.isChange ? this.year : Number(arr[0])
let month = this.isChange ? this.month : Number(arr[1])
let day = this.isChange ? this.day : Number(arr[2])
let days = this.getMonthDay(year, month)
let result = `${year}-${this.formatNum(month)}-${this.formatNum(day)}`
let weekText = this.getWeekText(result)
let isToday = false
if (`${year}-${month}-${day}` == this.today) {
isToday = true
}
this.$emit('change', {
year: year,
month: month,
day: day,
days: days,
result: result,
week: weekText,
isToday: isToday
})
} else {
if (!this.startDate || !this.endDate) return
let startMonth = this.formatNum(this.startMonth)
let startDay = this.formatNum(this.startDay)
let startDate = `${this.startYear}-${startMonth}-${startDay}`
let startWeek = this.getWeekText(startDate)
let endMonth = this.formatNum(this.endMonth)
let endDay = this.formatNum(this.endDay)
let endDate = `${this.endYear}-${endMonth}-${endDay}`
let endWeek = this.getWeekText(endDate)
this.$emit('change', {
startYear: this.startYear,
startMonth: this.startMonth,
startDay: this.startDay,
startDate: startDate,
startWeek: startWeek,
endYear: this.endYear,
endMonth: this.endMonth,
endDay: this.endDay,
endDate: endDate,
endWeek: endWeek
})
}
}
}
}
</script>
<style scoped lang="scss">
@import '../../libs/css/style.components.scss';
.popup {
.u-calendar {
color: #606266;
background: #EBEBEB;
.u-calendar__week-day {
font-size: 24px;
}
// .u-calendar__action__icon {
// font-size: 19px;
// }
&__header {
width: 100%;
box-sizing: border-box;
font-size: 15rpx;
background: #EBEBEB;
color: #303133;
&__text {
margin-top: 15rpx;
padding: 0 30rpx;
display: flex;
justify-content: center;
align-items: center;
}
}
&__action {
padding: 20rpx 0 20rpx 0;
&__icon {
margin: 0 8rpx;
}
&__text {
padding: 0 8rpx;
color: #303133;
font-size: 16rpx;
line-height: 16rpx;
font-weight: bold;
}
}
&__week-day {
display: flex;
align-items: center;
justify-content: center;
padding: 6px 0;
overflow: hidden;
&__text {
flex: 1;
text-align: center;
}
}
&__content {
width: 100%;
display: flex;
flex-wrap: wrap;
padding: 6px 0;
box-sizing: border-box;
background: #EBEBEB;
position: relative;
&--end-date {
border-top-right-radius: 4rpx;
border-bottom-right-radius: 4rpx;
}
&--start-date {
border-top-left-radius: 4rpx;
border-bottom-left-radius: 4rpx;
}
&__item {
width: 14.2857%;
display: flex;
align-items: center;
justify-content: center;
padding: 6px 0;
overflow: hidden;
position: relative;
z-index: 2;
&__inner {
height: 42rpx;
display: -webkit-box;
display: -webkit-flex;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-size: 16rpx;
position: relative;
border-radius: 50%;
&__desc {
width: 100%;
font-size: 12rpx;
line-height: 12rpx;
transform: scale(0.75);
transform-origin: center center;
position: absolute;
left: 0;
text-align: center;
bottom: 2rpx;
}
}
&__tips {
width: 100%;
font-size: 12rpx;
line-height: 12rpx;
position: absolute;
left: 0;
transform: scale(0.8);
transform-origin: center center;
text-align: center;
bottom: 4rpx;
z-index: 2;
}
}
&__bg-month {
position: absolute;
font-size: 17.85rpx;
line-height: 17.85rpx;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: #e4e7ed;
z-index: 1;
}
}
&__bottom {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: #EBEBEB;
padding: 0 20rpx 15rpx;
box-sizing: border-box;
font-size: 12rpx;
color: #909399;
&__choose {
height: 25rpx;
}
&__btn {
width: 100%;
}
}
}
}
</style>