@hbdlzy/ui-core 0.1.2 → 0.1.4

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 (64) hide show
  1. package/components.manifest.json +40 -1
  2. package/dist/components/BaseCard/BaseCard.types.d.ts +36 -0
  3. package/dist/components/BaseCard/BaseCard.vue.d.ts +122 -0
  4. package/dist/components/BaseCard/index.d.ts +3 -0
  5. package/dist/components/BaseDialog/BaseDialog.types.d.ts +25 -0
  6. package/dist/components/BaseDialog/BaseDialog.vue.d.ts +100 -0
  7. package/dist/components/BaseDialog/index.d.ts +3 -0
  8. package/dist/components/BaseEChart/BaseEChart.types.d.ts +26 -0
  9. package/dist/components/BaseEChart/BaseEChart.vue.d.ts +66 -0
  10. package/dist/components/BaseEChart/index.d.ts +3 -0
  11. package/dist/components/BaseExportButton/BaseExportButton.types.d.ts +21 -0
  12. package/dist/components/BaseExportButton/BaseExportButton.utils.d.ts +4 -0
  13. package/dist/components/BaseExportButton/BaseExportButton.vue.d.ts +128 -0
  14. package/dist/components/BaseExportButton/index.d.ts +5 -0
  15. package/dist/components/BaseSearchForm/BaseSearchForm.types.d.ts +42 -0
  16. package/dist/components/BaseSearchForm/BaseSearchForm.utils.d.ts +5 -0
  17. package/dist/components/BaseSearchForm/BaseSearchForm.vue.d.ts +88 -0
  18. package/dist/components/BaseSearchForm/index.d.ts +4 -0
  19. package/dist/components/BaseTable/BaseTable.types.d.ts +163 -0
  20. package/dist/components/BaseTable/BaseTable.vue.d.ts +157 -0
  21. package/dist/components/BaseTable/index.d.ts +3 -0
  22. package/dist/components/OutlinedCascader/OutlinedCascader.types.d.ts +25 -0
  23. package/dist/components/OutlinedCascader/OutlinedCascader.vue.d.ts +85 -0
  24. package/dist/components/OutlinedCascader/index.d.ts +3 -0
  25. package/dist/components/OutlinedDatePicker/OutlinedDatePicker.types.d.ts +27 -0
  26. package/dist/components/OutlinedDatePicker/OutlinedDatePicker.vue.d.ts +88 -0
  27. package/dist/components/OutlinedDatePicker/index.d.ts +3 -0
  28. package/dist/components/OutlinedDateTimePicker/OutlinedDateTimePicker.types.d.ts +26 -0
  29. package/dist/components/OutlinedDateTimePicker/OutlinedDateTimePicker.vue.d.ts +97 -0
  30. package/dist/components/OutlinedDateTimePicker/index.d.ts +3 -0
  31. package/dist/components/OutlinedInput/OutlinedInput.types.d.ts +29 -0
  32. package/dist/components/OutlinedInput/OutlinedInput.vue.d.ts +97 -0
  33. package/dist/components/OutlinedInput/index.d.ts +3 -0
  34. package/dist/components/OutlinedSelect/OutlinedSelect.types.d.ts +38 -0
  35. package/dist/components/OutlinedSelect/OutlinedSelect.vue.d.ts +116 -0
  36. package/dist/components/OutlinedSelect/index.d.ts +3 -0
  37. package/dist/components/OutlinedTimePicker/OutlinedTimePicker.types.d.ts +28 -0
  38. package/dist/components/OutlinedTimePicker/OutlinedTimePicker.vue.d.ts +94 -0
  39. package/dist/components/OutlinedTimePicker/index.d.ts +3 -0
  40. package/dist/components/OutlinedTreeSelect/OutlinedTreeSelect.types.d.ts +46 -0
  41. package/dist/components/OutlinedTreeSelect/OutlinedTreeSelect.vue.d.ts +137 -0
  42. package/dist/components/OutlinedTreeSelect/index.d.ts +3 -0
  43. package/dist/echarts/index.d.ts +9 -0
  44. package/dist/excel/exportExcel.d.ts +18 -0
  45. package/dist/index.cjs +1 -1
  46. package/dist/index.d.ts +30 -0
  47. package/dist/index.js +832 -169
  48. package/dist/style.css +1 -1
  49. package/package.json +7 -4
  50. package/src/components/BaseDialog/BaseDialog.types.ts +28 -0
  51. package/src/components/BaseDialog/BaseDialog.vue +158 -0
  52. package/src/components/BaseDialog/README.md +69 -0
  53. package/src/components/BaseDialog/index.ts +10 -0
  54. package/src/components/BaseExportButton/BaseExportButton.vue +3 -1
  55. package/src/components/BaseSearchForm/BaseSearchForm.types.ts +46 -0
  56. package/src/components/BaseSearchForm/BaseSearchForm.utils.ts +41 -0
  57. package/src/components/BaseSearchForm/BaseSearchForm.vue +267 -0
  58. package/src/components/BaseSearchForm/README.md +66 -0
  59. package/src/components/BaseSearchForm/index.ts +20 -0
  60. package/src/components/BaseTable/BaseTable.types.ts +13 -1
  61. package/src/components/BaseTable/BaseTable.vue +412 -13
  62. package/src/components/BaseTable/README.md +106 -120
  63. package/src/echarts/index.ts +13 -8
  64. package/src/index.ts +4 -0
@@ -75,6 +75,58 @@
75
75
  <slot :name="resolveHeaderSlotName(column)" v-bind="headerScope" :column-config="column"></slot>
76
76
  </template>
77
77
 
78
+ <template v-else-if="shouldRenderBuiltInHeader(column)" #header>
79
+ <div class="base-table__header">
80
+ <span class="base-table__header-label">{{ column.label }}</span>
81
+
82
+ <div class="base-table__header-actions">
83
+ <el-dropdown
84
+ :ref="bindHeaderSearchDropdown(column)"
85
+ class="base-table__header-dropdown"
86
+ trigger="click"
87
+ :hide-on-click="false"
88
+ placement="bottom"
89
+ popper-class="base-table__header-search-dropdown"
90
+ >
91
+ <button
92
+ class="base-table__header-icon"
93
+ :class="{ 'is-active': hasHeaderSearchValue(column) }"
94
+ type="button"
95
+ >
96
+ <span class="base-table__header-icon-mark" aria-hidden="true"></span>
97
+ </button>
98
+
99
+ <template #dropdown>
100
+ <el-dropdown-menu class="base-table__header-search-menu">
101
+ <div
102
+ class="base-table__header-search-panel"
103
+ :style="{ width: toCssValue(getHeaderSearchWidth(column)) || '280px' }"
104
+ @click.stop
105
+ >
106
+ <el-input
107
+ :model-value="getHeaderSearchValue(column)"
108
+ :placeholder="getHeaderSearchPlaceholder(column)"
109
+ clearable
110
+ @update:model-value="updateHeaderSearchValue(column, $event)"
111
+ @keyup.enter="handleHeaderSearch(column)"
112
+ />
113
+
114
+ <div class="base-table__header-search-footer">
115
+ <el-button link type="primary" @click="handleHeaderSearch(column)">
116
+ {{ getHeaderSearchSearchText(column) }}
117
+ </el-button>
118
+ <el-button link @click="handleHeaderSearchReset(column)">
119
+ {{ getHeaderSearchResetText(column) }}
120
+ </el-button>
121
+ </div>
122
+ </div>
123
+ </el-dropdown-menu>
124
+ </template>
125
+ </el-dropdown>
126
+ </div>
127
+ </div>
128
+ </template>
129
+
78
130
  <template #default="scope">
79
131
  <slot
80
132
  v-if="hasCellSlot(column)"
@@ -163,6 +215,7 @@ import type {
163
215
  BaseTableColumn,
164
216
  BaseTableCssValue,
165
217
  BaseTableExpose,
218
+ BaseTableHeaderSearchConfig,
166
219
  BaseTableLoadedPayload,
167
220
  BaseTableOption,
168
221
  BaseTablePagination,
@@ -230,8 +283,11 @@ const emit = defineEmits<{
230
283
  const slots = useSlots()
231
284
  const tableRef = ref<TableInstance>()
232
285
  const loading = ref(false)
286
+ const sourceRows = ref<BaseTableRow[]>(normalizeRows(props.data))
233
287
  const rows = ref<BaseTableRow[]>(normalizeRows(props.data))
234
288
  const selectionRows = ref<BaseTableRow[]>([])
289
+ const headerSearchValues = reactive<Record<string, string>>({})
290
+ const headerSearchDropdownRefs = ref<Record<string, { handleClose?: () => void }>>({})
235
291
  const sortState = reactive({
236
292
  prop: props.defaultSort?.prop,
237
293
  order: props.defaultSort?.order || null
@@ -303,20 +359,18 @@ onMounted(() => {
303
359
  }
304
360
 
305
361
  if (!props.request) {
306
- rows.value = normalizeRows(props.data)
307
- if (!props.pagination?.total) {
308
- paginationState.total = rows.value.length
309
- emitPagination()
310
- }
362
+ setData(props.data || [])
311
363
  }
312
364
  })
313
365
 
314
366
  function syncPagination(value?: Partial<BaseTablePagination>) {
367
+ const nextPageSizes = value?.pageSizes
368
+
315
369
  paginationState.currentPage = Number(value?.currentPage || paginationState.currentPage || 1)
316
370
  paginationState.pageSize = Number(value?.pageSize || paginationState.pageSize || 20)
317
371
  paginationState.total = Number(value?.total || value?.total === 0 ? value.total : paginationState.total || rows.value.length)
318
- paginationState.pageSizes = Array.isArray(value?.pageSizes) && value.pageSizes.length
319
- ? [...value.pageSizes]
372
+ paginationState.pageSizes = Array.isArray(nextPageSizes) && nextPageSizes.length
373
+ ? [...nextPageSizes]
320
374
  : [...(paginationState.pageSizes.length ? paginationState.pageSizes : [10, 20, 50, 100])]
321
375
  }
322
376
 
@@ -336,7 +390,7 @@ async function load(data?: BaseTableRow[]) {
336
390
  }
337
391
 
338
392
  if (!props.request) {
339
- setData(props.data || [])
393
+ applyLocalRows()
340
394
  return
341
395
  }
342
396
 
@@ -365,6 +419,11 @@ async function load(data?: BaseTableRow[]) {
365
419
  }
366
420
 
367
421
  async function refresh() {
422
+ if (!props.request) {
423
+ applyLocalRows()
424
+ return
425
+ }
426
+
368
427
  await load()
369
428
  }
370
429
 
@@ -375,11 +434,8 @@ async function resetPage() {
375
434
  }
376
435
 
377
436
  function setData(data: BaseTableRow[]) {
378
- rows.value = normalizeRows(data)
379
- if (!props.request) {
380
- paginationState.total = Number(props.pagination?.total ?? rows.value.length)
381
- emitPagination()
382
- }
437
+ sourceRows.value = normalizeRows(data)
438
+ applyLocalRows()
383
439
  }
384
440
 
385
441
  function clearSelection() {
@@ -471,6 +527,186 @@ function handleInputChange(value: string, row: BaseTableRow, column: BaseTableCo
471
527
  })
472
528
  }
473
529
 
530
+ function shouldRenderBuiltInHeader(column: BaseTableColumn<BaseTableRow>) {
531
+ return hasHeaderSearch(column)
532
+ }
533
+
534
+ function hasHeaderSearch(column: BaseTableColumn<BaseTableRow>) {
535
+ return Boolean(getHeaderSearchConfig(column))
536
+ }
537
+
538
+ function getHeaderSearchConfig(column: BaseTableColumn<BaseTableRow>): BaseTableHeaderSearchConfig | null {
539
+ if (!column.headerSearch) {
540
+ return null
541
+ }
542
+
543
+ if (column.headerSearch === true) {
544
+ return {}
545
+ }
546
+
547
+ return column.headerSearch
548
+ }
549
+
550
+ function getHeaderSearchStateKey(column: BaseTableColumn<BaseTableRow>) {
551
+ return resolveHeaderSearchParamKey(column) || getColumnProp(column) || getColumnKey(column)
552
+ }
553
+
554
+ function setHeaderSearchDropdownRef(
555
+ instance: { handleClose?: () => void } | null,
556
+ column: BaseTableColumn<BaseTableRow>
557
+ ) {
558
+ const stateKey = getHeaderSearchStateKey(column)
559
+
560
+ if (!instance) {
561
+ delete headerSearchDropdownRefs.value[stateKey]
562
+ return
563
+ }
564
+
565
+ headerSearchDropdownRefs.value[stateKey] = instance
566
+ }
567
+
568
+ function bindHeaderSearchDropdown(column: BaseTableColumn<BaseTableRow>) {
569
+ return (instance: { handleClose?: () => void } | null) => {
570
+ setHeaderSearchDropdownRef(instance, column)
571
+ }
572
+ }
573
+
574
+ function resolveHeaderSearchParamKey(column: BaseTableColumn<BaseTableRow>) {
575
+ const config = getHeaderSearchConfig(column)
576
+ const legacyParamKey = (column as Record<string, any>).otherProps
577
+
578
+ return config?.paramKey || legacyParamKey || getColumnProp(column) || ''
579
+ }
580
+
581
+ function getHeaderSearchValue(column: BaseTableColumn<BaseTableRow>) {
582
+ return headerSearchValues[getHeaderSearchStateKey(column)] || ''
583
+ }
584
+
585
+ function hasHeaderSearchValue(column: BaseTableColumn<BaseTableRow>) {
586
+ return Boolean(getHeaderSearchValue(column).trim())
587
+ }
588
+
589
+ function updateHeaderSearchValue(column: BaseTableColumn<BaseTableRow>, value: string) {
590
+ headerSearchValues[getHeaderSearchStateKey(column)] = normalizeHeaderSearchValue(value)
591
+ }
592
+
593
+ function getHeaderSearchPlaceholder(column: BaseTableColumn<BaseTableRow>) {
594
+ return getHeaderSearchConfig(column)?.placeholder || '请输入搜索内容'
595
+ }
596
+
597
+ function getHeaderSearchWidth(column: BaseTableColumn<BaseTableRow>) {
598
+ return getHeaderSearchConfig(column)?.width || 280
599
+ }
600
+
601
+ function getHeaderSearchSearchText(column: BaseTableColumn<BaseTableRow>) {
602
+ return getHeaderSearchConfig(column)?.searchText || '搜索'
603
+ }
604
+
605
+ function getHeaderSearchResetText(column: BaseTableColumn<BaseTableRow>) {
606
+ return getHeaderSearchConfig(column)?.resetText || '重置'
607
+ }
608
+
609
+ async function handleHeaderSearch(column: BaseTableColumn<BaseTableRow>) {
610
+ closeHeaderSearch(column)
611
+ paginationState.currentPage = 1
612
+ emitPagination()
613
+
614
+ if (props.request) {
615
+ await load()
616
+ return
617
+ }
618
+
619
+ applyLocalRows()
620
+ }
621
+
622
+ async function handleHeaderSearchReset(column: BaseTableColumn<BaseTableRow>) {
623
+ updateHeaderSearchValue(column, '')
624
+ closeHeaderSearch(column)
625
+ paginationState.currentPage = 1
626
+ emitPagination()
627
+
628
+ if (props.request) {
629
+ await load()
630
+ return
631
+ }
632
+
633
+ applyLocalRows()
634
+ }
635
+
636
+ function closeHeaderSearch(column: BaseTableColumn<BaseTableRow>) {
637
+ headerSearchDropdownRefs.value[getHeaderSearchStateKey(column)]?.handleClose?.()
638
+ }
639
+
640
+ function buildHeaderSearchParams() {
641
+ return props.columns.reduce<Record<string, unknown>>((result, column) => {
642
+ if (!hasHeaderSearch(column)) {
643
+ return result
644
+ }
645
+
646
+ const paramKey = resolveHeaderSearchParamKey(column)
647
+ const value = getHeaderSearchValue(column).trim()
648
+
649
+ if (!paramKey || !value) {
650
+ return result
651
+ }
652
+
653
+ result[paramKey] = value
654
+ return result
655
+ }, {})
656
+ }
657
+
658
+ function applyLocalRows() {
659
+ const filteredRows = filterLocalRows(sourceRows.value)
660
+ rows.value = filteredRows
661
+ paginationState.total = filteredRows.length
662
+ emitPagination()
663
+ }
664
+
665
+ function filterLocalRows(data: BaseTableRow[]) {
666
+ const activeColumns = props.columns
667
+ .filter((column) => hasHeaderSearch(column) && hasHeaderSearchValue(column))
668
+ .map((column) => ({
669
+ column,
670
+ keyword: getHeaderSearchValue(column).trim().toLowerCase()
671
+ }))
672
+
673
+ if (!activeColumns.length) {
674
+ return normalizeRows(data)
675
+ }
676
+
677
+ return normalizeRows(data).filter((row) => {
678
+ return activeColumns.every(({ column, keyword }) => {
679
+ const columnProp = getColumnProp(column)
680
+ if (!columnProp) {
681
+ return true
682
+ }
683
+
684
+ const value = getCellValue(row, column)
685
+ return toSearchableText(value).includes(keyword)
686
+ })
687
+ })
688
+ }
689
+
690
+ function normalizeHeaderSearchValue(value: unknown) {
691
+ if (value === undefined || value === null) {
692
+ return ''
693
+ }
694
+
695
+ return String(value)
696
+ }
697
+
698
+ function toSearchableText(value: unknown): string {
699
+ if (value === undefined || value === null) {
700
+ return ''
701
+ }
702
+
703
+ if (Array.isArray(value)) {
704
+ return value.map((item) => toSearchableText(item)).join(' ').toLowerCase()
705
+ }
706
+
707
+ return String(value).toLowerCase()
708
+ }
709
+
474
710
  function buildRequestParams(): BaseTableRequestParams {
475
711
  const params: BaseTableRequestParams = {
476
712
  ...props.requestParams,
@@ -482,10 +718,12 @@ function buildRequestParams(): BaseTableRequestParams {
482
718
 
483
719
  const currentColumn = props.columns.find((item) => String(item.prop || '') === String(sortState.prop || ''))
484
720
  const sortPayload = buildSortPayload(currentColumn, sortState.prop, sortState.order)
721
+ const headerSearchParams = buildHeaderSearchParams()
485
722
  const sortParams = buildSortParams(sortPayload)
486
723
 
487
724
  return {
488
725
  ...params,
726
+ ...headerSearchParams,
489
727
  ...sortParams
490
728
  }
491
729
  }
@@ -735,11 +973,78 @@ function toCssValue(value?: BaseTableCssValue) {
735
973
  return typeof value === 'number' ? `${value}px` : value
736
974
  }
737
975
 
976
+ function findHeaderSearchColumn(key: string) {
977
+ return props.columns.find((column) => {
978
+ return getHeaderSearchStateKey(column) === key || getColumnProp(column) === key
979
+ })
980
+ }
981
+
982
+ async function setHeaderSearchValue(key: string, value: string, shouldReload = true) {
983
+ const matchedColumn = findHeaderSearchColumn(key)
984
+ const stateKey = matchedColumn ? getHeaderSearchStateKey(matchedColumn) : key
985
+
986
+ headerSearchValues[stateKey] = normalizeHeaderSearchValue(value)
987
+
988
+ if (!shouldReload) {
989
+ return
990
+ }
991
+
992
+ if (matchedColumn) {
993
+ await handleHeaderSearch(matchedColumn)
994
+ return
995
+ }
996
+
997
+ paginationState.currentPage = 1
998
+ emitPagination()
999
+ if (props.request) {
1000
+ await load()
1001
+ return
1002
+ }
1003
+
1004
+ applyLocalRows()
1005
+ }
1006
+
1007
+ async function resetHeaderSearch(key?: string) {
1008
+ if (key) {
1009
+ const matchedColumn = findHeaderSearchColumn(key)
1010
+ if (matchedColumn) {
1011
+ await handleHeaderSearchReset(matchedColumn)
1012
+ return
1013
+ }
1014
+
1015
+ delete headerSearchValues[key]
1016
+ } else {
1017
+ Object.keys(headerSearchValues).forEach((stateKey) => {
1018
+ delete headerSearchValues[stateKey]
1019
+ })
1020
+ Object.keys(headerSearchDropdownRefs.value).forEach((stateKey) => {
1021
+ headerSearchDropdownRefs.value[stateKey]?.handleClose?.()
1022
+ })
1023
+ }
1024
+
1025
+ paginationState.currentPage = 1
1026
+ emitPagination()
1027
+
1028
+ if (props.request) {
1029
+ await load()
1030
+ return
1031
+ }
1032
+
1033
+ applyLocalRows()
1034
+ }
1035
+
1036
+ function getHeaderSearchValues() {
1037
+ return { ...headerSearchValues }
1038
+ }
1039
+
738
1040
  defineExpose<BaseTableExpose>({
739
1041
  load,
740
1042
  refresh,
741
1043
  setData,
742
1044
  resetPage,
1045
+ setHeaderSearchValue,
1046
+ resetHeaderSearch,
1047
+ getHeaderSearchValues,
743
1048
  clearSelection,
744
1049
  toggleRowSelection,
745
1050
  getSelectionRows,
@@ -781,6 +1086,100 @@ defineExpose<BaseTableExpose>({
781
1086
  flex-wrap: wrap;
782
1087
  }
783
1088
 
1089
+ .base-table__header {
1090
+ display: flex;
1091
+ align-items: center;
1092
+ gap: 6px;
1093
+ width: 100%;
1094
+ min-width: 0;
1095
+ }
1096
+
1097
+ .base-table__header-label {
1098
+ flex: 1 1 auto;
1099
+ min-width: 0;
1100
+ overflow: hidden;
1101
+ text-overflow: ellipsis;
1102
+ white-space: nowrap;
1103
+ }
1104
+
1105
+ .base-table__header-actions {
1106
+ display: flex;
1107
+ align-items: center;
1108
+ margin-left: auto;
1109
+ flex-shrink: 0;
1110
+ }
1111
+
1112
+ .base-table__header-icon {
1113
+ display: inline-flex;
1114
+ align-items: center;
1115
+ justify-content: center;
1116
+ width: 24px;
1117
+ height: 24px;
1118
+ padding: 0;
1119
+ border: none;
1120
+ border-radius: 999px;
1121
+ background: transparent;
1122
+ color: var(--el-text-color-secondary);
1123
+ cursor: pointer;
1124
+ transition: color 0.2s ease, background-color 0.2s ease;
1125
+ }
1126
+
1127
+ .base-table__header-icon:hover,
1128
+ .base-table__header-icon.is-active {
1129
+ color: var(--el-color-primary);
1130
+ background: rgba(64, 158, 255, 0.12);
1131
+ }
1132
+
1133
+ .base-table__header-icon-mark {
1134
+ position: relative;
1135
+ display: inline-block;
1136
+ width: 14px;
1137
+ height: 14px;
1138
+ box-sizing: border-box;
1139
+ border: 2px solid currentColor;
1140
+ border-radius: 999px;
1141
+ }
1142
+
1143
+ .base-table__header-icon-mark::after {
1144
+ content: '';
1145
+ position: absolute;
1146
+ right: -6px;
1147
+ bottom: -4px;
1148
+ width: 7px;
1149
+ height: 2px;
1150
+ border-radius: 999px;
1151
+ background: currentColor;
1152
+ transform: rotate(45deg);
1153
+ transform-origin: center;
1154
+ }
1155
+
1156
+ .base-table__header-dropdown {
1157
+ display: inline-flex;
1158
+ align-items: center;
1159
+ }
1160
+
1161
+ .base-table__header-search-panel {
1162
+ display: flex;
1163
+ flex-direction: column;
1164
+ gap: 12px;
1165
+ padding: 8px;
1166
+ }
1167
+
1168
+ :deep(.base-table__header-search-menu) {
1169
+ padding: 0;
1170
+ }
1171
+
1172
+ :deep(.base-table__header-search-dropdown) {
1173
+ padding: 0;
1174
+ border-radius: 12px;
1175
+ }
1176
+
1177
+ .base-table__header-search-footer {
1178
+ display: flex;
1179
+ align-items: center;
1180
+ justify-content: space-between;
1181
+ }
1182
+
784
1183
  .base-table__link {
785
1184
  padding: 0;
786
1185
  border: none;