@_tc/template-core 0.0.1-bate.42 → 0.0.1-bate.45

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 (47) hide show
  1. package/cjs/app/README.md +286 -0
  2. package/cjs/app/service/{bese.js → base.js} +3 -3
  3. package/cjs/app/service/project.js +2 -2
  4. package/cjs/bundler/utils.js +62 -4
  5. package/cjs/index.js +2 -2
  6. package/esm/app/README.md +286 -0
  7. package/esm/app/service/{bese.js → base.js} +3 -3
  8. package/esm/app/service/project.js +2 -2
  9. package/esm/bundler/utils.js +62 -4
  10. package/esm/index.js +2 -2
  11. package/fe/frontend/components/AsyncSelect/AsyncSelect.d.ts +8 -0
  12. package/fe/frontend/components/AsyncSelect/AsyncSelect.js +32 -0
  13. package/fe/frontend/components/AsyncSelect/index.d.ts +4 -0
  14. package/fe/frontend/components/AsyncSelect/index.js +3 -0
  15. package/fe/frontend/dash/Dashboard.js +12 -12
  16. package/fe/frontend/dash/dash.entry.js +26 -13
  17. package/fe/frontend/dash/types.d.ts +17 -0
  18. package/fe/frontend/dash/types.js +1 -0
  19. package/fe/frontend/extended/SchemaForm/data.d.ts +13 -0
  20. package/fe/frontend/extended/SchemaForm/data.js +8 -0
  21. package/fe/frontend/index.d.ts +3 -1
  22. package/fe/frontend/index.js +1 -0
  23. package/fe/frontend/typing/scalability.d.ts +47 -0
  24. package/fe/frontend/typing/scalability.js +1 -0
  25. package/fe/frontend/widgets/api/baseInfo.d.ts +1 -1
  26. package/fe/frontend/widgets/api/baseInfo.js +1 -1
  27. package/fe/frontend/widgets/common/menu.js +1 -1
  28. package/fe/frontend/widgets/defaultPages/Schema/components/CallCom/PopFrom.js +2 -2
  29. package/fe/frontend/widgets/defaultPages/Schema/stores/schemaStore.d.ts +1 -1
  30. package/fe/frontend/widgets/defaultPages/SidebarSlotPageTmp.js +1 -1
  31. package/fe/frontend/widgets/hooks/useCurrentMenuData.js +3 -3
  32. package/fe/frontend/widgets/store/mode.d.ts +3 -3
  33. package/fe/frontend/widgets/store/mode.js +8 -8
  34. package/fe/model/types/data/component.d.ts +6 -12
  35. package/fe/model/types/data/search.d.ts +4 -4
  36. package/fe/packages/ui/react/components/Form/SchemaForm/data.d.ts +5 -10
  37. package/fe/packages/ui/react/components/Form/SchemaForm/data.js +4 -2
  38. package/fe/packages/ui/react/components/Form/SchemaForm/index.d.ts +1 -1
  39. package/fe/packages/ui/react/hooks/useLanguage.d.ts +1 -1
  40. package/fe/packages/ui/react/i18n/useI18n.d.ts +4 -4
  41. package/fe/typings/type.d.ts +2 -3
  42. package/model/types/data/component.d.ts +6 -12
  43. package/model/types/data/search.d.ts +4 -4
  44. package/package.json +1 -1
  45. package/types/typings/type.d.ts +2 -3
  46. /package/model/{types/test.d.ts → test.d.ts} +0 -0
  47. /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/bese.ts
3
- var bese_default = (app) => class BaseService {
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 { bese_default as default };
15
+ export { base_default as default };
@@ -1,8 +1,8 @@
1
- import bese_default from "./bese.js";
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 = bese_default(app);
5
+ const BaseService = base_default(app);
6
6
  const modelData = loaderModel(app);
7
7
  return class ProjectService extends BaseService {
8
8
  async getModelList() {
@@ -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(runFEPath, aliasPath + ext)).find((filePath) => existsSync(filePath));
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,69 @@ var VBuildFE = async (input, OperatingEnv) => {
173
175
  outDir: outDir(),
174
176
  emptyOutDir: true,
175
177
  sourcemap: OperatingEnv === "dev" ? "inline" : "hidden",
176
- rollupOptions: { input }
178
+ rollupOptions: {
179
+ input,
180
+ output: { codeSplitting: { groups: [
181
+ {
182
+ name: getChunkName("__nm"),
183
+ test: generatePathReg("node_modules"),
184
+ maxSize: 5e5,
185
+ priority: 1
186
+ },
187
+ {
188
+ name: getChunkName("r"),
189
+ test: generatePathReg("node_modules", "react"),
190
+ maxSize: 5e5,
191
+ priority: 5
192
+ },
193
+ {
194
+ name: getChunkName("r-d"),
195
+ test: generatePathReg("node_modules", "react-dom"),
196
+ maxSize: 2e5,
197
+ priority: 10
198
+ },
199
+ {
200
+ name: getChunkName("r-r-d"),
201
+ test: generatePathReg("node_modules", "react-router-dom"),
202
+ maxSize: 5e5,
203
+ priority: 10
204
+ },
205
+ {
206
+ name: getChunkName("ajv"),
207
+ test: generatePathReg("node_modules", "ajv"),
208
+ maxSize: 2e5,
209
+ priority: 10
210
+ },
211
+ {
212
+ name: getChunkName("ui-lib"),
213
+ test: generatePathReg("components"),
214
+ minShareCount: 2,
215
+ maxSize: 2e5,
216
+ priority: 5
217
+ },
218
+ {
219
+ name: getChunkName("ui-f-lib"),
220
+ test: generatePathReg("components", ".*?[Ff]orm.*?"),
221
+ minShareCount: 2,
222
+ maxSize: 5e4,
223
+ priority: 10
224
+ }
225
+ ] } }
226
+ }
177
227
  },
178
228
  resolve: { alias: {
179
229
  react: resolvePackageDir("react"),
180
230
  "react-dom": resolvePackageDir("react-dom"),
181
231
  "@tc/ui-react": path.resolve(currentDir, "../../fe/packages/ui/react/"),
182
- ...resolveAliasWithFallback([["$business/SchemaForm/data", "./extended/SchemaForm/data"]])
232
+ ...resolveAliasWithFallback([
233
+ [
234
+ "@tc/scalability/SchemaForm/frameData",
235
+ "./extended/SchemaForm/data",
236
+ frameFEPath
237
+ ],
238
+ ["@tc/scalability/SchemaForm/data", "./extended/SchemaForm/data"],
239
+ ["@tc/scalability/dash/customRoutes", "./extended/dash/customRoutes"]
240
+ ])
183
241
  } }
184
242
  });
185
243
  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 bese_default from "./app/service/bese.js";
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: bese_default
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;
@@ -0,0 +1,4 @@
1
+ import AsyncSelect from './AsyncSelect';
2
+ export * from './AsyncSelect';
3
+ export default AsyncSelect;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,3 @@
1
+ import AsyncSelect from './AsyncSelect';
2
+ export * from './AsyncSelect';
3
+ 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, projestInfo } = useModeStore();
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 && projestInfo?.menuLayout === 'top') {
20
- const menuData = generateMenuItemData(projestInfo.menu);
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(projestInfo.menu, e);
23
+ const m = findMenuItem(projectInfo.menu, e);
24
24
  m && nav(m?.path);
25
25
  } }));
26
26
  }
27
27
  return _jsx(_Fragment, {});
28
- }, [initData, projestInfo, SK, nav]);
28
+ }, [initData, projectInfo, SK, nav]);
29
29
  // 重定向 处理
30
30
  useEffect(() => {
31
- if (initData && projestInfo) {
31
+ if (initData && projectInfo) {
32
32
  if (isInit.current)
33
33
  return;
34
- if (projestInfo.menuLayout !== 'top') {
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(projestInfo.menu);
41
- // projestInfo?.menu
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(projestInfo.menu);
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, projestInfo, params, nav]);
70
- return (_jsxs("div", { className: "dash-main h-screen flex flex-col", children: [_jsx(HeaderView, { title: projestInfo?.desc, menu: menu }), _jsx("div", { className: "dash-container p-1.5 flex-1", children: _jsx(Outlet, {}) })] }));
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
- // path: "schema",
53
- // component: renderImportComponent(import("../defaultPages/Schema")),
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
- // getBusinessRoutes(baseRoutes, sidebarRoutes[0]?.childrens ?? []);
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
@@ -0,0 +1,8 @@
1
+ import { lazy } from 'react';
2
+ /**
3
+ * @type {SchemaFormComponentsMap}
4
+ */
5
+ const frameComponentsMap = {
6
+ asyncSelect: lazy(async () => await import('../../components/AsyncSelect')),
7
+ };
8
+ export default frameComponentsMap;
@@ -1,3 +1,5 @@
1
+ import './typing/scalability';
2
+ export type * from './dash/types';
1
3
  export * from './main';
2
- export type { FormFieldSchema, SchemaFormBusinessComponentsMap, SchemaFormNamespace, SelectProps, } from '../packages/ui/react';
4
+ export type { FormFieldSchema, SchemaFormComponentsMap, SchemaFormNamespace, SelectProps, } from '../packages/ui/react';
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1,2 @@
1
+ import './typing/scalability';
1
2
  export * from './main';