@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,461 @@
1
+ <template>
2
+ <div class="table-box">
3
+ <ProTable
4
+ ref="proTable"
5
+ :key="isDefaultTenant ? 'default-tenant' : 'normal-tenant'"
6
+ row-key="id"
7
+ :indent="20"
8
+ :columns="columns"
9
+ :header-actions="headerActions"
10
+ :request-api="requestBaseDeptTable"
11
+ :pagination="false"
12
+ :default-expand-all="false"
13
+ :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
14
+ />
15
+
16
+ <FormDialog
17
+ v-model="dialog.visible"
18
+ ref="formDialogRef"
19
+ :title="dialog.title"
20
+ width="600px"
21
+ :model="formData"
22
+ :fields="formFields"
23
+ :rules="rules"
24
+ label-width="90px"
25
+ @confirm="handleSubmit"
26
+ @close="handleCloseDialog"
27
+ />
28
+ </div>
29
+ </template>
30
+
31
+ <script setup lang="ts">
32
+ import { computed, reactive, ref } from "vue";
33
+ import { ElMessage, ElMessageBox } from "element-plus";
34
+ import { CirclePlus, Delete, EditPen } from "@element-plus/icons-vue";
35
+ import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
36
+ import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
37
+ import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
38
+ import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
39
+ import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
40
+ import { defBaseDeptService } from "@liujitcn/kratos-admin-system/api/system/base_dept";
41
+ import { defBaseTenantService } from "@liujitcn/kratos-admin-system/api/system/base_tenant";
42
+ import { useUserStore } from "@liujitcn/kratos-admin-core/stores/runtime";
43
+ import type { BaseDept, BaseDeptForm } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_dept";
44
+ import type { SelectOptionResponse_Option, TreeOptionResponse_Option } from "@liujitcn/kratos-admin-system/rpc/common/v1/common";
45
+ import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
46
+ import { normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
47
+ import { DEFAULT_TENANT_CODE, requestTenantOptions } from "@liujitcn/kratos-admin-core/tenant";
48
+
49
+ defineOptions({
50
+ name: "BaseDept",
51
+ inheritAttrs: false
52
+ });
53
+
54
+ /** 部门表单状态,新增时租户必须由默认租户管理员显式选择。 */
55
+ type BaseDeptFormState = Omit<BaseDeptForm, "tenant_id"> & {
56
+ /** 租户ID。 */
57
+ tenant_id?: number;
58
+ };
59
+
60
+ const { BUTTONS } = useAuthButtons();
61
+ const userStore = useUserStore();
62
+ const proTable = ref<ProTableInstance>();
63
+ const formDialogRef = ref<InstanceType<typeof FormDialog>>();
64
+
65
+ const dialog = reactive({
66
+ title: "",
67
+ visible: false
68
+ });
69
+
70
+ const deptOptions = ref<TreeOptionResponse_Option[]>([]);
71
+ const tenantOptions = ref<SelectOptionResponse_Option[]>([]);
72
+ const currentTenantId = ref<number | undefined>();
73
+ const statusOptions: ProFormOption[] = [
74
+ { label: "启用", value: Status.ENABLE },
75
+ { label: "禁用", value: Status.DISABLE }
76
+ ];
77
+
78
+ const formData = reactive<BaseDeptFormState>({
79
+ /** 部门ID */
80
+ id: 0,
81
+ /** 租户ID */
82
+ tenant_id: undefined,
83
+ /** 父节点ID */
84
+ parent_id: 0,
85
+ /** 部门名称 */
86
+ name: "",
87
+ /** 排序 */
88
+ sort: 1,
89
+ /** 菜单状态 */
90
+ status: Status.ENABLE,
91
+ /** 备注 */
92
+ remark: ""
93
+ });
94
+
95
+ const rules = reactive({
96
+ tenant_id: [{ required: true, message: "所属租户不能为空", trigger: "change" }],
97
+ parent_id: [{ required: true, message: "上级部门不能为空", trigger: "change" }],
98
+ name: [
99
+ { required: true, message: "部门名称不能为空", trigger: "blur" },
100
+ { max: 255, message: "部门名称不能超过 255 个字符", trigger: "blur" }
101
+ ],
102
+ sort: [{ required: true, type: "number", min: 1, message: "排序必须大于 0", trigger: "blur" }],
103
+ status: [{ required: true, message: "状态不能为空", trigger: "change" }]
104
+ });
105
+
106
+ /** 当前登录账号是否默认租户。 */
107
+ const isDefaultTenant = computed(() => userStore.userInfo.tenant_code === DEFAULT_TENANT_CODE);
108
+
109
+ /** 部门表单字段配置。 */
110
+ const formFields = computed<ProFormField[]>(() => [
111
+ {
112
+ prop: "tenant_id",
113
+ label: "所属租户",
114
+ component: "select",
115
+ props: {
116
+ placeholder: "请选择所属租户",
117
+ filterable: true,
118
+ disabled: Boolean(formData.id),
119
+ onChange: handleFormTenantChange
120
+ },
121
+ visible: () => isDefaultTenant.value,
122
+ options: tenantOptions.value
123
+ },
124
+ {
125
+ prop: "parent_id",
126
+ label: "上级部门",
127
+ component: "tree-select",
128
+ options: deptOptions.value,
129
+ props: {
130
+ placeholder: "选择上级部门",
131
+ filterable: true,
132
+ checkStrictly: true,
133
+ renderAfterExpand: false,
134
+ style: { width: "100%" }
135
+ }
136
+ },
137
+ { prop: "name", label: "部门名称", component: "input", props: { placeholder: "请输入部门名称" } },
138
+ {
139
+ prop: "sort",
140
+ label: "排序",
141
+ component: "input-number",
142
+ props: { min: 1, precision: 0, step: 1, controlsPosition: "right", style: { width: "100%" } }
143
+ },
144
+ { prop: "remark", label: "备注", component: "textarea", props: { placeholder: "请输入备注" } },
145
+ { prop: "status", label: "状态", component: "radio-group", options: statusOptions }
146
+ ]);
147
+
148
+ /** 部门树表格列配置。 */
149
+ const columns = computed<ColumnProps[]>(() => [
150
+ { type: "selection", width: 55 },
151
+ ...(isDefaultTenant.value
152
+ ? ([
153
+ {
154
+ prop: "tenant_id",
155
+ label: "租户",
156
+ minWidth: 140,
157
+ showOverflowTooltip: true,
158
+ search: { el: "select", key: "tenant_id", props: { filterable: true }, order: 1 },
159
+ enum: requestTenantOptions
160
+ }
161
+ ] satisfies ColumnProps[])
162
+ : []),
163
+ { prop: "name", label: "部门名称", minWidth: 140, align: "left", search: { el: "input" } },
164
+ { prop: "remark", label: "备注", minWidth: 160, search: { el: "input" } },
165
+ { prop: "sort", label: "排序", minWidth: 90, align: "right" },
166
+ {
167
+ prop: "status",
168
+ label: "状态",
169
+ minWidth: 100,
170
+ search: { el: "select" },
171
+ cellType: "status",
172
+ statusProps: {
173
+ activeValue: Status.ENABLE,
174
+ inactiveValue: Status.DISABLE,
175
+ activeText: "启用",
176
+ inactiveText: "禁用",
177
+ disabled: () => !BUTTONS.value["base:dept:status"],
178
+ beforeChange: scope => handleBeforeSetStatus(scope.row as BaseDept)
179
+ }
180
+ },
181
+ { prop: "created_at", label: "创建时间", minWidth: 180 },
182
+ { prop: "updated_at", label: "更新时间", minWidth: 180 },
183
+ {
184
+ prop: "operation",
185
+ label: "操作",
186
+ width: 220,
187
+ fixed: "right",
188
+ cellType: "actions",
189
+ actions: [
190
+ {
191
+ label: "新增",
192
+ type: "primary",
193
+ link: true,
194
+ icon: CirclePlus,
195
+ hidden: () => !BUTTONS.value["base:dept:create"],
196
+ params: scope => ({ parent_id: scope.row.id, tenantId: scope.row.tenant_id }),
197
+ onClick: (_, params) =>
198
+ handleOpenDialog((params?.parent_id as number | undefined) ?? 0, undefined, params?.tenantId as number | undefined)
199
+ },
200
+ {
201
+ label: "编辑",
202
+ type: "primary",
203
+ link: true,
204
+ icon: EditPen,
205
+ hidden: () => !BUTTONS.value["base:dept:update"],
206
+ params: scope => ({
207
+ parent_id: scope.row.parent_id,
208
+ deptId: scope.row.id
209
+ }),
210
+ onClick: (_, params) => handleOpenDialog(params?.parent_id as number | undefined, params?.deptId as number | undefined)
211
+ },
212
+ {
213
+ label: "删除",
214
+ type: "danger",
215
+ link: true,
216
+ icon: Delete,
217
+ hidden: () => !BUTTONS.value["base:dept:delete"],
218
+ onClick: scope => handleDelete(scope.row as BaseDept)
219
+ }
220
+ ]
221
+ }
222
+ ]);
223
+
224
+ /** 部门顶部按钮配置。 */
225
+ const headerActions: HeaderActionProps[] = [
226
+ {
227
+ label: "新增",
228
+ type: "success",
229
+ icon: CirclePlus,
230
+ hidden: () => !BUTTONS.value["base:dept:create"],
231
+ onClick: () => handleOpenDialog(0)
232
+ },
233
+ {
234
+ label: "删除",
235
+ type: "danger",
236
+ icon: Delete,
237
+ hidden: () => !BUTTONS.value["base:dept:delete"],
238
+ disabled: scope => !scope.selectedList.length,
239
+ onClick: scope => handleDelete(scope.selectedList as BaseDept[])
240
+ }
241
+ ];
242
+
243
+ /**
244
+ * 按搜索条件递归过滤部门树,命中父节点或子节点时保留当前节点。
245
+ */
246
+ function filterDeptTree(deptList: BaseDept[], keywordMap: { name: string; remark: string; status: string }) {
247
+ const nameKeyword = keywordMap.name.trim().toLowerCase();
248
+ const remarkKeyword = keywordMap.remark.trim().toLowerCase();
249
+ const statusKeyword = keywordMap.status.trim();
250
+
251
+ return deptList.reduce<BaseDept[]>((result, item) => {
252
+ const children = filterDeptTree(item.children ?? [], keywordMap);
253
+ const name = item.name?.toLowerCase() ?? "";
254
+ const remark = item.remark?.toLowerCase() ?? "";
255
+ const status = String(item.status ?? "");
256
+ const matched =
257
+ (!nameKeyword || name.includes(nameKeyword)) &&
258
+ (!remarkKeyword || remark.includes(remarkKeyword)) &&
259
+ (!statusKeyword || status === statusKeyword);
260
+
261
+ if (!matched && !children.length) return result;
262
+
263
+ result.push({
264
+ ...item,
265
+ children
266
+ });
267
+ return result;
268
+ }, []);
269
+ }
270
+
271
+ /**
272
+ * 请求部门树数据,并按搜索条件过滤树形结构。
273
+ */
274
+ async function requestBaseDeptTable(params: Record<string, string>) {
275
+ currentTenantId.value = params.tenant_id ? Number(params.tenant_id) : undefined;
276
+ const data = await defBaseDeptService.TreeBaseDept({ tenant_id: currentTenantId.value });
277
+ const keywordMap = {
278
+ name: params.name ?? "",
279
+ remark: params.remark ?? "",
280
+ status: String(params.status ?? "")
281
+ };
282
+ return { data: filterDeptTree(data.base_depts ?? [], keywordMap) };
283
+ }
284
+
285
+ /**
286
+ * 刷新部门树表格。
287
+ */
288
+ function refreshTable() {
289
+ proTable.value?.getTableList();
290
+ }
291
+
292
+ /**
293
+ * 加载部门下拉树数据,供弹窗选择上级部门。
294
+ */
295
+ async function loadDeptOptions() {
296
+ // 默认租户未选择目标租户时仅保留顶级部门,避免混入其他租户的部门树。
297
+ if (isDefaultTenant.value && !formData.tenant_id) {
298
+ deptOptions.value = [{ value: 0, label: "顶级部门", disabled: false, has_children: true, children: [] }];
299
+ return;
300
+ }
301
+ const optionBaseDeptResponse = await defBaseDeptService.OptionBaseDept({
302
+ tenant_id: isDefaultTenant.value ? formData.tenant_id : undefined
303
+ });
304
+ deptOptions.value = [
305
+ {
306
+ value: 0,
307
+ label: "顶级部门",
308
+ disabled: false,
309
+ has_children: true,
310
+ children: optionBaseDeptResponse.list
311
+ }
312
+ ];
313
+ }
314
+
315
+ /**
316
+ * 加载租户下拉选项。
317
+ */
318
+ async function loadTenantOptions() {
319
+ if (!isDefaultTenant.value || tenantOptions.value.length) return;
320
+ const response = await defBaseTenantService.OptionBaseTenant({ keyword: "" });
321
+ tenantOptions.value = response.list ?? [];
322
+ }
323
+
324
+ /**
325
+ * 切换表单租户时重新加载对应租户的上级部门树。
326
+ */
327
+ async function handleFormTenantChange() {
328
+ formData.parent_id = 0;
329
+ await loadDeptOptions();
330
+ }
331
+
332
+ /**
333
+ * 打开部门弹窗。
334
+ */
335
+ async function handleOpenDialog(parent_id?: number, deptId?: number, tenantId?: number) {
336
+ resetForm();
337
+ await loadTenantOptions();
338
+ if (deptId) {
339
+ dialog.title = "修改部门";
340
+ dialog.visible = true;
341
+ defBaseDeptService.GetBaseDept({ id: deptId }).then(async data => {
342
+ Object.assign(formData, data);
343
+ await loadDeptOptions();
344
+ });
345
+ return;
346
+ }
347
+
348
+ // 从部门行新增子部门时,继承父部门租户并加载同租户上级部门树。
349
+ formData.tenant_id = tenantId;
350
+ await loadDeptOptions();
351
+ dialog.title = "新增部门";
352
+ dialog.visible = true;
353
+ formData.parent_id = parent_id ?? 0;
354
+ }
355
+
356
+ /**
357
+ * 关闭部门弹窗。
358
+ */
359
+ function handleCloseDialog() {
360
+ dialog.visible = false;
361
+ resetForm();
362
+ }
363
+
364
+ /**
365
+ * 重置部门表单。
366
+ */
367
+ function resetForm() {
368
+ formDialogRef.value?.resetFields();
369
+ formDialogRef.value?.clearValidate();
370
+ formData.id = 0;
371
+ formData.tenant_id = undefined;
372
+ formData.parent_id = 0;
373
+ formData.name = "";
374
+ formData.sort = 1;
375
+ formData.status = Status.ENABLE;
376
+ formData.remark = "";
377
+ deptOptions.value = [];
378
+ }
379
+
380
+ /**
381
+ * 提交部门表单。
382
+ */
383
+ function handleSubmit() {
384
+ formDialogRef.value?.validate()?.then(valid => {
385
+ if (!valid) return;
386
+
387
+ const submitData = JSON.parse(JSON.stringify(formData)) as BaseDeptForm;
388
+ const request = submitData.id
389
+ ? defBaseDeptService.UpdateBaseDept({ base_dept: submitData })
390
+ : defBaseDeptService.CreateBaseDept({ base_dept: submitData });
391
+ request.then(() => {
392
+ ElMessage.success(submitData.id ? "修改部门成功" : "新增部门成功");
393
+ handleCloseDialog();
394
+ refreshTable();
395
+ });
396
+ });
397
+ }
398
+
399
+ /**
400
+ * 在部门状态切换前先完成确认与接口调用,避免首屏渲染触发误操作。
401
+ */
402
+ async function handleBeforeSetStatus(row: BaseDept) {
403
+ const nextStatus = row.status === Status.ENABLE ? Status.DISABLE : Status.ENABLE;
404
+ const text = nextStatus === Status.ENABLE ? "启用" : "禁用";
405
+ const deptName = row.name || `ID:${row.id}`;
406
+ try {
407
+ await ElMessageBox.confirm(`是否确定${text}部门?\n部门名称:${deptName}`, "提示", {
408
+ confirmButtonText: "确认",
409
+ cancelButtonText: "取消",
410
+ type: "warning"
411
+ });
412
+ await defBaseDeptService.SetBaseDeptStatus({ id: row.id, status: nextStatus });
413
+ ElMessage.success(`${text}成功`);
414
+ refreshTable();
415
+ return true;
416
+ } catch {
417
+ return false;
418
+ }
419
+ }
420
+
421
+ /**
422
+ * 删除部门,兼容单项删除与批量删除。
423
+ */
424
+ function handleDelete(selected?: number | string | Array<number | string> | BaseDept | BaseDept[]) {
425
+ const deptList = Array.isArray(selected)
426
+ ? (selected.filter(item => typeof item === "object") as BaseDept[])
427
+ : selected && typeof selected === "object"
428
+ ? [selected as BaseDept]
429
+ : [];
430
+ const deptIds = (
431
+ deptList.length ? deptList.map(item => item.id) : normalizeSelectedIds(selected as number | string | Array<number | string>)
432
+ ).join(",");
433
+ if (!deptIds) {
434
+ ElMessage.warning("请勾选删除项");
435
+ return;
436
+ }
437
+
438
+ const confirmMessage = deptList.length
439
+ ? deptList.length === 1
440
+ ? `是否确定删除部门?\n部门名称:${deptList[0].name || `ID:${deptList[0].id}`}`
441
+ : `确认删除已选中的 ${deptList.length} 个部门吗?`
442
+ : "确认删除已选中的部门吗?";
443
+
444
+ ElMessageBox.confirm(confirmMessage, "警告", {
445
+ confirmButtonText: "确定",
446
+ cancelButtonText: "取消",
447
+ type: "warning"
448
+ }).then(
449
+ () => {
450
+ defBaseDeptService.DeleteBaseDept({ id: deptIds }).then(() => {
451
+ ElMessage.success("删除部门成功");
452
+ refreshTable();
453
+ });
454
+ },
455
+ () => {
456
+ ElMessage.info("已取消删除部门");
457
+ }
458
+ );
459
+ }
460
+
461
+ </script>