@_tc/template-core 0.2.0-bate.9 → 0.2.1-bate.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.
- package/AGENT_README.md +5 -2
- package/README.md +76 -31
- package/cjs/app/controller/project.js +1 -1
- package/cjs/app/controller/view.js +1 -1
- package/cjs/app/extends/db.js +4 -4
- package/cjs/app/middleware.js +1 -1
- package/cjs/app/middlewares/error-handle.js +1 -1
- package/cjs/app/middlewares/project-handler.js +1 -1
- package/cjs/app/utils/i18n.js +1 -0
- package/cjs/app/view/entry.tpl +1 -0
- package/cjs/config/config.default.js +1 -1
- package/cjs/packages/common/i18n/default.js +1 -1
- package/cjs/packages/common/i18n/en-US.js +1 -1
- package/cjs/packages/common/index.js +1 -1
- package/esm/app/controller/project.js +12 -11
- package/esm/app/controller/view.js +2 -1
- package/esm/app/extends/db.js +64 -60
- package/esm/app/middleware.js +1 -1
- package/esm/app/middlewares/error-handle.js +16 -15
- package/esm/app/middlewares/project-handler.js +8 -7
- package/esm/app/utils/i18n.js +36 -0
- package/esm/app/view/entry.tpl +1 -0
- package/esm/config/config.default.js +2 -1
- package/esm/packages/common/i18n/default.js +13 -0
- package/esm/packages/common/i18n/en-US.js +13 -0
- package/esm/packages/common/index.js +9 -9
- package/fe/frontend/apps/dash/Dashboard.js +6 -4
- package/fe/frontend/apps/dash/dash.entry.js +2 -0
- package/fe/frontend/src/common/generateMenuData.d.ts +4 -1
- package/fe/frontend/src/common/generateMenuData.js +3 -3
- package/fe/frontend/src/common/language.d.ts +1 -2
- package/fe/frontend/src/common/language.js +10 -10
- package/fe/frontend/src/common/request.js +3 -1
- package/fe/frontend/src/components/AsyncSelect/AsyncSelect.js +10 -2
- package/fe/frontend/src/components/BasePage/HeaderView.js +2 -2
- package/fe/frontend/src/components/LanguageSwitch/LanguageSwitch.js +13 -9
- package/fe/frontend/src/components/ThemeSwitch/ThemeSwitch.js +4 -3
- package/fe/frontend/src/defaultPages/NotFoundPage/index.js +4 -3
- package/fe/frontend/src/defaultPages/SchemaPage/components/CallCom/DetailPanel.js +14 -9
- package/fe/frontend/src/defaultPages/SchemaPage/components/CallCom/PopFrom.js +8 -7
- package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaSearch/index.js +6 -12
- package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaTable/index.js +25 -18
- package/fe/frontend/src/defaultPages/SchemaPage/index.js +5 -3
- package/fe/frontend/src/defaultPages/SidebarSlotPageTmp.js +4 -2
- package/fe/frontend/src/hooks/useText.d.ts +3 -0
- package/fe/frontend/src/hooks/useText.js +14 -0
- package/fe/frontend/src/index.d.ts +1 -0
- package/fe/frontend/src/index.js +3 -2
- package/fe/frontend/src/language/index.d.ts +0 -2
- package/fe/frontend/src/language/index.js +1 -7
- package/fe/frontend/src/language/resources.d.ts +2 -0
- package/fe/frontend/src/language/resources.js +9 -0
- package/fe/packages/common/i18n/default.d.ts +15 -0
- package/fe/packages/common/i18n/default.js +16 -0
- package/fe/packages/common/i18n/en-US.d.ts +15 -0
- package/fe/packages/common/i18n/en-US.js +18 -2
- package/fe/packages/common/i18n/index.js +13 -0
- package/fe/packages/common/i18n/locales.js +7 -0
- package/fe/packages/react/ui/components/Date/Calendar.js +9 -5
- package/fe/packages/react/ui/components/Date/LocaleContext.d.ts +22 -1
- package/fe/packages/react/ui/components/Date/LocaleContext.js +28 -3
- package/fe/packages/react/ui/components/Date/LocaleProvider.d.ts +1 -1
- package/fe/packages/react/ui/components/Date/LocaleProvider.js +7 -16
- package/fe/packages/react/ui/components/Date/index.js +2 -2
- package/fe/packages/react/ui/components/Date/locales.d.ts +2 -0
- package/fe/packages/react/ui/components/Date/locales.js +29 -13
- package/fe/packages/react/ui/components/TableSearch/TableSearch.js +21 -1
- package/fe/packages/react/ui/components/TableSearch/lang.d.ts +2 -0
- package/fe/packages/react/ui/components/TableSearch/lang.js +18 -7
- package/fe/packages/react/ui/components/Textarea/Textarea.d.ts +1 -1
- package/fe/packages/react/ui/components/Textarea/Textarea.js +1 -1
- package/model/frontend/src/common/language.d.ts +1 -2
- package/model/frontend/src/hooks/useText.d.ts +3 -0
- package/model/frontend/src/language/index.d.ts +0 -2
- package/model/frontend/src/language/resources.d.ts +2 -0
- package/model/packages/common/i18n/default.d.ts +15 -0
- package/model/packages/common/i18n/en-US.d.ts +15 -0
- package/model/packages/react/ui/components/Date/LocaleContext.d.ts +22 -1
- package/model/packages/react/ui/components/Date/LocaleProvider.d.ts +1 -1
- package/model/packages/react/ui/components/Date/locales.d.ts +2 -0
- package/model/packages/react/ui/components/TableSearch/lang.d.ts +2 -0
- package/model/packages/react/ui/components/Textarea/Textarea.d.ts +1 -1
- package/package.json +1 -1
- package/types/app/utils/i18n.d.ts +12 -0
- package/types/config/config.default.d.ts +6 -0
- package/types/packages/common/i18n/default.d.ts +19 -0
- package/types/packages/common/i18n/en-US.d.ts +21 -2
- package/types/packages/common/i18n/index.d.ts +21 -0
- package/types/packages/common/i18n/locales.d.ts +10 -0
- package/types/packages/common/i18n/types.d.ts +40 -0
package/AGENT_README.md
CHANGED
|
@@ -82,11 +82,14 @@ export default {
|
|
|
82
82
|
ATKey: 'Authorization',
|
|
83
83
|
RTKey: 'RT',
|
|
84
84
|
},
|
|
85
|
+
resourceCacheTimeMs: 5 * 60 * 1000,
|
|
85
86
|
}
|
|
86
87
|
```
|
|
87
88
|
|
|
88
89
|
`auth.ATKey` / `auth.RTKey` 是业务鉴权中间件读取短 token 和刷新 token header 的默认约定;默认分别是 `Authorization` / `RT`。
|
|
89
90
|
|
|
91
|
+
`resourceCacheTimeMs` 控制生产环境静态资源缓存时间,单位是 ms,默认 5 分钟。
|
|
92
|
+
|
|
90
93
|
访问内置后台:
|
|
91
94
|
|
|
92
95
|
```text
|
|
@@ -369,7 +372,6 @@ import '@_tc/template-core/fe/tailwind_ui.css'
|
|
|
369
372
|
|
|
370
373
|
```ts
|
|
371
374
|
import {
|
|
372
|
-
addLanguage,
|
|
373
375
|
addLanguageResources,
|
|
374
376
|
clearRafTimer,
|
|
375
377
|
api,
|
|
@@ -387,6 +389,7 @@ import {
|
|
|
387
389
|
setAuthToken,
|
|
388
390
|
setLanguage,
|
|
389
391
|
useSchemaStore,
|
|
392
|
+
useText,
|
|
390
393
|
LanguageSwitch,
|
|
391
394
|
ThemeSwitch,
|
|
392
395
|
} from '@_tc/template-core/fe'
|
|
@@ -423,7 +426,7 @@ import { Button, DataTable, Form, Input, Modal, Select } from '@_tc/template-cor
|
|
|
423
426
|
- 组件加载辅助:`renderImportComponent(import('./Page'))` 会用 `React.lazy` + `Suspense` 渲染动态组件。
|
|
424
427
|
- Schema 通信:`schemaEventBus`、`eventsInfo`、`merge`。
|
|
425
428
|
- 共享状态:`modeStore`、`schemaStore`、`apiFreezerStore` 及对应 hooks。
|
|
426
|
-
- 多语言:`addLanguageResources()`
|
|
429
|
+
- 多语言:`addLanguageResources()` 追加或新增某语种文案,`setLanguage()` 切换语言。React render 中用 `useText()`,非 React 工具代码用 `getText()`;`$i18n::` 前缀会被去掉后查询资源,无前缀字符串会按原 key 查询,未命中时原样返回。配置文案推荐写 `$i18n::...`,也可写普通字符串。
|
|
427
430
|
- 主题:`ThemeSwitch` 会同步根节点 `dark` class 和 `localStorage`。
|
|
428
431
|
- `Input type="password"` 会自动显示密码显隐按钮;`allowClear` 不作用于密码输入。
|
|
429
432
|
- RAF 风格计时器由 `@tc/common/rafTimer` 提供,浏览器优先使用 RAF,Node/SSR 自动降级到 `setTimeout`。
|
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ main().catch((error) => {
|
|
|
101
101
|
| `homePage` | `string` | 否 | - | 应用首页路径 |
|
|
102
102
|
| `additionalPublicPaths` | `string | string[]` | 否 | - | 追加静态资源目录;如需同时作为 Nunjucks 模板查找目录,建议传绝对路径数组 |
|
|
103
103
|
|
|
104
|
-
框架会自动读取 `config/config.default.ts` 中的配置(如 `port`、`env`、`auth` 等)。
|
|
104
|
+
框架会自动读取 `config/config.default.ts` 中的配置(如 `port`、`env`、`auth`、`resourceCacheTimeMs` 等)。
|
|
105
105
|
|
|
106
106
|
常用默认配置示例:
|
|
107
107
|
|
|
@@ -113,10 +113,15 @@ export default {
|
|
|
113
113
|
ATKey: 'Authorization',
|
|
114
114
|
RTKey: 'RT',
|
|
115
115
|
},
|
|
116
|
+
resourceCacheTimeMs: 5 * 60 * 1000,
|
|
116
117
|
}
|
|
117
118
|
```
|
|
118
119
|
|
|
119
|
-
`auth.ATKey` / `auth.RTKey`
|
|
120
|
+
`auth.ATKey` / `auth.RTKey` 用于约定项目鉴权中间件读取短 token 和刷新 token 的 header 名;默认分别为 `Authorization` 和 `RT`。
|
|
121
|
+
|
|
122
|
+
`resourceCacheTimeMs` 控制生产环境静态资源缓存时间,单位是 ms,默认 5 分钟。
|
|
123
|
+
|
|
124
|
+
服务端返回给前端的错误消息会按请求头里的语种翻译。当前优先读取 `x-tc-language`,也兼容 `tc_language`、`tc-language`、`language`、`lang`、`locale` 和 `accept-language`;如果没取到,默认按英文 `en-US` 处理。
|
|
120
125
|
|
|
121
126
|
静态资源挂载顺序为:项目 `app/public`、框架 `app/public`、`additionalPublicPaths`。Nunjucks 模板查找顺序为:项目 `app/public/dist`、框架 `app/public/dist`、`additionalPublicPaths/dist`。这些目录由 `app.publicsPath` 统一维护。当 `buildFE` 输出到自定义目录时,可以用 `additionalPublicPaths` 把该目录交给 Koa 提供静态资源访问和模板渲染;如果需要模板查找也命中追加目录,请传绝对路径数组。
|
|
122
127
|
|
|
@@ -127,7 +132,7 @@ buildFE(mode: 'dev' | 'prod', options?: BuildFEOptions)
|
|
|
127
132
|
```
|
|
128
133
|
|
|
129
134
|
**mode**:构建模式
|
|
130
|
-
- `'dev'
|
|
135
|
+
- `'dev'`:开发模式,构建一次并监听项目 `frontend/` 变化后重建
|
|
131
136
|
- `'prod'`:生产模式,构建优化后的静态资源
|
|
132
137
|
|
|
133
138
|
**options.output**:构建输出位置
|
|
@@ -163,6 +168,11 @@ await buildFE('prod', { minifyHtml: true })
|
|
|
163
168
|
// config/config.default.ts
|
|
164
169
|
export default {
|
|
165
170
|
port: 9000,
|
|
171
|
+
auth: {
|
|
172
|
+
ATKey: 'Authorization',
|
|
173
|
+
RTKey: 'RT',
|
|
174
|
+
},
|
|
175
|
+
resourceCacheTimeMs: 5 * 60 * 1000,
|
|
166
176
|
}
|
|
167
177
|
```
|
|
168
178
|
|
|
@@ -192,7 +202,7 @@ http://localhost:9000/dash?projk=demo
|
|
|
192
202
|
|
|
193
203
|
### 后端类型
|
|
194
204
|
|
|
195
|
-
`@_tc/template-core` 会导出常用 Node
|
|
205
|
+
`@_tc/template-core` 会导出常用 Node 侧类型,项目编写 `app/*` 文件时建议优先复用这些类型。
|
|
196
206
|
|
|
197
207
|
| 类型 | 使用场景 |
|
|
198
208
|
| --- | --- |
|
|
@@ -313,9 +323,7 @@ VS Code 建议安装官方 Tailwind CSS IntelliSense 插件,并在工作区 `.
|
|
|
313
323
|
import {
|
|
314
324
|
api,
|
|
315
325
|
apiFreezerStore,
|
|
316
|
-
addLanguage,
|
|
317
326
|
addLanguageResources,
|
|
318
|
-
addResources,
|
|
319
327
|
AsyncSelect,
|
|
320
328
|
clearAuthToken,
|
|
321
329
|
eventsInfo,
|
|
@@ -331,6 +339,7 @@ import {
|
|
|
331
339
|
modeStore,
|
|
332
340
|
post,
|
|
333
341
|
renderImportComponent,
|
|
342
|
+
registerFrontendI18nResources,
|
|
334
343
|
request,
|
|
335
344
|
schemaEventBus,
|
|
336
345
|
schemaStore,
|
|
@@ -343,6 +352,7 @@ import {
|
|
|
343
352
|
useApiFreezer,
|
|
344
353
|
useModeStore,
|
|
345
354
|
useSchemaStore,
|
|
355
|
+
useText,
|
|
346
356
|
} from '@_tc/template-core/fe'
|
|
347
357
|
|
|
348
358
|
import type {
|
|
@@ -380,7 +390,7 @@ import type {
|
|
|
380
390
|
| 请求类型 | `BaseResponse`、`PageParams`、`PageResponse`、`RequestConfig`、`ResponseConfig`、`AxiosError` |
|
|
381
391
|
| RAF 风格计时器 | `rafSetTimeout`、`rafSetInterval`、`rafClearTimeout`、`rafClearInterval`、`clearRafTimer`、`RafTimerId`、`RafTimerCallback` |
|
|
382
392
|
| Token 工具 | `getAuthToken`、`setAuthToken`、`clearAuthToken`、`localKeyMap` |
|
|
383
|
-
| 多语言工具 | `getText`、`t`、`
|
|
393
|
+
| 多语言工具 | `useText`、`getText`、`t`、`registerFrontendI18nResources`、`addLanguageResources`、`setLanguage`、`setFallbackLanguage`、`setResources`、`getCurrentLanguage`、`getFallbackLanguage`、`getSupportedLanguages` |
|
|
384
394
|
| 请求冻结 | `apiFreezerStore`、`useApiFreezer`、`FreezeState`、`ApiFreezerRequestMatcher` |
|
|
385
395
|
| 事件工具 | `eventsInfo`、`merge` |
|
|
386
396
|
| 共享状态 | `modeStore`、`useModeStore`、`schemaStore`、`useSchemaStore`、`schemaEventBus` |
|
|
@@ -393,7 +403,21 @@ import type {
|
|
|
393
403
|
|
|
394
404
|
### 前端多语言
|
|
395
405
|
|
|
396
|
-
TemplateCore 前端通过 `@_tc/template-core/fe` 暴露 i18n
|
|
406
|
+
TemplateCore 前端通过 `@_tc/template-core/fe` 暴露 i18n 能力。框架内置中文、英文资源,但不会在普通自定义页面 import 前端入口时自动注册,避免非 Dashboard 页面把框架文案整包带入运行时资源。
|
|
407
|
+
|
|
408
|
+
默认 Dashboard 入口会自动调用 `registerFrontendI18nResources()`,所以 Dashboard、Schema CRUD、内置页头、语言切换等框架页面可以直接使用框架内置文案。自定义入口如果也要复用这些框架文案,需要在渲染前手动注册:
|
|
409
|
+
|
|
410
|
+
```ts
|
|
411
|
+
import { initApp, registerFrontendI18nResources } from '@_tc/template-core/fe'
|
|
412
|
+
|
|
413
|
+
initApp(App, {
|
|
414
|
+
beforeRender: async () => {
|
|
415
|
+
await registerFrontendI18nResources()
|
|
416
|
+
},
|
|
417
|
+
})
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
项目可以继续追加自己的资源或新增语种。
|
|
397
421
|
|
|
398
422
|
**追加自定义语言资源**:
|
|
399
423
|
|
|
@@ -401,7 +425,7 @@ TemplateCore 前端通过 `@_tc/template-core/fe` 暴露 i18n 能力。框架内
|
|
|
401
425
|
import { addLanguageResources } from '@_tc/template-core/fe'
|
|
402
426
|
|
|
403
427
|
addLanguageResources('zh-CN', {
|
|
404
|
-
|
|
428
|
+
app: {
|
|
405
429
|
product: {
|
|
406
430
|
menu: '商品管理',
|
|
407
431
|
name: '商品名称',
|
|
@@ -411,8 +435,8 @@ addLanguageResources('zh-CN', {
|
|
|
411
435
|
},
|
|
412
436
|
})
|
|
413
437
|
|
|
414
|
-
|
|
415
|
-
|
|
438
|
+
addLanguageResources('en-US', {
|
|
439
|
+
app: {
|
|
416
440
|
product: {
|
|
417
441
|
menu: 'Products',
|
|
418
442
|
name: 'Product name',
|
|
@@ -426,10 +450,10 @@ i18nStore.getState().addResources('en-US', {
|
|
|
426
450
|
**新增语种并切换**:
|
|
427
451
|
|
|
428
452
|
```ts
|
|
429
|
-
import {
|
|
453
|
+
import { addLanguageResources, setLanguage } from '@_tc/template-core/fe'
|
|
430
454
|
|
|
431
|
-
|
|
432
|
-
|
|
455
|
+
addLanguageResources('ja-JP', {
|
|
456
|
+
app: {
|
|
433
457
|
product: {
|
|
434
458
|
menu: '商品管理',
|
|
435
459
|
},
|
|
@@ -439,19 +463,40 @@ addLanguage('ja-JP', {
|
|
|
439
463
|
setLanguage('ja-JP')
|
|
440
464
|
```
|
|
441
465
|
|
|
442
|
-
`addLanguageResources()`
|
|
466
|
+
`addLanguageResources()` 用于追加或新增某个语种的文案,默认会深合并同语种资源;传 `{ merge: false }` 可以替换该语种资源。`setResources(resources, { merge: true })` 可批量合并多语种资源。`LanguageSwitch` 默认会把已注册语种加入选项;需要自定义展示文案时仍可传入 `options`。
|
|
467
|
+
|
|
468
|
+
React 组件 render 中使用 `useText()` 读取文案。它会订阅语言和资源变化,调用 `setLanguage()` 后组件会自动重渲染。
|
|
469
|
+
|
|
470
|
+
`useText()` / `getText()` 遇到 `$i18n::` 前缀会先去掉前缀再查语言资源;没有前缀时会直接把传入字符串作为 key 查询,查不到才原样返回:
|
|
471
|
+
|
|
472
|
+
```tsx
|
|
473
|
+
import { useText } from '@_tc/template-core/fe'
|
|
474
|
+
|
|
475
|
+
function ProductTitle() {
|
|
476
|
+
const text = useText()
|
|
477
|
+
|
|
478
|
+
return (
|
|
479
|
+
<>
|
|
480
|
+
<h1>{text('$i18n::app.product.menu')}</h1>
|
|
481
|
+
<span>{text('Plain title')}</span>
|
|
482
|
+
</>
|
|
483
|
+
)
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
`getText()` 是普通函数,适合请求错误、日志、校验工具或事件回调等非 React 场景;它不会主动触发 React 组件重渲染。
|
|
443
488
|
|
|
444
489
|
资源注册时不写 `$i18n::` 前缀,配置中使用时才写:
|
|
445
490
|
|
|
446
491
|
```ts
|
|
447
|
-
const title = '$i18n::
|
|
492
|
+
const title = '$i18n::app.product.createTitle'
|
|
448
493
|
```
|
|
449
494
|
|
|
450
495
|
**在 model / Schema 配置中使用**:
|
|
451
496
|
|
|
452
497
|
```ts
|
|
453
498
|
{
|
|
454
|
-
name: '$i18n::
|
|
499
|
+
name: '$i18n::app.product.menu',
|
|
455
500
|
moduleType: 'schema',
|
|
456
501
|
schemaConfig: {
|
|
457
502
|
schema: {
|
|
@@ -459,7 +504,7 @@ const title = '$i18n::business.product.createTitle'
|
|
|
459
504
|
properties: {
|
|
460
505
|
name: {
|
|
461
506
|
type: 'string',
|
|
462
|
-
label: '$i18n::
|
|
507
|
+
label: '$i18n::app.product.name',
|
|
463
508
|
minLength: 2,
|
|
464
509
|
createFormOption: {
|
|
465
510
|
comType: 'input',
|
|
@@ -473,7 +518,7 @@ const title = '$i18n::business.product.createTitle'
|
|
|
473
518
|
tableConfig: {
|
|
474
519
|
headerButtons: [
|
|
475
520
|
{
|
|
476
|
-
label: '$i18n::
|
|
521
|
+
label: '$i18n::app.product.create',
|
|
477
522
|
eventKey: 'callComponent',
|
|
478
523
|
eventOption: { comName: 'createForm' },
|
|
479
524
|
},
|
|
@@ -481,7 +526,7 @@ const title = '$i18n::business.product.createTitle'
|
|
|
481
526
|
},
|
|
482
527
|
componentConfig: {
|
|
483
528
|
createForm: {
|
|
484
|
-
title: '$i18n::
|
|
529
|
+
title: '$i18n::app.product.createTitle',
|
|
485
530
|
saveBtnText: '$i18n::common.submit',
|
|
486
531
|
},
|
|
487
532
|
},
|
|
@@ -939,7 +984,7 @@ const unsafeUsers = app.extends.db.queryDB(
|
|
|
939
984
|
)
|
|
940
985
|
```
|
|
941
986
|
|
|
942
|
-
|
|
987
|
+
项目可以用自己的 `app/extends/db.ts` 覆盖默认实现。建议保留同一组方法名,这样 controller/service 调用方不用调整。
|
|
943
988
|
|
|
944
989
|
```ts
|
|
945
990
|
// app/extends/db.ts
|
|
@@ -1055,7 +1100,7 @@ export default (app: KoaApp, router: Router) => {
|
|
|
1055
1100
|
- 每个 `app/router/*.ts` 文件都会获得独立的 `koa-router` 实例。
|
|
1056
1101
|
- 可以通过 `router.level = number` 控制挂载顺序,数值越小越早挂载。
|
|
1057
1102
|
- 默认 `level` 是 `0`,框架兜底 router 是 `99`。
|
|
1058
|
-
- 通配、兜底、重定向类路由建议设置较大的 `level
|
|
1103
|
+
- 通配、兜底、重定向类路由建议设置较大的 `level`,避免抢先匹配项目 API。
|
|
1059
1104
|
|
|
1060
1105
|
```ts
|
|
1061
1106
|
import type { KoaApp, Router } from '@_tc/template-core'
|
|
@@ -1344,7 +1389,7 @@ DELETE {api} -> 删除
|
|
|
1344
1389
|
|
|
1345
1390
|
### 服务端兜底路由守卫
|
|
1346
1391
|
|
|
1347
|
-
|
|
1392
|
+
项目可以创建 `app/router-guard.ts` 或 `app/router-guard.js`。它只在所有正常 `app/router/*` 路由都没有命中时执行。
|
|
1348
1393
|
|
|
1349
1394
|
```ts
|
|
1350
1395
|
import type { Ctx, KoaApp } from '@_tc/template-core'
|
|
@@ -1369,7 +1414,7 @@ export default (_app: KoaApp) => {
|
|
|
1369
1414
|
|
|
1370
1415
|
### 扩展 Dashboard 顶部用户区域
|
|
1371
1416
|
|
|
1372
|
-
|
|
1417
|
+
项目可以创建 `frontend/extended/dash/components.tsx`,通过组件映射填充内置 Dashboard 页头右侧区域。
|
|
1373
1418
|
|
|
1374
1419
|
```tsx
|
|
1375
1420
|
// frontend/extended/dash/components.tsx
|
|
@@ -1390,7 +1435,7 @@ export default components
|
|
|
1390
1435
|
|
|
1391
1436
|
### 扩展 Dashboard 登录守卫
|
|
1392
1437
|
|
|
1393
|
-
|
|
1438
|
+
项目可以创建 `frontend/extended/dash/routeGuard.ts`,用于在 Dashboard 内置 `homePage` / 首菜单重定向前做登录判断。
|
|
1394
1439
|
|
|
1395
1440
|
```ts
|
|
1396
1441
|
// frontend/extended/dash/routeGuard.ts
|
|
@@ -1406,9 +1451,9 @@ export default dashRouteGuard
|
|
|
1406
1451
|
返回值规则:
|
|
1407
1452
|
|
|
1408
1453
|
- 返回 `string`:框架使用 `window.location.href` 跳转,登录页不需要在 Dash 路由下。
|
|
1409
|
-
- 返回非 `string`:中断 Dashboard
|
|
1454
|
+
- 返回非 `string`:中断 Dashboard 内置重定向,使用方可自行跳转或处理提示。
|
|
1410
1455
|
- `DashRouteGuardResult` 是 `string | undefined`;`undefined`(包括已登录分支的隐式返回)也会打断 Dashboard 内置重定向。
|
|
1411
|
-
-
|
|
1456
|
+
- 没有自定义 `routeGuard` 文件时,框架使用兜底空对象,不影响默认 Dashboard 重定向。
|
|
1412
1457
|
|
|
1413
1458
|
### 扩展 SchemaForm 字段组件
|
|
1414
1459
|
|
|
@@ -1580,7 +1625,7 @@ remark: {
|
|
|
1580
1625
|
|
|
1581
1626
|
### 扩展 SchemaTable 单元格渲染组件
|
|
1582
1627
|
|
|
1583
|
-
SchemaPage 表格列支持通过 `tableOption.renderComponent`
|
|
1628
|
+
SchemaPage 表格列支持通过 `tableOption.renderComponent` 使用内置或自定义注册的渲染组件。内置组件:
|
|
1584
1629
|
|
|
1585
1630
|
- `PreviewImage`:把当前单元格值渲染成图片预览;值是数组时直接作为图片列表,值是单个字符串时自动转成单图数组。
|
|
1586
1631
|
|
|
@@ -1635,7 +1680,7 @@ const componentsMap = {
|
|
|
1635
1680
|
export default componentsMap
|
|
1636
1681
|
```
|
|
1637
1682
|
|
|
1638
|
-
组件会收到 `value`、`record`、`rowIndex`、`fieldKey`,以及 `renderComponentProps`
|
|
1683
|
+
组件会收到 `value`、`record`、`rowIndex`、`fieldKey`,以及 `renderComponentProps` 中的自定义参数:
|
|
1639
1684
|
|
|
1640
1685
|
```tsx
|
|
1641
1686
|
// frontend/components/PriceCell.tsx
|
|
@@ -1775,7 +1820,7 @@ declare module '@_tc/template-core/model' {
|
|
|
1775
1820
|
|
|
1776
1821
|
- `RenderComponentPropsMap` 的 key 对应 `tableOption.renderComponent`。
|
|
1777
1822
|
- 运行时组件注册在 `frontend/extended/SchemaPage/SchemaTable/data.ts`。
|
|
1778
|
-
- 组件运行时会自动收到 `value`、`record`、`rowIndex`、`fieldKey`;`renderComponentProps`
|
|
1823
|
+
- 组件运行时会自动收到 `value`、`record`、`rowIndex`、`fieldKey`;`renderComponentProps` 只配置自定义参数。
|
|
1779
1824
|
|
|
1780
1825
|
### KoaApp 类型扩展
|
|
1781
1826
|
|
|
@@ -2130,6 +2175,6 @@ await buildBE({
|
|
|
2130
2175
|
- `model` 数组合并依赖稳定 `key`。
|
|
2131
2176
|
- Dashboard 默认需要 URL 带 `?projk=项目key`。
|
|
2132
2177
|
- Dashboard 登录守卫放在 `frontend/extended/dash/routeGuard.ts`;登录页通常不在 Dash 路由下,返回登录页 URL 即可。
|
|
2133
|
-
-
|
|
2178
|
+
- 服务端兜底守卫放在项目根目录的 `app/router-guard.ts|js`。
|
|
2134
2179
|
- 前端入口必须命名为 `.entry.tsx`、`.entry.ts`、`.entry.jsx` 或 `.entry.js`。
|
|
2135
2180
|
- 入口同目录的 `.html` 只能作为插槽文件使用,不能写完整 HTML 文档;页面外壳始终由 `app/view/entry.tpl` 生成。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`./base.js`);var
|
|
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.set(`Cache-Control`,`public, max-age=${n.config.resourceCacheTimeMs??300*1e3}, immutable`),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;
|
package/cjs/app/extends/db.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
require(`../../_virtual/_rolldown/runtime.js`);
|
|
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`,[
|
|
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 ?`,[
|
|
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
|
|
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;
|
package/cjs/app/middleware.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`../_virtual/_rolldown/runtime.js`);let t=require(`koa-compress`);t=e.__toESM(t);let n=require(`koa-bodyparser`);n=e.__toESM(n);let r=require(`koa-static`);r=e.__toESM(r);var i=(0,n.default)({formLimit:`1000mb`,enableTypes:[`form`,`json`,`text`]}),a=e=>{let n=e.envs.isLocal()?{maxage:0,setHeaders(e){e.setHeader(`Cache-Control`,`no-store, no-cache, must-revalidate, proxy-revalidate`),e.setHeader(`Pragma`,`no-cache`),e.setHeader(`Expires`,`0`)}}:{maxage:
|
|
1
|
+
const e=require(`../_virtual/_rolldown/runtime.js`);let t=require(`koa-compress`);t=e.__toESM(t);let n=require(`koa-bodyparser`);n=e.__toESM(n);let r=require(`koa-static`);r=e.__toESM(r);var i=(0,n.default)({formLimit:`1000mb`,enableTypes:[`form`,`json`,`text`]}),a=e=>{let n=e.envs.isLocal()?{maxage:0,setHeaders(e){e.setHeader(`Cache-Control`,`no-store, no-cache, must-revalidate, proxy-revalidate`),e.setHeader(`Pragma`,`no-cache`),e.setHeader(`Expires`,`0`)}}:{maxage:e.config.resourceCacheTimeMs??300*1e3};e.use(e.middlewares.errorHandle),e.use((0,t.default)({threshold:2048})),e.publicsPath.forEach(t=>e.use((0,r.default)(t,n))),e.use(i),e.use(e.middlewares.requestParameterParsing),e.use(e.middlewares.projectHandler),!e.envs.isLocal()&&e.use(e.middlewares.apiSignVerify),e.use(e.middlewares.apiParamsVerify)};module.exports=a;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
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;
|
package/cjs/app/view/entry.tpl
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e={frameName:`TemplateCore`,signKey:`sakjdfnkjwjfnfkjkjldljksndf`,apiSignVerify:{whiteList:[]},auth:{ATKey:`Authorization`,RTKey:`RT`},notFoundRedirectCount:5};module.exports=e;
|
|
1
|
+
var e={frameName:`TemplateCore`,signKey:`sakjdfnkjwjfnfkjkjldljksndf`,apiSignVerify:{whiteList:[]},auth:{ATKey:`Authorization`,RTKey:`RT`},notFoundRedirectCount:5,resourceCacheTimeMs:300*1e3};module.exports=e;
|
|
@@ -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(`./
|
|
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
|
|
4
|
-
let
|
|
5
|
-
return class extends
|
|
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:
|
|
43
|
-
if (!
|
|
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
|
|
48
|
-
if (!
|
|
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,
|
|
53
|
+
this.success(e, r);
|
|
53
54
|
};
|
|
54
55
|
};
|
|
55
56
|
});
|
|
56
57
|
//#endregion
|
|
57
|
-
export {
|
|
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),
|
|
@@ -23,7 +24,7 @@ var t = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u003e
|
|
|
23
24
|
n.extends.localCacheHtmlEtag.setEtag(s, e);
|
|
24
25
|
}
|
|
25
26
|
let c = n.extends.localCacheHtmlEtag.getEtag(s);
|
|
26
|
-
if (c || console.log("---- etag 缓存异常 请检查服务 ----"), r.etag = c ?? Date.now() + "", r.fresh) {
|
|
27
|
+
if (c || console.log("---- etag 缓存异常 请检查服务 ----"), r.etag = c ?? Date.now() + "", r.set("Cache-Control", `public, max-age=${n.config.resourceCacheTimeMs ?? 300 * 1e3}, immutable`), r.fresh) {
|
|
27
28
|
r.status = 304;
|
|
28
29
|
return;
|
|
29
30
|
}
|