cabloy 5.1.97 → 5.1.99

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 (240) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/hooks/contract-loop-gate.ts +151 -44
  3. package/CHANGELOG.md +48 -0
  4. package/CLAUDE.md +2 -0
  5. package/cabloy-docs/.vitepress/config.mjs +11 -0
  6. package/cabloy-docs/backend/controller-aop-guide.md +0 -1
  7. package/cabloy-docs/backend/image-guide.md +544 -0
  8. package/cabloy-docs/frontend/a-openapi-under-the-hood.md +1 -1
  9. package/cabloy-docs/frontend/generated-contract-consumption-entry-branch.md +1 -1
  10. package/cabloy-docs/frontend/generated-contract-consumption-list-branch.md +1 -1
  11. package/cabloy-docs/frontend/generated-contract-consumption-verify-playbook.md +1 -1
  12. package/cabloy-docs/frontend/image-guide.md +512 -0
  13. package/cabloy-docs/frontend/introduction.md +2 -0
  14. package/cabloy-docs/frontend/ioc-and-beans.md +34 -3
  15. package/cabloy-docs/frontend/model-architecture.md +2 -0
  16. package/cabloy-docs/frontend/model-resource-owner-pattern.md +3 -1
  17. package/cabloy-docs/frontend/model-state-guide.md +5 -1
  18. package/cabloy-docs/frontend/reading-zova-for-vue-developers.md +10 -8
  19. package/cabloy-docs/frontend/resource-entry-page-deep-dive.md +2 -2
  20. package/cabloy-docs/frontend/resource-list-page-deep-dive.md +1 -1
  21. package/cabloy-docs/frontend/rest-resource-source-reading-map.md +2 -2
  22. package/cabloy-docs/frontend/rest-resource-under-the-hood.md +4 -4
  23. package/cabloy-docs/frontend/server-data.md +2 -0
  24. package/cabloy-docs/frontend/state-architecture-for-vue-developers.md +218 -0
  25. package/cabloy-docs/frontend/system-startup-guide.md +2 -0
  26. package/cabloy-docs/frontend/use-state-data-best-practices.md +384 -0
  27. package/cabloy-docs/frontend/zova-vs-vue3-comparison.md +11 -10
  28. package/cabloy-docs/fullstack/image-workflow.md +403 -0
  29. package/cabloy-docs/fullstack/introduction.md +1 -0
  30. package/package.json +1 -1
  31. package/scripts/upgrade.ts +2 -0
  32. package/vona/package.original.json +0 -1
  33. package/vona/packages-cli/cli/package.json +1 -1
  34. package/vona/packages-cli/cli-set-api/package.json +1 -1
  35. package/vona/packages-vona/vona/package.json +1 -1
  36. package/vona/packages-vona/vona-core/package.json +1 -1
  37. package/vona/packages-vona/vona-core/src/lib/bean/beanBase.ts +9 -9
  38. package/vona/packages-vona/vona-mock/package.json +1 -1
  39. package/vona/pnpm-lock.yaml +424 -47
  40. package/vona/src/suite/a-training/modules/training-record/src/bean/fileScene.dossierFile.ts +22 -0
  41. package/vona/src/suite/a-training/modules/training-record/src/bean/meta.version.ts +1 -0
  42. package/vona/src/suite/a-training/modules/training-record/src/config/locale/en-us.ts +1 -0
  43. package/vona/src/suite/a-training/modules/training-record/src/config/locale/zh-cn.ts +1 -0
  44. package/vona/src/suite/a-training/modules/training-record/src/dto/recordDossierFileView.ts +47 -0
  45. package/vona/src/suite/a-training/modules/training-record/src/dto/recordSelectResItem.tsx +13 -0
  46. package/vona/src/suite/a-training/modules/training-record/src/dto/recordView.tsx +13 -0
  47. package/vona/src/suite/a-training/modules/training-record/src/entity/record.tsx +16 -5
  48. package/vona/src/suite/a-training/modules/training-record/src/index.ts +2 -0
  49. package/vona/src/suite/a-training/modules/training-record/src/lib/index.ts +1 -0
  50. package/vona/src/suite/a-training/modules/training-record/src/lib/resolveDossierFiles.ts +34 -0
  51. package/vona/src/suite/a-training/modules/training-record/test/record.test.ts +209 -123
  52. package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +1 -0
  53. package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +1 -0
  54. package/vona/src/suite/a-training/modules/training-student/src/dto/detailRecordBase.tsx +18 -1
  55. package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +0 -2
  56. package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +1 -0
  57. package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/bean/ssrSite.admin.ts +4 -0
  58. package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/bean/ssrSite.web.ts +4 -0
  59. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/cli/ssrSite/boilerplate/{{sceneName}}.{{beanName}}.ts_ +3 -0
  60. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/package.json +1 -1
  61. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/service/ssrHandler.ts +11 -2
  62. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/ssrSite.ts +6 -0
  63. package/vona/src/suite-vendor/a-cabloy/package.json +1 -1
  64. package/vona/src/suite-vendor/a-file/modules/a-file/cli/fileProvider/boilerplate/{{sceneName}}.{{beanName}}.ts_ +23 -0
  65. package/vona/src/suite-vendor/a-file/modules/a-file/cli/fileScene/boilerplate/{{sceneName}}.{{beanName}}.ts_ +5 -0
  66. package/vona/src/suite-vendor/a-file/modules/a-file/package.json +68 -0
  67. package/vona/src/suite-vendor/a-file/modules/a-file/src/.metadata/index.ts +425 -0
  68. package/vona/src/suite-vendor/a-file/modules/a-file/src/.metadata/locales.ts +18 -0
  69. package/vona/src/suite-vendor/a-file/modules/a-file/src/.metadata/this.ts +2 -0
  70. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/bean.file.ts +322 -0
  71. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/bean.fileProvider.ts +62 -0
  72. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/bean.fileUploadPolicy.ts +224 -0
  73. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/meta.redlock.ts +11 -0
  74. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/meta.version.ts +38 -0
  75. package/vona/src/suite-vendor/a-file/modules/a-file/src/config/config.ts +16 -0
  76. package/vona/src/suite-vendor/a-file/modules/a-file/src/config/locale/en-us.ts +1 -0
  77. package/vona/src/suite-vendor/a-file/modules/a-file/src/config/locale/zh-cn.ts +1 -0
  78. package/vona/src/suite-vendor/a-file/modules/a-file/src/controller/file.ts +175 -0
  79. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileDirectUploadRequest.ts +33 -0
  80. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileDirectUploadResponse.ts +41 -0
  81. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileDownloadRequest.ts +12 -0
  82. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadPolicyRequest.ts +15 -0
  83. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadPolicyResponse.ts +30 -0
  84. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadResponse.ts +59 -0
  85. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadTokenRequest.ts +24 -0
  86. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadTokenResponse.ts +16 -0
  87. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadUrlRequest.ts +33 -0
  88. package/vona/src/suite-vendor/a-file/modules/a-file/src/entity/file.ts +55 -0
  89. package/vona/src/suite-vendor/a-file/modules/a-file/src/entity/fileProvider.ts +24 -0
  90. package/vona/src/suite-vendor/a-file/modules/a-file/src/index.ts +4 -0
  91. package/vona/src/suite-vendor/a-file/modules/a-file/src/lib/fileProvider.ts +7 -0
  92. package/vona/src/suite-vendor/a-file/modules/a-file/src/lib/fileScene.ts +7 -0
  93. package/vona/src/suite-vendor/a-file/modules/a-file/src/lib/fileUploadValidation.ts +15 -0
  94. package/vona/src/suite-vendor/a-file/modules/a-file/src/lib/index.ts +3 -0
  95. package/vona/src/suite-vendor/a-file/modules/a-file/src/model/file.ts +10 -0
  96. package/vona/src/suite-vendor/a-file/modules/a-file/src/model/fileProvider.ts +10 -0
  97. package/vona/src/suite-vendor/a-file/modules/a-file/src/types/file.ts +144 -0
  98. package/vona/src/suite-vendor/a-file/modules/a-file/src/types/fileProvider.ts +111 -0
  99. package/vona/src/suite-vendor/a-file/modules/a-file/src/types/fileScene.ts +53 -0
  100. package/vona/src/suite-vendor/a-file/modules/a-file/src/types/index.ts +3 -0
  101. package/vona/src/suite-vendor/a-file/modules/a-file/tsconfig.build.json +11 -0
  102. package/vona/src/suite-vendor/a-file/modules/a-file/tsconfig.json +7 -0
  103. package/vona/src/suite-vendor/a-file/modules/file-cloudflare/package.json +53 -0
  104. package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/.metadata/index.ts +104 -0
  105. package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/.metadata/this.ts +2 -0
  106. package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/bean/fileProvider.cloudflare.ts +123 -0
  107. package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/index.ts +1 -0
  108. package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/service/fileCloudflare.ts +245 -0
  109. package/vona/src/suite-vendor/a-file/modules/file-cloudflare/tsconfig.build.json +11 -0
  110. package/vona/src/suite-vendor/a-file/modules/file-cloudflare/tsconfig.json +7 -0
  111. package/vona/src/suite-vendor/a-file/modules/file-native/package.json +50 -0
  112. package/vona/src/suite-vendor/a-file/modules/file-native/src/.metadata/index.ts +111 -0
  113. package/vona/src/suite-vendor/a-file/modules/file-native/src/.metadata/this.ts +2 -0
  114. package/vona/src/suite-vendor/a-file/modules/file-native/src/bean/fileProvider.native.ts +125 -0
  115. package/vona/src/suite-vendor/a-file/modules/file-native/src/config/config.ts +7 -0
  116. package/vona/src/suite-vendor/a-file/modules/file-native/src/index.ts +1 -0
  117. package/vona/src/suite-vendor/a-file/modules/file-native/src/service/fileNative.ts +125 -0
  118. package/vona/src/suite-vendor/a-file/modules/file-native/tsconfig.build.json +11 -0
  119. package/vona/src/suite-vendor/a-file/modules/file-native/tsconfig.json +7 -0
  120. package/vona/src/suite-vendor/a-file/package.json +14 -0
  121. package/vona/src/suite-vendor/a-file/tsconfig.base.json +4 -0
  122. package/vona/src/suite-vendor/a-file/tsconfig.json +16 -0
  123. package/vona/src/suite-vendor/a-image/modules/a-image/package.json +4 -1
  124. package/vona/src/suite-vendor/a-image/modules/a-image/src/.metadata/index.ts +61 -3
  125. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.image.ts +336 -152
  126. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.imageProvider.ts +21 -14
  127. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.imageUploadPolicy.ts +86 -11
  128. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/meta.index.ts +12 -0
  129. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/meta.redlock.ts +1 -1
  130. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/meta.version.ts +3 -0
  131. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/schedule.imageDraftPrune.ts +29 -0
  132. package/vona/src/suite-vendor/a-image/modules/a-image/src/config/config.ts +3 -0
  133. package/vona/src/suite-vendor/a-image/modules/a-image/src/controller/image.ts +32 -54
  134. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDirectUploadFinalizeRequest.ts +13 -0
  135. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDirectUploadFinalizeResponse.ts +10 -0
  136. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDirectUploadResponse.ts +10 -0
  137. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadPolicyRequest.ts +15 -0
  138. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadPolicyResponse.ts +27 -0
  139. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadResponse.ts +10 -1
  140. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageView.ts +10 -1
  141. package/vona/src/suite-vendor/a-image/modules/a-image/src/entity/image.ts +10 -1
  142. package/vona/src/suite-vendor/a-image/modules/a-image/src/lib/imageUploadValidation.ts +15 -0
  143. package/vona/src/suite-vendor/a-image/modules/a-image/src/lib/index.ts +1 -0
  144. package/vona/src/suite-vendor/a-image/modules/a-image/src/types/image.ts +18 -0
  145. package/vona/src/suite-vendor/a-image/modules/a-image/src/types/imageProvider.ts +28 -2
  146. package/vona/src/suite-vendor/a-image/modules/image-cloudflare/package.json +1 -1
  147. package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/bean/imageProvider.cloudflare.ts +13 -1
  148. package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/service/imageCloudflare.ts +26 -0
  149. package/vona/src/suite-vendor/a-image/modules/image-native/package.json +6 -2
  150. package/vona/src/suite-vendor/a-image/modules/image-native/src/.metadata/index.ts +37 -0
  151. package/vona/src/suite-vendor/a-image/modules/image-native/src/bean/imageProvider.native.ts +21 -1
  152. package/vona/src/suite-vendor/a-image/modules/image-native/src/controller/image.ts +57 -0
  153. package/vona/src/suite-vendor/a-image/modules/image-native/src/service/imageNative.ts +142 -34
  154. package/vona/src/suite-vendor/a-image/package.json +1 -1
  155. package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
  156. package/vona/src/suite-vendor/a-vona/modules/a-orm/package.json +1 -1
  157. package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/entity.ts +2 -4
  158. package/vona/src/suite-vendor/a-vona/modules/a-ormutils/package.json +1 -1
  159. package/vona/src/suite-vendor/a-vona/modules/a-ormutils/src/lib/columns.ts +7 -3
  160. package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
  161. package/vona/src/suite-vendor/a-vona/modules/a-permission/src/.metadata/index.ts +24 -9
  162. package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/bean.permission.ts +87 -73
  163. package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/summerCache.permissionActionByRoles.ts +27 -0
  164. package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/summerCache.permissionUser.ts +20 -0
  165. package/vona/src/suite-vendor/a-vona/modules/a-startup/package.json +1 -1
  166. package/vona/src/suite-vendor/a-vona/modules/a-startup/src/service/startup.ts +4 -3
  167. package/vona/src/suite-vendor/a-vona/modules/a-upload/package.json +1 -1
  168. package/vona/src/suite-vendor/a-vona/modules/a-upload/src/bean/interceptor.upload.ts +5 -1
  169. package/vona/src/suite-vendor/a-vona/modules/a-user/package.json +1 -1
  170. package/vona/src/suite-vendor/a-vona/modules/a-user/src/.metadata/index.ts +0 -13
  171. package/vona/src/suite-vendor/a-vona/modules/a-user/src/lib/passport.ts +0 -7
  172. package/vona/src/suite-vendor/a-vona/modules/a-version/package.json +1 -1
  173. package/vona/src/suite-vendor/a-vona/modules/a-version/src/bean/meta.version.ts +2 -24
  174. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  175. package/zova/packages-utils/zova-jsx/package.json +2 -2
  176. package/zova/packages-zova/zova/package.json +3 -3
  177. package/zova/packages-zova/zova-core/package.json +1 -1
  178. package/zova/packages-zova/zova-core/src/bean/beanBase.ts +9 -13
  179. package/zova/pnpm-lock.yaml +418 -411
  180. package/zova/src/suite/a-demo/modules/demo-basic/src/page/toolOne/controller.tsx +2 -2
  181. package/zova/src/suite/a-demo/modules/demo-todo/src/page/todo/controller.tsx +2 -2
  182. package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx +2 -2
  183. package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx +2 -2
  184. package/zova/src/suite/a-home/modules/home-login/src/page/login/controller.tsx +2 -2
  185. package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/blockDetails/controller.tsx +5 -1
  186. package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/blockTable/controller.tsx +20 -15
  187. package/zova/src/suite/cabloy-basic/modules/basic-details/src/service/detail.tsx +6 -1
  188. package/zova/src/suite/cabloy-basic/modules/basic-file/cli/openapi.config.ts +9 -0
  189. package/zova/src/suite/cabloy-basic/modules/basic-file/package.json +58 -0
  190. package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/component/formFieldFile.ts +31 -0
  191. package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/index.ts +222 -0
  192. package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/locales.ts +7 -0
  193. package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/this.ts +2 -0
  194. package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/file.ts +121 -0
  195. package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/baseURL.ts +5 -0
  196. package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/index.ts +3 -0
  197. package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/schemas.ts +306 -0
  198. package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/types.ts +5718 -0
  199. package/zova/src/suite/cabloy-basic/modules/basic-file/src/apiSchema/file.ts +40 -0
  200. package/zova/src/suite/cabloy-basic/modules/basic-file/src/bean/tableCell.file.tsx +187 -0
  201. package/zova/src/suite/cabloy-basic/modules/basic-file/src/component/formFieldFile/controller.tsx +534 -0
  202. package/zova/src/suite/cabloy-basic/modules/basic-file/src/config/locale/en-us.ts +15 -0
  203. package/zova/src/suite/cabloy-basic/modules/basic-file/src/config/locale/zh-cn.ts +15 -0
  204. package/zova/src/suite/cabloy-basic/modules/basic-file/src/index.ts +4 -0
  205. package/zova/src/suite/cabloy-basic/modules/basic-file/src/lib/file.ts +74 -0
  206. package/zova/src/suite/cabloy-basic/modules/basic-file/src/lib/index.ts +1 -0
  207. package/zova/src/suite/cabloy-basic/modules/basic-file/src/model/file.ts +23 -0
  208. package/zova/src/suite/cabloy-basic/modules/basic-file/src/types/file.ts +12 -0
  209. package/zova/src/suite/cabloy-basic/modules/basic-file/src/types/index.ts +1 -0
  210. package/zova/src/suite/cabloy-basic/modules/basic-file/tsconfig.build.json +13 -0
  211. package/zova/src/suite/cabloy-basic/modules/basic-file/tsconfig.json +5 -0
  212. package/zova/src/suite/cabloy-basic/modules/basic-image/src/.metadata/index.ts +61 -0
  213. package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/image.ts +38 -1
  214. package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/imageNativeImage.ts +31 -0
  215. package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/schemas.ts +52 -0
  216. package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/types.ts +614 -1
  217. package/zova/src/suite/cabloy-basic/modules/basic-image/src/apiSchema/image.ts +10 -0
  218. package/zova/src/suite/cabloy-basic/modules/basic-image/src/apiSchema/imageNativeImage.ts +13 -0
  219. package/zova/src/suite/cabloy-basic/modules/basic-image/src/component/formFieldImage/controller.tsx +126 -62
  220. package/zova/src/suite/cabloy-basic/modules/basic-image/src/model/image.ts +23 -0
  221. package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsx +44 -4
  222. package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockTable/controller.tsx +17 -12
  223. package/zova/src/suite/cabloy-basic/modules/basic-pageentry/src/component/blockPageEntry/controller.tsx +2 -2
  224. package/zova/src/suite/cabloy-basic/modules/basic-resource/src/component/formFieldResourcePicker/controller.tsx +2 -2
  225. package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/controller.tsx +7 -2
  226. package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/render.tsx +34 -33
  227. package/zova/src/suite/cabloy-basic/package.json +1 -0
  228. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
  229. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +5 -3
  230. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/entry/controller.tsx +2 -2
  231. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/resource/controller.tsx +2 -2
  232. package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
  233. package/zova/src/suite-vendor/a-zova/modules/a-model/package.json +1 -1
  234. package/zova/src/suite-vendor/a-zova/modules/a-model/src/lib/utils.ts +17 -17
  235. package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
  236. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +8 -3
  237. package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
  238. package/zova/src/suite-vendor/a-zova/package.json +4 -4
  239. package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/summerCache.permission.ts +0 -17
  240. package/vona/src/suite-vendor/a-vona/modules/a-user/src/bean/guard.userName.ts +0 -35
@@ -0,0 +1,22 @@
1
+ import { BeanBase } from 'vona';
2
+ import { FileScene } from 'vona-module-a-file';
3
+
4
+ @FileScene({
5
+ upload: {
6
+ maxSize: 20 * 1024 * 1024,
7
+ mimeTypes: [
8
+ 'application/pdf',
9
+ 'application/msword',
10
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
11
+ 'application/vnd.ms-excel',
12
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
13
+ 'application/zip',
14
+ 'application/x-zip-compressed',
15
+ 'text/plain',
16
+ ],
17
+ extensions: ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.zip', '.txt'],
18
+ multiple: true,
19
+ public: false,
20
+ },
21
+ })
22
+ export class FileSceneDossierFile extends BeanBase {}
@@ -18,6 +18,7 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate {
18
18
  table.decimal(entityRecord.averageScore, 8, 2).comment(entityRecord.$comment.averageScore);
19
19
  table.dateTime(entityRecord.trainingTime).comment(entityRecord.$comment.trainingTime);
20
20
  table.json(entityRecord.sceneImageIds).comment(entityRecord.$comment.sceneImageIds);
21
+ table.json(entityRecord.dossierFileIds).comment(entityRecord.$comment.dossierFileIds);
21
22
  table.string(entityRecord.description, 255).comment(entityRecord.$comment.description);
22
23
  });
23
24
  }
@@ -9,6 +9,7 @@ export default {
9
9
  TrainingRecordName: 'Training Record Name',
10
10
  TrainingTime: 'Training Time',
11
11
  ScenePhotos: 'Scene Photos',
12
+ DossierFiles: 'Dossier Files',
12
13
  AddTrainingRecord: 'Add Student Training Record',
13
14
  EditTrainingRecord: 'Edit Student Training Record',
14
15
  ViewTrainingRecord: 'View Student Training Record',
@@ -9,6 +9,7 @@ export default {
9
9
  TrainingRecordName: '培训记录名称',
10
10
  TrainingTime: '培训时间',
11
11
  ScenePhotos: '现场照片',
12
+ DossierFiles: '培训档案附件',
12
13
  AddTrainingRecord: '添加学生培训记录',
13
14
  EditTrainingRecord: '编辑学生培训记录',
14
15
  ViewTrainingRecord: '查看学生培训记录',
@@ -0,0 +1,47 @@
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
+ import z from 'zod';
7
+
8
+ export interface IDtoOptionsRecordDossierFileView extends IDecoratorDtoOptions {}
9
+
10
+ @Dto<IDtoOptionsRecordDossierFileView>()
11
+ export class DtoRecordDossierFileView {
12
+ @Api.field(v.tableIdentity())
13
+ id: TableIdentity;
14
+
15
+ @Api.field(z.string())
16
+ provider: string;
17
+
18
+ @Api.field(z.string())
19
+ clientName: string;
20
+
21
+ @Api.field(v.optional(), z.string())
22
+ fileScene?: string;
23
+
24
+ @Api.field(v.optional())
25
+ filename?: string;
26
+
27
+ @Api.field(v.optional())
28
+ contentType?: string;
29
+
30
+ @Api.field(v.optional())
31
+ size?: number;
32
+
33
+ @Api.field(v.optional())
34
+ public?: boolean;
35
+
36
+ @Api.field(v.optional())
37
+ uploadedAt?: Date;
38
+
39
+ @Api.field(v.optional(), z.record(z.string(), z.unknown()))
40
+ meta?: Record<string, unknown>;
41
+
42
+ @Api.field(z.string())
43
+ downloadUrl: string;
44
+
45
+ @Api.field(v.default(true))
46
+ signed: boolean;
47
+ }
@@ -7,7 +7,9 @@ import { Dto } from 'vona-module-a-web';
7
7
  import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
8
8
 
9
9
  import { $locale } from '../.metadata/locales.ts';
10
+ import { resolveDossierFiles } from '../lib/resolveDossierFiles.ts';
10
11
  import { ModelRecord } from '../model/record.ts';
12
+ import { DtoRecordDossierFileView } from './recordDossierFileView.ts';
11
13
 
12
14
  export interface IDtoOptionsRecordSelectResItem extends IDecoratorDtoOptions {}
13
15
 
@@ -37,6 +39,17 @@ export class DtoRecordSelectResItem extends $Dto.get(() => ModelRecord) {
37
39
  )
38
40
  sceneImages?: DtoImageView[];
39
41
 
42
+ @Api.field(
43
+ v.title($locale('DossierFiles')),
44
+ ZovaRender.visible(false),
45
+ v.optional(),
46
+ v.serializerTransform('a-serialization:custom', {
47
+ custom: resolveDossierFiles,
48
+ }),
49
+ v.array(DtoRecordDossierFileView),
50
+ )
51
+ dossierFiles?: DtoRecordDossierFileView[];
52
+
40
53
  @Api.field(
41
54
  v.title($locale('Operations')),
42
55
  ZovaRender.order(1, 'max'),
@@ -7,9 +7,11 @@ import { Dto } from 'vona-module-a-web';
7
7
  import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
8
8
 
9
9
  import { $locale } from '../.metadata/locales.ts';
10
+ import { resolveDossierFiles } from '../lib/resolveDossierFiles.ts';
10
11
  import { ModelRecord } from '../model/record.ts';
11
12
  import { DtoDetailRecordSubjectResItem } from './detailRecordSubjectResItem.tsx';
12
13
  import { DtoDetailRecordSubjectView } from './detailRecordSubjectView.tsx';
14
+ import { DtoRecordDossierFileView } from './recordDossierFileView.ts';
13
15
 
14
16
  export interface IDtoOptionsRecordView extends IDecoratorDtoOptions {}
15
17
 
@@ -49,6 +51,17 @@ export class DtoRecordView extends $Dto.get(() => ModelRecord, {
49
51
  )
50
52
  sceneImages?: DtoImageView[];
51
53
 
54
+ @Api.field(
55
+ v.title($locale('DossierFiles')),
56
+ ZovaRender.visible(false),
57
+ v.optional(),
58
+ v.serializerTransform('a-serialization:custom', {
59
+ custom: resolveDossierFiles,
60
+ }),
61
+ v.array(DtoRecordDossierFileView),
62
+ )
63
+ dossierFiles?: DtoRecordDossierFileView[];
64
+
52
65
  @Api.field(ZovaRender.visible(false), v.optional(), v.array(DtoDetailRecordSubjectResItem))
53
66
  _trainingRecordSubjects?: DtoDetailRecordSubjectResItem[];
54
67
  }
@@ -89,11 +89,8 @@ export class EntityRecord extends EntityBase {
89
89
  ZovaRender.order(7),
90
90
  ZovaRender.field('basic-image:formFieldImage', {
91
91
  imageScene: 'training-record:sceneImage',
92
- multiple: true,
93
- maxCount: 9,
92
+ maxCount: 3,
94
93
  relationName: 'sceneImages',
95
- accept: ['image/png', 'image/jpeg', 'image/webp'],
96
- maxSize: 2 * 1024 * 1024,
97
94
  enableCrop: false,
98
95
  resize: {
99
96
  width: 1280,
@@ -108,6 +105,20 @@ export class EntityRecord extends EntityBase {
108
105
  )
109
106
  sceneImageIds?: TableIdentity[];
110
107
 
111
- @Api.field(v.title($locale('Description')), v.optional(), ZovaRender.order(8))
108
+ @Api.field(
109
+ v.title($locale('DossierFiles')),
110
+ v.optional(),
111
+ ZovaRender.order(8),
112
+ ZovaRender.field('basic-file:formFieldFile', {
113
+ fileScene: 'training-record:dossierFile',
114
+ relationName: 'dossierFiles',
115
+ maxCount: 3,
116
+ }),
117
+ ZovaRender.cell('basic-file:file', { relationName: 'dossierFiles' }),
118
+ v.array(v.tableIdentity()),
119
+ )
120
+ dossierFileIds?: TableIdentity[];
121
+
122
+ @Api.field(v.title($locale('Description')), v.optional(), ZovaRender.order(9))
112
123
  description?: string;
113
124
  }
@@ -1,4 +1,6 @@
1
+ export * from './bean/fileScene.dossierFile.ts';
1
2
  export * from './bean/imageScene.sceneImage.ts';
3
+ export * from './dto/recordDossierFileView.ts';
2
4
  export * from './lib/index.ts';
3
5
  export * from './.metadata/locales.ts';
4
6
  export * from './.metadata/index.ts';
@@ -1,2 +1,3 @@
1
1
  export * from './onEffectForAverageScore.tsx';
2
2
  export * from './onEffectForTrainingRecordSubjects.tsx';
3
+ export * from './resolveDossierFiles.ts';
@@ -0,0 +1,34 @@
1
+ import type { TableIdentity } from 'table-identity';
2
+ import type { VonaContext } from 'vona';
3
+
4
+ import type { DtoRecordDossierFileView } from '../dto/recordDossierFileView.ts';
5
+
6
+ export async function resolveDossierFiles(
7
+ this: VonaContext,
8
+ _value: unknown,
9
+ data: { dossierFileIds?: TableIdentity[] },
10
+ ): Promise<DtoRecordDossierFileView[]> {
11
+ const dossierFileIds = data.dossierFileIds;
12
+ if (!dossierFileIds?.length) return [];
13
+ const items: Array<DtoRecordDossierFileView | undefined> = await Promise.all(
14
+ dossierFileIds.map(async dossierFileId => {
15
+ const file = await this.bean.file.get(dossierFileId);
16
+ if (!file || file.fileScene !== 'training-record:dossierFile') return undefined;
17
+ return {
18
+ id: file.id,
19
+ provider: String(file.provider),
20
+ clientName: file.clientName,
21
+ fileScene: file.fileScene ? String(file.fileScene) : undefined,
22
+ filename: file.filename,
23
+ contentType: file.contentType,
24
+ size: file.size,
25
+ public: file.public,
26
+ uploadedAt: file.uploadedAt,
27
+ meta: file.meta as Record<string, unknown> | undefined,
28
+ downloadUrl: await this.bean.file.getDownloadUrl(file.id),
29
+ signed: !file.public,
30
+ } satisfies DtoRecordDossierFileView;
31
+ }),
32
+ );
33
+ return items.filter((item): item is DtoRecordDossierFileView => !!item);
34
+ }
@@ -1,14 +1,16 @@
1
- import type {
2
- DtoRecordCreate,
3
- DtoRecordSelectRes,
4
- DtoRecordUpdate,
5
- } from 'vona-module-training-record';
1
+ import type { DtoRecordCreate, DtoRecordUpdate } from 'vona-module-training-record';
6
2
  import type { DtoStudentCreate } from 'vona-module-training-student';
7
3
 
4
+ import fse from 'fs-extra';
8
5
  import assert from 'node:assert';
6
+ import os from 'node:os';
7
+ import path from 'node:path';
9
8
  import { describe, it } from 'node:test';
10
9
  import { app } from 'vona-mock';
11
10
 
11
+ const dossierTextAttendance = Buffer.from('attendance dossier file');
12
+ const dossierTextAssessment = Buffer.from('assessment dossier file');
13
+
12
14
  describe('record.test.ts', () => {
13
15
  it('action:record', async () => {
14
16
  await app.bean.executor.mockCtx(async () => {
@@ -21,142 +23,226 @@ describe('record.test.ts', () => {
21
23
  };
22
24
  const trainingTime = new Date('2026-01-15T09:30:00.000Z');
23
25
  const trainingTimeUpdate = new Date('2026-02-20T14:45:00.000Z');
24
- const recordData = {
25
- studentId: 0 as any,
26
- name: '__Record__',
27
- subjectCount: 1,
28
- totalScore: 88,
29
- averageScore: 88,
30
- trainingTime,
31
- description: 'This is a record',
32
- trainingRecordSubjects: [
26
+ const dossierFilePathAttendance = path.join(
27
+ os.tmpdir(),
28
+ 'training-record-dossier-attendance.txt',
29
+ );
30
+ const dossierFilePathAssessment = path.join(
31
+ os.tmpdir(),
32
+ 'training-record-dossier-assessment.txt',
33
+ );
34
+ let dossierFileAttendance: any;
35
+ let dossierFileAssessment: any;
36
+ await app.bean.passport.signinMock();
37
+ try {
38
+ await fse.writeFile(dossierFilePathAttendance, dossierTextAttendance);
39
+ dossierFileAttendance = await app.bean.file.upload(
40
+ 'file-native:native',
33
41
  {
34
- name: '__Math__',
35
- score: 95,
36
- description: 'Math subject',
42
+ file: dossierFilePathAttendance,
43
+ filename: 'attendance.txt',
44
+ contentType: 'text/plain',
45
+ public: false,
46
+ meta: {
47
+ category: 'attendanceSheet',
48
+ source: 'upload',
49
+ },
37
50
  },
38
- ],
39
- } as any as DtoRecordCreate;
40
- await app.bean.passport.signinMock();
41
- const studentId = await app.bean.executor.performAction('post', '/training/student', {
42
- body: studentData,
43
- });
44
- recordData.studentId = studentId;
45
- const recordId = await app.bean.executor.performAction('post', '/training/record', {
46
- body: recordData,
47
- });
48
- assert.equal(!!recordId, true);
51
+ {
52
+ clientName: 'default',
53
+ fileScene: 'training-record:dossierFile',
54
+ },
55
+ );
56
+ const recordData = {
57
+ studentId: 0 as any,
58
+ name: '__Record__',
59
+ subjectCount: 1,
60
+ totalScore: 88,
61
+ averageScore: 88,
62
+ trainingTime,
63
+ dossierFileIds: [dossierFileAttendance.id],
64
+ description: 'This is a record',
65
+ trainingRecordSubjects: [
66
+ {
67
+ name: '__Math__',
68
+ score: 95,
69
+ description: 'Math subject',
70
+ },
71
+ ],
72
+ } as any as DtoRecordCreate;
73
+ const studentId = await app.bean.executor.performAction('post', '/training/student', {
74
+ body: studentData,
75
+ });
76
+ recordData.studentId = studentId;
77
+ const recordId = await app.bean.executor.performAction('post', '/training/record', {
78
+ body: recordData,
79
+ });
80
+ assert.equal(!!recordId, true);
49
81
 
50
- const selectRes: DtoRecordSelectRes = await app.bean.executor.performAction(
51
- 'get',
52
- '/training/record',
53
- );
54
- const recordItem = selectRes.list.find(item => String(item.id) === String(recordId));
55
- assert.equal(!!recordItem, true);
56
- assert.equal(recordItem!.name, recordData.name);
57
- assert.equal(String(recordItem!.studentId), String(studentId));
82
+ const selectRes: any = await app.bean.executor.performAction('get', '/training/record');
83
+ const recordItem = selectRes.list.find((item: any) => String(item.id) === String(recordId));
84
+ assert.equal(!!recordItem, true);
85
+ assert.equal(recordItem!.name, recordData.name);
86
+ assert.equal(String(recordItem!.studentId), String(studentId));
87
+ assert.equal(recordItem!.dossierFiles?.length, 1);
88
+ assert.equal(recordItem!.dossierFiles?.[0]?.filename, 'attendance.txt');
58
89
 
59
- let record: any = await app.bean.executor.performAction('get', '/training/record/:id', {
60
- params: { id: recordId },
61
- });
62
- const recordSubject = record.trainingRecordSubjects?.[0];
63
- assert.equal(record.name, recordData.name);
64
- assert.equal(String(record.studentId), String(studentId));
65
- assert.equal(record.subjectCount, recordData.subjectCount);
66
- assert.equal(record.totalScore, recordData.totalScore);
67
- assert.equal(record.averageScore, recordData.averageScore);
68
- assert.equal(new Date(record.trainingTime).toISOString(), trainingTime.toISOString());
69
- assert.equal(record.trainingRecordSubjects?.length, 1);
70
- assert.equal(recordSubject?.name, '__Math__');
71
- assert.equal(recordSubject?.score, 95);
90
+ let record: any = await app.bean.executor.performAction('get', '/training/record/:id', {
91
+ params: { id: recordId },
92
+ });
93
+ const recordSubject = record.trainingRecordSubjects?.[0];
94
+ const recordDossierFile = record.dossierFiles?.[0];
95
+ assert.equal(record.name, recordData.name);
96
+ assert.equal(String(record.studentId), String(studentId));
97
+ assert.equal(record.subjectCount, recordData.subjectCount);
98
+ assert.equal(record.totalScore, recordData.totalScore);
99
+ assert.equal(record.averageScore, recordData.averageScore);
100
+ assert.equal(new Date(record.trainingTime).toISOString(), trainingTime.toISOString());
101
+ assert.equal(record.dossierFileIds?.length, 1);
102
+ assert.equal(record.dossierFiles?.length, 1);
103
+ assert.equal(String(recordDossierFile?.id), String(dossierFileAttendance.id));
104
+ assert.equal(recordDossierFile?.filename, 'attendance.txt');
105
+ assert.equal(recordDossierFile?.signed, true);
106
+ assert.equal(recordDossierFile?.meta?.category, 'attendanceSheet');
107
+ assert.equal(record.trainingRecordSubjects?.length, 1);
108
+ assert.equal(recordSubject?.name, '__Math__');
109
+ assert.equal(recordSubject?.score, 95);
110
+ const downloadResponse = await fetch(recordDossierFile.downloadUrl);
111
+ assert.equal(downloadResponse.ok, true);
112
+ assert.equal(await downloadResponse.text(), dossierTextAttendance.toString());
72
113
 
73
- let student: any = await app.bean.executor.performAction('get', '/training/student/:id', {
74
- params: { id: studentId },
75
- });
76
- let studentRecord = student.trainingRecords?.find(
77
- (item: any) => String(item.id) === String(recordId),
78
- );
79
- assert.equal(!!studentRecord, true);
80
- assert.equal(studentRecord?.trainingRecordSubjects?.length, 1);
114
+ let student: any = await app.bean.executor.performAction('get', '/training/student/:id', {
115
+ params: { id: studentId },
116
+ });
117
+ let studentRecord = student.trainingRecords?.find(
118
+ (item: any) => String(item.id) === String(recordId),
119
+ );
120
+ assert.equal(!!studentRecord, true);
121
+ assert.equal(studentRecord?.dossierFiles?.length, 1);
122
+ assert.equal(studentRecord?.trainingRecordSubjects?.length, 1);
81
123
 
82
- const dataUpdate = {
83
- studentId,
84
- name: '__RecordNew__',
85
- subjectCount: 2,
86
- totalScore: 183,
87
- averageScore: 91.5,
88
- trainingTime: trainingTimeUpdate,
89
- description: 'This is an updated record',
90
- trainingRecordSubjects: [
124
+ await fse.writeFile(dossierFilePathAssessment, dossierTextAssessment);
125
+ dossierFileAssessment = await app.bean.file.upload(
126
+ 'file-native:native',
91
127
  {
92
- id: recordSubject.id,
93
- name: '__MathNew__',
94
- score: 96,
95
- description: 'Updated math subject',
128
+ file: dossierFilePathAssessment,
129
+ filename: 'assessment.txt',
130
+ contentType: 'text/plain',
131
+ public: false,
132
+ meta: {
133
+ category: 'assessmentReport',
134
+ source: 'upload',
135
+ },
96
136
  },
97
137
  {
98
- name: '__English__',
99
- score: 87,
100
- description: 'English subject',
138
+ clientName: 'default',
139
+ fileScene: 'training-record:dossierFile',
101
140
  },
102
- ],
103
- } as any as DtoRecordUpdate;
104
- await app.bean.executor.performAction('patch', '/training/record/:id', {
105
- params: { id: recordId },
106
- body: dataUpdate,
107
- });
141
+ );
142
+ const dataUpdate = {
143
+ studentId,
144
+ name: '__RecordNew__',
145
+ subjectCount: 2,
146
+ totalScore: 183,
147
+ averageScore: 91.5,
148
+ trainingTime: trainingTimeUpdate,
149
+ dossierFileIds: [dossierFileAttendance.id, dossierFileAssessment.id],
150
+ description: 'This is an updated record',
151
+ trainingRecordSubjects: [
152
+ {
153
+ id: recordSubject.id,
154
+ name: '__MathNew__',
155
+ score: 96,
156
+ description: 'Updated math subject',
157
+ },
158
+ {
159
+ name: '__English__',
160
+ score: 87,
161
+ description: 'English subject',
162
+ },
163
+ ],
164
+ } as any as DtoRecordUpdate;
165
+ await app.bean.executor.performAction('patch', '/training/record/:id', {
166
+ params: { id: recordId },
167
+ body: dataUpdate,
168
+ });
108
169
 
109
- record = await app.bean.executor.performAction('get', '/training/record/:id', {
110
- params: { id: recordId },
111
- });
112
- const [updatedMathSubject, updatedEnglishSubject] = record.trainingRecordSubjects ?? [];
113
- assert.equal(record.name, dataUpdate.name);
114
- assert.equal(record.subjectCount, dataUpdate.subjectCount);
115
- assert.equal(record.totalScore, dataUpdate.totalScore);
116
- assert.equal(record.averageScore, dataUpdate.averageScore);
117
- assert.equal(new Date(record.trainingTime).toISOString(), trainingTimeUpdate.toISOString());
118
- assert.equal(record.trainingRecordSubjects?.length, 2);
119
- assert.equal(updatedMathSubject?.name, '__MathNew__');
120
- assert.equal(updatedMathSubject?.score, 96);
121
- assert.equal(updatedEnglishSubject?.name, '__English__');
122
- assert.equal(updatedEnglishSubject?.score, 87);
170
+ record = await app.bean.executor.performAction('get', '/training/record/:id', {
171
+ params: { id: recordId },
172
+ });
173
+ const [updatedMathSubject, updatedEnglishSubject] = record.trainingRecordSubjects ?? [];
174
+ assert.equal(record.name, dataUpdate.name);
175
+ assert.equal(record.subjectCount, dataUpdate.subjectCount);
176
+ assert.equal(record.totalScore, dataUpdate.totalScore);
177
+ assert.equal(record.averageScore, dataUpdate.averageScore);
178
+ assert.equal(new Date(record.trainingTime).toISOString(), trainingTimeUpdate.toISOString());
179
+ assert.equal(record.dossierFileIds?.length, 2);
180
+ assert.equal(record.dossierFiles?.length, 2);
181
+ assert.equal(
182
+ record.dossierFiles.some((item: any) => item.filename === 'attendance.txt'),
183
+ true,
184
+ );
185
+ assert.equal(
186
+ record.dossierFiles.some((item: any) => item.filename === 'assessment.txt'),
187
+ true,
188
+ );
189
+ assert.equal(record.trainingRecordSubjects?.length, 2);
190
+ assert.equal(updatedMathSubject?.name, '__MathNew__');
191
+ assert.equal(updatedMathSubject?.score, 96);
192
+ assert.equal(updatedEnglishSubject?.name, '__English__');
193
+ assert.equal(updatedEnglishSubject?.score, 87);
123
194
 
124
- student = await app.bean.executor.performAction('get', '/training/student/:id', {
125
- params: { id: studentId },
126
- });
127
- studentRecord = student.trainingRecords?.find(
128
- (item: any) => String(item.id) === String(recordId),
129
- );
130
- assert.equal(studentRecord?.name, dataUpdate.name);
131
- assert.equal(studentRecord?.trainingRecordSubjects?.length, 2);
195
+ student = await app.bean.executor.performAction('get', '/training/student/:id', {
196
+ params: { id: studentId },
197
+ });
198
+ studentRecord = student.trainingRecords?.find(
199
+ (item: any) => String(item.id) === String(recordId),
200
+ );
201
+ assert.equal(studentRecord?.name, dataUpdate.name);
202
+ assert.equal(studentRecord?.dossierFiles?.length, 2);
203
+ assert.equal(studentRecord?.trainingRecordSubjects?.length, 2);
132
204
 
133
- await app.bean.executor.performAction('delete', '/training/record/:id', {
134
- params: { id: recordId },
135
- });
205
+ await app.bean.executor.performAction('delete', '/training/record/:id', {
206
+ params: { id: recordId },
207
+ });
136
208
 
137
- record = await app.bean.executor.performAction('get', '/training/record/:id', {
138
- params: { id: recordId },
139
- });
140
- assert.equal(record, undefined);
209
+ record = await app.bean.executor.performAction('get', '/training/record/:id', {
210
+ params: { id: recordId },
211
+ });
212
+ assert.equal(record, undefined);
141
213
 
142
- student = await app.bean.executor.performAction('get', '/training/student/:id', {
143
- params: { id: studentId },
144
- });
145
- studentRecord = student.trainingRecords?.find(
146
- (item: any) => String(item.id) === String(recordId),
147
- );
148
- assert.equal(studentRecord, undefined);
214
+ student = await app.bean.executor.performAction('get', '/training/student/:id', {
215
+ params: { id: studentId },
216
+ });
217
+ studentRecord = student.trainingRecords?.find(
218
+ (item: any) => String(item.id) === String(recordId),
219
+ );
220
+ assert.equal(studentRecord, undefined);
149
221
 
150
- await app.bean.executor.performAction('delete', '/training/student/:id', {
151
- params: { id: studentId },
152
- });
222
+ const retainedDossierFileAttendance = await app.bean.file.get(dossierFileAttendance.id);
223
+ const retainedDossierFileAssessment = await app.bean.file.get(dossierFileAssessment.id);
224
+ assert.equal(!!retainedDossierFileAttendance, true);
225
+ assert.equal(!!retainedDossierFileAssessment, true);
153
226
 
154
- student = await app.bean.executor.performAction('get', '/training/student/:id', {
155
- params: { id: studentId },
156
- });
157
- assert.equal(student, undefined);
227
+ await app.bean.executor.performAction('delete', '/training/student/:id', {
228
+ params: { id: studentId },
229
+ });
158
230
 
159
- await app.bean.passport.signout();
231
+ student = await app.bean.executor.performAction('get', '/training/student/:id', {
232
+ params: { id: studentId },
233
+ });
234
+ assert.equal(student, undefined);
235
+ } finally {
236
+ if (dossierFileAssessment) {
237
+ await app.bean.file.delete(dossierFileAssessment.id);
238
+ }
239
+ if (dossierFileAttendance) {
240
+ await app.bean.file.delete(dossierFileAttendance.id);
241
+ }
242
+ await fse.remove(dossierFilePathAttendance);
243
+ await fse.remove(dossierFilePathAssessment);
244
+ await app.bean.passport.signout();
245
+ }
160
246
  });
161
247
  });
162
248
  });
@@ -9,6 +9,7 @@ export default {
9
9
  Student: 'Student',
10
10
  StudentName: 'Student Name',
11
11
  StudentImage: 'Student Image',
12
+ DossierFiles: 'Dossier Files',
12
13
  Summary: 'Summary',
13
14
  LevelTitle: 'Level Title',
14
15
  DescriptionLength: 'Description Length',
@@ -9,6 +9,7 @@ export default {
9
9
  Student: '学生',
10
10
  StudentName: '学生姓名',
11
11
  StudentImage: '学生图片',
12
+ DossierFiles: '培训档案附件',
12
13
  Summary: '摘要',
13
14
  LevelTitle: '阶段名称',
14
15
  DescriptionLength: '描述长度',