v-nuxt-ui 0.1.35 → 0.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/button/Dropdown.vue +5 -1
  3. package/dist/runtime/components/date-picker/Input.d.vue.ts +9 -1
  4. package/dist/runtime/components/date-picker/Input.vue +55 -11
  5. package/dist/runtime/components/date-picker/Input.vue.d.ts +9 -1
  6. package/dist/runtime/components/date-picker/index.vue +3 -3
  7. package/dist/runtime/components/form/field/DatePicker.vue +1 -1
  8. package/dist/runtime/components/sys/table/CreateModal.vue +31 -33
  9. package/dist/runtime/components/sys/table/Table.vue +6 -4
  10. package/dist/runtime/components/sys/user/Table.vue +44 -27
  11. package/dist/runtime/components/table/permission/TablePermissionConfig.d.vue.ts +2 -2
  12. package/dist/runtime/components/table/permission/TablePermissionConfig.vue +3 -3
  13. package/dist/runtime/components/table/permission/TablePermissionConfig.vue.d.ts +2 -2
  14. package/dist/runtime/components/table/permission/TablePermissionTab.vue +7 -4
  15. package/dist/runtime/components/table/query/where/Newer.vue +2 -0
  16. package/dist/runtime/components/table/query/where/index.vue +46 -15
  17. package/dist/runtime/components/table/query/where/simple/item/ColumnPicker.vue +9 -4
  18. package/dist/runtime/components/table/query/where/simple/item/OprPicker.vue +3 -3
  19. package/dist/runtime/components/table/query/where/simple/item/opr/AsyncSelect.vue +45 -48
  20. package/dist/runtime/components/table/query/where/simple/item/opr/DatePicker.vue +137 -131
  21. package/dist/runtime/components/table/query/where/simple/item/opr/Select.d.vue.ts +4 -2
  22. package/dist/runtime/components/table/query/where/simple/item/opr/Select.vue +40 -40
  23. package/dist/runtime/components/table/query/where/simple/item/opr/Select.vue.d.ts +4 -2
  24. package/dist/runtime/components/table/query/where/simple/item/opr/index.vue +2 -0
  25. package/dist/runtime/components/table/settings/TableSettings.d.vue.ts +1 -1
  26. package/dist/runtime/components/table/settings/TableSettings.vue +0 -3
  27. package/dist/runtime/components/table/settings/TableSettings.vue.d.ts +1 -1
  28. package/dist/runtime/composables/api/sys/useRoleApi.js +3 -1
  29. package/dist/runtime/composables/api/sys/useUserApi.js +3 -1
  30. package/dist/runtime/composables/useDate.js +8 -8
  31. package/dist/runtime/constants/index.d.ts +1 -0
  32. package/dist/runtime/constants/index.js +1 -0
  33. package/dist/runtime/constants/options.js +2 -3
  34. package/dist/runtime/constants/table.d.ts +2 -0
  35. package/dist/runtime/constants/table.js +8 -0
  36. package/dist/runtime/types/components/table/column.d.ts +4 -3
  37. package/dist/runtime/types/components/table/query/where.d.ts +1 -5
  38. package/package.json +1 -1
  39. package/dist/runtime/components/table/query/where/simple/index.d.vue.ts +0 -21
  40. package/dist/runtime/components/table/query/where/simple/index.vue +0 -52
  41. package/dist/runtime/components/table/query/where/simple/index.vue.d.ts +0 -21
@@ -1,8 +1,8 @@
1
1
  <script setup>
2
- import { computed, useTemplateRef, nextTick } from "vue";
2
+ import { computed, ref, nextTick } from "vue";
3
3
  import { useTableOpr } from "#v/composables/table/useTableOpr";
4
4
  import { useToast } from "@nuxt/ui/composables";
5
- import TableQueryWhereSimple from "#v/components/table/query/where/simple/index.vue";
5
+ import TableQueryWhereSimpleItem from "#v/components/table/query/where/simple/item/index.vue";
6
6
  import TableQueryWhereNewer from "#v/components/table/query/where/Newer.vue";
7
7
  const props = defineProps({
8
8
  whereOptions: { type: Array, required: true },
@@ -23,7 +23,19 @@ const selectedWhereFields = computed(() => {
23
23
  const unselectedWhereFields = computed(() => {
24
24
  return props.whereOptions.map((option) => option.field).filter((field) => !selectedWhereFields.value.includes(field));
25
25
  });
26
- const simpleWhereQueryRef = useTemplateRef("simpleWhereQuery");
26
+ const itemRefMap = ref(/* @__PURE__ */ new Map());
27
+ function setItemRef(field, el) {
28
+ if (el && "focus" in el && typeof el.focus === "function") {
29
+ itemRefMap.value.set(field, el);
30
+ }
31
+ }
32
+ const onRemoveFilter = (field) => {
33
+ const updatedItems = props.whereQuery?.items?.filter((query) => query.field !== field) ?? [];
34
+ props.onUpdateWhereQuery({
35
+ ...props.whereQuery,
36
+ items: updatedItems
37
+ });
38
+ };
27
39
  const onNewField = (field) => {
28
40
  const option = props.whereOptions.find((option2) => option2.field === field);
29
41
  if (!option || !option.type) {
@@ -44,7 +56,10 @@ const onNewField = (field) => {
44
56
  }]
45
57
  });
46
58
  nextTick(() => {
47
- simpleWhereQueryRef.value?.focusItem(field);
59
+ const item = itemRefMap.value.get(field);
60
+ if (item) {
61
+ item.focus();
62
+ }
48
63
  });
49
64
  };
50
65
  const isWhereQueryEmpty = computed(() => {
@@ -52,7 +67,12 @@ const isWhereQueryEmpty = computed(() => {
52
67
  (props.whereQuery?.items?.filter((query) => props.whereOptions.find((option) => option.field === query.field)).length ?? 0) === 0 && (props.whereQuery?.groups?.length ?? 0) === 0;
53
68
  });
54
69
  const focusField = (field) => {
55
- return simpleWhereQueryRef.value?.focusItem(field) ?? false;
70
+ const item = itemRefMap.value.get(field);
71
+ if (item) {
72
+ item.focus();
73
+ return true;
74
+ }
75
+ return false;
56
76
  };
57
77
  defineExpose({ focusField });
58
78
  </script>
@@ -61,16 +81,27 @@ defineExpose({ focusField });
61
81
  <div class="flex items-start gap-2 pl-4 pr-2.5 py-2.5">
62
82
  <!-- conditions -->
63
83
  <div class="flex flex-wrap items-center gap-2.5">
64
- <TableQueryWhereSimple
65
- v-if="!isWhereQueryEmpty"
66
- v-bind="props"
67
- ref="simpleWhereQuery"
68
- :items="whereQuery?.items"
69
- @update-items="(newItems) => onUpdateWhereQuery({
70
- ...whereQuery,
71
- items: newItems
72
- })"
73
- />
84
+ <!-- key如果是field,那么field修改后,不能聚焦后面的组件,所以这里的key用idx代替 -->
85
+ <template v-if="!isWhereQueryEmpty">
86
+ <TableQueryWhereSimpleItem
87
+ v-for="(item, idx) in whereQuery?.items"
88
+ :ref="(el) => setItemRef(item.field, el)"
89
+ :key="idx"
90
+ :where-query-item="item"
91
+ :options="whereOptions"
92
+ :fetching="fetching"
93
+ :trigger-fetching="() => triggerFetching(true)"
94
+ @remove="onRemoveFilter"
95
+ @update:where-query-item="(newWhereQueryItem) => {
96
+ const updatedItems = [...props.whereQuery?.items ?? []];
97
+ updatedItems[idx] = newWhereQueryItem;
98
+ onUpdateWhereQuery({
99
+ ...whereQuery,
100
+ items: updatedItems
101
+ });
102
+ }"
103
+ />
104
+ </template>
74
105
  <TableQueryWhereNewer
75
106
  :options="whereOptions"
76
107
  :unselected-fields="unselectedWhereFields"
@@ -2,6 +2,7 @@
2
2
  import { computed, nextTick } from "vue";
3
3
  import { useTableOpr } from "#v/composables/table/useTableOpr";
4
4
  import ButtonDropdown from "#v/components/button/Dropdown.vue";
5
+ import { tableWhereQueryItemIconMap } from "#v/constants";
5
6
  const props = defineProps({
6
7
  options: { type: Array, required: true },
7
8
  disabled: { type: Boolean, required: false },
@@ -16,6 +17,7 @@ const items = computed(() => {
16
17
  items: props.options.map((option) => ({
17
18
  label: option.label,
18
19
  value: option.field,
20
+ icon: tableWhereQueryItemIconMap.get(option.type) || "field",
19
21
  onSelect: () => {
20
22
  modelValue.value = option.field;
21
23
  nextTick(() => {
@@ -43,9 +45,8 @@ const modelValue = computed({
43
45
  };
44
46
  }
45
47
  });
46
- const currentLabel = computed(() => {
47
- const option = props.options.find((opt) => opt.field === modelValue.value);
48
- return option?.label || "";
48
+ const currentOption = computed(() => {
49
+ return props.options.find((opt) => opt.field === modelValue.value);
49
50
  });
50
51
  </script>
51
52
 
@@ -58,8 +59,12 @@ const currentLabel = computed(() => {
58
59
  :size="'sm'"
59
60
  :color="'neutral'"
60
61
  :variant="'outline'"
61
- :label="currentLabel"
62
+ :label="currentOption?.label || '\u9009\u62E9\u5B57\u6BB5'"
62
63
  :disabled="disabled"
64
+ :icon="tableWhereQueryItemIconMap.get(currentOption?.type ?? 'unknown') || 'field'"
65
+ :ui="{
66
+ label: 'font-bold'
67
+ }"
63
68
  />
64
69
  </ButtonDropdown>
65
70
  </template>
@@ -58,9 +58,9 @@ const currentLabel = computed(() => {
58
58
  :groups="items"
59
59
  >
60
60
  <UButton
61
- :size="'sm'"
62
- :color="'neutral'"
63
- :variant="'outline'"
61
+ size="sm"
62
+ color="neutral"
63
+ variant="outline"
64
64
  :label="currentLabel"
65
65
  :disabled="disabled"
66
66
  />
@@ -1,10 +1,9 @@
1
1
  <script setup>
2
- import { ref, computed, useTemplateRef } from "vue";
2
+ import { ref, computed, useTemplateRef, watch } from "vue";
3
3
  import { useDebounceFn } from "@vueuse/core";
4
4
  import { defu } from "defu";
5
5
  import { useFetching } from "#v/composables/useBoolean";
6
6
  import { isEmptyString } from "#v/utils";
7
- import ButtonDropdown from "#v/components/button/Dropdown.vue";
8
7
  const props = defineProps({
9
8
  label: { type: String, required: true },
10
9
  disabled: { type: Boolean, required: false },
@@ -57,7 +56,7 @@ const items = computed(() => {
57
56
  value: p[props.valueField]
58
57
  })).filter((p) => p.label && !isEmptyString(String(p.value)));
59
58
  });
60
- const commandPaletteValue = computed({
59
+ const inputMenuValue = computed({
61
60
  get() {
62
61
  return whereQueryItem.value.value;
63
62
  },
@@ -80,26 +79,16 @@ const commandPaletteValue = computed({
80
79
  };
81
80
  }
82
81
  });
83
- const commandPaletteGroups = computed(() => {
84
- const options = [
85
- {
86
- id: "fields",
87
- items: items.value,
88
- ignoreFilter: true
89
- }
90
- ];
91
- return options;
92
- });
93
- const onFetchItems = async (searchTerm) => {
82
+ const onFetchItems = async (searchTerm2) => {
94
83
  try {
95
84
  startFetching();
96
85
  const query = {
97
86
  pagination: { pageNum: 1, pageSize: 10 },
98
87
  whereQuery: { items: [] }
99
88
  };
100
- if (!isEmptyString(searchTerm)) {
89
+ if (!isEmptyString(searchTerm2)) {
101
90
  props.searchFields.forEach((field) => {
102
- query.whereQuery?.items?.push({ field, opr: "like", value: searchTerm, andOr: "or" });
91
+ query.whereQuery?.items?.push({ field, opr: "like", value: searchTerm2, andOr: "or" });
103
92
  });
104
93
  }
105
94
  const result = await props.listApi(defu(query, props.extraQuery));
@@ -110,45 +99,53 @@ const onFetchItems = async (searchTerm) => {
110
99
  endFetching();
111
100
  }
112
101
  };
102
+ const searchTerm = ref("");
113
103
  const onDebounceFetchItems = useDebounceFn(onFetchItems, 512);
114
- const dropdownBtnRef = useTemplateRef("dropdownBtn");
104
+ watch(searchTerm, (newVal) => {
105
+ onDebounceFetchItems(newVal);
106
+ }, { immediate: false });
107
+ const inputMenuRef = useTemplateRef("inputMenu");
115
108
  defineExpose({
116
109
  focus: () => {
117
- dropdownBtnRef.value?.focus();
110
+ inputMenuRef.value?.inputRef.focus();
118
111
  }
119
112
  });
120
113
  </script>
121
114
 
122
115
  <template>
123
- <ButtonDropdown
124
- ref="dropdownBtn"
125
- v-model="commandPaletteValue"
126
- :groups="commandPaletteGroups"
116
+ <UInputMenu
117
+ ref="inputMenu"
118
+ v-model:search-term="searchTerm"
119
+ v-model="inputMenuValue"
120
+ :items="items"
121
+ :placeholder="placeholder"
127
122
  multiple
128
- enable-footer-toolbar
129
- @open="() => onFetchItems('')"
130
- @search="onDebounceFetchItems"
131
- >
132
- <UButton
133
- size="sm"
134
- color="neutral"
135
- variant="outline"
136
- >
137
- <div v-if="!whereQueryItem?.value || whereQueryItem.value.length === 0">
138
- --
139
- </div>
140
- <div v-else-if="whereQueryItem.value.length <= 2" class="flex items-center gap-1">
141
- {{ whereQueryItem.value.map((value2) => items.find((item) => item.value === value2)?.label || value2).join(", ") }}
142
- </div>
143
- <div v-else>
144
- <!-- 打印前两项,后面+1代替 -->
145
- <div class="flex items-center gap-1">
146
- <div v-for="value in whereQueryItem.value.slice(0, 2)" :key="value">
147
- {{ items.find((item) => item.value === value)?.label || value }}
148
- </div>
149
- <span>+{{ whereQueryItem.value.length - 2 }}</span>
150
- </div>
151
- </div>
152
- </UButton>
153
- </ButtonDropdown>
123
+ color="neutral"
124
+ delete-icon="i-lucide-trash"
125
+ value-key="value"
126
+ clear
127
+ clear-icon="i-lucide-circle-x"
128
+ icon=""
129
+ :loading="fetching"
130
+ :disabled="disabled"
131
+ open-on-focus
132
+ trailing
133
+ :ui="{
134
+ root: 'rounded-none min-w-32',
135
+ // TODO: 不然有rounded,这个应该是个bug
136
+ content: 'min-w-fit',
137
+ tagsInput: 'min-w-4 w-0'
138
+ }"
139
+ :content="{
140
+ align: 'start'
141
+ }"
142
+ @update:open="(opened) => {
143
+ if (opened) {
144
+ onFetchItems(searchTerm);
145
+ }
146
+ }"
147
+ @update:model-value="() => {
148
+ inputMenuRef?.inputRef.focus();
149
+ }"
150
+ />
154
151
  </template>
@@ -1,10 +1,10 @@
1
1
  <script setup>
2
2
  import { computed, useTemplateRef, nextTick, ref } from "vue";
3
- import { now, startOfWeek, endOfWeek, startOfMonth, endOfMonth } from "@internationalized/date";
3
+ import { now } from "@internationalized/date";
4
4
  import dayjs from "dayjs";
5
5
  import { useDate } from "#v/composables/useDate";
6
6
  import { useApp } from "#v/composables/useApp";
7
- import { dateFormat, TIME_ZONE } from "#v/constants";
7
+ import { TIME_ZONE } from "#v/constants";
8
8
  import DatePickerInput from "#v/components/date-picker/Input.vue";
9
9
  defineProps({
10
10
  disabled: { type: Boolean, required: false }
@@ -55,177 +55,183 @@ const calendarValue = computed({
55
55
  whereQueryItem.value = { ...whereQueryItem.value, value: updatedValue };
56
56
  }
57
57
  });
58
- const createDateStrComputed = (getValue, setValue) => computed({
59
- get: getValue,
58
+ const displayDateFormat = "YYYY-MM-DD";
59
+ const startDateStrValueInput = useTemplateRef("startDateStrValueInput");
60
+ const endDateStrValueInput = useTemplateRef("endDateStrValueInput");
61
+ const startDateStrValue = computed({
62
+ get() {
63
+ return useDate().dateValueToDayjs(calendarValue.value?.start)?.format(displayDateFormat) ?? void 0;
64
+ },
60
65
  set(newValue) {
61
66
  if (!newValue) {
62
- setValue(void 0);
67
+ calendarValue.value = { ...calendarValue.value, start: void 0 };
63
68
  return;
64
69
  }
65
- const formattedDayjs = dayjs(newValue, dateFormat, true);
70
+ const formattedDayjs = dayjs(newValue, displayDateFormat, true);
66
71
  if (formattedDayjs.isValid()) {
67
- setValue(useDate().dayjsToDateValue(formattedDayjs));
72
+ calendarValue.value = {
73
+ ...calendarValue.value,
74
+ start: useDate().dayjsToDateValue(formattedDayjs)
75
+ };
68
76
  }
69
77
  }
70
78
  });
71
- const startDateStrValueInput = useTemplateRef("startDateStrValueInput");
72
- const startDateStrValue = createDateStrComputed(
73
- () => useDate().dateValueToDayjs(calendarValue.value?.start)?.format(dateFormat) ?? void 0,
74
- (start) => {
75
- calendarValue.value = { ...calendarValue.value, start };
76
- }
77
- );
78
- const endDateStrValue = createDateStrComputed(
79
- () => useDate().dateValueToDayjs(calendarValue.value?.end)?.format(dateFormat) ?? void 0,
80
- (end) => {
81
- calendarValue.value = { ...calendarValue.value, end };
79
+ const endDateStrValue = computed({
80
+ get() {
81
+ return useDate().dateValueToDayjs(calendarValue.value?.end)?.format(displayDateFormat) ?? void 0;
82
+ },
83
+ set(newValue) {
84
+ if (!newValue) {
85
+ calendarValue.value = { ...calendarValue.value, end: void 0 };
86
+ return;
87
+ }
88
+ const formattedDayjs = dayjs(newValue, displayDateFormat, true);
89
+ if (formattedDayjs.isValid()) {
90
+ calendarValue.value = {
91
+ ...calendarValue.value,
92
+ end: useDate().dayjsToDateValue(formattedDayjs)
93
+ };
94
+ }
82
95
  }
83
- );
96
+ });
84
97
  const singleDateStrValueInput = useTemplateRef("singleDateStrValueInput");
85
- const singleDateStrValue = createDateStrComputed(
86
- () => useDate().dateValueToDayjs(calendarValue.value)?.format(dateFormat) || void 0,
87
- (date) => {
88
- calendarValue.value = date;
98
+ const singleDateStrValue = computed({
99
+ get() {
100
+ return useDate().dateValueToDayjs(calendarValue.value)?.format(displayDateFormat) || void 0;
101
+ },
102
+ set(newValue) {
103
+ if (!newValue) {
104
+ calendarValue.value = null;
105
+ return;
106
+ }
107
+ const formattedDayjs = dayjs(newValue, displayDateFormat, true);
108
+ if (formattedDayjs.isValid()) {
109
+ calendarValue.value = useDate().dayjsToDateValue(formattedDayjs);
110
+ }
89
111
  }
90
- );
91
- const dateStrInputFocus = () => {
112
+ });
113
+ const popoverOpen = ref(false);
114
+ const onOpenCalendar = () => {
115
+ popoverOpen.value = true;
116
+ };
117
+ const onCloseCalendar = () => {
118
+ popoverOpen.value = false;
119
+ };
120
+ const focusStartInput = () => {
92
121
  nextTick(() => {
93
- const input = isRangeOpr.value ? startDateStrValueInput : singleDateStrValueInput;
94
- input.value?.focus();
122
+ if (isRangeOpr.value) {
123
+ startDateStrValueInput.value?.focus();
124
+ } else {
125
+ singleDateStrValueInput.value?.focus();
126
+ }
95
127
  });
96
128
  };
97
- const popoverOpen = ref(false);
98
129
  defineExpose({
99
130
  focus: () => {
100
- popoverOpen.value = true;
101
- dateStrInputFocus();
131
+ focusStartInput();
102
132
  }
103
133
  });
134
+ const date = useDate();
104
135
  const dateRangeShortcuts = [
105
- {
106
- label: "\u672C\u5468",
107
- dateFn: () => {
108
- const today = now(TIME_ZONE);
109
- return {
110
- start: startOfWeek(today, "zh-CN", "mon"),
111
- end: endOfWeek(today, "zh-CN", "mon")
112
- };
113
- }
114
- },
115
- {
116
- label: "\u672C\u6708",
117
- dateFn: () => {
118
- const today = now(TIME_ZONE);
119
- return {
120
- start: startOfMonth(today),
121
- end: endOfMonth(today)
122
- };
123
- }
124
- },
125
- {
126
- label: "\u4E0A\u5468",
127
- dateFn: () => {
128
- const today = now(TIME_ZONE);
129
- const lastWeek = today.subtract({ weeks: 1 });
130
- return {
131
- start: startOfWeek(lastWeek, "zh-CN", "mon"),
132
- end: endOfWeek(lastWeek, "zh-CN", "mon")
133
- };
134
- }
135
- },
136
- {
137
- label: "\u4E0A\u6708",
138
- dateFn: () => {
139
- const today = now(TIME_ZONE);
140
- const lastMonth = today.subtract({ months: 1 });
141
- return {
142
- start: startOfMonth(lastMonth),
143
- end: endOfMonth(lastMonth)
144
- };
145
- }
146
- }
136
+ date.lastWeekDateShortcut,
137
+ date.lastMonthDateShortcut,
138
+ date.currentWeekDateShortcut,
139
+ date.currentMonthDateShortcut
147
140
  ];
148
- const isValueEmpty = computed(() => {
149
- if (isNoCalendarOpr.value) return false;
150
- const value = whereQueryItem.value.value;
151
- if (isRangeOpr.value) {
152
- return value === null || value?.start === null && value?.end === null;
153
- }
154
- return value === null || value === "";
155
- });
156
- const displayValue = computed(() => {
157
- if (isValueEmpty.value) return "";
158
- if (isRangeOpr.value) {
159
- const range = calendarValue.value;
160
- const start = useDate().dateValueToDayjs(range?.start)?.format(dateFormat) || "";
161
- const end = useDate().dateValueToDayjs(range?.end)?.format(dateFormat) || "";
162
- return `${start} ~ ${end}`;
163
- }
164
- return useDate().dateValueToDayjs(calendarValue.value)?.format(dateFormat) || "";
165
- });
166
141
  </script>
167
142
 
168
143
  <template>
169
144
  <UPopover
170
145
  v-model:open="popoverOpen"
146
+ :dismissible="false"
171
147
  :content="{
172
148
  align: 'start',
173
- onCloseAutoFocus: (e) => e.preventDefault()
149
+ onCloseAutoFocus: (e) => e.preventDefault(),
150
+ onOpenAutoFocus: (e) => e.preventDefault()
174
151
  }"
175
152
  >
176
- <UButton size="sm" color="neutral" variant="outline">
177
- {{ isValueEmpty ? "--" : displayValue }}
178
- </UButton>
153
+ <!-- 输入框直接暴露 -->
154
+ <template v-if="isNoCalendarOpr" />
179
155
 
180
- <template #content>
181
- <div class="p-3 flex flex-col gap-2">
182
- <UFieldGroup v-if="isRangeOpr" :orientation="app.isMobile.value ? 'vertical' : 'horizontal'">
183
- <DatePickerInput
184
- ref="startDateStrValueInput"
185
- v-model:value="startDateStrValue"
186
- placeholder="YYYY/MM/DD 开始日期"
187
- :disabled="disabled"
188
- />
189
- <DatePickerInput
190
- ref="endDateStrValueInput"
191
- v-model:value="endDateStrValue"
192
- placeholder="YYYY/MM/DD 结束日期"
193
- :disabled="disabled"
194
- />
195
- </UFieldGroup>
156
+ <template v-else-if="isRangeOpr">
157
+ <!-- 必须加这个div,不然第一个输入框无法正确渲染 -->
158
+ <div />
159
+ <DatePickerInput
160
+ ref="startDateStrValueInput"
161
+ v-model:value="startDateStrValue"
162
+ icon=""
163
+ input-class="w-32"
164
+ placeholder="YYYY-MM-DD"
165
+ @focus="onOpenCalendar"
166
+ @blur="onCloseCalendar"
167
+ />
168
+ <UBadge variant="outline" color="neutral">
169
+ ~
170
+ </UBadge>
171
+ <DatePickerInput
172
+ ref="endDateStrValueInput"
173
+ v-model:value="endDateStrValue"
174
+ icon=""
175
+ input-class="w-32"
176
+ placeholder="YYYY-MM-DD"
177
+ @focus="onOpenCalendar"
178
+ @blur="onCloseCalendar"
179
+ />
180
+ </template>
196
181
 
197
- <DatePickerInput
198
- v-else
199
- ref="singleDateStrValueInput"
200
- v-model:value="singleDateStrValue"
201
- placeholder="YYYY/MM/DD 日期"
202
- :disabled="disabled"
203
- />
182
+ <template v-else>
183
+ <div />
184
+ <DatePickerInput
185
+ ref="singleDateStrValueInput"
186
+ v-model:value="singleDateStrValue"
187
+ icon=""
188
+ input-class="w-32"
189
+ placeholder="YYYY-MM-DD"
190
+ @focus="onOpenCalendar"
191
+ @blur="onCloseCalendar"
192
+ />
193
+ </template>
204
194
 
195
+ <template #content>
196
+ <div
197
+ class="p-3 flex flex-col gap-2"
198
+ @mousedown.prevent
199
+ >
205
200
  <UCalendar
206
201
  v-if="!isNoCalendarOpr"
207
202
  :model-value="calendarValue"
208
203
  :range="isRangeOpr"
209
204
  size="sm"
205
+ variant="subtle"
210
206
  :disabled="disabled"
211
207
  :number-of-months="app.isMobile.value || !isRangeOpr ? 1 : 2"
212
208
  @update:model-value="(newValue) => calendarValue = newValue ?? null"
213
209
  />
214
210
 
215
- <div v-if="isRangeOpr" class="ml-auto">
216
- <UFieldGroup>
217
- <UButton
218
- v-for="shortcut in dateRangeShortcuts"
219
- :key="shortcut.label"
220
- :label="shortcut.label"
221
- size="xs"
222
- color="neutral"
223
- variant="outline"
224
- :disabled="disabled"
225
- @click="calendarValue = shortcut.dateFn()"
226
- />
227
- </UFieldGroup>
228
- </div>
211
+ <UFieldGroup class="ml-auto">
212
+ <UButton
213
+ v-for="shortcut in isRangeOpr ? dateRangeShortcuts : []"
214
+ :key="shortcut.label"
215
+ :label="shortcut.label"
216
+ size="xs"
217
+ color="neutral"
218
+ variant="outline"
219
+ :disabled="disabled"
220
+ :tabindex="-1"
221
+ @click="calendarValue = shortcut.dateFn()"
222
+ />
223
+ <UButton
224
+ v-if="!isRangeOpr"
225
+ label="今天"
226
+ size="xs"
227
+ color="neutral"
228
+ variant="outline"
229
+ :tabindex="-1"
230
+ @click="() => {
231
+ calendarValue = now(TIME_ZONE);
232
+ }"
233
+ />
234
+ </UFieldGroup>
229
235
  </div>
230
236
  </template>
231
237
  </UPopover>
@@ -1,8 +1,10 @@
1
- import type { SelectOption, WhereQueryItem } from '#v/types';
1
+ import type { WhereQueryItem } from '#v/types';
2
+ import type { InputMenuItem, InputMenuProps } from '@nuxt/ui';
2
3
  declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
4
  props: import("vue").PublicProps & __VLS_PrettifyLocal<({
4
5
  disabled?: boolean;
5
- items: SelectOption[];
6
+ items: InputMenuItem[];
7
+ placeholder?: InputMenuProps["placeholder"];
6
8
  } & {
7
9
  whereQueryItem: WhereQueryItem<T>;
8
10
  }) & {