wk-date-picker.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. <template>
  2. <view :style="{height: height + 'px'}" class="wk-date-picker picker">
  3. <view class="picker-header">
  4. <view class="cancel" @click="handleCancel">
  5. 取消
  6. </view>
  7. <view class="picker-header-title" />
  8. <view class="confirm" @click="handleConfirm">
  9. 确认
  10. </view>
  11. </view>
  12. <picker-view
  13. v-if="showPicker"
  14. v-model="valueIndexArr"
  15. indicator-class="indicator-active"
  16. class="picker-body"
  17. @change="bindChange">
  18. <picker-view-column class="picker-body-column">
  19. <view v-for="(item,index) in years" :key="index" class="picker-item">
  20. {{ item }}年
  21. </view>
  22. </picker-view-column>
  23. <picker-view-column class="picker-body-column">
  24. <view v-for="(item,index) in months" :key="index" class="picker-item">
  25. {{ item }}月
  26. </view>
  27. </picker-view-column>
  28. <template v-if="type !== 'month'">
  29. <picker-view-column class="picker-body-column">
  30. <view v-for="(item,index) in days" :key="index" class="picker-item">
  31. {{ item }}日
  32. </view>
  33. </picker-view-column>
  34. </template>
  35. <template v-if="type === 'datetime'">
  36. <picker-view-column class="picker-body-column">
  37. <view v-for="(item,index) in hours" :key="index" class="picker-item">
  38. {{ item }}时
  39. </view>
  40. </picker-view-column>
  41. <picker-view-column class="picker-body-column">
  42. <view v-for="(item,index) in minutes" :key="index" class="picker-item">
  43. {{ item }}分
  44. </view>
  45. </picker-view-column>
  46. <picker-view-column class="picker-body-column">
  47. <view v-for="(item,index) in seconds" :key="index" class="picker-item">
  48. {{ item }}秒
  49. </view>
  50. </picker-view-column>
  51. </template>
  52. </picker-view>
  53. </view>
  54. </template>
  55. <script>
  56. import moment from 'moment'
  57. export default {
  58. name: 'WkDatePicker',
  59. inject: ['popup'],
  60. props: {
  61. value: {
  62. type: String,
  63. default: null
  64. },
  65. type: {
  66. type: String,
  67. validator: val => {
  68. return ['date', 'datetime', 'month'].includes(val)
  69. },
  70. required: true
  71. },
  72. startTime: {
  73. type: String,
  74. default: null
  75. },
  76. endTime: {
  77. type: String,
  78. default: null
  79. }
  80. },
  81. data() {
  82. return {
  83. height: 0,
  84. valueArr: [],
  85. valueIndexArr: [],
  86. years: [],
  87. months: [],
  88. days: [],
  89. hours: [],
  90. minutes: [],
  91. seconds: [],
  92. maxDate: [],
  93. minDate: [],
  94. showPicker: false
  95. }
  96. },
  97. watch: {
  98. value() {
  99. this.initDate()
  100. }
  101. },
  102. mounted() {
  103. this.initDate()
  104. const that = this
  105. uni.getSystemInfo({
  106. success: res => {
  107. that.height = res.windowHeight * 0.4
  108. }
  109. })
  110. },
  111. methods: {
  112. /**
  113. * 初始化
  114. */
  115. initDate() {
  116. this.valueArr = this.dateToArr(this.value)
  117. this.hours = Array.from({length: 24}, (v, k) => k)
  118. this.minutes = Array.from({length: 60}, (v, k) => k)
  119. this.seconds = Array.from({length: 60}, (v, k) => k)
  120. // 计算结束日期
  121. if (!this.endTime) {
  122. const arr = this.dateToArr(this.endTime)
  123. // console.log('arr: ', arr)
  124. // arr[0] = arr[0] + 50
  125. arr[0] = arr[0] + 100
  126. this.maxDate = [arr[0], 12, 31, 23, 59, 59]
  127. } else {
  128. this.maxDate = this.dateToArr(this.endTime)
  129. }
  130. // 计算开始日期
  131. if (!this.startTime) {
  132. // this.minDate = [1900,1,1,0,0,0]
  133. const now = this.dateToArr()
  134. this.minDate = [now[0] - 100, 1, 1, 0, 0, 0]
  135. } else {
  136. this.minDate = this.dateToArr(this.startTime)
  137. }
  138. this.getYears()
  139. this.getMonths()
  140. this.getDays()
  141. this.showPicker = false
  142. // 获取初始位置
  143. this.$nextTick(() => {
  144. const arr = ['years', 'months', 'days', 'hours', 'minutes', 'seconds']
  145. this.valueArr.forEach((v, i) => {
  146. const findIndex = this[arr[i]].findIndex(o => o === v)
  147. this.$set(this.valueIndexArr, i, findIndex)
  148. })
  149. this.showPicker = true
  150. })
  151. },
  152. /**
  153. * 日期转数组
  154. * @param {Object} date
  155. */
  156. dateToArr(date) {
  157. if (!date) date = new Date()
  158. return moment(date).format('YYYY-MM-DD-HH-mm-ss').split('-').map(o => Number(o))
  159. },
  160. /**
  161. * 获取年份列表
  162. */
  163. getYears() {
  164. let list = []
  165. let i = this.minDate[0]
  166. do {
  167. list.push(i)
  168. i++
  169. } while (i <= this.maxDate[0])
  170. this.years = list
  171. // 计算年份位置
  172. this.$set(this.valueIndexArr, 0, this.valueArr[0] - this.minDate[0])
  173. },
  174. /**
  175. * 获取月份列表
  176. */
  177. getMonths() {
  178. const list = Array.from({length: 12}, (v, k) => k + 1)
  179. const year = this.valueArr[0]
  180. const minYear = this.years[0]
  181. const maxYear = this.years[this.years.length - 1]
  182. let min = 1 // 最小的月份
  183. let max = 12 // 最大的月份
  184. if (year === minYear) {
  185. min = this.minDate[1]
  186. } else {
  187. min = 1
  188. }
  189. if (year === maxYear) {
  190. max = this.maxDate[1]
  191. } else {
  192. max = 12
  193. }
  194. this.months = list.slice(min - 1, max - min + 1)
  195. // 计算月份位置
  196. const findIndex = this.months.findIndex(o => o === this.valueArr[1])
  197. if (findIndex !== -1) {
  198. this.$set(this.valueIndexArr, 1, findIndex)
  199. } else {
  200. this.valueArr[1] = this.months[this.months.length - 1]
  201. this.$set(this.valueIndexArr, 1, this.months.length - 1)
  202. }
  203. this.getDays()
  204. },
  205. /**
  206. * 获取天数列表
  207. */
  208. getDays() {
  209. let arr = []
  210. let list = [1, 3, 5, 7, 8, 10, 12]
  211. let start = 1, end = 1;
  212. let index = list.findIndex(item => {
  213. return this.valueArr[1] === item
  214. });
  215. if (index !== -1) {
  216. end = 31
  217. } else if (this.valueArr[1] !== 2) {
  218. end = 30
  219. } else if ((this.valueArr[0] % 4 === 0 && this.valueArr[0] % 100 !== 0) || this.valueArr[0] % 400 === 0) {
  220. // 闰年
  221. end = 29
  222. } else {
  223. end = 28
  224. }
  225. do {
  226. arr.push(start)
  227. start++;
  228. } while (start <= end)
  229. this.days = arr
  230. // 计算天数位置
  231. const findIndex = this.days.findIndex(o => o === this.valueArr[2])
  232. if (findIndex !== -1) {
  233. this.$set(this.valueIndexArr, 2, findIndex)
  234. } else {
  235. this.valueArr[2] = this.days[this.days.length - 1]
  236. this.$set(this.valueIndexArr, 2, this.days.length - 1)
  237. }
  238. },
  239. bindChange({ detail }) {
  240. const arr = ['years', 'months', 'days', 'hours', 'minutes', 'seconds']
  241. detail.value.forEach((item, index) => {
  242. if (this.valueIndexArr[index] !== item) {
  243. if (index === 0) {
  244. this.valueArr[0] = this.years[item]
  245. this.getMonths()
  246. } else if (index === 1) {
  247. this.valueArr[1] = this.months[item]
  248. this.getDays()
  249. } else {
  250. this.valueArr[index] = this[arr[index]][item]
  251. }
  252. this.valueIndexArr[index] = item
  253. }
  254. })
  255. },
  256. handleConfirm() {
  257. console.log('valueArr:', this.valueArr)
  258. console.log('valueIndexArr: ', this.valueIndexArr)
  259. const arr = [...this.valueArr]
  260. arr[1] = arr[1] - 1
  261. let date = moment(arr)
  262. if (this.type === 'date') {
  263. date = date.format('YYYY-MM-DD')
  264. } else if (this.type === 'datetime') {
  265. date = date.format('YYYY-MM-DD HH:mm:ss')
  266. } else if (this.type === 'month') {
  267. date = date.format('YYYY-MM')
  268. }
  269. console.log(' date,: ', date)
  270. this.$emit('input', date)
  271. this.$emit('select', date, () => {
  272. this.popup.close()
  273. })
  274. },
  275. handleCancel() {
  276. this.popup.close()
  277. }
  278. }
  279. }
  280. </script>
  281. <style scoped lang="scss">
  282. .picker {
  283. width: 100%;
  284. background-color: white;
  285. display: flex;
  286. flex-direction: column;
  287. overflow: hidden;
  288. .picker-header {
  289. height: 70rpx;
  290. font-size: 26rpx;
  291. border-bottom: 1rpx solid $border-color;
  292. padding: 0 30rpx;
  293. @include left;
  294. .picker-header-title {
  295. flex: 1;
  296. }
  297. .cancel {
  298. color: #666666;
  299. }
  300. .confirm {
  301. color: $theme-color;
  302. }
  303. }
  304. .picker-body {
  305. flex: 1;
  306. padding: 0 30rpx;
  307. .picker-view {
  308. width: 100%;
  309. height: 100%;
  310. }
  311. .picker-body-column {
  312. .picker-item {
  313. font-size: 26rpx;
  314. @include center;
  315. }
  316. }
  317. }
  318. }
  319. </style>