@_tc/template-core 0.0.1-bate.43 → 0.0.1-bate.46
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/cjs/app/README.md +286 -0
- package/cjs/app/service/{bese.js → base.js} +3 -3
- package/cjs/app/service/project.js +2 -2
- package/cjs/bundler/utils.js +67 -4
- package/cjs/index.js +2 -2
- package/esm/app/README.md +286 -0
- package/esm/app/service/{bese.js → base.js} +3 -3
- package/esm/app/service/project.js +2 -2
- package/esm/bundler/utils.js +67 -4
- package/esm/index.js +2 -2
- package/fe/frontend/components/AsyncSelect/AsyncSelect.d.ts +8 -0
- package/fe/frontend/components/AsyncSelect/AsyncSelect.js +32 -0
- package/fe/frontend/components/AsyncSelect/index.d.ts +4 -0
- package/fe/frontend/components/AsyncSelect/index.js +3 -0
- package/fe/frontend/dash/Dashboard.js +12 -12
- package/fe/frontend/dash/dash.entry.js +26 -13
- package/fe/frontend/dash/types.d.ts +17 -0
- package/fe/frontend/dash/types.js +1 -0
- package/fe/frontend/extended/SchemaForm/data.d.ts +13 -0
- package/fe/frontend/extended/SchemaForm/data.js +8 -0
- package/fe/frontend/index.d.ts +3 -1
- package/fe/frontend/index.js +1 -0
- package/fe/frontend/main.d.ts +6 -6
- package/fe/frontend/main.js +7 -6
- package/fe/frontend/typing/scalability.d.ts +47 -0
- package/fe/frontend/typing/scalability.js +1 -0
- package/fe/frontend/widgets/api/baseInfo.d.ts +1 -1
- package/fe/frontend/widgets/api/baseInfo.js +1 -1
- package/fe/frontend/widgets/common/menu.js +1 -1
- package/fe/frontend/widgets/defaultPages/Schema/stores/schemaStore.d.ts +1 -1
- package/fe/frontend/widgets/defaultPages/SidebarSlotPageTmp.js +1 -1
- package/fe/frontend/widgets/hooks/useCurrentMenuData.js +3 -3
- package/fe/frontend/widgets/store/mode.d.ts +3 -3
- package/fe/frontend/widgets/store/mode.js +8 -8
- package/fe/model/types/data/search.d.ts +4 -4
- package/fe/packages/ui/react/components/Form/SchemaForm/data.d.ts +5 -10
- package/fe/packages/ui/react/components/Form/SchemaForm/data.js +4 -2
- package/fe/packages/ui/react/components/Form/SchemaForm/index.d.ts +1 -1
- package/fe/packages/ui/react/hooks/useLanguage.d.ts +1 -1
- package/fe/packages/ui/react/i18n/useI18n.d.ts +4 -4
- package/fe/typings/type.d.ts +2 -3
- package/model/types/data/search.d.ts +4 -4
- package/package.json +1 -1
- package/types/typings/type.d.ts +2 -3
- /package/model/{types/test.d.ts → test.d.ts} +0 -0
- /package/types/app/service/{bese.d.ts → base.d.ts} +0 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# app 模块说明
|
|
2
|
+
|
|
3
|
+
## 0. 先看结论
|
|
4
|
+
|
|
5
|
+
`app` 是 TemplateCore 内置的 Koa 应用层。
|
|
6
|
+
|
|
7
|
+
- 它提供框架默认 controller、service、middleware、router、extend、router-schema 和页面模板。
|
|
8
|
+
- 它和业务项目的 `app/` 会被 `@tc/core` 一起加载,形成“框架默认能力 + 业务覆盖/扩展”的结构。
|
|
9
|
+
- 它主要承接两类请求:后台页面渲染,以及 `/api/project/*` 项目模型接口。
|
|
10
|
+
|
|
11
|
+
适合先读:
|
|
12
|
+
|
|
13
|
+
- 想看服务中间件顺序:看 `middleware.ts`。
|
|
14
|
+
- 想看页面怎么渲染:看 `router/view.ts`、`controller/view.ts`、`view/entry.tpl`。
|
|
15
|
+
- 想看项目数据接口:看 `router/project.ts`、`controller/project.ts`、`service/project.ts`。
|
|
16
|
+
|
|
17
|
+
## 关联阅读
|
|
18
|
+
|
|
19
|
+
- [packages/core 模块](../packages/core/README.md):Koa app 创建、loader 顺序和双路径加载。
|
|
20
|
+
- [frontend 模块](../frontend/README.md):页面模板加载后的 React 运行层。
|
|
21
|
+
- [bundler 模块](../bundler/README.md):生成 `app/public/dist/*.entry.tpl` 的构建逻辑。
|
|
22
|
+
- [model 模块](../model/README.md):项目 API 返回的模型配置结构。
|
|
23
|
+
|
|
24
|
+
## 1. 模块边界
|
|
25
|
+
|
|
26
|
+
`app` 做这些事:
|
|
27
|
+
|
|
28
|
+
- 装配内置 Koa 全局中间件。
|
|
29
|
+
- 提供静态资源服务。
|
|
30
|
+
- 渲染前端入口模板。
|
|
31
|
+
- 提供项目模型相关 API。
|
|
32
|
+
- 提供统一响应结构和基础 Controller/Service。
|
|
33
|
+
- 提供 API 签名校验、参数校验、错误处理。
|
|
34
|
+
- 对 `@tc/core` 做 TypeScript 类型增强。
|
|
35
|
+
|
|
36
|
+
`app` 不做这些事:
|
|
37
|
+
|
|
38
|
+
- 不实现 React 页面内部逻辑。
|
|
39
|
+
- 不扫描 `.entry.*` 前端入口。
|
|
40
|
+
- 不负责最终构建输出。
|
|
41
|
+
- 不直接维护业务 CRUD 数据;业务数据由业务 controller/service 实现。
|
|
42
|
+
|
|
43
|
+
## 2. 目录地图
|
|
44
|
+
|
|
45
|
+
| 路径 | 作用 |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| `middleware.ts` | 框架全局中间件装配入口。 |
|
|
48
|
+
| `middleware/*` | 具体中间件:错误处理、签名校验、参数校验、项目信息处理。 |
|
|
49
|
+
| `router/view.ts` | 页面路由,匹配 `pageBasePage + :page`。 |
|
|
50
|
+
| `controller/view.ts` | 渲染 `dist/{page}.entry.tpl`。 |
|
|
51
|
+
| `view/entry.tpl` | 默认页面模板,注入前端运行需要的全局变量。 |
|
|
52
|
+
| `router/project.ts` | 项目模型 API 路由。 |
|
|
53
|
+
| `controller/project.ts` | 项目模型 API controller。 |
|
|
54
|
+
| `service/project.ts` | 调用 `loaderModel(app)` 读取业务 model 配置。 |
|
|
55
|
+
| `controller/base.ts` | 基础 Controller,提供 `success/fail/sendData`。 |
|
|
56
|
+
| `service/base.ts` | 基础 Service,提供 `app/config/curl`。 |
|
|
57
|
+
| `router-schema/project.ts` | 项目 API 的 JSON Schema 校验配置。 |
|
|
58
|
+
| `extend/*` | 挂到 `app.extends` 的扩展能力。 |
|
|
59
|
+
| `typings.ts` | 对 `@tc/core` 的模块增强声明。 |
|
|
60
|
+
| `data/signKey.ts` | API 签名 key。 |
|
|
61
|
+
|
|
62
|
+
## 3. 服务加载链路
|
|
63
|
+
|
|
64
|
+
根入口 `index.ts` 导出 `serverStart(options)`,内部调用 `@tc/core` 的 `start`:
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
serverStart(options)
|
|
68
|
+
-> start({ ...options, frameBaseDir })
|
|
69
|
+
-> core 加载 frame app + business app
|
|
70
|
+
-> config
|
|
71
|
+
-> extend
|
|
72
|
+
-> router-schema
|
|
73
|
+
-> service
|
|
74
|
+
-> controller
|
|
75
|
+
-> middleware 目录
|
|
76
|
+
-> app/middleware.ts 全局装配
|
|
77
|
+
-> router
|
|
78
|
+
-> listen
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```mermaid
|
|
82
|
+
flowchart TD
|
|
83
|
+
A["serverStart(options)"] --> B["@tc/core start"]
|
|
84
|
+
B --> C["configLoader"]
|
|
85
|
+
C --> D["extendLoader"]
|
|
86
|
+
D --> E["routerSchemaLoader"]
|
|
87
|
+
E --> F["serviceLoader"]
|
|
88
|
+
F --> G["controllerLoader"]
|
|
89
|
+
G --> H["middlewareLoader"]
|
|
90
|
+
H --> I["app/middleware.ts"]
|
|
91
|
+
I --> J["routerLoader"]
|
|
92
|
+
J --> K["app.listen"]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
这里的 `app/` 是框架内置目录,业务项目也可以有自己的 `app/`。`@tc/core` 会把两者放进 `app.paths`:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
frame app -> TemplateCore/app
|
|
99
|
+
business app -> project/app
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
大多数 loader 都会同时扫描这两个目录。
|
|
103
|
+
|
|
104
|
+
## 4. 中间件顺序
|
|
105
|
+
|
|
106
|
+
`app/middleware.ts` 中的顺序是运行时请求的主干:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
errorHandle
|
|
110
|
+
-> compress
|
|
111
|
+
-> koaStatic(frame app/public)
|
|
112
|
+
-> koaStatic(business app/public)
|
|
113
|
+
-> koaBody
|
|
114
|
+
-> projectHandler
|
|
115
|
+
-> apiSignVerify 非 local
|
|
116
|
+
-> apiParamsVerify
|
|
117
|
+
-> router/controller/service
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
设计原因:
|
|
121
|
+
|
|
122
|
+
- `errorHandle` 最靠前,用于捕获后续中间件和 controller 抛出的错误。
|
|
123
|
+
- 静态资源在 body parser 前,减少不必要的请求解析。
|
|
124
|
+
- `projectHandler` 在 API 校验前写入项目上下文。
|
|
125
|
+
- `apiSignVerify` 只在非 local 环境启用。
|
|
126
|
+
- `apiParamsVerify` 依赖 `app.routerSchema` 和当前路由信息。
|
|
127
|
+
|
|
128
|
+
## 5. 页面渲染链路
|
|
129
|
+
|
|
130
|
+
请求 `/dash?projk=xxx` 这类页面时:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
GET /dash
|
|
134
|
+
-> app/router/view.ts
|
|
135
|
+
-> app.controller.view.renderPage
|
|
136
|
+
-> app.extends.renderView("dist/dash.entry.tpl", ctx, context)
|
|
137
|
+
-> app/view/entry.tpl 或构建后的 tpl
|
|
138
|
+
-> 注入 window._basePath / window._projKey / window.appOptions
|
|
139
|
+
-> 浏览器加载前端 bundle
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```mermaid
|
|
143
|
+
sequenceDiagram
|
|
144
|
+
participant Browser
|
|
145
|
+
participant Router as app/router/view.ts
|
|
146
|
+
participant Controller as app/controller/view.ts
|
|
147
|
+
participant Nunjucks as app.extends.renderView
|
|
148
|
+
participant Frontend as frontend bundle
|
|
149
|
+
Browser->>Router: GET /dash?projk=xxx
|
|
150
|
+
Router->>Controller: renderPage(ctx)
|
|
151
|
+
Controller->>Nunjucks: render dist/dash.entry.tpl
|
|
152
|
+
Nunjucks-->>Browser: HTML + window variables
|
|
153
|
+
Browser->>Frontend: load /dist assets
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
页面名和前端入口强绑定:
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
frontend/dash/dash.entry.tsx
|
|
160
|
+
-> bundler 输出 app/public/dist/dash.entry.tpl
|
|
161
|
+
-> GET /dash 渲染 dist/dash.entry.tpl
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## 6. 项目 API
|
|
165
|
+
|
|
166
|
+
内置项目 API 用于给前端 Dashboard 提供模型和菜单数据。
|
|
167
|
+
|
|
168
|
+
| 路由 | 作用 |
|
|
169
|
+
| --- | --- |
|
|
170
|
+
| `GET /api/project/model_list` | 返回模型列表和项目摘要。 |
|
|
171
|
+
| `GET /api/project/list?projk=xxx` | 返回项目列表,可按 key 过滤。 |
|
|
172
|
+
| `GET /api/project/:key` | 返回单个项目完整配置。 |
|
|
173
|
+
|
|
174
|
+
数据来源:
|
|
175
|
+
|
|
176
|
+
```text
|
|
177
|
+
app/service/project.ts
|
|
178
|
+
-> loaderModel(app)
|
|
179
|
+
-> 读取 business baseDir/model
|
|
180
|
+
-> 合并 model 配置和 project 覆盖配置
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
响应统一为:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
{
|
|
187
|
+
data: unknown,
|
|
188
|
+
code: number,
|
|
189
|
+
message: string
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 7. Controller 和 Service 约定
|
|
194
|
+
|
|
195
|
+
框架内置 Controller/Service 都是工厂函数:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
export default (app) => class XxxController {}
|
|
199
|
+
export default (app) => class XxxService {}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`@tc/core` loader 会:
|
|
203
|
+
|
|
204
|
+
1. 执行默认导出函数,传入 `app`。
|
|
205
|
+
2. 拿到 class。
|
|
206
|
+
3. `new` 出实例。
|
|
207
|
+
4. 挂到 `app.controller.xxx` 或 `app.service.xxx`。
|
|
208
|
+
|
|
209
|
+
基础 Controller 提供:
|
|
210
|
+
|
|
211
|
+
- `success(ctx, data)`
|
|
212
|
+
- `fail(ctx, code, message)`
|
|
213
|
+
- `sendData(ctx, data, code, message, status)`
|
|
214
|
+
|
|
215
|
+
基础 Service 提供:
|
|
216
|
+
|
|
217
|
+
- `app`
|
|
218
|
+
- `config`
|
|
219
|
+
- `curl`,即 `superagent`
|
|
220
|
+
|
|
221
|
+
## 8. 扩展能力
|
|
222
|
+
|
|
223
|
+
`app/extend/*` 会挂到 `app.extends`。
|
|
224
|
+
|
|
225
|
+
| 扩展 | 作用 |
|
|
226
|
+
| --- | --- |
|
|
227
|
+
| `render-view.ts` | Nunjucks 渲染封装。 |
|
|
228
|
+
| `logger.ts` | local 使用 console,非 local 使用 log4js。 |
|
|
229
|
+
| `generateErrorMessage.ts` | 构造并抛出可被 `errorHandle` 捕获的错误。 |
|
|
230
|
+
| `parsingParamsOnUrl.ts` | 根据路由模板解析 URL params。 |
|
|
231
|
+
| `db.ts` | 当前为占位扩展。 |
|
|
232
|
+
|
|
233
|
+
`logger.ts` 在非 local 环境下可覆盖原生 `console`,由 `overwriteOriginalLogs` 控制。
|
|
234
|
+
|
|
235
|
+
## 9. 参数校验与错误处理
|
|
236
|
+
|
|
237
|
+
`router-schema/*` 会被加载到 `app.routerSchema`。`apiParamsVerify` 会在 `/api` 请求中尝试:
|
|
238
|
+
|
|
239
|
+
1. 根据当前 path 找到匹配路由。
|
|
240
|
+
2. 从 route path 中解析 params。
|
|
241
|
+
3. 收集 `params/body/query/headers`。
|
|
242
|
+
4. 找到对应 schema。
|
|
243
|
+
5. 用 AJV 校验。
|
|
244
|
+
6. 失败时通过 `generateErrorMessage` 抛出错误。
|
|
245
|
+
|
|
246
|
+
`errorHandle` 会统一捕获错误。对 `template not found` 有特殊逻辑:
|
|
247
|
+
|
|
248
|
+
- 未超过 `notFoundRedirectCount` 时重定向到 `homePage`。
|
|
249
|
+
- 超过后返回普通错误响应。
|
|
250
|
+
|
|
251
|
+
## 10. 类型增强
|
|
252
|
+
|
|
253
|
+
`app/typings.ts` 通过 TypeScript module augmentation 扩展 `@tc/core`:
|
|
254
|
+
|
|
255
|
+
- `app.controller.project`
|
|
256
|
+
- `app.controller.view`
|
|
257
|
+
- `app.service.project`
|
|
258
|
+
- `app.extends.logger`
|
|
259
|
+
- `app.extends.renderView`
|
|
260
|
+
- `app.middlewares.errorHandle`
|
|
261
|
+
- `app.config` 默认配置类型
|
|
262
|
+
|
|
263
|
+
新增内置能力后,建议同步更新 `app/typings.ts`,否则调用侧类型会丢失。
|
|
264
|
+
|
|
265
|
+
## 11. 注意事项
|
|
266
|
+
|
|
267
|
+
- 页面模板名和前端入口名强绑定,请求 `/dash` 会寻找 `dist/dash.entry.tpl`。
|
|
268
|
+
- `projectHandler` 只对路径包含 `/api/proj/` 的请求强制要求 header `projk`,`/api/project/*` 不在这个判断内。
|
|
269
|
+
- `apiParamsVerify` 当前匹配路由时固定用 `r.match(path, "get")`,对非 GET 的覆盖需要结合实现确认。
|
|
270
|
+
- `renderPage` 中模板不存在会抛出 `template not found`,由 `errorHandle` 接住。
|
|
271
|
+
- `app/extend/db.ts` 当前是占位,不代表框架已内置数据库能力。
|
|
272
|
+
- 非 local 环境下 API 签名校验会生效,前后端签名 key 必须一致。
|
|
273
|
+
|
|
274
|
+
## 12. 常见问题
|
|
275
|
+
|
|
276
|
+
### 页面模板找不到
|
|
277
|
+
|
|
278
|
+
确认 `bundler` 已经生成 `app/public/dist/{page}.entry.tpl`,并且访问路径里的 `{page}` 和 entry 名一致。
|
|
279
|
+
|
|
280
|
+
### 非 local 环境接口返回签名错误
|
|
281
|
+
|
|
282
|
+
检查前端 `s_sign` 生成逻辑和服务端 `app/data/signKey.ts` 是否一致,同时确认请求时间戳没有超过超时时间。
|
|
283
|
+
|
|
284
|
+
### 新增 controller 后类型没有提示
|
|
285
|
+
|
|
286
|
+
运行时可能已经可用,但 TypeScript 类型需要在 `app/typings.ts` 或业务自己的模块增强文件中补充。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import superagent from "superagent";
|
|
2
|
-
//#region app/service/
|
|
3
|
-
var
|
|
2
|
+
//#region app/service/base.ts
|
|
3
|
+
var base_default = (app) => class BaseService {
|
|
4
4
|
get app() {
|
|
5
5
|
return app;
|
|
6
6
|
}
|
|
@@ -12,4 +12,4 @@ var bese_default = (app) => class BaseService {
|
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
14
|
//#endregion
|
|
15
|
-
export {
|
|
15
|
+
export { base_default as default };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import base_default from "./base.js";
|
|
2
2
|
import { loaderModel } from "../../packages/core/index.js";
|
|
3
3
|
//#region app/service/project.ts
|
|
4
4
|
var getProjectService = (app) => {
|
|
5
|
-
const BaseService =
|
|
5
|
+
const BaseService = base_default(app);
|
|
6
6
|
const modelData = loaderModel(app);
|
|
7
7
|
return class ProjectService extends BaseService {
|
|
8
8
|
async getModelList() {
|
package/esm/bundler/utils.js
CHANGED
|
@@ -151,14 +151,16 @@ function resolveAliasWithFallback(aliasList) {
|
|
|
151
151
|
".js",
|
|
152
152
|
".jsx"
|
|
153
153
|
];
|
|
154
|
-
return aliasList.reduce((o, [aliasName, aliasPath]) => {
|
|
155
|
-
const businessFilePath = aliasExtensions.map((ext) => path.resolve(
|
|
154
|
+
return aliasList.reduce((o, [aliasName, aliasPath, basePath = runFEPath]) => {
|
|
155
|
+
const businessFilePath = aliasExtensions.map((ext) => path.resolve(basePath, aliasPath + ext)).find((filePath) => existsSync(filePath));
|
|
156
156
|
let filePath = path.resolve(currentDir, "./defaultAlias");
|
|
157
157
|
if (businessFilePath) filePath = businessFilePath;
|
|
158
158
|
o[aliasName] = filePath;
|
|
159
159
|
return o;
|
|
160
160
|
}, {});
|
|
161
161
|
}
|
|
162
|
+
var generatePathReg = (...params) => new RegExp(params.join("[\\/]"));
|
|
163
|
+
var getChunkName = (str) => `_${str}_tcC`;
|
|
162
164
|
var VBuildFE = async (input, OperatingEnv) => {
|
|
163
165
|
try {
|
|
164
166
|
await build({
|
|
@@ -173,13 +175,74 @@ var VBuildFE = async (input, OperatingEnv) => {
|
|
|
173
175
|
outDir: outDir(),
|
|
174
176
|
emptyOutDir: true,
|
|
175
177
|
sourcemap: OperatingEnv === "dev" ? "inline" : "hidden",
|
|
176
|
-
rollupOptions: {
|
|
178
|
+
rollupOptions: {
|
|
179
|
+
input,
|
|
180
|
+
output: { codeSplitting: { groups: [
|
|
181
|
+
{
|
|
182
|
+
name: getChunkName("__nm"),
|
|
183
|
+
test: generatePathReg("node_modules"),
|
|
184
|
+
maxSize: 5e5,
|
|
185
|
+
minShareCount: 2,
|
|
186
|
+
priority: 1
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: getChunkName("r"),
|
|
190
|
+
test: generatePathReg("node_modules", "react"),
|
|
191
|
+
minShareCount: 2,
|
|
192
|
+
maxSize: 5e5,
|
|
193
|
+
priority: 5
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
name: getChunkName("r-d"),
|
|
197
|
+
test: generatePathReg("node_modules", "react-dom"),
|
|
198
|
+
minShareCount: 2,
|
|
199
|
+
maxSize: 2e5,
|
|
200
|
+
priority: 10
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: getChunkName("r-r-d"),
|
|
204
|
+
test: generatePathReg("node_modules", "react-router-dom"),
|
|
205
|
+
minShareCount: 2,
|
|
206
|
+
maxSize: 5e5,
|
|
207
|
+
priority: 10
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
name: getChunkName("ajv"),
|
|
211
|
+
test: generatePathReg("node_modules", "ajv"),
|
|
212
|
+
minShareCount: 2,
|
|
213
|
+
maxSize: 2e5,
|
|
214
|
+
priority: 10
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
name: getChunkName("ui-lib"),
|
|
218
|
+
test: generatePathReg("components"),
|
|
219
|
+
minShareCount: 2,
|
|
220
|
+
maxSize: 2e5,
|
|
221
|
+
priority: 5
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: getChunkName("ui-f-lib"),
|
|
225
|
+
test: generatePathReg("components", ".*?[Ff]orm.*?"),
|
|
226
|
+
minShareCount: 2,
|
|
227
|
+
maxSize: 5e4,
|
|
228
|
+
priority: 10
|
|
229
|
+
}
|
|
230
|
+
] } }
|
|
231
|
+
}
|
|
177
232
|
},
|
|
178
233
|
resolve: { alias: {
|
|
179
234
|
react: resolvePackageDir("react"),
|
|
180
235
|
"react-dom": resolvePackageDir("react-dom"),
|
|
181
236
|
"@tc/ui-react": path.resolve(currentDir, "../../fe/packages/ui/react/"),
|
|
182
|
-
...resolveAliasWithFallback([
|
|
237
|
+
...resolveAliasWithFallback([
|
|
238
|
+
[
|
|
239
|
+
"@tc/scalability/SchemaForm/frameData",
|
|
240
|
+
"./extended/SchemaForm/data",
|
|
241
|
+
frameFEPath
|
|
242
|
+
],
|
|
243
|
+
["@tc/scalability/SchemaForm/data", "./extended/SchemaForm/data"],
|
|
244
|
+
["@tc/scalability/dash/customRoutes", "./extended/dash/customRoutes"]
|
|
245
|
+
])
|
|
183
246
|
} }
|
|
184
247
|
});
|
|
185
248
|
logJoinColorized(colorize("builded", "green"), colorize(" -> ", "white"), colorize("time: ", "cyan"), colorize(/* @__PURE__ */ new Date(), "pink"));
|
package/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import getBaseController from "./app/controller/base.js";
|
|
2
|
-
import
|
|
2
|
+
import base_default from "./app/service/base.js";
|
|
3
3
|
import { resolve } from "./packages/utils/path.js";
|
|
4
4
|
import "./packages/utils/index.js";
|
|
5
5
|
import modelLoader from "./packages/core/loader/model.js";
|
|
@@ -13,7 +13,7 @@ var serverStart = (options) => {
|
|
|
13
13
|
};
|
|
14
14
|
var baseFn = {
|
|
15
15
|
baseControllerFn: getBaseController,
|
|
16
|
-
baseServiceFn:
|
|
16
|
+
baseServiceFn: base_default
|
|
17
17
|
};
|
|
18
18
|
//#endregion
|
|
19
19
|
export { baseFn, modelLoader, serverStart };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FetchInfo } from '../../../model/types/data/fetchInfo';
|
|
2
|
+
import { SelectProps } from '../../../packages/ui/react';
|
|
3
|
+
import { MergeType, MOmit } from '../../../typings/type';
|
|
4
|
+
export interface AsyncSelectProps extends MergeType<[MOmit<FetchInfo, 'fetchKey'>, MOmit<SelectProps, 'options'>]> {
|
|
5
|
+
}
|
|
6
|
+
declare const AsyncSelect: (props: AsyncSelectProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default AsyncSelect;
|
|
8
|
+
//# sourceMappingURL=AsyncSelect.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { request } from '../../widgets/common/request';
|
|
3
|
+
import { handlingRequestErrors } from '../../widgets/defaultPages/Schema/utils/fetchErrorShow';
|
|
4
|
+
import { Select } from '../../../packages/ui/react';
|
|
5
|
+
import useExecuteOnce from '../../../packages/ui/react/hooks/useExecuteOnce';
|
|
6
|
+
import { useState } from 'react';
|
|
7
|
+
const AsyncSelect = (props) => {
|
|
8
|
+
const { fetchConfig, ...params } = props;
|
|
9
|
+
const [options, setOptions] = useState([]);
|
|
10
|
+
const [loading, setLoading] = useState(false);
|
|
11
|
+
useExecuteOnce(async () => {
|
|
12
|
+
if (fetchConfig) {
|
|
13
|
+
setLoading(true);
|
|
14
|
+
const { method = 'get', url } = fetchConfig;
|
|
15
|
+
try {
|
|
16
|
+
const res = await handlingRequestErrors(request[method](url));
|
|
17
|
+
if (res.data.code === 0) {
|
|
18
|
+
setOptions(res.data.data.map((i) => {
|
|
19
|
+
i.searchText = i.label;
|
|
20
|
+
return i;
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
setLoading(false);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}, { executionPhase: 'mount' });
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
return _jsx(Select, { loading: loading, options: options, ...params });
|
|
31
|
+
};
|
|
32
|
+
export default AsyncSelect;
|
|
@@ -9,36 +9,36 @@ import { useModeStore } from '../widgets/store/mode';
|
|
|
9
9
|
import { Menu } from '../../packages/ui/react/components';
|
|
10
10
|
import useInit from '../../packages/ui/react/hooks/useInit';
|
|
11
11
|
const Dashboard = (props) => {
|
|
12
|
-
const { initModeData, initData,
|
|
12
|
+
const { initModeData, initData, projectInfo } = useModeStore();
|
|
13
13
|
useInit(initModeData);
|
|
14
14
|
const isInit = useRef(false);
|
|
15
15
|
const params = useRouterParams();
|
|
16
16
|
const [SK, uSK] = useState(params.key ?? params.custk);
|
|
17
17
|
const nav = useNavigate();
|
|
18
18
|
const menu = useMemo(() => {
|
|
19
|
-
if (initData &&
|
|
20
|
-
const menuData = generateMenuItemData(
|
|
19
|
+
if (initData && projectInfo?.menuLayout === 'top') {
|
|
20
|
+
const menuData = generateMenuItemData(projectInfo.menu);
|
|
21
21
|
return (_jsx(Menu, { className: " w-full", mode: "top", items: menuData, selectedKey: SK, onSelect: (e) => {
|
|
22
22
|
uSK(e);
|
|
23
|
-
const m = findMenuItem(
|
|
23
|
+
const m = findMenuItem(projectInfo.menu, e);
|
|
24
24
|
m && nav(m?.path);
|
|
25
25
|
} }));
|
|
26
26
|
}
|
|
27
27
|
return _jsx(_Fragment, {});
|
|
28
|
-
}, [initData,
|
|
28
|
+
}, [initData, projectInfo, SK, nav]);
|
|
29
29
|
// 重定向 处理
|
|
30
30
|
useEffect(() => {
|
|
31
|
-
if (initData &&
|
|
31
|
+
if (initData && projectInfo) {
|
|
32
32
|
if (isInit.current)
|
|
33
33
|
return;
|
|
34
|
-
if (
|
|
34
|
+
if (projectInfo.menuLayout !== 'top') {
|
|
35
35
|
console.log('left sidebar');
|
|
36
36
|
// 如果有参数 说明跳转的不是 根路径 并且路径带有专属前缀
|
|
37
37
|
if (Object.keys(params).length && location.pathname.includes(`/${leftSidebarBasePath}`)) {
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
|
-
const m = findMenuItem(
|
|
41
|
-
//
|
|
40
|
+
const m = findMenuItem(projectInfo.menu);
|
|
41
|
+
// projectInfo?.menu
|
|
42
42
|
nav({
|
|
43
43
|
pathname: `/${leftSidebarBasePath}${m.path.pathname}`,
|
|
44
44
|
search: m.path.search,
|
|
@@ -55,7 +55,7 @@ const Dashboard = (props) => {
|
|
|
55
55
|
// 残留路径
|
|
56
56
|
location.pathname.includes(`/${leftSidebarBasePath}`)) {
|
|
57
57
|
// 重定向
|
|
58
|
-
const m = findMenuItem(
|
|
58
|
+
const m = findMenuItem(projectInfo.menu);
|
|
59
59
|
// 因为这是父容器 所以只会初始化一次
|
|
60
60
|
// 重定向后不会走初始化流程 重新获取key
|
|
61
61
|
uSK(m.key);
|
|
@@ -66,8 +66,8 @@ const Dashboard = (props) => {
|
|
|
66
66
|
}
|
|
67
67
|
isInit.current = true;
|
|
68
68
|
}
|
|
69
|
-
}, [initData,
|
|
70
|
-
return (_jsxs("div", { className: "dash-main h-screen flex flex-col", children: [_jsx(HeaderView, { title:
|
|
69
|
+
}, [initData, projectInfo, params, nav]);
|
|
70
|
+
return (_jsxs("div", { className: "dash-main h-screen flex flex-col", children: [_jsx(HeaderView, { title: projectInfo?.desc, menu: menu }), _jsx("div", { className: "dash-container p-1.5 flex-1", children: _jsx(Outlet, {}) })] }));
|
|
71
71
|
};
|
|
72
72
|
Dashboard.displayName = 'Dashboard';
|
|
73
73
|
export default Dashboard;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { renderImportComponent } from '../widgets/common/importComponent';
|
|
3
3
|
import { leftSidebarBasePath, QK } from '../widgets/common/menu';
|
|
4
|
+
import extendDashRoutes from '@tc/scalability/dash/customRoutes';
|
|
4
5
|
import { initApp } from '../main';
|
|
5
6
|
import Dashboard from './Dashboard';
|
|
6
7
|
const baseRoutes = [
|
|
@@ -36,42 +37,54 @@ const baseRoutes = [
|
|
|
36
37
|
];
|
|
37
38
|
const sidebarRoutes = [
|
|
38
39
|
{
|
|
40
|
+
// top / left
|
|
39
41
|
// path: `/:${QK.k}/:${QK.sk}`,
|
|
40
42
|
path: `/:${QK.k}/*`,
|
|
41
43
|
component: renderImportComponent(import('../widgets/defaultPages/SidebarSlotPage')),
|
|
42
44
|
children: [
|
|
43
|
-
{
|
|
44
|
-
path: `todo`,
|
|
45
|
-
component: renderImportComponent(import('../widgets/defaultPages/Todo')),
|
|
46
|
-
},
|
|
47
45
|
{
|
|
48
46
|
path: `:${QK.sk}`,
|
|
49
47
|
component: renderImportComponent(import('../widgets/defaultPages/SlotPage')),
|
|
50
48
|
},
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
{
|
|
50
|
+
path: `todo`,
|
|
51
|
+
component: renderImportComponent(import('../widgets/defaultPages/Todo')),
|
|
52
|
+
},
|
|
55
53
|
// 插入自定义路由
|
|
56
54
|
],
|
|
57
55
|
},
|
|
58
56
|
{
|
|
57
|
+
// left
|
|
59
58
|
path: `/${leftSidebarBasePath}/*`,
|
|
60
59
|
component: renderImportComponent(import('../widgets/defaultPages/SidebarSlotPageTmp')),
|
|
61
60
|
children: [
|
|
62
|
-
{
|
|
63
|
-
path: `todo`,
|
|
64
|
-
component: renderImportComponent(import('../widgets/defaultPages/Todo')),
|
|
65
|
-
},
|
|
66
61
|
{
|
|
67
62
|
path: `:${QK.sk}`,
|
|
68
63
|
component: renderImportComponent(import('../widgets/defaultPages/SlotPage')),
|
|
69
64
|
},
|
|
65
|
+
{
|
|
66
|
+
path: `todo`,
|
|
67
|
+
component: renderImportComponent(import('../widgets/defaultPages/Todo')),
|
|
68
|
+
},
|
|
70
69
|
],
|
|
71
70
|
},
|
|
72
71
|
];
|
|
73
72
|
const getDefaultPageRoutes = () => {
|
|
74
|
-
|
|
73
|
+
if (typeof extendDashRoutes === 'function') {
|
|
74
|
+
const ctx = {
|
|
75
|
+
// 扩展 top menu
|
|
76
|
+
topRoutes: [],
|
|
77
|
+
// 扩展 left menu
|
|
78
|
+
sidebarRoutes: [],
|
|
79
|
+
};
|
|
80
|
+
extendDashRoutes(ctx);
|
|
81
|
+
const { topRoutes: customTopRoutes, sidebarRoutes: customSidebarRoutes } = ctx;
|
|
82
|
+
// 注入自定义路由
|
|
83
|
+
baseRoutes[0]?.children?.push(...customTopRoutes);
|
|
84
|
+
sidebarRoutes.forEach((sr) => {
|
|
85
|
+
sr.children?.push(...customSidebarRoutes);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
75
88
|
baseRoutes[0]?.children?.push(...sidebarRoutes);
|
|
76
89
|
return [...baseRoutes];
|
|
77
90
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RouteInfo } from '../widgets/components/Router';
|
|
2
|
+
export type DashRoutesContext = {
|
|
3
|
+
/**
|
|
4
|
+
* 扩展 topMenu 自定义页面
|
|
5
|
+
*
|
|
6
|
+
* !!!! 路径要为相对路径,不能为全路径
|
|
7
|
+
*/
|
|
8
|
+
topRoutes: RouteInfo[];
|
|
9
|
+
/**
|
|
10
|
+
* 扩展 leftMenu 自定义页面
|
|
11
|
+
*
|
|
12
|
+
* !!!! 路径要为相对路径,不能为全路径
|
|
13
|
+
*/
|
|
14
|
+
sidebarRoutes: RouteInfo[];
|
|
15
|
+
};
|
|
16
|
+
export type DashRoutesExtender = (context: DashRoutesContext) => void;
|
|
17
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @type {SchemaFormComponentsMap}
|
|
3
|
+
*/
|
|
4
|
+
declare const frameComponentsMap: {
|
|
5
|
+
asyncSelect: import("react").LazyExoticComponent<(props: import("../../components/AsyncSelect").AsyncSelectProps) => import("react/jsx-runtime").JSX.Element>;
|
|
6
|
+
};
|
|
7
|
+
export type FrameComponentsMap = typeof frameComponentsMap;
|
|
8
|
+
export type FrameComponentsMapKey = keyof FrameComponentsMap;
|
|
9
|
+
export type FrameComponentPropsMap = {
|
|
10
|
+
[K in FrameComponentsMapKey]: FrameComponentsMap[K] extends React.ComponentType<infer P> ? P : never;
|
|
11
|
+
};
|
|
12
|
+
export default frameComponentsMap;
|
|
13
|
+
//# sourceMappingURL=data.d.ts.map
|
package/fe/frontend/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import './typing/scalability';
|
|
2
|
+
export type * from './dash/types';
|
|
1
3
|
export * from './main';
|
|
2
|
-
export type { FormFieldSchema,
|
|
4
|
+
export type { FormFieldSchema, SchemaFormComponentsMap, SchemaFormNamespace, SelectProps, } from '../packages/ui/react';
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|