lunc-calendar.vue 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  1. <template>
  2. <view class="lunc-calendar">
  3. <!-- 头部上下月按钮及月份 -->
  4. <view class="header">
  5. <text class="day_tit" >选择日期</text>
  6. <text class="head-icon head-pre-month nocheck" v-if="showChangeBtn&&!isshowPrev"></text>
  7. <text class="head-icon head-pre-month" v-if="showChangeBtn&&isshowPrev" @click="changeMonthOrWeek('prev')"></text>
  8. <text class="head-month">{{selDate.year+'年'+(selDate.month<10?'0'+selDate.month:selDate.month)+'月'}}</text>
  9. <text class="head-icon head-next-month" v-if="showChangeBtn" @click="changeMonthOrWeek('next')"></text>
  10. <text class="go-to-today" v-if="showToday" @click="goToday">今天</text>
  11. </view>
  12. <!-- 星期 -->
  13. <view class="week-area" :class="firstDayOfWeek=='sunday'?'week-tit':''">
  14. <text class="week-font" v-for="(item, index) in weekArr" :key="index ">{{ getWeekType + '' + item }}</text>
  15. </view>
  16. <!-- 日历 -->
  17. <swiper class="calendar-data" :current="shrinkType?tranCurrent:tranIndex" circular :duration="tranDuration"
  18. @change="swiperChange" @animationfinish="swiperEndChange" :style="{height:shrinkType?'112rpx':'532rpx'}">
  19. <swiper-item class="swiper-item swiper-prev-item" v-for="(a, i) in getAllData" :key="i">
  20. <text class="month-bg" v-if="showMonthBg">{{ getMontBg }}</text>
  21. <view class="month-days" :class="[shrinkType?'item-week':'']">
  22. <view class="week-days" v-for="(b, j) in a" :key="j">
  23. <view class="day" v-for="(c, k) in b" :key="k" @click="clickDay(c)">
  24. <!-- 法定不可约,周六日不可约 不可约优先级高于节假日-->
  25. <view class="day-info" :class="[c.dayClass, getIsSelDay(c)&&'is-sel', c.dayType!='normal'&&'un-month',
  26. c.sign && c.sign.length > 0&&c.sign[0].title!='可预约'||c.sign.length==0 || configWeek.indexOf(c.week)!=-1 || c.isHoliday&&configHoliday=='N'?'day-infoa':''
  27. ]">
  28. <text class="day-solar">{{ c.day }}</text>
  29. <template v-if="showLunar || c.sign && c.sign.length > 0 || c.isHoliday">
  30. <!-- <text class="day-tag" v-if="c.sign && c.sign.length > 0"></text> -->
  31. <text class="day-sign" v-if="c.sign && c.sign.length > 0">
  32. <!-- 节假日 -->
  33. <block v-if="c.isHoliday">{{c.dayLunar}}</block>
  34. <block v-else>{{ configWeek.indexOf(c.week)==-1?c.sign[0].title:'不可约' }}</block>
  35. </text>
  36. <text class="day-lunar" v-else>{{c.dayLunar}}</text>
  37. </template>
  38. </view>
  39. </view>
  40. </view>
  41. </view>
  42. </swiper-item>
  43. </swiper>
  44. <!-- 收缩按钮 -->
  45. <view class="shrink" v-if="showShrink" @click="changeShrink">
  46. <image :src="upimg" class="shrink-img" :class="[shrinkType?'shrink-open':'shrink-close']"></image>
  47. <!-- <text class="shrink-btn" ></text> -->
  48. </view>
  49. </view>
  50. </template>
  51. <script>
  52. let { calendar } = require("./calendar.js");
  53. /**
  54. * @property {Boolean} showLunar = [true|false] 是否显示农历,默认false
  55. * @property {Boolean} showMonthBg = [true|false] 是否显示月份背景,默认true
  56. * @property {Boolean} showChangeBtn = [true|false] 是否显示上月下月箭头按钮,默认true
  57. * @property {String} firstDayOfWeek = [monday|sunday] 周几为每周的第一天,默认monday
  58. * @value monday 每周从周一开始(默认)
  59. * @value sunday 每周从周日开始
  60. * @property {String} weekType = [''|周|星期] 星期的前缀;如周一周二或星期一星期二,为空则只显示一、二等;不用预设值时可自定义前缀,填的值即为星期前缀;默认周
  61. * @value '' 星期显示:只显示一、二等
  62. * @value 周 星期显示:周一、周二等(默认)
  63. * @value 星期 星期显示:星期一、星期二等
  64. * @property {Boolean} weekend = [true|false] 周末标红(周六周日日期用红色字体),默认true
  65. * @property {Boolean} showShrink = [true|false] 是否显示收缩按钮,可显示一周的日期,默认false
  66. * @property {String} shrinkState = [week|month] 收缩状态,默认month
  67. * @value week 默认打开显示周数据(收起状态)
  68. * @value month 默认打开显示月数据(展开状态)
  69. * @property {Array} signList 标记数组,若当前有多个标记,则显示最后一个,期待格式[{date: '2021-09-10', title: '生日', info: '八月初四张三生日'}]
  70. * @event {Function()} dayChange 点击日期触发事件,返回参数e={year,month,day,week,date,lunar,daySign},详情参数见文档
  71. * @event {Function()} monthChange 切换月份触发事件,返回参数e={year,month,type},详情参数见文档
  72. * @event {Function()} shrinkClick 收缩和展开时触发事件,返回参数e=week|month
  73. */
  74. export default {
  75. name: 'LuncCalendar',
  76. props: {
  77. //是否显示农历
  78. showLunar: {
  79. type: Boolean,
  80. default: false
  81. },
  82. //是否显示月份背景
  83. showMonthBg: {
  84. type: Boolean,
  85. default: true
  86. },
  87. //是否显示上月下月按钮
  88. showChangeBtn: {
  89. type: Boolean,
  90. default: true
  91. },
  92. //每周的周几为第一天
  93. firstDayOfWeek: {
  94. type: String,
  95. default: 'monday'
  96. },
  97. //每周的周几为第一天
  98. weekType: {
  99. type: String,
  100. default: '周'
  101. },
  102. //周末标红
  103. weekend: {
  104. type: Boolean,
  105. default: true
  106. },
  107. //是否可收缩,收起来后以周显示
  108. showShrink: {
  109. type: Boolean,
  110. default: false
  111. },
  112. // 默认打开状态(收起或展开)
  113. shrinkState:{
  114. type: String,
  115. default: 'month'
  116. },
  117. //标记
  118. signList: {
  119. type: Array,
  120. default () {
  121. return []
  122. }
  123. },
  124. // 周几不可约
  125. configWeek:{
  126. type: Array,
  127. default () {
  128. return []
  129. }
  130. },
  131. // 节假日预约
  132. configHoliday:{
  133. type: String,
  134. default () {
  135. return 'Y'
  136. }
  137. },
  138. },
  139. data() {
  140. return {
  141. upimg:require("@/static/images/order/comes/up.png"),
  142. weekArr: ['一', '二', '三', '四', '五', '六', '日'], //星期数组
  143. today: {}, //今天日期 -> year, month, day
  144. selDate: {}, //选中日期信息 -> year, month, day
  145. allMonthList: [], // 月份数据 -> [[[周],[周]],[月],[月]]
  146. tranIndex: 1, // 月份轮播所在位置
  147. allWeekList: [], // 周月份数据 -> [[[周]],[月],[月]]
  148. tranCurrent: 1, // 周轮播所在位置
  149. tranDuration: 300, //轮播时间(单位毫秒)
  150. signArr: this.signList, // 标记列表
  151. showToday: false, //显示回到今天(非当月才显示)
  152. isshowPrev:false,//切换当月的上一个月
  153. shrinkType: false, // 收缩状态,true:收起(显示周),false展开(显示月)
  154. deterChange: true, // 防止切换月份过快
  155. }
  156. },
  157. created() {
  158. let nd = new Date();
  159. this.today = {
  160. year: nd.getFullYear(),
  161. month: nd.getMonth() + 1,
  162. day: nd.getDate()
  163. }
  164. if (this.firstDayOfWeek == "sunday") this.weekArr = ['日', '一', '二', '三', '四', '五', '六'];
  165. this.initDate();
  166. },
  167. watch: {
  168. signList(nList, oList){
  169. this.signArr = nList;
  170. this.setSignList();
  171. }
  172. },
  173. computed: {
  174. getAllData() { // 切换周或月时,展示的数据不同
  175. return this.shrinkType ? this.allWeekList : this.allMonthList;
  176. },
  177. getMontBg() { // 获取当前月背景
  178. let monthBg = this.selDate.month;
  179. return !this.shrinkType ? (monthBg < 10 ? '0' + monthBg : monthBg) : '';
  180. },
  181. getIsSelDay(c) { // 判断是否是选中日期
  182. return (d) => {
  183. let { year, month, day } = this.selDate;
  184. if(year == d.year && month == d.month && day == d.day){
  185. this.$emit('getIsSelDayFn',d)
  186. }
  187. return year == d.year && month == d.month && day == d.day
  188. }
  189. },
  190. getWeekType(){
  191. let weekType = this.weekType;
  192. if(weekType && weekType != "true" && weekType != "''" && weekType != '""'){
  193. return weekType
  194. }else{
  195. return ''
  196. }
  197. }
  198. },
  199. methods: {
  200. initDate() { // 初始化日期
  201. this.selDate = JSON.parse(JSON.stringify(this.today));
  202. let monthList = this.getMonthData(this.selDate); // 获取当月数据
  203. let prevMonthList = this.getMonthData(this.getMonthDate(this.selDate, -1)); // 上月数据
  204. let nextMonthList = this.getMonthData(this.getMonthDate(this.selDate)); // 下月数据
  205. this.allMonthList = [prevMonthList, monthList, nextMonthList]
  206. this.tranIndex = 1;
  207. if(this.shrinkState == "week" && !this.shrinkType) this.changeShrink();
  208. },
  209. /**
  210. * 根据指定日期获取当月的数据
  211. * @param {Object} date = { year, month, day } 指定的日期
  212. */
  213. getMonthData(date) {
  214. const { year, month, day } = date; //指定的日期
  215. let maxDay = new Date(year, month, 0).getDate(); //当前月最大日期
  216. let firstWeek = new Date(year + "/" + month + "/1").getDay(); //月份1号的星期数
  217. if (this.firstDayOfWeek == "monday") firstWeek = firstWeek - 1 < 0 ? 6 : firstWeek - 1;
  218. let list = [];
  219. //每月显示42天,6周,每周7天
  220. for (var i = 0; i < 42; i++) {
  221. let dayInfo = {}; // 每天的详细信息
  222. if (i < firstWeek) { //指定月份上月的最后几天
  223. let { year, month } = this.getMonthDate(date, -1);
  224. let preMaxDay = new Date(year, month, 0).getDate(); //上月最大日期
  225. let day = preMaxDay - firstWeek + i + 1;
  226. dayInfo = this.getDayInfo({ year, month, day }, 'prev');
  227. } else if (i > maxDay + firstWeek - 1) { //指定月份下月的前几天
  228. let { year, month } = this.getMonthDate(date);
  229. let day = i - maxDay - firstWeek + 1;
  230. dayInfo = this.getDayInfo({ year, month, day }, 'next');
  231. } else {
  232. let day = i - firstWeek + 1;
  233. dayInfo = this.getDayInfo({ year, month, day }, 'normal');
  234. }
  235. if (i % 7 == 0) list.push(new Array());
  236. list[list.length - 1].push(dayInfo);
  237. }
  238. return list;
  239. },
  240. /**
  241. * 获取指定日期的详细信息,包括农历节假日等
  242. * @param {Object} date = { year, month, day } 指定的日期
  243. * @param {String} dayType = [prev|next|normal] 日期类型,上月|下月|当前月
  244. */
  245. getDayInfo(date, dayType) {
  246. const { year, month, day } = date;
  247. let isToday = false; //是否今天
  248. if (year == this.today.year && month == this.today.month && day == this.today.day) isToday = true;
  249. let week = new Date(year + "/" + month + "/" + day).getDay(); //星期数
  250. let lunar = calendar.solar2lunar(year, month, day); //农历
  251. let dayLunar = lunar.IDayCn == '初一' ? lunar.IMonthCn + lunar.IDayCn : lunar.IDayCn;
  252. if (lunar.festival) dayLunar = lunar.festival; // 阳历节日
  253. else if (lunar.lunarFestival) dayLunar = lunar.lunarFestival; // 农历节日
  254. else if (lunar.Term) dayLunar = lunar.Term; // 节气
  255. let holidayArr = ["元旦", "春节", "清明节", "劳动节", "端午节", "中秋节", "国庆节"];
  256. let isHoliday = false;
  257. if (holidayArr.indexOf(dayLunar) != -1) isHoliday = true;
  258. let dayInfo = {
  259. date: year + "-" + month + "-" + day,
  260. year, month, day, week,
  261. lunar, // 农历
  262. dayLunar, // 显示的农历
  263. isToday, // 是否是今日
  264. isHoliday, // 是否是节假日
  265. dayType, // 日期类型,上月、下月或当前月
  266. sign: this.getSignByDate(date)
  267. }
  268. let dayClass = this.getDayClass(dayInfo);
  269. dayInfo["dayClass"] = dayClass;
  270. return dayInfo;
  271. },
  272. /**
  273. * 根据日期详细信息添加对应的class
  274. * @param {Object} dayInfo 日期详情
  275. */
  276. getDayClass(dayInfo) {
  277. let dClass = "";
  278. if (dayInfo.isToday) dClass += ' is-today'; // 今天日期
  279. if (dayInfo.isHoliday) dClass += ' is-holiday'; // 法定假日
  280. if (this.weekend && (dayInfo.week == 0 || dayInfo.week == 6)) dClass += ' week-end'; // 周末标红
  281. return dClass;
  282. },
  283. /**
  284. * 根据日期获取日期对应的事件
  285. * @param {Object} date = { year, month, day } 指定的日期
  286. */
  287. getSignByDate(date) {
  288. const { year, month, day } = date;
  289. let dayDateS = new Date(year + "/" + month + "/" + day + " 00:00:00").getTime();
  290. let dayDateE = new Date(year + "/" + month + "/" + day + " 23:59:59").getTime();
  291. let daySign = [];
  292. this.signArr.map(sign => {
  293. let signDate = sign.date.replace(/-/g, '/');
  294. let signTimes = new Date(sign.date).getTime();
  295. if (signTimes >= dayDateS && signTimes <= dayDateE) daySign.push(sign)
  296. })
  297. return daySign;
  298. },
  299. /**
  300. * 获取月份数据
  301. * @param {String} type=[pre|next]
  302. */
  303. getOtherData(type) {
  304. let nowMont = this.getMonthDate(this.selDate, type == 'prev' ? -1 : 1); // 获取当前月份
  305. this.selDate = nowMont; // 切换月份后设置选中的日期
  306. let monthData = this.getMonthData(this.getMonthDate(nowMont, type == 'prev' ? -1 : 1));
  307. // 获取上月或下月轮播所在位置
  308. let current = this.getTranIndex().prevNum;
  309. if (type == "next") current = this.getTranIndex().nextNum;
  310. this.allMonthList.splice(current, 1, monthData);
  311. this.judgeShowToday();
  312. this.returnMonthChange(type);
  313. },
  314. /**
  315. * 获取周数据
  316. * @param {String} type=[pre|next]
  317. */
  318. getOtherWeekData(type) {
  319. let oldSel = this.selDate; // 原选中的日期
  320. let newSel = this.getDateByDateAndDay(oldSel, type == 'prev' ? -7 : 7); // 获取7天前或后的日期
  321. if (oldSel.month != newSel.month) { // 跨月,先设置跨月后的月历
  322. // 设置月轮播位置
  323. let current = this.getTranIndex("month").prevNum;
  324. if (type == "next") current = this.getTranIndex("month").nextNum;
  325. this.tranIndex = current;
  326. this.getOtherData(type);
  327. }
  328. this.selDate = newSel;
  329. this.getWeekData(type);
  330. this.judgeShowToday();
  331. },
  332. // 从月历中获取周数据,切换周后获取上周或下周数据
  333. getWeekData(type) {
  334. const { prevNum: prevIndex, nowNum: nowIndex, nextNum: nextIndex } = this.getTranIndex("month");
  335. const { prevNum: prevCurrent, nowNum: nowCurrent, nextNum: nextCurrent } = this.getTranIndex("week");
  336. const { year: selYear, month: selMonth, day: selDay } = this.selDate;
  337. let sDate = selYear + "-" + selMonth + "-" + selDay
  338. let prevMonthList = this.allMonthList[prevIndex];
  339. let nowMonthList = this.allMonthList[nowIndex];
  340. let nextMonthList = this.allMonthList[nextIndex];
  341. for (let i = 0; i < nowMonthList.length; i++) {
  342. for (let j = 0; j < nowMonthList[i].length; j++) {
  343. if (sDate == nowMonthList[i][j].date) {
  344. this.returnDayChange(nowMonthList[i][j]); // 返回选中的日期
  345. if (type == "next") {
  346. this.allWeekList.splice(nextCurrent, 1, [nowMonthList[i + 1]]);
  347. if (i == 5) this.allWeekList.splice(nextCurrent, 1, [nextMonthList[1]]);
  348. } else {
  349. this.allWeekList.splice(prevCurrent, 1, [nowMonthList[i - 1]]);
  350. if (i == 0) {
  351. for (let k = prevMonthList.length - 1; k >= 0; k--) {
  352. if (prevMonthList[k][6].dayType == "normal") {
  353. this.allWeekList.splice(prevCurrent, 1, [prevMonthList[k]]);
  354. break;
  355. }
  356. }
  357. }
  358. }
  359. break;
  360. }
  361. }
  362. }
  363. },
  364. // 根据月份数据获取周数据,相当初始化周数据
  365. getAllWeekData() {
  366. const { prevNum, nowNum, nextNum } = this.getTranIndex("month");
  367. const { year: selYear, month: selMonth, day: selDay } = this.selDate;
  368. let sDate = selYear + "-" + selMonth + "-" + selDay; // 选中的日期
  369. let allWeekList = [[],[],[]];
  370. let prevMonthList = this.allMonthList[prevNum];
  371. let nowMonthList = this.allMonthList[nowNum];
  372. let nextMonthList = this.allMonthList[nextNum];
  373. for (let i = 0; i < nowMonthList.length; i++) {
  374. for (let j = 0; j < nowMonthList[i].length; j++) {
  375. if (sDate == nowMonthList[i][j].date) {
  376. allWeekList[0][0] = nowMonthList[i - 1];
  377. allWeekList[1][0] = nowMonthList[i];
  378. allWeekList[2][0] = nowMonthList[i + 1];
  379. if (i == 5) {
  380. allWeekList[2][0] = nextMonthList[1];
  381. } else if (i == 0) {
  382. for (let k = prevMonthList.length - 1; k >= 0; k--) {
  383. if (prevMonthList[k][6].dayType == "normal") {
  384. allWeekList[0][0] = prevMonthList[k];
  385. break;
  386. }
  387. }
  388. }
  389. break;
  390. }
  391. }
  392. }
  393. this.allWeekList = allWeekList;
  394. },
  395. // 滑动切换结束
  396. swiperEndChange() {
  397. this.tranDuration = 300;
  398. },
  399. // 滑动切换月份或周
  400. swiperChange(e) {
  401. let current = e.detail.current;
  402. let oldIndex = this.shrinkType ? this.tranCurrent : this.tranIndex;
  403. let type = (oldIndex - current == -1 || oldIndex - current == 2) ? 'next' : 'prev';
  404. if (this.shrinkType) {
  405. this.tranCurrent = current;
  406. if (current != oldIndex) this.getOtherWeekData(type);
  407. } else {
  408. this.tranIndex = current;
  409. if (current != oldIndex) this.getOtherData(type);
  410. }
  411. },
  412. // 点击切换月份或周(上月下月切换或上周下周切换)type = [prev|next] 切换类型
  413. changeMonthOrWeek(type) {
  414. if (!this.deterChange) return;
  415. this.deterChange = false;
  416. setTimeout(_ => {
  417. this.deterChange = true;
  418. }, 400); // 防止点击过快
  419. this.tranDuration = 300;
  420. let tranType = this.shrinkType ? 'week' : 'month';
  421. let current = this.getTranIndex(tranType).prevNum;
  422. if (type == "next") current = this.getTranIndex(tranType).nextNum;
  423. if (tranType == "week") {
  424. this.tranCurrent = current;
  425. this.getOtherWeekData(type);
  426. } else {
  427. this.tranIndex = current;
  428. this.getOtherData(type);
  429. }
  430. },
  431. // 点击收缩按钮,切换显示月份或显示周
  432. changeShrink() {
  433. this.shrinkType = !this.shrinkType;
  434. if (this.tranDuration != 0) this.tranDuration = 0;
  435. if (this.shrinkType) {
  436. this.tranCurrent = 1;
  437. this.getAllWeekData();
  438. }
  439. this.returnShrinkChange();
  440. this.judgeShowToday();
  441. },
  442. // 点击回到今天
  443. goToday() {
  444. if (this.tranDuration != 0) this.tranDuration = 0;
  445. let oldDate = JSON.parse(JSON.stringify(this.selDate));
  446. this.initDate();
  447. if (this.shrinkType) {
  448. this.tranCurrent = 1;
  449. this.getAllWeekData();
  450. let today = this.today;
  451. // 判断是否需要触发改变月份事件
  452. if(oldDate.year != today.year || oldDate.month != today.month){
  453. this.returnMonthChange("today");
  454. }else{
  455. this.returnDayChange(this.today);
  456. }
  457. } else {
  458. this.returnMonthChange("today"); // 事件
  459. }
  460. this.judgeShowToday();
  461. },
  462. // 点击日期
  463. clickDay(dayInfo) {
  464. var isweek=this.configWeek.indexOf(dayInfo.week)
  465. if(dayInfo.sign && dayInfo.sign.length > 0&&dayInfo.sign[0].title!='可预约'||dayInfo.sign.length==0||isweek!=-1||dayInfo.isHoliday&&this.configHoliday=='N'){
  466. return
  467. }
  468. let { year, month, day } = this.selDate;
  469. if (day == dayInfo.day && month == dayInfo.month && year == dayInfo.year) return;
  470. let oldSel = JSON.parse(JSON.stringify(this.selDate));
  471. this.selDate.day = dayInfo.day;
  472. if (oldSel.month != dayInfo.month) {
  473. if (!this.shrinkType) {
  474. this.changeMonthOrWeek(dayInfo.dayType);
  475. return;
  476. } else {
  477. this.selDate.year = dayInfo.year;
  478. this.selDate.month = dayInfo.month;
  479. let nowSel = JSON.parse(JSON.stringify(this.selDate));
  480. let type = "nowNum"
  481. if (nowSel.year > oldSel.year || (nowSel.year === oldSel.year && nowSel.month > oldSel.month)){
  482. type = "nextNum"
  483. } else if (nowSel.year < oldSel.year || (nowSel.year === oldSel.year && nowSel.month < oldSel.month)){
  484. type = "prevNum"
  485. }
  486. this.tranIndex = this.getTranIndex("month")[type];
  487. let monthData = this.getMonthData(this.getMonthDate(this.selDate, type == 'prevNum' ? -1 : 1));
  488. let current = this.getTranIndex("month")[type];
  489. this.allMonthList.splice(current, 1, monthData); // 设置上月或下月数据
  490. }
  491. this.returnMonthChange(dayInfo.dayType);
  492. } else {
  493. this.returnDayChange(dayInfo);
  494. }
  495. },
  496. // 判断是否需要显示回到今天(非本月或本周时显示)
  497. judgeShowToday() {
  498. const { year, month, day } = this.today;
  499. const { year: selYeat, month: selMonth, day: selDay } = this.selDate;
  500. if (this.shrinkType) { // 显示的周
  501. let selTimes = new Date(selYeat, selMonth - 1, selDay).getTime(); // 选中日期的时间戳
  502. let week = new Date(year, month - 1, day).getDay(); // 今天星期
  503. let firstWD = this.getDateByDateAndDay(this.today, -week + (this.firstDayOfWeek == "monday" ? 1 : 0));
  504. let lastWD = this.getDateByDateAndDay(this.today, 6 - week + (this.firstDayOfWeek == "monday" ? 1 : 0));
  505. let firstTimes = new Date(firstWD.year, firstWD.month - 1, firstWD.day).getTime();
  506. let lastTimes = new Date(lastWD.year, lastWD.month - 1, lastWD.day).getTime();
  507. if (selTimes > lastTimes || selTimes < firstTimes) this.showToday = true;
  508. else this.showToday = false;
  509. if(selTimes > lastTimes) this.isshowPrev=true;
  510. else this.isshowPrev=false;
  511. } else {
  512. if (year != selYeat || month != selMonth) this.showToday = true;
  513. else this.showToday = false;
  514. // 判断是并不是当前月上一个月
  515. if(Number(selYeat)>Number(year)||Number(selMonth)>Number(month)) this.isshowPrev=true;
  516. else this.isshowPrev=false;
  517. }
  518. },
  519. // 重新设置标记
  520. setSignList() {
  521. this.allMonthList.map(month => {
  522. month.map(week => {
  523. week.map(day => {
  524. day.sign = this.getSignByDate({ year: day.year, month: day.month, day: day.day })
  525. })
  526. })
  527. })
  528. },
  529. /**
  530. * 添加标记
  531. * @param {Array} list 需要添加的标记
  532. */
  533. addSignList(list) {
  534. let signArr = this.signArr.concat(list);
  535. this.signArr = signArr;
  536. this.setSignList();
  537. },
  538. /**
  539. * 删除标记
  540. * 根据date和title共同判断是否删除
  541. * @param {Array} list 需要删除的标记
  542. */
  543. deleteSignList(list) {
  544. let signArr = this.signArr;
  545. signArr = signArr.filter(s => {
  546. if (list.find(l => l.date == s.date && l.title == s.title)) return false
  547. else return true;
  548. })
  549. this.signArr = signArr;
  550. this.setSignList();
  551. },
  552. /**
  553. * 事件 - 设置返回日期
  554. * @param {Object} dayInfo 日期详情
  555. */
  556. returnDayChange(dayInfo) {
  557. let { year, month, day } = dayInfo;
  558. let dayDate = year + "-" + (month < 10 ? '0' + month : month) + "-" + (day < 10 ? '0' + day : day)
  559. let returnData = {
  560. date: dayDate,
  561. year: year,
  562. month: month,
  563. day: day,
  564. week: dayInfo.week,
  565. daySign: dayInfo.sign
  566. }
  567. if (this.showLunar) returnData["lunar"] = dayInfo.lunar;
  568. this.$emit("dayChange", returnData);
  569. },
  570. /**
  571. * 事件 - 设置返回月份
  572. * @param {String} type 类型
  573. */
  574. returnMonthChange(type) {
  575. let selDate = this.selDate.year + "-" + this.selDate.month + "-" + this.selDate.day;
  576. let monthList = this.allMonthList.flat().flat(); // 二维转一维
  577. let dayInfo = monthList.find(day => day.date == selDate);
  578. this.returnDayChange(dayInfo)
  579. this.$emit("monthChange", {
  580. year: dayInfo.year,
  581. month: dayInfo.month,
  582. type: type
  583. });
  584. },
  585. /**
  586. * 事件 - 返回收缩状态
  587. */
  588. returnShrinkChange() {
  589. let type = this.shrinkType ? 'week' : 'month'
  590. this.$emit("shrinkClick", type);
  591. },
  592. /**
  593. * 获取上一个或下一个轮播位置
  594. * @param {String} type = [month|week] 轮播类型,月轮播(tranIndex),周轮播(tranCurrent)
  595. * @returns {Object} {prevNum, nowNum, nextNum}
  596. */
  597. getTranIndex(type = 'month') {
  598. let current = this.tranIndex;
  599. if (type == "week") current = this.tranCurrent;
  600. let prevNum = current - 1 < 0 ? 2 : current - 1;
  601. let nowNum = current;
  602. let nextNum = current + 1 > 2 ? 0 : current + 1;
  603. return { prevNum, nowNum, nextNum }
  604. },
  605. /**
  606. * 根据日期获取几天后的日期
  607. * @param {Object} date = {year, month, day} 当前日期
  608. * @param {Number} day 当前日期的几天前或几天后(负数)
  609. * @returns {Object} {year, month, day}
  610. */
  611. getDateByDateAndDay(date, num) {
  612. let dTime = new Date(date.year + "/" + date.month + "/" + date.day).getTime() + num * 24 * 60 * 60 * 1000;
  613. let nd = new Date(dTime);
  614. return {
  615. year: nd.getFullYear(),
  616. month: nd.getMonth() + 1,
  617. day: nd.getDate()
  618. }
  619. },
  620. /**
  621. * 获取几个月前或后的日期
  622. * @param {Object} date = {year, month, day} 当前日期
  623. * @param {Number} num 当前日期的num月前或后,默认1月后(下月)
  624. * @returns {Object} {year, month, day}
  625. */
  626. getMonthDate(date, num = 1) {
  627. let nextMonth = date.month + num;
  628. let diffYear = parseInt(Math.abs(nextMonth) / 12);
  629. let year = date.year;
  630. let month = nextMonth;
  631. if (nextMonth > 12) {
  632. year = date.year + diffYear;
  633. month = nextMonth % 12;
  634. } else if (nextMonth < 1) {
  635. year = date.year - (diffYear + 1);
  636. month = nextMonth + 12 * (diffYear + 1);
  637. }
  638. let monthMaxDay = new Date(year, month, 0).getDate(); // 月份最大日期
  639. let day = date.day > monthMaxDay ? monthMaxDay : date.day;
  640. return { year, month, day }
  641. },
  642. }
  643. }
  644. </script>
  645. <style lang="scss">
  646. .lunc-calendar {
  647. background-color: #FFF;
  648. // 头部
  649. .header {
  650. display: flex;
  651. flex-direction: row;
  652. justify-content: center;
  653. align-items: center;
  654. position: relative;
  655. height: 88rpx;
  656. line-height: 88rpx;
  657. border-bottom: 2rpx solid $com-cd3;
  658. .head-month {
  659. font-size: 30rpx;
  660. padding: 0 40rpx;
  661. font-weight: bold;
  662. }
  663. .day_tit{
  664. position: absolute;
  665. left: 0rpx;
  666. top: 26rpx;
  667. font-size: 30rpx;
  668. line-height: 36rpx;
  669. color: #161616;
  670. text-align: center;
  671. font-weight: bold;
  672. }
  673. .go-to-today {
  674. position: absolute;
  675. right: 16rpx;
  676. top: 26rpx;
  677. font-size: 24rpx;
  678. line-height: 36rpx;
  679. color: $com-cd3;
  680. text-align: center;
  681. width: 80rpx;
  682. height: 36rpx;
  683. border: 2rpx solid $com-cd3;
  684. border-radius: 18rpx;
  685. box-sizing: border-box;
  686. }
  687. .head-icon {
  688. content: '';
  689. display: flex;
  690. width: 22rpx;
  691. height: 22rpx;
  692. border-top: 2rpx solid $com-cd3;
  693. border-left: 2rpx solid $com-cd3;
  694. }
  695. .head-icon.head-pre-month {
  696. transform: rotate(-45deg);
  697. }
  698. .head-icon.head-next-month {
  699. transform: rotate(135deg);
  700. }
  701. .head-icon.nocheck {
  702. border-top: 2rpx solid #aaaaaa;
  703. border-left: 2rpx solid #aaaaaa;
  704. }
  705. }
  706. // 星期
  707. .week-area {
  708. display: flex;
  709. flex-direction: row;
  710. align-items: center;
  711. // border-bottom: 1px solid #EEE;
  712. padding: 16rpx 0;
  713. // margin: 0 10rpx;
  714. .week-font {
  715. flex: 1;
  716. text-align: center;
  717. color: #161616;
  718. font-size: 30rpx;
  719. font-weight: bold;
  720. }
  721. &.week-tit{
  722. .week-font:first-child{color: #aaaaaa;}
  723. .week-font:last-child{color: #aaaaaa;}
  724. }
  725. }
  726. // 日历
  727. .calendar-data {
  728. // transition: all 300ms;
  729. .swiper-item {
  730. position: relative;
  731. display: flex;
  732. justify-content: center;
  733. align-items: center;
  734. flex-direction: row;
  735. .month-bg {
  736. position: absolute;
  737. font-size: 460rpx;
  738. color: #EEE;
  739. font-weight: bold;
  740. opacity: 0.4;
  741. z-index: -1;
  742. }
  743. .month-days {
  744. flex: 1;
  745. // margin-top: 10rpx;
  746. position: relative;
  747. .week-days {
  748. display: flex;
  749. flex-direction: row;
  750. .day {
  751. flex: 1;
  752. width: 14.28%;
  753. text-align: center;
  754. // height: 84rpx;
  755. height: 88rpx;
  756. color: #000;
  757. /* #ifndef APP-NVUE */
  758. padding: 0 6rpx;
  759. /* #endif */
  760. // box-sizing: border-box;
  761. display: flex;
  762. .day-info {
  763. flex: 1;
  764. display: flex;
  765. flex-direction: column;
  766. justify-content: flex-start;
  767. align-items: center;
  768. position: relative;
  769. .day-solar {
  770. display: flex;
  771. font-size: 34rpx;
  772. line-height: 34rpx;
  773. margin-top: 2rpx;
  774. width: calc(100% - 4rpx);
  775. height: 50rpx;
  776. padding-top: 10rpx;
  777. border-radius: 16rpx 16rpx 0 0;
  778. color: #D32C26;
  779. box-sizing: border-box;
  780. background:#ffffff;display: block;
  781. }
  782. .day-lunar,
  783. .day-sign {
  784. color: #161616;
  785. font-size: 24rpx;
  786. line-height: 24rpx;
  787. transform: scale(0.8);
  788. white-space: nowrap;
  789. margin-top: 6rpx;
  790. }
  791. .day-sign {
  792. color: #161616 !important;
  793. }
  794. .day-tag {
  795. content: "";
  796. position: absolute;
  797. top: 8rpx;
  798. right: 8rpx;
  799. width: 10rpx;
  800. height: 10rpx;
  801. border-radius: 6rpx;
  802. background-color: #F75858;
  803. }
  804. }
  805. // 非当月日期
  806. .day-info.un-month {
  807. opacity: 0.25;
  808. transition: opacity 300ms;
  809. }
  810. // 今天日期
  811. .is-today .day-solar,
  812. .is-today .day-sign,
  813. .is-today .day-lunar {
  814. color: $com-cd3;
  815. }
  816. // 周末
  817. .week-end .day-solar {
  818. // color: #FF9595;
  819. }
  820. // 法定假日
  821. .is-holiday .day-solar,
  822. .is-holiday .day-sign,
  823. .is-holiday .day-lunar {
  824. color: #161616 !important;
  825. }
  826. //不能预约的日期
  827. .day-infoa,{
  828. .day-solar{color: #AAAAAA !important;}
  829. .day-sign{color: #AAAAAA !important;}
  830. .day-lunar{color: #AAAAAA !important;}
  831. }
  832. // .is-holiday{
  833. // .day-solar{color: #AAAAAA !important;}
  834. // .day-sign{color: #AAAAAA !important;}
  835. // }
  836. // 当前选中的日期
  837. .is-sel {
  838. background-color: $com-cd3;
  839. border-radius: 16rpx;
  840. .day-solar{color: $com-cd3 !important;}
  841. .day-sign{color: #ffffff !important;}
  842. }
  843. }
  844. }
  845. // .week-days.week-hide {
  846. // display: none;
  847. // }
  848. }
  849. .item-week {
  850. .un-month {
  851. opacity: 1 !important;
  852. }
  853. }
  854. }
  855. }
  856. // 收缩按钮
  857. .shrink {
  858. display: flex;
  859. justify-content: center;
  860. align-items: center;
  861. height: 60rpx;
  862. // border-top: 1px solid #DDD;
  863. .shrink-img{width: 32rpx;height: 18rpx;}
  864. /* #ifndef APP-NVUE */
  865. .shrink-btn {
  866. width: 32rpx;
  867. height: 32rpx;
  868. background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAMhJREFUOE/dky8LAkEQxd9w0WjV72KxWXfggmAyWWzXxHbNYjIJhoOZarvid9FqNB4jCyes3h9OLghu3fceb36zS+h5qKcf/xYgIisAayJKnHMa8lFVZ2YpgB0z7193FQYisgCwAXA3s8QLicgbhwC2zHwMgxshBkFeXzE2Nvh2rW8NsiybRFE0ZuZTXZCIzIuiuMZxfKltICJTAAciegDwIM9eqKozAKmZDQAsmTlvHSGY/1YKR00cWl9iGYRP8p220BXm7//CE8WyQBHBXZb9AAAAAElFTkSuQmCC);
  869. }
  870. .shrink-close {
  871. transform: rotate(180deg);
  872. }
  873. /* #endif */
  874. /* #ifdef APP-NVUE */
  875. .shrink-btn{
  876. content: '';
  877. display: flex;
  878. width: 18rpx;
  879. height: 18rpx;
  880. border-top: 2rpx solid #606266;
  881. border-left: 2rpx solid #606266;
  882. transform: rotate(-135deg);
  883. }
  884. .shrink-close {
  885. transform: rotate(45deg);
  886. }
  887. /* #endif */
  888. }
  889. }
  890. </style>