index.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <template>
  2. <el-select
  3. :model-value="modelValue"
  4. @update:modelValue="(value) => {
  5. $emit('change', value)
  6. $emit('update:modelValue', value)
  7. }"
  8. :disabled="!editable"
  9. :clearable="clearable"
  10. :clear-icon="clearIcon"
  11. :size="size"
  12. :placeholder="placeholder"
  13. default-first-option
  14. filterable
  15. @change="
  16. (value) => {
  17. $emit('change', value)
  18. $emit('update:modelValue', value)
  19. }
  20. "
  21. @blur="(event) => $emit('blur', event)"
  22. @focus="(event) => $emit('focus', event)"
  23. >
  24. <el-option
  25. v-for="item in items"
  26. :key="item.value"
  27. :label="item.value"
  28. :value="item.value"
  29. :disabled="item.disabled"
  30. />
  31. <template #prefix>
  32. <i :class="`el-input__icon ${prefixIcon}`"></i>
  33. </template>
  34. </el-select>
  35. </template>
  36. <script>
  37. import { computed } from 'vue'
  38. import { ElSelect, ElOption } from 'element-plus'
  39. const parseTime = time => {
  40. const values = (time || '').split(':')
  41. if (values.length >= 2) {
  42. const hours = parseInt(values[0], 10)
  43. const minutes = parseInt(values[1], 10)
  44. return {
  45. hours,
  46. minutes
  47. }
  48. }
  49. return null
  50. }
  51. const compareTime = (time1, time2) => {
  52. const value1 = parseTime(time1)
  53. const value2 = parseTime(time2)
  54. const minutes1 = value1.minutes + value1.hours * 60
  55. const minutes2 = value2.minutes + value2.hours * 60
  56. if (minutes1 === minutes2) {
  57. return 0
  58. }
  59. return minutes1 > minutes2 ? 1 : -1
  60. }
  61. const formatTime = (time) => {
  62. return (
  63. (time.hours < 10 ? '0' + time.hours : time.hours) +
  64. ':' +
  65. (time.minutes < 10 ? '0' + time.minutes : time.minutes)
  66. )
  67. }
  68. const nextTime = (time, step) => {
  69. const timeValue = parseTime(time)
  70. const stepValue = parseTime(step)
  71. const next = {
  72. hours: timeValue.hours,
  73. minutes: timeValue.minutes
  74. }
  75. next.minutes += stepValue.minutes
  76. next.hours += stepValue.hours
  77. next.hours += Math.floor(next.minutes / 60)
  78. next.minutes = next.minutes % 60
  79. return formatTime(next)
  80. }
  81. export default {
  82. name: 'ElTimeSelect',
  83. components: { ElSelect, ElOption },
  84. model: {
  85. prop: 'value',
  86. event: 'change'
  87. },
  88. props: {
  89. modelValue: String,
  90. editable: {
  91. type: Boolean,
  92. default: true
  93. },
  94. clearable: {
  95. type: Boolean,
  96. default: true
  97. },
  98. size: {
  99. type: String,
  100. default: '',
  101. validator: value => !value || ['medium', 'small', 'mini'].indexOf(value) !== -1
  102. },
  103. placeholder: {
  104. type: String,
  105. default: ''
  106. },
  107. start: {
  108. type: String,
  109. default: '09:00'
  110. },
  111. end: {
  112. type: String,
  113. default: '18:00'
  114. },
  115. step: {
  116. type: String,
  117. default: '00:30'
  118. },
  119. minTime: {
  120. type: String,
  121. default: ''
  122. },
  123. maxTime: {
  124. type: String,
  125. default: ''
  126. },
  127. name: {
  128. type: String,
  129. default: ''
  130. },
  131. prefixIcon: {
  132. type: String,
  133. default: 'el-icon-time'
  134. },
  135. clearIcon: {
  136. type: String,
  137. default: 'el-icon-circle-close'
  138. }
  139. },
  140. emits: ['change', 'blur', 'focus', 'update:modelValue'],
  141. setup (props, context) {
  142. // data
  143. // const value = ref(props.modelValue)
  144. // computed
  145. const items = computed(() => {
  146. const result = []
  147. if (props.start && props.end && props.step) {
  148. let current = props.start
  149. while (compareTime(current, props.end) <= 0) {
  150. result.push({
  151. value: current,
  152. disabled:
  153. compareTime(current, props.minTime || '-1:-1') <= 0 ||
  154. compareTime(current, props.maxTime || '100:100') >= 0
  155. })
  156. current = nextTime(current, props.step)
  157. }
  158. }
  159. return result
  160. })
  161. // const emitInput = (val) => {
  162. // context.emit('update:modelValue', val)
  163. // }
  164. return {
  165. items
  166. // emitInput
  167. }
  168. }
  169. }
  170. </script>