biaofun-datetime-picker.vue 14 KB

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