lunc-calendar.vue 31 KB

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