lunc-calendar.vue 29 KB

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