diff --git a/src/components/date-picker/base/date-table.vue b/src/components/date-picker/base/date-table.vue index f67cf44d..6fccf470 100644 --- a/src/components/date-picker/base/date-table.vue +++ b/src/components/date-picker/base/date-table.vue @@ -1,13 +1,99 @@ \ No newline at end of file diff --git a/src/components/date-picker/base/month-table.vue b/src/components/date-picker/base/month-table.vue index f67cf44d..3f88c380 100644 --- a/src/components/date-picker/base/month-table.vue +++ b/src/components/date-picker/base/month-table.vue @@ -1,9 +1,9 @@ \ No newline at end of file diff --git a/src/components/date-picker/picker.vue b/src/components/date-picker/picker.vue index f67cf44d..d2c5a775 100644 --- a/src/components/date-picker/picker.vue +++ b/src/components/date-picker/picker.vue @@ -1,13 +1,148 @@ \ No newline at end of file diff --git a/src/components/date-picker/picker/date-picker.js b/src/components/date-picker/picker/date-picker.js index da91ca5e..d6bd690d 100644 --- a/src/components/date-picker/picker/date-picker.js +++ b/src/components/date-picker/picker/date-picker.js @@ -9,11 +9,15 @@ const getPanel = function (type) { return DatePanel; }; +import { oneOf } from '../../../utils/assist'; + export default { mixins: [Picker], props: { type: { - type: String, + validator (value) { + return oneOf(value, ['year', 'month', 'week', 'date', 'daterange', 'datetime', 'datetimerange']); + }, default: 'date' } }, diff --git a/src/components/date-picker/util.js b/src/components/date-picker/util.js new file mode 100644 index 00000000..fe439633 --- /dev/null +++ b/src/components/date-picker/util.js @@ -0,0 +1,159 @@ +import dateUtil from '../../utils/date'; + +const newArray = function(start, end) { + let result = []; + for (let i = start; i <= end; i++) { + result.push(i); + } + return result; +}; + +export const toDate = function(date) { + date = new Date(date); + if (isNaN(date.getTime())) return null; + return date; +}; + +export const formatDate = function(date, format) { + date = toDate(date); + if (!date) return ''; + return dateUtil.format(date, format || 'yyyy-MM-dd'); +}; + +export const parseDate = function(string, format) { + return dateUtil.parse(string, format || 'yyyy-MM-dd'); +}; + +export const getDayCountOfMonth = function(year, month) { + if (month === 3 || month === 5 || month === 8 || month === 10) { + return 30; + } + + if (month === 1) { + if (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0) { + return 29; + } else { + return 28; + } + } + + return 31; +}; + +export const getFirstDayOfMonth = function(date) { + const temp = new Date(date.getTime()); + temp.setDate(1); + return temp.getDay(); +}; + +export const DAY_DURATION = 86400000; + +export const getStartDateOfMonth = function(year, month) { + const result = new Date(year, month, 1); + const day = result.getDay(); + + if (day === 0) { + result.setTime(result.getTime() - DAY_DURATION * 7); + } else { + result.setTime(result.getTime() - DAY_DURATION * day); + } + + return result; +}; + +export const getWeekNumber = function(src) { + const date = new Date(src.getTime()); + date.setHours(0, 0, 0, 0); + // Thursday in current week decides the year. + date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); + // January 4 is always in week 1. + const week1 = new Date(date.getFullYear(), 0, 4); + // Adjust to Thursday in week 1 and count number of weeks from date to week 1. + return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7); +}; + +export const prevMonth = function(src) { + const year = src.getFullYear(); + const month = src.getMonth(); + const date = src.getDate(); + + const newYear = month === 0 ? year - 1 : year; + const newMonth = month === 0 ? 11 : month - 1; + + const newMonthDayCount = getDayCountOfMonth(newYear, newMonth); + if (newMonthDayCount < date) { + src.setDate(newMonthDayCount); + } + + src.setMonth(newMonth); + src.setFullYear(newYear); + + return new Date(src.getTime()); +}; + +export const nextMonth = function(src) { + const year = src.getFullYear(); + const month = src.getMonth(); + const date = src.getDate(); + + const newYear = month === 11 ? year + 1 : year; + const newMonth = month === 11 ? 0 : month + 1; + + const newMonthDayCount = getDayCountOfMonth(newYear, newMonth); + if (newMonthDayCount < date) { + src.setDate(newMonthDayCount); + } + + src.setMonth(newMonth); + src.setFullYear(newYear); + + return new Date(src.getTime()); +}; + +export const getRangeHours = function(ranges) { + const hours = []; + let disabledHours = []; + + (ranges || []).forEach(range => { + const value = range.map(date => date.getHours()); + + disabledHours = disabledHours.concat(newArray(value[0], value[1])); + }); + + if (disabledHours.length) { + for (let i = 0; i < 24; i++) { + hours[i] = disabledHours.indexOf(i) === -1; + } + } else { + for (let i = 0; i < 24; i++) { + hours[i] = false; + } + } + + return hours; +}; + +export const limitRange = function(date, ranges) { + if (!ranges || !ranges.length) return date; + + const len = ranges.length; + const format = 'HH:mm:ss'; + + date = dateUtil.parse(dateUtil.format(date, format), format); + for (let i = 0; i < len; i++) { + const range = ranges[i]; + if (date >= range[0] && date <= range[1]) { + return date; + } + } + + let maxDate = ranges[0][0]; + let minDate = ranges[0][0]; + + ranges.forEach(range => { + minDate = new Date(Math.min(range[0], minDate)); + maxDate = new Date(Math.max(range[1], maxDate)); + }); + + return date < minDate ? minDate : maxDate; +}; diff --git a/src/utils/date.js b/src/utils/date.js new file mode 100755 index 00000000..3fb89eac --- /dev/null +++ b/src/utils/date.js @@ -0,0 +1,319 @@ +/*eslint-disable*/ +// 把 YYYY-MM-DD 改成了 yyyy-MM-dd +(function (main) { + 'use strict'; + + /** + * Parse or format dates + * @class fecha + */ + var fecha = {}; + var token = /d{1,4}|M{1,4}|yy(?:yy)?|S{1,3}|Do|ZZ|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g; + var twoDigits = /\d\d?/; + var threeDigits = /\d{3}/; + var fourDigits = /\d{4}/; + var word = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i; + var noop = function () { + }; + + function shorten(arr, sLen) { + var newArr = []; + for (var i = 0, len = arr.length; i < len; i++) { + newArr.push(arr[i].substr(0, sLen)); + } + return newArr; + } + + function monthUpdate(arrName) { + return function (d, v, i18n) { + var index = i18n[arrName].indexOf(v.charAt(0).toUpperCase() + v.substr(1).toLowerCase()); + if (~index) { + d.month = index; + } + }; + } + + function pad(val, len) { + val = String(val); + len = len || 2; + while (val.length < len) { + val = '0' + val; + } + return val; + } + + var dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + var monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; + var monthNamesShort = shorten(monthNames, 3); + var dayNamesShort = shorten(dayNames, 3); + fecha.i18n = { + dayNamesShort: dayNamesShort, + dayNames: dayNames, + monthNamesShort: monthNamesShort, + monthNames: monthNames, + amPm: ['am', 'pm'], + DoFn: function DoFn(D) { + return D + ['th', 'st', 'nd', 'rd'][D % 10 > 3 ? 0 : (D - D % 10 !== 10) * D % 10]; + } + }; + + var formatFlags = { + D: function (dateObj) { + return dateObj.getDay(); + }, + DD: function (dateObj) { + return pad(dateObj.getDay()); + }, + Do: function (dateObj, i18n) { + return i18n.DoFn(dateObj.getDate()); + }, + d: function (dateObj) { + return dateObj.getDate(); + }, + dd: function (dateObj) { + return pad(dateObj.getDate()); + }, + ddd: function (dateObj, i18n) { + return i18n.dayNamesShort[dateObj.getDay()]; + }, + dddd: function (dateObj, i18n) { + return i18n.dayNames[dateObj.getDay()]; + }, + M: function (dateObj) { + return dateObj.getMonth() + 1; + }, + MM: function (dateObj) { + return pad(dateObj.getMonth() + 1); + }, + MMM: function (dateObj, i18n) { + return i18n.monthNamesShort[dateObj.getMonth()]; + }, + MMMM: function (dateObj, i18n) { + return i18n.monthNames[dateObj.getMonth()]; + }, + yy: function (dateObj) { + return String(dateObj.getFullYear()).substr(2); + }, + yyyy: function (dateObj) { + return dateObj.getFullYear(); + }, + h: function (dateObj) { + return dateObj.getHours() % 12 || 12; + }, + hh: function (dateObj) { + return pad(dateObj.getHours() % 12 || 12); + }, + H: function (dateObj) { + return dateObj.getHours(); + }, + HH: function (dateObj) { + return pad(dateObj.getHours()); + }, + m: function (dateObj) { + return dateObj.getMinutes(); + }, + mm: function (dateObj) { + return pad(dateObj.getMinutes()); + }, + s: function (dateObj) { + return dateObj.getSeconds(); + }, + ss: function (dateObj) { + return pad(dateObj.getSeconds()); + }, + S: function (dateObj) { + return Math.round(dateObj.getMilliseconds() / 100); + }, + SS: function (dateObj) { + return pad(Math.round(dateObj.getMilliseconds() / 10), 2); + }, + SSS: function (dateObj) { + return pad(dateObj.getMilliseconds(), 3); + }, + a: function (dateObj, i18n) { + return dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1]; + }, + A: function (dateObj, i18n) { + return dateObj.getHours() < 12 ? i18n.amPm[0].toUpperCase() : i18n.amPm[1].toUpperCase(); + }, + ZZ: function (dateObj) { + var o = dateObj.getTimezoneOffset(); + return (o > 0 ? '-' : '+') + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4); + } + }; + + var parseFlags = { + d: [twoDigits, function (d, v) { + d.day = v; + }], + M: [twoDigits, function (d, v) { + d.month = v - 1; + }], + yy: [twoDigits, function (d, v) { + var da = new Date(), cent = +('' + da.getFullYear()).substr(0, 2); + d.year = '' + (v > 68 ? cent - 1 : cent) + v; + }], + h: [twoDigits, function (d, v) { + d.hour = v; + }], + m: [twoDigits, function (d, v) { + d.minute = v; + }], + s: [twoDigits, function (d, v) { + d.second = v; + }], + yyyy: [fourDigits, function (d, v) { + d.year = v; + }], + S: [/\d/, function (d, v) { + d.millisecond = v * 100; + }], + SS: [/\d{2}/, function (d, v) { + d.millisecond = v * 10; + }], + SSS: [threeDigits, function (d, v) { + d.millisecond = v; + }], + D: [twoDigits, noop], + ddd: [word, noop], + MMM: [word, monthUpdate('monthNamesShort')], + MMMM: [word, monthUpdate('monthNames')], + a: [word, function (d, v, i18n) { + var val = v.toLowerCase(); + if (val === i18n.amPm[0]) { + d.isPm = false; + } else if (val === i18n.amPm[1]) { + d.isPm = true; + } + }], + ZZ: [/[\+\-]\d\d:?\d\d/, function (d, v) { + var parts = (v + '').match(/([\+\-]|\d\d)/gi), minutes; + + if (parts) { + minutes = +(parts[1] * 60) + parseInt(parts[2], 10); + d.timezoneOffset = parts[0] === '+' ? minutes : -minutes; + } + }] + }; + parseFlags.DD = parseFlags.DD; + parseFlags.dddd = parseFlags.ddd; + parseFlags.Do = parseFlags.dd = parseFlags.d; + parseFlags.mm = parseFlags.m; + parseFlags.hh = parseFlags.H = parseFlags.HH = parseFlags.h; + parseFlags.MM = parseFlags.M; + parseFlags.ss = parseFlags.s; + parseFlags.A = parseFlags.a; + + + // Some common format strings + fecha.masks = { + 'default': 'ddd MMM dd yyyy HH:mm:ss', + shortDate: 'M/D/yy', + mediumDate: 'MMM d, yyyy', + longDate: 'MMMM d, yyyy', + fullDate: 'dddd, MMMM d, yyyy', + shortTime: 'HH:mm', + mediumTime: 'HH:mm:ss', + longTime: 'HH:mm:ss.SSS' + }; + + /*** + * Format a date + * @method format + * @param {Date|number} dateObj + * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate' + */ + fecha.format = function (dateObj, mask, i18nSettings) { + var i18n = i18nSettings || fecha.i18n; + + if (typeof dateObj === 'number') { + dateObj = new Date(dateObj); + } + + if (Object.prototype.toString.call(dateObj) !== '[object Date]' || isNaN(dateObj.getTime())) { + throw new Error('Invalid Date in fecha.format'); + } + + mask = fecha.masks[mask] || mask || fecha.masks['default']; + + return mask.replace(token, function ($0) { + return $0 in formatFlags ? formatFlags[$0](dateObj, i18n) : $0.slice(1, $0.length - 1); + }); + }; + + /** + * Parse a date string into an object, changes - into / + * @method parse + * @param {string} dateStr Date string + * @param {string} format Date parse format + * @returns {Date|boolean} + */ + fecha.parse = function (dateStr, format, i18nSettings) { + var i18n = i18nSettings || fecha.i18n; + + if (typeof format !== 'string') { + throw new Error('Invalid format in fecha.parse'); + } + + format = fecha.masks[format] || format; + + // Avoid regular expression denial of service, fail early for really long strings + // https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS + if (dateStr.length > 1000) { + return false; + } + + var isValid = true; + var dateInfo = {}; + format.replace(token, function ($0) { + if (parseFlags[$0]) { + var info = parseFlags[$0]; + var index = dateStr.search(info[0]); + if (!~index) { + isValid = false; + } else { + dateStr.replace(info[0], function (result) { + info[1](dateInfo, result, i18n); + dateStr = dateStr.substr(index + result.length); + return result; + }); + } + } + + return parseFlags[$0] ? '' : $0.slice(1, $0.length - 1); + }); + + if (!isValid) { + return false; + } + + var today = new Date(); + if (dateInfo.isPm === true && dateInfo.hour != null && +dateInfo.hour !== 12) { + dateInfo.hour = +dateInfo.hour + 12; + } else if (dateInfo.isPm === false && +dateInfo.hour === 12) { + dateInfo.hour = 0; + } + + var date; + if (dateInfo.timezoneOffset != null) { + dateInfo.minute = +(dateInfo.minute || 0) - +dateInfo.timezoneOffset; + date = new Date(Date.UTC(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1, + dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0)); + } else { + date = new Date(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1, + dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0); + } + return date; + }; + + /* istanbul ignore next */ + if (typeof module !== 'undefined' && module.exports) { + module.exports = fecha; + } else if (typeof define === 'function' && define.amd) { + define(function () { + return fecha; + }); + } else { + main.fecha = fecha; + } +})(this); diff --git a/test/app.vue b/test/app.vue index 0cbef694..da70f421 100644 --- a/test/app.vue +++ b/test/app.vue @@ -45,6 +45,7 @@ li + li {
  • Dropdown
  • Tabs
  • Menu
  • +
  • Date
  • diff --git a/test/main.js b/test/main.js index 89559aed..2de4520a 100644 --- a/test/main.js +++ b/test/main.js @@ -122,6 +122,11 @@ router.map({ component: function (resolve) { require(['./routers/menu.vue'], resolve); } + }, + '/date': { + component: function (resolve) { + require(['./routers/date.vue'], resolve); + } } }); diff --git a/test/routers/date.vue b/test/routers/date.vue new file mode 100644 index 00000000..2190e029 --- /dev/null +++ b/test/routers/date.vue @@ -0,0 +1,15 @@ + + \ No newline at end of file