DateTimePicker.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <template>
  2. <Picker
  3. v-bind="props"
  4. :value="value"
  5. :columns="columns"
  6. @selectTextChange="() => {}"
  7. @update:value="updateValue"
  8. />
  9. </template>
  10. <script setup lang="ts">
  11. import { computed, onMounted } from 'vue';
  12. import type { PickerProps } from './Picker.vue';
  13. import type { PickerItem } from './Picker';
  14. import Picker from './Picker.vue';
  15. import { DateUtils } from '@imengyu/imengyu-utils';
  16. // 更新 DateTimePickerProps 接口,添加日期相关属性
  17. export interface DateTimePickerProps extends Omit<PickerProps, 'columns'|'value'> {
  18. modelValue?: Date,
  19. showYears?: boolean,
  20. showMonths?: boolean,
  21. showDays?: boolean,
  22. showHours?: boolean,
  23. showMinute?: boolean,
  24. showSecond?: boolean,
  25. startYear?: number,
  26. endYear?: number,
  27. startMonth?: number,
  28. endMonth?: number,
  29. startDay?: number,
  30. endDay?: number,
  31. minuteText?: string,
  32. secondText?: string,
  33. hourText?: string,
  34. yearText?: string,
  35. monthText?: string,
  36. dayText?: string,
  37. }
  38. const emit = defineEmits([ 'update:modelValue', 'selectTextChange' ]);
  39. const props = withDefaults(defineProps<DateTimePickerProps>(), {
  40. pickerHeight: 300,
  41. pickerWidth: 750,
  42. showYears: true,
  43. showMonths: true,
  44. showDays: true,
  45. showHours: true,
  46. showMinute: true,
  47. showSecond: true,
  48. startYear: () => new Date().getFullYear() - 50,
  49. endYear: () => new Date().getFullYear() + 20,
  50. startMonth: 1,
  51. endMonth: 12,
  52. startDay: 1,
  53. endDay: 31,
  54. yearText: '年',
  55. monthText: '月',
  56. dayText: '日',
  57. minuteText: '分',
  58. secondText: '秒',
  59. hourText: '时',
  60. });
  61. // 计算当前选中的值
  62. const value = computed(() => {
  63. const value : number[] = [];
  64. let date = props.modelValue;
  65. if (!date)
  66. date = new Date();
  67. if (!(date instanceof Date))
  68. date = typeof date === 'string' ? DateUtils.parseDate(date) : new Date();
  69. if (props.showYears)
  70. value.push(date.getFullYear());
  71. if (props.showMonths)
  72. value.push(date.getMonth() + 1);
  73. if (props.showDays)
  74. value.push(date.getDate());
  75. if (props.showHours)
  76. value.push(date.getHours());
  77. if (props.showMinute)
  78. value.push(date.getMinutes());
  79. if (props.showSecond)
  80. value.push(date.getSeconds());
  81. return value;
  82. });
  83. // 计算选择器的列数据
  84. const columns = computed(() => {
  85. const cols = [] as PickerItem[][];
  86. const currentDate = props.modelValue ?? new Date();
  87. // 年份列
  88. if (props.showYears) {
  89. const years = [] as PickerItem[];
  90. for (let i = props.startYear!; i <= props.endYear!; i++) {
  91. years.push({
  92. text: i.toString() + props.yearText,
  93. value: i,
  94. });
  95. }
  96. cols.push(years);
  97. }
  98. // 月份列
  99. if (props.showMonths) {
  100. const months = [] as PickerItem[];
  101. for (let i = props.startMonth!; i <= props.endMonth!; i++) {
  102. months.push({
  103. text: i.toString() + props.monthText,
  104. value: i,
  105. });
  106. }
  107. cols.push(months);
  108. }
  109. // 日期列
  110. if (props.showDays) {
  111. const selectedYear = props.showYears ? value.value[0] : currentDate.getFullYear();
  112. const selectedMonth = props.showMonths ? value.value[1] : currentDate.getMonth() + 1;
  113. const daysInMonth = DateUtils.getMonthDays(selectedYear, selectedMonth - 1) ?? 0;
  114. const days = [] as PickerItem[];
  115. for (let i = props.startDay; i <= daysInMonth; i++) {
  116. days.push({
  117. text: i.toString() + props.dayText,
  118. value: i,
  119. });
  120. }
  121. cols.push(days);
  122. }
  123. // 小时列
  124. if (props.showHours) {
  125. const hours = [] as PickerItem[];
  126. for (let i = 0; i < 24; i++) {
  127. hours.push({
  128. text: i.toString() + props.hourText,
  129. value: i,
  130. });
  131. }
  132. cols.push(hours);
  133. }
  134. // 分钟列
  135. if (props.showMinute) {
  136. const minutes = [] as PickerItem[];
  137. for (let i = 0; i < 60; i++) {
  138. minutes.push({
  139. text: i.toString() + props.minuteText,
  140. value: i,
  141. });
  142. }
  143. cols.push(minutes);
  144. }
  145. // 秒数列
  146. if (props.showSecond) {
  147. const seconds = [] as PickerItem[];
  148. for (let i = 0; i < 60; i++) {
  149. seconds.push({
  150. text: i.toString() + props.secondText,
  151. value: i,
  152. });
  153. }
  154. cols.push(seconds);
  155. }
  156. return cols;
  157. });
  158. let forceUpdate = true;
  159. // 更新选中的值
  160. function updateValue(v: number[]) {
  161. if (props.modelValue || v.length > 0) {
  162. const date = new Date(props.modelValue ?? new Date());
  163. let index = 0;
  164. if (v.length > 0) {
  165. if (props.showYears) {
  166. date.setFullYear(v[index]);
  167. index++;
  168. }
  169. if (props.showMonths) {
  170. date.setMonth(v[index] - 1);
  171. index++;
  172. }
  173. if (props.showDays) {
  174. date.setDate(v[index]);
  175. index++;
  176. }
  177. if (props.showHours) {
  178. date.setHours(v[index]);
  179. index++;
  180. }
  181. if (props.showMinute) {
  182. date.setMinutes(v[index]);
  183. index++;
  184. }
  185. if (props.showSecond) {
  186. date.setSeconds(v[index]);
  187. }
  188. emit('update:modelValue', date);
  189. }
  190. emit('selectTextChange', DateUtils.formatDate(date, 'yyyy-MM-dd'), forceUpdate);
  191. } else {
  192. emit('selectTextChange', '', forceUpdate);
  193. }
  194. forceUpdate = false;
  195. }
  196. onMounted(() => updateValue([]));
  197. defineOptions({
  198. options: {
  199. styleIsolation: "shared",
  200. virtualHost: true,
  201. }
  202. })
  203. </script>