@neatui/vue 2.15.3 → 2.15.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neatui/vue",
3
- "version": "2.15.3",
3
+ "version": "2.15.5",
4
4
  "description": "basic component ui",
5
5
  "main": "./src/index.ts",
6
6
  "license": "MIT",
@@ -26,28 +26,34 @@
26
26
  </div>
27
27
  </div>
28
28
  </div>
29
- <div ui-date-body="" class="flex-block pr min-h-ls+">
30
- <div v-if="state.type === 2" class="full n-ms">
31
- <ul ui-row="mob-6" class="n-ms ny-sm-sub">
29
+ <div ui-date-body="" :class="['flex-block pr', bodyClass]">
30
+ <div v-if="state.type === 2" class="full">
31
+ <ul ui-grid="mob:4" class="n-ms ny-sm-sub">
32
32
  <li v-for="(year, idx) in panel.years" :key="idx" ui-flex="col cm" @click="setDateValue('y', year)">
33
- <div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">{{ year }}</div>
33
+ <div
34
+ ui-flex="col cm"
35
+ class="w-ss h-xs ac ux-none r-sm"
36
+ :class="isSelectedYear(year) ? 'active bg-main-o-lm co-w' : 'co-main:hover'"
37
+ >
38
+ {{ year }}
39
+ </div>
34
40
  </li>
35
41
  </ul>
36
42
  </div>
37
43
  <div v-else-if="state.type === 1" class="full">
38
- <ul ui-row="mob-4" class="n-ms ny-sm-sub">
39
- <li ui-flex="col cm" @click="setDateValue('m', 1)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">1月</div></li>
40
- <li ui-flex="col cm" @click="setDateValue('m', 2)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">2月</div></li>
41
- <li ui-flex="col cm" @click="setDateValue('m', 3)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">3月</div></li>
42
- <li ui-flex="col cm" @click="setDateValue('m', 4)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">4月</div></li>
43
- <li ui-flex="col cm" @click="setDateValue('m', 5)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">5月</div></li>
44
- <li ui-flex="col cm" @click="setDateValue('m', 6)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">6月</div></li>
45
- <li ui-flex="col cm" @click="setDateValue('m', 7)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">7月</div></li>
46
- <li ui-flex="col cm" @click="setDateValue('m', 8)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">8月</div></li>
47
- <li ui-flex="col cm" @click="setDateValue('m', 9)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">9月</div></li>
48
- <li ui-flex="col cm" @click="setDateValue('m', 10)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">10月</div></li>
49
- <li ui-flex="col cm" @click="setDateValue('m', 11)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">11月</div></li>
50
- <li ui-flex="col cm" @click="setDateValue('m', 12)"><div ui-flex="col cm" class="w-xs+ h-xs+ ac ux-none co-main:hover">12月</div></li>
44
+ <ul ui-grid="mob:4" class="n-ms ny-sm-sub">
45
+ <li ui-flex="col cm" @click="setDateValue('m', 1)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(1) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">1月</div></li>
46
+ <li ui-flex="col cm" @click="setDateValue('m', 2)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(2) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">2月</div></li>
47
+ <li ui-flex="col cm" @click="setDateValue('m', 3)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(3) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">3月</div></li>
48
+ <li ui-flex="col cm" @click="setDateValue('m', 4)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(4) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">4月</div></li>
49
+ <li ui-flex="col cm" @click="setDateValue('m', 5)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(5) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">5月</div></li>
50
+ <li ui-flex="col cm" @click="setDateValue('m', 6)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(6) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">6月</div></li>
51
+ <li ui-flex="col cm" @click="setDateValue('m', 7)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(7) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">7月</div></li>
52
+ <li ui-flex="col cm" @click="setDateValue('m', 8)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(8) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">8月</div></li>
53
+ <li ui-flex="col cm" @click="setDateValue('m', 9)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(9) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">9月</div></li>
54
+ <li ui-flex="col cm" @click="setDateValue('m', 10)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(10) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">10月</div></li>
55
+ <li ui-flex="col cm" @click="setDateValue('m', 11)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(11) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">11月</div></li>
56
+ <li ui-flex="col cm" @click="setDateValue('m', 12)"><div ui-flex="col cm" class="w-ss h-xs ac ux-none r-sm" :class="isSelectedMonth(12) ? 'active bg-main-o-lm co-w' : 'co-main:hover'">12月</div></li>
51
57
  </ul>
52
58
  </div>
53
59
  <div v-else class="full">
@@ -132,11 +138,11 @@
132
138
  </div>
133
139
  <div v-else class="h-ss"></div>
134
140
  </template>
135
- <div v-if="tools" ui-date-foot="" ui-flex="row xm" class="flex-fixed nx-sl ny-sl b-solid bk-line-o-mm bt-xs">
141
+ <div v-if="showTools" ui-date-foot="" ui-flex="row xm" class="flex-fixed nx-sl ny-sl b-solid bk-line-o-mm bt-xs">
136
142
  <div ui-flex="row lm" class="nl-ss">
137
143
  <div v-if="state.panel" ui-flex="row lm">
138
- <span :anim-editing="state.type === 0" class="nx-ss">{{ idate(state.panel).format('YYYY-MM-DD') }}</span>
139
- <span v-if="!state.isNoTime" :anim-editing="state.type === 0" class="nx-ss">{{ idate(state.panel).format('HH:mm:ss') }}</span>
144
+ <span :anim-editing="state.type === baseType" class="nx-ss">{{ idate(state.panel).format(panelFormat) }}</span>
145
+ <span v-if="!state.isNoTime" :anim-editing="state.type === baseType" class="nx-ss">{{ idate(state.panel).format('HH:mm:ss') }}</span>
140
146
  </div>
141
147
  <div v-else-if="state.shortcuts?.length" ui-flex="row lm">
142
148
  <div class="mr-sm-sub nx-sl-sub ny-ss-sub lh-ss nowrap fs-ss dib-sub" ui-scroll=":x y:hidden">
@@ -159,9 +165,40 @@
159
165
  import { idate } from './date';
160
166
  import { Icon } from '../basic';
161
167
 
168
+ const normalizeDateInput = (value: any) => {
169
+ if (!value) {
170
+ return value;
171
+ }
172
+ if (isString(value)) {
173
+ if (/^\d{4}$/.test(value)) {
174
+ return `${value}-01-01`;
175
+ }
176
+ if (/^\d{4}-(\d{1,2})$/.test(value)) {
177
+ const [year, month] = value.split('-');
178
+ const m = month.padStart(2, '0');
179
+ return `${year}-${m}-01`;
180
+ }
181
+ }
182
+ return value;
183
+ };
184
+
185
+ interface PickerConfig {
186
+ baseType: number;
187
+ format: string;
188
+ bodyClass: string;
189
+ tools: boolean;
190
+ }
191
+
192
+ const PICKER_CONFIGS: Record<string, PickerConfig> = {
193
+ date: { baseType: 0, format: 'YYYY-MM-DD', bodyClass: 'min-h-ls+', tools: true },
194
+ month: { baseType: 1, format: 'YYYY-MM', bodyClass: 'min-h-ms', tools: false },
195
+ year: { baseType: 2, format: 'YYYY', bodyClass: 'min-h-ms', tools: false },
196
+ };
197
+
162
198
  // 创建日期
163
199
  const cDate = (date: any = null) => {
164
- return isDateString(date) ? new Date(date) : new Date();
200
+ const normalized = normalizeDateInput(date);
201
+ return isDateString(normalized) ? new Date(normalized) : new Date();
165
202
  };
166
203
 
167
204
  // 快捷预设
@@ -198,7 +235,7 @@
198
235
  tools?: boolean;
199
236
  range?: boolean;
200
237
  format?: string;
201
- picker?: 'date' | 'week' | 'month' | 'quarter';
238
+ picker?: 'date' | 'week' | 'month' | 'quarter' | 'year';
202
239
  holiday?: object;
203
240
  shortcuts?: Array<'yesterday' | 'today' | 'tomorrow'>;
204
241
  extras?: (item: any) => string;
@@ -211,7 +248,7 @@
211
248
  // 是否显示框架
212
249
  frame: false,
213
250
  // 是否是示工具
214
- tools: true,
251
+ tools: undefined,
215
252
  // 时间范围
216
253
  range: false,
217
254
  // 面板类型
@@ -223,7 +260,7 @@
223
260
  // 快捷选择
224
261
  shortcuts: () => ['yesterday', 'today', 'tomorrow'],
225
262
  // 数据格式化
226
- format: 'YYYY-MM-DD',
263
+ format: undefined,
227
264
  // 节假日
228
265
  holiday: () => ({}),
229
266
  time: false,
@@ -231,6 +268,11 @@
231
268
  lang: 'zh-CN',
232
269
  });
233
270
 
271
+ const pickerConfig = computed<PickerConfig>(() => {
272
+ const key = props.picker || 'date';
273
+ return PICKER_CONFIGS[key] || PICKER_CONFIGS.date;
274
+ });
275
+
234
276
  // 小时
235
277
  const hours = computed(() => {
236
278
  const _hours: any = [];
@@ -248,6 +290,27 @@
248
290
  return _seconds;
249
291
  });
250
292
 
293
+ const baseType = computed(() => pickerConfig.value.baseType);
294
+
295
+ const panelFormat = computed(() => props.format || pickerConfig.value.format);
296
+
297
+ const bodyClass = computed(() => pickerConfig.value.bodyClass);
298
+
299
+ const showTools = computed(() => {
300
+ if (props.tools !== undefined) {
301
+ return !!props.tools;
302
+ }
303
+ return pickerConfig.value.tools;
304
+ });
305
+
306
+ const isSelectedYear = (year: number) => {
307
+ return !!state.panel && state.curr?.y === year;
308
+ };
309
+
310
+ const isSelectedMonth = (month: number) => {
311
+ return !!state.panel && state.curr?.M === month;
312
+ };
313
+
251
314
  // 内部数据
252
315
  const state: any = reactive({
253
316
  // 面板显示时间
@@ -280,6 +343,28 @@
280
343
  }),
281
344
  });
282
345
 
346
+ watch(
347
+ () => baseType.value,
348
+ (value) => {
349
+ state.type = value;
350
+ },
351
+ { immediate: true },
352
+ );
353
+
354
+ watch(
355
+ () => panelFormat.value,
356
+ (format) => {
357
+ if (state.panel) {
358
+ const formatted = idate(state.panel).format(format);
359
+ if (formatted !== state.panel) {
360
+ state.panel = formatted;
361
+ }
362
+ state.value = formatted;
363
+ }
364
+ },
365
+ { immediate: true },
366
+ );
367
+
283
368
  // 面板
284
369
  const panel: any = reactive({
285
370
  years: computed(() => {
@@ -300,9 +385,18 @@
300
385
 
301
386
  // 设置日期
302
387
  const setDateValue = (type: any, value: number = 0, add: number = 0) => {
303
- state.panel = upload(type, value, add);
388
+ const panelValue = upload(type, value, add);
389
+ state.panel = panelValue;
390
+ state.value = panelValue;
304
391
  // 面板返回上一级
305
- state.type = Math.max(0, state.type - 1);
392
+ const base = baseType.value;
393
+ const nextType = Math.max(base, state.type - 1);
394
+ state.type = nextType;
395
+
396
+ if (base > 0 && nextType === base) {
397
+ emits('change', panelValue);
398
+ update();
399
+ }
306
400
  };
307
401
 
308
402
  // 时分秒
@@ -337,10 +431,11 @@
337
431
  watch(
338
432
  () => props.modelValue,
339
433
  (value: any) => {
434
+ const formatted = value ? idate(value).format(panelFormat.value) : undefined;
340
435
  // 面板显示日期
341
- state.panel = value || undefined;
436
+ state.panel = formatted;
342
437
  // 值
343
- state.value = value || undefined;
438
+ state.value = formatted;
344
439
  },
345
440
  { deep: true, immediate: true },
346
441
  );
@@ -405,7 +500,7 @@
405
500
  default:
406
501
  break;
407
502
  }
408
- return idate(date).format(props.format);
503
+ return idate(date).format(panelFormat.value);
409
504
  };
410
505
 
411
506
  // 日期前翻
@@ -419,7 +514,7 @@
419
514
 
420
515
  // 向外通信
421
516
  const change = (item: any) => {
422
- const panelValue = item ? idate(item.date).format(props.format) : item;
517
+ const panelValue = item ? idate(item.date).format(panelFormat.value) : item;
423
518
  state.panel = panelValue;
424
519
  state.value = panelValue;
425
520
  emits('change', panelValue);
@@ -431,13 +526,19 @@
431
526
  // 清空日期
432
527
  const remove = () => {
433
528
  state.panel = undefined;
529
+ state.value = undefined;
434
530
  update();
435
531
  };
436
532
 
437
533
  // 更新数据
438
534
  const update = () => {
439
- emits('update:modelValue', state.panel ? idate(state.panel).format(props.format) : undefined);
440
- emits('update', state.panel ? idate(state.panel).format(props.format) : undefined);
535
+ const nextValue = state.panel ? idate(state.panel).format(panelFormat.value) : undefined;
536
+ if (state.panel && nextValue !== state.panel) {
537
+ state.panel = nextValue;
538
+ }
539
+ state.value = nextValue;
540
+ emits('update:modelValue', nextValue);
541
+ emits('update', nextValue);
441
542
  };
442
543
 
443
544
  // 面板类型