From 572df690f72ed4a077d934823f261dec39b3cc7d Mon Sep 17 00:00:00 2001
From: 刘帅 <rr.iii@qq.com>
Date: 星期二, 08 九月 2026 17:11:34 +0800
Subject: [PATCH] feat&bug:文档内容修改

---
 cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/UserMgrController.java |  139 +++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 130 insertions(+), 9 deletions(-)

diff --git a/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/UserMgrController.java b/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/UserMgrController.java
index d20430b..373d8b5 100644
--- a/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/UserMgrController.java
+++ b/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/UserMgrController.java
@@ -34,10 +34,14 @@
 import com.dsh.guns.modular.system.util.ResultUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
+import org.springframework.util.StringUtils;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.ui.Model;
 import org.springframework.validation.BindingResult;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.beans.propertyeditors.CustomNumberEditor;
 
 import javax.naming.NoPermissionException;
 import javax.servlet.http.HttpServletResponse;
@@ -57,6 +61,12 @@
 
     private static String PREFIX = "/system/user/";
 
+    /** 多选框未选择时会提交空字符串;将其转换为空值,避免绑定 List<Integer> 时抛 NumberFormatException。 */
+    @InitBinder
+    public void initBinder(WebDataBinder binder) {
+        binder.registerCustomEditor(Integer.class, new CustomNumberEditor(Integer.class, true));
+    }
+
     @Autowired
     private GunsProperties gunsProperties;
 
@@ -75,6 +85,7 @@
     @RequestMapping("")
     public String index(Model model) {
         model.addAttribute("language",UserExt.getLanguage());
+        model.addAttribute("isSuperAdmin", "admin".equalsIgnoreCase(UserExt.getUser().getAccount()));
         return PREFIX + "user.html";
     }
 
@@ -95,7 +106,20 @@
         // 部门列表
         List<Dept> depts = deptService.list(new QueryWrapper<>());
         model.addAttribute("depts",depts);
+        model.addAttribute("stores", availableStores());
         return PREFIX + "user_add.html";
+    }
+
+    private List<TStore> availableStores() {
+        LambdaQueryWrapper<TStore> query = new LambdaQueryWrapper<TStore>().eq(TStore::getState, 1);
+        Integer objectType = UserExt.getUser().getObjectType();
+        Integer objectId = UserExt.getUser().getObjectId();
+        if (Integer.valueOf(2).equals(objectType)) {
+            query.eq(TStore::getOperatorId, objectId);
+        } else if (Integer.valueOf(3).equals(objectType)) {
+            query.eq(TStore::getId, objectId);
+        }
+        return storeService.list(query);
     }
 
     /**
@@ -128,6 +152,8 @@
         User user = this.userService.getById(userId);
         Role role = roleService.getById(user.getRoleid());
         Dept dept = deptService.getById(user.getDeptid());
+        user.setPhone(maskPhone(user.getPhone()));
+        user.setIdCard(maskIdCard(user.getIdCard()));
         model.addAttribute(user);
         if(role==null){
             model.addAttribute("roleName", "");
@@ -153,8 +179,21 @@
         // 部门列表
         List<Dept> depts = deptService.list(new QueryWrapper<>());
         model.addAttribute("depts",depts);
+        model.addAttribute("stores", availableStores());
+        // 回显同时兼容新关联表、sys_user 旧归属字段和 t_store.storeStaffId 旧数据。
+        List<Integer> selectedStoreIds = userMapper.getStoreIdsByUserId(userId);
+        model.addAttribute("selectedStoreIds", selectedStoreIds.stream()
+                .map(String::valueOf).collect(Collectors.joining(",")));
         model.addAttribute("type",type);
         return PREFIX + "user_edit.html";
+    }
+
+    /** 编辑页异步读取已关联门店,避免模板渲染集合造成多选回显丢失。 */
+    @GetMapping("/storeIds/{userId}")
+    @ResponseBody
+    public List<Integer> getStoreIds(@PathVariable Integer userId) {
+        assertAuth(userId);
+        return userMapper.getStoreIdsByUserId(userId);
     }
 
     /**
@@ -169,6 +208,8 @@
         User user = this.userService.getById(userId);
         Role role = roleService.getById(user.getRoleid());
         Dept dept = deptService.getById(user.getDeptid());
+        user.setPhone(maskPhone(user.getPhone()));
+        user.setIdCard(maskIdCard(user.getIdCard()));
         model.addAttribute(user);
         model.addAttribute("roleName", role.getName());
         if(dept==null){
@@ -213,6 +254,8 @@
 
     @Autowired
     private IStoreService storeService;
+    @Autowired
+    private UserMapper userMapper;
     /**
      * 查询管理员列表
      */
@@ -293,12 +336,12 @@
             throw new GunsException(BizExceptionEnum.REQUEST_NULL);
         }
 
-        // 判断账号是否重复
-        User theUser = new User();
-        if (user.getPhone()!=""){
-         theUser = userService.getByAccount(user.getPhone());
+        // 手机号既是登录账号,必须在 sys_user 中唯一;使用内容判断,不能使用 != 比较字符串引用。
+        if (StringUtils.isEmpty(user.getPhone())) {
+            return 5002;
         }
-        if (theUser != null){
+        User theUser = userService.getOne(new QueryWrapper<User>().eq("phone", user.getPhone()));
+        if (theUser != null || userService.getByAccount(user.getPhone()) != null){
             return 5001;
         }
 
@@ -308,7 +351,7 @@
         user.setCreatetime(new Date());
         User objectUser = UserFactory.createUser(user);
 
-        if (user.getRoleid().equals("")){
+        if (StringUtils.isEmpty(user.getRoleid())){
             objectUser.setObjectType(2);
         }else {
             objectUser.setObjectType(Integer.valueOf(user.getRoleid()));
@@ -326,8 +369,28 @@
         objectUser.setStatus(1);
         objectUser.setPassword(SecureUtil.md5("a123456"));
         objectUser.setCreatetime(new Date());
+        List<TStore> assignedStores = new ArrayList<TStore>();
+        if (user.getStoreIds() != null && !user.getStoreIds().isEmpty()) {
+            List<Integer> storeIds = user.getStoreIds().stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
+            if (storeIds.isEmpty()) return ResultUtil.error("请选择有效门店");
+            Integer currentType = UserExt.getUser().getObjectType();
+            Integer currentObjectId = UserExt.getUser().getObjectId();
+            for (Integer storeId : storeIds) {
+                TStore store = storeService.getById(storeId);
+                if (store == null || !Integer.valueOf(1).equals(store.getState())) return ResultUtil.error("所选门店不存在或已停用");
+                if ((Integer.valueOf(2).equals(currentType) && !currentObjectId.equals(store.getOperatorId()))
+                        || (Integer.valueOf(3).equals(currentType) && !currentObjectId.equals(store.getId()))) {
+                    return ResultUtil.error("所选门店不在当前账号的管理范围内");
+                }
+                assignedStores.add(store);
+            }
+            // 首个门店同步写入旧字段,保证既有权限、数据查询和登录逻辑无需改造。
+            TStore primaryStore = assignedStores.get(0);
+            objectUser.setObjectType(3);
+            objectUser.setRoleid("3");
+            objectUser.setObjectId(primaryStore.getId());
         // 运营商添加员工
-        if (UserExt.getUser().getObjectType() == 2){
+        } else if (UserExt.getUser().getObjectType() == 2){
             objectUser.setObjectType(UserExt.getUser().getObjectType());
             objectUser.setRoleid("2");
             objectUser.setObjectId(UserExt.getUser().getObjectId());
@@ -340,6 +403,15 @@
         }
         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);
+            }
+        }
         return SUCCESS_TIP;
     }
 
@@ -351,13 +423,17 @@
     @RequestMapping("/edit")
     @BussinessLog(value = "修改管理员", key = "account", dict = UserDict.class)
     @ResponseBody
+    @Transactional(rollbackFor = Exception.class)
     public Object edit(@Valid UserDto user, BindingResult result) throws NoPermissionException {
         if (result.hasErrors()) {
             throw new GunsException(BizExceptionEnum.REQUEST_NULL);
         }
         User oldUser = userService.getById(user.getId());
         // 判断是否更改电话
-        if (!oldUser.getPhone().equals(user.getPhone())){
+        if (user.getPhone() != null && 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())){
             User phone = userService.getOne(new QueryWrapper<User>().eq("phone", user.getPhone()));
             if (phone == null){
                 oldUser.setPhone(user.getPhone());
@@ -368,15 +444,60 @@
         oldUser.setName(user.getName());
         oldUser.setBirthday(user.getBirthday());
         oldUser.setDeptid(user.getDeptid());
-        oldUser.setIdCard(user.getIdCard());
+        if (user.getIdCard() == null || !user.getIdCard().contains("*")) oldUser.setIdCard(user.getIdCard());
         oldUser.setSex(user.getSex());
         oldUser.setEmail(user.getEmail());
         if (user.getAvatar()!=null && (!user.getAvatar().equals("")))
         oldUser.setAvatar(user.getAvatar());
+        if (user.getStoreIds() != null) {
+            List<TStore> assignedStores = validateStores(user.getStoreIds());
+            if (assignedStores == null) return ResultUtil.error("所选门店不存在、已停用或不在当前账号管理范围内");
+            userMapper.deleteStoreRelations(oldUser.getId());
+            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);
+                }
+            }
+        }
         this.userService.updateById(oldUser);
         return SUCCESS_TIP;
     }
 
+    private String maskPhone(String value) {
+        if (value == null) return null;
+        return value.length() <= 7 ? stars(value.length()) : value.substring(0, 3) + "****" + value.substring(7);
+    }
+
+    private String maskIdCard(String value) {
+        if (value == null) return null;
+        return value.length() <= 10 ? stars(value.length()) : value.substring(0, 6) + stars(value.length() - 10) + value.substring(value.length() - 4);
+    }
+
+    private String stars(int size) {
+        StringBuilder result = new StringBuilder();
+        for (int i = 0; i < size; i++) result.append('*');
+        return result.toString();
+    }
+
+    private List<TStore> validateStores(List<Integer> storeIds) {
+        List<TStore> stores = new ArrayList<TStore>();
+        Integer currentType = UserExt.getUser().getObjectType();
+        Integer currentObjectId = UserExt.getUser().getObjectId();
+        for (Integer storeId : storeIds.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList())) {
+            TStore store = storeService.getById(storeId);
+            if (store == null || !Integer.valueOf(1).equals(store.getState())) return null;
+            if ((Integer.valueOf(2).equals(currentType) && !currentObjectId.equals(store.getOperatorId()))
+                    || (Integer.valueOf(3).equals(currentType) && !currentObjectId.equals(store.getId()))) return null;
+            stores.add(store);
+        }
+        return stores;
+    }
+
     /**
      * 删除管理员(逻辑删除)
      * Delete administrator (logical deletion)

--
Gitblit v1.7.1