@hbdlzy/ui-core 0.1.6 → 0.1.7

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.
@@ -199,9 +199,9 @@ const resultAdapter = (result: any) => {
199
199
 
200
200
  如果接口参数结构更特殊,可以改用 `sortMapper`。
201
201
 
202
- ## 表头列搜索
202
+ ## 表头列搜索 / 筛选
203
203
 
204
- `BaseTable` 现在支持列头搜索能力,用法和旧 `TableComponent.vue` 里的 `isSearch` 很接近,但配置方式更收敛。
204
+ `BaseTable` 现在支持列头输入搜索、下拉筛选、多选下拉和级联筛选能力,用法和旧 `TableComponent.vue` 里的 `isSearch` 很接近,但配置方式更收敛。
205
205
 
206
206
  ### 基础写法
207
207
 
@@ -217,7 +217,7 @@ const columns = [
217
217
 
218
218
  开启后,这一列的表头会出现搜索图标,点击后会弹出输入框,并提供“搜索 / 重置”操作。
219
219
 
220
- ### 高级写法
220
+ ### 输入框高级写法
221
221
 
222
222
  ```ts
223
223
  const columns = [
@@ -235,13 +235,94 @@ const columns = [
235
235
  ]
236
236
  ```
237
237
 
238
+ ### 下拉筛选写法
239
+
240
+ ```ts
241
+ const columns = [
242
+ {
243
+ label: '状态',
244
+ prop: 'status',
245
+ kind: 'tag',
246
+ options: [
247
+ { label: '启用', value: 'enabled', tagType: 'success' },
248
+ { label: '停用', value: 'disabled', tagType: 'info' }
249
+ ],
250
+ headerSearch: {
251
+ type: 'select',
252
+ placeholder: '请选择状态',
253
+ width: 220,
254
+ searchText: '筛选'
255
+ }
256
+ }
257
+ ]
258
+ ```
259
+
260
+ 下拉筛选默认复用当前列的 `options`,也可以在 `headerSearch.options` 中单独传入选项。需要多选时可以配置 `multiple: true`,请求参数会以数组形式传出。
261
+
262
+ ### 多选下拉筛选写法
263
+
264
+ ```ts
265
+ const columns = [
266
+ {
267
+ label: '资讯分类',
268
+ prop: 'categories',
269
+ kind: 'tag',
270
+ options: [
271
+ { label: '市场资讯', value: 'market', tagType: 'primary' },
272
+ { label: '运行日报', value: 'operation', tagType: 'success' }
273
+ ],
274
+ headerSearch: {
275
+ type: 'select',
276
+ multiple: true,
277
+ placeholder: '请选择分类',
278
+ searchText: '筛选'
279
+ }
280
+ }
281
+ ]
282
+ ```
283
+
284
+ 多选下拉会在面板里保留展开状态,方便连续选择多个选项;点击“筛选”后请求参数形如 `{ categories: ['market', 'operation'] }`。
285
+
286
+ ### 级联下拉筛选写法
287
+
288
+ ```ts
289
+ const columns = [
290
+ {
291
+ label: '所在区域',
292
+ prop: 'regionPath',
293
+ headerSearch: {
294
+ type: 'cascader',
295
+ placeholder: '请选择区域',
296
+ width: 420,
297
+ options: [
298
+ {
299
+ label: '华北',
300
+ value: 'north',
301
+ children: [
302
+ {
303
+ label: '北京',
304
+ value: 'beijing',
305
+ children: [
306
+ { label: '朝阳区', value: 'chaoyang' }
307
+ ]
308
+ }
309
+ ]
310
+ }
311
+ ]
312
+ }
313
+ }
314
+ ]
315
+ ```
316
+
317
+ 级联筛选默认使用 `children` 作为子级字段,可以通过 `optionChildrenKey` 改写;请求参数会以完整路径数组传出,例如 `{ regionPath: ['north', 'beijing', 'chaoyang'] }`。
318
+
238
319
  ### 行为说明
239
320
 
240
321
  - 远程模式下,列头搜索值会自动合并到 `request(params)` 的参数里
241
322
  - 触发搜索或重置时,会自动把页码重置到第一页
242
323
  - 如果配置了 `paramKey`,请求参数会优先使用它
243
324
  - 如果没有配置 `paramKey`,默认使用当前列的 `prop`
244
- - 本地数据模式下,列头搜索会对当前 `data` 做简单文本包含过滤
325
+ - 本地数据模式下,输入搜索会对当前 `data` 做简单文本包含过滤,下拉筛选会按选项值精确匹配,级联筛选会按路径前缀匹配
245
326
  - 多个开启搜索的列会按“同时满足”处理
246
327
 
247
328
  示例请求参数:
@@ -250,7 +331,8 @@ const columns = [
250
331
  {
251
332
  currentPage: 1,
252
333
  pageSize: 20,
253
- owner: '张三'
334
+ owner: '张三',
335
+ status: 'enabled'
254
336
  }
255
337
  ```
256
338
 
@@ -362,6 +444,7 @@ const columns = [
362
444
 
363
445
  ```ts
364
446
  tableRef.value?.setHeaderSearchValue('owner', '张三')
447
+ tableRef.value?.setHeaderSearchValue('status', 'enabled')
365
448
  tableRef.value?.resetHeaderSearch()
366
449
  ```
367
450
 
@@ -10,6 +10,11 @@ export type {
10
10
  BaseTableColumnKind,
11
11
  BaseTableCssValue,
12
12
  BaseTableExpose,
13
+ BaseTableHeaderSearchConfig,
14
+ BaseTableHeaderSearchPathValue,
15
+ BaseTableHeaderSearchPrimitiveValue,
16
+ BaseTableHeaderSearchType,
17
+ BaseTableHeaderSearchValue,
13
18
  BaseTableLoadedPayload,
14
19
  BaseTableNormalizedResult,
15
20
  BaseTableOption,
@@ -0,0 +1,53 @@
1
+ # SvgIcon
2
+
3
+ `SvgIcon` 用来展示 SVG symbol sprite 或外链 SVG,兼容旧项目里 `<svg-icon icon-class="xxx" class-name="xxx" />` 的写法。
4
+
5
+ ## 解决的问题
6
+
7
+ - 统一 SVG 图标展示入口
8
+ - 支持 `#icon-xxx` 形式的 symbol 引用
9
+ - 支持 http、data、blob 等外链 SVG 通过 mask 渲染为 `currentColor`
10
+ - 自动去掉 `iconClass` 首尾空格,兼容旧模板里误带空格的图标名
11
+
12
+ ## 基础用法
13
+
14
+ ```vue
15
+ <template>
16
+ <SvgIcon
17
+ icon-class="filter"
18
+ class-name="table-search-icon"
19
+ />
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { SvgIcon } from '@hbdlzy/ui-core'
24
+ </script>
25
+ ```
26
+
27
+ 上面的写法会渲染 `<use href="#icon-filter" />`。页面或项目需要自行通过 SVG sprite 注入 `symbol id="icon-filter"`。
28
+
29
+ ## 外链 SVG
30
+
31
+ ```vue
32
+ <template>
33
+ <SvgIcon
34
+ :icon-class="externalSvgUrl"
35
+ class-name="status-icon"
36
+ />
37
+ </template>
38
+ ```
39
+
40
+ 外链模式会使用 CSS mask 渲染,图标颜色继承父级 `color`。
41
+
42
+ ## Props
43
+
44
+ - `iconClass`: 图标名或外链 SVG 地址,必填
45
+ - `className`: 追加到根节点的类名
46
+ - `prefix`: symbol 前缀,默认 `icon`,最终引用为 `#${prefix}-${iconClass}`
47
+ - `ariaLabel`: 无障碍标签,未传时图标默认 `aria-hidden="true"`
48
+
49
+ ## 推荐约定
50
+
51
+ - symbol sprite 的 id 统一使用 `icon-xxx`
52
+ - 需要调色时通过父级或 `className` 设置 `color`
53
+ - 业务项目如果已经有 `svg-sprite-loader` 或 Vite SVG sprite 插件,可继续复用原有注入方式
@@ -0,0 +1,6 @@
1
+ export interface SvgIconProps {
2
+ iconClass: string
3
+ className?: string
4
+ prefix?: string
5
+ ariaLabel?: string
6
+ }
@@ -0,0 +1,68 @@
1
+ <template>
2
+ <span
3
+ v-if="isExternal"
4
+ class="svg-external-icon svg-icon"
5
+ :class="className"
6
+ :style="externalIconStyle"
7
+ :aria-hidden="ariaHidden"
8
+ :aria-label="ariaLabel"
9
+ role="img"
10
+ />
11
+ <svg
12
+ v-else
13
+ class="svg-icon"
14
+ :class="className"
15
+ :aria-hidden="ariaHidden"
16
+ :aria-label="ariaLabel"
17
+ role="img"
18
+ >
19
+ <use
20
+ :href="iconName"
21
+ :xlink:href="iconName"
22
+ />
23
+ </svg>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { computed } from 'vue'
28
+ import type { CSSProperties } from 'vue'
29
+ import type { SvgIconProps } from './SvgIcon.types'
30
+
31
+ defineOptions({
32
+ name: 'SvgIcon'
33
+ })
34
+
35
+ const props = withDefaults(defineProps<SvgIconProps>(), {
36
+ className: '',
37
+ prefix: 'icon',
38
+ ariaLabel: ''
39
+ })
40
+
41
+ const normalizedIconClass = computed(() => props.iconClass.trim())
42
+ const normalizedPrefix = computed(() => props.prefix.trim() || 'icon')
43
+ const isExternal = computed(() => /^(https?:|mailto:|tel:|data:|blob:)/.test(normalizedIconClass.value))
44
+ const iconName = computed(() => `#${normalizedPrefix.value}-${normalizedIconClass.value}`)
45
+ const ariaHidden = computed(() => props.ariaLabel ? undefined : 'true')
46
+
47
+ const externalIconStyle = computed<CSSProperties>(() => ({
48
+ mask: `url(${normalizedIconClass.value}) no-repeat 50% 50%`,
49
+ WebkitMask: `url(${normalizedIconClass.value}) no-repeat 50% 50%`
50
+ }))
51
+ </script>
52
+
53
+ <style scoped>
54
+ .svg-icon {
55
+ width: 1em;
56
+ height: 1em;
57
+ vertical-align: -0.15em;
58
+ fill: currentColor;
59
+ overflow: hidden;
60
+ }
61
+
62
+ .svg-external-icon {
63
+ display: inline-block;
64
+ background-color: currentColor;
65
+ mask-size: cover !important;
66
+ -webkit-mask-size: cover !important;
67
+ }
68
+ </style>
@@ -0,0 +1,5 @@
1
+ import SvgIcon from './SvgIcon.vue'
2
+
3
+ export default SvgIcon
4
+
5
+ export type { SvgIconProps } from './SvgIcon.types'
package/src/index.ts CHANGED
@@ -19,6 +19,8 @@ export { default as BaseEChart } from './components/BaseEChart'
19
19
  export * from './components/BaseEChart'
20
20
  export { default as BaseExportButton } from './components/BaseExportButton'
21
21
  export * from './components/BaseExportButton'
22
+ export { default as SvgIcon } from './components/SvgIcon'
23
+ export * from './components/SvgIcon'
22
24
  export { default as OutlinedInput } from './components/OutlinedInput'
23
25
  export * from './components/OutlinedInput'
24
26
  export { default as OutlinedSelect } from './components/OutlinedSelect'