<!-- 日期组件 --> <template> <view class="tm-pickersDateView flex-start px-24" :class="[black_tmeme ? 'grey-darken-5' : bgColor]"> <!-- :value="value_default" @change="change" --> <picker-view @pickstart="$emit('aniStart')" @pickend="$emit('aniEnd')" @change="change" v-if="list_cD != null" :value="value_default" :mask-style="black_tmeme ? 'opacity:0;' : ''" indicator-style="height:50px;" indicator-class="tm-pickersCView-item-h" class="tm-pickersCView-wk" > <picker-view-column v-show="syheng_key[key]" v-for="(item, key) in list_cD" :key="key"> <view class="tm-pickersCView-item fulled-height flex-center " style="margin: 0 5px;" :class="[value_default[key] == index_pub ? ' text-weight-b active' : '', black_tmeme ? 'bk' : '', 'text-size-n']" v-for="(item_data, index_pub) in item" :key="index_pub" > <text>{{ buqi(item_data) }}</text> <text v-if="mode">{{ modhz[key] }}</text> </view> </picker-view-column> </picker-view> </view> </template> <script> /** * 日期下拉选择器(嵌入式) * @description 多级关联,单级关联选择 * @property {Array} default-value = [] 默认:当前的时间,初始显示的时间 * @property {String|Number} item-height = [34|42|50|58|62] 项目的高度单位px * @property {String|Boolean} black = [true|false] 是否开启暗黑模式。 * @property {String|Boolean} disabled = [true|false] 是否禁用 * @property {String} bg-color = [white|blue] 默认:white,白色背景;请填写背景的主题色名称。 * @property {Object} show-detail = [{year:true,month:true,day:true,hour:false,min:false,sec:false}] 默认:{year:true,month:true,day:true,hour:false,min:false,sec:false} * @property {String} start = [1900-1-1 00:00:00] 默认:1900-1-1 00:00:00,开始的时间 * @property {String} end = [] 默认:当前,结束的时间 * @property {String|Boolean} mode = [true|false] 默认:true,是否显示中文年,月后缀 * @property {String|Boolean} full-number = [true|false] 默认:true,是否把个位数补齐双位数 */ export default { name: 'tm-pickersDateView', props: { // 行高。 itemHeight: { type: String | Number, default: 40 }, black: { type: String | Boolean, default: null }, // 是否禁用 disabled: { type: String | Boolean, default: false }, // 背景颜色,主题色名称。 bgColor: { type: String, default: 'white' }, //要展示的时间。 showDetail: { type: Object, default: () => { return { year: true, //年 month: true, //月 day: true, //天 hour: false, //小时 min: false, //分 sec: false //秒 }; } }, start: { type: String, default: '1949-1-1 00:00:00' }, end: { type: String, default: '' }, defaultValue: '', // 是否显示中文年,月后缀 mode: { type: String | Boolean, default: true }, //要展示的时间。 modeValue: { type: Object, default: () => { return { year: '年', //年 month: '月', //月 day: '日', //天 hour: '时', //小时 min: '分', //分 sec: '秒' //秒 }; } }, // 是否把个位数补齐双位数 fullNumber: { type: String | Boolean, default: true } }, data() { return { dataCauser: { year: false, //年 month: false, //月 day: false, //天 hour: false, //小时 min: false, //分 sec: false //秒 }, hoz: { year: '年', //年 month: '月', //月 day: '日', //天 hour: '时', //小时 min: '分', //分 sec: '秒' //秒 }, totalRow:0, syheng_key: {}, //当前生成的所有数据年~秒 r_list:[], list_cD: null, value_default: [], nowObj:null, }; }, created() { this.dataCauser = {...this.dataCauser,...(this.showDetail||{})} this.setdataCauserArray(); this._reInits(); }, mounted() { }, watch: { showDetail:{ deep:true, handler(){ this.dataCauser = {...this.dataCauser,...this.showDetail}; this.setdataCauserArray(); } }, defaultValue: function(val) { let nowdateVal; if (val) { nowdateVal = new Date(val.replace(/-/g, '/')); } else { nowdateVal = new Date(); } this.nowObj = nowdateVal; if(this.list_cD==null) return; this._reInits(); }, start: async function() { if(this.list_cD==null) return; this._reInits(); }, end: async function() { if(this.list_cD==null) return; this._reInits(); } }, computed: { black_tmeme: function() { if (this.black !== null) return this.black; return this.$tm.vx.state().tmVuetify.black; }, modhz: function() { let hz = []; let moz = { ...this.hoz, ...this.modeValue }; hz.push(moz.year) hz.push(moz.month) hz.push(moz.day) hz.push(moz.hour) hz.push(moz.min) hz.push(moz.sec) return hz; }, detavlue:function () { let d = this.defaultValue; if(!d){ let ys = new Date(); d = ys.getFullYear()+'-'+(ys.getMonth()+1)+'-'+ys.getDate()+' '+ys.getHours()+':'+ys.getMinutes()+':'+ys.getSeconds() } return d.replace(/-/g, '/'); }, //结束的日期,默认为当前 end_str:function () { let d = this.end; if(!d){ let ys = new Date(); d = ys.getFullYear()+'-'+(ys.getMonth()+1)+'-'+ys.getDate()+' '+ys.getHours()+':'+ys.getMinutes()+':'+ys.getSeconds() } return d.replace(/-/g, '/'); }, //开始默认为1960年 start_str:function () { let d = this.start; if(!d){ d='1960-1-1 00:00:00' } return d.replace(/-/g, '/'); }, }, methods: { //设置显示的行当。 setdataCauserArray(){ let t = this; let f = { '0':this.dataCauser['year'], '1':this.dataCauser['month'], '2':this.dataCauser['day'], '3':this.dataCauser['hour'], '4':this.dataCauser['min'], '5':this.dataCauser['sec'], } //显示的列表数。 let totalHoz = 0; let p = Object.keys(this.dataCauser); p = p.filter(el=>t.dataCauser[el]==true) this.totalRow = p.length; this.syheng_key = f; }, //初始生成对应的开始和结束日期数据。 _reInits(date){ let t = this; let nowdateVal; if (date) { nowdateVal = new Date(date.replace(/-/g, '/')); } else { nowdateVal = new Date(this.detavlue); } this.nowObj = nowdateVal; /** * 接下来,需要比对,年月,日。 * 分开比较的原因是:如果年不变的话,只是改变月,那么只需重新 * 更改日的数据(如果每月的日期一样,也不需要改变。) */ //根据提供的值nodwdateVal来划定开始和结束的日期数据。为了保证流畅,采用一次性生成的方法。 //先生成开始的数据。 //开始 const start = new Date(this.start_str); //结束 const end = new Date(this.end_str); //当前 const now = nowdateVal; let list = []; let year = this.range(start.getFullYear(),end.getFullYear()) list.push(year) // 月。是需要根据nowdateVal提供的值来生成。因为月是不固定的。 //默认先生成start到12的 let month_s = this.range(start.getMonth()+1,12) let month_e = this.range(1,end.getMonth()+1) //同年同月 if(start.getFullYear()==end.getFullYear()&&start.getMonth()==end.getMonth()){ let tn = this.range(start.getMonth()+1,end.getMonth()+1); list.push([tn,tn]) }else{ list.push([month_s,month_e]) } let day_s = this.range(start.getDate(),this.monthDay(start.getFullYear(),start.getMonth())) let day_e = this.range(1,end.getDate()) //同年同月同日 if(start.getFullYear()==end.getFullYear() &&start.getMonth()==end.getMonth() &&start.getDate()==end.getDate() ){ let tn = this.range(start.getDate(),end.getDate()); list.push([tn,tn]) }else{ list.push([day_s,day_e]) } let hours_s = this.range(start.getHours(),23) let hours_e = this.range(0,end.getHours()) //同年同月同日同时 if(start.getFullYear()==end.getFullYear() &&start.getMonth()==end.getMonth() &&start.getDate()==end.getDate() &&start.getHours()==end.getHours() ){ let tn = this.range(start.getHours(),end.getHours()); list.push([tn,tn]) }else{ list.push([hours_s,hours_e]) } let minutes_s = this.range(start.getMinutes(),59) let minutes_e = this.range(0,end.getMinutes()) //同年同月同日同时同分 if(start.getFullYear()==end.getFullYear() &&start.getMonth()==end.getMonth() &&start.getDate()==end.getDate() &&start.getHours()==end.getHours() ){ let tn = this.range(start.getMinutes(),end.getMinutes()); list.push([tn,tn]) }else{ list.push([minutes_s,minutes_e]) } let seconds_s = this.range(start.getSeconds(),59) let seconds_e = this.range(0,end.getSeconds()) //同年同月同日同时同分同秒 if(start.getFullYear()==end.getFullYear() &&start.getMonth()==end.getMonth() &&start.getDate()==end.getDate() &&start.getHours()==end.getHours() &&start.getSeconds()==end.getSeconds() ){ let tn = this.range(start.getSeconds(),end.getSeconds()); list.push([tn,tn]) }else{ list.push([seconds_s,seconds_e]) } this.r_list = list; this.$nextTick(function () { this._getListCd(start,end,now) }) }, //生成对应的列表数据,以供选择。不需要生成所有,只要生成默认当前时间的。 _getListCd(start,end,now,issetd){ let list_cD = []; //年 list_cD.push(this.r_list[0]) //月。 let year_s = new Date(String(start.getFullYear())+'/1/1').getTime() let year_e = new Date(String(end.getFullYear())+'/1/1').getTime() let year_n = new Date(String(now.getFullYear())+'/1/1').getTime() if( year_s===year_e //开始和结束相同 ||(year_s!=year_e&&year_n==year_s) //现在=开始。 ||(year_s!=year_e&&year_n<year_s) //现在小于开始 ){ list_cD.push(this.r_list[1][0]) }else if( (year_s!=year_e&&year_n==year_e) //现在=结束。 ||(year_s!=year_e&&year_n>year_e) //现在大于结束 ){ list_cD.push(this.r_list[1][1]) }else{ //在开始和结束之间。 list_cD.push(this.range(1,12)) } //日。 let day_s = new Date(start.getFullYear()+'/'+(start.getMonth()+1)+'/1').getTime() let day_e = new Date(end.getFullYear()+'/'+(end.getMonth()+1)+'/1').getTime() let day_n = new Date(now.getFullYear()+'/'+(now.getMonth()+1)+'/1').getTime() if( day_s===day_e //开始和结束相同 ||(day_s!=day_e&&day_n==day_s) //现在=开始。 ||(day_s!=day_e&&day_n<day_s) //现在小于开始 ){ list_cD.push(this.r_list[2][0]) }else if( (day_s!=day_e&&day_n==day_e) //现在=结束。 ||(day_s!=day_e&&day_n>day_e) //现在大于结束 ){ list_cD.push(this.r_list[2][1]) }else{ //在开始和结束之间。 list_cD.push(this.range(1,this.monthDay(now.getFullYear(),now.getMonth()))) } //时。 let hours_s = new Date(String(start.getFullYear())+'/'+(start.getMonth()+1)+'/'+start.getDate()).getTime() let hours_e = new Date(String(end.getFullYear())+'/'+(end.getMonth()+1)+'/'+end.getDate()).getTime() let hours_n = new Date(String(now.getFullYear())+'/'+(now.getMonth()+1)+'/'+now.getDate()).getTime() if( hours_s===hours_e //开始和结束相同 ||(hours_s!=hours_e&&hours_n==hours_s) //现在=开始。 ||(hours_s!=hours_e&&hours_n<hours_s) //现在小于开始 ){ list_cD.push(this.r_list[3][0]) }else if( (hours_s!=hours_e&&hours_n==hours_e) //现在=结束。 ||(hours_s!=hours_e&&hours_n>hours_e) //现在大于结束 ){ list_cD.push(this.r_list[3][1]) }else{ //在开始和结束之间。 list_cD.push(this.range(0,23)) } //分。 let min_s = new Date(String(start.getFullYear())+'/'+(start.getMonth()+1)+'/'+start.getDate()+' '+start.getHours()+':00:00').getTime() let min_e = new Date(String(end.getFullYear())+'/'+(end.getMonth()+1)+'/'+end.getDate()+' '+end.getHours()+':00:00').getTime() let min_n = new Date(String(now.getFullYear())+'/'+(now.getMonth()+1)+'/'+now.getDate()+' '+now.getHours()+':00:00').getTime() if( min_s===min_e //开始和结束相同 ||(min_s!=min_e&&min_n==min_s) //现在=开始。 ||(min_s!=min_e&&min_n<min_s) //现在小于开始 ){ list_cD.push(this.r_list[4][0]) }else if( (min_s!=min_e&&min_n==min_e) //现在=结束。 ||(min_s!=min_e&&min_n>min_e) //现在大于结束 ){ list_cD.push(this.r_list[4][1]) }else{ //在开始和结束之间。 list_cD.push(this.range(0,59)) } //秒。 let seccode_s = new Date(String(start.getFullYear())+'/'+(start.getMonth()+1)+'/'+start.getDate()+' '+start.getHours()+':'+start.getMinutes()+':00').getTime() let seccode_e = new Date(String(end.getFullYear())+'/'+(end.getMonth()+1)+'/'+end.getDate()+' '+end.getHours()+':'+start.getMinutes()+':00').getTime() let seccode_n = new Date(String(now.getFullYear())+'/'+(now.getMonth()+1)+'/'+now.getDate()+' '+now.getHours()+':'+start.getMinutes()+':00').getTime() if( seccode_s===seccode_e //开始和结束相同 ||(seccode_s!=seccode_e&&seccode_n==seccode_s) //现在=开始。 ||(seccode_s!=seccode_e&&seccode_n<seccode_s) //现在小于开始 ){ list_cD.push(this.r_list[4][0]) }else if( (seccode_s!=seccode_e&&seccode_n==seccode_e) //现在=结束。 ||(seccode_s!=seccode_e&&seccode_n>seccode_e) //现在大于结束 ){ list_cD.push(this.r_list[4][1]) }else{ //在开始和结束之间。 list_cD.push(this.range(0,59)) } this.$nextTick(function () { this.list_cD = list_cD; if(!issetd){ this.$nextTick(function () { this.setDefaultIndex(); }) } }) }, monthDay(year, month) { let date = new Date(year, month, 1, 0, 0, 0); date.setMonth(date.getMonth()+1) let yesterDay = new Date(date - 1000); return yesterDay.getDate(); }, //生成一个数据数组。 range(from=0,to){ const range = []; if(from===to) return [from]; for (let i = from; i <= to; i++) { range.push(i) } return range }, //设置当前选中的索引。 setDefaultIndex(){ if(!this.list_cD) return; let value_default = []; let t = this; // 年。 let year = this.list_cD[0].findIndex(el=>el==t.nowObj.getFullYear()); year=year<=0?0:year; let month = this.list_cD[1].findIndex(el=>el==t.nowObj.getMonth()+1); month=month<=0?0:month; let day = this.list_cD[2].findIndex(el=>el==t.nowObj.getDate()); day=day<=0?0:day; let hours = this.list_cD[3].findIndex(el=>el==t.nowObj.getHours()); hours=hours<=0?0:hours; let minutes = this.list_cD[4].findIndex(el=>el==t.nowObj.getMinutes()); minutes=minutes<=0?0:minutes; let seconds = this.list_cD[5].findIndex(el=>el==t.nowObj.getSeconds()); seconds=seconds<=0?0:seconds; // 开始设置,如果当前默认的日期不在范围内。默认选中的索引日期。 value_default = [year,month,day,hours,minutes,seconds] this.$nextTick(function () { this.value_default = value_default; }) }, //回显到初始化值。 resetVal(setd){ let val = this.defaultValue; if(setd) val = setd; let nowdateVal; if (val) { nowdateVal = new Date(val.replace(/-/g, '/')); } else { nowdateVal = new Date(); } this.nowObj = nowdateVal; if(this.list_cD==null) return; this._reInits(); this.$nextTick(function () { this.setDefaultIndex(); }) }, buqi(val) { return val > 9 ? '' + val : '0' + val; }, //通过索引获取当前数据 SeletecdeIndexdefault(value_default) { if(!value_default) value_default = this.value_default; let t = this; let ap = []; this.value_default.forEach((item,index) => { let f = t.list_cD[index][parseInt(item)]; f = typeof(f)=="undefined"? t.list_cD[index][ t.list_cD[index].length-1]:f; ap.push(f); }); return ap; }, // 获取当前选中的数据。 getSelectedValue() { let t = this; let ap = this.SeletecdeIndexdefault(); let jg = { year: ap[0], //年 month: ap[1], //月 day: ap[2], //天 hour: ap[3], //小时 min: ap[4], //分 sec: ap[5] //秒 }; let ar = Object.keys(this.dataCauser); ar.forEach(item => { if (t.dataCauser[item] === false) { delete jg[item]; } }); return jg; }, getSelsectDate() { let t = this; let ap = this.SeletecdeIndexdefault(); let jg = { year: ap[0], //年 month: ap[1], //月 day: ap[2], //天 hour: ap[3], //小时 min: ap[4], //分 sec: ap[5] //秒 }; return new Date(ap[0]+'/'+ap[1]+'/'+ap[2]+' '+ap[3]+':'+ap[4]+':'+ap[5]); }, change(e) { //滑动后,要动态修改数据。 let val = e.detail.value; let index =0; // 找出修改的index项。 let nowD = [this.nowObj.getFullYear(),1,1,0,0,0]; let nowObj = [this.nowObj.getFullYear(),this.nowObj.getMonth()+1,this.nowObj.getDate(),this.nowObj.getHours(),this.nowObj.getMinutes(),this.nowObj.getSeconds()]; for (var i = 0; i < 6; i++) { if(this.value_default[i]!==val[i]){ nowD[i] = this.list_cD[i][val[i]] }else{ let idx = this.list_cD[i].findIndex(el=>el==nowObj[i]) if(idx==-1){ nowD[i] = this.list_cD[i][0] }else{ nowD[i] = nowObj[i] } } } const now = nowD[0]+'/'+(nowD[1])+'/'+nowD[2]+' '+nowD[3]+':'+nowD[4]+':'+nowD[5]; this._reInits(now) let nowVal = val.map(el=>{ let dsdd = el<=0?0:el; return dsdd }) this.$nextTick(function () { this.value_default = nowVal; // 发送滚动选中的时间数据。 this.$emit('change',this.getSelectedValue()); }) }, jswid() { let wd = this.gridNum - 1 - 2; if (wd <= 0) wd = 1; return 100 / wd; }, } }; </script> <style> .tm-pickersDateView .tm-pickersCView-item-h { height: 50px; background-color: rgba(0, 0, 0, 0.03); width: calc(100% - 10px); margin-left: 5px; border-radius: 20rpx; border: none; } .tm-pickersDateView .tm-pickersCView-item-h::after, .tm-pickersDateView .tm-pickersCView-item-h::before { border: none; } .tm-pickersDateView .tm-pickersCView-wk { position: relative; width: 750rpx; height: 500rpx; } .tm-pickersDateView .tm-pickersCView-wk .tm-pickersCView-item.bk { opacity: 0.4; } .tm-pickersDateView .tm-pickersCView-wk .tm-pickersCView-item.active { opacity: 1; border-radius: 20rpx; border: none; background-color: rgba(0, 0, 0, 0.06); } .tm-pickersDateView .tm-pickersCView-wk .tm-pickersCView-item.active.bk { background-color: rgba(255, 255, 255, 0.06); } </style>