@hbdlzy/ui-core 0.1.0 → 0.1.2

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 (51) hide show
  1. package/README.md +61 -3
  2. package/components.manifest.json +239 -24
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.js +3005 -13
  5. package/dist/style.css +1 -0
  6. package/package.json +5 -3
  7. package/src/components/BaseCard/BaseCard.types.ts +38 -0
  8. package/src/components/BaseCard/BaseCard.vue +250 -0
  9. package/src/components/BaseCard/README.md +164 -0
  10. package/src/components/BaseCard/index.ts +5 -0
  11. package/src/components/BaseEChart/BaseEChart.types.ts +35 -0
  12. package/src/components/BaseEChart/BaseEChart.vue +327 -0
  13. package/src/components/BaseEChart/README.md +136 -0
  14. package/src/components/BaseEChart/index.ts +5 -0
  15. package/src/components/BaseExportButton/BaseExportButton.vue +1 -1
  16. package/src/components/BaseExportButton/README.md +104 -8
  17. package/src/components/BaseTable/BaseTable.types.ts +174 -0
  18. package/src/components/BaseTable/BaseTable.vue +809 -0
  19. package/src/components/BaseTable/README.md +398 -0
  20. package/src/components/BaseTable/index.ts +25 -0
  21. package/src/components/OutlinedCascader/OutlinedCascader.types.ts +28 -0
  22. package/src/components/OutlinedCascader/OutlinedCascader.vue +250 -0
  23. package/src/components/OutlinedCascader/README.md +91 -0
  24. package/src/components/OutlinedCascader/index.ts +10 -0
  25. package/src/components/OutlinedDatePicker/OutlinedDatePicker.types.ts +40 -0
  26. package/src/components/OutlinedDatePicker/OutlinedDatePicker.vue +365 -0
  27. package/src/components/OutlinedDatePicker/README.md +137 -0
  28. package/src/components/OutlinedDatePicker/index.ts +11 -0
  29. package/src/components/OutlinedDateTimePicker/OutlinedDateTimePicker.types.ts +34 -0
  30. package/src/components/OutlinedDateTimePicker/OutlinedDateTimePicker.vue +421 -0
  31. package/src/components/OutlinedDateTimePicker/README.md +88 -0
  32. package/src/components/OutlinedDateTimePicker/index.ts +11 -0
  33. package/src/components/OutlinedInput/OutlinedInput.types.ts +32 -0
  34. package/src/components/OutlinedInput/OutlinedInput.vue +307 -0
  35. package/src/components/OutlinedInput/README.md +154 -0
  36. package/src/components/OutlinedInput/index.ts +10 -0
  37. package/src/components/OutlinedSelect/OutlinedSelect.types.ts +48 -0
  38. package/src/components/OutlinedSelect/OutlinedSelect.vue +359 -0
  39. package/src/components/OutlinedSelect/README.md +166 -0
  40. package/src/components/OutlinedSelect/index.ts +12 -0
  41. package/src/components/OutlinedTimePicker/OutlinedTimePicker.types.ts +36 -0
  42. package/src/components/OutlinedTimePicker/OutlinedTimePicker.vue +303 -0
  43. package/src/components/OutlinedTimePicker/README.md +93 -0
  44. package/src/components/OutlinedTimePicker/index.ts +10 -0
  45. package/src/components/OutlinedTreeSelect/OutlinedTreeSelect.types.ts +56 -0
  46. package/src/components/OutlinedTreeSelect/OutlinedTreeSelect.vue +354 -0
  47. package/src/components/OutlinedTreeSelect/README.md +107 -0
  48. package/src/components/OutlinedTreeSelect/index.ts +12 -0
  49. package/src/echarts/index.ts +12 -0
  50. package/src/excel/exportExcel.ts +36 -10
  51. package/src/index.ts +29 -0
@@ -0,0 +1,421 @@
1
+ <template>
2
+ <div
3
+ class="outlined-date-time-picker"
4
+ :class="[rootClass]"
5
+ :style="rootStyle"
6
+ >
7
+ <div
8
+ class="outlined-date-time-picker__field"
9
+ :class="fieldClasses"
10
+ :style="fieldStyle"
11
+ >
12
+ <el-date-picker
13
+ ref="datePickerRef"
14
+ class="outlined-date-time-picker__control"
15
+ :model-value="dateValue"
16
+ type="date"
17
+ format="YYYY-MM-DD"
18
+ value-format="YYYY-MM-DD"
19
+ :placeholder="placeholder"
20
+ :clearable="clearable"
21
+ :disabled-date="resolvedDisabledDate"
22
+ :style="controlStyle"
23
+ @update:model-value="handleDateUpdate"
24
+ @focus="handleFocus('date')"
25
+ @blur="handleBlur('date', $event)"
26
+ @change="handleDateChange"
27
+ @visible-change="handleVisibleChange('date', $event)"
28
+ />
29
+
30
+ <div
31
+ v-if="floatingLabel"
32
+ class="outlined-date-time-picker__label"
33
+ :class="dateLabelClasses"
34
+ >
35
+ {{ floatingLabel }}
36
+ </div>
37
+ </div>
38
+
39
+ <span class="outlined-date-time-picker__separator">{{ separatorText }}</span>
40
+
41
+ <div
42
+ class="outlined-date-time-picker__field"
43
+ :class="fieldClasses"
44
+ :style="fieldStyle"
45
+ >
46
+ <el-time-picker
47
+ ref="timePickerRef"
48
+ class="outlined-date-time-picker__control"
49
+ :model-value="timeValue"
50
+ format="HH:mm"
51
+ value-format="HH:mm"
52
+ :placeholder="timePlaceholder"
53
+ :clearable="clearable"
54
+ :disabled="!dateValue"
55
+ :disabled-hours="resolvedDisabledHours"
56
+ :disabled-minutes="resolvedDisabledMinutes"
57
+ :style="controlStyle"
58
+ @update:model-value="handleTimeUpdate"
59
+ @focus="handleFocus('time')"
60
+ @blur="handleBlur('time', $event)"
61
+ @change="handleTimeChange"
62
+ @visible-change="handleVisibleChange('time', $event)"
63
+ />
64
+
65
+ <div
66
+ class="outlined-date-time-picker__label"
67
+ :class="timeLabelClasses"
68
+ >
69
+ {{ timePlaceholder }}
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </template>
74
+
75
+ <script setup lang="ts">
76
+ import { computed, ref, useAttrs, watch } from 'vue'
77
+ import dayjs from 'dayjs'
78
+ import type {
79
+ OutlinedDateTimePickerCssValue,
80
+ OutlinedDateTimePickerDisabledDate,
81
+ OutlinedDateTimePickerExpose,
82
+ OutlinedDateTimePickerProps,
83
+ OutlinedDateTimePickerValue
84
+ } from './OutlinedDateTimePicker.types'
85
+
86
+ defineOptions({
87
+ name: 'OutlinedDateTimePicker',
88
+ inheritAttrs: false
89
+ })
90
+
91
+ const props = withDefaults(defineProps<OutlinedDateTimePickerProps>(), {
92
+ value: '',
93
+ placeholder: '',
94
+ label: '',
95
+ inputHeight: 40,
96
+ isBorder: false,
97
+ disabledDate: undefined,
98
+ separatorText: '-',
99
+ timePlaceholder: '时间',
100
+ clearable: false,
101
+ marginBottom: 20,
102
+ paddingTop: 20
103
+ })
104
+
105
+ const emit = defineEmits<{
106
+ (event: 'input', value: OutlinedDateTimePickerValue): void
107
+ (event: 'update:value', value: OutlinedDateTimePickerValue): void
108
+ (event: 'change', value: OutlinedDateTimePickerValue): void
109
+ (event: 'focus', payload: { field: 'date' | 'time'; event: FocusEvent }): void
110
+ (event: 'blur', payload: { field: 'date' | 'time'; event: FocusEvent }): void
111
+ (event: 'visible-change', payload: { field: 'date' | 'time'; visible: boolean }): void
112
+ }>()
113
+
114
+ const attrs = useAttrs()
115
+ const datePickerRef = ref<any>(null)
116
+ const timePickerRef = ref<any>(null)
117
+ const dateValue = ref<string | null>(null)
118
+ const timeValue = ref<string | null>(null)
119
+ const dateFocused = ref(false)
120
+ const timeFocused = ref(false)
121
+ const dateBlurred = ref(false)
122
+ const timeBlurred = ref(false)
123
+ const dateVisible = ref(false)
124
+ const timeVisible = ref(false)
125
+
126
+ watch(
127
+ () => props.value,
128
+ (value) => {
129
+ syncFromValue(value)
130
+ },
131
+ { immediate: true }
132
+ )
133
+
134
+ const rootClass = computed(() => attrs.class)
135
+ const rootStyle = computed(() => attrs.style)
136
+ const floatingLabel = computed(() => props.label || props.placeholder || '')
137
+
138
+ const fieldClasses = computed(() => ({
139
+ 'outlined-date-time-picker__field--bordered': props.isBorder
140
+ }))
141
+
142
+ const fieldStyle = computed(() => ({
143
+ marginBottom: toCssValue(props.marginBottom),
144
+ paddingTop: toCssValue(props.paddingTop)
145
+ }))
146
+
147
+ const controlStyle = computed(() => ({
148
+ height: `${props.inputHeight}px`
149
+ }))
150
+
151
+ const resolvedDisabledDate = computed(() => createDisabledDateHandler(props.disabledDate))
152
+
153
+ const resolvedDisabledHours = computed(() => {
154
+ if (!shouldLimitCurrentTime()) {
155
+ return undefined
156
+ }
157
+
158
+ return () => {
159
+ const hours = new Date().getHours()
160
+ return Array.from({ length: hours }, (_, index) => index)
161
+ }
162
+ })
163
+
164
+ const resolvedDisabledMinutes = computed(() => {
165
+ if (!shouldLimitCurrentTime()) {
166
+ return undefined
167
+ }
168
+
169
+ return () => {
170
+ const minutes = new Date().getMinutes()
171
+ return Array.from({ length: minutes }, (_, index) => index)
172
+ }
173
+ })
174
+
175
+ const dateLabelClasses = computed(() => ({
176
+ 'outlined-date-time-picker__label--floating': dateFocused.value || Boolean(dateValue.value),
177
+ 'outlined-date-time-picker__label--placeholder': !dateFocused.value && !dateValue.value,
178
+ 'outlined-date-time-picker__label--filled': Boolean(dateValue.value) && !dateFocused.value
179
+ }))
180
+
181
+ const timeLabelClasses = computed(() => ({
182
+ 'outlined-date-time-picker__label--floating': timeFocused.value || Boolean(timeValue.value),
183
+ 'outlined-date-time-picker__label--placeholder': !timeFocused.value && !timeValue.value,
184
+ 'outlined-date-time-picker__label--filled': Boolean(timeValue.value) && !timeFocused.value
185
+ }))
186
+
187
+ function syncFromValue(value: OutlinedDateTimePickerValue) {
188
+ if (!value) {
189
+ dateValue.value = null
190
+ timeValue.value = null
191
+ return
192
+ }
193
+
194
+ const [datePart, timePart] = value.split(' ')
195
+ dateValue.value = datePart || null
196
+ timeValue.value = timePart || null
197
+ }
198
+
199
+ function handleDateUpdate(value: string | null) {
200
+ dateValue.value = value || null
201
+ }
202
+
203
+ function handleTimeUpdate(value: string | null) {
204
+ timeValue.value = value || null
205
+ }
206
+
207
+ function handleDateChange() {
208
+ if (dateValue.value && !timeValue.value) {
209
+ timeValue.value = dayjs().format('HH:mm')
210
+ }
211
+
212
+ emitCombinedValue()
213
+ }
214
+
215
+ function handleTimeChange() {
216
+ emitCombinedValue()
217
+ }
218
+
219
+ function handleFocus(field: 'date' | 'time') {
220
+ return (event: FocusEvent) => {
221
+ if (field === 'date') {
222
+ dateBlurred.value = false
223
+ dateFocused.value = true
224
+ } else {
225
+ timeBlurred.value = false
226
+ timeFocused.value = true
227
+ }
228
+
229
+ emit('focus', { field, event })
230
+ }
231
+ }
232
+
233
+ function handleBlur(field: 'date' | 'time', event: FocusEvent) {
234
+ if (field === 'date') {
235
+ dateBlurred.value = true
236
+
237
+ if (!dateVisible.value) {
238
+ dateFocused.value = false
239
+ emitCombinedValue()
240
+ }
241
+ } else {
242
+ timeBlurred.value = true
243
+
244
+ if (!timeVisible.value) {
245
+ timeFocused.value = false
246
+ emitCombinedValue()
247
+ }
248
+ }
249
+
250
+ emit('blur', { field, event })
251
+ }
252
+
253
+ function handleVisibleChange(field: 'date' | 'time', visible: boolean) {
254
+ if (field === 'date') {
255
+ dateVisible.value = visible
256
+
257
+ if (!visible && dateBlurred.value) {
258
+ dateFocused.value = false
259
+ }
260
+ } else {
261
+ timeVisible.value = visible
262
+
263
+ if (!visible && timeBlurred.value) {
264
+ timeFocused.value = false
265
+ }
266
+ }
267
+
268
+ emit('visible-change', { field, visible })
269
+ }
270
+
271
+ function emitCombinedValue() {
272
+ const value = dateValue.value && timeValue.value ? `${dateValue.value} ${timeValue.value}` : ''
273
+ emit('input', value)
274
+ emit('update:value', value)
275
+ emit('change', value)
276
+ }
277
+
278
+ function createDisabledDateHandler(disabledDate: OutlinedDateTimePickerDisabledDate | undefined) {
279
+ if (!disabledDate) {
280
+ return undefined
281
+ }
282
+
283
+ if (typeof disabledDate === 'function') {
284
+ return disabledDate
285
+ }
286
+
287
+ const boundary = normalizeBoundary(disabledDate)
288
+ return (value: Date) => value.getTime() < boundary - 86400000
289
+ }
290
+
291
+ function normalizeBoundary(value: Exclude<OutlinedDateTimePickerDisabledDate, (date: Date) => boolean>) {
292
+ if (value === 'nowDate') {
293
+ return Date.now()
294
+ }
295
+
296
+ if (value instanceof Date) {
297
+ return value.getTime()
298
+ }
299
+
300
+ if (typeof value === 'number') {
301
+ return value
302
+ }
303
+
304
+ return new Date(value).getTime()
305
+ }
306
+
307
+ function shouldLimitCurrentTime() {
308
+ return Boolean(props.disabledDate) && dateValue.value === dayjs().format('YYYY-MM-DD')
309
+ }
310
+
311
+ function toCssValue(value: OutlinedDateTimePickerCssValue | undefined) {
312
+ if (typeof value === 'number') {
313
+ return `${value}px`
314
+ }
315
+
316
+ return value
317
+ }
318
+
319
+ defineExpose<OutlinedDateTimePickerExpose>({
320
+ focusDate: () => {
321
+ datePickerRef.value?.focus?.()
322
+ },
323
+ focusTime: () => {
324
+ timePickerRef.value?.focus?.()
325
+ },
326
+ blurDate: () => {
327
+ datePickerRef.value?.blur?.()
328
+ },
329
+ blurTime: () => {
330
+ timePickerRef.value?.blur?.()
331
+ },
332
+ openDatePanel: () => {
333
+ datePickerRef.value?.handleOpen?.()
334
+ },
335
+ openTimePanel: () => {
336
+ timePickerRef.value?.handleOpen?.()
337
+ },
338
+ getDatePickerRef: () => datePickerRef.value,
339
+ getTimePickerRef: () => timePickerRef.value
340
+ })
341
+ </script>
342
+
343
+ <style scoped>
344
+ .outlined-date-time-picker {
345
+ display: flex;
346
+ align-items: center;
347
+ gap: 8px;
348
+ }
349
+
350
+ .outlined-date-time-picker__field {
351
+ position: relative;
352
+ flex: 1;
353
+ }
354
+
355
+ .outlined-date-time-picker__separator {
356
+ flex: 0 0 auto;
357
+ color: var(--el-text-color-regular);
358
+ }
359
+
360
+ .outlined-date-time-picker__label {
361
+ position: absolute;
362
+ left: -2px;
363
+ padding: 2px 5px;
364
+ border-radius: 2px;
365
+ background-color: #ffffff;
366
+ font-size: 12px;
367
+ line-height: 1;
368
+ transition: color 200ms cubic-bezier(0, 0, 0.2, 1), transform 200ms cubic-bezier(0, 0, 0.2, 1);
369
+ pointer-events: none;
370
+ }
371
+
372
+ .outlined-date-time-picker__label--floating {
373
+ top: 18px;
374
+ z-index: 1;
375
+ opacity: 1;
376
+ transform: translate(14px, -6px) scale(1);
377
+ color: var(--el-color-primary);
378
+ }
379
+
380
+ .outlined-date-time-picker__label--placeholder {
381
+ top: 50%;
382
+ left: 1px;
383
+ z-index: -1;
384
+ opacity: 0;
385
+ transform: translate(14px, 6px) scale(1);
386
+ }
387
+
388
+ .outlined-date-time-picker__label--filled {
389
+ color: var(--el-text-color-regular);
390
+ }
391
+
392
+ :deep(.outlined-date-time-picker__control.el-date-editor) {
393
+ width: 100%;
394
+ }
395
+
396
+ :deep(.outlined-date-time-picker__control .el-input__wrapper) {
397
+ position: relative;
398
+ min-height: inherit;
399
+ height: inherit;
400
+ }
401
+
402
+ :deep(.outlined-date-time-picker__control .el-input__prefix) {
403
+ position: absolute;
404
+ right: 0;
405
+ }
406
+
407
+ :deep(.outlined-date-time-picker__control .el-input__suffix) {
408
+ position: absolute;
409
+ right: 30px;
410
+ }
411
+
412
+ :deep(.outlined-date-time-picker__field--bordered .el-input__wrapper) {
413
+ box-shadow: none;
414
+ border-radius: 0;
415
+ border-bottom: 1px solid #cccccc;
416
+ }
417
+
418
+ :deep(.outlined-date-time-picker__field--bordered .el-input__wrapper.is-focus) {
419
+ border-bottom-color: var(--el-color-primary);
420
+ }
421
+ </style>
@@ -0,0 +1,88 @@
1
+ # OutlinedDateTimePicker
2
+
3
+ `OutlinedDateTimePicker` 是 `OutlinedForm` 系列里的日期时间组合控件,用来统一封装“先选日期,再补时间”的输入壳子、浮动标签、禁用日期规则和实例方法暴露。
4
+
5
+ ## 适用场景
6
+
7
+ - 页面里经常出现“日期 + 时间”成对输入,但不想每次都重复写两个控件的布局和状态联动
8
+ - 需要统一日期时间输入框的浮动标签风格
9
+ - 需要基于当前日期限制时间可选范围
10
+ - 需要在页面层直接调用日期面板或时间面板的打开方法
11
+
12
+ ## 基本用法
13
+
14
+ ```vue
15
+ <script setup lang="ts">
16
+ import { ref } from 'vue'
17
+ import { OutlinedDateTimePicker, type OutlinedDateTimePickerExpose } from '@hbdlzy/ui'
18
+
19
+ const pickerRef = ref<OutlinedDateTimePickerExpose | null>(null)
20
+ const executeAt = ref('')
21
+
22
+ const openDatePanel = () => {
23
+ pickerRef.value?.openDatePanel()
24
+ }
25
+ </script>
26
+
27
+ <template>
28
+ <OutlinedDateTimePicker
29
+ ref="pickerRef"
30
+ v-model:value="executeAt"
31
+ placeholder="执行日期"
32
+ time-placeholder="执行时间"
33
+ :is-border="true"
34
+ :disabled-date="'nowDate'"
35
+ clearable
36
+ />
37
+
38
+ <el-button @click="openDatePanel">
39
+ 打开日期面板
40
+ </el-button>
41
+ </template>
42
+ ```
43
+
44
+ ## Props
45
+
46
+ | 属性 | 类型 | 默认值 | 说明 |
47
+ | --- | --- | --- | --- |
48
+ | `value` | `string` | `''` | `v-model:value` 绑定值,格式为 `YYYY-MM-DD HH:mm` |
49
+ | `placeholder` | `string` | `''` | 日期部分占位文案,也会作为浮动标签主文案 |
50
+ | `label` | `string` | `''` | 自定义浮动标签文案,优先级高于 `placeholder` |
51
+ | `inputHeight` | `number` | `40` | 输入框高度 |
52
+ | `isBorder` | `boolean` | `false` | 是否启用下边框风格 |
53
+ | `disabledDate` | `string \| number \| Date \| ((date: Date) => boolean)` | `undefined` | 日期禁用规则,支持 `nowDate` |
54
+ | `separatorText` | `string` | `'-'` | 日期和时间之间的分隔文案 |
55
+ | `timePlaceholder` | `string` | `'时间'` | 时间部分占位文案 |
56
+ | `clearable` | `boolean` | `false` | 是否允许清空 |
57
+ | `marginBottom` | `string \| number` | `20` | 外层下边距 |
58
+ | `paddingTop` | `string \| number` | `20` | 外层上内边距,用于浮动标签留白 |
59
+
60
+ ## Emits
61
+
62
+ | 事件 | 参数 | 说明 |
63
+ | --- | --- | --- |
64
+ | `input` | `string` | 输入值变化时触发 |
65
+ | `update:value` | `string` | `v-model:value` 同步事件 |
66
+ | `change` | `string` | 日期或时间确认变化后触发 |
67
+ | `focus` | `{ field: 'date' \| 'time'; event: FocusEvent }` | 某一侧输入聚焦时触发 |
68
+ | `blur` | `{ field: 'date' \| 'time'; event: FocusEvent }` | 某一侧输入失焦时触发 |
69
+ | `visible-change` | `{ field: 'date' \| 'time'; visible: boolean }` | 日期面板或时间面板开关变化时触发 |
70
+
71
+ ## Expose
72
+
73
+ | 方法 | 说明 |
74
+ | --- | --- |
75
+ | `focusDate()` | 聚焦日期输入 |
76
+ | `focusTime()` | 聚焦时间输入 |
77
+ | `blurDate()` | 取消日期输入聚焦 |
78
+ | `blurTime()` | 取消时间输入聚焦 |
79
+ | `openDatePanel()` | 打开日期面板 |
80
+ | `openTimePanel()` | 打开时间面板 |
81
+ | `getDatePickerRef()` | 获取内部 `el-date-picker` 实例 |
82
+ | `getTimePickerRef()` | 获取内部 `el-time-picker` 实例 |
83
+
84
+ ## 设计约束
85
+
86
+ - 组件内部只处理输入壳子、标签浮层、日期禁用和时间联动,不直接耦合接口、表单校验器或业务规则
87
+ - 如果只选了日期但没有选时间,组件会在日期确认时自动补一个当前 `HH:mm`
88
+ - 页面层如果需要更复杂的日期时间协议,建议继续在外层包业务组件,不要把业务判断塞回 `ui-core`
@@ -0,0 +1,11 @@
1
+ import OutlinedDateTimePicker from './OutlinedDateTimePicker.vue'
2
+
3
+ export default OutlinedDateTimePicker
4
+
5
+ export type {
6
+ OutlinedDateTimePickerCssValue,
7
+ OutlinedDateTimePickerDisabledDate,
8
+ OutlinedDateTimePickerExpose,
9
+ OutlinedDateTimePickerProps,
10
+ OutlinedDateTimePickerValue
11
+ } from './OutlinedDateTimePicker.types'
@@ -0,0 +1,32 @@
1
+ export type OutlinedInputValue = string | number
2
+
3
+ export type OutlinedInputCssValue = string | number
4
+
5
+ export interface OutlinedInputProps {
6
+ value?: OutlinedInputValue
7
+ disabled?: boolean
8
+ regex?: RegExp
9
+ placeholder?: string
10
+ label?: string
11
+ maxlength?: string | number
12
+ max?: string | number
13
+ min?: string | number
14
+ typeInput?: string
15
+ showPassword?: boolean
16
+ isNumber?: boolean
17
+ inputHeight?: number
18
+ isBorder?: boolean
19
+ suffixText?: string
20
+ clearable?: boolean
21
+ showWordLimit?: boolean
22
+ marginBottom?: OutlinedInputCssValue
23
+ paddingTop?: OutlinedInputCssValue
24
+ }
25
+
26
+ export interface OutlinedInputExpose {
27
+ focus: () => void
28
+ blur: () => void
29
+ clear: () => void
30
+ select: () => void
31
+ getInputRef: () => unknown | null
32
+ }