| | |
| | | package com.dsh.guns.modular.system.controller.system; |
| | | |
| | | import cn.hutool.crypto.SecureUtil; |
| | | import com.baomidou.mybatisplus.core.toolkit.IdWorker; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | |
| | | 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 { |
| | |
| | | } |
| | | 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()); |
| | | // 部门列表 |
| | |
| | | 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); |
| | |
| | | @BussinessLog(value = "添加管理员", key = "account", dict = UserDict.class) |
| | | @Permission(Const.ADMIN_NAME) |
| | | @ResponseBody |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Object add(@Valid UserDto user, BindingResult result) { |
| | | if (result.hasErrors()) { |
| | | throw new GunsException(BizExceptionEnum.REQUEST_NULL); |
| | |
| | | if (StringUtils.isEmpty(user.getPhone())) { |
| | | return 5002; |
| | | } |
| | | User theUser = userService.getOne(new QueryWrapper<User>().eq("phone", user.getPhone())); |
| | | // 已逻辑删除的员工(status=3)不占用手机号,可用同一手机号重新创建员工。 |
| | | User theUser = userService.getOne(new QueryWrapper<User>() |
| | | .eq("phone", user.getPhone()) |
| | | .ne("status", ManagerStatus.DELETED.getCode())); |
| | | if (theUser != null || userService.getByAccount(user.getPhone()) != null){ |
| | | return 5001; |
| | | } |
| | |
| | | objectUser.setVersion(UserExt.getUser().getId()); |
| | | this.userService.save(objectUser); |
| | | if (!assignedStores.isEmpty()) { |
| | | userMapper.deleteStoreRelations(objectUser.getId()); |
| | | userMapper.insertStoreRelations(objectUser.getId(), assignedStores.stream().map(TStore::getId).collect(Collectors.toList())); |
| | | // 各所选门店同步负责人账号;旧系统仍可通过 storeStaffId 查询主负责人。 |
| | | for (TStore store : assignedStores) { |
| | | store.setStoreStaffId(objectUser.getId()); |
| | | storeService.updateById(store); |
| | | } |
| | | replaceStoreRelations(objectUser.getId(), assignedStores); |
| | | } |
| | | return SUCCESS_TIP; |
| | | } |
| | |
| | | } |
| | | 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. |
| | | } else if (!oldUser.getPhone().equals(user.getPhone())){ |
| | | // 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){ |
| | | oldUser.setPhone(user.getPhone()); |
| | |
| | | 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(""))) |
| | |
| | | if (user.getStoreIds() != null) { |
| | | List<TStore> assignedStores = validateStores(user.getStoreIds()); |
| | | if (assignedStores == null) return ResultUtil.error("所选门店不存在、已停用或不在当前账号管理范围内"); |
| | | userMapper.deleteStoreRelations(oldUser.getId()); |
| | | replaceStoreRelations(oldUser.getId(), assignedStores); |
| | | if (!assignedStores.isEmpty()) { |
| | | oldUser.setObjectType(3); |
| | | oldUser.setObjectId(assignedStores.get(0).getId()); |
| | | oldUser.setRoleid("3"); |
| | | userMapper.insertStoreRelations(oldUser.getId(), assignedStores.stream().map(TStore::getId).collect(Collectors.toList())); |
| | | 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) { |
| | |
| | | return stores; |
| | | } |
| | | |
| | | /** 每条关联记录单独生成雪花主键,避免 MyBatis foreach 复用同一个绑定变量。 */ |
| | | private void replaceStoreRelations(Integer userId, List<TStore> stores) { |
| | | userMapper.deleteStoreRelations(userId); |
| | | for (TStore store : stores) { |
| | | userMapper.insertStoreRelation(IdWorker.getId(), userId, store.getId()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 删除管理员(逻辑删除) |
| | | * Delete administrator (logical deletion) |