cabloy 5.1.61 → 5.1.62
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/.claude/skills/cabloy-backend-scaffold/SKILL.md +2 -0
- package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +1 -1
- package/.claude/skills/cabloy-domain-planning/SKILL.md +212 -0
- package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +2 -0
- package/CHANGELOG.md +42 -0
- package/CLAUDE.md +1 -0
- package/cabloy-docs/.vitepress/config.mjs +158 -12
- package/cabloy-docs/ai/docs-skills-rules-mapping.md +8 -0
- package/cabloy-docs/ai/future-skill-roadmap.md +2 -0
- package/cabloy-docs/ai/skills.md +1 -0
- package/cabloy-docs/backend/backend-contract-emission-output-inspection.md +189 -0
- package/cabloy-docs/backend/backend-contract-emission-source-reading-map.md +160 -0
- package/cabloy-docs/backend/backend-contract-emission-specimen.md +170 -0
- package/cabloy-docs/backend/backend-resource-module-contract-chain.md +323 -0
- package/cabloy-docs/backend/backend-source-reading-debug-checklist.md +173 -0
- package/cabloy-docs/backend/backend-source-reading-roadmap.md +129 -0
- package/cabloy-docs/backend/backend-source-reading-verify-playbook.md +166 -0
- package/cabloy-docs/backend/bean-scene-authoring.md +4 -4
- package/cabloy-docs/backend/broadcast-guide.md +3 -3
- package/cabloy-docs/backend/cli.md +20 -11
- package/cabloy-docs/backend/config-guide.md +4 -4
- package/cabloy-docs/backend/controller-aop-guide.md +10 -10
- package/cabloy-docs/backend/controller-guide.md +12 -2
- package/cabloy-docs/backend/crud-workflow.md +7 -3
- package/cabloy-docs/backend/dto-guide.md +12 -2
- package/cabloy-docs/backend/dto-infer-generation.md +201 -25
- package/cabloy-docs/backend/election-guide.md +2 -2
- package/cabloy-docs/backend/entity-guide.md +12 -3
- package/cabloy-docs/backend/error-guide.md +3 -3
- package/cabloy-docs/backend/event-guide.md +4 -4
- package/cabloy-docs/backend/external-aop-guide.md +2 -2
- package/cabloy-docs/backend/field-indexes.md +9 -3
- package/cabloy-docs/backend/foundation.md +8 -8
- package/cabloy-docs/backend/i18n-guide.md +6 -6
- package/cabloy-docs/backend/internal-aop-guide.md +2 -2
- package/cabloy-docs/backend/introduction.md +13 -0
- package/cabloy-docs/backend/migration-and-changes.md +3 -3
- package/cabloy-docs/backend/model-guide.md +16 -6
- package/cabloy-docs/backend/openapi-guide.md +3 -0
- package/cabloy-docs/backend/queue-guide.md +3 -3
- package/cabloy-docs/backend/redlock-guide.md +2 -2
- package/cabloy-docs/backend/schedule-guide.md +2 -2
- package/cabloy-docs/backend/scripts.md +8 -0
- package/cabloy-docs/backend/serialization-guide.md +2 -2
- package/cabloy-docs/backend/service-guide.md +18 -9
- package/cabloy-docs/backend/startup-guide.md +5 -5
- package/cabloy-docs/backend/status-guide.md +7 -7
- package/cabloy-docs/backend/unit-testing.md +3 -3
- package/cabloy-docs/backend/vona-source-reading-map.md +157 -0
- package/cabloy-docs/backend/websocket-protocol-guide.md +5 -5
- package/cabloy-docs/backend/websocket-usage-guide.md +15 -8
- package/cabloy-docs/frontend/a-model-under-the-hood.md +281 -0
- package/cabloy-docs/frontend/a-openapi-under-the-hood.md +248 -0
- package/cabloy-docs/frontend/a-router-guide.md +307 -0
- package/cabloy-docs/frontend/api-guide.md +4 -4
- package/cabloy-docs/frontend/api-schema-guide.md +1 -0
- package/cabloy-docs/frontend/app-startup-guide.md +7 -4
- package/cabloy-docs/frontend/bean-scene-authoring.md +1 -1
- package/cabloy-docs/frontend/behavior-guide.md +16 -16
- package/cabloy-docs/frontend/cli.md +5 -5
- package/cabloy-docs/frontend/command-scene-authoring.md +17 -8
- package/cabloy-docs/frontend/component-guide.md +5 -5
- package/cabloy-docs/frontend/component-props-guide.md +1 -1
- package/cabloy-docs/frontend/component-v-model-guide.md +2 -2
- package/cabloy-docs/frontend/filter-query-select-data-flow-guide.md +260 -0
- package/cabloy-docs/frontend/form-guide.md +19 -28
- package/cabloy-docs/frontend/form-scene-to-page-meta-guide.md +303 -0
- package/cabloy-docs/frontend/foundation.md +10 -6
- package/cabloy-docs/frontend/frontend-source-reading-roadmap.md +249 -0
- package/cabloy-docs/frontend/generated-contract-consumption-debug-checklist.md +190 -0
- package/cabloy-docs/frontend/generated-contract-consumption-entry-branch.md +205 -0
- package/cabloy-docs/frontend/generated-contract-consumption-list-branch.md +157 -0
- package/cabloy-docs/frontend/generated-contract-consumption-specimen.md +203 -0
- package/cabloy-docs/frontend/generated-contract-consumption-verify-playbook.md +189 -0
- package/cabloy-docs/frontend/generic-component-guide.md +1 -1
- package/cabloy-docs/frontend/introduction.md +29 -7
- package/cabloy-docs/frontend/model-architecture.md +38 -2
- package/cabloy-docs/frontend/model-resource-cookbook.md +11 -8
- package/cabloy-docs/frontend/model-resource-internals-deep-dive.md +238 -0
- package/cabloy-docs/frontend/model-resource-owner-pattern.md +22 -2
- package/cabloy-docs/frontend/model-resource-usage-guide.md +22 -6
- package/cabloy-docs/frontend/model-state-guide.md +12 -9
- package/cabloy-docs/frontend/module-scope.md +8 -8
- package/cabloy-docs/frontend/modules-and-suites.md +2 -1
- package/cabloy-docs/frontend/navigation-guards-guide.md +7 -0
- package/cabloy-docs/frontend/openapi-sdk-guide.md +12 -4
- package/cabloy-docs/frontend/page-guide.md +9 -9
- package/cabloy-docs/frontend/page-meta-guide.md +466 -0
- package/cabloy-docs/frontend/page-params-guide.md +3 -3
- package/cabloy-docs/frontend/page-query-guide.md +2 -2
- package/cabloy-docs/frontend/page-route-guide.md +6 -0
- package/cabloy-docs/frontend/permission-formscene-action-visibility-guide.md +263 -0
- package/cabloy-docs/frontend/quickstart.md +14 -2
- package/cabloy-docs/frontend/resource-entry-page-deep-dive.md +271 -0
- package/cabloy-docs/frontend/resource-list-page-deep-dive.md +279 -0
- package/cabloy-docs/frontend/rest-resource-source-reading-map.md +522 -0
- package/cabloy-docs/frontend/rest-resource-under-the-hood.md +622 -0
- package/cabloy-docs/frontend/root-behaviors-guide.md +282 -0
- package/cabloy-docs/frontend/route-alias-guide.md +6 -0
- package/cabloy-docs/frontend/router-stack-guide.md +229 -0
- package/cabloy-docs/frontend/router-tabs-introduction.md +26 -3
- package/cabloy-docs/frontend/router-tabs-layout-integration.md +367 -0
- package/cabloy-docs/frontend/router-tabs-mechanism.md +6 -0
- package/cabloy-docs/frontend/router-tabs-route-meta-cookbook.md +7 -0
- package/cabloy-docs/frontend/router-tabs-vs-stack.md +167 -0
- package/cabloy-docs/frontend/router-view-hosts-guide.md +450 -0
- package/cabloy-docs/frontend/server-data.md +2 -1
- package/cabloy-docs/frontend/system-startup-guide.md +2 -2
- package/cabloy-docs/frontend/table-action-visibility-permission-flow-guide.md +263 -0
- package/cabloy-docs/frontend/table-cell-cookbook.md +568 -0
- package/cabloy-docs/frontend/table-guide.md +373 -0
- package/cabloy-docs/frontend/table-resource-crud-cookbook.md +496 -0
- package/cabloy-docs/frontend/zova-app-guide.md +251 -0
- package/cabloy-docs/frontend/zova-form-source-reading-map.md +7 -9
- package/cabloy-docs/frontend/zova-form-under-the-hood.md +5 -0
- package/cabloy-docs/frontend/zova-router-under-the-hood.md +561 -0
- package/cabloy-docs/frontend/zova-source-reading-map.md +101 -7
- package/cabloy-docs/frontend/zova-table-controller-render-supplement.md +225 -0
- package/cabloy-docs/frontend/zova-table-source-reading-map.md +317 -0
- package/cabloy-docs/frontend/zova-table-under-the-hood.md +532 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-debug-checklist.md +245 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-source-reading-map.md +139 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-verify-playbook.md +248 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions.md +511 -0
- package/cabloy-docs/fullstack/contract-loop-playbook.md +8 -2
- package/cabloy-docs/fullstack/edition-collaboration-differences.md +6 -0
- package/cabloy-docs/fullstack/frontend-metadata-to-backend.md +181 -48
- package/cabloy-docs/fullstack/introduction.md +3 -0
- package/cabloy-docs/fullstack/openapi-to-sdk.md +116 -2
- package/cabloy-docs/fullstack/suites-and-modules.md +333 -0
- package/cabloy-docs/fullstack/tutorial-1-first-module.md +3 -0
- package/cabloy-docs/fullstack/tutorial-2-first-crud.md +4 -0
- package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +4 -0
- package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +31 -19
- package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +5 -0
- package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +4 -0
- package/cabloy-docs/fullstack/tutorials-overview.md +1 -1
- package/cabloy-docs/reference/bean-scene-boilerplates.md +13 -13
- package/cabloy-docs/reference/package-map.md +4 -3
- package/package.json +1 -1
- package/vona/pnpm-lock.yaml +22 -258
- package/vona/src/suite/a-training/modules/training-student/package.json +53 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/index.ts +400 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/locales.ts +18 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/this.ts +2 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/meta.index.ts +12 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/meta.version.ts +21 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/ssrMenu.student.ts +29 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +15 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +15 -0
- package/vona/src/suite/a-training/modules/training-student/src/controller/student.ts +74 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx +28 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectReq.tsx +44 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectRes.tsx +11 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectResItem.tsx +45 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSummary.tsx +42 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +28 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +25 -0
- package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +84 -0
- package/vona/src/suite/a-training/modules/training-student/src/index.ts +2 -0
- package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +10 -0
- package/vona/src/suite/a-training/modules/training-student/src/service/student.ts +57 -0
- package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +173 -0
- package/vona/src/suite/a-training/modules/training-student/tsconfig.build.json +11 -0
- package/vona/src/suite/a-training/modules/training-student/tsconfig.json +7 -0
- package/vona/src/suite/a-training/package.json +12 -0
- package/vona/src/suite/a-training/tsconfig.base.json +4 -0
- package/vona/src/suite/a-training/tsconfig.json +10 -0
- package/zova/packages-zova/zova/package.json +2 -2
- package/zova/pnpm-lock.yaml +406 -680
- package/zova/src/suite/a-training/modules/training-student/cli/openapi.config.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/package.json +52 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/component/formFieldLevel.ts +31 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/index.ts +258 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/locales.ts +7 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/this.ts +2 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/baseURL.ts +5 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/index.ts +3 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +196 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +4146 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/trainingStudent.ts +151 -0
- package/zova/src/suite/a-training/modules/training-student/src/apiSchema/trainingStudent.ts +43 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionDeleteForce.tsx +51 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionSummary.tsx +56 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.level.tsx +63 -0
- package/zova/src/suite/a-training/modules/training-student/src/component/formFieldLevel/controller.tsx +117 -0
- package/zova/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/src/index.ts +2 -0
- package/zova/src/suite/a-training/modules/training-student/src/model/student.ts +42 -0
- package/zova/src/suite/a-training/modules/training-student/tsconfig.build.json +13 -0
- package/zova/src/suite/a-training/modules/training-student/tsconfig.json +5 -0
- package/zova/src/suite/a-training/package.json +12 -0
- package/zova/src/suite/a-training/tsconfig.base.json +4 -0
- package/zova/src/suite/a-training/tsconfig.json +4 -0
- package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/formFieldSelect/controller.tsx +29 -7
- package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/select/controller.tsx +34 -11
- package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx +3 -3
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/lib/tableCell.ts +1 -1
- package/zova/src/suite-vendor/a-zova/package.json +2 -2
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IDecoratorDtoOptions } from 'vona-module-a-web';
|
|
2
|
+
|
|
3
|
+
import { $Dto } from 'vona-module-a-orm';
|
|
4
|
+
import { Dto } from 'vona-module-a-web';
|
|
5
|
+
|
|
6
|
+
import { DtoStudentSelectResItem } from './studentSelectResItem.tsx';
|
|
7
|
+
|
|
8
|
+
export interface IDtoOptionsStudentSelectRes extends IDecoratorDtoOptions {}
|
|
9
|
+
|
|
10
|
+
@Dto<IDtoOptionsStudentSelectRes>()
|
|
11
|
+
export class DtoStudentSelectRes extends $Dto.listAndCount(DtoStudentSelectResItem) {}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { IDecoratorDtoOptions } from 'vona-module-a-web';
|
|
2
|
+
|
|
3
|
+
import { Api, v } from 'vona-module-a-openapiutils';
|
|
4
|
+
import { $Dto } from 'vona-module-a-orm';
|
|
5
|
+
import { Dto } from 'vona-module-a-web';
|
|
6
|
+
import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
|
|
7
|
+
|
|
8
|
+
import { $locale } from '../.metadata/locales.ts';
|
|
9
|
+
import { ModelStudent } from '../model/student.ts';
|
|
10
|
+
|
|
11
|
+
export interface IDtoOptionsStudentSelectResItem extends IDecoratorDtoOptions {}
|
|
12
|
+
|
|
13
|
+
@Dto<IDtoOptionsStudentSelectResItem>({
|
|
14
|
+
blocks: [
|
|
15
|
+
ZovaRender.block('basic-page:blockPage', {
|
|
16
|
+
blocks: [
|
|
17
|
+
ZovaRender.block('basic-page:blockFilter'),
|
|
18
|
+
ZovaRender.block('basic-page:blockToolbarBulk', {
|
|
19
|
+
actions: [ZovaRender.tableActionBulk('basic-table:actionCreate')],
|
|
20
|
+
}),
|
|
21
|
+
ZovaRender.block('basic-page:blockTable'),
|
|
22
|
+
ZovaRender.block('basic-page:blockPager'),
|
|
23
|
+
],
|
|
24
|
+
}),
|
|
25
|
+
],
|
|
26
|
+
})
|
|
27
|
+
export class DtoStudentSelectResItem extends $Dto.get(() => ModelStudent) {
|
|
28
|
+
@Api.field(
|
|
29
|
+
v.title($locale('Operations')),
|
|
30
|
+
ZovaRender.order(1, 'max'),
|
|
31
|
+
ZovaRender.cell('basic-table:actionOperationsRow', {
|
|
32
|
+
actions: [
|
|
33
|
+
ZovaRender.tableActionRow('training-student:actionSummary', {
|
|
34
|
+
permission: { actionInherit: 'view' },
|
|
35
|
+
}),
|
|
36
|
+
ZovaRender.tableActionRow('basic-table:actionUpdate'),
|
|
37
|
+
ZovaRender.tableActionRow('basic-table:actionDelete'),
|
|
38
|
+
ZovaRender.tableActionRow('training-student:actionDeleteForce', {
|
|
39
|
+
permission: { actionInherit: 'delete' },
|
|
40
|
+
}),
|
|
41
|
+
],
|
|
42
|
+
}),
|
|
43
|
+
)
|
|
44
|
+
_operationsRow?: unknown;
|
|
45
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
2
|
+
import type { IDecoratorDtoOptions } from 'vona-module-a-web';
|
|
3
|
+
|
|
4
|
+
import { Api, v } from 'vona-module-a-openapiutils';
|
|
5
|
+
import { Dto } from 'vona-module-a-web';
|
|
6
|
+
|
|
7
|
+
import { $locale } from '../.metadata/locales.ts';
|
|
8
|
+
|
|
9
|
+
export interface IDtoOptionsStudentSummary extends IDecoratorDtoOptions {}
|
|
10
|
+
|
|
11
|
+
@Dto<IDtoOptionsStudentSummary>()
|
|
12
|
+
export class DtoStudentSummary {
|
|
13
|
+
@Api.field(v.tableIdentity())
|
|
14
|
+
id: TableIdentity;
|
|
15
|
+
|
|
16
|
+
@Api.field(v.title($locale('Name')))
|
|
17
|
+
name: string;
|
|
18
|
+
|
|
19
|
+
@Api.field(
|
|
20
|
+
v.title($locale('Mobile')),
|
|
21
|
+
v.serializerReplace({
|
|
22
|
+
patternFrom: /^(\d{3})\d{4}(\d+)$/,
|
|
23
|
+
patternTo: '$1****$2',
|
|
24
|
+
}),
|
|
25
|
+
)
|
|
26
|
+
mobile: string;
|
|
27
|
+
|
|
28
|
+
@Api.field(v.title($locale('Level')))
|
|
29
|
+
level: 1 | 2 | 3;
|
|
30
|
+
|
|
31
|
+
@Api.field(v.title($locale('LevelTitle')))
|
|
32
|
+
levelTitle: string;
|
|
33
|
+
|
|
34
|
+
@Api.field(v.title($locale('Description')), v.optional())
|
|
35
|
+
description?: string;
|
|
36
|
+
|
|
37
|
+
@Api.field(v.title($locale('DescriptionLength')))
|
|
38
|
+
descriptionLength: number;
|
|
39
|
+
|
|
40
|
+
@Api.field(v.title($locale('Summary')))
|
|
41
|
+
summaryText: string;
|
|
42
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { IDecoratorDtoOptions } from 'vona-module-a-web';
|
|
2
|
+
|
|
3
|
+
import { $Dto } from 'vona-module-a-orm';
|
|
4
|
+
import { Dto } from 'vona-module-a-web';
|
|
5
|
+
import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
|
|
6
|
+
|
|
7
|
+
import { ModelStudent } from '../model/student.ts';
|
|
8
|
+
|
|
9
|
+
export interface IDtoOptionsStudentUpdate extends IDecoratorDtoOptions {}
|
|
10
|
+
|
|
11
|
+
@Dto<IDtoOptionsStudentUpdate>({
|
|
12
|
+
blocks: [
|
|
13
|
+
ZovaRender.block('basic-pageentry:blockPageEntry', {
|
|
14
|
+
blocks: [
|
|
15
|
+
ZovaRender.block('basic-pageentry:blockForm'),
|
|
16
|
+
ZovaRender.block('basic-pageentry:blockToolbarRow', {
|
|
17
|
+
actions: [
|
|
18
|
+
ZovaRender.formActionRow('basic-form:actionSubmit', {
|
|
19
|
+
permission: { actionInherit: 'update', formScene: ['create', 'edit'] },
|
|
20
|
+
}),
|
|
21
|
+
ZovaRender.formActionRow('basic-form:actionBack', { permission: { public: true } }),
|
|
22
|
+
],
|
|
23
|
+
}),
|
|
24
|
+
],
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
})
|
|
28
|
+
export class DtoStudentUpdate extends $Dto.update(() => ModelStudent) {}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { IDecoratorDtoOptions } from 'vona-module-a-web';
|
|
2
|
+
|
|
3
|
+
import { $Dto } from 'vona-module-a-orm';
|
|
4
|
+
import { Dto } from 'vona-module-a-web';
|
|
5
|
+
import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
|
|
6
|
+
|
|
7
|
+
import { ModelStudent } from '../model/student.ts';
|
|
8
|
+
|
|
9
|
+
export interface IDtoOptionsStudentView extends IDecoratorDtoOptions {}
|
|
10
|
+
|
|
11
|
+
@Dto<IDtoOptionsStudentView>({
|
|
12
|
+
blocks: [
|
|
13
|
+
ZovaRender.block('basic-pageentry:blockPageEntry', {
|
|
14
|
+
blocks: [
|
|
15
|
+
ZovaRender.block('basic-pageentry:blockForm'),
|
|
16
|
+
ZovaRender.block('basic-pageentry:blockToolbarRow', {
|
|
17
|
+
actions: [
|
|
18
|
+
ZovaRender.formActionRow('basic-form:actionBack', { permission: { public: true } }),
|
|
19
|
+
],
|
|
20
|
+
}),
|
|
21
|
+
],
|
|
22
|
+
}),
|
|
23
|
+
],
|
|
24
|
+
})
|
|
25
|
+
export class DtoStudentView extends $Dto.get(() => ModelStudent) {}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { IDecoratorEntityOptions } from 'vona-module-a-orm';
|
|
2
|
+
|
|
3
|
+
import { $makeMetadata, Api, v } from 'vona-module-a-openapiutils';
|
|
4
|
+
import { Entity, EntityBase } from 'vona-module-a-orm';
|
|
5
|
+
import z from 'zod';
|
|
6
|
+
import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
|
|
7
|
+
|
|
8
|
+
import { $locale } from '../.metadata/locales.ts';
|
|
9
|
+
|
|
10
|
+
export const studentLevelSchema = z.union([z.literal(1), z.literal(2), z.literal(3)]);
|
|
11
|
+
|
|
12
|
+
export const studentLevelItems = [
|
|
13
|
+
{ value: 1, title: $locale('LevelBeginner') },
|
|
14
|
+
{ value: 2, title: $locale('LevelIntermediate') },
|
|
15
|
+
{ value: 3, title: $locale('LevelAdvanced') },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
export interface IEntityOptionsStudent extends IDecoratorEntityOptions {}
|
|
19
|
+
|
|
20
|
+
@Entity<IEntityOptionsStudent>('trainingStudent', {
|
|
21
|
+
openapi: { title: $locale('Student') },
|
|
22
|
+
fields: {
|
|
23
|
+
id: $makeMetadata(ZovaRender.order(1, 'core')),
|
|
24
|
+
iid: $makeMetadata(ZovaRender.visible(false)),
|
|
25
|
+
deleted: $makeMetadata(ZovaRender.visible(false)),
|
|
26
|
+
createdAt: $makeMetadata(
|
|
27
|
+
ZovaRender.order(-2, 'max'),
|
|
28
|
+
ZovaRender.field('basic-date:formFieldDate'),
|
|
29
|
+
ZovaRender.cell('basic-date:date'),
|
|
30
|
+
),
|
|
31
|
+
updatedAt: $makeMetadata(
|
|
32
|
+
ZovaRender.order(-1, 'max'),
|
|
33
|
+
ZovaRender.field('basic-date:formFieldDate'),
|
|
34
|
+
ZovaRender.cell('basic-date:date'),
|
|
35
|
+
),
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
export class EntityStudent extends EntityBase {
|
|
39
|
+
@Api.field(
|
|
40
|
+
v.title($locale('Name')),
|
|
41
|
+
v.required(),
|
|
42
|
+
v.min(2),
|
|
43
|
+
ZovaRender.order(1),
|
|
44
|
+
ZovaRender.cell('basic-table:actionView'),
|
|
45
|
+
)
|
|
46
|
+
name: string;
|
|
47
|
+
|
|
48
|
+
@Api.field(v.title($locale('Description')), v.optional(), ZovaRender.order(2))
|
|
49
|
+
description?: string;
|
|
50
|
+
|
|
51
|
+
@Api.field(
|
|
52
|
+
v.title($locale('Mobile')),
|
|
53
|
+
v.required(),
|
|
54
|
+
v.min(11),
|
|
55
|
+
v.serializerReplace({
|
|
56
|
+
patternFrom: /^(\d{3})\d{4}(\d+)$/,
|
|
57
|
+
patternTo: '$1****$2',
|
|
58
|
+
}),
|
|
59
|
+
ZovaRender.order(3),
|
|
60
|
+
)
|
|
61
|
+
mobile: string;
|
|
62
|
+
|
|
63
|
+
@Api.field(
|
|
64
|
+
v.title($locale('Level')),
|
|
65
|
+
v.required(),
|
|
66
|
+
ZovaRender.order(4),
|
|
67
|
+
// Tutorial 3 built-in form renderer example. Keep it commented here for side-by-side comparison.
|
|
68
|
+
// ZovaRender.field('basic-select:formFieldSelect', {
|
|
69
|
+
// items: studentLevelItems,
|
|
70
|
+
// placeholder: $locale('Level'),
|
|
71
|
+
// }),
|
|
72
|
+
// Tutorial 3 built-in table cell renderer example.
|
|
73
|
+
// ZovaRender.cell('basic-select:select', { items: studentLevelItems }),
|
|
74
|
+
// Tutorial 4 custom form renderer example used by the current implementation.
|
|
75
|
+
ZovaRender.field('training-student:formFieldLevel', {
|
|
76
|
+
items: studentLevelItems,
|
|
77
|
+
placeholder: $locale('Level'),
|
|
78
|
+
}),
|
|
79
|
+
// Tutorial 4 custom table cell renderer example used by the current implementation.
|
|
80
|
+
ZovaRender.cell('training-student:level', { items: studentLevelItems }),
|
|
81
|
+
studentLevelSchema,
|
|
82
|
+
)
|
|
83
|
+
level: 1 | 2 | 3;
|
|
84
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IDecoratorModelOptions } from 'vona-module-a-orm';
|
|
2
|
+
|
|
3
|
+
import { BeanModelBase, Model } from 'vona-module-a-orm';
|
|
4
|
+
|
|
5
|
+
import { EntityStudent } from '../entity/student.tsx';
|
|
6
|
+
|
|
7
|
+
export interface IModelOptionsStudent extends IDecoratorModelOptions<EntityStudent> {}
|
|
8
|
+
|
|
9
|
+
@Model<IModelOptionsStudent>({ entity: EntityStudent })
|
|
10
|
+
export class ModelStudent extends BeanModelBase<EntityStudent> {}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
2
|
+
import type { IQueryParams } from 'vona-module-a-orm';
|
|
3
|
+
|
|
4
|
+
import { BeanBase } from 'vona';
|
|
5
|
+
import { Service } from 'vona-module-a-bean';
|
|
6
|
+
|
|
7
|
+
import type { DtoStudentCreate } from '../dto/studentCreate.tsx';
|
|
8
|
+
import type { DtoStudentSelectRes } from '../dto/studentSelectRes.tsx';
|
|
9
|
+
import type { DtoStudentSummary } from '../dto/studentSummary.tsx';
|
|
10
|
+
import type { DtoStudentUpdate } from '../dto/studentUpdate.tsx';
|
|
11
|
+
import type { DtoStudentView } from '../dto/studentView.tsx';
|
|
12
|
+
import type { EntityStudent } from '../entity/student.tsx';
|
|
13
|
+
import type { ModelStudent } from '../model/student.ts';
|
|
14
|
+
|
|
15
|
+
@Service()
|
|
16
|
+
export class ServiceStudent extends BeanBase {
|
|
17
|
+
async create(student: DtoStudentCreate): Promise<EntityStudent> {
|
|
18
|
+
return await this.scope.model.student.insert(student);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async select(params?: IQueryParams<ModelStudent>): Promise<DtoStudentSelectRes> {
|
|
22
|
+
return await this.scope.model.student.selectAndCount(params);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async view(id: TableIdentity): Promise<DtoStudentView | undefined> {
|
|
26
|
+
return await this.scope.model.student.getById(id);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async update(id: TableIdentity, student: DtoStudentUpdate) {
|
|
30
|
+
return await this.scope.model.student.updateById(id, student);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async summary(id: TableIdentity): Promise<DtoStudentSummary | undefined> {
|
|
34
|
+
const student = await this.scope.model.student.getById(id);
|
|
35
|
+
if (!student) return undefined;
|
|
36
|
+
const descriptionLength = student.description?.length ?? 0;
|
|
37
|
+
const levelTitle = String(student.level);
|
|
38
|
+
return {
|
|
39
|
+
id: student.id,
|
|
40
|
+
name: student.name,
|
|
41
|
+
mobile: student.mobile,
|
|
42
|
+
level: student.level,
|
|
43
|
+
levelTitle,
|
|
44
|
+
description: student.description,
|
|
45
|
+
descriptionLength,
|
|
46
|
+
summaryText: `${student.name} is in level ${student.level}. Description length: ${descriptionLength}.`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async delete(id: TableIdentity) {
|
|
51
|
+
return await this.scope.model.student.deleteById(id);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async deleteForce(id: TableIdentity) {
|
|
55
|
+
return await this.scope.model.student.deleteById(id, { disableDeleted: true });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DtoStudentCreate,
|
|
3
|
+
DtoStudentSelectRes,
|
|
4
|
+
DtoStudentSummary,
|
|
5
|
+
DtoStudentUpdate,
|
|
6
|
+
EntityStudent,
|
|
7
|
+
} from 'vona-module-training-student';
|
|
8
|
+
|
|
9
|
+
import assert from 'node:assert';
|
|
10
|
+
import { describe, it } from 'node:test';
|
|
11
|
+
import { app } from 'vona-mock';
|
|
12
|
+
|
|
13
|
+
describe('student.test.ts', () => {
|
|
14
|
+
it('action:student', async () => {
|
|
15
|
+
await app.bean.executor.mockCtx(async () => {
|
|
16
|
+
// data
|
|
17
|
+
const mobile = '13812345678';
|
|
18
|
+
const maskedMobile = '138****5678';
|
|
19
|
+
const mobileUpdate = '13987654321';
|
|
20
|
+
const maskedMobileUpdate = '139****4321';
|
|
21
|
+
const data: DtoStudentCreate = {
|
|
22
|
+
name: '__Tom__',
|
|
23
|
+
description: 'This is a test',
|
|
24
|
+
mobile,
|
|
25
|
+
level: 1,
|
|
26
|
+
};
|
|
27
|
+
const dataUpdate: DtoStudentUpdate = {
|
|
28
|
+
name: '__TomNew__',
|
|
29
|
+
description: 'This is a test',
|
|
30
|
+
mobile: mobileUpdate,
|
|
31
|
+
level: 2,
|
|
32
|
+
};
|
|
33
|
+
// login
|
|
34
|
+
await app.bean.passport.signinMock();
|
|
35
|
+
// create
|
|
36
|
+
const studentId = await app.bean.executor.performAction('post', '/training/student', {
|
|
37
|
+
body: data,
|
|
38
|
+
});
|
|
39
|
+
assert.equal(!!studentId, true);
|
|
40
|
+
// findMany
|
|
41
|
+
const selectRes: DtoStudentSelectRes = await app.bean.executor.performAction(
|
|
42
|
+
'get',
|
|
43
|
+
'/training/student',
|
|
44
|
+
);
|
|
45
|
+
const studentItem = selectRes.list.find(item => item.name === data.name);
|
|
46
|
+
assert.equal(!!studentItem, true);
|
|
47
|
+
assert.equal(studentItem!.level, data.level);
|
|
48
|
+
assert.equal(studentItem!.mobile, maskedMobile);
|
|
49
|
+
// findMany: level filter
|
|
50
|
+
const selectResByLevel: DtoStudentSelectRes = await app.bean.executor.performAction(
|
|
51
|
+
'get',
|
|
52
|
+
'/training/student',
|
|
53
|
+
{
|
|
54
|
+
query: {
|
|
55
|
+
level: data.level,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
assert.equal(
|
|
60
|
+
selectResByLevel.list.some(item => item.name === data.name),
|
|
61
|
+
true,
|
|
62
|
+
);
|
|
63
|
+
assert.equal(
|
|
64
|
+
selectResByLevel.list.every(item => item.level === data.level),
|
|
65
|
+
true,
|
|
66
|
+
);
|
|
67
|
+
// update
|
|
68
|
+
await app.bean.executor.performAction('patch', '/training/student/:id', {
|
|
69
|
+
params: { id: studentId },
|
|
70
|
+
body: dataUpdate,
|
|
71
|
+
});
|
|
72
|
+
// findOne
|
|
73
|
+
let student: EntityStudent = await app.bean.executor.performAction(
|
|
74
|
+
'get',
|
|
75
|
+
'/training/student/:id',
|
|
76
|
+
{ params: { id: studentId } },
|
|
77
|
+
);
|
|
78
|
+
assert.equal(student.name, dataUpdate.name);
|
|
79
|
+
assert.equal(student.level, dataUpdate.level);
|
|
80
|
+
assert.equal(student.mobile, maskedMobileUpdate);
|
|
81
|
+
const studentRaw = await app.bean.scope('training-student').model.student.getById(studentId, {
|
|
82
|
+
disableDeleted: true,
|
|
83
|
+
});
|
|
84
|
+
assert.equal(studentRaw!.mobile, mobileUpdate);
|
|
85
|
+
// summary
|
|
86
|
+
const summary: DtoStudentSummary = await app.bean.executor.performAction(
|
|
87
|
+
'get',
|
|
88
|
+
'/training/student/summary/:id',
|
|
89
|
+
{ params: { id: studentId } },
|
|
90
|
+
);
|
|
91
|
+
assert.equal(summary.name, dataUpdate.name);
|
|
92
|
+
assert.equal(summary.mobile, maskedMobileUpdate);
|
|
93
|
+
assert.equal(summary.level, dataUpdate.level);
|
|
94
|
+
assert.equal(summary.descriptionLength, dataUpdate.description?.length);
|
|
95
|
+
assert.equal(typeof summary.levelTitle, 'string');
|
|
96
|
+
assert.equal(typeof summary.summaryText, 'string');
|
|
97
|
+
// delete
|
|
98
|
+
await app.bean.executor.performAction('delete', '/training/student/:id', {
|
|
99
|
+
params: { id: student.id },
|
|
100
|
+
});
|
|
101
|
+
// findOne
|
|
102
|
+
student = await app.bean.executor.performAction('get', '/training/student/:id', {
|
|
103
|
+
params: { id: student.id },
|
|
104
|
+
});
|
|
105
|
+
assert.equal(student, undefined);
|
|
106
|
+
// create again for force delete
|
|
107
|
+
const studentIdForce = await app.bean.executor.performAction('post', '/training/student', {
|
|
108
|
+
body: data,
|
|
109
|
+
});
|
|
110
|
+
await app.bean.executor.performAction('delete', '/training/student/deleteForce/:id', {
|
|
111
|
+
params: { id: studentIdForce },
|
|
112
|
+
});
|
|
113
|
+
const studentForce = await app.bean
|
|
114
|
+
.scope('training-student')
|
|
115
|
+
.model.student.getById(studentIdForce, {
|
|
116
|
+
disableDeleted: true,
|
|
117
|
+
});
|
|
118
|
+
assert.equal(studentForce, undefined);
|
|
119
|
+
// logout
|
|
120
|
+
await app.bean.passport.signout();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('action:student:level invalid', async () => {
|
|
125
|
+
await app.bean.executor.mockCtx(async () => {
|
|
126
|
+
await app.bean.passport.signinMock();
|
|
127
|
+
await assert.rejects(async () => {
|
|
128
|
+
await app.bean.executor.performAction('post', '/training/student', {
|
|
129
|
+
body: {
|
|
130
|
+
name: '__Tom__',
|
|
131
|
+
description: 'This is a test',
|
|
132
|
+
mobile: '13812345678',
|
|
133
|
+
level: 4,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
await app.bean.passport.signout();
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('action:student:mobile required', async () => {
|
|
142
|
+
await app.bean.executor.mockCtx(async () => {
|
|
143
|
+
await app.bean.passport.signinMock();
|
|
144
|
+
await assert.rejects(async () => {
|
|
145
|
+
await app.bean.executor.performAction('post', '/training/student', {
|
|
146
|
+
body: {
|
|
147
|
+
name: '__Tom__',
|
|
148
|
+
description: 'This is a test',
|
|
149
|
+
level: 1,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
await app.bean.passport.signout();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('action:student:mobile too short', async () => {
|
|
158
|
+
await app.bean.executor.mockCtx(async () => {
|
|
159
|
+
await app.bean.passport.signinMock();
|
|
160
|
+
await assert.rejects(async () => {
|
|
161
|
+
await app.bean.executor.performAction('post', '/training/student', {
|
|
162
|
+
body: {
|
|
163
|
+
name: '__Tom__',
|
|
164
|
+
description: 'This is a test',
|
|
165
|
+
mobile: '1381234567',
|
|
166
|
+
level: 1,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
await app.bean.passport.signout();
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zova",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.104",
|
|
4
4
|
"gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
|
|
5
5
|
"description": "A vue3 framework with ioc",
|
|
6
6
|
"keywords": [
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"zova-core": "^5.1.57",
|
|
49
|
-
"zova-suite-a-zova": "^5.1.
|
|
49
|
+
"zova-suite-a-zova": "^5.1.103"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"clean-package": "^2.2.0",
|