| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- <template>
- <view class="picker">
- <!-- 日期选择器 -->
- <view v-if="type!='time'" class="picker-modal">
- <view class="picker-modal-header">
- <!-- <view class="picker-icon picker-icon-zuozuo" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetYear('-1')"></view> -->
- <view class="date-btn" style="justify-content: flex-start;padding-left: 8px;" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetMonth('-1')">
- <image class="inner-img" src="/static/c-datepicker/left_btn.png" mode="aspectFit"></image>
- </view>
- <view class="picker-modal-header-title"><text style="margin-left: 0px;">{{title.substr(0,5)}}</text><text style="margin-left: 10px;">{{title.substr(5)}}</text></view>
- <view class="date-btn" style="justify-content: flex-end;padding-right: 8px;" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetMonth('+1')">
- <image class="inner-img" src="/static/c-datepicker/right_btn.png" mode="aspectFit"></image>
- </view>
- <!-- <view class="picker-icon picker-icon-youyou" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetYear('+1')"></view> -->
- </view>
- <swiper class="picker-modal-body" :circular="true" :duration="200" :skip-hidden-item-layout="true" :current="calendarIndex" @change="onSwiperChange">
- <swiper-item class="picker-calendar" v-for="(calendar,calendarIndex2) in calendars" :key="calendarIndex2">
- <view class="picker-calendar-view" v-for="(week,index) in weeks" :key="index">
- <view class="picker-calendar-view-item" style="color: #000000;font-weight: bold;">{{week}}</view>
- </view>
- <view class="picker-calendar-view" v-for="(date,dateIndex) in calendar" :key="dateIndex" @click="onSelectDate(date)">
- <!-- 背景样式 -->
- <view v-show="date.bgStyle.type" :class="'picker-calendar-view-'+date.bgStyle.type" :style="{background: date.bgStyle.background}"></view>
- <!-- 正常和选中样式 -->
- <view class="picker-calendar-view-item" :style="{opacity: date.statusStyle.opacity, color: date.statusStyle.color, background: date.statusStyle.background}">
- <text class="text">{{date.title}}</text>
- </view>
- <!-- 小圆点样式 -->
- <view class="picker-calendar-view-dot" :style="{opacity: date.dotStyle.opacity, background: date.dotStyle.background}"></view>
- <!-- 信息样式 -->
- <view v-show="date.tips" class="picker-calendar-view-tips">{{date.tips}}</view>
- </view>
- </swiper-item>
- </swiper>
- </view>
- </view>
- </template>
- <script>
- /**
- * 工具函数库
- */
- const DateTools = {
- /**
- * 获取公历节日
- * @param date Date对象
- */
- getHoliday(date) {
- let holidays = {
- '0101': '元旦',
- '0214': '情人',
- '0308': '妇女',
- '0312': '植树',
- '0401': '愚人',
- '0501': '劳动',
- '0504': '青年',
- '0601': '儿童',
- '0701': '建党',
- '0801': '建军',
- '0903': '抗日',
- '0910': '教师',
- '1001': '国庆',
- '1031': '万圣',
- '1224': '平安',
- '1225': '圣诞'
- };
- let value = this.format(date, 'mmdd');
- if (holidays[value]) return holidays[value];
- return false;
- },
- /**
- * 解析标准日期格式
- * @param s 日期字符串
- * @return 返回Date对象
- */
- parse: s => new Date(s.replace(/(年|月|-)/g, '/').replace(/(日)/g, '')),
- /**
- * 比较日期是否为同一天
- * @param a Date对象
- * @param b Date对象
- * @return Boolean
- */
- isSameDay: (a, b) => a.getMonth() == b.getMonth() && a.getFullYear() == b.getFullYear() && a.getDate() == b.getDate(),
- isBigDay: (a, b) => {
- if(new Date(a.getFullYear(),a.getMonth(),a.getDate()) >= new Date(b.getFullYear(),b.getMonth(),b.getDate())){
- return true
- }else {
- return false
- }
- },
- /**
- * 格式化Date对象
- * @param d 日期对象
- * @param f 格式字符串
- * @return 返回格式化后的字符串
- */
- format(d, f) {
- var o = {
- "m+": d.getMonth() + 1,
- "d+": d.getDate(),
- "h+": d.getHours(),
- "i+": d.getMinutes(),
- "s+": d.getSeconds(),
- "q+": Math.floor((d.getMonth() + 3) / 3),
- };
- if (/(y+)/.test(f))
- f = f.replace(RegExp.$1, (d.getFullYear() + "").substr(4 - RegExp.$1.length));
- for (var k in o)
- if (new RegExp("(" + k + ")").test(f))
- f = f.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
- return f;
- },
- /**
- * 用于format格式化后的反解析
- * @param s 日期字符串
- * @param f 格式字符串
- * @return 返回Date对象
- */
- inverse(s, f) {
- var o = {
- "y": '',
- "m": '',
- "d": '',
- "h": '',
- "i": '',
- "s": '',
- };
- let d = new Date();
- if (s.length != f.length) return d;
- for (let i in f)
- if (o[f[i]] != undefined) o[f[i]] += s[i];
- if (o.y) d.setFullYear(o.y.length < 4 ? (d.getFullYear() + '').substr(0, 4 - o.y.length) + o.y : o.y);
- o.m && d.setMonth(o.m - 1, 1);
- o.d && d.setDate(o.d - 0);
- o.h && d.setHours(o.h - 0);
- o.i && d.setMinutes(o.i - 0);
- o.s && d.setSeconds(o.s - 0);
- return d;
- },
- /**
- * 获取日历数组(42天)
- * @param date 日期对象或日期字符串
- * @param proc 处理日历(和forEach类似),传递一个数组中的item
- * @return Array
- */
- getCalendar(date, proc) {
- let it = new Date(date),
- calendars = [];
- it.setDate(1);
- it.setDate(it.getDate() - ((it.getDay() == 0 ? 7 : it.getDay()) - 0)); //偏移量
- for (let i = 0; i < 42; i++) {
- let tmp = {
- dateObj: new Date(it),
- title: it.getDate(),
- isOtherMonth: it.getMonth() < date.getMonth() || it.getMonth() > date.getMonth()
- };
- calendars.push(Object.assign(tmp, proc ? proc(tmp) : {}));
- it.setDate(it.getDate() + 1);
- }
- return calendars;
- },
- /**
- * 获取日期到指定的月份1号(不改变原来的date对象)
- * @param d Date对象
- * @param v 指定的月份
- * @return Date对象
- */
- getDateToMonth(d, v) {
- let n = new Date(d);
- n.setMonth(v, 1);
- return n;
- },
- /**
- * 把时间数组转为时间字符串
- * @param t Array[时,分,秒]
- * @param showSecinds 是否显示秒
- * @return 字符串 时:分[:秒]
- */
- formatTimeArray(t, s) {
- let r = [...t];
- if (!s) r.length = 2;
- r.forEach((v, k) => r[k] = ('0' + v).slice(-2));
- return r.join(':');
- }
- };
- export default {
- props: {
- //颜色
- color: {
- type: String,
- default: '#79A9CE'
- },
- //是否显示秒 针对type为datetime或time时生效
- showSeconds: {
- type: Boolean,
- default: false
- },
- //初始的值
- value: [String, Array],
- //类型date time datetime range rangetime
- type: {
- type: String,
- default: 'date'
- },
- //是否显示
- show: {
- type: Boolean,
- default: false
- },
- //初始格式
- format: {
- type: String,
- default: ''
- },
- //显示公历节日
- showHoliday: {
- type: Boolean,
- default: false
- },
- //显示提示
- showTips: {
- type: Boolean,
- default: false
- },
- //开始文案 针对type为范围选择时生效
- beginText: {
- type: String,
- default: '开始'
- },
- //结束文案 针对type为范围选择时生效
- endText: {
- type: String,
- default: '结束'
- },
- // 开始时间
- beginDate: {
- type: String,
- default: ''
- },
- // 结束时间
- endDate: {
- type: String,
- default: ''
- }
- },
- data() {
- return {
- isShow: false, //是否显示
- isMultiSelect: false, //是否为多选
- isContainTime: false, //是否包含时间
- date: {}, //当前日期对象
- weeks: ["日", "一", "二", "三", "四", "五", "六"],
- title: DateTools.format(new Date(), 'yyyy年mm月'), //标题
- calendars: [[],[],[]], //日历数组
- calendarIndex: 1, //当前日历索引
- checkeds: [], //选中的日期对象集合
- showTimePicker: false, //是否显示时间选择器
- timeValue: [0, 0, 0], //时间选择器的值
- timeType: 'begin', //当前时间选择的类型
- beginTime: [0, 0, 0], //当前所选的开始时间值
- endTime: [0, 0, 0], //当前所选的结束时间值
- };
- },
- methods: {
- //设置值
- setValue(value) {
- if(this.beginDate && this.endDate){
- if(DateTools.isBigDay(new Date(),new Date(this.beginDate)) && DateTools.isBigDay(new Date(this.endDate), new Date())){
- this.date = new Date();
- }else{
- this.date = new Date(this.endDate);
- }
- }else if(this.beginDate){
- if(DateTools.isBigDay(new Date(),new Date(this.beginDate)) ){
- this.date = new Date();
- }else{
- this.date = new Date(this.beginDate);
- }
- }else if(this.endDate){
- if(DateTools.isBigDay(new Date(this.endDate),new Date()) ){
- this.date = new Date();
- }else{
- this.date = new Date(this.endDate);
- }
- }else{
- this.date = new Date();
- }
- this.checkeds = [];
- this.isMultiSelect = this.type.indexOf('range') >= 0;
- this.isContainTime = this.type.indexOf('time') >= 0;
- //将字符串解析为Date对象
- let parseDateStr = (str) => (this.format ? DateTools.inverse(str, this.format) : DateTools.parse(str));
- if (value) {
- if (this.isMultiSelect) {
- Array.isArray(value) && value.forEach((dateStr, index) => {
- let date = parseDateStr(dateStr);
- let time = [date.getHours(), date.getMinutes(), date.getSeconds()];
- if (index == 0) this.beginTime = time;
- else this.endTime = time;
- this.checkeds.push(date);
- });
- } else {
- if (this.type == 'time') {
- let date = parseDateStr('2019/1/1 ' + value);
- this.beginTime = [date.getHours(), date.getMinutes(), date.getSeconds()];
- this.onShowTimePicker('begin');
- } else {
- this.checkeds.push(parseDateStr(value));
- if (this.isContainTime) this.beginTime = [
- this.checkeds[0].getHours(),
- this.checkeds[0].getMinutes(),
- this.checkeds[0].getSeconds()
- ];
- }
- }
- if (this.checkeds.length) this.date = new Date(this.checkeds[0]);
- } else {
- if (this.isContainTime) {
- this.beginTime = [this.date.getHours(), this.date.getMinutes(), this.date.getSeconds()];
- if (this.isMultiSelect) this.endTime = [...this.beginTime];
- }
- this.checkeds.push(new Date(this.date));
- }
- if (this.type != 'time') this.refreshCalendars(true);
- else this.onShowTimePicker('begin');
- },
- //改变年份
- onSetYear(value) {
- this.date.setFullYear(this.date.getFullYear() + parseInt(value));
- this.refreshCalendars(true);
- },
- //改变月份
- onSetMonth(value) {
- this.date.setMonth(this.date.getMonth() + parseInt(value));
- this.refreshCalendars(true);
- },
- //时间选择变更
- onTimeChange(e) {
- this.timeValue = e.detail.value;
- },
- //设置时间选择器的显示状态
- onShowTimePicker(type) {
- this.showTimePicker = true;
- this.timeType = type;
- this.timeValue = type == 'begin' ? [...this.beginTime] : [...this.endTime];
- },
- //处理日历
- procCalendar(item) {
- let color = '#ddd';
- let isChoice = false;
- if(this.beginDate && this.endDate){
- if(DateTools.isBigDay(item.dateObj,new Date(this.beginDate)) && DateTools.isBigDay(new Date(this.endDate),item.dateObj) && !item.isOtherMonth){
- color = '#000';
- }
- if(DateTools.isBigDay(item.dateObj,new Date(this.beginDate)) && DateTools.isBigDay(new Date(this.endDate),item.dateObj)){
- isChoice = true;
- }
- }else if(this.beginDate){
-
- if(DateTools.isBigDay(item.dateObj,new Date(this.beginDate)) && !item.isOtherMonth){
- color = '#000';
- }
-
- if(DateTools.isBigDay(item.dateObj,new Date(this.beginDate))){
- isChoice = true;
- }
- }else if(this.endDate){
- if(DateTools.isBigDay(new Date(this.endDate),item.dateObj) && !item.isOtherMonth){
- color = '#000';
- }
- if(DateTools.isBigDay(new Date(this.endDate),item.dateObj)){
- isChoice = true;
- }
- }else{
- if(!item.isOtherMonth){
- color = '#000';
- }
- isChoice = true;
- }
-
- item.isChoice = isChoice;
-
- //定义初始样式
- item.statusStyle = {
- opacity: 1,
- color: color,
- background: 'transparent'
- };
- item.bgStyle = {
- type: '',
- background: 'transparent'
- };
- item.dotStyle = {
- opacity: 1,
- background: 'transparent'
- };
- item.tips = "";
-
- //标记今天的日期
- if (DateTools.isSameDay(new Date(), item.dateObj)) {
- item.statusStyle.color = this.color;
- if (item.isOtherMonth) item.statusStyle.opacity = 0.3;
- }
- //标记选中项
- this.checkeds.forEach(date => {
- if (DateTools.isSameDay(date, item.dateObj)) {
- item.statusStyle.background = this.color;
- item.statusStyle.color = '#fff';
- item.statusStyle.opacity = 1;
- if (this.isMultiSelect && this.showTips) item.tips = this.beginText;
- }
- });
- //节假日或今日的日期标点
- if (item.statusStyle.background != this.color) {
- let holiday = this.showHoliday ? DateTools.getHoliday(item.dateObj) : false;
- if (holiday || DateTools.isSameDay(new Date(), item.dateObj)) {
- item.title = holiday || item.title;
- item.dotStyle.background = this.color;
- if (item.isOtherMonth) item.dotStyle.opacity = 0.2;
- }
- } else {
- item.title = item.dateObj.getDate();
- }
- //有两个日期
- if (this.checkeds.length == 2) {
- if (DateTools.isSameDay(this.checkeds[0], item.dateObj)) { //开始日期
- item.bgStyle.type = 'bgbegin';
- }
- if (DateTools.isSameDay(this.checkeds[1], item.dateObj)) { //结束日期
- if (this.isMultiSelect && this.showTips) item.tips = item.bgStyle.type ? this.beginText + ' / ' + this.endText : this.endText;
- if (!item.bgStyle.type) { //开始日期不等于结束日期
- item.bgStyle.type = 'bgend';
- } else {
- item.bgStyle.type = '';
- }
- }
- if (!item.bgStyle.type && (+item.dateObj > +this.checkeds[0] && +item.dateObj < +this.checkeds[1])) { //中间的日期
- item.bgStyle.type = 'bg';
- item.statusStyle.color = this.color;
- }
- if (item.bgStyle.type) {
- item.bgStyle.background = this.color;
- item.dotStyle.opacity = 1;
- item.statusStyle.opacity = 1;
- }
- }
- },
- //刷新日历
- refreshCalendars(refresh = false) {
- let date = new Date(this.date);
- let before = DateTools.getDateToMonth(date, date.getMonth() - 1);
- let after = DateTools.getDateToMonth(date, date.getMonth() + 1);
- if (this.calendarIndex == 0) {
- if(refresh) this.calendars.splice(0, 1, DateTools.getCalendar(date, this.procCalendar));
- this.calendars.splice(1, 1, DateTools.getCalendar(after, this.procCalendar));
- this.calendars.splice(2, 1, DateTools.getCalendar(before, this.procCalendar));
- } else if (this.calendarIndex == 1) {
- this.calendars.splice(0, 1, DateTools.getCalendar(before, this.procCalendar));
- if(refresh) this.calendars.splice(1, 1, DateTools.getCalendar(date, this.procCalendar));
- this.calendars.splice(2, 1, DateTools.getCalendar(after, this.procCalendar));
- } else if (this.calendarIndex == 2) {
- this.calendars.splice(0, 1, DateTools.getCalendar(after, this.procCalendar));
- this.calendars.splice(1, 1, DateTools.getCalendar(before, this.procCalendar));
- if(refresh) this.calendars.splice(2, 1, DateTools.getCalendar(date, this.procCalendar));
- }
- this.title = DateTools.format(this.date, 'yyyy年mm月');
- },
- //滑块切换
- onSwiperChange(e) {
- this.calendarIndex = e.detail.current;
- let calendar = this.calendars[this.calendarIndex];
- this.date = new Date(calendar[22].dateObj); //取中间一天,保证是当前的月份
- this.refreshCalendars();
- },
- //选中日期
- onSelectDate(date) {
- if(!date.isChoice) {
- uni.showToast({
- title: '禁止时间',
- icon: 'none'
- });
- return false
- }
- if (~this.type.indexOf('range') && this.checkeds.length == 2) this.checkeds = [];
- else if (!(~this.type.indexOf('range')) && this.checkeds.length) this.checkeds = [];
- this.checkeds.push(new Date(date.dateObj));
- this.checkeds.sort((a, b) => a - b); //从小到大排序
- this.calendars.forEach(calendar => {
- calendar.forEach(this.procCalendar); //重新处理
- });
- this.onConfirm(date)
- },
- //时间选择取消
- onCancelTime() {
- this.showTimePicker = false;
- this.type == 'time' && this.onCancel();
- },
- //时间选择确定
- onConfirmTime() {
- if (this.timeType == 'begin') this.beginTime = this.timeValue;
- else this.endTime = this.timeValue;
- this.showTimePicker = false;
- this.type == 'time' && this.onConfirm();
- },
- //取消
- onCancel() {
- this.$emit('cancel', false);
- },
- //确定
- onConfirm(date) {
- const value = DateTools.format(date.dateObj, 'yyyy/mm/dd')
- this.$emit('confirm', value);
- this.$emit('input', value);
- this.$emit('change', value);
- }
- },
- computed: {
- BeginTitle() {
- let value = '未选择';
- if (this.checkeds.length) value = DateTools.format(this.checkeds[0], 'yy/mm/dd');
- return value;
- },
- EndTitle() {
- let value = '未选择';
- if (this.checkeds.length == 2) value = DateTools.format(this.checkeds[1], 'yy/mm/dd');
- return value;
- },
- PickerTimeTitle() {
- return DateTools.formatTimeArray(this.timeValue, this.showSeconds);
- },
- BeginTimeTitle() {
- return this.BeginTitle != '未选择' ? DateTools.formatTimeArray(this.beginTime, this.showSeconds) : '';
- },
- EndTimeTitle() {
- return this.EndTitle != '未选择' ? DateTools.formatTimeArray(this.endTime, this.showSeconds) : '';
- }
- },
- watch: {
- show(newValue, oldValue) {
- newValue && this.setValue(this.value);
- this.isShow = newValue;
- },
- value(newValue, oldValue) {
- setTimeout(()=>{
- this.setValue(newValue);
- }, 0);
- }
- },
- mounted(){
- setTimeout(()=>{
- this.setValue();
- }, 0);
- }
- }
- </script>
- <style lang="scss" scoped>
- @import './index.scss';
- </style>
|