刘帅
2026-09-23 52422adc2297f11e5e0c4b0feaed0688537ddc9c
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/UserMgrController.java
@@ -153,9 +153,16 @@
        User user = this.userService.getById(userId);
        Role role = roleService.getById(user.getRoleid());
        Dept dept = deptService.getById(user.getDeptid());
        // 兼容历史账号:部分账号的登录手机号仅保存在 account 字段。
        // 个人资料页必须能回显该绑定手机号,避免前端提交空值。
        if (StringUtils.isEmpty(user.getPhone()) && !StringUtils.isEmpty(user.getAccount())) {
            user.setPhone(user.getAccount());
        }
        user.setPhone(maskPhone(user.getPhone()));
        user.setIdCard(maskIdCard(user.getIdCard()));
        model.addAttribute(user);
        // 显式指定模型名称和身份证回显字段,避免模板按隐式参数名解析失败。
        model.addAttribute("user", user);
        model.addAttribute("idCard", user.getIdCard());
        if(role==null){
            model.addAttribute("roleName", "");
        }else {
@@ -175,6 +182,11 @@
        }
        roleLambdaQueryWrapper.eq(Role::getObjType,UserExt.getUser().getObjectType());
        List<Role> list = roleService.list(roleLambdaQueryWrapper);
        // 员工可能是由平台账号创建、后续归属到门店的,原角色不一定属于当前登录人的角色范围。
        // 编辑时仍需保留该角色作为可选项,避免下拉框无法回显。
        if (role != null && list.stream().noneMatch(item -> Objects.equals(item.getId(), role.getId()))) {
            list.add(role);
        }
        model.addAttribute("list",list);
        model.addAttribute("language",UserExt.getLanguage());
        // 部门列表
@@ -209,6 +221,11 @@
        User user = this.userService.getById(userId);
        Role role = roleService.getById(user.getRoleid());
        Dept dept = deptService.getById(user.getDeptid());
        // 兼容历史账号:部分账号的登录手机号仅保存在 account 字段。
        // 个人资料页必须能回显该绑定手机号,避免前端提交空值。
        if (StringUtils.isEmpty(user.getPhone()) && !StringUtils.isEmpty(user.getAccount())) {
            user.setPhone(user.getAccount());
        }
        user.setPhone(maskPhone(user.getPhone()));
        user.setIdCard(maskIdCard(user.getIdCard()));
        model.addAttribute(user);
@@ -410,11 +427,6 @@
        this.userService.save(objectUser);
        if (!assignedStores.isEmpty()) {
            replaceStoreRelations(objectUser.getId(), assignedStores);
            // 各所选门店同步负责人账号;旧系统仍可通过 storeStaffId 查询主负责人。
            for (TStore store : assignedStores) {
                store.setStoreStaffId(objectUser.getId());
                storeService.updateById(store);
            }
        }
        return SUCCESS_TIP;
    }
@@ -434,9 +446,12 @@
        }
        User oldUser = userService.getById(user.getId());
        // 判断是否更改电话
        if (user.getPhone() != null && user.getPhone().contains("*")) {
        if (StringUtils.isEmpty(user.getPhone()) || user.getPhone().contains("*")) {
            // The edit view displays a masked phone. Treat an unchanged masked
            // value as "keep original", never as a value to persist.
            // value, or an omitted field, as "keep original", never as a
            // value to persist. Some edit forms do not submit disabled or
            // hidden fields; allowing an empty value through would erase the
            // stored phone after deployment.
        } else if (!Objects.equals(oldUser.getPhone(), user.getPhone())) {
            User phone = userService.getOne(new QueryWrapper<User>().eq("phone", user.getPhone()));
            if (phone == null){
@@ -448,7 +463,11 @@
        oldUser.setName(user.getName());
        oldUser.setBirthday(user.getBirthday());
        oldUser.setDeptid(user.getDeptid());
        if (user.getIdCard() == null || !user.getIdCard().contains("*")) oldUser.setIdCard(user.getIdCard());
        // 身份证号为空说明本次表单没有提交该字段,不能覆盖数据库中的历史值;
        // 脱敏值同样只用于回显,不能写回数据库。
        if (!StringUtils.isEmpty(user.getIdCard()) && !user.getIdCard().contains("*")) {
            oldUser.setIdCard(user.getIdCard());
        }
        oldUser.setSex(user.getSex());
        oldUser.setEmail(user.getEmail());
        if (user.getAvatar()!=null && (!user.getAvatar().equals("")))
@@ -461,16 +480,39 @@
                oldUser.setObjectType(3);
                oldUser.setObjectId(assignedStores.get(0).getId());
                oldUser.setRoleid("3");
                for (TStore store : assignedStores) {
                    store.setStoreStaffId(oldUser.getId());
                    storeService.updateById(store);
                }
            } else if (Integer.valueOf(3).equals(oldUser.getObjectType())) {
                // 清除旧字段关联,避免已移除的首个门店仍被当作该员工所属门店。
                oldUser.setObjectId(null);
            }
        }
        // 门店关联会维护员工归属信息,但不能覆盖编辑页明确选择的角色。
        // 必须在关联处理后写入,否则有门店的员工会被上面的兼容逻辑强制改回角色 3。
        // 个人资料页不提供 roleid_ 回显控件时,旧版前端可能提交字符串
        // "undefined";该值绝不能覆盖 sys_user.roleid。
        if (isValidRoleId(user.getRoleid())) {
            oldUser.setRoleid(user.getRoleid());
            // 仅内置平台管理员(1)和门店管理员(3)切换数据归属类型;
            // 其他自定义角色只控制菜单权限,不改变账号归属。objectId 始终保留。
            syncObjectTypeWithBuiltInRole(oldUser, user.getRoleid());
        }
        this.userService.updateById(oldUser);
        return SUCCESS_TIP;
    }
    private boolean isValidRoleId(String roleId) {
        return !StringUtils.isEmpty(roleId)
                && !"undefined".equalsIgnoreCase(roleId)
                && !"null".equalsIgnoreCase(roleId);
    }
    private void syncObjectTypeWithBuiltInRole(User user, String roleId) {
        if ("1".equals(roleId)) {
            user.setObjectType(1);
        } else if ("3".equals(roleId)) {
            user.setObjectType(3);
        }
    }
    private String maskPhone(String value) {
        if (value == null) return null;
        return value.length() <= 7 ? stars(value.length()) : value.substring(0, 3) + "****" + value.substring(7);