507 lines
14 KiB
Plaintext
507 lines
14 KiB
Plaintext
<script lang="ts">
|
|
import { type PropType } from "vue"
|
|
import { getUid, setPagePullRefresh, getPagePullRefresh } from "../../core/util/xCoreUtil.uts"
|
|
import { getDefaultColor } from "../../core/util/xCoreColorUtil.uts"
|
|
import { xDate, xDateTypeTime, createDate } from "../../core/util/xDate.uts"
|
|
import { xConfig } from "../../config/xConfig.uts"
|
|
import { PICKER_ITEM_INFO } from "../../interface.uts"
|
|
type coverValue = {
|
|
value : string[][],
|
|
str : string
|
|
}
|
|
type ModelType = "year" | "month" | "day" | "hour" | "minute" | "second";
|
|
|
|
/**
|
|
* @name 嵌入式日期选择器 xDateView
|
|
* @description 内嵌日期选择,可以控制显示精确到秒。默认的开始时间为当前时间的上一年,结束时间为默认当前时间
|
|
* 使用时,建议不要显示过多年份以防卡太多数据。
|
|
* @page /pages/index/picker-date
|
|
* @category 表单组件
|
|
* @constant 平台兼容
|
|
* | Harmony | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
|
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
| ☑ | ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.76+ | 1.1.18 |
|
|
*/
|
|
export default {
|
|
data() {
|
|
let startValue = new xDate();
|
|
let endValue = new xDate();
|
|
startValue.subtraction(1, 'y')
|
|
return {
|
|
nowValue: [] as string[][],
|
|
nowValueStr: '',
|
|
startDate: startValue,
|
|
endDate: endValue,
|
|
dateList: [] as PICKER_ITEM_INFO[][],
|
|
changeIndex: 0,
|
|
nowPull: false
|
|
}
|
|
},
|
|
emits: [
|
|
|
|
/**
|
|
* 滑动变换时触发
|
|
* @param {string} date - 当前选中时间
|
|
*/
|
|
'change',
|
|
/**
|
|
* 经格式化后的值。等同v-model:model-str
|
|
*/
|
|
'update:modelStr',
|
|
'update:modelValue'
|
|
],
|
|
props: {
|
|
|
|
/**
|
|
* 当前时间,与modelStr不同,此提供的值必须是正常的时间格式
|
|
* 否则报错,无法运行。可以提供以下合法格式:
|
|
* YYYY,YYYY-MM,YYYY-MM-DD,YYYY-MM-DD HH,YYYY-MM-DD HH:mm,YYYY-MM-DD HH:mm:ss
|
|
*/
|
|
modelValue: {
|
|
type: String,
|
|
default: ""
|
|
},
|
|
/**
|
|
* 当前时间经过format格式化后输出的值。
|
|
* 此值不会处理输入,只输出显示。
|
|
*/
|
|
modelStr: {
|
|
type: String,
|
|
default: ""
|
|
},
|
|
/**
|
|
* 顶部标题
|
|
*/
|
|
title: {
|
|
type: String,
|
|
default: "请选择时间"
|
|
},
|
|
/**
|
|
* 开始时间,请提供正确的时间格式
|
|
*/
|
|
start: {
|
|
type: String,
|
|
default: ""
|
|
},
|
|
/**
|
|
* 结束时间,请提供正确的时间格式
|
|
*/
|
|
end: {
|
|
type: String,
|
|
default: ""
|
|
},
|
|
/**
|
|
* 精确到的级别
|
|
* year:年
|
|
* month:年月
|
|
* day:年月日
|
|
* hour:年月日小时
|
|
* minute:年月日小时分钟
|
|
* second:年月日小时分钟秒
|
|
*/
|
|
type: {
|
|
type: String as PropType<ModelType>,
|
|
default: "day"
|
|
},
|
|
/**
|
|
* 输出时间格式,只对v-model:modelStr有效
|
|
* 如果桢同步对vmodel:modelValue有效需要设置formatSyncValue为true
|
|
* 有效格式:
|
|
* YYYY年
|
|
* MM月
|
|
* DD日
|
|
* hh小时
|
|
* mm分钟
|
|
* ss秒
|
|
*/
|
|
format: {
|
|
type: String,
|
|
default: "YYYY-MM-DD"
|
|
},
|
|
/**
|
|
* 是否将format格式化的v-model:modelStr同步到v-model:modelValue
|
|
* 默认false,注意:如果开启了同步,你要确保format的值是正常的时间值
|
|
* 正常兼容以下时间格式:
|
|
* YYYY,YYYY-MM,YYYY-MM-DD,YYYY-MM-DD HH,YYYY-MM-DD HH:mm,YYYY-MM-DD HH:mm:ss
|
|
*/
|
|
formatSyncValue:{
|
|
type:Boolean,
|
|
default:false
|
|
},
|
|
/**
|
|
* 上方的单位名称,'年', '月', '日', '时', '分', '秒'
|
|
*/
|
|
cellUnits: {
|
|
type: Array as PropType<string[]>,
|
|
default: () : string[] => [] as string[]
|
|
},
|
|
|
|
},
|
|
computed: {
|
|
_cellUnits():string[]{
|
|
if(this.cellUnits.length==0){
|
|
|
|
return [
|
|
this!.i18n.t("tmui4x.pickerDate.year"),
|
|
this!.i18n.t("tmui4x.pickerDate.month"),
|
|
this!.i18n.t("tmui4x.pickerDate.day"),
|
|
this!.i18n.t("tmui4x.pickerDate.hour"),
|
|
this!.i18n.t("tmui4x.pickerDate.minute"),
|
|
this!.i18n.t("tmui4x.pickerDate.second"),
|
|
]
|
|
}
|
|
return this.cellUnits;
|
|
},
|
|
_start_date() : xDate {
|
|
if (this.start == "") return this.startDate
|
|
|
|
return new xDate(this.start)
|
|
},
|
|
_end_date() : xDate {
|
|
if (this.end == "") return this.endDate
|
|
return new xDate(this.end)
|
|
},
|
|
_getDateType():xDateTypeTime{
|
|
let isType = 's' as xDateTypeTime
|
|
if (this.type == 'year') isType = 'y'
|
|
if (this.type == 'month') isType = 'm'
|
|
if (this.type == 'day') isType = 'd'
|
|
if (this.type == 'hour') isType = 'h'
|
|
if (this.type == 'minute') isType = 'M'
|
|
return isType;
|
|
}
|
|
},
|
|
watch: {
|
|
modelValue(newvalue : string) {
|
|
if (newvalue == '') return;
|
|
let isType = this._getDateType
|
|
if (new xDate(newvalue).isBetweenOf(new xDate(this.nowValueStr), '=', isType)) return;
|
|
this.defaultModelvalue(newvalue,true)
|
|
}
|
|
},
|
|
|
|
mounted() {
|
|
this.nowPull = getPagePullRefresh()
|
|
let nowValue = new xDate(this.modelValue)
|
|
this.defaultModelvalue(nowValue.format('YYYY-MM-DD'), this.modelValue != '')
|
|
|
|
},
|
|
methods: {
|
|
defaultModelvalue(newvalue:string, showStr : boolean){
|
|
let isType = this._getDateType
|
|
let nowValue = new xDate(newvalue)
|
|
if(nowValue.isBetweenOf(this._start_date, '<=', isType)){
|
|
nowValue = this._start_date;
|
|
}
|
|
if(nowValue.isBetweenOf(this._end_date, '>=', isType)){
|
|
nowValue = this._end_date;
|
|
}
|
|
|
|
let stp = this.getRangByDateTime(nowValue)
|
|
|
|
this.nowValue = stp.value;
|
|
this.nowValueStr = stp.str;
|
|
this.dateList = this.getTimeTreeByStartAndEnd(this._start_date, this._end_date)
|
|
/**
|
|
* 经格式化后的值。等同v-model:model-str
|
|
*/
|
|
this.$emit('update:modelStr', this.formatTimeDate());
|
|
},
|
|
getRangByDateTime(d : xDate) : coverValue {
|
|
let nowRange = [
|
|
[d.getYear().toString()],
|
|
[(d.getMonth()).toString()],
|
|
[d.getDate().toString()],
|
|
[d.getHours().toString()],
|
|
[d.getMinutes().toString()],
|
|
[d.getSeconds().toString()],
|
|
] as string[][]
|
|
let nowRangeStr = d.getYear().toString() + "-" + (d.getMonth() + 1).toString()
|
|
+ "-" + d.getDate().toString()
|
|
+ " " + d.getHours().toString() + ":"
|
|
+ d.getMinutes().toString() + ":"
|
|
+ d.getSeconds().toString()
|
|
return {
|
|
value: nowRange as string[][],
|
|
str: nowRangeStr
|
|
} as coverValue
|
|
},
|
|
|
|
getNowTypeLenIndex() : number {
|
|
let index = 6
|
|
if (this.type == 'year') {
|
|
index = 1;
|
|
} else if (this.type == 'month') {
|
|
index = 2;
|
|
} else if (this.type == 'day') {
|
|
index = 3;
|
|
} else if (this.type == 'hour') {
|
|
index = 4;
|
|
} else if (this.type == 'minute') {
|
|
index = 5;
|
|
}
|
|
return index;
|
|
},
|
|
indexToHex(i : number) : string {
|
|
let n = i.toString()
|
|
if (n.length == 1) return '0' + n;
|
|
return n;
|
|
},
|
|
getTimeTreeByStartAndEnd(start : xDate, end : xDate) : PICKER_ITEM_INFO[][] {
|
|
let startCopy = start.getClone();
|
|
let nowDate = new xDate(this.nowValueStr)
|
|
let endCopy = end.getClone();
|
|
let years = [] as PICKER_ITEM_INFO[];
|
|
let months = [] as PICKER_ITEM_INFO[];
|
|
let days = [] as PICKER_ITEM_INFO[];
|
|
let hours = [] as PICKER_ITEM_INFO[];
|
|
let minutes = [] as PICKER_ITEM_INFO[];
|
|
let seconds = [] as PICKER_ITEM_INFO[];
|
|
|
|
for (let i = startCopy.getYear(); i <= endCopy.getYear(); i++) {
|
|
years.push({
|
|
id: i.toString(),
|
|
title: this.indexToHex(i)
|
|
} as PICKER_ITEM_INFO)
|
|
}
|
|
let _this = this;
|
|
function getD(type : string, s : number, n : number) {
|
|
if (type == 'm') {
|
|
for (let i = s; i <= n; i++) {
|
|
months.push({
|
|
id: i.toString(),
|
|
title: _this.indexToHex(i + 1)
|
|
} as PICKER_ITEM_INFO)
|
|
}
|
|
} else if (type == 'd') {
|
|
for (let i = s; i <= n; i++) {
|
|
days.push({
|
|
id: i.toString(),
|
|
title: _this.indexToHex(i)
|
|
} as PICKER_ITEM_INFO)
|
|
}
|
|
} else if (type == 'h') {
|
|
for (let i = s; i <= n; i++) {
|
|
hours.push({
|
|
id: i.toString(),
|
|
title: _this.indexToHex(i)
|
|
} as PICKER_ITEM_INFO)
|
|
}
|
|
} else if (type == 'M') {
|
|
for (let i = s; i <= n; i++) {
|
|
minutes.push({
|
|
id: i.toString(),
|
|
title: _this.indexToHex(i)
|
|
} as PICKER_ITEM_INFO)
|
|
}
|
|
} else if (type == 's') {
|
|
for (let i = s; i <= n; i++) {
|
|
seconds.push({
|
|
id: i.toString(),
|
|
title: _this.indexToHex(i)
|
|
} as PICKER_ITEM_INFO)
|
|
}
|
|
}
|
|
}
|
|
function getDnumber(type : xDateTypeTime, target : xDateTypeTime) : number[] {
|
|
let st = 0;
|
|
let et = 0
|
|
|
|
// 不包含起始, 开始和结束内。
|
|
if (nowDate.isBetween(startCopy, endCopy, type, '()')) {
|
|
if (target == 'm') {
|
|
st = 0
|
|
et = 11
|
|
} else if (target == 'd') {
|
|
st = 1
|
|
et = nowDate.getMonthCountDay()
|
|
} else if (target == 'h') {
|
|
st = 0
|
|
et = 23
|
|
} else if (target == 'M' || target == 's') {
|
|
st = 0
|
|
et = 59
|
|
}
|
|
|
|
//
|
|
} else {
|
|
|
|
// 开始和结束相等
|
|
if (startCopy.isBetweenOf(endCopy, '=', type)) {
|
|
|
|
if (target == 'm') {
|
|
st = startCopy.getMonth()
|
|
et = endCopy.getMonth()
|
|
} else if (target == 'd') {
|
|
st = startCopy.getDate()
|
|
et = endCopy.getDate()
|
|
} else if (target == 'h') {
|
|
st = startCopy.getHours()
|
|
et = endCopy.getHours()
|
|
} else if (target == 'M') {
|
|
st = startCopy.getMinutes()
|
|
et = endCopy.getMinutes()
|
|
} else if (target == 's') {
|
|
st = startCopy.getSeconds()
|
|
et = endCopy.getSeconds()
|
|
}
|
|
|
|
} else if (nowDate.isBetweenOf(startCopy, '<=', type)) {
|
|
|
|
if (target == 'm') {
|
|
st = startCopy.getMonth()
|
|
et = 11
|
|
} else if (target == 'd') {
|
|
st = startCopy.getDate()
|
|
et = startCopy.getMonthCountDay()
|
|
} else if (target == 'h') {
|
|
st = startCopy.getHours()
|
|
et = 23
|
|
} else if (target == 'M') {
|
|
st = startCopy.getMinutes()
|
|
et = 59
|
|
} else if (target == 's') {
|
|
st = startCopy.getSeconds()
|
|
et = 59
|
|
}
|
|
} else if (nowDate.isBetweenOf(endCopy, '>=', type)) {
|
|
|
|
if (target == 'm') {
|
|
|
|
st = 0
|
|
et = endCopy.getMonth()
|
|
} else if (target == 'd') {
|
|
st = 1
|
|
et = endCopy.getDate()
|
|
|
|
} else if (target == 'h') {
|
|
st = 0
|
|
et = endCopy.getHours()
|
|
} else if (target == 'M') {
|
|
st = 0
|
|
et = endCopy.getMinutes()
|
|
} else if (target == 's') {
|
|
st = 0
|
|
et = endCopy.getSeconds()
|
|
}
|
|
}
|
|
}
|
|
return [st, et] as number[]
|
|
}
|
|
let maxlen = this.getNowTypeLenIndex();
|
|
|
|
if (maxlen > 1) {
|
|
let sdate = getDnumber('y', 'm')
|
|
getD('m', sdate[0]!, sdate[1]!)
|
|
}
|
|
if (maxlen > 2) {
|
|
let sdate = getDnumber('m', 'd')
|
|
|
|
getD('d', sdate[0]!, sdate[1]!)
|
|
}
|
|
if (maxlen > 3) {
|
|
let sdate = getDnumber('d', 'h')
|
|
getD('h', sdate[0]!, sdate[1]!)
|
|
}
|
|
if (maxlen > 4) {
|
|
let sdate = getDnumber('h', 'M')
|
|
getD('M', sdate[0]!, sdate[1]!)
|
|
}
|
|
if (maxlen > 5) {
|
|
let sdate = getDnumber('m', 's')
|
|
getD('s', sdate[0]!, sdate[1]!)
|
|
}
|
|
|
|
|
|
return [years, months, days, hours, minutes, seconds].slice(0, this.getNowTypeLenIndex()) as PICKER_ITEM_INFO[][];
|
|
},
|
|
getRangNumber(start : number, end : number) : string[] {
|
|
let iar = [] as string[];
|
|
for (let i = start; i <= end; i++) {
|
|
iar.push(i.toString());
|
|
}
|
|
return iar;
|
|
},
|
|
stringArValuCoverToString() : string {
|
|
if (this.nowValue.length != 6) return "";
|
|
|
|
let newsday = new xDate(this.nowValue[0][0] + "-" + (parseInt(this.nowValue[1][0]) + 1).toString() + "-1")
|
|
let days = parseInt(this.nowValue[2][0])
|
|
days = days >= newsday.getMonthCountDay() ? newsday.getMonthCountDay() : days
|
|
this.nowValue.splice(2, 1, [days.toString()])
|
|
|
|
return this.fillNumber(this.nowValue[0][0]) + "-" + this.fillNumber((parseInt(this.nowValue[1][0]) + 1).toString())
|
|
+ "-" + this.fillNumber(this.nowValue[2][0])
|
|
+ " " + this.fillNumber(this.nowValue[3][0]) + ":"
|
|
+ this.fillNumber(this.nowValue[4][0]) + ":"
|
|
+ this.fillNumber(this.nowValue[5][0])
|
|
},
|
|
fillNumber(n : string) : string {
|
|
if (parseInt(n) > 9) return n;
|
|
return "0" + n
|
|
},
|
|
formatTimeDate() : string {
|
|
if (this.nowValue.length != 6) return "";
|
|
let sp = this.format;
|
|
sp = sp.replace(/YYYY/g, this.fillNumber(this.nowValue[0][0]))
|
|
sp = sp.replace(/MM/g, this.fillNumber((parseInt(this.nowValue[1][0]) + 1).toString()))
|
|
sp = sp.replace(/DD/g, this.fillNumber(this.nowValue[2][0]))
|
|
sp = sp.replace(/hh/g, this.fillNumber(this.nowValue[3][0]))
|
|
sp = sp.replace(/mm/g, this.fillNumber(this.nowValue[4][0]))
|
|
sp = sp.replace(/ss/g, this.fillNumber(this.nowValue[5][0]))
|
|
return sp;
|
|
},
|
|
|
|
|
|
mchange(ids : string[], index : number) {
|
|
|
|
this.nowValue.splice(index, 1, ids)
|
|
this.nowValueStr = this.stringArValuCoverToString()
|
|
/**
|
|
* 滑动变换时触发
|
|
* @param {string} date 当前选中时间
|
|
*/
|
|
this.$emit('change', this.nowValueStr)
|
|
|
|
this.dateList = this.getTimeTreeByStartAndEnd(this._start_date, this._end_date)
|
|
|
|
this.$forceUpdate()
|
|
this.onConfirm()
|
|
},
|
|
|
|
onTouchstart() {
|
|
setPagePullRefresh(false)
|
|
},
|
|
onTouchend() {
|
|
setPagePullRefresh(this.nowPull)
|
|
},
|
|
onConfirm() {
|
|
const syncValue:string = this.formatSyncValue?this.formatTimeDate():(toRaw(this.nowValueStr) as string)
|
|
/**
|
|
* 点击确认时同步。等同v-model
|
|
*/
|
|
this.$emit('update:modelValue', syncValue);
|
|
|
|
/**
|
|
* 经格式化后的值。等同v-model:model-str
|
|
*/
|
|
this.$emit('update:modelStr', this.formatTimeDate());
|
|
|
|
|
|
}
|
|
},
|
|
}
|
|
</script>
|
|
<template>
|
|
<view class="xPickerDateWrap" @touchstart="onTouchstart" @touchend="onTouchend" @touchcancel="onTouchend">
|
|
<x-picker-view :cellUnits="[_cellUnits[index]]" @change="mchange($event as string[],index)"
|
|
:model-value="nowValue[index]" v-for="(item,index) in dateList" :key="index" style="flex: 1;"
|
|
:list="item"></x-picker-view>
|
|
</view>
|
|
</template>
|
|
<style scoped>
|
|
.xPickerDateWrap {
|
|
display: flex;
|
|
flex-direction: row;
|
|
}
|
|
</style> |