mx-datepicker.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. <template>
  2. <view v-if="isShow" class="picker">
  3. <!-- 日期选择器 -->
  4. <view v-if="type!='time'" class="picker-modal">
  5. <view class="picker-modal-header">
  6. <view class="picker-icon picker-icon-zuozuo" :hover-stay-time="100" hover-class="picker-icon-active"
  7. @click="onSetYear('-1')"></view>
  8. <view class="picker-icon picker-icon-zuo" :hover-stay-time="100" hover-class="picker-icon-active"
  9. @click="onSetMonth('-1')"></view>
  10. <text class="picker-modal-header-title">{{title}}</text>
  11. <view class="picker-icon picker-icon-you" :hover-stay-time="100" hover-class="picker-icon-active"
  12. @click="onSetMonth('+1')"></view>
  13. <view class="picker-icon picker-icon-youyou" :hover-stay-time="100" hover-class="picker-icon-active"
  14. @click="onSetYear('+1')"></view>
  15. </view>
  16. <swiper class="picker-modal-body" :circular="true" :duration="200" :skip-hidden-item-layout="true"
  17. :current="calendarIndex" @change="onSwiperChange">
  18. <swiper-item class="picker-calendar" v-for="(calendar,calendarIndex2) in calendars"
  19. :key="calendarIndex2">
  20. <view class="picker-calendar-view" v-for="(week,index) in weeks" :key="index - 7">
  21. <view class="picker-calendar-view-item">{{week}}</view>
  22. </view>
  23. <view class="picker-calendar-view" v-for="(date,dateIndex) in calendar" :key="dateIndex"
  24. @click="onSelectDate(date)">
  25. <!-- 背景样式 -->
  26. <view v-show="date.bgStyle.type" :class="'picker-calendar-view-'+date.bgStyle.type"
  27. :style="{background: date.bgStyle.background}"></view>
  28. <!-- 正常和选中样式 -->
  29. <view class="picker-calendar-view-item"
  30. :style="{opacity: date.statusStyle.opacity, color: date.statusStyle.color, background: date.statusStyle.background}">
  31. <text>{{date.title}}</text>
  32. </view>
  33. <!-- 小圆点样式 -->
  34. <view class="picker-calendar-view-dot"
  35. :style="{opacity: date.dotStyle.opacity, background: date.dotStyle.background}"></view>
  36. <!-- 信息样式 -->
  37. <view v-show="date.tips" class="picker-calendar-view-tips">{{date.tips}}</view>
  38. </view>
  39. </swiper-item>
  40. </swiper>
  41. <view class="picker-modal-footer">
  42. <view class="picker-modal-footer-info">
  43. <block v-if="isMultiSelect">
  44. <view class="picker-display">
  45. <text>{{beginText}}日期</text>
  46. <text class="picker-display-text">{{BeginTitle}}</text>
  47. <view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100"
  48. hover-class="picker-display-link-active" :style="{color}"
  49. @click="onShowTimePicker('begin')">{{BeginTimeTitle}}</view>
  50. </view>
  51. <view class="picker-display">
  52. <text>{{endText}}日期</text>
  53. <text class="picker-display-text">{{EndTitle}}</text>
  54. <view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100"
  55. hover-class="picker-display-link-active" :style="{color}"
  56. @click="onShowTimePicker('end')">{{EndTimeTitle}}</view>
  57. </view>
  58. </block>
  59. <block v-else>
  60. <view class="picker-display">
  61. <text>当前选择</text>
  62. <text class="picker-display-text">{{BeginTitle}}</text>
  63. <view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100"
  64. hover-class="picker-display-link-active" :style="{color}"
  65. @click="onShowTimePicker('begin')">{{BeginTimeTitle}}</view>
  66. </view>
  67. </block>
  68. </view>
  69. <view class="picker-modal-footer-btn">
  70. <view class="picker-btn" :hover-stay-time="100" hover-class="picker-btn-active" @click="onCancel">取消
  71. </view>
  72. <view class="picker-btn" :style="{color}" :hover-stay-time="100" hover-class="picker-btn-active"
  73. @click="onConfirm">确定</view>
  74. </view>
  75. </view>
  76. </view>
  77. <!-- 时间选择器 -->
  78. <view v-if="showTimePicker" class="picker">
  79. <view class="picker-modal picker-time">
  80. <view class="picker-modal-header">
  81. <text class="picker-modal-header-title">选择日期</text>
  82. </view>
  83. <picker-view class="picker-modal-time" indicator-class="picker-modal-time-item" :value="timeValue"
  84. @change="onTimeChange">
  85. <picker-view-column>
  86. <view v-for="(v,i) in 24" :key="i">{{i<10?'0'+i:i}}时</view>
  87. </picker-view-column>
  88. <picker-view-column>
  89. <view v-for="(v,i) in 60" :key="i">{{i<10?'0'+i:i}}分</view>
  90. </picker-view-column>
  91. <picker-view-column v-if="showSeconds">
  92. <view v-for="(v,i) in 60" :key="i">{{i<10?'0'+i:i}}秒</view>
  93. </picker-view-column>
  94. </picker-view>
  95. <view class="picker-modal-footer">
  96. <view class="picker-modal-footer-info">
  97. <view class="picker-display">
  98. <text>当前选择</text>
  99. <text class="picker-display-text">{{PickerTimeTitle}}</text>
  100. </view>
  101. </view>
  102. <view class="picker-modal-footer-btn">
  103. <view class="picker-btn" :hover-stay-time="100" hover-class="picker-btn-active"
  104. @click="onCancelTime">取消</view>
  105. <view class="picker-btn" :style="{color}" :hover-stay-time="100" hover-class="picker-btn-active"
  106. @click="onConfirmTime">确定</view>
  107. </view>
  108. </view>
  109. </view>
  110. </view>
  111. </view>
  112. </template>
  113. <script>
  114. /**
  115. * 工具函数库
  116. */
  117. const DateTools = {
  118. /**
  119. * 获取公历节日
  120. * @param date Date对象
  121. */
  122. getHoliday(date) {
  123. let holidays = {
  124. '0101': '元旦',
  125. '0214': '情人',
  126. '0308': '妇女',
  127. '0312': '植树',
  128. '0401': '愚人',
  129. '0501': '劳动',
  130. '0504': '青年',
  131. '0601': '儿童',
  132. '0701': '建党',
  133. '0801': '建军',
  134. '0903': '抗日',
  135. '0910': '教师',
  136. '1001': '国庆',
  137. '1031': '万圣',
  138. '1224': '平安',
  139. '1225': '圣诞'
  140. };
  141. let value = this.format(date, 'mmdd');
  142. if (holidays[value]) return holidays[value];
  143. return false;
  144. },
  145. /**
  146. * 解析标准日期格式
  147. * @param s 日期字符串
  148. * @return 返回Date对象
  149. */
  150. parse: s => new Date(s.replace(/(年|月|-)/g, '/').replace(/(日)/g, '')),
  151. /**
  152. * 比较日期是否为同一天
  153. * @param a Date对象
  154. * @param b Date对象
  155. * @return Boolean
  156. */
  157. isSameDay: (a, b) => a.getMonth() == b.getMonth() && a.getFullYear() == b.getFullYear() && a.getDate() == b
  158. .getDate(),
  159. /**
  160. * 格式化Date对象
  161. * @param d 日期对象
  162. * @param f 格式字符串
  163. * @return 返回格式化后的字符串
  164. */
  165. format(d, f) {
  166. var o = {
  167. "m+": d.getMonth() + 1,
  168. "d+": d.getDate(),
  169. "h+": d.getHours(),
  170. "i+": d.getMinutes(),
  171. "s+": d.getSeconds(),
  172. "q+": Math.floor((d.getMonth() + 3) / 3),
  173. };
  174. if (/(y+)/.test(f))
  175. f = f.replace(RegExp.$1, (d.getFullYear() + "").substr(4 - RegExp.$1.length));
  176. for (var k in o)
  177. if (new RegExp("(" + k + ")").test(f))
  178. f = f.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k])
  179. .length)));
  180. return f;
  181. },
  182. /**
  183. * 用于format格式化后的反解析
  184. * @param s 日期字符串
  185. * @param f 格式字符串
  186. * @return 返回Date对象
  187. */
  188. inverse(s, f) {
  189. var o = {
  190. "y": '',
  191. "m": '',
  192. "d": '',
  193. "h": '',
  194. "i": '',
  195. "s": '',
  196. };
  197. let d = new Date();
  198. if (s.length != f.length) return d;
  199. for (let i in f)
  200. if (o[f[i]] != undefined) o[f[i]] += s[i];
  201. if (o.y) d.setFullYear(o.y.length < 4 ? (d.getFullYear() + '').substr(0, 4 - o.y.length) + o.y : o.y);
  202. o.m && d.setMonth(o.m - 1, 1);
  203. o.d && d.setDate(o.d - 0);
  204. o.h && d.setHours(o.h - 0);
  205. o.i && d.setMinutes(o.i - 0);
  206. o.s && d.setSeconds(o.s - 0);
  207. return d;
  208. },
  209. /**
  210. * 获取日历数组(42天)
  211. * @param date 日期对象或日期字符串
  212. * @param proc 处理日历(和forEach类似),传递一个数组中的item
  213. * @return Array
  214. */
  215. getCalendar(date, proc) {
  216. let it = new Date(date),
  217. calendars = [];
  218. it.setDate(1);
  219. it.setDate(it.getDate() - ((it.getDay() == 0 ? 7 : it.getDay()) - 1)); //偏移量
  220. for (let i = 0; i < 42; i++) {
  221. let tmp = {
  222. dateObj: new Date(it),
  223. title: it.getDate(),
  224. isOtherMonth: it.getMonth() < date.getMonth() || it.getMonth() > date.getMonth()
  225. };
  226. calendars.push(Object.assign(tmp, proc ? proc(tmp) : {}));
  227. it.setDate(it.getDate() + 1);
  228. }
  229. return calendars;
  230. },
  231. /**
  232. * 获取日期到指定的月份1号(不改变原来的date对象)
  233. * @param d Date对象
  234. * @param v 指定的月份
  235. * @return Date对象
  236. */
  237. getDateToMonth(d, v) {
  238. let n = new Date(d);
  239. n.setMonth(v, 1);
  240. return n;
  241. },
  242. /**
  243. * 把时间数组转为时间字符串
  244. * @param t Array[时,分,秒]
  245. * @param showSecinds 是否显示秒
  246. * @return 字符串 时:分[:秒]
  247. */
  248. formatTimeArray(t, s) {
  249. let r = [...t];
  250. if (!s) r.length = 2;
  251. r.forEach((v, k) => r[k] = ('0' + v).slice(-2));
  252. return r.join(':');
  253. }
  254. };
  255. export default {
  256. props: {
  257. //颜色
  258. color: {
  259. type: String,
  260. default: '#409eff'
  261. },
  262. //是否显示秒 针对type为datetime或time时生效
  263. showSeconds: {
  264. type: Boolean,
  265. default: false
  266. },
  267. //初始的值
  268. value: [String, Array],
  269. //类型date time datetime range rangetime
  270. type: {
  271. type: String,
  272. default: 'range'
  273. },
  274. //是否显示
  275. show: {
  276. type: Boolean,
  277. default: false
  278. },
  279. //初始格式
  280. format: {
  281. type: String,
  282. default: ''
  283. },
  284. //显示公历节日
  285. showHoliday: {
  286. type: Boolean,
  287. default: true
  288. },
  289. //显示提示
  290. showTips: {
  291. type: Boolean,
  292. default: false
  293. },
  294. //开始文案 针对type为范围选择时生效
  295. beginText: {
  296. type: String,
  297. default: '开始'
  298. },
  299. //结束文案 针对type为范围选择时生效
  300. endText: {
  301. type: String,
  302. default: '结束'
  303. }
  304. },
  305. data() {
  306. return {
  307. isShow: false, //是否显示
  308. isMultiSelect: false, //是否为多选
  309. isContainTime: false, //是否包含时间
  310. date: {}, //当前日期对象
  311. weeks: ["一", "二", "三", "四", "五", "六", "日"],
  312. title: '初始化', //标题
  313. calendars: [
  314. [],
  315. [],
  316. []
  317. ], //日历数组
  318. calendarIndex: 1, //当前日历索引
  319. checkeds: [], //选中的日期对象集合
  320. showTimePicker: false, //是否显示时间选择器
  321. timeValue: [0, 0, 0], //时间选择器的值
  322. timeType: 'begin', //当前时间选择的类型
  323. beginTime: [0, 0, 0], //当前所选的开始时间值
  324. endTime: [0, 0, 0], //当前所选的结束时间值
  325. };
  326. },
  327. methods: {
  328. //设置值
  329. setValue(value) {
  330. this.date = new Date();
  331. this.checkeds = [];
  332. this.isMultiSelect = this.type.indexOf('range') >= 0;
  333. this.isContainTime = this.type.indexOf('time') >= 0;
  334. //将字符串解析为Date对象
  335. let parseDateStr = (str) => (this.format ? DateTools.inverse(str, this.format) : DateTools.parse(str));
  336. if (value) {
  337. if (this.isMultiSelect) {
  338. Array.isArray(value) && value.forEach((dateStr, index) => {
  339. let date = parseDateStr(dateStr);
  340. let time = [date.getHours(), date.getMinutes(), date.getSeconds()];
  341. if (index == 0) this.beginTime = time;
  342. else this.endTime = time;
  343. this.checkeds.push(date);
  344. });
  345. } else {
  346. if (this.type == 'time') {
  347. let date = parseDateStr('2019/1/1 ' + value);
  348. this.beginTime = [date.getHours(), date.getMinutes(), date.getSeconds()];
  349. this.onShowTimePicker('begin');
  350. } else {
  351. this.checkeds.push(parseDateStr(value));
  352. if (this.isContainTime) this.beginTime = [
  353. this.checkeds[0].getHours(),
  354. this.checkeds[0].getMinutes(),
  355. this.checkeds[0].getSeconds()
  356. ];
  357. }
  358. }
  359. if (this.checkeds.length) this.date = new Date(this.checkeds[0]);
  360. } else {
  361. if (this.isContainTime) {
  362. this.beginTime = [this.date.getHours(), this.date.getMinutes(), this.date.getSeconds()];
  363. if (this.isMultiSelect) this.endTime = [...this.beginTime];
  364. }
  365. this.checkeds.push(new Date(this.date));
  366. }
  367. if (this.type != 'time') this.refreshCalendars(true);
  368. else this.onShowTimePicker('begin');
  369. },
  370. //改变年份
  371. onSetYear(value) {
  372. this.date.setFullYear(this.date.getFullYear() + parseInt(value));
  373. this.refreshCalendars(true);
  374. },
  375. //改变月份
  376. onSetMonth(value) {
  377. this.date.setMonth(this.date.getMonth() + parseInt(value));
  378. this.refreshCalendars(true);
  379. },
  380. //时间选择变更
  381. onTimeChange(e) {
  382. this.timeValue = e.detail.value;
  383. },
  384. //设置时间选择器的显示状态
  385. onShowTimePicker(type) {
  386. this.showTimePicker = true;
  387. this.timeType = type;
  388. this.timeValue = type == 'begin' ? [...this.beginTime] : [...this.endTime];
  389. },
  390. //处理日历
  391. procCalendar(item) {
  392. //定义初始样式
  393. item.statusStyle = {
  394. opacity: 1,
  395. color: item.isOtherMonth ? '#ddd' : '#000',
  396. background: 'transparent'
  397. };
  398. item.bgStyle = {
  399. type: '',
  400. background: 'transparent'
  401. };
  402. item.dotStyle = {
  403. opacity: 1,
  404. background: 'transparent'
  405. };
  406. item.tips = "";
  407. //标记今天的日期
  408. if (DateTools.isSameDay(new Date(), item.dateObj)) {
  409. item.statusStyle.color = this.color;
  410. if (item.isOtherMonth) item.statusStyle.opacity = 0.3;
  411. }
  412. //标记选中项
  413. this.checkeds.forEach(date => {
  414. if (DateTools.isSameDay(date, item.dateObj)) {
  415. item.statusStyle.background = this.color;
  416. item.statusStyle.color = '#fff';
  417. item.statusStyle.opacity = 1;
  418. if (this.isMultiSelect && this.showTips) item.tips = this.beginText;
  419. }
  420. });
  421. //节假日或今日的日期标点
  422. if (item.statusStyle.background != this.color) {
  423. let holiday = this.showHoliday ? DateTools.getHoliday(item.dateObj) : false;
  424. if (holiday || DateTools.isSameDay(new Date(), item.dateObj)) {
  425. item.title = holiday || item.title;
  426. item.dotStyle.background = this.color;
  427. if (item.isOtherMonth) item.dotStyle.opacity = 0.2;
  428. }
  429. } else {
  430. item.title = item.dateObj.getDate();
  431. }
  432. //有两个日期
  433. if (this.checkeds.length == 2) {
  434. if (DateTools.isSameDay(this.checkeds[0], item.dateObj)) { //开始日期
  435. item.bgStyle.type = 'bgbegin';
  436. }
  437. if (DateTools.isSameDay(this.checkeds[1], item.dateObj)) { //结束日期
  438. if (this.isMultiSelect && this.showTips) item.tips = item.bgStyle.type ? this.beginText + ' / ' +
  439. this.endText : this.endText;
  440. if (!item.bgStyle.type) { //开始日期不等于结束日期
  441. item.bgStyle.type = 'bgend';
  442. } else {
  443. item.bgStyle.type = '';
  444. }
  445. }
  446. if (!item.bgStyle.type && (+item.dateObj > +this.checkeds[0] && +item.dateObj < +this.checkeds[
  447. 1])) { //中间的日期
  448. item.bgStyle.type = 'bg';
  449. item.statusStyle.color = this.color;
  450. }
  451. if (item.bgStyle.type) {
  452. item.bgStyle.background = this.color;
  453. item.dotStyle.opacity = 1;
  454. item.statusStyle.opacity = 1;
  455. }
  456. }
  457. },
  458. //刷新日历
  459. refreshCalendars(refresh = false) {
  460. let date = new Date(this.date);
  461. let before = DateTools.getDateToMonth(date, date.getMonth() - 1);
  462. let after = DateTools.getDateToMonth(date, date.getMonth() + 1);
  463. if (this.calendarIndex == 0) {
  464. if (refresh) this.calendars.splice(0, 1, DateTools.getCalendar(date, this.procCalendar));
  465. this.calendars.splice(1, 1, DateTools.getCalendar(after, this.procCalendar));
  466. this.calendars.splice(2, 1, DateTools.getCalendar(before, this.procCalendar));
  467. } else if (this.calendarIndex == 1) {
  468. this.calendars.splice(0, 1, DateTools.getCalendar(before, this.procCalendar));
  469. if (refresh) this.calendars.splice(1, 1, DateTools.getCalendar(date, this.procCalendar));
  470. this.calendars.splice(2, 1, DateTools.getCalendar(after, this.procCalendar));
  471. } else if (this.calendarIndex == 2) {
  472. this.calendars.splice(0, 1, DateTools.getCalendar(after, this.procCalendar));
  473. this.calendars.splice(1, 1, DateTools.getCalendar(before, this.procCalendar));
  474. if (refresh) this.calendars.splice(2, 1, DateTools.getCalendar(date, this.procCalendar));
  475. }
  476. this.title = DateTools.format(this.date, 'yyyy年mm月');
  477. },
  478. //滑块切换
  479. onSwiperChange(e) {
  480. this.calendarIndex = e.detail.current;
  481. let calendar = this.calendars[this.calendarIndex];
  482. this.date = new Date(calendar[22].dateObj); //取中间一天,保证是当前的月份
  483. this.refreshCalendars();
  484. },
  485. //选中日期
  486. onSelectDate(date) {
  487. if (~this.type.indexOf('range') && this.checkeds.length == 2) this.checkeds = [];
  488. else if (!(~this.type.indexOf('range')) && this.checkeds.length) this.checkeds = [];
  489. this.checkeds.push(new Date(date.dateObj));
  490. this.checkeds.sort((a, b) => a - b); //从小到大排序
  491. this.calendars.forEach(calendar => {
  492. calendar.forEach(this.procCalendar); //重新处理
  493. });
  494. },
  495. //时间选择取消
  496. onCancelTime() {
  497. this.showTimePicker = false;
  498. this.type == 'time' && this.onCancel();
  499. },
  500. //时间选择确定
  501. onConfirmTime() {
  502. if (this.timeType == 'begin') this.beginTime = this.timeValue;
  503. else this.endTime = this.timeValue;
  504. this.showTimePicker = false;
  505. this.type == 'time' && this.onConfirm();
  506. },
  507. //取消
  508. onCancel() {
  509. this.$emit('cancel', false);
  510. },
  511. //确定
  512. onConfirm() {
  513. let result = {
  514. value: null,
  515. date: null
  516. };
  517. //定义默认格式
  518. let defaultFormat = {
  519. 'date': 'yyyy/mm/dd',
  520. 'time': 'hh:ii' + (this.showSeconds ? ':ss' : ''),
  521. 'datetime': ''
  522. };
  523. defaultFormat['datetime'] = defaultFormat.date + ' ' + defaultFormat.time;
  524. let fillTime = (date, timeArr) => {
  525. date.setHours(timeArr[0], timeArr[1]);
  526. if (this.showSeconds) date.setSeconds(timeArr[2]);
  527. };
  528. if (this.type == 'time') {
  529. let date = new Date();
  530. fillTime(date, this.beginTime);
  531. result.value = DateTools.format(date, this.format ? this.format : defaultFormat.time);
  532. result.date = date;
  533. } else {
  534. if (this.isMultiSelect) {
  535. let values = [],
  536. dates = [];
  537. if (this.checkeds.length < 2) return uni.showToast({
  538. icon: 'none',
  539. title: '请选择两个日期'
  540. });
  541. this.checkeds.forEach((date, index) => {
  542. let newDate = new Date(date);
  543. if (this.isContainTime) {
  544. let time = [this.beginTime, this.endTime];
  545. fillTime(newDate, time[index]);
  546. }
  547. values.push(DateTools.format(newDate, this.format ? this.format : defaultFormat[this
  548. .isContainTime ?
  549. 'datetime' : 'date']));
  550. dates.push(newDate);
  551. });
  552. result.value = values;
  553. result.date = dates;
  554. } else {
  555. let newDate = new Date(this.checkeds[0]);
  556. if (this.isContainTime) {
  557. newDate.setHours(this.beginTime[0], this.beginTime[1]);
  558. if (this.showSeconds) newDate.setSeconds(this.beginTime[2]);
  559. }
  560. result.value = DateTools.format(newDate, this.format ? this.format : defaultFormat[this
  561. .isContainTime ?
  562. 'datetime' : 'date']);
  563. result.date = newDate;
  564. }
  565. }
  566. this.$emit('confirm', result);
  567. }
  568. },
  569. computed: {
  570. BeginTitle() {
  571. let value = '未选择';
  572. if (this.checkeds.length) value = DateTools.format(this.checkeds[0], 'yy/mm/dd');
  573. return value;
  574. },
  575. EndTitle() {
  576. let value = '未选择';
  577. if (this.checkeds.length == 2) value = DateTools.format(this.checkeds[1], 'yy/mm/dd');
  578. return value;
  579. },
  580. PickerTimeTitle() {
  581. return DateTools.formatTimeArray(this.timeValue, this.showSeconds);
  582. },
  583. BeginTimeTitle() {
  584. return this.BeginTitle != '未选择' ? DateTools.formatTimeArray(this.beginTime, this.showSeconds) : '';
  585. },
  586. EndTimeTitle() {
  587. return this.EndTitle != '未选择' ? DateTools.formatTimeArray(this.endTime, this.showSeconds) : '';
  588. }
  589. },
  590. watch: {
  591. show(newValue, oldValue) {
  592. newValue && this.setValue(this.value);
  593. this.isShow = newValue;
  594. },
  595. value(newValue, oldValue) {
  596. setTimeout(() => {
  597. this.setValue(newValue);
  598. }, 0);
  599. }
  600. }
  601. }
  602. </script>
  603. <style lang="scss" scoped>
  604. $z-index: 99999;
  605. $cell-spacing: 20upx;
  606. $calendar-size: 630upx;
  607. $calendar-item-size: 90upx;
  608. .picker {
  609. position: fixed;
  610. z-index: $z-index;
  611. background: rgba(0, 0, 0, .7);
  612. left: 0;
  613. top: 0;
  614. width: 100%;
  615. height: 100%;
  616. font-size: 28upx;
  617. &-btn {
  618. padding: $cell-spacing*0.5 $cell-spacing;
  619. border-radius: 12upx;
  620. color: #666;
  621. &-active {
  622. background: rgba(0, 0, 0, .1);
  623. }
  624. }
  625. &-display {
  626. color: #666;
  627. &-text {
  628. color: #000;
  629. margin: 0 $cell-spacing*0.5;
  630. }
  631. &-link {
  632. display: inline-block;
  633. &-active {
  634. background: rgba(0, 0, 0, .1);
  635. }
  636. }
  637. }
  638. &-time {
  639. width: $calendar-size - 80upx !important;
  640. left: ((750upx - $calendar-size) / 2 + 40upx) !important;
  641. }
  642. &-modal {
  643. background: #fff;
  644. position: absolute;
  645. top: 50%;
  646. left: (750upx - $calendar-size) / 2;
  647. width: $calendar-size;
  648. transform: translateY(-50%);
  649. box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.1);
  650. border-radius: 12upx;
  651. &-header {
  652. text-align: center;
  653. line-height: 80upx;
  654. font-size: 32upx;
  655. &-title {
  656. display: inline-block;
  657. width: 40%;
  658. }
  659. .picker-icon {
  660. display: inline-block;
  661. line-height: 50upx;
  662. width: 50upx;
  663. height: 50upx;
  664. border-radius: 50upx;
  665. text-align: center;
  666. margin: 10upx;
  667. background: #fff;
  668. font-size: 36upx;
  669. &-active {
  670. background: rgba(0, 0, 0, .1);
  671. }
  672. }
  673. }
  674. &-body {
  675. width: $calendar-size !important;
  676. height: $calendar-size !important;
  677. position: relative;
  678. }
  679. &-time {
  680. width: 100%;
  681. height: 180upx;
  682. text-align: center;
  683. line-height: 60upx;
  684. }
  685. &-footer {
  686. display: flex;
  687. justify-content: space-between;
  688. align-items: center;
  689. padding: $cell-spacing;
  690. &-info {
  691. flex-grow: 1;
  692. }
  693. &-btn {
  694. flex-shrink: 0;
  695. display: flex;
  696. }
  697. }
  698. }
  699. &-calendar {
  700. position: absolute;
  701. left: 0;
  702. top: 0;
  703. width: 100%;
  704. height: 100%;
  705. display: flex;
  706. align-items: center;
  707. flex-wrap: wrap;
  708. &-view {
  709. position: relative;
  710. width: $calendar-item-size;
  711. height: $calendar-item-size;
  712. text-align: center;
  713. &-bgbegin,
  714. &-bg,
  715. &-bgend,
  716. &-item,
  717. &-dot,
  718. &-tips {
  719. position: absolute;
  720. transition: .2s;
  721. }
  722. &-bgbegin,
  723. &-bg,
  724. &-bgend {
  725. opacity: .15;
  726. height: 80%;
  727. }
  728. &-bg {
  729. left: 0;
  730. top: 10%;
  731. width: 100%;
  732. }
  733. &-bgbegin {
  734. border-radius: $calendar-item-size 0 0 $calendar-item-size;
  735. top: 10%;
  736. left: 10%;
  737. width: 90%;
  738. }
  739. &-bgend {
  740. border-radius: 0 $calendar-item-size $calendar-item-size 0;
  741. top: 10%;
  742. left: 0%;
  743. width: 90%;
  744. }
  745. &-item {
  746. left: 5%;
  747. top: 5%;
  748. width: 90%;
  749. height: 90%;
  750. border-radius: $calendar-item-size;
  751. display: flex;
  752. align-items: center;
  753. justify-content: center;
  754. }
  755. &-dot {
  756. right: 10%;
  757. top: 10%;
  758. width: 12upx;
  759. height: 12upx;
  760. border-radius: 12upx;
  761. }
  762. &-tips {
  763. bottom: 100%;
  764. left: 50%;
  765. transform: translateX(-50%);
  766. background: #4E4B46;
  767. color: #fff;
  768. border-radius: 12upx;
  769. padding: 10upx 20upx;
  770. font-size: 24upx;
  771. width: max-content;
  772. margin-bottom: 5px;
  773. pointer-events: none;
  774. &:after {
  775. content: "";
  776. position: absolute;
  777. top: 100%;
  778. left: 50%;
  779. transform: translateX(-50%);
  780. width: 0;
  781. height: 0;
  782. border-style: solid;
  783. border-width: 5px 5px 0 5px;
  784. border-color: #4E4B46 transparent transparent transparent;
  785. }
  786. }
  787. }
  788. }
  789. }
  790. @font-face {
  791. font-family: "mxdatepickericon";
  792. src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAMYAAsAAAAACBgAAALMAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDIgqDRIJiATYCJAMUCwwABCAFhG0HSRvfBsg+QCa3noNAyAQ9w6GDvbwpNp2vloCyn8bD/x+y+/5qDhtj+T4eRVEcbsCoKMFASzCgLdDkmqYDwgxkWQ6YH5L/YnppOlLEjlnter43YRjU7M6vJ3iGADVAgJn5kqjv/wEii23T86UsAQT+04fV+o97VTMx4PPZt4DlorLXwIQiGMA5uhaVrBWqGHfQXcTEiE+PE+g2SUlxWlLVBHwUYFMgrgwSB3wstTKSGzqF1nOyiGeeOtNjV4An/vvxR58PSc3AzrMViyDvPo/7dVEUzn5GROfIWAcU4rLXfMFdhte56y4We9gGNEVIezkBOOaQXUrbTf/hJVkhGpDdCw7dSOEzByMEn3kIic98hMxnAfeFPKWCbjRcA148/HxhCEkaA94eGWFaGolsblpaWz8/Po2WVuNHh1fmBpZHIpqal9fOjizhTteY+RZ9rv02I/pq0W6QVH3pSncBz3m55r9ZIPycHfmenvxe4uyutIgfT5u4bgkDusl9gcF0rnfnz+b2NpSaQWBFeu8GIL1xQj5AH/6FAsEr/50F28e/gA9ny6KjLrxIp0TE+UucmQOl5AFNLXkzZufWamWHYEI39PEP2If97CMdm51N6DSmIekwAVmneXTBr0PVYx+aTgfQbU3p+R4jKHdRurBq0oEw6AKSfm+QDbpGF/w3VOP+oBnMHbqdx409FjP4RRHHkAj5IWgQiBUjHfMTuQ1Icpg5avI4sQVRu8EHdWptM1aKrIjuscfeL+kZwxBTYoElztOQ2UygjRIjEphaZsyWodHgvm9SC8QC/JygEA6DiCDeEMhAQFhhOpvxa/18A0TiYMahIy0L2hYIZWeYH9JR085Al4qts1re5St2/SR6DINBGEVYQCWOETHDMAHZ+pcZIQJGTV4RtMmg8UbhuWL1+VLLA2RFHYC71kiRo0SNpjwQh8pj2EFU3oTNmS1WqgIA') format('woff2');
  793. }
  794. .picker-icon {
  795. font-family: "mxdatepickericon" !important;
  796. }
  797. .picker-icon-you:before {
  798. content: "\e63e";
  799. }
  800. .picker-icon-zuo:before {
  801. content: "\e640";
  802. }
  803. .picker-icon-zuozuo:before {
  804. content: "\e641";
  805. }
  806. .picker-icon-youyou:before {
  807. content: "\e642";
  808. }
  809. </style>