openxiangda 1.0.265 → 2.0.0-alpha.2

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 (537) hide show
  1. package/README.md +11 -675
  2. package/bin/run.js +11 -0
  3. package/dist/browser/AuthoritativeSelector.d.ts +37 -0
  4. package/dist/browser/AuthoritativeSelector.d.ts.map +1 -0
  5. package/dist/browser/AuthoritativeSelector.js +357 -0
  6. package/dist/browser/AuthoritativeSelector.js.map +1 -0
  7. package/dist/browser/FilePreviewPage.d.ts +2 -0
  8. package/dist/browser/FilePreviewPage.d.ts.map +1 -0
  9. package/dist/browser/FilePreviewPage.js +191 -0
  10. package/dist/browser/FilePreviewPage.js.map +1 -0
  11. package/dist/browser/Shell.d.ts +6 -0
  12. package/dist/browser/Shell.d.ts.map +1 -0
  13. package/dist/browser/Shell.js +198 -0
  14. package/dist/browser/Shell.js.map +1 -0
  15. package/dist/browser/appearance.d.ts +12 -0
  16. package/dist/browser/appearance.d.ts.map +1 -0
  17. package/dist/browser/appearance.js +100 -0
  18. package/dist/browser/appearance.js.map +1 -0
  19. package/dist/browser/application.d.ts +8 -0
  20. package/dist/browser/application.d.ts.map +1 -0
  21. package/dist/browser/application.js +42 -0
  22. package/dist/browser/application.js.map +1 -0
  23. package/dist/browser/components/platform-fields/AddressField.d.ts +12 -0
  24. package/dist/browser/components/platform-fields/AddressField.d.ts.map +1 -0
  25. package/dist/browser/components/platform-fields/AddressField.js +179 -0
  26. package/dist/browser/components/platform-fields/AddressField.js.map +1 -0
  27. package/dist/browser/components/platform-fields/AttachmentFileList.d.ts +9 -0
  28. package/dist/browser/components/platform-fields/AttachmentFileList.d.ts.map +1 -0
  29. package/dist/browser/components/platform-fields/AttachmentFileList.js +164 -0
  30. package/dist/browser/components/platform-fields/AttachmentFileList.js.map +1 -0
  31. package/dist/browser/components/platform-fields/CascadeField.d.ts +13 -0
  32. package/dist/browser/components/platform-fields/CascadeField.d.ts.map +1 -0
  33. package/dist/browser/components/platform-fields/CascadeField.js +14 -0
  34. package/dist/browser/components/platform-fields/CascadeField.js.map +1 -0
  35. package/dist/browser/components/platform-fields/DateTimeField.d.ts +16 -0
  36. package/dist/browser/components/platform-fields/DateTimeField.d.ts.map +1 -0
  37. package/dist/browser/components/platform-fields/DateTimeField.js +51 -0
  38. package/dist/browser/components/platform-fields/DateTimeField.js.map +1 -0
  39. package/dist/browser/components/platform-fields/JsonField.d.ts +11 -0
  40. package/dist/browser/components/platform-fields/JsonField.d.ts.map +1 -0
  41. package/dist/browser/components/platform-fields/JsonField.js +40 -0
  42. package/dist/browser/components/platform-fields/JsonField.js.map +1 -0
  43. package/dist/browser/components/platform-fields/LocationField.d.ts +11 -0
  44. package/dist/browser/components/platform-fields/LocationField.d.ts.map +1 -0
  45. package/dist/browser/components/platform-fields/LocationField.js +73 -0
  46. package/dist/browser/components/platform-fields/LocationField.js.map +1 -0
  47. package/dist/browser/components/platform-fields/PlatformDirectoryPicker.d.ts +12 -0
  48. package/dist/browser/components/platform-fields/PlatformDirectoryPicker.d.ts.map +1 -0
  49. package/dist/browser/components/platform-fields/PlatformDirectoryPicker.js +269 -0
  50. package/dist/browser/components/platform-fields/PlatformDirectoryPicker.js.map +1 -0
  51. package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts +12 -0
  52. package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts.map +1 -0
  53. package/dist/browser/components/platform-fields/ResourceReferenceField.js +22 -0
  54. package/dist/browser/components/platform-fields/ResourceReferenceField.js.map +1 -0
  55. package/dist/browser/components/platform-fields/RichTextField.d.ts +14 -0
  56. package/dist/browser/components/platform-fields/RichTextField.d.ts.map +1 -0
  57. package/dist/browser/components/platform-fields/RichTextField.js +214 -0
  58. package/dist/browser/components/platform-fields/RichTextField.js.map +1 -0
  59. package/dist/browser/components/platform-fields/SignatureField.d.ts +15 -0
  60. package/dist/browser/components/platform-fields/SignatureField.d.ts.map +1 -0
  61. package/dist/browser/components/platform-fields/SignatureField.js +179 -0
  62. package/dist/browser/components/platform-fields/SignatureField.js.map +1 -0
  63. package/dist/browser/components/platform-fields/SubtableField.d.ts +18 -0
  64. package/dist/browser/components/platform-fields/SubtableField.d.ts.map +1 -0
  65. package/dist/browser/components/platform-fields/SubtableField.js +236 -0
  66. package/dist/browser/components/platform-fields/SubtableField.js.map +1 -0
  67. package/dist/browser/components/platform-fields/address-value.d.ts +13 -0
  68. package/dist/browser/components/platform-fields/address-value.d.ts.map +1 -0
  69. package/dist/browser/components/platform-fields/address-value.js +70 -0
  70. package/dist/browser/components/platform-fields/address-value.js.map +1 -0
  71. package/dist/browser/components/platform-fields/cascade-value.d.ts +6 -0
  72. package/dist/browser/components/platform-fields/cascade-value.d.ts.map +1 -0
  73. package/dist/browser/components/platform-fields/cascade-value.js +47 -0
  74. package/dist/browser/components/platform-fields/cascade-value.js.map +1 -0
  75. package/dist/browser/components/platform-fields/directory-value.d.ts +7 -0
  76. package/dist/browser/components/platform-fields/directory-value.d.ts.map +1 -0
  77. package/dist/browser/components/platform-fields/directory-value.js +35 -0
  78. package/dist/browser/components/platform-fields/directory-value.js.map +1 -0
  79. package/dist/browser/components/platform-fields/field-form-codec.d.ts +10 -0
  80. package/dist/browser/components/platform-fields/field-form-codec.d.ts.map +1 -0
  81. package/dist/browser/components/platform-fields/field-form-codec.js +82 -0
  82. package/dist/browser/components/platform-fields/field-form-codec.js.map +1 -0
  83. package/dist/browser/components/platform-fields/location-value.d.ts +20 -0
  84. package/dist/browser/components/platform-fields/location-value.d.ts.map +1 -0
  85. package/dist/browser/components/platform-fields/location-value.js +57 -0
  86. package/dist/browser/components/platform-fields/location-value.js.map +1 -0
  87. package/dist/browser/components/platform-fields/resource-query.d.ts +14 -0
  88. package/dist/browser/components/platform-fields/resource-query.d.ts.map +1 -0
  89. package/dist/browser/components/platform-fields/resource-query.js +102 -0
  90. package/dist/browser/components/platform-fields/resource-query.js.map +1 -0
  91. package/dist/browser/components/platform-fields/rich-text-value.d.ts +12 -0
  92. package/dist/browser/components/platform-fields/rich-text-value.d.ts.map +1 -0
  93. package/dist/browser/components/platform-fields/rich-text-value.js +83 -0
  94. package/dist/browser/components/platform-fields/rich-text-value.js.map +1 -0
  95. package/dist/browser/components/platform-fields/subtable-value.d.ts +31 -0
  96. package/dist/browser/components/platform-fields/subtable-value.d.ts.map +1 -0
  97. package/dist/browser/components/platform-fields/subtable-value.js +120 -0
  98. package/dist/browser/components/platform-fields/subtable-value.js.map +1 -0
  99. package/dist/browser/components/resource/GeneratedResourceCrud.d.ts +8 -0
  100. package/dist/browser/components/resource/GeneratedResourceCrud.d.ts.map +1 -0
  101. package/dist/browser/components/resource/GeneratedResourceCrud.js +580 -0
  102. package/dist/browser/components/resource/GeneratedResourceCrud.js.map +1 -0
  103. package/dist/browser/components/resource/ResourceBatchActions.d.ts +25 -0
  104. package/dist/browser/components/resource/ResourceBatchActions.d.ts.map +1 -0
  105. package/dist/browser/components/resource/ResourceBatchActions.js +168 -0
  106. package/dist/browser/components/resource/ResourceBatchActions.js.map +1 -0
  107. package/dist/browser/components/resource/StandardResourcePages.d.ts +57 -0
  108. package/dist/browser/components/resource/StandardResourcePages.d.ts.map +1 -0
  109. package/dist/browser/components/resource/StandardResourcePages.js +89 -0
  110. package/dist/browser/components/resource/StandardResourcePages.js.map +1 -0
  111. package/dist/browser/components/resource/SurfaceFields.d.ts +88 -0
  112. package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -0
  113. package/dist/browser/components/resource/SurfaceFields.js +497 -0
  114. package/dist/browser/components/resource/SurfaceFields.js.map +1 -0
  115. package/dist/browser/components/resource/generated-resource-definition.d.ts +19 -0
  116. package/dist/browser/components/resource/generated-resource-definition.d.ts.map +1 -0
  117. package/dist/browser/components/resource/generated-resource-definition.js +2 -0
  118. package/dist/browser/components/resource/generated-resource-definition.js.map +1 -0
  119. package/dist/browser/components/resource/resource-import.d.ts +15 -0
  120. package/dist/browser/components/resource/resource-import.d.ts.map +1 -0
  121. package/dist/browser/components/resource/resource-import.js +197 -0
  122. package/dist/browser/components/resource/resource-import.js.map +1 -0
  123. package/dist/browser/data-provider.d.ts +4 -0
  124. package/dist/browser/data-provider.d.ts.map +1 -0
  125. package/dist/browser/data-provider.js +45 -0
  126. package/dist/browser/data-provider.js.map +1 -0
  127. package/dist/browser/platform-client.d.ts +81 -0
  128. package/dist/browser/platform-client.d.ts.map +1 -0
  129. package/dist/browser/platform-client.js +422 -0
  130. package/dist/browser/platform-client.js.map +1 -0
  131. package/dist/browser/resource-definitions.d.ts +8 -0
  132. package/dist/browser/resource-definitions.d.ts.map +1 -0
  133. package/dist/browser/resource-definitions.js +14 -0
  134. package/dist/browser/resource-definitions.js.map +1 -0
  135. package/dist/browser/runtime-meta.d.ts +22 -0
  136. package/dist/browser/runtime-meta.d.ts.map +1 -0
  137. package/dist/browser/runtime-meta.js +79 -0
  138. package/dist/browser/runtime-meta.js.map +1 -0
  139. package/dist/browser/runtime.d.ts +13 -0
  140. package/dist/browser/runtime.d.ts.map +1 -0
  141. package/dist/browser/runtime.js +47 -0
  142. package/dist/browser/runtime.js.map +1 -0
  143. package/dist/browser/styles.css +1941 -0
  144. package/dist/config.d.ts +2 -0
  145. package/dist/config.d.ts.map +1 -0
  146. package/dist/config.js +2 -0
  147. package/dist/config.js.map +1 -0
  148. package/dist/core.d.ts +6 -0
  149. package/dist/core.d.ts.map +1 -0
  150. package/dist/core.js +4 -0
  151. package/dist/core.js.map +1 -0
  152. package/dist/field-kit.d.ts +22 -0
  153. package/dist/field-kit.d.ts.map +1 -0
  154. package/dist/field-kit.js +22 -0
  155. package/dist/field-kit.js.map +1 -0
  156. package/dist/index.d.ts +2 -0
  157. package/dist/index.d.ts.map +1 -0
  158. package/dist/index.js +2 -0
  159. package/dist/index.js.map +1 -0
  160. package/dist/nest.d.ts +10 -0
  161. package/dist/nest.d.ts.map +1 -0
  162. package/dist/nest.js +9 -0
  163. package/dist/nest.js.map +1 -0
  164. package/dist/react.d.ts +12 -0
  165. package/dist/react.d.ts.map +1 -0
  166. package/dist/react.js +11 -0
  167. package/dist/react.js.map +1 -0
  168. package/dist/testing.d.ts +4 -0
  169. package/dist/testing.d.ts.map +1 -0
  170. package/dist/testing.js +4 -0
  171. package/dist/testing.js.map +1 -0
  172. package/package.json +95 -200
  173. package/skills/manifest.json +10 -0
  174. package/skills/openxiangda-v2/SKILL.md +55 -0
  175. package/skills/openxiangda-v2/references/architecture.md +7 -0
  176. package/skills/openxiangda-v2/references/backend.md +116 -0
  177. package/skills/openxiangda-v2/references/data-authz.md +93 -0
  178. package/skills/openxiangda-v2/references/delivery.md +11 -0
  179. package/skills/openxiangda-v2/references/discovery.md +15 -0
  180. package/skills/openxiangda-v2/references/frontend.md +10 -0
  181. package/skills/openxiangda-v2/references/testing.md +16 -0
  182. package/skills/openxiangda-v2/references/workflow-notification.md +69 -0
  183. package/skills/openxiangda-v2/references/workspace.md +21 -0
  184. package/bin/openxiangda.js +0 -26
  185. package/lib/app-function-invoke.js +0 -28
  186. package/lib/application-environments.js +0 -1134
  187. package/lib/change-baseline.js +0 -1359
  188. package/lib/cli.js +0 -31084
  189. package/lib/config.js +0 -450
  190. package/lib/content-cache.js +0 -97
  191. package/lib/delivery-v2-cli.js +0 -329
  192. package/lib/delivery-v2-executor.js +0 -1703
  193. package/lib/delivery-v2-package.js +0 -1176
  194. package/lib/dependency-capsule.js +0 -246
  195. package/lib/design-gates.js +0 -668
  196. package/lib/design-review.js +0 -220
  197. package/lib/developer-center.js +0 -160
  198. package/lib/form-field-contract.js +0 -79
  199. package/lib/form-schema-loader.js +0 -181
  200. package/lib/git-remote-identity.js +0 -89
  201. package/lib/http.js +0 -196
  202. package/lib/integration-bundle.js +0 -225
  203. package/lib/js-code-build.js +0 -175
  204. package/lib/open-api.js +0 -256
  205. package/lib/policy.js +0 -137
  206. package/lib/publish-context.js +0 -98
  207. package/lib/publish-lease-heartbeat.js +0 -182
  208. package/lib/publish-lease.js +0 -221
  209. package/lib/release-error-classification.js +0 -41
  210. package/lib/release-explain.js +0 -75
  211. package/lib/release-mainline.js +0 -654
  212. package/lib/release-plan.js +0 -550
  213. package/lib/release-telemetry.js +0 -182
  214. package/lib/resource-binding-contract.js +0 -210
  215. package/lib/role-resolution.js +0 -57
  216. package/lib/runtime-lineage.js +0 -326
  217. package/lib/sdd.js +0 -3306
  218. package/lib/skills.js +0 -453
  219. package/lib/source-dependencies.js +0 -921
  220. package/lib/task-status.js +0 -330
  221. package/lib/utils.js +0 -178
  222. package/lib/workspace-bootstrap.js +0 -268
  223. package/lib/workspace-init.js +0 -202
  224. package/lib/worktree-cleanup.js +0 -631
  225. package/lib/worktree-owner.js +0 -354
  226. package/openxiangda-skills/SKILL.md +0 -229
  227. package/openxiangda-skills/references/architecture-design.md +0 -409
  228. package/openxiangda-skills/references/architecture-patterns.md +0 -264
  229. package/openxiangda-skills/references/automation-v3.md +0 -349
  230. package/openxiangda-skills/references/best-practices.md +0 -272
  231. package/openxiangda-skills/references/component-guide.md +0 -287
  232. package/openxiangda-skills/references/connector-resources.md +0 -80
  233. package/openxiangda-skills/references/data-views.md +0 -360
  234. package/openxiangda-skills/references/forms/component-registry.md +0 -90
  235. package/openxiangda-skills/references/forms/form-schema.md +0 -146
  236. package/openxiangda-skills/references/forms/layout-and-rules.md +0 -24
  237. package/openxiangda-skills/references/notifications.md +0 -227
  238. package/openxiangda-skills/references/openxiangda-api.md +0 -971
  239. package/openxiangda-skills/references/pages/app-shell.md +0 -66
  240. package/openxiangda-skills/references/pages/page-sdk.md +0 -401
  241. package/openxiangda-skills/references/pages/publish-flow.md +0 -84
  242. package/openxiangda-skills/references/pages/workspace-structure.md +0 -41
  243. package/openxiangda-skills/references/permission-design-patterns.md +0 -313
  244. package/openxiangda-skills/references/permissions-settings.md +0 -468
  245. package/openxiangda-skills/references/platform-data-model.md +0 -340
  246. package/openxiangda-skills/references/resource-manifest-cheatsheet.md +0 -936
  247. package/openxiangda-skills/references/school-contact-relations.md +0 -242
  248. package/openxiangda-skills/references/style-system.md +0 -218
  249. package/openxiangda-skills/references/troubleshooting.md +0 -271
  250. package/openxiangda-skills/references/workflow-v3.md +0 -441
  251. package/openxiangda-skills/references/workspace-state.md +0 -115
  252. package/openxiangda-skills/skills/openxiangda-app/SKILL.md +0 -118
  253. package/openxiangda-skills/skills/openxiangda-architecture-design/SKILL.md +0 -137
  254. package/openxiangda-skills/skills/openxiangda-core/SKILL.md +0 -222
  255. package/openxiangda-skills/skills/openxiangda-form/SKILL.md +0 -184
  256. package/openxiangda-skills/skills/openxiangda-inspect/SKILL.md +0 -63
  257. package/openxiangda-skills/skills/openxiangda-open-api/SKILL.md +0 -57
  258. package/openxiangda-skills/skills/openxiangda-open-api/agents/openai.yaml +0 -4
  259. package/openxiangda-skills/skills/openxiangda-open-api/references/backend-authentication.md +0 -63
  260. package/openxiangda-skills/skills/openxiangda-open-api/references/dingtalk-api.openapi.json +0 -15653
  261. package/openxiangda-skills/skills/openxiangda-page/SKILL.md +0 -154
  262. package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +0 -209
  263. package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +0 -201
  264. package/packages/sdk/bin/lowcode-workspace.mjs +0 -4
  265. package/packages/sdk/dist/ProcessPreview-DSUIJi5V.d.mts +0 -1292
  266. package/packages/sdk/dist/ProcessPreview-DSUIJi5V.d.ts +0 -1292
  267. package/packages/sdk/dist/build/index.cjs +0 -1
  268. package/packages/sdk/dist/build/index.d.mts +0 -60
  269. package/packages/sdk/dist/build/index.d.ts +0 -60
  270. package/packages/sdk/dist/build/index.mjs +0 -1
  271. package/packages/sdk/dist/components/index.cjs +0 -148
  272. package/packages/sdk/dist/components/index.d.mts +0 -970
  273. package/packages/sdk/dist/components/index.d.ts +0 -970
  274. package/packages/sdk/dist/components/index.mjs +0 -148
  275. package/packages/sdk/dist/dataManagementApi-Ro9itwm8.d.ts +0 -142
  276. package/packages/sdk/dist/dataManagementApi-p_HOhQnA.d.mts +0 -142
  277. package/packages/sdk/dist/runtime/index.cjs +0 -148
  278. package/packages/sdk/dist/runtime/index.d.mts +0 -171
  279. package/packages/sdk/dist/runtime/index.d.ts +0 -171
  280. package/packages/sdk/dist/runtime/index.mjs +0 -148
  281. package/packages/sdk/dist/runtime/react.cjs +0 -148
  282. package/packages/sdk/dist/runtime/react.d.mts +0 -3209
  283. package/packages/sdk/dist/runtime/react.d.ts +0 -3209
  284. package/packages/sdk/dist/runtime/react.mjs +0 -148
  285. package/packages/sdk/dist/styles/antd-theme.cjs +0 -1
  286. package/packages/sdk/dist/styles/antd-theme.d.mts +0 -6
  287. package/packages/sdk/dist/styles/antd-theme.d.ts +0 -6
  288. package/packages/sdk/dist/styles/antd-theme.mjs +0 -1
  289. package/packages/sdk/dist/styles/tailwind-preset.cjs +0 -1
  290. package/packages/sdk/dist/styles/tailwind-preset.d.mts +0 -74
  291. package/packages/sdk/dist/styles/tailwind-preset.d.ts +0 -74
  292. package/packages/sdk/dist/styles/tailwind-preset.mjs +0 -1
  293. package/packages/sdk/dist/styles/tokens.css +0 -74
  294. package/packages/sdk/dist/workflow/index.cjs +0 -3
  295. package/packages/sdk/dist/workflow/index.d.mts +0 -291
  296. package/packages/sdk/dist/workflow/index.d.ts +0 -291
  297. package/packages/sdk/dist/workflow/index.mjs +0 -3
  298. package/packages/sdk/source/admin-list/AdminList.tsx +0 -1734
  299. package/packages/sdk/source/admin-list/README.md +0 -12
  300. package/packages/sdk/source/admin-list/dataSources.ts +0 -345
  301. package/packages/sdk/source/admin-list/index.ts +0 -42
  302. package/packages/sdk/source/admin-list/preferences.ts +0 -174
  303. package/packages/sdk/source/admin-list/types.ts +0 -273
  304. package/packages/sdk/src/build-source/README.md +0 -9
  305. package/packages/sdk/src/build-source/bin/lowcode-workspace.mjs +0 -7
  306. package/packages/sdk/src/build-source/package.json +0 -34
  307. package/packages/sdk/src/build-source/scripts/build-forms.mjs +0 -1129
  308. package/packages/sdk/src/build-source/scripts/build-pages.mjs +0 -897
  309. package/packages/sdk/src/build-source/scripts/build-workspace.mjs +0 -89
  310. package/packages/sdk/src/build-source/scripts/publish-all.mjs +0 -190
  311. package/packages/sdk/src/build-source/scripts/publish-oss.mjs +0 -144
  312. package/packages/sdk/src/build-source/scripts/register-bundle.mjs +0 -1
  313. package/packages/sdk/src/build-source/scripts/register.mjs +0 -362
  314. package/packages/sdk/src/build-source/scripts/sync-schema.mjs +0 -381
  315. package/packages/sdk/src/build-source/scripts/utils/form-api.mjs +0 -1058
  316. package/packages/sdk/src/build-source/scripts/utils/form-runtime-assets.mjs +0 -57
  317. package/packages/sdk/src/build-source/scripts/utils/incremental.mjs +0 -348
  318. package/packages/sdk/src/build-source/scripts/utils/load-config.mjs +0 -331
  319. package/packages/sdk/src/build-source/scripts/utils/mime-types.mjs +0 -70
  320. package/packages/sdk/src/build-source/scripts/utils/namespace-css.mjs +0 -77
  321. package/packages/sdk/src/build-source/scripts/utils/oss-client.mjs +0 -128
  322. package/packages/sdk/src/build-source/scripts/utils/pages.mjs +0 -150
  323. package/packages/sdk/src/build-source/scripts/utils/progress.mjs +0 -57
  324. package/packages/sdk/src/build-source/scripts/utils/publish-oss-patterns.mjs +0 -20
  325. package/packages/sdk/src/build-source/scripts/utils/register-payload.mjs +0 -90
  326. package/packages/sdk/src/build-source/scripts/utils/runtime-css-check.mjs +0 -44
  327. package/packages/sdk/src/build-source/scripts/utils/schema-transform.mjs +0 -142
  328. package/packages/sdk/src/build-source/scripts/utils/static-assets.mjs +0 -165
  329. package/packages/sdk/src/build-source/scripts/utils/tailwind-config.mjs +0 -283
  330. package/packages/sdk/src/build-source/scripts/utils/tailwind-token-warnings.mjs +0 -146
  331. package/packages/sdk/src/build-source/scripts/utils/workspace-style-entry.mjs +0 -29
  332. package/packages/sdk/src/build-source/src/cli.mjs +0 -735
  333. package/policy/openxiangda-policy.json +0 -72
  334. package/templates/openxiangda-react-spa/.cursor/rules/openxiangda-form.mdc +0 -24
  335. package/templates/openxiangda-react-spa/.cursor/rules/openxiangda-page.mdc +0 -25
  336. package/templates/openxiangda-react-spa/.cursor/rules/openxiangda-resources.mdc +0 -32
  337. package/templates/openxiangda-react-spa/.cursor/rules/openxiangda-workflow-automation.mdc +0 -26
  338. package/templates/openxiangda-react-spa/.cursor/rules/openxiangda.mdc +0 -68
  339. package/templates/openxiangda-react-spa/.env.example +0 -4
  340. package/templates/openxiangda-react-spa/.qoder/rules/openxiangda-form.md +0 -37
  341. package/templates/openxiangda-react-spa/.qoder/rules/openxiangda-page.md +0 -29
  342. package/templates/openxiangda-react-spa/.qoder/rules/openxiangda-resources.md +0 -32
  343. package/templates/openxiangda-react-spa/.qoder/rules/openxiangda-workflow-automation.md +0 -34
  344. package/templates/openxiangda-react-spa/.qoder/rules/openxiangda.md +0 -66
  345. package/templates/openxiangda-react-spa/AGENTS.md +0 -197
  346. package/templates/openxiangda-react-spa/DELIVERY.md +0 -43
  347. package/templates/openxiangda-react-spa/app-workspace.config.ts +0 -50
  348. package/templates/openxiangda-react-spa/index.html +0 -12
  349. package/templates/openxiangda-react-spa/package.json +0 -53
  350. package/templates/openxiangda-react-spa/postcss.config.cjs +0 -6
  351. package/templates/openxiangda-react-spa/scripts/build-js-code.mjs +0 -600
  352. package/templates/openxiangda-react-spa/scripts/deploy.mjs +0 -18
  353. package/templates/openxiangda-react-spa/scripts/guard-publish.mjs +0 -21
  354. package/templates/openxiangda-react-spa/src/app/navigation.ts +0 -73
  355. package/templates/openxiangda-react-spa/src/app/router.tsx +0 -146
  356. package/templates/openxiangda-react-spa/src/app/starter-content.ts +0 -144
  357. package/templates/openxiangda-react-spa/src/forms/.gitkeep +0 -1
  358. package/templates/openxiangda-react-spa/src/layouts/AdminShell.tsx +0 -570
  359. package/templates/openxiangda-react-spa/src/main.tsx +0 -21
  360. package/templates/openxiangda-react-spa/src/pages/admin/AdminDashboardPage.tsx +0 -170
  361. package/templates/openxiangda-react-spa/src/pages/admin/LoginLogPage.tsx +0 -425
  362. package/templates/openxiangda-react-spa/src/pages/defaults/DataRoutePage.tsx +0 -36
  363. package/templates/openxiangda-react-spa/src/pages/defaults/FilePreviewRoutePage.tsx +0 -65
  364. package/templates/openxiangda-react-spa/src/pages/defaults/FormRoutePage.tsx +0 -235
  365. package/templates/openxiangda-react-spa/src/pages/public/PublicRegisterPage.tsx +0 -15
  366. package/templates/openxiangda-react-spa/src/pages/states/NotFoundPage.tsx +0 -31
  367. package/templates/openxiangda-react-spa/src/resources/menus/menus.json +0 -22
  368. package/templates/openxiangda-react-spa/src/resources/permissions/page-groups/app-admin.json +0 -8
  369. package/templates/openxiangda-react-spa/src/resources/permissions/page-groups/public-visitor.json +0 -8
  370. package/templates/openxiangda-react-spa/src/resources/public-access/public-register.json +0 -14
  371. package/templates/openxiangda-react-spa/src/resources/roles/roles.json +0 -15
  372. package/templates/openxiangda-react-spa/src/resources/routes/public-register.json +0 -8
  373. package/templates/openxiangda-react-spa/src/runtime/default-page-overrides.tsx +0 -35
  374. package/templates/openxiangda-react-spa/src/runtime/default-routes.ts +0 -16
  375. package/templates/openxiangda-react-spa/src/shared/form-schema.ts +0 -135
  376. package/templates/openxiangda-react-spa/src/shared/mac-admin.tsx +0 -651
  377. package/templates/openxiangda-react-spa/src/shared/ui.tsx +0 -22
  378. package/templates/openxiangda-react-spa/src/styles/index.css +0 -105
  379. package/templates/openxiangda-react-spa/tailwind.config.cjs +0 -37
  380. package/templates/openxiangda-react-spa/tsconfig.app.json +0 -36
  381. package/templates/openxiangda-react-spa/tsconfig.js-code-nodes.json +0 -19
  382. package/templates/openxiangda-react-spa/tsconfig.json +0 -7
  383. package/templates/openxiangda-react-spa/tsconfig.node.json +0 -10
  384. package/templates/openxiangda-react-spa/vite.config.ts +0 -209
  385. package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-form.mdc +0 -24
  386. package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-page.mdc +0 -21
  387. package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-resources.mdc +0 -40
  388. package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-workflow-automation.mdc +0 -21
  389. package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda.mdc +0 -81
  390. package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-form.md +0 -38
  391. package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-page.md +0 -39
  392. package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-resources.md +0 -59
  393. package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-workflow-automation.md +0 -46
  394. package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda.md +0 -82
  395. package/templates/sy-lowcode-app-workspace/AGENTS.md +0 -159
  396. package/templates/sy-lowcode-app-workspace/DELIVERY.md +0 -43
  397. package/templates/sy-lowcode-app-workspace/app-workspace.config.ts +0 -51
  398. package/templates/sy-lowcode-app-workspace/examples/best-practices/README.md +0 -43
  399. package/templates/sy-lowcode-app-workspace/examples/best-practices/access-governance.md +0 -239
  400. package/templates/sy-lowcode-app-workspace/examples/best-practices/catalog.json +0 -99
  401. package/templates/sy-lowcode-app-workspace/examples/best-practices/decision-guide.md +0 -94
  402. package/templates/sy-lowcode-app-workspace/examples/best-practices/design-style.md +0 -91
  403. package/templates/sy-lowcode-app-workspace/examples/best-practices/module-structure.md +0 -48
  404. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/index.ts +0 -2
  405. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/permissions.test.ts +0 -52
  406. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/permissions.ts +0 -37
  407. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/types.ts +0 -19
  408. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/index.ts +0 -4
  409. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/permissions.test.ts +0 -42
  410. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/permissions.ts +0 -25
  411. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/state-machine.test.ts +0 -63
  412. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/state-machine.ts +0 -73
  413. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/ticket-query.test.ts +0 -34
  414. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/ticket-query.ts +0 -73
  415. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/types.ts +0 -66
  416. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/app-role/page.tsx +0 -1
  417. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/app-role/schema.ts +0 -109
  418. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/customer-profile/page.tsx +0 -1
  419. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/customer-profile/schema.ts +0 -92
  420. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/service-ticket/page.tsx +0 -1
  421. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/service-ticket/schema.ts +0 -153
  422. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/ticket-action-log/page.tsx +0 -1
  423. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/ticket-action-log/schema.ts +0 -65
  424. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/js-code-nodes/daily_ticket_digest/index.ts +0 -44
  425. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/js-code-nodes/sync_roles_to_platform/index.ts +0 -33
  426. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/glass-home-dashboard/App.tsx +0 -8
  427. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/glass-home-dashboard/GlassHomeDashboard.tsx +0 -232
  428. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/glass-home-dashboard/index.tsx +0 -10
  429. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/glass-home-dashboard/page.config.ts +0 -14
  430. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/glass-home-dashboard/styles.css +0 -196
  431. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/App.tsx +0 -7
  432. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/WorkbenchPage.tsx +0 -36
  433. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/components/ConfigPanel.tsx +0 -34
  434. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/components/PreviewPanel.tsx +0 -17
  435. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/index.tsx +0 -10
  436. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/page.config.ts +0 -9
  437. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/reducer.ts +0 -29
  438. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/styles.css +0 -24
  439. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mint-analytics-dashboard/App.tsx +0 -8
  440. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mint-analytics-dashboard/MintAnalyticsDashboard.tsx +0 -279
  441. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mint-analytics-dashboard/index.tsx +0 -10
  442. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mint-analytics-dashboard/page.config.ts +0 -14
  443. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mint-analytics-dashboard/styles.css +0 -163
  444. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/App.tsx +0 -7
  445. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/MobilePortalShell.tsx +0 -31
  446. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/index.tsx +0 -10
  447. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/modules/MobileHome.tsx +0 -13
  448. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/page.config.ts +0 -14
  449. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/routes.ts +0 -13
  450. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/styles.css +0 -11
  451. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/ops-monitor-dashboard/App.tsx +0 -8
  452. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/ops-monitor-dashboard/OpsMonitorDashboard.tsx +0 -306
  453. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/ops-monitor-dashboard/index.tsx +0 -10
  454. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/ops-monitor-dashboard/page.config.ts +0 -14
  455. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/ops-monitor-dashboard/styles.css +0 -248
  456. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/App.tsx +0 -7
  457. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/PcPortalShell.tsx +0 -35
  458. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/components/PortalMetric.tsx +0 -11
  459. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/index.tsx +0 -10
  460. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/modules/HomeModule.tsx +0 -25
  461. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/modules/TicketsModule.tsx +0 -14
  462. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/page.config.ts +0 -14
  463. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/routes.ts +0 -19
  464. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/styles.css +0 -35
  465. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/App.tsx +0 -7
  466. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/TicketOpsPage.tsx +0 -105
  467. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketActionTimeline.tsx +0 -22
  468. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketDetailDrawer.tsx +0 -44
  469. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketTableActions.tsx +0 -57
  470. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/index.tsx +0 -10
  471. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/page.config.ts +0 -9
  472. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/styles.css +0 -35
  473. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/work-order-list-drawer/App.tsx +0 -8
  474. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/work-order-list-drawer/WorkOrderListDrawerPage.tsx +0 -371
  475. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/work-order-list-drawer/index.tsx +0 -10
  476. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/work-order-list-drawer/page.config.ts +0 -14
  477. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/work-order-list-drawer/styles.css +0 -182
  478. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/automations/daily-ticket-digest/automation.json +0 -25
  479. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/automations/daily-ticket-digest/trigger.json +0 -9
  480. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/notifications/daily-ticket-digest.json +0 -24
  481. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/permissions/form-groups/service-ticket-college.json +0 -21
  482. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/permissions/roles.json +0 -17
  483. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/workflows/expense-approval-workflow.json +0 -48
  484. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/ConfirmAction.tsx +0 -22
  485. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/QueryState.tsx +0 -37
  486. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/StatusTag.tsx +0 -20
  487. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/admin-ui-templates/DashboardPrimitives.tsx +0 -832
  488. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/admin-ui-templates/chartOptions.ts +0 -140
  489. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/admin-ui-templates/sampleData.ts +0 -466
  490. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/admin-ui-templates/styles.css +0 -874
  491. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/admin-ui-templates/types.ts +0 -150
  492. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/hooks/useTicketOps.ts +0 -96
  493. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/services/role-governance.ts +0 -48
  494. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/services/service-ticket.ts +0 -113
  495. package/templates/sy-lowcode-app-workspace/examples/forms/customer/page.tsx +0 -1
  496. package/templates/sy-lowcode-app-workspace/examples/forms/customer/schema.ts +0 -36
  497. package/templates/sy-lowcode-app-workspace/index.html +0 -12
  498. package/templates/sy-lowcode-app-workspace/package.json +0 -58
  499. package/templates/sy-lowcode-app-workspace/postcss.config.cjs +0 -9
  500. package/templates/sy-lowcode-app-workspace/scripts/build-js-code.mjs +0 -600
  501. package/templates/sy-lowcode-app-workspace/scripts/guard-publish.mjs +0 -29
  502. package/templates/sy-lowcode-app-workspace/src/dev/App.tsx +0 -820
  503. package/templates/sy-lowcode-app-workspace/src/forms/.gitkeep +0 -1
  504. package/templates/sy-lowcode-app-workspace/src/forms/README.md +0 -52
  505. package/templates/sy-lowcode-app-workspace/src/index.css +0 -26
  506. package/templates/sy-lowcode-app-workspace/src/js-code-nodes/.gitkeep +0 -1
  507. package/templates/sy-lowcode-app-workspace/src/js-code-nodes/types.d.ts +0 -3
  508. package/templates/sy-lowcode-app-workspace/src/main.tsx +0 -29
  509. package/templates/sy-lowcode-app-workspace/src/pages/.gitkeep +0 -1
  510. package/templates/sy-lowcode-app-workspace/src/runtime/builtin-overrides.tsx +0 -8
  511. package/templates/sy-lowcode-app-workspace/src/shared/form-schema.ts +0 -135
  512. package/templates/sy-lowcode-app-workspace/src/types/app-workspace.types.ts +0 -88
  513. package/templates/sy-lowcode-app-workspace/tailwind.config.cjs +0 -31
  514. package/templates/sy-lowcode-app-workspace/tsconfig.app.json +0 -40
  515. package/templates/sy-lowcode-app-workspace/tsconfig.examples.json +0 -24
  516. package/templates/sy-lowcode-app-workspace/tsconfig.js-code-nodes.json +0 -19
  517. package/templates/sy-lowcode-app-workspace/tsconfig.json +0 -7
  518. package/templates/sy-lowcode-app-workspace/tsconfig.node.json +0 -10
  519. package/templates/sy-lowcode-app-workspace/vite.config.ts +0 -85
  520. package/v2/README.md +0 -35
  521. package/v2/skills/manifest.json +0 -45
  522. package/v2/skills/openxiangda-v1-maintenance/SKILL.md +0 -21
  523. package/v2/skills/openxiangda-v1-maintenance/agents/openai.yaml +0 -4
  524. package/v2/skills/openxiangda-v2/SKILL.md +0 -38
  525. package/v2/skills/openxiangda-v2-architecture/SKILL.md +0 -29
  526. package/v2/skills/openxiangda-v2-architecture/agents/openai.yaml +0 -4
  527. package/v2/skills/openxiangda-v2-backend/SKILL.md +0 -28
  528. package/v2/skills/openxiangda-v2-backend/agents/openai.yaml +0 -4
  529. package/v2/skills/openxiangda-v2-data-authz/SKILL.md +0 -28
  530. package/v2/skills/openxiangda-v2-data-authz/agents/openai.yaml +0 -4
  531. package/v2/skills/openxiangda-v2-delivery/SKILL.md +0 -30
  532. package/v2/skills/openxiangda-v2-delivery/agents/openai.yaml +0 -4
  533. package/v2/skills/openxiangda-v2-frontend/SKILL.md +0 -21
  534. package/v2/skills/openxiangda-v2-frontend/agents/openai.yaml +0 -4
  535. package/v2/skills/openxiangda-v2-workflow-events/SKILL.md +0 -28
  536. package/v2/skills/openxiangda-v2-workflow-events/agents/openai.yaml +0 -4
  537. /package/{v2/skills → skills}/openxiangda-v2/agents/openai.yaml +0 -0
@@ -1,1734 +0,0 @@
1
- // Complete ejectable AdminList source. Generated by npm run source:admin-list.
2
- // After copying this directory into an application it is fully application-owned.
3
- import {
4
- Alert,
5
- Button,
6
- Checkbox,
7
- DatePicker,
8
- Drawer,
9
- Dropdown,
10
- Empty,
11
- Form,
12
- Input,
13
- InputNumber,
14
- Modal,
15
- Result,
16
- Segmented,
17
- Select,
18
- Space,
19
- Switch,
20
- Table,
21
- Tabs,
22
- Tag,
23
- message,
24
- notification,
25
- } from "antd"
26
- import {
27
- DeleteOutlined,
28
- DownOutlined,
29
- DownloadOutlined,
30
- HolderOutlined,
31
- PlusOutlined,
32
- ReloadOutlined,
33
- SettingOutlined,
34
- UpOutlined,
35
- } from "@ant-design/icons"
36
- import type {
37
- MenuProps,
38
- TablePaginationConfig,
39
- TableProps,
40
- } from "antd"
41
- import type { Key, ReactNode } from "react"
42
- import {
43
- useCallback,
44
- useEffect,
45
- useMemo,
46
- useRef,
47
- useState,
48
- } from "react"
49
-
50
- import { mergeAdminListPreference } from "./preferences"
51
- import type {
52
- AdminListColumn,
53
- AdminListColumnPreference,
54
- AdminListExportInput,
55
- AdminListExportTask,
56
- AdminListPreference,
57
- AdminListProps,
58
- AdminListQuery,
59
- AdminListResult,
60
- AdminListSearchField,
61
- AdminListSort,
62
- } from "./types"
63
-
64
- const { RangePicker } = DatePicker
65
-
66
- const isEmpty = (value: unknown) =>
67
- value === undefined ||
68
- value === null ||
69
- value === "" ||
70
- (Array.isArray(value) && value.length === 0)
71
-
72
- const normalizeFilterValue = (value: unknown): unknown => {
73
- if (Array.isArray(value)) {
74
- return value.map(normalizeFilterValue)
75
- }
76
- if (
77
- value &&
78
- typeof value === "object" &&
79
- "format" in value &&
80
- typeof value.format === "function"
81
- ) {
82
- return value.format("YYYY-MM-DD")
83
- }
84
- return value
85
- }
86
-
87
- const normalizeFilters = (values: Record<string, unknown>) =>
88
- Object.fromEntries(
89
- Object.entries(values)
90
- .filter(([, value]) => !isEmpty(value))
91
- .map(([key, value]) => [key, normalizeFilterValue(value)]),
92
- )
93
-
94
- const sortFingerprint = (sorts: AdminListSort[]) =>
95
- sorts.map((sort) => `${sort.field}:${sort.direction}`).join("|")
96
-
97
- const queryFingerprint = (query: AdminListQuery, sourceKey: string) =>
98
- JSON.stringify({
99
- sourceKey,
100
- filters: query.filters,
101
- fixedFilters: query.fixedFilters,
102
- sorts: query.sorts,
103
- })
104
-
105
- const positiveInteger = (value: unknown, fallback: number) => {
106
- const numberValue = Number(value)
107
- return Number.isFinite(numberValue) && numberValue > 0
108
- ? Math.floor(numberValue)
109
- : fallback
110
- }
111
-
112
- const reconcileResultTotal = <Row,>(
113
- result: AdminListResult<Row>,
114
- query: AdminListQuery,
115
- rows: Row[],
116
- ) => {
117
- const reportedTotal = Number(result.total)
118
- const normalizedReportedTotal = Number.isFinite(reportedTotal)
119
- ? Math.max(0, reportedTotal)
120
- : 0
121
- if (!rows.length) return normalizedReportedTotal
122
-
123
- const currentPage = positiveInteger(result.currentPage, query.currentPage)
124
- const pageSize = positiveInteger(result.pageSize, query.pageSize)
125
- const visibleRowsLowerBound = (currentPage - 1) * pageSize + rows.length
126
- return Math.max(normalizedReportedTotal, visibleRowsLowerBound)
127
- }
128
-
129
- const getRowKey = <Row,>(
130
- rowKey: AdminListProps<Row>["rowKey"],
131
- row: Row,
132
- ): Key => {
133
- if (typeof rowKey === "function") return rowKey(row)
134
- return (row as Record<string, unknown>)[rowKey] as Key
135
- }
136
-
137
- const getDataValue = (row: unknown, dataIndex?: string | string[]) => {
138
- const path = Array.isArray(dataIndex)
139
- ? dataIndex
140
- : typeof dataIndex === "string"
141
- ? dataIndex.split(".")
142
- : []
143
- return path.reduce<unknown>((value, key) => {
144
- if (!value || typeof value !== "object") return undefined
145
- return (value as Record<string, unknown>)[key]
146
- }, row)
147
- }
148
-
149
- const toColumnPreferences = <Row,>(
150
- columns: AdminListColumn<Row>[],
151
- ): AdminListColumnPreference[] =>
152
- columns.map((column) => ({
153
- key: column.key,
154
- visible: column.defaultVisible ?? !column.hidden,
155
- width: column.width,
156
- fixed: column.fixed || null,
157
- }))
158
-
159
- function renderSearchControl(field: AdminListSearchField) {
160
- const placeholder =
161
- field.placeholder ||
162
- (field.type === "select" || field.type === "multiSelect"
163
- ? `请选择${String(field.label)}`
164
- : `请输入${String(field.label)}`)
165
- if (field.type === "select" || field.type === "multiSelect") {
166
- return (
167
- <Select
168
- allowClear
169
- disabled={field.disabled}
170
- mode={field.type === "multiSelect" ? "multiple" : undefined}
171
- options={field.options}
172
- placeholder={placeholder}
173
- showSearch={{ optionFilterProp: "label" }}
174
- />
175
- )
176
- }
177
- if (field.type === "number") {
178
- return (
179
- <InputNumber
180
- disabled={field.disabled}
181
- placeholder={placeholder}
182
- style={{ width: "100%" }}
183
- />
184
- )
185
- }
186
- if (field.type === "date") {
187
- return (
188
- <DatePicker
189
- disabled={field.disabled}
190
- placeholder={placeholder}
191
- style={{ width: "100%" }}
192
- />
193
- )
194
- }
195
- if (field.type === "dateRange") {
196
- return (
197
- <RangePicker
198
- disabled={field.disabled}
199
- style={{ width: "100%" }}
200
- />
201
- )
202
- }
203
- return (
204
- <Input
205
- allowClear
206
- disabled={field.disabled}
207
- placeholder={placeholder}
208
- />
209
- )
210
- }
211
-
212
- export function AdminList<Row>(props: AdminListProps<Row>) {
213
- const {
214
- batchActions = [],
215
- className,
216
- columns,
217
- configVersion = 1,
218
- dataSource,
219
- defaultPageSize = 20,
220
- defaultSorts = [],
221
- defaultVisibleSearchCount = 4,
222
- emptyText,
223
- exportable = true,
224
- fileName,
225
- fixedFilters,
226
- listKey,
227
- lockedPreference,
228
- onQueryChange,
229
- onRow,
230
- onSelectionChange,
231
- pageSizeOptions = [20, 50, 100],
232
- preserveSelectionAcrossPages = true,
233
- rowActions = [],
234
- rowKey,
235
- rowSelectable,
236
- rowSelectionReason,
237
- searchFields = [],
238
- selectable = true,
239
- selectedRowKeys: controlledSelectedKeys,
240
- style,
241
- toolbar,
242
- } = props
243
- const [form] = Form.useForm()
244
- const [messageApi, messageHolder] = message.useMessage()
245
- const [notificationApi, notificationHolder] =
246
- notification.useNotification()
247
- const [modalApi, modalHolder] = Modal.useModal()
248
- const sourceKey = dataSource.key || "anonymous"
249
- const listIdentity = JSON.stringify([listKey, sourceKey])
250
- const [rawPreference, setRawPreference] =
251
- useState<AdminListPreference | null>(null)
252
- const [preference, setPreference] = useState<AdminListPreference>(() =>
253
- mergeAdminListPreference({
254
- version: configVersion,
255
- columns,
256
- searchFields,
257
- defaultSorts,
258
- defaults: {
259
- pageSize: defaultPageSize,
260
- defaultVisibleSearchCount,
261
- },
262
- locked: lockedPreference,
263
- }),
264
- )
265
- const [settingsDraft, setSettingsDraft] = useState(preference)
266
- const [settingsOpen, setSettingsOpen] = useState(false)
267
- const [settingsTab, setSettingsTab] = useState("search")
268
- const [columnSearch, setColumnSearch] = useState("")
269
- const [expanded, setExpanded] = useState(false)
270
- const [readyIdentity, setReadyIdentity] = useState<string | null>(null)
271
- const ready = readyIdentity === listIdentity
272
- const [rows, setRows] = useState<Row[]>([])
273
- const [total, setTotal] = useState(0)
274
- const [allowedColumnKeys, setAllowedColumnKeys] = useState<
275
- string[] | undefined
276
- >(undefined)
277
- const [hiddenFieldsCount, setHiddenFieldsCount] = useState(0)
278
- const [loading, setLoading] = useState(false)
279
- const [error, setError] = useState<Error | null>(null)
280
- const [query, setQuery] = useState<AdminListQuery>({
281
- currentPage: 1,
282
- pageSize: defaultPageSize,
283
- filters: {},
284
- sorts: defaultSorts,
285
- fixedFilters,
286
- })
287
- const [selectedKeys, setSelectedKeys] = useState<Key[]>([])
288
- const selectedRowsRef = useRef(new Map<Key, Row>())
289
- const previousFingerprintRef = useRef("")
290
- const [exportConfirmOpen, setExportConfirmOpen] = useState(false)
291
- const [exporting, setExporting] = useState(false)
292
- const [draggedColumnKey, setDraggedColumnKey] = useState("")
293
- const [draggedSearchKey, setDraggedSearchKey] = useState("")
294
- const selectedKeysRef = useRef<Key[]>([])
295
- const dataSourceRef = useRef(dataSource)
296
- const listIdentityRef = useRef(listIdentity)
297
- const requestVersionRef = useRef(0)
298
- const onQueryChangeRef = useRef(onQueryChange)
299
- const onSelectionChangeRef = useRef(onSelectionChange)
300
- dataSourceRef.current = dataSource
301
- listIdentityRef.current = listIdentity
302
- onQueryChangeRef.current = onQueryChange
303
- onSelectionChangeRef.current = onSelectionChange
304
- const definitionFingerprint = JSON.stringify({
305
- columns: columns.map((column) => ({
306
- key: column.key,
307
- width: column.width,
308
- fixed: column.fixed,
309
- hidden: column.hidden,
310
- locked: column.locked,
311
- sortable: column.sortable,
312
- sortField: column.sortField,
313
- })),
314
- searches: searchFields.map((field) => ({
315
- key: field.key,
316
- type: field.type,
317
- locked: field.locked,
318
- defaultVisible: field.defaultVisible,
319
- })),
320
- defaultSorts,
321
- fixedFilters,
322
- lockedPreference,
323
- })
324
-
325
- const clearSelection = useCallback(
326
- (reason?: string) => {
327
- if (selectedKeysRef.current.length && reason) {
328
- void messageApi.info(reason)
329
- }
330
- selectedRowsRef.current.clear()
331
- selectedKeysRef.current = []
332
- setSelectedKeys([])
333
- onSelectionChangeRef.current?.({ rowKeys: [], rows: [] })
334
- },
335
- [messageApi],
336
- )
337
-
338
- useEffect(() => {
339
- if (!controlledSelectedKeys) return
340
- const nextKeys = [...controlledSelectedKeys]
341
- const nextKeySet = new Set(nextKeys)
342
- for (const key of selectedRowsRef.current.keys()) {
343
- if (!nextKeySet.has(key)) selectedRowsRef.current.delete(key)
344
- }
345
- for (const row of rows) {
346
- const key = getRowKey(rowKey, row)
347
- if (nextKeySet.has(key)) selectedRowsRef.current.set(key, row)
348
- }
349
- selectedKeysRef.current = nextKeys
350
- setSelectedKeys(nextKeys)
351
- }, [controlledSelectedKeys, rowKey, rows])
352
-
353
- useEffect(() => {
354
- if (!rowSelectable || !selectedKeysRef.current.length || !rows.length) {
355
- return
356
- }
357
- const disabledKeys = new Set(
358
- rows
359
- .filter((row) => !rowSelectable(row))
360
- .map((row) => getRowKey(rowKey, row)),
361
- )
362
- if (!disabledKeys.size) return
363
- const nextKeys = selectedKeysRef.current.filter(
364
- (key) => !disabledKeys.has(key),
365
- )
366
- if (nextKeys.length === selectedKeysRef.current.length) return
367
- for (const key of disabledKeys) selectedRowsRef.current.delete(key)
368
- selectedKeysRef.current = nextKeys
369
- setSelectedKeys(nextKeys)
370
- onSelectionChangeRef.current?.({
371
- rowKeys: nextKeys,
372
- rows: nextKeys
373
- .map((key) => selectedRowsRef.current.get(key))
374
- .filter(Boolean) as Row[],
375
- })
376
- }, [rowKey, rowSelectable, rows])
377
-
378
- useEffect(() => {
379
- let active = true
380
- const initializationVersion = ++requestVersionRef.current
381
- setReadyIdentity(null)
382
- setRows([])
383
- setTotal(0)
384
- setAllowedColumnKeys(undefined)
385
- setHiddenFieldsCount(0)
386
- setLoading(false)
387
- setError(null)
388
- const load = async () => {
389
- const saved = dataSourceRef.current.preferences
390
- ? await dataSourceRef.current.preferences
391
- .get(listKey)
392
- .catch(() => null)
393
- : null
394
- if (
395
- !active ||
396
- initializationVersion !== requestVersionRef.current ||
397
- listIdentityRef.current !== listIdentity
398
- ) {
399
- return
400
- }
401
- setRawPreference(saved)
402
- const merged = mergeAdminListPreference({
403
- version: configVersion,
404
- columns,
405
- searchFields,
406
- defaultSorts,
407
- defaults: {
408
- pageSize: defaultPageSize,
409
- defaultVisibleSearchCount,
410
- },
411
- user: saved,
412
- locked: lockedPreference,
413
- })
414
- setPreference(merged)
415
- setSettingsDraft(merged)
416
- setQuery({
417
- currentPage: 1,
418
- pageSize: merged.pageSize || defaultPageSize,
419
- filters: {},
420
- sorts: merged.sorts || defaultSorts,
421
- fixedFilters,
422
- })
423
- form.resetFields()
424
- selectedRowsRef.current.clear()
425
- selectedKeysRef.current = []
426
- setSelectedKeys([])
427
- previousFingerprintRef.current = ""
428
- setReadyIdentity(listIdentity)
429
- }
430
- void load()
431
- return () => {
432
- active = false
433
- }
434
- }, [
435
- configVersion,
436
- defaultPageSize,
437
- defaultVisibleSearchCount,
438
- definitionFingerprint,
439
- form,
440
- listIdentity,
441
- ])
442
-
443
- useEffect(() => {
444
- if (!allowedColumnKeys) return
445
- const merged = mergeAdminListPreference({
446
- version: configVersion,
447
- columns,
448
- searchFields,
449
- defaultSorts,
450
- defaults: {
451
- pageSize: defaultPageSize,
452
- defaultVisibleSearchCount,
453
- },
454
- user: rawPreference,
455
- locked: lockedPreference,
456
- allowedColumnKeys,
457
- })
458
- setPreference((current) => ({
459
- ...merged,
460
- pageSize: current.pageSize,
461
- sorts: current.sorts,
462
- }))
463
- }, [
464
- allowedColumnKeys,
465
- columns,
466
- configVersion,
467
- defaultPageSize,
468
- defaultSorts,
469
- defaultVisibleSearchCount,
470
- lockedPreference,
471
- rawPreference,
472
- searchFields,
473
- ])
474
-
475
- const loadData = useCallback(async () => {
476
- if (!ready) return
477
- const requestVersion = ++requestVersionRef.current
478
- const requestedIdentity = listIdentity
479
- const requestedDataSource = dataSourceRef.current
480
- const isCurrentRequest = () =>
481
- requestVersion === requestVersionRef.current &&
482
- requestedIdentity === listIdentityRef.current
483
- setLoading(true)
484
- setError(null)
485
- onQueryChangeRef.current?.(query)
486
- try {
487
- const result = await requestedDataSource.query(query)
488
- if (!isCurrentRequest()) return
489
- const resultRows = Array.isArray(result.rows) ? result.rows : []
490
- setRows(resultRows)
491
- setTotal(reconcileResultTotal(result, query, resultRows))
492
- setAllowedColumnKeys(result.allowedColumnKeys)
493
- setHiddenFieldsCount(Math.max(0, Number(result.hiddenFieldsCount || 0)))
494
- } catch (requestError) {
495
- if (!isCurrentRequest()) return
496
- setRows([])
497
- setTotal(0)
498
- setError(
499
- requestError instanceof Error
500
- ? requestError
501
- : new Error(String(requestError || "数据加载失败")),
502
- )
503
- } finally {
504
- if (isCurrentRequest()) setLoading(false)
505
- }
506
- }, [listIdentity, query, ready])
507
-
508
- useEffect(() => {
509
- if (!ready) return
510
- const fingerprint = queryFingerprint(query, listIdentity)
511
- if (
512
- previousFingerprintRef.current &&
513
- previousFingerprintRef.current !== fingerprint &&
514
- selectedKeysRef.current.length
515
- ) {
516
- clearSelection("查询条件或排序已变化,已清空跨页选择")
517
- }
518
- previousFingerprintRef.current = fingerprint
519
- void loadData()
520
- }, [
521
- clearSelection,
522
- loadData,
523
- query,
524
- ready,
525
- listIdentity,
526
- ])
527
-
528
- const visibleSearchFields = useMemo(() => {
529
- const searchMap = new Map(searchFields.map((field) => [field.key, field]))
530
- const ordered = (preference.searches || [])
531
- .filter((item) => item.visible !== false)
532
- .map((item) => searchMap.get(item.key))
533
- .filter(Boolean) as AdminListSearchField[]
534
- const fallback = ordered.length ? ordered : searchFields
535
- return expanded
536
- ? fallback
537
- : fallback.slice(
538
- 0,
539
- preference.defaultVisibleSearchCount ||
540
- defaultVisibleSearchCount,
541
- )
542
- }, [
543
- defaultVisibleSearchCount,
544
- expanded,
545
- preference.defaultVisibleSearchCount,
546
- preference.searches,
547
- searchFields,
548
- ])
549
-
550
- const resolvedColumns = useMemo(() => {
551
- const definitions = new Map(columns.map((column) => [column.key, column]))
552
- const sortablePriority = new Map(
553
- (preference.sorts || []).map((sort, index) => [
554
- sort.field,
555
- index + 1,
556
- ]),
557
- )
558
- const preferenceColumns =
559
- preference.columns || toColumnPreferences(columns)
560
- const tableColumns = preferenceColumns
561
- .filter((item) => item.visible !== false)
562
- .map((item) => {
563
- const definition = definitions.get(item.key)
564
- if (!definition) return null
565
- const sortField = definition.sortField || definition.key
566
- const activeSort = (preference.sorts || []).find(
567
- (sort) => sort.field === sortField,
568
- )
569
- const title = definition.sortable ? (
570
- <Space size={4}>
571
- <span>{definition.title}</span>
572
- {sortablePriority.has(sortField) ? (
573
- <Tag color="blue" variant="filled">
574
- {sortablePriority.get(sortField)}
575
- </Tag>
576
- ) : null}
577
- </Space>
578
- ) : (
579
- definition.title
580
- )
581
- return {
582
- key: definition.key,
583
- title,
584
- dataIndex: definition.dataIndex,
585
- align: definition.align,
586
- width: item.width || definition.width,
587
- fixed: item.fixed || definition.fixed,
588
- ellipsis: definition.ellipsis,
589
- sorter: definition.sortable
590
- ? { multiple: sortablePriority.get(sortField) || 99 }
591
- : undefined,
592
- sortOrder: activeSort?.direction,
593
- render: (value: unknown, row: Row, index: number) =>
594
- definition.render
595
- ? definition.render(value, row, index)
596
- : (value as ReactNode),
597
- }
598
- })
599
- .filter(Boolean)
600
- if (rowActions.length) {
601
- tableColumns.push({
602
- key: "__actions",
603
- title: "操作",
604
- width: Math.max(96, Math.min(220, rowActions.length * 56)),
605
- fixed: "right",
606
- render: (_value: unknown, row: Row) => (
607
- <Space size={4} wrap>
608
- {rowActions.map((action) => {
609
- const hidden =
610
- typeof action.hidden === "function"
611
- ? action.hidden(row)
612
- : action.hidden
613
- if (hidden) return null
614
- const disabled =
615
- typeof action.disabled === "function"
616
- ? action.disabled(row)
617
- : action.disabled
618
- return (
619
- <Button
620
- danger={action.danger}
621
- disabled={disabled}
622
- key={action.key}
623
- size="small"
624
- type="link"
625
- onClick={() => void action.onClick(row)}
626
- >
627
- {action.label}
628
- </Button>
629
- )
630
- })}
631
- </Space>
632
- ),
633
- } as never)
634
- }
635
- return tableColumns as TableProps<Row>["columns"]
636
- }, [columns, preference.columns, preference.sorts, rowActions])
637
-
638
- const applySearch = (values: Record<string, unknown>) => {
639
- setQuery((current) => ({
640
- ...current,
641
- currentPage: 1,
642
- filters: normalizeFilters(values),
643
- }))
644
- }
645
-
646
- const resetSearch = () => {
647
- form.resetFields()
648
- setQuery((current) => ({
649
- ...current,
650
- currentPage: 1,
651
- filters: {},
652
- }))
653
- }
654
-
655
- const handleTableChange: NonNullable<TableProps<Row>["onChange"]> = (
656
- pagination,
657
- _filters,
658
- sorter,
659
- extra,
660
- ) => {
661
- const paginationOnly = extra.action === "paginate"
662
- const nextSorts = paginationOnly
663
- ? query.sorts
664
- : (Array.isArray(sorter) ? sorter : [sorter])
665
- .filter(
666
- (item) =>
667
- item?.order === "ascend" || item?.order === "descend",
668
- )
669
- .map((item) => {
670
- const definition = columns.find(
671
- (column) => column.key === String(item.columnKey || item.field),
672
- )
673
- return {
674
- field:
675
- definition?.sortField ||
676
- definition?.key ||
677
- String(item.field || item.columnKey),
678
- direction: item.order as "ascend" | "descend",
679
- }
680
- })
681
- const sortsChanged =
682
- sortFingerprint(nextSorts) !== sortFingerprint(query.sorts)
683
- const nextPageSize = pagination.pageSize || query.pageSize
684
- setPreference((current) => ({
685
- ...current,
686
- sorts: nextSorts,
687
- pageSize: nextPageSize,
688
- }))
689
- setQuery((current) => ({
690
- ...current,
691
- currentPage: sortsChanged
692
- ? 1
693
- : pagination.current || current.currentPage,
694
- pageSize: nextPageSize,
695
- sorts: nextSorts,
696
- }))
697
- }
698
-
699
- const handleSelectionChange = (keys: Key[], selectedRows: Row[]) => {
700
- const nextKeys = preserveSelectionAcrossPages
701
- ? keys
702
- : keys.filter((key) =>
703
- rows.some((row) => getRowKey(rowKey, row) === key),
704
- )
705
- const nextKeySet = new Set(nextKeys)
706
- for (const key of selectedRowsRef.current.keys()) {
707
- if (!nextKeySet.has(key)) selectedRowsRef.current.delete(key)
708
- }
709
- for (const row of [...rows, ...selectedRows]) {
710
- const key = getRowKey(rowKey, row)
711
- if (nextKeySet.has(key)) selectedRowsRef.current.set(key, row)
712
- }
713
- setSelectedKeys(nextKeys)
714
- selectedKeysRef.current = nextKeys
715
- onSelectionChangeRef.current?.({
716
- rowKeys: nextKeys,
717
- rows: nextKeys
718
- .map((key) => selectedRowsRef.current.get(key))
719
- .filter(Boolean) as Row[],
720
- })
721
- }
722
-
723
- const pollExportTask = useCallback(
724
- async (initial: AdminListExportTask) => {
725
- if (!dataSource.getExportTask) return initial
726
- let task = initial
727
- for (let attempt = 0; attempt < 120; attempt += 1) {
728
- if (task.status === "completed" || task.status === "failed") break
729
- await new Promise((resolve) => setTimeout(resolve, 1500))
730
- task = await dataSource.getExportTask(task.id)
731
- if (task.status === "running") {
732
- notificationApi.info({
733
- key: `admin-list-export:${task.id}`,
734
- title: `正在生成 ${Math.max(
735
- 0,
736
- Math.min(100, Number(task.progress || 0)),
737
- )}%`,
738
- description: task.total
739
- ? `共 ${task.total} 条`
740
- : "正在分批处理导出数据",
741
- duration: 0,
742
- showProgress: true,
743
- })
744
- }
745
- }
746
- return task
747
- },
748
- [dataSource, notificationApi],
749
- )
750
-
751
- const downloadExportTask = async (task: AdminListExportTask) => {
752
- try {
753
- if (dataSource.downloadExportTask) {
754
- await dataSource.downloadExportTask(task, { fileName })
755
- return
756
- }
757
- if (
758
- typeof window !== "undefined" &&
759
- task.downloadUrl &&
760
- (/^(https?:)?\/\//i.test(task.downloadUrl) ||
761
- /^(blob|data):/i.test(task.downloadUrl))
762
- ) {
763
- window.open(task.downloadUrl, "_blank", "noopener")
764
- return
765
- }
766
- throw new Error("当前数据源未配置导出文件下载能力")
767
- } catch (downloadError) {
768
- notificationApi.error({
769
- key: `admin-list-export-download:${task.id}`,
770
- title: "下载失败",
771
- description:
772
- downloadError instanceof Error
773
- ? downloadError.message
774
- : String(downloadError || "请稍后重试"),
775
- duration: 0,
776
- })
777
- }
778
- }
779
-
780
- const executeExport = async (scope: "selected" | "all") => {
781
- if (!dataSource.createExportTask) return
782
- setExporting(true)
783
- try {
784
- const exportColumns = (preference.columns || [])
785
- .filter((column) => column.visible !== false)
786
- .map((column) => columns.find((item) => item.key === column.key))
787
- .filter(
788
- (definition): definition is AdminListColumn<Row> =>
789
- Boolean(
790
- definition &&
791
- definition.exportable !== false &&
792
- definition.export !== false,
793
- ),
794
- )
795
- .map((definition) => {
796
- const configured = definition.export || {}
797
- const title =
798
- typeof definition.title === "string" ||
799
- typeof definition.title === "number"
800
- ? String(definition.title)
801
- : definition.key
802
- const dataPath = Array.isArray(definition.dataIndex)
803
- ? definition.dataIndex.join(".")
804
- : definition.dataIndex || definition.key
805
- return {
806
- key: definition.key,
807
- title,
808
- valuePath: dataPath,
809
- ...configured,
810
- }
811
- })
812
- const input: AdminListExportInput = {
813
- scope,
814
- query: { ...query },
815
- rowIds: scope === "selected" ? selectedKeys : undefined,
816
- fieldKeys: exportColumns.map((column) => column.key),
817
- columns: exportColumns,
818
- fileName,
819
- }
820
- const created = await dataSource.createExportTask(input)
821
- notificationApi.info({
822
- key: `admin-list-export:${created.id}`,
823
- title: "导出任务已创建",
824
- description: "可继续使用当前页面,完成后会通知",
825
- duration: 3,
826
- })
827
- const finished = await pollExportTask(created)
828
- if (finished.status === "completed") {
829
- notificationApi.success({
830
- key: `admin-list-export:${finished.id}`,
831
- title: "导出完成",
832
- description: finished.message || "文件已生成",
833
- duration: 0,
834
- actions: finished.downloadUrl ? (
835
- <Button
836
- size="small"
837
- type="primary"
838
- onClick={() => void downloadExportTask(finished)}
839
- >
840
- 下载文件
841
- </Button>
842
- ) : undefined,
843
- })
844
- } else if (finished.status === "failed") {
845
- notificationApi.error({
846
- key: `admin-list-export:${finished.id}`,
847
- title: "导出失败",
848
- description: finished.message || "请稍后重试",
849
- duration: 0,
850
- })
851
- }
852
- } catch (exportError) {
853
- notificationApi.error({
854
- title: "导出失败",
855
- description:
856
- exportError instanceof Error
857
- ? exportError.message
858
- : String(exportError || "请稍后重试"),
859
- })
860
- } finally {
861
- setExporting(false)
862
- setExportConfirmOpen(false)
863
- }
864
- }
865
-
866
- const exportMenuItems: MenuProps["items"] = [
867
- {
868
- key: "selected",
869
- label: `导出选中(${selectedKeys.length} 条)`,
870
- disabled: selectedKeys.length === 0,
871
- onClick: () => void executeExport("selected"),
872
- },
873
- {
874
- key: "all",
875
- label: `导出全部(当前条件共 ${total} 条)`,
876
- onClick: () => setExportConfirmOpen(true),
877
- },
878
- ]
879
-
880
- const openSettings = () => {
881
- setSettingsDraft(preference)
882
- setSettingsOpen(true)
883
- }
884
-
885
- const saveSettings = async () => {
886
- const normalized = mergeAdminListPreference({
887
- version: configVersion,
888
- columns,
889
- searchFields,
890
- defaultSorts,
891
- defaults: {
892
- pageSize: defaultPageSize,
893
- defaultVisibleSearchCount,
894
- },
895
- user: settingsDraft,
896
- locked: lockedPreference,
897
- allowedColumnKeys,
898
- })
899
- try {
900
- const saved = dataSource.preferences
901
- ? await dataSource.preferences.put(listKey, normalized)
902
- : normalized
903
- const next = { ...normalized, ...saved }
904
- setRawPreference(next)
905
- setPreference(next)
906
- setSettingsDraft(next)
907
- setSettingsOpen(false)
908
- setQuery((current) => ({
909
- ...current,
910
- currentPage: 1,
911
- pageSize: next.pageSize || current.pageSize,
912
- sorts: next.sorts || current.sorts,
913
- }))
914
- void messageApi.success("列表设置已保存")
915
- } catch (saveError) {
916
- void messageApi.error(
917
- saveError instanceof Error
918
- ? saveError.message
919
- : "列表设置保存失败",
920
- )
921
- }
922
- }
923
-
924
- const resetSettings = async () => {
925
- try {
926
- await dataSource.preferences?.remove(listKey)
927
- const reset = mergeAdminListPreference({
928
- version: configVersion,
929
- columns,
930
- searchFields,
931
- defaultSorts,
932
- defaults: {
933
- pageSize: defaultPageSize,
934
- defaultVisibleSearchCount,
935
- },
936
- locked: lockedPreference,
937
- allowedColumnKeys,
938
- })
939
- setRawPreference(null)
940
- setPreference(reset)
941
- setSettingsDraft(reset)
942
- setQuery((current) => ({
943
- ...current,
944
- currentPage: 1,
945
- pageSize: reset.pageSize || current.pageSize,
946
- sorts: reset.sorts || current.sorts,
947
- }))
948
- void messageApi.success("已恢复系统默认设置")
949
- } catch (resetError) {
950
- void messageApi.error(
951
- resetError instanceof Error
952
- ? resetError.message
953
- : "恢复默认设置失败",
954
- )
955
- }
956
- }
957
-
958
- const reorderDraft = (
959
- kind: "columns" | "searches",
960
- draggedKey: string,
961
- targetKey: string,
962
- ) => {
963
- if (!draggedKey || draggedKey === targetKey) return
964
- setSettingsDraft((current) => {
965
- const items = [...(current[kind] || [])]
966
- const from = items.findIndex((item) => item.key === draggedKey)
967
- const to = items.findIndex((item) => item.key === targetKey)
968
- if (from < 0 || to < 0) return current
969
- const [moved] = items.splice(from, 1)
970
- items.splice(to, 0, moved)
971
- return { ...current, [kind]: items }
972
- })
973
- }
974
-
975
- const updateDraftColumn = (
976
- key: string,
977
- patch: Partial<AdminListColumnPreference>,
978
- ) => {
979
- setSettingsDraft((current) => ({
980
- ...current,
981
- columns: (current.columns || []).map((column) =>
982
- column.key === key ? { ...column, ...patch } : column,
983
- ),
984
- }))
985
- }
986
-
987
- const settingsContent = (
988
- <Tabs
989
- activeKey={settingsTab}
990
- items={[
991
- {
992
- key: "search",
993
- label: "搜索项",
994
- children: (
995
- <Space orientation="vertical" size={12} style={{ width: "100%" }}>
996
- <Space>
997
- <span>默认展示</span>
998
- <InputNumber
999
- min={1}
1000
- max={Math.max(1, searchFields.length)}
1001
- value={
1002
- settingsDraft.defaultVisibleSearchCount ||
1003
- defaultVisibleSearchCount
1004
- }
1005
- onChange={(value) =>
1006
- setSettingsDraft((current) => ({
1007
- ...current,
1008
- defaultVisibleSearchCount:
1009
- Number(value) || defaultVisibleSearchCount,
1010
- }))
1011
- }
1012
- />
1013
- <span>项</span>
1014
- </Space>
1015
- {(settingsDraft.searches || []).map((item, index) => {
1016
- const definition = searchFields.find(
1017
- (field) => field.key === item.key,
1018
- )
1019
- if (!definition) return null
1020
- const locked =
1021
- definition.locked ||
1022
- lockedPreference?.lockedSearchKeys?.includes(item.key)
1023
- return (
1024
- <div
1025
- draggable={!locked}
1026
- key={item.key}
1027
- onDragStart={() => setDraggedSearchKey(item.key)}
1028
- onDragOver={(event) => event.preventDefault()}
1029
- onDrop={() =>
1030
- reorderDraft(
1031
- "searches",
1032
- draggedSearchKey,
1033
- item.key,
1034
- )
1035
- }
1036
- style={{
1037
- alignItems: "center",
1038
- borderBottom: "1px solid rgba(5, 5, 5, 0.06)",
1039
- display: "grid",
1040
- gap: 12,
1041
- gridTemplateColumns: "24px 1fr auto",
1042
- padding: "12px 4px",
1043
- }}
1044
- >
1045
- <span
1046
- aria-label={`拖动第 ${index + 1} 项`}
1047
- style={{ color: "#8c8c8c", cursor: "grab" }}
1048
- >
1049
- <HolderOutlined />
1050
- </span>
1051
- <span>{definition.label}</span>
1052
- <Checkbox
1053
- checked={item.visible !== false}
1054
- disabled={locked}
1055
- onChange={(event) =>
1056
- setSettingsDraft((current) => ({
1057
- ...current,
1058
- searches: (current.searches || []).map(
1059
- (search) =>
1060
- search.key === item.key
1061
- ? {
1062
- ...search,
1063
- visible: event.target.checked,
1064
- }
1065
- : search,
1066
- ),
1067
- }))
1068
- }
1069
- >
1070
- 显示
1071
- </Checkbox>
1072
- </div>
1073
- )
1074
- })}
1075
- </Space>
1076
- ),
1077
- },
1078
- {
1079
- key: "columns",
1080
- label: "列设置",
1081
- children: (
1082
- <Space orientation="vertical" size={12} style={{ width: "100%" }}>
1083
- <Input
1084
- allowClear
1085
- placeholder="搜索列名称"
1086
- value={columnSearch}
1087
- onChange={(event) => setColumnSearch(event.target.value)}
1088
- />
1089
- {(settingsDraft.columns || [])
1090
- .filter((item) => {
1091
- const definition = columns.find(
1092
- (column) => column.key === item.key,
1093
- )
1094
- return (
1095
- definition &&
1096
- String(definition.title)
1097
- .toLowerCase()
1098
- .includes(columnSearch.trim().toLowerCase())
1099
- )
1100
- })
1101
- .map((item, index) => {
1102
- const definition = columns.find(
1103
- (column) => column.key === item.key,
1104
- )
1105
- if (!definition) return null
1106
- const locked =
1107
- definition.locked ||
1108
- lockedPreference?.lockedColumnKeys?.includes(item.key)
1109
- return (
1110
- <div
1111
- draggable={!locked}
1112
- key={item.key}
1113
- onDragStart={() => setDraggedColumnKey(item.key)}
1114
- onDragOver={(event) => event.preventDefault()}
1115
- onDrop={() =>
1116
- reorderDraft(
1117
- "columns",
1118
- draggedColumnKey,
1119
- item.key,
1120
- )
1121
- }
1122
- style={{
1123
- alignItems: "center",
1124
- borderBottom: "1px solid rgba(5, 5, 5, 0.06)",
1125
- display: "grid",
1126
- gap: 12,
1127
- gridTemplateColumns: "24px minmax(0, 1fr) 76px 116px",
1128
- padding: "12px 4px",
1129
- }}
1130
- >
1131
- <span
1132
- aria-label={`拖动第 ${index + 1} 列`}
1133
- style={{ color: "#8c8c8c", cursor: "grab" }}
1134
- >
1135
- <HolderOutlined />
1136
- </span>
1137
- <Checkbox
1138
- checked={item.visible !== false}
1139
- disabled={locked}
1140
- onChange={(event) =>
1141
- updateDraftColumn(item.key, {
1142
- visible: event.target.checked,
1143
- })
1144
- }
1145
- >
1146
- {definition.title}
1147
- {locked ? (
1148
- <Tag variant="filled" style={{ marginInlineStart: 4 }}>
1149
- 锁定
1150
- </Tag>
1151
- ) : null}
1152
- </Checkbox>
1153
- <InputNumber
1154
- min={60}
1155
- max={800}
1156
- size="small"
1157
- value={item.width}
1158
- onChange={(value) =>
1159
- updateDraftColumn(item.key, {
1160
- width: value ? Number(value) : undefined,
1161
- })
1162
- }
1163
- />
1164
- <Select
1165
- size="small"
1166
- value={item.fixed || "none"}
1167
- options={[
1168
- { label: "固定在左侧", value: "left" },
1169
- { label: "不固定", value: "none" },
1170
- { label: "固定在右侧", value: "right" },
1171
- ]}
1172
- onChange={(value) =>
1173
- updateDraftColumn(item.key, {
1174
- fixed:
1175
- value === "left" || value === "right"
1176
- ? value
1177
- : null,
1178
- })
1179
- }
1180
- />
1181
- </div>
1182
- )
1183
- })}
1184
- </Space>
1185
- ),
1186
- },
1187
- {
1188
- key: "sort",
1189
- label: "排序",
1190
- children: (
1191
- <Space orientation="vertical" size={12} style={{ width: "100%" }}>
1192
- <Alert
1193
- showIcon
1194
- type="info"
1195
- title="列头快捷排序会同步更新此处"
1196
- />
1197
- {(settingsDraft.sorts || []).map((sort, index) => (
1198
- <div
1199
- key={`${sort.field}:${index}`}
1200
- style={{
1201
- alignItems: "center",
1202
- borderBottom: "1px solid rgba(5, 5, 5, 0.06)",
1203
- display: "grid",
1204
- gap: 12,
1205
- gridTemplateColumns: "28px 1fr 100px auto",
1206
- padding: "12px 4px",
1207
- }}
1208
- >
1209
- <Tag color="blue" variant="filled">
1210
- {index + 1}
1211
- </Tag>
1212
- <Select
1213
- value={sort.field}
1214
- options={columns
1215
- .filter((column) => column.sortable)
1216
- .map((column) => ({
1217
- label: column.title,
1218
- value: column.sortField || column.key,
1219
- }))}
1220
- onChange={(field) =>
1221
- setSettingsDraft((current) => ({
1222
- ...current,
1223
- sorts: (current.sorts || []).map((item, itemIndex) =>
1224
- itemIndex === index ? { ...item, field } : item,
1225
- ),
1226
- }))
1227
- }
1228
- />
1229
- <Select
1230
- value={sort.direction}
1231
- options={[
1232
- { label: "升序", value: "ascend" },
1233
- { label: "降序", value: "descend" },
1234
- ]}
1235
- onChange={(direction) =>
1236
- setSettingsDraft((current) => ({
1237
- ...current,
1238
- sorts: (current.sorts || []).map((item, itemIndex) =>
1239
- itemIndex === index
1240
- ? { ...item, direction }
1241
- : item,
1242
- ),
1243
- }))
1244
- }
1245
- />
1246
- <Button
1247
- danger
1248
- icon={<DeleteOutlined />}
1249
- size="small"
1250
- type="text"
1251
- onClick={() =>
1252
- setSettingsDraft((current) => ({
1253
- ...current,
1254
- sorts: (current.sorts || []).filter(
1255
- (_item, itemIndex) => itemIndex !== index,
1256
- ),
1257
- }))
1258
- }
1259
- >
1260
- 删除
1261
- </Button>
1262
- </div>
1263
- ))}
1264
- <Button
1265
- block
1266
- disabled={
1267
- (settingsDraft.sorts || []).length >=
1268
- columns.filter((column) => column.sortable).length
1269
- }
1270
- icon={<PlusOutlined />}
1271
- type="text"
1272
- onClick={() => {
1273
- const used = new Set(
1274
- (settingsDraft.sorts || []).map((sort) => sort.field),
1275
- )
1276
- const next = columns.find(
1277
- (column) =>
1278
- column.sortable &&
1279
- !used.has(column.sortField || column.key),
1280
- )
1281
- if (!next) return
1282
- setSettingsDraft((current) => ({
1283
- ...current,
1284
- sorts: [
1285
- ...(current.sorts || []),
1286
- {
1287
- field: next.sortField || next.key,
1288
- direction: "ascend",
1289
- },
1290
- ],
1291
- }))
1292
- }}
1293
- >
1294
- 添加排序字段
1295
- </Button>
1296
- </Space>
1297
- ),
1298
- },
1299
- {
1300
- key: "display",
1301
- label: "显示",
1302
- children: (
1303
- <Space orientation="vertical" size={20} style={{ width: "100%" }}>
1304
- <Space orientation="vertical">
1305
- <span>表格密度</span>
1306
- <Segmented
1307
- options={[
1308
- { label: "紧凑", value: "small" },
1309
- { label: "默认", value: "middle" },
1310
- { label: "宽松", value: "large" },
1311
- ]}
1312
- value={settingsDraft.density}
1313
- onChange={(density) =>
1314
- setSettingsDraft((current) => ({
1315
- ...current,
1316
- density: density as AdminListPreference["density"],
1317
- }))
1318
- }
1319
- />
1320
- </Space>
1321
- <Space orientation="vertical">
1322
- <span>默认每页</span>
1323
- <Segmented
1324
- options={pageSizeOptions.map((value) => ({
1325
- label: `${value}`,
1326
- value,
1327
- }))}
1328
- value={settingsDraft.pageSize}
1329
- onChange={(pageSize) =>
1330
- setSettingsDraft((current) => ({
1331
- ...current,
1332
- pageSize: Number(pageSize),
1333
- }))
1334
- }
1335
- />
1336
- </Space>
1337
- <Space style={{ justifyContent: "space-between", width: "100%" }}>
1338
- <span>完整边框</span>
1339
- <Switch
1340
- checked={settingsDraft.showBorders}
1341
- onChange={(showBorders) =>
1342
- setSettingsDraft((current) => ({
1343
- ...current,
1344
- showBorders,
1345
- }))
1346
- }
1347
- />
1348
- </Space>
1349
- <Space style={{ justifyContent: "space-between", width: "100%" }}>
1350
- <span>斑马纹</span>
1351
- <Switch
1352
- checked={settingsDraft.striped}
1353
- onChange={(striped) =>
1354
- setSettingsDraft((current) => ({
1355
- ...current,
1356
- striped,
1357
- }))
1358
- }
1359
- />
1360
- </Space>
1361
- <Space style={{ justifyContent: "space-between", width: "100%" }}>
1362
- <span>行悬浮操作</span>
1363
- <Switch
1364
- checked={settingsDraft.hoverActions}
1365
- onChange={(hoverActions) =>
1366
- setSettingsDraft((current) => ({
1367
- ...current,
1368
- hoverActions,
1369
- }))
1370
- }
1371
- />
1372
- </Space>
1373
- </Space>
1374
- ),
1375
- },
1376
- ]}
1377
- onChange={setSettingsTab}
1378
- />
1379
- )
1380
-
1381
- const unauthorized = Number((error as Error & { status?: number })?.status) === 403
1382
- const localeEmpty = error ? (
1383
- unauthorized ? (
1384
- <Result
1385
- status="403"
1386
- title="暂无访问权限"
1387
- subTitle="请联系应用管理员开通页面权限"
1388
- />
1389
- ) : (
1390
- <Result
1391
- status="error"
1392
- title="数据加载失败"
1393
- subTitle={error.message || "网络异常或服务暂不可用"}
1394
- extra={
1395
- <Button onClick={() => void loadData()} type="primary">
1396
- 重新加载
1397
- </Button>
1398
- }
1399
- />
1400
- )
1401
- ) : (
1402
- <Empty
1403
- description={emptyText || "暂无符合条件的数据"}
1404
- image={Empty.PRESENTED_IMAGE_SIMPLE}
1405
- >
1406
- {Object.keys(query.filters).length ? (
1407
- <Button onClick={resetSearch}>清空筛选</Button>
1408
- ) : null}
1409
- </Empty>
1410
- )
1411
-
1412
- const tablePagination: TablePaginationConfig = {
1413
- current: query.currentPage,
1414
- pageSize: query.pageSize,
1415
- pageSizeOptions,
1416
- showQuickJumper: true,
1417
- showSizeChanger: true,
1418
- showTotal: (count) => `共 ${count} 条`,
1419
- total,
1420
- }
1421
-
1422
- return (
1423
- <div className={className} style={style}>
1424
- {messageHolder}
1425
- {notificationHolder}
1426
- {modalHolder}
1427
- <Space orientation="vertical" size={16} style={{ width: "100%" }}>
1428
- {searchFields.length ? (
1429
- <div
1430
- style={{
1431
- background: "#fff",
1432
- border: "1px solid #e8edf3",
1433
- borderRadius: 8,
1434
- overflowX: "auto",
1435
- padding: "18px 20px",
1436
- }}
1437
- >
1438
- <Form
1439
- form={form}
1440
- layout="vertical"
1441
- onFinish={applySearch}
1442
- >
1443
- <div
1444
- style={{
1445
- alignItems: "end",
1446
- display: "grid",
1447
- gap: 12,
1448
- gridTemplateColumns:
1449
- "repeat(4, minmax(180px, 1fr)) minmax(256px, auto)",
1450
- minWidth: 1040,
1451
- }}
1452
- >
1453
- {visibleSearchFields.map((field) => (
1454
- <Form.Item
1455
- key={field.key}
1456
- label={field.label}
1457
- name={field.render ? undefined : field.key}
1458
- style={{ marginBottom: 0 }}
1459
- >
1460
- {field.render ? (
1461
- <Form.Item noStyle shouldUpdate>
1462
- {() =>
1463
- field.render?.({
1464
- disabled: field.disabled,
1465
- value: form.getFieldValue(field.key),
1466
- onChange: (value) =>
1467
- form.setFieldValue(field.key, value),
1468
- })
1469
- }
1470
- </Form.Item>
1471
- ) : (
1472
- renderSearchControl(field)
1473
- )}
1474
- </Form.Item>
1475
- ))}
1476
- <Form.Item
1477
- style={{
1478
- justifySelf: "end",
1479
- gridColumn: 5,
1480
- marginBottom: 0,
1481
- minWidth: 256,
1482
- }}
1483
- >
1484
- <Space size={8}>
1485
- <Button htmlType="submit" type="primary">
1486
- 查询
1487
- </Button>
1488
- <Button onClick={resetSearch}>重置</Button>
1489
- {searchFields.length >
1490
- (preference.defaultVisibleSearchCount ||
1491
- defaultVisibleSearchCount) ? (
1492
- <Button
1493
- icon={expanded ? <UpOutlined /> : <DownOutlined />}
1494
- iconPlacement="end"
1495
- type="link"
1496
- onClick={() => setExpanded((current) => !current)}
1497
- >
1498
- {expanded ? "收起" : "更多筛选"}
1499
- </Button>
1500
- ) : null}
1501
- </Space>
1502
- </Form.Item>
1503
- </div>
1504
- </Form>
1505
- </div>
1506
- ) : null}
1507
-
1508
- <div
1509
- style={{
1510
- padding: "2px 0 0",
1511
- }}
1512
- >
1513
- <Space
1514
- align="center"
1515
- style={{ justifyContent: "space-between", width: "100%" }}
1516
- wrap
1517
- >
1518
- <Space wrap>
1519
- {typeof toolbar === "function"
1520
- ? toolbar({ reload: () => void loadData() })
1521
- : toolbar}
1522
- {batchActions.length ? (
1523
- <Dropdown
1524
- menu={{
1525
- items: batchActions.map((action) => ({
1526
- key: action.key,
1527
- label: action.label,
1528
- danger: action.danger,
1529
- disabled:
1530
- action.disabled || selectedKeys.length === 0,
1531
- onClick: () =>
1532
- void action.onClick(
1533
- selectedKeys
1534
- .map((key) =>
1535
- selectedRowsRef.current.get(key),
1536
- )
1537
- .filter(Boolean) as Row[],
1538
- selectedKeys,
1539
- ),
1540
- })),
1541
- }}
1542
- trigger={["click"]}
1543
- >
1544
- <Button disabled={selectedKeys.length === 0}>
1545
- 批量操作
1546
- </Button>
1547
- </Dropdown>
1548
- ) : null}
1549
- {exportable && dataSource.createExportTask ? (
1550
- <Dropdown menu={{ items: exportMenuItems }} trigger={["click"]}>
1551
- <Button
1552
- icon={<DownloadOutlined />}
1553
- loading={exporting}
1554
- >
1555
- 导出
1556
- </Button>
1557
- </Dropdown>
1558
- ) : null}
1559
- </Space>
1560
- <Space>
1561
- <Button
1562
- aria-label="刷新列表"
1563
- icon={<ReloadOutlined />}
1564
- title="刷新"
1565
- onClick={() => void loadData()}
1566
- />
1567
- <Button
1568
- icon={<SettingOutlined />}
1569
- onClick={openSettings}
1570
- >
1571
- 列表设置
1572
- </Button>
1573
- </Space>
1574
- </Space>
1575
- </div>
1576
-
1577
- {selectedKeys.length ? (
1578
- <Alert
1579
- action={
1580
- <Button
1581
- size="small"
1582
- type="link"
1583
- onClick={() => clearSelection()}
1584
- >
1585
- 清空选择
1586
- </Button>
1587
- }
1588
- showIcon
1589
- title={`已选择 ${selectedKeys.length} 条${
1590
- preserveSelectionAcrossPages ? "(支持跨页保留)" : ""
1591
- }`}
1592
- type="info"
1593
- />
1594
- ) : null}
1595
-
1596
- {hiddenFieldsCount ? (
1597
- <Alert
1598
- closable
1599
- showIcon
1600
- title={`部分字段因权限限制未展示(${hiddenFieldsCount} 个)`}
1601
- type="info"
1602
- />
1603
- ) : null}
1604
-
1605
- <div
1606
- style={{
1607
- background: "#fff",
1608
- border: "1px solid #edf0f4",
1609
- borderRadius: 8,
1610
- overflow: "hidden",
1611
- }}
1612
- >
1613
- <Table<Row>
1614
- bordered={preference.showBorders}
1615
- columns={resolvedColumns}
1616
- dataSource={rows}
1617
- loading={loading}
1618
- locale={{ emptyText: localeEmpty }}
1619
- pagination={tablePagination}
1620
- rowClassName={(_row, index) =>
1621
- preference.striped && index % 2 === 1
1622
- ? "admin-list-row-striped"
1623
- : ""
1624
- }
1625
- rowKey={(row) => getRowKey(rowKey, row)}
1626
- rowSelection={
1627
- selectable
1628
- ? {
1629
- preserveSelectedRowKeys:
1630
- preserveSelectionAcrossPages,
1631
- selectedRowKeys: selectedKeys,
1632
- getCheckboxProps: (row: Row) => ({
1633
- disabled: rowSelectable ? !rowSelectable(row) : false,
1634
- title: rowSelectionReason?.(row),
1635
- }),
1636
- onChange: handleSelectionChange,
1637
- }
1638
- : undefined
1639
- }
1640
- scroll={{ x: "max-content" }}
1641
- size={preference.density}
1642
- onChange={handleTableChange}
1643
- onRow={onRow}
1644
- />
1645
- </div>
1646
- </Space>
1647
-
1648
- <Drawer
1649
- destroyOnHidden
1650
- footer={
1651
- <Space
1652
- style={{ justifyContent: "space-between", width: "100%" }}
1653
- >
1654
- <Button
1655
- onClick={() =>
1656
- modalApi.confirm({
1657
- title: "恢复系统默认设置?",
1658
- content: "当前账号保存的列表配置将被清除。",
1659
- okText: "恢复",
1660
- cancelText: "取消",
1661
- onOk: resetSettings,
1662
- })
1663
- }
1664
- >
1665
- 恢复默认
1666
- </Button>
1667
- <Space>
1668
- <Button onClick={() => setSettingsOpen(false)}>取消</Button>
1669
- <Button type="primary" onClick={() => void saveSettings()}>
1670
- 应用设置
1671
- </Button>
1672
- </Space>
1673
- </Space>
1674
- }
1675
- open={settingsOpen}
1676
- title={
1677
- <div>
1678
- <div>列表设置</div>
1679
- <div
1680
- style={{
1681
- color: "rgba(0, 0, 0, 0.45)",
1682
- fontSize: 12,
1683
- fontWeight: 400,
1684
- marginTop: 2,
1685
- }}
1686
- >
1687
- 配置将保存到当前账号
1688
- </div>
1689
- </div>
1690
- }
1691
- size={420}
1692
- onClose={() => {
1693
- if (
1694
- JSON.stringify(settingsDraft) !==
1695
- JSON.stringify(preference)
1696
- ) {
1697
- modalApi.confirm({
1698
- title: "放弃未保存的设置?",
1699
- content: "当前调整尚未应用,关闭后将丢失。",
1700
- okText: "放弃修改",
1701
- cancelText: "继续编辑",
1702
- onOk: () => setSettingsOpen(false),
1703
- })
1704
- return
1705
- }
1706
- setSettingsOpen(false)
1707
- }}
1708
- >
1709
- {settingsContent}
1710
- </Drawer>
1711
-
1712
- <Modal
1713
- cancelText="取消"
1714
- confirmLoading={exporting}
1715
- okText="开始导出"
1716
- open={exportConfirmOpen}
1717
- title="导出全部数据"
1718
- onCancel={() => setExportConfirmOpen(false)}
1719
- onOk={() => void executeExport("all")}
1720
- >
1721
- <Space orientation="vertical" size={12} style={{ width: "100%" }}>
1722
- <div>数据范围:当前查询结果</div>
1723
- <div>预计数量:{total} 条</div>
1724
- <div>导出格式:Excel (.xlsx)</div>
1725
- <Alert
1726
- showIcon
1727
- title="大数据量将在后台生成,完成后通知"
1728
- type="info"
1729
- />
1730
- </Space>
1731
- </Modal>
1732
- </div>
1733
- )
1734
- }