@@ -110,6 +110,7 @@ App({
method: 'POST',
data,
success(res) {
+
if (res.statusCode !== 200 || typeof res.data !== 'object') {
reject('网络出错')
return false;
@@ -121,7 +122,8 @@ App({
_this.gotoLogin()
return
}
- resolve(res.data);
+ console.log("res", res.data)
+ resolve( res.data );
return true;
},
fail(res) {
@@ -0,0 +1,33 @@
+import WxData from './wxData'
+class Config extends WxData {
+ constructor(component) {
+ super(component)
+ this.Component = component
+ }
+ getCalendarConfig() {
+ if (!this.Component || !this.Component.config) return {}
+ return this.Component.config
+ setCalendarConfig(config) {
+ return new Promise((resolve, reject) => {
+ if (!this.Component || !this.Component.config) {
+ reject('异常:未找到组件配置信息')
+ return
+ let conf = { ...this.Component.config, ...config }
+ this.Component.config = conf
+ this.setData(
+ {
+ calendarConfig: conf
+ },
+ () => {
+ resolve(conf)
+ )
+ })
+}
+export default component => new Config(component)
@@ -0,0 +1,1036 @@
+/**
+ * @1900-2100区间内的公历、农历互转
+ * @Version 1.0.3
+ * @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
+ * @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
+ */
+/* 公历年月日转农历数据 返回json */
+// calendar.solar2lunar(1987,11,01);
+/** 农历年月日转公历年月日 **/
+// calendar.lunar2solar(1987,9,10);
+// 调用以上方法后返回类似如下object(json)具体以上就不需要解释了吧!
+// c开头的是公历各属性值 l开头的自然就是农历咯 gz开头的就是天干地支纪年的数据啦~
+// {
+// Animal: "兔",
+// IDayCn: "初十",
+// IMonthCn: "九月",
+// Term: null,
+// astro: "天蝎座",
+// cDay: 1,
+// cMonth: 11,
+// cYear: 1987,
+// gzDay: "甲寅",
+// gzMonth: "庚戌",
+// gzYear: "丁卯",
+// isLeap: false,
+// isTerm: false,
+// isToday: false,
+// lDay: 10,
+// lMonth: 9,
+// lYear: 1987,
+// nWeek: 7,
+// ncWeek: "星期日"
+// }
+// 该代码还有其他可以调用的方法,请自己查看代码中的详细注释
+const calendar = {
+ /**
+ * 农历1900-2100的润大小信息表
+ * @Array Of Property
+ * @return Hex
+ lunarInfo: [
+ 0x04bd8,
+ 0x04ae0,
+ 0x0a570,
+ 0x054d5,
+ 0x0d260,
+ 0x0d950,
+ 0x16554,
+ 0x056a0,
+ 0x09ad0,
+ 0x055d2, // 1900-1909
+ 0x0a5b6,
+ 0x0a4d0,
+ 0x0d250,
+ 0x1d255,
+ 0x0b540,
+ 0x0d6a0,
+ 0x0ada2,
+ 0x095b0,
+ 0x14977, // 1910-1919
+ 0x04970,
+ 0x0a4b0,
+ 0x0b4b5,
+ 0x06a50,
+ 0x06d40,
+ 0x1ab54,
+ 0x02b60,
+ 0x09570,
+ 0x052f2,
+ 0x04970, // 1920-1929
+ 0x06566,
+ 0x0d4a0,
+ 0x0ea50,
+ 0x06e95,
+ 0x05ad0,
+ 0x186e3,
+ 0x092e0,
+ 0x1c8d7,
+ 0x0c950, // 1930-1939
+ 0x1d8a6,
+ 0x0b550,
+ 0x1a5b4,
+ 0x025d0,
+ 0x092d0,
+ 0x0d2b2,
+ 0x0a950,
+ 0x0b557, // 1940-1949
+ 0x06ca0,
+ 0x15355,
+ 0x04da0,
+ 0x0a5b0,
+ 0x14573,
+ 0x052b0,
+ 0x0a9a8,
+ 0x0e950,
+ 0x06aa0, // 1950-1959
+ 0x0aea6,
+ 0x0ab50,
+ 0x04b60,
+ 0x0aae4,
+ 0x05260,
+ 0x0f263,
+ 0x05b57,
+ 0x056a0, // 1960-1969
+ 0x096d0,
+ 0x04dd5,
+ 0x04ad0,
+ 0x0d4d4,
+ 0x0d558,
+ 0x0b6a0,
+ 0x195a6, // 1970-1979
+ 0x049b0,
+ 0x0a974,
+ 0x0b27a,
+ 0x0af46,
+ 0x0ab60,
+ 0x09570, // 1980-1989
+ 0x04af5,
+ 0x064b0,
+ 0x074a3,
+ 0x06b58,
+ 0x055c0,
+ 0x096d5,
+ 0x092e0, // 1990-1999
+ 0x0c960,
+ 0x0d954,
+ 0x0da50,
+ 0x07552,
+ 0x0abb7,
+ 0x0cab5, // 2000-2009
+ 0x0b4a0,
+ 0x0baa4,
+ 0x0ad50,
+ 0x055d9,
+ 0x04ba0,
+ 0x15176,
+ 0x0a930, // 2010-2019
+ 0x07954,
+ 0x06aa0,
+ 0x05b52,
+ 0x0a6e6,
+ 0x0a4e0,
+ 0x0ea65,
+ 0x0d530, // 2020-2029
+ 0x05aa0,
+ 0x076a3,
+ 0x04afb,
+ 0x1d0b6,
+ 0x0d520,
+ 0x0dd45, // 2030-2039
+ 0x0b5a0,
+ 0x056d0,
+ 0x055b2,
+ 0x0a577,
+ 0x0aa50,
+ 0x1b255,
+ 0x06d20,
+ 0x0ada0, // 2040-2049
+ /** Add By JJonline@JJonline.Cn **/
+ 0x14b63,
+ 0x09370,
+ 0x049f8,
+ 0x168a6,
+ 0x06b20,
+ 0x1a6c4,
+ 0x0aae0, // 2050-2059
+ 0x0a2e0,
+ 0x0d2e3,
+ 0x0d557,
+ 0x05d55,
+ 0x0a6d0,
+ 0x055d4, // 2060-2069
+ 0x052d0,
+ 0x0a9b8,
+ 0x0b6a6,
+ 0x055a0,
+ 0x0aba4,
+ 0x052b0, // 2070-2079
+ 0x0b273,
+ 0x06930,
+ 0x07337,
+ 0x14b55,
+ 0x054e4,
+ 0x0d160, // 2080-2089
+ 0x0e968,
+ 0x0daa0,
+ 0x16aa6,
+ 0x0a9d4,
+ 0x0a2d0,
+ 0x0d150,
+ 0x0f252, // 2090-2099
+ 0x0d520
+ ], // 2100
+ * 公历每个月份的天数普通表
+ * @return Number
+ solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+ * 天干地支之天干速查表
+ * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
+ * @return Cn string
+ Gan: [
+ '\u7532',
+ '\u4e59',
+ '\u4e19',
+ '\u4e01',
+ '\u620a',
+ '\u5df1',
+ '\u5e9a',
+ '\u8f9b',
+ '\u58ec',
+ '\u7678'
+ ],
+ * 天干地支之地支速查表
+ * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
+ Zhi: [
+ '\u5b50',
+ '\u4e11',
+ '\u5bc5',
+ '\u536f',
+ '\u8fb0',
+ '\u5df3',
+ '\u5348',
+ '\u672a',
+ '\u7533',
+ '\u9149',
+ '\u620c',
+ '\u4ea5'
+ * 天干地支之地支速查表<=>生肖
+ * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
+ Animals: [
+ '\u9f20',
+ '\u725b',
+ '\u864e',
+ '\u5154',
+ '\u9f99',
+ '\u86c7',
+ '\u9a6c',
+ '\u7f8a',
+ '\u7334',
+ '\u9e21',
+ '\u72d7',
+ '\u732a'
+ * 24节气速查表
+ * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
+ solarTerm: [
+ '\u5c0f\u5bd2',
+ '\u5927\u5bd2',
+ '\u7acb\u6625',
+ '\u96e8\u6c34',
+ '\u60ca\u86f0',
+ '\u6625\u5206',
+ '\u6e05\u660e',
+ '\u8c37\u96e8',
+ '\u7acb\u590f',
+ '\u5c0f\u6ee1',
+ '\u8292\u79cd',
+ '\u590f\u81f3',
+ '\u5c0f\u6691',
+ '\u5927\u6691',
+ '\u7acb\u79cb',
+ '\u5904\u6691',
+ '\u767d\u9732',
+ '\u79cb\u5206',
+ '\u5bd2\u9732',
+ '\u971c\u964d',
+ '\u7acb\u51ac',
+ '\u5c0f\u96ea',
+ '\u5927\u96ea',
+ '\u51ac\u81f3'
+ * 1900-2100各年的24节气日期速查表
+ * @return 0x string For splice
+ sTermInfo: [
+ '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e',
+ '97bcf97c3598082c95f8c965cc920f',
+ '97bd0b06bdb0722c965ce1cfcc920f',
+ 'b027097bd097c36b0b6fc9274c91aa',
+ '97bcf97c359801ec95f8c965cc920f',
+ '9778397bd19801ec9210c965cc920e',
+ '97b6b97bd19801ec95f8c965cc920f',
+ '97bd09801d98082c95f8e1cfcc920f',
+ '97bd097bd097c36b0b6fc9210c8dc2',
+ '9778397bd197c36c9210c9274c91aa',
+ '97b6b97bd19801ec95f8c965cc920e',
+ '9778397bd097c36c9210c9274c91aa',
+ '97bcf97c3598082c95f8e1cfcc920f',
+ '97bd097bd097c35b0b6fc920fb0722',
+ '97bd097bd07f595b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9210c8dc2',
+ '9778397bd19801ec9210c9274c920e',
+ '97bd07f5307f595b0b0bc920fb0722',
+ '7f0e397bd097c36b0b6fc9210c8dc2',
+ '9778397bd097c36c9210c9274c920e',
+ '97bd07f1487f595b0b0bc920fb0722',
+ '97bcf7f1487f595b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc920fb0722',
+ '97bcf7f1487f531b0b0bb0b6fb0722',
+ '7f0e397bd07f595b0b6fc920fb0722',
+ '97b6b97bd19801ec9210c9274c920e',
+ '97bcf7f0e47f531b0b0bb0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722',
+ '9778397bd097c36b0b6fc9210c91aa',
+ '97b6b97bd197c36c9210c9274c920e',
+ '97b6b7f0e47f531b0723b0b6fb0722',
+ '7f0e37f5307f595b0b0bc920fb0722',
+ '9778397bd097c36b0b70c9274c91aa',
+ '97b6b7f0e47f531b0723b0b6fb0721',
+ '7f0e37f1487f595b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc9210c8dc2',
+ '7f0e27f1487f595b0b0bb0b6fb0722',
+ '7f0e27f1487f531b0b0bb0b6fb0722',
+ '97b6b7f0e47f531b0723b0787b0721',
+ '7f0e27f0e47f531b0b0bb0b6fb0722',
+ '97b6b7f0e47f149b0723b0787b0721',
+ '7f0e27f0e47f531b0723b0b6fb0722',
+ '977837f0e37f149b0723b0787b0721',
+ '7f07e7f0e47f531b0723b0b6fb0722',
+ '977837f0e37f14998082b0787b0721',
+ '7f07e7f0e47f531b0723b0b6fb0721',
+ '977837f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f149b0723b0787b0721',
+ '977837f0e37f14998082b0723b06bd',
+ '7f07e7f0e37f149b0723b0787b0721',
+ '977837f0e37f14898082b0723b02d5',
+ '7ec967f0e37f14998082b0787b0721',
+ '7f0e37f0e37f14898082b0723b02d5',
+ '7f0e37f1487f531b0b0bb0b6fb0722',
+ '7ec967f0e37f14998082b0787b06bd',
+ '7f0e37f0e37f14898082b072297c35',
+ '7f0e37f0e366aa89801eb072297c35',
+ '7ec967f0e37f14998082b0723b06bd',
+ '7f07e7f0e37f14998083b0787b0721',
+ '7ec967f0e37f14898082b0723b02d5',
+ '7f07e7f0e37f14998082b0787b0721',
+ '7f0e36665b66aa89801e9808297c35',
+ '665f67f0e37f14898082b0723b02d5',
+ '7f0e36665b66a449801e9808297c35',
+ '665f67f0e37f14898082b072297c35',
+ '7f0e26665b66a449801e9808297c35',
+ '665f67f0e37f1489801eb072297c35',
+ '7f0e27f1487f531b0b0bb0b6fb0722'
+ * 数字转中文速查表
+ * @trans ['日','一','二','三','四','五','六','七','八','九','十']
+ nStr1: [
+ '\u65e5',
+ '\u4e00',
+ '\u4e8c',
+ '\u4e09',
+ '\u56db',
+ '\u4e94',
+ '\u516d',
+ '\u4e03',
+ '\u516b',
+ '\u4e5d',
+ '\u5341'
+ * 日期转农历称呼速查表
+ * @trans ['初','十','廿','卅']
+ nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
+ * 月份转农历称呼速查表
+ * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
+ nStr3: [
+ '\u6b63',
+ '\u5341',
+ '\u51ac',
+ '\u814a'
+ * 返回农历y年一整年的总天数
+ * @param lunar Year
+ * @eg:var count = calendar.lYearDays(1987) ;//count=387
+ lYearDays: function(y) {
+ let i
+ let sum = 348
+ for (i = 0x8000; i > 0x8; i >>= 1) {
+ sum += calendar.lunarInfo[y - 1900] & i ? 1 : 0
+ return sum + calendar.leapDays(y)
+ * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
+ * @return Number (0-12)
+ * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
+ leapMonth: function(y) {
+ // 闰字编码 \u95f0
+ return calendar.lunarInfo[y - 1900] & 0xf
+ * 返回农历y年闰月的天数 若该年没有闰月则返回0
+ * @return Number (0、29、30)
+ * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
+ leapDays: function(y) {
+ if (calendar.leapMonth(y)) {
+ return calendar.lunarInfo[y - 1900] & 0x10000 ? 30 : 29
+ return 0
+ * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
+ * @return Number (-1、29、30)
+ * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
+ monthDays: function(y, m) {
+ if (m > 12 || m < 1) return -1 // 月份参数从1至12,参数错误返回-1
+ return calendar.lunarInfo[y - 1900] & (0x10000 >> m) ? 30 : 29
+ * 返回公历(!)y年m月的天数
+ * @param solar Year
+ * @return Number (-1、28、29、30、31)
+ * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
+ solarDays: function(y, m) {
+ if (m > 12 || m < 1) return -1 // 若参数错误 返回-1
+ const ms = m - 1
+ if (+ms === 1) {
+ // 2月份的闰平规律测算后确认返回28或29
+ return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 ? 29 : 28
+ } else {
+ return calendar.solarMonth[ms]
+ * 农历年份转换为干支纪年
+ * @param lYear 农历年的年份数
+ toGanZhiYear: function(lYear) {
+ let ganKey = (lYear - 3) % 10
+ let zhiKey = (lYear - 3) % 12
+ if (+ganKey === 0) ganKey = 10 // 如果余数为0则为最后一个天干
+ if (+zhiKey === 0) zhiKey = 12 // 如果余数为0则为最后一个地支
+ return calendar.Gan[ganKey - 1] + calendar.Zhi[zhiKey - 1]
+ * 公历月、日判断所属星座
+ * @param cMonth [description]
+ * @param cDay [description]
+ toAstro: function(cMonth, cDay) {
+ const s =
+ '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
+ const arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
+ return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7' // 座
+ * 传入offset偏移量返回干支
+ * @param offset 相对甲子的偏移量
+ toGanZhi: function(offset) {
+ return calendar.Gan[offset % 10] + calendar.Zhi[offset % 12]
+ * 传入公历(!)y年获得该年第n个节气的公历日期
+ * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
+ * @return day Number
+ * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
+ getTerm: function(y, n) {
+ if (y < 1900 || y > 2100) return -1
+ if (n < 1 || n > 24) return -1
+ const _table = calendar.sTermInfo[y - 1900]
+ const _info = [
+ parseInt('0x' + _table.substr(0, 5)).toString(),
+ parseInt('0x' + _table.substr(5, 5)).toString(),
+ parseInt('0x' + _table.substr(10, 5)).toString(),
+ parseInt('0x' + _table.substr(15, 5)).toString(),
+ parseInt('0x' + _table.substr(20, 5)).toString(),
+ parseInt('0x' + _table.substr(25, 5)).toString()
+ ]
+ const _calday = [
+ _info[0].substr(0, 1),
+ _info[0].substr(1, 2),
+ _info[0].substr(3, 1),
+ _info[0].substr(4, 2),
+ _info[1].substr(0, 1),
+ _info[1].substr(1, 2),
+ _info[1].substr(3, 1),
+ _info[1].substr(4, 2),
+ _info[2].substr(0, 1),
+ _info[2].substr(1, 2),
+ _info[2].substr(3, 1),
+ _info[2].substr(4, 2),
+ _info[3].substr(0, 1),
+ _info[3].substr(1, 2),
+ _info[3].substr(3, 1),
+ _info[3].substr(4, 2),
+ _info[4].substr(0, 1),
+ _info[4].substr(1, 2),
+ _info[4].substr(3, 1),
+ _info[4].substr(4, 2),
+ _info[5].substr(0, 1),
+ _info[5].substr(1, 2),
+ _info[5].substr(3, 1),
+ _info[5].substr(4, 2)
+ return parseInt(_calday[n - 1])
+ * 传入农历数字月份返回汉语通俗表示法
+ * @param lunar month
+ * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
+ toChinaMonth: function(m) {
+ // 月 => \u6708
+ let s = calendar.nStr3[m - 1]
+ s += '\u6708' // 加上月字
+ return s
+ * 传入农历日期数字返回汉字表示法
+ * @param lunar day
+ * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
+ toChinaDay: function(d) {
+ // 日 => \u65e5
+ let s
+ switch (d) {
+ case 10:
+ s = '\u521d\u5341'
+ break
+ case 20:
+ s = '\u4e8c\u5341'
+ case 30:
+ s = '\u4e09\u5341'
+ default:
+ s = calendar.nStr2[Math.floor(d / 10)]
+ s += calendar.nStr1[d % 10]
+ * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
+ * @param y year
+ * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
+ getAnimal: function(y) {
+ return calendar.Animals[(y - 4) % 12]
+ * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
+ * @param y solar year
+ * @param m solar month
+ * @param d solar day
+ * @return JSON object
+ * @eg:console.log(calendar.solar2lunar(1987,11,01));
+ solar2lunar: function(y, m, d) {
+ // 参数区间1900.1.31~2100.12.31
+ // 年份限定、上限
+ if (y < 1900 || y > 2100) {
+ return -1 // undefined转换为数字变为NaN
+ // 公历传参最下限
+ if (+y === 1900 && +m === 1 && +d < 31) {
+ return -1
+ // 未传参 获得当天
+ let objDate
+ if (!y) {
+ objDate = new Date()
+ objDate = new Date(y, parseInt(m) - 1, d)
+ let leap = 0
+ let temp = 0
+ // 修正ymd参数
+ y = objDate.getFullYear()
+ m = objDate.getMonth() + 1
+ d = objDate.getDate()
+ let offset =
+ (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) -
+ Date.UTC(1900, 0, 31)) /
+ 86400000
+ for (i = 1900; i < 2101 && offset > 0; i++) {
+ temp = calendar.lYearDays(i)
+ offset -= temp
+ if (offset < 0) {
+ offset += temp
+ i--
+ // 是否今天
+ const isTodayObj = new Date()
+ let isToday = false
+ if (
+ isTodayObj.getFullYear() === +y &&
+ isTodayObj.getMonth() + 1 === +m &&
+ isTodayObj.getDate() === +d
+ ) {
+ isToday = true
+ // 星期几
+ let nWeek = objDate.getDay()
+ const cWeek = calendar.nStr1[nWeek]
+ // 数字表示周几顺应天朝周一开始的惯例
+ if (+nWeek === 0) {
+ nWeek = 7
+ // 农历年
+ const year = i
+ leap = calendar.leapMonth(i) // 闰哪个月
+ let isLeap = false
+ // 效验闰月
+ for (i = 1; i < 13 && offset > 0; i++) {
+ // 闰月
+ if (leap > 0 && i === leap + 1 && isLeap === false) {
+ --i
+ isLeap = true
+ temp = calendar.leapDays(year) // 计算农历闰月天数
+ temp = calendar.monthDays(year, i) // 计算农历普通月天数
+ // 解除闰月
+ if (isLeap === true && i === leap + 1) isLeap = false
+ // 闰月导致数组下标重叠取反
+ if (offset === 0 && leap > 0 && i === leap + 1) {
+ if (isLeap) {
+ isLeap = false
+ // 农历月
+ const month = i
+ // 农历日
+ const day = offset + 1
+ // 天干地支处理
+ const sm = m - 1
+ const gzY = calendar.toGanZhiYear(year)
+ // 当月的两个节气
+ // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
+ const firstNode = calendar.getTerm(y, m * 2 - 1) // 返回当月「节」为几日开始
+ const secondNode = calendar.getTerm(y, m * 2) // 返回当月「节」为几日开始
+ // 依据12节气修正干支月
+ let gzM = calendar.toGanZhi((y - 1900) * 12 + m + 11)
+ if (d >= firstNode) {
+ gzM = calendar.toGanZhi((y - 1900) * 12 + m + 12)
+ // 传入的日期的节气与否
+ let isTerm = false
+ let Term = null
+ if (+firstNode === d) {
+ isTerm = true
+ Term = calendar.solarTerm[m * 2 - 2]
+ if (+secondNode === d) {
+ Term = calendar.solarTerm[m * 2 - 1]
+ // 日柱 当月一日与 1900/1/1 相差天数
+ const dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
+ const gzD = calendar.toGanZhi(dayCyclical + d - 1)
+ // 该日期所属的星座
+ const astro = calendar.toAstro(m, d)
+ return {
+ lYear: year,
+ lMonth: month,
+ lDay: day,
+ Animal: calendar.getAnimal(year),
+ IMonthCn: (isLeap ? '\u95f0' : '') + calendar.toChinaMonth(month),
+ IDayCn: calendar.toChinaDay(day),
+ cYear: y,
+ cMonth: m,
+ cDay: d,
+ gzYear: gzY,
+ gzMonth: gzM,
+ gzDay: gzD,
+ isToday: isToday,
+ isLeap: isLeap,
+ nWeek: nWeek,
+ ncWeek: '\u661f\u671f' + cWeek,
+ isTerm: isTerm,
+ Term: Term,
+ astro: astro
+ * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
+ * @param y lunar year
+ * @param m lunar month
+ * @param d lunar day
+ * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
+ * @eg:console.log(calendar.lunar2solar(1987,9,10));
+ lunar2solar: function(y, m, d, isLeapMonth) {
+ // 参数区间1900.1.31~2100.12.1
+ isLeapMonth = !!isLeapMonth
+ // let leapOffset = 0;
+ const leapMonth = calendar.leapMonth(y)
+ // let leapDay = calendar.leapDays(y);
+ if (isLeapMonth && leapMonth !== m) return -1 // 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
+ (+y === 2100 && +m === 12 && +d > 1) ||
+ (+y === 1900 && +m === 1 && +d < 31)
+ return -1 // 超出了最大极限值
+ const day = calendar.monthDays(y, m)
+ let _day = day
+ // bugFix 2016-9-25
+ // if month is leap, _day use leapDays method
+ if (isLeapMonth) {
+ _day = calendar.leapDays(y, m)
+ if (y < 1900 || y > 2100 || d > _day) return -1 // 参数合法性效验
+ // 计算农历的时间差
+ let offset = 0
+ for (let i = 1900; i < y; i++) {
+ offset += calendar.lYearDays(i)
+ let isAdd = false
+ for (let i = 1; i < m; i++) {
+ leap = calendar.leapMonth(y)
+ if (!isAdd) {
+ // 处理闰月
+ if (leap <= i && leap > 0) {
+ offset += calendar.leapDays(y)
+ isAdd = true
+ offset += calendar.monthDays(y, i)
+ // 转换闰月农历 需补充该年闰月的前一个月的时差
+ if (isLeapMonth) offset += day
+ // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
+ const stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
+ const calObj = new Date((offset + d - 31) * 86400000 + stmap)
+ const cY = calObj.getUTCFullYear()
+ const cM = calObj.getUTCMonth() + 1
+ const cD = calObj.getUTCDate()
+ return calendar.solar2lunar(cY, cM, cD)
+const {
+ Gan,
+ Zhi,
+ nStr1,
+ nStr2,
+ nStr3,
+ Animals,
+ solarTerm,
+ lunarInfo,
+ sTermInfo,
+ solarMonth,
+ ...rest
+} = calendar
+export default rest
@@ -0,0 +1,543 @@
+import CalendarConfig from './config'
+import convertSolarLunar from './convertSolarLunar'
+import {
+ Logger,
+ GetDate,
+ getDateTimeStamp,
+ uniqueArrayByDate,
+ delRepeatedEnableDay,
+ convertEnableAreaToTimestamp,
+ converEnableDaysToTimestamp
+} from './utils'
+const logger = new Logger()
+const getDate = new GetDate()
+const toString = Object.prototype.toString
+class Day extends WxData {
+ *
+ * @param {number} year
+ * @param {number} month
+ buildDate(year, month) {
+ const today = getDate.todayDate()
+ const thisMonthDays = getDate.thisMonthDays(year, month)
+ const dates = []
+ for (let i = 1; i <= thisMonthDays; i++) {
+ const isToday =
+ +today.year === +year && +today.month === +month && i === +today.date
+ const config = this.getCalendarConfig()
+ const date = {
+ year,
+ month,
+ day: i,
+ choosed: false,
+ week: getDate.dayOfWeek(year, month, i),
+ isToday: isToday && config.highlightToday,
+ lunar: convertSolarLunar.solar2lunar(+year, +month, +i)
+ dates.push(date)
+ return dates
+ * 指定可选日期范围
+ * @param {array} area 日期访问数组
+ enableArea(dateArea = []) {
+ if (dateArea.length === 2) {
+ const isRight = this.__judgeParam(dateArea)
+ if (isRight) {
+ let { days = [], selectedDay = [] } = this.getData('calendar')
+ const { startTimestamp, endTimestamp } = convertEnableAreaToTimestamp(
+ dateArea
+ const dataAfterHandle = this.__handleEnableArea(
+ dateArea,
+ days,
+ startTimestamp,
+ endTimestamp
+ selectedDay
+ this.setData({
+ 'calendar.enableArea': dateArea,
+ 'calendar.days': dataAfterHandle.dates,
+ 'calendar.selectedDay': dataAfterHandle.selectedDay,
+ 'calendar.enableAreaTimestamp': [startTimestamp, endTimestamp]
+ logger.warn(
+ 'enableArea()参数需为时间范围数组,形如:["2018-8-4" , "2018-8-24"]'
+ * 指定特定日期可选
+ * @param {array} days 指定日期数组
+ enableDays(dates = []) {
+ const { enableArea = [] } = this.getData('calendar')
+ let expectEnableDaysTimestamp = []
+ if (enableArea.length) {
+ expectEnableDaysTimestamp = delRepeatedEnableDay(dates, enableArea)
+ expectEnableDaysTimestamp = converEnableDaysToTimestamp(dates)
+ const dataAfterHandle = this.__handleEnableDays(
+ expectEnableDaysTimestamp
+ 'calendar.enableDays': dates,
+ 'calendar.enableDaysTimestamp': expectEnableDaysTimestamp
+ * 设置多个日期选中
+ * @param {array} selected 需选中日期
+ setSelectedDays(selected) {
+ const config = CalendarConfig(this.Component).getCalendarConfig()
+ if (!config.multi) {
+ return logger.warn('单选模式下不能设置多日期选中,请配置 multi')
+ let { days } = this.getData('calendar')
+ let newSelectedDay = []
+ if (!selected) {
+ days.map(item => {
+ item.choosed = true
+ item.showTodoLabel = false
+ newSelectedDay = days
+ } else if (selected && selected.length) {
+ const { dates, selectedDates } = this.__handleSelectedDays(
+ newSelectedDay,
+ selected
+ days = dates
+ newSelectedDay = selectedDates
+ CalendarConfig(this.Component).setCalendarConfig('multi', true)
+ 'calendar.days': days,
+ 'calendar.selectedDay': newSelectedDay
+ * 禁用指定日期
+ * @param {array} dates 禁用
+ disableDays(dates) {
+ const { disableDays = [], days } = this.getData('calendar')
+ if (Object.prototype.toString.call(dates) !== '[object Array]') {
+ return logger.warn('disableDays 参数为数组')
+ let _disableDays = []
+ if (dates.length) {
+ _disableDays = uniqueArrayByDate(dates.concat(disableDays))
+ const disableDaysCol = _disableDays.map(d => getDate.toTimeStr(d))
+ days.forEach(item => {
+ const cur = getDate.toTimeStr(item)
+ if (disableDaysCol.includes(cur)) item.disable = true
+ item.disable = false
+ 'calendar.disableDays': _disableDays
+ * 设置连续日期选择区域
+ * @param {array} dateArea 区域开始结束日期数组
+ chooseArea(dateArea = []) {
+ if (dateArea.length === 1) {
+ dateArea = dateArea.concat(dateArea)
+ calendarConfig: {
+ ...config,
+ chooseAreaMode: true,
+ mulit: true
+ 'calendar.chooseAreaTimestamp': [startTimestamp, endTimestamp]
+ this.__chooseContinuousDates(startTimestamp, endTimestamp)
+ .then(resolve)
+ .catch(reject)
+ __pusheNextMonthDateArea(item, startTimestamp, endTimestamp, selectedDates) {
+ const days = this.buildDate(item.year, item.month)
+ let daysLen = days.length
+ for (let i = 0; i < daysLen; i++) {
+ const item = days[i]
+ const timeStamp = getDateTimeStamp(item)
+ if (timeStamp <= endTimestamp && timeStamp >= startTimestamp) {
+ selectedDates.push({
+ ...item,
+ choosed: true
+ if (i === daysLen - 1 && timeStamp < endTimestamp) {
+ this.__pusheNextMonthDateArea(
+ getDate.nextMonth(item),
+ endTimestamp,
+ selectedDates
+ __pushPrevMonthDateArea(item, startTimestamp, endTimestamp, selectedDates) {
+ const days = getDate.sortDates(
+ this.buildDate(item.year, item.month),
+ 'desc'
+ let firstDate = getDateTimeStamp(days[0])
+ if (timeStamp >= startTimestamp && timeStamp <= endTimestamp) {
+ if (i === daysLen - 1 && firstDate > startTimestamp) {
+ this.__pushPrevMonthDateArea(
+ getDate.prevMonth(item),
+ * 当设置日期区域非当前时保存其他月份的日期至已选日期数组
+ * @param {object} info
+ __calcDateWhenNotInOneMonth(info) {
+ const {
+ firstDate,
+ lastDate,
+ filterSelectedDate
+ } = info
+ if (getDateTimeStamp(firstDate) > startTimestamp) {
+ getDate.prevMonth(firstDate),
+ if (getDateTimeStamp(lastDate) < endTimestamp) {
+ getDate.nextMonth(lastDate),
+ const newSelectedDates = [...getDate.sortDates(filterSelectedDate)]
+ return newSelectedDates
+ * 设置连续日期段
+ * @param {number} startTimestamp 连续日期段开始日期时间戳
+ * @param {number} endTimestamp 连续日期段结束日期时间戳
+ __chooseContinuousDates(startTimestamp, endTimestamp) {
+ const { days, selectedDay = [] } = this.getData('calendar')
+ const selectedDateStr = []
+ let filterSelectedDate = []
+ selectedDay.forEach(item => {
+ filterSelectedDate.push(item)
+ selectedDateStr.push(getDate.toTimeStr(item))
+ const dateInSelecedArray = selectedDateStr.includes(
+ getDate.toTimeStr(item)
+ if (dateInSelecedArray) {
+ item.choosed = false
+ const idx = filterSelectedDate.findIndex(
+ selectedDate =>
+ getDate.toTimeStr(selectedDate) === getDate.toTimeStr(item)
+ if (idx > -1) {
+ filterSelectedDate.splice(idx, 1)
+ const firstDate = days[0]
+ const lastDate = days[days.length - 1]
+ const newSelectedDates = this.__calcDateWhenNotInOneMonth({
+ try {
+ 'calendar.days': [...days],
+ 'calendar.selectedDay': newSelectedDates
+ resolve(newSelectedDates)
+ } catch (err) {
+ reject(err)
+ * 设置指定日期样式
+ * @param {array} dates 待设置特殊样式的日期
+ setDateStyle(dates) {
+ if (toString.call(dates) !== '[object Array]') return
+ const { days, specialStyleDates } = this.getData('calendar')
+ if (toString.call(specialStyleDates) === '[object Array]') {
+ dates = uniqueArrayByDate([...specialStyleDates, ...dates])
+ const _specialStyleDates = dates.map(
+ item => `${item.year}_${item.month}_${item.day}`
+ const _days = days.map(item => {
+ const idx = _specialStyleDates.indexOf(
+ `${item.year}_${item.month}_${item.day}`
+ class: dates[idx].class
+ return { ...item }
+ 'calendar.days': _days,
+ 'calendar.specialStyleDates': dates
+ __judgeParam(dateArea) {
+ start,
+ end,
+ } = convertEnableAreaToTimestamp(dateArea)
+ if (!start || !end) return
+ const startMonthDays = getDate.thisMonthDays(start[0], start[1])
+ const endMonthDays = getDate.thisMonthDays(end[0], end[1])
+ if (start[2] > startMonthDays || start[2] < 1) {
+ logger.warn('enableArea() 开始日期错误,指定日期不在当前月份天数范围内')
+ return false
+ } else if (start[1] > 12 || start[1] < 1) {
+ logger.warn('enableArea() 开始日期错误,月份超出1-12月份')
+ } else if (end[2] > endMonthDays || end[2] < 1) {
+ logger.warn('enableArea() 截止日期错误,指定日期不在当前月份天数范围内')
+ } else if (end[1] > 12 || end[1] < 1) {
+ logger.warn('enableArea() 截止日期错误,月份超出1-12月份')
+ } else if (startTimestamp > endTimestamp) {
+ logger.warn('enableArea()参数最小日期大于了最大日期')
+ return true
+ __getDisableDateTimestamp() {
+ let disableDateTimestamp
+ const { date, type } = this.getCalendarConfig().disableMode || {}
+ if (date) {
+ const t = date.split('-')
+ if (t.length < 3) {
+ logger.warn('配置 disableMode.date 格式错误')
+ return {}
+ disableDateTimestamp = getDateTimeStamp({
+ year: +t[0],
+ month: +t[1],
+ day: +t[2]
+ disableDateTimestamp,
+ disableType: type
+ __handleEnableArea(data = {}, selectedDay = []) {
+ const { area, days, startTimestamp, endTimestamp } = data
+ const enableDays = this.getData('calendar.enableDays') || []
+ if (enableDays.length) {
+ expectEnableDaysTimestamp = delRepeatedEnableDay(enableDays, area)
+ disableType
+ } = this.__getDisableDateTimestamp()
+ const dates = [...days]
+ dates.forEach(item => {
+ const timestamp = +getDate
+ .newDate(item.year, item.month, item.day)
+ .getTime()
+ const ifOutofArea =
+ (+startTimestamp > timestamp || timestamp > +endTimestamp) &&
+ !expectEnableDaysTimestamp.includes(timestamp)
+ ifOutofArea ||
+ (disableType === 'before' &&
+ disableDateTimestamp &&
+ timestamp < disableDateTimestamp) ||
+ (disableType === 'after' &&
+ timestamp > disableDateTimestamp)
+ item.disable = true
+ if (item.choosed) {
+ selectedDay = selectedDay.filter(
+ d => getDate.toTimeStr(item) !== getDate.toTimeStr(d)
+ } else if (item.disable) {
+ dates,
+ __handleEnableDays(data = {}, selectedDay = []) {
+ const { days, expectEnableDaysTimestamp } = data
+ const { enableAreaTimestamp = [] } = this.getData('calendar')
+ const timestamp = getDate
+ let setDisable = false
+ if (enableAreaTimestamp.length) {
+ (+enableAreaTimestamp[0] > +timestamp ||
+ +timestamp > +enableAreaTimestamp[1]) &&
+ !expectEnableDaysTimestamp.includes(+timestamp)
+ setDisable = true
+ } else if (!expectEnableDaysTimestamp.includes(+timestamp)) {
+ if (setDisable) {
+ __handleSelectedDays(days = [], newSelectedDay = [], selected) {
+ const { selectedDay, showLabelAlways } = this.getData('calendar')
+ if (selectedDay && selectedDay.length) {
+ newSelectedDay = uniqueArrayByDate(selectedDay.concat(selected))
+ newSelectedDay = selected
+ const { year: curYear, month: curMonth } = days[0]
+ const currentSelectedDays = []
+ newSelectedDay.forEach(item => {
+ if (+item.year === +curYear && +item.month === +curMonth) {
+ currentSelectedDays.push(getDate.toTimeStr(item))
+ ;[...days].map(item => {
+ if (currentSelectedDays.includes(getDate.toTimeStr(item))) {
+ if (showLabelAlways && item.showTodoLabel) {
+ item.showTodoLabel = true
+ dates: days,
+ selectedDates: newSelectedDay
+export default component => new Day(component)
@@ -0,0 +1,375 @@
+import Day from './day'
+import Todo from './todo'
+class Calendar extends WxData {
+ * 渲染日历
+ * @param {number} curYear 年份
+ * @param {number} curMonth 月份
+ * @param {number} curDate 日期
+ * @param {boolean} disableSelect 是否禁用选中
+ renderCalendar(curYear, curMonth, curDate, disableSelect) {
+ return new Promise(resolve => {
+ this.calculateEmptyGrids(curYear, curMonth)
+ this.calculateDays(curYear, curMonth, curDate, disableSelect).then(() => {
+ const { todoLabels, specialStyleDates, enableDays, selectedDay } =
+ this.getData('calendar') || {}
+ todoLabels &&
+ todoLabels.find(
+ item => +item.month === +curMonth && +item.year === +curYear
+ Todo(this.Component).setTodoLabels()
+ specialStyleDates &&
+ specialStyleDates.length &&
+ specialStyleDates.find(
+ Day(this.Component).setDateStyle(specialStyleDates)
+ enableDays &&
+ enableDays.length &&
+ enableDays.find(item => {
+ let ymd = item.split('-')
+ return +ymd[1] === +curMonth && +ymd[0] === +curYear
+ Day(this.Component).enableDays(enableDays)
+ selectedDay &&
+ selectedDay.length &&
+ selectedDay.find(
+ ) &&
+ config.mulit
+ Day(this.Component).setSelectedDays(selectedDay)
+ if (!this.Component.firstRender) {
+ resolve({
+ firstRender: true
+ firstRender: false
+ * 计算当前月份前后两月应占的格子
+ * @param {number} year 年份
+ * @param {number} month 月份
+ calculateEmptyGrids(year, month) {
+ this.calculatePrevMonthGrids(year, month)
+ this.calculateNextMonthGrids(year, month)
+ * 计算上月应占的格子
+ calculatePrevMonthGrids(year, month) {
+ let empytGrids = []
+ const prevMonthDays = getDate.thisMonthDays(year, month - 1)
+ let firstDayOfWeek = getDate.firstDayOfWeek(year, month)
+ const config = this.getCalendarConfig() || {}
+ if (config.firstDayOfWeek === 'Mon') {
+ if (firstDayOfWeek === 0) {
+ firstDayOfWeek = 6
+ firstDayOfWeek -= 1
+ if (firstDayOfWeek > 0) {
+ const len = prevMonthDays - firstDayOfWeek
+ const { onlyShowCurrentMonth } = config
+ const { showLunar } = this.getCalendarConfig()
+ for (let i = prevMonthDays; i > len; i--) {
+ if (onlyShowCurrentMonth) {
+ empytGrids.push('')
+ empytGrids.push({
+ lunar: showLunar
+ ? convertSolarLunar.solar2lunar(year, month - 1, i)
+ : null
+ 'calendar.empytGrids': empytGrids.reverse()
+ 'calendar.empytGrids': null
+ * 计算下一月日期是否需要多展示的日期
+ * 某些月份日期为5排,某些月份6排,统一为6排
+ * @param {object} config
+ calculateExtraEmptyDate(year, month, config) {
+ let extDate = 0
+ if (+month === 2) {
+ extDate += 7
+ let firstDayofMonth = getDate.dayOfWeek(year, month, 1)
+ if (+firstDayofMonth === 1) extDate += 7
+ if (+firstDayofMonth === 0) extDate += 7
+ if (firstDayofMonth !== 0 && firstDayofMonth < 6) {
+ if (firstDayofMonth <= 5) {
+ return extDate
+ * 计算下月应占的格子
+ calculateNextMonthGrids(year, month) {
+ let lastEmptyGrids = []
+ let lastDayWeek = getDate.dayOfWeek(year, month, thisMonthDays)
+ if (lastDayWeek === 0) {
+ lastDayWeek = 6
+ lastDayWeek -= 1
+ let len = 7 - (lastDayWeek + 1)
+ const { onlyShowCurrentMonth, showLunar } = config
+ if (!onlyShowCurrentMonth) {
+ len = len + this.calculateExtraEmptyDate(year, month, config)
+ for (let i = 1; i <= len; i++) {
+ lastEmptyGrids.push('')
+ lastEmptyGrids.push({
+ ? convertSolarLunar.solar2lunar(year, month + 1, i)
+ 'calendar.lastEmptyGrids': lastEmptyGrids
+ * 日历初始化将默认值写入 selectDay
+ * @param {number} curDate
+ setSelectedDay(year, month, curDate) {
+ let selectedDay = []
+ if (config.noDefault) {
+ selectedDay = []
+ config.noDefault = false
+ const data = this.getData('calendar') || {}
+ selectedDay = curDate
+ ? [
+ day: curDate,
+ choosed: true,
+ week: getDate.dayOfWeek(year, month, curDate),
+ ? convertSolarLunar.solar2lunar(year, month, curDate)
+ : data.selectedDay
+ return selectedDay
+ resetDates() {
+ 'calendar.days': []
+ * 设置日历面板数据
+ calculateDays(year, month, curDate, disableSelect) {
+ // 避免切换日期时样式残影
+ this.resetDates()
+ let days = []
+ disableDays = [],
+ chooseAreaTimestamp = [],
+ selectedDay: selectedDates = []
+ } = this.getData('calendar')
+ days = Day(this.Component).buildDate(year, month)
+ let selectedDay = selectedDates
+ if (!disableSelect) {
+ selectedDay = this.setSelectedDay(year, month, curDate)
+ const selectedDayStr = selectedDay.map(d => getDate.toTimeStr(d))
+ const disableDaysStr = disableDays.map(d => getDate.toTimeStr(d))
+ const [areaStart, areaEnd] = chooseAreaTimestamp
+ const timestamp = getDateTimeStamp(item)
+ if (selectedDayStr.includes(cur) && !disableSelect) {
+ if (timestamp > areaEnd || timestamp < areaStart) {
+ const idx = selectedDay.findIndex(
+ selectedDay.splice(idx, 1)
+ } else if (
+ areaStart &&
+ areaEnd &&
+ timestamp >= areaStart &&
+ timestamp <= areaEnd &&
+ !disableSelect
+ selectedDay.push(item)
+ if (disableDaysStr.includes(cur)) item.disable = true
+ let disabelByConfig = false
+ if (disableDateTimestamp) {
+ (disableType === 'before' && timestamp < disableDateTimestamp) ||
+ (disableType === 'after' && timestamp > disableDateTimestamp)
+ disabelByConfig = true
+ const isDisable = disabelByConfig || this.__isDisable(timestamp)
+ if (isDisable) {
+ 'calendar.selectedDay': [...selectedDay] || []
+ resolve()
+ __isDisable(timestamp) {
+ enableArea = [],
+ enableDays = [],
+ enableAreaTimestamp = []
+ let expectEnableDaysTimestamp = converEnableDaysToTimestamp(enableDays)
+ expectEnableDaysTimestamp = delRepeatedEnableDay(enableDays, enableArea)
+ expectEnableDaysTimestamp.length &&
+ return setDisable
+export default component => new Calendar(component)
@@ -0,0 +1,182 @@
+import { Logger, uniqueArrayByDate, GetDate } from './utils'
+class Todo extends WxData {
+ * 设置待办事项标志
+ * @param {object} options 待办事项配置
+ setTodoLabels(options) {
+ if (options) this.Component.todoConfig = options
+ const calendar = this.getData('calendar')
+ if (!calendar || !calendar.days) {
+ return logger.warn('请等待日历初始化完成后再调用该方法')
+ const dates = [...calendar.days]
+ const { curYear, curMonth } = calendar
+ circle,
+ dotColor = '',
+ pos = 'bottom',
+ showLabelAlways,
+ days: todoDays = []
+ } = options || this.Component.todoConfig || {}
+ const { todoLabels = [] } = calendar
+ const currentMonthTodoLabels = this.getTodoLabels({
+ year: curYear,
+ month: curMonth
+ let newTodoLabels = todoDays.filter(
+ item => +item.year === +curYear && +item.month === +curMonth
+ if (this.Component.weekMode) {
+ newTodoLabels = todoDays
+ const allTodos = currentMonthTodoLabels.concat(newTodoLabels)
+ for (let todo of allTodos) {
+ let target
+ target = dates.find(
+ date =>
+ +todo.year === +date.year &&
+ +todo.month === +date.month &&
+ +todo.day === +date.day
+ target = dates[todo.day - 1]
+ if (!target) continue
+ if (showLabelAlways) {
+ target.showTodoLabel = true
+ target.showTodoLabel = !target.choosed
+ if (target.showTodoLabel) {
+ target.todoText = todo.todoText
+ target.color = todo.color
+ const o = {
+ 'calendar.days': dates,
+ 'calendar.todoLabels': uniqueArrayByDate(todoLabels.concat(todoDays))
+ if (!circle) {
+ o['calendar.todoLabelPos'] = pos
+ o['calendar.todoLabelColor'] = dotColor
+ o['calendar.todoLabelCircle'] = circle || false
+ o['calendar.showLabelAlways'] = showLabelAlways || false
+ this.setData(o)
+ * 删除指定日期的待办事项
+ * @param {array} todos 需要删除待办事项的日期
+ deleteTodoLabels(todos) {
+ if (!(todos instanceof Array) || !todos.length) return
+ const todoLabels = this.filterTodos(todos)
+ const { days: dates, curYear, curMonth } = this.getData('calendar')
+ const currentMonthTodoLabels = todoLabels.filter(
+ item => curYear === +item.year && curMonth === +item.month
+ currentMonthTodoLabels.forEach(item => {
+ dates[item.day - 1].showTodoLabel = !dates[item.day - 1].choosed
+ 'calendar.todoLabels': todoLabels
+ * 清空所有待办事项
+ clearTodoLabels() {
+ const { days = [] } = this.getData('calendar')
+ const dates = [].concat(days)
+ 'calendar.todoLabels': []
+ * 获取所有待办事项
+ * @param {object} target 指定年月
+ * @param {number} [target.year] 年
+ * @param {number} [target.month] 月
+ getTodoLabels(target) {
+ const { todoLabels = [] } = this.getData('calendar')
+ if (target) {
+ const { year, month } = target
+ const _todoLabels = todoLabels.filter(
+ item => +item.year === +year && +item.month === +month
+ return _todoLabels
+ return todoLabels
+ * 过滤将删除的待办事项
+ * @param {array} todos 需要删除待办事项
+ filterTodos(todos) {
+ const todoLabels = this.getData('calendar.todoLabels') || []
+ const deleteTodo = todos.map(item => getDate.toTimeStr(item))
+ return todoLabels.filter(
+ item => !deleteTodo.includes(getDate.toTimeStr(item))
+ * 单选时显示待办事项
+ * @param {array} todoDays
+ * @param {array} days
+ * @param {array} selectedDays
+ showTodoLabels(todoDays, days, selectedDays) {
+ todoDays.forEach(item => {
+ days.forEach((_item, idx) => {
+ if (+_item.day === +item.day) {
+ const day = days[idx]
+ day.hasTodo = true
+ day.todoText = item.todoText
+ selectedDays &&
+ selectedDays.length &&
+ +selectedDays[0].day === +item.day
+ day.showTodoLabel = true
+ const day = days[item.day - 1]
+ if (!day) return
+ days[selectedDays[0].day - 1].showTodoLabel = true
+export default component => new Todo(component)
@@ -0,0 +1,367 @@
+let systemInfo
+export function getSystemInfo() {
+ if (systemInfo) return systemInfo
+ systemInfo = wx.getSystemInfoSync()
+ return systemInfo
+export function isComponent(target) {
+ return (
+ target &&
+ target.__wxExparserNodeId__ !== void 0 &&
+ typeof target.setData === 'function'
+export class Logger {
+ info(msg) {
+ console.log(
+ '%cInfo: %c' + msg,
+ 'color:#FF0080;font-weight:bold',
+ 'color: #FF509B'
+ warn(msg) {
+ '%cWarn: %c' + msg,
+ 'color:#FF6600;font-weight:bold',
+ 'color: #FF9933'
+ tips(msg) {
+ '%cTips: %c' + msg,
+ 'color:#00B200;font-weight:bold',
+ 'color: #00CC33'
+export class Slide {
+ * 上滑
+ * @param {object} e 事件对象
+ * @returns {boolean} 布尔值
+ isUp(gesture = {}, touche = {}) {
+ const { startX, startY } = gesture
+ const deltaX = touche.clientX - startX
+ const deltaY = touche.clientY - startY
+ if (deltaY < -60 && deltaX < 20 && deltaX > -20) {
+ this.slideLock = false
+ * 下滑
+ isDown(gesture = {}, touche = {}) {
+ if (deltaY > 60 && deltaX < 20 && deltaX > -20) {
+ * 左滑
+ isLeft(gesture = {}, touche = {}) {
+ if (deltaX < -60 && deltaY < 20 && deltaY > -20) {
+ * 右滑
+ isRight(gesture = {}, touche = {}) {
+ if (deltaX > 60 && deltaY < 20 && deltaY > -20) {
+export class GetDate {
+ * new Date 区分平台
+ * @param {number} day
+ newDate(year, month, day) {
+ let cur = `${+year}-${+month}-${+day}`
+ if (isIos()) {
+ cur = `${+year}/${+month}/${+day}`
+ return new Date(cur)
+ * 计算指定月份共多少天
+ thisMonthDays(year, month) {
+ return new Date(Date.UTC(year, month, 0)).getUTCDate()
+ * 计算指定月份第一天星期几
+ firstDayOfWeek(year, month) {
+ return new Date(Date.UTC(year, month - 1, 1)).getUTCDay()
+ * 计算指定日期星期几
+ * @param {number} date 日期
+ dayOfWeek(year, month, date) {
+ return new Date(Date.UTC(year, month - 1, date)).getUTCDay()
+ todayDate() {
+ const _date = new Date()
+ const year = _date.getFullYear()
+ const month = _date.getMonth() + 1
+ const date = _date.getDate()
+ date
+ todayTimestamp() {
+ const { year, month, date } = this.todayDate()
+ const timestamp = this.newDate(year, month, date).getTime()
+ return timestamp
+ toTimeStr(dateInfo) {
+ if (dateInfo.day) {
+ dateInfo.date = dateInfo.day
+ return `${+dateInfo.year}-${+dateInfo.month}-${+dateInfo.date}`
+ sortDates(dates, sortType) {
+ return dates.sort(function(a, b) {
+ const at = getDateTimeStamp(a)
+ const bt = getDateTimeStamp(b)
+ if (at < bt && sortType !== 'desc') {
+ return 1
+ prevMonth(dataInfo) {
+ const prevMonthInfo =
+ +dataInfo.month > 1
+ ? {
+ year: dataInfo.year,
+ month: dataInfo.month - 1
+ : {
+ year: dataInfo.year - 1,
+ month: 12
+ return prevMonthInfo
+ nextMonth(dataInfo) {
+ const nextMonthInfo =
+ +dataInfo.month < 12
+ month: dataInfo.month + 1
+ year: dataInfo.year + 1,
+ month: 1
+ return nextMonthInfo
+ convertLunar(dates = []) {
+ const datesWithLunar = dates.map(date => {
+ date.lunar = convertSolarLunar.solar2lunar(
+ +date.year,
+ +date.month,
+ +date.day
+ return date
+ return datesWithLunar
+export function isIos() {
+ const sys = getSystemInfo()
+ return /iphone|ios/i.test(sys.platform)
+ * 浅比较对象是否相等
+ * @param {Object} origin 对比源
+ * @param {Object} target 对比目标
+ * @return {Boolean} true 为相等,false 为不等
+export function shallowEqual(origin, target) {
+ if (origin === target) {
+ typeof origin === 'object' &&
+ origin != null &&
+ typeof target === 'object' &&
+ target != null
+ if (Object.keys(origin).length !== Object.keys(target).length) return false
+ for (var prop in origin) {
+ if (target.hasOwnProperty(prop)) {
+ if (!shallowEqual(origin[prop], target[prop])) return false
+ } else return false
+ * 获取当前页面实例
+export function getCurrentPage() {
+ const pages = getCurrentPages()
+ const last = pages.length - 1
+ return pages[last]
+export function getComponent(componentId) {
+ const logger = new Logger()
+ let page = getCurrentPage() || {}
+ if (page.selectComponent && typeof page.selectComponent === 'function') {
+ if (componentId) {
+ return page.selectComponent(componentId)
+ logger.warn('请传入组件ID')
+ logger.warn('该基础库暂不支持多个小程序日历组件')
+ * 日期数组根据日期去重
+ * @param {array} array 数组
+export function uniqueArrayByDate(array = []) {
+ let uniqueObject = {}
+ let uniqueArray = []
+ array.forEach(item => {
+ uniqueObject[`${item.year}-${item.month}-${item.day}`] = item
+ for (let i in uniqueObject) {
+ uniqueArray.push(uniqueObject[i])
+ return uniqueArray
+ * 指定可选日期及可选日期数组去重
+ * @param {array} enableDays 特定可选日期数组
+ * @param {array} enableArea 可选日期区域数组
+export function delRepeatedEnableDay(enableDays = [], enableArea = []) {
+ let _startTimestamp
+ let _endTimestamp
+ if (enableArea.length === 2) {
+ enableArea
+ _startTimestamp = startTimestamp
+ _endTimestamp = endTimestamp
+ const enableDaysTimestamp = converEnableDaysToTimestamp(enableDays)
+ const tmp = enableDaysTimestamp.filter(
+ item => item < _startTimestamp || item > _endTimestamp
+ return tmp
+ * 指定日期区域转时间戳
+ * @param {array} timearea 时间区域
+export function convertEnableAreaToTimestamp(timearea = []) {
+ const getDate = new GetDate()
+ const start = timearea[0].split('-')
+ const end = timearea[1].split('-')
+ if (start.length !== 3 || end.length !== 3) {
+ logger.warn('enableArea() 参数格式为: ["2018-2-1", "2018-3-1"]')
+ const startTimestamp = getDate.newDate(start[0], start[1], start[2]).getTime()
+ const endTimestamp = getDate.newDate(end[0], end[1], end[2]).getTime()
+ * 计算指定日期时间戳
+ * @param {object} dateInfo
+export function getDateTimeStamp(dateInfo) {
+ if (Object.prototype.toString.call(dateInfo) !== '[object Object]') return
+ return getDate.newDate(dateInfo.year, dateInfo.month, dateInfo.day).getTime()
+ * 指定特定日期数组转时间戳
+ * @param {array} enableDays 指定时间数组
+export function converEnableDaysToTimestamp(enableDays = []) {
+ const enableDaysTimestamp = []
+ enableDays.forEach(item => {
+ if (typeof item !== 'string')
+ return logger.warn('enableDays()入参日期格式错误')
+ const tmp = item.split('-')
+ if (tmp.length !== 3) return logger.warn('enableDays()入参日期格式错误')
+ const timestamp = getDate.newDate(tmp[0], tmp[1], tmp[2]).getTime()
+ enableDaysTimestamp.push(timestamp)
+ return enableDaysTimestamp
+// 同一页面多个日历组件按先后顺序渲染
+export const initialTasks = {
+ flag: 'finished', // process 处理中,finished 处理完成
+ tasks: []
@@ -0,0 +1,601 @@
+import Render from './render'
+import { GetDate, Logger, getDateTimeStamp } from './utils'
+class WeekMode extends WxData {
+ this.getCalendarConfig = CalendarConfig(this.Component).getCalendarConfig
+ * 周、月视图切换
+ * @param {string} view 视图 [week, month]
+ * @param {object} date {year: 2017, month: 11, day: 1}
+ switchWeek(view, date) {
+ if (config.multi) return logger.warn('多选模式不能切换周月视图')
+ const { selectedDay = [], curYear, curMonth } = this.getData('calendar')
+ let currentDate = []
+ let disableSelected = false
+ if (!selectedDay.length) {
+ currentDate = getDate.todayDate()
+ currentDate.day = currentDate.date
+ disableSelected = true
+ // return this.__tipsWhenCanNotSwtich();
+ currentDate = selectedDay[0]
+ let selectedDate = date || currentDate
+ const { year, month } = selectedDate
+ const notInCurrentMonth = curYear !== year || curMonth !== month
+ if (view === 'week') {
+ if (this.Component.weekMode) return
+ if ((selectedDay.length && notInCurrentMonth) || !selectedDay.length) {
+ selectedDate = {
+ month: curMonth,
+ day: selectedDate.day
+ this.Component.weekMode = true
+ 'calendarConfig.weekMode': true
+ this.jump(selectedDate, disableSelected)
+ this.Component.weekMode = false
+ 'calendarConfig.weekMode': false
+ const disableSelected =
+ (selectedDay.length && notInCurrentMonth) || !selectedDay.length
+ Render(this.Component)
+ .renderCalendar(curYear, curMonth, selectedDate.day, disableSelected)
+ * 更新当前年月
+ updateCurrYearAndMonth(type) {
+ let { days, curYear, curMonth } = this.getData('calendar')
+ const { month: firstMonth } = days[0]
+ const { month: lastMonth } = days[days.length - 1]
+ const lastDayOfThisMonth = getDate.thisMonthDays(curYear, curMonth)
+ const lastDayOfThisWeek = days[days.length - 1]
+ const firstDayOfThisWeek = days[0]
+ (lastDayOfThisWeek.day + 7 > lastDayOfThisMonth ||
+ (curMonth === firstMonth && firstMonth !== lastMonth)) &&
+ type === 'next'
+ curMonth = curMonth + 1
+ if (curMonth > 12) {
+ curYear = curYear + 1
+ curMonth = 1
+ (+firstDayOfThisWeek.day <= 7 ||
+ (curMonth === lastMonth && firstMonth !== lastMonth)) &&
+ type === 'prev'
+ curMonth = curMonth - 1
+ if (curMonth <= 0) {
+ curYear = curYear - 1
+ curMonth = 12
+ Uyear: curYear,
+ Umonth: curMonth
+ * 计算周视图下当前这一周和当月的最后一天
+ calculateLastDay() {
+ const { days = [], curYear, curMonth } = this.getData('calendar')
+ const lastDayInThisWeek = days[days.length - 1].day
+ const lastDayInThisMonth = getDate.thisMonthDays(curYear, curMonth)
+ return { lastDayInThisWeek, lastDayInThisMonth }
+ * 计算周视图下当前这一周第一天
+ calculateFirstDay() {
+ const { days } = this.getData('calendar')
+ const firstDayInThisWeek = days[0].day
+ return { firstDayInThisWeek }
+ * 当月第一周所有日期范围
+ * @param {boolean} firstDayOfWeekIsMon 每周是否配置为以周一开始
+ firstWeekInMonth(year, month, firstDayOfWeekIsMon) {
+ let firstDay = getDate.dayOfWeek(year, month, 1)
+ if (firstDayOfWeekIsMon && firstDay === 0) {
+ firstDay = 7
+ const [, end] = [0, 7 - firstDay]
+ let days = this.getData('calendar.days') || []
+ const daysCut = days.slice(0, firstDayOfWeekIsMon ? end + 1 : end)
+ return daysCut
+ * 当月最后一周所有日期范围
+ lastWeekInMonth(year, month, firstDayOfWeekIsMon) {
+ const lastDay = getDate.thisMonthDays(year, month)
+ const lastDayWeek = getDate.dayOfWeek(year, month, lastDay)
+ const [start, end] = [lastDay - lastDayWeek, lastDay]
+ const daysCut = days.slice(firstDayOfWeekIsMon ? start : start - 1, end)
+ __getDisableDateTimestamp(config) {
+ const { date, type } = config.disableMode || {}
+ * 渲染日期之前初始化已选日期
+ * @param {array} dates 当前日期数组
+ initSelectedDay(dates) {
+ let datesCopy = [...dates]
+ const { selectedDay = [] } = this.getData('calendar')
+ const selectedDayStr = selectedDay.map(
+ item => `${+item.year}-${+item.month}-${+item.day}`
+ } = this.__getDisableDateTimestamp(config)
+ datesCopy = datesCopy.map(item => {
+ if (!item) return {}
+ const dateTimestamp = getDateTimeStamp(item)
+ let date = { ...item }
+ selectedDayStr.includes(`${+date.year}-${+date.month}-${+date.day}`)
+ date.choosed = true
+ date.choosed = false
+ (disableType === 'after' && dateTimestamp > disableDateTimestamp) ||
+ (disableType === 'before' && dateTimestamp < disableDateTimestamp)
+ date.disable = true
+ date = this.__setTodoWhenJump(date, config)
+ if (config.showLunar) {
+ date = this.__setSolarLunar(date)
+ if (config.highlightToday) {
+ date = this.__highlightToday(date)
+ return datesCopy
+ * 周视图下设置可选日期范围
+ * @param {object} days 当前展示的日期
+ setEnableAreaOnWeekMode(dates = []) {
+ let { enableAreaTimestamp = [], enableDaysTimestamp = [] } = this.getData(
+ 'calendar'
+ !enableDaysTimestamp.includes(+timestamp)
+ enableDaysTimestamp.length &&
+ updateYMWhenSwipeCalendarHasSelected(dates) {
+ const hasSelectedDate = dates.filter(date => date.choosed)
+ if (hasSelectedDate && hasSelectedDate.length) {
+ const { year, month } = hasSelectedDate[0]
+ month
+ * 计算下一周的日期
+ calculateNextWeekDays() {
+ let { lastDayInThisWeek, lastDayInThisMonth } = this.calculateLastDay()
+ let { curYear, curMonth } = this.getData('calendar')
+ if (lastDayInThisMonth - lastDayInThisWeek >= 7) {
+ const { Uyear, Umonth } = this.updateCurrYearAndMonth('next')
+ curYear = Uyear
+ curMonth = Umonth
+ for (let i = lastDayInThisWeek + 1; i <= lastDayInThisWeek + 7; i++) {
+ days.push({
+ week: getDate.dayOfWeek(curYear, curMonth, i)
+ for (let i = lastDayInThisWeek + 1; i <= lastDayInThisMonth; i++) {
+ for (let i = 1; i <= 7 - (lastDayInThisMonth - lastDayInThisWeek); i++) {
+ days = this.initSelectedDay(days)
+ year: updateYear,
+ month: updateMonth
+ } = this.updateYMWhenSwipeCalendarHasSelected(days)
+ if (updateYear && updateMonth) {
+ curYear = updateYear
+ curMonth = updateMonth
+ this.setEnableAreaOnWeekMode(days)
+ 'calendar.curYear': curYear,
+ 'calendar.curMonth': curMonth,
+ 'calendar.days': days
+ Day(this.Component).setDateStyle()
+ * 计算上一周的日期
+ calculatePrevWeekDays() {
+ let { firstDayInThisWeek } = this.calculateFirstDay()
+ if (firstDayInThisWeek - 7 > 0) {
+ const { Uyear, Umonth } = this.updateCurrYearAndMonth('prev')
+ for (let i = firstDayInThisWeek - 7; i < firstDayInThisWeek; i++) {
+ let temp = []
+ for (let i = 1; i < firstDayInThisWeek; i++) {
+ temp.push({
+ const prevMonthDays = getDate.thisMonthDays(curYear, curMonth)
+ for (
+ let i = prevMonthDays - Math.abs(firstDayInThisWeek - 7);
+ i <= prevMonthDays;
+ i++
+ days = days.concat(temp)
+ calculateDatesWhenJump(
+ { year, month, day },
+ { firstWeekDays, lastWeekDays },
+ firstDayOfWeekIsMon
+ const inFirstWeek = this.__dateIsInWeek({ year, month, day }, firstWeekDays)
+ const inLastWeek = this.__dateIsInWeek({ year, month, day }, lastWeekDays)
+ let dates = []
+ if (inFirstWeek) {
+ dates = this.__calculateDatesWhenInFirstWeek(
+ firstWeekDays,
+ } else if (inLastWeek) {
+ dates = this.__calculateDatesWhenInLastWeek(
+ lastWeekDays,
+ dates = this.__calculateDates({ year, month, day }, firstDayOfWeekIsMon)
+ jump({ year, month, day }, disableSelected) {
+ const firstDayOfWeekIsMon = config.firstDayOfWeek === 'Mon'
+ const firstWeekDays = this.firstWeekInMonth(
+ let lastWeekDays = this.lastWeekInMonth(year, month, firstDayOfWeekIsMon)
+ let dates = this.calculateDatesWhenJump(
+ lastWeekDays
+ dates = dates.map(d => {
+ let date = { ...d }
+ +date.year === +year &&
+ +date.month === +month &&
+ +date.day === +day &&
+ !disableSelected
+ this.setEnableAreaOnWeekMode(dates)
+ const tmpData = {
+ 'calendar.curYear': year,
+ 'calendar.curMonth': month,
+ 'calendar.empytGrids': [],
+ 'calendar.lastEmptyGrids': []
+ if (!disableSelected) {
+ tmpData['calendar.selectedDay'] = dates.filter(item => item.choosed)
+ this.setData(tmpData, () => {
+ resolve({ year, month, date: day })
+ __setTodoWhenJump(dateInfo) {
+ const date = { ...dateInfo }
+ const { todoLabels = [], showLabelAlways } = this.getData('calendar')
+ const todosStr = todoLabels.map(d => `${+d.year}-${+d.month}-${+d.day}`)
+ const idx = todosStr.indexOf(`${+date.year}-${+date.month}-${+date.day}`)
+ if (idx !== -1) {
+ date.showTodoLabel = true
+ date.showTodoLabel = !date.choosed
+ const todo = todoLabels[idx] || {}
+ if (date.showTodoLabel && todo.todoText) date.todoText = todo.todoText
+ if (todo.color) date.color = todo.color
+ __setSolarLunar(dateInfo) {
+ __highlightToday(dateInfo) {
+ +today.year === +date.year &&
+ +today.month === +date.month &&
+ +date.day === +today.date
+ date.isToday = isToday
+ __calculateDatesWhenInFirstWeek(firstWeekDays) {
+ const dates = [...firstWeekDays]
+ if (dates.length < 7) {
+ let { year, month } = dates[0]
+ let len = 7 - dates.length
+ let lastDate
+ if (month > 1) {
+ month -= 1
+ lastDate = getDate.thisMonthDays(year, month)
+ month = 12
+ year -= 1
+ while (len) {
+ dates.unshift({
+ day: lastDate,
+ week: getDate.dayOfWeek(year, month, lastDate)
+ lastDate -= 1
+ len -= 1
+ __calculateDatesWhenInLastWeek(lastWeekDays) {
+ const dates = [...lastWeekDays]
+ let firstDate = 1
+ if (month > 11) {
+ month = 1
+ year += 1
+ month += 1
+ dates.push({
+ day: firstDate,
+ week: getDate.dayOfWeek(year, month, firstDate)
+ firstDate += 1
+ __calculateDates({ year, month, day }, firstDayOfWeekIsMon) {
+ const week = getDate.dayOfWeek(year, month, day)
+ let range = [day - week, day + (6 - week)]
+ if (firstDayOfWeekIsMon) {
+ range = [day + 1 - week, day + (7 - week)]
+ const dates = Day(this.Component).buildDate(year, month)
+ const weekDates = dates.slice(range[0] - 1, range[1])
+ return weekDates
+ __dateIsInWeek(date, week) {
+ return week.find(
+ item =>
+ +item.year === +date.year &&
+ +item.month === +date.month &&
+ +item.day === +date.day
+ __tipsWhenCanNotSwtich() {
+ logger.info(
+ '当前月份未选中日期下切换为周视图,不能明确该展示哪一周的日期,故此情况不允许切换'
+export default component => new WeekMode(component)
@@ -0,0 +1,26 @@
+class WxData {
+ getData(key) {
+ const data = this.Component.data
+ if (!key) return data
+ if (key.includes('.')) {
+ let keys = key.split('.')
+ const tmp = keys.reduce((prev, next) => {
+ return prev[next]
+ }, data)
+ return this.Component.data[key]
+ setData(data, cb = () => {}) {
+ if (!data) return
+ if (typeof data === 'object') {
+ this.Component.setData(data, cb)
+export default WxData
@@ -1,2287 +1,254 @@
-!(function(e) {
- var t = {};
- function a(n) {
- if (t[n]) return t[n].exports;
- var s = (t[n] = { i: n, l: !1, exports: {} });
- return e[n].call(s.exports, s, s.exports, a), (s.l = !0), s.exports;
- }
- (a.m = e),
- (a.c = t),
- (a.d = function(e, t, n) {
- a.o(e, t) || Object.defineProperty(e, t, { enumerable: !0, get: n });
- }),
- (a.r = function(e) {
- 'undefined' != typeof Symbol &&
- Symbol.toStringTag &&
- Object.defineProperty(e, Symbol.toStringTag, { value: 'Module' }),
- Object.defineProperty(e, '__esModule', { value: !0 });
- (a.t = function(e, t) {
- if ((1 & t && (e = a(e)), 8 & t)) return e;
- if (4 & t && 'object' == typeof e && e && e.__esModule) return e;
- var n = Object.create(null);
- if (
- (a.r(n),
- Object.defineProperty(n, 'default', { enumerable: !0, value: e }),
- 2 & t && 'string' != typeof e)
- )
- for (var s in e)
- a.d(
- n,
- s,
- function(t) {
- return e[t];
- }.bind(null, s)
- );
- return n;
- (a.n = function(e) {
- var t =
- e && e.__esModule
- ? function() {
- return e.default;
- : function() {
- return e;
- };
- return a.d(t, 'a', t), t;
- (a.o = function(e, t) {
- return Object.prototype.hasOwnProperty.call(e, t);
- (a.p = ''),
- a((a.s = 7));
-})([
- function(e, t, a) {
- 'use strict';
- let n;
- function s() {
- return n || (n = wx.getSystemInfoSync());
- Object.defineProperty(t, '__esModule', { value: !0 }),
- (t.getSystemInfo = s),
- (t.isComponent = function(e) {
- return (
- e &&
- void 0 !== e.__wxExparserNodeId__ &&
- 'function' == typeof e.setData
- (t.isIos = c),
- (t.getCurrentPage = l),
- (t.getComponent = function(e) {
- const t = new r();
- let a = l() || {};
- if (a.selectComponent && 'function' == typeof a.selectComponent) {
- if (e) return a.selectComponent(e);
- t.warn('请传入组件ID');
- } else t.warn('该基础库暂不支持多个小程序日历组件');
- (t.uniqueArrayByDate = function(e = []) {
- let t = {},
- a = [];
- e.forEach(e => {
- t[`${e.year}-${e.month}-${e.day}`] = e;
- });
- for (let e in t) a.push(t[e]);
- return a;
- (t.delRepeatedEnableDay = function(e = [], t = []) {
- let a, n;
- if (2 === t.length) {
- const { startTimestamp: e, endTimestamp: s } = b(t);
- (a = e), (n = s);
- return d(e).filter(e => e < a || e > n);
- (t.convertEnableAreaToTimestamp = b),
- (t.converEnableDaysToTimestamp = d),
- (t.initialTasks = t.GetDate = t.Slide = t.Logger = void 0);
- class r {
- info(e) {
- console.log(
- '%cInfo: %c' + e,
- 'color:#FF0080;font-weight:bold',
- 'color: #FF509B'
- warn(e) {
- '%cWarn: %c' + e,
- 'color:#FF6600;font-weight:bold',
- 'color: #FF9933'
- tips(e) {
- '%cTips: %c' + e,
- 'color:#00B200;font-weight:bold',
- 'color: #00CC33'
- t.Logger = r;
- t.Slide = class {
- isUp(e = {}, t = {}) {
- const { startX: a, startY: n } = e,
- s = t.clientX - a;
- t.clientY - n < -60 &&
- s < 20 &&
- s > -20 &&
- ((this.slideLock = !1), !0)
- isDown(e = {}, t = {}) {
- return t.clientY - n > 60 && s < 20 && s > -20;
- isLeft(e = {}, t = {}) {
- s = t.clientX - a,
- r = t.clientY - n;
- return s < -60 && r < 20 && r > -20;
- isRight(e = {}, t = {}) {
- return s > 60 && r < 20 && r > -20;
- class o {
- newDate(e, t, a) {
- let n = `${+e}-${+t}-${+a}`;
- return c() && (n = `${+e}/${+t}/${+a}`), new Date(n);
- thisMonthDays(e, t) {
- return new Date(Date.UTC(e, t, 0)).getUTCDate();
- firstDayOfWeek(e, t) {
- return new Date(Date.UTC(e, t - 1, 1)).getUTCDay();
- dayOfWeek(e, t, a) {
- return new Date(Date.UTC(e, t - 1, a)).getUTCDay();
- todayDate() {
- const e = new Date();
- return {
- year: e.getFullYear(),
- month: e.getMonth() + 1,
- date: e.getDate()
- todayTimestamp() {
- const { year: e, month: t, date: a } = this.todayDate();
- return this.newDate(e, t, a).getTime();
- function c() {
- const e = s();
- return /iphone|ios/i.test(e.platform);
- function l() {
- const e = getCurrentPages();
- return e[e.length - 1];
- function b(e = []) {
- const t = new o(),
- a = e[0].split('-'),
- n = e[1].split('-'),
- s = new r();
- return 3 !== a.length || 3 !== n.length
- ? (s.warn('enableArea() 参数格式为: ["2018-2-1", "2018-3-1"]'), {})
- : {
- start: a,
- end: n,
- startTimestamp: t.newDate(a[0], a[1], a[2]).getTime(),
- endTimestamp: t.newDate(n[0], n[1], n[2]).getTime()
- function d(e = []) {
- const t = new r(),
- a = new o(),
- n = [];
- if ('string' != typeof e)
- return t.warn('enableDays()入参日期格式错误');
- const s = e.split('-');
- if (3 !== s.length) return t.warn('enableDays()入参日期格式错误');
- const r = a.newDate(s[0], s[1], s[2]).getTime();
- n.push(r);
- n
- t.GetDate = o;
- t.initialTasks = { flag: 'finished', tasks: [] };
- },
- Object.defineProperty(t, '__esModule', { value: !0 }), (t.default = void 0);
- var n = class {
- constructor(e) {
- this.Component = e;
- getData(e) {
- const t = this.Component.data;
- if (!e) return t;
- if (e.includes('.')) {
- return e.split('.').reduce((e, t) => e[t], t);
- return this.Component.data[e];
- setData(e, t = () => {}) {
- e && 'object' == typeof e && this.Component.setData(e, t);
- t.default = n;
- const n = {
- lunarInfo: [
- 19416,
- 19168,
- 42352,
- 21717,
- 53856,
- 55632,
- 91476,
- 22176,
- 39632,
- 21970,
- 42422,
- 42192,
- 53840,
- 119381,
- 46400,
- 54944,
- 44450,
- 38320,
- 84343,
- 18800,
- 42160,
- 46261,
- 27216,
- 27968,
- 109396,
- 11104,
- 38256,
- 21234,
- 25958,
- 54432,
- 59984,
- 28309,
- 23248,
- 100067,
- 37600,
- 116951,
- 51536,
- 120998,
- 46416,
- 107956,
- 9680,
- 37584,
- 53938,
- 43344,
- 46423,
- 27808,
- 86869,
- 19872,
- 42416,
- 83315,
- 21168,
- 43432,
- 59728,
- 27296,
- 44710,
- 43856,
- 19296,
- 43748,
- 21088,
- 62051,
- 23383,
- 38608,
- 19925,
- 19152,
- 54484,
- 54616,
- 46752,
- 103846,
- 18864,
- 43380,
- 45690,
- 44870,
- 43872,
- 19189,
- 25776,
- 29859,
- 27480,
- 21952,
- 38613,
- 51552,
- 55636,
- 55888,
- 30034,
- 43959,
- 51893,
- 46240,
- 47780,
- 44368,
- 21977,
- 19360,
- 86390,
- 43312,
- 31060,
- 23378,
- 42726,
- 42208,
- 60005,
- 54576,
- 23200,
- 30371,
- 19195,
- 118966,
- 54560,
- 56645,
- 46496,
- 22224,
- 21938,
- 42359,
- 43600,
- 111189,
- 27936,
- 44448,
- 84835,
- 37744,
- 18936,
- 92326,
- 27424,
- 108228,
- 43744,
- 41696,
- 53987,
- 54615,
- 23893,
- 42704,
- 21972,
- 21200,
- 43448,
- 46758,
- 21920,
- 43940,
- 45683,
- 26928,
- 29495,
- 84821,
- 21732,
- 53600,
- 59752,
- 55968,
- 92838,
- 43476,
- 41680,
- 53584,
- 62034,
- 54560
- ],
- solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
- Gan: ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'],
- Zhi: [
- '子',
- '丑',
- '寅',
- '卯',
- '辰',
- '巳',
- '午',
- '未',
- '申',
- '酉',
- '戌',
- '亥'
- Animals: [
- '鼠',
- '牛',
- '虎',
- '兔',
- '龙',
- '蛇',
- '马',
- '羊',
- '猴',
- '鸡',
- '狗',
- '猪'
- solarTerm: [
- '小寒',
- '大寒',
- '立春',
- '雨水',
- '惊蛰',
- '春分',
- '清明',
- '谷雨',
- '立夏',
- '小满',
- '芒种',
- '夏至',
- '小暑',
- '大暑',
- '立秋',
- '处暑',
- '白露',
- '秋分',
- '寒露',
- '霜降',
- '立冬',
- '小雪',
- '大雪',
- '冬至'
- sTermInfo: [
- '9778397bd097c36b0b6fc9274c91aa',
- '97b6b97bd19801ec9210c965cc920e',
- '97bcf97c3598082c95f8c965cc920f',
- '97bd0b06bdb0722c965ce1cfcc920f',
- 'b027097bd097c36b0b6fc9274c91aa',
- '97bcf97c359801ec95f8c965cc920f',
- '9778397bd19801ec9210c965cc920e',
- '97b6b97bd19801ec95f8c965cc920f',
- '97bd09801d98082c95f8e1cfcc920f',
- '97bd097bd097c36b0b6fc9210c8dc2',
- '9778397bd197c36c9210c9274c91aa',
- '97b6b97bd19801ec95f8c965cc920e',
- '9778397bd097c36c9210c9274c91aa',
- '97bcf97c3598082c95f8e1cfcc920f',
- '97bd097bd097c35b0b6fc920fb0722',
- '97bd097bd07f595b0b6fc920fb0722',
- '9778397bd097c36b0b6fc9210c8dc2',
- '9778397bd19801ec9210c9274c920e',
- '97bd07f5307f595b0b0bc920fb0722',
- '7f0e397bd097c36b0b6fc9210c8dc2',
- '9778397bd097c36c9210c9274c920e',
- '97bd07f1487f595b0b0bc920fb0722',
- '97bcf7f1487f595b0b0bb0b6fb0722',
- '7f0e397bd097c35b0b6fc920fb0722',
- '97bcf7f1487f531b0b0bb0b6fb0722',
- '7f0e397bd07f595b0b6fc920fb0722',
- '97b6b97bd19801ec9210c9274c920e',
- '97bcf7f0e47f531b0b0bb0b6fb0722',
- '7f0e397bd07f595b0b0bc920fb0722',
- '9778397bd097c36b0b6fc9210c91aa',
- '97b6b97bd197c36c9210c9274c920e',
- '97b6b7f0e47f531b0723b0b6fb0722',
- '7f0e37f5307f595b0b0bc920fb0722',
- '9778397bd097c36b0b70c9274c91aa',
- '97b6b7f0e47f531b0723b0b6fb0721',
- '7f0e37f1487f595b0b0bb0b6fb0722',
- '7f0e397bd097c35b0b6fc9210c8dc2',
- '7f0e27f1487f595b0b0bb0b6fb0722',
- '7f0e27f1487f531b0b0bb0b6fb0722',
- '97b6b7f0e47f531b0723b0787b0721',
- '7f0e27f0e47f531b0b0bb0b6fb0722',
- '97b6b7f0e47f149b0723b0787b0721',
- '7f0e27f0e47f531b0723b0b6fb0722',
- '977837f0e37f149b0723b0787b0721',
- '7f07e7f0e47f531b0723b0b6fb0722',
- '977837f0e37f14998082b0787b0721',
- '7f07e7f0e47f531b0723b0b6fb0721',
- '977837f0e37f14998082b0787b06bd',
- '7f07e7f0e47f149b0723b0787b0721',
- '977837f0e37f14998082b0723b06bd',
- '7f07e7f0e37f149b0723b0787b0721',
- '977837f0e37f14898082b0723b02d5',
- '7ec967f0e37f14998082b0787b0721',
- '7f0e37f0e37f14898082b0723b02d5',
- '7f0e37f1487f531b0b0bb0b6fb0722',
- '7ec967f0e37f14998082b0787b06bd',
- '7f0e37f0e37f14898082b072297c35',
- '7f0e37f0e366aa89801eb072297c35',
- '7ec967f0e37f14998082b0723b06bd',
- '7f07e7f0e37f14998083b0787b0721',
- '7ec967f0e37f14898082b0723b02d5',
- '7f07e7f0e37f14998082b0787b0721',
- '7f0e36665b66aa89801e9808297c35',
- '665f67f0e37f14898082b0723b02d5',
- '7f0e36665b66a449801e9808297c35',
- '665f67f0e37f14898082b072297c35',
- '7f0e26665b66a449801e9808297c35',
- '665f67f0e37f1489801eb072297c35',
- '7f0e27f1487f531b0b0bb0b6fb0722'
- nStr1: [
- '日',
- '一',
- '二',
- '三',
- '四',
- '五',
- '六',
- '七',
- '八',
- '九',
- '十'
- nStr2: ['初', '十', '廿', '卅'],
- nStr3: [
- '正',
- '十',
- '冬',
- '腊'
- lYearDays: function(e) {
- let t,
- a = 348;
- for (t = 32768; t > 8; t >>= 1)
- a += n.lunarInfo[e - 1900] & t ? 1 : 0;
- return a + n.leapDays(e);
- leapMonth: function(e) {
- return 15 & n.lunarInfo[e - 1900];
- leapDays: function(e) {
- return n.leapMonth(e) ? (65536 & n.lunarInfo[e - 1900] ? 30 : 29) : 0;
- monthDays: function(e, t) {
- return t > 12 || t < 1
- ? -1
- : n.lunarInfo[e - 1900] & (65536 >> t)
- ? 30
- : 29;
- solarDays: function(e, t) {
- if (t > 12 || t < 1) return -1;
- const a = t - 1;
- return 1 == +a
- ? (e % 4 == 0 && e % 100 != 0) || e % 400 == 0
- ? 29
- : 28
- : n.solarMonth[a];
- toGanZhiYear: function(e) {
- let t = (e - 3) % 10,
- a = (e - 3) % 12;
- 0 == +t && (t = 10),
- 0 == +a && (a = 12),
- n.Gan[t - 1] + n.Zhi[a - 1]
- toAstro: function(e, t) {
- '魔羯水瓶双鱼白羊金牛双子巨蟹狮子处女天秤天蝎射手魔羯'.substr(
- 2 * e -
- (t < [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22][e - 1]
- ? 2
- : 0),
- 2
- ) + '座'
- toGanZhi: function(e) {
- return n.Gan[e % 10] + n.Zhi[e % 12];
- getTerm: function(e, t) {
- if (e < 1900 || e > 2100) return -1;
- if (t < 1 || t > 24) return -1;
- const a = n.sTermInfo[e - 1900],
- s = [
- parseInt('0x' + a.substr(0, 5)).toString(),
- parseInt('0x' + a.substr(5, 5)).toString(),
- parseInt('0x' + a.substr(10, 5)).toString(),
- parseInt('0x' + a.substr(15, 5)).toString(),
- parseInt('0x' + a.substr(20, 5)).toString(),
- parseInt('0x' + a.substr(25, 5)).toString()
- r = [
- s[0].substr(0, 1),
- s[0].substr(1, 2),
- s[0].substr(3, 1),
- s[0].substr(4, 2),
- s[1].substr(0, 1),
- s[1].substr(1, 2),
- s[1].substr(3, 1),
- s[1].substr(4, 2),
- s[2].substr(0, 1),
- s[2].substr(1, 2),
- s[2].substr(3, 1),
- s[2].substr(4, 2),
- s[3].substr(0, 1),
- s[3].substr(1, 2),
- s[3].substr(3, 1),
- s[3].substr(4, 2),
- s[4].substr(0, 1),
- s[4].substr(1, 2),
- s[4].substr(3, 1),
- s[4].substr(4, 2),
- s[5].substr(0, 1),
- s[5].substr(1, 2),
- s[5].substr(3, 1),
- s[5].substr(4, 2)
- ];
- return parseInt(r[t - 1]);
- toChinaMonth: function(e) {
- if (e > 12 || e < 1) return -1;
- let t = n.nStr3[e - 1];
- return (t += '月');
- toChinaDay: function(e) {
- let t;
- switch (e) {
- case 10:
- t = '初十';
- break;
- case 20:
- t = '二十';
- case 30:
- t = '三十';
- default:
- (t = n.nStr2[Math.floor(e / 10)]), (t += n.nStr1[e % 10]);
- return t;
- getAnimal: function(e) {
- return n.Animals[(e - 4) % 12];
- solar2lunar: function(e, t, a) {
- if (1900 == +e && 1 == +t && +a < 31) return -1;
- let s,
- r,
- o = 0,
- c = 0;
- (e = (s = e
- ? new Date(e, parseInt(t) - 1, a)
- : new Date()).getFullYear()),
- (t = s.getMonth() + 1),
- (a = s.getDate());
- let l =
- (Date.UTC(s.getFullYear(), s.getMonth(), s.getDate()) -
- Date.UTC(1900, 0, 31)) /
- 864e5;
- for (r = 1900; r < 2101 && l > 0; r++) l -= c = n.lYearDays(r);
- l < 0 && ((l += c), r--);
- const b = new Date();
- let d = !1;
- b.getFullYear() === +e &&
- b.getMonth() + 1 === +t &&
- b.getDate() === +a &&
- (d = !0);
- let f = s.getDay();
- const i = n.nStr1[f];
- 0 == +f && (f = 7);
- const h = r;
- o = n.leapMonth(r);
- let u = !1;
- for (r = 1; r < 13 && l > 0; r++)
- o > 0 && r === o + 1 && !1 === u
- ? (--r, (u = !0), (c = n.leapDays(h)))
- : (c = n.monthDays(h, r)),
- !0 === u && r === o + 1 && (u = !1),
- (l -= c);
- 0 === l && o > 0 && r === o + 1 && (u ? (u = !1) : ((u = !0), --r)),
- l < 0 && ((l += c), --r);
- const y = r,
- m = l + 1,
- D = t - 1,
- g = n.toGanZhiYear(h),
- p = n.getTerm(e, 2 * t - 1),
- w = n.getTerm(e, 2 * t);
- let C = n.toGanZhi(12 * (e - 1900) + t + 11);
- a >= p && (C = n.toGanZhi(12 * (e - 1900) + t + 12));
- let T = !1,
- M = null;
- +p === a && ((T = !0), (M = n.solarTerm[2 * t - 2])),
- +w === a && ((T = !0), (M = n.solarTerm[2 * t - 1]));
- const k = Date.UTC(e, D, 1, 0, 0, 0, 0) / 864e5 + 25567 + 10,
- _ = n.toGanZhi(k + a - 1),
- L = n.toAstro(t, a);
- lYear: h,
- lMonth: y,
- lDay: m,
- Animal: n.getAnimal(h),
- IMonthCn: (u ? '闰' : '') + n.toChinaMonth(y),
- IDayCn: n.toChinaDay(m),
- cYear: e,
- cMonth: t,
- cDay: a,
- gzYear: g,
- gzMonth: C,
- gzDay: _,
- isToday: d,
- isLeap: u,
- nWeek: f,
- ncWeek: '星期' + i,
- isTerm: T,
- Term: M,
- astro: L
- lunar2solar: function(e, t, a, s) {
- s = !!s;
- const r = n.leapMonth(e);
- if (s && r !== t) return -1;
- (2100 == +e && 12 == +t && +a > 1) ||
- (1900 == +e && 1 == +t && +a < 31)
- return -1;
- const o = n.monthDays(e, t);
- let c = o;
- if ((s && (c = n.leapDays(e, t)), e < 1900 || e > 2100 || a > c))
- let l = 0;
- for (let t = 1900; t < e; t++) l += n.lYearDays(t);
- let b = 0,
- d = !1;
- for (let a = 1; a < t; a++)
- (b = n.leapMonth(e)),
- d || (b <= a && b > 0 && ((l += n.leapDays(e)), (d = !0))),
- (l += n.monthDays(e, a));
- s && (l += o);
- const f = Date.UTC(1900, 1, 30, 0, 0, 0),
- i = new Date(864e5 * (l + a - 31) + f),
- h = i.getUTCFullYear(),
- u = i.getUTCMonth() + 1,
- y = i.getUTCDate();
- return n.solar2lunar(h, u, y);
- {
- Gan: s,
- Zhi: r,
- nStr1: o,
- nStr2: c,
- nStr3: l,
- Animals: b,
- solarTerm: d,
- lunarInfo: f,
- sTermInfo: i,
- solarMonth: h,
- ...u
- } = n;
- var y = u;
- t.default = y;
- class n {
- getCalendarConfig() {
- return this.Component && this.Component.config
- ? this.Component.config
- : {};
- setCalendarConfig(e, t) {
- this.Component &&
- this.Component.config &&
- (this.Component.config[e] = t);
- t.default = e => new n(e);
- var n = l(a(1)),
- s = l(a(5)),
- r = l(a(3)),
- o = l(a(2)),
- c = a(0);
- function l(e) {
- return e && e.__esModule ? e : { default: e };
- const b = new c.GetDate(),
- d = new c.Logger();
- class f extends n.default {
- super(e),
- (this.Component = e),
- (this.getCalendarConfig = (0, r.default)(
- this.Component
- ).getCalendarConfig);
- switchWeek(e, t) {
- return new Promise((a, n) => {
- if ((0, r.default)(this.Component).getCalendarConfig().multi)
- return d.warn('多选模式不能切换周月视图');
- const { selectedDay: o = [], curYear: c, curMonth: l } = this.getData(
- 'calendar'
- if (!o.length) return this.__tipsWhenCanNotSwtich();
- const b = o[0];
- if ('week' === e) {
- if (this.Component.weekMode) return;
- const e = t || b,
- { year: s, month: r } = e;
- if (c !== s || l !== r) return this.__tipsWhenCanNotSwtich();
- (this.Component.weekMode = !0),
- this.setData({ 'calendar.weekMode': !0 }),
- this.jump(e)
- .then(a)
- .catch(n);
- } else
- (this.Component.weekMode = !1),
- this.setData({ 'calendar.weekMode': !1 }),
- (0, s.default)(this.Component)
- .renderCalendar(c, l, t)
- updateCurrYearAndMonth(e) {
- let { days: t, curYear: a, curMonth: n } = this.getData('calendar');
- const { month: s } = t[0],
- { month: r } = t[t.length - 1],
- o = b.thisMonthDays(a, n),
- c = t[t.length - 1],
- l = t[0];
- (c.day + 7 > o || (n === s && s !== r)) && 'next' === e
- ? (n += 1) > 12 && ((a += 1), (n = 1))
- : (+l.day <= 7 || (n === r && s !== r)) &&
- 'prev' === e &&
- (n -= 1) <= 0 &&
- ((a -= 1), (n = 12)),
- { Uyear: a, Umonth: n }
- calculateLastDay() {
- const { days: e, curYear: t, curMonth: a } = this.getData('calendar');
- lastDayInThisWeek: e[e.length - 1].day,
- lastDayInThisMonth: b.thisMonthDays(t, a)
- calculateFirstDay() {
- const { days: e } = this.getData('calendar');
- return { firstDayInThisWeek: e[0].day };
- firstWeekInMonth(e, t, a) {
- let n = b.dayOfWeek(e, t, 1);
- const [, r] = [0, 7 - n];
- let o = this.getData('calendar.days') || [];
- this.Component.weekMode &&
- (o = (0, s.default)(this.Component).buildDate(e, t)),
- o.slice(0, a ? r + 1 : r)
- lastWeekInMonth(e, t, a) {
- const n = b.thisMonthDays(e, t),
- r = b.dayOfWeek(e, t, n),
- [o, c] = [n - r, n];
- let l = this.getData('calendar.days') || [];
- (l = (0, s.default)(this.Component).buildDate(e, t)),
- l.slice(a ? o : o - 1, c)
- initSelectedDay(e) {
- const t = [...e],
- selectedDay: a = [],
- todoLabels: n = [],
- showLabelAlways: s
- } = this.getData('calendar'),
- r = a.map(e => `${+e.year}-${+e.month}-${+e.day}`),
- c = n.map(e => `${+e.year}-${+e.month}-${+e.day}`),
- l = this.getCalendarConfig();
- t.forEach(e => {
- r.includes(`${+e.year}-${+e.month}-${+e.day}`)
- ? (e.choosed = !0)
- : (e.choosed = !1);
- const t = c.indexOf(`${+e.year}-${+e.month}-${+e.day}`);
- if (-1 !== t) {
- e.showTodoLabel = !!s || !e.choosed;
- const a = n[t] || {};
- e.showTodoLabel && a.todoText && (e.todoText = a.todoText);
- (l.showLunar &&
- (e.lunar = o.default.solar2lunar(+e.year, +e.month, +e.day)),
- l.highlightToday)
- ) {
- const t = b.todayDate(),
- a =
- +t.year == +e.year &&
- +t.month == +e.month &&
- +e.day == +t.date;
- e.isToday = a;
- t
- setEnableAreaOnWeekMode(e) {
- let {
- todayTimestamp: t,
- enableAreaTimestamp: a = [],
- enableDaysTimestamp: n = []
- } = this.getData('calendar');
- const s = b.newDate(e.year, e.month, e.day).getTime();
- let o = !1;
- a.length
- ? (+a[0] > +s || +s > +a[1]) && !n.includes(+s) && (o = !0)
- : n.length && !n.includes(+s) && (o = !0),
- o && ((e.disable = !0), (e.choosed = !1));
- const { disablePastDay: c } =
- (0, r.default)(this.Component).getCalendarConfig() || {};
- c && s - t < 0 && !e.disable && (e.disable = !0);
- calculateNextWeekDays() {
- lastDayInThisWeek: e,
- lastDayInThisMonth: t
- } = this.calculateLastDay(),
- { curYear: a, curMonth: n } = this.getData('calendar'),
- s = [];
- if (t - e >= 7) {
- const { Uyear: t, Umonth: r } = this.updateCurrYearAndMonth('next');
- (a = t), (n = r);
- for (let t = e + 1; t <= e + 7; t++)
- s.push({ year: a, month: n, day: t, week: b.dayOfWeek(a, n, t) });
- } else {
- for (let r = e + 1; r <= t; r++)
- s.push({ year: a, month: n, day: r, week: b.dayOfWeek(a, n, r) });
- const { Uyear: r, Umonth: o } = this.updateCurrYearAndMonth('next');
- (a = r), (n = o);
- for (let r = 1; r <= 7 - (t - e); r++)
- (s = this.initSelectedDay(s)),
- this.setEnableAreaOnWeekMode(s),
- this.setData({
- 'calendar.curYear': a,
- 'calendar.curMonth': n,
- 'calendar.days': s
- calculatePrevWeekDays() {
- let { firstDayInThisWeek: e } = this.calculateFirstDay(),
- { curYear: t, curMonth: a } = this.getData('calendar'),
- if (e - 7 > 0) {
- const { Uyear: s, Umonth: r } = this.updateCurrYearAndMonth('prev');
- (t = s), (a = r);
- for (let s = e - 7; s < e; s++)
- n.push({ year: t, month: a, day: s, week: b.dayOfWeek(t, a, s) });
- let s = [];
- for (let n = 1; n < e; n++)
- s.push({ year: t, month: a, day: n, week: b.dayOfWeek(t, a, n) });
- const { Uyear: r, Umonth: o } = this.updateCurrYearAndMonth('prev');
- (t = r), (a = o);
- const c = b.thisMonthDays(t, a);
- for (let s = c - Math.abs(e - 7); s <= c; s++)
- n = n.concat(s);
- (n = this.initSelectedDay(n)),
- this.setEnableAreaOnWeekMode(n),
- 'calendar.curYear': t,
- 'calendar.curMonth': a,
- 'calendar.days': n
- calculateDatesWhenJump(
- { year: e, month: t, day: a },
- { firstWeekDays: n, lastWeekDays: s },
- r
- const o = this.__dateIsInWeek({ year: e, month: t, day: a }, n),
- c = this.__dateIsInWeek({ year: e, month: t, day: a }, s);
- let l = [];
- return (l = o
- ? this.__calculateDatesWhenInFirstWeek(n, r)
- : c
- ? this.__calculateDatesWhenInLastWeek(s, r)
- : this.__calculateDates({ year: e, month: t, day: a }));
- jump({ year: e, month: t, day: a }) {
- return new Promise(n => {
- if (!a) return;
- const s = 'Mon' === this.getCalendarConfig().firstDayOfWeek,
- r = this.firstWeekInMonth(e, t, s);
- let o = this.lastWeekInMonth(e, t, s);
- const c = this.calculateDatesWhenJump(
- { firstWeekDays: r, lastWeekDays: o },
- s
- c.map(n => {
- +n.year == +e && +n.month == +t && +n.day == +a && (n.choosed = !0);
- this.initSelectedDay(c),
- this.setEnableAreaOnWeekMode(c),
- this.setData(
- 'calendar.days': c,
- 'calendar.curYear': e,
- 'calendar.curMonth': t,
- 'calendar.empytGrids': [],
- 'calendar.lastEmptyGrids': []
- __calculateDatesWhenInFirstWeek(e, t) {
- const a = [...e];
- if (a.length < 7) {
- let e,
- { year: t, month: n } = a[0],
- s = 7 - a.length;
- for (
- n > 1
- ? ((n -= 1), (e = b.thisMonthDays(t, n)))
- : ((n = 12), (t -= 1), (e = b.thisMonthDays(t, n)));
- s;
+import Week from './func/week'
+import { Logger, Slide, GetDate, initialTasks } from './func/utils'
+import initCalendar, {
+ jump,
+ getCurrentYM,
+ whenChangeDate,
+ renderCalendar,
+ whenMulitSelect,
+ whenSingleSelect,
+ whenChooseArea,
+ getCalendarDates
+} from './main.js'
- a.unshift({
- year: t,
- month: n,
- day: e,
- week: b.dayOfWeek(t, n, e)
- (e -= 1),
- (s -= 1);
- __calculateDatesWhenInLastWeek(e, t) {
- if (t && a.length < 7) {
- let { year: e, month: t } = a[0],
- n = 7 - a.length,
- s = 1;
- for (t > 11 ? ((t = 1), (e += 1)) : (t += 1); n; )
- a.push({ year: e, month: t, day: s, week: b.dayOfWeek(e, t, s) }),
- (s += 1),
- (n -= 1);
- __calculateDates({ year: e, month: t, day: a }, n) {
- const r = b.dayOfWeek(e, t, a);
- let o = [a - r, a + (6 - r)];
- n && (o = [a + 1 - r, a + (7 - r)]),
- .buildDate(e, t)
- .slice(o[0] - 1, o[1])
- __dateIsInWeek(e, t) {
- return t.find(
- t => +t.year == +e.year && +t.month == +e.month && +t.day == +e.day
- __tipsWhenCanNotSwtich() {
- d.info(
- '当前月份未选中日期下切换为周视图,不能明确该展示哪一周的日期,故此情况不允许切换'
- t.default = e => new f(e);
+const slide = new Slide()
+Component({
+ options: {
+ styleIsolation: 'apply-shared',
+ multipleSlots: true // 在组件定义时的选项中启用多slot支持
- var n = c(a(6)),
- s = c(a(1)),
- r = c(a(2)),
- o = a(0);
- function c(e) {
+ properties: {
+ type: Object,
+ value: {}
- const l = new o.GetDate();
- class b extends s.default {
- super(e), (this.Component = e);
- return this.Component.config;
- renderCalendar(e, t, a) {
- return new Promise(s => {
- this.calculateEmptyGrids(e, t), this.calculateDays(e, t, a);
- const { todoLabels: r } = this.getData('calendar') || {};
- r &&
- r instanceof Array &&
- r.find(e => +e.month == +t) &&
- (0, n.default)(this.Component).setTodoLabels(),
- this.Component.firstRender || s();
- calculateEmptyGrids(e, t) {
- this.calculatePrevMonthGrids(e, t), this.calculateNextMonthGrids(e, t);
- calculatePrevMonthGrids(e, t) {
- let a = [];
- const n = l.thisMonthDays(e, t - 1);
- let s = l.firstDayOfWeek(e, t);
- const o = this.getCalendarConfig() || {};
- ('Mon' === o.firstDayOfWeek && (0 === s ? (s = 6) : (s -= 1)), s > 0)
- const c = n - s,
- { onlyShowCurrentMonth: l } = o,
- { showLunar: b } = this.getCalendarConfig();
- for (let s = n; s > c; s--)
- l
- ? a.push('')
- : a.push({
- day: s,
- lunar: b ? r.default.solar2lunar(e, t - 1, s) : null
- this.setData({ 'calendar.empytGrids': a.reverse() });
- } else this.setData({ 'calendar.empytGrids': null });
- calculateExtraEmptyDate(e, t, a) {
- let n = 0;
- if (2 == +t) {
- n += 7;
- let s = l.dayOfWeek(e, t, 1);
- 'Mon' === a.firstDayOfWeek
- ? 1 == +s && (n += 7)
- : 0 == +s && (n += 7);
- ? 0 !== s && s < 6 && (n += 7)
- : s < 6 && (n += 7);
- calculateNextMonthGrids(e, t) {
- const n = l.thisMonthDays(e, t);
- let s = l.dayOfWeek(e, t, n);
- 'Mon' === o.firstDayOfWeek && (0 === s ? (s = 6) : (s -= 1));
- let c = 7 - (s + 1);
- const { onlyShowCurrentMonth: b, showLunar: d } = o;
- b || (c += this.calculateExtraEmptyDate(e, t, o));
- for (let n = 1; n <= c; n++)
- b
- day: n,
- lunar: d ? r.default.solar2lunar(e, t + 1, n) : null
- this.setData({ 'calendar.lastEmptyGrids': a });
- setSelectedDay(e, t, a) {
- let n = [];
- const s = this.getCalendarConfig();
- if (s.noDefault) (n = []), (s.noDefault = !1);
- else {
- const s = this.getData('calendar') || {},
- { showLunar: o } = this.getCalendarConfig();
- n = a
- ? [
- year: e,
- month: t,
- day: a,
- choosed: !0,
- week: l.dayOfWeek(e, t, a),
- lunar: o ? r.default.solar2lunar(e, t, a) : null
- ]
- : s.selectedDay;
- buildDate(e, t) {
- const a = l.todayDate(),
- n = l.thisMonthDays(e, t),
- for (let r = 1; r <= n; r++) {
- const n = +a.year == +e && +a.month == +t && r === +a.date,
- o = this.getCalendarConfig();
- s.push({
- day: r,
- choosed: !1,
- week: l.dayOfWeek(e, t, r),
- isToday: n && o.highlightToday
- return s;
- calculateDays(e, t, a) {
- const { todayTimestamp: s, disableDays: o = [] } = this.getData(
- n = this.buildDate(e, t);
- const c = this.setSelectedDay(e, t, a),
- b = c.map(e => `${+e.year}-${+e.month}-${+e.day}`),
- d = o.map(e => `${+e.year}-${+e.month}-${+e.day}`);
- n.forEach(e => {
- const t = `${+e.year}-${+e.month}-${+e.day}`;
- b.includes(t) && (e.choosed = !0), d.includes(t) && (e.disable = !0);
- const a = l.newDate(e.year, e.month, e.day).getTime(),
- showLunar: n,
- disablePastDay: o,
- disableLaterDay: c
- } = this.getCalendarConfig();
- n && (e.lunar = r.default.solar2lunar(+e.year, +e.month, +e.day));
- let f = !1;
- o
- ? (f = o && a - s < 0 && !e.disable)
- : c && (f = c && a - s > 0 && !e.disable),
- (f || this.__isDisable(a)) && ((e.disable = !0), (e.choosed = !1));
- this.setData({ 'calendar.days': n, 'calendar.selectedDay': c || [] });
- __isDisable(e) {
- const {
- enableArea: t = [],
- enableDays: a = [],
- enableAreaTimestamp: n = []
- let s = !1,
- r = (0, o.converEnableDaysToTimestamp)(a);
- t.length && (r = (0, o.delRepeatedEnableDay)(a, t)),
- n.length
- ? (+n[0] > +e || +e > +n[1]) && !r.includes(+e) && (s = !0)
- : r.length && !r.includes(+e) && (s = !0),
- t.default = e => new b(e);
- var n,
- s = (n = a(1)) && n.__esModule ? n : { default: n },
- r = a(0);
- const o = new r.Logger();
- class c extends s.default {
- setTodoLabels(e) {
- e && (this.Component.todoConfig = e);
- const t = this.getData('calendar');
- if (!t || !t.days) return o.warn('请等待日历初始化完成后再调用该方法');
- const a = [...t.days],
- { curYear: n, curMonth: s } = t,
- circle: c,
- dotColor: l = '',
- pos: b = 'bottom',
- showLabelAlways: d,
- days: f = []
- } = e || this.Component.todoConfig || {},
- { todoLabels: i = [], todoLabelPos: h, todoLabelColor: u } = t,
- y = this.getTodoLabels({ year: n, month: s });
- let m = f.filter(e => +e.year == +n && +e.month == +s);
- this.Component.weekMode && (m = f);
- const D = y.concat(m);
- for (let e of D) {
- (t = this.Component.weekMode
- ? a.find(
- t =>
- +e.year == +t.year && +e.month == +t.month && +e.day == +t.day
- : a[e.day - 1]) &&
- ((t.showTodoLabel = !!d || !t.choosed),
- t.showTodoLabel && e.todoText && (t.todoText = e.todoText));
- const g = {
- 'calendar.days': a,
- 'calendar.todoLabels': (0, r.uniqueArrayByDate)(f.concat(i))
- c ||
- (b && b !== h && (g['calendar.todoLabelPos'] = b),
- l && l !== u && (g['calendar.todoLabelColor'] = l)),
- (g['calendar.todoLabelCircle'] = c || !1),
- (g['calendar.showLabelAlways'] = d || !1),
- this.setData(g);
- deleteTodoLabels(e) {
- if (!(e instanceof Array && e.length)) return;
- const t = this.filterTodos(e),
- { days: a, curYear: n, curMonth: s } = this.getData('calendar'),
- r = t.filter(e => n === +e.year && s === +e.month);
- a.forEach(e => {
- e.showTodoLabel = !1;
- r.forEach(e => {
- a[e.day - 1].showTodoLabel = !a[e.day - 1].choosed;
- this.setData({ 'calendar.days': a, 'calendar.todoLabels': t });
- clearTodoLabels() {
- const { days: e = [] } = this.getData('calendar'),
- t = [].concat(e);
- this.setData({ 'calendar.days': t, 'calendar.todoLabels': [] });
- getTodoLabels(e) {
- const { todoLabels: t = [] } = this.getData('calendar');
- if (e) {
- const { year: a, month: n } = e;
- return t.filter(e => +e.year == +a && +e.month == +n);
- filterTodos(e) {
- const t = this.getData('calendar.todoLabels') || [],
- a = e.map(e => `${e.year}-${e.month}-${e.day}`);
- return t.filter(e => !a.includes(`${e.year}-${e.month}-${e.day}`));
- showTodoLabels(e, t, a) {
- if (this.Component.weekMode)
- t.forEach((n, s) => {
- if (+n.day == +e.day) {
- const n = t[s];
- (n.hasTodo = !0),
- (n.todoText = e.todoText),
- a &&
- a.length &&
- +a[0].day == +e.day &&
- (n.showTodoLabel = !0);
- const n = t[e.day - 1];
- if (!n) return;
- (t[a[0].day - 1].showTodoLabel = !0);
+ data: {
+ handleMap: {
+ prev_year: 'chooseYear',
+ prev_month: 'chooseMonth',
+ next_month: 'chooseMonth',
+ next_year: 'chooseYear'
- t.default = e => new c(e);
- s = (n = a(4)) && n.__esModule ? n : { default: n },
- r = a(0),
- o = (function(e) {
- if (e && e.__esModule) return e;
- if (null != e)
- for (var a in e)
- if (Object.prototype.hasOwnProperty.call(e, a)) {
- var n =
- Object.defineProperty && Object.getOwnPropertyDescriptor
- ? Object.getOwnPropertyDescriptor(e, a)
- n.get || n.set ? Object.defineProperty(t, a, n) : (t[a] = e[a]);
- return (t.default = e), t;
- })(a(8));
- const c = new r.Slide(),
- l = new r.Logger();
- Component({
- options: { multipleSlots: !0 },
- properties: { calendarConfig: { type: Object, value: {} } },
- data: {
- handleMap: {
- prev_year: 'chooseYear',
- prev_month: 'chooseMonth',
- next_month: 'chooseMonth',
- next_year: 'chooseYear'
- lifetimes: {
- attached: function() {
- this.initComp();
- methods: {
- initComp() {
- const e = this.properties.calendarConfig || {};
- this.setTheme(e.theme), (0, o.default)(this, e);
- setTheme(e) {
- this.setData({ 'calendarConfig.theme': e || 'default' });
- chooseDate(e) {
- const { type: t } = e.currentTarget.dataset;
- t && this[this.data.handleMap[t]](t);
- chooseYear(e) {
- const { curYear: t, curMonth: a } = this.data.calendar;
- if (!t || !a) return l.warn('异常:未获取到当前年月');
- if (this.weekMode) return console.warn('周视图下不支持点击切换年月');
- let n = +t,
- s = +a;
- 'prev_year' === e ? (n -= 1) : 'next_year' === e && (n += 1),
- this.render(t, a, n, s);
- chooseMonth(e) {
- 'prev_month' === e
- ? (s -= 1) < 1 && ((n -= 1), (s = 12))
- : 'next_month' === e && (s += 1) > 12 && ((n += 1), (s = 1)),
- render(e, t, a, n) {
- o.whenChangeDate.call(this, {
- curYear: e,
- curMonth: t,
- newYear: a,
- newMonth: n
- this.setData({ 'calendar.curYear': a, 'calendar.curMonth': n }),
- o.renderCalendar.call(this, a, n);
- tapDayItem(e) {
- const { idx: t, disable: a } = e.currentTarget.dataset;
- if (a) return;
- const n = this.config || {},
- { multi: s } = n;
- ? o.whenMulitSelect.call(this, t)
- : o.whenSingleSelect.call(this, t);
- doubleClickToToday() {
- if (!this.config.multi && !this.weekMode)
- (void 0 === this.count ? (this.count = 1) : (this.count += 1),
- this.lastClick)
- new Date().getTime() - this.lastClick < 500 &&
- this.count >= 2 &&
- o.jump.call(this),
- (this.count = void 0),
- (this.lastClick = void 0);
- } else this.lastClick = new Date().getTime();
- calendarTouchstart(e) {
- const t = e.touches[0],
- a = t.clientX,
- n = t.clientY;
- (this.slideLock = !0),
- this.setData({ 'gesture.startX': a, 'gesture.startY': n });
- calendarTouchmove(e) {
- const { gesture: t } = this.data;
- if (this.slideLock) {
- if (c.isLeft(t, e.touches[0])) {
- if ((this.setData({ 'calendar.leftSwipe': 1 }), this.weekMode))
- (this.slideLock = !1),
- (this.currentDates = (0, o.getCalendarDates)()),
- (this.currentYM = (0, o.getCurrentYM)()),
- (0, s.default)(this).calculateNextWeekDays(),
- this.onSwipeCalendar('next_week'),
- void this.onWeekChange('next_week')
- this.chooseMonth('next_month'),
- this.onSwipeCalendar('next_month'),
- (this.slideLock = !1);
- if (c.isRight(t, e.touches[0])) {
- if ((this.setData({ 'calendar.rightSwipe': 1 }), this.weekMode))
- (0, s.default)(this).calculatePrevWeekDays(),
- this.onSwipeCalendar('prev_week'),
- void this.onWeekChange('prev_week')
- this.chooseMonth('prev_month'),
- this.onSwipeCalendar('prev_month'),
- calendarTouchend(e) {
- this.setData({ 'calendar.leftSwipe': 0, 'calendar.rightSwipe': 0 });
- onSwipeCalendar(e) {
- this.triggerEvent('onSwipe', { directionType: e });
- onWeekChange(e) {
- this.triggerEvent('whenChangeWeek', {
- current: {
- currentYM: this.currentYM,
- dates: [...this.currentDates]
- next: {
- currentYM: (0, o.getCurrentYM)(),
- dates: (0, o.getCalendarDates)()
- directionType: e
- (this.currentDates = null),
- (this.currentYM = null);
- (t.getCurrentYM = L),
- (t.getSelectedDay = v),
- (t.cancelAllSelectedDay = W),
- (t.jump = S),
- (t.setTodoLabels = $),
- (t.deleteTodoLabels = Y),
- (t.clearTodoLabels = O),
- (t.getTodoLabels = x),
- (t.disableDay = A),
- (t.enableArea = E),
- (t.enableDays = I),
- (t.setSelectedDays = P),
- (t.getCalendarConfig = j),
- (t.setCalendarConfig = G),
- (t.getCalendarDates = U),
- (t.switchView = F),
- (t.default = t.calculateNextWeekDays = t.calculatePrevWeekDays = t.whenMulitSelect = t.whenSingleSelect = t.renderCalendar = t.whenChangeDate = void 0);
- var n = f(a(9)),
- s = f(a(4)),
- r = f(a(6)),
- o = f(a(1)),
- c = f(a(5)),
- l = f(a(3)),
- b = f(a(2)),
- d = a(0);
- function f(e) {
- let i = {},
- h = new d.Logger(),
- u = new d.GetDate(),
- y = null;
- function m(e) {
- e && (i = (0, d.getComponent)(e));
- function D(e, t) {
- return m(t), (y = new o.default(i)).getData(e);
+ lifetimes: {
+ attached: function() {
+ this.initComp()
+ detached: function() {
+ initialTasks.flag = 'finished'
+ initialTasks.tasks.length = 0
- function g(e, t = () => {}) {
- return new o.default(i).setData(e, t);
- const p = {
- (0, d.isComponent)(this) && (i = this),
- new Promise((n, s) => {
- (0, c.default)(i)
- .renderCalendar(e, t, a)
- .then(() => {
- !(function(e) {
- e.calendar = {
- jump: S,
- switchView: F,
- disableDay: A,
- enableArea: E,
- enableDays: I,
- getCurrentYM: L,
- getSelectedDay: v,
- cancelAllSelectedDay: W,
- setTodoLabels: $,
- getTodoLabels: x,
- deleteTodoLabels: Y,
- clearTodoLabels: O,
- setSelectedDays: P,
- getCalendarConfig: j,
- setCalendarConfig: G,
- getCalendarDates: U
- })((0, d.getCurrentPage)()),
- i.triggerEvent('afterCalendarRender', i),
- (i.firstRender = !0),
- (d.initialTasks.flag = 'finished'),
- d.initialTasks.tasks.length &&
- d.initialTasks.tasks.shift()(),
- n();
- })
- whenChangeDate({ curYear: e, curMonth: t, newYear: a, newMonth: n }) {
- i.triggerEvent('whenChangeMonth', {
- current: { year: e, month: t },
- next: { year: a, month: n }
- whenMulitSelect(e) {
- (0, d.isComponent)(this) && (i = this);
- const { calendar: t = {} } = D(),
- { days: a, todoLabels: n } = t;
- let { selectedDay: s = [] } = t;
- const r = a[e];
- if (r) {
- if (((r.choosed = !r.choosed), r.choosed)) {
- r.cancel = !1;
- const { showLabelAlways: e } = D('calendar');
- e && r.showTodoLabel
- ? (r.showTodoLabel = !0)
- : (r.showTodoLabel = !1),
- s.push(r);
- r.cancel = !0;
- const e = `${r.year}-${r.month}-${r.day}`;
- (s = s.filter(t => e !== `${t.year}-${t.month}-${t.day}`)),
- n &&
- n.forEach(t => {
- e === `${t.year}-${t.month}-${t.day}` &&
- (r.showTodoLabel = !0);
- if ((0, l.default)(i).getCalendarConfig().takeoverTap)
- return i.triggerEvent('onTapDay', r);
- g({ 'calendar.days': a, 'calendar.selectedDay': s }),
- p.afterTapDay(r, s);
- whenSingleSelect(e) {
- { days: a, selectedDay: n = [], todoLabels: s } = t;
- let o = [];
- const c = a[e];
- if (!c) return;
- const b = (n[0] || {}).day,
- f = (b && a[b - 1]) || {},
- { month: h, year: u } = a[0] || {},
- y = (0, l.default)(i).getCalendarConfig();
- if (y.takeoverTap) return i.triggerEvent('onTapDay', c);
- if ((p.afterTapDay(c), !y.inverse && f.day === c.day)) return;
- i.weekMode &&
- a.forEach((e, t) => {
- e.day === b && (a[t].choosed = !1);
- s && (o = s.filter(e => +e.year === u && +e.month === h)),
- (0, r.default)(i).showTodoLabels(o, a, n);
- const m = { 'calendar.days': a };
- f.day !== c.day
- ? ((f.choosed = !1),
- (c.choosed = !0),
- (t.showLabelAlways && c.showTodoLabel) || (c.showTodoLabel = !1),
- (m['calendar.selectedDay'] = [c]))
- : y.inverse &&
- ((c.choosed = !c.choosed),
- c.choosed &&
- (c.showTodoLabel && t.showLabelAlways
- ? (c.showTodoLabel = !0)
- : (c.showTodoLabel = !1)),
- (m['calendar.selectedDay'] = [])),
- g(m);
- afterTapDay(e, t) {
- const a = (0, l.default)(i).getCalendarConfig(),
- { multi: n } = a;
- ? i.triggerEvent('afterTapDay', {
- currentSelected: e,
- selectedDays: t
- : i.triggerEvent('afterTapDay', e);
- jumpToToday() {
- const { year: e, month: t, date: a } = u.todayDate(),
- n = u.todayTimestamp();
- g({
- 'calendar.selectedDay': [
- lunar: (0, l.default)(i).getCalendarConfig().showLunar
- ? b.default.solar2lunar(e, t, a)
- : null
- 'calendar.todayTimestamp': n
- p.renderCalendar(e, t, a);
- w = p.whenChangeDate;
- t.whenChangeDate = w;
- const C = p.renderCalendar;
- t.renderCalendar = C;
- const T = p.whenSingleSelect;
- t.whenSingleSelect = T;
- const M = p.whenMulitSelect;
- t.whenMulitSelect = M;
- const k = p.calculatePrevWeekDays;
- t.calculatePrevWeekDays = k;
- const _ = p.calculateNextWeekDays;
- function L(e) {
- m(e), { year: D('calendar.curYear'), month: D('calendar.curMonth') }
- function v(e) {
- return m(e), D('calendar.selectedDay');
- function W(e) {
- m(e);
- const t = [...D('calendar.days')];
- t.map(e => {
- e.choosed = !1;
- g({ 'calendar.days': t, 'calendar.selectedDay': [] });
- function S(e, t, a, n) {
- m(n);
- const { selectedDay: r = [], weekMode: o } = D('calendar') || {},
- { year: c, month: l, day: b } = r[0] || {};
- if (+c != +e || +l != +t || +b != +a) {
- if (o) return (0, s.default)(i).jump({ year: e, month: t, day: a });
- if (e && t) {
- if ('number' != typeof +e || 'number' != typeof +t)
- return h.warn('jump 函数年月日参数必须为数字');
- const n = u.todayTimestamp();
- g(
- () => {
- if ('number' == typeof +a) return p.renderCalendar(e, t, a);
- p.renderCalendar(e, t);
- } else p.jumpToToday();
- function $(e, t) {
- m(t), (0, r.default)(i).setTodoLabels(e);
- function Y(e, t) {
- m(t), (0, r.default)(i).deleteTodoLabels(e);
- function O(e) {
- m(e), (0, r.default)(i).clearTodoLabels();
- function x(e) {
- return m(e), (0, r.default)(i).getTodoLabels();
- function A(e = [], t) {
- m(t), (0, n.default)(i).disableDays(e);
- function E(e = [], t) {
- m(t), (0, n.default)(i).enableArea(e);
- function I(e = [], t) {
- m(t), (0, n.default)(i).enableDays(e);
- function P(e, t) {
- m(t), (0, n.default)(i).setSelectedDays(e);
- function j(e) {
- m(e), (0, l.default)(i).getCalendarConfig();
- function G(e, t, a) {
- m(a), (0, l.default)(i).setCalendarConfig(e, t);
- function U(e) {
- return m(e), D('calendar.days', e);
- function F(...e) {
- return new Promise((t, a) => {
- const n = e[0];
- if (!e[1])
- return (0, s.default)(i)
- .switchWeek(n)
- .then(t)
- .catch(a);
- 'string' == typeof e[1]
- ? (m(e[1]),
- (0, s.default)(i)
- .switchWeek(n, e[2])
- .catch(a))
- : 'object' == typeof e[1] &&
- ('string' == typeof e[2] && m(e[1]),
- .switchWeek(n, e[1])
- .catch(a));
- function N(e, t) {
- (d.initialTasks.flag = 'process'),
- ((i = e).config = t),
- (function(e) {
- let t = ['日', '一', '二', '三', '四', '五', '六'];
- 'Mon' === e && (t = ['一', '二', '三', '四', '五', '六', '日']),
- g({ 'calendar.weeksCh': t });
- })(t.firstDayOfWeek),
- if (e && 'string' == typeof e) {
- const t = e.split('-');
- if (t.length < 3)
- return h.warn('配置 jumpTo 格式应为: 2018-4-2 或 2018-04-02');
- S(+t[0], +t[1], +t[2]);
- } else e ? S() : ((i.config.noDefault = !0), S());
- })(t.defaultDay),
- h.tips(
- '使用中若遇问题请反馈至 https://github.com/treadpit/wx_calendar/issues ✍️'
- t.calculateNextWeekDays = _;
- t.default = (e, t = {}) => {
- if ('process' === d.initialTasks.flag)
- return d.initialTasks.tasks.push(function() {
- N(e, t);
- var n = o(a(1)),
- s = o(a(3)),
- function o(e) {
- const c = new r.Logger(),
- l = new r.GetDate();
- class b extends n.default {
- enableArea(e = []) {
- if (2 === e.length) {
- const { start: t, end: a, startTimestamp: n, endTimestamp: s } = (0,
- r.convertEnableAreaToTimestamp)(e);
- if (!t || !a) return;
- const o = l.thisMonthDays(t[0], t[1]),
- c = l.thisMonthDays(a[0], a[1]);
- this.__judgeParam({
- start: t,
- end: a,
- startMonthDays: o,
- endMonthDays: c,
- startTimestamp: n,
- endTimestamp: s
- let { days: t = [], selectedDay: a = [] } = this.getData(
- const r = this.__handleEnableArea(
- { area: e, days: t, startTimestamp: n, endTimestamp: s },
- a
- 'calendar.enableArea': e,
- 'calendar.days': r.dates,
- 'calendar.selectedDay': r.selectedDay,
- 'calendar.enableAreaTimestamp': [n, s]
- c.warn(
- 'enableArea()参数需为时间范围数组,形如:["2018-8-4" , "2018-8-24"]'
- enableDays(e = []) {
- const { enableArea: t = [] } = this.getData('calendar');
- a = t.length
- ? (0, r.delRepeatedEnableDay)(e, t)
- : (0, r.converEnableDaysToTimestamp)(e);
- let { days: n = [], selectedDay: s = [] } = this.getData('calendar');
- const o = this.__handleEnableDays(
- { days: n, expectEnableDaysTimestamp: a },
- 'calendar.days': o.dates,
- 'calendar.selectedDay': o.selectedDay,
- 'calendar.enableDays': e,
- 'calendar.enableDaysTimestamp': a
- setSelectedDays(e) {
- if (!(0, s.default)(this.Component).getCalendarConfig().multi)
- return c.warn('单选模式下不能设置多日期选中,请配置 multi');
- let { days: t } = this.getData('calendar'),
- if (e && e.length) {
- const { dates: n, selectedDates: s } = this.__handleSelectedDays(
- t,
- a,
- e
- (t = n), (a = s);
- (e.choosed = !0), (e.showTodoLabel = !1);
- (a = t);
- (0, s.default)(this.Component).setCalendarConfig('multi', !0),
- this.setData({ 'calendar.days': t, 'calendar.selectedDay': a });
- disableDays(e) {
- const { disableDays: t = [], days: a } = this.getData('calendar');
- if ('[object Array]' !== Object.prototype.toString.call(e))
- return c.warn('disableDays 参数为数组');
- if (e.length) {
- const s = (n = (0, r.uniqueArrayByDate)(e.concat(t))).map(
- e => `${e.year}-${e.month}-${e.day}`
- const t = `${e.year}-${e.month}-${e.day}`;
- s.includes(t) && (e.disable = !0);
- e.disable = !1;
- this.setData({ 'calendar.days': a, 'calendar.disableDays': n });
- __judgeParam(e) {
- startMonthDays: n,
- endMonthDays: s,
- startTimestamp: r,
- endTimestamp: o
- } = e;
- return t[2] > n || t[2] < 1
- ? (c.warn(
- 'enableArea() 开始日期错误,指定日期不在当前月份天数范围内'
- ),
- !1)
- : t[1] > 12 || t[1] < 1
- ? (c.warn('enableArea() 开始日期错误,月份超出1-12月份'), !1)
- : a[2] > s || a[2] < 1
- 'enableArea() 截止日期错误,指定日期不在当前月份天数范围内'
- : a[1] > 12 || a[1] < 1
- ? (c.warn('enableArea() 截止日期错误,月份超出1-12月份'), !1)
- : !(r > o) || (c.warn('enableArea()参数最小日期大于了最大日期'), !1);
- __handleEnableArea(e = {}, t = []) {
- const { area: a, days: n, startTimestamp: s, endTimestamp: o } = e,
- c = this.getData('calendar.enableDays') || [];
- let b = [];
- c.length && (b = (0, r.delRepeatedEnableDay)(c, a));
- const d = [...n];
- d.forEach(e => {
- const a = l.newDate(e.year, e.month, e.day).getTime();
- (+s > +a || +a > +o) && !b.includes(+a)
- ? ((e.disable = !0),
- e.choosed &&
- ((e.choosed = !1),
- (t = t.filter(
- `${e.year}-${e.month}-${e.day}` !==
- `${t.year}-${t.month}-${t.day}`
- ))))
- : e.disable && (e.disable = !1);
- { dates: d, selectedDay: t }
- __handleEnableDays(e = {}, t = []) {
- const { days: a, expectEnableDaysTimestamp: n } = e,
- { enableAreaTimestamp: s = [] } = this.getData('calendar'),
- r = [...a];
- let r = !1;
- s.length
- ? (+s[0] > +a || +a > +s[1]) && !n.includes(+a) && (r = !0)
- : n.includes(+a) || (r = !0),
- : (e.disable = !1);
- { dates: r, selectedDay: t }
- __handleSelectedDays(e = [], t = [], a) {
- const { selectedDay: n, showLabelAlways: s } = this.getData('calendar');
- t = n && n.length ? (0, r.uniqueArrayByDate)(n.concat(a)) : a;
- const { year: o, month: c } = e[0],
- l = [];
- +e.year == +o &&
- +e.month == +c &&
- l.push(`${e.year}-${e.month}-${e.day}`);
- [...e].map(e => {
- l.includes(`${e.year}-${e.month}-${e.day}`) &&
- ((e.choosed = !0),
- s && e.showTodoLabel
- ? (e.showTodoLabel = !0)
- : (e.showTodoLabel = !1));
- { dates: e, selectedDates: t }
+ methods: {
+ initComp() {
+ const calendarConfig = this.setDefaultDisableDate()
+ this.setConfig(calendarConfig)
+ setDefaultDisableDate() {
+ const calendarConfig = this.properties.calendarConfig || {}
+ if (calendarConfig.disableMode && !calendarConfig.disableMode.date) {
+ calendarConfig.disableMode.date = getDate.toTimeStr(getDate.todayDate())
+ return calendarConfig
+ setConfig(config) {
+ if (config.markToday && typeof config.markToday === 'string') {
+ config.highlightToday = true
+ config.theme = config.theme || 'default'
+ this.weekMode = config.weekMode
+ calendarConfig: config
+ initCalendar(this, config)
+ chooseDate(e) {
+ const { type } = e.currentTarget.dataset
+ if (!type) return
+ const methodName = this.data.handleMap[type]
+ this[methodName](type)
+ chooseYear(type) {
+ const { curYear, curMonth } = this.data.calendar
+ if (!curYear || !curMonth) return logger.warn('异常:未获取到当前年月')
+ if (this.weekMode) {
+ return console.warn('周视图下不支持点击切换年月')
+ let newYear = +curYear
+ let newMonth = +curMonth
+ if (type === 'prev_year') {
+ newYear -= 1
+ } else if (type === 'next_year') {
+ newYear += 1
+ this.render(curYear, curMonth, newYear, newMonth)
+ chooseMonth(type) {
+ if (this.weekMode) return console.warn('周视图下不支持点击切换年月')
+ if (type === 'prev_month') {
+ newMonth = newMonth - 1
+ if (newMonth < 1) {
+ newMonth = 12
+ } else if (type === 'next_month') {
+ newMonth += 1
+ if (newMonth > 12) {
+ newMonth = 1
+ render(curYear, curMonth, newYear, newMonth) {
+ whenChangeDate.call(this, {
+ curYear,
+ curMonth,
+ newYear,
+ newMonth
+ 'calendar.curYear': newYear,
+ 'calendar.curMonth': newMonth
+ renderCalendar.call(this, newYear, newMonth)
+ * 日期点击事件
+ * @param {!object} e 事件对象
+ tapDayItem(e) {
+ const { idx, date = {} } = e.currentTarget.dataset
+ const { day, disable } = date
+ if (disable || !day) return
+ const config = this.data.calendarConfig || this.config || {}
+ const { multi, chooseAreaMode } = config
+ if (multi) {
+ whenMulitSelect.call(this, idx)
+ } else if (chooseAreaMode) {
+ whenChooseArea.call(this, idx)
+ whenSingleSelect.call(this, idx)
+ 'calendar.noDefault': false
+ doubleClickToToday() {
+ if (this.config.multi || this.weekMode) return
+ if (this.count === undefined) {
+ this.count = 1
+ this.count += 1
+ if (this.lastClick) {
+ const difference = new Date().getTime() - this.lastClick
+ if (difference < 500 && this.count >= 2) {
+ jump.call(this)
+ this.count = undefined
+ this.lastClick = undefined
+ this.lastClick = new Date().getTime()
+ * 日历滑动开始
+ * @param {object} e
+ calendarTouchstart(e) {
+ const t = e.touches[0]
+ const startX = t.clientX
+ const startY = t.clientY
+ this.slideLock = true // 滑动事件加锁
+ 'gesture.startX': startX,
+ 'gesture.startY': startY
+ * 日历滑动中
+ calendarTouchmove(e) {
+ const { gesture } = this.data
+ const { preventSwipe } = this.properties.calendarConfig
+ if (!this.slideLock || preventSwipe) return
+ if (slide.isLeft(gesture, e.touches[0])) {
+ this.handleSwipe('left')
+ if (slide.isRight(gesture, e.touches[0])) {
+ this.handleSwipe('right')
+ calendarTouchend(e) {
+ 'calendar.leftSwipe': 0,
+ 'calendar.rightSwipe': 0
+ handleSwipe(direction) {
+ let swipeKey = 'calendar.leftSwipe'
+ let swipeCalendarType = 'next_month'
+ let weekChangeType = 'next_week'
+ if (direction === 'right') {
+ swipeKey = 'calendar.rightSwipe'
+ swipeCalendarType = 'prev_month'
+ weekChangeType = 'prev_week'
+ [swipeKey]: 1
+ this.currentYM = getCurrentYM()
+ this.currentDates = getCalendarDates()
+ if (weekChangeType === 'prev_week') {
+ Week(this).calculatePrevWeekDays()
+ } else if (weekChangeType === 'next_week') {
+ Week(this).calculateNextWeekDays()
+ this.onSwipeCalendar(weekChangeType)
+ this.onWeekChange(weekChangeType)
+ this.chooseMonth(swipeCalendarType)
+ this.onSwipeCalendar(swipeCalendarType)
+ onSwipeCalendar(direction) {
+ this.triggerEvent('onSwipe', {
+ directionType: direction,
+ currentYM: this.currentYM
+ onWeekChange(direction) {
+ this.triggerEvent('whenChangeWeek', {
+ current: {
+ currentYM: this.currentYM,
+ dates: [...this.currentDates]
+ next: {
+ currentYM: getCurrentYM(),
+ dates: getCalendarDates()
+ directionType: direction
+ this.currentDates = null
+ this.currentYM = null
-]);
-
+})
@@ -2,52 +2,55 @@
<view class="calendar b tb">
<!-- 头部操作栏 -->
<view wx:if="{{!calendarConfig.hideHeadOnWeekMode}}" class="handle {{calendarConfig.theme}}_handle-color fs28 b lr ac pc">
- <view class="prev fs36" wx:if="{{calendarConfig.showHandlerOnWeekMode || !calendar.weekMode}}">
+ <view class="prev fs36" wx:if="{{calendarConfig.showHandlerOnWeekMode || !calendarConfig.weekMode}}">
<text class="prev-handle iconfont icon-doubleleft" bindtap="chooseDate" data-type="prev_year"></text>
<text class="prev-handle iconfont icon-left" bindtap="chooseDate" data-type="prev_month"></text>
</view>
<view class="flex date-in-handle b lr cc" bindtap="doubleClickToToday">{{calendar.curYear || "--"}} 年 {{calendar.curMonth || "--"}} 月</view>
- <view class="next fs36" wx:if="{{calendarConfig.showHandlerOnWeekMode || !calendar.weekMode}}">
+ <view class="next fs36" wx:if="{{calendarConfig.showHandlerOnWeekMode || !calendarConfig.weekMode}}">
<text class="next-handle iconfont icon-right" bindtap="chooseDate" data-type="next_month"></text>
<text class="next-handle iconfont icon-doubleright" bindtap="chooseDate" data-type="next_year"></text>
<!-- 星期栏 -->
<view class="weeks b lr ac {{calendarConfig.theme}}_week-color">
- <view class="week fs28" wx:for="{{calendar.weeksCh}}" wx:key="{{index}}" data-idx="{{index}}">{{item}}</view>
+ <view class="week fs28" wx:for="{{calendar.weeksCh}}" wx:key="index" data-idx="{{index}}">{{item}}</view>
<!-- 日历面板主体 -->
<view class="b lr wrap"
bindtouchstart="calendarTouchstart"
- bindtouchmove="calendarTouchmove"
- bindtouchend="calendarTouchend">
+ catchtouchmove="calendarTouchmove"
+ catchtouchend="calendarTouchend">
<!-- 上月日期格子 -->
<view
class="grid b ac pc {{calendarConfig.theme}}_prev-month-date"
wx:if="{{calendar.empytGrids}}"
wx:for="{{calendar.empytGrids}}"
- wx:key="{{index}}"
+ wx:key="index"
data-idx="{{index}}">
- <view class="date">
- {{item.day}}
- <view
- wx:if="{{calendarConfig.showLunar && item.lunar}}"
- class="date-desc date-desc-bottom">
- {{item.lunar.Term || item.lunar.IDayCn}}
+ <view class="date-wrap b cc">
+ <view class="date">
+ {{item.day}}
+ <view
+ wx:if="{{calendarConfig.showLunar && item.lunar}}"
+ class="date-desc date-desc-bottom">
+ {{item.lunar.Term || item.lunar.IDayCn}}
+ </view>
<!-- 本月日期格子 -->
- <view class="grid {{calendarConfig.theme}}_normal-date b ac pc"
wx:for="{{calendar.days}}"
- data-disable="{{item.disable}}"
data-idx="{{index}}"
- bindtap="tapDayItem">
+ data-date="{{item}}"
+ bindtap="tapDayItem"
+ class="grid {{item.class ? item.class : ''}} {{calendarConfig.theme}}_normal-date b ac pc">
- class="date-wrap b cc">
- <view class="date b ac pc {{(item.week === 0 || item.week === 6) ? calendarConfig.theme + '_weekend-color' : ''}} {{calendar.todoLabelCircle && item.showTodoLabel && !item.choosed ? calendarConfig.theme + '_todo-circle todo-circle' : '' }} {{item.isToday ? calendarConfig.theme + '_today' : ''}} {{item.choosed ? calendarConfig.theme + '_choosed' : ''}} {{item.disable ? calendarConfig.theme + '_date-disable' : ''}}">
+ class="date-wrap b cc {{(item.week === 0 || item.week === 6) ? calendarConfig.theme + '_weekend-color' : ''}}">
+ <view class="date b ac pc {{item.class ? item.class : ''}} {{calendarConfig.chooseAreaMode ? 'date-area-mode' : ''}} {{calendar.todoLabelCircle && item.showTodoLabel && !item.choosed ? calendarConfig.theme + '_todo-circle todo-circle' : '' }} {{item.isToday ? calendarConfig.theme + '_today' : ''}} {{item.choosed ? calendarConfig.theme + '_choosed' : ''}} {{item.disable ? calendarConfig.theme + '_date-disable' : ''}}">
+ {{calendarConfig.markToday && item.isToday ? calendarConfig.markToday : item.day}}
wx:if="{{(calendarConfig.showLunar && item.lunar && !item.showTodoLabel) || (item.showTodoLabel && calendar.todoLabelPos !== 'bottom')}}"
class="date-desc {{calendarConfig.theme}}_date-desc date-desc-bottom {{(item.choosed || item.isToday) ? 'date-desc-bottom-always' : ''}} {{item.disable ? calendarConfig.theme + '_date-desc-disable' : ''}}">
@@ -56,7 +59,7 @@
wx:if="{{item.showTodoLabel && !calendar.todoLabelCircle}}"
class="{{item.todoText ? 'date-desc' : calendarConfig.theme + '_todo-dot todo-dot'}} {{calendarConfig.showLunar ? calendarConfig.theme + '_date-desc-lunar' : ''}} {{calendar.todoLabelPos === 'bottom' ? 'date-desc-bottom todo-dot-bottom' : 'date-desc-top todo-dot-top'}} {{calendar.showLabelAlways && item.choosed && calendar.todoLabelPos === 'bottom' ? 'date-desc-bottom-always todo-dot-bottom-always' : ''}} {{calendar.showLabelAlways && item.choosed && calendar.todoLabelPos === 'top' ? 'date-desc-top-always todo-dot-top-always' : ''}}"
- style="background-color: {{calendar.todoLabelColor}};">
+ style="background-color: {{item.todoText ? '' : item.color || calendar.todoLabelColor}}; color: {{item.color}}">
{{item.todoText}}
@@ -66,8 +69,9 @@
class="grid b ac pc {{calendarConfig.theme}}_next-month-date"
wx:for="{{calendar.lastEmptyGrids}}"
<view class="date">
{{item.day}}
@@ -76,6 +80,7 @@
{{item.lunar.Term || item.lunar.IDayCn}}
@@ -98,7 +98,8 @@
.date-wrap {
- height: 72rpx;
+ width: 100%;
+ height: 80rpx;
position: relative;
left: 0;
top: 0;
@@ -122,6 +123,11 @@
animation-iteration-count: 1;
+.date-area-mode {
+ border-radius: 0;
.date-desc {
width: 150%;
height: 32rpx;
@@ -199,6 +205,10 @@
bottom: -14rpx;
+.todo-circle .date-desc.date-desc-bottom {
+ bottom: -30rpx;
.date-desc.date-desc-bottom-always {
bottom: -28rpx;
@@ -0,0 +1,877 @@
+import Day from './func/day'
+import Todo from './func/todo'
+import WxData from './func/wxData'
+import Calendar from './func/render'
+import CalendarConfig from './func/config'
+import convertSolarLunar from './func/convertSolarLunar'
+ isComponent,
+ initialTasks,
+ getCurrentPage,
+ getComponent,
+ getDateTimeStamp
+} from './func/utils'
+let Component = {}
+let logger = new Logger()
+let getDate = new GetDate()
+let dataInstance = null
+ * 全局赋值正在操作的组件实例,方便读/写各自的 data
+ * @param {string} componentId 要操作的日历组件ID
+function bindCurrentComponent(componentId) {
+ Component = getComponent(componentId)
+ return Component
+ * 获取日历内部数据
+ * @param {string} key 获取值的键名
+function getData(key, componentId) {
+ bindCurrentComponent(componentId)
+ dataInstance = new WxData(Component)
+ return dataInstance.getData(key)
+ * 设置日历内部数据
+ * @param {object}} data 待设置的数据
+ * @param {function} callback 设置成功回调函数
+function setData(data, callback = () => {}) {
+ const dataInstance = new WxData(Component)
+ return dataInstance.setData(data, callback)
+const conf = {
+ * @param {number} curYear
+ * @param {number} curMonth
+ renderCalendar(curYear, curMonth, curDate) {
+ if (isComponent(this)) Component = this
+ Calendar(Component)
+ .renderCalendar(curYear, curMonth, curDate)
+ .then((info = {}) => {
+ if (!info.firstRender) {
+ return resolve({
+ date: curDate
+ mountEventsOnPage(getCurrentPage())
+ Component.triggerEvent('afterCalendarRender', Component)
+ Component.firstRender = true
+ if (initialTasks.tasks.length) {
+ initialTasks.tasks.shift()()
+ .catch(err => {
+ * 当改变月份时触发
+ * @param {object} param
+ whenChangeDate({ curYear, curMonth, newYear, newMonth }) {
+ Component.triggerEvent('whenChangeMonth', {
+ year: newYear,
+ month: newMonth
+ * 多选
+ * @param {number} dateIdx 当前选中日期索引值
+ whenMulitSelect(dateIdx) {
+ const { calendar = {} } = getData()
+ const { days, todoLabels } = calendar
+ const config = CalendarConfig(Component).getCalendarConfig()
+ let { selectedDay: selectedDays = [] } = calendar
+ const currentDay = days[dateIdx]
+ if (!currentDay) return
+ currentDay.choosed = !currentDay.choosed
+ if (!currentDay.choosed) {
+ currentDay.cancel = true // 该次点击是否为取消日期操作
+ const currentDayStr = getDate.toTimeStr(currentDay)
+ selectedDays = selectedDays.filter(
+ item => currentDayStr !== getDate.toTimeStr(item)
+ if (todoLabels) {
+ todoLabels.forEach(item => {
+ if (currentDayStr === getDate.toTimeStr(item)) {
+ currentDay.showTodoLabel = true
+ currentDay.cancel = false
+ const { showLabelAlways } = getData('calendar')
+ if (showLabelAlways && currentDay.showTodoLabel) {
+ currentDay.showTodoLabel = false
+ if (!config.takeoverTap) {
+ selectedDays.push(currentDay)
+ if (config.takeoverTap) {
+ return Component.triggerEvent('onTapDay', currentDay)
+ setData({
+ 'calendar.selectedDay': selectedDays
+ conf.afterTapDay(currentDay, selectedDays)
+ * 单选
+ whenSingleSelect(dateIdx) {
+ const { days, selectedDay: selectedDays = [], todoLabels } = calendar
+ let shouldMarkerTodoDay = []
+ const preSelectedDate = [...selectedDays].pop() || {}
+ const { month: dMonth, year: dYear } = days[0] || {}
+ conf.afterTapDay(currentDay)
+ if (!config.inverse && preSelectedDate.day === currentDay.day) return
+ days.forEach((item, idx) => {
+ if (+item.day === +preSelectedDate.day) days[idx].choosed = false
+ // 筛选当月待办事项的日期
+ shouldMarkerTodoDay = todoLabels.filter(
+ item => +item.year === dYear && +item.month === dMonth
+ Todo(Component).showTodoLabels(shouldMarkerTodoDay, days, selectedDays)
+ const tmp = {
+ if (preSelectedDate.day !== currentDay.day) {
+ preSelectedDate.choosed = false
+ currentDay.choosed = true
+ if (!calendar.showLabelAlways || !currentDay.showTodoLabel) {
+ tmp['calendar.selectedDay'] = [currentDay]
+ } else if (config.inverse) {
+ if (currentDay.choosed) {
+ if (currentDay.showTodoLabel && calendar.showLabelAlways) {
+ tmp['calendar.selectedDay'] = []
+ if (config.weekMode) {
+ tmp['calendar.curYear'] = currentDay.year
+ tmp['calendar.curMonth'] = currentDay.month
+ setData(tmp)
+ gotoSetContinuousDates(start, end) {
+ return chooseDateArea([
+ `${getDate.toTimeStr(start)}`,
+ `${getDate.toTimeStr(end)}`
+ ])
+ timeRangeHelper(currentDate, selectedDay) {
+ const currentDateTimestamp = getDateTimeStamp(currentDate)
+ const startDate = selectedDay[0]
+ let endDate
+ let endDateTimestamp
+ let selectedLen = selectedDay.length
+ if (selectedLen > 1) {
+ endDate = selectedDay[selectedLen - 1]
+ endDateTimestamp = getDateTimeStamp(endDate)
+ const startTimestamp = getDateTimeStamp(startDate)
+ endDate,
+ startDate,
+ currentDateTimestamp,
+ endDateTimestamp,
+ startTimestamp
+ * 计算连续日期选择的开始及结束日期
+ * @param {object} currentDate 当前选择日期
+ * @param {array} selectedDay 已选择的的日期
+ calculateDateRange(currentDate, selectedDay) {
+ } = this.timeRangeHelper(currentDate, selectedDay)
+ let range = []
+ const isWantToChooseOneDate = selectedDay.filter(
+ item => getDate.toTimeStr(item) === getDate.toTimeStr(currentDate)
+ if (selectedLen === 2 && isWantToChooseOneDate.length) {
+ range = [currentDate, currentDate]
+ return range
+ currentDateTimestamp >= startTimestamp &&
+ endDateTimestamp &&
+ currentDateTimestamp <= endDateTimestamp
+ const currentDateIdxInChoosedDateArea = selectedDay.findIndex(
+ if (selectedLen / 2 > currentDateIdxInChoosedDateArea) {
+ range = [currentDate, endDate]
+ range = [startDate, currentDate]
+ } else if (currentDateTimestamp < startTimestamp) {
+ } else if (currentDateTimestamp > startTimestamp) {
+ chooseAreaWhenExistArea(currentDate, selectedDay) {
+ const range = conf.calculateDateRange(
+ currentDate,
+ getDate.sortDates(selectedDay)
+ conf
+ .gotoSetContinuousDates(...range)
+ .then(data => {
+ resolve(data)
+ conf.afterTapDay(currentDate)
+ chooseAreaWhenHasOneDate(currentDate, selectedDay, lastChoosedDate) {
+ const startDate = lastChoosedDate || selectedDay[0]
+ let range = [startDate, currentDate]
+ const lastChoosedDateTimestamp = getDateTimeStamp(startDate)
+ if (lastChoosedDateTimestamp > currentDateTimestamp) {
+ range = [currentDate, startDate]
+ * 日期范围选择模式
+ whenChooseArea(dateIdx) {
+ if (Component.weekMode) return
+ const { days = [], selectedDay, lastChoosedDate } = getData('calendar')
+ const currentDate = days[dateIdx]
+ if (currentDate.disable) return
+ return Component.triggerEvent('onTapDay', currentDate)
+ if (selectedDay && selectedDay.length > 1) {
+ .chooseAreaWhenExistArea(currentDate, selectedDay)
+ .then(dates => {
+ resolve(dates)
+ } else if (lastChoosedDate || (selectedDay && selectedDay.length === 1)) {
+ .chooseAreaWhenHasOneDate(currentDate, selectedDay, lastChoosedDate)
+ days.forEach(date => {
+ if (+date.day === +currentDate.day) {
+ dataInstance.setData({
+ 'calendar.lastChoosedDate': currentDate
+ * 点击日期后触发事件
+ * @param {object} currentSelected 当前选择的日期
+ * @param {array} selectedDates 多选状态下选中的日期
+ afterTapDay(currentSelected, selectedDates) {
+ const { multi } = config
+ if (!multi) {
+ Component.triggerEvent('afterTapDay', currentSelected)
+ Component.triggerEvent('afterTapDay', {
+ currentSelected,
+ * 跳转至今天
+ jumpToToday() {
+ const { year, month, date } = getDate.todayDate()
+ const timestamp = getDate.todayTimestamp()
+ 'calendar.selectedDay': [
+ year: year,
+ day: date,
+ month: month,
+ lunar: config.showLunar
+ ? convertSolarLunar.solar2lunar(year, month, date)
+ 'calendar.todayTimestamp': timestamp
+ .renderCalendar(year, month, date)
+ .then(() => {
+ resolve({ year, month, date })
+ .catch(() => {
+ reject('jump failed')
+export const whenChangeDate = conf.whenChangeDate
+export const renderCalendar = conf.renderCalendar
+export const whenSingleSelect = conf.whenSingleSelect
+export const whenChooseArea = conf.whenChooseArea
+export const whenMulitSelect = conf.whenMulitSelect
+export const calculatePrevWeekDays = conf.calculatePrevWeekDays
+export const calculateNextWeekDays = conf.calculateNextWeekDays
+ * 获取当前年月
+export function getCurrentYM(componentId) {
+ year: getData('calendar.curYear'),
+ month: getData('calendar.curMonth')
+ * 获取已选择的日期
+ * @param {object } options 日期配置选项 {lunar} 是否返回农历信息
+export function getSelectedDay(options = {}, componentId) {
+ const config = getCalendarConfig()
+ const dates = getData('calendar.selectedDay') || []
+ if (options.lunar && !config.showLunar) {
+ const datesWithLunar = getDate.convertLunar(dates)
+ * 取消选中日期
+ * @param {array} dates 需要取消的日期,不传则取消所有已选择的日期
+export function cancelSelectedDates(dates, componentId) {
+ const { days = [], selectedDay = [] } = getData('calendar') || {}
+ if (!dates || !dates.length) {
+ 'calendar.selectedDay': []
+ const cancelDatesStr = dates.map(
+ date => `${+date.year}-${+date.month}-${+date.day}`
+ const filterSelectedDates = selectedDay.filter(
+ !cancelDatesStr.includes(`${+date.year}-${+date.month}-${+date.day}`)
+ cancelDatesStr.includes(`${+date.year}-${+date.month}-${+date.day}`)
+ 'calendar.selectedDay': filterSelectedDates
+ * 周视图跳转
+ * @param {object} date info
+ * @param {boolean} disableSelected 跳转时是否需要选中,周视图切换调用该方法,如未选择日期时不选中日期
+function jumpWhenWeekMode({ year, month, day }, disableSelected) {
+ Week(Component)
+ .jump(
+ year: +year,
+ month: +month,
+ day: +day
+ disableSelected
+ .then(date => {
+ resolve(date)
+ * 月视图跳转
+function jumpWhenNormalMode({ year, month, day }) {
+ if (typeof +year !== 'number' || typeof +month !== 'number') {
+ return logger.warn('jump 函数年月日参数必须为数字')
+ let tmp = {
+ 'calendar.curYear': +year,
+ 'calendar.curMonth': +month,
+ setData(tmp, () => {
+ .renderCalendar(+year, +month, +day)
+ * 跳转至指定日期
+export function jump(year, month, day, componentId) {
+ const { selectedDay = [] } = getData('calendar') || {}
+ const { weekMode } = getData('calendarConfig') || {}
+ const { year: y, month: m, day: d } = selectedDay[0] || {}
+ if (+y === +year && +m === +month && +d === +day) {
+ if (weekMode) {
+ if (!year || !month || !day) {
+ year = today.year
+ month = today.month
+ day = today.date
+ jumpWhenWeekMode({ year, month, day }, disableSelected)
+ if (year && month) {
+ jumpWhenNormalMode({ year, month, day })
+ .jumpToToday()
+ * 设置待办事项日期标记
+ * @param {object} todos 待办事项配置
+ * @param {string} [todos.pos] 标记显示位置,默认值'bottom' ['bottom', 'top']
+ * @param {string} [todos.dotColor] 标记点颜色,backgroundColor 支持的值都行
+ * @param {object[]} [todos.days] 需要标记的所有日期,如:[{year: 2015, month: 5, day: 12}],其中年月日字段必填
+export function setTodoLabels(todos, componentId) {
+ Todo(Component).setTodoLabels(todos)
+ * 删除指定日期待办事项
+ * @param {array} todos 需要删除的待办日期数组
+export function deleteTodoLabels(todos, componentId) {
+ Todo(Component).deleteTodoLabels(todos)
+export function clearTodoLabels(componentId) {
+ Todo(Component).clearTodoLabels()
+export function getTodoLabels(options = {}, componentId) {
+ const todoDates = Todo(Component).getTodoLabels() || []
+ const todoDatesWithLunar = getDate.convertLunar(todoDates)
+ return todoDatesWithLunar
+ return todoDates
+ * @param {array} days 日期
+ * @param {number} [days.year]
+ * @param {number} [days.month]
+ * @param {number} [days.day]
+export function disableDay(days = [], componentId) {
+ Day(Component).disableDays(days)
+export function enableArea(area = [], componentId) {
+ Day(Component).enableArea(area)
+export function enableDays(days = [], componentId) {
+ Day(Component).enableDays(days)
+ * 设置选中日期(多选模式下)
+export function setSelectedDays(selected, componentId) {
+ Day(Component).setSelectedDays(selected)
+ * 获取当前日历配置
+export function getCalendarConfig(componentId) {
+ return CalendarConfig(Component).getCalendarConfig()
+ * 设置日历配置
+export function setCalendarConfig(config, componentId) {
+ if (!config || Object.keys(config).length === 0) {
+ return logger.warn('setCalendarConfig 参数必须为非空对象')
+ const existConfig = getCalendarConfig()
+ CalendarConfig(Component)
+ .setCalendarConfig(config)
+ .then(conf => {
+ const { date, type } = existConfig.disableMode || {}
+ const { _date, _type } = config.disableMode || {}
+ if (type !== _type || date !== _date) {
+ const { year, month } = getCurrentYM()
+ jump(year, month)
+ * 获取当前日历面板日期
+export function getCalendarDates(options = {}, componentId) {
+ const dates = getData('calendar.days', componentId) || []
+ * 选择连续日期范围
+export function chooseDateArea(dateArea, componentId) {
+ return Day(Component).chooseArea(dateArea)
+export function setDateStyle(dates, componentId) {
+ if (!dates) return
+ Day(Component).setDateStyle(dates)
+ * 切换周月视图
+ * 切换视图时可传入指定日期,如: {year: 2019, month: 1, day: 3}
+ * args[0] view 视图模式[week, month]
+ * args[1]|args[2]为day object或者 componentId
+export function switchView(...args) {
+ const view = args[0]
+ if (!args[1]) {
+ return Week(Component)
+ .switchWeek(view)
+ if (typeof args[1] === 'string') {
+ bindCurrentComponent(args[1], this)
+ .switchWeek(view, args[2])
+ } else if (typeof args[1] === 'object') {
+ if (typeof args[2] === 'string') {
+ .switchWeek(view, args[1])
+ * 绑定日历事件至当前页面实例
+ * @param {object} page 当前页面实例
+function mountEventsOnPage(page) {
+ page.calendar = {
+ switchView,
+ disableDay,
+ enableArea,
+ enableDays,
+ chooseDateArea,
+ getSelectedDay,
+ cancelSelectedDates,
+ setDateStyle,
+ setTodoLabels,
+ getTodoLabels,
+ deleteTodoLabels,
+ clearTodoLabels,
+ setSelectedDays,
+ getCalendarConfig,
+ setCalendarConfig,
+function setWeekHeader(firstDayOfWeek) {
+ let weeksCh = ['日', '一', '二', '三', '四', '五', '六']
+ if (firstDayOfWeek === 'Mon') {
+ weeksCh = ['一', '二', '三', '四', '五', '六', '日']
+ 'calendar.weeksCh': weeksCh
+function autoSelectDay(defaultDay) {
+ Component.firstRenderWeekMode = true
+ if (defaultDay && typeof defaultDay === 'string') {
+ const day = defaultDay.split('-')
+ if (day.length < 3) {
+ return logger.warn('配置 jumpTo 格式应为: 2018-4-2 或 2018-04-02')
+ jump(+day[0], +day[1], +day[2])
+ if (!defaultDay) {
+ Component.config.noDefault = true
+ 'config.noDefault': true
+ jump()
+function init(component, config) {
+ initialTasks.flag = 'process'
+ Component = component
+ Component.config = config
+ setWeekHeader(config.firstDayOfWeek)
+ autoSelectDay(config.defaultDay)
+ logger.tips(
+ '使用中若遇问题请反馈至 https://github.com/treadpit/wx_calendar/issues ✍️'
+export default (component, config = {}) => {
+ if (initialTasks.flag === 'process') {
+ return initialTasks.tasks.push(function() {
+ init(component, config)
@@ -0,0 +1,144 @@
+import { dateUtil, getCalendarConfig } from './utils/index'
+function calculateEmptyGrids(year, month, config) {
+ const prevMonthGrids = calculatePrevMonthGrids(year, month, config)
+ const nextMonthGrids = calculateNextMonthGrids(year, month, config)
+ prevMonthGrids,
+ nextMonthGrids
+function calculatePrevMonthGrids(year, month, config) {
+ let emptyGrids = []
+ const prevMonthDays = dateUtil.getDatesCountOfMonth(year, month - 1)
+ let firstDayOfWeek = dateUtil.firstDayOfWeek(year, month)
+ const YMInfo = dateUtil.getPrevMonthInfo({ year, month })
+ emptyGrids.push('')
+ const week = dateUtil.getDayOfWeek(+year, +month, i)
+ emptyGrids.push({
+ ...YMInfo,
+ date: i,
+ week
+ emptyGrids.reverse()
+ return emptyGrids
+function calculateExtraEmptyDate(year, month, config) {
+ let firstDayofMonth = dateUtil.getDayOfWeek(year, month, 1)
+function calculateNextMonthGrids(year, month, config) {
+ const datesCount = dateUtil.getDatesCountOfMonth(year, month)
+ let lastDayWeek = dateUtil.getDayOfWeek(year, month, datesCount)
+ len = len + calculateExtraEmptyDate(year, month, config)
+ const YMInfo = dateUtil.getNextMonthInfo({ year, month })
+ id: i - 1,
+ week: week || 7
+function calculateCurrentMonthDates(year, month) {
+ return dateUtil.calcDates(year, month)
+export function calcJumpData({ dateInfo, config, component }) {
+ dateInfo = dateInfo || dateUtil.todayFMD()
+ const { year, month, date } = dateInfo
+ const calendarConfig = config || getCalendarConfig(component)
+ const emptyGrids = calculateEmptyGrids(year, month, calendarConfig)
+ const calendar = {
+ curYear: year,
+ curMonth: month,
+ curDate: date,
+ dates: calculateCurrentMonthDates(year, month),
+ ...emptyGrids
+ return calendar
@@ -0,0 +1,12 @@
+import { dateUtil } from './utils/index'
+export function calcTargetYMInfo() {
+ right: dateUtil.getPrevMonthInfo,
+ left: dateUtil.getNextMonthInfo,
+ prev_month: dateUtil.getPrevMonthInfo,
+ next_month: dateUtil.getNextMonthInfo,
+ prev_year: dateUtil.getPrevYearInfo,
+ next_year: dateUtil.getNextYearInfo
@@ -0,0 +1,257 @@
+import plugins from './plugins/index'
+import { calcJumpData } from './core'
+import { renderCalendar } from './render'
+import { calcTargetYMInfo } from './helper'
+import { dateUtil, calendarGesture, logger } from './utils/index'
+ config: {
+ // 禁用某天日期配置默认为今天
+ const calendarConfig = this.properties.config || {}
+ calendarConfig.disableMode.date = dateUtil.toTimeStr(
+ dateUtil.todayFMD()
+ initCalendar(config) {
+ const { defaultDate } = config
+ let date = dateUtil.todayFMD()
+ if (defaultDate && typeof defaultDate === 'string') {
+ const dateInfo = defaultDate.split('-')
+ if (dateInfo.length < 3) {
+ return logger.warn('defaultDate配置格式应为: 2018-4-2 或 2018-04-02')
+ date = {
+ year: +dateInfo[0],
+ month: +dateInfo[1],
+ date: +dateInfo[2]
+ const waitRenderData = calcJumpData({
+ dateInfo: date,
+ config
+ const timestamp = dateUtil.todayTimestamp()
+ if (config.autoChoosedWhenJump) {
+ const target = waitRenderData.dates.filter(
+ item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(date)
+ if (target && target.length) {
+ if (!waitRenderData.selectedDates) {
+ waitRenderData.selectedDates = target
+ waitRenderData.selectedDates.push(target[0])
+ ...waitRenderData,
+ todayTimestamp: timestamp,
+ weeksCh: dateUtil.getWeekHeader(config.firstDayOfWeek)
+ for (let plugin of plugins.installed) {
+ const [, p] = plugin
+ if (typeof p.install === 'function') {
+ p.install(this)
+ if (typeof p.methods === 'function') {
+ const methods = p.methods(this)
+ for (let fnName in methods) {
+ if (fnName.startsWith('__')) continue
+ const fn = methods[fnName]
+ if (typeof fn === 'function') {
+ if (!this.calendar) this.calendar = {}
+ this.calendar[fnName] = fn
+ const initData = this.initCalendar(config)
+ renderCalendar.call(this, initData, config)
+ tapDate(e) {
+ const { info } = e.currentTarget.dataset
+ const { date, disable } = info || {}
+ if (disable || !date) return
+ const { calendar, config } = this.data
+ let calendarData = calendar
+ let calendarConfig = config
+ return this.triggerEvent('takeoverTap', info)
+ if (typeof p.onTapDate === 'function') {
+ calendarData: __calendarData,
+ calendarConfig: __calendarConfig
+ } = p.onTapDate(info, calendarData, calendarConfig)
+ calendarData = __calendarData
+ calendarConfig = __calendarConfig
+ renderCalendar.call(this, calendarData, calendarConfig).then(() => {
+ this.triggerEvent('afterTapDate', info)
+ this.swipeLock = true
+ const { preventSwipe } = this.properties.config
+ if (!this.swipeLock || preventSwipe) return
+ if (calendarGesture.isLeft(gesture, e.touches[0])) {
+ this.swipeLock = false
+ if (calendarGesture.isRight(gesture, e.touches[0])) {
+ const { calendar } = this.data
+ const { curYear, curMonth } = calendarData
+ const getMonthInfo = calcTargetYMInfo()[direction]
+ const target = getMonthInfo({
+ year: +curYear,
+ month: +curMonth
+ target.direction = direction
+ this.renderCalendar(target)
+ changeDate(e) {
+ const { calendar: calendarData } = this.data
+ const getMonthInfo = calcTargetYMInfo()[type]
+ target.direction = type
+ renderCalendar(target) {
+ let { calendar: calendarData, config } = this.data
+ const { curYear, curMonth } = calendarData || {}
+ if (typeof p.onSwitchCalendar === 'function') {
+ calendarData = p.onSwitchCalendar(target, calendarData, this)
+ return renderCalendar.call(this, calendarData, config).then(() => {
+ let triggerEventName = 'whenChangeMonth'
+ triggerEventName = 'whenChangeWeek'
+ this.triggerEvent(triggerEventName, {
+ next: target
+ next: target,
+ type: triggerEventName
+ doubleClickJumpToToday() {
+ const { multi, weekMode } = this.calendar.getCalendarConfig() || {}
+ if (multi || weekMode) return
+ difference < 500 &&
+ this.count >= 2 &&
+ typeof this.calendar.jump === 'function'
+ const today = dateUtil.todayFMD()
+ this.calendar.jump(today)
@@ -0,0 +1,3 @@
+{
+ "component": true
@@ -0,0 +1,60 @@
+<view class="flex b tb ac" wx:if="{{calendar}}">
+ <view class="calendar b tb">
+ <!-- 头部操作栏 -->
+ wx:if="{{!config.hideHeader}}"
+ class="handle {{config.theme}}_handle-color fs28 b lr ac pc">
+ <view class="prev fs36" wx:if="{{!config.weekMode}}">
+ <text class="prev-handle iconfont icon-doubleleft" bindtap="changeDate" data-type="prev_year"></text>
+ <text class="prev-handle iconfont icon-left" bindtap="changeDate" data-type="prev_month"></text>
+ <view class="flex date-in-handle b lr cc" bindtap="doubleClickJumpToToday">{{calendar.curYear || "--"}} 年 {{calendar.curMonth || "--"}} 月</view>
+ <view class="next fs36" wx:if="{{!config.weekMode}}">
+ <text class="next-handle iconfont icon-right" bindtap="changeDate" data-type="next_month"></text>
+ <text class="next-handle iconfont icon-doubleright" bindtap="changeDate" data-type="next_year"></text>
+ <!-- 星期栏 -->
+ <view class="weeks b lr ac {{config.theme}}_week-color">
+ <!-- 日历面板主体 -->
+ <view class="b lr wrap" bindtouchstart="calendarTouchstart" catchtouchmove="calendarTouchmove" catchtouchend="calendarTouchend">
+ <!-- 上月日期格子 -->
+ <view class="grid b ac pc {{config.theme}}_prev-month-date" wx:for="{{calendar.prevMonthGrids}}" wx:key="index" data-idx="{{index}}">
+ {{item.date}}
+ <!-- 本月日期格子 -->
+ <view wx:for="{{calendar.dates}}" wx:key="index" data-idx="{{index}}" data-info="{{item}}" bindtap="tapDate" class="grid {{item.class ? item.class : ''}} {{config.theme}}_normal-date b ac pc">
+ <view class="date-wrap b cc {{config.emphasisWeek && (item.week === 0 || item.week === 6) ? config.theme + '_weekend-color' : ''}}">
+ <view class="date b ac pc {{item.class ? item.class : ''}} {{item.isToday && config.highlightToday ? config.theme + '_today' : ''}} {{item.choosed ? config.theme + '_choosed' : ''}} {{item.disable ? config.theme + '_date-disable' : ''}} {{config.chooseAreaMode ? 'date-area-mode' : ''}} {{calendar.todoLabelCircle && item.showTodoLabel && !item.choosed ? config.theme + '_todo-circle todo-circle' : '' }}">
+ {{config.markToday && item.isToday ? config.markToday : item.date}}
+ wx:if="{{(config.showLunar && item.lunar && !item.showTodoLabel) || (item.showTodoLabel && calendar.todoLabelPos !== 'bottom') || config.showHolidays}}"
+ class="date-desc {{config.theme}}_date-desc date-desc-bottom {{(item.choosed || item.isToday) ? 'date-desc-bottom-always' : ''}} {{item.disable ? config.theme + '_date-desc-disable' : ''}}">
+ <text class="{{config.showHolidays && !item.showTodoLabel && item.label && !item.choosed ? config.theme + '_date-desc-lunar' : ''}} {{item.type === 'festival' ? config.theme + '_festival' : ''}}">{{item.label || item.lunar.Term || item.lunar.IDayCn}}</text>
+ wx:if="{{item.showTodoLabel && !calendar.todoLabelCircle}}"
+ class="{{item.todoText ? 'date-desc' : config.theme + '_todo-dot todo-dot'}} {{config.showLunar ? config.theme + '_date-desc-lunar' : ''}} {{calendar.todoLabelPos === 'bottom' ? 'date-desc-bottom todo-dot-bottom' : 'date-desc-top todo-dot-top'}} {{calendar.showLabelAlways && item.choosed && calendar.todoLabelPos === 'bottom' ? 'date-desc-bottom-always todo-dot-bottom-always' : ''}} {{calendar.showLabelAlways && item.choosed && calendar.todoLabelPos === 'top' ? 'date-desc-top-always todo-dot-top-always' : ''}}"
+ {{item.todoText}}
+ <!-- 下月日期格子 -->
+ <view class="grid b ac pc {{config.theme}}_next-month-date" wx:for="{{calendar.nextMonthGrids}}" wx:key="index" data-idx="{{index}}">
+</view>
@@ -0,0 +1,215 @@
+@import './theme/iconfont.wxss';
+@import './theme/theme-default.wxss';
+@import './theme/theme-elegant.wxss';
+.b {
+ display: flex;
+.lr {
+ flex-direction: row;
+.tb {
+ flex-direction: column;
+.pc {
+ justify-content: center;
+.ac {
+ align-items: center;
+.cc {
+.wrap {
+ flex-wrap: wrap;
+.flex {
+ flex-grow: 1;
+.bg {
+ background-image: linear-gradient(to bottom, #faefe7, #ffcbd7);
+ overflow: hidden;
+.white-color {
+ color: #fff;
+.fs24 {
+ font-size: 24rpx;
+.fs28 {
+ font-size: 28rpx;
+.fs32 {
+ font-size: 32rpx;
+.fs36 {
+ font-size: 36rpx;
+.calendar {
+ box-sizing: border-box;
+/* 日历操作栏 */
+.handle {
+.prev-handle,
+.next-handle {
+ padding: 20rpx;
+.date-in-handle {
+/* 星期栏 */
+.weeks {
+ height: 50rpx;
+ line-height: 50rpx;
+ opacity: 0.5;
+.week {
+ text-align: center;
+.grid,
+ width: 14.286014285714286%;
+.date-wrap {
+ position: relative;
+ left: 0;
+ top: 0;
+.date {
+ width: 55rpx;
+ height: 55rpx;
+ line-height: 55rpx;
+ font-size: 38rpx;
+ padding: 10rpx;
+ font-weight: 200;
+ border-radius: 50%;
+ transition: all 0.3s;
+ animation-name: choosed;
+ animation-duration: 0.5s;
+ animation-timing-function: linear;
+ animation-iteration-count: 1;
+.date-desc {
+ width: 150%;
+ height: 32rpx;
+ font-size: 20rpx;
+ line-height: 32rpx;
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ word-break: break-all;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ -webkit-line-clamp: 1;
+@keyframes choosed {
+ from {
+ transform: scale(1);
+ 50% {
+ transform: scale(0.9);
+ to {
+/* 日期圆圈标记 */
+.todo-circle {
+ border-width: 1rpx;
+ border-style: solid;
+/* 待办点标记相关样式 */
+.todo-dot {
+ width: 10rpx;
+ height: 10rpx;
+.todo-dot-top {
+ top: 3rpx;
+.todo-dot.todo-dot-top-always {
+ top: -8rpx;
+.todo-dot.todo-dot-bottom {
+ bottom: 0;
+.todo-dot.todo-dot-bottom-always {
+ bottom: -10rpx;
+/* 日期描述文字(待办文字/农历)相关样式 */
+.date-desc.date-desc-top {
+ top: -6rpx;
+.date-desc.date-desc-top-always {
+ top: -20rpx;
+.date-desc.date-desc-bottom {
+ bottom: -14rpx;
+.date-desc.date-desc-bottom-always {
+ bottom: -28rpx;
@@ -0,0 +1,212 @@
+/* *
+ @Author: drfu*
+ @Description: 数据来源于国务院办公厅关于2020年部分节假日安排的通知(国办发明电〔2019〕16号)_政府信息公开专栏,http://www.gov.cn/zhengce/content/2019-11/21/content_5454164.htm
+ @Date: 2020-10-12 14:29:45*
+ * @Last Modified by: drfu
+ * @Last Modified time: 2020-10-16 17:38:08
+*/
+// 节日列表
+export const festival = {
+ // 农历固定日期节日
+ lunar: {
+ 1: {
+ type: 'festival',
+ name: '春节',
+ label: '春节'
+ 8: {
+ name: '腊八节',
+ label: '腊八'
+ 15: {
+ name: '元宵节',
+ label: '元宵'
+ 7: {
+ name: '七夕节',
+ label: '七夕'
+ name: '中元节',
+ label: '中元节'
+ 9: {
+ name: '重阳节',
+ label: '重阳节'
+ // 阳历固定日期节日
+ solar: {
+ 2: {
+ 14: {
+ name: '情人节',
+ label: '情人节'
+ 3: {
+ 12: {
+ name: '植树节',
+ label: '植树节'
+ 4: {
+ name: '愚人节',
+ label: '愚人节'
+ 5: {
+ name: '清明节',
+ label: '清明节'
+ name: '劳动节',
+ label: '劳动节'
+ 6: {
+ name: '儿童节',
+ label: '儿童节'
+ name: '建党节',
+ label: '建党节'
+ name: '建军节',
+ label: '建军节'
+ 10: {
+ name: '教师节',
+ label: '教师节'
+ name: '国庆节',
+ label: '国庆节'
+ 25: {
+ name: '圣诞节',
+ label: '圣诞节'
+export const holidays = {
+ 2020: {
+ type: 'holiday',
+ name: '元旦',
+ label: '休'
+ 19: {
+ type: 'work',
+ name: '调班',
+ label: '班'
+ '24-30': {
+ '4-6': {
+ 26: {
+ '1-5': {
+ '25-27': {
+ name: '端午节',
+ 28: {
+ 27: {
+ '1-8': {
+ name: '国庆节/中秋节',
@@ -0,0 +1,201 @@
+ @Description: 显示法定节假日班/休情况
+ * @Last Modified time: 2020-10-16 17:34:13
+import { holidays, festival } from './holidays-map'
+import { dateUtil, getCalendarData, logger } from '../../utils/index'
+ * 当前是否在休假期内
+ * @param {object} { year, month }
+ * @param {object} { start, end, current }
+ * @returns
+function inHolidays({ year, month }, { start, end, current }) {
+ const getTimeStamp = dateUtil.getTimeStamp
+ const startTimestamp = getTimeStamp({
+ date: start
+ const endTimestamp = getTimeStamp({
+ date: end
+ const currentDateTimestamp = getTimeStamp({
+ date: current
+ currentDateTimestamp <= endTimestamp
+function addSpecialFestival(date, component) {
+ const { convertlLunar2Solar, convertSolarLunar } = component.calendar || {}
+ const lunarDateInfo = convertSolarLunar(date)
+ const { lYear, lMonth } = lunarDateInfo || {}
+ // 春节
+ const info = {
+ name: '除夕',
+ label: '除夕'
+ if (lMonth === 12) {
+ if (!festival.lunar['12']) festival.lunar['12'] = {}
+ if (convertlLunar2Solar(`${lYear}-12-30`) === -1) {
+ festival.lunar['12']['29'] = info
+ festival.lunar['12']['30'] = info
+ * 是否匹配到节日
+ * @param {object} [dateInfo={}]
+ * @param {object} [component={}]
+ * @returns {object|boolean} 匹配到的节日数据或者false
+function hasFestivalDate(dateInfo = {}, component = {}) {
+ const { month, date } = dateInfo
+ let festivalDate = festival.solar[month] && festival.solar[month][date]
+ if (!festivalDate) {
+ const { convertSolarLunar } = component.calendar || {}
+ const lunarDateInfo = convertSolarLunar(dateInfo)
+ const { lMonth, lDay } = lunarDateInfo
+ festivalDate = festival.lunar[lMonth] && festival.lunar[lMonth][lDay]
+ const festivalOfMonth = festival.lunar[lMonth] || {}
+ const festivalDateKey = Object.keys(festivalOfMonth).find(item =>
+ item.match(new RegExp(`\\b${lDay}\\b`))
+ if (!festivalDateKey) {
+ festivalDate = false
+ const festivalInfo = festival.lunar[lMonth][festivalDateKey]
+ if (!festivalInfo) {
+ const { condition } = festivalInfo
+ if (typeof condition === 'function') {
+ festivalDate = condition(lunarDateInfo)
+ return festivalDate
+export default () => {
+ name: 'holidays',
+ beforeRender(calendarData = {}, calendarConfig = {}, component) {
+ let { dates = [] } = calendarData
+ if (calendarConfig.showHolidays || calendarConfig.showFestival) {
+ let item = { ...d }
+ const { year, month, date } = item
+ const holidaysOfMonth =
+ (holidays[year] && holidays[year][month]) || {}
+ const holidayDate = holidaysOfMonth[date]
+ if (holidayDate) {
+ item = {
+ ...holidayDate
+ const holidayKeys = Object.keys(holidaysOfMonth).filter(item =>
+ item.includes('-')
+ let target = ''
+ for (let v of holidayKeys) {
+ const [start, end] = v.split('-')
+ if (+d.date >= +start && +d.date <= +end) {
+ target = v
+ const [start, end] = target.split('-')
+ const isInHolidays = inHolidays(
+ current: date
+ if (isInHolidays) {
+ ...holidaysOfMonth[target]
+ } else if (calendarConfig.showFestival) {
+ const { convertSolarLunar, convertlLunar2Solar } =
+ component.calendar || {}
+ typeof convertSolarLunar !== 'function' ||
+ typeof convertlLunar2Solar !== 'function'
+ return logger.warn(
+ '农历节日显示需要引入农历插件(/component/v2/plugins/solarLunar)'
+ addSpecialFestival(item, component)
+ const festivalDate = hasFestivalDate(item, component)
+ if (festivalDate) {
+ ...festivalDate
+ return item
+ calendarData: {
+ ...calendarData,
+ dates: dates
+ calendarConfig
+ methods(component) {
+ getHolidaysOfCurrentYear() {
+ const calendar = getCalendarData('calendar', component)
+ const { curYear } = calendar
+ return this.methods(component).getHolidaysOfYear(curYear)
+ getHolidaysOfYear(year) {
+ if (!year) return logger.warn('getHolidaysOfCurrentYear() 入参错误')
+ if (!holidays[year]) {
+ logger.warn('未匹配到当前年份节假日信息,请自行补充')
+ err: 'not match'
+ return holidays[year]
@@ -0,0 +1,18 @@
+import preset from './preset/index'
+export default {
+ installed: [...preset],
+ use(plugin) {
+ if (typeof plugin !== 'function') return
+ const info = plugin() || {}
+ const { name } = info
+ name &&
+ name !== 'methods' &&
+ !this.installed.some(p => p[0] === name)
+ this.installed.unshift([name, info])
+ return this
@@ -0,0 +1,277 @@
+ * @Author: drfu*
+ * @Description: 基础功能
+ * @Date: 2020-10-08 21:22:09*
+ * @Last Modified time: 2020-10-11 13:28:52
+ * */
+import { calcJumpData } from '../../core'
+import { renderCalendar } from '../../render'
+ dateUtil,
+ getCalendarData,
+ setCalendarData,
+ getCalendarConfig
+} from '../../utils/index'
+ name: 'base',
+ beforeRender(calendarData = {}, calendarConfig) {
+ const calendar = calendarData
+ const { selectedDates = [], dates } = calendar
+ let _dates = [...dates]
+ if (selectedDates.length) {
+ const selectedDatesStr = selectedDates.map(date =>
+ dateUtil.toTimeStr(date)
+ _dates.forEach(date => {
+ const dateStr = dateUtil.toTimeStr(date)
+ if (selectedDatesStr.includes(dateStr)) {
+ dates: _dates
+ onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) {
+ ...calendarData
+ const dateIndex = dateUtil.findDateIndexInArray(
+ tapedDate,
+ calendarData.dates
+ const { multi, inverse } = calendarConfig
+ let dates = [...calendar.dates]
+ const { selectedDates = [] } = calendar
+ let preSelectedDate = {}
+ preSelectedDate = [...selectedDates].pop() || {}
+ const timeStr = dateUtil.toTimeStr
+ if (!inverse && timeStr(preSelectedDate) === timeStr(tapedDate)) {
+ let _tapedDate = { ...tapedDate, choosed: !tapedDate.choosed }
+ dates[dateIndex] = _tapedDate
+ if (preSelectedDate.date) {
+ const idx = dateUtil.findDateIndexInArray(preSelectedDate, dates)
+ const date = dates[idx]
+ if (dates[dateIndex].choosed) {
+ calendar.selectedDates = [dates[dateIndex]]
+ calendar.selectedDates = []
+ dates[dateIndex] = {
+ ...dates[dateIndex],
+ choosed: !dates[dateIndex].choosed
+ if (!calendar.selectedDates) {
+ calendar.selectedDates.push(dates[dateIndex])
+ calendar.selectedDates = calendar.selectedDates.filter(
+ dateUtil.toTimeStr(date) !== dateUtil.toTimeStr(dates[dateIndex])
+ ...calendar,
+ dates
+ onSwitchCalendar(date, calendarData = {}, component) {
+ const calendarConfig = getCalendarConfig(component)
+ if (calendarConfig.weekMode) {
+ return calendarData
+ const updatedRenderData = calcJumpData({
+ config: calendarConfig
+ ...updatedRenderData
+ jump: dateInfo => {
+ if (Object.prototype.toString.call(dateInfo) !== '[object Object]')
+ dateInfo,
+ component
+ const existCalendarData = getCalendarData('calendar', component)
+ const config = getCalendarConfig(component)
+ const target = updatedRenderData.dates[dateInfo.date - 1]
+ if (!updatedRenderData.selectedDates) {
+ updatedRenderData.selectedDates = [target]
+ updatedRenderData.selectedDates.push(target)
+ return renderCalendar.call(component, {
+ ...existCalendarData,
+ return getCalendarConfig(component)
+ if (!component || !component.data.config) {
+ let conf = { ...component.config, ...config }
+ component.config = conf
+ setCalendarData({ config: conf }, component)
+ cancelSelectedDates(cancelDates = []) {
+ const existCalendarData = getCalendarData('calendar', component) || {}
+ const { dates = [], selectedDates = [] } = existCalendarData
+ let updatedRenderData = {}
+ let chooseAreaData = {}
+ if (config.chooseAreaMode) {
+ chooseAreaData = {
+ chooseAreaTimestamp: [],
+ tempChooseAreaTimestamp: []
+ if (!cancelDates.length) {
+ updatedRenderData = {
+ selectedDates: []
+ const cancelDatesStr = cancelDates.map(date =>
+ const filterSelectedDates = selectedDates.filter(
+ date => !cancelDatesStr.includes(dateUtil.toTimeStr(date))
+ dates.forEach(date => {
+ if (cancelDatesStr.includes(dateUtil.toTimeStr(date))) {
+ selectedDates: filterSelectedDates
+ ...updatedRenderData,
+ ...chooseAreaData
+ setSelectedDates: targetDates => {
+ let { dates, selectedDates = [] } = existCalendarData || {}
+ let __selectedDates = []
+ let __dates = dates
+ if (!targetDates) {
+ __dates = dates.map(item => {
+ const date = { ...item }
+ if (existCalendarData.showLabelAlways && date.showTodoLabel) {
+ date.showTodoLabel = false
+ __selectedDates = dates
+ } else if (targetDates && targetDates.length) {
+ const allSelected = dateUtil.uniqueArrayByDate(
+ selectedDates.concat(targetDates)
+ const allSelectedDateStr = allSelected.map(d =>
+ dateUtil.toTimeStr(d)
+ if (allSelectedDateStr.includes(dateUtil.toTimeStr(date))) {
+ __selectedDates.push(date)
+ dates: __dates,
+ selectedDates: __selectedDates
+ setDateStyle: toSetDates => {
+ if (!Array.isArray(toSetDates)) return Promise.reject()
+ const { dates = [], specialStyleDates } = existCalendarData || {}
+ if (Array.isArray(specialStyleDates)) {
+ toSetDates = dateUtil.uniqueArrayByDate([
+ ...specialStyleDates,
+ ...toSetDates
+ const toSetDatesStr = toSetDates.map(item => dateUtil.toTimeStr(item))
+ const _dates = dates.map(item => {
+ const idx = toSetDatesStr.indexOf(dateUtil.toTimeStr(item))
+ class: toSetDates[idx].class
+ dates: _dates,
+ specialStyleDates: toSetDates
@@ -0,0 +1,69 @@
+ * @Description: 获取日历数据
+ * @Last Modified time: 2020-10-11 13:42:37
+import { getCalendarData, logger, getCalendarConfig } from '../../utils/index'
+function wrapDateWithLunar(dates = [], convertFn) {
+ const datesWithLunar = JSON.parse(JSON.stringify(dates)).map(date => ({
+ ...date,
+ lunar: convertFn(date)
+ }))
+ name: 'getData',
+ getCurrentYM: () => {
+ const { curYear, curMonth } = getCalendarData('calendar', component)
+ getSelectedDates: (options = {}) => {
+ const dates =
+ getCalendarData('calendar.selectedDates', component) || []
+ const config = getCalendarConfig(component) || {}
+ const injectedFns = component.calendar || {}
+ if (typeof injectedFns.convertSolarLunar === 'function') {
+ return wrapDateWithLunar(dates, injectedFns.convertSolarLunar)
+ logger.warn('获取农历信息需引入农历插件')
+ getCalendarDates: (options = {}) => {
+ const dates = getCalendarData('calendar.dates', component)
+ getCalendarAllData: () => {
+ data: getCalendarData('calendar', component) || {},
+ config: getCalendarConfig(component) || {}
@@ -0,0 +1,9 @@
+import base from './base'
+import getCalendarData from './get-calendar-data'
+const preset = [
+ ['base', base()],
+ ['get-calendar-data', getCalendarData()]
+]
+export default preset
@@ -0,0 +1,219 @@
+ * @Description: 禁用、启用日期选择
+ * @Last Modified time: 2020-10-08 21:25:00
+import { getCalendarData, dateUtil, logger } from '../utils/index'
+import { renderCalendar } from '../render'
+function convertEnableAreaToTimestamp(timearea = []) {
+ const startTimestamp = dateUtil
+ .newDate(start[0], start[1], start[2])
+ const endTimestamp = dateUtil.newDate(end[0], end[1], end[2]).getTime()
+function isValiditeOfDateArea(dateArea) {
+ const datesCountOfStart = dateUtil.getDatesCountOfMonth(start[0], start[1])
+ const datesCountOfEnd = dateUtil.getDatesCountOfMonth(end[0], end[1])
+ if (start[2] > datesCountOfStart || start[2] < 1) {
+ logger.warn('enableArea() 开始日期错误,指定日期不在指定月份天数范围内')
+ } else if (end[2] > datesCountOfEnd || end[2] < 1) {
+ logger.warn('enableArea() 截止日期错误,指定日期不在指定月份天数范围内')
+function handleDisableMode(calendarConfig) {
+ const { disableMode } = calendarConfig
+ if (!disableMode) return {}
+ const disableBound =
+ dateUtil.getTimeStamp(disableMode.date) || dateUtil.todayTimestamp()
+ disableBound,
+ disableType: disableMode.type
+function disabledByConfig(dateInfo, currentDate, calendarConfig) {
+ const { disableType, disableBound } = handleDisableMode(calendarConfig)
+ (disableType === 'before' && disableBound && currentDate < disableBound) ||
+ (disableType === 'after' && disableBound && currentDate > disableBound)
+ date.disable = false
+ name: 'enable',
+ beforeRender(calendarData = {}, calendarConfig = {}) {
+ enableDates,
+ disableDates,
+ renderCausedBy
+ } = calendarData
+ const _dates = [...dates].map(date => {
+ let item = { ...date }
+ const timeStr = dateUtil.toTimeStr(date)
+ const timestamp = +dateUtil.getTimeStamp(item)
+ if (renderCausedBy === 'enableDates') {
+ if (enableDates && enableDates.length) {
+ if (enableDates.includes(timeStr)) {
+ } else if (renderCausedBy === 'enableArea') {
+ if (enableArea && enableArea.length) {
+ const [startTimestamp, endTimestamp] = enableArea || []
+ +startTimestamp > timestamp || timestamp > +endTimestamp
+ item.disable = ifOutofArea
+ } else if (renderCausedBy === 'disableDates') {
+ if (disableDates && disableDates.length) {
+ if (disableDates && disableDates.includes(timeStr)) {
+ return disabledByConfig(item, timestamp, calendarConfig)
+ enableArea: (dateArea = []) => {
+ const validate = isValiditeOfDateArea(dateArea)
+ if (validate) {
+ renderCausedBy: 'enableArea',
+ enableArea: [startTimestamp, endTimestamp]
+ return Promise.inject(
+ enableDates: (toSet = []) => {
+ if (!toSet.length) return
+ const { enableDates = [] } = existCalendarData || {}
+ let toSetDates = toSet.map(item => {
+ if (typeof item === 'string') {
+ return dateUtil.transformDateRow2Dict(item)
+ if (enableDates.length) {
+ ...toSetDates,
+ ...enableDates.map(d => dateUtil.transformDateRow2Dict(d))
+ renderCausedBy: 'enableDates',
+ enableDates: toSetDates.map(date => {
+ if (typeof date !== 'string') {
+ return dateUtil.toTimeStr(date)
+ disableDates: toSet => {
+ const { disableDates = [], dates = [] } = existCalendarData || {}
+ if (typeof date === 'string') {
+ ...disableDates.map(d => dateUtil.transformDateRow2Dict(d))
+ renderCausedBy: 'disableDates',
+ disableDates: toSetDates.map(date => {
@@ -0,0 +1,59 @@
+import { dateUtil } from '../../utils/index'
+function getDateRow2Dict(dateInfo) {
+ if (!dateInfo) return dateInfo
+ if (typeof dateInfo === 'string' && dateInfo.includes('-')) {
+ dateInfo = dateUtil.transformDateRow2Dict(dateInfo)
+ return dateInfo
+ name: 'convertSolarLunar',
+ let { dates = [], selectedDates = [] } = calendarData
+ if (calendarConfig.showLunar) {
+ dates = dates.map(dataInfo => {
+ const { year, month, date } = dataInfo
+ ...dataInfo,
+ lunar: convertSolarLunar.solar2lunar(year, month, date)
+ selectedDates = selectedDates.map(dataInfo => {
+ dates: dates,
+ selectedDates: selectedDates
+ methods() {
+ convertSolarLunar: dateInfo => {
+ dateInfo = getDateRow2Dict(dateInfo)
+ return convertSolarLunar.solar2lunar(year, month, date)
+ convertlLunar2Solar: (dateInfo, isLeapMonth) => {
+ return convertSolarLunar.lunar2solar(year, month, date, isLeapMonth)
@@ -0,0 +1,305 @@
+ * @Description: 时间区域选择
+ * @Last Modified time: 2020-10-11 13:56:32
+ logger,
+ getCalendarData
+} from '../utils/index'
+function pusheNextMonthDateArea(
+ dateInfo = {},
+ selectedDates = []
+) {
+ let tempOfSelectedDate = [...selectedDates]
+ const dates = dateUtil.calcDates(dateInfo.year, dateInfo.month)
+ let datesLen = dates.length
+ for (let i = 0; i < datesLen; i++) {
+ const date = dates[i]
+ const timeStamp = dateUtil.getTimeStamp(date)
+ tempOfSelectedDate.push({
+ if (i === datesLen - 1 && timeStamp < endTimestamp) {
+ pusheNextMonthDateArea(
+ dateUtil.getNextMonthInfo(date),
+ tempOfSelectedDate
+ return tempOfSelectedDate
+function pushPrevMonthDateArea(
+ const dates = dateUtil.sortDatesByTime(
+ dateUtil.calcDates(dateInfo.year, dateInfo.month),
+ let firstDate = dateUtil.getTimeStamp(dates[0])
+ if (i === datesLen - 1 && firstDate > startTimestamp) {
+ pushPrevMonthDateArea(
+ dateUtil.getPrevMonthInfo(date),
+function calcDateWhenNotInOneMonth(info) {
+ const { firstDate, lastDate, startTimestamp, endTimestamp } = info
+ let { selectedDate } = info
+ if (dateUtil.getTimeStamp(firstDate) > startTimestamp) {
+ selectedDate = pushPrevMonthDateArea(
+ dateUtil.getPrevMonthInfo(firstDate),
+ selectedDate
+ if (dateUtil.getTimeStamp(lastDate) < endTimestamp) {
+ selectedDate = pusheNextMonthDateArea(
+ dateUtil.getNextMonthInfo(lastDate),
+ return [...selectedDate]
+export function convertTimeRangeToTimestamp(timearea = []) {
+ * 校验时间区域是否合法
+ * @param {array} dateArea 时间区域
+function validateTimeRange(dateArea) {
+ } = convertTimeRangeToTimestamp(dateArea)
+ const startMonthDays = dateUtil.getDatesCountOfMonth(start[0], start[1])
+ const endMonthDays = dateUtil.getDatesCountOfMonth(end[0], end[1])
+ name: 'timeRange',
+ dates = [],
+ let __selectedDates = selectedDates
+ const [startDateTimestamp, endDateTimestamp] = chooseAreaTimestamp
+ if (chooseAreaTimestamp.length === 2) {
+ __selectedDates = []
+ __dates = dates.map(d => {
+ const date = { ...d }
+ const dateTimeStamp = dateUtil.getTimeStamp(date)
+ dateTimeStamp >= startDateTimestamp &&
+ endDateTimestamp >= dateTimeStamp
+ __selectedDates = __selectedDates.filter(
+ item => dateUtil.getTimeStamp(item) !== dateTimeStamp
+ const monthOfStartDate = new Date(startDateTimestamp).getMonth()
+ const monthOfEndDate = new Date(endDateTimestamp).getMonth()
+ if (monthOfStartDate !== monthOfEndDate) {
+ __selectedDates = calcDateWhenNotInOneMonth({
+ firstDate: __dates[0],
+ lastDate: __dates[__dates.length - 1],
+ startTimestamp: startDateTimestamp,
+ endTimestamp: endDateTimestamp,
+ selectedDate: __selectedDates
+ selectedDates: dateUtil.sortDatesByTime(
+ dateUtil.uniqueArrayByDate(__selectedDates)
+ if (!calendarConfig.chooseAreaMode) {
+ calendarData,
+ let {
+ tempChooseAreaTimestamp = [],
+ chooseAreaTimestamp: existChooseAreaTimestamp = [],
+ selectedDates = [],
+ dates = []
+ const timestamp = dateUtil.getTimeStamp(tapedDate)
+ let __dates = [...dates]
+ let __selectedDates = [...selectedDates]
+ tempChooseAreaTimestamp.length === 2 ||
+ existChooseAreaTimestamp.length === 2
+ tempChooseAreaTimestamp = [tapedDate]
+ __dates.forEach(d => (d.choosed = false))
+ } else if (tempChooseAreaTimestamp.length === 1) {
+ const preChoosedDate = tempChooseAreaTimestamp[0]
+ const preTimestamp = dateUtil.getTimeStamp(preChoosedDate)
+ if (preTimestamp <= timestamp) {
+ tempChooseAreaTimestamp.push(tapedDate)
+ } else if (preTimestamp > timestamp) {
+ tempChooseAreaTimestamp.unshift(tapedDate)
+ let chooseAreaTimestamp = []
+ if (tempChooseAreaTimestamp.length === 2) {
+ const [startDate, endDate] = tempChooseAreaTimestamp
+ const startDateTimestamp = dateUtil.getTimeStamp(startDate)
+ const endDateTimestamp = dateUtil.getTimeStamp(endDate)
+ chooseAreaTimestamp = [startDateTimestamp, endDateTimestamp]
+ chooseAreaTimestamp,
+ tempChooseAreaTimestamp,
+ ...calendarConfig,
+ multi: true
+ chooseDateArea: (dateArea = []) => {
+ if (dateArea.length !== 2) return
+ const isRight = validateTimeRange(dateArea)
+ if (!isRight) return
+ const { startTimestamp, endTimestamp } = convertTimeRangeToTimestamp(
+ return renderCalendar.call(
+ component,
+ chooseAreaTimestamp: [startTimestamp, endTimestamp]
+ multi: true,
+ chooseAreaMode: true
@@ -0,0 +1,135 @@
+ * @Description: 代办事项
+ * @Last Modified time: 2020-10-11 14:23:02
+import { getCalendarData, dateUtil } from '../utils/index'
+function updateDatePropertyOfTodoLabel(todos, dates, showLabelAlways) {
+ const datesInfo = [...dates]
+ for (let todo of todos) {
+ let targetIdx = datesInfo.findIndex(
+ item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(todo)
+ let target = datesInfo[targetIdx]
+ return datesInfo
+ name: 'todo',
+ const { todos = [], dates = [], showLabelAlways } = calendarData
+ const dateWithTodoInfo = updateDatePropertyOfTodoLabel(
+ todos,
+ showLabelAlways
+ dates: dateWithTodoInfo
+ setTodos: (options = {}) => {
+ if (!calendar || !calendar.dates) {
+ return Promise.reject('请等待日历初始化完成后再调用该方法')
+ dates: todoDates = []
+ } = options
+ const { todos = [] } = calendar
+ const tranformStr2NumOfTodo = todoDates.map(date =>
+ dateUtil.tranformStr2NumOfDate(date)
+ const calendarData = {
+ dates: calendar.dates,
+ todos: dateUtil.uniqueArrayByDate(
+ todos.concat(tranformStr2NumOfTodo)
+ calendarData.todoLabelPos = pos
+ calendarData.todoLabelColor = dotColor
+ calendarData.todoLabelCircle = circle || false
+ calendarData.showLabelAlways = showLabelAlways || false
+ deleteTodos(todos = []) {
+ if (!(todos instanceof Array) || !todos.length)
+ return Promise.reject('deleteTodos()应为入参为非空数组')
+ const allTodos = existCalendarData.todos || []
+ const toDeleteTodos = todos.map(item => dateUtil.toTimeStr(item))
+ const remainTodos = allTodos.filter(
+ item => !toDeleteTodos.includes(dateUtil.toTimeStr(item))
+ const { dates, curYear, curMonth } = existCalendarData
+ const _dates = [...dates]
+ const currentMonthTodos = dateUtil.filterDatesByYM(
+ remainTodos
+ _dates.forEach(item => {
+ currentMonthTodos.forEach(item => {
+ _dates[item.date - 1].showTodoLabel = !_dates[item.date - 1].choosed
+ todos: remainTodos
+ clearTodos() {
+ const _dates = [...existCalendarData.dates]
+ todos: []
+ getTodos() {
+ return getCalendarData('calendar.todos', component) || []
@@ -0,0 +1,432 @@
+ * @Description: 周视图
+ * @Last Modified time: 2020-10-12 14:39:45
+ dateUtil
+import { calcJumpData } from '../core'
+ * 当月第一周所有日期
+function firstWeekInMonth(
+ target = {},
+ calendarDates = [],
+ calendarConfig = {}
+ const { firstDayOfWeek } = calendarConfig
+ const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon'
+ let firstDay = dateUtil.getDayOfWeek(year, month, 1)
+ return calendarDates.slice(0, firstDayOfWeekIsMon ? end + 1 : end)
+ * 当月最后一周所有日期
+function lastWeekInMonth(target = {}, calendarDates = [], calendarConfig = {}) {
+ const lastDay = dateUtil.getDatesCountOfMonth(year, month)
+ let lastDayWeek = dateUtil.getDayOfWeek(year, month, lastDay)
+ if (firstDayOfWeekIsMon && lastDayWeek === 0) {
+ lastDayWeek = 7
+ return calendarDates.slice(firstDayOfWeekIsMon ? start : start - 1, end)
+ * 判断目标日期是否在某些指定日历内
+function dateIsInDatesRange(target, dates) {
+ if (!target || !dates || !dates.length) return false
+ const targetDateStr = dateUtil.toTimeStr(target)
+ let rst = false
+ for (let date of dates) {
+ if (dateStr === targetDateStr) {
+ rst = true
+ return rst
+ rst = false
+function getDatesWhenTargetInFirstWeek(target, firstWeekDates) {
+ const prevMonthInfo = dateUtil.getPrevMonthInfo({ year, month })
+ let lastMonthDatesCount = dateUtil.getDatesCountOfMonth(
+ prevMonthInfo.year,
+ prevMonthInfo.month
+ let dates = firstWeekDates
+ let firstWeekCount = firstWeekDates.length
+ for (let i = 0; i < 7 - firstWeekCount; i++) {
+ const week = dateUtil.getDayOfWeek(+year, +month, lastMonthDatesCount)
+ year: prevMonthInfo.year,
+ month: prevMonthInfo.month,
+ date: lastMonthDatesCount,
+ lastMonthDatesCount -= 1
+function getDatesWhenTargetInLastWeek(target, lastWeekDates) {
+ const prevMonthInfo = dateUtil.getNextMonthInfo({ year, month })
+ let dates = lastWeekDates
+ let lastWeekCount = lastWeekDates.length
+ for (let i = 0; i < 7 - lastWeekCount; i++) {
+ const week = dateUtil.getDayOfWeek(+year, +month, i + 1)
+ date: i + 1,
+function getDates(target, calendarDates = [], calendarConfig = {}) {
+ const { year, month, date } = target
+ const targetDay = dateUtil.getDayOfWeek(year, month, date)
+ const startIdx = date - (targetDay || 7)
+ return calendarDates.splice(startIdx, 7)
+ const startIdx = date - targetDay - 1
+function getTargetWeekDates(target, calendarConfig) {
+ if (!target) return
+ const calendarDates = dateUtil.calcDates(year, month)
+ const firstWeekDates = firstWeekInMonth(target, calendarDates, calendarConfig)
+ const lastWeekDates = lastWeekInMonth(target, calendarDates, calendarConfig)
+ if (dateIsInDatesRange(target, firstWeekDates)) {
+ return getDatesWhenTargetInFirstWeek(target, firstWeekDates)
+ } else if (dateIsInDatesRange(target, lastWeekDates)) {
+ return getDatesWhenTargetInLastWeek(target, lastWeekDates)
+ return getDates(target, calendarDates, calendarConfig)
+ * 计算周视图下当前这一周最后一天
+function calculateLastDateOfCurrentWeek(calendarData = {}) {
+ const { dates = [] } = calendarData
+ return dates[dates.length - 1]
+function calculateFirstDateOfCurrentWeek(calendarData = {}) {
+ const { dates } = calendarData
+ return dates[0]
+function calculateNextWeekDates(calendarData = {}) {
+ let { curYear, curMonth } = calendarData
+ let calendarDates = []
+ let lastDateInThisWeek = calculateLastDateOfCurrentWeek(calendarData)
+ const { year: LYear, month: LMonth } = lastDateInThisWeek
+ if (curYear !== LYear || curMonth !== LMonth) {
+ calendarDates = dateUtil.calcDates(LYear, LMonth)
+ curYear = LYear
+ curMonth = LMonth
+ calendarDates = dateUtil.calcDates(curYear, curMonth)
+ const lastDateInThisMonth = dateUtil.getDatesCountOfMonth(curYear, curMonth)
+ const count = lastDateInThisMonth - lastDateInThisWeek.date
+ const lastDateIdx = calendarDates.findIndex(
+ date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(lastDateInThisWeek)
+ const startIdx = lastDateIdx + 1
+ if (count >= 7) {
+ dates: calendarDates.splice(startIdx, 7),
+ const nextMonth = dateUtil.getNextMonthInfo({
+ const { year, month } = nextMonth || {}
+ const calendarDatesOfNextMonth = dateUtil.calcDates(year, month)
+ const remainDatesOfThisMonth = calendarDates.splice(startIdx)
+ const patchDatesOfNextMonth = calendarDatesOfNextMonth.splice(
+ 0,
+ 7 - remainDatesOfThisMonth.length
+ dates: [...remainDatesOfThisMonth, ...patchDatesOfNextMonth],
+ ...nextMonth
+function calculatePrevWeekDates(calendarData = {}) {
+ let firstDateInThisWeek = calculateFirstDateOfCurrentWeek(calendarData)
+ const { year: FYear, month: FMonth } = firstDateInThisWeek
+ if (curYear !== FYear || curMonth !== FMonth) {
+ calendarDates = dateUtil.calcDates(FYear, FMonth)
+ curYear = FYear
+ curMonth = FMonth
+ const firstDateIdx = calendarDates.findIndex(
+ date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(firstDateInThisWeek)
+ if (firstDateIdx - 7 >= 0) {
+ const startIdx = firstDateIdx - 7
+ const prevMonth = dateUtil.getPrevMonthInfo({
+ const { year, month } = prevMonth || {}
+ const calendarDatesOfPrevMonth = dateUtil.calcDates(year, month)
+ const remainDatesOfThisMonth = calendarDates.splice(
+ firstDateInThisWeek.date - 1
+ const patchDatesOfPrevMonth = calendarDatesOfPrevMonth.splice(
+ -(7 - remainDatesOfThisMonth.length)
+ dates: [...patchDatesOfPrevMonth, ...remainDatesOfThisMonth],
+ ...prevMonth
+ name: 'week',
+ const { initializedWeekMode, selectedDates } = calendarData
+ if (calendarConfig.weekMode && !initializedWeekMode) {
+ const { defaultDate } = calendarConfig
+ const target =
+ (selectedDates && selectedDates[0]) ||
+ (defaultDate && dateUtil.transformDateRow2Dict(defaultDate)) ||
+ const waitRenderData = this.methods(
+ ).__calcDatesWhenSwitchView('week', target)
+ const { data, config } = waitRenderData || {}
+ const setSelectDates = this.methods(
+ ).__selectTargetDateWhenJump(target, data.dates, config)
+ ...data,
+ ...setSelectDates,
+ weeksCh: dateUtil.getWeekHeader(calendarConfig.firstDayOfWeek),
+ initializedWeekMode: true
+ onSwitchCalendar(target = {}, calendarData = {}, component) {
+ const { direction } = target
+ let waitRenderData = {}
+ if (direction === 'left') {
+ waitRenderData = calculateNextWeekDates(calendarData)
+ waitRenderData = calculatePrevWeekDates(calendarData)
+ const { dates, year, month } = waitRenderData
+ curYear: year || curYear,
+ curMonth: month || curMonth
+ __selectTargetDateWhenJump: (target = {}, dates = [], config = {}) => {
+ let selectedDate = target
+ const weekDates = dates.map((date, idx) => {
+ const tmp = { ...date }
+ tmp.id = idx
+ const isTarget =
+ dateUtil.toTimeStr(target) === dateUtil.toTimeStr(tmp)
+ if (isTarget && !target.choosed && config.autoChoosedWhenJump) {
+ tmp.choosed = true
+ selectedDate = tmp
+ dates: weekDates,
+ selectedDates: [selectedDate]
+ __calcDatesForWeekMode(target, config = {}, calendarData = {}) {
+ const { year, month } = target || {}
+ const weekDates = getTargetWeekDates(target, config)
+ weekDates.forEach((date, idx) => (date.id = idx))
+ prevMonthGrids: null,
+ nextMonthGrids: null,
+ curMonth: month
+ weekMode: true
+ __calcDatesForMonthMode(target, config = {}, calendarData = {}) {
+ dateInfo: target,
+ weekMode: false
+ * @param {object} target
+ __calcDatesWhenSwitchView: (view, target) => {
+ if (calendarConfig.multi)
+ return logger.warn('多选模式不能切换周月视图')
+ curMonth
+ } = existCalendarData
+ const currentMonthSelected = selectedDates.filter(
+ item => curYear === +item.year || curMonth === +item.month
+ let jumpTarget = {}
+ jumpTarget = target
+ if (currentMonthSelected.length) {
+ jumpTarget = currentMonthSelected.pop()
+ jumpTarget = dates[0]
+ return this.methods(component).__calcDatesForWeekMode(
+ jumpTarget,
+ calendarConfig,
+ existCalendarData
+ return this.methods(component).__calcDatesForMonthMode(
+ weekModeJump: dateInfo => {
+ const target = dateInfo || dateUtil.todayFMD()
+ ...setSelectDates
+ switchView: (view, target) => {
+ ).__calcDatesWhenSwitchView(view, target)
+ if (!data) return logger.warn('当前状态不能切换为周视图')
+ return renderCalendar.call(component, data, config)
@@ -0,0 +1,51 @@
+import { getCalendarConfig } from './utils/index'
+export function renderCalendar(calendarData, calendarConfig) {
+ const Component = this
+ if (Component.firstRender === void 0) {
+ Component.firstRender = false
+ const exitData = Component.data.calendar || {}
+ if (typeof p.beforeRender === 'function') {
+ calendarData: newData,
+ calendarConfig: newConfig
+ } = p.beforeRender(
+ { ...exitData, ...calendarData },
+ calendarConfig || getCalendarConfig(Component),
+ Component
+ calendarData = newData
+ calendarConfig = newConfig
+ Component.setData(
+ config: calendarConfig,
+ calendar: calendarData
+ const rst = {
+ calendar: calendarData,
+ firstRender: Component.firstRender
+ resolve(rst)
+ if (Component.firstRender) {
+ Component.triggerEvent('afterCalendarRender', rst)
@@ -27,4 +27,3 @@
.icon-doubleright::before {
content: "\e7ee";
@@ -0,0 +1,61 @@
+/* 日历主要颜色相关样式 */
+.default_color,
+.default_weekend-color,
+.default_handle-color,
+.default_week-color {
+ color: #ff629a;
+.default_today {
+ background-color: #874fb4;
+.default_choosed {
+ background-color: #ff629a;
+.default_date-disable {
+ color: #c7c7c7;
+.default_choosed.default_date-disable {
+ color: #e2e2e2;
+ background-color: #c2afb6;
+.default_prev-month-date,
+.default_next-month-date {
+.default_normal-date {
+ color: #88d2ac;
+.default_todo-circle {
+ border-color: #88d2ac;
+.default_todo-dot {
+ background-color: #e54d42;
+.default_date-desc {
+ color: #c2c2c2;
+.default_date-desc-lunar {
+ color: #e54d42;
+.default_date-desc-disable {
+.default_festival {
@@ -0,0 +1,58 @@
+.elegant_color,
+.elegant_weekend-color,
+.elegant_handle-color,
+.elegant_week-color {
+ color: #333;
+.elegant_today {
+ color: #000;
+ background-color: #e1e7f5;
+.elegant_choosed {
+ background-color: #e2e2e2;
+.elegant_date-disable {
+.elegant_choosed.elegant_date-disable {
+ color: #999;
+ background-color: #ebebeb;
+.elegant_prev-month-date,
+.elegant_next-month-date {
+.elegant_normal-date {
+ color: #777;
+.elegant_todo-circle {
+ border-color: #161035;
+.elegant_todo-dot {
+ background-color: #161035;
+.elegant_date-desc {
+.elegant_date-desc-lunar {
+ color: #161035;
+.elegant_date-desc-disable {
+.elegant_festival {
@@ -0,0 +1,285 @@
+import Logger from './logger'
+class Gesture {
+class DateUtil {
+ newDate(year, month, date) {
+ let cur = `${+year}-${+month}-${+date}`
+ cur = `${+year}/${+month}/${+date}`
+ * @param {object} date
+ getTimeStamp(dateInfo) {
+ if (typeof dateInfo === 'string') {
+ dateInfo = this.transformDateRow2Dict(dateInfo)
+ const dateUtil = new DateUtil()
+ return dateUtil
+ .newDate(dateInfo.year, dateInfo.month, dateInfo.date)
+ getDatesCountOfMonth(year, month) {
+ getDayOfWeek(year, month, date) {
+ todayFMD() {
+ date: +date
+ const { year, month, date } = this.todayFMD()
+ toTimeStr(dateInfo = {}) {
+ transformDateRow2Dict(dateStr) {
+ if (typeof dateStr === 'string' && dateStr.includes('-')) {
+ const [year, month, date] = dateStr.split('-')
+ return this.tranformStr2NumOfDate({
+ tranformStr2NumOfDate(date = {}) {
+ const target = { ...date }
+ // 可能传入字符串
+ target.year = +target.year
+ target.month = +target.month
+ target.date = +target.date
+ return target
+ sortDatesByTime(dates = [], sortType) {
+ return dates.sort((a, b) => {
+ const at = this.getTimeStamp(a)
+ const bt = this.getTimeStamp(b)
+ getPrevMonthInfo(date = {}) {
+ Number(date.month) > 1
+ year: +date.year,
+ month: Number(date.month) - 1
+ year: Number(date.year) - 1,
+ getNextMonthInfo(date = {}) {
+ Number(date.month) < 12
+ month: Number(date.month) + 1
+ year: Number(date.year) + 1,
+ getPrevYearInfo(date = {}) {
+ month: +date.month
+ getNextYearInfo(date = {}) {
+ findDateIndexInArray(target, dates) {
+ return dates.findIndex(
+ item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(target)
+ calcDates(year, month) {
+ const datesCount = this.getDatesCountOfMonth(year, month)
+ for (let i = 1; i <= datesCount; i++) {
+ week,
+ isToday:
+ uniqueArrayByDate(array = []) {
+ uniqueObject[dateUtil.toTimeStr(item)] = item
+ * 筛选指定年月日期
+ * @param {array} dates 待筛选日期
+ filterDatesByYM(target, dates) {
+ const _dates = dates.filter(
+ return _dates
+ getWeekHeader(firstDayOfWeek) {
+ return weeksCh
+ const pages = getCurrentPages() || []
+ return pages[last] || {}
+export function getComponentById(componentId) {
+export const logger = new Logger()
+export const calendarGesture = new Gesture()
+export const dateUtil = new DateUtil()
+export const getCalendarData = (key, component) =>
+ new WxData(component).getData(key)
+export const setCalendarData = (data, component) =>
+ new WxData(component).setData(data)
+export const getCalendarConfig = component =>
+ getCalendarData('config', component)
+export const setCalendarConfig = (config, component) =>
+ setCalendarData(
@@ -0,0 +1,23 @@
+export default class Logger {
@@ -0,0 +1,30 @@
+ setData(data) {
+ if (!data) return reject('no data to set')
+ this.Component.setData(data, () => {
@@ -0,0 +1,318 @@
+ showLunar: true
+ // chooseAreaMode: true,
+ // firstDayOfWeek: 'Mon',
+ // disableMode: {
+ // type: 'after',
+ // date: '2020-03-9'
+ // },
+ // defaultDay: '2020-3-6'
+ // multi: true
+ actionBtn: [
+ text: '跳转指定日期',
+ action: 'jump',
+ color: 'olive'
+ text: '获取当前已选',
+ action: 'getSelectedDay',
+ color: 'red'
+ text: '取消选中日期',
+ action: 'cancelSelectedDates',
+ color: 'mauve'
+ text: '设置待办事项',
+ action: 'setTodoLabels',
+ color: 'cyan'
+ text: '删除指定代办',
+ action: 'deleteTodoLabels',
+ color: 'pink'
+ text: '清空待办事项',
+ action: 'clearTodoLabels',
+ text: '获取所有代办',
+ action: 'getTodoLabels',
+ color: 'purple'
+ text: '禁选指定日期',
+ action: 'disableDay',
+ text: '指定可选区域',
+ action: 'enableArea',
+ text: '指定特定可选',
+ action: 'enableDays',
+ text: '选中指定日期',
+ action: 'setSelectedDays',
+ text: '周月视图切换',
+ action: 'switchView',
+ color: 'orange'
+ text: '自定义配置',
+ action: 'config',
+ text: '获取自定义配置',
+ action: 'getConfig',
+ text: '获取日历面板日期',
+ action: 'getCalendarDates',
+ afterTapDay(e) {
+ console.log('afterTapDay', e.detail)
+ whenChangeMonth(e) {
+ console.log('whenChangeMonth', e.detail)
+ whenChangeWeek(e) {
+ console.log('whenChangeWeek', e.detail)
+ onTapDay(e) {
+ console.log('onTapDay', e.detail)
+ afterCalendarRender(e) {
+ console.log('afterCalendarRender', e)
+ // this.calendar.switchView('week').then(() => {
+ // this.calendar.jump(2020, 3, 1).then(date => {}); // 跳转至某日
+ // });
+ onSwipe(e) {
+ console.log('onSwipe', e)
+ showToast(msg) {
+ if (!msg || typeof msg !== 'string') return
+ wx.showToast({
+ title: msg,
+ icon: 'none',
+ duration: 1500
+ generateRandomDate(type) {
+ let random = ~~(Math.random() * 10)
+ switch (type) {
+ case 'year':
+ random = 201 * 10 + ~~(Math.random() * 10)
+ case 'month':
+ random = (~~(Math.random() * 10) % 9) + 1
+ case 'date':
+ random = (~~(Math.random() * 100) % 27) + 1
+ return random
+ handleAction(e) {
+ const { action, disable } = e.currentTarget.dataset
+ if (disable) {
+ this.showToast('抱歉,还不支持~😂')
+ rst: []
+ const calendar = this.calendar
+ const { year, month } = calendar.getCurrentYM()
+ switch (action) {
+ case 'config':
+ calendar
+ .setCalendarConfig({
+ showLunar: false,
+ theme: 'elegant',
+ console.log('设置成功:', conf)
+ case 'getConfig':
+ const config = calendar.getCalendarConfig()
+ this.showToast('请在控制台查看结果')
+ console.log('自定义配置: ', config)
+ case 'jump': {
+ const year = this.generateRandomDate('year')
+ const month = this.generateRandomDate('month')
+ const date = this.generateRandomDate('date')
+ calendar[action](year, month, date)
+ case 'getSelectedDay': {
+ const selected = calendar[action]()
+ if (!selected || !selected.length)
+ return this.showToast('当前未选择任何日期')
+ console.log('get selected days: ', selected)
+ const rst = selected.map(item => JSON.stringify(item))
+ rst
+ case 'cancelSelectedDates':
+ calendar[action]([
+ year: 2020,
+ month: 3,
+ day: 3
+ case 'setTodoLabels': {
+ const days = [
+ day: this.generateRandomDate('date'),
+ todoText: Math.random() * 10 > 5 ? '领奖日' : ''
+ calendar[action]({
+ showLabelAlways: true,
+ days
+ console.log('set todo labels: ', days)
+ case 'deleteTodoLabels': {
+ const todos = [...calendar.getTodoLabels()]
+ if (todos && todos.length) {
+ todos.length = 1
+ calendar[action](todos)
+ const _todos = [...calendar.getTodoLabels()]
+ setTimeout(() => {
+ const rst = _todos.map(item => JSON.stringify(item))
+ console.log('set todo labels: ', todos)
+ this.showToast('没有待办事项')
+ case 'clearTodoLabels':
+ if (!todos || !todos.length) {
+ return this.showToast('没有待办事项')
+ calendar[action]()
+ case 'getTodoLabels': {
+ return this.showToast('未设置待办事项')
+ rst.map(item => JSON.stringify(item))
+ case 'disableDay':
+ day: this.generateRandomDate('date')
+ case 'enableArea': {
+ let sDate = this.generateRandomDate('date')
+ let eDate = this.generateRandomDate('date')
+ if (sDate > eDate) {
+ ;[eDate, sDate] = [sDate, eDate]
+ const area = [`${year}-${month}-${sDate}`, `${year}-${month}-${eDate}`]
+ calendar[action](area)
+ rstStr: JSON.stringify(area)
+ case 'enableDays':
+ `${year}-${month}-${this.generateRandomDate('date')}`,
+ `${year}-${month}-${this.generateRandomDate('date')}`
+ calendar[action](days)
+ rstStr: JSON.stringify(days)
+ case 'switchView':
+ if (!this.week) {
+ calendar[action]('week')
+ this.week = true
+ this.week = false
+ case 'setSelectedDays':
+ const toSet = [
+ calendar[action](toSet)
+ case 'getCalendarDates':
+ console.log(calendar.getCalendarDates())
+Page(conf)
@@ -0,0 +1,6 @@
+ "navigationBarTitleText": "小历-calendar 组件示例",
+ "usingComponents": {
+ "calendar": "../../component/calendar/index"
+<view style="width: 90%;height:640rpx;overflow:hidden;margin: 0 auto 40rpx;">
+ <calendar
+ calendarConfig="{{calendarConfig}}"
+ bind:onSwipe="onSwipe"
+ bind:onTapDay="onTapDay"
+ bind:afterTapDay="afterTapDay"
+ bind:whenChangeWeek="whenChangeWeek"
+ bind:whenChangeMonth="whenChangeMonth"
+ bind:afterCalendarRender="afterCalendarRender"
+ ></calendar>
+<view class='b cc wrap btn-wrap'>
+ <button
+ class='b cc btn btn-{{item.color}} btn-action-{{item.action}}'
+ wx:for="{{actionBtn}}"
+ wx:key="action"
+ data-action="{{item.action}}"
+ data-disable="{{item.disable}}"
+ bindtap="handleAction">{{item.text}}</button>
+<view class="show-rst-wrap">
+ <view wx:if="{{rst}}" wx:for="{{rst}}" wx:key="index" class="show-rst">{{item}}</view>
+ <view wx:if="{{rstStr}}" wx:key="index" class="show-rst">{{rstStr}}</view>
@@ -0,0 +1,161 @@
+.ps {
+ justify-content: flex-start;
+.pb {
+ justify-content: space-between;
+.btn-wrap {
+ width: 90%;
+ margin: 0 auto;
+.btn {
+ padding: 0 20rpx;
+ height: 60rpx;
+ line-height: 1;
+ background: transparent;
+ margin-bottom: 20rpx;
+.btn:active {
+ filter: grayscale(100%);
+.btn-red {
+.btn-red::after {
+ border-color: #e54d42;
+ border-radius: 60rpx;
+.btn-olive {
+ color: #8dc63f;
+.btn-olive::after {
+ border-color: #8dc63f;
+.btn-orange {
+ color: #f37b1d;
+.btn-orange::after {
+ border-color: #f37b1d;
+.btn-cyan {
+ color: #1cbbb4;
+.btn-cyan::after {
+ border-color: #1cbbb4;
+.btn-mauve {
+ color: #9c26b0;
+.btn-mauve::after {
+ border-color: #9c26b0;
+.btn-pink {
+ color: #e03997;
+.btn-pink::after {
+ border-color: #e03997;
+.btn-purple {
+ color: #6739b6;
+.btn-purple::after {
+ border-color: #6739b6;
+.btn-brown {
+ color: #a5673f;
+.btn-brown::after {
+ border-color: #a5673f;
+.btn-grey {
+ color: #8799a3;
+.btn-grey::after {
+ border-color: #8799a3;
+.show-rst-wrap {
+ padding: 20rpx 30rpx 50rpx;
+.show-rst {
+ font-size: 26rpx;
+ color: #a3a3a3;
+ line-height: 26rpx;
+ margin-bottom: 15rpx;
+ word-wrap: break-word;
+.blue-date {
+ color: blue;
+.orange-date {
+ color: #f40;
@@ -1,25 +1,107 @@
-import { jump } from '../../component/calendar/index.js';
+import todo from '../../component/v2/plugins/todo'
+import selectable from '../../component/v2/plugins/selectable'
+import solarLunar from '../../component/v2/plugins/solarLunar/index'
+import timeRange from '../../component/v2/plugins/time-range'
+import week from '../../component/v2/plugins/week'
+import holidays from '../../component/v2/plugins/holidays/index'
+import plugin from '../../component/v2/plugins/index'
+import util, {formatDate, sec2Date} from '../../utils/util.js'
const app = getApp()
+plugin
+ .use(todo)
+ .use(solarLunar)
+ .use(selectable)
+ .use(week)
+ .use(timeRange)
+ .use(holidays)
const conf = {
data: {
+ outList:[],
+ visitList:[],
calendarConfig: {
- // 配置内置主题
- theme: 'default'
+ // showHolidays: true,
+ // emphasisWeek: true,
+ // chooseAreaMode: true
+ defaultDate: formatDate(new Date()),
+ // autoChoosedWhenJump: true
+ action: 'getSelectedDates',
+ action: 'setTodos',
+ action: 'deleteTodos',
+ action: 'clearTodos',
+ action: 'getTodos',
+ action: 'disableDates',
+ action: 'enableDates',
+ action: 'setSelectedDates',
- doSomeThing() {
- // 调用日历方法
- this.calendar.enableArea(['2022-3-7', '2022-4-7']);
-};
-Page({
- /**
- * 选择日期后执行的事件
- * currentSelect 当前点击的日期
- * allSelectedDays 选择的所有日期(当mulit为true时,allSelectedDays有值)
- */
- afterTapDay(e) {
- console.log('afterTapDay', e.detail); // => { currentSelect: {}, allSelectedDays: [] }
+ afterTapDate(e) {
+ console.log('afterTapDate', e.detail)
onLoad: function(){
app.checkLogin(res=>{
@@ -27,48 +109,304 @@ Page({
wx.navigateTo({
url: '/pages/index/index',
})
+ }else{
+ console.log("loadData", res )
+ this.loadData()
- * 当日历滑动时触发(适用于周/月视图)
- * 可在滑动时按需在该方法内获取当前日历的一些数据
- onSwipe(e) {
- console.log('onSwipe', e.detail);
- const dates = this.calendar.getCalendarDates();
+ loadData(){
+ let curDate = this.data.calendarConfig.defaultDate;
+ let fromDate = curDate.substr(0,8)+ "01"
+ let toDate = curDate.substr(0,8)+ "31"
+ app.formPost("User.loadData", {fromDate, toDate}).then( res=>{
+ if( res.code == 200){
+ let outList = res.data.outList||[];
+ let visitList = res.data.visitList||[];
+ this.setData({outList, visitList});
+ this.loadMarks()
+ loadMarks(){
+ const calendar = this.selectComponent('#calendar').calendar
+ let {outList, visitList} = this.data;
+ console.log("loadMarks", outList, visitList )
+ var dateMap = {};
+ // 外出
+ for(let i in outList ){
+ let item = outList[i];
+ let {fromDate,toDate} = item;
+ if( toDate < fromDate) continue;
+ while( fromDate <= toDate){
+ dateMap[fromDate] = 1
+ fromDate = util.nextDate( fromDate);
+ //
+ for(let i in visitList ){
+ let item = visitList[i];
+ dateMap[fromDate] = dateMap[fromDate]?3:2
+ var dates = [];
+ for( let date in dateMap ){
+ let d = new Date(date);
+ let item = {year: d.getFullYear(), month: d.getMonth()+1, date: d.getDate()};
+ switch( dateMap[date]){
+ case 1:
+ item.todoText = "出";
+ break;
+ case 2:
+ item.todoText = "临";
+ item.todoText = "临&出";
+ dates.push( item );
+ console.log("dates", dates );
+ calendar.setTodos({
- * 当改变月份时触发
- * => current 当前年月 / next 切换后的年月
whenChangeMonth(e) {
- console.log('whenChangeMonth', e.detail);
- // => { current: { month: 3, ... }, next: { month: 4, ... }}
- * 周视图下当改变周时触发
- * => current 当前周信息 / next 切换后周信息
whenChangeWeek(e) {
- console.log('whenChangeWeek', e.detail);
- // {
- // current: { currentYM: {year: 2019, month: 1 }, dates: [{}] },
- // next: { currentYM: {year: 2019, month: 1}, dates: [{}] },
- // directionType: 'next_week'
- // }
- * 日期点击事件(此事件会完全接管点击事件),需自定义配置 takeoverTap 值为真才能生效
- onTapDay(e) {
- console.log('onTapDay', e.detail); // => { year: 2019, month: 12, day: 3, ...}
+ takeoverTap(e) {
+ console.log('takeoverTap', e.detail)
- * 日历初次渲染完成后触发事件,如设置事件标记
afterCalendarRender(e) {
- console.log('afterCalendarRender', e);
+ // 获取日历组件上的 calendar 对象
+ // const calendar = this.selectComponent('#calendar').calendar
+ // console.log('afterCalendarRender -> calendar', calendar)
+ calendar['weekModeJump']({ year, month, date })
+ calendar[action]({ year, month, date })
+ case 'getSelectedDates': {
+ console.log('get selected dates: ', selected)
+ const selected = calendar.getSelectedDates()
+ calendar[action](selected)
+ case 'setTodos': {
+ const dates = [
+ date: this.generateRandomDate('date'),
+ console.log('set todo: ', dates)
+ case 'deleteTodos': {
+ const todos = [...calendar.getTodos()]
+ if (todos.length) {
+ calendar[action]([todos[0]]).then(() => {
+ const _todos = [...calendar.getTodos()]
+ console.log('delete todo: ', todos[0])
+ case 'clearTodos':
+ case 'getTodos': {
+ console.log("rst", rst)
+ case 'disableDates':
+ date: this.generateRandomDate('date')
+ case 'enableDates':
+ calendar[action](dates)
+ rstStr: JSON.stringify(dates)
+ calendar[action]('week').then(calendarData => {
+ console.log('switch success!', calendarData)
+ calendar[action]().then(calendarData => {
+ case 'setSelectedDates':
+ calendar.getCalendarDates({
+ lunar: true
-});
@@ -1,5 +1,6 @@
{
+ "navigationBarTitleText": "莅临&外出",
"usingComponents": {
- "calendar": "../../component/calendar/index"
+ "calendar": "../../component/v2/index"
@@ -1,9 +1,27 @@
-<calendar
- calendarConfig="{{calendarConfig}}"
- bind:onTapDay="onTapDay"
- bind:afterTapDay="afterTapDay"
- bind:onSwipe="onSwipe"
- bind:whenChangeWeek="whenChangeWeek"
- bind:whenChangeMonth="whenChangeMonth"
- bind:afterCalendarRender="afterCalendarRender"
-></calendar>
+ id="calendar"
+ config="{{calendarConfig}}"
+ bind:takeoverTap="takeoverTap"
+ bind:afterTapDate="afterTapDate"
+<!-- <view class='b cc wrap btn-wrap'>
+</view> -->
+<!-- <view class="show-rst-wrap">
@@ -1 +1 @@
-/* pages/rili/index.wxss */
+@import '../calendarComponent/index.wxss'
@@ -1,6 +1,6 @@
<view class='userinfo' wx:if="{{userInfo.userId}}">
<view class='userinfo-avatar'>
- <image src="{{userInfo.headerImg}}" mode="widthFix" style="width:100%"></image>
+ <image src="/assets/icon/1.jpg" mode="widthFix" style="width:100%"></image>
<view class='userinfo-name'>
<view> {{userInfo.nickname}}</view>
@@ -21,10 +21,14 @@
<view>
<i-cell-group i-class="my-group-margin">
- <i-cell title="历史记录" is-link bindtap="gotoFileList" data-api="getViewArticalList">
+ <i-cell title="预留功能1" is-link bindtap="gotoFileList" data-api="getViewArticalList">
<i-icon type="mine_fill" slot="icon" size="20" />
</i-cell>
+ <i-cell title="预留功能2" is-link bindtap="gotoFileList" data-api="getViewArticalList">
+ <i-icon type="shop_fill" slot="icon" size="20" />
+ </i-cell>
<i-cell title="退出登入" bind:click="logOut">
<i-icon type="flashlight_fill" slot="icon" size="20" />
@@ -42,7 +42,7 @@
"compileType": "miniprogram",
"libVersion": "2.8.0",
"appid": "wx147197ea9d0b992b",
- "projectname": "%E5%86%85%E4%B8%9A%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F",
+ "projectname": "莅临&外出",
"debugOptions": {
"hidedInDevtools": []
@@ -13,6 +13,31 @@ const formatTime = date => {
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
+const formatDate = date => {
+ const year = date.getFullYear()
+ const month = date.getMonth() + 1
+ const day = date.getDate()
+ return [year, month, day].map(formatNumber).join('-')
+const sec2Date = sec => {
+ let date = new Date( sec * 1000 );
+const nextDate = datestr => {
+ let date = new Date( datestr );
+ date = new Date(+date + 86400*1000)
const formatNumber = n => {
n = n.toString()
return n[1] ? n : '0' + n
@@ -159,5 +184,8 @@ module.exports = {
showSuccess,
showToast,
showMsg,
+ sec2Date,
+ nextDate,
+ formatDate,
showBusy