foodlunc-calendar.vue 30 KB

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