日历修改

This commit is contained in:
huichao
2020-07-27 15:41:31 +08:00
parent 51e7486f9f
commit ba3c497b2b
8 changed files with 2167 additions and 36 deletions

View File

@@ -50,7 +50,7 @@
</div>
<div class="flex h50 border-gb ml15 align-items-c fwb">
<div>迟到</div>
<div class="absolute right30 c-gray-base">{{lateNum}}</div>
<div class="absolute right30 c-gray-base">{{lateNum}},{{lateTime}}分钟</div>
</div>
<div class="flex h50 border-gb ml15 align-items-c fwb">
<div>早退</div>

View File

@@ -0,0 +1,775 @@
<template>
<div class="calendar_body" v-show="show">
<div class="calendar_week" ref="weekTitle">
<div class="calendar_item" v-for="item in calendarWeek" :key="item">
<p class="calendar_day">{{ item }}</p>
</div>
</div>
<div
class="calendar_group"
:style="{ height: `${calendarGroupHeight}px` }"
ref="calendar"
@touchstart="touchStart"
@touchmove.stop.prevent="touchMove"
@touchend="touchEnd"
>
<ul :style="{ transform: `translate3d(${-translateIndex * 100}%, 0, 0)` }">
<li
class="calendar_group_li"
v-for="(item, i) in calendarOfMonthShow"
:key="i"
:style="{
transform: `translate3d(${(i - 1 + translateIndex + (isTouching ? touch.x : 0)) * 100}%, ${calendarY}px, 0)`,
transitionDuration: `${isTouching ? 0 : transitionDuration}s`
}"
>
<div
class="calendar_item"
ref="calendarItem"
v-for="(date, j) in item"
:key="i + j"
:class="{ calendar_item_disable: formatDisabledDate(date) }"
@click="clickCalendarDay(date)"
>
<div class="calendar_day_nochecked" :class="{ calendar_day_checked: isCheckedDay(date) }">
<p
v-if="date.day === 1 && !isNotCurrentMonthDay(date, i)"
:class="{ checked_color: isCheckedDay(date) }"
class="calendar_day calendar_first_today"
ref="calendarDay"
>
{{ calendarMonth[date.month] }}
</p>
<p
v-else
class="calendar_day"
ref="calendarDay"
:style="{ 'border-color': markDateColor(date, 'circle') }"
:class="{
checked_color: isCheckedDay(date),
calendar_day_today: isToday(date),
calendar_day_not: isNotCurrentMonthDay(date, i),
calendar_mark_circle: markDateColor(date, 'circle')
}"
>
{{ date.day }}
</p>
<p
class="fs10 text-center calendar_day_not"
:class="{
checked_color: isCheckedDay(date),
calendar_day_today: isToday(date),
calendar_mark_circle: markDateColor(date, 'circle')
}"
>
{{ lunar(date) }}
</p>
</div>
<div :style="{ background: markDateColor(date, 'dot') }" class="calendar_dot"></div>
</div>
</li>
</ul>
</div>
</div>
</template>
<script>
import { formatDate } from './utils/util'
import sloarToLunar from './utils/calendarConvert'
export default {
name: 'Calendar',
props: {
// 滑动的时候,是否触发改变日期
scrollChangeDate: {
type: Boolean,
default: true
},
// 禁用周视图
disabledWeekView: {
type: Boolean,
default: false
},
defaultDate: {
type: Date,
default() {
return new Date()
}
},
show: {
type: Boolean,
default: false
},
weekStart: {
type: String,
default: 'Sunday'
},
// 是否展示周视图
isShowWeekView: {
type: Boolean,
default: false
},
// 日期下面的标记
markDate: {
type: Array,
default: () => []
},
// 日期标记类型
markType: {
type: String,
default: 'dot'
},
// 禁用的日期
disabledDate: {
type: Function,
default: () => {
return false
}
},
// 使用的语言包
lang: {
type: String,
default: 'CN'
}
},
data() {
return {
currentChangeIsScroll: false, // 改变当前日期的方式是否为滑动事件
yearOfCurrentShow: new Date().getFullYear(), // 当前日历展示的年份
monthOfCurrentShow: new Date().getMonth(), // 当前日历展示的月份
yearOfToday: new Date().getFullYear(), // 今天所在的年份
monthOfToday: new Date().getMonth(), // 今天所在的月份
dayOfToday: new Date().getDate(), // 今天所在的日期
weekArray: ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'], // 星期数组
calendarWeek: ['日', '一', '二', '三', '四', '五', '六'], // 日历对应的星期
calendarMonth: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
calendarOfMonth: [], // 月份对应的日历表
calendarOfMonthShow: [], // 月份对应的日历表
calendarDaysTotalLength: 42, // 日历表展示的总天数 6行7列
lastMonthYear: null, // 上个月的年份
lastMonth: null, // 上个月的月份
nextMonthYear: null, // 下个月的年份
nextMonth: null, // 下个月的月份
checkedDate: {}, // 被选中的日期
weekStartIndex: 0, // 日历第一天星期名称的index
translateIndex: 0, // 用于计算上下偏移的距离
transitionDuration: 0.3, // 动画持续时间
touch: {
x: 0,
y: 0
}, // 本次touch事件横向纵向滑动的距离
isTouching: false, // 是否正在滑动
calendarGroupHeight: 0,
calendarWeekTitleHeight: 0,
calendarItemHeight: 0,
touchStartPositionX: null, // 开始滑动x轴的值
touchStartPositionY: null, // 开始滑动时y轴的值
isShowWeek: false, // 当前日历是否以星期方式展示
calendarY: 0, // 日历相对于Y轴的位置
selectedDayIndex: 0, // 当前选中的日期,在这一周的第几天
lastWeek: [], // 上一周的数据
nextWeek: [], // 下一周的数据
isLastWeekInCurrentMonth: false, // 上一周的数据是否在本月
isNextWeekInCurrentMonth: false, // 下一周的数据是否在本月
markDateColorObj: [] // 所有被标记的日期所对应的颜色
}
},
mounted() {
this.weekStartIndex = this.weekArray.indexOf(this.weekStart.toLowerCase())
this.calendarWeek = [...this.calendarWeek.slice(this.weekStartIndex, this.calendarWeek.length), ...this.calendarWeek.slice(0, this.weekStartIndex)]
},
watch: {
markDate: {
handler(val) {
val.forEach((item, index) => {
if (item.color === undefined) {
let obj = {}
obj.color = '#E9332E'
if (typeof item === 'string' || typeof item === 'number') {
item = [item]
}
obj.date = item || []
val[index] = obj
}
/* val[index].forEach(dateObj => {
this.$set(this.markDateColorObj, this.formatDate(dateObj.date), dateObj.color)
}) 待简化 */
val[index].date = this.dateFormat(val[index].date)
})
this.markDateColorObj = []
val.forEach(item => {
item.date.forEach(date => {
this.$set(this.markDateColorObj, date, item.color)
})
})
},
deep: true,
immediate: true
},
weekStartIndex() {
this.calculateCalendarOfThreeMonth(this.checkedDate.year, this.checkedDate.month)
},
defaultDate: {
handler(val) {
if (!(val instanceof Date)) {
throw new Error(`The calendar component's defaultDate must be date type!`)
}
this.$set(this.checkedDate, 'day', val.getDate())
this.calculateCalendarOfThreeMonth(val.getFullYear(), val.getMonth())
},
immediate: true
},
checkedDate: {
handler(val) {
this.$emit('change', val)
},
deep: true,
immediate: true
},
show: {
handler(val) {
if (val) {
this.calculateCalendarOfThreeMonth(this.checkedDate.year, this.checkedDate.month)
this.initDom()
}
},
immediate: true
},
isShowWeekView: {
handler(val) {
if (val) {
this.$nextTick(() => {
this.showWeek()
})
} else {
this.$nextTick(() => {
this.showMonth()
})
}
},
immediate: true
},
calendarGroupHeight(val) {
this.$emit('height', val + this.calendarWeekTitleHeight)
}
},
computed: {},
methods: {
lunar(date) {
let lunar = sloarToLunar.solarToLunar(new Date(date.year, date.month, date.day), 'MD')
return lunar.slice(lunar.indexOf('月') + 1)
},
initDom() {
// 初始化日历dom
this.$nextTick(() => {
this.calendarItemHeight = this.$refs.calendarDay[0].offsetHeight + 35
this.calendarWeekTitleHeight = this.$refs.weekTitle.offsetHeight
let calendarItemGroup = this.$refs.calendarItem
calendarItemGroup.forEach(item => {
item.style.height = `${this.calendarItemHeight}px`
})
this.showMonth()
this.calendarGroupHeight = this.calendarItemHeight * 6
})
},
today() {
// 今天
this.$set(this.checkedDate, 'day', new Date().getDate())
this.yearOfCurrentShow = new Date().getFullYear() // 当前日历展示的年份
this.monthOfCurrentShow = new Date().getMonth() // 当前日历展示的月份
this.calculateCalendarOfThreeMonth()
if (this.isShowWeek) {
setTimeout(() => {
this.isTouching = true
this.showWeek()
}, this.transitionDuration * 1000)
}
},
// 计算当前展示月份的前后月份日历信息 flag -1:获取上个月日历信息 0:当月信息或者跨月展示日历信息 1:获取下个月日历信息
calculateCalendarOfThreeMonth(year = new Date().getFullYear(), month = new Date().getMonth()) {
this.lastMonthYear = month === 0 ? year - 1 : year // 上个月的年份
this.lastMonth = month === 0 ? 11 : month - 1 // 上个月的月份
this.nextMonthYear = month === 11 ? year + 1 : year // 下个月的年份
this.nextMonth = month === 11 ? 0 : month + 1 // 下个月的月份
let firstMonth = this.calculateCalendarOfMonth(this.lastMonthYear, this.lastMonth)
let secondMonth = this.calculateCalendarOfMonth(year, month)
let thirdMonth = this.calculateCalendarOfMonth(this.nextMonthYear, this.nextMonth)
this.calendarOfMonth = []
this.calendarOfMonth.push(firstMonth, secondMonth, thirdMonth)
this.calendarOfMonthShow = JSON.parse(JSON.stringify(this.calendarOfMonth))
if (!this.scrollChangeDate && this.currentChangeIsScroll) {
this.currentChangeIsScroll = false
return
}
// 改变日期选择的日期
let tempDate = {}
let day = this.checkedDate.day
if (day > 30 || (day > 28 && month === 1)) {
day = this.daysOfMonth(year)[month]
}
tempDate = { day: day, year: year, month: month }
if (this.formatDisabledDate(tempDate)) return
this.$set(this.checkedDate, 'day', tempDate.day)
this.$set(this.checkedDate, 'year', year)
this.$set(this.checkedDate, 'month', month)
},
calculateCalendarOfMonth(year = new Date().getFullYear(), month = new Date().getMonth()) {
// 计算每个月的日历
let calendarOfCurrentMonth = []
let lastMonthYear = month === 0 ? year - 1 : year // 上个月的年份
let lastMonth = month === 0 ? 11 : month - 1 // 上个月的月份
let nextMonthYear = month === 11 ? year + 1 : year // 下个月的年份
let nextMonth = month === 11 ? 0 : month + 1 // 下个月的月份
// 如果当月第一天不是指定的开始星期名称,则在前面补齐上个月的日期
let dayOfWeek = this.getDayOfWeek(year, month)
let lastMonthDays = this.daysOfMonth(year)[lastMonth] // 上个月的总天数
if (dayOfWeek < this.weekStartIndex) {
dayOfWeek = 7 - this.weekStartIndex + dayOfWeek
} else {
dayOfWeek -= this.weekStartIndex
}
for (let i = 0; i < dayOfWeek; i++) {
calendarOfCurrentMonth.push({
year: lastMonthYear,
month: lastMonth,
day: lastMonthDays - (dayOfWeek - 1 - i)
})
}
// 当月日期
for (let i = 0; i < this.daysOfMonth(year)[month]; i++) {
calendarOfCurrentMonth.push({
year: year,
month: month,
day: i + 1
})
}
// 在日历后面填充下个月的日期补齐6行7列
let fillDays = this.calendarDaysTotalLength - calendarOfCurrentMonth.length
for (let i = 0; i < fillDays; i++) {
calendarOfCurrentMonth.push({
year: nextMonthYear,
month: nextMonth,
day: i + 1
})
}
return calendarOfCurrentMonth
},
daysOfMonth(year) {
return [31, 28 + this.isLeap(year), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
},
isLeap(year) {
// 判断是否为闰年
return year % 4 === 0 ? (year % 100 !== 0 ? 1 : year % 400 === 0 ? 1 : 0) : 0
},
getDayOfWeek(year = new Date().getFullYear(), month = new Date().getMonth(), day = 1) {
// 获取月份某一天是星期几
let dayOfMonth = new Date(year, month, day) // 获取当月的第day天
let dayOfWeek = dayOfMonth.getDay() // 判断第day天是星期几(返回[0-6]中的一个0代表星期天1代表星期一)
return dayOfWeek
},
clickCalendarDay(date) {
// 点击日历上的日期
if (!date) return
if (this.formatDisabledDate(date)) return
this.$set(this.checkedDate, 'year', date.year)
this.$set(this.checkedDate, 'month', date.month)
this.$set(this.checkedDate, 'day', date.day)
if (date.month === this.lastMonth && date.year === this.lastMonthYear) {
this.getLastMonth()
}
if (date.month === this.nextMonth && date.year === this.nextMonthYear) {
this.getNextMonth()
}
if (this.isShowWeek) {
this.showWeek()
}
this.$emit('click', this.checkedDate)
},
isToday(date) {
// 该日期是否为今天
return this.yearOfToday === date.year && this.monthOfToday === date.month && this.dayOfToday === date.day
},
isCheckedDay(date) {
// 该日期是否为选中的日期
if (this.formatDisabledDate(date)) return false
return this.checkedDate.year === date.year && this.checkedDate.month === date.month && this.checkedDate.day === date.day
},
isNotCurrentMonthDay(date, index) {
// 非本月日期
let dateOfCurrentShow = this.calendarOfMonth[index][15] // 本月中间的日期一定为本月
return date.year !== dateOfCurrentShow.year || date.month !== dateOfCurrentShow.month
},
touchStart(event) {
// 监听手指开始滑动事件
this.$emit('touchstart', event)
this.touchStartPositionX = event.touches[0].clientX
this.touchStartPositionY = event.touches[0].clientY
this.touch = {
x: 0
}
this.isTouching = true
},
touchMove(event) {
// 监听手指移动事件
this.$emit('touchmove', event)
let moveX = event.touches[0].clientX - this.touchStartPositionX
let moveY = event.touches[0].clientY - this.touchStartPositionY
if (Math.abs(moveX) > Math.abs(moveY)) {
this.touch = {
x: moveX / this.$refs.calendar.offsetWidth,
y: 0
}
} else {
// 禁用周视图(禁止上下滑动)
if (this.disabledWeekView) return
this.touch = {
x: 0,
y: moveY / this.$refs.calendar.offsetHeight
}
}
},
touchEnd(e) {
// 监听touch结束事件
this.$emit('touchend', e)
this.isTouching = false
if (Math.abs(this.touch.x) > Math.abs(this.touch.y) && Math.abs(this.touch.x) > 0.2) {
this.currentChangeIsScroll = true
if (this.touch.x > 0) {
this.$emit('slidechange', 'right')
this.getLastMonth()
if (this.isShowWeek) {
setTimeout(() => {
this.isTouching = true
this.currentChangeIsScroll = true
this.getLastWeek()
}, this.transitionDuration * 1000)
}
} else if (this.touch.x < 0) {
this.$emit('slidechange', 'left')
this.getNextMonth()
if (this.isShowWeek) {
setTimeout(() => {
this.isTouching = true
this.currentChangeIsScroll = true
this.getNextWeek()
}, this.transitionDuration * 1000)
}
}
}
if (Math.abs(this.touch.y) > Math.abs(this.touch.x) && Math.abs(this.touch.y * this.$refs.calendar.offsetHeight) > 50) {
if (this.touch.y > 0 && this.isShowWeek) {
this.$emit('slidechange', 'down')
this.showMonth()
} else if (this.touch.y < 0 && !this.isShowWeek) {
this.$emit('slidechange', 'up')
this.showWeek()
}
} else {
this.touch = {
x: 0,
y: 0
}
}
},
showMonth() {
// 日历以月份方式展示
this.calendarY = 0
this.isShowWeek = false
this.calendarGroupHeight = this.calendarItemHeight * 6
this.isLastWeekInCurrentMonth = false
this.isNextWeekInCurrentMonth = false
this.calculateCalendarOfThreeMonth(this.checkedDate.year, this.checkedDate.month)
},
showWeek(checkedDate = this.checkedDate) {
// 日历以星期方式展示
let daysArr = []
this.calendarOfMonth[1].forEach(item => {
daysArr.push(item.day)
})
let dayIndexOfMonth = daysArr.indexOf(checkedDate.day)
// 当day为月底的天数时有可能在daysArr的前面也存在上一个月对应的日期所以需要取lastIndexOf
if (checkedDate.day > 15) {
dayIndexOfMonth = daysArr.lastIndexOf(checkedDate.day)
}
// 计算当前日期在第几行
let indexOfLine = Math.ceil((dayIndexOfMonth + 1) / 7)
let lastLine = indexOfLine - 1
this.calendarY = -(this.calendarItemHeight * lastLine)
this.isShowWeek = true
this.calendarGroupHeight = this.calendarItemHeight
let currentWeek = []
let sliceStart = lastLine * 7
let sliceEnd = sliceStart + 7
this.isLastWeekInCurrentMonth = false
currentWeek = this.calendarOfMonth[1].slice(sliceStart, sliceEnd)
for (let i in currentWeek) {
if (currentWeek[i].day === checkedDate.day) {
this.selectedDayIndex = i
}
}
let firstDayOfCurrentWeek = currentWeek[0]
let lastDayOfCurrentWeek = currentWeek[6]
if (lastDayOfCurrentWeek.day < firstDayOfCurrentWeek.day && lastDayOfCurrentWeek.month === checkedDate.month) {
this.lastWeek = this.calendarOfMonth[0].slice(21, 28)
} else {
if (firstDayOfCurrentWeek.day === 1) {
this.lastWeek = this.calendarOfMonth[0].slice(28, 35)
} else {
this.lastWeek = this.calendarOfMonth[1].slice(sliceStart - 7, sliceEnd - 7)
if (this.lastWeek[this.selectedDayIndex].month === checkedDate.month) {
this.isLastWeekInCurrentMonth = true
}
}
}
this.isNextWeekInCurrentMonth = false
if (lastDayOfCurrentWeek.day < firstDayOfCurrentWeek.day && lastDayOfCurrentWeek.month !== checkedDate.month) {
this.nextWeek = this.calendarOfMonth[2].slice(7, 14)
} else {
if (lastDayOfCurrentWeek.day === this.daysOfMonth(lastDayOfCurrentWeek.year)[lastDayOfCurrentWeek.month]) {
this.nextWeek = this.calendarOfMonth[2].slice(0, 7)
} else {
this.nextWeek = this.calendarOfMonth[1].slice(sliceStart + 7, sliceEnd + 7)
if (this.nextWeek[this.selectedDayIndex].month === checkedDate.month) {
this.isNextWeekInCurrentMonth = true
}
}
}
this.calendarOfMonthShow[0].splice(sliceStart, 7, ...this.lastWeek)
this.calendarOfMonthShow[2].splice(sliceStart, 7, ...this.nextWeek)
},
getLastWeek() {
// 显示上一周
let checkedDate = this.lastWeek[this.selectedDayIndex]
this.showWeek(checkedDate)
if (this.formatDisabledDate(checkedDate)) return
if (!this.scrollChangeDate && this.currentChangeIsScroll) {
this.currentChangeIsScroll = false
return
}
this.checkedDate = checkedDate
},
getNextWeek() {
// 显示下一周
let checkedDate = this.nextWeek[this.selectedDayIndex]
this.showWeek(checkedDate)
if (this.formatDisabledDate(checkedDate)) return
if (!this.scrollChangeDate && this.currentChangeIsScroll) {
this.currentChangeIsScroll = false
return
}
this.checkedDate = checkedDate
},
getLastMonth() {
// 获取上个月日历
this.translateIndex += 1
if (!this.isLastWeekInCurrentMonth) {
this.yearOfCurrentShow = this.lastMonthYear
this.monthOfCurrentShow = this.lastMonth
}
this.calculateCalendarOfThreeMonth(this.yearOfCurrentShow, this.monthOfCurrentShow)
},
getNextMonth() {
// 获取下个月日历
this.translateIndex -= 1
if (!this.isNextWeekInCurrentMonth) {
this.yearOfCurrentShow = this.nextMonthYear
this.monthOfCurrentShow = this.nextMonth
}
this.calculateCalendarOfThreeMonth(this.yearOfCurrentShow, this.monthOfCurrentShow)
},
markDateColor(date, type) {
// 当前日期是否需要标记
if (this.markType.indexOf(type) === -1) return
let dateString = `${date.year}/${this.fillNumber(date.month + 1)}/${this.fillNumber(date.day)}`
return this.markDateColorObj[dateString]
},
formatDisabledDate(date) {
let fDate = new Date(`${date.year}/${date.month + 1}/${date.day}`)
return this.disabledDate(fDate)
},
fillNumber(val) {
// 小于10在前面补0
return val > 9 ? val : '0' + val
},
dateFormat(dateArr) {
// 日期格式转换
dateArr.forEach((date, index) => {
dateArr[index] = formatDate(date, 'YY/MM/DD')
})
return dateArr
}
}
}
</script>
<style lang="scss" scoped>
.calendar_body {
position: relative;
width: 100%;
background: #F7F7F7;
}
.calendar_week {
position: absolute;
width: 100%;
left: 0;
top: 5px;
display: flex;
align-items: center;
color: #898989;
z-index: 2;
}
.calendar_group {
position: absolute;
// top: 35px;
left: 0;
bottom: 12px;
right: 0;
overflow: hidden;
}
.calendar_group ul {
height: 100%;
}
.calendar_group_li {
position: absolute;
top: 0;
left: 2px;
bottom: 0;
right: 0;
height: 100%;
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
will-change: transform;
}
.calendar_item {
width: 14.13333335%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
border-radius: 50%;
}
.calendar_item_disable {
background-color: #f5f7fa;
opacity: 1;
cursor: not-allowed;
color: #c0c4cc;
}
.calendar_day {
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 1px;
font-weight: bold;
color: #333333;
}
.calendar_first_today {
// color: #E9332E;
}
.calendar_first_today span {
font-size: 10px;
margin-top: 1px;
}
.calendar_day_today {
// background: #f4f4f4;
}
.calendar_mark_circle {
border: 1px solid #E9332E;
}
.calendar_day_not {
color: #c0c4cc;
}
.calendar_day_checked {
width: 40px;
height: 40px;
border-radius: 50%;
background: #00BFFF;
color: white;
}
.calendar_day_nochecked {
width: 40px;
height: 40px;
}
.checked_color {
color: white;
}
.calendar_dot {
width: 5px;
height: 5px;
border-radius: 50%;
margin-top: 4px;
}
.fs10 {
transform: scale(0.7);
}
</style>

View File

@@ -0,0 +1,357 @@
<template>
<!-- :class="{ calendar_inline: model === 'inline' }" class="hash-calendar" -->
<div
:class="model === 'inline' ? 'calendar_inline' : 'hash-calendar'"
v-show="isShowDatetimePicker"
:style="{ height: `${model === 'inline' ? calendarContentHeight : undefined}px` }"
@click="close"
>
<div class="calendar_content" :style="{ height: `${calendarContentHeight}px` }" @click.stop>
<!-- <div class="calendar_title" ref="calendarTitle">
<div class="calendar_title_date">
<span v-if="pickerType !== 'time'" class="calendar_title_date_year" :class="{ calendar_title_date_active: isShowCalendar }" @click="showCalendar">
{{ formatDate(`${checkedDate.year}/${this.checkedDate.month + 1}/${this.checkedDate.day}`, 'YY年MM月DD日') }}
</span>
<span v-if="pickerType !== 'time'" class="calendar_title_date_year" :class="{ calendar_title_date_active: isShowCalendar }" @click="showCalendar">
{{ lunar(checkedDate.year, this.checkedDate.month, this.checkedDate.day) }}
</span>
<span v-if="pickerType !== 'date'" class="calendar_title_date_time" :class="{ calendar_title_date_active: !isShowCalendar }" @click="showTime">
{{
formatDate(
`${checkedDate.year}/${this.checkedDate.month + 1}/${this.checkedDate.day} ${fillNumber(checkedDate.hours)}:${fillNumber(checkedDate.minutes)}`,
'hh:mm'
)
}}</span
>
</div>
<div class="flex">
<div v-if="showTodayButton" class="calendar_confirm fs17 text-center" :class="{ today_disable: disabledDate(new Date()) }" @click="today"></div>
<div class="calendar_confirm fs17 text-center" @click="confirm">+</div>
</div>
</div> -->
<calendar
ref="calendar"
v-if="pickerType !== 'time'"
:show="isShowCalendar"
v-bind="{ ...$props, ...$attrs }"
@height="heightChange"
:default-date="defaultDatetime"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
@slidechange="slideChange"
@change="dateChange"
@click="dateClick"
></calendar>
<time-picker
v-if="pickerType !== 'date'"
:show="!isShowCalendar"
:default-time="defaultDatetime"
v-bind="{ ...$props, ...$attrs }"
@change="timeChange"
></time-picker>
</div>
</div>
</template>
<script>
import Calendar from './Calendar.vue'
import TimePicker from './TimePicker.vue'
import { formatDate } from './utils/util'
import sloarToLunar from './utils/calendarConvert'
export default {
props: {
visible: {
// 是否显示日历组件
type: Boolean,
default: false
},
pickerType: {
// 选择器类型 datetime日期+时间 date日期 time时间
type: String,
default: 'datetime'
},
showTodayButton: {
// 是否显示返回今日按钮
type: Boolean,
default: true
},
defaultDatetime: {
// 默认时间
type: Date,
default() {
return new Date()
}
},
format: null, // 确认选择之后,返回的日期格式
model: {
type: String,
default: 'inline'
},
// 日期下面的标记
markDate: {
type: Array,
default: () => []
},
// 禁用的日期
disabledDate: {
type: Function,
default: () => {
return false
}
}
},
components: {
TimePicker,
Calendar
},
name: 'VueHashCalendar',
data() {
return {
checkedDate: {
year: new Date().getFullYear(),
month: new Date().getMonth(),
day: new Date().getDate(),
hours: new Date().getHours(),
minutes: new Date().getMinutes()
}, // 被选中的日期
isShowCalendar: false, // 是否显示日历选择控件
calendarContentHeight: 0, // 日历组件高度
calendarTitleHeight: 0, // 日历组件标题高度
firstTimes: true // 第一次触发
}
},
// inject: ['reload'],
created() {
window.onresize = () => {
console.log('重置页面')
this.reload()
}
},
mounted() {
if (this.model === 'inline') {
this.isShowDatetimePicker = true
}
},
destroyed() {
window.onresize = () => {}
},
watch: {
defaultDatetime(val) {
if (!(val instanceof Date)) {
throw new Error(`The calendar component's defaultDate must be date type!`)
}
},
pickerType: {
handler(val) {
if (val === 'time') {
this.showTime()
}
},
immediate: true
},
checkedDate: {
handler() {
let date = new Date(
`${this.checkedDate.year}/${this.checkedDate.month + 1}/${this.checkedDate.day} ${this.checkedDate.hours}:${this.checkedDate.minutes}`
)
if (this.format) {
date = formatDate(date, this.format)
}
this.$emit('change', date)
},
deep: true
},
visible: {
handler(val) {
this.isShowCalendar = val
this.$nextTick(() => {
// this.calendarTitleHeight = this.$refs.calendarTitle.offsetHeight
})
},
immediate: true
}
},
computed: {
isShowDatetimePicker: {
// 是否显示日期控件
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
}
},
methods: {
lunar(year, month, day) {
let lunar = sloarToLunar.solarToLunar(new Date(year, month, day), 'MD')
return lunar.split('').reverse()[0] === '月' ? `${lunar.slice(lunar.indexOf('月') + 1)}初一` : lunar
},
today() {
if (this.disabledDate(new Date())) return
this.$refs.calendar.today()
},
dateChange(date) {
date.hours = this.checkedDate.hours
date.minutes = this.checkedDate.minutes
this.checkedDate = date
},
dateClick(date) {
date.hours = this.checkedDate.hours
date.minutes = this.checkedDate.minutes
this.checkedDate = date
let fDate = new Date(
`${this.checkedDate.year}/${this.checkedDate.month + 1}/${this.checkedDate.day} ${this.checkedDate.hours}:${this.checkedDate.minutes}`
)
if (this.format) {
fDate = formatDate(fDate, this.format)
}
this.$emit('click', fDate)
},
timeChange(date) {
date.year = this.checkedDate.year
date.month = this.checkedDate.month
date.day = this.checkedDate.day
this.checkedDate = date
},
confirm() {
// 确认选择时间
let date = new Date(
`${this.checkedDate.year}/${this.checkedDate.month + 1}/${this.checkedDate.day} ${this.checkedDate.hours}:${this.checkedDate.minutes}`
)
if (this.format) {
date = formatDate(date, this.format)
}
this.$emit('confirm', date)
if (this.model === 'dialog') {
this.close()
}
},
show() {
this.isShowDatetimePicker = true
},
close() {
this.isShowDatetimePicker = false
},
fillNumber(val) {
// 小于10在前面补0
return val > 9 ? val : '0' + val
},
formatDate(time, format) {
return formatDate(time, format)
},
showCalendar() {
// 显示日历控件
this.isShowCalendar = true
},
showTime() {
// 显示时间选择控件
this.isShowCalendar = false
},
heightChange(height) {
// 高度变化
if (!this.firstTimes && this.model === 'dialog') return
this.calendarContentHeight = height + this.calendarTitleHeight + 30
this.$emit('get-height', this.calendarContentHeight)
this.firstTimes = false
},
touchStart(event) {
// 监听手指开始滑动事件
this.$emit('touchstart', event)
},
touchMove(event) {
// 监听手指开始滑动事件
this.$emit('touchmove', event)
},
touchEnd(event) {
// 监听手指开始滑动事件
this.$emit('touchend', event)
},
slideChange(direction) {
// 滑动方向改变
this.$emit('slidechange', direction)
}
}
}
</script>
<style lang="scss" scoped>
.hash-calendar {
position: fixed;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 999;
}
.calendar_inline {
position: relative;
width: 100vw;
background: none;
height: 355px;
z-index: 1;
}
.calendar_content {
position: absolute;
width: 100%;
left: 0;
bottom: 0;
display: flex;
flex-wrap: wrap;
background: white;
height: 355px;
overflow: hidden;
box-sizing: border-box;
}
.calendar_title {
position: absolute;
width: 100%;
left: 0;
top: 0;
background: white;
border-bottom: 1px solid color;
display: flex;
align-items: center;
justify-content: space-between;
z-index: 1;
}
.calendar_title_date {
color: #898989;
padding: 15px 8px;
}
.calendar_title_date_active {
color: #4c4c4c;
font-weight: bold;
}
.calendar_title_date_time {
margin-left: 10px;
}
.calendar_confirm {
width: 35px;
height: 35px;
line-height: 35px;
border-radius: 50%;
color: #ffffff;
background: #E9332E;
margin-right: 17px;
box-shadow: 0px 3px 7px 0px rgba(233,51,46, 0.53);
}
.today_disable {
color: #c0c4cc;
}
</style>

View File

@@ -9,26 +9,34 @@
</div>
</div>
<div class="calendar">
<vue-hash-calendar
<DatetimePicker
ref="datetimepicker"
model="inline"
:scroll-change-date="true"
:visible.sync="isShowCalendar"
@change="change"
:markDate="mask"
:showTodayButton="showTodayButton"
@click="timeDate"
:disabledWeekView="disable"
:defaultDatetime="date1"
@touchend="touchend"
class="hashCalendar"
style="height:350px;"
></vue-hash-calendar>
:default-datetime="defaultDatetime"
:is-show-week-view="isShowWeek"
:minute-step="1"
:mark-date="markDate"
mark-type="dot"
week-start="sunday"
picker-type="date"
:show-today-button="true"
:disabled-week-view="false"
format="YY/MM/DD hh:mm"
@get-height="getHeight"
@confirm="dateConfirm"
@change="dateChange"
:disabledWeekView='disabledWeekView'
></DatetimePicker>
</div>
<div class="footer" v-if="flagGo!=='4'">
<div class="fs12 c-gray-base h30 line-height">班次正常 09:00-18:00</div>
<div class=" h40 flex align-items-c border-gb">
<div class="fs12 c-gray-base h30 line-height ml15">班次正常 09:00-18:00</div>
<div class=" h40 flex align-items-c border-gb footer-bg">
<img class="h15 w15 ml15" src="@/assets/images/u20046.png" alt />
<div class="fs14 ml5">今日打卡{{count}}工时共计{{Number(amount).toFixed(2)}}小时</div>
</div>
<div class=" flex pt10">
<div class=" flex pt10 footer-bg">
<div class="text-center ml10 white">
<div class="w18 h18 fs12 bg-gray radius50"></div>
<div class="lin"></div>
@@ -36,14 +44,14 @@
</div>
<div>
<div class="fs14 fw500 ml15">
打卡时间 <span v-if="flagGo=='0'">{{goWorkTime}}</span>
打卡时间 <span v-if="flagGo!=='4'">{{goWorkTime}}</span>
<span class="c-gray-base">(上班 时间 {{workTime}})</span>
</div>
<!-- <img class="w30 h20 ml15" src="@/assets/images/u1213.png" alt /> -->
<div class="w41 h18 ml15 bg-blue-dark white fs13 text-center text1" v-if="flagGo=='0'">{{text}}</div>
<div class="w41 h18 ml15 white fs13 text-center text" v-if="flagGo=='1'||flagGo=='2'">{{text1}}</div>
<div class="fs14 fw500 ml15 mt50">
打卡时间 <span v-if="flagOff=='0'">{{offWorkTime}}</span>
打卡时间 <span v-if="flagOff!=='4'">{{offWorkTime}}</span>
<span class="c-gray-base">(下班 时间 {{workTimeOff}})</span>
</div>
<div class="w41 h18 ml15 bg-blue-dark white fs13 text-center text1" v-if="flagOff=='0'">{{text}}</div>
@@ -51,29 +59,41 @@
</div>
</div>
</div>
<div v-if="flagGo=='4'">
<div v-if="flagGo=='4'" class="ml15">
今日休息
</div>
</div>
</template>
<script>
import vueHashCalendar from 'vue-hash-calendar';
import DatetimePicker from './DatetimePicker.vue'
import { getDayDetail,getMonthDetail } from '@/api/ebiz/attendance/attendance';
import utils from '@/assets/js/utils/date-utils'
import { formatDate } from './utils/util'
export default {
name: 'monthly',
components: {
[vueHashCalendar.name]: vueHashCalendar
DatetimePicker
},
data() {
return {
currentDate: new Date(),
date1:new Date(),
defaultDatetime: new Date(),
date: '',
show: false,
isShowCalendar: true,
showTodayButton: false,
mask: [],
isShowCalendar: true, // 是否显示弹窗
disabledWeekView:false,//是否显示周试图
markDate: [
{
color: 'red',
date: ['2020/03/25']
},
{
color: '#000000',
date: ['2020/03/29']
}
], // 对象数组形式的标记日期,可以自定义标记颜色
// 所有的行事历任务
isShowWeek: false,
workTime:'',
workTimeOff:'',
count:'',
@@ -95,19 +115,20 @@ export default {
},
created(){
this.isShowCalendar=true
console.log(JSON.parse(window.localStorage.getItem('obj1')).time)
// console.log(JSON.parse(window.localStorage.getItem('obj1')).time)
this.date1=new Date(JSON.parse(window.localStorage.getItem('obj1')).time)
this.time=JSON.parse(window.localStorage.getItem('obj1')).time
this.name=JSON.parse(window.localStorage.getItem('obj1')).name
this.getMonthDetail1();
this.time=utils.formatDate(this.currentDate, 'yyyy-MM-dd')
this.time=formatDate(this.currentDate, 'YY-MM-DD')
},
methods: {
onConfirm(date) {
this.show = false
},
change(e) {
this.time=utils.formatDate(e, 'yyyy-MM-dd')
//点击日期
dateChange(e) {
this.time=formatDate(e, 'YY-MM-DD')
console.log(this.time)
this.getMonthDetail1()
this.week=String(new Date(e).getDay()).replace("0","日").replace("1","一").replace("2","二").replace("3","三").replace("4","四").replace("5","五").replace("6","六")
@@ -143,9 +164,9 @@ export default {
}
})
},
timeDate(date){
this.time = utils.formatDate(date, 'yyyy-MM-dd')
this.timeChange= utils.formatDate(date, 'yyyy-MM')
dateConfirm(date){
this.time = utils.formatDate(date, 'YY-MM-DD')
this.timeChange= formatDate(date, 'YY-MM')
this.week=String(new Date(date).getDay()).replace("0","日").replace("1","一").replace("2","二").replace("3","三").replace("4","四").replace("5","五").replace("6","六")
let date1={
date:this.time
@@ -184,7 +205,7 @@ export default {
let date={
date:this.time
}
if(Date.parse(this.time)<=Date.parse(utils.formatDate(new Date(), 'yyyy-MM-dd'))){
if(Date.parse(this.time)<=Date.parse(formatDate(new Date(), 'YY-MM-DD'))){
getMonthDetail(date).then(res=>{
// console.log(res)
if(res.result == 0){
@@ -195,7 +216,7 @@ export default {
for(let i=0;i<res.content.rest.length;i++){
let workTime=res.content.rest[i].split(' ')
let workTime1=workTime[0]
if(Date.parse(workTime1)<Date.parse(utils.formatDate(new Date(), 'yyyy-MM-dd'))){
if(Date.parse(workTime1)<Date.parse(formatDate(new Date(), 'YY-MM-DD'))){
let arr2=res.content.rest.slice(0,i+1)
obj1.date=arr2
// console.log(arr2)
@@ -219,12 +240,17 @@ export default {
arr.push(obj)
// arr3=arr3.concat(arr1,arr)
this.mask=arr
this.markDate=arr
// console.log(this.mask)
}
})
}
},
getHeight(val) {
this.calendarHeight = val
// let taskList = document.getElementsByClassName('task-list')[0].previousElementSibling
// taskList.style.height = `${this.calendarHeight + 36}px`
},
//滑动结束
touchend(e){
@@ -249,7 +275,7 @@ export default {
/* z-index: -1; */
width: 100%;
height:340px;
padding-top:0px !important;
padding-top:70px !important;
}
.calendar_title[data-v-f3b38220] {
display: none;
@@ -279,4 +305,7 @@ export default {
.calendar_title{
display:none !important;
}
.footer-bg{
background:#F7F7F7;
}
</style>

View File

@@ -0,0 +1,289 @@
<template>
<div class="time_body" v-show="show">
<div class="time_group">
<div
class="time_content"
:id="hashID[index]"
v-for="(item, index) in timeArray"
:key="index"
@touchstart="timeTouchStart"
@touchmove="timeTouchMove($event, index)"
@touchend="timeTouchEnd($event, index)"
>
<div class="time_item" :class="[{ time_item_show: isBeSelectedTime(time, index) }, hashClass]" v-for="(time, j) in item" :key="index + j">
>{{ time | fillNumber }}
</div>
</div>
</div>
</div>
</template>
<script>
import { checkPlatform } from './utils/util'
export default {
name: 'TimePicker',
props: {
defaultTime: null,
show: false,
minuteStep: {
type: Number,
default: 1
},
selectableRange: {
type: String | Array,
default: ''
}
},
data() {
return {
hashID: [], // 用于生成随机ID
hashClass: '', // 用于生成随机class
timeRange: [], // 时间范围
timeOptions: {
minHours: 24,
minMinutes: 59,
maxHours: 0,
maxMinutes: 0
},
checkedDate: {
hours: new Date().getHours(),
minutes: new Date().getMinutes()
}, // 被选中的日期
timeHeight: 0, // 单个时间项的高度
timeArray: [], // 时间选择器数据
timeStartY: 0, // touchstart,Y轴坐标
timeStartUp: 0 // 滑动开始前时间控件dom与顶部的偏移量
}
},
created() {
this.hashID = [`time${parseInt(Math.random() * 1000000)}`, `time${parseInt(Math.random() * 1000000)}`]
this.hashClass = `time_item_${parseInt(Math.random() * 1000000)}`
},
computed: {},
watch: {
defaultTime: {
handler(val) {
if (!(val instanceof Date)) {
throw new Error(`The calendar component's defaultTime must be date type!`)
}
this.$set(this.checkedDate, 'hours', val.getHours())
this.$set(this.checkedDate, 'minutes', val.getMinutes())
},
immediate: true
},
checkedDate: {
handler(val) {
this.$emit('change', val)
},
deep: true,
immediate: true
},
show: {
handler(val) {
if (val) {
this.initTimeArray()
}
},
immediate: true
},
minuteStep: {
handler(val) {
if (val <= 0 || val >= 60) {
throw new Error(`The minutes-step can't be: ${val}!`)
}
if (60 % val !== 0) {
throw new Error(`The minutes-step must be divided by 60!`)
}
},
immediate: true
},
selectableRange: {
handler(val) {
if (!val) return
this.timeRange = []
let formatPass = false
if (typeof val === 'string') {
formatPass = this.checkTimeRange(val)
} else if (val instanceof Array) {
formatPass = val.every(item => this.checkTimeRange(item))
}
if (!formatPass) throw new Error('The format of selectableRange is error!')
},
immediate: true
}
},
filters: {
fillNumber(val) {
// 小于10在前面补0
return val > 9 ? val : '0' + val
}
},
methods: {
initTimeArray() {
// 初始化时间选择器数据
let hours = []
this.timeArray = []
for (let i = 0; i < 24; i++) {
hours.push(i)
}
let minutes = []
for (let i = 0; i < 60; i++) {
if (i % this.minuteStep === 0) {
minutes.push(i)
}
}
this.timeArray.push(hours, minutes)
this.$nextTick(() => {
let checkHours = this.checkedDate.hours
let checkMinutes = this.checkedDate.minutes
this.timeHeight = getComputedStyle(document.querySelector(`.${this.hashClass}`)).height || ''
this.timeHeight = parseFloat(this.timeHeight.split('px')[0])
let hoursUp = (2 - parseFloat(checkHours)) * this.timeHeight
let minutesUp = (2 - parseFloat(checkMinutes) / this.minuteStep) * this.timeHeight
document.querySelector(`#${this.hashID[0]}`).style.webkitTransform = 'translate3d(0px,' + hoursUp + 'px,0px)'
document.querySelector(`#${this.hashID[1]}`).style.webkitTransform = 'translate3d(0px,' + minutesUp + 'px,0px)'
})
},
timeTouchStart(e) {
e.preventDefault()
this.timeStartY = e.changedTouches[0].pageY
let transform = e.currentTarget.style.webkitTransform
if (transform) {
this.timeStartUp = parseFloat(transform.split(' ')[1].split('px')[0])
}
},
timeTouchMove(e, index) {
let moveEndY = e.changedTouches[0].pageY
let Y = moveEndY - this.timeStartY
e.currentTarget.style.webkitTransform = 'translate3d(0px,' + (Y + this.timeStartUp) + 'px,0px)'
if (checkPlatform() === '2') {
this.timeTouchEnd(e, index)
return false
}
},
timeTouchEnd(e, index) {
let transform = e.currentTarget.style.webkitTransform
let endUp = this.timeStartUp
if (transform) {
endUp = parseFloat(e.currentTarget.style.webkitTransform.split(' ')[1].split('px')[0])
}
let distance = Math.abs(endUp - this.timeStartUp)
let upCount = Math.floor(distance / this.timeHeight) || 1
let halfWinWith = this.timeHeight / 2
let up = this.timeStartUp
if (endUp <= this.timeStartUp) {
// 向上滑动 未过临界值
if (distance <= halfWinWith) {
up = this.timeStartUp
} else {
up = this.timeStartUp - this.timeHeight * upCount
if (up < -(this.timeArray[index].length - 3) * this.timeHeight) {
up = -(this.timeArray[index].length - 3) * this.timeHeight
}
}
} else {
// 向下滑动 未过临界值
if (distance <= halfWinWith) {
up = this.timeStartUp
} else {
up = this.timeStartUp + this.timeHeight * upCount
if (up > this.timeHeight * 2) {
up = this.timeHeight * 2
}
}
}
if (index === 0) {
let hour = 2 - Math.round(parseFloat(up) / parseFloat(this.timeHeight))
this.$set(this.checkedDate, 'hours', hour)
} else {
let minute = 2 - Math.round(parseFloat(up) / parseFloat(this.timeHeight))
this.$set(this.checkedDate, 'minutes', minute * this.minuteStep)
}
e.currentTarget.style.webkitTransition = 'transform 300ms'
e.currentTarget.style.webkitTransform = 'translate3d(0px,' + up + 'px,0px)'
},
isBeSelectedTime(time, index) {
// 是否为当前选中的时间
return (index === 0 && time === this.checkedDate.hours) || (index === 1 && time === this.checkedDate.minutes)
},
isDisableTime(time, index) {
// 是否禁用当前时间
// console.log(this.timeRange, 'timeRange')
for (let i in this.timeRange) {
for (let j in this.timeRange[i]) {
if (index === 0) {
let currentHours = this.timeRange[i][j].split(':')[0]
if (currentHours > time) {
this.timeOptions.minHours = currentHours
return true
}
}
}
}
return false
},
checkTimeRange(timeRange) {
// 校验时间范围
if (!timeRange) return
let timeArr = timeRange.split('-')
if (timeArr.length === 0 || timeArr.length > 2) return false
this.timeRange.push(timeRange)
return timeArr.every(time => {
let mhArr = time.split(':')
if (mhArr.length === 0 || mhArr.length > 2) return false
// 校验单个时间是否符合规范 00:00 - 24:00
if (parseInt(mhArr[0]) < 0 || parseInt(mhArr[0]) > 24) return false
if (parseInt(mhArr[1]) < 0 || parseInt(mhArr[1]) > 59) return false
if (parseInt(mhArr[0]) === 24 && parseInt(mhArr[1]) > 0) return false
return true
})
}
}
}
</script>
<style lang="scss" scoped>
.time_body {
width: 100%;
margin-top: 50px;
}
.time_group {
width: 100%;
display: flex;
align-items: flex-start;
justify-content: center;
height: 180px;
margin-top: 50px;
-webkit-overflow-scrolling: touch;
overflow: hidden;
}
.time_content {
touch-action: none;
padding: 0 20px;
-webkit-overflow-scrolling: touch;
}
.time_item {
padding: 10px 0;
color: #898989;
}
.time_item_show {
color: #4c4c4c;
}
.time_disabled {
color: red;
}
</style>

View File

@@ -0,0 +1,627 @@
/*
农历每一年,对应公历的数据
此数据来源于互联网,原作者不详细,在此感谢
MAPPING[0][0]每年闰月的月份0表示不闰
MAPPING[0][1, 13]:表示每月初一对应的阳历时间,前两个字符表示月,后两个字符表示月
*/
var MAPPING = [
[8, '0131', '0301', '0331', '0429', '0528', '0627', '0726', '0825', '0924', '1023', '1122', '1222', '1320'], //1900
[0, '0219', '0320', '0419', '0518', '0616', '0716', '0814', '0913', '1012', '1111', '1211', '1310'], //1901
[0, '0208', '0310', '0408', '0508', '0606', '0705', '0804', '0902', '1002', '1031', '1130', '1230'], //1902
[5, '0129', '0227', '0329', '0427', '0527', '0625', '0724', '0823', '0921', '1020', '1119', '1219', '1317'], //1903
[0, '0216', '0317', '0416', '0515', '0614', '0713', '0811', '0910', '1009', '1107', '1207', '1306'], //1904
[0, '0204', '0306', '0405', '0504', '0603', '0703', '0801', '0830', '0929', '1028', '1127', '1226'], //1905
[4, '0125', '0223', '0325', '0424', '0523', '0622', '0721', '0820', '0918', '1018', '1116', '1216', '1314'], //1906
[0, '0213', '0314', '0413', '0512', '0611', '0710', '0809', '0908', '1007', '1106', '1205', '1304'], //1907
[0, '0202', '0303', '0401', '0430', '0530', '0629', '0728', '0827', '0925', '1025', '1124', '1223'], //1908
[2, '0122', '0220', '0322', '0420', '0519', '0618', '0717', '0816', '0914', '1014', '1113', '1213', '1311'], //1909
[0, '0210', '0311', '0410', '0509', '0607', '0707', '0805', '0904', '1003', '1102', '1202', '1301'], //1910
[6, '0130', '0301', '0330', '0429', '0528', '0626', '0726', '0824', '0922', '1022', '1121', '1220', '1319'], //1911
[0, '0218', '0319', '0417', '0517', '0615', '0714', '0813', '0911', '1010', '1109', '1209', '1307'], //1912
[0, '0206', '0308', '0407', '0506', '0605', '0704', '0802', '0901', '0930', '1029', '1128', '1227'], //1913
[5, '0126', '0225', '0327', '0425', '0525', '0623', '0723', '0821', '0920', '1019', '1117', '1217', '1315'], //1914
[0, '0214', '0316', '0414', '0514', '0613', '0712', '0811', '0909', '1009', '1107', '1207', '1305'], //1915
[0, '0203', '0304', '0403', '0502', '0601', '0630', '0730', '0829', '0927', '1027', '1125', '1225'], //1916
[2, '0123', '0222', '0323', '0421', '0521', '0619', '0719', '0818', '0916', '1016', '1115', '1214', '1313'], //1917
[0, '0211', '0313', '0411', '0510', '0609', '0708', '0807', '0905', '1005', '1104', '1203', '1302'], //1918
[7, '0201', '0302', '0401', '0430', '0529', '0628', '0727', '0825', '0924', '1024', '1122', '1222', '1321'], //1919
[0, '0220', '0320', '0419', '0518', '0616', '0716', '0814', '0912', '1012', '1110', '1210', '1309'], //1920
[0, '0208', '0310', '0408', '0508', '0606', '0705', '0804', '0902', '1001', '1031', '1129', '1229'], //1921
[5, '0128', '0227', '0328', '0427', '0527', '0625', '0724', '0823', '0921', '1020', '1119', '1218', '1317'], //1922
[0, '0216', '0317', '0416', '0516', '0614', '0714', '0812', '0911', '1010', '1108', '1208', '1306'], //1923
[0, '0205', '0305', '0404', '0504', '0602', '0702', '0801', '0830', '0929', '1028', '1127', '1226'], //1924
[4, '0124', '0223', '0324', '0423', '0522', '0621', '0721', '0819', '0918', '1018', '1116', '1216', '1314'], //1925
[0, '0213', '0314', '0412', '0512', '0610', '0710', '0808', '0907', '1007', '1105', '1205', '1304'], //1926
[0, '0202', '0304', '0402', '0501', '0531', '0629', '0729', '0827', '0926', '1025', '1124', '1224'], //1927
[2, '0123', '0221', '0322', '0420', '0519', '0618', '0717', '0815', '0914', '1013', '1112', '1212', '1311'], //1928
[0, '0210', '0311', '0410', '0509', '0607', '0707', '0805', '0903', '1003', '1101', '1201', '1231'], //1929
[6, '0130', '0228', '0330', '0429', '0528', '0626', '0726', '0824', '0922', '1022', '1120', '1220', '1319'], //1930
[0, '0217', '0319', '0418', '0517', '0616', '0715', '0814', '0912', '1011', '1110', '1209', '1308'], //1931
[0, '0206', '0307', '0406', '0506', '0604', '0704', '0802', '0901', '0930', '1029', '1128', '1227'], //1932
[5, '0126', '0224', '0326', '0425', '0524', '0623', '0722', '0821', '0920', '1019', '1118', '1217', '1315'], //1933
[0, '0214', '0315', '0414', '0513', '0612', '0712', '0810', '0909', '1008', '1107', '1207', '1305'], //1934
[0, '0204', '0305', '0403', '0503', '0601', '0701', '0730', '0829', '0928', '1027', '1126', '1226'], //1935
[3, '0124', '0223', '0323', '0421', '0521', '0619', '0718', '0817', '0916', '1015', '1114', '1214', '1313'], //1936
[0, '0211', '0313', '0411', '0510', '0609', '0708', '0806', '0905', '1004', '1103', '1203', '1302'], //1937
[7, '0131', '0302', '0401', '0430', '0529', '0628', '0727', '0825', '0924', '1023', '1122', '1222', '1320'], //1938
[0, '0219', '0321', '0420', '0519', '0617', '0717', '0815', '0913', '1013', '1111', '1211', '1309'], //1939
[0, '0208', '0309', '0408', '0507', '0606', '0705', '0804', '0902', '1001', '1031', '1129', '1229'], //1940
[6, '0127', '0226', '0328', '0426', '0526', '0625', '0724', '0823', '0921', '1020', '1119', '1218', '1317'], //1941
[0, '0215', '0317', '0415', '0515', '0614', '0713', '0812', '0910', '1010', '1108', '1208', '1306'], //1942
[0, '0205', '0306', '0405', '0504', '0603', '0702', '0801', '0831', '0929', '1029', '1127', '1227'], //1943
[4, '0125', '0224', '0324', '0423', '0522', '0621', '0720', '0819', '0917', '1017', '1116', '1215', '1314'], //1944
[0, '0213', '0314', '0412', '0512', '0610', '0709', '0808', '0906', '1006', '1105', '1205', '1303'], //1945
[0, '0202', '0304', '0402', '0501', '0531', '0629', '0728', '0827', '0925', '1025', '1124', '1223'], //1946
[2, '0122', '0221', '0323', '0421', '0520', '0619', '0718', '0816', '0915', '1014', '1113', '1212', '1311'], //1947
[0, '0210', '0311', '0409', '0509', '0607', '0707', '0805', '0903', '1003', '1101', '1201', '1230'], //1948
[7, '0129', '0228', '0329', '0428', '0528', '0626', '0726', '0824', '0922', '1022', '1120', '1220', '1318'], //1949
[0, '0217', '0318', '0417', '0517', '0615', '0715', '0814', '0912', '1011', '1110', '1209', '1308'], //1950
[0, '0206', '0308', '0406', '0506', '0605', '0704', '0803', '0901', '1001', '1030', '1129', '1228'], //1951
[5, '0127', '0225', '0326', '0424', '0524', '0622', '0722', '0820', '0919', '1019', '1117', '1217', '1315'], //1952
[0, '0214', '0315', '0414', '0513', '0611', '0711', '0810', '0908', '1008', '1107', '1206', '1305'], //1953
[0, '0203', '0305', '0403', '0503', '0601', '0630', '0730', '0828', '0927', '1027', '1126', '1225'], //1954
[3, '0124', '0222', '0324', '0422', '0522', '0620', '0719', '0818', '0916', '1016', '1114', '1214', '1313'], //1955
[0, '0212', '0312', '0411', '0510', '0609', '0708', '0806', '0905', '1004', '1103', '1203', '1301'], //1956
[8, '0131', '0302', '0331', '0430', '0529', '0628', '0727', '0825', '0924', '1023', '1122', '1221', '1320'], //1957
[0, '0218', '0320', '0419', '0519', '0617', '0717', '0815', '0913', '1013', '1111', '1211', '1309'], //1958
[0, '0208', '0309', '0408', '0508', '0606', '0706', '0804', '0903', '1002', '1101', '1130', '1230'], //1959
[6, '0128', '0227', '0327', '0426', '0525', '0624', '0724', '0822', '0921', '1020', '1119', '1218', '1317'], //1960
[0, '0215', '0317', '0415', '0515', '0613', '0713', '0811', '0910', '1010', '1108', '1208', '1306'], //1961
[0, '0205', '0306', '0405', '0504', '0602', '0702', '0731', '0830', '0929', '1028', '1127', '1227'], //1962
[4, '0125', '0224', '0325', '0424', '0523', '0621', '0721', '0819', '0918', '1017', '1116', '1216', '1315'], //1963
[0, '0213', '0314', '0412', '0512', '0610', '0709', '0808', '0906', '1006', '1104', '1204', '1303'], //1964
[0, '0202', '0303', '0402', '0501', '0531', '0629', '0728', '0827', '0925', '1024', '1123', '1223'], //1965
[3, '0121', '0220', '0322', '0421', '0520', '0619', '0718', '0816', '0915', '1014', '1112', '1212', '1311'], //1966
[0, '0209', '0311', '0410', '0509', '0608', '0708', '0806', '0904', '1004', '1102', '1202', '1231'], //1967
[7, '0130', '0228', '0329', '0427', '0527', '0626', '0725', '0824', '0922', '1022', '1120', '1220', '1318'], //1968
[0, '0217', '0318', '0417', '0516', '0615', '0714', '0813', '0912', '1011', '1110', '1209', '1308'], //1969
[0, '0206', '0308', '0406', '0505', '0604', '0703', '0802', '0901', '0930', '1030', '1129', '1228'], //1970
[5, '0127', '0225', '0327', '0425', '0524', '0623', '0722', '0821', '0919', '1019', '1118', '1218', '1316'], //1971
[0, '0215', '0315', '0414', '0513', '0611', '0711', '0809', '0908', '1007', '1106', '1206', '1304'], //1972
[0, '0203', '0305', '0403', '0503', '0601', '0630', '0730', '0828', '0926', '1026', '1125', '1224'], //1973
[4, '0123', '0222', '0324', '0422', '0522', '0620', '0719', '0818', '0916', '1015', '1114', '1214', '1312'], //1974
[0, '0211', '0313', '0412', '0511', '0610', '0709', '0807', '0906', '1005', '1103', '1203', '1301'], //1975
[8, '0131', '0301', '0331', '0429', '0529', '0627', '0727', '0825', '0924', '1023', '1121', '1221', '1319'], //1976
[0, '0218', '0320', '0418', '0518', '0617', '0716', '0815', '0913', '1013', '1111', '1211', '1309'], //1977
[0, '0207', '0309', '0407', '0507', '0606', '0705', '0804', '0902', '1002', '1101', '1130', '1230'], //1978
[6, '0128', '0227', '0328', '0426', '0526', '0624', '0724', '0823', '0921', '1021', '1120', '1219', '1318'], //1979
[0, '0216', '0317', '0415', '0514', '0613', '0712', '0811', '0909', '1009', '1108', '1207', '1306'], //1980
[0, '0205', '0306', '0405', '0504', '0602', '0702', '0731', '0829', '0928', '1028', '1126', '1226'], //1981
[4, '0125', '0224', '0325', '0424', '0523', '0621', '0721', '0819', '0917', '1017', '1115', '1215', '1314'], //1982
[0, '0213', '0315', '0413', '0513', '0611', '0710', '0809', '0907', '1006', '1105', '1204', '1303'], //1983
[10, '0202', '0303', '0401', '0501', '0531', '0629', '0728', '0827', '0925', '1024', '1123', '1222', '1321'], //1984
[0, '0220', '0321', '0420', '0520', '0618', '0718', '0816', '0915', '1014', '1112', '1212', '1310'], //1985
[0, '0209', '0310', '0409', '0509', '0607', '0707', '0806', '0904', '1004', '1102', '1202', '1231'], //1986
[6, '0129', '0228', '0329', '0428', '0527', '0626', '0726', '0824', '0923', '1023', '1121', '1221', '1319'], //1987
[0, '0217', '0318', '0416', '0516', '0614', '0714', '0812', '0911', '1011', '1109', '1209', '1308'], //1988
[0, '0206', '0308', '0406', '0505', '0604', '0703', '0802', '0831', '0930', '1029', '1128', '1228'], //1989
[5, '0127', '0225', '0327', '0425', '0524', '0623', '0722', '0820', '0919', '1018', '1117', '1217', '1316'], //1990
[0, '0215', '0316', '0415', '0514', '0612', '0712', '0810', '0908', '1008', '1106', '1206', '1305'], //1991
[0, '0204', '0304', '0403', '0503', '0601', '0630', '0730', '0828', '0926', '1026', '1124', '1224'], //1992
[3, '0123', '0221', '0323', '0422', '0521', '0620', '0719', '0818', '0916', '1015', '1114', '1213', '1312'], //1993
[0, '0210', '0312', '0411', '0511', '0609', '0709', '0807', '0906', '1005', '1103', '1203', '1301'], //1994
[8, '0131', '0301', '0331', '0430', '0529', '0628', '0727', '0826', '0925', '1024', '1122', '1222', '1320'], //1995
[0, '0219', '0319', '0418', '0517', '0616', '0715', '0814', '0912', '1012', '1111', '1211', '1309'], //1996
[0, '0207', '0309', '0407', '0507', '0605', '0705', '0803', '0902', '1002', '1031', '1130', '1230'], //1997
[5, '0128', '0227', '0328', '0426', '0526', '0624', '0723', '0822', '0921', '1020', '1119', '1219', '1317'], //1998
[0, '0216', '0318', '0416', '0515', '0614', '0713', '0811', '0910', '1009', '1108', '1208', '1307'], //1999
[0, '0205', '0306', '0405', '0504', '0602', '0702', '0731', '0829', '0928', '1027', '1126', '1226'], //2000
[4, '0124', '0223', '0325', '0423', '0523', '0621', '0721', '0819', '0917', '1017', '1115', '1215', '1313'], //2001
[0, '0212', '0314', '0413', '0512', '0611', '0710', '0809', '0907', '1006', '1105', '1204', '1303'], //2002
[0, '0201', '0303', '0402', '0501', '0531', '0630', '0729', '0828', '0926', '1025', '1124', '1223'], //2003
[2, '0122', '0220', '0321', '0419', '0519', '0618', '0717', '0816', '0914', '1014', '1112', '1212', '1310'], //2004
[0, '0209', '0310', '0409', '0508', '0607', '0706', '0805', '0904', '1003', '1102', '1201', '1231'], //2005
[7, '0129', '0228', '0329', '0428', '0527', '0626', '0725', '0824', '0922', '1022', '1121', '1220', '1319'], //2006
[0, '0218', '0319', '0417', '0517', '0615', '0714', '0813', '0911', '1011', '1110', '1210', '1308'], //2007
[0, '0207', '0308', '0406', '0505', '0604', '0703', '0801', '0831', '0929', '1029', '1128', '1227'], //2008
[5, '0126', '0225', '0327', '0425', '0524', '0623', '0722', '0820', '0919', '1018', '1117', '1216', '1315'], //2009
[0, '0214', '0316', '0414', '0514', '0612', '0712', '0810', '0908', '1008', '1106', '1206', '1304'], //2010
[0, '0203', '0305', '0403', '0503', '0602', '0701', '0731', '0829', '0927', '1027', '1125', '1225'], //2011
[4, '0123', '0222', '0322', '0421', '0521', '0619', '0719', '0817', '0916', '1015', '1114', '1213', '1312'], //2012
[0, '0210', '0312', '0410', '0510', '0608', '0708', '0807', '0905', '1005', '1103', '1203', '1301'], //2013
[9, '0131', '0301', '0331', '0429', '0529', '0627', '0727', '0825', '0924', '1024', '1122', '1222', '1320'], //2014
[0, '0219', '0320', '0419', '0518', '0616', '0716', '0814', '0913', '1013', '1112', '1211', '1310'], //2015
[0, '0208', '0309', '0407', '0507', '0605', '0704', '0803', '0901', '1001', '1031', '1129', '1229'], //2016
[6, '0128', '0226', '0328', '0426', '0526', '0624', '0723', '0822', '0920', '1020', '1118', '1218', '1317'], //2017
[0, '0216', '0317', '0416', '0515', '0614', '0713', '0811', '0910', '1009', '1108', '1207', '1306'], //2018
[0, '0205', '0307', '0405', '0505', '0603', '0703', '0801', '0830', '0929', '1028', '1126', '1226'], //2019
[4, '0125', '0223', '0324', '0423', '0523', '0621', '0721', '0819', '0917', '1017', '1115', '1215', '1313'], //2020
[0, '0212', '0313', '0412', '0512', '0610', '0710', '0808', '0907', '1006', '1105', '1204', '1303'], //2021
[0, '0201', '0303', '0401', '0501', '0530', '0629', '0729', '0827', '0926', '1025', '1124', '1223'], //2022
[2, '0122', '0220', '0322', '0420', '0519', '0618', '0718', '0816', '0915', '1015', '1113', '1213', '1311'], //2023
[0, '0210', '0310', '0409', '0508', '0606', '0706', '0804', '0903', '1003', '1101', '1201', '1231'], //2024
[6, '0129', '0228', '0329', '0428', '0527', '0625', '0725', '0823', '0922', '1021', '1120', '1220', '1319'], //2025
[0, '0217', '0319', '0417', '0517', '0615', '0714', '0813', '0911', '1010', '1109', '1209', '1308'], //2026
[0, '0206', '0308', '0407', '0506', '0605', '0704', '0802', '0901', '0930', '1029', '1128', '1228'], //2027
[5, '0126', '0225', '0326', '0425', '0524', '0623', '0722', '0820', '0919', '1018', '1116', '1216', '1315'], //2028
[0, '0213', '0315', '0414', '0513', '0612', '0711', '0810', '0908', '1008', '1106', '1205', '1304'], //2029
[0, '0203', '0304', '0403', '0502', '0601', '0701', '0730', '0829', '0927', '1027', '1125', '1225'], //2030
[3, '0123', '0221', '0323', '0422', '0521', '0620', '0719', '0818', '0917', '1016', '1115', '1214', '1313'], //2031
[0, '0211', '0312', '0410', '0509', '0608', '0707', '0806', '0905', '1004', '1103', '1203', '1301'], //2032
[7, '0131', '0301', '0331', '0429', '0528', '0627', '0726', '0825', '0923', '1023', '1122', '1222', '1320'], //2033
[0, '0219', '0320', '0419', '0518', '0616', '0716', '0814', '0913', '1012', '1111', '1211', '1309'], //2034
[0, '0208', '0310', '0408', '0508', '0606', '0705', '0804', '0902', '1001', '1031', '1130', '1229'], //2035
[6, '0128', '0227', '0328', '0426', '0526', '0624', '0723', '0822', '0920', '1019', '1118', '1217', '1316'], //2036
[0, '0215', '0317', '0416', '0515', '0614', '0713', '0811', '0910', '1009', '1107', '1207', '1305'], //2037
[0, '0204', '0306', '0405', '0504', '0603', '0702', '0801', '0830', '0929', '1028', '1126', '1226'], //2038
[5, '0124', '0223', '0325', '0423', '0523', '0622', '0721', '0820', '0918', '1018', '1116', '1216', '1314'], //2039
[0, '0212', '0313', '0411', '0511', '0610', '0709', '0808', '0906', '1006', '1105', '1204', '1303'], //2040
[0, '0201', '0302', '0401', '0430', '0530', '0628', '0728', '0827', '0925', '1025', '1124', '1223'], //2041
[2, '0122', '0220', '0322', '0420', '0519', '0618', '0717', '0816', '0914', '1014', '1113', '1212', '1311'], //2042
[0, '0210', '0311', '0410', '0509', '0607', '0707', '0805', '0903', '1003', '1102', '1201', '1231'], //2043
[7, '0130', '0229', '0329', '0428', '0527', '0625', '0725', '0823', '0921', '1021', '1119', '1219', '1318'], //2044
[0, '0217', '0319', '0417', '0517', '0615', '0714', '0813', '0911', '1010', '1109', '1208', '1307'], //2045
[0, '0206', '0308', '0406', '0506', '0604', '0704', '0802', '0901', '0930', '1029', '1128', '1227'], //2046
[5, '0126', '0225', '0326', '0425', '0525', '0623', '0723', '0821', '0920', '1019', '1117', '1217', '1315'], //2047
[0, '0214', '0314', '0413', '0513', '0611', '0711', '0810', '0908', '1008', '1106', '1205', '1304'], //2048
[0, '0202', '0304', '0402', '0502', '0531', '0630', '0730', '0828', '0927', '1027', '1125', '1225'], //2049
[3, '0123', '0221', '0323', '0421', '0521', '0619', '0719', '0817', '0916', '1016', '1114', '1214', '1313'], //2050
[0, '0211', '0313', '0411', '0510', '0609', '0708', '0806', '0905', '1005', '1103', '1203', '1302'], //2051
[8, '0201', '0301', '0331', '0429', '0528', '0627', '0726', '0824', '0923', '1022', '1121', '1221', '1320'], //2052
[0, '0219', '0320', '0419', '0518', '0616', '0716', '0814', '0912', '1012', '1110', '1210', '1309'], //2053
[0, '0208', '0309', '0408', '0508', '0606', '0705', '0804', '0902', '1001', '1031', '1129', '1229'], //2054
[6, '0128', '0226', '0328', '0427', '0526', '0625', '0724', '0823', '0921', '1020', '1119', '1218', '1317'], //2055
[0, '0215', '0316', '0415', '0515', '0613', '0713', '0811', '0910', '1009', '1107', '1207', '1305'], //2056
[0, '0204', '0305', '0404', '0504', '0602', '0702', '0731', '0830', '0929', '1028', '1126', '1226'], //2057
[4, '0124', '0223', '0324', '0423', '0522', '0621', '0720', '0819', '0918', '1017', '1116', '1216', '1314'], //2058
[0, '0212', '0314', '0412', '0512', '0610', '0710', '0808', '0907', '1006', '1105', '1205', '1304'], //2059
[0, '0202', '0303', '0401', '0501', '0530', '0628', '0727', '0826', '0924', '1024', '1123', '1223'], //2060
[3, '0121', '0220', '0322', '0420', '0519', '0618', '0717', '0815', '0914', '1013', '1112', '1212', '1311'], //2061
[0, '0209', '0311', '0410', '0509', '0607', '0707', '0805', '0903', '1003', '1101', '1201', '1231'], //2062
[7, '0129', '0228', '0330', '0428', '0528', '0626', '0726', '0824', '0922', '1022', '1120', '1220', '1318'], //2063
[0, '0217', '0318', '0417', '0516', '0615', '0714', '0813', '0911', '1010', '1109', '1208', '1307'], //2064
[0, '0205', '0307', '0406', '0505', '0604', '0704', '0802', '0901', '0930', '1029', '1128', '1227'], //2065
[5, '0126', '0224', '0326', '0424', '0524', '0623', '0722', '0821', '0919', '1019', '1117', '1217', '1315'], //2066
[0, '0214', '0315', '0414', '0513', '0612', '0711', '0810', '0909', '1008', '1107', '1206', '1305'], //2067
[0, '0203', '0304', '0402', '0502', '0531', '0629', '0729', '0828', '0926', '1026', '1125', '1224'], //2068
[4, '0123', '0221', '0323', '0421', '0521', '0619', '0718', '0817', '0915', '1015', '1114', '1214', '1312'], //2069
[0, '0211', '0312', '0411', '0510', '0609', '0708', '0806', '0905', '1004', '1103', '1203', '1301'], // 2070
[8, '0131', '0302', '0331', '0430', '0529', '0628', '0727', '0825', '0924', '1023', '1122', '1221', '1320'], // 2071
[0, '0219', '0320', '0418', '0518', '0616', '0716', '0814', '0912', '1012', '1110', '1210', '1308'], // 2072
[0, '0207', '0309', '0407', '0507', '0606', '0705', '0804', '0902', '1001', '1031', '1129', '1229'], // 2073
[6, '0127', '0226', '0327', '0426', '0526', '0624', '0724', '0822', '0921', '1020', '1119', '1218', '1317'], // 2074
[0, '0215', '0317', '0415', '0515', '0613', '0713', '0812', '0910', '1010', '1108', '1208', '1306'], // 2075
[0, '0205', '0305', '0404', '0503', '0602', '0701', '0731', '0829', '0928', '1028', '1126', '1226'], // 2076
[4, '0124', '0223', '0324', '0423', '0522', '0620', '0720', '0818', '0917', '1017', '1116', '1215', '1314'], // 2077
[0, '0212', '0314', '0412', '0512', '0610', '0709', '0808', '0906', '1006', '1105', '1204', '1303'], // 2078
[0, '0202', '0303', '0402', '0501', '0531', '0629', '0728', '0827', '0925', '1025', '1123', '1223'], // 2079
[3, '0122', '0221', '0321', '0420', '0519', '0618', '0717', '0815', '0914', '1013', '1111', '1211', '1310'], // 2080
[0, '0209', '0310', '0409', '0509', '0607', '0707', '0805', '0903', '1003', '1101', '1130', '1230'], // 2081
[7, '0129', '0227', '0329', '0428', '0528', '0626', '0725', '0824', '0922', '1022', '1120', '1219', '1318'], // 2082
[0, '0217', '0318', '0417', '0517', '0615', '0715', '0813', '0912', '1011', '1110', '1209', '1308'], // 2083
[0, '0206', '0307', '0405', '0505', '0603', '0703', '0802', '0831', '0930', '1029', '1128', '1227'], // 2084
[5, '0126', '0224', '0326', '0424', '0523', '0622', '0722', '0820', '0919', '1019', '1117', '1217', '1315'], // 2085
[0, '0214', '0315', '0414', '0513', '0611', '0711', '0809', '0908', '1008', '1106', '1206', '1305'], // 2086
[0, '0203', '0305', '0403', '0503', '0601', '0630', '0730', '0828', '0927', '1026', '1125', '1225'], // 2087
[4, '0124', '0222', '0323', '0421', '0521', '0619', '0718', '0817', '0915', '1014', '1113', '1213', '1312'], // 2088
[0, '0210', '0312', '0411', '0510', '0609', '0708', '0806', '0904', '1004', '1102', '1202', '1301'], // 2089
[8, '0130', '0301', '0331', '0430', '0529', '0628', '0727', '0825', '0924', '1023', '1121', '1221', '1320'], // 2090
[0, '0218', '0320', '0419', '0518', '0617', '0716', '0815', '0913', '1013', '1111', '1210', '1309'], // 2091
[0, '0207', '0308', '0407', '0506', '0605', '0705', '0803', '0902', '1001', '1031', '1129', '1229'], // 2092
[6, '0127', '0225', '0327', '0426', '0525', '0624', '0723', '0822', '0921', '1020', '1119', '1218', '1317'], // 2093
[0, '0215', '0316', '0415', '0514', '0613', '0712', '0811', '0910', '1009', '1108', '1208', '1306'], // 2094
[0, '0205', '0306', '0405', '0504', '0602', '0702', '0731', '0830', '0928', '1028', '1127', '1227'], // 2095
[4, '0125', '0224', '0324', '0423', '0522', '0620', '0720', '0818', '0916', '1016', '1115', '1215', '1313'], // 2096
[0, '0212', '0314', '0412', '0512', '0610', '0709', '0808', '0906', '1005', '1104', '1204', '1302'], // 2097
[0, '0201', '0303', '0402', '0501', '0531', '0629', '0728', '0826', '0925', '1024', '1123', '1222'], // 2098
[2, '0121', '0220', '0322', '0420', '0520', '0619', '0718', '0816', '0915', '1014', '1112', '1212', '1310'] // 2099
]
var MINYEAR = 1900
var _chineseLunar = {}
/*
* 分析日期表达式,并提取其中的单位和数值
*/
var _expression = function(expr) {
var list = expr.match(/[+-]?\d+((ms)|[yMdhmsw])/g)
var result = []
for (var i = 0; i < list.length; i++) {
//提取单位和数值
if (/([+-])(\d+)(.+)/.test(list[i])) {
var val = parseInt(RegExp.$2)
if (RegExp.$1 === '-') val = -val
result.push({
value: val,
unit: RegExp.$3
})
}
return result
}
}
//计算公历两个日期之差
var _solarDiff = function(left, right, interval) {
var span = left.getTime() - right.getTime() //相差毫秒
switch (interval) {
case 'y':
return parseInt(left.getFullYear() - right.getFullYear())
case 'M':
return parseInt((left.getFullYear() - right.getFullYear()) * 12 + (left.getMonth() - right.getMonth()))
case 'd':
return Math.ceil(span / 1000 / 60 / 60 / 24)
case 'w':
return Math.floor(span / 1000 / 60 / 60 / 24 / 7)
case 'h':
return Math.floor(span / 1000 / 60 / 60)
case 'm':
return Math.floor(span / 1000 / 60)
case 's':
return Math.floor(span / 1000)
case 'ms':
return parseInt(span)
}
}
/*
找到农历
isPerYear是否为农历前一年的对应数据
*/
var _findLunar = function(solar, index, minMonth, maxMonth, isPreYear) {
//取得映射的数据
var mapping = MAPPING[index]
if (!mapping) return false
var year = solar.getFullYear(),
month = solar.getMonth() + 1,
date = solar.getDate()
var lunarYear = year
var lunarMonth, find, solarMonth
//查找农历
for (var i = mapping.length - 1; i > 0; i--) {
lunarMonth = i
//取对应的农历月与天
var segMonth = Number(mapping[i].substring(0, 2))
var segDay = Number(mapping[i].substring(2, 4))
solarMonth = isPreYear && segMonth > 12 ? segMonth - 12 : segMonth
find = solarMonth < month || (solarMonth == month && segDay <= date) || ((segMonth <= minMonth || segMonth >= maxMonth) && isPreYear)
if (solarMonth == 12 && solarMonth > month && i == 1) {
find = true
year--
}
if (find) break
}
//如果找到,则赋值
if (!find) return false
//取前一年
if (isPreYear && segMonth == 12) year = year - 1
lunarYear = isPreYear ? lunarYear - 1 : lunarYear
return {
year: year,
month: solarMonth,
day: segDay,
lunarYear: lunarYear,
lunarMonth: lunarMonth,
leapMonth: mapping[0] //闰月
}
}
//日期累加
var _dateAdd = function(lunar, value, unit) {
if (unit == 'M') {
return _chineseLunar.monthAdd(lunar, value)
} else {
//转换为阳历,计算完再转为农历
var solar = _chineseLunar.lunarToSolar(lunar)
return _chineseLunar.solarToLunar(solar)
}
}
/*
农历相加
*/
_chineseLunar.dateAdd = function(lunar, expr) {
//分析表达式
var list = _expression(expr)
for (var i = 0; i < list.length; i++) {
lunar = _dateAdd(lunar, list[i])
}
return lunar
}
/*
计算两个农历时间的差值,主要计算月份之间的差,其它和公历是一样的
*/
_chineseLunar.dateDiff = function(lunar1, lunar2, expr) {
//计算农历月份差值
if (expr == 'M') {
return _chineseLunar.monthDiff(lunar1, lunar2)
}
//先转成公历,除了月份,其它的都可以按公历计算
var solar1 = _chineseLunar.lunarToSolar(lunar1)
var solar2 = _chineseLunar.lunarToSolar(lunar2)
//再把农历转到公历
return _solarDiff(solar2, solar1, expr)
}
/*
农历月份相加
*/
_chineseLunar.monthAdd = function(lunar, inc) {
//如果是Date则转换为农历
if (lunar instanceof Date) lunar = _chineseLunar.solarToLunar(lunar)
if (inc == 0) return lunar
var year = lunar.year,
count
var month = lunar.month
if (lunar.leap || (lunar.leapMonth > 0 && lunar.month > lunar.leapMonth)) month++
var run = true
do {
//计算当前年有多少个月
count = _chineseLunar.monthsOfYear(year)
inc = inc + month - count
if (inc <= 0) {
run = false
month = year == lunar.year ? count + inc : count + inc - month
} else {
year++
month = 1
}
} while (run)
//获取最后的结果年的闰月是哪一个月
var leapMonth = _chineseLunar.leapMonthOfYear(year)
var leap = false
//如果闰月大于农历月则月份减1
if (leapMonth > 0 && month > leapMonth) {
month--
//如果减完后月份和闰月相等,表示是闰月
leap = month == leapMonth
}
return {
year: year,
month: month,
leap: leap,
leapMonth: leapMonth
}
}
/*
* 返回两段日期的农历差了多少个月,因为有闰月,所以和公历不一样
* date1和date2允许为公历
*/
_chineseLunar.monthDiff = function(lunar1, lunar2) {
//如果是公历的日期格式,则转换为农历
var count = 0
//如果数据类型是日期,则转换为农历
if (lunar1 instanceof Date) lunar1 = _chineseLunar.solarToLunar(lunar1)
if (lunar2 instanceof Date) lunar2 = _chineseLunar.solarToLunar(lunar2)
//两个日期是同一年
if (lunar1.year == lunar2.year) {
count = lunar2.month - lunar1.month
//中间有闰月的存在,计数器加一
if (lunar1.leapMonth >= lunar1.month && lunar1.leapMonth <= lunar2.month) count++
} else {
//计算首年,如果当前的闰月大于当前月,或者当前年有闰月且当前月等于闰月,但当前月又不是闰月,则要多添加一个月
count = 12
if (lunar1.leapMonth > lunar1.month || (lunar1.leapMonth == lunar1.month && !lunar1.isLeaMonth)) count += 1
count -= lunar1.month
//计算两年之间中间的年月份
var year = lunar1.year + 1
for (var i = year; i < lunar2.year; i++) {
count += _chineseLunar.monthsOfYear(year++)
}
//计算最后一年
count += lunar2.month
if (lunar2.isLeapMonth || lunar2.month < lunar2.leapMonth) count++
}
return count
}
/*
* 计算某年某月一个有多少天
* daysOfMonth({}) 或者 daysOfMonth(year, month, leap)
*/
_chineseLunar.daysOfMonth = function(year, month, leap) {
if (typeof year == 'object') {
month = year.month
leap = year.leap
year = year.year
}
var date1 = _chineseLunar.lunarToSolar(year, month, 1, leap)
var leapMonth = _chineseLunar.leapMonthOfYear(year)
if (leapMonth == month && !leap) {
//如果是闰月和当前一月一至且当前月不是闰月说明下一个月是闰月例如2009年5月这一年闰5月如果传过来的不是闰月那么下一个月就是闰月
leap = true
} else if (month == 12) {
//农历的最后一个月
year++
month = 1
} else {
leap = false
month++
}
var date2 = _chineseLunar.lunarToSolar(year, month, 1, leap)
return _chineseLunar.dateDiff(date2, date1, 'd')
}
//获取农历某一年有多少个月
_chineseLunar.monthsOfYear = function(year) {
return MAPPING[year - MINYEAR].length - 1
}
//获取农历某年的闰月是几月,
_chineseLunar.leapMonthOfYear = function(year) {
var info = MAPPING[year - MINYEAR]
return info ? info[0] : 0
}
/*
农历转阳历
lunarToSolar({})或者lunarToSolar(year, month, day, leap)
*/
_chineseLunar.lunarToSolar = function(year, month, day, leap) {
var arg0 = arguments[0]
//第一个参数是对象
if (typeof arg0 == 'object' && arguments.length == 1) {
year = arg0.year
month = arg0.month
day = arg0.day
leap = arg0.leap
}
//根据偏移量取得映射数据
var offset = year - MINYEAR
//所查询的日期超出范围
if (offset < 0 || offset > MAPPING.length) {
throw new Error('Specified date range is invalid.')
}
//取得润月是哪一个月
var leapMonth = MAPPING[offset][0]
//如果isLeap=true并且当前月份就是闰月或者本月有闰月且当前月份大于闰月则月份需要加1
if ((leap && month == leapMonth) || (leapMonth > 0 && month > leapMonth)) {
month += 1
}
//取出对应到某个月的片断
var segment = MAPPING[offset][month] //农历第一天对应公历的具体天
var mapMonth = Number(segment.substring(0, 2))
var mapDate = Number(segment.substring(2, 4))
if (mapMonth > 12) {
year += 1
mapMonth -= 12
}
var solar = new Date(year, mapMonth - 1, mapDate)
var time = solar.getTime() + (day - 1) * 24 * 60 * 60 * 1000
return new Date(time)
}
/*
公历转农历
1.查找对应农历初一是哪一天
2.将农历初一转换为公历
3.计入偏移量
*/
_chineseLunar.solarToLunar = function(solar, format) {
var offset = solar.getFullYear() - MINYEAR
//超出范围
if (offset <= 0 || offset >= MAPPING.length) {
throw new Error('Specified date range is invalid.')
}
//查找范围内的农历数据
var data = _findLunar(solar, offset, 0, 13, false)
//如果没有找到,则找前一年的,因为农历在公历之前,并且不会超过一年,查一年就可以了
data = data || _findLunar(solar, offset - 1, 12, 99, true)
//还是没有找到,表示超出范围
if (!data) return false
//农历初一对应公历的哪一天
var firstDay = new Date(data.year, data.month - 1, data.day)
var day = _solarDiff(solar, firstDay, 'd') + 1
//返回的农历结果
var result = {
leap: data.leapMonth > 0 && data.leapMonth + 1 == data.lunarMonth,
year: data.lunarYear,
month: data.leapMonth > 0 && data.lunarMonth > data.leapMonth ? data.lunarMonth - 1 : data.lunarMonth,
day: day,
leapMonth: data.leapMonth
}
//判断是否要格式化结果
return format && result ? _chineseLunar.format(result, format) : result
}
//获取中国传统干支的名称
_chineseLunar.traditionalYearName = function(year) {
var Gan = '甲乙丙丁戊己庚辛壬癸'.split('')
var Zhi = '子丑寅卯辰巳午未申酉戌亥'.split('')
year = year - MINYEAR + 36
return Gan[year % 10] + Zhi[year % 12] + '年'
}
//获取中文的年
_chineseLunar.yearName = function(year) {
var cnStr = ',一,二,三,四,五,六,七,八,九'.split(',')
var cYear = year.toString()
var result = ''
for (var i = 0; i < cYear.length; i++) {
result += cnStr[parseInt(cYear.charAt(i))]
}
return result + '年'
}
//获取中国的生肖
_chineseLunar.animalName = function(year) {
return '鼠牛虎兔龙蛇马羊猴鸡狗猪'.split('')[(year - 4) % 12]
}
//获取农历月的名称
_chineseLunar.monthName = function(month, traditional, leap) {
var monthName = '正,二,三,四,五,六,七,八,九,十,十一,十二'.split(',')
if (traditional) {
monthName[11] = '腊'
}
return (leap ? '闰' : '') + monthName[month - 1] + '月'
}
//获取农历传统天的名称
_chineseLunar.dayName = function(lunar) {
switch (lunar) {
case 10:
return '初十'
case 20:
return '二十'
case 30:
return '三十'
default:
return '初十廿卅'.split('')[Math.floor(lunar / 10)] + '一二三四五六七八九十'.split('')[(lunar - 1) % 10] || lunar
}
}
//格式化农历日期date是农历的日期
_chineseLunar.format = function(lunar, expr) {
return expr.replace(/[TAYyMmdD]/g, function(m, i) {
switch (m) {
//获取传统的年
case 'T':
return _chineseLunar.traditionalYearName(lunar.year)
//获取生肖
case 'A':
return _chineseLunar.animalName(lunar.year)
//获取中文的年
case 'Y':
return _chineseLunar.yearName(lunar.year)
//获取数字年
case 'y':
return lunar.year
//获取月份
case 'm':
return _chineseLunar.monthName(lunar.month, false, lunar.leap)
//获取传统的月
case 'M':
return _chineseLunar.monthName(lunar.month, true, lunar.leap)
//获取天
case 'd':
return _chineseLunar.dayName(lunar.day)
//如果是初一,则显示月,而不是显示
case 'D':
if (lunar.day == 1) {
return _chineseLunar.monthName(lunar.month, false, lunar.leap)
} else {
return _chineseLunar.dayName(lunar.day)
}
}
})
}
export default _chineseLunar

View File

@@ -0,0 +1,48 @@
/**
* @Description: 各种工具类
* @Author: TSY
* @CreateDate: 2018/6/9 13:28
*/
/**
* 判断安卓与IOS平台
* @returns {string}
*/
export const checkPlatform = function() {
if (/android/i.test(navigator.userAgent)) {
return '1'
}
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
return '2'
}
}
/**
* 日期格式化
* @param time
* @param format
* @returns {string}
*/
export let formatDate = function(time, format) {
format = format || 'YY年MM月DD日 hh:mm'
let date = time ? new Date(time) : new Date()
let year = date.getFullYear()
let month = date.getMonth() + 1 // 月份是从0开始的
let day = date.getDate()
let hour = date.getHours()
let min = date.getMinutes()
let sec = date.getSeconds()
let preArr = Array.apply(null, Array(10)).map(function(elem, index) {
return '0' + index
}) // /开个长度为10的数组 格式为 00 01 02 03
let newTime = format
.replace(/YY/g, year)
.replace(/F/g, hour >= 12 ? 'pm' : 'am')
.replace(/ss/g, preArr[sec] || sec)
.replace(/mm/g, preArr[min] || min)
.replace(/hh/g, hour > 12 && format.includes('F') ? hour - 12 : format.includes('F') ? hour : preArr[hour] || hour)
.replace(/DD/g, preArr[day] || day)
.replace(/MM/g, preArr[month] || month)
return newTime
}

View File

@@ -33,8 +33,9 @@
<span class="red">{{Name}}</span>
</div>
<div class="flex align-items-c h86 content1 bg-white mt10">
<div class="absolute h60 ml20 mt20 fs13 white captain">团队长</div>
<div
class="w40 h60 ml15 text-center relative"
class="w40 h60 ml15 text-center relative header-box"
v-for="(item, index) in headerList"
:key="index"
>
@@ -377,4 +378,9 @@ export default {
border-radius: 20px;
position: absolute;
}
.captain{
z-index: 2000;
text-align: center;
width:26px;
}
</style>