@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,783 @@
1
+ <!-- 用户管理 -->
2
+ <template>
3
+ <div class="main-box">
4
+ <TreeFilter
5
+ :key="`dept-filter-${selectedTenantId ?? 0}`"
6
+ label="name"
7
+ title="部门列表"
8
+ :request-api="requestDeptTreeFilter"
9
+ :show-all="false"
10
+ :default-value="deptFilterValue"
11
+ @change="changeTreeFilter"
12
+ />
13
+
14
+ <div class="table-box">
15
+ <ProTable
16
+ ref="proTable"
17
+ :key="`user-table-${isDefaultTenant ? 'default-tenant' : 'current'}`"
18
+ row-key="id"
19
+ :columns="columns"
20
+ :header-actions="headerActions"
21
+ :request-api="requestBaseUserTable"
22
+ :init-param="initParam"
23
+ />
24
+ </div>
25
+
26
+ <FormDialog
27
+ v-model="dialog.visible"
28
+ ref="formDialogRef"
29
+ :title="dialog.title"
30
+ width="800px"
31
+ :model="formData"
32
+ :fields="formFields"
33
+ :rules="rules"
34
+ label-width="90px"
35
+ @confirm="handleSubmit"
36
+ @close="handleCloseDialog"
37
+ >
38
+ <template #passwordStrength>
39
+ <PasswordStrength :password="formData.pwd" />
40
+ </template>
41
+ </FormDialog>
42
+
43
+ <FormDialog
44
+ v-model="resetPwdDialog.visible"
45
+ ref="resetPwdFormDialogRef"
46
+ :title="resetPwdDialog.title"
47
+ width="520px"
48
+ :model="resetPwdForm"
49
+ :fields="resetPwdFields"
50
+ :rules="resetPwdRules"
51
+ label-width="90px"
52
+ @confirm="handleConfirmResetPassword"
53
+ @close="handleCloseResetPasswordDialog"
54
+ >
55
+ <template #resetPwdStrength>
56
+ <PasswordStrength :password="resetPwdForm.pwd" />
57
+ </template>
58
+ </FormDialog>
59
+ </div>
60
+ </template>
61
+
62
+ <script setup lang="ts">
63
+ import { computed, reactive, ref } from "vue";
64
+ import { useDebounceFn } from "@vueuse/core";
65
+ import { ElMessage, ElMessageBox } from "element-plus";
66
+ import { CirclePlus, Delete, EditPen, RefreshLeft } from "@element-plus/icons-vue";
67
+ import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
68
+ import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
69
+ import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
70
+ import PasswordStrength from "@liujitcn/kratos-admin-core/components/PasswordStrength/index.vue";
71
+ import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
72
+ import TreeFilter from "@liujitcn/kratos-admin-core/components/TreeFilter/index.vue";
73
+ import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
74
+ import { defBaseUserService } from "@liujitcn/kratos-admin-system/api/system/base_user";
75
+ import type { BaseUser, BaseUserForm, PageBaseUserRequest, ResetBaseUserPasswordRequest } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_user";
76
+ import { defBaseDeptService } from "@liujitcn/kratos-admin-system/api/system/base_dept";
77
+ import { defBaseRoleService } from "@liujitcn/kratos-admin-system/api/system/base_role";
78
+ import { defBasePostService } from "@liujitcn/kratos-admin-system/api/system/base_post";
79
+ import { defBaseTenantService } from "@liujitcn/kratos-admin-system/api/system/base_tenant";
80
+ import type { SelectOptionResponse_Option, TreeOptionResponse_Option } from "@liujitcn/kratos-admin-system/rpc/common/v1/common";
81
+ import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
82
+ import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
83
+ import {
84
+ PASSWORD_CRYPTO_SCENE,
85
+ PASSWORD_STRENGTH_ERROR_MESSAGE,
86
+ encryptPassword,
87
+ validatePasswordStrengthValue
88
+ } from "@liujitcn/kratos-admin-core/security";
89
+ import { DEFAULT_TENANT_CODE, requestTenantOptions } from "@liujitcn/kratos-admin-core/tenant";
90
+ import { useUserStore } from "@liujitcn/kratos-admin-core/stores/runtime";
91
+
92
+ /** 用户表单状态,前端保留明文密码并在提交前加密。 */
93
+ interface BaseUserFormState extends Omit<BaseUserForm, "dept_id" | "post_id" | "pwd" | "role_id" | "tenant_id"> {
94
+ /** 租户ID,默认租户新增时必须由管理员显式选择。 */
95
+ tenant_id?: number;
96
+ /** 部门ID,未选择时保持空白。 */
97
+ dept_id?: number;
98
+ /** 岗位ID,未选择时保持空白。 */
99
+ post_id?: number;
100
+ /** 角色ID,未选择时保持空白。 */
101
+ role_id?: number;
102
+ /** 密码明文只保留在前端表单中,提交前转换为密码密文。 */
103
+ pwd: string;
104
+ }
105
+
106
+ /** 重置用户密码表单状态,前端保留明文密码并在提交前加密。 */
107
+ interface ResetBaseUserPasswordFormState extends Omit<ResetBaseUserPasswordRequest, "pwd"> {
108
+ /** 密码明文只保留在前端表单中,提交前转换为密码密文。 */
109
+ pwd: string;
110
+ }
111
+
112
+ defineOptions({
113
+ name: "BaseUser",
114
+ inheritAttrs: false
115
+ });
116
+
117
+ /** 用户管理左侧部门筛选树节点。 */
118
+ type DeptFilterNode = {
119
+ id: string;
120
+ name: string;
121
+ children?: DeptFilterNode[];
122
+ };
123
+
124
+ const { BUTTONS } = useAuthButtons();
125
+ const userStore = useUserStore();
126
+ const proTable = ref<ProTableInstance>();
127
+ const formDialogRef = ref<InstanceType<typeof FormDialog>>();
128
+ const resetPwdFormDialogRef = ref<InstanceType<typeof FormDialog>>();
129
+
130
+ const initParam = reactive({
131
+ dept_id: undefined as number | undefined
132
+ });
133
+ const selectedTenantId = ref<number | undefined>();
134
+ const deptFilterValue = ref("");
135
+
136
+ const dialog = reactive({
137
+ visible: false,
138
+ title: "新增用户"
139
+ });
140
+ const resetPwdDialog = reactive({
141
+ visible: false,
142
+ title: "重置密码"
143
+ });
144
+
145
+ const formData = reactive<BaseUserFormState>({
146
+ /** 用户ID */
147
+ id: 0,
148
+ /** 租户ID */
149
+ tenant_id: undefined,
150
+ /** 用户账号 */
151
+ user_name: "",
152
+ /** 用户编号 */
153
+ user_code: "",
154
+ /** 用户昵称 */
155
+ nick_name: "",
156
+ /** 角色ID */
157
+ role_id: undefined,
158
+ /** 部门ID */
159
+ dept_id: undefined,
160
+ /** 岗位ID */
161
+ post_id: undefined,
162
+ /** 手机号 */
163
+ phone: "",
164
+ /** 密码 */
165
+ pwd: "",
166
+ /** 性别 */
167
+ gender: 3,
168
+ /** 头像 */
169
+ avatar: "",
170
+ /** 用户状态 */
171
+ status: Status.ENABLE,
172
+ /** 备注名 */
173
+ remark: ""
174
+ });
175
+ const resetPwdForm = reactive<ResetBaseUserPasswordFormState>({
176
+ id: 0,
177
+ pwd: ""
178
+ });
179
+ const resetPwdTargetName = ref("");
180
+
181
+ const rules = reactive({
182
+ tenant_id: [{ required: true, message: "所属租户不能为空", trigger: "change" }],
183
+ user_name: [
184
+ { required: true, message: "用户账号不能为空", trigger: "blur" },
185
+ { max: 50, message: "用户账号不能超过 50 个字符", trigger: "blur" }
186
+ ],
187
+ user_code: [
188
+ { required: true, message: "用户编号不能为空", trigger: "blur" },
189
+ { max: 30, message: "用户编号不能超过 30 个字符", trigger: "blur" }
190
+ ],
191
+ nick_name: [
192
+ { required: true, message: "用户昵称不能为空", trigger: "blur" },
193
+ { max: 30, message: "用户昵称不能超过 30 个字符", trigger: "blur" }
194
+ ],
195
+ dept_id: [{ required: true, message: "用户部门不能为空", trigger: "change" }],
196
+ role_id: [{ required: true, message: "用户角色不能为空", trigger: "change" }],
197
+ phone: [
198
+ { max: 20, message: "手机号不能超过 20 个字符", trigger: "blur" },
199
+ {
200
+ pattern: /^1[3-9]\d{9}$/,
201
+ message: "请输入正确的手机号码",
202
+ trigger: "blur"
203
+ }
204
+ ],
205
+ pwd: [
206
+ { required: true, message: "请输入密码", trigger: "blur" },
207
+ { validator: validatePasswordField, trigger: "blur" }
208
+ ],
209
+ status: [{ required: true, message: "用户状态不能为空", trigger: "change" }],
210
+ remark: [{ max: 500, message: "备注不能超过 500 个字符", trigger: "blur" }]
211
+ });
212
+ const resetPwdRules = reactive({
213
+ pwd: [
214
+ { required: true, message: "请输入新密码", trigger: "blur" },
215
+ { validator: validatePasswordField, trigger: "blur" }
216
+ ]
217
+ });
218
+
219
+ const basedDeptOptions = ref<TreeOptionResponse_Option[]>([]);
220
+ const baseRoleOptions = ref<SelectOptionResponse_Option[]>([]);
221
+ const basePostOptions = ref<SelectOptionResponse_Option[]>([]);
222
+ const tenantOptions = ref<SelectOptionResponse_Option[]>([]);
223
+ const statusOptions: ProFormOption[] = [
224
+ { label: "启用", value: Status.ENABLE },
225
+ { label: "禁用", value: Status.DISABLE }
226
+ ];
227
+ const resetPwdFields: ProFormField[] = [
228
+ {
229
+ prop: "pwd",
230
+ label: "新密码",
231
+ component: "password",
232
+ props: { placeholder: "请输入新密码", showPassword: true }
233
+ },
234
+ {
235
+ prop: "resetPwdStrength",
236
+ label: "强度提示",
237
+ component: "slot",
238
+ slotName: "resetPwdStrength"
239
+ }
240
+ ];
241
+
242
+ /** 当前登录账号是否默认租户。 */
243
+ const isDefaultTenant = computed(() => userStore.userInfo.tenant_code === DEFAULT_TENANT_CODE);
244
+
245
+ /** 当前编辑用户是否绑定 super 或 tenant 内置角色。 */
246
+ const isProtectedUserRole = computed(() => {
247
+ if (!formData.id || !formData.role_id) return false;
248
+ return baseRoleOptions.value.some(item => item.value === formData.role_id && item.disabled);
249
+ });
250
+
251
+ /** 当前是否正在编辑受状态保护的超级管理员。 */
252
+ const isSuperEditUser = computed(() => Boolean(formData.id && formData.user_name === "super"));
253
+
254
+ /** 用户表单字段配置。 */
255
+ const formFields = computed<ProFormField[]>(() => [
256
+ {
257
+ prop: "tenant_id",
258
+ label: "所属租户",
259
+ component: "select",
260
+ props: {
261
+ placeholder: "请选择所属租户",
262
+ filterable: true,
263
+ disabled: Boolean(formData.id),
264
+ onChange: handleFormTenantChange
265
+ },
266
+ visible: () => isDefaultTenant.value,
267
+ options: tenantOptions.value
268
+ },
269
+ {
270
+ prop: "user_name",
271
+ label: "用户账号",
272
+ component: "input",
273
+ props: { placeholder: "请输入用户账号", disabled: Boolean(formData.id) }
274
+ },
275
+ {
276
+ prop: "user_code",
277
+ label: "用户编号",
278
+ component: "input",
279
+ props: { placeholder: "请输入用户编号", disabled: Boolean(formData.id) }
280
+ },
281
+ { prop: "nick_name", label: "用户昵称", component: "input", props: { placeholder: "请输入用户昵称" } },
282
+ {
283
+ prop: "role_id",
284
+ label: "角色",
285
+ component: "select",
286
+ options: baseRoleOptions.value.map(item => ({ label: item.label, value: item.value, disabled: item.disabled })),
287
+ props: { placeholder: "请选择", disabled: isProtectedUserRole.value }
288
+ },
289
+ {
290
+ prop: "dept_id",
291
+ label: "用户部门",
292
+ component: "tree-select",
293
+ options: basedDeptOptions.value as unknown as ProFormOption[],
294
+ props: {
295
+ placeholder: "请选择用户部门",
296
+ filterable: true,
297
+ checkStrictly: true,
298
+ renderAfterExpand: false,
299
+ style: { width: "100%" }
300
+ }
301
+ },
302
+ {
303
+ prop: "post_id",
304
+ label: "用户岗位",
305
+ component: "select",
306
+ options: basePostOptions.value.map(item => ({ label: item.label, value: item.value, disabled: item.disabled })),
307
+ props: { placeholder: "请选择用户岗位", clearable: true, filterable: true }
308
+ },
309
+ { prop: "phone", label: "手机号码", component: "input", props: { placeholder: "请输入手机号码" } },
310
+ {
311
+ prop: "pwd",
312
+ label: "密码",
313
+ component: "password",
314
+ props: { placeholder: "请输入密码", showPassword: true },
315
+ visible: model => !model.id
316
+ },
317
+ {
318
+ prop: "passwordStrength",
319
+ label: "强度提示",
320
+ component: "slot",
321
+ slotName: "passwordStrength",
322
+ visible: model => !model.id
323
+ },
324
+ { prop: "gender", label: "性别", component: "dict", props: { code: "base_user_gender" } },
325
+ {
326
+ prop: "status",
327
+ label: "状态",
328
+ component: "radio-group",
329
+ options: statusOptions,
330
+ props: { disabled: isSuperEditUser.value }
331
+ },
332
+ { prop: "remark", label: "备注", component: "textarea", props: { placeholder: "请输入备注" } }
333
+ ]);
334
+
335
+ /** 用户表格列配置。 */
336
+ const columns = computed<ColumnProps[]>(() => [
337
+ { type: "selection", width: 55, selectable: row => !isProtectedManagementUser(row as BaseUser) },
338
+ ...(isDefaultTenant.value
339
+ ? ([
340
+ {
341
+ prop: "tenant_id",
342
+ label: "租户",
343
+ minWidth: 140,
344
+ showOverflowTooltip: true,
345
+ search: { el: "select", key: "tenant_id", props: { filterable: true }, order: 1 },
346
+ enum: requestTenantOptions
347
+ }
348
+ ] satisfies ColumnProps[])
349
+ : []),
350
+ { prop: "user_name", label: "用户账号", minWidth: 140, search: { el: "input" } },
351
+ { prop: "user_code", label: "用户编号", minWidth: 140, search: { el: "input" } },
352
+ { prop: "nick_name", label: "昵称", minWidth: 100, search: { el: "input" } },
353
+ { prop: "role_id", label: "角色", minWidth: 140, enum: requestRoleOptions },
354
+ { prop: "dept_id", label: "部门", minWidth: 180, showOverflowTooltip: true, enum: requestDeptOptions },
355
+ { prop: "post_id", label: "岗位", minWidth: 120, enum: requestPostOptions },
356
+ { prop: "phone", label: "手机号码", minWidth: 130, search: { el: "input" } },
357
+ { prop: "gender", label: "性别", minWidth: 90, align: "center", dictCode: "base_user_gender", search: { el: "select" } },
358
+ {
359
+ prop: "status",
360
+ label: "状态",
361
+ minWidth: 100,
362
+ search: { el: "select" },
363
+ cellType: "status",
364
+ statusProps: {
365
+ activeValue: Status.ENABLE,
366
+ inactiveValue: Status.DISABLE,
367
+ activeText: "启用",
368
+ inactiveText: "禁用",
369
+ disabled: scope => isProtectedManagementUser(scope.row as BaseUser) || !BUTTONS.value["base:user:status"],
370
+ beforeChange: scope => handleBeforeSetStatus(scope.row as BaseUser)
371
+ }
372
+ },
373
+ { prop: "remark", label: "备注", minWidth: 160 },
374
+ { prop: "created_at", label: "创建时间", minWidth: 180 },
375
+ { prop: "updated_at", label: "更新时间", minWidth: 180 },
376
+ {
377
+ prop: "operation",
378
+ label: "操作",
379
+ width: 260,
380
+ fixed: "right",
381
+ cellType: "actions",
382
+ actions: [
383
+ {
384
+ label: "重置密码",
385
+ type: "primary",
386
+ link: true,
387
+ icon: RefreshLeft,
388
+ hidden: scope => isProtectedManagementUser(scope.row as BaseUser) || !BUTTONS.value["base:user:pwd"],
389
+ onClick: scope => handleResetPassword(scope.row as BaseUser)
390
+ },
391
+ {
392
+ label: "编辑",
393
+ type: "primary",
394
+ link: true,
395
+ icon: EditPen,
396
+ hidden: scope => isProtectedManagementUser(scope.row as BaseUser) || !BUTTONS.value["base:user:update"],
397
+ params: scope => ({ userId: scope.row.id }),
398
+ onClick: (scope, params) => handleOpenDialog((params?.userId as number | undefined) ?? (scope.row as BaseUser).id)
399
+ },
400
+ {
401
+ label: "删除",
402
+ type: "danger",
403
+ link: true,
404
+ icon: Delete,
405
+ hidden: scope => isProtectedManagementUser(scope.row as BaseUser) || !BUTTONS.value["base:user:delete"],
406
+ onClick: scope => handleDelete(scope.row as BaseUser)
407
+ }
408
+ ]
409
+ }
410
+ ]);
411
+
412
+ /** 用户顶部按钮配置。 */
413
+ const headerActions: HeaderActionProps[] = [
414
+ {
415
+ label: "新增",
416
+ type: "success",
417
+ icon: CirclePlus,
418
+ hidden: () => !BUTTONS.value["base:user:create"],
419
+ onClick: () => handleOpenDialog()
420
+ },
421
+ {
422
+ label: "删除",
423
+ type: "danger",
424
+ icon: Delete,
425
+ hidden: () => !BUTTONS.value["base:user:delete"],
426
+ disabled: scope => !scope.selectedList.length,
427
+ onClick: scope => handleDelete(scope.selectedList as BaseUser[])
428
+ }
429
+ ];
430
+
431
+ /**
432
+ * 递归转换部门树筛选数据,适配 TreeFilter 组件的 id/name 字段。
433
+ */
434
+ function transformDeptFilterNodes(options: TreeOptionResponse_Option[] = []): DeptFilterNode[] {
435
+ return options.map(option => ({
436
+ id: String(option.value),
437
+ name: option.label,
438
+ children: transformDeptFilterNodes(option.children ?? [])
439
+ }));
440
+ }
441
+
442
+ /**
443
+ * 将部门树选项转换为完整路径标签,便于扁平列表关联字段按部门 ID 映射展示。
444
+ */
445
+ function transformDeptOptionPaths(
446
+ options: TreeOptionResponse_Option[] = [],
447
+ parentPath = ""
448
+ ): TreeOptionResponse_Option[] {
449
+ return options.map(option => {
450
+ const label = option.label || "";
451
+ const fullPath = [parentPath, label].filter(Boolean).join("/");
452
+ return {
453
+ ...option,
454
+ label: fullPath,
455
+ children: transformDeptOptionPaths(option.children ?? [], fullPath)
456
+ };
457
+ });
458
+ }
459
+
460
+ /**
461
+ * 请求部门树筛选数据。
462
+ */
463
+ async function requestDeptTreeFilter() {
464
+ const response = await defBaseDeptService.OptionBaseDept({ tenant_id: selectedTenantId.value });
465
+ return {
466
+ data: transformDeptFilterNodes(response.list ?? [])
467
+ };
468
+ }
469
+
470
+ /**
471
+ * 切换部门树筛选时同步更新表格初始化参数。
472
+ */
473
+ function changeTreeFilter(value: string) {
474
+ deptFilterValue.value = value ?? "";
475
+ initParam.dept_id = value ? Number(value) : undefined;
476
+ if (proTable.value) {
477
+ proTable.value.pageable.page_num = 1;
478
+ }
479
+ }
480
+
481
+ /**
482
+ * 请求用户分页列表,并统一处理分页参数。
483
+ */
484
+ async function requestBaseUserTable(params: PageBaseUserRequest) {
485
+ const tenantId = isDefaultTenant.value ? params.tenant_id : undefined;
486
+ if (tenantId !== selectedTenantId.value) {
487
+ selectedTenantId.value = tenantId;
488
+ initParam.dept_id = undefined;
489
+ deptFilterValue.value = "";
490
+ await proTable.value?.refreshEnums();
491
+ }
492
+ const data = await defBaseUserService.PageBaseUser({
493
+ ...buildPageRequest(params),
494
+ tenant_id: tenantId,
495
+ dept_id: initParam.dept_id
496
+ });
497
+ return { data: { list: data.base_users ?? [], total: data.total } };
498
+ }
499
+
500
+ /** 读取当前列表关联选项使用的租户。 */
501
+ function getOptionTenantId() {
502
+ return isDefaultTenant.value ? selectedTenantId.value : undefined;
503
+ }
504
+
505
+ /** 请求角色关联选项。 */
506
+ async function requestRoleOptions() {
507
+ const response = await defBaseRoleService.OptionBaseRole({ tenant_id: getOptionTenantId() });
508
+ return { data: response.list ?? [] };
509
+ }
510
+
511
+ /** 请求部门关联选项。 */
512
+ async function requestDeptOptions() {
513
+ const response = await defBaseDeptService.OptionBaseDept({ tenant_id: getOptionTenantId() });
514
+ return { data: transformDeptOptionPaths(response.list ?? []) };
515
+ }
516
+
517
+ /** 请求岗位关联选项。 */
518
+ async function requestPostOptions() {
519
+ const response = await defBasePostService.OptionBasePost({ tenant_id: getOptionTenantId() });
520
+ return { data: response.list ?? [] };
521
+ }
522
+
523
+ /**
524
+ * 刷新用户表格数据。
525
+ */
526
+ function refreshTable() {
527
+ proTable.value?.getTableList();
528
+ }
529
+
530
+ /**
531
+ * 加载用户表单依赖的角色和部门选项。
532
+ */
533
+ async function loadFormOptions() {
534
+ // 默认租户必须先选择目标租户,避免角色和部门选项跨租户混用。
535
+ if (isDefaultTenant.value && !formData.tenant_id) {
536
+ baseRoleOptions.value = [];
537
+ basePostOptions.value = [];
538
+ basedDeptOptions.value = [];
539
+ return;
540
+ }
541
+ const tenantId = isDefaultTenant.value ? formData.tenant_id : undefined;
542
+ const [optionBaseRoleResponse, optionBaseDeptResponse, optionBasePostResponse] = await Promise.all([
543
+ defBaseRoleService.OptionBaseRole({ tenant_id: tenantId }),
544
+ defBaseDeptService.OptionBaseDept({ tenant_id: tenantId }),
545
+ defBasePostService.OptionBasePost({ tenant_id: tenantId })
546
+ ]);
547
+ baseRoleOptions.value = optionBaseRoleResponse.list || [];
548
+ basePostOptions.value = optionBasePostResponse.list || [];
549
+ basedDeptOptions.value = optionBaseDeptResponse.list || [];
550
+ }
551
+
552
+ /**
553
+ * 加载租户下拉选项。
554
+ */
555
+ async function loadTenantOptions() {
556
+ if (!isDefaultTenant.value || tenantOptions.value.length) return;
557
+ const response = await defBaseTenantService.OptionBaseTenant({ keyword: "" });
558
+ tenantOptions.value = response.list ?? [];
559
+ }
560
+
561
+ /**
562
+ * 切换用户表单租户时,清空角色和部门并重新加载选项。
563
+ */
564
+ async function handleFormTenantChange() {
565
+ formData.role_id = undefined;
566
+ formData.dept_id = undefined;
567
+ formData.post_id = undefined;
568
+ await loadFormOptions();
569
+ }
570
+
571
+ /**
572
+ * 打开用户弹窗,并加载角色和部门下拉选项。
573
+ */
574
+ async function handleOpenDialog(id?: number) {
575
+ resetForm();
576
+ await loadTenantOptions();
577
+ dialog.title = id ? "修改用户" : "新增用户";
578
+ dialog.visible = true;
579
+ if (!id) {
580
+ await loadFormOptions();
581
+ return;
582
+ }
583
+
584
+ defBaseUserService.GetBaseUser({ id }).then(async data => {
585
+ Object.assign(formData, data);
586
+ await loadFormOptions();
587
+ });
588
+ }
589
+
590
+ /**
591
+ * 关闭用户弹窗并恢复默认表单值。
592
+ */
593
+ function handleCloseDialog() {
594
+ dialog.visible = false;
595
+ resetForm();
596
+ }
597
+
598
+ /**
599
+ * 重置用户表单,避免新增与编辑之间互相污染。
600
+ */
601
+ function resetForm() {
602
+ formDialogRef.value?.resetFields();
603
+ formDialogRef.value?.clearValidate();
604
+ formData.id = 0;
605
+ formData.tenant_id = undefined;
606
+ formData.user_name = "";
607
+ formData.user_code = "";
608
+ formData.nick_name = "";
609
+ formData.role_id = undefined;
610
+ formData.dept_id = undefined;
611
+ formData.post_id = undefined;
612
+ formData.phone = "";
613
+ formData.pwd = "";
614
+ formData.gender = 3;
615
+ formData.avatar = "";
616
+ formData.status = Status.ENABLE;
617
+ formData.remark = "";
618
+ baseRoleOptions.value = [];
619
+ basePostOptions.value = [];
620
+ basedDeptOptions.value = [];
621
+ }
622
+
623
+ /**
624
+ * 打开重置密码弹窗,并回填当前操作用户。
625
+ */
626
+ function handleResetPassword(row: BaseUser) {
627
+ resetPwdFormDialogRef.value?.resetFields();
628
+ resetPwdFormDialogRef.value?.clearValidate();
629
+ resetPwdForm.id = row.id;
630
+ resetPwdForm.pwd = "";
631
+ resetPwdTargetName.value = row.nick_name || row.user_name || `ID:${row.id}`;
632
+ resetPwdDialog.title = `重置密码:${resetPwdTargetName.value}`;
633
+ resetPwdDialog.visible = true;
634
+ }
635
+
636
+ /**
637
+ * 关闭重置密码弹窗并恢复默认表单值。
638
+ */
639
+ function handleCloseResetPasswordDialog() {
640
+ resetPwdDialog.visible = false;
641
+ resetPwdFormDialogRef.value?.resetFields();
642
+ resetPwdFormDialogRef.value?.clearValidate();
643
+ resetPwdForm.id = 0;
644
+ resetPwdForm.pwd = "";
645
+ resetPwdTargetName.value = "";
646
+ }
647
+
648
+ /**
649
+ * 确认重置用户密码,并复用统一密码强度校验。
650
+ */
651
+ async function handleConfirmResetPassword() {
652
+ resetPwdFormDialogRef.value?.validate()?.then(async valid => {
653
+ if (!valid) return;
654
+
655
+ const pwd = await encryptPassword(resetPwdForm.pwd, PASSWORD_CRYPTO_SCENE.RESET_BASE_USER_PASSWORD);
656
+ defBaseUserService.ResetBaseUserPassword({ id: resetPwdForm.id, pwd }).then(() => {
657
+ ElMessage.success(`重置密码成功\n用户名称:${resetPwdTargetName.value}`);
658
+ handleCloseResetPasswordDialog();
659
+ });
660
+ });
661
+ }
662
+
663
+ /**
664
+ * 提交用户表单,使用防抖避免重复提交。
665
+ */
666
+ const handleSubmit = useDebounceFn(() => {
667
+ formDialogRef.value?.validate()?.then(async valid => {
668
+ if (!valid) return;
669
+
670
+ const submitData = JSON.parse(JSON.stringify(formData)) as BaseUserFormState;
671
+ const baseUser = {
672
+ ...submitData,
673
+ pwd: submitData.id ? undefined : await encryptPassword(submitData.pwd, PASSWORD_CRYPTO_SCENE.CREATE_BASE_USER)
674
+ } as BaseUserForm;
675
+ const request = submitData.id
676
+ ? defBaseUserService.UpdateBaseUser({ base_user: baseUser })
677
+ : defBaseUserService.CreateBaseUser({ base_user: baseUser });
678
+ request.then(() => {
679
+ ElMessage.success(submitData.id ? "修改用户成功" : "新增用户成功");
680
+ handleCloseDialog();
681
+ refreshTable();
682
+ });
683
+ });
684
+ }, 1000);
685
+
686
+ /**
687
+ * 在用户状态切换前先完成确认与接口调用,避免首屏渲染触发误操作。
688
+ */
689
+ async function handleBeforeSetStatus(row: BaseUser) {
690
+ if (isProtectedManagementUser(row)) {
691
+ ElMessage.warning("内置管理员账号只能通过个人中心修改");
692
+ return false;
693
+ }
694
+
695
+ const nextStatus = row.status === Status.ENABLE ? Status.DISABLE : Status.ENABLE;
696
+ const text = nextStatus === Status.ENABLE ? "启用" : "禁用";
697
+ const user_name = row.nick_name || row.user_name || `ID:${row.id}`;
698
+ try {
699
+ await ElMessageBox.confirm(`是否确定${text}用户?\n用户名称:${user_name}`, "提示", {
700
+ confirmButtonText: "确认",
701
+ cancelButtonText: "取消",
702
+ type: "warning"
703
+ });
704
+ await defBaseUserService.SetBaseUserStatus({ id: row.id, status: nextStatus });
705
+ ElMessage.success(`${text}成功`);
706
+ refreshTable();
707
+ return true;
708
+ } catch {
709
+ return false;
710
+ }
711
+ }
712
+
713
+ /**
714
+ * 删除用户,兼容单条删除与批量删除。
715
+ */
716
+ function handleDelete(selected?: number | string | Array<number | string> | BaseUser | BaseUser[]) {
717
+ const userList = Array.isArray(selected)
718
+ ? (selected.filter(item => typeof item === "object") as BaseUser[])
719
+ : selected && typeof selected === "object"
720
+ ? [selected]
721
+ : [];
722
+ if (userList.some(isProtectedManagementUser)) {
723
+ ElMessage.warning("内置管理员账号只能通过个人中心修改");
724
+ return;
725
+ }
726
+ const userIds = normalizeSelectedIds(
727
+ userList.length ? userList.map(item => item.id) : (selected as number | string | Array<number | string> | undefined)
728
+ ).join(",");
729
+ if (!userIds) {
730
+ ElMessage.warning("请勾选删除项");
731
+ return;
732
+ }
733
+
734
+ const confirmMessage = userList.length
735
+ ? userList.length === 1
736
+ ? `是否确定删除用户?\n用户名称:${userList[0].nick_name || userList[0].user_name || `ID:${userList[0].id}`}`
737
+ : `确认删除已选中的 ${userList.length} 个用户吗?`
738
+ : "确认删除已选中的用户吗?";
739
+
740
+ ElMessageBox.confirm(confirmMessage, "警告", {
741
+ confirmButtonText: "确定",
742
+ cancelButtonText: "取消",
743
+ type: "warning"
744
+ }).then(
745
+ () => {
746
+ defBaseUserService.DeleteBaseUser({ id: userIds }).then(() => {
747
+ ElMessage.success("删除用户成功");
748
+ refreshTable();
749
+ });
750
+ },
751
+ () => {
752
+ ElMessage.info("已取消删除用户");
753
+ }
754
+ );
755
+ }
756
+
757
+ /**
758
+ * 校验密码强度,新增用户和重置密码统一要求达到最高强度。
759
+ *
760
+ * @param _rule 表单规则对象
761
+ * @param value 当前密码值
762
+ * @param callback 校验回调
763
+ */
764
+ function validatePasswordField(_rule: unknown, value: string, callback: (error?: Error) => void) {
765
+ if (!value) {
766
+ callback();
767
+ return;
768
+ }
769
+ const result = validatePasswordStrengthValue(value);
770
+ if (!result.valid) {
771
+ callback(new Error(result.message || PASSWORD_STRENGTH_ERROR_MESSAGE));
772
+ return;
773
+ }
774
+ callback();
775
+ }
776
+
777
+ /**
778
+ * 根据后端管理保护标记判断用户是否禁止通过用户管理操作。
779
+ */
780
+ function isProtectedManagementUser(row?: BaseUser) {
781
+ return Boolean(row?.is_protected);
782
+ }
783
+ </script>