urit-qf-ui 0.2.6 → 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.
- package/README.md +88 -22
- package/dist/components/UBaseInfo.vue.d.ts +22 -0
- package/dist/components/UCascader.vue.d.ts +22 -37
- package/dist/components/UDialog.vue.d.ts +94 -0
- package/dist/components/UForm.vue.d.ts +233 -0
- package/dist/components/UMenu.vue.d.ts +230 -11
- package/dist/components/UResults.vue.d.ts +23 -0
- package/dist/components/USearch.vue.d.ts +51 -0
- package/dist/components/UTable.vue.d.ts +54 -0
- package/dist/components/UTablePage.vue.d.ts +152 -0
- package/dist/index.d.ts +35 -20
- package/dist/index.js +3078 -3276
- package/dist/index.umd.cjs +1 -2
- package/dist/layout/UGrid.vue.d.ts +44 -0
- package/dist/model/base-info.d.ts +113 -0
- package/dist/model/cascader.d.ts +135 -0
- package/dist/model/form.d.ts +143 -0
- package/dist/model/grid.d.ts +53 -0
- package/dist/model/menu.d.ts +140 -0
- package/dist/model/results.d.ts +90 -0
- package/dist/model/search.d.ts +93 -0
- package/dist/model/table-page.d.ts +44 -0
- package/dist/model/table.d.ts +163 -0
- package/dist/parser/cascader.d.ts +35 -0
- package/dist/parser/form.d.ts +7 -0
- package/dist/parser/menu.d.ts +5 -0
- package/dist/parser/table-page.d.ts +15 -0
- package/dist/parser/yaml-parser.d.ts +41 -0
- package/dist/qf/http.d.ts +50 -28
- package/dist/qf/interface.d.ts +45 -4
- package/dist/qf/qf.d.ts +52 -6
- package/dist/style.css +1 -1
- package/dist/utils/base-info.d.ts +39 -0
- package/dist/utils/cascader.d.ts +45 -0
- package/dist/utils/form.d.ts +59 -0
- package/dist/utils/menu.d.ts +14 -0
- package/dist/utils/results.d.ts +38 -0
- package/dist/utils/search.d.ts +8 -0
- package/dist/utils/table.d.ts +16 -0
- package/package.json +1 -1
- package/dist/components/UDate.vue.d.ts +0 -47
- package/dist/components/UDict.vue.d.ts +0 -49
- package/dist/components/UInput.vue.d.ts +0 -52
- package/dist/components/UInputNumber.vue.d.ts +0 -52
- package/dist/components/UToggle.vue.d.ts +0 -54
- package/dist/show/UCascaderShow.vue.d.ts +0 -11
- package/dist/show/UDateShow.vue.d.ts +0 -15
- package/dist/show/UDictShow.vue.d.ts +0 -9
- package/dist/show/UFieldView.vue.d.ts +0 -24
- package/dist/show/UInputShow.vue.d.ts +0 -10
- package/dist/show/UToggleShow.vue.d.ts +0 -12
- package/dist/ts/constant.d.ts +0 -24
- package/dist/ts/dict.d.ts +0 -105
- package/dist/ts/form-render.d.ts +0 -30
- package/dist/ts/http.d.ts +0 -13
- package/dist/ts/model.d.ts +0 -202
- package/dist/ts/notify.d.ts +0 -42
- package/dist/ts/table-data-service.d.ts +0 -30
- package/dist/ts/table-render.d.ts +0 -210
- package/dist/uform/FormContainer.vue.d.ts +0 -37
- package/dist/uform/FormField.vue.d.ts +0 -16
- package/dist/uform/FormGrid.vue.d.ts +0 -24
- package/dist/uform/FormRender.vue.d.ts +0 -104
- package/dist/uform/TableDetail.vue.d.ts +0 -37
- package/dist/uform/TableGrid.vue.d.ts +0 -51
- package/dist/uform/TablePagination.vue.d.ts +0 -14
- package/dist/uform/TableRender.vue.d.ts +0 -618
- package/dist/uform/TableSearch.vue.d.ts +0 -38
- 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,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
|
+
}
|
package/dist/qf/http.d.ts
CHANGED
|
@@ -1,48 +1,70 @@
|
|
|
1
|
-
import { QfOptions } from './interface.ts';
|
|
1
|
+
import { HttpResponse, QfOptions } from './interface.ts';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* 解析「本页面所在**目录**」的绝对地址(不含结尾斜杠)—— 免配模式下接口前缀的推导依据。
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* 用于前后端不同机/不同端口/走网关的场景;
|
|
8
|
-
* 2. 本文档自己的地址 `document.baseURI` —— 免配默认值;
|
|
9
|
-
* 3. `window.$wujie.location.origin` —— 无界子应用的兜底;
|
|
10
|
-
* 4. `window.location.origin` —— 最后兜底。
|
|
5
|
+
* 结果只取决于**页面自己的地址**(`document.baseURI`),与构建/部署方式无关,
|
|
6
|
+
* 所以同一份产物放到任意路径下都能用:
|
|
11
7
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
8
|
+
* | 页面地址 | 返回 |
|
|
9
|
+
* |---|---|
|
|
10
|
+
* | `http://host/` | `http://host` |
|
|
11
|
+
* | `http://host/index.html` | `http://host` |
|
|
12
|
+
* | `http://host/qfcms/` | `http://host/qfcms` |
|
|
13
|
+
* | `http://host/qfcms`(末尾无斜杠,nginx try_files 的常见形态) | `http://host/qfcms` |
|
|
14
|
+
* | `http://host/qfcms/index.html` | `http://host/qfcms` |
|
|
19
15
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
16
|
+
* 两条容易踩的细节:
|
|
17
|
+
* 1. **只有当最后一段含 `.` 时才当成文件名丢掉**(`index.html` → 丢,`qfcms` → 保留)。
|
|
18
|
+
* 否则访问 `/qfcms`(无斜杠)会被误判成文件,前缀掉成站点根。
|
|
19
|
+
* 2. 不用 `window.location.origin`:无界(wujie)嵌入时子应用跑在同源 `blob:` 空 iframe 里,
|
|
20
|
+
* `window.location` 指向**主应用**(实测把请求发成了 `http://主应用:8111/api/...`)。
|
|
21
|
+
* `document.baseURI` 描述文档自身,无界会注入正确的 `<base href="子应用地址">`,
|
|
22
|
+
* 「独立运行」和「被嵌入」两种情况下都指向子应用自己。
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveAppBase(): string;
|
|
25
|
+
/**
|
|
26
|
+
* 全库**唯一**的 HTTP 客户端(`Qf.WebApi`)。
|
|
27
|
+
*
|
|
28
|
+
* 组件、渲染器、工具函数一律通过 `getQf().Get/Post/...` 发请求,
|
|
29
|
+
* 不再各自 `axios.create`(历史上另有一份 `ts/http.ts`,已删)。
|
|
30
|
+
*
|
|
31
|
+
* 三条约定:
|
|
32
|
+
* 1. **鉴权头是 `token`**,不是 `Authorization`。httptoqfapi 会把全部 HTTP header
|
|
33
|
+
* 合并进请求参数,后端按 `Token` 取用 —— 所以只有 `token` 头能通过鉴权。
|
|
34
|
+
* 2. **响应做「业务码归一化」**:后端恒返回 `{code, message, data}`,`code === 0` 为成功。
|
|
35
|
+
* 这里给成功的响应补一个 `status = 200` 字段,让调用方可以继续写
|
|
36
|
+
* `if (res.status === 200)`(兼容旧后端的 status 字段,两边都认)。
|
|
37
|
+
* 3. **blob 原样返回**:下载/导出走 `Download` / `PostDownload`,拦截器不脱壳,
|
|
38
|
+
* 调用方自己取 `res.data as Blob`。
|
|
22
39
|
*/
|
|
23
|
-
export declare function resolveBaseUrl(): string;
|
|
24
40
|
export declare class Http {
|
|
25
41
|
private axiosInstance;
|
|
26
|
-
private
|
|
42
|
+
private baseCache;
|
|
27
43
|
constructor(options: QfOptions);
|
|
28
44
|
/**
|
|
29
|
-
*
|
|
45
|
+
* GET 请求(params 会被 axios 序列化成 query string)
|
|
30
46
|
*/
|
|
31
|
-
|
|
47
|
+
Get<T = any>(url: string, params?: any): Promise<HttpResponse<T>>;
|
|
32
48
|
/**
|
|
33
|
-
*
|
|
49
|
+
* POST 请求(body 支持普通对象与 FormData;
|
|
50
|
+
* FormData 时 axios 会自动让浏览器设置带 boundary 的 Content-Type)
|
|
34
51
|
*/
|
|
35
|
-
|
|
52
|
+
Post<T = any>(url: string, data?: any): Promise<HttpResponse<T>>;
|
|
36
53
|
/**
|
|
37
|
-
* DELETE
|
|
54
|
+
* DELETE 请求(参数走 query string,与后端路由约定一致)
|
|
38
55
|
*/
|
|
39
|
-
Delete(url: string, params?: any): Promise<
|
|
56
|
+
Delete<T = any>(url: string, params?: any): Promise<HttpResponse<T>>;
|
|
40
57
|
/**
|
|
41
58
|
* PUT 请求
|
|
42
59
|
*/
|
|
43
|
-
Put(url: string, data?: any): Promise<
|
|
60
|
+
Put<T = any>(url: string, data?: any): Promise<HttpResponse<T>>;
|
|
61
|
+
/**
|
|
62
|
+
* 下载文件(GET + blob)—— 返回**完整 AxiosResponse**,调用方取 `res.data as Blob`
|
|
63
|
+
*/
|
|
64
|
+
Download<T = any>(url: string, params?: any): Promise<T>;
|
|
44
65
|
/**
|
|
45
|
-
*
|
|
66
|
+
* 下载文件(POST + blob,用于「按查询条件导出」这类接口)——
|
|
67
|
+
* 同样返回完整 AxiosResponse。
|
|
46
68
|
*/
|
|
47
|
-
|
|
69
|
+
PostDownload<T = any>(url: string, data?: any): Promise<T>;
|
|
48
70
|
}
|
package/dist/qf/interface.d.ts
CHANGED
|
@@ -1,13 +1,54 @@
|
|
|
1
|
+
import { FormConfig } from '../model/form';
|
|
2
|
+
import { TablePageConfig } from '../model/table-page';
|
|
3
|
+
import { MenuConfig } from '../model/menu';
|
|
4
|
+
/**
|
|
5
|
+
* 后端统一响应包。
|
|
6
|
+
*
|
|
7
|
+
* httptoqfapi 恒返回 `{code, message, data}`,`code === 0` 表示成功;
|
|
8
|
+
* Http 的响应拦截器会给成功响应补一个 `status = 200`,所以
|
|
9
|
+
* `if (res.status === 200)` 与 `if (res.code === 0)` 两种写法都可用。
|
|
10
|
+
*/
|
|
11
|
+
export interface HttpResponse<T = any> {
|
|
12
|
+
code?: number;
|
|
13
|
+
status?: number;
|
|
14
|
+
message?: string;
|
|
15
|
+
data: T;
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
}
|
|
1
18
|
export interface QfInterface {
|
|
2
19
|
On(event: string, callback: any): void;
|
|
3
20
|
Emit(event: string, data: any): void;
|
|
4
21
|
Off(event: string, callback: any): void;
|
|
5
|
-
Post<T>(url: string, data
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
22
|
+
Post<T>(url: string, data?: any): Promise<HttpResponse<T>>;
|
|
23
|
+
/** GET;params 可选(省略即不带 query string) */
|
|
24
|
+
Get<T>(url: string, params?: any): Promise<HttpResponse<T>>;
|
|
25
|
+
/** DELETE;参数走 query string */
|
|
26
|
+
Delete<T>(url: string, params?: any): Promise<HttpResponse<T>>;
|
|
27
|
+
Put<T>(url: string, data?: any): Promise<HttpResponse<T>>;
|
|
28
|
+
/** 下载(GET + blob):返回**完整 AxiosResponse**,调用方取 .data as Blob */
|
|
9
29
|
Download<T>(url: string, params?: any): Promise<T>;
|
|
30
|
+
/** 导出(POST + blob):返回**完整 AxiosResponse**,调用方取 .data as Blob */
|
|
31
|
+
PostDownload<T>(url: string, data?: any): Promise<T>;
|
|
10
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>;
|
|
11
52
|
}
|
|
12
53
|
export interface QfOptions {
|
|
13
54
|
module: string;
|
package/dist/qf/qf.d.ts
CHANGED
|
@@ -1,13 +1,42 @@
|
|
|
1
1
|
import { Http } from './http';
|
|
2
|
-
import { QfInterface, QfOptions } from './interface';
|
|
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';
|
|
9
|
+
/**
|
|
10
|
+
* 初始化(或取回)Qf 单例 —— **使用方入口调用一次**,通常在 main.ts / App.vue 里:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const options = await fetch('./config/config.json').then(r => r.json()).then(c => c.qfOptions)
|
|
14
|
+
* const Qf = GetQf(options)
|
|
15
|
+
* Qf.Get('/api/user', {})
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* 重复调用只会返回首次创建的那个实例;若此前是 getQf() 的兜底实例,
|
|
19
|
+
* 则用本次传入的 options 重建(保证入口配置最终生效)。
|
|
20
|
+
*/
|
|
5
21
|
export declare const GetQf: (options: QfOptions) => QfInterface;
|
|
22
|
+
/**
|
|
23
|
+
* 取 Qf 单例 —— **库内部与使用方通用**。
|
|
24
|
+
*
|
|
25
|
+
* 与 GetQf(options) 的区别:不需要传 options,且在「使用方还没初始化」时不会报错,
|
|
26
|
+
* 而是用一个「免配 options」惰性建一个实例(后端 = 页面所在目录 + /api,即 resolveAppBase 的语义)。
|
|
27
|
+
*
|
|
28
|
+
* 为什么需要它:Qf 一般在 App.vue 里**异步**初始化(要先 fetch config.json),
|
|
29
|
+
* 而使用方与解析层(parser)可能在同一帧就已经想要取配置了。
|
|
30
|
+
* 兜底实例随后会被真正的 GetQf(options) 替换,所以不会影响最终配置。
|
|
31
|
+
*/
|
|
32
|
+
export declare const getQf: () => QfInterface;
|
|
6
33
|
export declare class QfImpl implements QfInterface {
|
|
7
34
|
EventBus: EventBus;
|
|
8
35
|
WebApi: Http;
|
|
9
36
|
Mqtt: MqttAdapter;
|
|
10
37
|
options: QfOptions;
|
|
38
|
+
/** 动态配置解析器(parser/):Qf 只做转发,实现都在解析层 */
|
|
39
|
+
yamlParser: YamlParser;
|
|
11
40
|
constructor(options: QfOptions);
|
|
12
41
|
/**
|
|
13
42
|
* 初始化 Qf
|
|
@@ -16,10 +45,27 @@ export declare class QfImpl implements QfInterface {
|
|
|
16
45
|
On(event: string, callback: any): void;
|
|
17
46
|
Emit(event: string, data: any): void;
|
|
18
47
|
Off(event: string, callback: any): void;
|
|
19
|
-
Post(url: string, data?: any): Promise<
|
|
20
|
-
Get(url: string, params?: any): Promise<
|
|
21
|
-
Delete(url: string, params?: any): Promise<
|
|
22
|
-
Put(url: string, data?: any): Promise<
|
|
23
|
-
Download(url: string, params?: any): Promise<
|
|
48
|
+
Post<T>(url: string, data?: any): Promise<HttpResponse<T>>;
|
|
49
|
+
Get<T>(url: string, params?: any): Promise<HttpResponse<T>>;
|
|
50
|
+
Delete<T>(url: string, params?: any): Promise<HttpResponse<T>>;
|
|
51
|
+
Put<T>(url: string, data?: any): Promise<HttpResponse<T>>;
|
|
52
|
+
Download<T>(url: string, params?: any): Promise<T>;
|
|
53
|
+
PostDownload<T>(url: string, data?: any): Promise<T>;
|
|
24
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>;
|
|
25
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-8bfd4dcf]{display:flex;width:100%}.u-dict.u-dict-label-left .u-dict-label[data-v-8bfd4dcf]{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-8bfd4dcf]{flex:1}.u-dict.u-dict-label-top[data-v-8bfd4dcf]{flex-direction:column}.u-dict.u-dict-label-top .u-dict-label[data-v-8bfd4dcf]{width:100%;font-size:14px;color:#606266;margin-bottom:8px;white-space:nowrap}.u-dict .required-star[data-v-8bfd4dcf]{color:#f56c6c;display:inline-block;width:10px}.u-dict .required-star[data-v-8bfd4dcf]: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-fe63251c]{display:flex;height:100%;min-height:0;background:#fff}.u-menu .u-menu-icon[data-v-fe63251c]{margin-right:6px}.u-menu.u-menu--sidebar[data-v-fe63251c]{flex-direction:column;border-right:1px solid #e4e7ed}.u-menu.u-menu--sidebar .u-menu-brand[data-v-fe63251c]{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-fe63251c]{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;border-right:none}.u-menu.u-menu--sidebar .u-menu-logout[data-v-fe63251c]{flex-shrink:0;width:100%;border-top:1px solid #e4e7ed}.u-menu.u-menu--sidebar .u-menu-logout-btn[data-v-fe63251c]{display:block;width:100%}.u-menu.u-menu--horizontal[data-v-fe63251c]{flex-direction:row;align-items:center;width:100%;border-bottom:1px solid #e4e7ed}.u-menu.u-menu--horizontal .u-menu-brand[data-v-fe63251c]{flex-shrink:0;display:flex;align-items:center;padding:0 16px;white-space:nowrap}.u-menu.u-menu--horizontal .u-menu-list[data-v-fe63251c]{flex:1;min-width:0;border-bottom:none}.u-menu.u-menu--horizontal .u-menu-logout[data-v-fe63251c]{flex-shrink:0;display:flex;align-items:center;padding:0 12px;margin-left:auto}.u-menu .u-menu-logo[data-v-fe63251c]{height:28px;margin-right:8px}.u-menu .u-menu-brand-text[data-v-fe63251c]{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-10299c8d]{width:100%}.field-error[data-v-10299c8d]{color:#f56c6c;font-size:12px;min-height:12px;line-height:1.5;transition:opacity .2s}.field-error[data-v-10299c8d]: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-0538c013]{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-0538c013]{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-5d8fe268]{display:flex;flex-direction:column;height:100%;min-height:0;background:#fff}.table-render .table-body[data-v-5d8fe268]{display:flex;flex:1;min-height:0;overflow:hidden}.table-render .table-container[data-v-5d8fe268]{flex:1;display:flex;flex-direction:column;min-width:0;overflow:hidden}.table-render .table-container[data-v-5d8fe268] .table-grid{flex:1;min-height:0;max-height:var(--table-grid-max-height, none)}.table-render .table-container[data-v-5d8fe268] .table-grid>.el-table{height:100%}.table-render .table-pagination[data-v-5d8fe268]{flex-shrink:0}.table-render .table-detail-inline[data-v-5d8fe268]{flex-shrink:0;height:100%;overflow:hidden;border-left:1px solid #ebeef5}.table-render .table-detail-inline.table-detail-inline-left[data-v-5d8fe268]{order:-1;border-left:none;border-right:1px solid #ebeef5}.table-render .table-toolbar-bottom[data-v-5d8fe268]{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
|
+
};
|