biaofun-datetime-picker.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. <!--
  2. * @插件:日期时间选择器
  3. * @作者:陈万照
  4. * @公司:山东标梵互动信息技术有限公司
  5. * @官网:http://biaofun.com/
  6. * @微信:C207668802
  7. * @QQ:207668802
  8. * @邮箱:cwz@biaofun.com || 207668802@qq.com
  9. * @版本:v1.0.8
  10. -->
  11. <template>
  12. <view class="datatime">
  13. <picker mode="multiSelector" :range="range" range-key="text" @change="change" @columnchange="columnchange" :value="value" :disabled="disabled">
  14. <view class="content" :class="{ placeholder: !dateStr }">
  15. <text>{{ dateStr ? dateStr : placeholder }}</text>
  16. </view>
  17. </picker>
  18. </view>
  19. </template>
  20. <script>
  21. import utils from '@/common/utils.js'; // 封装的工具集
  22. export default {
  23. /**
  24. * 数据
  25. */
  26. props: {
  27. // 是否禁用
  28. disabled: {
  29. type: Boolean,
  30. default: false
  31. },
  32. // 占位符
  33. placeholder: {
  34. type: String,
  35. default: '请选择日期时间'
  36. },
  37. // 表示有效日期时间范围的开始,
  38. // 字符串格式为 "YYYY-MM-DD hh:mm"
  39. start: {
  40. type: String,
  41. default: '1970-1-1 00:00'
  42. },
  43. // 表示有效日期时间范围的结束
  44. // 字符串格式为 "YYYY-MM-DD hh:mm"
  45. end: {
  46. type: String,
  47. default: '2300-1-1 00:00'
  48. },
  49. // 表示选择器的粒度,有效值:year | month | day | hour | minute
  50. fields: {
  51. type: String,
  52. default: 'minute'
  53. },
  54. // 默认值
  55. // 字符串格式为 "YYYY-MM-DD hh:mm"
  56. defaultValue: {
  57. type: String,
  58. default: ''
  59. }
  60. },
  61. /**
  62. * 数据
  63. */
  64. data() {
  65. return {
  66. range: [],
  67. value: [],
  68. dateStr: '', // 最终显示的字符串
  69. dtStart: null, // 有效范围开始
  70. dtEnd: null, // 有效范围结束
  71. };
  72. },
  73. /**
  74. * 监听数据
  75. */
  76. watch: {
  77. // 默认值
  78. defaultValue() {
  79. // 设置默认值
  80. this.setDefaultValue();
  81. }
  82. },
  83. /**
  84. * 组件初次加载完成
  85. */
  86. mounted() {
  87. // 有效日期开始和结束
  88. let start = this.start;
  89. let end = this.end;
  90. // 验证是否是有效的开始和结束日期
  91. if(!utils.isString(this.start)) {
  92. console.log('开始日期需为String类型,格式为 "YYYY-MM-DD hh:mm"');
  93. start = '1970-1-1 00:00';
  94. }
  95. if(!utils.isString(this.start)) {
  96. console.log('结束日期需为String类型,格式为 "YYYY-MM-DD hh:mm"');
  97. start = '2300-1-1 00:00';
  98. }
  99. // 将开始日期和结束日期转为 Date
  100. let dtStart = utils.formatDate(start).dt;
  101. let dtEnd = utils.formatDate(end).dt;
  102. // 判断有效日期结束是否大于有效日期开始,如果不是,则将有效日期结束修改为有效日期开始往后300年
  103. if (dtEnd <= dtStart) {
  104. dtEnd = utils.formatDate(start).dt;
  105. dtEnd.setFullYear(dtStart.getFullYear() + 300);
  106. dtEnd.setDate(dtEnd.getDate() - 1);
  107. }
  108. // 更新开始日期和结束日期
  109. this.dtStart = dtStart;
  110. this.dtEnd = dtEnd;
  111. // 设置默认值
  112. this.setDefaultValue();
  113. },
  114. /**
  115. * 方法
  116. */
  117. methods: {
  118. /**
  119. * 清空
  120. */
  121. clearTime(){
  122. this.dateStr = ''
  123. },
  124. /**
  125. * 确认选择
  126. */
  127. change(event) {
  128. let year, month, day, hour, minute;
  129. if(this.fields == 'year') {
  130. year = this.range[0][this.value[0]].number; // 年
  131. let dtStr = `${year}`;
  132. this.setDateStr(dtStr);
  133. this.$emit('change', utils.formatDate(dtStr));
  134. return;
  135. }
  136. else if(this.fields == 'month') {
  137. year = this.range[0][this.value[0]].number; // 年
  138. month = this.range[1][this.value[1]].number; // 月
  139. let dtStr = `${year}-${month}`;
  140. this.setDateStr(dtStr);
  141. this.$emit('change', utils.formatDate(dtStr));
  142. return;
  143. }
  144. else if(this.fields == 'day') {
  145. year = this.range[0][this.value[0]].number; // 年
  146. month = this.range[1][this.value[1]].number; // 月
  147. day = this.range[2][this.value[2]].number; // 日
  148. let dtStr = `${year}-${month}-${day}`;
  149. this.setDateStr(dtStr);
  150. this.$emit('change', utils.formatDate(dtStr));
  151. return;
  152. }
  153. else if(this.fields == 'hour') {
  154. year = this.range[0][this.value[0]].number; // 年
  155. month = this.range[1][this.value[1]].number; // 月
  156. day = this.range[2][this.value[2]].number; // 日
  157. hour = this.range[3][this.value[3]].number; // 时
  158. day = this.range[2][this.value[2]].number; // 日
  159. let dtStr = `${year}-${month}-${day} ${hour}`;
  160. this.setDateStr(dtStr);
  161. this.$emit('change', utils.formatDate(dtStr));
  162. return;
  163. }
  164. else if(this.fields == 'minute') {
  165. year = this.range[0][this.value[0]].number; // 年
  166. month = this.range[1][this.value[1]].number; // 月
  167. day = this.range[2][this.value[2]].number; // 日
  168. hour = this.range[3][this.value[3]].number; // 时
  169. minute = this.range[4][this.value[4]].number; // 分
  170. let dtStr = `${year}-${month}-${day} ${hour}:${minute}`;
  171. this.setDateStr(dtStr);
  172. this.$emit('change', utils.formatDate(dtStr));
  173. return;
  174. }
  175. },
  176. /**
  177. * 设置显示的值
  178. * @param {Date|String} date 日期字符串或日期对象
  179. */
  180. setDateStr(date) {
  181. let dt = utils.formatDate(date);
  182. if(this.fields == 'year') {
  183. this.dateStr = `${dt.YYYY}年`;
  184. return;
  185. }
  186. if(this.fields == 'month') {
  187. this.dateStr = `${dt.YYYY}年${dt.M}月`;
  188. return;
  189. }
  190. if(this.fields == 'day') {
  191. this.dateStr = `${dt.YYYY}年${dt.M}月${dt.D}日`;
  192. return;
  193. }
  194. if(this.fields == 'hour') {
  195. this.dateStr = `${dt.YYYY}年${dt.M}月${dt.D}日 ${dt.h}时`;
  196. return;
  197. }
  198. this.dateStr = `${dt.YYYY}年${dt.M}月${dt.D}日 ${dt.h}时${dt.m}分`;
  199. },
  200. /**
  201. * 设置年数据
  202. */
  203. setYearData() {
  204. // 有效日期
  205. let yearStart = this.dtStart.getFullYear();
  206. let yearEnd = this.dtEnd.getFullYear();
  207. // 年
  208. let years = [];
  209. for (let year = yearStart; year <= yearEnd; year++) {
  210. let item = {
  211. number: year,
  212. text: `${year}年`,
  213. };
  214. years.push(item);
  215. }
  216. this.range.splice(0, 1, years);
  217. },
  218. /**
  219. * 设置月数据
  220. * @param {Number} year 年
  221. */
  222. setMonthData(year) {
  223. // 有效日期
  224. let yearStart = this.dtStart.getFullYear();
  225. let monthStart = this.dtStart.getMonth() + 1;
  226. let yearEnd = this.dtEnd.getFullYear();
  227. let monthEnd = this.dtEnd.getMonth() + 1;
  228. // 月
  229. let months = [];
  230. let monthStartIndex = year == yearStart ? monthStart : 1;
  231. let monthEndIndex = year == yearEnd ? monthEnd : 12;
  232. for (let month = monthStartIndex; month <= monthEndIndex; month++) {
  233. let item = {
  234. number: month,
  235. text: `${month}月`,
  236. };
  237. months.push(item);
  238. }
  239. this.range.splice(1, 1, months);
  240. },
  241. /**
  242. * 设置日数据
  243. * @param {Number} year 年
  244. * @param {Number} month 月
  245. */
  246. setDayData(year, month) {
  247. // 有效日期
  248. let yearStart = this.dtStart.getFullYear();
  249. let monthStart = this.dtStart.getMonth() + 1;
  250. let dayStart = this.dtStart.getDate();
  251. let yearEnd = this.dtEnd.getFullYear();
  252. let monthEnd = this.dtEnd.getMonth() + 1;
  253. let dayEnd = this.dtEnd.getDate();
  254. // 日
  255. let days = [];
  256. let dayStartIndex = year == yearStart && month == monthStart ? dayStart : 1;
  257. let dayEndIndex;
  258. if(year == yearEnd && month == monthEnd) {
  259. dayEndIndex = dayEnd;
  260. } else {
  261. dayEndIndex = (new Date(year, month, 0)).getDate();
  262. }
  263. for (let day = dayStartIndex; day <= dayEndIndex; day++) {
  264. let item = {
  265. number: day,
  266. text: `${day}日`,
  267. };
  268. days.push(item);
  269. }
  270. this.range.splice(2, 1, days);
  271. },
  272. /**
  273. * 设置时数据
  274. * @param {Number} year 年
  275. * @param {Number} month 月
  276. * @param {Number} day 日
  277. */
  278. setHourData(year, month, day) {
  279. // 有效日期
  280. let yearStart = this.dtStart.getFullYear();
  281. let monthStart = this.dtStart.getMonth() + 1;
  282. let dayStart = this.dtStart.getDate();
  283. let hourStart = this.dtStart.getHours();
  284. let yearEnd = this.dtEnd.getFullYear();
  285. let monthEnd = this.dtEnd.getMonth() + 1;
  286. let dayEnd = this.dtEnd.getDate();
  287. let hourEnd = this.dtEnd.getHours();
  288. // 时
  289. let hours = [];
  290. let hourStartIndex = year == yearStart && month == monthStart && day == dayStart ? hourStart : 0;
  291. let hourEndIndex = year == yearEnd && month == monthEnd && day == dayEnd ? hourEnd : 23;
  292. for (let hour = hourStartIndex; hour <= hourEndIndex; hour++) {
  293. let item = {
  294. number: hour,
  295. text: `${hour}时`,
  296. };
  297. hours.push(item);
  298. }
  299. this.range.splice(3, 1, hours);
  300. },
  301. /**
  302. * 设置分数据
  303. * @param {Number} year 年
  304. * @param {Number} month 月
  305. * @param {Number} day 日
  306. * @param {Number} hour 时
  307. */
  308. setMinuteData(year, month, day, hour) {
  309. // 有效日期
  310. let yearStart = this.dtStart.getFullYear();
  311. let monthStart = this.dtStart.getMonth() + 1;
  312. let dayStart = this.dtStart.getDate();
  313. let hourStart = this.dtStart.getHours();
  314. let minuteStart = this.dtStart.getMinutes();
  315. let yearEnd = this.dtEnd.getFullYear();
  316. let monthEnd = this.dtEnd.getMonth() + 1;
  317. let dayEnd = this.dtEnd.getDate();
  318. let hourEnd = this.dtEnd.getHours();
  319. let minuteEnd = this.dtEnd.getMinutes();
  320. // 分
  321. let minutes = [];
  322. let minuteStartIndex = year == yearStart && month == monthStart && day == dayStart && hour == hourStart ? minuteStart : 0;
  323. let minuteEndIndex = year == yearEnd && month == monthEnd && day == dayEnd && hour == hourEnd ? minuteEnd : 59;
  324. for(let minute = minuteStartIndex; minute <= minuteEndIndex; minute++) {
  325. let item = {
  326. number: minute,
  327. text: `${minute}分`,
  328. }
  329. minutes.push(item);
  330. }
  331. this.range.splice(4, 1, minutes);
  332. },
  333. /**
  334. * 设置默认值
  335. */
  336. setDefaultValue() {
  337. // 默认日期
  338. let dtDefault;
  339. // 开始日期和结束日期
  340. let dtStart = this.dtStart;
  341. let dtEnd = this.dtEnd;
  342. // 判断是否传了默认日期
  343. // 传了默认日期,格式化默认日期为日期对象
  344. if(this.defaultValue) {
  345. /* 上一天 */
  346. /* const curDate = new Date();
  347. curDate.setDate(curDate.getDate() - 1);
  348. dtDefault = utils.formatDate(curDate).dt; */
  349. /* 上一月 */
  350. /* const curDate = new Date();
  351. let nowDate = curDate.getDate();
  352. let lastMonth = new Date(curDate.getTime());
  353. // 设置上一个月(这里不需要减1)
  354. lastMonth.setMonth(lastMonth.getMonth());
  355. // 设置为0,默认为当前月的最后一天
  356. lastMonth.setDate(0);
  357. // 上一个月的天数
  358. let daysOflastMonth = lastMonth.getDate();
  359. // 设置上一个月的日期,如果当前月的日期大于上个月的总天数,则为最后一天
  360. lastMonth.setDate(nowDate > daysOflastMonth ? daysOflastMonth : nowDate);
  361. dtDefault = utils.formatDate(lastMonth).dt; */
  362. /* 原先的 */
  363. dtDefault = utils.formatDate(this.defaultValue).dt;
  364. }
  365. // 如果没有传默认日期,将默认日期设置为当前日期
  366. else {
  367. dtDefault = new Date();
  368. // dtDefault = new Date(new Date().getTi me() - 24*60*60*1000);
  369. }
  370. // 如果默认日期不在有效日期范围内,设置默认日期为有效日期开始值
  371. if (dtDefault < dtStart || dtDefault > dtEnd) {
  372. dtDefault = dtStart;
  373. }
  374. // 更新 dateStr
  375. if(this.defaultValue) this.setDateStr(dtDefault);
  376. // 默认值相关数据
  377. let dfYear = dtDefault.getFullYear();
  378. let dfMonth = dtDefault.getMonth() + 1;
  379. let dfDay = dtDefault.getDate();
  380. let dfHour = dtDefault.getHours();
  381. let dfMinute = dtDefault.getMinutes();
  382. // 设置年数据
  383. this.setYearData();
  384. // 设置 Year 这一列的 value 值
  385. let yearIndex = this.range[0].findIndex(year => {
  386. return dfYear == year.number;
  387. });
  388. this.value.splice(0, 1, yearIndex >= 0 ? yearIndex : 0);
  389. // 设置月数据
  390. if(this.fields == 'year') return;
  391. this.setMonthData(dfYear);
  392. // 设置 Month 这一列的 value 值
  393. let monthIndex = this.range[1].findIndex(month => {
  394. return dfMonth == month.number;
  395. });
  396. this.value.splice(1, 1, monthIndex >=0 ? monthIndex : 0);
  397. // 设置日数据
  398. if(this.fields == 'month') return;
  399. this.setDayData(dfYear, dfMonth);
  400. // 设置 Day 这一列的 value 值
  401. let dayIndex = this.range[2].findIndex(day => {
  402. return dfDay == day.number;
  403. });
  404. this.value.splice(2, 1, dayIndex >=0 ? dayIndex : 0);
  405. // 设置时数据
  406. if(this.fields == 'day') return;
  407. this.setHourData(dfYear, dfMonth, dfDay);
  408. // 设置 Hour 这一列的 value 值
  409. let hourIndex = this.range[3].findIndex(hour => {
  410. return dfHour == hour.number;
  411. });
  412. this.value.splice(3, 1, hourIndex >=0 ? hourIndex : 0);
  413. // 设置分数据
  414. if(this.fields == 'hour') return;
  415. this.setMinuteData(dfYear, dfMonth, dfDay, dfHour);
  416. // 设置 Minute 这一列的 value 值
  417. let minuteIndex = this.range[4].findIndex(minute => {
  418. return dfMinute == minute.number;
  419. });
  420. this.value.splice(4, 1, minuteIndex >=0 ? minuteIndex : 0);
  421. },
  422. /**
  423. * 某一列的值改变时触发
  424. * @param {Number} event.detail.column 表示改变了第几列(下标从0开始)
  425. * @param {Number} event.detail.value 表示变更值的下标
  426. */
  427. columnchange(event) {
  428. let columnIndex = event.detail.column; // 改变的列的下标
  429. let valueIndex = event.detail.value; // 变更值的下标
  430. // 更新改变列的 value
  431. this.value.splice(columnIndex, 1, valueIndex);
  432. // 改变年要更新月数据
  433. if(this.fields == 'year') return;
  434. if (columnIndex == 0) {
  435. // 当前选择的月
  436. let monthBeforeUpdate = this.range[1][this.value[1]];
  437. // 更新月数据
  438. this.setMonthData(this.range[0][this.value[0]].number);
  439. // 更新 Month Value
  440. let monthIndex = this.range[1].findIndex(month => {
  441. return month.number == monthBeforeUpdate.number;
  442. });
  443. this.value.splice(1, 1, monthIndex >= 0 ? monthIndex : 0);
  444. }
  445. // 改变年、月都要更新日数据
  446. if(this.fields == 'month') return;
  447. if (columnIndex == 0 || columnIndex == 1) {
  448. // 当前选择的日
  449. let dayBeforeUpdate = this.range[2][this.value[2]];
  450. // 更新日数据
  451. this.setDayData(this.range[0][this.value[0]].number, this.range[1][this.value[1]].number);
  452. // 更新 Day Value
  453. let dayIndex = this.range[2].findIndex(day => {
  454. return day.number == dayBeforeUpdate.number;
  455. });
  456. this.value.splice(2, 1, dayIndex >= 0 ? dayIndex : 0);
  457. }
  458. // 改变年、月、日都要更新时数据
  459. if(this.fields == 'day') return;
  460. if (columnIndex == 0 || columnIndex == 1 || columnIndex == 2) {
  461. // 当前选择的时
  462. let hourBeforeUpdate = this.range[3][this.value[3]];
  463. // 更新时数据
  464. this.setHourData(this.range[0][this.value[0]].number, this.range[1][this.value[1]].number, this.range[2][this.value[2]].number);
  465. // 更新 Hour Value
  466. let hourIndex = this.range[3].findIndex(hour => {
  467. return hour.number == hourBeforeUpdate.number;
  468. });
  469. this.value.splice(3, 1, hourIndex >= 0 ? hourIndex : 0);
  470. }
  471. // 当前选择的分
  472. if(this.fields == 'hour') return;
  473. let minuteBeforeUpdate = this.range[4][this.value[4]];
  474. // 更新分数据
  475. this.setMinuteData(this.range[0][this.value[0]].number, this.range[1][this.value[1]].number, this.range[2][this.value[2]].number, this.range[3][this.value[3]].number);
  476. // 更新 Minute Value
  477. let minuteIndex = this.range[4].findIndex(minute => {
  478. return minute.number == minuteBeforeUpdate.number;
  479. });
  480. this.value.splice(4, 1, minuteIndex >= 0 ? minuteIndex : 0);
  481. },
  482. }
  483. };
  484. </script>
  485. <style lang="scss" scoped>
  486. .content {
  487. // text-align: right;
  488. }
  489. .placeholder {
  490. color: #949596;
  491. }
  492. </style>