@hbdlzy/ui-core 0.1.1 → 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 (35) hide show
  1. package/README.md +37 -2
  2. package/components.manifest.json +195 -163
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.js +1877 -13
  5. package/dist/style.css +1 -1
  6. package/package.json +2 -1
  7. package/src/components/OutlinedCascader/OutlinedCascader.types.ts +28 -0
  8. package/src/components/OutlinedCascader/OutlinedCascader.vue +250 -0
  9. package/src/components/OutlinedCascader/README.md +91 -0
  10. package/src/components/OutlinedCascader/index.ts +10 -0
  11. package/src/components/OutlinedDatePicker/OutlinedDatePicker.types.ts +40 -0
  12. package/src/components/OutlinedDatePicker/OutlinedDatePicker.vue +365 -0
  13. package/src/components/OutlinedDatePicker/README.md +137 -0
  14. package/src/components/OutlinedDatePicker/index.ts +11 -0
  15. package/src/components/OutlinedDateTimePicker/OutlinedDateTimePicker.types.ts +34 -0
  16. package/src/components/OutlinedDateTimePicker/OutlinedDateTimePicker.vue +421 -0
  17. package/src/components/OutlinedDateTimePicker/README.md +88 -0
  18. package/src/components/OutlinedDateTimePicker/index.ts +11 -0
  19. package/src/components/OutlinedInput/OutlinedInput.types.ts +32 -0
  20. package/src/components/OutlinedInput/OutlinedInput.vue +307 -0
  21. package/src/components/OutlinedInput/README.md +154 -0
  22. package/src/components/OutlinedInput/index.ts +10 -0
  23. package/src/components/OutlinedSelect/OutlinedSelect.types.ts +48 -0
  24. package/src/components/OutlinedSelect/OutlinedSelect.vue +359 -0
  25. package/src/components/OutlinedSelect/README.md +166 -0
  26. package/src/components/OutlinedSelect/index.ts +12 -0
  27. package/src/components/OutlinedTimePicker/OutlinedTimePicker.types.ts +36 -0
  28. package/src/components/OutlinedTimePicker/OutlinedTimePicker.vue +303 -0
  29. package/src/components/OutlinedTimePicker/README.md +93 -0
  30. package/src/components/OutlinedTimePicker/index.ts +10 -0
  31. package/src/components/OutlinedTreeSelect/OutlinedTreeSelect.types.ts +56 -0
  32. package/src/components/OutlinedTreeSelect/OutlinedTreeSelect.vue +354 -0
  33. package/src/components/OutlinedTreeSelect/README.md +107 -0
  34. package/src/components/OutlinedTreeSelect/index.ts +12 -0
  35. package/src/index.ts +14 -0
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .base-card[data-v-6bfddf1c]{display:flex;flex-direction:column;min-width:0;min-height:0;padding:var(--base-card-padding);border:1px solid var(--base-card-border-color);background:var(--base-card-background-color);box-shadow:0 0 2px 0 var(--base-card-shadow-color);border-radius:var(--base-card-radius)}.base-card__header[data-v-6bfddf1c]{display:flex;align-items:center;justify-content:space-between;gap:var(--base-card-header-gap);margin-bottom:var(--base-card-header-margin-bottom);min-height:24px;flex-wrap:wrap}.base-card__header-left[data-v-6bfddf1c],.base-card__header-right[data-v-6bfddf1c]{display:flex;align-items:center;min-width:0;flex-wrap:wrap}.base-card__header-left[data-v-6bfddf1c]{flex:1 1 auto;gap:var(--base-card-left-gap)}.base-card__header-right[data-v-6bfddf1c]{flex:0 1 auto;justify-content:flex-end;gap:var(--base-card-right-gap)}.base-card__title-wrap[data-v-6bfddf1c]{display:flex;align-items:center;min-width:0}.base-card__title-marker[data-v-6bfddf1c]{width:var(--base-card-marker-width);height:var(--base-card-marker-height);background:var(--base-card-marker-color);border-radius:var(--base-card-marker-radius);margin-right:var(--base-card-marker-gap);flex:0 0 auto}.base-card__title[data-v-6bfddf1c]{margin:0;min-width:0;color:var(--base-card-title-color);font-size:var(--base-card-title-size);font-weight:var(--base-card-title-weight);line-height:1.4;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.base-card__meta[data-v-6bfddf1c]{color:var(--base-card-meta-color);font-size:var(--base-card-meta-size);line-height:1.4}.base-card__export[data-v-6bfddf1c]{border:none;background:transparent;padding:0;color:var(--base-card-export-color);cursor:pointer;font-size:var(--base-card-meta-size);line-height:1.4}.base-card__export[data-v-6bfddf1c]:disabled{opacity:.5;cursor:not-allowed}.base-card__body[data-v-6bfddf1c]{display:flex;flex:1 1 auto;flex-direction:column;min-height:0}.base-card__tip[data-v-6bfddf1c]{flex:0 0 auto}.base-card__content[data-v-6bfddf1c]{flex:1 1 auto;min-height:0}.base-table[data-v-429ba785]{display:flex;flex-direction:column;height:100%;min-height:0}.base-table__toolbar[data-v-429ba785]{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:16px;min-height:32px;flex-wrap:wrap}.base-table__toolbar-left[data-v-429ba785]{flex:1 1 auto;min-width:0}.base-table__toolbar-right[data-v-429ba785]{flex:0 1 auto}.base-table__actions[data-v-429ba785]{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.base-table__link[data-v-429ba785]{padding:0;border:none;background:transparent;color:var(--el-color-primary);cursor:pointer}.base-table__text[data-v-429ba785]{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.base-table__tags[data-v-429ba785]{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.base-table__image[data-v-429ba785]{border-radius:4px;overflow:hidden}.base-echart[data-v-51bc4772],.base-echart__inner[data-v-51bc4772]{width:100%;height:100%}
1
+ .base-card[data-v-6bfddf1c]{display:flex;flex-direction:column;min-width:0;min-height:0;padding:var(--base-card-padding);border:1px solid var(--base-card-border-color);background:var(--base-card-background-color);box-shadow:0 0 2px 0 var(--base-card-shadow-color);border-radius:var(--base-card-radius)}.base-card__header[data-v-6bfddf1c]{display:flex;align-items:center;justify-content:space-between;gap:var(--base-card-header-gap);margin-bottom:var(--base-card-header-margin-bottom);min-height:24px;flex-wrap:wrap}.base-card__header-left[data-v-6bfddf1c],.base-card__header-right[data-v-6bfddf1c]{display:flex;align-items:center;min-width:0;flex-wrap:wrap}.base-card__header-left[data-v-6bfddf1c]{flex:1 1 auto;gap:var(--base-card-left-gap)}.base-card__header-right[data-v-6bfddf1c]{flex:0 1 auto;justify-content:flex-end;gap:var(--base-card-right-gap)}.base-card__title-wrap[data-v-6bfddf1c]{display:flex;align-items:center;min-width:0}.base-card__title-marker[data-v-6bfddf1c]{width:var(--base-card-marker-width);height:var(--base-card-marker-height);background:var(--base-card-marker-color);border-radius:var(--base-card-marker-radius);margin-right:var(--base-card-marker-gap);flex:0 0 auto}.base-card__title[data-v-6bfddf1c]{margin:0;min-width:0;color:var(--base-card-title-color);font-size:var(--base-card-title-size);font-weight:var(--base-card-title-weight);line-height:1.4;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.base-card__meta[data-v-6bfddf1c]{color:var(--base-card-meta-color);font-size:var(--base-card-meta-size);line-height:1.4}.base-card__export[data-v-6bfddf1c]{border:none;background:transparent;padding:0;color:var(--base-card-export-color);cursor:pointer;font-size:var(--base-card-meta-size);line-height:1.4}.base-card__export[data-v-6bfddf1c]:disabled{opacity:.5;cursor:not-allowed}.base-card__body[data-v-6bfddf1c]{display:flex;flex:1 1 auto;flex-direction:column;min-height:0}.base-card__tip[data-v-6bfddf1c]{flex:0 0 auto}.base-card__content[data-v-6bfddf1c]{flex:1 1 auto;min-height:0}.base-table[data-v-429ba785]{display:flex;flex-direction:column;height:100%;min-height:0}.base-table__toolbar[data-v-429ba785]{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:16px;min-height:32px;flex-wrap:wrap}.base-table__toolbar-left[data-v-429ba785]{flex:1 1 auto;min-width:0}.base-table__toolbar-right[data-v-429ba785]{flex:0 1 auto}.base-table__actions[data-v-429ba785]{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.base-table__link[data-v-429ba785]{padding:0;border:none;background:transparent;color:var(--el-color-primary);cursor:pointer}.base-table__text[data-v-429ba785]{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.base-table__tags[data-v-429ba785]{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.base-table__image[data-v-429ba785]{border-radius:4px;overflow:hidden}.base-echart[data-v-51bc4772],.base-echart__inner[data-v-51bc4772]{width:100%;height:100%}.outlined-input[data-v-2bf89ccd]{position:relative}.outlined-input__label[data-v-2bf89ccd]{position:absolute;left:-2px;padding:2px 5px;border-radius:2px;background-color:#fff;font-size:12px;line-height:1;transition:color .2s cubic-bezier(0,0,.2,1),transform .2s cubic-bezier(0,0,.2,1);pointer-events:none}.outlined-input__label--floating[data-v-2bf89ccd]{top:18px;z-index:1;opacity:1;transform:translate(14px,-6px) scale(1);color:var(--el-color-primary)}.outlined-input__label--placeholder[data-v-2bf89ccd]{top:50%;left:1px;z-index:-1;opacity:0;transform:translate(14px,6px) scale(1)}.outlined-input__label--filled[data-v-2bf89ccd]{color:var(--el-text-color-regular)}.outlined-input__suffix-text[data-v-2bf89ccd]{white-space:nowrap}[data-v-2bf89ccd] .outlined-input--bordered .el-input__wrapper{box-shadow:none;border-radius:0;border-bottom:1px solid #cccccc}[data-v-2bf89ccd] .outlined-input--bordered .el-input__wrapper.is-focus{border-bottom-color:var(--el-color-primary)}[data-v-2bf89ccd] .outlined-input--bordered .el-textarea__inner{border-width:0 0 1px;border-radius:0;box-shadow:none}[data-v-2bf89ccd] .outlined-input--bordered .el-textarea__inner:focus{border-bottom-color:var(--el-color-primary)}[data-v-2bf89ccd] .outlined-input--textarea-default .el-textarea__inner{min-height:100px!important;max-height:180px}.outlined-select[data-v-7bd2b5f2]{position:relative}.outlined-select__label[data-v-7bd2b5f2]{position:absolute;left:-2px;padding:2px 5px;border-radius:2px;background-color:#fff;font-size:12px;line-height:1;transition:color .2s cubic-bezier(0,0,.2,1),transform .2s cubic-bezier(0,0,.2,1);pointer-events:none}.outlined-select__label--floating[data-v-7bd2b5f2]{top:18px;z-index:1;opacity:1;transform:translate(14px,-6px) scale(1);color:var(--el-color-primary)}.outlined-select__label--placeholder[data-v-7bd2b5f2]{top:50%;left:1px;z-index:-1;opacity:0;transform:translate(14px,6px) scale(1)}.outlined-select__label--filled[data-v-7bd2b5f2]{color:var(--el-text-color-regular)}[data-v-7bd2b5f2] .outlined-select__control.el-select{width:100%}[data-v-7bd2b5f2] .outlined-select__control .el-select__wrapper{min-height:inherit;height:inherit}[data-v-7bd2b5f2] .outlined-select__control .el-select__tags{padding-top:4px}[data-v-7bd2b5f2] .outlined-select__control .el-select__selection{min-height:inherit}[data-v-7bd2b5f2] .outlined-select--bordered .el-select__wrapper{box-shadow:none;border-radius:0;border-bottom:1px solid #cccccc}[data-v-7bd2b5f2] .outlined-select--bordered .el-select__wrapper.is-focused{border-bottom-color:var(--el-color-primary)}.outlined-date-picker[data-v-c95a293c]{position:relative}.outlined-date-picker__label[data-v-c95a293c]{position:absolute;left:-2px;padding:2px 5px;border-radius:2px;background-color:#fff;font-size:12px;line-height:1;transition:color .2s cubic-bezier(0,0,.2,1),transform .2s cubic-bezier(0,0,.2,1);pointer-events:none}.outlined-date-picker__label--floating[data-v-c95a293c]{top:18px;z-index:1;opacity:1;transform:translate(14px,-6px) scale(1);color:var(--el-color-primary)}.outlined-date-picker__label--placeholder[data-v-c95a293c]{top:50%;left:1px;z-index:-1;opacity:0;transform:translate(14px,6px) scale(1)}.outlined-date-picker__label--filled[data-v-c95a293c]{color:var(--el-text-color-regular)}[data-v-c95a293c] .outlined-date-picker__control.el-date-editor{width:100%}[data-v-c95a293c] .outlined-date-picker__control .el-input__wrapper{position:relative;min-height:inherit;height:inherit}[data-v-c95a293c] .outlined-date-picker__control .el-input__prefix{position:absolute;right:0}[data-v-c95a293c] .outlined-date-picker__control .el-input__suffix{position:absolute;right:30px}[data-v-c95a293c] .outlined-date-picker--bordered .el-input__wrapper{box-shadow:none;border-radius:0;border-bottom:1px solid #cccccc}[data-v-c95a293c] .outlined-date-picker--bordered .el-input__wrapper.is-focus{border-bottom-color:var(--el-color-primary)}.outlined-date-time-picker[data-v-f2fefd22]{display:flex;align-items:center;gap:8px}.outlined-date-time-picker__field[data-v-f2fefd22]{position:relative;flex:1}.outlined-date-time-picker__separator[data-v-f2fefd22]{flex:0 0 auto;color:var(--el-text-color-regular)}.outlined-date-time-picker__label[data-v-f2fefd22]{position:absolute;left:-2px;padding:2px 5px;border-radius:2px;background-color:#fff;font-size:12px;line-height:1;transition:color .2s cubic-bezier(0,0,.2,1),transform .2s cubic-bezier(0,0,.2,1);pointer-events:none}.outlined-date-time-picker__label--floating[data-v-f2fefd22]{top:18px;z-index:1;opacity:1;transform:translate(14px,-6px) scale(1);color:var(--el-color-primary)}.outlined-date-time-picker__label--placeholder[data-v-f2fefd22]{top:50%;left:1px;z-index:-1;opacity:0;transform:translate(14px,6px) scale(1)}.outlined-date-time-picker__label--filled[data-v-f2fefd22]{color:var(--el-text-color-regular)}[data-v-f2fefd22] .outlined-date-time-picker__control.el-date-editor{width:100%}[data-v-f2fefd22] .outlined-date-time-picker__control .el-input__wrapper{position:relative;min-height:inherit;height:inherit}[data-v-f2fefd22] .outlined-date-time-picker__control .el-input__prefix{position:absolute;right:0}[data-v-f2fefd22] .outlined-date-time-picker__control .el-input__suffix{position:absolute;right:30px}[data-v-f2fefd22] .outlined-date-time-picker__field--bordered .el-input__wrapper{box-shadow:none;border-radius:0;border-bottom:1px solid #cccccc}[data-v-f2fefd22] .outlined-date-time-picker__field--bordered .el-input__wrapper.is-focus{border-bottom-color:var(--el-color-primary)}.outlined-time-picker[data-v-6a467b88]{position:relative}.outlined-time-picker__label[data-v-6a467b88]{position:absolute;left:-2px;padding:2px 5px;border-radius:2px;background-color:#fff;font-size:12px;line-height:1;transition:color .2s cubic-bezier(0,0,.2,1),transform .2s cubic-bezier(0,0,.2,1);pointer-events:none}.outlined-time-picker__label--floating[data-v-6a467b88]{top:18px;z-index:1;opacity:1;transform:translate(14px,-6px) scale(1);color:var(--el-color-primary)}.outlined-time-picker__label--placeholder[data-v-6a467b88]{top:50%;left:1px;z-index:-1;opacity:0;transform:translate(14px,6px) scale(1)}.outlined-time-picker__label--filled[data-v-6a467b88]{color:var(--el-text-color-regular)}[data-v-6a467b88] .outlined-time-picker__control.el-date-editor{width:100%}[data-v-6a467b88] .outlined-time-picker__control .el-input__wrapper{position:relative;min-height:inherit;height:inherit}[data-v-6a467b88] .outlined-time-picker__control .el-input__prefix{position:absolute;right:0}[data-v-6a467b88] .outlined-time-picker__control .el-input__suffix{position:absolute;right:30px}[data-v-6a467b88] .outlined-time-picker--bordered .el-input__wrapper{box-shadow:none;border-radius:0;border-bottom:1px solid #cccccc}[data-v-6a467b88] .outlined-time-picker--bordered .el-input__wrapper.is-focus{border-bottom-color:var(--el-color-primary)}.outlined-cascader[data-v-2c93c0e4]{position:relative}.outlined-cascader__label[data-v-2c93c0e4]{position:absolute;left:-2px;padding:2px 5px;border-radius:2px;background-color:#fff;font-size:12px;line-height:1;transition:color .2s cubic-bezier(0,0,.2,1),transform .2s cubic-bezier(0,0,.2,1);pointer-events:none}.outlined-cascader__label--floating[data-v-2c93c0e4]{top:18px;z-index:1;opacity:1;transform:translate(14px,-6px) scale(1);color:var(--el-color-primary)}.outlined-cascader__label--placeholder[data-v-2c93c0e4]{top:50%;left:1px;z-index:-1;opacity:0;transform:translate(14px,6px) scale(1)}.outlined-cascader__label--filled[data-v-2c93c0e4]{color:var(--el-text-color-regular)}[data-v-2c93c0e4] .outlined-cascader__control .el-input{height:100%}[data-v-2c93c0e4] .outlined-cascader--bordered .el-input__wrapper{box-shadow:none;border-radius:0;border-bottom:1px solid #cccccc}[data-v-2c93c0e4] .outlined-cascader--bordered .el-input__wrapper.is-focus{border-bottom-color:var(--el-color-primary)}.outlined-tree-select[data-v-8403e6ea]{position:relative}.outlined-tree-select__label[data-v-8403e6ea]{position:absolute;left:-2px;padding:2px 5px;border-radius:2px;background-color:#fff;font-size:12px;line-height:1;transition:color .2s cubic-bezier(0,0,.2,1),transform .2s cubic-bezier(0,0,.2,1);pointer-events:none}.outlined-tree-select__label--floating[data-v-8403e6ea]{top:18px;z-index:1;opacity:1;transform:translate(14px,-6px) scale(1);color:var(--el-color-primary)}.outlined-tree-select__label--placeholder[data-v-8403e6ea]{top:50%;left:1px;z-index:-1;opacity:0;transform:translate(14px,6px) scale(1)}.outlined-tree-select__label--filled[data-v-8403e6ea]{color:var(--el-text-color-regular)}[data-v-8403e6ea] .outlined-tree-select__control.el-select{width:100%}[data-v-8403e6ea] .outlined-tree-select__control .el-select__wrapper{min-height:inherit;height:inherit}[data-v-8403e6ea] .outlined-tree-select__control .el-select__selection{min-height:inherit}[data-v-8403e6ea] .outlined-tree-select__control .el-select__tags{padding-top:4px}[data-v-8403e6ea] .outlined-tree-select--bordered .el-select__wrapper{box-shadow:none;border-radius:0;border-bottom:1px solid #cccccc}[data-v-8403e6ea] .outlined-tree-select--bordered .el-select__wrapper.is-focused{border-bottom-color:var(--el-color-primary)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hbdlzy/ui-core",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Company shared Vue UI core package.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -30,6 +30,7 @@
30
30
  "vue": "^3.5.14"
31
31
  },
32
32
  "dependencies": {
33
+ "dayjs": "^1.11.13",
33
34
  "echarts": "^5.5.1",
34
35
  "exceljs": "^4.4.0",
35
36
  "file-saver": "2.0.5"
@@ -0,0 +1,28 @@
1
+ export type OutlinedCascaderCssValue = string | number
2
+
3
+ export type OutlinedCascaderValue = Array<string | number>
4
+
5
+ export interface OutlinedCascaderProps {
6
+ value?: OutlinedCascaderValue
7
+ options?: Record<string, unknown>[]
8
+ clearable?: boolean
9
+ propsValue?: Record<string, unknown>
10
+ placeholder?: string
11
+ label?: string
12
+ popperClass?: string
13
+ disabled?: boolean
14
+ inputHeight?: number
15
+ isBorder?: boolean
16
+ filterable?: boolean
17
+ levels?: boolean
18
+ marginBottom?: OutlinedCascaderCssValue
19
+ paddingTop?: OutlinedCascaderCssValue
20
+ }
21
+
22
+ export interface OutlinedCascaderExpose {
23
+ focus: () => void
24
+ blur: () => void
25
+ togglePopperVisible: () => void
26
+ clear: () => void
27
+ getCascaderRef: () => unknown | null
28
+ }
@@ -0,0 +1,250 @@
1
+ <template>
2
+ <div
3
+ class="outlined-cascader"
4
+ :class="[containerClasses, rootClass]"
5
+ :style="[containerStyle, rootStyle]"
6
+ >
7
+ <el-cascader
8
+ ref="cascaderRef"
9
+ v-bind="cascaderAttrs"
10
+ class="outlined-cascader__control"
11
+ :model-value="cascaderValue"
12
+ :options="options"
13
+ :props="propsValue"
14
+ :clearable="clearable"
15
+ :placeholder="placeholder"
16
+ :filterable="filterable"
17
+ :show-all-levels="levels"
18
+ :disabled="disabled"
19
+ :popper-class="popperClass"
20
+ :style="cascaderStyle"
21
+ @update:model-value="handleModelValueUpdate"
22
+ @focus="handleFocus"
23
+ @blur="handleBlur"
24
+ @change="handleChange"
25
+ @visible-change="handleVisibleChange"
26
+ />
27
+
28
+ <div
29
+ v-if="floatingLabel"
30
+ class="outlined-cascader__label"
31
+ :class="labelClasses"
32
+ >
33
+ {{ floatingLabel }}
34
+ </div>
35
+ </div>
36
+ </template>
37
+
38
+ <script setup lang="ts">
39
+ import { computed, ref, useAttrs, watch } from 'vue'
40
+ import type {
41
+ OutlinedCascaderCssValue,
42
+ OutlinedCascaderExpose,
43
+ OutlinedCascaderProps,
44
+ OutlinedCascaderValue
45
+ } from './OutlinedCascader.types'
46
+
47
+ defineOptions({
48
+ name: 'OutlinedCascader',
49
+ inheritAttrs: false
50
+ })
51
+
52
+ const props = withDefaults(defineProps<OutlinedCascaderProps>(), {
53
+ value: () => [],
54
+ options: () => [],
55
+ clearable: false,
56
+ propsValue: undefined,
57
+ placeholder: '',
58
+ label: '',
59
+ popperClass: '',
60
+ disabled: false,
61
+ inputHeight: 40,
62
+ isBorder: false,
63
+ filterable: true,
64
+ levels: true,
65
+ marginBottom: 20,
66
+ paddingTop: 20
67
+ })
68
+
69
+ const emit = defineEmits<{
70
+ (event: 'input', value: OutlinedCascaderValue): void
71
+ (event: 'update:value', value: OutlinedCascaderValue): void
72
+ (event: 'change', value: OutlinedCascaderValue): void
73
+ (event: 'focus', value: FocusEvent): void
74
+ (event: 'blur', value: FocusEvent): void
75
+ (event: 'visible-change', value: boolean): void
76
+ }>()
77
+
78
+ const attrs = useAttrs()
79
+ const cascaderRef = ref<any>(null)
80
+ const cascaderValue = ref<OutlinedCascaderValue>(normalizeValue(props.value))
81
+ const focused = ref(false)
82
+ const blurred = ref(false)
83
+ const visible = ref(false)
84
+
85
+ watch(
86
+ () => props.value,
87
+ (value) => {
88
+ cascaderValue.value = normalizeValue(value)
89
+ },
90
+ { immediate: true }
91
+ )
92
+
93
+ const rootClass = computed(() => attrs.class)
94
+ const rootStyle = computed(() => attrs.style)
95
+
96
+ const cascaderAttrs = computed(() => {
97
+ const { class: _class, style: _style, ...rest } = attrs
98
+ return rest
99
+ })
100
+
101
+ const containerClasses = computed(() => ({
102
+ 'outlined-cascader--bordered': props.isBorder
103
+ }))
104
+
105
+ const containerStyle = computed(() => ({
106
+ marginBottom: toCssValue(props.marginBottom),
107
+ paddingTop: toCssValue(props.paddingTop)
108
+ }))
109
+
110
+ const cascaderStyle = computed(() => ({
111
+ width: '100%',
112
+ height: `${props.inputHeight}px`
113
+ }))
114
+
115
+ const floatingLabel = computed(() => props.label || props.placeholder || '')
116
+
117
+ const hasContent = computed(() => cascaderValue.value.length > 0)
118
+
119
+ const labelClasses = computed(() => ({
120
+ 'outlined-cascader__label--floating': focused.value || hasContent.value,
121
+ 'outlined-cascader__label--placeholder': !focused.value && !hasContent.value,
122
+ 'outlined-cascader__label--filled': hasContent.value && !focused.value
123
+ }))
124
+
125
+ function handleModelValueUpdate(value: OutlinedCascaderValue) {
126
+ const normalizedValue = normalizeValue(value)
127
+ cascaderValue.value = normalizedValue
128
+ emitModelValue(normalizedValue)
129
+ }
130
+
131
+ function handleChange(value: OutlinedCascaderValue) {
132
+ const normalizedValue = normalizeValue(value)
133
+ cascaderValue.value = normalizedValue
134
+ emit('change', normalizedValue)
135
+ }
136
+
137
+ function handleFocus(event: FocusEvent) {
138
+ blurred.value = false
139
+ focused.value = true
140
+ emit('focus', event)
141
+ }
142
+
143
+ function handleBlur(event: FocusEvent) {
144
+ blurred.value = true
145
+
146
+ if (!visible.value) {
147
+ focused.value = false
148
+ emitModelValue(cascaderValue.value)
149
+ }
150
+
151
+ emit('blur', event)
152
+ }
153
+
154
+ function handleVisibleChange(nextVisible: boolean) {
155
+ visible.value = nextVisible
156
+
157
+ if (!nextVisible && blurred.value) {
158
+ focused.value = false
159
+ }
160
+
161
+ emit('visible-change', nextVisible)
162
+ }
163
+
164
+ function emitModelValue(value: OutlinedCascaderValue) {
165
+ emit('input', value)
166
+ emit('update:value', value)
167
+ }
168
+
169
+ function normalizeValue(value: OutlinedCascaderValue | undefined) {
170
+ return Array.isArray(value) ? value : []
171
+ }
172
+
173
+ function toCssValue(value: OutlinedCascaderCssValue | undefined) {
174
+ if (typeof value === 'number') {
175
+ return `${value}px`
176
+ }
177
+
178
+ return value
179
+ }
180
+
181
+ defineExpose<OutlinedCascaderExpose>({
182
+ focus: () => {
183
+ cascaderRef.value?.togglePopperVisible?.(true)
184
+ },
185
+ blur: () => {
186
+ cascaderRef.value?.togglePopperVisible?.(false)
187
+ },
188
+ togglePopperVisible: () => {
189
+ cascaderRef.value?.togglePopperVisible?.()
190
+ },
191
+ clear: () => {
192
+ cascaderValue.value = []
193
+ emitModelValue([])
194
+ emit('change', [])
195
+ },
196
+ getCascaderRef: () => cascaderRef.value
197
+ })
198
+ </script>
199
+
200
+ <style scoped>
201
+ .outlined-cascader {
202
+ position: relative;
203
+ }
204
+
205
+ .outlined-cascader__label {
206
+ position: absolute;
207
+ left: -2px;
208
+ padding: 2px 5px;
209
+ border-radius: 2px;
210
+ background-color: #ffffff;
211
+ font-size: 12px;
212
+ line-height: 1;
213
+ transition: color 200ms cubic-bezier(0, 0, 0.2, 1), transform 200ms cubic-bezier(0, 0, 0.2, 1);
214
+ pointer-events: none;
215
+ }
216
+
217
+ .outlined-cascader__label--floating {
218
+ top: 18px;
219
+ z-index: 1;
220
+ opacity: 1;
221
+ transform: translate(14px, -6px) scale(1);
222
+ color: var(--el-color-primary);
223
+ }
224
+
225
+ .outlined-cascader__label--placeholder {
226
+ top: 50%;
227
+ left: 1px;
228
+ z-index: -1;
229
+ opacity: 0;
230
+ transform: translate(14px, 6px) scale(1);
231
+ }
232
+
233
+ .outlined-cascader__label--filled {
234
+ color: var(--el-text-color-regular);
235
+ }
236
+
237
+ :deep(.outlined-cascader__control .el-input) {
238
+ height: 100%;
239
+ }
240
+
241
+ :deep(.outlined-cascader--bordered .el-input__wrapper) {
242
+ box-shadow: none;
243
+ border-radius: 0;
244
+ border-bottom: 1px solid #cccccc;
245
+ }
246
+
247
+ :deep(.outlined-cascader--bordered .el-input__wrapper.is-focus) {
248
+ border-bottom-color: var(--el-color-primary);
249
+ }
250
+ </style>
@@ -0,0 +1,91 @@
1
+ # OutlinedCascader
2
+
3
+ `OutlinedCascader` 是 `OutlinedForm` 系列里的级联选择控件,用来统一封装浮动标签、边框风格、级联面板显隐和实例方法暴露。
4
+
5
+ ## 适用场景
6
+
7
+ - 页面里经常出现区域、组织、站点树这类级联选择
8
+ - 需要统一 `el-cascader` 的浮动标签样式
9
+ - 需要在页面层直接打开或关闭级联面板
10
+ - 需要统一 `props` 映射、`clearable`、`filterable` 等高频配置
11
+
12
+ ## 基本用法
13
+
14
+ ```vue
15
+ <script setup lang="ts">
16
+ import { ref } from 'vue'
17
+ import { OutlinedCascader, type OutlinedCascaderExpose } from '@hbdlzy/ui'
18
+
19
+ const cascaderRef = ref<OutlinedCascaderExpose | null>(null)
20
+ const areaPath = ref<Array<string | number>>([])
21
+
22
+ const areaOptions = [
23
+ {
24
+ label: '华北',
25
+ value: 'north',
26
+ children: [
27
+ { label: '北京', value: 'beijing' },
28
+ { label: '天津', value: 'tianjin' }
29
+ ]
30
+ }
31
+ ]
32
+ </script>
33
+
34
+ <template>
35
+ <OutlinedCascader
36
+ ref="cascaderRef"
37
+ v-model:value="areaPath"
38
+ placeholder="所属区域"
39
+ :options="areaOptions"
40
+ :is-border="true"
41
+ clearable
42
+ filterable
43
+ />
44
+ </template>
45
+ ```
46
+
47
+ ## Props
48
+
49
+ | 属性 | 类型 | 默认值 | 说明 |
50
+ | --- | --- | --- | --- |
51
+ | `value` | `Array<string \| number>` | `[]` | `v-model:value` 绑定值 |
52
+ | `options` | `Record<string, unknown>[]` | `[]` | 级联选项数据 |
53
+ | `clearable` | `boolean` | `false` | 是否允许清空 |
54
+ | `propsValue` | `Record<string, unknown>` | `undefined` | 透传给 `el-cascader` 的 `props` |
55
+ | `placeholder` | `string` | `''` | 占位文案,也会作为浮动标签文案 |
56
+ | `label` | `string` | `''` | 自定义浮动标签文案,优先级高于 `placeholder` |
57
+ | `popperClass` | `string` | `''` | 自定义弹层类名 |
58
+ | `disabled` | `boolean` | `false` | 是否禁用 |
59
+ | `inputHeight` | `number` | `40` | 输入框高度 |
60
+ | `isBorder` | `boolean` | `false` | 是否启用下边框风格 |
61
+ | `filterable` | `boolean` | `true` | 是否允许搜索 |
62
+ | `levels` | `boolean` | `true` | 是否展示完整级联路径 |
63
+ | `marginBottom` | `string \| number` | `20` | 外层下边距 |
64
+ | `paddingTop` | `string \| number` | `20` | 外层上内边距,用于浮动标签留白 |
65
+
66
+ ## Emits
67
+
68
+ | 事件 | 参数 | 说明 |
69
+ | --- | --- | --- |
70
+ | `input` | `Array<string \| number>` | 输入值变化时触发 |
71
+ | `update:value` | `Array<string \| number>` | `v-model:value` 同步事件 |
72
+ | `change` | `Array<string \| number>` | 选项确认变化时触发 |
73
+ | `focus` | `FocusEvent` | 聚焦时触发 |
74
+ | `blur` | `FocusEvent` | 失焦时触发 |
75
+ | `visible-change` | `boolean` | 级联面板显隐变化时触发 |
76
+
77
+ ## Expose
78
+
79
+ | 方法 | 说明 |
80
+ | --- | --- |
81
+ | `focus()` | 打开级联面板 |
82
+ | `blur()` | 关闭级联面板 |
83
+ | `togglePopperVisible()` | 切换级联面板显隐 |
84
+ | `clear()` | 清空当前值 |
85
+ | `getCascaderRef()` | 获取内部 `el-cascader` 实例 |
86
+
87
+ ## 设计约束
88
+
89
+ - 组件只负责通用级联选择壳子和交互状态,不直接耦合区域接口、组织树接口等业务数据源
90
+ - 页面层如果需要多选级联、懒加载或复杂回填逻辑,优先先通过 `propsValue` 和插值配置解决
91
+ - 如果业务需要固定某种树结构,可以在业务包里再封一层领域组件,而不是反向污染 `ui-core`
@@ -0,0 +1,10 @@
1
+ import OutlinedCascader from './OutlinedCascader.vue'
2
+
3
+ export default OutlinedCascader
4
+
5
+ export type {
6
+ OutlinedCascaderCssValue,
7
+ OutlinedCascaderExpose,
8
+ OutlinedCascaderProps,
9
+ OutlinedCascaderValue
10
+ } from './OutlinedCascader.types'
@@ -0,0 +1,40 @@
1
+ export type OutlinedDatePickerCssValue = string | number
2
+
3
+ export type OutlinedDatePickerValue =
4
+ | string
5
+ | number
6
+ | Date
7
+ | Array<string | number | Date>
8
+ | null
9
+
10
+ export type OutlinedDatePickerDisabledDate =
11
+ | string
12
+ | number
13
+ | Date
14
+ | ((date: Date) => boolean)
15
+
16
+ export interface OutlinedDatePickerProps {
17
+ value?: OutlinedDatePickerValue
18
+ placeholder?: string
19
+ label?: string
20
+ disabled?: boolean
21
+ timeValue?: boolean
22
+ typeDate?: string
23
+ format?: string
24
+ valueFormat?: string
25
+ showPassword?: boolean
26
+ multiple?: boolean
27
+ inputHeight?: number
28
+ isBorder?: boolean
29
+ disabledDate?: OutlinedDatePickerDisabledDate
30
+ marginBottom?: OutlinedDatePickerCssValue
31
+ paddingTop?: OutlinedDatePickerCssValue
32
+ }
33
+
34
+ export interface OutlinedDatePickerExpose {
35
+ focus: () => void
36
+ blur: () => void
37
+ handleOpen: () => void
38
+ handleClose: () => void
39
+ getPickerRef: () => unknown | null
40
+ }