@liujitcn/kratos-admin-system 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/README.md +137 -0
  2. package/dist/package/declarations/index.d.ts +1 -0
  3. package/dist/package/declarations/src/ai.d.ts +10 -0
  4. package/dist/package/declarations/src/api/base/ai_message.d.ts +27 -0
  5. package/dist/package/declarations/src/api/base/ai_session.d.ts +17 -0
  6. package/dist/package/declarations/src/api/base/ai_tool.d.ts +7 -0
  7. package/dist/package/declarations/src/api/base/oauth.d.ts +13 -0
  8. package/dist/package/declarations/src/api/base/sse.d.ts +31 -0
  9. package/dist/package/declarations/src/api/system/auth.d.ts +17 -0
  10. package/dist/package/declarations/src/api/system/base_api.d.ts +22 -0
  11. package/dist/package/declarations/src/api/system/base_area.d.ts +19 -0
  12. package/dist/package/declarations/src/api/system/base_config.d.ts +20 -0
  13. package/dist/package/declarations/src/api/system/base_dept.d.ts +21 -0
  14. package/dist/package/declarations/src/api/system/base_dict.d.ts +32 -0
  15. package/dist/package/declarations/src/api/system/base_job.d.ts +28 -0
  16. package/dist/package/declarations/src/api/system/base_log.d.ts +9 -0
  17. package/dist/package/declarations/src/api/system/base_menu.d.ts +21 -0
  18. package/dist/package/declarations/src/api/system/base_migration.d.ts +10 -0
  19. package/dist/package/declarations/src/api/system/base_post.d.ts +21 -0
  20. package/dist/package/declarations/src/api/system/base_role.d.ts +23 -0
  21. package/dist/package/declarations/src/api/system/base_tenant.d.ts +21 -0
  22. package/dist/package/declarations/src/api/system/base_user.d.ts +23 -0
  23. package/dist/package/declarations/src/api/system/code_gen.d.ts +14 -0
  24. package/dist/package/declarations/src/api/system/code_gen_column.d.ts +12 -0
  25. package/dist/package/declarations/src/api/system/code_gen_proto.d.ts +10 -0
  26. package/dist/package/declarations/src/api/system/code_gen_sse.d.ts +8 -0
  27. package/dist/package/declarations/src/api/system/code_gen_table.d.ts +18 -0
  28. package/dist/package/declarations/src/api/system/project_document.d.ts +9 -0
  29. package/dist/package/declarations/src/components/Ai.vue.d.ts +3 -0
  30. package/dist/package/declarations/src/index.d.ts +3 -0
  31. package/dist/package/declarations/src/module.d.ts +2 -0
  32. package/dist/package/declarations/src/rpc/base/v1/ai_message.d.ts +82 -0
  33. package/dist/package/declarations/src/rpc/base/v1/ai_session.d.ts +176 -0
  34. package/dist/package/declarations/src/rpc/base/v1/ai_tool.d.ts +59 -0
  35. package/dist/package/declarations/src/rpc/base/v1/oauth.d.ts +167 -0
  36. package/dist/package/declarations/src/rpc/base/v1/sse.d.ts +13 -0
  37. package/dist/package/declarations/src/rpc/common/v1/common.d.ts +57 -0
  38. package/dist/package/declarations/src/rpc/common/v1/enum.d.ts +58 -0
  39. package/dist/package/declarations/src/rpc/common/v1/types.d.ts +60 -0
  40. package/dist/package/declarations/src/rpc/google/protobuf/empty.d.ts +11 -0
  41. package/dist/package/declarations/src/rpc/google/protobuf/timestamp.d.ts +107 -0
  42. package/dist/package/declarations/src/rpc/system/admin/v1/auth.d.ts +156 -0
  43. package/dist/package/declarations/src/rpc/system/admin/v1/base_api.d.ts +193 -0
  44. package/dist/package/declarations/src/rpc/system/admin/v1/base_area.d.ts +82 -0
  45. package/dist/package/declarations/src/rpc/system/admin/v1/base_config.d.ts +112 -0
  46. package/dist/package/declarations/src/rpc/system/admin/v1/base_dept.d.ts +112 -0
  47. package/dist/package/declarations/src/rpc/system/admin/v1/base_dict.d.ts +215 -0
  48. package/dist/package/declarations/src/rpc/system/admin/v1/base_job.d.ts +177 -0
  49. package/dist/package/declarations/src/rpc/system/admin/v1/base_log.d.ts +87 -0
  50. package/dist/package/declarations/src/rpc/system/admin/v1/base_menu.d.ts +151 -0
  51. package/dist/package/declarations/src/rpc/system/admin/v1/base_migration.d.ts +64 -0
  52. package/dist/package/declarations/src/rpc/system/admin/v1/base_post.d.ts +112 -0
  53. package/dist/package/declarations/src/rpc/system/admin/v1/base_role.d.ts +128 -0
  54. package/dist/package/declarations/src/rpc/system/admin/v1/base_tenant.d.ts +112 -0
  55. package/dist/package/declarations/src/rpc/system/admin/v1/base_user.d.ts +161 -0
  56. package/dist/package/declarations/src/rpc/system/admin/v1/code_gen.d.ts +155 -0
  57. package/dist/package/declarations/src/rpc/system/admin/v1/code_gen_column.d.ts +143 -0
  58. package/dist/package/declarations/src/rpc/system/admin/v1/code_gen_proto.d.ts +86 -0
  59. package/dist/package/declarations/src/rpc/system/admin/v1/code_gen_table.d.ts +149 -0
  60. package/dist/package/declarations/src/rpc/system/admin/v1/project_document.d.ts +64 -0
  61. package/dist/package/declarations/src/rpc/system/common/v1/enum.d.ts +67 -0
  62. package/dist/package/declarations/src/views/ai/chat/attachment.d.ts +14 -0
  63. package/dist/package/declarations/src/views/ai/chat/components/AiMarkdown.vue.d.ts +13 -0
  64. package/dist/package/declarations/src/views/ai/chat/components/ChatPanel.vue.d.ts +45 -0
  65. package/dist/package/declarations/src/views/ai/chat/components/SessionPanel.vue.d.ts +34 -0
  66. package/dist/package/declarations/src/views/ai/chat/components/XSender.vue.d.ts +12 -0
  67. package/dist/package/declarations/src/views/ai/chat/index.vue.d.ts +4 -0
  68. package/dist/package/declarations/src/views/ai/chat/message.d.ts +59 -0
  69. package/dist/package/declarations/src/views/ai/chat/stream.d.ts +10 -0
  70. package/dist/package/declarations/src/views/ai/chat/types.d.ts +115 -0
  71. package/dist/package/declarations/src/views/base/api/index.vue.d.ts +3 -0
  72. package/dist/package/declarations/src/views/base/area/index.vue.d.ts +3 -0
  73. package/dist/package/declarations/src/views/base/config/index.vue.d.ts +3 -0
  74. package/dist/package/declarations/src/views/base/dept/index.vue.d.ts +3 -0
  75. package/dist/package/declarations/src/views/base/dict/index.vue.d.ts +3 -0
  76. package/dist/package/declarations/src/views/base/dict/item.vue.d.ts +3 -0
  77. package/dist/package/declarations/src/views/base/job/index.vue.d.ts +3 -0
  78. package/dist/package/declarations/src/views/base/job/log.vue.d.ts +3 -0
  79. package/dist/package/declarations/src/views/base/log/index.vue.d.ts +3 -0
  80. package/dist/package/declarations/src/views/base/menu/index.vue.d.ts +3 -0
  81. package/dist/package/declarations/src/views/base/migration/index.vue.d.ts +4 -0
  82. package/dist/package/declarations/src/views/base/post/index.vue.d.ts +3 -0
  83. package/dist/package/declarations/src/views/base/role/index.vue.d.ts +3 -0
  84. package/dist/package/declarations/src/views/base/tenant/index.vue.d.ts +3 -0
  85. package/dist/package/declarations/src/views/base/user/components/dept-tree.vue.d.ts +19 -0
  86. package/dist/package/declarations/src/views/base/user/index.vue.d.ts +3 -0
  87. package/dist/package/declarations/src/views/profile/components/base.vue.d.ts +13 -0
  88. package/dist/package/declarations/src/views/profile/components/password.vue.d.ts +3 -0
  89. package/dist/package/declarations/src/views/profile/components/security.vue.d.ts +15 -0
  90. package/dist/package/declarations/src/views/profile/index.vue.d.ts +3 -0
  91. package/dist/package/declarations/src/views/tool/api-doc/index.vue.d.ts +4 -0
  92. package/dist/package/declarations/src/views/tool/code-gen/code-preview/index.vue.d.ts +3 -0
  93. package/dist/package/declarations/src/views/tool/code-gen/columns/index.vue.d.ts +3 -0
  94. package/dist/package/declarations/src/views/tool/code-gen/columns/option-copy.d.ts +25 -0
  95. package/dist/package/declarations/src/views/tool/code-gen/components/CodeGenProgressDialog.vue.d.ts +16 -0
  96. package/dist/package/declarations/src/views/tool/code-gen/components/CodePreviewPane.vue.d.ts +9 -0
  97. package/dist/package/declarations/src/views/tool/code-gen/config.d.ts +32 -0
  98. package/dist/package/declarations/src/views/tool/code-gen/preview/capabilities.d.ts +20 -0
  99. package/dist/package/declarations/src/views/tool/code-gen/preview/data.d.ts +42 -0
  100. package/dist/package/declarations/src/views/tool/code-gen/preview/index.vue.d.ts +3 -0
  101. package/dist/package/declarations/src/views/tool/code-gen/proto/index.vue.d.ts +3 -0
  102. package/dist/package/declarations/src/views/tool/code-gen/table/index.vue.d.ts +3 -0
  103. package/dist/package/declarations/src/views/tool/project-doc/index.vue.d.ts +4 -0
  104. package/dist/package/src/ai.ts +16 -0
  105. package/dist/package/src/api/base/ai_message.ts +139 -0
  106. package/dist/package/src/api/base/ai_session.ts +77 -0
  107. package/dist/package/src/api/base/ai_tool.ts +22 -0
  108. package/dist/package/src/api/base/oauth.ts +47 -0
  109. package/dist/package/src/api/base/sse.ts +192 -0
  110. package/dist/package/src/api/system/auth.ts +65 -0
  111. package/dist/package/src/api/system/base_api.ts +95 -0
  112. package/dist/package/src/api/system/base_area.ts +73 -0
  113. package/dist/package/src/api/system/base_config.ts +82 -0
  114. package/dist/package/src/api/system/base_dept.ts +83 -0
  115. package/dist/package/src/api/system/base_dict.ts +144 -0
  116. package/dist/package/src/api/system/base_job.ts +125 -0
  117. package/dist/package/src/api/system/base_log.ts +32 -0
  118. package/dist/package/src/api/system/base_menu.ts +83 -0
  119. package/dist/package/src/api/system/base_migration.ts +35 -0
  120. package/dist/package/src/api/system/base_post.ts +83 -0
  121. package/dist/package/src/api/system/base_role.ts +93 -0
  122. package/dist/package/src/api/system/base_tenant.ts +83 -0
  123. package/dist/package/src/api/system/base_user.ts +93 -0
  124. package/dist/package/src/api/system/code_gen.ts +56 -0
  125. package/dist/package/src/api/system/code_gen_column.ts +43 -0
  126. package/dist/package/src/api/system/code_gen_proto.ts +32 -0
  127. package/dist/package/src/api/system/code_gen_sse.ts +33 -0
  128. package/dist/package/src/api/system/code_gen_table.ts +74 -0
  129. package/dist/package/src/api/system/project_document.ts +33 -0
  130. package/dist/package/src/components/Ai.vue +57 -0
  131. package/dist/package/src/index.ts +3 -0
  132. package/dist/package/src/module.ts +17 -0
  133. package/dist/package/src/rpc/base/v1/ai_message.ts +98 -0
  134. package/dist/package/src/rpc/base/v1/ai_session.ts +214 -0
  135. package/dist/package/src/rpc/base/v1/ai_tool.ts +74 -0
  136. package/dist/package/src/rpc/base/v1/oauth.ts +199 -0
  137. package/dist/package/src/rpc/base/v1/sse.ts +22 -0
  138. package/dist/package/src/rpc/common/v1/common.ts +71 -0
  139. package/dist/package/src/rpc/common/v1/enum.ts +71 -0
  140. package/dist/package/src/rpc/common/v1/types.ts +77 -0
  141. package/dist/package/src/rpc/google/protobuf/empty.ts +19 -0
  142. package/dist/package/src/rpc/google/protobuf/timestamp.ts +115 -0
  143. package/dist/package/src/rpc/system/admin/v1/auth.ts +208 -0
  144. package/dist/package/src/rpc/system/admin/v1/base_api.ts +241 -0
  145. package/dist/package/src/rpc/system/admin/v1/base_area.ts +105 -0
  146. package/dist/package/src/rpc/system/admin/v1/base_config.ts +140 -0
  147. package/dist/package/src/rpc/system/admin/v1/base_dept.ts +140 -0
  148. package/dist/package/src/rpc/system/admin/v1/base_dict.ts +249 -0
  149. package/dist/package/src/rpc/system/admin/v1/base_job.ts +206 -0
  150. package/dist/package/src/rpc/system/admin/v1/base_log.ts +101 -0
  151. package/dist/package/src/rpc/system/admin/v1/base_menu.ts +195 -0
  152. package/dist/package/src/rpc/system/admin/v1/base_migration.ts +81 -0
  153. package/dist/package/src/rpc/system/admin/v1/base_post.ts +134 -0
  154. package/dist/package/src/rpc/system/admin/v1/base_role.ts +151 -0
  155. package/dist/package/src/rpc/system/admin/v1/base_tenant.ts +134 -0
  156. package/dist/package/src/rpc/system/admin/v1/base_user.ts +190 -0
  157. package/dist/package/src/rpc/system/admin/v1/code_gen.ts +176 -0
  158. package/dist/package/src/rpc/system/admin/v1/code_gen_column.ts +170 -0
  159. package/dist/package/src/rpc/system/admin/v1/code_gen_proto.ts +104 -0
  160. package/dist/package/src/rpc/system/admin/v1/code_gen_table.ts +179 -0
  161. package/dist/package/src/rpc/system/admin/v1/project_document.ts +79 -0
  162. package/dist/package/src/rpc/system/common/v1/enum.ts +80 -0
  163. package/dist/package/src/typings/swagger-ui-dist.d.ts +28 -0
  164. package/dist/package/src/typings/x-markdown-vue.d.ts +1 -0
  165. package/dist/package/src/views/ai/chat/attachment.ts +65 -0
  166. package/dist/package/src/views/ai/chat/components/AiMarkdown.vue +162 -0
  167. package/dist/package/src/views/ai/chat/components/ChatPanel.vue +1861 -0
  168. package/dist/package/src/views/ai/chat/components/SessionPanel.vue +316 -0
  169. package/dist/package/src/views/ai/chat/components/XSender.vue +554 -0
  170. package/dist/package/src/views/ai/chat/index.vue +848 -0
  171. package/dist/package/src/views/ai/chat/message.ts +416 -0
  172. package/dist/package/src/views/ai/chat/stream.ts +115 -0
  173. package/dist/package/src/views/ai/chat/types.ts +126 -0
  174. package/dist/package/src/views/base/api/index.vue +455 -0
  175. package/dist/package/src/views/base/area/index.vue +269 -0
  176. package/dist/package/src/views/base/config/index.vue +530 -0
  177. package/dist/package/src/views/base/dept/index.vue +461 -0
  178. package/dist/package/src/views/base/dict/index.vue +304 -0
  179. package/dist/package/src/views/base/dict/item.vue +373 -0
  180. package/dist/package/src/views/base/job/index.vue +535 -0
  181. package/dist/package/src/views/base/job/log.vue +202 -0
  182. package/dist/package/src/views/base/log/index.vue +317 -0
  183. package/dist/package/src/views/base/menu/index.vue +944 -0
  184. package/dist/package/src/views/base/migration/index.vue +791 -0
  185. package/dist/package/src/views/base/post/index.vue +324 -0
  186. package/dist/package/src/views/base/role/index.vue +684 -0
  187. package/dist/package/src/views/base/tenant/index.vue +328 -0
  188. package/dist/package/src/views/base/user/components/dept-tree.vue +75 -0
  189. package/dist/package/src/views/base/user/index.vue +783 -0
  190. package/dist/package/src/views/profile/components/base.vue +320 -0
  191. package/dist/package/src/views/profile/components/password.vue +269 -0
  192. package/dist/package/src/views/profile/components/security.vue +443 -0
  193. package/dist/package/src/views/profile/index.vue +199 -0
  194. package/dist/package/src/views/tool/api-doc/index.vue +275 -0
  195. package/dist/package/src/views/tool/code-gen/code-preview/index.vue +233 -0
  196. package/dist/package/src/views/tool/code-gen/columns/index.vue +1456 -0
  197. package/dist/package/src/views/tool/code-gen/columns/option-copy.ts +125 -0
  198. package/dist/package/src/views/tool/code-gen/components/CodeGenProgressDialog.vue +328 -0
  199. package/dist/package/src/views/tool/code-gen/components/CodePreviewPane.vue +42 -0
  200. package/dist/package/src/views/tool/code-gen/config.ts +175 -0
  201. package/dist/package/src/views/tool/code-gen/preview/capabilities.ts +34 -0
  202. package/dist/package/src/views/tool/code-gen/preview/data.ts +331 -0
  203. package/dist/package/src/views/tool/code-gen/preview/index.vue +831 -0
  204. package/dist/package/src/views/tool/code-gen/proto/index.vue +703 -0
  205. package/dist/package/src/views/tool/code-gen/table/index.vue +864 -0
  206. package/dist/package/src/views/tool/project-doc/index.vue +561 -0
  207. package/package.json +60 -0
  208. package/tsconfig.json +13 -0
@@ -0,0 +1,125 @@
1
+ import type { CodeGenColumnOptionConfig } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/code_gen_column";
2
+
3
+ /** 字段选项配置所属范围。 */
4
+ export type CodeGenOptionScope = "query" | "list" | "form";
5
+
6
+ /** 单个范围内参与选项复刻的配置。 */
7
+ export interface CodeGenOptionContainer {
8
+ enabled: boolean;
9
+ component: string;
10
+ option: CodeGenColumnOptionConfig;
11
+ }
12
+
13
+ /** 查询、列表和表单三范围的选项配置集合。 */
14
+ export interface CodeGenOptionCopyColumn {
15
+ query_config: CodeGenOptionContainer;
16
+ list_config: CodeGenOptionContainer;
17
+ form_config: CodeGenOptionContainer;
18
+ }
19
+
20
+ const optionScopes: CodeGenOptionScope[] = ["query", "list", "form"];
21
+ const optionSourceTypes = new Set(["static", "dict", "table"]);
22
+
23
+ /** 返回指定范围的选项配置容器。 */
24
+ export function getCodeGenOptionContainer(column: CodeGenOptionCopyColumn, scope: CodeGenOptionScope) {
25
+ switch (scope) {
26
+ case "query":
27
+ return column.query_config;
28
+ case "list":
29
+ return column.list_config;
30
+ case "form":
31
+ return column.form_config;
32
+ }
33
+ }
34
+
35
+ /** 判断静态选项 JSON 是否至少包含一条完整数据。 */
36
+ function hasCompleteStaticOptions(value: string) {
37
+ try {
38
+ const options = JSON.parse(value) as unknown;
39
+ return (
40
+ Array.isArray(options) &&
41
+ options.length > 0 &&
42
+ options.every(item => {
43
+ if (!item || typeof item !== "object") return false;
44
+ const label = Reflect.get(item, "label");
45
+ const optionValue = Reflect.get(item, "value");
46
+ return (
47
+ (typeof label === "string" || typeof label === "number") &&
48
+ label !== "" &&
49
+ (typeof optionValue === "string" || typeof optionValue === "number" || typeof optionValue === "boolean") &&
50
+ optionValue !== ""
51
+ );
52
+ })
53
+ );
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
58
+
59
+ /** 判断选项配置是否满足当前保存规则并可作为复刻来源。 */
60
+ export function isCompleteCodeGenOptionConfig(option: CodeGenColumnOptionConfig) {
61
+ if (!option.kind) return false;
62
+ if (option.kind === "switch") {
63
+ return (
64
+ option.source_type === "dict" &&
65
+ !!option.source_value &&
66
+ !!option.active_value &&
67
+ !!option.inactive_value &&
68
+ option.active_value !== option.inactive_value
69
+ );
70
+ }
71
+ if (option.active_value || option.inactive_value) return false;
72
+ if (!optionSourceTypes.has(option.source_type) || !option.source_value) return false;
73
+ if (option.kind === "tree") {
74
+ return option.source_type === "table" && !!option.label_field && !!option.value_field && !!option.parent_field;
75
+ }
76
+ if (option.source_type === "static") return hasCompleteStaticOptions(option.source_value);
77
+ if (option.source_type === "table") return !!option.label_field && !!option.value_field;
78
+ return true;
79
+ }
80
+
81
+ /** 将来源选项字段复制到目标的独立配置对象。 */
82
+ function copyCodeGenOption(source: CodeGenOptionContainer, target: CodeGenOptionContainer) {
83
+ target.option = { ...source.option };
84
+ }
85
+
86
+ /** 从第一个相同组件的完整范围复刻选项配置。 */
87
+ export function copyFirstMatchingCodeGenOption(column: CodeGenOptionCopyColumn, targetScope: CodeGenOptionScope) {
88
+ const target = getCodeGenOptionContainer(column, targetScope);
89
+ if (!target.enabled) return false;
90
+ const source = optionScopes
91
+ .filter(scope => scope !== targetScope)
92
+ .map(scope => getCodeGenOptionContainer(column, scope))
93
+ .find(
94
+ item =>
95
+ item.enabled &&
96
+ item.component === target.component &&
97
+ isCompleteCodeGenOptionConfig(item.option)
98
+ );
99
+ if (!source) return false;
100
+ copyCodeGenOption(source, target);
101
+ return true;
102
+ }
103
+
104
+ /** 用当前范围补齐相同组件中尚未完整配置的其他范围。 */
105
+ export function copyCodeGenOptionToEmptyMatches(column: CodeGenOptionCopyColumn, sourceScope: CodeGenOptionScope) {
106
+ const source = getCodeGenOptionContainer(column, sourceScope);
107
+ if (!source.enabled || !isCompleteCodeGenOptionConfig(source.option)) return [];
108
+ return optionScopes.filter(scope => {
109
+ if (scope === sourceScope) return false;
110
+ const target = getCodeGenOptionContainer(column, scope);
111
+ if (!target.enabled || target.component !== source.component || isCompleteCodeGenOptionConfig(target.option)) {
112
+ return false;
113
+ }
114
+ copyCodeGenOption(source, target);
115
+ return true;
116
+ });
117
+ }
118
+
119
+ /** 页面加载时按固定优先级补齐相同组件的空配置。 */
120
+ export function fillMissingCodeGenOptionConfigs(column: CodeGenOptionCopyColumn) {
121
+ return optionScopes.filter(scope => {
122
+ const target = getCodeGenOptionContainer(column, scope);
123
+ return !isCompleteCodeGenOptionConfig(target.option) && copyFirstMatchingCodeGenOption(column, scope);
124
+ });
125
+ }
@@ -0,0 +1,328 @@
1
+ <template>
2
+ <ProDialog
3
+ :model-value="modelValue"
4
+ title="代码生成进度"
5
+ width="min(1080px, 94vw)"
6
+ top="4vh"
7
+ :close-on-click-modal="false"
8
+ :show-footer="false"
9
+ @update:model-value="emit('update:modelValue', $event)"
10
+ >
11
+ <div v-loading="loading" class="progress-dialog">
12
+ <template v-if="task">
13
+ <div class="task-heading">
14
+ <div>
15
+ <strong>{{ task.message }}</strong>
16
+ <span v-if="task.current_table_name">当前:{{ task.current_table_name }}</span>
17
+ </div>
18
+ <el-tag :type="statusMeta(task.status).type" effect="plain">{{ statusMeta(task.status).label }}</el-tag>
19
+ </div>
20
+ <el-progress
21
+ :percentage="percentage(task.completed_steps, task.total_steps)"
22
+ :status="progressStatus(task.status)"
23
+ :stroke-width="12"
24
+ />
25
+ <div class="task-meta">
26
+ <span>{{ task.completed_steps }} / {{ task.total_steps }} 步</span>
27
+ <span>创建:{{ formatTime(task.created_at) }}</span>
28
+ <span v-if="task.finished_at">完成:{{ formatTime(task.finished_at) }}</span>
29
+ </div>
30
+
31
+ <el-collapse v-model="expandedTables" class="table-progress-list">
32
+ <el-collapse-item v-for="table in task.tables" :key="table.table_id" :name="table.table_id">
33
+ <template #title>
34
+ <div class="table-heading">
35
+ <strong>{{ table.table_name }}</strong>
36
+ <span>{{ table.completed_steps }} / {{ table.total_steps }}</span>
37
+ <el-tag :type="statusMeta(table.status).type" size="small" effect="plain">
38
+ {{ statusMeta(table.status).label }}
39
+ </el-tag>
40
+ </div>
41
+ </template>
42
+ <div v-if="table.message" class="table-message">
43
+ <span>{{ table.message }}</span>
44
+ <el-tooltip content="复制错误信息" placement="top">
45
+ <el-button :icon="CopyDocument" link aria-label="复制错误信息" @click.stop="copyMessage(table.message)" />
46
+ </el-tooltip>
47
+ </div>
48
+ <el-table :data="table.steps" row-key="id" size="small" border>
49
+ <el-table-column label="状态" width="86" align="center">
50
+ <template #default="{ row }">
51
+ <el-icon :class="{ 'is-loading': row.status === CodeGenTaskStepStatus.CODE_GEN_TASK_STEP_STATUS_RUNNING }">
52
+ <Loading v-if="row.status === CodeGenTaskStepStatus.CODE_GEN_TASK_STEP_STATUS_RUNNING" />
53
+ <Check v-else-if="row.status === CodeGenTaskStepStatus.CODE_GEN_TASK_STEP_STATUS_SUCCEEDED" />
54
+ <CircleClose v-else-if="row.status === CodeGenTaskStepStatus.CODE_GEN_TASK_STEP_STATUS_FAILED" />
55
+ <Minus v-else-if="row.status === CodeGenTaskStepStatus.CODE_GEN_TASK_STEP_STATUS_SKIPPED" />
56
+ <Clock v-else />
57
+ </el-icon>
58
+ </template>
59
+ </el-table-column>
60
+ <el-table-column prop="label" label="步骤" min-width="130" />
61
+ <el-table-column prop="path" label="文件路径" min-width="260" show-overflow-tooltip />
62
+ <el-table-column prop="message" label="结果" min-width="180" show-overflow-tooltip />
63
+ <el-table-column label="输出" width="90" align="center">
64
+ <template #default="{ row }">
65
+ <el-button v-if="row.output" :icon="Document" link @click="showOutput(row.label, row.output)" />
66
+ </template>
67
+ </el-table-column>
68
+ </el-table>
69
+ </el-collapse-item>
70
+ </el-collapse>
71
+ </template>
72
+ <el-result v-else-if="errorMessage" icon="error" title="任务不可用" :sub-title="errorMessage">
73
+ <template #extra>
74
+ <el-button type="primary" @click="startTracking">重新加载</el-button>
75
+ </template>
76
+ </el-result>
77
+ </div>
78
+
79
+ </ProDialog>
80
+ </template>
81
+
82
+ <script setup lang="ts">
83
+ import { onBeforeUnmount, ref, watch } from "vue";
84
+ import { Check, CircleClose, Clock, CopyDocument, Document, Loading, Minus } from "@element-plus/icons-vue";
85
+ import ProDialog from "@liujitcn/kratos-admin-core/components/Dialog/ProDialog.vue";
86
+ import { defCodeGenService } from "@liujitcn/kratos-admin-system/api/system/code_gen";
87
+ import { subscribeCodeGenProgress, type SseStop } from "@liujitcn/kratos-admin-system/api/system/code_gen_sse";
88
+ import type { CodeGenTask } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/code_gen";
89
+ import { CodeGenTaskStatus, CodeGenTaskStepStatus } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/code_gen";
90
+
91
+ defineOptions({ name: "CodeGenProgressDialog", inheritAttrs: false });
92
+
93
+ /** 代码生成进度弹窗属性。 */
94
+ const props = defineProps<{ modelValue: boolean; taskId: string }>();
95
+
96
+ /** 代码生成进度弹窗事件。 */
97
+ const emit = defineEmits<{
98
+ "update:modelValue": [value: boolean];
99
+ completed: [];
100
+ unavailable: [];
101
+ }>();
102
+
103
+ /** 状态展示信息。 */
104
+ type StatusMeta = { label: string; type: "success" | "warning" | "danger" | "info" };
105
+
106
+ const task = ref<CodeGenTask>();
107
+ const loading = ref(false);
108
+ const errorMessage = ref("");
109
+ const expandedTables = ref<number[]>([]);
110
+ let stopSse: SseStop | undefined;
111
+ let refreshTimer: ReturnType<typeof setInterval> | undefined;
112
+ let completedTaskId = "";
113
+
114
+ /** 启动SSE订阅与三秒轮询兜底。 */
115
+ async function startTracking() {
116
+ stopTracking();
117
+ const taskId = props.taskId;
118
+ await loadTask(false, taskId);
119
+ if (taskId !== props.taskId || !task.value || isFinished(task.value.status)) return;
120
+ stopSse = subscribeCodeGenProgress(taskId, latest => {
121
+ if (taskId === props.taskId) applyTask(latest);
122
+ });
123
+ refreshTimer = setInterval(() => void loadTask(true, taskId), 3000);
124
+ }
125
+
126
+ /** 查询当前任务快照。 */
127
+ async function loadTask(silent = false, taskId = props.taskId) {
128
+ if (!taskId) {
129
+ markUnavailable();
130
+ return;
131
+ }
132
+ if (!silent) loading.value = true;
133
+ try {
134
+ const latest = await defCodeGenService.GetCodeGenTask({ task_id: taskId });
135
+ if (taskId !== props.taskId) return;
136
+ if (!latest.task_id) {
137
+ markUnavailable();
138
+ return;
139
+ }
140
+ applyTask(latest);
141
+ errorMessage.value = "";
142
+ } catch {
143
+ if (taskId === props.taskId && (!silent || !task.value)) markUnavailable();
144
+ } finally {
145
+ if (!silent && taskId === props.taskId) loading.value = false;
146
+ }
147
+ }
148
+
149
+ /** 应用实时或轮询返回的任务快照。 */
150
+ function applyTask(latest: CodeGenTask) {
151
+ task.value = latest;
152
+ const runningTable = latest.tables.find(table => table.status === CodeGenTaskStatus.CODE_GEN_TASK_STATUS_RUNNING);
153
+ if (runningTable && !expandedTables.value.includes(runningTable.table_id)) {
154
+ expandedTables.value = [runningTable.table_id];
155
+ }
156
+ if (isFinished(latest.status)) {
157
+ stopTracking();
158
+ if (completedTaskId !== latest.task_id) {
159
+ completedTaskId = latest.task_id;
160
+ emit("completed");
161
+ }
162
+ }
163
+ }
164
+
165
+ /** 标记任务已过期或无权访问。 */
166
+ function markUnavailable() {
167
+ stopTracking();
168
+ task.value = undefined;
169
+ errorMessage.value = "任务不存在、已过期或无权访问";
170
+ emit("unavailable");
171
+ }
172
+
173
+ /** 停止当前任务跟踪。 */
174
+ function stopTracking() {
175
+ stopSse?.();
176
+ stopSse = undefined;
177
+ if (refreshTimer) clearInterval(refreshTimer);
178
+ refreshTimer = undefined;
179
+ }
180
+
181
+ /** 返回状态标签配置。 */
182
+ function statusMeta(status: CodeGenTaskStatus): StatusMeta {
183
+ if (status === CodeGenTaskStatus.CODE_GEN_TASK_STATUS_RUNNING) return { label: "执行中", type: "warning" };
184
+ if (status === CodeGenTaskStatus.CODE_GEN_TASK_STATUS_SUCCEEDED) return { label: "已完成", type: "success" };
185
+ if (status === CodeGenTaskStatus.CODE_GEN_TASK_STATUS_FAILED) return { label: "失败", type: "danger" };
186
+ return { label: "等待中", type: "info" };
187
+ }
188
+
189
+ /** 返回进度条状态。 */
190
+ function progressStatus(status: CodeGenTaskStatus): "success" | "exception" | undefined {
191
+ if (status === CodeGenTaskStatus.CODE_GEN_TASK_STATUS_SUCCEEDED) return "success";
192
+ if (status === CodeGenTaskStatus.CODE_GEN_TASK_STATUS_FAILED) return "exception";
193
+ return undefined;
194
+ }
195
+
196
+ /** 计算任务完成百分比。 */
197
+ function percentage(completed: number, total: number) {
198
+ return total > 0 ? Math.round((completed / total) * 100) : 0;
199
+ }
200
+
201
+ /** 判断任务是否进入终态。 */
202
+ function isFinished(status: CodeGenTaskStatus) {
203
+ return status === CodeGenTaskStatus.CODE_GEN_TASK_STATUS_SUCCEEDED || status === CodeGenTaskStatus.CODE_GEN_TASK_STATUS_FAILED;
204
+ }
205
+
206
+ /** 格式化任务时间。 */
207
+ function formatTime(value: string) {
208
+ const date = new Date(value);
209
+ return !value || Number.isNaN(date.getTime()) ? "-" : date.toLocaleString();
210
+ }
211
+
212
+ /** 弹出展示命令输出。 */
213
+ function showOutput(title: string, output: string) {
214
+ ElMessageBox.alert(`<pre class="code-gen-command-output">${escapeHTML(output)}</pre>`, title, {
215
+ dangerouslyUseHTMLString: true,
216
+ customClass: "code-gen-output-dialog",
217
+ confirmButtonText: "关闭"
218
+ });
219
+ }
220
+
221
+ /** 复制生成任务的错误信息,便于定位生成命令问题。 */
222
+ async function copyMessage(message: string) {
223
+ try {
224
+ await navigator.clipboard.writeText(message);
225
+ ElMessage.success("错误信息已复制");
226
+ } catch {
227
+ ElMessage.error("复制失败,请手动复制");
228
+ }
229
+ }
230
+
231
+ /** 转义命令输出中的HTML字符。 */
232
+ function escapeHTML(value: string) {
233
+ return value.replace(
234
+ /[&<>"']/g,
235
+ character => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[character]!
236
+ );
237
+ }
238
+
239
+ watch(
240
+ () => props.taskId,
241
+ taskId => {
242
+ if (taskId) {
243
+ // 任务运行期间即使弹窗隐藏,也继续跟踪终态并通知父页面解除生成锁定。
244
+ void startTracking();
245
+ return;
246
+ }
247
+ stopTracking();
248
+ task.value = undefined;
249
+ errorMessage.value = "";
250
+ },
251
+ { immediate: true }
252
+ );
253
+
254
+ onBeforeUnmount(stopTracking);
255
+ </script>
256
+
257
+ <style scoped lang="scss">
258
+ .progress-dialog {
259
+ min-height: 220px;
260
+ }
261
+
262
+ .task-heading,
263
+ .table-heading,
264
+ .task-meta {
265
+ display: flex;
266
+ gap: 12px;
267
+ align-items: center;
268
+ }
269
+
270
+ .task-heading {
271
+ justify-content: space-between;
272
+ margin-bottom: 14px;
273
+ }
274
+
275
+ .task-heading > div {
276
+ display: flex;
277
+ gap: 12px;
278
+ align-items: baseline;
279
+ }
280
+
281
+ .task-meta {
282
+ flex-wrap: wrap;
283
+ justify-content: space-between;
284
+ margin: 10px 0 18px;
285
+ color: var(--el-text-color-secondary);
286
+ font-size: 13px;
287
+ }
288
+
289
+ .table-progress-list {
290
+ max-height: 54vh;
291
+ overflow: auto;
292
+ }
293
+
294
+ .table-heading {
295
+ width: 100%;
296
+ padding-right: 16px;
297
+ }
298
+
299
+ .table-heading strong {
300
+ margin-right: auto;
301
+ }
302
+
303
+ .table-message {
304
+ display: flex;
305
+ gap: 6px;
306
+ align-items: flex-start;
307
+ margin: 0 0 10px;
308
+ color: var(--el-text-color-secondary);
309
+ }
310
+
311
+ .table-message span {
312
+ min-width: 0;
313
+ white-space: pre-wrap;
314
+ word-break: break-word;
315
+ }
316
+ </style>
317
+
318
+ <style lang="scss">
319
+ .code-gen-command-output {
320
+ max-height: 56vh;
321
+ margin: 0;
322
+ overflow: auto;
323
+ font-size: 12px;
324
+ line-height: 1.6;
325
+ text-align: left;
326
+ white-space: pre-wrap;
327
+ }
328
+ </style>
@@ -0,0 +1,42 @@
1
+ <template>
2
+ <el-table v-loading="loading" :data="files" row-key="path" border height="100%">
3
+ <el-table-column type="expand">
4
+ <template #default="{ row }">
5
+ <pre class="code-preview">{{ row.content || row.message }}</pre>
6
+ </template>
7
+ </el-table-column>
8
+ <el-table-column prop="path" label="文件路径" min-width="320" show-overflow-tooltip />
9
+ <el-table-column prop="action" label="动作" width="100" />
10
+ <el-table-column label="状态" width="100" align="center">
11
+ <template #default="{ row }">
12
+ <el-tag :type="row.exists ? 'info' : 'success'" effect="plain">{{ row.exists ? "已存在" : "待创建" }}</el-tag>
13
+ </template>
14
+ </el-table-column>
15
+ <el-table-column prop="message" label="说明" min-width="220" show-overflow-tooltip />
16
+ </el-table>
17
+ </template>
18
+
19
+ <script setup lang="ts">
20
+ import type { CodeGenPreviewFile } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/code_gen";
21
+
22
+ /** 代码预览面板属性。 */
23
+ defineProps<{
24
+ files: CodeGenPreviewFile[];
25
+ loading: boolean;
26
+ }>();
27
+ </script>
28
+
29
+ <style scoped lang="scss">
30
+ .code-preview {
31
+ max-height: 56vh;
32
+ padding: 14px;
33
+ margin: 0;
34
+ overflow: auto;
35
+ font-family: var(--el-font-family-monospace, monospace);
36
+ font-size: 12px;
37
+ line-height: 1.6;
38
+ color: var(--el-text-color-primary);
39
+ white-space: pre;
40
+ background: var(--el-fill-color-light);
41
+ }
42
+ </style>
@@ -0,0 +1,175 @@
1
+ import type { FormRules } from "element-plus";
2
+ import type { ProFormComponentType, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
3
+ import type {
4
+ CodeGenColumnFormConfig,
5
+ CodeGenColumnListConfig,
6
+ CodeGenColumnOptionConfig,
7
+ CodeGenColumnQueryConfig
8
+ } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/code_gen_column";
9
+ import type { CodeGenLeftTreeConfig, CodeGenTableForm } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/code_gen_table";
10
+ import { CodeGenTableStatus } from "@liujitcn/kratos-admin-system/rpc/system/common/v1/enum";
11
+
12
+ /** 代码生成表配置页面类型选项。 */
13
+ export const codeGenPageTypeOptions: ProFormOption[] = [
14
+ { label: "普通表格", value: "normal" },
15
+ { label: "树形表格", value: "tree" },
16
+ { label: "树形懒加载", value: "tree_lazy" },
17
+ { label: "左树右表", value: "left_tree" }
18
+ ];
19
+
20
+ /** 判断页面类型是否使用树形表格配置。 */
21
+ export function isCodeGenTreePageType(pageType?: string) {
22
+ return pageType === "tree" || pageType === "tree_lazy";
23
+ }
24
+
25
+ /** 左树数据源类型选项。 */
26
+ export const codeGenSourceTypeOptions: ProFormOption[] = [
27
+ { label: "静态数据", value: "static" },
28
+ { label: "字典", value: "dict" },
29
+ { label: "数据表", value: "table" }
30
+ ];
31
+
32
+ /** 查询操作符选项。 */
33
+ export const codeGenQueryOperatorOptions: ProFormOption[] = [
34
+ { label: "等于", value: "eq" },
35
+ { label: "模糊", value: "like" },
36
+ { label: "区间", value: "between" }
37
+ ];
38
+
39
+ /** 查询组件选项。 */
40
+ export const codeGenQueryComponentOptions: ProFormOption[] = [
41
+ { label: "输入框", value: "input" },
42
+ { label: "数字输入", value: "input-number" },
43
+ { label: "下拉选择", value: "select" },
44
+ { label: "树形选择", value: "tree-select" },
45
+ { label: "日期", value: "date-picker" }
46
+ ];
47
+
48
+ /** 列表展示组件选项。 */
49
+ export const codeGenListComponentOptions: ProFormOption[] = [
50
+ { label: "文本", value: "text" },
51
+ { label: "开关", value: "switch" },
52
+ { label: "下拉", value: "select" },
53
+ { label: "树形", value: "tree-select" },
54
+ { label: "图片", value: "image" },
55
+ { label: "金额", value: "money" },
56
+ { label: "日期", value: "date" }
57
+ ];
58
+
59
+ /** ProForm 全量组件类型对应的中文名称。 */
60
+ const codeGenFormComponentLabels: Record<ProFormComponentType, string> = {
61
+ input: "输入框",
62
+ password: "密码框",
63
+ textarea: "文本域",
64
+ "input-number": "数字输入",
65
+ segmented: "分段选择",
66
+ switch: "开关",
67
+ checkbox: "复选框",
68
+ select: "下拉选择",
69
+ dict: "字典选择",
70
+ "radio-group": "单选组",
71
+ "checkbox-group": "复选组",
72
+ "tree-select": "树形选择",
73
+ "date-picker": "日期选择",
74
+ "cron-expression": "Cron 表达式",
75
+ transfer: "穿梭框",
76
+ "image-upload": "单图上传",
77
+ "images-upload": "多图上传",
78
+ "file-upload": "单文件上传",
79
+ "files-upload": "多文件上传",
80
+ "rich-text": "富文本",
81
+ "dynamic-list": "动态列表",
82
+ "kv-list": "键值列表",
83
+ slot: "自定义插槽"
84
+ };
85
+
86
+ /** 表单录入组件选项,保持与 ProForm 支持类型完整一致。 */
87
+ export const codeGenFormComponentOptions: ProFormOption[] = (
88
+ Object.entries(codeGenFormComponentLabels) as Array<[ProFormComponentType, string]>
89
+ ).map(([value, label]) => ({ label, value }));
90
+
91
+ /** 代码生成表配置校验规则。 */
92
+ export const codeGenTableRules: FormRules = {
93
+ name: [{ required: true, max: 128, message: "请选择业务表", trigger: "change" }],
94
+ business_module: [
95
+ { required: true, max: 64, pattern: /^[a-z][a-z0-9_]*$/, message: "请选择有效业务模块", trigger: "change" }
96
+ ],
97
+ comment: [{ max: 128, message: "业务表描述不能超过128个字符", trigger: "blur" }],
98
+ parent_menu_id: [{ required: true, type: "number", min: 1, message: "请选择父级菜单", trigger: "change" }],
99
+ page_type: [{ required: true, max: 32, message: "请选择页面类型", trigger: "change" }],
100
+ parent_column: [{ required: true, max: 64, message: "请选择父节点字段", trigger: "change" }],
101
+ tree_label_column: [{ required: true, max: 64, message: "请选择树显示字段", trigger: "change" }],
102
+ remark: [{ max: 500, message: "备注不能超过500个字符", trigger: "blur" }],
103
+ "left_tree_config.table_name": [{ required: true, message: "请选择左树数据表", trigger: "change" }],
104
+ "left_tree_config.filter_column": [{ required: true, message: "请选择筛选字段", trigger: "change" }],
105
+ "left_tree_config.parent_column": [{ required: true, message: "请配置左树父字段", trigger: ["blur", "change"] }],
106
+ "left_tree_config.label_column": [{ required: true, message: "请配置左树显示字段", trigger: ["blur", "change"] }],
107
+ "left_tree_config.value_column": [{ required: true, message: "请配置左树值字段", trigger: ["blur", "change"] }]
108
+ };
109
+
110
+ /** 创建默认左树右表页面配置。 */
111
+ export function createDefaultCodeGenLeftTreeConfig(): CodeGenLeftTreeConfig {
112
+ return {
113
+ table_name: "",
114
+ filter_column: "",
115
+ parent_column: "",
116
+ label_column: "",
117
+ value_column: "",
118
+ comment: "",
119
+ lazy: false
120
+ };
121
+ }
122
+
123
+ /** 创建代码生成表配置默认表单。 */
124
+ export function createDefaultCodeGenTableForm(): CodeGenTableForm {
125
+ return {
126
+ id: 0,
127
+ name: "",
128
+ comment: "",
129
+ business_module: "",
130
+ page_type: "normal",
131
+ parent_column: "",
132
+ tree_label_column: "",
133
+ left_tree_config: createDefaultCodeGenLeftTreeConfig(),
134
+ gen_backend: true,
135
+ gen_frontend: true,
136
+ gen_sql: true,
137
+ parent_menu_id: 0,
138
+ status: CodeGenTableStatus.DRAFT_CGTS,
139
+ remark: ""
140
+ };
141
+ }
142
+
143
+ /** 创建默认字段查询配置。 */
144
+ export function createDefaultCodeGenQueryConfig(): CodeGenColumnQueryConfig {
145
+ return { enabled: false, operator: "like", component: "input", option: createDefaultCodeGenOptionConfig() };
146
+ }
147
+
148
+ /** 创建默认字段列表配置。 */
149
+ export function createDefaultCodeGenListConfig(): CodeGenColumnListConfig {
150
+ return {
151
+ enabled: true,
152
+ component: "text",
153
+ option: createDefaultCodeGenOptionConfig()
154
+ };
155
+ }
156
+
157
+ /** 创建默认字段表单配置。 */
158
+ export function createDefaultCodeGenFormConfig(): CodeGenColumnFormConfig {
159
+ return { enabled: true, component: "input", required: false, multiple: false, option: createDefaultCodeGenOptionConfig() };
160
+ }
161
+
162
+ /** 创建一份独立的字段选项配置。 */
163
+ export function createDefaultCodeGenOptionConfig(): CodeGenColumnOptionConfig {
164
+ return {
165
+ kind: "",
166
+ source_type: "",
167
+ source_value: "",
168
+ label_field: "",
169
+ value_field: "",
170
+ parent_field: "",
171
+ active_value: "",
172
+ inactive_value: "",
173
+ lazy: false
174
+ };
175
+ }