lunc-calendar.vue 31 KB

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