From b96bbc9a62d3365e4b63cf410a974e7ce53d6516 Mon Sep 17 00:00:00 2001 From: chenxing Date: Mon, 17 Aug 2026 16:41:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/globals.d.ts | 42 +++++- src/views/group-user/index.vue | 4 +- .../group-user/user/AddUserContainer.vue | 73 ++++++--- .../group-user/user/EditUserContainer.vue | 132 +++++++++++++---- src/views/group-user/user/UserForm.vue | 139 ++++++++++-------- 5 files changed, 279 insertions(+), 111 deletions(-) diff --git a/src/api/globals.d.ts b/src/api/globals.d.ts index 2c36330..725523a 100644 --- a/src/api/globals.d.ts +++ b/src/api/globals.d.ts @@ -2659,6 +2659,42 @@ declare global { ): Alova2Method; }; SysUser: { + /** + * --- + * + * [GET] getGroups + * + * **path:** /api/sysuser/Groups/{userId} + * + * --- + * + * **Path Parameters** + * ```ts + * type PathParameters = { + * // userId + * userId: number + * } + * ``` + * + * --- + * + * **Response** + * ```ts + * type Response = number[] + * ``` + */ + getGroups< + Config extends Alova2MethodConfig & { + pathParams: { + /** + * userId + */ + userId: number; + }; + } + >( + config: Config + ): Alova2Method; /** * --- * @@ -2693,16 +2729,16 @@ declare global { * * **Response** * ```ts - * type Response = null + * type Response = number * ``` */ add< - Config extends Alova2MethodConfig & { + Config extends Alova2MethodConfig & { data: SysUserRequest; } >( config: Config - ): Alova2Method; + ): Alova2Method; /** * --- * diff --git a/src/views/group-user/index.vue b/src/views/group-user/index.vue index 596fa56..5702850 100644 --- a/src/views/group-user/index.vue +++ b/src/views/group-user/index.vue @@ -257,7 +257,9 @@ function showAddUser() { /* ================= 编辑 ================= */ const editRef = ref(); function handleEdit(row: any) { - editRef.value?.open(row, groupOptions.value, () => { + // 当前点击所在的组(SysUserVo 不含 groupId,故以左侧选中节点为准,供"所在组"只读展示并默认选中) + const curGroupId = selectedNode.value?.id ?? null; + editRef.value?.open(row, groupOptions.value, curGroupId, () => { tableRef.value?.reloadData(OperatorEnum.edit); }); } diff --git a/src/views/group-user/user/AddUserContainer.vue b/src/views/group-user/user/AddUserContainer.vue index 50b6552..755586a 100644 --- a/src/views/group-user/user/AddUserContainer.vue +++ b/src/views/group-user/user/AddUserContainer.vue @@ -1,5 +1,5 @@ @@ -10,19 +10,24 @@ import UserForm from "./UserForm.vue"; /* ---------- 对外暴露:由父组件(group-user/index)调用 ---------- */ const visible = ref(false); -// 所在组下拉数据(拍平后的组织树) -const groupOptions = ref([]); +// 当前所在组(新增时由左侧选中节点带入,作为创建分组,不展示) +const currentGroupId = ref(null); -// 新增模式:始终传空初始值;若带 defaultGroupId 则预填 groupId +// 新增模式:始终传空初始值 const initFormData = ref>({}); +// 角色属性下拉:来自角色授权页的全量角色 +const roleOptions = ref<{ id: number; name: string }[]>([]); +// 待保存的角色属性(用户多选结果) +let appRolesToSave: number[] = []; + // 成功后回调 let onSuccessCallback: (() => void) | null = null; // useForm 托管提交:loading=submitting、sendForm 发请求、onSuccess/onError 处理结果 const { form, loading: submitting, send: sendForm, onSuccess, onError } = useForm( (dto) => Apis.SysUser.add({ data: dto }), - { initialForm: { account: '', realName: '', password: '', confirmPassword: '', idcard: '', phone: '', phone2: '', gender: 0, groupId: undefined, userType: [], role: undefined }, resetAfterSubmiting: true } + { initialForm: { account: '', realName: '', password: '', confirmPassword: '', idcard: '', phone: '', gender: 0, userType: [] }, resetAfterSubmiting: true } ); onSuccess(() => { @@ -31,45 +36,75 @@ onSuccess(() => { onSuccessCallback?.(); }); onError((event) => { - Message.error(event?.error?.message || '新增失败'); + const msg = event?.error?.message || '新增失败'; + Message.error(normalizeAccountError(msg, form.value.account)); }); /* ---------- 打开弹窗 ---------- */ function open(groups: any[], defaultGroupId?: number | null, onSuccess?: () => void) { - groupOptions.value = groups || []; - // 若已选中某个组织节点,新增弹窗自动带入该组;未选时不带入 - initFormData.value = defaultGroupId != null ? { groupId: defaultGroupId } : {}; + // 当前所在组作为创建分组(提交时回写 groupId),新增模式不展示 + currentGroupId.value = defaultGroupId != null ? defaultGroupId : null; + initFormData.value = {}; onSuccessCallback = onSuccess || null; visible.value = true; + // 加载角色属性下拉(失败时静默降级,不影响新增主流程) + Apis.AppRole.roleList({ params: { pageIndex: 1, pageSize: 999 } }) + .then((resp: any) => { + roleOptions.value = (resp?.content || []).map((r: any) => ({ id: r.id, name: r.name })); + }) + .catch(() => { + roleOptions.value = []; + }); } /* ---------- 提交:由 useForm 接管 loading 与异常处理 ---------- */ async function handleSubmit(formData: Record) { + appRolesToSave = (formData.appRoles || []) as number[]; form.value = buildPayload(formData); - await sendForm(); + let newId: number | undefined; + try { + newId = (await sendForm()) as number; + } catch { + // 新增失败(onError 已提示),不继续绑定角色 + return; + } + // 新增成功后再绑定业务角色 + if (newId != null && appRolesToSave.length) { + try { + await Apis.AppRole.saveUserRoles({ data: { userId: newId, roleIds: appRolesToSave } }); + } catch (e: any) { + Message.error('用户已创建,但角色属性保存失败:' + (e?.message || '未知错误')); + } + } } /** * 把表单字段映射成 SysUserRequest: * - 只提交后端 SysUserRequest 里声明的字段 - * - "用户身份"(userType checkbox) + "角色属性"(role select) 合并为 roles[](去重) + * - 角色仅来自"用户身份"勾选(userType),groupId 由当前所在组回写 */ function buildPayload(formData: Record) { - const roleSet = new Set(); - (formData.userType || []).forEach((v: any) => roleSet.add(Number(v))); - if (formData.role != null && formData.role !== '') roleSet.add(Number(formData.role)); - + const roles: number[] = (formData.userType || []).map((v: any) => Number(v)); return { account: formData.account, password: formData.password, confirmPassword: formData.confirmPassword, realName: formData.realName, idcard: formData.idcard || undefined, - phone: formData.phone, - groupId: formData.groupId, - roles: Array.from(roleSet), + phone: formData.phone || undefined, + gender: formData.gender, + groupId: currentGroupId.value, + roles, }; } +/* ---------- 工具:账号重复提示标准化 ---------- */ +function normalizeAccountError(msg: string, account: string): string { + if (account && /账号/.test(msg) && /(已存在|重复|已被其他用户使用)/.test(msg)) { + return `账号${account}已存在`; + } + return msg; +} + defineExpose({ open, visible }); - \ No newline at end of file + diff --git a/src/views/group-user/user/EditUserContainer.vue b/src/views/group-user/user/EditUserContainer.vue index dcf52db..addc1c8 100644 --- a/src/views/group-user/user/EditUserContainer.vue +++ b/src/views/group-user/user/EditUserContainer.vue @@ -1,6 +1,6 @@ \ No newline at end of file + diff --git a/src/views/group-user/user/UserForm.vue b/src/views/group-user/user/UserForm.vue index 28514c5..2be5cd3 100644 --- a/src/views/group-user/user/UserForm.vue +++ b/src/views/group-user/user/UserForm.vue @@ -45,14 +45,9 @@ - + - - - - - - + 女 @@ -62,12 +57,12 @@ - - + + - - + @@ -86,16 +81,18 @@ - + - - + +