foggy-data-viewer 1.0.1-beta.38 → 1.0.1-beta.40

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.
package/README.md CHANGED
@@ -149,6 +149,20 @@ function handlePageChange(page: number, pageSize: number) {
149
149
 
150
150
  `DataTableWithSearch` 在 `schema + fetchData` 服务端查询模式下默认 `localFilter=false`:列头筛选仍会提交给 `fetchData`,但返回数据不会再被前端二次过滤,避免聚合字段、派生字段、字典展示字段被简单本地比较误删。需要纯前端过滤时,可显式设置 `localFilter=true` 或 `schema.localFilter=true`。
151
151
 
152
+ ### DataTableWithSearch tableInstanceId 默认查询配置
153
+
154
+ `schema + fetchData` 模式支持按 `tableInstanceId` 加载默认查询配置。默认查询配置只负责默认展示列、排序、分页和筛选;`requiredRuntimeColumns`、`lockedColumns` 由 TM/QM 产出的 `TableSchema` 提供。
155
+
156
+ ```vue
157
+ <DataTableWithSearch
158
+ :schema="{ ...tableSchema, qmModel: 'TicketQueryModel', tableInstanceId: 'ticket-list' }"
159
+ :fetch-data="fetchTickets"
160
+ :default-query-config-scope="{ userId: currentUser.id, tenantId: currentTenant.id, roleIds: currentRoleIds }"
161
+ />
162
+ ```
163
+
164
+ 后端可通过 `foggy.data-viewer.table-defaults.system/tenants/roles` 配置 fallback;用户默认配置仍可通过 `listPreset` 覆盖。`requiredRuntimeColumns` 只会追加到 `fetchData(params).columns`,不会显示为普通列。
165
+
152
166
  ### DataTable Events
153
167
 
154
168
  | 事件名 | 参数 | 说明 |
@@ -256,6 +270,66 @@ const columns = buildTableColumns(qmSchema, {
256
270
 
257
271
  选择原则:需要绑定业务事件时优先用 `column-*` 插槽;只改显示内容时使用 `render` 更轻。
258
272
 
273
+ ### 全局列渲染器(应用级统一增强)
274
+
275
+ 业务系统可以在应用启动时注册 `globalColumnRenderers`,按列元数据统一增强单元格展示。生成的 QueryTable wrapper 不需要批量修改。
276
+
277
+ ```typescript
278
+ import { h } from 'vue'
279
+ import { globalColumnRenderers } from 'foggy-data-viewer'
280
+
281
+ const dispose = globalColumnRenderers.add({
282
+ id: 'app.orderNoLink',
283
+ priority: 100,
284
+ match: ({ column }) => column.name === 'orderNo' && /运单号/.test(column.title ?? ''),
285
+ render: ({ value }) => {
286
+ const text = String(value ?? '').trim()
287
+ if (!text) return '-'
288
+ return h('button', {
289
+ type: 'button',
290
+ class: 'data-viewer-link-cell',
291
+ onClick: (event: MouseEvent) => {
292
+ event.stopPropagation()
293
+ // 在业务应用闭包里调用 router.push(...)
294
+ }
295
+ }, text)
296
+ }
297
+ })
298
+
299
+ // 应用卸载或测试清理
300
+ dispose()
301
+ ```
302
+
303
+ 渲染优先级固定为:`column-*` 插槽 > `column.customRender` > `globalColumnRenderers` > 默认渲染/字典/formatter。列级退出可设置 `column.uiConfig.disableGlobalRender = true`。
304
+
305
+ ### 全局搜索生命周期 Hook
306
+
307
+ `globalSearchHooks` 作用于搜索动作层,早于最终 `fetchData` 和 `globalQueryHooks.onBeforeQuery`。它可以区分搜索来源和触发原因,适合埋点、默认条件补充和无效查询拦截。
308
+
309
+ ```typescript
310
+ import { globalSearchHooks } from 'foggy-data-viewer'
311
+
312
+ globalSearchHooks.register({
313
+ beforeSearch: (ctx) => {
314
+ if (ctx.trigger === 'search' && ctx.slice.length === 0) return false
315
+ return {
316
+ slice: [
317
+ ...ctx.slice,
318
+ { field: 'tenantId', op: '=', value: currentTenantId }
319
+ ]
320
+ }
321
+ },
322
+ afterSearch: (ctx, result) => {
323
+ console.log(ctx.source, ctx.trigger, result.total)
324
+ },
325
+ searchError: (ctx, error) => {
326
+ console.warn(ctx.source, ctx.trigger, error)
327
+ }
328
+ })
329
+ ```
330
+
331
+ `ctx.source` 为 `search-toolbar | query-panel | column-filter | external | api`,`ctx.trigger` 为 `search | reset | filter | sort | page | refresh | reload | mount`。
332
+
259
333
  ## 类型定义
260
334
 
261
335
  ```typescript
@@ -3,6 +3,7 @@ export interface ListPresetScope {
3
3
  userId: string;
4
4
  model: string;
5
5
  businessKey?: string;
6
+ tableInstanceId?: string;
6
7
  }
7
8
  export interface SaveListPresetRequest {
8
9
  title: string;
@@ -0,0 +1,2 @@
1
+ import type { TableDefaultQueryConfig, TableDefaultQueryConfigScope } from '@/types';
2
+ export declare function getTableDefaultQueryConfig(scope: TableDefaultQueryConfigScope): Promise<TableDefaultQueryConfig | null>;
@@ -1,5 +1,5 @@
1
1
  import type { VxeGridInstance } from 'vxe-table';
2
- import type { EnhancedColumnSchema, SliceRequestDef, FilterOption, CellCopyConfig, MemberQueryRequest, MemberQueryResponse, TableDensity } from '@/types';
2
+ import type { EnhancedColumnSchema, SliceRequestDef, FilterOption, CellCopyConfig, MemberQueryRequest, MemberQueryResponse, TableDensity, TableSchema } from '@/types';
3
3
  /**
4
4
  * DataTable 组件属性
5
5
  *
@@ -44,6 +44,8 @@ interface Props {
44
44
  filterMemberLoader?: (request: MemberQueryRequest) => Promise<MemberQueryResponse>;
45
45
  /** QM 模型名称(远程成员加载所需) */
46
46
  qmModel?: string;
47
+ /** 表格 Schema 元数据(全局列渲染器上下文使用) */
48
+ tableSchema?: TableSchema;
47
49
  /** 自定义过滤器组件映射 */
48
50
  customFilterComponents?: Record<string, unknown>;
49
51
  /** 普通单元格悬浮复制配置 */
@@ -1,4 +1,4 @@
1
- import type { EnhancedColumnSchema, SliceRequestDef, FilterOption, TableSchema, FetchDataParams, FetchDataResult, OrderRequestDef, QueryHooks, MemberQueryRequest, MemberQueryResponse, CellCopyConfig, QueryMode, ListViewState, ListPresetConfig, TableDensity } from '@/types';
1
+ import type { EnhancedColumnSchema, SliceRequestDef, FilterOption, TableSchema, FetchDataParams, FetchDataResult, OrderRequestDef, QueryHooks, MemberQueryRequest, MemberQueryResponse, CellCopyConfig, QueryMode, ListViewState, ListPresetConfig, TableDensity, SearchHooks, TableDefaultQueryConfig, TableDefaultQueryConfigScope, TableDefaultQueryConfigLoadOptions } from '@/types';
2
2
  import type { QueryPanelExpose, QuerySchema } from './QueryPanel.vue';
3
3
  /**
4
4
  * DataTableWithSearch 组件
@@ -55,14 +55,24 @@ interface Props {
55
55
  filterMergeMode?: 'replace' | 'merge';
56
56
  /** 查询钩子(声明式) */
57
57
  queryHooks?: QueryHooks;
58
+ /** 搜索动作层钩子(声明式) */
59
+ searchHooks?: SearchHooks;
58
60
  /** 查询 Schema(传统查询区定义) */
59
61
  querySchema?: QuerySchema;
60
62
  /** 是否显示传统查询区 */
61
63
  showQueryPanel?: boolean;
62
64
  /** QM 模型名称(远程成员加载所需) */
63
65
  qmModel?: string;
66
+ /** 同一 QM 下的业务表格实例标识 */
67
+ tableInstanceId?: string;
64
68
  /** 远程维度成员加载器 */
65
69
  filterMemberLoader?: (request: MemberQueryRequest) => Promise<MemberQueryResponse>;
70
+ /** 已解析的表格实例默认查询配置 */
71
+ defaultQueryConfig?: TableDefaultQueryConfig | null;
72
+ /** 默认查询配置自动加载作用域 */
73
+ defaultQueryConfigScope?: TableDefaultQueryConfigLoadOptions;
74
+ /** 自定义默认查询配置加载器 */
75
+ defaultQueryConfigLoader?: (scope: TableDefaultQueryConfigScope) => Promise<TableDefaultQueryConfig | null>;
66
76
  /** 启用保存查询功能 */
67
77
  enableSavedQuery?: boolean;
68
78
  /** 自定义列表配置 */
@@ -84,6 +94,9 @@ interface DataTableExpose {
84
94
  clearSelection: (options?: ClearSelectionOptions) => void;
85
95
  }
86
96
  declare function clearSelectionState(options?: ClearSelectionOptions): void;
97
+ declare function applyTableDefaultQueryConfig(config: TableDefaultQueryConfig, options?: {
98
+ reload?: boolean;
99
+ }): void;
87
100
  declare function searchQueryPanel(): void;
88
101
  declare function resetQueryPanel(): void;
89
102
  declare function getListViewState(): ListViewState;
@@ -166,6 +179,8 @@ declare const __VLS_component: import("vue").DefineComponent<Props, {
166
179
  getListViewState: typeof getListViewState;
167
180
  /** 应用列表视图状态(用于加载自定义列表) */
168
181
  applyListViewState: typeof applyListViewState;
182
+ /** 应用表格实例默认查询配置 */
183
+ applyTableDefaultQueryConfig: typeof applyTableDefaultQueryConfig;
169
184
  /** 重置列表视图状态 */
170
185
  resetListViewState: typeof resetListViewState;
171
186
  /** 获取当前查询状态(用于保存查询) */
@@ -65,12 +65,12 @@ declare const _default: import("vue").DefineComponent<Props, {
65
65
  reset: typeof handleReset;
66
66
  getSlices: () => SliceRequestDef[];
67
67
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
68
- "update:modelValue": (value: SliceRequestDef[]) => any;
69
68
  search: () => any;
70
69
  reset: () => any;
70
+ "update:modelValue": (value: SliceRequestDef[]) => any;
71
71
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
72
- "onUpdate:modelValue"?: (value: SliceRequestDef[]) => any;
73
72
  onSearch?: () => any;
74
73
  onReset?: () => any;
74
+ "onUpdate:modelValue"?: (value: SliceRequestDef[]) => any;
75
75
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
76
76
  export default _default;
@@ -33,13 +33,13 @@ declare const _default: import("vue").DefineComponent<Props, {
33
33
  /** 获取当前筛选条件 */
34
34
  getFilters: () => SliceRequestDef[];
35
35
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
36
- "update:modelValue": (value: SliceRequestDef[]) => any;
37
36
  search: () => any;
38
37
  reset: () => any;
38
+ "update:modelValue": (value: SliceRequestDef[]) => any;
39
39
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
40
- "onUpdate:modelValue"?: (value: SliceRequestDef[]) => any;
41
40
  onSearch?: () => any;
42
41
  onReset?: () => any;
42
+ "onUpdate:modelValue"?: (value: SliceRequestDef[]) => any;
43
43
  }>, {
44
44
  layout: "horizontal" | "vertical";
45
45
  showActions: boolean;
@@ -0,0 +1,16 @@
1
+ import type { GlobalColumnRenderContext, GlobalColumnRenderResolution, GlobalColumnRenderer } from '@/types';
2
+ /**
3
+ * Global column renderer registry.
4
+ *
5
+ * Host applications register business-specific renderers once at startup.
6
+ * DataTable keeps page-level slots and customRender ahead of this registry.
7
+ */
8
+ export declare const globalColumnRenderers: {
9
+ add(renderer: GlobalColumnRenderer): () => void;
10
+ register(renderers: GlobalColumnRenderer | GlobalColumnRenderer[]): () => void;
11
+ remove(id: string): void;
12
+ clear(): void;
13
+ list(): GlobalColumnRenderer[];
14
+ resolve(ctx: GlobalColumnRenderContext): GlobalColumnRenderer | undefined;
15
+ render(ctx: GlobalColumnRenderContext): GlobalColumnRenderResolution | undefined;
16
+ };
@@ -0,0 +1,21 @@
1
+ import type { AfterSearchHookFn, BeforeSearchHookFn, ErrorSearchHookFn, SearchHookName, SearchHooks } from '@/types';
2
+ import { SearchHookRegistry } from './searchHookRegistry';
3
+ type SearchHookFnMap = {
4
+ beforeSearch: BeforeSearchHookFn;
5
+ afterSearch: AfterSearchHookFn;
6
+ searchError: ErrorSearchHookFn;
7
+ };
8
+ /**
9
+ * Global search lifecycle hooks.
10
+ *
11
+ * These hooks run at the DataTableWithSearch action layer, before the final
12
+ * fetch/query lifecycle handled by globalQueryHooks.
13
+ */
14
+ export declare const globalSearchHooks: {
15
+ add<N extends SearchHookName>(name: N, fn: SearchHookFnMap[N]): () => void;
16
+ remove<N extends SearchHookName>(name: N, fn: SearchHookFnMap[N]): void;
17
+ register(hooks: SearchHooks): () => void;
18
+ clear(): void;
19
+ _getRegistry(): SearchHookRegistry;
20
+ };
21
+ export {};
@@ -6,5 +6,8 @@ export { useDeferredVisibility } from './useDeferredVisibility';
6
6
  export type { DeferredVisibilityOptions, DeferredVisibilityState } from './useDeferredVisibility';
7
7
  export { HookRegistry } from './hookRegistry';
8
8
  export { globalQueryHooks } from './globalQueryHooks';
9
+ export { globalColumnRenderers } from './globalColumnRenderers';
10
+ export { SearchHookRegistry } from './searchHookRegistry';
11
+ export { globalSearchHooks } from './globalSearchHooks';
9
12
  export { useQueryState } from './useQueryState';
10
13
  export type { UseQueryStateReturn } from './useQueryState';
@@ -0,0 +1,19 @@
1
+ import type { AfterSearchHookFn, BeforeSearchHookFn, ErrorSearchHookFn, FetchDataResult, SearchHookContext, SearchHookName, SearchHooks } from '@/types';
2
+ type SearchHookFnMap = {
3
+ beforeSearch: BeforeSearchHookFn;
4
+ afterSearch: AfterSearchHookFn;
5
+ searchError: ErrorSearchHookFn;
6
+ };
7
+ export declare class SearchHookRegistry {
8
+ private hooks;
9
+ add<N extends SearchHookName>(name: N, fn: SearchHookFnMap[N]): () => void;
10
+ remove<N extends SearchHookName>(name: N, fn: SearchHookFnMap[N]): void;
11
+ register(hooks: SearchHooks): () => void;
12
+ removeRegistered(hooks: SearchHooks): void;
13
+ size(name: SearchHookName): number;
14
+ clear(): void;
15
+ runBefore(ctx: SearchHookContext): Promise<void | false>;
16
+ runAfter(ctx: SearchHookContext, result: FetchDataResult): Promise<void>;
17
+ runError(ctx: SearchHookContext, error: Error): Promise<boolean>;
18
+ }
19
+ export {};
@@ -24,6 +24,7 @@ export interface UseTableQueryReturn {
24
24
  currentOrderBy: ReturnType<typeof ref<OrderRequestDef[]>>;
25
25
  currentSlice: ReturnType<typeof ref<SliceRequestDef[]>>;
26
26
  currentColumns: ReturnType<typeof ref<string[]>>;
27
+ currentTableInstanceId: ReturnType<typeof ref<string | undefined>>;
27
28
  loadData: (trigger?: QueryTrigger) => Promise<void>;
28
29
  refresh: () => Promise<void>;
29
30
  reload: () => Promise<void>;
@@ -31,6 +32,7 @@ export interface UseTableQueryReturn {
31
32
  setSort: (orderBy: OrderRequestDef[]) => void;
32
33
  setSlice: (slice: SliceRequestDef[]) => void;
33
34
  setColumns: (columns: string[]) => void;
35
+ setTableInstanceId: (tableInstanceId?: string) => void;
34
36
  addHook: <N extends QueryHookName>(name: N, fn: HookFnMap[N]) => () => void;
35
37
  removeHook: <N extends QueryHookName>(name: N, fn: HookFnMap[N]) => void;
36
38
  }
package/dist/index.d.ts CHANGED
@@ -26,4 +26,5 @@ export { saveQuery, listSavedQueries, getSavedQuery, updateSavedQuery, deleteSav
26
26
  export type { SavedQueryDef, SaveQueryRequest, QueryVisibility } from './api/savedQuery';
27
27
  export { listPresets, getDefaultListPreset, createListPreset, getListPreset, updateListPreset, deleteListPreset, setDefaultListPreset, clearDefaultListPreset } from './api/listPreset';
28
28
  export type { ListPresetScope, SaveListPresetRequest, UpdateListPresetRequest } from './api/listPreset';
29
- export type { ColumnSchema, EnhancedColumnSchema, TableConfig, TableSchema, CellRenderContext, CellRenderFn, CellCopyConfig, QueryMode, ColumnCustomization, QueryMetaResponse, ViewerQueryRequest, ViewerDataResponse, SliceRequestDef, OrderRequestDef, FilterOption, FetchDataParams, FetchDataResult, FetchDataFn, DictItem, PaginationState, SortState, QueryHooks, QueryHookContext, QueryTrigger, QueryHookName, BeforeQueryHookFn, AfterQueryHookFn, ErrorQueryHookFn, MaybePromise, PivotAxisField, PivotAxisPage, PivotAxisPageScope, PivotAxisRole, PivotHeaderNode, PivotHeaderRole, PivotMetric, PivotRawAxisMember, PivotRawCell, PivotRawPayload, PivotShape, PivotViewMode, PivotViewModel, ListPresetVisibility, ListPresetPlacement, ListPresetConfig, ColumnViewSetting, QueryConditionPreset, ListViewState, ListPresetDef, FrontendMeta, FieldMeta, FieldCategory, MemberLookupMeta, UiHintsMeta, DefaultsMeta, CapabilitiesMeta, ParamsMeta, MemberQueryRequest, MemberOption, MemberQueryResponse } from './types';
29
+ export { getTableDefaultQueryConfig } from './api/tableDefaultQueryConfig';
30
+ export type { ColumnSchema, EnhancedColumnSchema, TableConfig, TableSchema, CellRenderContext, CellRenderFn, GlobalColumnRenderContext, GlobalColumnMatchFn, GlobalColumnRenderFn, GlobalColumnRenderer, GlobalColumnRenderResolution, CellCopyConfig, QueryMode, ColumnCustomization, QueryMetaResponse, ViewerQueryRequest, ViewerDataResponse, SliceRequestDef, OrderRequestDef, FilterOption, FetchDataParams, FetchDataResult, FetchDataFn, DictItem, PaginationState, SortState, QueryHooks, QueryHookContext, QueryTrigger, QueryHookName, BeforeQueryHookFn, AfterQueryHookFn, ErrorQueryHookFn, SearchSource, SearchTrigger, SearchHookContext, SearchHookUpdate, SearchHookName, BeforeSearchHookFn, AfterSearchHookFn, ErrorSearchHookFn, SearchHooks, MaybePromise, PivotAxisField, PivotAxisPage, PivotAxisPageScope, PivotAxisRole, PivotHeaderNode, PivotHeaderRole, PivotMetric, PivotRawAxisMember, PivotRawCell, PivotRawPayload, PivotShape, PivotViewMode, PivotViewModel, ListPresetVisibility, ListPresetPlacement, ListPresetConfig, TableDefaultQueryConfig, TableDefaultQueryConfigScope, TableDefaultQueryConfigLoadOptions, TableDefaultQueryConfigSource, ColumnViewSetting, QueryConditionPreset, ListViewState, ListPresetDef, FrontendMeta, FieldMeta, FieldCategory, MemberLookupMeta, UiHintsMeta, DefaultsMeta, CapabilitiesMeta, ParamsMeta, MemberQueryRequest, MemberOption, MemberQueryResponse } from './types';