index.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <template>
  2. <div :class="[n([''])]">
  3. <div
  4. :class="[n(['input']), isDatePanelShow && n(['input-active'])]"
  5. @click="setDatePanelDisplay(!isDatePanelShow)"
  6. >
  7. <slot name="start-icon" />
  8. <input
  9. v-model="startFormatDate"
  10. :placeholder="startPlaceholderVal"
  11. :class="[n(['input-start'])]"
  12. style="pointer-events: none"
  13. type="text"
  14. :readonly="true"
  15. :disabled="isUniFrameWork"
  16. autocomplete="false"
  17. >
  18. <span v-if="type !== 'single'">-</span>
  19. <input
  20. v-if="type !== 'single'"
  21. v-model="endFormatDate"
  22. :placeholder="endPlaceholderVal"
  23. :class="[n(['input-end'])]"
  24. style="pointer-events: none"
  25. type="text"
  26. :readonly="true"
  27. :disabled="isUniFrameWork"
  28. autocomplete="false"
  29. >
  30. <slot name="end-icon" />
  31. </div>
  32. <div
  33. v-if="isDatePanelShow"
  34. :class="[n(['dialog'])]"
  35. >
  36. <div
  37. :class="[
  38. n([
  39. 'dialog-container',
  40. 'dialog-container-' + rangeTableType,
  41. 'dialog-container-' + popupPosition,
  42. ]),
  43. ]"
  44. >
  45. <DatePickerPanel
  46. :type="props.type"
  47. rangeType="left"
  48. :date="dateValue"
  49. :startDate="startValue"
  50. :endDate="endValue"
  51. :currentOtherPanelValue="rightCurrentPanelValue"
  52. @pick="handlePick"
  53. @change="handleLeftPanelChange"
  54. />
  55. <DatePickerPanel
  56. v-if="props.type === 'range' && isPC && rangeTableType === 'two'"
  57. :type="props.type"
  58. rangeType="right"
  59. :date="dateValue"
  60. :startDate="startValue"
  61. :endDate="endValue"
  62. :currentOtherPanelValue="leftCurrentPanelValue"
  63. @pick="handlePick"
  64. @change="handleRightPanelChange"
  65. />
  66. </div>
  67. </div>
  68. </div>
  69. </template>
  70. <script setup lang="ts">
  71. import { ref, computed } from '../../../adapter-vue';
  72. import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
  73. // dayjs extension
  74. import dayjs, { Dayjs } from 'dayjs';
  75. import localeData from 'dayjs/plugin/localeData.js';
  76. import isSameOrAfter from 'dayjs/plugin/isSameOrAfter.js';
  77. import isSameOrBefore from 'dayjs/plugin/isSameOrBefore.js';
  78. import 'dayjs/locale/zh-cn';
  79. import DatePickerPanel from './date-picker-panel.vue';
  80. import { DateCell } from './date-picker';
  81. import { isPC, isUniFrameWork } from '../../../utils/env';
  82. dayjs.extend(localeData);
  83. dayjs.extend(isSameOrAfter);
  84. dayjs.extend(isSameOrBefore);
  85. dayjs.locale('zh-cn');
  86. const emit = defineEmits(['pick', 'change']);
  87. const props = defineProps({
  88. type: {
  89. type: String,
  90. default: 'range', // "single" / "range"
  91. },
  92. rangeTableType: {
  93. type: String,
  94. default: 'one', // "one"/ "two"
  95. },
  96. startPlaceholder: {
  97. type: String,
  98. default: () => TUITranslateService.t('开始时间'),
  99. },
  100. endPlaceholder: {
  101. type: String,
  102. default: () => TUITranslateService.t('开始时间'),
  103. },
  104. popupPosition: {
  105. type: String,
  106. default: 'bottom', // "top" / "bottom"
  107. },
  108. // Default single-select date
  109. defaultSingleDate: {
  110. type: Dayjs,
  111. default: null,
  112. required: false,
  113. },
  114. });
  115. const isDatePanelShow = ref<boolean>(false);
  116. const dateValue = ref<typeof Dayjs>(props.type === 'single' ? props?.defaultSingleDate : null);
  117. const startValue = ref<typeof Dayjs>(props.type === 'single' ? props?.defaultSingleDate : null);
  118. const endValue = ref<typeof Dayjs>(props.type === 'single' ? props?.defaultSingleDate : null);
  119. const startFormatDate = computed(() => startValue?.value?.format('YYYY/MM/DD'));
  120. const endFormatDate = computed(() => endValue?.value?.format('YYYY/MM/DD'));
  121. const startPlaceholderVal = props.startPlaceholder;
  122. const endPlaceholderVal = props.endPlaceholder;
  123. const leftCurrentPanelValue = ref<typeof Dayjs>();
  124. const rightCurrentPanelValue = ref<typeof Dayjs>();
  125. const setDatePanelDisplay = (show: boolean) => {
  126. isDatePanelShow.value = show;
  127. };
  128. const n = (classNameList: string[]) => {
  129. const resultClassList: string[] = [];
  130. classNameList.forEach((className: string) => {
  131. if (className) {
  132. resultClassList.push('tui-date-picker-' + className);
  133. !isPC && resultClassList.push('tui-date-picker-h5-' + className);
  134. } else {
  135. resultClassList.push('tui-date-picker');
  136. !isPC && resultClassList.push('tui-date-picker-h5');
  137. }
  138. });
  139. return resultClassList;
  140. };
  141. const handlePick = (cell: DateCell) => {
  142. switch (props.type) {
  143. case 'single':
  144. startValue.value = cell.date;
  145. endValue.value = cell.date;
  146. dateValue.value = cell.date;
  147. emit('change', cell);
  148. emit('pick', dateValue.value);
  149. setTimeout(() => {
  150. setDatePanelDisplay(false);
  151. }, 300);
  152. break;
  153. case 'range':
  154. if (!startValue?.value) {
  155. startValue.value = cell.date;
  156. } else if (!endValue?.value) {
  157. if (startValue?.value?.isSameOrBefore(cell.date, 'day')) {
  158. endValue.value = cell.date;
  159. } else {
  160. endValue.value = startValue.value;
  161. startValue.value = cell.date;
  162. }
  163. emit('pick', {
  164. startDate: startValue?.value?.startOf('date'),
  165. endDate: endValue?.value?.endOf('date'),
  166. });
  167. setTimeout(() => {
  168. setDatePanelDisplay(false);
  169. }, 200);
  170. } else {
  171. startValue.value = cell.date;
  172. endValue.value = null;
  173. }
  174. emit('change', {
  175. startDate: startValue.value,
  176. endDate: endValue.value,
  177. leftCurrentPanel: leftCurrentPanelValue.value,
  178. rightCurrentPanel: leftCurrentPanelValue.value,
  179. });
  180. break;
  181. }
  182. };
  183. const handleLeftPanelChange = (value: typeof Dayjs) => {
  184. leftCurrentPanelValue.value = value;
  185. emit('change', {
  186. startDate: startValue.value,
  187. endDate: endValue.value,
  188. leftCurrentPanel: leftCurrentPanelValue.value,
  189. rightCurrentPanel: leftCurrentPanelValue.value,
  190. });
  191. };
  192. const handleRightPanelChange = (value: typeof Dayjs) => {
  193. rightCurrentPanelValue.value = value;
  194. emit('change', {
  195. startDate: startValue.value,
  196. endDate: endValue.value,
  197. leftCurrentPanel: leftCurrentPanelValue.value,
  198. rightCurrentPanel: leftCurrentPanelValue.value,
  199. });
  200. };
  201. </script>
  202. <style scoped lang="scss">
  203. .tui-date-picker {
  204. &-input {
  205. min-width: 160px;
  206. display: flex;
  207. flex-direction: row;
  208. color: #666;
  209. border-radius: 5px;
  210. font-size: 12px;
  211. &-start,
  212. &-end {
  213. flex: 1;
  214. color: #666;
  215. height: 17px;
  216. border: none;
  217. width: 67px;
  218. background-color: transparent;
  219. font-size: 12px;
  220. text-align: center;
  221. &:focus {
  222. border: none;
  223. outline: none;
  224. }
  225. &::placeholder {
  226. text-align: center;
  227. }
  228. }
  229. }
  230. &-dialog {
  231. position: relative;
  232. &-container {
  233. position: absolute;
  234. display: flex;
  235. flex-direction: row;
  236. padding: 10px;
  237. left: 5px;
  238. background-color: #fff;
  239. box-shadow: rgba(0, 0, 0, 0.16) 0 3px 6px, rgba(0, 0, 0, 0.23) 0 3px 6px;
  240. z-index: 1000;
  241. &-bottom {
  242. left: 5px;
  243. }
  244. &-top {
  245. bottom: 30px;
  246. }
  247. &-one {
  248. left: -5px;
  249. }
  250. }
  251. }
  252. }
  253. </style>