yc-pro-components 0.0.20 → 0.0.21

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 (59) hide show
  1. package/es/components/index.mjs +3 -1
  2. package/es/components/yc-plus-page/index.d.ts +5 -1
  3. package/es/components/yc-plus-page/index.mjs +5 -1
  4. package/es/components/yc-plus-page/src/constants.d.ts +22 -0
  5. package/es/components/yc-plus-page/src/constants.mjs +41 -0
  6. package/es/components/yc-plus-page/src/header-filter-cell.vue.d.ts +85 -0
  7. package/es/components/yc-plus-page/src/header-filter-cell.vue.mjs +6 -0
  8. package/es/components/yc-plus-page/src/header-filter-cell.vue2.mjs +354 -0
  9. package/es/components/yc-plus-page/src/index.vue.d.ts +327 -23
  10. package/es/components/yc-plus-page/src/index.vue.mjs +1 -1
  11. package/es/components/yc-plus-page/src/index.vue2.mjs +126 -8
  12. package/es/components/yc-plus-page/src/type.d.ts +112 -0
  13. package/es/components/yc-plus-page/src/use-header-filter.d.ts +55 -0
  14. package/es/components/yc-plus-page/src/use-header-filter.mjs +172 -0
  15. package/es/index.css +2 -1
  16. package/es/index.mjs +3 -1
  17. package/index.css +10 -6
  18. package/index.js +844 -163
  19. package/index.min.css +2 -1
  20. package/index.min.js +7 -7
  21. package/index.min.mjs +7 -7
  22. package/index.mjs +839 -164
  23. package/lib/components/index.js +8 -0
  24. package/lib/components/yc-plus-page/index.d.ts +5 -1
  25. package/lib/components/yc-plus-page/index.js +10 -0
  26. package/lib/components/yc-plus-page/src/constants.d.ts +22 -0
  27. package/lib/components/yc-plus-page/src/constants.js +46 -0
  28. package/lib/components/yc-plus-page/src/header-filter-cell.vue.d.ts +85 -0
  29. package/lib/components/yc-plus-page/src/header-filter-cell.vue.js +10 -0
  30. package/lib/components/yc-plus-page/src/header-filter-cell.vue2.js +358 -0
  31. package/lib/components/yc-plus-page/src/index.vue.d.ts +327 -23
  32. package/lib/components/yc-plus-page/src/index.vue.js +1 -1
  33. package/lib/components/yc-plus-page/src/index.vue2.js +125 -7
  34. package/lib/components/yc-plus-page/src/type.d.ts +112 -0
  35. package/lib/components/yc-plus-page/src/use-header-filter.d.ts +55 -0
  36. package/lib/components/yc-plus-page/src/use-header-filter.js +174 -0
  37. package/lib/index.css +2 -1
  38. package/lib/index.js +8 -0
  39. package/locale/en.js +1 -1
  40. package/locale/en.min.js +1 -1
  41. package/locale/en.min.mjs +1 -1
  42. package/locale/en.mjs +1 -1
  43. package/locale/ja.js +1 -1
  44. package/locale/ja.min.js +1 -1
  45. package/locale/ja.min.mjs +1 -1
  46. package/locale/ja.mjs +1 -1
  47. package/locale/ko.js +1 -1
  48. package/locale/ko.min.js +1 -1
  49. package/locale/ko.min.mjs +1 -1
  50. package/locale/ko.mjs +1 -1
  51. package/locale/zh-cn.js +1 -1
  52. package/locale/zh-cn.min.js +1 -1
  53. package/locale/zh-cn.min.mjs +1 -1
  54. package/locale/zh-cn.mjs +1 -1
  55. package/locale/zh-tw.js +1 -1
  56. package/locale/zh-tw.min.js +1 -1
  57. package/locale/zh-tw.min.mjs +1 -1
  58. package/locale/zh-tw.mjs +1 -1
  59. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import _sfc_main from './index.vue2.mjs';
2
2
  import _export_sfc from '../../../_virtual/_plugin-vue_export-helper.mjs';
3
3
 
4
- var YcPlusPageComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-7c1490fd"], ["__file", "index.vue"]]);
4
+ var YcPlusPageComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-a59fd3d9"], ["__file", "index.vue"]]);
5
5
 
6
6
  export { YcPlusPageComponent as default };
@@ -1,7 +1,9 @@
1
- import { defineComponent, ref, computed, useSlots, watch, onMounted, nextTick, onUnmounted, openBlock, createElementBlock, createVNode, unref, mergeProps, createSlots, withCtx, renderSlot, createElementVNode, renderList, normalizeProps, createCommentVNode } from 'vue';
1
+ import { defineComponent, ref, computed, useSlots, h, watch, onMounted, nextTick, onUnmounted, openBlock, createElementBlock, createVNode, unref, mergeProps, createSlots, withCtx, renderSlot, createElementVNode, renderList, normalizeProps, createCommentVNode } from 'vue';
2
2
  import { merge } from 'lodash-es';
3
3
  import { PlusPage } from '../../page/index.mjs';
4
4
  import YcSvgIcon from '../../yc-svg-icon/src/index.vue.mjs';
5
+ import { useHeaderFilter } from './use-header-filter.mjs';
6
+ import YcTableHeaderFilterCellComponent from './header-filter-cell.vue.mjs';
5
7
  import { useYcShowPageSearch, useYcCdnUrl, useYcComponentConfig } from '../../yc-config-provider/src/useYcConfig.mjs';
6
8
 
7
9
  const DEFAULT_PAGE_SIZE = 20;
@@ -25,10 +27,14 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
25
27
  defaultPageSize: 20
26
28
  }) },
27
29
  hideColumnSettingsIcon: { type: Boolean, default: false },
28
- showSearch: { type: Boolean, default: void 0 }
30
+ showSearch: { type: Boolean, default: void 0 },
31
+ headerFilter: { type: [Object, Boolean], default: false },
32
+ hideHeaderFilter: { type: Boolean, default: true }
29
33
  },
30
- setup(__props, { expose: __expose }) {
34
+ emits: ["header-filter-confirm", "header-filter-reset"],
35
+ setup(__props, { expose: __expose, emit: __emit }) {
31
36
  const props = __props;
37
+ const emit = __emit;
32
38
  const globalShowPageSearch = useYcShowPageSearch();
33
39
  const { getCdnUrl } = useYcCdnUrl();
34
40
  const plusPageConfig = useYcComponentConfig("plusPage");
@@ -54,6 +60,102 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
54
60
  });
55
61
  });
56
62
  };
63
+ const {
64
+ isEnabled: isHeaderFilterEnabled,
65
+ headerFiltersState,
66
+ orderByState,
67
+ operatorCatalogState,
68
+ fieldCatalogState,
69
+ upsertHeaderFilter,
70
+ removeHeaderFilter,
71
+ setOrderBy,
72
+ getOpsByProp,
73
+ getMergedQuery,
74
+ updateCatalogs,
75
+ isFieldFilterable
76
+ // isFieldVisible 已在 enhancedColumns 中直接使用 fieldCatalogState 实现
77
+ } = useHeaderFilter({
78
+ headerFilterConfig: () => props.headerFilter,
79
+ hideHeaderFilter: () => props.hideHeaderFilter,
80
+ onRefresh: () => {
81
+ var _a, _b;
82
+ (_b = (_a = plusPageRef.value) == null ? void 0 : _a.getList) == null ? void 0 : _b.call(_a);
83
+ }
84
+ });
85
+ const refreshList = () => {
86
+ var _a, _b;
87
+ (_b = (_a = plusPageRef.value) == null ? void 0 : _a.getList) == null ? void 0 : _b.call(_a);
88
+ };
89
+ const handleFilterConfirm = (payload) => {
90
+ var _a;
91
+ const field = String(((_a = payload.column) == null ? void 0 : _a.prop) || "");
92
+ upsertHeaderFilter(field, payload.op, payload.value);
93
+ refreshList();
94
+ emit("header-filter-confirm", payload);
95
+ };
96
+ const handleFilterReset = (payload) => {
97
+ var _a;
98
+ const field = String(((_a = payload.column) == null ? void 0 : _a.prop) || "");
99
+ removeHeaderFilter(field);
100
+ refreshList();
101
+ emit("header-filter-reset", payload);
102
+ };
103
+ const handleSortChange = (payload) => {
104
+ setOrderBy(payload.field, payload.direction);
105
+ refreshList();
106
+ };
107
+ const enhancedColumns = computed(() => {
108
+ const cols = props.columns || [];
109
+ if (!cols.length) return cols;
110
+ const isEnabled = isHeaderFilterEnabled.value;
111
+ const catalog = fieldCatalogState.value;
112
+ const visibleCols = isEnabled && catalog && Object.keys(catalog).length > 0 ? cols.filter((col) => {
113
+ const prop = String(col.prop || "");
114
+ const fieldConfig = Object.values(catalog).find(
115
+ (val) => String((val == null ? void 0 : val.allowedField) || "") === prop
116
+ );
117
+ return (fieldConfig == null ? void 0 : fieldConfig.nullable) !== false;
118
+ }) : cols;
119
+ if (!isEnabled) return visibleCols;
120
+ return visibleCols.map((col) => {
121
+ const colHideFilter = col.hideHeaderFilter === true;
122
+ const fieldFilterable = isFieldFilterable(col.prop);
123
+ if (colHideFilter || !fieldFilterable) {
124
+ return col;
125
+ }
126
+ const operators = getOpsByProp(col.prop);
127
+ const FILTER_ICON_WIDTH = 24;
128
+ const SORT_ICON_WIDTH = 16;
129
+ const EXTRA_WIDTH = FILTER_ICON_WIDTH + SORT_ICON_WIDTH;
130
+ const originalWidth = col.width || col.minWidth;
131
+ let adjustedWidth = originalWidth;
132
+ if (typeof originalWidth === "number") {
133
+ adjustedWidth = originalWidth + EXTRA_WIDTH;
134
+ } else if (typeof originalWidth === "string") {
135
+ const numWidth = parseInt(originalWidth, 10);
136
+ if (!isNaN(numWidth)) {
137
+ adjustedWidth = numWidth + EXTRA_WIDTH;
138
+ }
139
+ }
140
+ return {
141
+ ...col,
142
+ // 如果有原始宽度,增加图标宽度;否则设置最小宽度
143
+ ...originalWidth ? { width: adjustedWidth } : { minWidth: 120 },
144
+ renderHeader: (label) => {
145
+ return h(YcTableHeaderFilterCellComponent, {
146
+ label,
147
+ column: col,
148
+ operators,
149
+ filters: headerFiltersState.filters,
150
+ orderBy: orderByState,
151
+ onConfirm: handleFilterConfirm,
152
+ onReset: handleFilterReset,
153
+ onSortChange: handleSortChange
154
+ });
155
+ }
156
+ };
157
+ });
158
+ });
57
159
  const showSearch = computed(() => {
58
160
  if (props.showSearch !== void 0) {
59
161
  return props.showSearch;
@@ -215,13 +317,16 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
215
317
  return async (query) => {
216
318
  var _a;
217
319
  const finalPageSize = (query == null ? void 0 : query.pageSize) && query.pageSize > 0 ? query.pageSize : DEFAULT_PAGE_SIZE;
218
- const queryWithDefaults = {
320
+ const baseQuery = {
219
321
  ...query,
220
322
  page: (query == null ? void 0 : query.page) || 1,
221
- // 确保 pageSize 使用我们计算的值
222
323
  pageSize: finalPageSize
223
324
  };
224
- const result = await props.request(queryWithDefaults);
325
+ const queryWithFilters = isHeaderFilterEnabled.value ? getMergedQuery(baseQuery) : baseQuery;
326
+ const result = await props.request(queryWithFilters);
327
+ if (isHeaderFilterEnabled.value) {
328
+ updateCatalogs(result.operator_catalog, result.field_catalog);
329
+ }
225
330
  return {
226
331
  data: result.data,
227
332
  total: (_a = result.total) != null ? _a : 0
@@ -238,7 +343,19 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
238
343
  plusPageRef,
239
344
  plusTableInstance,
240
345
  tableInstance,
241
- formRefs
346
+ formRefs,
347
+ // 表头筛选相关
348
+ headerFiltersState,
349
+ orderByState,
350
+ operatorCatalogState,
351
+ fieldCatalogState,
352
+ upsertHeaderFilter,
353
+ removeHeaderFilter,
354
+ setOrderBy,
355
+ getList: () => {
356
+ var _a, _b;
357
+ return (_b = (_a = plusPageRef.value) == null ? void 0 : _a.getList) == null ? void 0 : _b.call(_a);
358
+ }
242
359
  });
243
360
  return (_ctx, _cache) => {
244
361
  return openBlock(), createElementBlock(
@@ -253,6 +370,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
253
370
  ref_key: "plusPageRef",
254
371
  ref: plusPageRef
255
372
  }, props, {
373
+ columns: enhancedColumns.value,
256
374
  "is-card": _ctx.isCard,
257
375
  request: wrappedRequest.value,
258
376
  search: mergedSearch.value,
@@ -295,7 +413,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
295
413
  ])
296
414
  };
297
415
  })
298
- ]), 1040, ["is-card", "request", "search", "search-card-props", "table-card-props", "table", "pagination", "default-page-info"])
416
+ ]), 1040, ["columns", "is-card", "request", "search", "search-card-props", "table-card-props", "table", "pagination", "default-page-info"])
299
417
  ],
300
418
  512
301
419
  /* NEED_PATCH */
@@ -10,8 +10,108 @@ export type RequestResponse = {
10
10
  data: unknown[];
11
11
  success?: boolean;
12
12
  total?: number;
13
+ /** 操作符目录(可选,来自后端) */
14
+ operator_catalog?: Record<string, string[]>;
15
+ /** 字段目录(可选,来自后端) */
16
+ field_catalog?: FieldCatalog;
13
17
  [key: string]: unknown;
14
18
  };
19
+ /**
20
+ * 字段目录项 - 来自后端的字段配置
21
+ */
22
+ export interface FieldCatalogItem {
23
+ /** 字段类型 */
24
+ type?: 'string' | 'number' | 'date' | 'boolean' | 'json';
25
+ /** 字段标签 */
26
+ label?: string;
27
+ /** 是否支持筛选 */
28
+ filter?: boolean;
29
+ /** 是否可为空/控制列显示 */
30
+ nullable?: boolean;
31
+ /** 是否为字典字段 */
32
+ dictField?: boolean;
33
+ /** 对应 column.prop */
34
+ allowedField?: string;
35
+ /** 原始字段名(如 vwProjectCountparking.projectName) */
36
+ [key: string]: unknown;
37
+ }
38
+ /**
39
+ * 字段目录
40
+ */
41
+ export type FieldCatalog = Record<string, FieldCatalogItem>;
42
+ /**
43
+ * 操作符选项
44
+ */
45
+ export interface OperatorOption {
46
+ /** 显示标签 */
47
+ label: string;
48
+ /** 操作符代码 */
49
+ code: string;
50
+ }
51
+ /**
52
+ * 表头筛选配置
53
+ */
54
+ export interface HeaderFilterConfig {
55
+ /** 是否启用表头筛选,默认 false */
56
+ enabled?: boolean;
57
+ /** 字段目录(来自后端) */
58
+ fieldCatalog?: FieldCatalog;
59
+ /** 操作符目录(可选,默认使用内置) */
60
+ operatorCatalog?: Record<string, string[]>;
61
+ /** 默认排序 */
62
+ defaultOrderBy?: Array<{
63
+ field: string;
64
+ direction: 'asc' | 'desc';
65
+ }>;
66
+ }
67
+ /**
68
+ * 列级别的表头筛选配置
69
+ */
70
+ export interface ColumnHeaderFilterConfig {
71
+ /** 自定义操作符列表 */
72
+ operators?: OperatorOption[];
73
+ /** 确认回调 */
74
+ onConfirm?: (payload: HeaderFilterPayload) => void;
75
+ /** 重置回调 */
76
+ onReset?: (payload: HeaderFilterResetPayload) => void;
77
+ }
78
+ /**
79
+ * 表头筛选确认事件 payload
80
+ */
81
+ export interface HeaderFilterPayload {
82
+ column: PlusColumn;
83
+ op: string;
84
+ value?: string;
85
+ }
86
+ /**
87
+ * 表头筛选重置事件 payload
88
+ */
89
+ export interface HeaderFilterResetPayload {
90
+ column: PlusColumn;
91
+ op: string;
92
+ }
93
+ /**
94
+ * 筛选项
95
+ */
96
+ export interface FilterItem {
97
+ field: string;
98
+ op: string;
99
+ value?: string;
100
+ }
101
+ /**
102
+ * 筛选状态
103
+ */
104
+ export interface HeaderFiltersState {
105
+ logic: 'and' | 'or';
106
+ filters: FilterItem[];
107
+ }
108
+ /**
109
+ * 排序项
110
+ */
111
+ export interface OrderByItem {
112
+ field: string;
113
+ direction: 'asc' | 'desc';
114
+ }
15
115
  /**
16
116
  * YcPlusPage 组件属性
17
117
  */
@@ -44,5 +144,17 @@ export interface YcPlusPageProps extends /* @vue-ignore */ Omit<Partial<PlusPage
44
144
  * - 如果全局配置也未设置,默认 true
45
145
  */
46
146
  showSearch?: boolean;
147
+ /**
148
+ * 表头筛选配置
149
+ * - 传入 true 启用默认配置
150
+ * - 传入对象自定义配置
151
+ * - 不传或传入 false 禁用(默认)
152
+ */
153
+ headerFilter?: HeaderFilterConfig | boolean;
154
+ /**
155
+ * 是否隐藏表头筛选(简写方式)
156
+ * @default true(默认隐藏)
157
+ */
158
+ hideHeaderFilter?: boolean;
47
159
  }
48
160
  export type RePlusPageProps = YcPlusPageProps;
@@ -0,0 +1,55 @@
1
+ import { FieldCatalog, HeaderFilterConfig, HeaderFiltersState, OrderByItem, OperatorOption } from './type';
2
+ import { PlusColumn } from 'yc-pro-components/es/types/plus';
3
+ import { Ref } from 'vue';
4
+
5
+ export interface UseHeaderFilterOptions {
6
+ /** 表头筛选配置 - 支持 getter 函数以实现响应式 */
7
+ headerFilterConfig?: HeaderFilterConfig | boolean | (() => HeaderFilterConfig | boolean | undefined);
8
+ /** 是否隐藏表头筛选 - 支持 getter 函数以实现响应式 */
9
+ hideHeaderFilter?: boolean | (() => boolean | undefined);
10
+ /** 刷新列表回调 */
11
+ onRefresh?: () => void;
12
+ /** 筛选确认回调 */
13
+ onFilterConfirm?: (payload: {
14
+ column: PlusColumn;
15
+ op: string;
16
+ value?: string;
17
+ }) => void;
18
+ /** 筛选重置回调 */
19
+ onFilterReset?: (payload: {
20
+ column: PlusColumn;
21
+ op: string;
22
+ }) => void;
23
+ }
24
+ export interface UseHeaderFilterReturn {
25
+ /** 是否启用表头筛选 */
26
+ isEnabled: Ref<boolean>;
27
+ /** 筛选状态 */
28
+ headerFiltersState: HeaderFiltersState;
29
+ /** 排序状态 */
30
+ orderByState: OrderByItem[];
31
+ /** 操作符目录(来自接口) */
32
+ operatorCatalogState: Ref<Record<string, string[]>>;
33
+ /** 字段目录(来自接口) */
34
+ fieldCatalogState: Ref<FieldCatalog>;
35
+ /** 更新或插入筛选项 */
36
+ upsertHeaderFilter: (field: string, op: string, value?: string) => void;
37
+ /** 移除筛选项 */
38
+ removeHeaderFilter: (field: string) => void;
39
+ /** 设置排序 */
40
+ setOrderBy: (field: string, direction?: 'asc' | 'desc') => void;
41
+ /** 根据 prop 获取操作符列表 */
42
+ getOpsByProp: (prop?: string) => OperatorOption[];
43
+ /** 获取合并后的请求参数 */
44
+ getMergedQuery: (baseQuery: Record<string, unknown>) => Record<string, unknown>;
45
+ /** 更新目录(从接口返回数据) */
46
+ updateCatalogs: (operatorCatalog?: Record<string, string[]>, fieldCatalog?: FieldCatalog) => void;
47
+ /** 判断字段是否支持筛选(基于 fieldCatalog 的 filter 属性) */
48
+ isFieldFilterable: (prop?: string) => boolean;
49
+ /** 判断字段是否允许显示(基于 fieldCatalog 的 nullable 属性) */
50
+ isFieldVisible: (prop?: string) => boolean;
51
+ }
52
+ /**
53
+ * 表头筛选 Hook
54
+ */
55
+ export declare function useHeaderFilter(options?: UseHeaderFilterOptions): UseHeaderFilterReturn;
@@ -0,0 +1,172 @@
1
+ import { computed, reactive } from 'vue';
2
+ import { OPERATOR_CATALOG, OPERATOR_LABELS, DEFAULT_OPERATORS } from './constants.mjs';
3
+
4
+ function useHeaderFilter(options = {}) {
5
+ const { headerFilterConfig: headerFilterConfigOption, hideHeaderFilter: hideHeaderFilterOption } = options;
6
+ const getHeaderFilterConfig = () => {
7
+ return typeof headerFilterConfigOption === "function" ? headerFilterConfigOption() : headerFilterConfigOption;
8
+ };
9
+ const getHideHeaderFilter = () => {
10
+ return typeof hideHeaderFilterOption === "function" ? hideHeaderFilterOption() : hideHeaderFilterOption;
11
+ };
12
+ const isEnabled = computed(() => {
13
+ const hideHeaderFilter = getHideHeaderFilter();
14
+ const headerFilterConfig = getHeaderFilterConfig();
15
+ if (hideHeaderFilter === true) return false;
16
+ if (typeof headerFilterConfig === "boolean") return headerFilterConfig;
17
+ if (headerFilterConfig && typeof headerFilterConfig === "object") {
18
+ return headerFilterConfig.enabled !== false;
19
+ }
20
+ return false;
21
+ });
22
+ const operatorCatalogState = computed(() => {
23
+ const headerFilterConfig = getHeaderFilterConfig();
24
+ if (typeof headerFilterConfig === "object" && (headerFilterConfig == null ? void 0 : headerFilterConfig.operatorCatalog)) {
25
+ return headerFilterConfig.operatorCatalog;
26
+ }
27
+ return {};
28
+ });
29
+ const fieldCatalogState = computed(() => {
30
+ const headerFilterConfig = getHeaderFilterConfig();
31
+ if (typeof headerFilterConfig === "object" && (headerFilterConfig == null ? void 0 : headerFilterConfig.fieldCatalog)) {
32
+ return headerFilterConfig.fieldCatalog;
33
+ }
34
+ return {};
35
+ });
36
+ const headerFiltersState = reactive({
37
+ logic: "and",
38
+ filters: []
39
+ });
40
+ const initConfig = getHeaderFilterConfig();
41
+ const orderByState = reactive(
42
+ typeof initConfig === "object" && (initConfig == null ? void 0 : initConfig.defaultOrderBy) || []
43
+ );
44
+ const updateCatalogs = (_operatorCatalog, _fieldCatalog) => {
45
+ };
46
+ const findTypeByProp = (prop) => {
47
+ const p = String(prop || "");
48
+ const catalog = fieldCatalogState.value || {};
49
+ for (const [key, val] of Object.entries(catalog)) {
50
+ if (key === p || String((val == null ? void 0 : val.allowedField) || "") === p) {
51
+ const t = String((val == null ? void 0 : val.type) || "").toLowerCase();
52
+ return t || void 0;
53
+ }
54
+ }
55
+ return void 0;
56
+ };
57
+ const isFieldFilterable = (prop) => {
58
+ const p = String(prop || "");
59
+ const catalog = fieldCatalogState.value || {};
60
+ for (const [, val] of Object.entries(catalog)) {
61
+ if (String((val == null ? void 0 : val.allowedField) || "") === p) {
62
+ return (val == null ? void 0 : val.filter) === true;
63
+ }
64
+ }
65
+ return true;
66
+ };
67
+ const isFieldVisible = (prop) => {
68
+ const p = String(prop || "");
69
+ const catalog = fieldCatalogState.value || {};
70
+ for (const [, val] of Object.entries(catalog)) {
71
+ const allowedField = String((val == null ? void 0 : val.allowedField) || "");
72
+ if (allowedField === p) {
73
+ return (val == null ? void 0 : val.nullable) !== false;
74
+ }
75
+ }
76
+ return true;
77
+ };
78
+ const getOpsByProp = (prop) => {
79
+ const typeKey = findTypeByProp(prop);
80
+ const source = operatorCatalogState.value[String(typeKey || "")] || OPERATOR_CATALOG[String(typeKey || "")];
81
+ if (Array.isArray(source) && source.length) {
82
+ return source.map((s) => {
83
+ var _a;
84
+ return { label: (_a = OPERATOR_LABELS[s]) != null ? _a : s, code: s };
85
+ });
86
+ }
87
+ return DEFAULT_OPERATORS;
88
+ };
89
+ const mapOp = (op) => {
90
+ if (op === "eq") return "=";
91
+ if (op === "neq") return "!=";
92
+ return op;
93
+ };
94
+ const upsertHeaderFilter = (field, op, value) => {
95
+ const idx = headerFiltersState.filters.findIndex((i) => i.field === field);
96
+ const next = {
97
+ field,
98
+ op: mapOp(op),
99
+ value: value != null ? String(value) : void 0
100
+ };
101
+ if (op === "empty" || op === "not_empty" || op === "is null" || op === "is not null" || op === "is true" || op === "is false") {
102
+ delete next.value;
103
+ }
104
+ if (idx >= 0) {
105
+ headerFiltersState.filters.splice(idx, 1, next);
106
+ } else {
107
+ headerFiltersState.filters.push(next);
108
+ }
109
+ };
110
+ const removeHeaderFilter = (field) => {
111
+ const idx = headerFiltersState.filters.findIndex((i) => i.field === field);
112
+ if (idx >= 0) {
113
+ headerFiltersState.filters.splice(idx, 1);
114
+ }
115
+ };
116
+ const setOrderBy = (field, direction) => {
117
+ const idx = orderByState.findIndex((i) => i.field === field);
118
+ if (!direction) {
119
+ if (idx >= 0) orderByState.splice(idx, 1);
120
+ return;
121
+ }
122
+ const next = { field, direction };
123
+ if (idx >= 0) {
124
+ orderByState.splice(idx, 1, next);
125
+ } else {
126
+ orderByState.push(next);
127
+ }
128
+ };
129
+ const getMergedQuery = (baseQuery) => {
130
+ let mergedFilters = baseQuery.filters;
131
+ if (headerFiltersState.filters.length > 0) {
132
+ const baseFilters = baseQuery.filters;
133
+ if (baseFilters && typeof baseFilters === "object" && Array.isArray(baseFilters.filters)) {
134
+ mergedFilters = {
135
+ logic: baseFilters.logic || "and",
136
+ filters: [
137
+ ...baseFilters.filters,
138
+ ...headerFiltersState.filters
139
+ ]
140
+ };
141
+ } else {
142
+ mergedFilters = {
143
+ logic: headerFiltersState.logic,
144
+ filters: [...headerFiltersState.filters]
145
+ };
146
+ }
147
+ }
148
+ const mergedOrderBy = orderByState.length > 0 ? [...orderByState] : baseQuery.order_by;
149
+ return {
150
+ ...baseQuery,
151
+ filters: mergedFilters,
152
+ order_by: mergedOrderBy
153
+ };
154
+ };
155
+ return {
156
+ isEnabled,
157
+ headerFiltersState,
158
+ orderByState,
159
+ operatorCatalogState,
160
+ fieldCatalogState,
161
+ upsertHeaderFilter,
162
+ removeHeaderFilter,
163
+ setOrderBy,
164
+ getOpsByProp,
165
+ getMergedQuery,
166
+ updateCatalogs,
167
+ isFieldFilterable,
168
+ isFieldVisible
169
+ };
170
+ }
171
+
172
+ export { useHeaderFilter };
package/es/index.css CHANGED
@@ -1,5 +1,6 @@
1
1
  .yc-svg-icon[data-v-34e1f2f7]{display:inline-block;-webkit-mask-size:contain;mask-size:contain;vertical-align:middle}.yc-svg-icon--original[data-v-34e1f2f7]{-o-object-fit:contain;object-fit:contain}
2
- .yc-plus-page[data-v-7c1490fd]{height:100%}.yc-plus-page[data-v-7c1490fd] [data-v-7c1490fd] .plus-page>.el-card{border-radius:8px}[data-v-7c1490fd] .yc-search-card-body{padding-right:0}[data-v-7c1490fd] .plus-table-title-bar__toolbar__icon{font-size:16px!important;position:relative;top:-2px}.column-settings-wrapper[data-v-7c1490fd]{align-items:center;cursor:pointer;display:flex;gap:4px;margin-left:8px}.column-settings-text[data-v-7c1490fd]{font-size:14px}
2
+
3
+ .yc-plus-page[data-v-a59fd3d9]{height:100%}.yc-plus-page[data-v-a59fd3d9] [data-v-a59fd3d9] .plus-page>.el-card{border-radius:8px}[data-v-a59fd3d9] .yc-search-card-body{padding-right:0}[data-v-a59fd3d9] .plus-table-title-bar__toolbar__icon{font-size:16px!important;position:relative;top:-2px}.column-settings-wrapper[data-v-a59fd3d9]{align-items:center;cursor:pointer;display:flex;gap:4px;margin-left:8px}.column-settings-text[data-v-a59fd3d9]{font-size:14px}
3
4
  .yc-select-v2-loading.el-select-dropdown__item{color:#909399;cursor:default;font-size:13px;pointer-events:none;text-align:center}.yc-select-v2-loading.el-select-dropdown__item.is-disabled{color:#909399;cursor:default}
4
5
  .el-tree .el-tree-node__content{position:relative}.yc-tree-node-label-wrapper{align-items:center;display:flex;flex:1;min-width:0}.yc-tree-node-label{font-size:12px}.yc-tree-node-line-ver{border-left:1px dashed var(--el-border-color-light,#dcdfe6);display:block;height:100%;left:0;position:absolute;top:0}.yc-tree-node-line-ver.last-node-line{border-left:1px dashed transparent}.yc-tree-node-line-ver.last-node-isLeaf-line{height:50%}.yc-tree-node-line-hor{border-bottom:1px dashed var(--el-border-color-light,#dcdfe6);display:block;height:0;left:0;position:absolute;top:50%}
5
6
  .yc-plus-tree[data-v-0043eed3]{display:flex;flex-direction:column;height:100%;overflow:auto}.yc-plus-tree[data-v-0043eed3] .search-input[data-v-0043eed3]{flex-shrink:0;margin-bottom:16px}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3]{flex:1;min-height:0;overflow:hidden}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] [data-v-0043eed3] .el-tree-v2{overflow-x:visible!important}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .inline-input-node[data-v-0043eed3]{align-items:center;display:flex;flex:1;padding-left:0;padding-right:8px;position:relative;z-index:1}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .inline-input-node[data-v-0043eed3] .inline-input[data-v-0043eed3]{flex-shrink:0;width:100%}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .inline-input-node[data-v-0043eed3] .inline-input[data-v-0043eed3] [data-v-0043eed3] .el-input__wrapper{border-radius:4px;box-shadow:0 0 0 1px var(--el-border-color) inset;font-size:14px;height:26px;line-height:18px;padding:0 8px;transition:box-shadow .2s ease}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .inline-input-node[data-v-0043eed3] .inline-input[data-v-0043eed3] [data-v-0043eed3] .el-input__wrapper[data-v-0043eed3]:hover{box-shadow:0 0 0 1px var(--el-border-color-hover) inset}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .inline-input-node[data-v-0043eed3] .inline-input[data-v-0043eed3] [data-v-0043eed3] .el-input__wrapper.is-focus[data-v-0043eed3]{box-shadow:0 0 0 1px var(--el-color-primary) inset}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .inline-input-node[data-v-0043eed3] .inline-input[data-v-0043eed3] [data-v-0043eed3] .el-input__inner{color:rgba(0,0,0,.7);font-size:14px;height:24px;line-height:18px}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .inline-input-node[data-v-0043eed3] .inline-input[data-v-0043eed3] [data-v-0043eed3] .el-input__inner[data-v-0043eed3]::-moz-placeholder{color:rgba(0,0,0,.4)}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .inline-input-node[data-v-0043eed3] .inline-input[data-v-0043eed3] [data-v-0043eed3] .el-input__inner[data-v-0043eed3]::placeholder{color:rgba(0,0,0,.4)}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] [data-v-0043eed3] .el-tree-node__content:hover{background-color:var(--el-color-primary-light-9)}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] [data-v-0043eed3] .el-tree-node__content:hover .label-text[data-v-0043eed3]{color:var(--el-color-primary)}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] [data-v-0043eed3] .el-tree-node__content:hover .label-text{color:var(--el-color-primary)}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] [data-v-0043eed3] .el-tree-node.is-current>.el-tree-node__content{background-color:var(--el-color-primary-light-9)}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] [data-v-0043eed3] .el-tree-node.is-current>.el-tree-node__content .label-text{color:var(--el-color-primary)}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3]{align-items:center;display:flex;gap:4px;width:100%}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3][data-v-0043eed3]:hover .node-actions[data-v-0043eed3]{opacity:1;pointer-events:auto}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] .node-label[data-v-0043eed3],.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] [data-v-0043eed3] .custom-node-label{align-items:center;display:flex;flex:1;gap:4px;min-width:0}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] .node-label[data-v-0043eed3] [data-v-0043eed3] .el-tooltip__trigger,.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] [data-v-0043eed3] .custom-node-label [data-v-0043eed3] .el-tooltip__trigger{display:block;min-width:0;overflow:hidden}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] .node-label[data-v-0043eed3] .label-text[data-v-0043eed3],.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] .node-label[data-v-0043eed3] .node-text[data-v-0043eed3],.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] [data-v-0043eed3] .custom-node-label .label-text[data-v-0043eed3],.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] [data-v-0043eed3] .custom-node-label .node-text[data-v-0043eed3]{color:var(--el-text-color-primary);display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] .node-label[data-v-0043eed3] .label-text[data-v-0043eed3] [data-v-0043eed3] .highlight-keyword,.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] .node-label[data-v-0043eed3] .node-text[data-v-0043eed3] [data-v-0043eed3] .highlight-keyword,.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] [data-v-0043eed3] .custom-node-label .label-text[data-v-0043eed3] [data-v-0043eed3] .highlight-keyword,.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] [data-v-0043eed3] .custom-node-label .node-text[data-v-0043eed3] [data-v-0043eed3] .highlight-keyword{background-color:var(--el-color-primary-light-9);border-radius:2px;color:var(--el-color-primary);font-weight:600;padding:0 2px}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] .node-label[data-v-0043eed3] .node-count[data-v-0043eed3],.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] [data-v-0043eed3] .custom-node-label .node-count[data-v-0043eed3]{color:var(--el-text-color-secondary);font-size:12px}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] .node-actions[data-v-0043eed3]{align-items:center;display:flex;flex-shrink:0;margin-left:auto;margin-right:8px;opacity:0;pointer-events:none;transition:opacity .2s ease}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] .node-actions[data-v-0043eed3] .action-icon-wrapper[data-v-0043eed3]{align-items:center;cursor:pointer;display:flex;justify-content:center}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] .node-actions[data-v-0043eed3] .action-icon[data-v-0043eed3]{align-items:center;border-radius:4px;color:var(--el-color-primary);cursor:pointer;display:flex;height:20px;justify-content:center;transition:background-color .2s ease;width:20px}.yc-plus-tree[data-v-0043eed3] .tree-container[data-v-0043eed3] .node-label-wrapper[data-v-0043eed3] .node-actions[data-v-0043eed3] .action-icon[data-v-0043eed3][data-v-0043eed3]:hover{background-color:var(--el-color-primary-light-8)}.tree-dropdown-menu[data-v-0043eed3]{border-radius:8px!important;min-width:156px!important;padding:8px!important}.tree-dropdown-menu[data-v-0043eed3] [data-v-0043eed3] .el-dropdown-menu__item{border-radius:8px;font-size:12px;height:32px;line-height:32px;margin:0;padding:0 12px;transition:background-color .2s ease}.tree-dropdown-menu[data-v-0043eed3] [data-v-0043eed3] .el-dropdown-menu__item[data-v-0043eed3]:hover{background-color:var(--el-color-primary-light-9)!important;color:var(--el-color-primary)!important}.tree-dropdown-menu[data-v-0043eed3] [data-v-0043eed3] .el-dropdown-menu__item[data-v-0043eed3]:not(:last-child){margin-bottom:4px}.tree-dropdown-menu[data-v-0043eed3] [data-v-0043eed3] .el-divider{border-top:1px solid #e5e7eb;margin:12px 0}.tree-dropdown-menu[data-v-0043eed3] [data-v-0043eed3] .sortable-ghost{background-color:var(--el-color-primary-light-9);border:1px dashed var(--el-color-primary);border-radius:4px;opacity:.4}.tree-dropdown-menu[data-v-0043eed3] [data-v-0043eed3] .sortable-chosen{background-color:var(--el-color-primary-light-8);box-shadow:0 2px 8px rgba(0,0,0,.1)}.tree-dropdown-menu[data-v-0043eed3] [data-v-0043eed3] .sortable-drag{background-color:#fff;box-shadow:0 4px 12px rgba(0,0,0,.15);cursor:move;opacity:1;transform:rotate(2deg)}.tree-dropdown-menu[data-v-0043eed3] [data-v-0043eed3] .sortable-fallback{-webkit-user-select:none;-moz-user-select:none;user-select:none}
package/es/index.mjs CHANGED
@@ -38,7 +38,9 @@ export { PlusCheckCardGroup } from './components/check-card-group/index.mjs';
38
38
  export { DEFAULT_CDN_CONFIG, DEFAULT_YC_CONFIG, YC_CONFIG_KEY } from './components/yc-config-provider/src/type.mjs';
39
39
  export { useYcAuth, useYcCdn, useYcCdnUrl, useYcComponentConfig, useYcConfig, useYcPerms, useYcShowPageSearch, useYcTranslate } from './components/yc-config-provider/src/useYcConfig.mjs';
40
40
  export { YcConfigProvider as ReConfigProvider, YcConfigProvider } from './components/yc-config-provider/index.mjs';
41
- export { RePlusPage, YcPlusPage } from './components/yc-plus-page/index.mjs';
41
+ export { useHeaderFilter } from './components/yc-plus-page/src/use-header-filter.mjs';
42
+ export { DEFAULT_OPERATORS, NO_VALUE_OPERATORS, OPERATOR_CATALOG, OPERATOR_LABELS } from './components/yc-plus-page/src/constants.mjs';
43
+ export { RePlusPage, YcPlusPage, YcTableHeaderFilterCell } from './components/yc-plus-page/index.mjs';
42
44
  export { default as ReSelectV2, default as YcSelectV2 } from './components/yc-select-v2/src/index.vue.mjs';
43
45
  export { findNodeById, findNodeByPath, findNodePosition, insertAsChild, insertAsSibling, insertNodeAtPosition, removeNode, reorderNodeChildren, reorderSiblingNodes } from './components/yc-plus-tree/src/treeDataUtils.mjs';
44
46
  export { RePlusTree, YcPlusTree } from './components/yc-plus-tree/index.mjs';
package/index.css CHANGED
@@ -10,27 +10,31 @@
10
10
  object-fit: contain;
11
11
  }
12
12
  @charset "UTF-8";
13
- .yc-plus-page[data-v-7c1490fd] {
13
+ .yc-header-filter-cell[data-v-87ce6807] {
14
+ /* 基础样式已通过内联样式设置 */
15
+ }
16
+ @charset "UTF-8";
17
+ .yc-plus-page[data-v-a59fd3d9] {
14
18
  height: 100%;
15
19
  /* 卡片模式下设置圆角 8px */
16
20
  }
17
- .yc-plus-page[data-v-7c1490fd] [data-v-7c1490fd] .plus-page > .el-card {
21
+ .yc-plus-page[data-v-a59fd3d9] [data-v-a59fd3d9] .plus-page > .el-card {
18
22
  border-radius: 8px;
19
23
  }
20
24
 
21
- [data-v-7c1490fd] .yc-search-card-body {
25
+ [data-v-a59fd3d9] .yc-search-card-body {
22
26
  padding-right: 0;
23
27
  }
24
28
 
25
29
  /* 密度图标样式调整 */
26
- [data-v-7c1490fd] .plus-table-title-bar__toolbar__icon {
30
+ [data-v-a59fd3d9] .plus-table-title-bar__toolbar__icon {
27
31
  position: relative;
28
32
  top: -2px;
29
33
  font-size: 16px !important;
30
34
  }
31
35
 
32
36
  /* 字段管理样式 */
33
- .column-settings-wrapper[data-v-7c1490fd] {
37
+ .column-settings-wrapper[data-v-a59fd3d9] {
34
38
  display: flex;
35
39
  gap: 4px;
36
40
  align-items: center;
@@ -38,7 +42,7 @@
38
42
  cursor: pointer;
39
43
  }
40
44
 
41
- .column-settings-text[data-v-7c1490fd] {
45
+ .column-settings-text[data-v-a59fd3d9] {
42
46
  font-size: 14px;
43
47
  }
44
48