urit-qf-ui 0.2.7 → 1.0.0

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 (68) hide show
  1. package/README.md +88 -22
  2. package/dist/components/UBaseInfo.vue.d.ts +22 -0
  3. package/dist/components/UCascader.vue.d.ts +22 -37
  4. package/dist/components/UDialog.vue.d.ts +94 -0
  5. package/dist/components/UForm.vue.d.ts +233 -0
  6. package/dist/components/UMenu.vue.d.ts +230 -11
  7. package/dist/components/UResults.vue.d.ts +23 -0
  8. package/dist/components/USearch.vue.d.ts +51 -0
  9. package/dist/components/UTable.vue.d.ts +54 -0
  10. package/dist/components/UTablePage.vue.d.ts +152 -0
  11. package/dist/index.d.ts +33 -18
  12. package/dist/index.js +2962 -3147
  13. package/dist/index.umd.cjs +1 -2
  14. package/dist/layout/UGrid.vue.d.ts +44 -0
  15. package/dist/model/base-info.d.ts +113 -0
  16. package/dist/model/cascader.d.ts +135 -0
  17. package/dist/model/form.d.ts +143 -0
  18. package/dist/model/grid.d.ts +53 -0
  19. package/dist/model/menu.d.ts +140 -0
  20. package/dist/model/results.d.ts +90 -0
  21. package/dist/model/search.d.ts +93 -0
  22. package/dist/model/table-page.d.ts +44 -0
  23. package/dist/model/table.d.ts +163 -0
  24. package/dist/parser/cascader.d.ts +35 -0
  25. package/dist/parser/form.d.ts +7 -0
  26. package/dist/parser/menu.d.ts +5 -0
  27. package/dist/parser/table-page.d.ts +15 -0
  28. package/dist/parser/yaml-parser.d.ts +41 -0
  29. package/dist/qf/interface.d.ts +22 -0
  30. package/dist/qf/qf.d.ts +23 -1
  31. package/dist/style.css +1 -1
  32. package/dist/utils/base-info.d.ts +39 -0
  33. package/dist/utils/cascader.d.ts +45 -0
  34. package/dist/utils/form.d.ts +59 -0
  35. package/dist/utils/menu.d.ts +14 -0
  36. package/dist/utils/results.d.ts +38 -0
  37. package/dist/utils/search.d.ts +8 -0
  38. package/dist/utils/table.d.ts +16 -0
  39. package/package.json +1 -1
  40. package/dist/components/UDate.vue.d.ts +0 -47
  41. package/dist/components/UDict.vue.d.ts +0 -49
  42. package/dist/components/UInput.vue.d.ts +0 -52
  43. package/dist/components/UInputNumber.vue.d.ts +0 -52
  44. package/dist/components/UToggle.vue.d.ts +0 -54
  45. package/dist/show/UCascaderShow.vue.d.ts +0 -11
  46. package/dist/show/UDateShow.vue.d.ts +0 -15
  47. package/dist/show/UDictShow.vue.d.ts +0 -9
  48. package/dist/show/UFieldView.vue.d.ts +0 -24
  49. package/dist/show/UInputShow.vue.d.ts +0 -10
  50. package/dist/show/UToggleShow.vue.d.ts +0 -12
  51. package/dist/ts/constant.d.ts +0 -24
  52. package/dist/ts/dict.d.ts +0 -105
  53. package/dist/ts/form-render.d.ts +0 -30
  54. package/dist/ts/http.d.ts +0 -13
  55. package/dist/ts/model.d.ts +0 -202
  56. package/dist/ts/notify.d.ts +0 -42
  57. package/dist/ts/table-data-service.d.ts +0 -30
  58. package/dist/ts/table-render.d.ts +0 -210
  59. package/dist/uform/FormContainer.vue.d.ts +0 -37
  60. package/dist/uform/FormField.vue.d.ts +0 -16
  61. package/dist/uform/FormGrid.vue.d.ts +0 -24
  62. package/dist/uform/FormRender.vue.d.ts +0 -104
  63. package/dist/uform/TableDetail.vue.d.ts +0 -37
  64. package/dist/uform/TableGrid.vue.d.ts +0 -51
  65. package/dist/uform/TablePagination.vue.d.ts +0 -14
  66. package/dist/uform/TableRender.vue.d.ts +0 -618
  67. package/dist/uform/TableSearch.vue.d.ts +0 -38
  68. package/dist/uform/TableToolbar.vue.d.ts +0 -31
@@ -0,0 +1,44 @@
1
+ import { TableOptions } from './table';
2
+ import { SearchOptions } from './search';
3
+ /**
4
+ * 列表页用到的接口地址(yaml 的 api 段原样带出)。
5
+ *
6
+ * ⚠️ **只在配了对应地址时组件才发请求**,没配就把交互 emit 给使用方 —— 这是
7
+ * UTablePage 愿意内建请求的前提(与 UForm / UTable / USearch 的「组件不发请求」不冲突:
8
+ * 那几个组件没有 api 配置这一说,永远不会自己发)。
9
+ */
10
+ export interface TablePageApi {
11
+ /** 列表查询接口(GET)。查询 / 重置 / 翻页 / 增删改成功后都打它 */
12
+ list?: string;
13
+ /** 删除接口(POST)。主键走 query:`POST <delete>?<key>=<row[key]>` */
14
+ delete?: string;
15
+ /** 其它自定义接口地址原样保留(使用方自己消费) */
16
+ [key: string]: any;
17
+ }
18
+ /** 列表页配置:搜索条件 + 表格 + 页面级接口,前两者都能单独喂给对应组件 */
19
+ export interface TablePageConfig {
20
+ /** 表格配置,直接喂 <UTable :options> */
21
+ tableOptions: TableOptions;
22
+ /** 搜索栏配置,直接喂 <USearch :options> */
23
+ searchOptions: SearchOptions;
24
+ /**
25
+ * 主键字段名(yaml 的 `key`,如 `id`)。
26
+ * 删除与编辑回显都靠它拼参数:`?<key>=<row[key]>`;不写时组件兜底用 `'id'`。
27
+ */
28
+ key?: string;
29
+ /**
30
+ * 关联的表单配置 ID(yaml 的 `form`,如 `user`)。
31
+ * edit / add 时用它调 `GetFormConfig(form)` 取表单;也可由行按钮的 `action.form` 覆盖。
32
+ */
33
+ form?: string;
34
+ /** 接口地址(yaml 的 `api` 段):list / delete */
35
+ api?: TablePageApi;
36
+ /**
37
+ * 分页方式(yaml 的 `pagination`)。
38
+ * 非空表示列表接口吃 `page` / `pageSize`,组件会自动把这两个参数拼上,
39
+ * 并按 `{rows, total}` 解析响应(见 qfcms 的 pageSlice)。
40
+ */
41
+ pagination?: any;
42
+ /** 后端 yaml 的 meta 段原样带出(tableId / title / version) */
43
+ meta?: Record<string, any>;
44
+ }
@@ -0,0 +1,163 @@
1
+ /**
2
+ * UTable —— 动态列表格的数据结构定义(model 层)
3
+ *
4
+ * 本层只定义**数据结构**,不放任何逻辑:
5
+ * - 逻辑(取值 / 显示文案 / 列宽解析)在 ../utils/table.ts;
6
+ * - 后端 yaml → 本层结构的转换在 ../parser/table-page.ts。
7
+ *
8
+ * 设计原则:
9
+ * 1. 基于 el-table / el-table-column 封装,属性语义 = EP 原生语义。
10
+ * 2. 组件本身不发任何请求。数据、分页、排序、筛选全由使用方通过 props 传入,
11
+ * 交互一律通过事件抛出,操作栏一律通过插槽交给使用方渲染。
12
+ * 3. 列的个性化配置走 column.props 逃生舱,EP 的 el-table-column 有什么属性能配什么;
13
+ * 单元格内容默认按 field 取值渲染,需要自定义就配 column.slot 走具名插槽。
14
+ */
15
+ /**
16
+ * 列类型(渲染方式),与 form.ts 的 type 同思路,但表格列只区分「怎么显示」:
17
+ * text —— 纯文本(默认),按 field 取值
18
+ * tag —— el-tag 标签,可用 options 映射文字与颜色
19
+ * image —— el-image 图片
20
+ * link —— el-link 链接
21
+ * switch —— el-switch(只读展示场景少见,一般配 disabled)
22
+ * progress —— el-progress 进度条
23
+ * index —— 行序号(不需要 field)
24
+ * selection —— 多选勾选框(不需要 field)
25
+ * expand —— 展开行(内容走 expand 插槽)
26
+ * slot —— 完全交给使用方的具名插槽渲染
27
+ */
28
+ export type TableColumnType = 'text' | 'tag' | 'image' | 'link' | 'switch' | 'progress' | 'index' | 'selection' | 'expand' | 'slot';
29
+ /** tag 列的值映射项(把后端的 1/0 等映射成文字 + 颜色) */
30
+ export interface TableColumnOption {
31
+ /** 匹配的值 */
32
+ value: any;
33
+ /** 显示文字 */
34
+ label: string;
35
+ /** el-tag 的类型:primary / success / info / warning / danger */
36
+ type?: 'primary' | 'success' | 'info' | 'warning' | 'danger';
37
+ /** 自定义颜色(优先于 type,直接给 el-tag 的 color) */
38
+ color?: string;
39
+ }
40
+ /**
41
+ * 行操作按钮配置(对应 yaml 里 tables/<id>.yaml 的 actions)。
42
+ *
43
+ * 组件只负责把按钮画出来,点击时把**整个 action 配置**连同行数据通过
44
+ * `action-click` 事件原样抛出 —— 具体干什么(打开表单 / 调删除接口 …)由使用方决定。
45
+ * 所以 yaml 里附加的自定义字段(如 form: user)会一路保留到事件参数里。
46
+ *
47
+ * 注:页面底部的工具栏(导出/返回/设置…)是**页面级**的,不归 UTable。
48
+ */
49
+ export interface TableActionConfig {
50
+ /** 点击意图(edit / delete / add / 自定义),使用方按它分发 */
51
+ action: string;
52
+ /** 按钮文字 */
53
+ text?: string;
54
+ /** 按钮颜色类型(给 el-button 的 type):primary / success / warning / danger / info */
55
+ style?: 'primary' | 'success' | 'warning' | 'danger' | 'info';
56
+ /** 关联的表单配置 ID(edit / add 场景的提示信息,组件只透传不使用) */
57
+ form?: string;
58
+ /** 透传给 el-button 的其它属性(size / icon / plain / disabled …) */
59
+ props?: Record<string, any>;
60
+ /** 其它自定义字段原样保留(emit 时一并抛出) */
61
+ [key: string]: any;
62
+ }
63
+ /** 单列配置 */
64
+ export interface TableColumnConfig {
65
+ /**
66
+ * 取值字段名,对应行数据里的 key。
67
+ * 支持点路径(如 'user.name')。
68
+ * index / selection / expand 三类列不需要 field。
69
+ */
70
+ field?: string;
71
+ /** 列标题 */
72
+ label?: string;
73
+ /** 列渲染类型,默认 'text' */
74
+ type?: TableColumnType;
75
+ /**
76
+ * 透传给 el-table-column 的属性:
77
+ * width / minWidth / fixed / align / headerAlign / sortable / showOverflowTooltip …
78
+ */
79
+ props?: Record<string, any>;
80
+ /** 该列是否显示(false 或 hidden: true 都不渲染),默认显示 */
81
+ hidden?: boolean;
82
+ /** 列宽快捷写法(等价于 props.width),数字按 px */
83
+ width?: number | string;
84
+ /** 最小列宽快捷写法(等价于 props.minWidth),数字按 px */
85
+ minWidth?: number | string;
86
+ /** 固定列快捷写法(等价于 props.fixed) */
87
+ fixed?: boolean | 'left' | 'right';
88
+ /** 对齐快捷写法(等价于 props.align) */
89
+ align?: 'left' | 'center' | 'right';
90
+ /** 是否可排序快捷写法(等价于 props.sortable) */
91
+ sortable?: boolean | 'custom';
92
+ /** 内容超出是否显示 tooltip(等价于 props.showOverflowTooltip) */
93
+ showOverflowTooltip?: boolean;
94
+ /** tag 列的值映射(type: 'tag' 时生效) */
95
+ options?: TableColumnOption[];
96
+ /**
97
+ * 是否使用具名插槽渲染该列。
98
+ * 传字符串则作为插槽名(便于 field 与插槽名不一致);传 true 时用 field 当插槽名。
99
+ * 插槽作用域:{ row, column, $index, value }
100
+ */
101
+ slot?: boolean | string;
102
+ /** 空值占位文字,默认 '-' */
103
+ emptyText?: string;
104
+ /** 简单格式化:只有是函数时才生效(Vue 模板里也能配,适合日期等轻量转换) */
105
+ formatter?: (row: any, value: any, index: number) => any;
106
+ }
107
+ /** UTable 表格级配置 */
108
+ export interface TableOptions {
109
+ /** 列配置 */
110
+ columns: TableColumnConfig[];
111
+ /** 表格数据(也可以走组件的 data prop,两处取其一,data prop 优先) */
112
+ data?: any[];
113
+ /** 行数据的唯一键,透传给 el-table 的 row-key;不传则自动尝试用 id */
114
+ rowKey?: string;
115
+ /** 是否显示边框(等价于 el-table 的 border),默认 true */
116
+ border?: boolean;
117
+ /** 是否斑马纹,默认 false */
118
+ stripe?: boolean;
119
+ /** 是否显示表头,默认 true */
120
+ showHeader?: boolean;
121
+ /** 空数据文案,默认 '暂无数据' */
122
+ emptyText?: string;
123
+ /** 表格尺寸,默认继承 el-form 默认值 */
124
+ size?: 'large' | 'default' | 'small';
125
+ /** 是否默认展开所有行 */
126
+ defaultExpandAll?: boolean;
127
+ /** 行高(表头行高 + 数据行高快捷配置) */
128
+ headerRowClassName?: string | ((data: any) => string);
129
+ rowClassName?: string | ((data: any) => string);
130
+ /** 是否高亮当前行,默认 false */
131
+ highlightCurrentRow?: boolean;
132
+ /** 最大高度 / 高度(给 el-table 做固定表头用),数字按 px */
133
+ maxHeight?: number | string;
134
+ height?: number | string;
135
+ /** 默认排序,同 el-table 的 default-sort,如 {prop: 'createTime', order: 'descending'} */
136
+ defaultSort?: Record<string, any>;
137
+ /** 行操作按钮配置(点击意图 action + 文字 text + 颜色 style …)。点击时 emit action-click(整个配置, 行数据, 行号) */
138
+ actions?: TableActionConfig[];
139
+ /** 操作栏固定位置,默认 'right'(配了 actions 或传了 #actions 插槽才渲染操作栏) */
140
+ actionFixed?: boolean | 'left' | 'right';
141
+ /** 操作栏宽度,默认 160 */
142
+ actionWidth?: number | string;
143
+ /** 操作栏对齐,默认 'center' */
144
+ actionAlign?: 'left' | 'center' | 'right';
145
+ }
146
+ /** 表格列插槽作用域 */
147
+ export interface TableColumnSlotProps {
148
+ /** 当前行数据 */
149
+ row: any;
150
+ /** el-table-column 的 column 对象 */
151
+ column: any;
152
+ /** 行索引 */
153
+ $index: number;
154
+ /** 该列对应的值(已按 field 取好) */
155
+ value: any;
156
+ }
157
+ /** 操作栏插槽作用域(每行一份) */
158
+ export interface TableActionSlotProps {
159
+ /** 当前行数据 */
160
+ row: any;
161
+ /** 行索引 */
162
+ $index: number;
163
+ }
@@ -0,0 +1,35 @@
1
+ import { CascaderLevelMeta, CascaderOption, CascaderOptions } from '../model/cascader';
2
+ export declare class CascaderParser {
3
+ /**
4
+ * 逐级往下走 children,得到层级链(第 1 级在最前)。
5
+ * 一个 field 都没写就返回空数组(不猜)。
6
+ */
7
+ parseLevels(yaml: Record<string, any>): CascaderLevelMeta[];
8
+ /**
9
+ * 该 yaml 项是不是一个**级联** select。
10
+ * 判定依据只看结构,不看 dictType —— 单层字典下拉(type: dict + dictType)不是级联:
11
+ * - 内联树里有嵌套(节点带 children)或节点上描述了下一级(带 field)→ 是级联;
12
+ * - children 链声明了不止一级 → 是级联。
13
+ */
14
+ isCascade(yaml: Record<string, any>): boolean;
15
+ /**
16
+ * yaml 的级联项 → UCascader 配置。
17
+ * - 写法 B(有 options 树)→ options 直接就是规范化后的树;
18
+ * - 写法 A(children 链)→ options 是空数组,真实选项要用 stampLevels(字典树, levels) 拿到后再补上。
19
+ */
20
+ parse(yaml: Record<string, any>): CascaderOptions;
21
+ /**
22
+ * 把「每级一个字段名」的层级链打到字典树上:
23
+ * 深度 0 的节点打上 levels[1] 的 field/fieldLabel(**描述的是下一级**),
24
+ * 深度 1 的节点打上 levels[2],以此类推;最后一层的节点不带 field。
25
+ *
26
+ * 用于写法 A —— 整棵级联树来自一个 dictType,yaml 里只声明了每级叫什么。
27
+ * 返回新树,不改原数据。
28
+ */
29
+ stampLevels(tree: any, levels: CascaderLevelMeta[]): CascaderOption[];
30
+ /**
31
+ * 便捷组合:解析 + 打层级(拿到字典树之后一步到位)。
32
+ * 已经内联了 options 树(写法 B)时不会覆盖它。
33
+ */
34
+ build(yaml: Record<string, any>, tree: any): CascaderOptions;
35
+ }
@@ -0,0 +1,7 @@
1
+ import { FormConfig, FormFieldConfig } from '../model/form';
2
+ export declare class FormParser {
3
+ /** 单个 yaml 字段 → UForm 字段配置 */
4
+ parseField(yamlField: Record<string, any>): FormFieldConfig;
5
+ /** 表单 yaml → FormConfig(formOptions + api / layout / meta) */
6
+ parse(yaml: Record<string, any>): FormConfig;
7
+ }
@@ -0,0 +1,5 @@
1
+ import { MenuConfig } from '../model/menu';
2
+ export declare class MenuParser {
3
+ /** 菜单 yaml → MenuConfig(menuOptions + menuId / meta) */
4
+ parse(yaml: Record<string, any>): MenuConfig;
5
+ }
@@ -0,0 +1,15 @@
1
+ import { TablePageConfig } from '../model/table-page';
2
+ import { TableColumnConfig } from '../model/table';
3
+ import { SearchItem, SearchOptions } from '../model/search';
4
+ export declare class TablePageParser {
5
+ /** 级联(多级联动 select)单独处理,本类通过它把级联配置组合进搜索项 */
6
+ private readonly cascader;
7
+ /** 单个 yaml 列 → UTable 列配置 */
8
+ parseColumn(yamlColumn: Record<string, any>): TableColumnConfig;
9
+ /** 单个 yaml 搜索条件 → USearch 搜索项(级联项在这里交给 CascaderParser) */
10
+ parseSearchItem(yamlItem: Record<string, any>): SearchItem;
11
+ /** yaml 的 search 段 → USearch 配置(传数组或整份 yaml 都行) */
12
+ parseSearch(yaml: Record<string, any>[] | Record<string, any>): SearchOptions;
13
+ /** 列表页 yaml → TablePageConfig(表格 + 搜索条件 + 页面级参数) */
14
+ parse(yaml: Record<string, any>): TablePageConfig;
15
+ }
@@ -0,0 +1,41 @@
1
+ import { Http } from '../qf/http';
2
+ import { FormConfig } from '../model/form';
3
+ import { TablePageConfig } from '../model/table-page';
4
+ import { MenuConfig } from '../model/menu';
5
+ /**
6
+ * 配置类别(对应后端 /api/form 的 type 参数)
7
+ * forms —— 表单配置(config/forms/<id>.yaml)
8
+ * tables —— 表格配置(config/tables/<id>.yaml)
9
+ * menus —— 菜单配置(config/menus/<id>.yaml)
10
+ */
11
+ export type CfgType = 'forms' | 'tables' | 'menus';
12
+ /**
13
+ * 配置接口路径 —— 本文件是唯一真源,使用方要自己取原始 yaml 时也用它拼地址:
14
+ * `GetQf(options).Get(formCfgApi('user', 'tables'))`。
15
+ *
16
+ * GET /api/form?type=<forms|tables|menus>&id=<配置文件名称>
17
+ * 后端读取 ./output/config/<type>/<id>.yaml
18
+ *
19
+ * @param id 配置文件名称(不带 .yaml)
20
+ * @param type 配置类别:forms(表单)/ tables(表格)/ menus(菜单)
21
+ */
22
+ export declare function formCfgApi(id: string, type?: CfgType): string;
23
+ export declare class YamlParser {
24
+ /** Qf 的请求出口(qf/http 的 Http 实例,由 QfImpl 构造时传进来) */
25
+ private readonly WebApi;
26
+ private readonly formParser;
27
+ private readonly tablePageParser;
28
+ private readonly menuParser;
29
+ constructor(WebApi: Http);
30
+ /** 表单配置:取 forms/<id>.yaml → 交给 FormParser → FormConfig */
31
+ parseForm(id: string): Promise<FormConfig>;
32
+ /** 列表页配置:取 tables/<id>.yaml → 交给 TablePageParser → TablePageConfig */
33
+ parseTablePage(id: string): Promise<TablePageConfig>;
34
+ /** 菜单配置:取 menus/<id>.yaml → 交给 MenuParser → MenuConfig */
35
+ parseMenu(id: string): Promise<MenuConfig>;
36
+ /**
37
+ * 取一份后端配置(yaml 转出的 JSON,原样返回、不做转换)。
38
+ * 三个 parse 方法共用;请求失败 / 业务码非 0 时抛错,message 带上配置 ID 方便定位。
39
+ */
40
+ private getYaml;
41
+ }
@@ -1,3 +1,6 @@
1
+ import { FormConfig } from '../model/form';
2
+ import { TablePageConfig } from '../model/table-page';
3
+ import { MenuConfig } from '../model/menu';
1
4
  /**
2
5
  * 后端统一响应包。
3
6
  *
@@ -27,6 +30,25 @@ export interface QfInterface {
27
30
  /** 导出(POST + blob):返回**完整 AxiosResponse**,调用方取 .data as Blob */
28
31
  PostDownload<T>(url: string, data?: any): Promise<T>;
29
32
  RegNotice(topic: string, cb: (data: any) => void): void;
33
+ /**
34
+ * 取表单配置(GET /api/form?type=forms&id=<id>)并解析成 FormConfig。
35
+ * `config.formOptions` 直接喂 `<UForm :options="...">`;
36
+ * `config.api`(get / add / edit)与 `config.layout`(弹窗宽度等)由打开表单的一方消费。
37
+ */
38
+ GetFormConfig(id: string): Promise<FormConfig>;
39
+ /**
40
+ * 取列表页配置(GET /api/form?type=tables&id=<id>)并解析成 TablePageConfig。
41
+ * 直接喂 `<UTablePage :options="...">`(或只给 tableId,让它自己取);
42
+ * 也可以拆开分别给 `<UTable>` / `<USearch>` 用。
43
+ */
44
+ GetTablePageConfig(id: string): Promise<TablePageConfig>;
45
+ /**
46
+ * 取菜单配置(GET /api/form?type=menus&id=<id>)并解析成 MenuConfig。
47
+ * `config.menuOptions` 直接喂 `<UMenu :options="...">`。
48
+ * 字典菜单的 dictType 会原样带在 menuOptions 上 ——
49
+ * 字典树要使用方自己取好后填进 menus。
50
+ */
51
+ GetMenuConfig(id: string): Promise<MenuConfig>;
30
52
  }
31
53
  export interface QfOptions {
32
54
  module: string;
package/dist/qf/qf.d.ts CHANGED
@@ -2,6 +2,10 @@ import { Http } from './http';
2
2
  import { HttpResponse, QfInterface, QfOptions } from './interface';
3
3
  import { EventBus } from './event-bus';
4
4
  import { MqttAdapter } from './mqtt-adapter';
5
+ import { YamlParser } from '../parser/yaml-parser';
6
+ import { FormConfig } from '../model/form';
7
+ import { TablePageConfig } from '../model/table-page';
8
+ import { MenuConfig } from '../model/menu';
5
9
  /**
6
10
  * 初始化(或取回)Qf 单例 —— **使用方入口调用一次**,通常在 main.ts / App.vue 里:
7
11
  *
@@ -22,7 +26,7 @@ export declare const GetQf: (options: QfOptions) => QfInterface;
22
26
  * 而是用一个「免配 options」惰性建一个实例(后端 = 页面所在目录 + /api,即 resolveAppBase 的语义)。
23
27
  *
24
28
  * 为什么需要它:Qf 一般在 App.vue 里**异步**初始化(要先 fetch config.json),
25
- * 而组件(UDict 的字典、UMenu 的菜单、TableRender 的表格配置)可能在同一帧就已经发请求了。
29
+ * 而使用方与解析层(parser)可能在同一帧就已经想要取配置了。
26
30
  * 兜底实例随后会被真正的 GetQf(options) 替换,所以不会影响最终配置。
27
31
  */
28
32
  export declare const getQf: () => QfInterface;
@@ -31,6 +35,8 @@ export declare class QfImpl implements QfInterface {
31
35
  WebApi: Http;
32
36
  Mqtt: MqttAdapter;
33
37
  options: QfOptions;
38
+ /** 动态配置解析器(parser/):Qf 只做转发,实现都在解析层 */
39
+ yamlParser: YamlParser;
34
40
  constructor(options: QfOptions);
35
41
  /**
36
42
  * 初始化 Qf
@@ -46,4 +52,20 @@ export declare class QfImpl implements QfInterface {
46
52
  Download<T>(url: string, params?: any): Promise<T>;
47
53
  PostDownload<T>(url: string, data?: any): Promise<T>;
48
54
  RegNotice(topic: string, cb: (data: any) => void): void;
55
+ /**
56
+ * 取表单配置并解析(GET /api/form?type=forms&id=<id>)。
57
+ * 返回 FormConfig:`config.formOptions` 喂 <UForm :options>,
58
+ * `config.api` / `config.layout` 是页面级参数(提交地址、弹窗宽度),组件不吃。
59
+ */
60
+ GetFormConfig(id: string): Promise<FormConfig>;
61
+ /**
62
+ * 取列表页配置并解析(GET /api/form?type=tables&id=<id>)。
63
+ * 返回 TablePageConfig:直接喂 <UTablePage :options="...">(也可以只给 tableId 让它自己取)。
64
+ */
65
+ GetTablePageConfig(id: string): Promise<TablePageConfig>;
66
+ /**
67
+ * 取菜单配置并解析(GET /api/form?type=menus&id=<id>)。
68
+ * 返回 MenuConfig:`config.menuOptions` 喂 <UMenu :options>。
69
+ */
70
+ GetMenuConfig(id: string): Promise<MenuConfig>;
49
71
  }
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- @charset "UTF-8";.u-input[data-v-ecf5177c]{display:flex;width:100%}.u-input.u-input-label-left .u-input-label[data-v-ecf5177c]{padding-top:10px;flex-shrink:0;text-align:right;padding-right:12px;font-size:14px;color:#606266;white-space:nowrap}.u-input.u-input-label-left .u-input-field[data-v-ecf5177c]{flex:1}.u-input.u-input-label-top[data-v-ecf5177c]{flex-direction:column}.u-input.u-input-label-top .u-input-label[data-v-ecf5177c]{width:100%;font-size:14px;color:#606266;margin-bottom:8px;white-space:nowrap}.u-input .required-star[data-v-ecf5177c]{color:#f56c6c;display:inline-block;width:10px}.u-input .required-star[data-v-ecf5177c]:not(.required-star--visible){color:transparent}.u-input .u-input-field--top[data-v-ecf5177c]{width:100%}.u-input-number[data-v-cb70bd5b]{display:flex;width:100%}.u-input-number.u-input-number-label-left .u-input-number-label[data-v-cb70bd5b]{padding-top:10px;flex-shrink:0;text-align:right;padding-right:12px;font-size:14px;color:#606266;white-space:nowrap}.u-input-number.u-input-number-label-left .u-input-number-field[data-v-cb70bd5b]{flex:1}.u-input-number.u-input-number-label-top[data-v-cb70bd5b]{flex-direction:column}.u-input-number.u-input-number-label-top .u-input-number-label[data-v-cb70bd5b]{width:100%;font-size:14px;color:#606266;margin-bottom:8px;white-space:nowrap}.u-input-number .required-star[data-v-cb70bd5b]{color:#f56c6c;display:inline-block;width:10px}.u-input-number .required-star[data-v-cb70bd5b]:not(.required-star--visible){color:transparent}.u-dict[data-v-d0ae00fe]{display:flex;width:100%}.u-dict.u-dict-label-left .u-dict-label[data-v-d0ae00fe]{padding-top:10px;flex-shrink:0;text-align:right;padding-right:12px;font-size:14px;color:#606266;white-space:nowrap}.u-dict.u-dict-label-left .u-dict-field[data-v-d0ae00fe]{flex:1}.u-dict.u-dict-label-top[data-v-d0ae00fe]{flex-direction:column}.u-dict.u-dict-label-top .u-dict-label[data-v-d0ae00fe]{width:100%;font-size:14px;color:#606266;margin-bottom:8px;white-space:nowrap}.u-dict .required-star[data-v-d0ae00fe]{color:#f56c6c;display:inline-block;width:10px}.u-dict .required-star[data-v-d0ae00fe]:not(.required-star--visible){color:transparent}.u-toggle[data-v-94c1fd38]{display:flex;width:100%}.u-toggle.u-toggle-label-left[data-v-94c1fd38]{flex-direction:row;align-items:flex-start}.u-toggle.u-toggle-label-left .u-toggle-label[data-v-94c1fd38]{padding-top:10px;flex-shrink:0;text-align:right;padding-right:12px;margin-bottom:0;white-space:nowrap}.u-toggle.u-toggle-label-left .u-toggle-field[data-v-94c1fd38]{flex:1}.u-toggle[data-v-94c1fd38]:not(.u-toggle-label-left){flex-direction:column}.u-toggle:not(.u-toggle-label-left) .u-toggle-label[data-v-94c1fd38]{width:100%;margin-bottom:4px;white-space:nowrap}.u-toggle .u-toggle-label[data-v-94c1fd38]{font-size:14px;color:#606266}.u-toggle .u-toggle-label .required-star[data-v-94c1fd38]{color:#f56c6c;display:inline-block;width:10px}.u-toggle .u-toggle-label .required-star[data-v-94c1fd38]:not(.required-star--visible){color:transparent}.u-toggle .u-toggle-field[data-v-94c1fd38]{display:flex;align-items:center}.u-cascader[data-v-d66c339c]{display:flex;width:100%}.u-cascader.u-cascader-label-left[data-v-d66c339c]{flex-direction:row;align-items:flex-start}.u-cascader.u-cascader-label-left .u-cascader-label[data-v-d66c339c]{padding-top:10px;flex-shrink:0;text-align:right;padding-right:12px;margin-bottom:0;white-space:nowrap}.u-cascader.u-cascader-label-left .u-cascader-levels[data-v-d66c339c]{flex:1}.u-cascader[data-v-d66c339c]:not(.u-cascader-label-left){flex-direction:column}.u-cascader:not(.u-cascader-label-left) .u-cascader-label[data-v-d66c339c]{width:100%;margin-bottom:8px;white-space:nowrap}.u-cascader .u-cascader-label[data-v-d66c339c]{font-size:14px;color:#606266}.u-cascader .u-cascader-label .required-star[data-v-d66c339c]{color:#f56c6c;display:inline-block;width:10px}.u-cascader .u-cascader-label .required-star[data-v-d66c339c]:not(.required-star--visible){color:transparent}.u-cascader .u-cascader-levels[data-v-d66c339c]{display:flex;gap:8px;flex-wrap:wrap}.u-cascader .u-cascader-level[data-v-d66c339c]{flex:1;min-width:120px}.u-date[data-v-9cd05064]{display:flex;width:100%}.u-date.u-date-label-left[data-v-9cd05064]{flex-direction:row;align-items:flex-start}.u-date.u-date-label-left .u-date-label[data-v-9cd05064]{padding-top:10px;flex-shrink:0;text-align:right;padding-right:12px;margin-bottom:0;white-space:nowrap}.u-date.u-date-label-left .u-date-field[data-v-9cd05064]{flex:1}.u-date[data-v-9cd05064]:not(.u-date-label-left){flex-direction:column}.u-date:not(.u-date-label-left) .u-date-label[data-v-9cd05064]{width:100%;margin-bottom:8px;white-space:nowrap}.u-date .u-date-label[data-v-9cd05064]{font-size:14px;color:#606266}.u-date .u-date-label .required-star[data-v-9cd05064]{color:#f56c6c;display:inline-block;width:10px}.u-date .u-date-label .required-star[data-v-9cd05064]:not(.required-star--visible){color:transparent}.u-menu[data-v-41cadcd8]{display:flex;height:100%;min-height:0;background:#fff}.u-menu .u-menu-icon[data-v-41cadcd8]{margin-right:6px}.u-menu.u-menu--sidebar[data-v-41cadcd8]{flex-direction:column;border-right:1px solid #e4e7ed}.u-menu.u-menu--sidebar .u-menu-brand[data-v-41cadcd8]{flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:16px 12px;border-bottom:1px solid #e4e7ed}.u-menu.u-menu--sidebar .u-menu-list[data-v-41cadcd8]{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;border-right:none}.u-menu.u-menu--sidebar .u-menu-logout[data-v-41cadcd8]{flex-shrink:0;width:100%;border-top:1px solid #e4e7ed}.u-menu.u-menu--sidebar .u-menu-logout-btn[data-v-41cadcd8]{display:block;width:100%}.u-menu.u-menu--horizontal[data-v-41cadcd8]{flex-direction:row;align-items:center;width:100%;border-bottom:1px solid #e4e7ed}.u-menu.u-menu--horizontal .u-menu-brand[data-v-41cadcd8]{flex-shrink:0;display:flex;align-items:center;padding:0 16px;white-space:nowrap}.u-menu.u-menu--horizontal .u-menu-list[data-v-41cadcd8]{flex:1;min-width:0;border-bottom:none}.u-menu.u-menu--horizontal .u-menu-logout[data-v-41cadcd8]{flex-shrink:0;display:flex;align-items:center;padding:0 12px;margin-left:auto}.u-menu .u-menu-logo[data-v-41cadcd8]{height:28px;margin-right:8px}.u-menu .u-menu-brand-text[data-v-41cadcd8]{font-size:18px;font-weight:600;color:#303133;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.form-content[data-v-83362259]{min-height:100px}.form-layout[data-v-83362259]{width:100%;background:#fff}.form-header[data-v-83362259]{display:flex;align-items:center;padding:16px;border-bottom:1px solid #eee}.form-header .title[data-v-83362259]{font-size:18px;font-weight:500}.form-body[data-v-83362259]{padding:16px;min-height:100px}.form-footer[data-v-83362259]{display:flex;justify-content:flex-end;gap:8px;padding:16px;border-top:1px solid #eee}.is-loading[data-v-83362259]{display:flex;justify-content:center;align-items:center;min-height:100px;color:#409eff}.form-grid[data-v-90ed35a4]{display:grid;grid-template-columns:repeat(var(--grid-columns, 1),minmax(0,1fr));gap:8px;width:100%}.form-grid-item[data-v-90ed35a4]{min-width:0}.form-field[data-v-96994a9a]{width:100%}.field-error[data-v-96994a9a]{color:#f56c6c;font-size:12px;min-height:12px;line-height:1.5;transition:opacity .2s}.field-error[data-v-96994a9a]:not(.field-error--visible){opacity:0}.form-render[data-v-b3267c00]{width:100%}.form-actions[data-v-b3267c00]{display:flex;gap:8px}.justify-end[data-v-b3267c00]{justify-content:flex-end}.justify-start[data-v-b3267c00]{justify-content:flex-start}.table-search[data-v-0281d2ce]{display:flex;align-items:center;flex-wrap:wrap;gap:12px;padding:16px;background:#fff;border-bottom:1px solid #eee}.table-search .search-fields[data-v-0281d2ce]{display:flex;flex-wrap:wrap;gap:12px}.table-search .search-field[data-v-0281d2ce]{display:flex;align-items:center;gap:8px;min-width:200px}.table-search .search-actions[data-v-0281d2ce]{display:flex;gap:8px;flex-shrink:0}.table-toolbar[data-v-2a87e101]{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:8px;padding:12px 16px;border-top:1px solid darkgrey}.table-toolbar .toolbar-items[data-v-2a87e101]{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.u-input-show[data-v-c78b151e]{font-size:14px;line-height:1.5;color:#333;word-break:break-all}.u-input-show.u-input-multiline[data-v-c78b151e]{white-space:pre-wrap}.u-dict-show[data-v-908045c4]{font-size:14px;line-height:1.5;color:#333}.u-dict-show.u-dict-loading[data-v-908045c4]{color:#999}.u-toggle-show[data-v-bac05efc]{display:inline-block;padding:2px 8px;border-radius:4px;font-size:14px;line-height:1.5}.u-toggle-show.toggle-true[data-v-bac05efc]{background-color:#e6f7ed;color:#52c41a}.u-toggle-show.toggle-false[data-v-bac05efc]{background-color:#fff1f0;color:#ff4d4f}.u-toggle-show.toggle-default[data-v-bac05efc]{color:#999}.u-cascader-show[data-v-5d84df67]{font-size:14px;line-height:1.5;color:#333}.u-cascader-show.u-cascader-loading[data-v-5d84df67]{color:#999}.u-date-show[data-v-930657df]{font-size:14px;line-height:1.5;color:#333}.u-date-show.u-date-empty[data-v-930657df]{color:#999}.u-field-view[data-v-05ef52d9]{display:inline-block}.table-grid[data-v-d3eed11d]{background:#fff}.table-grid .no-data[data-v-d3eed11d]{padding:48px;text-align:center;color:#999}.table-grid[data-v-d3eed11d] .table-grid-active-row td.el-table__cell{background-color:var(--el-color-primary-light-9, #ecf5ff)!important}.table-pagination[data-v-2ca77d18]{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:#fff;border-top:1px solid #eee}.table-pagination .page-size-select[data-v-2ca77d18]{display:flex;align-items:center;gap:12px}.table-pagination .total-text[data-v-2ca77d18]{color:#666;font-size:14px}.table-pagination .load-more[data-v-2ca77d18]{flex:1;text-align:center}.table-detail[data-v-7e47b0ba]{display:flex;flex-direction:column;height:100%;min-height:0;background:#fff}.table-detail .detail-header[data-v-7e47b0ba]{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid #ebeef5}.table-detail .detail-header .detail-title[data-v-7e47b0ba]{font-size:15px;font-weight:500}.table-detail .detail-body[data-v-7e47b0ba]{flex:1;min-height:0;overflow:auto}.table-detail .detail-status[data-v-7e47b0ba]{display:flex;align-items:center;justify-content:center;height:100%;padding:24px;color:#999;font-size:13px}.table-detail .detail-content[data-v-7e47b0ba]{padding:4px 16px 16px}.table-detail .detail-item[data-v-7e47b0ba]{display:flex;padding:12px 0;border-bottom:1px solid #eee}.table-detail .detail-item[data-v-7e47b0ba]:last-child{border-bottom:none}.table-detail .detail-item .detail-label[data-v-7e47b0ba]{width:100px;flex-shrink:0;color:#666;font-size:14px}.table-detail .detail-item .detail-value[data-v-7e47b0ba]{flex:1;min-width:0;color:#333;font-size:14px;word-break:break-all}.table-render[data-v-1d0ae5e9]{display:flex;flex-direction:column;height:100%;min-height:0;background:#fff}.table-render .table-body[data-v-1d0ae5e9]{display:flex;flex:1;min-height:0;overflow:hidden}.table-render .table-container[data-v-1d0ae5e9]{flex:1;display:flex;flex-direction:column;min-width:0;overflow:hidden}.table-render .table-container[data-v-1d0ae5e9] .table-grid{flex:1;min-height:0;max-height:var(--table-grid-max-height, none)}.table-render .table-container[data-v-1d0ae5e9] .table-grid>.el-table{height:100%}.table-render .table-pagination[data-v-1d0ae5e9]{flex-shrink:0}.table-render .table-detail-inline[data-v-1d0ae5e9]{flex-shrink:0;height:100%;overflow:hidden;border-left:1px solid #ebeef5}.table-render .table-detail-inline.table-detail-inline-left[data-v-1d0ae5e9]{order:-1;border-left:none;border-right:1px solid #ebeef5}.table-render .table-toolbar-bottom[data-v-1d0ae5e9]{flex-shrink:0}
1
+ @charset "UTF-8";.u-form[data-v-4d3a2327]{width:100%}.u-form-tip[data-v-4d3a2327]{width:100%;font-size:12px;line-height:1.5;color:#909399;margin-top:2px}.u-table[data-v-4abfaa00]{width:100%}.u-table-image[data-v-4abfaa00]{width:40px;height:40px;border-radius:4px;vertical-align:middle}.u-table-actions[data-v-4abfaa00]{display:flex;align-items:center;justify-content:center;gap:4px;flex-wrap:wrap}.u-cascader[data-v-8fb1ac06]{display:flex;width:100%}.u-cascader .u-cascader-label[data-v-8fb1ac06]{flex-shrink:0;font-size:14px;color:#606266;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.u-cascader .u-cascader-level[data-v-8fb1ac06]{display:flex;align-items:center;flex:1 1 0;min-width:0}.u-cascader .u-cascader-control[data-v-8fb1ac06]{flex:1;min-width:0}.u-cascader.u-cascader--label-left .u-cascader-label[data-v-8fb1ac06]{padding-right:8px}.u-cascader.u-cascader--label-top[data-v-8fb1ac06]{align-items:flex-start}.u-cascader.u-cascader--label-top .u-cascader-level[data-v-8fb1ac06]{flex-direction:column;align-items:stretch}.u-cascader.u-cascader--label-top .u-cascader-label[data-v-8fb1ac06]{line-height:1.6;margin-bottom:4px;padding-right:0;text-align:left}.u-cascader.u-cascader--disabled[data-v-8fb1ac06]{opacity:.85}.u-search[data-v-bf97f714]{display:flex;align-items:flex-start;flex-wrap:wrap;gap:12px;width:100%}.u-search.u-search--disabled[data-v-bf97f714]{opacity:.85}.u-search .u-search-fields[data-v-bf97f714]{display:flex;align-items:flex-start;flex-wrap:wrap;flex:1;min-width:0}.u-search .u-search-item[data-v-bf97f714]{display:flex;flex-shrink:0;min-width:0}.u-search .u-search-label[data-v-bf97f714]{flex-shrink:0;font-size:14px;line-height:32px;color:#606266;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.u-search .u-search-control[data-v-bf97f714],.u-search .u-search-cascade[data-v-bf97f714]{flex:1;min-width:0}.u-search .u-search-actions[data-v-bf97f714]{display:flex;align-items:center;flex-shrink:0;margin-left:auto}.u-search.u-search--label-left .u-search-item[data-v-bf97f714]{align-items:center}.u-search.u-search--label-left .u-search-label[data-v-bf97f714]{padding-right:8px}.u-search.u-search--label-top .u-search-item[data-v-bf97f714]{flex-direction:column;align-items:stretch}.u-search.u-search--label-top .u-search-label[data-v-bf97f714]{line-height:1.6;margin-bottom:4px;padding-right:0;text-align:left}.u-search.u-search--label-top .u-search-actions[data-v-bf97f714]{align-self:flex-end}.u-dialog-body[data-v-1343d239]{min-height:24px}.u-dialog-loading[data-v-1343d239]{padding:24px 0;text-align:center;font-size:13px;color:#909399}.u-dialog--no-header .el-dialog__header{display:none}.u-table-page[data-v-ab43e7b3]{display:flex;flex-direction:column;gap:12px;width:100%;min-width:0}.u-table-page--fill[data-v-ab43e7b3]{overflow:hidden}.u-table-page-search[data-v-ab43e7b3],.u-table-page-pagination[data-v-ab43e7b3],.u-table-page-footer[data-v-ab43e7b3]{flex-shrink:0}.u-table-page-table[data-v-ab43e7b3]{flex:1 1 auto;min-height:0}.u-table-page--fill .u-table-page-table[data-v-ab43e7b3]{overflow:hidden}.u-table-page--fill .u-table-page-table>.u-table[data-v-ab43e7b3]{height:100%}.u-table-page-pagination[data-v-ab43e7b3]{display:flex;justify-content:flex-end}.u-table-page-footer[data-v-ab43e7b3]{display:flex;align-items:center}.u-table-page-form[data-v-ab43e7b3]{min-height:80px}.u-table-page-form-tip[data-v-ab43e7b3]{padding:24px 0;text-align:center;font-size:13px;color:#909399}.u-menu[data-v-fd5c101a]{display:flex;height:100%;min-height:0;background:#fff}.u-menu .u-menu-icon[data-v-fd5c101a]{margin-right:6px}.u-menu .u-menu-list[data-v-fd5c101a] .el-sub-menu__title{font-weight:600}.u-menu.u-menu--sidebar[data-v-fd5c101a]{flex-direction:column;border-right:1px solid #e4e7ed}.u-menu.u-menu--sidebar .u-menu-brand[data-v-fd5c101a]{flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:16px 12px;border-bottom:1px solid #e4e7ed}.u-menu.u-menu--sidebar .u-menu-list[data-v-fd5c101a]{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;border-right:none}.u-menu.u-menu--sidebar .u-menu-logout[data-v-fd5c101a]{flex-shrink:0;width:100%;border-top:1px solid #e4e7ed}.u-menu.u-menu--sidebar .u-menu-logout-btn[data-v-fd5c101a]{display:block;width:100%}.u-menu.u-menu--horizontal[data-v-fd5c101a]{flex-direction:row;align-items:center;width:100%;border-bottom:1px solid #e4e7ed}.u-menu.u-menu--horizontal .u-menu-brand[data-v-fd5c101a]{flex-shrink:0;display:flex;align-items:center;padding:0 16px;white-space:nowrap}.u-menu.u-menu--horizontal .u-menu-list[data-v-fd5c101a]{flex:1;min-width:0;border-bottom:none}.u-menu.u-menu--horizontal .u-menu-logout[data-v-fd5c101a]{flex-shrink:0;display:flex;align-items:center;padding:0 12px;margin-left:auto}.u-menu .u-menu-logo[data-v-fd5c101a]{height:28px;margin-right:8px}.u-menu .u-menu-brand-text[data-v-fd5c101a]{font-size:18px;font-weight:600;color:#303133;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.u-base-info[data-v-ad75dd63]{box-sizing:border-box;width:100%;min-width:0}.u-base-info-grid[data-v-ad75dd63]{display:grid;align-items:start}.u-base-info-item[data-v-ad75dd63]{display:flex;align-items:center;min-width:0;font-size:14px;line-height:1.6}.u-base-info-item.is-top[data-v-ad75dd63]{flex-direction:column;align-items:flex-start;gap:2px}.u-base-info-label[data-v-ad75dd63]{display:inline-block;flex-shrink:0;box-sizing:border-box;color:#606266}.u-base-info-label.is-justify .u-base-info-label-text[data-v-ad75dd63]{display:inline-block;width:calc(100% - 1em);text-align:justify;text-align-last:justify}.u-base-info-value[data-v-ad75dd63]{flex:1;min-width:0;color:#303133;word-break:break-word}.u-base-info-empty[data-v-ad75dd63]{display:flex;align-items:center;justify-content:center;min-height:48px;font-size:13px;color:#c0c4cc}.u-results[data-v-a44e2489]{box-sizing:border-box;display:flex;flex-direction:column;width:100%;min-width:0;font-size:14px;line-height:1.5;color:#303133;background:var(--u-results-item-bg)}.u-results-body[data-v-a44e2489]{flex:1;min-height:0;overflow:auto}.u-results-head[data-v-a44e2489]{display:grid;position:sticky;top:0;z-index:2;background:var(--u-results-header-bg);color:var(--u-results-header-color);font-weight:600}.u-results-row[data-v-a44e2489]{display:grid;background:var(--u-results-item-bg)}.u-results-row.is-striped[data-v-a44e2489]:nth-child(2n){background:var(--u-results-stripe-bg)}.u-results-cell[data-v-a44e2489]{display:flex;align-items:center;box-sizing:border-box;min-width:0;padding:8px 12px;overflow-wrap:break-word;word-break:break-word}.u-results.is-border[data-v-a44e2489]{border:1px solid var(--u-results-line)}.u-results.is-border .u-results-head[data-v-a44e2489]{border-bottom:1px solid var(--u-results-line)}.u-results.is-border .u-results-row+.u-results-row[data-v-a44e2489]{border-top:1px solid var(--u-results-line)}.u-results.is-border .u-results-cell+.u-results-cell[data-v-a44e2489]{border-left:1px solid var(--u-results-line)}.u-results-empty[data-v-a44e2489]{display:flex;align-items:center;justify-content:center;padding:24px 12px;font-size:13px;color:#909399}.u-grid[data-v-8011a025]{box-sizing:border-box;overflow:hidden}.u-grid-cards[data-v-8011a025]{box-sizing:border-box;width:100%;height:100%;align-content:flex-start;overflow:auto}.u-grid-card-col[data-v-8011a025]{box-sizing:border-box;min-width:0;min-height:0}.u-grid-card[data-v-8011a025]{box-sizing:border-box;width:100%;height:100%;background:#fff;border:1px solid #ebeef5;overflow:hidden;min-width:0;min-height:0;justify-content:center;align-items:center}.u-grid-card-default[data-v-8011a025]{font-size:14px;color:#909399}.u-grid-empty[data-v-8011a025]{display:flex;align-items:center;justify-content:center;min-height:120px;font-size:13px;color:#c0c4cc}
@@ -0,0 +1,39 @@
1
+ import { BaseInfoItem, BaseInfoLabelAlign, BaseInfoLayout, BaseInfoOptions } from '../model/base-info';
2
+ import { getByPath, toCssSize, toDisplayText } from './form';
3
+ export { getByPath, toCssSize, toDisplayText };
4
+ /** label 在 value 左边时的默认宽度:5em = 4 个汉字 + 1 个全角冒号(跟着字号缩放) */
5
+ export declare const DEFAULT_LABEL_WIDTH = "5em";
6
+ /** 默认间距(行间距 8px、栏间距 24px) */
7
+ export declare const DEFAULT_GAP = "8px 24px";
8
+ /** 栏数:默认 3,至少 1;非法值(0 / 负数 / NaN / 字符串垃圾)一律回退默认 */
9
+ export declare function resolveColumns(columns?: number): number;
10
+ /** 布局:默认 left(label 在 value 左边);只有明确写 top 才走上下布局 */
11
+ export declare function resolveLayout(layout?: BaseInfoLayout): BaseInfoLayout;
12
+ /**
13
+ * label 对齐:默认 right(右对齐,报告单最常见)。
14
+ * 上下布局时强制 left —— 顶部 label 是整行宽度,右对齐 / 两端对齐都没有意义。
15
+ */
16
+ export declare function resolveLabelAlign(align: BaseInfoLabelAlign | undefined, layout: BaseInfoLayout): BaseInfoLabelAlign;
17
+ /** label 宽度 -> css 尺寸(不给或给了空串就用默认 5em) */
18
+ export declare function resolveLabelWidth(width: number | string | undefined): string;
19
+ /**
20
+ * 冒号:只有「label 在左边」时才会出现。
21
+ * `layout: 'top'` → 永远返回空串(顶部不带冒号)
22
+ * `colon: false` → 返回空串(显式关掉)
23
+ * 其余 → `colonText`,不给则全角冒号 `:`
24
+ */
25
+ export declare function resolveColon(colon: boolean | undefined, layout: BaseInfoLayout, colonText?: string): string;
26
+ /**
27
+ * 取该条的原始值:`item.value` 优先(写死的常量),否则按 `field` 从数据对象里取。
28
+ * `value` 用 `!== undefined` 判断,所以 `value: ''` / `value: null` 算「显式给了空值」,不会再去取 field。
29
+ */
30
+ export declare function resolveItemValue(item: BaseInfoItem | undefined, record?: Record<string, any>): any;
31
+ /** 该条是否用插槽渲染 value(字符串 = 插槽名;true = 用 field 当插槽名);没用插槽返回 undefined */
32
+ export declare function resolveItemSlotName(item: BaseInfoItem | undefined): string | undefined;
33
+ /** 跨栏数:默认 1(不跨栏),最多不超过总栏数 */
34
+ export declare function resolveSpan(span: number | undefined, columns: number): number;
35
+ /** 栅格样式:栏数 + 间距(间距走 toCssSize,数字按 px;不传用默认 '8px 24px') */
36
+ export declare function gridStyle(options: BaseInfoOptions | null | undefined, columns: number): {
37
+ gridTemplateColumns: string;
38
+ gap: string;
39
+ };
@@ -0,0 +1,45 @@
1
+ import { CascaderLevel, CascaderOption, CascaderSource } from '../model/cascader';
2
+ export { getByPath, setByPath, isEmptyValue, toCssSize } from './form';
3
+ /** 该配置是否是级联(选项树里存在 children) */
4
+ export declare function isCascadedSelect(item: CascaderSource): boolean;
5
+ /**
6
+ * 该级联项一共要渲染几级 = 选项树的最大深度(至少 1 级)。
7
+ * 层级是**静态**算出来的:一级都没选也要把每一级都画出来。
8
+ */
9
+ export declare function selectDepth(item: CascaderSource): number;
10
+ /**
11
+ * 收集该项可能用到的**全部**层级字段名(第 1 级 + 树上每个节点的 field)。
12
+ * 用于「上一级改选后把更深层级清空」—— 清的不只是当前已渲染出来的那几级,
13
+ * 还有历史选过、当前分支用不到的那些字段。
14
+ */
15
+ export declare function collectLevelFields(item: CascaderSource): string[];
16
+ /**
17
+ * 算出该级联项的「层级骨架」:每一级渲染用哪个字段、标签叫什么。
18
+ *
19
+ * 完全由选项树**静态**决定,跟当前选中什么无关:
20
+ * 第 1 级 = item.field / item.fieldLabel(或 item.label);
21
+ * 之后每一级的 field / fieldLabel = 上一级里**第一个有子级的节点**的 field / fieldLabel
22
+ * (同一层的节点通常声明同一个字段名,取第一个就够)。
23
+ * 只有这样才能做到「一级都没选,3 个下拉连标签也全都画出来」。
24
+ */
25
+ export declare function buildLevelSkeleton(item: CascaderSource): Array<{
26
+ field: string;
27
+ label: string;
28
+ }>;
29
+ /**
30
+ * 按当前模型对象算出级联每一级要渲染的内容。
31
+ *
32
+ * 层级数固定 = selectDepth(**与是否选中无关**,默认全部渲染):
33
+ * - field / label 取自静态骨架(见 buildLevelSkeleton),所以未选择时标签也是对的;
34
+ * - options:第 1 级是配置的选项树,之后每一级 = 上一级**已选中节点**的 children;
35
+ * 上一级没选(或选中的节点没有下级)时就是空数组 —— 下拉照样在,只是没有可选项;
36
+ * - value:按该级的 field 从模型对象里取。
37
+ */
38
+ export declare function buildSelectLevels(item: CascaderSource, model: Record<string, any>): CascaderLevel[];
39
+ /**
40
+ * 把「普通树」规范成级联选项树(使用方从字典/接口拿到树后可以直接过一遍)。
41
+ * - 显示文字依次取 label / text / name / dict_value;
42
+ * - 值依次取 value / id / dict_code / info.code;
43
+ * - field / fieldLabel / disabled 原样保留,children 递归。
44
+ */
45
+ export declare function normalizeCascaderTree(list: any): CascaderOption[];
@@ -0,0 +1,59 @@
1
+ import { FormControlType, FormFieldConfig, FormOptions } from '../model/form';
2
+ /** 该控件类型的校验触发时机是 change 还是 blur */
3
+ export declare function getValidateTrigger(type?: FormControlType): 'change' | 'blur';
4
+ /** 按点路径读值:'info.remark' -> model.info.remark;path 为空直接返回 undefined */
5
+ export declare function getByPath(target: any, path?: string): any;
6
+ /**
7
+ * 按点路径写值(会浅拷贝沿途对象,不污染原引用)。
8
+ * 顶层对象由调用方自行拷贝,这里只保证中间层不被改写。
9
+ */
10
+ export declare function setByPath(target: any, path: string, value: any): void;
11
+ /**
12
+ * 是否空值(undefined / null / '' / 空数组,或数组里全是空值)。
13
+ * 表单、搜索栏、级联都用它判断「这个值算不算没填」,故放在这里共用。
14
+ */
15
+ export declare function isEmptyValue(value: any): boolean;
16
+ /**
17
+ * 数值 / css 尺寸归一(数字按 px):labelWidth / itemWidth / 列宽 / 宽高都用它。
18
+ *
19
+ * ⚠️ **纯数字字符串也按 px 处理**(`'240'` → `'240px'`)。因为它多半来自 YAML/JSON
20
+ * (`width: '240'`)或组件的字符串 form 值,而 CSS 的 `width: 240` 是**无效值**、
21
+ * 会静默失效(不报错、尺寸就是不生效),这种坑很难查。带单位的字符串(`'5em'` /
22
+ * `'100%'` / `'8px 24px'`)原样返回,不受影响。
23
+ */
24
+ export declare function toCssSize(value: number | string | undefined): string | undefined;
25
+ /**
26
+ * 把值转成可显示的文本(null / undefined / 空串统一走空值占位)。
27
+ * 表格单元格、报告信息栏都要用同一套「空值怎么显示」的语义,故放在这个底座文件里。
28
+ */
29
+ export declare function toDisplayText(value: any, emptyText?: string): string;
30
+ /**
31
+ * 依据配置生成表单初始数据(只取配了 default 的字段)。
32
+ * 组件本身不会自动注入默认值 —— 表单数据始终由使用方通过 v-model 掌控。
33
+ */
34
+ export declare function getDefaultModel(options: FormOptions): Record<string, any>;
35
+ /** 该字段是否必填(配置了 required 或给了一条 required 规则) */
36
+ export declare function isRequiredField(field: FormFieldConfig): boolean;
37
+ /**
38
+ * 嵌套对象 → 扁平的「点路径」模型(表单回显用)。
39
+ *
40
+ * 后端返回的是 `{id: 1, info: {remark: 'x'}}`,而表单字段写的是 `'info.remark'`,
41
+ * 扁平化后 `model['info.remark']` 才有值、控件才显示得出来。
42
+ *
43
+ * 只摊平传入的 field 列表(不是递归摊平全部)—— 表单配了哪些点路径字段就摊哪些,
44
+ * 其余键(含顶层对象本身)原样保留,这样提交时信息不丢。
45
+ *
46
+ * @param source 后端返回的原始对象
47
+ * @param fields 需要摊平的字段名(含点路径的才有作用),一般传 `formOptions.fields.map(f => f.field)`
48
+ */
49
+ export declare function nestedToFlat(source?: Record<string, any>, fields?: string[]): Record<string, any>;
50
+ /**
51
+ * 扁平的「点路径」模型 → 嵌套对象(表单提交用),是 nestedToFlat 的逆运算。
52
+ *
53
+ * 表单里填的是 `'info.remark'`,而后端接的是 `models.UserInfo`(`Info` 是嵌套对象),
54
+ * 所以要还原成 `{info: {remark: 'x'}}` 再提交。
55
+ *
56
+ * 规则:不含点号的键先原样铺一层(包括 `info` 这个对象本身),
57
+ * 再让点路径键覆盖它下面的子键 —— 所以「顶层有 info,同时又有 info.remark」时以点路径为准。
58
+ */
59
+ export declare function flattenToNested(source?: Record<string, any>): Record<string, any>;
@@ -0,0 +1,14 @@
1
+ import { MenuItem } from '../model/menu';
2
+ /**
3
+ * 规范化菜单列表(**只做兜底、不做业务**):
4
+ * - 依次尝试 label / name 当显示文字,两者都没有的节点丢弃;
5
+ * - type 缺省补 'route',path / icon 缺省补空串;
6
+ * - children 递归处理(最多 2 级,第 2 级的 children 会被丢掉)。
7
+ *
8
+ * 用来兼容 yaml 里「用 name 代替 label」这类写法。
9
+ * 字典节点(dict_value / info.code)不在这里处理 —— 那是使用方的活:
10
+ * 使用方按 dictType 取到字典树后,先用 utils/cascader 的 normalizeCascaderTree 转一遍再喂进来。
11
+ */
12
+ export declare function normalizeMenuList(list: any): MenuItem[];
13
+ /** 规范化单个菜单节点(配合 normalizeMenuList 使用) */
14
+ export declare function normalizeMenuNode(node: any): MenuItem | null;