@_tc/template-core 0.2.0 → 0.2.1

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 (82) hide show
  1. package/AGENT_README.md +2 -2
  2. package/README.md +67 -30
  3. package/cjs/app/controller/project.js +1 -1
  4. package/cjs/app/controller/view.js +1 -1
  5. package/cjs/app/extends/db.js +4 -4
  6. package/cjs/app/middlewares/error-handle.js +1 -1
  7. package/cjs/app/middlewares/project-handler.js +1 -1
  8. package/cjs/app/utils/i18n.js +1 -0
  9. package/cjs/app/view/entry.tpl +1 -0
  10. package/cjs/packages/common/i18n/default.js +1 -1
  11. package/cjs/packages/common/i18n/en-US.js +1 -1
  12. package/cjs/packages/common/index.js +1 -1
  13. package/esm/app/controller/project.js +12 -11
  14. package/esm/app/controller/view.js +1 -0
  15. package/esm/app/extends/db.js +64 -60
  16. package/esm/app/middlewares/error-handle.js +16 -15
  17. package/esm/app/middlewares/project-handler.js +8 -7
  18. package/esm/app/utils/i18n.js +36 -0
  19. package/esm/app/view/entry.tpl +1 -0
  20. package/esm/packages/common/i18n/default.js +13 -0
  21. package/esm/packages/common/i18n/en-US.js +13 -0
  22. package/esm/packages/common/index.js +9 -9
  23. package/fe/frontend/apps/dash/Dashboard.js +6 -4
  24. package/fe/frontend/apps/dash/dash.entry.js +2 -0
  25. package/fe/frontend/src/common/generateMenuData.d.ts +4 -1
  26. package/fe/frontend/src/common/generateMenuData.js +3 -3
  27. package/fe/frontend/src/common/language.d.ts +1 -2
  28. package/fe/frontend/src/common/language.js +10 -10
  29. package/fe/frontend/src/common/request.js +3 -1
  30. package/fe/frontend/src/components/AsyncSelect/AsyncSelect.js +10 -2
  31. package/fe/frontend/src/components/BasePage/HeaderView.js +2 -2
  32. package/fe/frontend/src/components/LanguageSwitch/LanguageSwitch.js +13 -9
  33. package/fe/frontend/src/components/ThemeSwitch/ThemeSwitch.js +4 -3
  34. package/fe/frontend/src/defaultPages/NotFoundPage/index.js +4 -3
  35. package/fe/frontend/src/defaultPages/SchemaPage/components/CallCom/DetailPanel.js +14 -9
  36. package/fe/frontend/src/defaultPages/SchemaPage/components/CallCom/PopFrom.js +8 -7
  37. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaSearch/index.js +6 -12
  38. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaTable/index.js +25 -18
  39. package/fe/frontend/src/defaultPages/SchemaPage/index.js +5 -3
  40. package/fe/frontend/src/defaultPages/SidebarSlotPageTmp.js +4 -2
  41. package/fe/frontend/src/hooks/useText.d.ts +3 -0
  42. package/fe/frontend/src/hooks/useText.js +14 -0
  43. package/fe/frontend/src/index.d.ts +1 -0
  44. package/fe/frontend/src/index.js +3 -2
  45. package/fe/frontend/src/language/index.d.ts +0 -2
  46. package/fe/frontend/src/language/index.js +1 -7
  47. package/fe/frontend/src/language/resources.d.ts +2 -0
  48. package/fe/frontend/src/language/resources.js +9 -0
  49. package/fe/packages/common/i18n/default.d.ts +15 -0
  50. package/fe/packages/common/i18n/default.js +16 -0
  51. package/fe/packages/common/i18n/en-US.d.ts +15 -0
  52. package/fe/packages/common/i18n/en-US.js +18 -2
  53. package/fe/packages/common/i18n/index.js +13 -0
  54. package/fe/packages/common/i18n/locales.js +7 -0
  55. package/fe/packages/react/ui/components/Date/Calendar.js +9 -5
  56. package/fe/packages/react/ui/components/Date/LocaleContext.d.ts +22 -1
  57. package/fe/packages/react/ui/components/Date/LocaleContext.js +28 -3
  58. package/fe/packages/react/ui/components/Date/LocaleProvider.d.ts +1 -1
  59. package/fe/packages/react/ui/components/Date/LocaleProvider.js +7 -16
  60. package/fe/packages/react/ui/components/Date/index.js +2 -2
  61. package/fe/packages/react/ui/components/Date/locales.d.ts +2 -0
  62. package/fe/packages/react/ui/components/Date/locales.js +29 -13
  63. package/fe/packages/react/ui/components/TableSearch/TableSearch.js +21 -1
  64. package/fe/packages/react/ui/components/TableSearch/lang.d.ts +2 -0
  65. package/fe/packages/react/ui/components/TableSearch/lang.js +18 -7
  66. package/model/frontend/src/common/language.d.ts +1 -2
  67. package/model/frontend/src/hooks/useText.d.ts +3 -0
  68. package/model/frontend/src/language/index.d.ts +0 -2
  69. package/model/frontend/src/language/resources.d.ts +2 -0
  70. package/model/packages/common/i18n/default.d.ts +15 -0
  71. package/model/packages/common/i18n/en-US.d.ts +15 -0
  72. package/model/packages/react/ui/components/Date/LocaleContext.d.ts +22 -1
  73. package/model/packages/react/ui/components/Date/LocaleProvider.d.ts +1 -1
  74. package/model/packages/react/ui/components/Date/locales.d.ts +2 -0
  75. package/model/packages/react/ui/components/TableSearch/lang.d.ts +2 -0
  76. package/package.json +1 -1
  77. package/types/app/utils/i18n.d.ts +12 -0
  78. package/types/packages/common/i18n/default.d.ts +19 -0
  79. package/types/packages/common/i18n/en-US.d.ts +21 -2
  80. package/types/packages/common/i18n/index.d.ts +21 -0
  81. package/types/packages/common/i18n/locales.d.ts +10 -0
  82. package/types/packages/common/i18n/types.d.ts +40 -0
package/AGENT_README.md CHANGED
@@ -369,7 +369,6 @@ import '@_tc/template-core/fe/tailwind_ui.css'
369
369
 
370
370
  ```ts
371
371
  import {
372
- addLanguage,
373
372
  addLanguageResources,
374
373
  clearRafTimer,
375
374
  api,
@@ -387,6 +386,7 @@ import {
387
386
  setAuthToken,
388
387
  setLanguage,
389
388
  useSchemaStore,
389
+ useText,
390
390
  LanguageSwitch,
391
391
  ThemeSwitch,
392
392
  } from '@_tc/template-core/fe'
@@ -423,7 +423,7 @@ import { Button, DataTable, Form, Input, Modal, Select } from '@_tc/template-cor
423
423
  - 组件加载辅助:`renderImportComponent(import('./Page'))` 会用 `React.lazy` + `Suspense` 渲染动态组件。
424
424
  - Schema 通信:`schemaEventBus`、`eventsInfo`、`merge`。
425
425
  - 共享状态:`modeStore`、`schemaStore`、`apiFreezerStore` 及对应 hooks。
426
- - 多语言:`addLanguageResources()` / `addResources()` 追加某语种文案,`addLanguage()` 新增语种,`setLanguage()` 切换语言,配置文案可写 `$i18n::...`。
426
+ - 多语言:`addLanguageResources()` 追加或新增某语种文案,`setLanguage()` 切换语言。React render 中用 `useText()`,非 React 工具代码用 `getText()`;`$i18n::` 前缀会被去掉后查询资源,无前缀字符串会按原 key 查询,未命中时原样返回。配置文案推荐写 `$i18n::...`,也可写普通字符串。
427
427
  - 主题:`ThemeSwitch` 会同步根节点 `dark` class 和 `localStorage`。
428
428
  - `Input type="password"` 会自动显示密码显隐按钮;`allowClear` 不作用于密码输入。
429
429
  - RAF 风格计时器由 `@tc/common/rafTimer` 提供,浏览器优先使用 RAF,Node/SSR 自动降级到 `setTimeout`。
package/README.md CHANGED
@@ -116,7 +116,9 @@ export default {
116
116
  }
117
117
  ```
118
118
 
119
- `auth.ATKey` / `auth.RTKey` 用于约定业务鉴权中间件读取短 token 和刷新 token 的 header 名;默认分别为 `Authorization` 和 `RT`。
119
+ `auth.ATKey` / `auth.RTKey` 用于约定项目鉴权中间件读取短 token 和刷新 token 的 header 名;默认分别为 `Authorization` 和 `RT`。
120
+
121
+ 服务端返回给前端的错误消息会按请求头里的语种翻译。当前优先读取 `x-tc-language`,也兼容 `tc_language`、`tc-language`、`language`、`lang`、`locale` 和 `accept-language`;如果没取到,默认按英文 `en-US` 处理。
120
122
 
121
123
  静态资源挂载顺序为:项目 `app/public`、框架 `app/public`、`additionalPublicPaths`。Nunjucks 模板查找顺序为:项目 `app/public/dist`、框架 `app/public/dist`、`additionalPublicPaths/dist`。这些目录由 `app.publicsPath` 统一维护。当 `buildFE` 输出到自定义目录时,可以用 `additionalPublicPaths` 把该目录交给 Koa 提供静态资源访问和模板渲染;如果需要模板查找也命中追加目录,请传绝对路径数组。
122
124
 
@@ -127,7 +129,7 @@ buildFE(mode: 'dev' | 'prod', options?: BuildFEOptions)
127
129
  ```
128
130
 
129
131
  **mode**:构建模式
130
- - `'dev'`:开发模式,构建一次并监听业务 `frontend/` 变化后重建
132
+ - `'dev'`:开发模式,构建一次并监听项目 `frontend/` 变化后重建
131
133
  - `'prod'`:生产模式,构建优化后的静态资源
132
134
 
133
135
  **options.output**:构建输出位置
@@ -192,7 +194,7 @@ http://localhost:9000/dash?projk=demo
192
194
 
193
195
  ### 后端类型
194
196
 
195
- `@_tc/template-core` 会导出常用 Node 侧类型,业务项目写 `app/*` 文件时建议优先复用这些类型。
197
+ `@_tc/template-core` 会导出常用 Node 侧类型,项目编写 `app/*` 文件时建议优先复用这些类型。
196
198
 
197
199
  | 类型 | 使用场景 |
198
200
  | --- | --- |
@@ -313,9 +315,7 @@ VS Code 建议安装官方 Tailwind CSS IntelliSense 插件,并在工作区 `.
313
315
  import {
314
316
  api,
315
317
  apiFreezerStore,
316
- addLanguage,
317
318
  addLanguageResources,
318
- addResources,
319
319
  AsyncSelect,
320
320
  clearAuthToken,
321
321
  eventsInfo,
@@ -331,6 +331,7 @@ import {
331
331
  modeStore,
332
332
  post,
333
333
  renderImportComponent,
334
+ registerFrontendI18nResources,
334
335
  request,
335
336
  schemaEventBus,
336
337
  schemaStore,
@@ -343,6 +344,7 @@ import {
343
344
  useApiFreezer,
344
345
  useModeStore,
345
346
  useSchemaStore,
347
+ useText,
346
348
  } from '@_tc/template-core/fe'
347
349
 
348
350
  import type {
@@ -380,7 +382,7 @@ import type {
380
382
  | 请求类型 | `BaseResponse`、`PageParams`、`PageResponse`、`RequestConfig`、`ResponseConfig`、`AxiosError` |
381
383
  | RAF 风格计时器 | `rafSetTimeout`、`rafSetInterval`、`rafClearTimeout`、`rafClearInterval`、`clearRafTimer`、`RafTimerId`、`RafTimerCallback` |
382
384
  | Token 工具 | `getAuthToken`、`setAuthToken`、`clearAuthToken`、`localKeyMap` |
383
- | 多语言工具 | `getText`、`t`、`addLanguage`、`addLanguageResources`、`addResources`、`setLanguage`、`setFallbackLanguage`、`setResources`、`getCurrentLanguage`、`getFallbackLanguage`、`getSupportedLanguages` |
385
+ | 多语言工具 | `useText`、`getText`、`t`、`registerFrontendI18nResources`、`addLanguageResources`、`setLanguage`、`setFallbackLanguage`、`setResources`、`getCurrentLanguage`、`getFallbackLanguage`、`getSupportedLanguages` |
384
386
  | 请求冻结 | `apiFreezerStore`、`useApiFreezer`、`FreezeState`、`ApiFreezerRequestMatcher` |
385
387
  | 事件工具 | `eventsInfo`、`merge` |
386
388
  | 共享状态 | `modeStore`、`useModeStore`、`schemaStore`、`useSchemaStore`、`schemaEventBus` |
@@ -393,7 +395,21 @@ import type {
393
395
 
394
396
  ### 前端多语言
395
397
 
396
- TemplateCore 前端通过 `@_tc/template-core/fe` 暴露 i18n 能力。框架内置中文、英文资源,项目可以继续追加自己的资源或新增语种。
398
+ TemplateCore 前端通过 `@_tc/template-core/fe` 暴露 i18n 能力。框架内置中文、英文资源,但不会在普通自定义页面 import 前端入口时自动注册,避免非 Dashboard 页面把框架文案整包带入运行时资源。
399
+
400
+ 默认 Dashboard 入口会自动调用 `registerFrontendI18nResources()`,所以 Dashboard、Schema CRUD、内置页头、语言切换等框架页面可以直接使用框架内置文案。自定义入口如果也要复用这些框架文案,需要在渲染前手动注册:
401
+
402
+ ```ts
403
+ import { initApp, registerFrontendI18nResources } from '@_tc/template-core/fe'
404
+
405
+ initApp(App, {
406
+ beforeRender: async () => {
407
+ await registerFrontendI18nResources()
408
+ },
409
+ })
410
+ ```
411
+
412
+ 项目可以继续追加自己的资源或新增语种。
397
413
 
398
414
  **追加自定义语言资源**:
399
415
 
@@ -401,7 +417,7 @@ TemplateCore 前端通过 `@_tc/template-core/fe` 暴露 i18n 能力。框架内
401
417
  import { addLanguageResources } from '@_tc/template-core/fe'
402
418
 
403
419
  addLanguageResources('zh-CN', {
404
- business: {
420
+ app: {
405
421
  product: {
406
422
  menu: '商品管理',
407
423
  name: '商品名称',
@@ -411,8 +427,8 @@ addLanguageResources('zh-CN', {
411
427
  },
412
428
  })
413
429
 
414
- i18nStore.getState().addResources('en-US', {
415
- business: {
430
+ addLanguageResources('en-US', {
431
+ app: {
416
432
  product: {
417
433
  menu: 'Products',
418
434
  name: 'Product name',
@@ -426,10 +442,10 @@ i18nStore.getState().addResources('en-US', {
426
442
  **新增语种并切换**:
427
443
 
428
444
  ```ts
429
- import { addLanguage, setLanguage } from '@_tc/template-core/fe'
445
+ import { addLanguageResources, setLanguage } from '@_tc/template-core/fe'
430
446
 
431
- addLanguage('ja-JP', {
432
- business: {
447
+ addLanguageResources('ja-JP', {
448
+ app: {
433
449
  product: {
434
450
  menu: '商品管理',
435
451
  },
@@ -439,19 +455,40 @@ addLanguage('ja-JP', {
439
455
  setLanguage('ja-JP')
440
456
  ```
441
457
 
442
- `addLanguageResources()` / `addResources()` 默认会深合并同语种文案;传 `{ merge: false }` 可以替换该语种资源。`setResources(resources, { merge: true })` 可批量合并多语种资源。`LanguageSwitch` 默认会把已注册语种加入选项;需要自定义展示文案时仍可传入 `options`。
458
+ `addLanguageResources()` 用于追加或新增某个语种的文案,默认会深合并同语种资源;传 `{ merge: false }` 可以替换该语种资源。`setResources(resources, { merge: true })` 可批量合并多语种资源。`LanguageSwitch` 默认会把已注册语种加入选项;需要自定义展示文案时仍可传入 `options`。
459
+
460
+ React 组件 render 中使用 `useText()` 读取文案。它会订阅语言和资源变化,调用 `setLanguage()` 后组件会自动重渲染。
461
+
462
+ `useText()` / `getText()` 遇到 `$i18n::` 前缀会先去掉前缀再查语言资源;没有前缀时会直接把传入字符串作为 key 查询,查不到才原样返回:
463
+
464
+ ```tsx
465
+ import { useText } from '@_tc/template-core/fe'
466
+
467
+ function ProductTitle() {
468
+ const text = useText()
469
+
470
+ return (
471
+ <>
472
+ <h1>{text('$i18n::app.product.menu')}</h1>
473
+ <span>{text('Plain title')}</span>
474
+ </>
475
+ )
476
+ }
477
+ ```
478
+
479
+ `getText()` 是普通函数,适合请求错误、日志、校验工具或事件回调等非 React 场景;它不会主动触发 React 组件重渲染。
443
480
 
444
481
  资源注册时不写 `$i18n::` 前缀,配置中使用时才写:
445
482
 
446
483
  ```ts
447
- const title = '$i18n::business.product.createTitle'
484
+ const title = '$i18n::app.product.createTitle'
448
485
  ```
449
486
 
450
487
  **在 model / Schema 配置中使用**:
451
488
 
452
489
  ```ts
453
490
  {
454
- name: '$i18n::business.product.menu',
491
+ name: '$i18n::app.product.menu',
455
492
  moduleType: 'schema',
456
493
  schemaConfig: {
457
494
  schema: {
@@ -459,7 +496,7 @@ const title = '$i18n::business.product.createTitle'
459
496
  properties: {
460
497
  name: {
461
498
  type: 'string',
462
- label: '$i18n::business.product.name',
499
+ label: '$i18n::app.product.name',
463
500
  minLength: 2,
464
501
  createFormOption: {
465
502
  comType: 'input',
@@ -473,7 +510,7 @@ const title = '$i18n::business.product.createTitle'
473
510
  tableConfig: {
474
511
  headerButtons: [
475
512
  {
476
- label: '$i18n::business.product.create',
513
+ label: '$i18n::app.product.create',
477
514
  eventKey: 'callComponent',
478
515
  eventOption: { comName: 'createForm' },
479
516
  },
@@ -481,7 +518,7 @@ const title = '$i18n::business.product.createTitle'
481
518
  },
482
519
  componentConfig: {
483
520
  createForm: {
484
- title: '$i18n::business.product.createTitle',
521
+ title: '$i18n::app.product.createTitle',
485
522
  saveBtnText: '$i18n::common.submit',
486
523
  },
487
524
  },
@@ -939,7 +976,7 @@ const unsafeUsers = app.extends.db.queryDB(
939
976
  )
940
977
  ```
941
978
 
942
- 业务项目可以用自己的 `app/extends/db.ts` 覆盖默认实现。建议保留同一组方法名,这样 controller/service 调用方不用调整。
979
+ 项目可以用自己的 `app/extends/db.ts` 覆盖默认实现。建议保留同一组方法名,这样 controller/service 调用方不用调整。
943
980
 
944
981
  ```ts
945
982
  // app/extends/db.ts
@@ -1055,7 +1092,7 @@ export default (app: KoaApp, router: Router) => {
1055
1092
  - 每个 `app/router/*.ts` 文件都会获得独立的 `koa-router` 实例。
1056
1093
  - 可以通过 `router.level = number` 控制挂载顺序,数值越小越早挂载。
1057
1094
  - 默认 `level` 是 `0`,框架兜底 router 是 `99`。
1058
- - 通配、兜底、重定向类路由建议设置较大的 `level`,避免抢先匹配业务 API。
1095
+ - 通配、兜底、重定向类路由建议设置较大的 `level`,避免抢先匹配项目 API。
1059
1096
 
1060
1097
  ```ts
1061
1098
  import type { KoaApp, Router } from '@_tc/template-core'
@@ -1344,7 +1381,7 @@ DELETE {api} -> 删除
1344
1381
 
1345
1382
  ### 服务端兜底路由守卫
1346
1383
 
1347
- 业务项目可以创建 `app/router-guard.ts` 或 `app/router-guard.js`。它只在所有正常 `app/router/*` 路由都没有命中时执行。
1384
+ 项目可以创建 `app/router-guard.ts` 或 `app/router-guard.js`。它只在所有正常 `app/router/*` 路由都没有命中时执行。
1348
1385
 
1349
1386
  ```ts
1350
1387
  import type { Ctx, KoaApp } from '@_tc/template-core'
@@ -1369,7 +1406,7 @@ export default (_app: KoaApp) => {
1369
1406
 
1370
1407
  ### 扩展 Dashboard 顶部用户区域
1371
1408
 
1372
- 业务项目可以创建 `frontend/extended/dash/components.tsx`,通过组件映射填充内置 Dashboard 页头右侧区域。
1409
+ 项目可以创建 `frontend/extended/dash/components.tsx`,通过组件映射填充内置 Dashboard 页头右侧区域。
1373
1410
 
1374
1411
  ```tsx
1375
1412
  // frontend/extended/dash/components.tsx
@@ -1390,7 +1427,7 @@ export default components
1390
1427
 
1391
1428
  ### 扩展 Dashboard 登录守卫
1392
1429
 
1393
- 业务项目可以创建 `frontend/extended/dash/routeGuard.ts`,用于在 Dashboard 内置 `homePage` / 首菜单重定向前做登录判断。
1430
+ 项目可以创建 `frontend/extended/dash/routeGuard.ts`,用于在 Dashboard 内置 `homePage` / 首菜单重定向前做登录判断。
1394
1431
 
1395
1432
  ```ts
1396
1433
  // frontend/extended/dash/routeGuard.ts
@@ -1406,9 +1443,9 @@ export default dashRouteGuard
1406
1443
  返回值规则:
1407
1444
 
1408
1445
  - 返回 `string`:框架使用 `window.location.href` 跳转,登录页不需要在 Dash 路由下。
1409
- - 返回非 `string`:中断 Dashboard 内置重定向,业务方可自行跳转或处理提示。
1446
+ - 返回非 `string`:中断 Dashboard 内置重定向,使用方可自行跳转或处理提示。
1410
1447
  - `DashRouteGuardResult` 是 `string | undefined`;`undefined`(包括已登录分支的隐式返回)也会打断 Dashboard 内置重定向。
1411
- - 没有业务 `routeGuard` 文件时,框架使用兜底空对象,不影响默认 Dashboard 重定向。
1448
+ - 没有自定义 `routeGuard` 文件时,框架使用兜底空对象,不影响默认 Dashboard 重定向。
1412
1449
 
1413
1450
  ### 扩展 SchemaForm 字段组件
1414
1451
 
@@ -1580,7 +1617,7 @@ remark: {
1580
1617
 
1581
1618
  ### 扩展 SchemaTable 单元格渲染组件
1582
1619
 
1583
- SchemaPage 表格列支持通过 `tableOption.renderComponent` 使用内置或业务注册的渲染组件。内置组件:
1620
+ SchemaPage 表格列支持通过 `tableOption.renderComponent` 使用内置或自定义注册的渲染组件。内置组件:
1584
1621
 
1585
1622
  - `PreviewImage`:把当前单元格值渲染成图片预览;值是数组时直接作为图片列表,值是单个字符串时自动转成单图数组。
1586
1623
 
@@ -1635,7 +1672,7 @@ const componentsMap = {
1635
1672
  export default componentsMap
1636
1673
  ```
1637
1674
 
1638
- 组件会收到 `value`、`record`、`rowIndex`、`fieldKey`,以及 `renderComponentProps` 中的业务参数:
1675
+ 组件会收到 `value`、`record`、`rowIndex`、`fieldKey`,以及 `renderComponentProps` 中的自定义参数:
1639
1676
 
1640
1677
  ```tsx
1641
1678
  // frontend/components/PriceCell.tsx
@@ -1775,7 +1812,7 @@ declare module '@_tc/template-core/model' {
1775
1812
 
1776
1813
  - `RenderComponentPropsMap` 的 key 对应 `tableOption.renderComponent`。
1777
1814
  - 运行时组件注册在 `frontend/extended/SchemaPage/SchemaTable/data.ts`。
1778
- - 组件运行时会自动收到 `value`、`record`、`rowIndex`、`fieldKey`;`renderComponentProps` 只配置业务参数。
1815
+ - 组件运行时会自动收到 `value`、`record`、`rowIndex`、`fieldKey`;`renderComponentProps` 只配置自定义参数。
1779
1816
 
1780
1817
  ### KoaApp 类型扩展
1781
1818
 
@@ -2130,6 +2167,6 @@ await buildBE({
2130
2167
  - `model` 数组合并依赖稳定 `key`。
2131
2168
  - Dashboard 默认需要 URL 带 `?projk=项目key`。
2132
2169
  - Dashboard 登录守卫放在 `frontend/extended/dash/routeGuard.ts`;登录页通常不在 Dash 路由下,返回登录页 URL 即可。
2133
- - 服务端兜底守卫放在业务 `app/router-guard.ts|js`,不是 `app/business` 子目录。
2170
+ - 服务端兜底守卫放在项目根目录的 `app/router-guard.ts|js`。
2134
2171
  - 前端入口必须命名为 `.entry.tsx`、`.entry.ts`、`.entry.jsx` 或 `.entry.js`。
2135
2172
  - 入口同目录的 `.html` 只能作为插槽文件使用,不能写完整 HTML 文档;页面外壳始终由 `app/view/entry.tpl` 生成。
@@ -1 +1 @@
1
- const e=require(`./base.js`);var t=(t=>{let n=e(t);return class extends n{getModelList=async e=>{let t=(await this.service.project.getModelList()).reduce((e,t)=>{let{model:n,project:r}=t,{key:i,name:a,desc:o}=n,s={key:i,name:a,desc:o},c=Object.keys(r).reduce((e,t)=>{let{key:n,name:i,desc:a,homePage:o}=r[t];return e[t]={key:n,name:i,desc:a,homePage:o},e},{});return e.push({model:s,project:c}),e},[]);this.success(e,t)};getProjectList=async e=>{let t=e.reqData?.data.projk,n=(await this.service.project.getList(t))?.map(e=>{let{modelKey:t,key:n,name:r,desc:i,homePage:a}=e;return{modelKey:t,key:n,name:r,desc:i,homePage:a}});this.success(e,n)};getProject=async e=>{let{key:t}=e.params;if(!t){this.fail(e,10001,`获取项目异常`);return}let n=this.service.project.getProject(t);if(!n){this.fail(e,10001,`获取项目异常`);return}this.success(e,n)}}});module.exports=t;
1
+ const e=require(`./base.js`),t=require(`../utils/i18n.js`);var n=(n=>{let r=e(n);return class extends r{getModelList=async e=>{let t=(await this.service.project.getModelList()).reduce((e,t)=>{let{model:n,project:r}=t,{key:i,name:a,desc:o}=n,s={key:i,name:a,desc:o},c=Object.keys(r).reduce((e,t)=>{let{key:n,name:i,desc:a,homePage:o}=r[t];return e[t]={key:n,name:i,desc:a,homePage:o},e},{});return e.push({model:s,project:c}),e},[]);this.success(e,t)};getProjectList=async e=>{let t=e.reqData?.data.projk,n=(await this.service.project.getList(t))?.map(e=>{let{modelKey:t,key:n,name:r,desc:i,homePage:a}=e;return{modelKey:t,key:n,name:r,desc:i,homePage:a}});this.success(e,n)};getProject=async e=>{let{key:n}=e.params;if(!n){this.fail(e,10001,t.requestT(e,`server.errors.getProjectFailed`));return}let r=this.service.project.getProject(n);if(!r){this.fail(e,10001,t.requestT(e,`server.errors.getProjectFailed`));return}this.success(e,r)}}});module.exports=n;
@@ -1 +1 @@
1
- const e=require(`../../packages/common/string/index.js`);var t=e=>JSON.stringify(e).replace(/</g,`\\u003c`).replace(/>/g,`\\u003e`).replace(/&/g,`\\u0026`).replace(/\u2028/g,`\\u2028`).replace(/\u2029/g,`\\u2029`),n=(n=>class{async renderPage(r,i){let a=r.path;if(n.extends.localCacheHtmlEtag.keepFreshFEBuildKey(),a.includes(`${n.options.apiPrefix}/`))await i();else{n.extends.logger.log(` - render page: `+r.params.page);try{let i=r.query.projk;Array.isArray(i)&&(i=e.joinStr(...i));let a={projKey:i??``,name:n.options?.name??``,env:n.envs.get(),basePath:t(`${n.options.pageBasePage}${r.params.page}`),projKeyJson:t(String(r.query.projk??``)),signKey:t(n.config.signKey),options:t(n.options)},o=n.extends.renderView(`${r.params.page}.entry.tpl`,r,a),s=e.joinStr(a.basePath,a.name,a.env,a.projKey);if(!n.extends.localCacheHtmlEtag.hasEtag(s)){let e=n.extends.crypto.hmacSign(o);n.extends.localCacheHtmlEtag.setEtag(s,e)}let c=n.extends.localCacheHtmlEtag.getEtag(s);if(c||console.log(`---- etag 缓存异常 请检查服务 ----`),r.etag=c??Date.now()+``,r.fresh){r.status=304;return}}catch(e){console.log(`-------------- render view error --------------`),console.log(e),n.extends.generateErrorMessage(`template not found`,{status:404,showError:!0,code:0})}}}});module.exports=n;
1
+ const e=require(`../../packages/common/string/index.js`);var t=e=>JSON.stringify(e).replace(/</g,`\\u003c`).replace(/>/g,`\\u003e`).replace(/&/g,`\\u0026`).replace(/\u2028/g,`\\u2028`).replace(/\u2029/g,`\\u2029`),n=(n=>class{async renderPage(r,i){let a=r.path;if(n.extends.localCacheHtmlEtag.keepFreshFEBuildKey(),a.includes(`${n.options.apiPrefix}/`))await i();else{n.extends.logger.log(` - render page: `+r.params.page);try{let i=r.query.projk;Array.isArray(i)&&(i=e.joinStr(...i));let a={projKey:i??``,name:n.options?.name??``,env:n.envs.get(),FEBasePage:t(`${n.options.pageBasePage}`),basePath:t(`${n.options.pageBasePage}${r.params.page}`),projKeyJson:t(String(r.query.projk??``)),signKey:t(n.config.signKey),options:t(n.options)},o=n.extends.renderView(`${r.params.page}.entry.tpl`,r,a),s=e.joinStr(a.basePath,a.name,a.env,a.projKey);if(!n.extends.localCacheHtmlEtag.hasEtag(s)){let e=n.extends.crypto.hmacSign(o);n.extends.localCacheHtmlEtag.setEtag(s,e)}let c=n.extends.localCacheHtmlEtag.getEtag(s);if(c||console.log(`---- etag 缓存异常 请检查服务 ----`),r.etag=c??Date.now()+``,r.fresh){r.status=304;return}}catch(e){console.log(`-------------- render view error --------------`),console.log(e),n.extends.generateErrorMessage(`template not found`,{status:404,showError:!0,code:0})}}}});module.exports=n;
@@ -1,12 +1,12 @@
1
- require(`../../_virtual/_rolldown/runtime.js`);let e=require(`node:fs`),t=require(`node:path`);var n=`framework`,r=`.template-core/template-core.sqlite`;function i(n){let r=s(n),i,c=!1,l=0,g=()=>(v(c),i||((0,e.mkdirSync)((0,t.dirname)(r),{recursive:!0}),i=a(r),o(i)),i),y={dbPath:r,getDBConnection:g,execDB:e=>{g().exec(e)},runDB:(e,t)=>{let n=g().prepare(e).run(...u(t));return{changes:Number(n.changes??0),lastInsertRowid:n.lastInsertRowid??0}},queryDB:(e,t)=>g().prepare(e).all(...u(t)),getDBFirst:(e,t)=>g().prepare(e).get(...u(t)),transactionDB:e=>{let t=g(),n=`tc_savepoint_${l}`,r=l===0;t.exec(r?`BEGIN IMMEDIATE`:`SAVEPOINT ${n}`),l+=1;try{let i=e(y);return--l,t.exec(r?`COMMIT`:`RELEASE SAVEPOINT ${n}`),i}catch(e){throw--l,t.exec(r?`ROLLBACK`:`ROLLBACK TO SAVEPOINT ${n}`),r||t.exec(`RELEASE SAVEPOINT ${n}`),e}},getDBData:(e,t)=>y.getDBDataRecord(e,t)?.value,getDBDataRecord:(e,t)=>{let n=y.getDBFirst(`SELECT namespace, data_key, data_value, created_at, updated_at FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1`,[d(t?.namespace),f(e)]);return n?_(n):void 0},setDBData:(e,t,n)=>{let r=new Date().toISOString();return y.runDB(`INSERT INTO tc_framework_data (namespace, data_key, data_value, created_at, updated_at)
1
+ require(`../../_virtual/_rolldown/runtime.js`);const e=require(`../utils/i18n.js`);let t=require(`node:fs`),n=require(`node:path`);var r=`framework`,i=`.template-core/template-core.sqlite`;function a(e){let r=c(e),i,a=!1,l=0,u=()=>(y(a),i||((0,t.mkdirSync)((0,n.dirname)(r),{recursive:!0}),i=o(r),s(i)),i),_={dbPath:r,getDBConnection:u,execDB:e=>{u().exec(e)},runDB:(e,t)=>{let n=u().prepare(e).run(...d(t));return{changes:Number(n.changes??0),lastInsertRowid:n.lastInsertRowid??0}},queryDB:(e,t)=>u().prepare(e).all(...d(t)),getDBFirst:(e,t)=>u().prepare(e).get(...d(t)),transactionDB:e=>{let t=u(),n=`tc_savepoint_${l}`,r=l===0;t.exec(r?`BEGIN IMMEDIATE`:`SAVEPOINT ${n}`),l+=1;try{let i=e(_);return--l,t.exec(r?`COMMIT`:`RELEASE SAVEPOINT ${n}`),i}catch(e){throw--l,t.exec(r?`ROLLBACK`:`ROLLBACK TO SAVEPOINT ${n}`),r||t.exec(`RELEASE SAVEPOINT ${n}`),e}},getDBData:(e,t)=>_.getDBDataRecord(e,t)?.value,getDBDataRecord:(e,t)=>{let n=_.getDBFirst(`SELECT namespace, data_key, data_value, created_at, updated_at FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1`,[f(t?.namespace),p(e)]);return n?v(n):void 0},setDBData:(e,t,n)=>{let r=new Date().toISOString();return _.runDB(`INSERT INTO tc_framework_data (namespace, data_key, data_value, created_at, updated_at)
2
2
  VALUES (?, ?, ?, ?, ?)
3
3
  ON CONFLICT(namespace, data_key) DO UPDATE SET
4
4
  data_value = excluded.data_value,
5
- updated_at = excluded.updated_at`,[d(n?.namespace),f(e),h(t),r,r])},hasDBData:(e,t)=>!!y.getDBFirst(`SELECT 1 AS exists_value FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1`,[d(t?.namespace),f(e)]),deleteDBData:(e,t)=>y.runDB(`DELETE FROM tc_framework_data WHERE namespace = ? AND data_key = ?`,[d(t?.namespace),f(e)]).changes>0,listDBData:e=>{let t=p(e?.limit),n=m(e?.offset);return y.queryDB(`SELECT namespace, data_key, data_value, created_at, updated_at
5
+ updated_at = excluded.updated_at`,[f(n?.namespace),p(e),g(t),r,r])},hasDBData:(e,t)=>!!_.getDBFirst(`SELECT 1 AS exists_value FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1`,[f(t?.namespace),p(e)]),deleteDBData:(e,t)=>_.runDB(`DELETE FROM tc_framework_data WHERE namespace = ? AND data_key = ?`,[f(t?.namespace),p(e)]).changes>0,listDBData:e=>{let t=m(e?.limit),n=h(e?.offset);return _.queryDB(`SELECT namespace, data_key, data_value, created_at, updated_at
6
6
  FROM tc_framework_data
7
7
  WHERE namespace = ?
8
8
  ORDER BY updated_at DESC, data_key ASC
9
- LIMIT ? OFFSET ?`,[d(e?.namespace),t,n]).map(e=>_(e))},countDBData:e=>{let t=y.getDBFirst(`SELECT COUNT(1) AS count_value FROM tc_framework_data WHERE namespace = ?`,[d(e?.namespace)]);return Number(t?.count_value??0)},clearDBData:e=>y.runDB(`DELETE FROM tc_framework_data WHERE namespace = ?`,[d(e?.namespace)]).changes,closeDB:()=>{c||=(i?.close(),!0)}};return y}function a(e){let t=`node:sqlite`,n;try{n=require(t)}catch(e){throw Error(`[db] 默认数据库依赖 Node.js 内置 ${t},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。${y(e)}`)}if(!n.DatabaseSync)throw Error(`[db] ${t} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。`);return new n.DatabaseSync(e)}function o(e){e.exec(`
9
+ LIMIT ? OFFSET ?`,[f(e?.namespace),t,n]).map(e=>v(e))},countDBData:e=>{let t=_.getDBFirst(`SELECT COUNT(1) AS count_value FROM tc_framework_data WHERE namespace = ?`,[f(e?.namespace)]);return Number(t?.count_value??0)},clearDBData:e=>_.runDB(`DELETE FROM tc_framework_data WHERE namespace = ?`,[f(e?.namespace)]).changes,closeDB:()=>{a||=(i?.close(),!0)}};return _}function o(t){let n=`node:sqlite`,r;try{r=require(n)}catch(t){throw e.createI18nError(`server.errors.dbNodeSqliteUnavailable`,{sqliteSpecifier:n,cause:b(t)})}if(!r.DatabaseSync)throw e.createI18nError(`server.errors.dbDatabaseSyncUnavailable`,{sqliteSpecifier:n});return new r.DatabaseSync(t)}function s(e){e.exec(`
10
10
  CREATE TABLE IF NOT EXISTS tc_framework_data (
11
11
  namespace TEXT NOT NULL,
12
12
  data_key TEXT NOT NULL,
@@ -17,4 +17,4 @@ require(`../../_virtual/_rolldown/runtime.js`);let e=require(`node:fs`),t=requir
17
17
  );
18
18
  CREATE INDEX IF NOT EXISTS idx_tc_framework_data_namespace_updated_at
19
19
  ON tc_framework_data (namespace, updated_at);
20
- `)}function s(e){let n=c(e),i=typeof n==`string`?n:n?.path??n?.filename??n?.sqlitePath??l(n?.sqlite);return i?(0,t.isAbsolute)(i)?i:(0,t.resolve)(e.baseDir,i):(0,t.resolve)(e.baseDir,r)}function c(e){let t=e.config;return t.db??(t.sqlite?{sqlite:t.sqlite}:void 0)}function l(e){if(e)return typeof e==`string`?e:e.path??e.filename}function u(e){return e?Array.isArray(e)?e:[e]:[]}function d(e=n){let t=e.trim();if(!t)throw Error(`[db] namespace 不能为空`);return t}function f(e){let t=e.trim();if(!t)throw Error(`[db] key 不能为空`);return t}function p(e=100){if(!Number.isSafeInteger(e)||e<=0)throw Error(`[db] limit 必须是大于 0 的整数`);return e}function m(e=0){if(!Number.isSafeInteger(e)||e<0)throw Error(`[db] offset 必须是大于等于 0 的整数`);return e}function h(e){try{let t=JSON.stringify(e);if(t===void 0)throw Error(`value is not JSON serializable`);return t}catch(e){throw Error(`[db] value 必须可以被 JSON.stringify 序列化。${y(e)}`)}}function g(e){return JSON.parse(e)}function _(e){return{key:e.data_key,value:g(e.data_value),namespace:e.namespace,createdAt:e.created_at,updatedAt:e.updated_at}}function v(e){if(e)throw Error(`[db] SQLite 数据库连接已关闭`)}function y(e){return e instanceof Error&&e.message?` Cause: ${e.message}`:``}module.exports=i;
20
+ `)}function c(e){let t=l(e),r=typeof t==`string`?t:t?.path??t?.filename??t?.sqlitePath??u(t?.sqlite);return r?(0,n.isAbsolute)(r)?r:(0,n.resolve)(e.baseDir,r):(0,n.resolve)(e.baseDir,i)}function l(e){let t=e.config;return t.db??(t.sqlite?{sqlite:t.sqlite}:void 0)}function u(e){if(e)return typeof e==`string`?e:e.path??e.filename}function d(e){return e?Array.isArray(e)?e:[e]:[]}function f(t=r){let n=t.trim();if(!n)throw e.createI18nError(`server.errors.dbNamespaceRequired`);return n}function p(t){let n=t.trim();if(!n)throw e.createI18nError(`server.errors.dbKeyRequired`);return n}function m(t=100){if(!Number.isSafeInteger(t)||t<=0)throw e.createI18nError(`server.errors.dbLimitInvalid`);return t}function h(t=0){if(!Number.isSafeInteger(t)||t<0)throw e.createI18nError(`server.errors.dbOffsetInvalid`);return t}function g(t){try{let e=JSON.stringify(t);if(e===void 0)throw Error(`value is not JSON serializable`);return e}catch(t){throw e.createI18nError(`server.errors.dbValueNotSerializable`,{cause:b(t)})}}function _(e){return JSON.parse(e)}function v(e){return{key:e.data_key,value:_(e.data_value),namespace:e.namespace,createdAt:e.created_at,updatedAt:e.updated_at}}function y(t){if(t)throw e.createI18nError(`server.errors.dbClosed`)}function b(e){return e instanceof Error&&e.message?` Cause: ${e.message}`:``}module.exports=a;
@@ -1 +1 @@
1
- var e={},t=t=>async(n,r)=>{try{await r()}catch(r){let{status:i=200,message:a,detail:o,code:s=5e4,returnError:c}=r;if(t.extends.logger?.info(`error info -> ${JSON.stringify(r)}`),t.extends.logger?.error(`-- [excption] --`,r),t.extends.logger?.error(`-- [excption] info --`,i,a,o),a?.includes(`template not found`)){let r=n.path??n.req.url??n.url;if(e[r]===void 0?e[r]=0:e[r]+=1,e[r]<t.config.notFoundRedirectCount){n.status=302,n.redirect(t.options?.homePage??`/`);return}else e[r]=0}c?(n.status=i,n.body={code:s,message:a}):(n.status=200,n.body={code:5e4,message:`网络错误`})}};module.exports=t;
1
+ const e=require(`../utils/i18n.js`);var t={},n=n=>async(r,i)=>{try{await i()}catch(i){let a=i,{status:o=200,message:s,detail:c,code:l=5e4,returnError:u}=a,d=e.getRequestErrorMessage(r,a,s);if(n.extends.logger?.info(`error info -> ${JSON.stringify(i)}`),n.extends.logger?.error(`-- [excption] --`,i),n.extends.logger?.error(`-- [excption] info --`,o,s,c),s?.includes(`template not found`)){let e=r.path??r.req.url??r.url;if(t[e]===void 0?t[e]=0:t[e]+=1,t[e]<n.config.notFoundRedirectCount){r.status=302,r.redirect(n.options?.homePage??`/`);return}else t[e]=0}u?(r.status=o,r.body={code:l,message:d}):(r.status=200,r.body={code:5e4,message:e.requestT(r,`server.errors.network`)})}};module.exports=n;
@@ -1 +1 @@
1
- var e=e=>async(t,n)=>{let r=t.headers.projk,{path:i}=t;if(i.indexOf(`${e.options.apiPrefix}/proj/`)!==-1&&(!r||[`undefined`,`null`].includes(r))){t.status=200,t.body={code:110,data:null,message:`请求不合法`};return}t.extInfo={key:r},await n()};module.exports=e;
1
+ const e=require(`../utils/i18n.js`);var t=t=>async(n,r)=>{let i=n.headers.projk,{path:a}=n;if(a.indexOf(`${t.options.apiPrefix}/proj/`)!==-1&&(!i||[`undefined`,`null`].includes(i))){n.status=200,n.body={code:110,data:null,message:e.requestT(n,`server.errors.invalidRequest`)};return}n.extInfo={key:i},await r()};module.exports=t;
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../../packages/common/i18n/index.js`);var t=`x-tc-language`,n=`en-US`,r=[t,`tc_language`,`tc-language`,`language`,`lang`,`locale`],i=e=>Array.isArray(e)?e[0]:e,a=(e,t)=>i(e[t.toLowerCase()]),o=e=>e?e.split(`,`).map(e=>e.trim().split(`;`)[0]?.trim()).filter(e=>!!e):[],s=t=>{if(!t)return n;let r=Object.keys(e.i18nStore.getState().resources),i=t.trim().toLowerCase(),a=r.find(e=>e.toLowerCase()===i);if(a)return a;let o=i.split(`-`)[0];return r.find(e=>e.toLowerCase().split(`-`)[0]===o)??n},c=e=>{for(let t of r){let n=a(e.headers,t);if(n)return s(n)}let t=o(a(e.headers,`accept-language`));for(let e of t){let t=s(e);if(t)return t}return n},l=(t,r,i,a)=>e.i18n(r,i,{...a,language:a?.language??c(t),fallbackLanguage:a?.fallbackLanguage??n}),u=(e,t,n)=>{let r=Error(n??e);return r.i18nKey=e,r.i18nData=t,r},d=(e,t,n)=>t.i18nKey?l(e,t.i18nKey,t.i18nData,{fallback:n??t.message}):n??t.message;exports.LANGUAGE_HEADER_KEY=t,exports.createI18nError=u,exports.getRequestErrorMessage=d,exports.getRequestLanguage=c,exports.normalizeI18nLanguage=s,exports.requestT=l;
@@ -10,6 +10,7 @@
10
10
 
11
11
  <script id="input">
12
12
  window['_basePath'] = {{basePath | safe}}
13
+ window['_FEBasePage'] = {{FEBasePage | safe}}
13
14
  window['_projKey'] = {{projKeyJson | safe}}
14
15
  window['_signKey'] = {{signKey | safe}}
15
16
  const s = document.getElementById('input')
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={common:{tip:`提示`,confirm:`确认`,cancel:`取消`,close:`关闭`,submit:`提交`,reset:`重置`},components:{breadcrumb:{close:`关闭`},confirmDialog:{title:`提示`,okText:`确认`,cancelText:`取消`},dataTable:{noData:`暂无数据`},date:{placeholder:`请选择日期`,placeholderDateTime:`请选择日期时间`,placeholderRange:`选择日期范围`,placeholderDateTimeRange:`选择日期时间范围`,weekDays:[`日`,`一`,`二`,`三`,`四`,`五`,`六`],selectTime:`选择时间`,startTime:`开始时间`,endTime:`结束时间`,confirm:`确认`,monthFormat:`yyyy年 M月`,quickRanges:`快速选择`,quickRangeToday:`今天`,quickRangeYesterday:`昨天`,quickRangeLast7Days:`近7天`,quickRangeLast30Days:`近30天`,quickRangeThisMonth:`本月`,quickRangeLastYear:`最近一年`,clear:`清除`},form:{submit:`提交`,cancel:`取消`},imagePreview:{closePreview:`关闭预览`,previousImage:`上一张`,nextImage:`下一张`,zoomOut:`缩小`,zoomIn:`放大`,reset:`重置`,rotateLeft:`左旋转`,rotateRight:`右旋转`,flipHorizontal:`左右镜像`,flipVertical:`上下镜像`,previewImage:`预览第{index}张`},modal:{close:`关闭`,confirmTitle:`提示`,okText:`确认`,cancelText:`取消`},message:{close:`关闭`},select:{empty:`暂无选项`},tableSearch:{reset:`重置`,search:`查询`,export:`导出Excel`,expand:`展开`,collapse:`收起`,exportCurrentPage:`当前页`,exportCurrentQuery:`当前查询条件`},upload:{deleteImage:`删除图片`,upload:`上传`}}};exports.defaultLanguageResources=e;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={common:{tip:`提示`,confirm:`确认`,cancel:`取消`,close:`关闭`,submit:`提交`,reset:`重置`},server:{errors:{network:`网络错误`,invalidRequest:`请求不合法`,getProjectFailed:`获取项目异常`,dbNodeSqliteUnavailable:`[db] 默认数据库依赖 Node.js 内置 {sqliteSpecifier},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。{cause}`,dbDatabaseSyncUnavailable:`[db] {sqliteSpecifier} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。`,dbNamespaceRequired:`[db] namespace 不能为空`,dbKeyRequired:`[db] key 不能为空`,dbLimitInvalid:`[db] limit 必须是大于 0 的整数`,dbOffsetInvalid:`[db] offset 必须是大于等于 0 的整数`,dbValueNotSerializable:`[db] value 必须可以被 JSON.stringify 序列化。{cause}`,dbClosed:`[db] SQLite 数据库连接已关闭`}},components:{breadcrumb:{close:`关闭`},confirmDialog:{title:`提示`,okText:`确认`,cancelText:`取消`},dataTable:{noData:`暂无数据`},date:{placeholder:`请选择日期`,placeholderDateTime:`请选择日期时间`,placeholderRange:`选择日期范围`,placeholderDateTimeRange:`选择日期时间范围`,weekDays:[`日`,`一`,`二`,`三`,`四`,`五`,`六`],selectTime:`选择时间`,startTime:`开始时间`,endTime:`结束时间`,confirm:`确认`,monthFormat:`yyyy年 M月`,quickRanges:`快速选择`,quickRangeToday:`今天`,quickRangeYesterday:`昨天`,quickRangeLast7Days:`近7天`,quickRangeLast30Days:`近30天`,quickRangeThisMonth:`本月`,quickRangeLastYear:`最近一年`,clear:`清除`},form:{submit:`提交`,cancel:`取消`},imagePreview:{closePreview:`关闭预览`,previousImage:`上一张`,nextImage:`下一张`,zoomOut:`缩小`,zoomIn:`放大`,reset:`重置`,rotateLeft:`左旋转`,rotateRight:`右旋转`,flipHorizontal:`左右镜像`,flipVertical:`上下镜像`,previewImage:`预览第{index}张`},modal:{close:`关闭`,confirmTitle:`提示`,okText:`确认`,cancelText:`取消`},message:{close:`关闭`},select:{empty:`暂无选项`},tableSearch:{reset:`重置`,search:`查询`,export:`导出Excel`,expand:`展开`,collapse:`收起`,exportCurrentPage:`当前页`,exportCurrentQuery:`当前查询条件`},upload:{deleteImage:`删除图片`,upload:`上传`}}};exports.defaultLanguageResources=e;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={common:{tip:`Prompt`,confirm:`Confirm`,cancel:`Cancel`,close:`Close`,submit:`Submit`,reset:`Reset`},components:{breadcrumb:{close:`Close`},confirmDialog:{title:`Prompt`,okText:`Confirm`,cancelText:`Cancel`},dataTable:{noData:`No Data`},date:{placeholder:`Select date`,placeholderDateTime:`Select date and time`,placeholderRange:`Select date range`,placeholderDateTimeRange:`Select date and time range`,weekDays:[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`],selectTime:`Select time`,startTime:`Start time`,endTime:`End time`,confirm:`Confirm`,monthFormat:`MMM yyyy`,quickRanges:`Quick ranges`,quickRangeToday:`Today`,quickRangeYesterday:`Yesterday`,quickRangeLast7Days:`Last 7 days`,quickRangeLast30Days:`Last 30 days`,quickRangeThisMonth:`This month`,quickRangeLastYear:`Last year`,clear:`Clear`},form:{submit:`Submit`,cancel:`Cancel`},imagePreview:{closePreview:`Close preview`,previousImage:`Previous image`,nextImage:`Next image`,zoomOut:`Zoom out`,zoomIn:`Zoom in`,reset:`Reset`,rotateLeft:`Rotate left`,rotateRight:`Rotate right`,flipHorizontal:`Flip horizontal`,flipVertical:`Flip vertical`,previewImage:`Preview image {index}`},modal:{close:`Close`,confirmTitle:`Prompt`,okText:`Confirm`,cancelText:`Cancel`},message:{close:`Close`},select:{empty:`No options`},tableSearch:{reset:`Reset`,search:`Search`,export:`Export Excel`,expand:`Expand`,collapse:`Collapse`,exportCurrentPage:`Current Page`,exportCurrentQuery:`Current Filters`},upload:{deleteImage:`Delete image`,upload:`Upload`}}};exports.defaultEnglishResources=e;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={common:{tip:`Prompt`,confirm:`Confirm`,cancel:`Cancel`,close:`Close`,submit:`Submit`,reset:`Reset`},server:{errors:{network:`Network error`,invalidRequest:`Invalid request`,getProjectFailed:`Failed to get project`,dbNodeSqliteUnavailable:`[db] The default database depends on Node.js built-in {sqliteSpecifier}, which is unavailable in the current runtime. Upgrade Node.js or override app/extends/db.ts in the business project.{cause}`,dbDatabaseSyncUnavailable:`[db] {sqliteSpecifier} does not provide DatabaseSync, so the default SQLite database cannot be initialized.`,dbNamespaceRequired:`[db] namespace cannot be empty`,dbKeyRequired:`[db] key cannot be empty`,dbLimitInvalid:`[db] limit must be an integer greater than 0`,dbOffsetInvalid:`[db] offset must be an integer greater than or equal to 0`,dbValueNotSerializable:`[db] value must be serializable by JSON.stringify.{cause}`,dbClosed:`[db] SQLite database connection is closed`}},components:{breadcrumb:{close:`Close`},confirmDialog:{title:`Prompt`,okText:`Confirm`,cancelText:`Cancel`},dataTable:{noData:`No Data`},date:{placeholder:`Select date`,placeholderDateTime:`Select date and time`,placeholderRange:`Select date range`,placeholderDateTimeRange:`Select date and time range`,weekDays:[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`],selectTime:`Select time`,startTime:`Start time`,endTime:`End time`,confirm:`Confirm`,monthFormat:`MMM yyyy`,quickRanges:`Quick ranges`,quickRangeToday:`Today`,quickRangeYesterday:`Yesterday`,quickRangeLast7Days:`Last 7 days`,quickRangeLast30Days:`Last 30 days`,quickRangeThisMonth:`This month`,quickRangeLastYear:`Last year`,clear:`Clear`},form:{submit:`Submit`,cancel:`Cancel`},imagePreview:{closePreview:`Close preview`,previousImage:`Previous image`,nextImage:`Next image`,zoomOut:`Zoom out`,zoomIn:`Zoom in`,reset:`Reset`,rotateLeft:`Rotate left`,rotateRight:`Rotate right`,flipHorizontal:`Flip horizontal`,flipVertical:`Flip vertical`,previewImage:`Preview image {index}`},modal:{close:`Close`,confirmTitle:`Prompt`,okText:`Confirm`,cancelText:`Cancel`},message:{close:`Close`},select:{empty:`No options`},tableSearch:{reset:`Reset`,search:`Search`,export:`Export Excel`,expand:`Expand`,collapse:`Collapse`,exportCurrentPage:`Current Page`,exportCurrentQuery:`Current Filters`},upload:{deleteImage:`Delete image`,upload:`Upload`}}};exports.defaultEnglishResources=e;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./guards/index.js`),t=require(`./array/index.js`),n=require(`./cache/LRUCache.js`),r=require(`./http/index.js`),i=require(`./i18n/default.js`),a=require(`./i18n/en-US.js`),o=require(`./i18n/locales.js`),s=require(`./i18n/index.js`),c=require(`./log/index.js`),l=require(`./number/index.js`),u=require(`./object/filterEmpty.js`),d=require(`./object/index.js`),f=require(`./rafTimer.js`),p=require(`./string/index.js`);exports.ANSI_RESET=c.ANSI_RESET,exports.FetchAxios=r.FetchAxios,exports.LRUCache=n.LRUCache,exports.ansiColors=c.ansiColors,exports.axios=r.axios,exports.capitalize=p.capitalize,exports.chunk=t.chunk,exports.clamp=l.clamp,exports.clearRafTimer=f.clearRafTimer,exports.colorLog=c.colorLog,exports.colorize=c.colorize,exports.compact=t.compact,exports.createInstance=r.createInstance,exports.defaultEnglishResources=a.defaultEnglishResources,exports.defaultLanguage=o.defaultLanguage,exports.defaultLanguageResources=i.defaultLanguageResources,exports.filterEmpty=u.filterEmpty,exports.filtereEmpty=u.filtereEmpty,exports.getI18nPathValue=s.getI18nPathValue,exports.getLanguage=s.getLanguage,exports.groupBy=t.groupBy,exports.i18n=s.i18n,exports.i18nStore=s.i18nStore,exports.interpolateI18nMessage=s.interpolateI18nMessage,exports.isBlank=p.isBlank,exports.isBoolean=e.isBoolean,exports.isFunction=e.isFunction,exports.isNil=e.isNil,exports.isNonNullable=e.isNonNullable,exports.isNumber=e.isNumber,exports.isPlainI18nDictionary=s.isPlainI18nDictionary,exports.isPlainObject=e.isPlainObject,exports.isString=e.isString,exports.joinColorized=c.joinColorized,exports.joinStr=p.joinStr,exports.kebabCase=p.kebabCase,exports.languageLocalKey=o.languageLocalKey,exports.logColor=c.logColor,exports.logColorized=c.logColorized,exports.logGreen=c.logGreen,exports.logJoinColorized=c.logJoinColorized,exports.logPink=c.logPink,exports.logRed=c.logRed,exports.logWhite=c.logWhite,exports.logYellow=c.logYellow,exports.mapValues=d.mapValues,exports.mergeI18nDictionary=s.mergeI18nDictionary,exports.mergeI18nResources=s.mergeI18nResources,exports.omit=d.omit,exports.pick=d.pick,exports.rafClearInterval=f.rafClearInterval,exports.rafClearTimeout=f.rafClearTimeout,exports.rafSetInterval=f.rafSetInterval,exports.rafSetTimeout=f.rafSetTimeout,exports.t=s.t,exports.toArray=t.toArray,exports.toFiniteNumber=l.toFiniteNumber,exports.translate=s.translate,exports.translations=o.translations,exports.uniqueBy=t.uniqueBy;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./i18n/default.js`),t=require(`./i18n/en-US.js`),n=require(`./i18n/locales.js`),r=require(`./i18n/index.js`),i=require(`./guards/index.js`),a=require(`./array/index.js`),o=require(`./cache/LRUCache.js`),s=require(`./http/index.js`),c=require(`./log/index.js`),l=require(`./number/index.js`),u=require(`./object/filterEmpty.js`),d=require(`./object/index.js`),f=require(`./rafTimer.js`),p=require(`./string/index.js`);exports.ANSI_RESET=c.ANSI_RESET,exports.FetchAxios=s.FetchAxios,exports.LRUCache=o.LRUCache,exports.ansiColors=c.ansiColors,exports.axios=s.axios,exports.capitalize=p.capitalize,exports.chunk=a.chunk,exports.clamp=l.clamp,exports.clearRafTimer=f.clearRafTimer,exports.colorLog=c.colorLog,exports.colorize=c.colorize,exports.compact=a.compact,exports.createInstance=s.createInstance,exports.defaultEnglishResources=t.defaultEnglishResources,exports.defaultLanguage=n.defaultLanguage,exports.defaultLanguageResources=e.defaultLanguageResources,exports.filterEmpty=u.filterEmpty,exports.filtereEmpty=u.filtereEmpty,exports.getI18nPathValue=r.getI18nPathValue,exports.getLanguage=r.getLanguage,exports.groupBy=a.groupBy,exports.i18n=r.i18n,exports.i18nStore=r.i18nStore,exports.interpolateI18nMessage=r.interpolateI18nMessage,exports.isBlank=p.isBlank,exports.isBoolean=i.isBoolean,exports.isFunction=i.isFunction,exports.isNil=i.isNil,exports.isNonNullable=i.isNonNullable,exports.isNumber=i.isNumber,exports.isPlainI18nDictionary=r.isPlainI18nDictionary,exports.isPlainObject=i.isPlainObject,exports.isString=i.isString,exports.joinColorized=c.joinColorized,exports.joinStr=p.joinStr,exports.kebabCase=p.kebabCase,exports.languageLocalKey=n.languageLocalKey,exports.logColor=c.logColor,exports.logColorized=c.logColorized,exports.logGreen=c.logGreen,exports.logJoinColorized=c.logJoinColorized,exports.logPink=c.logPink,exports.logRed=c.logRed,exports.logWhite=c.logWhite,exports.logYellow=c.logYellow,exports.mapValues=d.mapValues,exports.mergeI18nDictionary=r.mergeI18nDictionary,exports.mergeI18nResources=r.mergeI18nResources,exports.omit=d.omit,exports.pick=d.pick,exports.rafClearInterval=f.rafClearInterval,exports.rafClearTimeout=f.rafClearTimeout,exports.rafSetInterval=f.rafSetInterval,exports.rafSetTimeout=f.rafSetTimeout,exports.t=r.t,exports.toArray=a.toArray,exports.toFiniteNumber=l.toFiniteNumber,exports.translate=r.translate,exports.translations=n.translations,exports.uniqueBy=a.uniqueBy;
@@ -1,8 +1,9 @@
1
1
  import e from "./base.js";
2
+ import { requestT as t } from "../utils/i18n.js";
2
3
  //#region app/controller/project.ts
3
- var t = ((t) => {
4
- let n = e(t);
5
- return class extends n {
4
+ var n = ((n) => {
5
+ let r = e(n);
6
+ return class extends r {
6
7
  getModelList = async (e) => {
7
8
  let t = (await this.service.project.getModelList()).reduce((e, t) => {
8
9
  let { model: n, project: r } = t, { key: i, name: a, desc: o } = n, s = {
@@ -39,19 +40,19 @@ var t = ((t) => {
39
40
  this.success(e, n);
40
41
  };
41
42
  getProject = async (e) => {
42
- let { key: t } = e.params;
43
- if (!t) {
44
- this.fail(e, 10001, "获取项目异常");
43
+ let { key: n } = e.params;
44
+ if (!n) {
45
+ this.fail(e, 10001, t(e, "server.errors.getProjectFailed"));
45
46
  return;
46
47
  }
47
- let n = this.service.project.getProject(t);
48
- if (!n) {
49
- this.fail(e, 10001, "获取项目异常");
48
+ let r = this.service.project.getProject(n);
49
+ if (!r) {
50
+ this.fail(e, 10001, t(e, "server.errors.getProjectFailed"));
50
51
  return;
51
52
  }
52
- this.success(e, n);
53
+ this.success(e, r);
53
54
  };
54
55
  };
55
56
  });
56
57
  //#endregion
57
- export { t as default };
58
+ export { n as default };
@@ -13,6 +13,7 @@ var t = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u003e
13
13
  projKey: i ?? "",
14
14
  name: n.options?.name ?? "",
15
15
  env: n.envs.get(),
16
+ FEBasePage: t(`${n.options.pageBasePage}`),
16
17
  basePath: t(`${n.options.pageBasePage}${r.params.page}`),
17
18
  projKeyJson: t(String(r.query.projk ?? "")),
18
19
  signKey: t(n.config.signKey),