562 lines
12 KiB
Vue
562 lines
12 KiB
Vue
<template>
|
||
<view style="width: 100%;" :style="{height}">
|
||
<input type="hidden" :name="name" :value="tostamp(tvalue)" style="display:none;" />
|
||
<input v-if="hasmore" type="hidden" :name="name+'_date'" :value="todatetime(tvalue,'d')" style="display:none;" />
|
||
<view class="yearmonth" :style="{padding:selectmonth?'0 1.5em':''}">
|
||
<view class="itm">
|
||
<view v-if="selectmonth" @tap="asyear(-10)" class="flex" style="padding-right:2em;">
|
||
<view class="arrow left ciy-icon-arrow" style="margin-right:-1em;"></view>
|
||
<view class="arrow left ciy-icon-arrow" style="margin-right:-1em;"></view>
|
||
</view>
|
||
<view class="arrow left ciy-icon-arrow" @tap="asyear(-1)"></view>
|
||
<view class="maintxt" @tap="chgpage(1)">{{year}} {{lang('calendar.year')}}</view>
|
||
<view class="arrow right ciy-icon-arrow" @tap="asyear(1)"></view>
|
||
|
||
<view v-if="selectmonth" @tap="asyear(10)" class="flex" style="padding-left:2em;">
|
||
<view class="arrow right ciy-icon-arrow" style="margin-left:-1em;"></view>
|
||
<view class="arrow right ciy-icon-arrow" style="margin-left:-1em;"></view>
|
||
</view>
|
||
</view>
|
||
<view class="itm" v-if="!selectmonth">
|
||
<view class="arrow left ciy-icon-arrow" @tap="asmonth(-1)"></view>
|
||
<view class="maintxt" @tap="chgpage(2)">{{month+1}} {{lang('calendar.month')}}</view>
|
||
<view class="arrow right ciy-icon-arrow" @tap="asmonth(1)"></view>
|
||
</view>
|
||
<view class="itm" v-else>
|
||
</view>
|
||
<view v-if="!selectmonth" class="itm today" @tap="today">{{lang('calendar.today')}}</view>
|
||
<view v-else class="itm today" @tap="today">{{lang('calendar.tomonth')}}</view>
|
||
</view>
|
||
<view v-if="cpage == 0" style="padding: 0 0.2em;position: relative;">
|
||
<view class="week">
|
||
<view class="itm" v-for="(w,index) in weeks">
|
||
<slot name="header" :itm="{week:w}">
|
||
<view class="defweek">
|
||
<view class="itm" :style="{borderLeftColor:index?bordercolor:''}">
|
||
{{lang('week.'+w)}}
|
||
</view>
|
||
</view>
|
||
</slot>
|
||
</view>
|
||
</view>
|
||
<ciy-gesture @toleft="asmonth(1)" @toright="asmonth(-1)">
|
||
<view class="days">
|
||
<view class="itm" v-for="item in dayarr" @tap="clksel(item)">
|
||
<slot name="data" :itm="{year:year,month:month+1,day:item,date:tvalue,select:cal_valueselect(item),cansel:cal_opminmax(item)}">
|
||
<view class="defday" :style="cal_valueselect(item)?'color:' + selecttextcolor + ';background:' + selectbg + ';border:1px solid ' + bordercolor:''">
|
||
<view :style="{opacity:cal_opminmax(item)?1:0.4}">{{item}}</view>
|
||
</view>
|
||
</slot>
|
||
</view>
|
||
</view>
|
||
</ciy-gesture>
|
||
<view style="position: absolute;bottom:0.8em;right:0.5em;" v-if="clearbtn">
|
||
<button class="btn def" @tap="clknodate">{{lang('calendar.nodate')}}</button>
|
||
</view>
|
||
</view>
|
||
<view v-if="cpage == 1" class="syear">
|
||
<view v-if="!selectmonth" class="itm lr" @tap="odyear(-10)">
|
||
<view class="arrow left ciy-icon-arrow"></view>
|
||
<view class="arrow left ciy-icon-arrow"></view>
|
||
</view>
|
||
<view v-if="!selectmonth" class="itm lr" @tap="odyear(10)">
|
||
<view class="arrow right ciy-icon-arrow"></view>
|
||
<view class="arrow right ciy-icon-arrow"></view>
|
||
</view>
|
||
<view class="itm" v-for="yy in 12" @tap="clkyear(startyear+yy)" :style="startyear+yy==year?'font-weight:bolder;color:' + selecttextcolor:''">
|
||
{{startyear+yy}}
|
||
</view>
|
||
</view>
|
||
<view v-if="cpage == 2" class="smonth">
|
||
<view class="itm" v-for="mon in 12" @tap="clkmon(mon)" :style="month+1==mon?'font-weight:bolder;color:' + selecttextcolor:''">
|
||
{{mon}} {{lang('calendar.month')}}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
behaviors: ['uni://form-field-group'],
|
||
emits: ['change', 'update:modelValue', 'viewchange'],
|
||
props: {
|
||
name: {
|
||
type: String
|
||
},
|
||
modelValue: {
|
||
type: [String, Number, Date],
|
||
default: ''
|
||
},
|
||
value: {
|
||
type: [String, Number, Date],
|
||
default: ''
|
||
},
|
||
initevent: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
hasmore: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
bordercolor: {
|
||
type: String,
|
||
default: 'var(--bg6)'
|
||
},
|
||
selecttextcolor: {
|
||
type: String,
|
||
default: 'var(--man5)'
|
||
},
|
||
selectbg: {
|
||
type: String,
|
||
default: 'var(--bg1)'
|
||
},
|
||
height: {
|
||
type: String,
|
||
default: '23em'
|
||
},
|
||
selectmonth: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
weekmonday: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
mindate: {
|
||
type: [String, Number, Date],
|
||
default: ''
|
||
},
|
||
maxdate: {
|
||
type: [String, Number, Date],
|
||
default: ''
|
||
},
|
||
clearbtn: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
v: '',
|
||
startyear: 0,
|
||
year: 0,
|
||
month: 0,
|
||
cpage: 0 //0日期,1年,2月
|
||
};
|
||
},
|
||
watch: {
|
||
value: {
|
||
handler(newD, oldD) {
|
||
if (newD || oldD)
|
||
this.v = 'value';
|
||
},
|
||
immediate: true
|
||
},
|
||
modelValue: {
|
||
handler(newD, oldD) {
|
||
if (newD || oldD)
|
||
this.v = 'modelValue';
|
||
},
|
||
immediate: true
|
||
}
|
||
},
|
||
computed: {
|
||
tvalue() {
|
||
var val = '';
|
||
if (this.v == 'modelValue') {
|
||
if (typeof(this.modelValue) == 'number')
|
||
val = new Date(this.modelValue * 1000);
|
||
else if (this.modelValue)
|
||
val = this.modelValue;
|
||
} else if (this.v == 'value') {
|
||
if (typeof(this.value) == 'number')
|
||
val = new Date(this.value * 1000);
|
||
else if (this.value)
|
||
val = this.value;
|
||
} else {
|
||
val = this.v;
|
||
}
|
||
this._is0 = false;
|
||
if (!(val instanceof Date)) {
|
||
if (val.indexOf('-') > -1 || val.indexOf('/') > -1) {
|
||
val = this.str2date(val);
|
||
} else {
|
||
val = this.toint(val);
|
||
if (val == 0) {
|
||
this._is0 = true;
|
||
val = new Date();
|
||
} else {
|
||
val = new Date(val * 1000);
|
||
}
|
||
}
|
||
} else if (isNaN(val.getTime())) {
|
||
this._is0 = true;
|
||
val = new Date();
|
||
}
|
||
|
||
if (this.max && this.max <= val)
|
||
val = this.max;
|
||
|
||
if (this.min && this.min >= val && val.getTime() != 0)
|
||
val = this.min;
|
||
if (val.getTime() != 0) {
|
||
this.year = val.getFullYear();
|
||
this.month = val.getMonth();
|
||
}
|
||
return val;
|
||
},
|
||
max() {
|
||
var val = this.maxdate;
|
||
if (val instanceof Date) {
|
||
if (isNaN(val.getTime()))
|
||
val = null;
|
||
} else if (typeof(val) == 'number') {
|
||
val = new Date(val * 1000);
|
||
} else if (val.indexOf('-') > -1 || val.indexOf('/') > -1) {
|
||
val = this.str2date(val);
|
||
} else if (val == 'now') {
|
||
val = new Date();
|
||
} else {
|
||
val = this.toint(val);
|
||
if (val == 0)
|
||
val = null;
|
||
else {
|
||
val = new Date(val * 1000);
|
||
}
|
||
}
|
||
return val;
|
||
},
|
||
min() {
|
||
var val = this.mindate;
|
||
if (val instanceof Date) {
|
||
if (isNaN(val.getTime()))
|
||
val = null;
|
||
} else if (typeof(val) == 'number') {
|
||
val = new Date(val * 1000);
|
||
} else if (val.indexOf('-') > -1 || val.indexOf('/') > -1) {
|
||
val = new Date(val);
|
||
} else if (val == 'now') {
|
||
val = new Date();
|
||
} else {
|
||
val = this.toint(val);
|
||
if (val == 0)
|
||
val = null;
|
||
else {
|
||
val = new Date(val);
|
||
}
|
||
}
|
||
return val;
|
||
},
|
||
weeks() {
|
||
var wks = [];
|
||
if (!this.weekmonday)
|
||
wks.push(0);
|
||
wks.push(1);
|
||
wks.push(2);
|
||
wks.push(3);
|
||
wks.push(4);
|
||
wks.push(5);
|
||
wks.push(6);
|
||
if (this.weekmonday)
|
||
wks.push(0);
|
||
return wks;
|
||
},
|
||
dayarr() {
|
||
if (this.year == 0)
|
||
return;
|
||
var darr = [];
|
||
var monthdaycnt = new Date(this.year, this.month + 1, 0).getDate();
|
||
var day1 = new Date(this.year, this.month, 1);
|
||
var week = day1.getDay();
|
||
if (this.weekmonday)
|
||
week--;
|
||
for (var i = 0; i < week; i++)
|
||
darr.push('');
|
||
for (var i = 1; i <= monthdaycnt; i++)
|
||
darr.push(i);
|
||
var nt = 7 - (darr.length % 7);
|
||
for (var i = darr.length; i < 42; i++)
|
||
darr.push('');
|
||
return darr;
|
||
}
|
||
},
|
||
mounted() {
|
||
this.year = this.tvalue.getFullYear();
|
||
this.month = this.tvalue.getMonth();
|
||
if (this.initevent) {
|
||
this.$emit('change', {
|
||
name: this.name,
|
||
from: 'init',
|
||
value: this.tostamp(this.tvalue),
|
||
date: this.tvalue
|
||
});
|
||
}
|
||
if (this.selectmonth)
|
||
this.cpage = 2;
|
||
},
|
||
methods: {
|
||
clkyear(y) {
|
||
if (this.selectmonth) {
|
||
if (this.year != y)
|
||
this.month = -1;
|
||
this.year = y;
|
||
this.cpage = 2;
|
||
return;
|
||
}
|
||
this.year = y;
|
||
this.cpage = 0;
|
||
this.$emit('viewchange', {
|
||
name: this.name,
|
||
from: 'year',
|
||
month: this.month,
|
||
year: this.year
|
||
});
|
||
},
|
||
clkmon(mon) {
|
||
this.month = mon - 1;
|
||
if (this.selectmonth) {
|
||
this.clksel(1);
|
||
return;
|
||
}
|
||
this.cpage = 0;
|
||
this.$emit('viewchange', {
|
||
name: this.name,
|
||
from: 'month',
|
||
month: this.month,
|
||
year: this.year
|
||
});
|
||
},
|
||
chgpage(p) {
|
||
var page = this.cpage == p ? (this.selectmonth ? 2 : 0) : p;
|
||
if (page == 1)
|
||
this.startyear = parseInt((this.year - 1) / 10) * 10;
|
||
this.cpage = page;
|
||
},
|
||
odyear(od10) {
|
||
this.startyear += od10;
|
||
},
|
||
asyear(od) {
|
||
this.year += od;
|
||
if (this.selectmonth) {
|
||
this.cpage = 2;
|
||
this.month = -1;
|
||
return;
|
||
}
|
||
this.cpage = 0;
|
||
this.$emit('viewchange', {
|
||
name: this.name,
|
||
from: 'year',
|
||
month: this.month,
|
||
year: this.year
|
||
});
|
||
},
|
||
asmonth(od) {
|
||
this.month += od;
|
||
if (this.month < 0) {
|
||
this.year--;
|
||
this.month = 11;
|
||
}
|
||
if (this.month > 11) {
|
||
this.year++;
|
||
this.month = 0;
|
||
}
|
||
|
||
this.$emit('viewchange', {
|
||
name: this.name,
|
||
from: 'month',
|
||
month: this.month,
|
||
year: this.year
|
||
});
|
||
this.cpage = 0;
|
||
},
|
||
today(od) {
|
||
var val = new Date();
|
||
if (this.max && this.max <= val)
|
||
val = this.max;
|
||
if (this.min && this.min >= val)
|
||
val = this.min;
|
||
this.v = val;
|
||
this.year = val.getFullYear();
|
||
this.month = val.getMonth();
|
||
val.setHours(0);
|
||
val.setMinutes(0); //val.getTimezoneOffset()
|
||
val.setSeconds(0);
|
||
//var vt = this.tostamp(val);
|
||
// this.$emit('update:modelValue', vt);
|
||
// this.$emit('change', {
|
||
// name: this.name,
|
||
// from: 'today',
|
||
// value: vt,
|
||
// date: val
|
||
// });
|
||
if (this.selectmonth)
|
||
this.clksel(1);
|
||
else
|
||
this.clksel(val.getDate());
|
||
},
|
||
cal_opminmax(day) {
|
||
var date = new Date(this.year, this.month, day);
|
||
if (this.max) {
|
||
if (date > this.max)
|
||
return false;
|
||
}
|
||
if (this.min) {
|
||
if (date < this.min)
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
cal_valueselect(day) {
|
||
if (this._is0)
|
||
return false;
|
||
if (this.tvalue.getFullYear() != this.year)
|
||
return false;
|
||
if (this.tvalue.getMonth() != this.month)
|
||
return false;
|
||
if (this.tvalue.getDate() != day)
|
||
return false;
|
||
return true;
|
||
},
|
||
clknodate() {
|
||
var date = new Date(0);
|
||
this.$emit('update:modelValue', 0);
|
||
this.$emit('change', {
|
||
name: this.name,
|
||
from: 'nodate',
|
||
value: 0,
|
||
date: date
|
||
});
|
||
this.v = date;
|
||
},
|
||
clksel(day) {
|
||
if (!day)
|
||
return;
|
||
var date = new Date(this.year, this.month, day);
|
||
if (this.max) {
|
||
if (date > this.max)
|
||
return;
|
||
}
|
||
if (this.min) {
|
||
if (date < this.min)
|
||
return;
|
||
}
|
||
var val = this.tostamp(date);
|
||
this.$emit('update:modelValue', val);
|
||
this.$emit('change', {
|
||
name: this.name,
|
||
from: 'click',
|
||
value: val,
|
||
date: date
|
||
});
|
||
this.v = date;
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
<style scoped>
|
||
.syear {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.syear>.itm {
|
||
text-align: center;
|
||
flex: 0 0 25%;
|
||
line-height: 6em;
|
||
}
|
||
|
||
.syear .lr {
|
||
flex: 0 0 50%;
|
||
line-height: 2em;
|
||
margin-bottom: -1em;
|
||
padding-top: 1em;
|
||
}
|
||
|
||
.smonth {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
line-height: 6em;
|
||
}
|
||
|
||
.smonth>.itm {
|
||
text-align: center;
|
||
flex: 0 0 25%;
|
||
}
|
||
|
||
.week {
|
||
display: flex;
|
||
}
|
||
|
||
.week>.itm {
|
||
flex: 1;
|
||
text-align: center;
|
||
}
|
||
|
||
.week .defweek {
|
||
padding: 0.5em 0;
|
||
}
|
||
|
||
.week .defweek>.itm {
|
||
font-weight: bolder;
|
||
border-left: 1px solid transparent;
|
||
}
|
||
|
||
.days {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
}
|
||
|
||
.days .itm {
|
||
text-align: center;
|
||
flex: 0 0 14.28%;
|
||
}
|
||
|
||
.days .defday {
|
||
height: 3em;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
border-radius: 0.5em;
|
||
}
|
||
|
||
.yearmonth {
|
||
display: flex;
|
||
height: 3em;
|
||
gap: 1em;
|
||
}
|
||
|
||
.yearmonth>.itm {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.yearmonth .today {
|
||
flex: none;
|
||
padding-right: 0.5em;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.yearmonth .maintxt {
|
||
flex: 1;
|
||
text-align: center;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.arrow {
|
||
width: 1.5em;
|
||
height: 1.5em;
|
||
display: inline-block;
|
||
}
|
||
|
||
.arrow.left {
|
||
transform: rotate(90deg);
|
||
}
|
||
|
||
.arrow.right {
|
||
transform: rotate(-90deg);
|
||
}
|
||
</style> |