uv-calendars.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. <template>
  2. <view class="uv-calendar">
  3. <view class="uv-calendar__content" v-if="insert">
  4. <uv-calendar-body
  5. :date="date"
  6. :nowDate="nowDate"
  7. :weeks="weeks"
  8. :calendar="calendar"
  9. :selected="selected"
  10. :lunar="lunar"
  11. :showMonth="showMonth"
  12. :color="color"
  13. :startText="startText"
  14. :endText="endText"
  15. @bindDateChange="bindDateChange"
  16. @pre="pre"
  17. @next="next"
  18. @backToday="backToday"
  19. @choiceDate="choiceDate"
  20. ></uv-calendar-body>
  21. </view>
  22. <uv-popup ref="popup" mode="bottom" v-else :round="round" :close-on-click-overlay="closeOnClickOverlay" @maskClick="maskClick">
  23. <view style="min-height: 100px;">
  24. <uv-toolbar
  25. :show="true"
  26. :cancelColor="cancelColor"
  27. :confirmColor="getConfirmColor"
  28. :cancelText="cancelText"
  29. :confirmText="confirmText"
  30. :title="title"
  31. @cancel="close"
  32. @confirm="confirm"></uv-toolbar>
  33. <view class="line"></view>
  34. <uv-calendar-body
  35. :nowDate="nowDate"
  36. :weeks="weeks"
  37. :calendar="calendar"
  38. :selected="selected"
  39. :lunar="lunar"
  40. :showMonth="showMonth"
  41. :color="color"
  42. :startText="startText"
  43. :endText="endText"
  44. @bindDateChange="bindDateChange"
  45. @pre="pre"
  46. @next="next"
  47. @backToday="backToday"
  48. @choiceDate="choiceDate"
  49. ></uv-calendar-body>
  50. </view>
  51. </uv-popup>
  52. </view>
  53. </template>
  54. <script>
  55. /**
  56. * Calendar 日历
  57. * @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
  58. * @tutorial https://ext.dcloud.net.cn/plugin?name=uv-calendar
  59. * @property {String} date 自定义当前时间,默认为今天
  60. * @property {Boolean} lunar 显示农历
  61. * @property {String} startDate 日期选择范围-开始日期
  62. * @property {String} endDate 日期选择范围-结束日期
  63. * @property {Boolean} range 范围选择
  64. * @property {Boolean} insert = [true|false] 插入模式,默认为false
  65. * @value true 弹窗模式
  66. * @value false 插入模式
  67. * @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
  68. * @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
  69. * @property {String} cancelColor 取消按钮颜色
  70. * @property {String} confirmColor 确认按钮颜色,默认#3c9cff
  71. * @property {String} title 头部工具条中间的标题文字
  72. * @property {String} color 主题色,默认#3c9cff
  73. * @property {Number} round :insert="false"时的圆角
  74. * @property {Boolean} closeOnClickOverlay 点击遮罩是否关闭
  75. * @property {String} startText range为true时,第一个日期底部的提示文字
  76. * @property {String} endText range为true时,最后一个日期底部的提示文字
  77. *
  78. * @event {Function} change 日期改变,`insert :ture` 时生效
  79. * @event {Function} confirm 确认选择`insert :false` 时生效
  80. * @event {Function} monthSwitch 切换月份时触发
  81. *
  82. * @example <uv-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
  83. */
  84. import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
  85. import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
  86. import Calendar from './util.js';
  87. import uvCalendarBody from './uv-calendar-body.vue';
  88. import { initVueI18n } from '@dcloudio/uni-i18n';
  89. import i18nMessages from './i18n/index.js';
  90. const { t } = initVueI18n(i18nMessages);
  91. export default {
  92. components: {
  93. uvCalendarBody
  94. },
  95. mixins: [mpMixin, mixin],
  96. emits: ['close', 'confirm', 'change', 'monthSwitch'],
  97. props: {
  98. cancelColor: {
  99. type: String,
  100. default: ''
  101. },
  102. confirmColor: {
  103. type: String,
  104. default: '#3c9cff'
  105. },
  106. title: {
  107. type: String,
  108. default: ''
  109. },
  110. color: {
  111. type: String,
  112. default: '#3c9cff'
  113. },
  114. date: {
  115. type: String,
  116. default: ''
  117. },
  118. selected: {
  119. type: Array,
  120. default () {
  121. return []
  122. }
  123. },
  124. lunar: {
  125. type: Boolean,
  126. default: false
  127. },
  128. startDate: {
  129. type: String,
  130. default: ''
  131. },
  132. endDate: {
  133. type: String,
  134. default: ''
  135. },
  136. range: {
  137. type: Boolean,
  138. default: false
  139. },
  140. insert: {
  141. type: Boolean,
  142. default: false
  143. },
  144. showMonth: {
  145. type: Boolean,
  146. default: true
  147. },
  148. clearDate: {
  149. type: Boolean,
  150. default: true
  151. },
  152. round: {
  153. type: Number,
  154. default: 8
  155. },
  156. closeOnClickOverlay: {
  157. type: Boolean,
  158. default: true
  159. },
  160. startText: {
  161. type: String,
  162. default: '开始'
  163. },
  164. endText: {
  165. type: String,
  166. default: '结束'
  167. }
  168. },
  169. data(){
  170. return {
  171. weeks: [],
  172. calendar: {},
  173. nowDate: '',
  174. allowConfirm: false
  175. }
  176. },
  177. computed:{
  178. /**
  179. * for i18n
  180. */
  181. confirmText() {
  182. return t("uv-calender.ok")
  183. },
  184. cancelText() {
  185. return t("uv-calender.cancel")
  186. },
  187. getConfirmColor() {
  188. if(!this.range) {
  189. return this.confirmColor;
  190. }else {
  191. return this.allowConfirm? this.confirmColor: '#999'
  192. }
  193. }
  194. },
  195. watch: {
  196. date(newVal) {
  197. this.init(newVal)
  198. },
  199. startDate(val) {
  200. this.cale.resetSatrtDate(val)
  201. this.cale.setDate(this.nowDate.fullDate)
  202. this.weeks = this.cale.weeks
  203. },
  204. endDate(val) {
  205. this.cale.resetEndDate(val)
  206. this.cale.setDate(this.nowDate.fullDate)
  207. this.weeks = this.cale.weeks
  208. },
  209. selected(newVal) {
  210. this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
  211. this.weeks = this.cale.weeks
  212. }
  213. },
  214. created() {
  215. this.cale = new Calendar({
  216. selected: this.selected,
  217. startDate: this.startDate,
  218. endDate: this.endDate,
  219. range: this.range,
  220. })
  221. this.init(this.date)
  222. },
  223. methods: {
  224. async open() {
  225. if (this.clearDate && !this.insert) {
  226. this.cale.cleanMultipleStatus()
  227. this.init(this.date)
  228. }
  229. if(!this.insert){
  230. this.$refs.popup.open();
  231. }
  232. },
  233. close() {
  234. this.$refs.popup.close();
  235. this.$emit('close');
  236. },
  237. confirm() {
  238. if(this.range && !this.cale.multipleStatus.after) {
  239. return;
  240. }
  241. this.setEmit('confirm');
  242. this.close()
  243. },
  244. maskClick() {
  245. if(this.closeOnClickOverlay) {
  246. this.$emit('close');
  247. }
  248. },
  249. bindDateChange(e) {
  250. const value = e.detail.value + '-1'
  251. this.setDate(value)
  252. const { year, month } = this.cale.getDate(value)
  253. this.$emit('monthSwitch', {
  254. year,
  255. month
  256. })
  257. },
  258. /**
  259. * 初始化日期显示
  260. * @param {Object} date
  261. */
  262. init(date) {
  263. if(this.range) {
  264. // 重置多选状态
  265. this.cale.cleanMultipleStatus();
  266. }
  267. this.cale.setDate(date)
  268. this.weeks = this.cale.weeks
  269. this.nowDate = this.calendar = this.cale.getInfo(date)
  270. if(this.range) {
  271. this.choiceDate(this.nowDate);
  272. }
  273. },
  274. /**
  275. * 变化触发
  276. */
  277. change() {
  278. if (this.range) {
  279. this.allowConfirm = this.cale.multipleStatus.after ? true : false;
  280. }
  281. if (!this.insert) return
  282. this.setEmit('change')
  283. },
  284. /**
  285. * 选择月份触发
  286. */
  287. monthSwitch() {
  288. let {
  289. year,
  290. month
  291. } = this.nowDate
  292. this.$emit('monthSwitch', {
  293. year,
  294. month: Number(month)
  295. })
  296. },
  297. /**
  298. * 派发事件
  299. * @param {Object} name
  300. */
  301. setEmit(name) {
  302. let {
  303. year,
  304. month,
  305. date,
  306. fullDate,
  307. lunar,
  308. extraInfo
  309. } = this.calendar
  310. this.$emit(name, {
  311. range: this.cale.multipleStatus,
  312. year,
  313. month,
  314. date,
  315. fulldate: fullDate,
  316. lunar,
  317. extraInfo: extraInfo || {}
  318. })
  319. },
  320. /**
  321. * 选择天触发
  322. * @param {Object} weeks
  323. */
  324. choiceDate(weeks) {
  325. if (weeks.disable) return
  326. this.calendar = weeks
  327. // 设置多选
  328. this.cale.setMultiple(this.calendar.fullDate)
  329. this.weeks = this.cale.weeks
  330. this.change()
  331. },
  332. /**
  333. * 回到今天
  334. */
  335. backToday() {
  336. const nowYearMonth = `${this.nowDate.year}-${this.nowDate.month}`
  337. const date = this.cale.getDate(new Date())
  338. const todayYearMonth = `${date.year}-${date.month}`
  339. if (nowYearMonth !== todayYearMonth) {
  340. this.monthSwitch()
  341. }
  342. this.init(date.fullDate)
  343. this.change()
  344. },
  345. /**
  346. * 上个月
  347. */
  348. pre() {
  349. const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
  350. this.setDate(preDate)
  351. this.monthSwitch()
  352. },
  353. /**
  354. * 下个月
  355. */
  356. next() {
  357. const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
  358. this.setDate(nextDate)
  359. this.monthSwitch()
  360. },
  361. /**
  362. * 设置日期
  363. * @param {Object} date
  364. */
  365. setDate(date) {
  366. this.cale.setDate(date)
  367. this.weeks = this.cale.weeks
  368. this.nowDate = this.cale.getInfo(date)
  369. }
  370. }
  371. }
  372. </script>
  373. <style scoped lang="scss">
  374. $uv-border-color: #EDEDED !default;
  375. .uv-calendar__content {
  376. background-color: #fff;
  377. }
  378. .line {
  379. width: 750rpx;
  380. height: 1px;
  381. border-bottom-color: $uv-border-color;
  382. border-bottom-style: solid;
  383. border-bottom-width: 1px;
  384. }
  385. </style>