cabloy 5.1.134 → 5.1.136

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 (185) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/skills/cabloy-backend-scaffold/SKILL.md +9 -0
  3. package/.claude/skills/cabloy-zova-source-reading/SKILL.md +24 -1
  4. package/.claude/skills/cabloy-zova-source-reading/references/analysis-modes.md +12 -0
  5. package/.claude/skills/cabloy-zova-source-reading/references/core-reading-paths.md +28 -0
  6. package/.github/workflows/playwright-e2e.yml +2 -2
  7. package/.github/workflows/vona-test-pg.yml +1 -1
  8. package/.github/workflows/vona-test-sqlite3.yml +1 -1
  9. package/CHANGELOG.md +38 -0
  10. package/CLAUDE.md +1 -0
  11. package/cabloy-docs/.vitepress/config.mjs +7 -0
  12. package/cabloy-docs/backend/markdown-guide.md +189 -0
  13. package/cabloy-docs/frontend/component-guide.md +6 -0
  14. package/cabloy-docs/frontend/css-in-js-guide.md +6 -0
  15. package/cabloy-docs/frontend/markdown-guide.md +258 -0
  16. package/cabloy-docs/frontend/page-guide.md +48 -0
  17. package/cabloy-docs/frontend/page-params-guide.md +4 -2
  18. package/cabloy-docs/frontend/page-route-guide.md +2 -2
  19. package/cabloy-docs/frontend/zova-router-under-the-hood.md +2 -0
  20. package/cabloy-docs/frontend/zova-source-reading-map.md +53 -9
  21. package/cabloy-docs/fullstack/a-pay-payment-suite.md +333 -0
  22. package/cabloy-docs/fullstack/payment-sandbox-configuration.md +285 -0
  23. package/e2e/specs/a-commerce/commerce.spec.ts +503 -47
  24. package/e2e/specs/cabloy-basic/basic.spec.ts +30 -0
  25. package/package.json +1 -1
  26. package/vona/env/.env +2 -0
  27. package/vona/packages-cli/cli/package.json +1 -1
  28. package/vona/packages-cli/cli-set-api/cli/templates/init/error/boilerplate/config/errors.ts +6 -1
  29. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/entity/{{resourceName}}.tsx_ +2 -0
  30. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/entity/{{resourceName}}.tsx_ +2 -0
  31. package/vona/packages-cli/cli-set-api/package.json +1 -1
  32. package/vona/packages-utils/localeutil/package.json +1 -1
  33. package/vona/packages-utils/localeutil/src/util.ts +1 -1
  34. package/vona/packages-vona/vona/package.json +1 -1
  35. package/vona/packages-vona/vona-core/package.json +1 -1
  36. package/vona/packages-vona/vona-mock/package.json +1 -1
  37. package/vona/patches/{zova-core@5.1.82.patch → zova-core@5.1.84.patch} +2 -2
  38. package/vona/pnpm-lock.yaml +826 -270
  39. package/vona/pnpm-workspace.yaml +1 -1
  40. package/vona/src/suite/a-commerce/modules/commerce-catalog/package.json +1 -1
  41. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/.metadata/index.ts +99 -1
  42. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/bean/meta.index.ts +1 -0
  43. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/bean/meta.version.ts +19 -0
  44. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/config/locale/en-us.ts +3 -0
  45. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/config/locale/zh-cn.ts +3 -0
  46. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/controller/product.ts +3 -3
  47. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productContentUpdate.tsx +14 -0
  48. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productContentView.tsx +19 -0
  49. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productCreate.tsx +48 -3
  50. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productPublicDetail.tsx +15 -0
  51. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productUpdate.tsx +48 -3
  52. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productView.tsx +52 -3
  53. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/entity/productContent.tsx +36 -0
  54. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/model/product.ts +6 -0
  55. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/model/productContent.ts +22 -0
  56. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/service/product.ts +82 -6
  57. package/vona/src/suite/a-commerce/modules/commerce-catalog/test/productContent.test.ts +271 -0
  58. package/vona/src/suite/a-commerce/modules/commerce-catalog/test/productPresentation.test.ts +81 -2
  59. package/vona/src/suite/a-commerce/modules/commerce-payment/package.json +4 -1
  60. package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/payScene.commerceOrder.ts +32 -15
  61. package/vona/src/suite/a-commerce/modules/commerce-payment/test/paymentAttempt.test.ts +8 -2
  62. package/vona/src/suite/a-commerce/modules/commerce-siteweb/src/.metadata/index.ts +8 -2
  63. package/vona/src/suite/a-commerce/modules/commerce-siteweb/src/.metadata/locales.ts +18 -0
  64. package/vona/src/suite/a-commerce/modules/commerce-siteweb/src/bean/ssrMenu.home.ts +3 -1
  65. package/vona/src/suite/a-commerce/modules/commerce-siteweb/src/config/locale/en-us.ts +3 -0
  66. package/vona/src/suite/a-commerce/modules/commerce-siteweb/src/config/locale/zh-cn.ts +3 -0
  67. package/vona/src/suite/a-commerce/modules/commerce-siteweb/src/index.ts +1 -0
  68. package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/checkout.ts +13 -2
  69. package/vona/src/suite/a-commerce/modules/commerce-trade/src/lib/providerReference.ts +18 -0
  70. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +43 -8
  71. package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +74 -0
  72. package/vona/src/suite/a-commerce/modules/commerce-trade/test/providerReference.test.ts +33 -0
  73. package/vona/src/suite/a-commerce/modules/commerce-trade/test/refundLifecycle.test.ts +73 -0
  74. package/vona/src/suite/a-commerce/modules/commerce-trade/test/reservationExpiry.test.ts +2 -0
  75. package/vona/src/suite/a-home/modules/home-user/src/.metadata/index.ts +30 -0
  76. package/vona/src/suite/a-home/modules/home-user/src/bean/meta.version.ts +7 -2
  77. package/vona/src/suite/a-home/modules/home-user/src/config/locale/en-us.ts +4 -1
  78. package/vona/src/suite/a-home/modules/home-user/src/config/locale/zh-cn.ts +4 -1
  79. package/vona/src/suite/a-home/modules/home-user/src/config/roles.ts +4 -4
  80. package/vona/src/suite/a-home/modules/home-user/src/entity/role.ts +2 -2
  81. package/vona/src/suite/a-home/modules/home-user/src/entity/user.ts +8 -1
  82. package/vona/src/suite/a-home/modules/home-user/src/service/userAdapter.ts +6 -2
  83. package/vona/src/suite/a-home/modules/home-user/test/passportTest.test.ts +1 -0
  84. package/vona/src/suite/a-home/modules/home-user/test/role.test.ts +4 -4
  85. package/vona/src/suite-vendor/a-cabloy/modules/a-markdown/package.json +64 -0
  86. package/vona/src/suite-vendor/a-cabloy/modules/a-markdown/src/.metadata/index.ts +54 -0
  87. package/vona/src/suite-vendor/a-cabloy/modules/a-markdown/src/.metadata/this.ts +2 -0
  88. package/vona/src/suite-vendor/a-cabloy/modules/a-markdown/src/bean/bean.markdown.ts +137 -0
  89. package/vona/src/suite-vendor/a-cabloy/modules/a-markdown/src/index.ts +1 -0
  90. package/vona/src/suite-vendor/a-cabloy/modules/a-markdown/tsconfig.build.json +11 -0
  91. package/vona/src/suite-vendor/a-cabloy/modules/a-markdown/tsconfig.json +7 -0
  92. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/package.json +1 -1
  93. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/bean/bean.ssr.ts +17 -0
  94. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/lib/beanSsrSiteBase.ts +11 -3
  95. package/vona/src/suite-vendor/a-cabloy/package.json +2 -1
  96. package/vona/src/suite-vendor/a-cabloy/tsconfig.json +3 -0
  97. package/vona/src/suite-vendor/a-pay/modules/a-pay/package.json +1 -1
  98. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.version.ts +1 -0
  99. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperation.tsx +8 -1
  100. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/lib/index.ts +1 -0
  101. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/lib/providerOperationFailure.ts +8 -0
  102. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/providerOperation.ts +187 -29
  103. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payment.ts +4 -0
  104. package/vona/src/suite-vendor/a-pay/modules/pay-mock/package.json +1 -1
  105. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/package.json +1 -1
  106. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/bean/payProvider.paypal.ts +0 -6
  107. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/index.ts +1 -0
  108. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/package.json +2 -1
  109. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/bean/payProvider.stripe.ts +458 -22
  110. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/index.ts +1 -0
  111. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/lib/stripeGateway.ts +85 -0
  112. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/types/index.ts +2 -0
  113. package/vona/src/suite-vendor/a-pay/package.json +5 -5
  114. package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
  115. package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
  116. package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/bean.permission.ts +1 -0
  117. package/vona/src/suite-vendor/a-vona/modules/a-user/package.json +1 -1
  118. package/vona/src/suite-vendor/a-vona/modules/a-user/src/bean/bean.passport.ts +14 -0
  119. package/vona/src/suite-vendor/a-vona/modules/a-user/src/bean/guard.passport.ts +4 -0
  120. package/vona/src/suite-vendor/a-vona/modules/a-user/src/types/role.ts +3 -2
  121. package/vona/src/suite-vendor/a-vona/modules/a-user/src/types/user.ts +4 -0
  122. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  123. package/zova/packages-utils/logger/package.json +2 -2
  124. package/zova/packages-utils/zova-jsx/package.json +2 -2
  125. package/zova/packages-zova/zova/package.json +3 -3
  126. package/zova/packages-zova/zova-core/package.json +3 -3
  127. package/zova/packages-zova/zova-core/src/core/sys/resource.ts +1 -1
  128. package/zova/packages-zova/zova-core/src/core/sys/util.ts +8 -0
  129. package/zova/pnpm-lock.yaml +570 -11
  130. package/zova/src/front/config/config/config.cabloyCommerce.ts +0 -6
  131. package/zova/src/suite/a-commerce/modules/commerce-catalog/package.json +3 -1
  132. package/zova/src/suite/a-commerce/modules/commerce-catalog/src/api/openapi/schemas.ts +236 -36
  133. package/zova/src/suite/a-commerce/modules/commerce-catalog/src/api/openapi/types.ts +4962 -2402
  134. package/zova/src/suite/a-commerce/modules/commerce-catalog/src/config/locale/en-us.ts +1 -0
  135. package/zova/src/suite/a-commerce/modules/commerce-catalog/src/config/locale/zh-cn.ts +1 -0
  136. package/zova/src/suite/a-commerce/modules/commerce-catalog/src/page/product/controller.tsx +8 -3
  137. package/zova/src/suite/a-commerce/modules/commerce-member/src/.metadata/index.ts +6 -7
  138. package/zova/src/suite/a-commerce/modules/commerce-member/src/page/address/controller.tsx +1 -3
  139. package/zova/src/suite/a-commerce/modules/commerce-member/src/routes.ts +2 -3
  140. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +13 -20
  141. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/cart/controller.tsx +3 -9
  142. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/checkout/controller.tsx +9 -11
  143. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/order/controller.tsx +0 -1
  144. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/orders/controller.tsx +6 -4
  145. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +78 -17
  146. package/zova/src/suite/a-commerce/modules/commerce-trade/src/routes.ts +10 -13
  147. package/zova/src/suite/a-home/modules/home-api/mock/passport.fake.ts +3 -3
  148. package/zova/src/suite/a-home/modules/home-api/src/.metadata/index.ts +31 -1
  149. package/zova/src/suite/a-home/modules/home-api/src/api/homeBaseSiteCatalog.ts +24 -0
  150. package/zova/src/suite/a-home/modules/home-api/src/api/openapi/schemas.ts +329 -17
  151. package/zova/src/suite/a-home/modules/home-api/src/api/openapi/types.ts +5866 -1829
  152. package/zova/src/suite/a-home/modules/home-api/src/apiSchema/homeBaseSiteCatalog.ts +13 -0
  153. package/zova/src/suite/a-home/modules/home-base/src/component/page/controller.tsx +1 -0
  154. package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.header.tsx +0 -1
  155. package/zova/src/suite/cabloy-basic/modules/basic-details/src/types/detail.ts +1 -0
  156. package/zova/src/suite/cabloy-basic/modules/basic-markdown/package.json +61 -0
  157. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/.metadata/component/formFieldMarkdown.ts +36 -0
  158. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/.metadata/component/markdownHtml.ts +36 -0
  159. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/.metadata/index.ts +147 -0
  160. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/.metadata/this.ts +2 -0
  161. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/component/formFieldMarkdown/controller.tsx +111 -0
  162. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/component/formFieldMarkdown/render.tsx +40 -0
  163. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/component/formFieldMarkdown/style.ts +13 -0
  164. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/component/markdownHtml/controller.tsx +17 -0
  165. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/component/markdownHtml/render.tsx +9 -0
  166. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/component/markdownHtml/style.ts +13 -0
  167. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/index.ts +1 -0
  168. package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/lib/richTextContentStyle.ts +142 -0
  169. package/zova/src/suite/cabloy-basic/modules/basic-markdown/tsconfig.build.json +13 -0
  170. package/zova/src/suite/cabloy-basic/modules/basic-markdown/tsconfig.json +5 -0
  171. package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsx +25 -3
  172. package/zova/src/suite/cabloy-basic/modules/basic-page/src/types/page.ts +1 -0
  173. package/zova/src/suite/cabloy-basic/modules/basic-pageentry/src/types/pageEntry.ts +1 -0
  174. package/zova/src/suite/cabloy-basic/package.json +1 -0
  175. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
  176. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +7 -0
  177. package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
  178. package/zova/src/suite-vendor/a-zova/modules/a-logger/package.json +2 -2
  179. package/zova/src/suite-vendor/a-zova/modules/a-router/package.json +1 -1
  180. package/zova/src/suite-vendor/a-zova/modules/a-router/src/bean/sys.router.ts +3 -2
  181. package/zova/src/suite-vendor/a-zova/modules/a-ssr/package.json +1 -1
  182. package/zova/src/suite-vendor/a-zova/modules/a-ssr/test/lib/ssrProfile.test.ts +88 -0
  183. package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
  184. package/zova/src/suite-vendor/a-zova/package.json +5 -5
  185. package/.claude/scheduled_tasks.lock +0 -1
@@ -53,4 +53,4 @@ allowBuilds:
53
53
  vue-demi: true
54
54
 
55
55
  patchedDependencies:
56
- zova-core@5.1.82: patches/zova-core@5.1.82.patch
56
+ zova-core@5.1.84: patches/zova-core@5.1.84.patch
@@ -30,7 +30,6 @@
30
30
  "prepack": "clean-package",
31
31
  "postpack": "clean-package restore"
32
32
  },
33
- "dependencies": {},
34
33
  "devDependencies": {
35
34
  "clean-package": "^2.2.0",
36
35
  "rimraf": "^6.1.3"
@@ -46,6 +45,7 @@
46
45
  "title": "commerce-catalog",
47
46
  "vonaModule": {
48
47
  "dependencies": {
48
+ "a-markdown": "5.0.0",
49
49
  "a-vona": "5.0.0",
50
50
  "commerce-trade": "5.0.0"
51
51
  },
@@ -1,13 +1,15 @@
1
1
  // eslint-disable
2
- import type { TypeEntityMeta,TypeModelsClassLikeGeneral,TypeSymbolKeyFieldsMore,IModelRelationBelongsTo,IModelRelationHasMany } from 'vona-module-a-orm';
2
+ import type { TypeEntityMeta,TypeModelsClassLikeGeneral,TypeSymbolKeyFieldsMore,IModelRelationHasOne,IModelRelationBelongsTo,IModelRelationHasMany } from 'vona-module-a-orm';
3
3
  import type { TypeEntityOptionsFields,TypeControllerOptionsActions } from 'vona-module-a-openapi';
4
4
  import type { TableIdentity } from 'table-identity';
5
5
  /** entity: begin */
6
6
  export * from '../entity/category.tsx';
7
7
  export * from '../entity/product.tsx';
8
+ export * from '../entity/productContent.tsx';
8
9
  export * from '../entity/sku.tsx';
9
10
  import type { IEntityOptionsCategory } from '../entity/category.tsx';
10
11
  import type { IEntityOptionsProduct } from '../entity/product.tsx';
12
+ import type { IEntityOptionsProductContent } from '../entity/productContent.tsx';
11
13
  import type { IEntityOptionsSku } from '../entity/sku.tsx';
12
14
  import 'vona-module-a-orm';
13
15
  declare module 'vona-module-a-orm' {
@@ -15,6 +17,7 @@ declare module 'vona-module-a-orm' {
15
17
  export interface IEntityRecord {
16
18
  'commerce-catalog:category': IEntityOptionsCategory;
17
19
  'commerce-catalog:product': IEntityOptionsProduct;
20
+ 'commerce-catalog:productContent': IEntityOptionsProductContent;
18
21
  'commerce-catalog:sku': IEntityOptionsSku;
19
22
  }
20
23
 
@@ -27,24 +30,29 @@ declare module 'vona-module-commerce-catalog' {
27
30
  /** entity: begin */
28
31
  import type { EntityCategory } from '../entity/category.tsx';
29
32
  import type { EntityProduct } from '../entity/product.tsx';
33
+ import type { EntityProductContent } from '../entity/productContent.tsx';
30
34
  import type { EntitySku } from '../entity/sku.tsx';
31
35
  export interface IModuleEntity {
32
36
  'category': EntityCategoryMeta;
33
37
  'product': EntityProductMeta;
38
+ 'productContent': EntityProductContentMeta;
34
39
  'sku': EntitySkuMeta;
35
40
  }
36
41
  /** entity: end */
37
42
  /** entity: begin */
38
43
  export type EntityCategoryTableName = 'commerceCatalogCategory';
39
44
  export type EntityProductTableName = 'commerceCatalogProduct';
45
+ export type EntityProductContentTableName = 'commerceCatalogProductContent';
40
46
  export type EntitySkuTableName = 'commerceCatalogSku';
41
47
  export type EntityCategoryMeta=TypeEntityMeta<EntityCategory,EntityCategoryTableName>;
42
48
  export type EntityProductMeta=TypeEntityMeta<EntityProduct,EntityProductTableName>;
49
+ export type EntityProductContentMeta=TypeEntityMeta<EntityProductContent,EntityProductContentTableName>;
43
50
  export type EntitySkuMeta=TypeEntityMeta<EntitySku,EntitySkuTableName>;
44
51
  declare module 'vona-module-a-orm' {
45
52
  export interface ITableRecord {
46
53
  'commerceCatalogCategory': EntityCategoryMeta;
47
54
  'commerceCatalogProduct': EntityProductMeta;
55
+ 'commerceCatalogProductContent': EntityProductContentMeta;
48
56
  'commerceCatalogSku': EntitySkuMeta;
49
57
  }
50
58
  }
@@ -58,6 +66,10 @@ declare module 'vona-module-commerce-catalog' {
58
66
  fields?: TypeEntityOptionsFields<EntityProduct, IEntityOptionsProduct[TypeSymbolKeyFieldsMore]>;
59
67
  }
60
68
 
69
+ export interface IEntityOptionsProductContent {
70
+ fields?: TypeEntityOptionsFields<EntityProductContent, IEntityOptionsProductContent[TypeSymbolKeyFieldsMore]>;
71
+ }
72
+
61
73
  export interface IEntityOptionsSku {
62
74
  fields?: TypeEntityOptionsFields<EntitySku, IEntityOptionsSku[TypeSymbolKeyFieldsMore]>;
63
75
  }
@@ -66,9 +78,11 @@ declare module 'vona-module-commerce-catalog' {
66
78
  /** model: begin */
67
79
  export * from '../model/category.ts';
68
80
  export * from '../model/product.ts';
81
+ export * from '../model/productContent.ts';
69
82
  export * from '../model/sku.ts';
70
83
  import type { IModelOptionsCategory } from '../model/category.ts';
71
84
  import type { IModelOptionsProduct } from '../model/product.ts';
85
+ import type { IModelOptionsProductContent } from '../model/productContent.ts';
72
86
  import type { IModelOptionsSku } from '../model/sku.ts';
73
87
  import 'vona-module-a-orm';
74
88
  declare module 'vona-module-a-orm' {
@@ -76,6 +90,7 @@ declare module 'vona-module-a-orm' {
76
90
  export interface IModelRecord {
77
91
  'commerce-catalog:category': IModelOptionsCategory;
78
92
  'commerce-catalog:product': IModelOptionsProduct;
93
+ 'commerce-catalog:productContent': IModelOptionsProductContent;
79
94
  'commerce-catalog:sku': IModelOptionsSku;
80
95
  }
81
96
 
@@ -105,6 +120,17 @@ declare module 'vona-module-commerce-catalog' {
105
120
  get $onionOptions(): IModelOptionsProduct;
106
121
  }
107
122
 
123
+ export interface ModelProductContent {
124
+ /** @internal */
125
+ get scope(): ScopeModuleCommerceCatalog;
126
+ }
127
+
128
+ export interface ModelProductContent {
129
+ get $beanFullName(): 'commerce-catalog.model.productContent';
130
+ get $onionName(): 'commerce-catalog:productContent';
131
+ get $onionOptions(): IModelOptionsProductContent;
132
+ }
133
+
108
134
  export interface ModelSku {
109
135
  /** @internal */
110
136
  get scope(): ScopeModuleCommerceCatalog;
@@ -120,10 +146,12 @@ declare module 'vona-module-commerce-catalog' {
120
146
  /** model: begin */
121
147
  import type { ModelCategory } from '../model/category.ts';
122
148
  import type { ModelProduct } from '../model/product.ts';
149
+ import type { ModelProductContent } from '../model/productContent.ts';
123
150
  import type { ModelSku } from '../model/sku.ts';
124
151
  export interface IModuleModel {
125
152
  'category': ModelCategory;
126
153
  'product': ModelProduct;
154
+ 'productContent': ModelProductContent;
127
155
  'sku': ModelSku;
128
156
  }
129
157
  /** model: end */
@@ -134,6 +162,7 @@ declare module 'vona' {
134
162
  export interface IBeanRecordGeneral {
135
163
  'commerce-catalog.model.category': ModelCategory;
136
164
  'commerce-catalog.model.product': ModelProduct;
165
+ 'commerce-catalog.model.productContent': ModelProductContent;
137
166
  'commerce-catalog.model.sku': ModelSku;
138
167
  }
139
168
  }
@@ -150,10 +179,17 @@ declare module 'vona-module-commerce-catalog' {
150
179
  export interface IModelOptionsProduct {
151
180
  relations: {
152
181
  category: IModelRelationBelongsTo<'commerce-catalog:product', 'commerce-catalog:category', false, 'id'|'name'|'published'>;
182
+ productContent: IModelRelationHasOne<'commerce-catalog:productContent', 'productId', false, 'id'|'productId'|'descriptionMarkdown'|'descriptionHtml'>;
183
+ productContentForm: IModelRelationHasOne<'commerce-catalog:productContent', 'productId', false, 'id'|'productId'|'descriptionMarkdown'>;
153
184
  skus: IModelRelationHasMany<'commerce-catalog:sku', 'productId', false, '*', undefined, undefined, undefined>;
154
185
  skuAvailables: IModelRelationHasMany<'commerce-catalog:sku', 'productId', false, 'id'|'code'|'productId'|'priceCents', ['commerce-trade:stockBalance'], undefined, undefined>;
155
186
  };
156
187
  }
188
+ export interface IModelOptionsProductContent {
189
+ relations: {
190
+ product: IModelRelationBelongsTo<'commerce-catalog:productContent', 'commerce-catalog:product', false, '*'>;
191
+ };
192
+ }
157
193
  export interface IModelOptionsSku {
158
194
  relations: {
159
195
  product: IModelRelationBelongsTo<'commerce-catalog:sku', 'commerce-catalog:product', false, '*'>;
@@ -237,6 +273,43 @@ export interface ModelProduct {
237
273
  updateById<T extends IModelUpdateOptions<EntityProduct,ModelProduct>>(id: TableIdentity, data: TypeModelMutateRelationData<EntityProduct,ModelProduct, T>, options?: T): Promise<TypeModelMutateRelationData<EntityProduct,ModelProduct, T>>;
238
274
  deleteById<T extends IModelDeleteOptions<EntityProduct,ModelProduct>>(id: TableIdentity, options?: T): Promise<void>;
239
275
  }
276
+ export interface ModelProductContent {
277
+ [SymbolKeyEntity]: EntityProductContent;
278
+ [SymbolKeyEntityMeta]: EntityProductContentMeta;
279
+ [SymbolKeyModelOptions]: IModelOptionsProductContent;
280
+ get<T extends IModelGetOptions<EntityProductContent,ModelProductContent>>(where: TypeModelWhere<EntityProductContent>, options?: T): Promise<TypeModelRelationResult<EntityProductContent, ModelProductContent, T> | undefined>;
281
+ /**
282
+ * Retrieves one matching primary row with a pessimistic FOR UPDATE lock.
283
+ * Requires an active transaction. The lock is released when that transaction completes.
284
+ * Entity and query caches are bypassed.
285
+ */
286
+ getForUpdate<T extends IModelGetOptions<EntityProductContent,ModelProductContent>>(where: TypeModelWhere<EntityProductContent>, options?: T): Promise<TypeModelRelationResult<EntityProductContent, ModelProductContent, T> | undefined>;
287
+ /**
288
+ * Retrieves a primary row by ID with the same pessimistic FOR UPDATE lock semantics.
289
+ * Requires an active transaction. The lock is released when that transaction completes.
290
+ * Entity and query caches are bypassed.
291
+ */
292
+ getByIdForUpdate<T extends IModelGetOptions<EntityProductContent,ModelProductContent>>(id: TableIdentity, options?: T): Promise<TypeModelRelationResult<EntityProductContent, ModelProductContent, T> | undefined>;
293
+ mget<T extends IModelGetOptions<EntityProductContent,ModelProductContent>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityProductContent, ModelProductContent, T>[]>;
294
+ selectAndCount<T extends IModelSelectParams<EntityProductContent,ModelProductContent,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityProductContent, ModelProductContent, T>>;
295
+ select<T extends IModelSelectParams<EntityProductContent,ModelProductContent,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelRelationResult<EntityProductContent, ModelProductContent, T>[]>;
296
+ insert<T extends IModelInsertOptions<EntityProductContent,ModelProductContent>>(data?: TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>, options?: T): Promise<TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T, true>>;
297
+ insertBulk<T extends IModelInsertOptions<EntityProductContent,ModelProductContent>>(items: TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T, true>[]>;
298
+ update<T extends IModelUpdateOptions<EntityProductContent,ModelProductContent>>(data: TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>, options?: T): Promise<TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>>;
299
+ updateBulk<T extends IModelUpdateOptions<EntityProductContent,ModelProductContent>>(items: TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>[]>;
300
+ delete<T extends IModelDeleteOptions<EntityProductContent,ModelProductContent>>(where?: TypeModelWhere<EntityProductContent>, options?: T): Promise<void>;
301
+ deleteBulk<T extends IModelDeleteOptions<EntityProductContent,ModelProductContent>>(ids: TableIdentity[], options?: T): Promise<void>;
302
+ mutate<T extends IModelMutateOptions<EntityProductContent,ModelProductContent>>(data?: TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>, options?: T): Promise<TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>>;
303
+ mutateBulk<T extends IModelMutateOptions<EntityProductContent,ModelProductContent>>(items: TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>[]>;
304
+ count<T extends IModelSelectCountParams<EntityProductContent,ModelProductContent,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<string | undefined>;
305
+ increment<T extends IModelIncrementParams<EntityProductContent,ModelProductContent,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<number>;
306
+ decrement<T extends IModelIncrementParams<EntityProductContent,ModelProductContent,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<number>;
307
+ aggregate<T extends IModelSelectAggrParams<EntityProductContent,ModelProductContent,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelAggrRelationResult<T>>;
308
+ group<T extends IModelSelectGroupParams<EntityProductContent,ModelProductContent,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelGroupRelationResult<EntityProductContent, T>[]>;
309
+ getById<T extends IModelGetOptions<EntityProductContent,ModelProductContent>>(id: TableIdentity, options?: T): Promise<TypeModelRelationResult<EntityProductContent, ModelProductContent, T> | undefined>;
310
+ updateById<T extends IModelUpdateOptions<EntityProductContent,ModelProductContent>>(id: TableIdentity, data: TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>, options?: T): Promise<TypeModelMutateRelationData<EntityProductContent,ModelProductContent, T>>;
311
+ deleteById<T extends IModelDeleteOptions<EntityProductContent,ModelProductContent>>(id: TableIdentity, options?: T): Promise<void>;
312
+ }
240
313
  export interface ModelSku {
241
314
  [SymbolKeyEntity]: EntitySku;
242
315
  [SymbolKeyEntityMeta]: EntitySkuMeta;
@@ -279,6 +352,7 @@ declare module 'vona-module-a-orm' {
279
352
  export interface IModelClassRecord {
280
353
  'commerce-catalog:category': ModelCategory;
281
354
  'commerce-catalog:product': ModelProduct;
355
+ 'commerce-catalog:productContent': ModelProductContent;
282
356
  'commerce-catalog:sku': ModelSku;
283
357
  }
284
358
  }
@@ -402,8 +476,11 @@ export * from '../dto/categorySelectRes.tsx';
402
476
  export * from '../dto/categorySelectResItem.tsx';
403
477
  export * from '../dto/categoryUpdate.tsx';
404
478
  export * from '../dto/categoryView.tsx';
479
+ export * from '../dto/productContentUpdate.tsx';
480
+ export * from '../dto/productContentView.tsx';
405
481
  export * from '../dto/productCreate.tsx';
406
482
  export * from '../dto/productPublic.tsx';
483
+ export * from '../dto/productPublicDetail.tsx';
407
484
  export * from '../dto/productPublicSelectReq.tsx';
408
485
  export * from '../dto/productPublicSelectRes.tsx';
409
486
  export * from '../dto/productPublicSku.tsx';
@@ -425,8 +502,11 @@ import type { IDtoOptionsCategorySelectRes } from '../dto/categorySelectRes.tsx'
425
502
  import type { IDtoOptionsCategorySelectResItem } from '../dto/categorySelectResItem.tsx';
426
503
  import type { IDtoOptionsCategoryUpdate } from '../dto/categoryUpdate.tsx';
427
504
  import type { IDtoOptionsCategoryView } from '../dto/categoryView.tsx';
505
+ import type { IDtoOptionsProductContentUpdate } from '../dto/productContentUpdate.tsx';
506
+ import type { IDtoOptionsProductContentView } from '../dto/productContentView.tsx';
428
507
  import type { IDtoOptionsProductCreate } from '../dto/productCreate.tsx';
429
508
  import type { IDtoOptionsProductPublic } from '../dto/productPublic.tsx';
509
+ import type { IDtoOptionsProductPublicDetail } from '../dto/productPublicDetail.tsx';
430
510
  import type { IDtoOptionsProductPublicSelectReq } from '../dto/productPublicSelectReq.tsx';
431
511
  import type { IDtoOptionsProductPublicSelectRes } from '../dto/productPublicSelectRes.tsx';
432
512
  import type { IDtoOptionsProductPublicSku } from '../dto/productPublicSku.tsx';
@@ -452,8 +532,11 @@ declare module 'vona-module-a-web' {
452
532
  'commerce-catalog:categorySelectResItem': IDtoOptionsCategorySelectResItem;
453
533
  'commerce-catalog:categoryUpdate': IDtoOptionsCategoryUpdate;
454
534
  'commerce-catalog:categoryView': IDtoOptionsCategoryView;
535
+ 'commerce-catalog:productContentUpdate': IDtoOptionsProductContentUpdate;
536
+ 'commerce-catalog:productContentView': IDtoOptionsProductContentView;
455
537
  'commerce-catalog:productCreate': IDtoOptionsProductCreate;
456
538
  'commerce-catalog:productPublic': IDtoOptionsProductPublic;
539
+ 'commerce-catalog:productPublicDetail': IDtoOptionsProductPublicDetail;
457
540
  'commerce-catalog:productPublicSelectReq': IDtoOptionsProductPublicSelectReq;
458
541
  'commerce-catalog:productPublicSelectRes': IDtoOptionsProductPublicSelectRes;
459
542
  'commerce-catalog:productPublicSku': IDtoOptionsProductPublicSku;
@@ -484,8 +567,11 @@ import type { DtoCategorySelectRes } from '../dto/categorySelectRes.tsx';
484
567
  import type { DtoCategorySelectResItem } from '../dto/categorySelectResItem.tsx';
485
568
  import type { DtoCategoryUpdate } from '../dto/categoryUpdate.tsx';
486
569
  import type { DtoCategoryView } from '../dto/categoryView.tsx';
570
+ import type { DtoProductContentUpdate } from '../dto/productContentUpdate.tsx';
571
+ import type { DtoProductContentView } from '../dto/productContentView.tsx';
487
572
  import type { DtoProductCreate } from '../dto/productCreate.tsx';
488
573
  import type { DtoProductPublic } from '../dto/productPublic.tsx';
574
+ import type { DtoProductPublicDetail } from '../dto/productPublicDetail.tsx';
489
575
  import type { DtoProductPublicSelectReq } from '../dto/productPublicSelectReq.tsx';
490
576
  import type { DtoProductPublicSelectRes } from '../dto/productPublicSelectRes.tsx';
491
577
  import type { DtoProductPublicSku } from '../dto/productPublicSku.tsx';
@@ -527,6 +613,14 @@ declare module 'vona-module-commerce-catalog' {
527
613
  fields?: TypeEntityOptionsFields<DtoCategoryView, IDtoOptionsCategoryView[TypeSymbolKeyFieldsMore]>;
528
614
  }
529
615
 
616
+ export interface IDtoOptionsProductContentUpdate {
617
+ fields?: TypeEntityOptionsFields<DtoProductContentUpdate, IDtoOptionsProductContentUpdate[TypeSymbolKeyFieldsMore]>;
618
+ }
619
+
620
+ export interface IDtoOptionsProductContentView {
621
+ fields?: TypeEntityOptionsFields<DtoProductContentView, IDtoOptionsProductContentView[TypeSymbolKeyFieldsMore]>;
622
+ }
623
+
530
624
  export interface IDtoOptionsProductCreate {
531
625
  fields?: TypeEntityOptionsFields<DtoProductCreate, IDtoOptionsProductCreate[TypeSymbolKeyFieldsMore]>;
532
626
  }
@@ -535,6 +629,10 @@ declare module 'vona-module-commerce-catalog' {
535
629
  fields?: TypeEntityOptionsFields<DtoProductPublic, IDtoOptionsProductPublic[TypeSymbolKeyFieldsMore]>;
536
630
  }
537
631
 
632
+ export interface IDtoOptionsProductPublicDetail {
633
+ fields?: TypeEntityOptionsFields<DtoProductPublicDetail, IDtoOptionsProductPublicDetail[TypeSymbolKeyFieldsMore]>;
634
+ }
635
+
538
636
  export interface IDtoOptionsProductPublicSelectReq {
539
637
  fields?: TypeEntityOptionsFields<DtoProductPublicSelectReq, IDtoOptionsProductPublicSelectReq[TypeSymbolKeyFieldsMore]>;
540
638
  }
@@ -8,6 +8,7 @@ import { $tableColumns } from 'vona-module-a-ormutils';
8
8
  indexes: {
9
9
  ...$tableColumns('commerceCatalogSku', ['code', 'productId', 'lifecycle']),
10
10
  ...$tableColumns('commerceCatalogProduct', ['title', 'categoryId']),
11
+ ...$tableColumns('commerceCatalogProductContent', ['productId']),
11
12
  ...$tableColumns('commerceCatalogCategory', ['name', 'parentId']),
12
13
  },
13
14
  })
@@ -35,6 +35,25 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate {
35
35
  table.index([entityProduct.categoryId], `idx_${entityProduct.$table}_categoryId`);
36
36
  });
37
37
 
38
+ const entityProductContent = this.scope.entity.productContent;
39
+ await this.bean.model.createTable(entityProductContent.$table, table => {
40
+ table.comment(entityProductContent.$comment.$table);
41
+ table.basicFields();
42
+ table
43
+ .text(entityProductContent.descriptionMarkdown)
44
+ .comment(entityProductContent.$comment.descriptionMarkdown);
45
+ table
46
+ .text(entityProductContent.descriptionHtml)
47
+ .comment(entityProductContent.$comment.descriptionHtml);
48
+ table
49
+ .tableIdentity(entityProductContent.productId)
50
+ .comment(entityProductContent.$comment.productId);
51
+ table.index(
52
+ [entityProductContent.productId],
53
+ `idx_${entityProductContent.$table}_productId`,
54
+ );
55
+ });
56
+
38
57
  const entitySku = this.scope.entity.sku;
39
58
  await this.bean.model.createTable(entitySku.$table, table => {
40
59
  table.comment(entitySku.$comment.$table);
@@ -2,11 +2,14 @@ export default {
2
2
  Available: 'Available',
3
3
  Category: 'Category',
4
4
  Description: 'Description',
5
+ DescriptionHtml: 'Product description (HTML)',
6
+ DescriptionMarkdown: 'Product description (Markdown)',
5
7
  Name: 'Name',
6
8
  Operations: 'Operations',
7
9
  ParentCategory: 'Parent category',
8
10
  PriceCents: 'Price (cents)',
9
11
  Product: 'Product',
12
+ ProductContent: 'Product content',
10
13
  ProductTitle: 'Product title',
11
14
  Published: 'Published',
12
15
  Unpublished: 'Unpublished',
@@ -2,11 +2,14 @@ export default {
2
2
  Available: '可用库存',
3
3
  Category: '分类',
4
4
  Description: '描述',
5
+ DescriptionHtml: '商品描述(HTML)',
6
+ DescriptionMarkdown: '商品描述(Markdown)',
5
7
  Name: '名称',
6
8
  Operations: '操作',
7
9
  ParentCategory: '父分类',
8
10
  PriceCents: '价格(分)',
9
11
  Product: '商品',
12
+ ProductContent: '商品详情',
10
13
  ProductTitle: '商品标题',
11
14
  Published: '已发布',
12
15
  Unpublished: '未发布',
@@ -11,7 +11,7 @@ import { z } from 'zod';
11
11
  import type { ModelProduct } from '../model/product.ts';
12
12
 
13
13
  import { DtoProductCreate } from '../dto/productCreate.tsx';
14
- import { DtoProductPublic } from '../dto/productPublic.tsx';
14
+ import { DtoProductPublicDetail } from '../dto/productPublicDetail.tsx';
15
15
  import { DtoProductPublicSelectReq } from '../dto/productPublicSelectReq.tsx';
16
16
  import { DtoProductPublicSelectRes } from '../dto/productPublicSelectRes.tsx';
17
17
  import { DtoProductSelectReq } from '../dto/productSelectReq.tsx';
@@ -50,11 +50,11 @@ export class ControllerProduct extends BeanBase {
50
50
  }
51
51
 
52
52
  @Web.get('public/:id')
53
- @Api.body(v.optional(), v.object(DtoProductPublic))
53
+ @Api.body(v.optional(), v.object(DtoProductPublicDetail))
54
54
  @Passport.public()
55
55
  async viewPublic(
56
56
  @Arg.param('id', v.tableIdentity()) id: TableIdentity,
57
- ): Promise<DtoProductPublic | undefined> {
57
+ ): Promise<DtoProductPublicDetail | undefined> {
58
58
  return await this.scope.service.product.viewPublic(id);
59
59
  }
60
60
 
@@ -0,0 +1,14 @@
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-web';
5
+
6
+ import { $locale } from '../.metadata/locales.ts';
7
+
8
+ export interface IDtoOptionsProductContentUpdate extends IDecoratorDtoOptions {}
9
+
10
+ @Dto<IDtoOptionsProductContentUpdate>()
11
+ export class DtoProductContentUpdate {
12
+ @Api.field(v.title($locale('DescriptionMarkdown')), v.optional())
13
+ descriptionMarkdown?: string;
14
+ }
@@ -0,0 +1,19 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+
3
+ import { $makeMetadata, Api, v } from 'vona-module-a-openapiutils';
4
+ import { Dto } from 'vona-module-a-web';
5
+ import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
6
+
7
+ import { $locale } from '../.metadata/locales.ts';
8
+
9
+ export interface IDtoOptionsProductContentView extends IDecoratorDtoOptions {}
10
+
11
+ @Dto<IDtoOptionsProductContentView>({
12
+ fields: {
13
+ descriptionMarkdown: $makeMetadata(ZovaRender.field('basic-markdown:formFieldMarkdown')),
14
+ },
15
+ })
16
+ export class DtoProductContentView {
17
+ @Api.field(v.title($locale('DescriptionMarkdown')), v.optional())
18
+ descriptionMarkdown?: string;
19
+ }
@@ -1,18 +1,61 @@
1
1
  import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
2
 
3
+ import { $makeMetadata } from 'vona-module-a-openapiutils';
3
4
  import { $Dto } from 'vona-module-a-orm';
4
5
  import { Dto } from 'vona-module-a-web';
5
6
  import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
6
7
 
8
+ import { $locale } from '../.metadata/locales.ts';
7
9
  import { ModelProduct } from '../model/product.ts';
8
10
 
9
- export interface IDtoOptionsProductCreate extends IDecoratorDtoOptions {}
11
+ export interface IDtoOptionsProductCreate extends IDecoratorDtoOptions<'productContentForm'> {}
10
12
 
11
13
  @Dto<IDtoOptionsProductCreate>({
14
+ fields: {
15
+ productContentForm: $makeMetadata(
16
+ ZovaRender.fieldSource('productContentForm.descriptionMarkdown'),
17
+ ZovaRender.field('basic-markdown:formFieldMarkdown'),
18
+ ),
19
+ },
12
20
  blocks: [
13
21
  ZovaRender.block('basic-pageentry:blockPageEntry', {
14
22
  blocks: [
15
- ZovaRender.block('basic-pageentry:blockForm'),
23
+ ZovaRender.block('basic-pageentry:blockForm', {
24
+ blocks: [
25
+ ZovaRender.block('basic-form:blockFormLayout', {
26
+ formLayout: {
27
+ children: [
28
+ {
29
+ type: 'group',
30
+ title: $locale('Product'),
31
+ children: [
32
+ {
33
+ type: 'section',
34
+ columns: { default: 1, md: 2 },
35
+ children: [
36
+ { type: 'field', name: 'title' },
37
+ { type: 'field', name: 'categoryId' },
38
+ { type: 'field', name: 'published' },
39
+ { type: 'field', name: 'description', span: { default: 1, md: 2 } },
40
+ ],
41
+ },
42
+ ],
43
+ },
44
+ {
45
+ type: 'group',
46
+ title: $locale('ProductContent'),
47
+ children: [
48
+ {
49
+ type: 'section',
50
+ children: [{ type: 'field', name: 'productContentForm' }],
51
+ },
52
+ ],
53
+ },
54
+ ],
55
+ },
56
+ }),
57
+ ],
58
+ }),
16
59
  ZovaRender.block('basic-pageentry:blockToolbarRow', {
17
60
  actions: [
18
61
  ZovaRender.formActionRow('basic-form:actionSubmit', {
@@ -25,4 +68,6 @@ export interface IDtoOptionsProductCreate extends IDecoratorDtoOptions {}
25
68
  }),
26
69
  ],
27
70
  })
28
- export class DtoProductCreate extends $Dto.create(() => ModelProduct) {}
71
+ export class DtoProductCreate extends $Dto.create(() => ModelProduct, {
72
+ include: { productContentForm: true },
73
+ }) {}
@@ -0,0 +1,15 @@
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-web';
5
+
6
+ import { $locale } from '../.metadata/locales.ts';
7
+ import { DtoProductPublic } from './productPublic.tsx';
8
+
9
+ export interface IDtoOptionsProductPublicDetail extends IDecoratorDtoOptions {}
10
+
11
+ @Dto<IDtoOptionsProductPublicDetail>()
12
+ export class DtoProductPublicDetail extends DtoProductPublic {
13
+ @Api.field(v.title($locale('DescriptionHtml')), v.optional())
14
+ descriptionHtml?: string;
15
+ }
@@ -1,18 +1,61 @@
1
1
  import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
2
 
3
+ import { $makeMetadata } from 'vona-module-a-openapiutils';
3
4
  import { $Dto } from 'vona-module-a-orm';
4
5
  import { Dto } from 'vona-module-a-web';
5
6
  import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
6
7
 
8
+ import { $locale } from '../.metadata/locales.ts';
7
9
  import { ModelProduct } from '../model/product.ts';
8
10
 
9
- export interface IDtoOptionsProductUpdate extends IDecoratorDtoOptions {}
11
+ export interface IDtoOptionsProductUpdate extends IDecoratorDtoOptions<'productContentForm'> {}
10
12
 
11
13
  @Dto<IDtoOptionsProductUpdate>({
14
+ fields: {
15
+ productContentForm: $makeMetadata(
16
+ ZovaRender.fieldSource('productContentForm.descriptionMarkdown'),
17
+ ZovaRender.field('basic-markdown:formFieldMarkdown'),
18
+ ),
19
+ },
12
20
  blocks: [
13
21
  ZovaRender.block('basic-pageentry:blockPageEntry', {
14
22
  blocks: [
15
- ZovaRender.block('basic-pageentry:blockForm'),
23
+ ZovaRender.block('basic-pageentry:blockForm', {
24
+ blocks: [
25
+ ZovaRender.block('basic-form:blockFormLayout', {
26
+ formLayout: {
27
+ children: [
28
+ {
29
+ type: 'group',
30
+ title: $locale('Product'),
31
+ children: [
32
+ {
33
+ type: 'section',
34
+ columns: { default: 1, md: 2 },
35
+ children: [
36
+ { type: 'field', name: 'title' },
37
+ { type: 'field', name: 'categoryId' },
38
+ { type: 'field', name: 'published' },
39
+ { type: 'field', name: 'description', span: { default: 1, md: 2 } },
40
+ ],
41
+ },
42
+ ],
43
+ },
44
+ {
45
+ type: 'group',
46
+ title: $locale('ProductContent'),
47
+ children: [
48
+ {
49
+ type: 'section',
50
+ children: [{ type: 'field', name: 'productContentForm' }],
51
+ },
52
+ ],
53
+ },
54
+ ],
55
+ },
56
+ }),
57
+ ],
58
+ }),
16
59
  ZovaRender.block('basic-pageentry:blockToolbarRow', {
17
60
  actions: [
18
61
  ZovaRender.formActionRow('basic-form:actionSubmit', {
@@ -25,4 +68,6 @@ export interface IDtoOptionsProductUpdate extends IDecoratorDtoOptions {}
25
68
  }),
26
69
  ],
27
70
  })
28
- export class DtoProductUpdate extends $Dto.update(() => ModelProduct) {}
71
+ export class DtoProductUpdate extends $Dto.update(() => ModelProduct, {
72
+ include: { productContentForm: true },
73
+ }) {}
@@ -1,18 +1,64 @@
1
1
  import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
2
 
3
+ import { $makeMetadata } from 'vona-module-a-openapiutils';
3
4
  import { $Dto } from 'vona-module-a-orm';
4
5
  import { Dto } from 'vona-module-a-web';
5
6
  import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
6
7
 
8
+ import { $locale } from '../.metadata/locales.ts';
7
9
  import { ModelProduct } from '../model/product.ts';
8
10
 
9
- export interface IDtoOptionsProductView extends IDecoratorDtoOptions {}
11
+ export interface IDtoOptionsProductView extends IDecoratorDtoOptions<'productContentForm'> {}
10
12
 
11
13
  @Dto<IDtoOptionsProductView>({
14
+ fields: {
15
+ productContentForm: $makeMetadata(
16
+ ZovaRender.fieldSource('productContentForm.descriptionMarkdown'),
17
+ ZovaRender.field('basic-markdown:formFieldMarkdown'),
18
+ ),
19
+ },
12
20
  blocks: [
13
21
  ZovaRender.block('basic-pageentry:blockPageEntry', {
14
22
  blocks: [
15
- ZovaRender.block('basic-pageentry:blockForm'),
23
+ ZovaRender.block('basic-pageentry:blockForm', {
24
+ blocks: [
25
+ ZovaRender.block('basic-form:blockFormLayout', {
26
+ formLayout: {
27
+ children: [
28
+ {
29
+ type: 'group',
30
+ title: $locale('Product'),
31
+ children: [
32
+ {
33
+ type: 'section',
34
+ columns: { default: 1, md: 2 },
35
+ children: [
36
+ { type: 'field', name: 'id' },
37
+ { type: 'field', name: 'title' },
38
+ { type: 'field', name: 'categoryId' },
39
+ { type: 'field', name: 'published' },
40
+ { type: 'field', name: 'description', span: { default: 1, md: 2 } },
41
+ { type: 'field', name: 'createdAt' },
42
+ { type: 'field', name: 'updatedAt' },
43
+ ],
44
+ },
45
+ ],
46
+ },
47
+ {
48
+ type: 'group',
49
+ title: $locale('ProductContent'),
50
+ children: [
51
+ {
52
+ type: 'section',
53
+ children: [{ type: 'field', name: 'productContentForm' }],
54
+ },
55
+ ],
56
+ },
57
+ ],
58
+ },
59
+ }),
60
+ ],
61
+ }),
16
62
  ZovaRender.block('basic-pageentry:blockToolbarRow', {
17
63
  actions: [
18
64
  ZovaRender.formActionRow('basic-form:actionBack', { permission: { public: true } }),
@@ -23,5 +69,8 @@ export interface IDtoOptionsProductView extends IDecoratorDtoOptions {}
23
69
  ],
24
70
  })
25
71
  export class DtoProductView extends $Dto.get(() => ModelProduct, {
26
- include: { category: true },
72
+ include: {
73
+ category: true,
74
+ productContentForm: true,
75
+ },
27
76
  }) {}