tui-datetime.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. <template>
  2. <view class="tui-datetime-picker">
  3. <view class="tui-mask" :class="{ 'tui-mask-show': isShow }" @touchmove.stop.prevent="stop" catchtouchmove="stop" @tap="hide"></view>
  4. <view class="tui-header" :class="{ 'tui-show': isShow }">
  5. <view class="tui-picker-header" :class="{ 'tui-date-radius': radius }" @touchmove.stop.prevent="stop" catchtouchmove="stop">
  6. <view class="tui-btn-picker" :style="{ color: cancelColor }" hover-class="tui-opacity" :hover-stay-time="150"
  7. @tap="hide">取消</view>
  8. <view class="tui-btn-picker" :style="{ color: color }" hover-class="tui-opacity" :hover-stay-time="150" @tap="btnFix">确定</view>
  9. </view>
  10. <view class="tui-date-header" v-if="unitTop">
  11. <view class="tui-date-unit" v-if="type < 4 || type == 7">年</view>
  12. <view class="tui-date-unit" v-if="type < 4 || type == 7">月</view>
  13. <view class="tui-date-unit" v-if="type == 1 || type == 2 || type == 7">日</view>
  14. <view class="tui-date-unit" v-if="type == 1 || type == 4 || type == 5 || type == 7">时</view>
  15. <view class="tui-date-unit" v-if="type == 1 || type > 3">分</view>
  16. <view class="tui-date-unit" v-if="type > 4">秒</view>
  17. </view>
  18. <view class="tui-picker-body">
  19. <picker-view :value="value" @change="change" class="tui-picker-view">
  20. <picker-view-column v-if="!reset && (type < 4 || type == 7)">
  21. <view class="tui-column-item" :class="{ 'tui-font-size_32': !unitTop && type == 7 }" v-for="(item, index) in years"
  22. :key="index">
  23. {{ item }}
  24. <text class="tui-unit-text" v-if="!unitTop">年</text>
  25. </view>
  26. </picker-view-column>
  27. <picker-view-column v-if="!reset && (type < 4 || type == 7)">
  28. <view class="tui-column-item" :class="{ 'tui-font-size_32': !unitTop && type == 7 }" v-for="(item, index) in months"
  29. :key="index">
  30. {{ formatNum(item) }}
  31. <text class="tui-unit-text" v-if="!unitTop">月</text>
  32. </view>
  33. </picker-view-column>
  34. <picker-view-column v-if="!reset && (type == 1 || type == 2 || type == 7)">
  35. <view class="tui-column-item" :class="{ 'tui-font-size_32': !unitTop && type == 7 }" v-for="(item, index) in days"
  36. :key="index">
  37. {{ formatNum(item) }}
  38. <text class="tui-unit-text" v-if="!unitTop">日</text>
  39. </view>
  40. </picker-view-column>
  41. <picker-view-column v-if="!reset && (type == 1 || type == 4 || type == 5 || type == 7)">
  42. <view class="tui-column-item" :class="{ 'tui-font-size_32': !unitTop && type == 7 }" v-for="(item, index) in hours"
  43. :key="index">
  44. {{ formatNum(item) }}
  45. <text class="tui-unit-text" v-if="!unitTop">时</text>
  46. </view>
  47. </picker-view-column>
  48. <picker-view-column v-if="!reset && (type == 1 || type > 3)">
  49. <view class="tui-column-item" :class="{ 'tui-font-size_32': !unitTop && type == 7 }" v-for="(item, index) in minutes"
  50. :key="index">
  51. {{ formatNum(item) }}
  52. <text class="tui-unit-text" v-if="!unitTop">分</text>
  53. </view>
  54. </picker-view-column>
  55. <picker-view-column v-if="!reset && type > 4">
  56. <view class="tui-column-item" :class="{ 'tui-font-size_32': !unitTop && type == 7 }" v-for="(item, index) in seconds"
  57. :key="index">
  58. {{ formatNum(item) }}
  59. <text class="tui-unit-text" v-if="!unitTop">秒</text>
  60. </view>
  61. </picker-view-column>
  62. </picker-view>
  63. </view>
  64. </view>
  65. </view>
  66. </template>
  67. <script>
  68. export default {
  69. name: 'tuiDatetime',
  70. props: {
  71. //1-日期+时间(年月日+时分) 2-日期(年月日) 3-日期(年月) 4-时间(时分) 5-时分秒 6-分秒 7-年月日 时分秒
  72. type: {
  73. type: Number,
  74. default: 1
  75. },
  76. //年份区间
  77. startYear: {
  78. type: Number,
  79. default: 1980
  80. },
  81. //年份区间
  82. endYear: {
  83. type: Number,
  84. default: 2050
  85. },
  86. //"取消"字体颜色
  87. cancelColor: {
  88. type: String,
  89. default: '#888'
  90. },
  91. //"确定"字体颜色
  92. color: {
  93. type: String,
  94. default: '#C74547'
  95. },
  96. //设置默认显示日期 2019-08-01 || 2019-08-01 17:01 || 2019/08/01
  97. setDateTime: {
  98. type: String,
  99. default: ''
  100. },
  101. //单位置顶
  102. unitTop: {
  103. type: Boolean,
  104. default: false
  105. },
  106. //圆角设置
  107. radius: {
  108. type: Boolean,
  109. default: false
  110. }
  111. },
  112. data() {
  113. return {
  114. isShow: false,
  115. years: [],
  116. months: [],
  117. days: [],
  118. hours: [],
  119. minutes: [],
  120. seconds: [],
  121. year: 0,
  122. month: 0,
  123. day: 0,
  124. hour: 0,
  125. minute: 0,
  126. second: 0,
  127. startDate: '',
  128. endDate: '',
  129. value: [0, 0, 0, 0, 0, 0],
  130. reset: false
  131. };
  132. },
  133. mounted() {
  134. this.initData();
  135. },
  136. computed: {
  137. yearOrMonth() {
  138. return `${this.year}-${this.month}`;
  139. },
  140. propsChange() {
  141. return `${this.setDateTime}-${this.type}-${this.startYear}-${this.endYear}`;
  142. }
  143. },
  144. watch: {
  145. yearOrMonth() {
  146. this.setDays();
  147. },
  148. propsChange() {
  149. this.reset = true;
  150. setTimeout(() => {
  151. this.initData();
  152. }, 10);
  153. }
  154. },
  155. methods: {
  156. stop() {},
  157. formatNum: function(num) {
  158. return num < 10 ? '0' + num : num + '';
  159. },
  160. generateArray: function(start, end) {
  161. return Array.from(new Array(end + 1).keys()).slice(start);
  162. },
  163. getIndex: function(arr, val) {
  164. let index = arr.indexOf(val);
  165. return ~index ? index : 0;
  166. },
  167. //日期时间处理
  168. initSelectValue() {
  169. let fdate = this.setDateTime.replace(/\-/g, '/');
  170. fdate = fdate && fdate.indexOf('/') == -1 ? `2020/01/01 ${fdate}` : fdate;
  171. let time = null;
  172. if (fdate) time = new Date(fdate);
  173. else time = new Date();
  174. this.year = time.getFullYear();
  175. this.month = time.getMonth() + 1;
  176. this.day = time.getDate();
  177. this.hour = time.getHours();
  178. this.minute = time.getMinutes();
  179. this.second = time.getSeconds();
  180. },
  181. initData() {
  182. this.initSelectValue();
  183. this.reset = false;
  184. switch (this.type) {
  185. case 1:
  186. this.value = [0, 0, 0, 0, 0];
  187. this.setYears();
  188. this.setMonths();
  189. this.setDays();
  190. this.setHours();
  191. this.setMinutes();
  192. break;
  193. case 2:
  194. this.value = [0, 0, 0];
  195. this.setYears();
  196. this.setMonths();
  197. this.setDays();
  198. break;
  199. case 3:
  200. this.value = [0, 0];
  201. this.setYears();
  202. this.setMonths();
  203. break;
  204. case 4:
  205. this.value = [0, 0];
  206. this.setHours();
  207. this.setMinutes();
  208. break;
  209. case 5:
  210. this.value = [0, 0, 0];
  211. this.setHours();
  212. this.setMinutes();
  213. this.setSeconds();
  214. break;
  215. case 6:
  216. this.value = [0, 0];
  217. this.setMinutes();
  218. this.setSeconds();
  219. break;
  220. case 7:
  221. this.value = [0, 0, 0, 0, 0, 0];
  222. this.setYears();
  223. this.setMonths();
  224. this.setDays();
  225. this.setHours();
  226. this.setMinutes();
  227. this.setSeconds();
  228. break;
  229. default:
  230. break;
  231. }
  232. },
  233. setYears() {
  234. this.years = this.generateArray(this.startYear, this.endYear);
  235. setTimeout(() => {
  236. this.$set(this.value, 0, this.getIndex(this.years, this.year));
  237. }, 8);
  238. },
  239. setMonths() {
  240. this.months = this.generateArray(1, 12);
  241. setTimeout(() => {
  242. this.$set(this.value, 1, this.getIndex(this.months, this.month));
  243. }, 8);
  244. },
  245. setDays() {
  246. if (this.type == 3 || this.type == 4) return;
  247. let totalDays = new Date(this.year, this.month, 0).getDate();
  248. this.days = this.generateArray(1, totalDays);
  249. setTimeout(() => {
  250. this.$set(this.value, 2, this.getIndex(this.days, this.day));
  251. }, 8);
  252. },
  253. setHours() {
  254. this.hours = this.generateArray(0, 23);
  255. setTimeout(() => {
  256. let index = this.type == 5 || this.type == 7 ? this.value.length - 3 : this.value.length - 2;
  257. this.$set(this.value, index, this.getIndex(this.hours, this.hour));
  258. }, 8);
  259. },
  260. setMinutes() {
  261. this.minutes = this.generateArray(0, 59);
  262. setTimeout(() => {
  263. let index = this.type > 4 ? this.value.length - 2 : this.value.length - 1;
  264. this.$set(this.value, index, this.getIndex(this.minutes, this.minute));
  265. }, 8);
  266. },
  267. setSeconds() {
  268. this.seconds = this.generateArray(0, 59);
  269. setTimeout(() => {
  270. this.$set(this.value, this.value.length - 1, this.getIndex(this.seconds, this.second));
  271. }, 8);
  272. },
  273. show() {
  274. setTimeout(() => {
  275. this.isShow = true;
  276. }, 50);
  277. },
  278. hide() {
  279. this.isShow = false;
  280. this.$emit('cancel',{})
  281. },
  282. change(e) {
  283. this.value = e.detail.value;
  284. switch (this.type) {
  285. case 1:
  286. this.year = this.years[this.value[0]];
  287. this.month = this.months[this.value[1]];
  288. this.day = this.days[this.value[2]];
  289. this.hour = this.hours[this.value[3]];
  290. this.minute = this.minutes[this.value[4]];
  291. break;
  292. case 2:
  293. this.year = this.years[this.value[0]];
  294. this.month = this.months[this.value[1]];
  295. this.day = this.days[this.value[2]];
  296. break;
  297. case 3:
  298. this.year = this.years[this.value[0]];
  299. this.month = this.months[this.value[1]];
  300. break;
  301. case 4:
  302. this.hour = this.hours[this.value[0]];
  303. this.minute = this.minutes[this.value[1]];
  304. break;
  305. case 5:
  306. this.hour = this.hours[this.value[0]];
  307. this.minute = this.minutes[this.value[1]];
  308. this.second = this.seconds[this.value[2]];
  309. break;
  310. case 6:
  311. this.minute = this.minutes[this.value[0]];
  312. this.second = this.seconds[this.value[1]];
  313. break;
  314. case 7:
  315. this.year = this.years[this.value[0]];
  316. this.month = this.months[this.value[1]];
  317. this.day = this.days[this.value[2]];
  318. this.hour = this.hours[this.value[3]];
  319. this.minute = this.minutes[this.value[4]];
  320. this.second = this.seconds[this.value[5]];
  321. break;
  322. default:
  323. break;
  324. }
  325. },
  326. btnFix() {
  327. setTimeout(() => {
  328. let result = {};
  329. let year = this.year;
  330. let month = this.formatNum(this.month || 0);
  331. let day = this.formatNum(this.day || 0);
  332. let hour = this.formatNum(this.hour || 0);
  333. let minute = this.formatNum(this.minute || 0);
  334. let second = this.formatNum(this.second || 0);
  335. switch (this.type) {
  336. case 1:
  337. result = {
  338. year: year,
  339. month: month,
  340. day: day,
  341. hour: hour,
  342. minute: minute,
  343. result: `${year}-${month}-${day} ${hour}:${minute}`
  344. };
  345. break;
  346. case 2:
  347. result = {
  348. year: year,
  349. month: month,
  350. day: day,
  351. result: `${year}-${month}-${day}`
  352. };
  353. break;
  354. case 3:
  355. result = {
  356. year: year,
  357. month: month,
  358. result: `${year}-${month}`
  359. };
  360. break;
  361. case 4:
  362. result = {
  363. hour: hour,
  364. minute: minute,
  365. result: `${hour}:${minute}`
  366. };
  367. break;
  368. case 5:
  369. result = {
  370. hour: hour,
  371. minute: minute,
  372. second: second,
  373. result: `${hour}:${minute}:${second}`
  374. };
  375. break;
  376. case 6:
  377. result = {
  378. minute: minute,
  379. second: second,
  380. result: `${minute}:${second}`
  381. };
  382. break;
  383. case 7:
  384. result = {
  385. year: year,
  386. month: month,
  387. day: day,
  388. hour: hour,
  389. minute: minute,
  390. second: second,
  391. result: `${year}-${month}-${day} ${hour}:${minute}:${second}`
  392. };
  393. break;
  394. default:
  395. break;
  396. }
  397. this.$emit('confirm', result);
  398. this.hide();
  399. }, 80);
  400. }
  401. }
  402. };
  403. </script>
  404. <style scoped>
  405. .tui-datetime-picker {
  406. position: relative;
  407. z-index: 999;
  408. }
  409. .tui-picker-view {
  410. height: 100%;
  411. box-sizing: border-box;
  412. }
  413. .tui-mask {
  414. position: fixed;
  415. z-index: 9998;
  416. top: 0;
  417. right: 0;
  418. bottom: 0;
  419. left: 0;
  420. background-color: rgba(0, 0, 0, 0.6);
  421. visibility: hidden;
  422. opacity: 0;
  423. transition: all 0.3s ease-in-out;
  424. }
  425. .tui-mask-show {
  426. visibility: visible !important;
  427. opacity: 1 !important;
  428. }
  429. .tui-header {
  430. z-index: 9999;
  431. position: fixed;
  432. bottom: 0;
  433. left: 0;
  434. width: 100%;
  435. transition: all 0.3s ease-in-out;
  436. transform: translateY(100%);
  437. }
  438. .tui-date-header {
  439. width: 100%;
  440. height: 52rpx;
  441. display: flex;
  442. align-items: center;
  443. justify-content: space-between;
  444. background-color: #fff;
  445. font-size: 26rpx;
  446. line-height: 26rpx;
  447. color: #555;
  448. /* #ifdef MP */
  449. box-shadow: 0 15rpx 10rpx -15rpx #efefef;
  450. /* #endif */
  451. /* #ifndef MP */
  452. box-shadow: 0 15rpx 10rpx -15rpx #888;
  453. /* #endif */
  454. position: relative;
  455. z-index: 2;
  456. }
  457. .tui-date-unit {
  458. flex: 1;
  459. text-align: center;
  460. }
  461. .tui-show {
  462. transform: translateY(0);
  463. }
  464. .tui-picker-header {
  465. width: 100%;
  466. height: 90rpx;
  467. padding: 0 40rpx;
  468. display: flex;
  469. justify-content: space-between;
  470. align-items: center;
  471. box-sizing: border-box;
  472. font-size: 32rpx;
  473. background-color: #fff;
  474. position: relative;
  475. }
  476. .tui-date-radius {
  477. border-top-left-radius: 20rpx;
  478. border-top-right-radius: 20rpx;
  479. overflow: hidden;
  480. }
  481. .tui-picker-header::after {
  482. content: '';
  483. position: absolute;
  484. border-bottom: 1rpx solid #eaeef1;
  485. -webkit-transform: scaleY(0.5);
  486. transform: scaleY(0.5);
  487. bottom: 0;
  488. right: 0;
  489. left: 0;
  490. }
  491. .tui-picker-body {
  492. width: 100%;
  493. height: 520rpx;
  494. overflow: hidden;
  495. background-color: #fff;
  496. }
  497. .tui-column-item {
  498. display: flex;
  499. align-items: center;
  500. justify-content: center;
  501. font-size: 36rpx;
  502. color: #333;
  503. }
  504. .tui-font-size_32 {
  505. font-size: 32rpx !important;
  506. }
  507. .tui-unit-text {
  508. font-size: 24rpx !important;
  509. padding-left: 8rpx;
  510. }
  511. .tui-btn-picker {
  512. padding: 16rpx;
  513. box-sizing: border-box;
  514. text-align: center;
  515. text-decoration: none;
  516. }
  517. .tui-opacity {
  518. opacity: 0.5;
  519. }
  520. </style>