543 lines
13 KiB
Vue
543 lines
13 KiB
Vue
<template>
|
||
<view style="position: relative;">
|
||
<input type="hidden" :name="name" :value="tostamp(tvalue)" style="display:none;" />
|
||
<input v-if="hasmore" type="hidden" :name="name+'_date'" :value="todatetime(tvalue,btime?'':(selectmonth?'m':'d'))" style="display:none;" />
|
||
<view class="_show" :class="{_left:left,_disabled:disabled}" @tap="showpop" v-if="tostamp(tvalue)==0" style="color:var(--txt1)">{{placeholder===undefined?lang('placeholder.select'):placeholder}}</view>
|
||
<view class="_show" :class="{_left:left,_disabled:disabled}" @tap="showpop" v-else>{{todatetime(tvalue,btime?'':(selectmonth?'m':'d'))}}</view>
|
||
<view class="_mask" v-if="popclass" @tap="hidepop"></view>
|
||
<view class="_pop" :animation="anidatapop" v-if="popclass" :class="popclass">
|
||
<view class="_main" :class="popclass">
|
||
<view class="ciy-hr" style="flex:none;"></view>
|
||
<ciy-calendar :selectmonth="selectmonth" :value="vdate" @change="chgcalendar" v-if="cpage == 0" name="tp" :mindate="mindate" :maxdate="maxdate" :weekmonday="weekmonday" :selectbg="selectbg" :bordercolor="bordercolor" :selecttextcolor="selecttextcolor" :clearbtn="clearbtn"></ciy-calendar>
|
||
<view v-if="cpage == 1" class="_shour">
|
||
<view class="itm" v-for="(_,val) in 24" @tap="clkhour(val)" :style="val==vhour?'font-weight:bolder;color:var(--man5);':''">
|
||
{{val}}
|
||
</view>
|
||
</view>
|
||
<view v-if="cpage == 2" class="_smin" :class="popclass">
|
||
<view class="_smin2">
|
||
<view class="itm" v-for="(_,val) in 10" @tap="clkmin2(val)" :style="val==vminute2?'font-weight:bolder;color:var(--man5);':''">
|
||
{{val}}
|
||
</view>
|
||
</view>
|
||
<view class="ciy-hr"></view>
|
||
<view class="_smin1">
|
||
<view class="itm" v-for="(_,val) in 6" @tap="clkmin1(val)" :style="val==vminute1?'font-weight:bolder;color:var(--man5);':''">
|
||
{{val*10}}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="_selcard" v-if="btime">
|
||
<view class="itm" :class="{_sel:cpage==0}" @tap="clkpage(0)">
|
||
<view>{{todatetime(vdate,'y', ' ')}}</view>
|
||
<view>{{todatetime(vdate,'x', ' ')}}</view>
|
||
<view class="_txt">{{lang('inputdate.date')}}</view>
|
||
</view>
|
||
<view class="itm" :class="{_sel:cpage==1}" @tap="clkpage(1)">
|
||
<view style="font-size:2em;">{{topad0(vhour,2)}}</view>
|
||
<view class="_txt">{{lang('inputdate.hour')}}</view>
|
||
</view>
|
||
<view class="itm" :class="{_sel:cpage==2}" @tap="clkpage(2)">
|
||
<view style="font-size:2em;">{{topad0(vminute1*10+vminute2,2)}}</view>
|
||
<view class="_txt">{{lang('inputdate.minute')}}</view>
|
||
</view>
|
||
<view class="itm _bbtn" :class="popclass">
|
||
<view class="btn def" @tap="today">{{lang('inputdate.now')}}</view>
|
||
<view class="btn" @tap="done">{{lang('inputdate.done')}}</view>
|
||
</view>
|
||
</view>
|
||
<view class="ciy-hr"></view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
behaviors: ['uni://form-field-group'],
|
||
emits: ['change', 'update:modelValue'],
|
||
props: {
|
||
name: {
|
||
type: String
|
||
},
|
||
modelValue: {
|
||
type: [String, Number, Date],
|
||
default: ''
|
||
},
|
||
value: {
|
||
type: [String, Number, Date],
|
||
default: ''
|
||
},
|
||
disabled: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
initevent: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
hasmore: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
placeholder: {
|
||
type: String
|
||
},
|
||
btime: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
left: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
bordercolor: {
|
||
type: String,
|
||
default: 'var(--bg6)'
|
||
},
|
||
selecttextcolor: {
|
||
type: String,
|
||
default: 'var(--man5)'
|
||
},
|
||
selectbg: {
|
||
type: String,
|
||
default: 'var(--bg1)'
|
||
},
|
||
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
|
||
},
|
||
diastema: { //间隙
|
||
type: Number,
|
||
default: 16
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
v: '',
|
||
vdate: 0,
|
||
vhour: 0,
|
||
vminute1: 0,
|
||
vminute2: 0,
|
||
cpage: 0,
|
||
anidatapop: {},
|
||
popclass: ''
|
||
};
|
||
},
|
||
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;
|
||
}
|
||
|
||
if (!(val instanceof Date)) {
|
||
if (val.indexOf('-') > -1 || val.indexOf('/') > -1) {
|
||
val = this.str2date(val);
|
||
} else {
|
||
val = this.toint(val);
|
||
val = new Date(val * 1000);
|
||
}
|
||
} else if (isNaN(val.getTime()))
|
||
val = new Date();
|
||
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 = 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;
|
||
}
|
||
},
|
||
mounted() {
|
||
// var vd = new Date(this.tvalue.getFullYear(), this.tvalue.getMonth(), this.tvalue.getDate());
|
||
// vd.setMinutes(-vd.getTimezoneOffset());
|
||
// this.vdate = this.tostamp(vd);
|
||
var date = this.tostamp(this.onlydate(this.tvalue));
|
||
this.vdate = date;
|
||
this.vhour = this.tvalue.getHours();
|
||
var minute = this.tvalue.getMinutes();
|
||
this.vminute1 = parseInt(minute / 10);
|
||
this.vminute2 = minute - this.vminute1 * 10;
|
||
if (this.vdate == 0 && this.vhour == 8)
|
||
this.vhour = 0;
|
||
if (this.initevent) {
|
||
this.emit('init', this.tvalue, true);
|
||
}
|
||
},
|
||
methods: {
|
||
onlydate(val) {
|
||
var dt = new Date(val.toLocaleDateString());
|
||
dt.setMinutes(-dt.getTimezoneOffset());
|
||
return dt;
|
||
},
|
||
chgcalendar(e) {
|
||
var from = 'calendar'; //false 同步value到父
|
||
if (!this.btime || e.from == 'today' || e.from == 'nodate')
|
||
from = 'done';
|
||
if (from == 'done') {
|
||
setTimeout(() => {
|
||
this.hidepop();
|
||
}, 300);
|
||
}
|
||
if (e.from == 'nodate') {
|
||
this.vhour = 0;
|
||
this.vminute1 = 0;
|
||
this.vminute2 = 0;
|
||
}
|
||
this.vdate = e.value;
|
||
this.updatevalue(from);
|
||
},
|
||
updatevalue(from) {
|
||
var d = new Date(this.vdate * 1000);
|
||
if (this.vdate != 0) {
|
||
d.setHours(this.vhour);
|
||
d.setMinutes(this.vminute1 * 10 + this.vminute2);
|
||
}
|
||
if (d.getTime() == this.tvalue.getTime())
|
||
return;
|
||
this.emit(from, d);
|
||
},
|
||
emit(from, date) {
|
||
if (!this.btime) {
|
||
var date = new Date(date.getTime());
|
||
if (date.getTime() != 0) {
|
||
date.setHours(0);
|
||
date.setMinutes(0);
|
||
date.setSeconds(0);
|
||
}
|
||
}
|
||
// if (date.getFullYear() == 1970 && date.getMonth() == 0 && date.getDate() == 1)
|
||
// date.setMinutes(-date.getTimezoneOffset());
|
||
var stramp = this.tostamp(date);
|
||
if (from == 'done') {
|
||
this.$emit('update:modelValue', stramp);
|
||
this.v = date;
|
||
}
|
||
this.$emit('change', {
|
||
name: this.name,
|
||
from: from,
|
||
value: stramp,
|
||
date: date
|
||
});
|
||
},
|
||
today() {
|
||
var dt = new Date();
|
||
this.vhour = dt.getHours();
|
||
var min = dt.getMinutes();
|
||
this.vminute1 = parseInt(min / 10);
|
||
this.vminute2 = min - parseInt(min / 10) * 10;
|
||
dt.setSeconds(0);
|
||
this.vdate = this.tostamp(dt);
|
||
//this.updatevalue('today', this.vdate, true);
|
||
},
|
||
done() {
|
||
var date = new Date(this.vdate * 1000);
|
||
if (this.vdate != 0) {
|
||
date.setHours(this.vhour);
|
||
date.setMinutes(this.vminute1 * 10 + this.vminute2);
|
||
date.setSeconds(0);
|
||
}
|
||
this.emit('done', date);
|
||
this.hidepop();
|
||
},
|
||
clkhour(val) {
|
||
this.vhour = val;
|
||
this.updatevalue('hour');
|
||
},
|
||
clkmin1(val) {
|
||
this.vminute1 = val;
|
||
this.updatevalue('minute');
|
||
},
|
||
clkmin2(val) {
|
||
this.vminute2 = val;
|
||
this.updatevalue('minute');
|
||
},
|
||
clkpage(page) {
|
||
this.cpage = page;
|
||
},
|
||
hidepop() {
|
||
var app = getApp();
|
||
var animation = uni.createAnimation({});
|
||
animation.translateX('100vw');
|
||
animation.opacity(0);
|
||
animation.step({
|
||
duration: 200
|
||
});
|
||
this.anidatapop = animation.export();
|
||
setTimeout(() => {
|
||
this.popclass = '';
|
||
}, 300);
|
||
},
|
||
async showpop() {
|
||
if (this.disabled)
|
||
return;
|
||
if (this.popclass) {
|
||
return this.hidepop();
|
||
}
|
||
var app = getApp();
|
||
app.globalData.scrollcbs['com_datetime'] = e => {
|
||
delete app.globalData.scrollcbs['com_datetime'];
|
||
this.hidepop();
|
||
};
|
||
const {
|
||
headerheight,
|
||
footerheight
|
||
} = await this.com_gethdft();
|
||
var fixtop = 0;
|
||
if (this.fix) {
|
||
//向上遍历页面中带fixed和absolute的父元素,累加top。
|
||
}
|
||
|
||
this.cpage = 0;
|
||
// if (this.tvalue.getTime() == 0)
|
||
// this.vdate = this.tostamp();
|
||
var showrect = await this.getrect('._show');
|
||
if (!showrect) {
|
||
return;
|
||
}
|
||
this.popclass = 'temp';
|
||
var mainrect = await this.getrect('._main');
|
||
if (!mainrect)
|
||
return;
|
||
this.vdate = this.tostamp(this.tvalue);
|
||
if (this.vdate != 0) {
|
||
this.vhour = this.tvalue.getHours();
|
||
var minute = this.tvalue.getMinutes();
|
||
this.vminute1 = parseInt(minute / 10);
|
||
this.vminute2 = minute - this.vminute1 * 10;
|
||
} else {
|
||
this.vhour = 0;
|
||
this.vminute1 = 0;
|
||
this.vminute2 = 0;
|
||
}
|
||
var bott = app.globalData._sysinfo.windowHeight - showrect.bottom - footerheight - this.diastema;
|
||
var topcls = '_btm';
|
||
var sytop = showrect.bottom + this.diastema - fixtop;
|
||
if (bott < mainrect.height) {
|
||
sytop = showrect.top - this.diastema - mainrect.height;
|
||
if (sytop < headerheight + fixtop)
|
||
sytop = headerheight + fixtop;
|
||
topcls = '_top';
|
||
}
|
||
this.popclass = topcls;
|
||
this.$nextTick(() => {
|
||
var animation = uni.createAnimation({});
|
||
animation.translateX(0);
|
||
animation.top(sytop);
|
||
animation.opacity(1);
|
||
animation.step({
|
||
duration: 200
|
||
});
|
||
this.anidatapop = animation.export();
|
||
});
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
<style scoped>
|
||
._show {
|
||
white-space: nowrap;
|
||
}
|
||
|
||
._show._left {
|
||
text-align: left;
|
||
}
|
||
|
||
._show._disabled {
|
||
color: var(--bg7);
|
||
}
|
||
|
||
._smin {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
width: 100%;
|
||
}
|
||
|
||
._smin1 {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
line-height: 7em;
|
||
width: 100%;
|
||
}
|
||
|
||
._smin1>.itm {
|
||
text-align: center;
|
||
flex: 0 0 16.667%;
|
||
}
|
||
|
||
._smin2 {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
line-height: 7em;
|
||
width: 100%;
|
||
}
|
||
|
||
._smin2>.itm {
|
||
text-align: center;
|
||
flex: 0 0 20%;
|
||
}
|
||
|
||
._shour {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
line-height: 5.5em;
|
||
width: 100%;
|
||
}
|
||
|
||
._shour>.itm {
|
||
text-align: center;
|
||
flex: 0 0 16.6666%;
|
||
}
|
||
|
||
._selcard {
|
||
display: flex;
|
||
width: calc(100% - 1em);
|
||
margin: 0.5em;
|
||
white-space: nowrap;
|
||
gap: 0.3em;
|
||
}
|
||
|
||
._selcard ._sel {
|
||
background: linear-gradient(33deg, var(--bg1), var(--bg4));
|
||
border-radius: 0.5em;
|
||
border: 1px solid var(--bg6);
|
||
}
|
||
|
||
._selcard ._txt {
|
||
color: var(--txt1);
|
||
}
|
||
|
||
._selcard>.itm {
|
||
flex: 1;
|
||
text-align: center;
|
||
padding: 0.5em 0;
|
||
border: 1px solid transparent;
|
||
transition: all 0.3s;
|
||
height: 5em;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
._selcard ._bbtn {
|
||
position: relative;
|
||
padding: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex: none;
|
||
}
|
||
|
||
._pop {
|
||
position: fixed;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
transform: translateX(100vw);
|
||
opacity: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 50001;
|
||
}
|
||
|
||
._pop ._main {
|
||
background: var(--bg2);
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
._btm,
|
||
._pop ._main._btm,
|
||
._selcard ._bbtn._btm {
|
||
justify-content: flex-end;
|
||
flex-direction: column-reverse;
|
||
}
|
||
|
||
._mask {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
top: 0;
|
||
z-index: 50001;
|
||
flex: 1;
|
||
backgroundx: #f3abec99;
|
||
}
|
||
</style> |