刘帅
7 天以前 d41e0da5df20d559b0b9b8c180d1bf70ba7c1845
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/system/UserMgrController.java
@@ -1,13 +1,10 @@
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;
import com.dsh.course.feignClient.account.model.Company;
import com.dsh.course.feignClient.activity.CompanyClient;
import com.dsh.course.feignClient.activity.DriverClient;
import com.dsh.course.feignClient.activity.model.CompanyInfoRes;
import com.dsh.course.feignClient.activity.model.CompanyQueryStateAndFlgReq;
import com.dsh.course.feignClient.activity.model.UpdateCompanyDriverReq;
import com.dsh.course.mapper.UserMapper;
import com.dsh.guns.config.UserExt;
import com.dsh.guns.config.properties.GunsProperties;
@@ -25,26 +22,33 @@
import com.dsh.guns.core.exception.GunsException;
import com.dsh.guns.core.log.LogObjectHolder;
import com.dsh.guns.core.util.SinataUtil;
import com.dsh.guns.core.util.ToolUtil;
import com.dsh.guns.modular.system.controller.util.MD5;
import com.dsh.guns.modular.system.factory.UserFactory;
import com.dsh.guns.modular.system.model.Role;
import com.dsh.guns.modular.system.model.User;
import com.dsh.guns.modular.system.model.*;
import com.dsh.guns.modular.system.service.IDeptService;
import com.dsh.guns.modular.system.service.IRoleService;
import com.dsh.guns.modular.system.service.IStoreService;
import com.dsh.guns.modular.system.service.IUserService;
import com.dsh.guns.modular.system.transfer.UserDto;
import com.dsh.guns.modular.system.util.OBSUploadUtil;
import com.dsh.guns.modular.system.util.OssUploadUtil;
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.annotation.Resource;
import javax.naming.NoPermissionException;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
/**
 * 系统管理员控制器
@@ -58,20 +62,22 @@
    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;
    @Autowired
    private IUserService userService;
    @Resource
    private DriverClient itDriverService;
    @Autowired
    private IRoleService roleService;
    @Resource
    private CompanyClient itCompanyService;
    @Autowired
    private IDeptService deptService;
    /**
@@ -80,6 +86,7 @@
    @RequestMapping("")
    public String index(Model model) {
        model.addAttribute("language",UserExt.getLanguage());
        model.addAttribute("isSuperAdmin", "admin".equalsIgnoreCase(UserExt.getUser().getAccount()));
        return PREFIX + "user.html";
    }
@@ -88,8 +95,39 @@
     */
    @RequestMapping("/user_add")
    public String addView(Model model) {
        model.addAttribute("role",UserExt.getUser().getObjectType());
        model.addAttribute("language",UserExt.getLanguage());
        LambdaQueryWrapper<Role> roleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(UserExt.getUser().getObjectType()!=1){
            roleLambdaQueryWrapper.eq(Role::getObjId,UserExt.getUser().getObjectId());
        }
        roleLambdaQueryWrapper.eq(Role::getObjType,UserExt.getUser().getObjectType());
        List<Role> list = roleService.list(roleLambdaQueryWrapper);
        model.addAttribute("list",list);
        // 部门列表
        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);
        User currentUser = UserExt.getUser();
        // 超级管理员可维护全部启用门店;其他员工仅能看到自己被分配的门店。
        // getStoreIdsByUserId 同时兼容 sys_user_store、多门店改造前的 objectId,及历史店长数据。
        if (!isSuperAdmin(currentUser)) {
            List<Integer> storeIds = userMapper.getStoreIdsByUserId(currentUser.getId());
            if (storeIds == null || storeIds.isEmpty()) {
                return Collections.emptyList();
            }
            query.in(TStore::getId, storeIds);
        }
        return storeService.list(query);
    }
    private boolean isSuperAdmin(User user) {
        return user != null && "admin".equalsIgnoreCase(user.getAccount());
    }
    /**
@@ -109,22 +147,73 @@
    }
    /**
     * 跳转到编辑管理员页面
     * 跳转到编辑管理员页面 type=1编辑 type=2 查看详情
     */
    @Permission
    @RequestMapping("/user_edit/{userId}")
    public String userEdit(@PathVariable Integer userId, Model model) {
    @RequestMapping("/user_edit/{userId}/{type}")
    public String userEdit(@PathVariable Integer userId,@PathVariable Integer type, Model model) {
        model.addAttribute("role",UserExt.getUser().getObjectType());
        if (Objects.isNull(userId)) {
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        assertAuth(userId);
        User user = this.userService.getById(userId);
        model.addAttribute(user);
        model.addAttribute("roleName", ConstantFactory.me().getRoleName(user.getRoleid()));
        model.addAttribute("deptName", ConstantFactory.me().getDeptName(user.getDeptid()));
        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", user);
        model.addAttribute("idCard", user.getIdCard());
        if(role==null){
            model.addAttribute("roleName", "");
        }else {
            model.addAttribute("roleName", role.getName());
        }
        if(dept==null){
            model.addAttribute("deptName","");
        }else {
            model.addAttribute("deptName", dept.getFullname());
        }
        LogObjectHolder.me().set(user);
        LambdaQueryWrapper<Role> roleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(UserExt.getUser().getObjectType()!=1){
            roleLambdaQueryWrapper.eq(Role::getObjId,UserExt.getUser().getObjectId());
        }
        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());
        // 部门列表
        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);
    }
    /**
@@ -137,9 +226,23 @@
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        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("roleName", ConstantFactory.me().getRoleName(user.getRoleid()));
        model.addAttribute("deptName", user.getDeptid()==0?"顶级":ConstantFactory.me().getDeptName(user.getDeptid()));
        model.addAttribute("roleName", role.getName());
        if(dept==null){
            model.addAttribute("deptName", "无");
        }else{
            model.addAttribute("deptName", user.getDeptid()==0?"顶级":dept.getFullname());
        }
        LogObjectHolder.me().set(user);
        return PREFIX + "user_view.html";
    }
@@ -167,7 +270,6 @@
        if (user.getPassword().equals(oldMd5)) {
            String newMd5 = MD5.md5(newPwd);
            user.setPassword(newMd5);
            user.setPassWordUpdate(new Date());
            user.updateById();
            return SUCCESS_TIP;
        } else {
@@ -175,32 +277,80 @@
        }
    }
    @Autowired
    private IStoreService storeService;
    @Autowired
    private UserMapper userMapper;
    /**
     * 查询管理员列表
     */
    @RequestMapping("/list")
    @Permission
    @ResponseBody
    public Object list(@RequestParam(required = false) String name, @RequestParam(required = false) String createTime, @RequestParam(required = false) Integer deptid) {
        //创建日期
        String beginTime = null;
        String endTime = null;
        if (SinataUtil.isNotEmpty(createTime)){
            String[] timeArray = createTime.split(" - ");
            beginTime = timeArray[0];
            endTime = timeArray[1];
    public List<UserListVO> list(String name, String phone, String idCard, Integer isSales, Integer state) {
        UserQuery userQuery = new UserQuery();
        userQuery.setName(name);
        userQuery.setPhone(phone);
        userQuery.setIdCard(idCard);
        userQuery.setIsSales(isSales);
        userQuery.setStatus(state);
        // 根据当前登陆人类型来查询员工列表
        Integer objectType = UserExt.getUser().getObjectType();
        Integer objectId = UserExt.getUser().getObjectId();
        switch (objectType){
            case 1:
                // 平台查询所有
                List<UserListVO> res= userService.searchUsers(userQuery);
                return res;
            case 2:
                // 运营商查询运营商账号的员工和属于该运营商门店的员工
//                userQuery.setObjectType(2);
//                userQuery.setObjectId(objectId);
//                // 获取属于这个运营商的门店的店长ids
//                List<Integer> storeStaffIds = storeService.list(new QueryWrapper<TStore>().eq("operatorId", objectId)
//                        .ne("state", 3)).stream().map(TStore::getStoreStaffId).collect(Collectors.toList());
//                userQuery.setStoreIds(storeStaffIds);
//                List<UserListVO> res1= userService.searchUsers(userQuery);
                List<UserListVO> res1= userService.searchUsers(userQuery);
                List<UserListVO> filteredList = res1.stream()
                        .filter(vo -> Objects.equals(vo.getVersion(), UserExt.getUser().getId()))
                        .collect(Collectors.toList());
//                return res1;
                return filteredList;
            case 3:
                // 门店员工可同时归属多个门店,员工列表应汇总这些门店下的所有员工。
                List<Integer> currentStoreIds = userMapper.getStoreIdsByUserId(UserExt.getUser().getId());
                List<Integer> employeeIds = currentStoreIds == null || currentStoreIds.isEmpty()
                        ? Collections.<Integer>emptyList()
                        : userMapper.getUserIdsByStoreIds(currentStoreIds);
                // searchUsers 在集合为空时不会拼接 IN 条件;用不存在的 ID 明确返回空结果,避免越权看到全部员工。
                userQuery.setStoreIds(employeeIds == null || employeeIds.isEmpty()
                        ? Collections.singletonList(-1) : employeeIds);
                List<UserListVO> res2= userService.searchUsers(userQuery);
                return res2;
        }
        User user = UserExt.getUser();
        Role role = roleService.getBaseMapper().selectById(user.getRoleid());
        if ("administrator".equals(role.getTips())) {
            Page<Map<String, Object>> page = new PageFactory<Map<String, Object>>().defaultPage();
            page.setRecords(userService.getUserListPage(page,null, name, beginTime, endTime, deptid));
            return super.packForBT(page);
        } else {
            Page<Map<String, Object>> page = new PageFactory<Map<String, Object>>().defaultPage();
            page.setRecords(userService.getUserListPage(page,null, name, beginTime, endTime, deptid));
            return super.packForBT(page);
        }
        return new ArrayList<>();
//        //创建日期
//        String beginTime = null;
//        String endTime = null;
//        if (SinataUtil.isNotEmpty(createTime)){
//            String[] timeArray = createTime.split(" - ");
//            beginTime = timeArray[0];
//            endTime = timeArray[1];
//        }
//        User user = UserExt.getUser();
//        Role role = roleService.getBaseMapper().selectById(user.getRoleid());
//        if ("administrator".equals(role.getTips())) {
//            Page<Map<String, Object>> page = new PageFactory<Map<String, Object>>().defaultPage();
//            page.setRecords(userService.getUserListPage(page,null, name, beginTime, endTime, deptid));
//            return super.packForBT(page);
//        } else {
//            Page<Map<String, Object>> page = new PageFactory<Map<String, Object>>().defaultPage();
//            page.setRecords(userService.getUserListPage(page,null, name, beginTime, endTime, deptid));
//            return super.packForBT(page);
//        }
    }
    /**
@@ -210,34 +360,74 @@
    @BussinessLog(value = "添加管理员", key = "account", dict = UserDict.class)
    @Permission(Const.ADMIN_NAME)
    @ResponseBody
    public Tip add(@Valid UserDto user, BindingResult result) {
    @Transactional(rollbackFor = Exception.class)
    public Object add(@Valid UserDto user, BindingResult result) {
        if (result.hasErrors()) {
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        // 判断账号是否重复
        //Check if the account is duplicated
        User theUser = userService.getByAccount(user.getAccount());
        if (theUser != null) {
            throw new GunsException(BizExceptionEnum.USER_ALREADY_REG);
        // 手机号既是登录账号,必须在 sys_user 中唯一;使用内容判断,不能使用 != 比较字符串引用。
        if (StringUtils.isEmpty(user.getPhone())) {
            return 5002;
        }
        // 已逻辑删除的员工(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;
        }
        // 完善账号信息
        // Complete account information
        user.setPassword(SecureUtil.md5(user.getPassword()));
        user.setStatus(ManagerStatus.OK.getCode());
        user.setCreatetime(new Date());
        User objectUser = UserFactory.createUser(user);
        //查找平台所属公司
        //Search for the company that owns the platform.
        Company company = itCompanyService.getCompanyByTypeAndFlag(new CompanyQueryStateAndFlgReq(1,3));
        if (SinataUtil.isNotEmpty(company)){
            objectUser.setObjectId(company.getId());
        }
        objectUser.setPassWordUpdate(new Date());
        this.userService.save(objectUser);
        if (StringUtils.isEmpty(user.getRoleid())){
            objectUser.setObjectType(2);
        }else {
            objectUser.setObjectType(Integer.valueOf(user.getRoleid()));
        }
        objectUser.setObjectId(UserExt.getUser().getObjectId());
        objectUser.setRoleid(user.getRoleid());
        objectUser.setAccount(user.getPhone());
        objectUser.setName(user.getName());
        objectUser.setPhone(user.getPhone());
        objectUser.setBirthday(user.getBirthday());
        objectUser.setDeptid(user.getDeptid());
        objectUser.setIdCard(user.getIdCard());
        objectUser.setSex(user.getSex());
        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()) {
            assignedStores = validateStores(user.getStoreIds());
            if (assignedStores == null || assignedStores.isEmpty()) return ResultUtil.error("所选门店不存在、已停用或不在当前账号的管理范围内");
            // 首个门店同步写入旧字段,保证既有权限、数据查询和登录逻辑无需改造。
            TStore primaryStore = assignedStores.get(0);
            objectUser.setObjectType(3);
            objectUser.setRoleid("3");
            objectUser.setObjectId(primaryStore.getId());
        // 运营商添加员工
        } else if (UserExt.getUser().getObjectType() == 2){
            objectUser.setObjectType(UserExt.getUser().getObjectType());
            objectUser.setRoleid("2");
            objectUser.setObjectId(UserExt.getUser().getObjectId());
        }
        // 门店添加员工
        if (UserExt.getUser().getObjectType() == 3){
            objectUser.setObjectType(UserExt.getUser().getObjectType());
            objectUser.setRoleid("3");
            objectUser.setObjectId(UserExt.getUser().getObjectId());
        }
        objectUser.setVersion(UserExt.getUser().getId());
        this.userService.save(objectUser);
        if (!assignedStores.isEmpty()) {
            replaceStoreRelations(objectUser.getId(), assignedStores);
        }
        return SUCCESS_TIP;
    }
@@ -249,26 +439,153 @@
    @RequestMapping("/edit")
    @BussinessLog(value = "修改管理员", key = "account", dict = UserDict.class)
    @ResponseBody
    public Tip edit(@Valid UserDto user, BindingResult result) throws NoPermissionException {
    @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());
//        UserExt.hasRole(Const.ADMIN_NAME)
        if (false) {
            this.userService.updateById(UserFactory.editUser(user, oldUser));
            return SUCCESS_TIP;
        } else {
            assertAuth(user.getId());
            User shiroUser = UserExt.getUser();
            if (shiroUser.getId().equals(user.getId()) || shiroUser.getId()==1) {
                this.userService.updateById(UserFactory.editUser(user, oldUser));
                return SUCCESS_TIP;
            } else {
                throw new GunsException(BizExceptionEnum.NO_PERMITION);
        // 判断是否更改电话
        if (StringUtils.isEmpty(user.getPhone()) || user.getPhone().contains("*")) {
            // The edit view displays a masked phone. Treat an unchanged masked
            // 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());
            }else{
                return 5001;
            }
        }
        oldUser.setName(user.getName());
        oldUser.setBirthday(user.getBirthday());
        oldUser.setDeptid(user.getDeptid());
        // 身份证号为空说明本次表单没有提交该字段,不能覆盖数据库中的历史值;
        // 脱敏值同样只用于回显,不能写回数据库。
        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("")))
        oldUser.setAvatar(user.getAvatar());
        if (user.getStoreIds() != null) {
            List<TStore> assignedStores = validateStores(user.getStoreIds());
            if (assignedStores == null) return ResultUtil.error("所选门店不存在、已停用或不在当前账号管理范围内");
            // 非超级管理员的页面只会展示自己有权限的门店。保存时仅更新这个范围,
            // 被编辑员工在其他门店(当前账号无权查看)的归属必须原样保留。
            List<TStore> effectiveStores = mergeEditableAndProtectedStores(oldUser.getId(), assignedStores);
            replaceStoreRelations(oldUser.getId(), effectiveStores);
            if (!effectiveStores.isEmpty()) {
                oldUser.setObjectType(3);
                oldUser.setObjectId(effectiveStores.get(0).getId());
                oldUser.setRoleid("3");
            } 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);
    }
    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>();
        User currentUser = UserExt.getUser();
        if (storeIds == null) return stores;
        Set<Integer> manageableStoreIds = null;
        if (!isSuperAdmin(currentUser)) {
            List<Integer> assignedStoreIds = userMapper.getStoreIdsByUserId(currentUser.getId());
            manageableStoreIds = assignedStoreIds == null ? Collections.<Integer>emptySet() : new HashSet<>(assignedStoreIds);
        }
        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 (manageableStoreIds != null && !manageableStoreIds.contains(storeId)) return null;
            stores.add(store);
        }
        return stores;
    }
    /**
     * 合并本次可编辑范围内的选择与原有不可编辑门店,避免局部管理员覆盖其他门店的归属。
     */
    private List<TStore> mergeEditableAndProtectedStores(Integer userId, List<TStore> editableStores) {
        if (isSuperAdmin(UserExt.getUser())) {
            return editableStores;
        }
        List<Integer> currentUserStoreIds = userMapper.getStoreIdsByUserId(UserExt.getUser().getId());
        Set<Integer> editableStoreIds = currentUserStoreIds == null
                ? Collections.<Integer>emptySet() : new HashSet<>(currentUserStoreIds);
        Map<Integer, TStore> effectiveStoreMap = new LinkedHashMap<>();
        for (TStore store : editableStores) {
            effectiveStoreMap.put(store.getId(), store);
        }
        List<Integer> previousStoreIds = userMapper.getStoreIdsByUserId(userId);
        if (previousStoreIds != null) {
            for (Integer storeId : previousStoreIds) {
                if (storeId == null || editableStoreIds.contains(storeId)) {
                    continue;
                }
                TStore store = storeService.getById(storeId);
                if (store != null) {
                    effectiveStoreMap.put(storeId, store);
                }
            }
        }
        return new ArrayList<>(effectiveStoreMap.values());
    }
    /** 每条关联记录单独生成雪花主键,避免 MyBatis foreach 复用同一个绑定变量。 */
    private void replaceStoreRelations(Integer userId, List<TStore> stores) {
        userMapper.deleteStoreRelations(userId);
        for (TStore store : stores) {
            userMapper.insertStoreRelation(IdWorker.getId(), userId, store.getId());
        }
    }
@@ -348,28 +665,6 @@
        assertAuth(userId);
        this.userService.setStatus(userId, ManagerStatus.FREEZED.getCode());
        User user = userService.getById(userId);
        if (user.getRoleType() == 2){
            //查询分公司 Query branch office
            CompanyInfoRes company = itCompanyService.queryById(user.getObjectId());
            company.setState(1);
            itCompanyService.updateCompany(company);
            //设置该分公司下的所有司机状态
            //Set the status of all drivers under this branch
            itDriverService.updateCompanyDriverState(new UpdateCompanyDriverReq(3,company.getId()));
        }else if (user.getRoleType() == 3){
            //查询加盟商
            //Search for franchisees
            CompanyInfoRes franchisee = itCompanyService.queryById(user.getObjectId());
            franchisee.setState(1);
            itCompanyService.updateCompany(franchisee);
            //设置该加盟商下的所有司机状态
            //Set the status of all drivers under this franchisee
            itDriverService.updateFranchiseeDriverState(new UpdateCompanyDriverReq(3,franchisee.getId()));
        }
        return SUCCESS_TIP;
    }
@@ -387,29 +682,6 @@
        assertAuth(userId);
        this.userService.setStatus(userId, ManagerStatus.OK.getCode());
        User user = userService.getById(userId);
        if (user.getRoleType() == 2){
            //查询分公司
            //Query branch office
            CompanyInfoRes company = itCompanyService.queryById(user.getObjectId());
            company.setState(0);
            itCompanyService.updateCompany(company);
            //设置该分公司下的所有司机状态
            ////Set the status of all drivers under this branch
            itDriverService.updateCompanyDriverState(new UpdateCompanyDriverReq(2,company.getId()));
        }else if (user.getRoleType() == 3){
            //查询加盟商
            ////Search for franchisees
            CompanyInfoRes franchisee = itCompanyService.queryById(user.getObjectId());
            franchisee.setState(0);
            itCompanyService.updateCompany(franchisee);
            //设置该加盟商下的所有司机状态
            //Set the status of all drivers under this branch
            itDriverService.updateFranchiseeDriverState(new UpdateCompanyDriverReq(2,franchisee.getId()));
        }
        return SUCCESS_TIP;
    }
@@ -439,21 +711,57 @@
    /**
     * 上传图片
     */
    @RequestMapping(method = RequestMethod.POST, path = "/upload")
    @RequestMapping(method = RequestMethod.POST, path = "/uploadImg")
    @ResponseBody
    public String upload(@RequestPart("file") MultipartFile picture) {
        String pictureName = UUID.randomUUID().toString() + "." + ToolUtil.getFileSuffix(picture.getOriginalFilename());
    public String uploadImg(@RequestPart("file") MultipartFile picture) {
        String pictureName = "";
        try {
            String fileSavePath = gunsProperties.getFileUploadPath();
            picture.transferTo(new File(fileSavePath + pictureName));
        } catch (Exception e) {
            throw new GunsException(BizExceptionEnum.UPLOAD_ERROR);
            pictureName = OssUploadUtil.ossUpload("img/", picture);
        }catch (Exception e){
            e.printStackTrace();
        }
        return pictureName;
    }
    /**
     * 上传图片
     */
    /**
     * 上传图片Amis
     */
    @RequestMapping(method = RequestMethod.POST, path = "/uploadImgAmis")
    @ResponseBody
    public ResultUtil uploadImgAmis(@RequestPart("file") MultipartFile picture, HttpServletResponse response) {
        String value = "";
        try {
            value = OssUploadUtil.ossUpload("img/", picture);
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("图片返回地址-------"+value);
        Map<String, String> map = new HashMap<>();
        map.put("value",value);
//        return  ResultUtil.success(0,map);
        return  ResultUtil.getResult(0,null,null,map);
    }
    @RequestMapping(method = RequestMethod.POST, path = "/uploadFile")
    @ResponseBody
    public String uploadFile(@RequestPart("file") MultipartFile picture) {
        String pictureName = "";
        try {
            pictureName = OssUploadUtil.ossUpload("video/", picture);
        }catch (Exception e){
            e.printStackTrace();
        }
        return pictureName;
    }
    /**
     * 判断当前登录的用户是否有操作这个用户的权限
     */
    private void assertAuth(Integer userId) {