@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,307 @@
1
+ <template>
2
+ <div
3
+ class="outlined-input"
4
+ :class="[containerClasses, rootClass]"
5
+ :style="[containerStyle, rootStyle]"
6
+ >
7
+ <el-input
8
+ ref="inputRef"
9
+ v-bind="inputAttrs"
10
+ :model-value="inputValue"
11
+ :type="resolvedType"
12
+ :placeholder="placeholder"
13
+ :disabled="disabled"
14
+ :maxlength="maxlength"
15
+ :max="max"
16
+ :min="min"
17
+ :show-password="showPassword"
18
+ :show-word-limit="showWordLimit"
19
+ :clearable="clearable"
20
+ :style="inputStyle"
21
+ @update:model-value="handleModelValueUpdate"
22
+ @focus="handleFocus"
23
+ @blur="handleBlur"
24
+ @change="handleChange"
25
+ @clear="handleClear"
26
+ >
27
+ <template v-if="$slots.prefix" #prefix>
28
+ <slot name="prefix" />
29
+ </template>
30
+
31
+ <template v-if="$slots.prepend" #prepend>
32
+ <slot name="prepend" />
33
+ </template>
34
+
35
+ <template v-if="$slots.append" #append>
36
+ <slot name="append" />
37
+ </template>
38
+
39
+ <template v-if="$slots.suffix || suffixText" #suffix>
40
+ <slot name="suffix">
41
+ <span class="outlined-input__suffix-text">{{ suffixText }}</span>
42
+ </slot>
43
+ </template>
44
+ </el-input>
45
+
46
+ <div
47
+ v-if="floatingLabel"
48
+ class="outlined-input__label"
49
+ :class="labelClasses"
50
+ >
51
+ {{ floatingLabel }}
52
+ </div>
53
+ </div>
54
+ </template>
55
+
56
+ <script setup lang="ts">
57
+ import { computed, ref, useAttrs, watch } from 'vue'
58
+ import type { InputInstance } from 'element-plus'
59
+ import type {
60
+ OutlinedInputCssValue,
61
+ OutlinedInputExpose,
62
+ OutlinedInputProps,
63
+ OutlinedInputValue
64
+ } from './OutlinedInput.types'
65
+
66
+ defineOptions({
67
+ name: 'OutlinedInput',
68
+ inheritAttrs: false
69
+ })
70
+
71
+ const DEFAULT_REGEX = /^\d+$/
72
+
73
+ const props = withDefaults(defineProps<OutlinedInputProps>(), {
74
+ value: '',
75
+ disabled: false,
76
+ placeholder: '',
77
+ label: '',
78
+ typeInput: 'text',
79
+ showPassword: false,
80
+ isNumber: false,
81
+ inputHeight: 40,
82
+ isBorder: false,
83
+ suffixText: '',
84
+ clearable: false,
85
+ showWordLimit: true,
86
+ marginBottom: 20,
87
+ paddingTop: 20
88
+ })
89
+
90
+ const emit = defineEmits<{
91
+ (event: 'input', value: OutlinedInputValue | ''): void
92
+ (event: 'update:value', value: OutlinedInputValue | ''): void
93
+ (event: 'warning', value: string): void
94
+ (event: 'focus', value: FocusEvent): void
95
+ (event: 'blur', value: FocusEvent): void
96
+ (event: 'change', value: OutlinedInputValue | ''): void
97
+ (event: 'clear'): void
98
+ }>()
99
+
100
+ const attrs = useAttrs()
101
+ const inputRef = ref<InputInstance | null>(null)
102
+ const inputValue = ref<OutlinedInputValue | ''>(props.value ?? '')
103
+ const focused = ref(false)
104
+
105
+ watch(
106
+ () => props.value,
107
+ (value) => {
108
+ inputValue.value = value ?? ''
109
+ },
110
+ { immediate: true }
111
+ )
112
+
113
+ const rootClass = computed(() => attrs.class)
114
+ const rootStyle = computed(() => attrs.style)
115
+
116
+ const inputAttrs = computed(() => {
117
+ const { class: _class, style: _style, ...rest } = attrs
118
+ return rest
119
+ })
120
+
121
+ const resolvedType = computed(() => props.typeInput || 'text')
122
+
123
+ const hasTextareaAutosize = computed(() => {
124
+ const autosize = inputAttrs.value.autosize
125
+ return autosize !== undefined && autosize !== false
126
+ })
127
+
128
+ const containerClasses = computed(() => ({
129
+ 'outlined-input--bordered': props.isBorder,
130
+ 'outlined-input--textarea-default': resolvedType.value === 'textarea' && !hasTextareaAutosize.value
131
+ }))
132
+
133
+ const containerStyle = computed(() => ({
134
+ marginBottom: toCssValue(props.marginBottom),
135
+ paddingTop: toCssValue(props.paddingTop)
136
+ }))
137
+
138
+ const inputStyle = computed(() => {
139
+ if (resolvedType.value === 'textarea') {
140
+ return undefined
141
+ }
142
+
143
+ return {
144
+ height: `${props.inputHeight}px`
145
+ }
146
+ })
147
+
148
+ const floatingLabel = computed(() => props.label || props.placeholder || '')
149
+
150
+ const hasContent = computed(() => hasFilledValue(inputValue.value))
151
+
152
+ const labelClasses = computed(() => ({
153
+ 'outlined-input__label--floating': focused.value || hasContent.value,
154
+ 'outlined-input__label--placeholder': !focused.value && !hasContent.value,
155
+ 'outlined-input__label--filled': hasContent.value && !focused.value
156
+ }))
157
+
158
+ function handleModelValueUpdate(value: string | number) {
159
+ const normalizedValue = normalizeValue(value)
160
+ inputValue.value = normalizedValue
161
+ emitModelValue(normalizedValue)
162
+ }
163
+
164
+ function handleFocus(event: FocusEvent) {
165
+ focused.value = true
166
+ emit('focus', event)
167
+ }
168
+
169
+ function handleBlur(event: FocusEvent) {
170
+ focused.value = false
171
+ emitModelValue(inputValue.value)
172
+ emit('blur', event)
173
+ }
174
+
175
+ function handleChange(value: string | number) {
176
+ const normalizedValue = normalizeValue(value)
177
+ inputValue.value = normalizedValue
178
+ emit('change', normalizedValue)
179
+ }
180
+
181
+ function handleClear() {
182
+ emit('clear')
183
+ }
184
+
185
+ function emitModelValue(value: OutlinedInputValue | '') {
186
+ emit('input', value)
187
+ emit('update:value', value)
188
+ }
189
+
190
+ function normalizeValue(value: string | number | null | undefined): OutlinedInputValue | '' {
191
+ const normalizedValue = value ?? ''
192
+
193
+ if (!props.isNumber) {
194
+ return normalizedValue
195
+ }
196
+
197
+ const nextText = String(normalizedValue)
198
+
199
+ if (!nextText) {
200
+ return ''
201
+ }
202
+
203
+ const regex = props.regex || DEFAULT_REGEX
204
+
205
+ if (!regex.test(nextText)) {
206
+ emit('warning', nextText)
207
+ return ''
208
+ }
209
+
210
+ return normalizedValue
211
+ }
212
+
213
+ function hasFilledValue(value: OutlinedInputValue | '') {
214
+ return value !== undefined && value !== null && String(value) !== ''
215
+ }
216
+
217
+ function toCssValue(value: OutlinedInputCssValue | undefined) {
218
+ if (typeof value === 'number') {
219
+ return `${value}px`
220
+ }
221
+
222
+ return value
223
+ }
224
+
225
+ defineExpose<OutlinedInputExpose>({
226
+ focus: () => {
227
+ inputRef.value?.focus()
228
+ },
229
+ blur: () => {
230
+ inputRef.value?.blur()
231
+ },
232
+ clear: () => {
233
+ inputRef.value?.clear()
234
+ },
235
+ select: () => {
236
+ inputRef.value?.select()
237
+ },
238
+ getInputRef: () => inputRef.value
239
+ })
240
+ </script>
241
+
242
+ <style scoped>
243
+ .outlined-input {
244
+ position: relative;
245
+ }
246
+
247
+ .outlined-input__label {
248
+ position: absolute;
249
+ left: -2px;
250
+ padding: 2px 5px;
251
+ border-radius: 2px;
252
+ background-color: #ffffff;
253
+ font-size: 12px;
254
+ line-height: 1;
255
+ transition: color 200ms cubic-bezier(0, 0, 0.2, 1), transform 200ms cubic-bezier(0, 0, 0.2, 1);
256
+ pointer-events: none;
257
+ }
258
+
259
+ .outlined-input__label--floating {
260
+ top: 18px;
261
+ z-index: 1;
262
+ opacity: 1;
263
+ transform: translate(14px, -6px) scale(1);
264
+ color: var(--el-color-primary);
265
+ }
266
+
267
+ .outlined-input__label--placeholder {
268
+ top: 50%;
269
+ left: 1px;
270
+ z-index: -1;
271
+ opacity: 0;
272
+ transform: translate(14px, 6px) scale(1);
273
+ }
274
+
275
+ .outlined-input__label--filled {
276
+ color: var(--el-text-color-regular);
277
+ }
278
+
279
+ .outlined-input__suffix-text {
280
+ white-space: nowrap;
281
+ }
282
+
283
+ :deep(.outlined-input--bordered .el-input__wrapper) {
284
+ box-shadow: none;
285
+ border-radius: 0;
286
+ border-bottom: 1px solid #cccccc;
287
+ }
288
+
289
+ :deep(.outlined-input--bordered .el-input__wrapper.is-focus) {
290
+ border-bottom-color: var(--el-color-primary);
291
+ }
292
+
293
+ :deep(.outlined-input--bordered .el-textarea__inner) {
294
+ border-width: 0 0 1px;
295
+ border-radius: 0;
296
+ box-shadow: none;
297
+ }
298
+
299
+ :deep(.outlined-input--bordered .el-textarea__inner:focus) {
300
+ border-bottom-color: var(--el-color-primary);
301
+ }
302
+
303
+ :deep(.outlined-input--textarea-default .el-textarea__inner) {
304
+ min-height: 100px !important;
305
+ max-height: 180px;
306
+ }
307
+ </style>
@@ -0,0 +1,154 @@
1
+ # OutlinedInput
2
+
3
+ `OutlinedInput` 用来统一项目里带浮动标签样式的输入框,避免页面层重复写输入框高度、标签悬浮、数值校验和实例方法暴露逻辑。
4
+
5
+ ## 解决的问题
6
+
7
+ - 统一浮动标签输入框样式
8
+ - 统一 `v-model:value`、`input`、`update:value` 事件约定
9
+ - 统一数值校验和非法输入警告
10
+ - 自动透传 `autosize`、`resize`、`rows` 等 `el-input` 原生属性
11
+ - 通过组件实例直接调用 `focus`、`blur`、`clear`、`select`
12
+
13
+ ## 适用场景
14
+
15
+ - 页面需要和现有 `OutlinedSelect / OutlinedDatePicker` 保持一致视觉语言
16
+ - 表单页有大量重复的带悬浮标题输入框
17
+ - 页面只想传业务字段和少量配置,不想重复写输入框壳子
18
+ - 需要兼容旧项目大量 `v-model:value` 的写法
19
+
20
+ ## 不适用场景
21
+
22
+ - 页面需要完全自定义输入框 DOM 结构
23
+ - 只是普通输入框,没有浮动标签需求
24
+ - 需要强业务联动校验且不适合在基础组件里收敛
25
+
26
+ ## 基础用法
27
+
28
+ ```vue
29
+ <template>
30
+ <OutlinedInput
31
+ v-model:value="form.stationName"
32
+ placeholder="电站名称"
33
+ :is-border="true"
34
+ :input-height="40"
35
+ />
36
+ </template>
37
+
38
+ <script setup lang="ts">
39
+ import { reactive } from 'vue'
40
+ import { OutlinedInput } from '@hbdlzy/ui-core'
41
+
42
+ const form = reactive({
43
+ stationName: ''
44
+ })
45
+ </script>
46
+ ```
47
+
48
+ ## 数值校验示例
49
+
50
+ ```vue
51
+ <template>
52
+ <OutlinedInput
53
+ v-model:value="form.capacity"
54
+ placeholder="计划充电量"
55
+ type-input="number"
56
+ :is-number="true"
57
+ :regex="/^(0|[1-9]\\d*)(\\.\\d+)?$/"
58
+ @warning="handleWarning"
59
+ />
60
+ </template>
61
+
62
+ <script setup lang="ts">
63
+ import { reactive } from 'vue'
64
+ import { ElMessage } from 'element-plus'
65
+ import { OutlinedInput } from '@hbdlzy/ui-core'
66
+
67
+ const form = reactive({
68
+ capacity: ''
69
+ })
70
+
71
+ const handleWarning = (value: string) => {
72
+ ElMessage.warning(`输入值不合法:${value}`)
73
+ }
74
+ </script>
75
+ ```
76
+
77
+ ## Textarea 示例
78
+
79
+ ```vue
80
+ <template>
81
+ <OutlinedInput
82
+ v-model:value="remark"
83
+ placeholder="备注"
84
+ type-input="textarea"
85
+ :is-border="true"
86
+ :autosize="{ minRows: 4, maxRows: 4 }"
87
+ resize="none"
88
+ />
89
+ </template>
90
+
91
+ <script setup lang="ts">
92
+ import { ref } from 'vue'
93
+ import { OutlinedInput } from '@hbdlzy/ui-core'
94
+
95
+ const remark = ref('')
96
+ </script>
97
+ ```
98
+
99
+ ## Props
100
+
101
+ - `value`: 当前输入值,推荐通过 `v-model:value` 使用
102
+ - `placeholder`: 输入框占位文案,同时默认作为浮动标签文案
103
+ - `label`: 自定义浮动标签文案,未传时回退到 `placeholder`
104
+ - `disabled`: 是否禁用
105
+ - `regex`: 数值校验正则,仅在 `isNumber` 为 `true` 时生效
106
+ - `maxlength`: 最大输入长度
107
+ - `max`: 最大值,透传给底层输入框
108
+ - `min`: 最小值,透传给底层输入框
109
+ - `typeInput`: 输入框类型,默认 `text`
110
+ - `showPassword`: 是否显示密码切换按钮
111
+ - `isNumber`: 是否启用数值校验模式
112
+ - `inputHeight`: 非 textarea 模式下的输入框高度,默认 `40`
113
+ - `isBorder`: 是否启用底部边框样式
114
+ - `suffixText`: 默认后缀文案
115
+ - `clearable`: 是否可清空
116
+ - `showWordLimit`: 是否显示字数统计,默认 `true`
117
+ - `marginBottom`: 外层容器底部间距,默认 `20`
118
+ - `paddingTop`: 外层容器顶部留白,默认 `20`
119
+
120
+ ## Events
121
+
122
+ - `input`: 输入变化时触发
123
+ - `update:value`: `v-model:value` 对应更新事件
124
+ - `warning`: 数值校验失败时触发,返回非法输入值
125
+ - `focus`: 聚焦时触发
126
+ - `blur`: 失焦时触发
127
+ - `change`: 值确认变化时触发
128
+ - `clear`: 点击清空按钮时触发
129
+
130
+ ## Slots
131
+
132
+ - `prefix`: 输入框前缀插槽
133
+ - `suffix`: 输入框后缀插槽,优先级高于 `suffixText`
134
+ - `prepend`: 前置内容插槽
135
+ - `append`: 后置内容插槽
136
+
137
+ ## Expose
138
+
139
+ - `focus`: 手动聚焦输入框
140
+ - `blur`: 手动失焦输入框
141
+ - `clear`: 手动清空输入框
142
+ - `select`: 选中当前输入内容
143
+ - `getInputRef`: 获取底层 `el-input` 实例
144
+
145
+ ## 透传规则
146
+
147
+ - 未被组件显式声明的属性,会自动透传给内部 `el-input`
148
+ - 适合继续传 `autosize`、`resize`、`rows`、`readonly` 等 Element Plus 原生能力
149
+
150
+ ## 推荐约定
151
+
152
+ - 新页面优先使用 `v-model:value`
153
+ - 需要浮动标签输入框时优先复用 `OutlinedInput`
154
+ - 数值输入优先使用 `isNumber + regex` 收敛基础校验,不要在页面层重复写相同逻辑
@@ -0,0 +1,10 @@
1
+ import OutlinedInput from './OutlinedInput.vue'
2
+
3
+ export default OutlinedInput
4
+
5
+ export type {
6
+ OutlinedInputCssValue,
7
+ OutlinedInputExpose,
8
+ OutlinedInputProps,
9
+ OutlinedInputValue
10
+ } from './OutlinedInput.types'
@@ -0,0 +1,48 @@
1
+ export type OutlinedSelectCssValue = string | number
2
+
3
+ export type OutlinedSelectOptionValue =
4
+ | string
5
+ | number
6
+ | boolean
7
+ | Record<string, unknown>
8
+ | null
9
+
10
+ export type OutlinedSelectValue = OutlinedSelectOptionValue | OutlinedSelectOptionValue[]
11
+
12
+ export interface OutlinedSelectOption {
13
+ label?: string
14
+ value?: OutlinedSelectOptionValue
15
+ disabled?: boolean
16
+ [key: string]: unknown
17
+ }
18
+
19
+ export interface OutlinedSelectProps {
20
+ value?: OutlinedSelectValue
21
+ options?: OutlinedSelectOption[]
22
+ placeholder?: string
23
+ label?: string
24
+ disabled?: boolean
25
+ typeInput?: string
26
+ showPassword?: boolean
27
+ collapseTags?: boolean
28
+ collapseTagsTooltip?: boolean
29
+ filterable?: boolean
30
+ clearable?: boolean
31
+ multiple?: boolean
32
+ inputHeight?: number
33
+ isBorder?: boolean
34
+ keyValue?: string
35
+ labelValue?: string
36
+ noCheck?: boolean
37
+ maxCollapseTags?: number
38
+ marginBottom?: OutlinedSelectCssValue
39
+ paddingTop?: OutlinedSelectCssValue
40
+ }
41
+
42
+ export interface OutlinedSelectExpose {
43
+ focus: () => void
44
+ blur: () => void
45
+ clear: () => void
46
+ toggleMenu: () => void
47
+ getSelectRef: () => unknown | null
48
+ }