date-range-picker.uvue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <template>
  2. <view class="date-range-picker">
  3. <view class="date-range-item" :class="{'no-margin': !showLabel}">
  4. <text class="date-range-label" v-if="showLabel && label.length > 0" :style="{ width: labelWidth }">{{ label }}</text>
  5. <view class="date-range-input-box" @click="showStartPicker = true">
  6. <text class="date-range-input-text" :class="{'placeholder': props.startValue.length == 0 || props.endValue.length == 0}">{{ displayText }}</text>
  7. <view class="date-range-input-icons">
  8. <image v-if="clearable && props.startValue.length > 0 && props.endValue.length > 0" class="date-range-input-clear" src="/static/images/common/2.png" mode="aspectFit" @click.stop="handleClear"></image>
  9. <image class="date-range-input-arrow" src="/static/images/common/1.png" mode="aspectFit"></image>
  10. </view>
  11. </view>
  12. </view>
  13. <!-- 开始日期选择器 -->
  14. <l-popup v-model="showStartPicker" position="bottom">
  15. <l-date-time-picker
  16. v-model="innerStartValue"
  17. :title="startTitle"
  18. title-style="font-size: 32rpx; font-weight: 500; color: #000000;"
  19. cancel-style="font-size: 32rpx; color: #888888;"
  20. confirm-style="font-size: 32rpx; color: #1890ff;"
  21. mode="年月日"
  22. format="YYYY-MM-DD"
  23. cancel-btn="取消"
  24. confirm-btn="确定"
  25. :start="start"
  26. :end="end"
  27. @cancel="showStartPicker = false"
  28. @confirm="handleStartConfirm"
  29. >
  30. </l-date-time-picker>
  31. </l-popup>
  32. <!-- 结束日期选择器 -->
  33. <l-popup v-model="showEndPicker" position="bottom">
  34. <l-date-time-picker
  35. v-model="innerEndValue"
  36. :title="endTitle"
  37. title-style="font-size: 32rpx; font-weight: 500; color: #000000;"
  38. cancel-style="font-size: 32rpx; color: #888888;"
  39. confirm-style="font-size: 32rpx; color: #1890ff;"
  40. mode="年月日"
  41. format="YYYY-MM-DD"
  42. cancel-btn="取消"
  43. confirm-btn="确定"
  44. :start="start"
  45. :end="end"
  46. @cancel="showEndPicker = false"
  47. @confirm="handleEndConfirm"
  48. >
  49. </l-date-time-picker>
  50. </l-popup>
  51. </view>
  52. </template>
  53. <script setup lang="uts">
  54. import { ref, computed } from 'vue'
  55. // Props 定义
  56. type Props = {
  57. startValue: string
  58. endValue: string
  59. label?: string
  60. placeholder?: string
  61. startTitle?: string
  62. endTitle?: string
  63. start?: string
  64. end?: string
  65. labelWidth?: string
  66. showLabel?: boolean
  67. clearable?: boolean
  68. }
  69. const props = withDefaults(defineProps<Props>(), {
  70. label: '',
  71. placeholder: '请选择日期范围',
  72. startTitle: '选择开始日期',
  73. endTitle: '选择结束日期',
  74. start: '',
  75. end: '',
  76. labelWidth: '140rpx',
  77. showLabel: true,
  78. clearable: true
  79. })
  80. // Emits 定义
  81. const emit = defineEmits<{
  82. (e: 'update:startValue', value: string): void
  83. (e: 'update:endValue', value: string): void
  84. }>()
  85. // 弹窗显示状态
  86. const showStartPicker = ref<boolean>(false)
  87. const showEndPicker = ref<boolean>(false)
  88. // 内部值
  89. const innerStartValue = ref<string>(props.startValue)
  90. const innerEndValue = ref<string>(props.endValue)
  91. // 显示文本
  92. const displayText = computed<string>(() => {
  93. if (props.startValue.length > 0 && props.endValue.length > 0) {
  94. return `${props.startValue} - ${props.endValue}`
  95. }
  96. return props.placeholder
  97. })
  98. // 确认开始日期
  99. const handleStartConfirm = (value: string): void => {
  100. emit('update:startValue', value)
  101. showStartPicker.value = false
  102. // 自动弹出结束日期选择
  103. setTimeout(() => {
  104. showEndPicker.value = true
  105. }, 300)
  106. }
  107. // 确认结束日期
  108. const handleEndConfirm = (value: string): void => {
  109. emit('update:endValue', value)
  110. showEndPicker.value = false
  111. }
  112. // 清除选择
  113. const handleClear = (): void => {
  114. emit('update:startValue', '')
  115. emit('update:endValue', '')
  116. innerStartValue.value = ''
  117. innerEndValue.value = ''
  118. }
  119. </script>
  120. <style lang="scss">
  121. .date-range-picker {
  122. .date-range-item {
  123. display: flex;
  124. flex-direction: row;
  125. align-items: center;
  126. margin-bottom: 24rpx;
  127. &.no-margin {
  128. margin-bottom: 0;
  129. }
  130. .date-range-label {
  131. display: flex;
  132. align-items: center;
  133. justify-content: flex-start;
  134. font-weight: 400;
  135. font-size: 28rpx;
  136. color: #6e7580;
  137. }
  138. .date-range-input-box {
  139. flex: 1;
  140. display: flex;
  141. flex-direction: row;
  142. align-items: center;
  143. justify-content: space-between;
  144. padding: 20rpx;
  145. background-color: #f5f7fa;
  146. border-radius: 8rpx;
  147. .date-range-input-text {
  148. font-weight: 400;
  149. font-size: 28rpx;
  150. color: #131415;
  151. flex: 1;
  152. &.placeholder {
  153. color: #999999;
  154. }
  155. }
  156. .date-range-input-icons {
  157. display: flex;
  158. flex-direction: row;
  159. align-items: center;
  160. margin-left: 20rpx;
  161. .date-range-input-clear {
  162. width: 28rpx;
  163. height: 28rpx;
  164. margin-right: 12rpx;
  165. }
  166. .date-range-input-arrow {
  167. width: 24rpx;
  168. height: 24rpx;
  169. }
  170. }
  171. }
  172. }
  173. }
  174. </style>