package com.sckw.system.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sckw.core.common.enums.enums.DictEnum;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.exception.SystemException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.enums.ApprovalEnum;
import com.sckw.core.model.enums.ClientTypeEnum;
import com.sckw.core.model.enums.SystemTypeEnum;
import com.sckw.core.utils.*;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.constant.RequestConstant;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.model.LoginUserInfo;
import com.sckw.core.web.request.RequestUtil;
import com.sckw.excel.utils.ExcelUtil;
import com.sckw.redis.constant.RedisConstant;
import com.sckw.redis.utils.RedissonUtils;
import com.sckw.system.api.model.dto.req.RegisterReqDto;
import com.sckw.system.api.model.dto.req.UpdatePasswordReqDto;
import com.sckw.system.api.model.dto.res.AreaTreeFrontResDto;
import com.sckw.system.api.model.dto.res.EntCacheResDto;
import com.sckw.system.api.model.dto.res.KwsUserResDto;
import com.sckw.system.api.model.dto.res.RegisterResDto;
import com.sckw.system.api.model.dto.res.SysDictResDto;
import com.sckw.system.dao.*;
import com.sckw.system.dubbo.RemoteSystemServiceImpl;
import com.sckw.system.model.*;
import com.sckw.system.model.LoginLogs;
import com.sckw.system.api.model.dto.res.RoleInfoDto;
import com.sckw.system.model.report.KwsUserExcel;
import com.sckw.system.model.vo.req.*;
import com.sckw.system.model.vo.res.*;
import com.sckw.system.repository.KwsRoleRepository;
import com.sckw.system.repository.KwsUserRepository;
import com.sckw.system.repository.KwsUserRoleRepository;
import com.sckw.system.repository.LoginLogsService;
import com.sckw.transport.api.dubbo.TransportRemoteStatisticsService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户service接口
 *
 * @author zk
 * @date 2023-05-31
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class KwsUserService {

    @Autowired
    KwsUserDao kwsUserDao;

    @Autowired
    KwsUserDeptDao kwsUserDeptDao;

    @Autowired
    KwsEntCheckTrackDao kwsEntCheckTrackDao;

    @Autowired
    KwsRoleService kwsRoleService;

    @Autowired
    KwsUserRoleDao kwsUserRoleDao;

    @Autowired
    KwsDeptService kwsDeptService;

    @Autowired
    KwsEnterpriseDao kwsEnterpriseDao;

    @Autowired
    private KwsSpecialService kwsSpecialService;

    @Autowired
    KwsMenuService kwsMenuService;

    @Autowired
    private RemoteSystemServiceImpl remoteSystemService;

    @Autowired
    private CommonService commonService;

    private final KwsRoleRepository kwsRoleRepository;

    private final KwsUserRoleRepository kwsUserRoleRepository;

    private final KwsUserRepository kwsUserRepository;

    private final LoginLogsService loginLogsService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private TransportRemoteStatisticsService transportStatisticsService;

    /**
     * @param reqVo 入参
     * @desc: 新增
     * @author: czh
     * @date: 2023/7/7
     */
    @Transactional(rollbackFor = {})
    public void add(UserAddReqVo reqVo) {
        // 平台端用户只能新增平台员工，不能新增企业员工
        if (LoginUserHolder.isManager() && !Objects.equals(reqVo.getSystemType(), SystemTypeEnum.MANAGE.getCode())) {
            throw new BusinessException("平台端只能新增平台员工数据");
        }
        commonService.checkPhone(reqVo.getAccount());
        KwsUser kwsUser = new KwsUser();
        BeanUtils.copyProperties(reqVo, kwsUser);
        kwsUser.setPhone(kwsUser.getAccount());
        kwsUser.setIsMain(Global.NO);
        kwsUser.setSystemType(kwsUser.getSystemType());

        /*1、数据校验*/
        checkAccountValid(kwsUser.getAccount(), kwsUser.getSystemType());

        /*2、填充密码*/
        fillPassword(kwsUser);
        synchronized (this) {
            //再次校验数据
            checkAccountValid(kwsUser.getAccount(), kwsUser.getSystemType());
            /*3、存库*/
            long userId = new IdWorker(1).nextId();
            kwsUser.setId(userId);
            if (kwsUserDao.insert(kwsUser) <= 0) {
                throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.INSERT_FAIL);
            }

            /*4、填充用户角色*/
            fillUserRole(reqVo.getRoleIds(), userId, reqVo.getSystemType());

            /*5、用户机构关系*/
//            fillUserDept(kwsUser.getId(), reqVo.getDeptId());
        }

    }

    /**
     * @param reqDto 入参
     * @return RegisterResDto
     * @desc: 注册
     * @author: czh
     * @date: 2023/7/7
     */
    @Transactional(rollbackFor = {})
    public RegisterResDto register(RegisterReqDto reqDto) {
        commonService.checkEntRepeat(reqDto.getEntName(), reqDto.getPhone());
        /*1、数据校验*/
        checkAccountValid(reqDto.getPhone(), reqDto.getSystemType());

        /*存用户表、企业表，暂时不处理角色关系，需要认证*/
        KwsUser kwsUser = new KwsUser();
        long userId = new IdWorker(1).nextId();
        Long createBy = userId;
        if (Objects.nonNull(LoginUserHolder.getUserId()) && LoginUserHolder.getUserId().compareTo(1L) != 0) {
            createBy = LoginUserHolder.getUserId();
        }
        long entId = new IdWorker(1L).nextId();

        kwsUser.setSystemType(reqDto.getSystemType());
        kwsUser.setAccount(reqDto.getPhone());
        kwsUser.setPassword(reqDto.getPassword());
        kwsUser.setName(reqDto.getName());
        kwsUser.setPhone(reqDto.getPhone());
        kwsUser.setIsMain(reqDto.getIsMain());
        kwsUser.setId(userId);
        kwsUser.setEntId(entId);

        kwsUser.setCreateBy(createBy);
        kwsUser.setUpdateBy(createBy);
        //填充密码、入库
        fillPassword(kwsUser);
        if (kwsUserDao.insert(kwsUser) <= 0) {
            throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.INSERT_FAIL);
        }

        //组装返参
        RegisterResDto registerResDto = new RegisterResDto();
        registerResDto.setUserId(userId);

        /*存企业机构等*/
        //目前注册接口只有企业管理员进来
        if (reqDto.getIsMain() == Global.YES && !reqDto.getSystemType().equals(SystemTypeEnum.MANAGE.getCode())) {
            KwsEnterprise kwsEnterprise = new KwsEnterprise();
            kwsEnterprise.setId(entId);
            kwsEnterprise.setCode("");
            kwsEnterprise.setRegTime(new Date());
            kwsEnterprise.setFirmName(reqDto.getEntName());
            kwsEnterprise.setApproval(ApprovalEnum.NO.getCode());
            kwsEnterprise.setContacts(reqDto.getName());
            kwsEnterprise.setPhone(reqDto.getPhone());
            kwsEnterprise.setCreateBy(createBy);
            kwsEnterprise.setUpdateBy(createBy);

            //默认给一个客户经理(admin账号)-公共平台
            List<KwsUserSystemTypeVo> userSystemTypeVos = kwsUserDao.selectUserBySystemType(SystemTypeEnum.MANAGE.getCode());
            if (CollectionUtils.isNotEmpty(userSystemTypeVos)) {
                KwsUserSystemTypeVo kwsUserSystemTypeVo = userSystemTypeVos.get(0);
                kwsEnterprise.setManager(kwsUserSystemTypeVo.getId());
            }

            if (kwsEnterpriseDao.insert(kwsEnterprise) <= 0) {
                throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.INSERT_FAIL);
            }

            registerResDto.setEntId(entId);
            /*1、新增管理员机构*/
//            KwsDept kwsDept = new KwsDept();
//            Integer systemType = SystemTypeEnum.COMPANY.getCode();
//            kwsDept.setEntId(entId);
//            kwsDept.setName(reqDto.getEntName());
//            kwsDept.setSystemType(systemType);
//            kwsDept.setCompany(Global.NO);
//            kwsDept.setUpdateBy(createBy);
//            kwsDept.setCreateBy(createBy);
//            kwsDeptService.add(kwsDept);
//
//            /*3、绑定用户机构关系*/
//            fillUserDept(userId, kwsDept.getId());

            /*2、新增管理员角色*/
            EditRoleReqVo editRoleReqVo = new EditRoleReqVo();
            editRoleReqVo.setEntId(entId);
            List<KwsMenu> kwsMenus = kwsMenuService.selectAll();
            if (CollectionUtils.isEmpty(kwsMenus)) {
                throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.MENU_NOT_EXISTS);
            }
            kwsMenus = kwsMenus.stream().filter(item -> item.getClientType().equals(Global.NUMERICAL_TWO)).collect(Collectors.toList());

            //企业属性 （1供应商，2采购商，34PL物流，43PL物流）
//            if (org.apache.commons.lang3.StringUtils.equals("1",reqDto.getEntTypes())){
//                editRoleReqVo.setName("供应商管理员");
//            }else if (org.apache.commons.lang3.StringUtils.equals("2",reqDto.getEntTypes())){
//                editRoleReqVo.setName("采购商管理员");
//            }else if (org.apache.commons.lang3.StringUtils.equals("3",reqDto.getEntTypes())){
//                editRoleReqVo.setName("物流商管理员");
//            }
            editRoleReqVo.setName(Global.MANAGE_NAME);
            editRoleReqVo.setCurrentUnitId(null);
            editRoleReqVo.setMenuIds(String.join(Global.COMMA, kwsMenus.stream().map(KwsMenu::getId).map(String::valueOf).toList()));
            editRoleReqVo.setVisiblePersonal(false);
            editRoleReqVo.setIsManage(true);
            editRoleReqVo.setAdminFlag(1);
            kwsRoleService.add(editRoleReqVo);
        }

        return registerResDto;
    }

    /**
     * @param userId 用户id，deptId 机构id
     * @desc: 填充用户机构
     * @author: czh
     * @date: 2023/7/11
     */
    private void fillUserDept(long userId, long deptId) {
        KwsUserDept kwsUserDept = new KwsUserDept();
        kwsUserDept.setUserId(userId);
        kwsUserDept.setDeptId(deptId);
        kwsUserDept.setId(new IdWorker(1).nextId());
        kwsUserDept.setRemark("");
        kwsUserDept.setStatus(Global.NO);
        kwsUserDept.setDelFlag(Global.NO);
        if (kwsUserDeptDao.insert(kwsUserDept) <= 0) {
            throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.INSERT_FAIL);
        }
    }

    /**
     * @param roleIds 角色ids，userId用户id，systemType系统类型
     * @desc: 填充用户角色
     * @author: czh
     * @date: 2023/7/7
     */
    public void fillUserRole(String roleIds, long userId, Integer systemType) {
        UserBindRoleReqVo userBindRoleReqVo = new UserBindRoleReqVo();
        userBindRoleReqVo.setUserId(userId);
        userBindRoleReqVo.setRoleIds(roleIds);
        userBindRoleReqVo.setSystemType(systemType);
        kwsRoleService.userBindRole(userBindRoleReqVo);
    }

    /**
     * @param kwsUser 实体类
     * @desc: 填充密码
     * @author: czh
     * @date: 2023/7/7
     */
    private void fillPassword(KwsUser kwsUser) {
        //密码为空时，以登录名作为密码
        String salt = PasswordUtils.generateSalt();
        String password;
        if (StringUtils.isBlank(kwsUser.getPassword())) {
            password = PasswordUtils.entryptPassword(kwsUser.getAccount() + PasswordUtils.md5(kwsUser.getAccount()), salt);
            kwsUser.setPassword(password);
        } else {
            password = PasswordUtils.entryptPassword(kwsUser.getAccount() + kwsUser.getPassword(), salt);
            kwsUser.setPassword(password);
        }
        kwsUser.setSalt(salt);
    }

    /**
     * 删除记录-根据主键
     */
    @Transactional(rollbackFor = {})
    public void deleteByKey(String ids) {
        /*1.数据校验*/
        if (StringUtils.isBlank(ids)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.ACCOUNT_MISSING);
        }

        String[] idArray = ids.split(",");
        for (String id : idArray) {
            if (id.equals(String.valueOf(LoginUserHolder.getUserId()))) {
                throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.MSG_025);
            }
            KwsUser kwsUser = kwsUserDao.selectByKey(Long.parseLong(id));
            if (null != kwsUser) {
                // 平台端用户只能删除平台员工，不能删除企业员工
                if (LoginUserHolder.isManager() && !Objects.equals(kwsUser.getSystemType(), SystemTypeEnum.MANAGE.getCode())) {
                    throw new BusinessException("平台端只能删除平台员工数据");
                }
                if (!LoginUserHolder.isManager()) {
                    if (Objects.equals(kwsUser.getIsMain(), 1)) {//企业管理员用户，默认用户不允许删除
                        throw new BusinessException(String.format("默认企业管理员账号[%s]不允许删除", kwsUser.getName()));
                    }
                }
                kwsUser.setDelFlag(Global.YES);
                if (kwsUserDao.updateById(kwsUser) <= 0) {
                    throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.DELETE_FAIL);
                }
            }
        }
    }

    /**
     * 更新记录
     *
     * @param params KwsUser
     */
    @Transactional(rollbackFor = {})
    public void update(UserAddReqVo params) {
        commonService.checkPhone(params.getAccount());
        KwsUser kwsUser = kwsUserDao.selectByKey(params.getId());
        if (Objects.isNull(kwsUser)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.ACCOUNT_NOT_EXISTS);
        }
        // 平台端用户只能修改平台员工，不能修改企业员工
        if (LoginUserHolder.isManager() && !Objects.equals(kwsUser.getSystemType(), SystemTypeEnum.MANAGE.getCode())) {
            throw new BusinessException("平台端只能修改平台员工数据");
        }
        if (!LoginUserHolder.isManager()) {
            if (Objects.equals(kwsUser.getIsMain(), 1)) {//企业管理员用户，只修改名称和备注，归属企业和角色都不允许修改。
                kwsUser.setRemark(params.getRemark());
                kwsUser.setName(params.getName());
                kwsUserDao.updateById(kwsUser);
                return;
            }
        }
        //更换账号后账号唯一性校验
//        if (StringUtils.isNotBlank(params.getAccount())) {
//            //用户信息
//            KwsUser userByAccount = getUserByAccount(params.getAccount(), params.getSystemType());
//            if (Objects.isNull(userByAccount)) {
//                throw new SystemException(HttpStatus.PARAMETERS_MISSING_CODE, HttpStatus.ACCOUNT_EXISTS);
//            }
//        }

        //以前的关联数据先删除再新增
        List<KwsUserDept> kwsUserDepts = kwsUserDeptDao.findAllByUserId(params.getId());
        if (CollectionUtils.isNotEmpty(kwsUserDepts)) {
            for (KwsUserDept kwsUserDept : kwsUserDepts) {
                kwsUserDept.setDelFlag(Global.YES);
                if (kwsUserDeptDao.update(kwsUserDept) <= 0) {
                    throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
                }
            }
        }

        List<KwsUserRole> kwsUserRoles = kwsUserRoleDao.findAllByUserId(params.getId());
        if (CollectionUtils.isNotEmpty(kwsUserRoles)) {
            for (KwsUserRole kwsUserRole : kwsUserRoles) {
                kwsUserRole.setDelFlag(Global.YES);
                if (kwsUserRoleDao.update(kwsUserRole) <= 0) {
                    throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
                }
            }
        }

        kwsUser.setRemark(params.getRemark());
        kwsUser.setName(params.getName());
        kwsUserDao.updateById(kwsUser);

        /*填充用户角色*/
        fillUserRole(params.getRoleIds(), kwsUser.getId(), kwsUser.getSystemType());

        /*用户机构关系*/
//        fillUserDept(kwsUser.getId(), params.getDeptId());
    }

    /**
     * @param id 主键ID
     * @desc 重置密码
     * @author zk
     * @date 2023/06/02
     **/
    public void resetPassword(Long id) {
        //查用户信息
        KwsUser kwsUser = checkUserBase(id);

        //重置密码
        updatePwd(PasswordUtils.md5(kwsUser.getAccount()), kwsUser);
    }

    /**
     * 根据主键查询
     */
    public KwsUser selectByKey(Long key) {
        return kwsUserDao.selectByKey(key);
    }

    /**
     * 根据主键查询
     */
    public KwsUser selectByPhone(String phone) {
        return kwsUserDao.selectByPhone(phone);
    }

    /**
     * 根据主键查询
     */
    public List<KwsUser> selectByKeys(List<Long> key) {
        return kwsUserDao.selectByKeys(key);
    }

    /**
     * 分页查询
     */
    public List<KwsUserResVo> findPage(Map<String, Object> params) {
        if (!LoginUserHolder.isManager()) {
            params.put("systemType", SystemTypeEnum.COMPANY.getCode());
            if (Objects.equals(LoginUserHolder.getIsMain(), Global.YES)) {
                params.put("entList", LoginUserHolder.getChildEntList());
            } else {
                params.put("entId", LoginUserHolder.getEntId());
            }
        }
//        else {
//            //params.put("systemType", SystemTypeEnum.MANAGE.getCode());
//            params.put("entList", LoginUserHolder.getChildEntList());
//        }

        return kwsUserDao.findPage(params);
    }

    /**
     * 查询
     */
    public List<KwsUserResVo> findList(Map<String, Object> params) {
        return kwsUserDao.findList(params);
    }

    public KwsUser queryUserInfo(String username, int systemType) {
        return kwsUserDao.selectOne(new LambdaQueryWrapper<KwsUser>()
                .eq(KwsUser::getAccount, username)
                .eq(KwsUser::getSystemType, systemType)
                .eq(KwsUser::getIsMain, 1)
        );
    }

    /**
     * 根据用户名查用户信息
     */
    public KwsUser getUserByAccount(String username, int systemType) {
        Map<String, Object> params = new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
            put("account", username);
            put("systemType", systemType);
        }};
        List<KwsUserResVo> list = kwsUserDao.findList(params);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        KwsUser kwsUser = new KwsUser();
        KwsUserResVo kwsUserResVo = list.get(0);
        BeanUtils.copyProperties(kwsUserResVo, kwsUser);
        return kwsUser;
    }

    /**
     * @param reqVo 修改密码入参
     * @desc: 修改密码
     * @author: czh
     * @date: 2023/7/3
     */
    public void updatePassword(UpdatePasswordReqDto reqVo) {
        //查用户信息
        KwsUser kwsUser = checkUserBase(reqVo.getId());

        //密码校验
        String account = kwsUser.getAccount();
        String password = reqVo.getPassword();
        String currentPwd = kwsUser.getPassword();
        String salt = kwsUser.getSalt();
        checkPassword(account, password, currentPwd, salt);

        //校验新密码是否可用
        String newPassword = reqVo.getNewPassword();
        if (PasswordUtils.validatePassword(kwsUser.getAccount() + newPassword, currentPwd, kwsUser.getSalt())) {
            throw new SystemException(HttpStatus.CODE_10301, HttpStatus.PASSWD_REPEAT);
        }

        //修改密码
        updatePwd(newPassword, kwsUser);
    }

    private void updatePwd(String newPassword, KwsUser kwsUser) {
        String salt = PasswordUtils.generateSalt();
        String password = PasswordUtils.entryptPassword(kwsUser.getAccount() + newPassword, salt);
        kwsUser.setPassword(password);
        kwsUser.setSalt(salt);
        if (kwsUserDao.updateById(kwsUser) <= 0) {
            throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
        }
        //token重置
        for (ClientTypeEnum value : ClientTypeEnum.values()) {
            String fullUserTokenKey = Global.getFullUserTokenKey(value.getValue(), kwsUser.getId());
            RedissonUtils.delete(fullUserTokenKey);
        }
    }

    /**
     * 忘记密码
     */
    public void forgetPassword(ForgetPasswordReqVo reqVo) {
        //查用户信息
        KwsUser kwsUser = checkUserBase(reqVo.getAccount(), reqVo.getSystemType());

        //从缓存中取出验证码,校验
        String key = StringUtils.format(RedisConstant.MESSAGE_SMS_VERIFY_CODE_VALUE_KEY, DictEnum.SMS_UPDATE_PASSWORD.getValue(), reqVo.getAccount());
        String sms = RedissonUtils.getString(key);
        if (!reqVo.getCaptcha().equals(sms)) {
            throw new SystemException(HttpStatus.CODE_10301, HttpStatus.CAPTCHA_ERROR);
        }

        //修改密码
        updatePwd(reqVo.getPassword(), kwsUser);
    }

    /**
     * @param account 账号 systemType 系统类型
     * @return KwsUser
     * @desc: 根据登录名校验，为空抛异常用户信息不存在或已失效
     * @author: czh
     * @date: 2023/6/16
     */
    public KwsUser checkUserBase(String account, int systemType) {
        KwsUser kwsUser = getUserByAccount(account, systemType);
        if (Objects.isNull(kwsUser) || kwsUser.getStatus().equals(Global.YES)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.ACCOUNT_NOT_EXISTS);
        }
        return kwsUser;
    }

    /**
     * 根据id校验
     */
    public KwsUser checkUserBase(long id) {
        KwsUser kwsUser = kwsUserDao.selectByKey(id);
        if (Objects.isNull(kwsUser) || kwsUser.getDelFlag() != Global.NO) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.ACCOUNT_NOT_EXISTS);
        }
        return kwsUser;
    }

    /**
     * 校验密码
     *
     * @param password   入参传的密码
     * @param currentPwd 当前用户的密码
     */
    public void checkPassword(String account, String password, String currentPwd, String salt) {
        if (!PasswordUtils.validatePassword(account + password, currentPwd, salt)) {
            throw new SystemException(HttpStatus.CODE_10301, HttpStatus.PASSWD_ERROR);
        }
    }

    /**
     * @param userId 用户id
     * @return KwsUserDept
     * @desc: 根据用户id查用户机构关联关系
     * @author: czh
     * @date: 2023/7/7
     */
    public List<KwsUserDept> queryUserDeptByUserId(Long userId) {
        return kwsUserDao.queryUserDeptByUserId(userId);
    }

    /**
     * @param list 机构主键
     * @return KwsDept
     * @desc: 批量查机构
     * @author: czh
     * @date: 2023/7/7
     */
    public List<KwsDept> queryDeptByIds(List<Long> list) {
        return kwsUserDao.queryDeptByIds(list);
    }

    /**
     * @param account 账号 systemType系统类型
     * @desc: 校验账号有效性, 存在抛异常用户账号已存在
     * @author: czh
     * @date: 2023/6/16
     */
    public void checkAccountValid(String account, Integer systemType) {
        if (Objects.nonNull(getUserByAccount(account, systemType))) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.ACCOUNT_EXISTS);
        }
    }

    /**
     * @param entId 企业id
     * @return KwsUser
     * @desc: 根据企业id查用户
     * @author: czh
     * @date: 2023/6/26
     */
    public List<KwsUser> selectByEntId(Long entId) {
        return kwsUserDao.selectByEntId(entId);
    }

    /**
     * @param id 用户id
     * @desc: 注销
     * @author: czh
     * @date: 2023/7/3
     */
    public void closeAccount(Long id) {
        KwsUser kwsUser = kwsUserDao.selectByKey(id);
        if (Objects.isNull(kwsUser)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.ACCOUNT_NOT_EXISTS);
        }
        // 平台端用户只能注销平台员工，不能注销企业员工
        if (LoginUserHolder.isManager() && !Objects.equals(kwsUser.getSystemType(), SystemTypeEnum.MANAGE.getCode())) {
            throw new BusinessException("平台端只能注销平台员工数据");
        }
        kwsUser.setDelFlag(Global.YES);
        if (kwsUserDao.updateById(kwsUser) <= 0) {
            throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.DELETE_FAIL);
        }
    }


    /**
     * @param ids 主键
     * @desc: 冻结
     * @author: czh
     * @date: 2023/7/12
     */
    public void freeze(String ids) {
        if (StringUtils.isBlank(ids)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.ID_MISSING);
        }

        String[] split = ids.split(Global.COMMA);
        for (String id : split) {
            KwsUser kwsUser = kwsUserDao.selectByKey(Long.parseLong(id));
            if (Objects.isNull(kwsUser) || !kwsUser.getStatus().equals(Global.NO)) {
                throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.ACCOUNT_FREEZE);
            }

            kwsUser.setStatus(Global.YES);
            if (kwsUserDao.updateById(kwsUser) <= 0) {
                throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
            }
            RedissonUtils.remove(Global.getFullUserLoginKey(kwsUser.getSystemType(), kwsUser.getId()));
        }
    }


    /**
     * @param ids 主键
     * @desc: 解冻
     * @author: czh
     * @date: 2023/7/12
     */
    public void unFreeze(String ids) {
        if (StringUtils.isBlank(ids)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.ID_MISSING);
        }

        String[] split = ids.split(Global.COMMA);
        for (String id : split) {
            KwsUser kwsUser = kwsUserDao.selectByKey(Long.parseLong(id));
            if (Objects.isNull(kwsUser) || !kwsUser.getStatus().equals(Global.YES)) {
                throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.ACCOUNT_UNFREEZE);
            }

            kwsUser.setStatus(Global.NO);
            if (kwsUserDao.updateById(kwsUser) <= 0) {
                throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
            }
        }
    }

    /**
     * @param reqVo 入参
     * @desc: 重置密码
     * @author: czh
     * @date: 2023/7/14
     */
    @Transactional(rollbackFor = {})
    public void resetPasswordByMain(ResetPasswordReqVo reqVo) {
        //查用户信息
        KwsUser kwsUser = checkUserBase(reqVo.getId());

        //重置密码
        updatePwd(reqVo.getNewPassword(), kwsUser);
    }

    public List<AreaTreeFrontResDto> test(List<Integer> list) {
        List<SysDictResDto> sysDictResDtos = remoteSystemService.queryDictFrontAll("product_name_type", "2");
        return null;
    }

    /**
     * 根据用户姓名模糊查用户信息
     *
     * @param name 用户姓名
     * @return list
     */
    public List<KwsUserResDto> getUserByName(String name) {
        List<KwsUser> list = kwsUserDao.getUserByName(name);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        return BeanUtils.copyToList(list, KwsUserResDto.class);
    }

    /**
     * @param deptIds 机构id
     * @return KwsUser
     * @desc: 查机构下的用户
     * @author: czh
     * @date: 2023/9/4
     */
    public List<KwsUser> queryUserByDeptIds(List<Long> deptIds) {
        return kwsUserDao.selectByDeptIds(deptIds);
    }


    public void export(HashMap params, HttpServletResponse response) {
        params.put("entId", LoginUserHolder.getEntId());
        String ids = StringUtils.valueOf(params.get("ids"));
        if (StringUtils.isNotBlank(ids)) {
            params.put("idList", StringUtils.splitStrToList(ids, Long.class));
        }
        List<KwsUserResVo> list = kwsUserDao.findPage(params);
        if (CollectionUtils.isEmpty(list)) {
            throw new SystemException(HttpStatus.SUCCESS_CODE, "暂无数据，请确认！");
        }

        List<KwsUserExcel> result = new ArrayList<>();
        list.forEach(item -> {
            KwsUserExcel kwsUserExce = new KwsUserExcel();
            BeanUtils.copyProperties(item, kwsUserExce);
            kwsUserExce.setStatus(item.getStatus().equals(Global.NO) ? "正常" : "冻结");
            result.add(kwsUserExce);
        });
        ExcelUtil.downData(response, KwsUserExcel.class, result);
    }

    public List<KwsUserSystemTypeVo> getManager() {
        return kwsUserDao.selectUserBySystemTypeAndMain(SystemTypeEnum.MANAGE.getCode(), 0);
    }

    public SalesResp getSales(SalesReq req) {
        log.info("查询销售参数：{}", JSON.toJSONString(req));
        //根据供应方的企业id查出供应方员工作为销售
        List<KwsRole> roles = kwsRoleRepository.queryByEntId(req.getEntId());
        if (CollectionUtils.isEmpty(roles)) {
            return new SalesResp();
        }
        //获取角色id
        Set<Long> roleIds = roles.stream()
                .map(KwsRole::getId)
                .collect(Collectors.toSet());
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(roleIds)) {
            return new SalesResp();
        }
        //获取角色用户管理数据
        List<KwsUserRole> kwsUserRoles = kwsUserRoleRepository.queryByRoleIds(roleIds);
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(kwsUserRoles)) {
            return new SalesResp();
        }
        //获取用户id
        Set<Long> userIds = kwsUserRoles.stream()
                .map(KwsUserRole::getUserId)
                .collect(Collectors.toSet());
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(userIds)) {
            return new SalesResp();
        }

        //获取用户信息
        List<KwsUser> kwsUsers = kwsUserRepository.queryByUserIds(userIds);
        //组装返回数据
        List<SalesResp.Sales> salesList = kwsUsers.stream()
                .map(KwsUserService::getSales)
                .collect(Collectors.toList());
        SalesResp salesResp = new SalesResp();
        salesResp.setSalesRespList(salesList);
        return salesResp;
    }

    private static SalesResp.Sales getSales(KwsUser u) {
        SalesResp.Sales sales = new SalesResp.Sales();
        sales.setSalesName(u.getName());
        sales.setSalesId(String.valueOf(u.getId()));
        sales.setSalesPhone(u.getPhone());
        return sales;
    }

    /**
     * 查询用户信息和角色信息
     *
     * @param params
     * @return
     */
    public KwsUserResVo queryUserRole(Map<String, Object> params) {
        KwsUserResVo kwsUserResVo = kwsUserDao.queryUser(params);
        if (Objects.nonNull(kwsUserResVo)) {
            List<RoleInfoDto> roleInfoVos = kwsUserRoleDao.queryRoleList(kwsUserResVo.getId());
            if (CollUtil.isNotEmpty(roleInfoVos)) {
                kwsUserResVo.setRoleInfoDto(roleInfoVos);
                Optional<RoleInfoDto> first = roleInfoVos.stream().findFirst();
                first.ifPresent(d -> {
                    d.setActivate(true);
                    kwsUserResVo.setRoleId(d.getRoleId());
                    kwsUserResVo.setRoleName(d.getRoleName());
                });
            }
        }
        return kwsUserResVo;

    }

    /**
     * 根据用户ID查询用户信息（头像、姓名、电话、角色、账号状态）
     *
     * @param userId 用户ID
     * @return UserInfoResVo
     */
    public UserInfoResVo getUserInfoById(Long userId) {
        log.info("查询用户信息，用户ID: {}", userId);

        // 1. 查询用户基本信息
        KwsUser kwsUser = kwsUserRepository.getById(userId);
        if (Objects.isNull(kwsUser) || kwsUser.getDelFlag() != Global.NO) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, "用户不存在或已删除");
        }

        // 2. 查询用户角色信息
        List<RoleInfoDto> roleInfoList = kwsUserRoleDao.queryRoleList(userId);
        String roleName = "";
        if (CollUtil.isNotEmpty(roleInfoList)) {
            // 获取第一个角色名称，如有多个角色可用逗号分隔
            roleName = roleInfoList.stream()
                    .map(RoleInfoDto::getRoleName)
                    .collect(Collectors.joining(","));
        }

        // 3. 组装返回结果
        String statusDesc = kwsUser.getStatus() != null && kwsUser.getStatus() == Global.YES ? "锁定" : "正常";

        return UserInfoResVo.builder()
                .userId(kwsUser.getId())
                .photo(kwsUser.getPhoto())
                .name(kwsUser.getName())
                .phone(kwsUser.getPhone())
                .roleName(roleName)
                .status(kwsUser.getStatus())
                .statusDesc(statusDesc)
                .build();
    }

    /**
     * 修改密码（叉车APP）
     *
     * @param userId      用户ID
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     */
    public void updatePasswordForApp(Long userId, String oldPassword, String newPassword,
                                     String clientType, Integer systemType, String deviceId) {
        log.info("修改密码，用户ID: {}", userId);

        // 1. 查询用户信息
        KwsUser kwsUser = checkUserBase(userId);

        // 2. 校验旧密码
        String account = kwsUser.getAccount();
        String currentPwd = kwsUser.getPassword();
        String salt = kwsUser.getSalt();
        oldPassword = PasswordUtils.md5(oldPassword);
        checkPassword(account, oldPassword, currentPwd, salt);

        // 3. 校验新密码是否与旧密码相同
        if (PasswordUtils.validatePassword(kwsUser.getAccount() + newPassword, currentPwd, kwsUser.getSalt())) {
            throw new SystemException(HttpStatus.CODE_10301, "新密码不能与旧密码相同");
        }

        // 4. 修改密码
        updatePwd(newPassword, kwsUser);
        // 5. 清除当前登录用户的token缓存
        clearCurrentUserToken(deviceId, kwsUser);
        log.info("密码修改成功，用户ID: {}", userId);
    }

    private void clearCurrentUserToken(String deviceId, KwsUser kwsUser) {
        try {
            if (kwsUser.getId() != null) {
                for (ClientTypeEnum clientTypeEnum : ClientTypeEnum.values()) {
                    // 清除当前用户的refreshToken
                    String refreshTokenKey = Global.getFullRefreshTokenKey(clientTypeEnum.getValue(), kwsUser.getId(), deviceId);
                    RedissonUtils.delete(refreshTokenKey);
                }

                for (SystemTypeEnum systemTypeEnum : SystemTypeEnum.values()) {
                    // 清除当前用户的登录信息缓存
                    String loginKey = Global.getFullUserLoginKey(systemTypeEnum.getCode(), kwsUser.getId());
                    RedissonUtils.delete(loginKey);
                }
                log.info("已清除当前用户token缓存，userId：{}", kwsUser.getId());
            }
        } catch (Exception e) {
            log.warn("清除当前用户token缓存失败", e);
        }
    }

    /**
     * 用户登录（叉车APP）
     *
     * @param account    账号
     * @param password   密码
     * @param systemType 系统类型
     * @param request    HTTP请求（用于记录登录日志）
     * @return LoginResVo
     */
    public LoginResVo login(String account, String password, Integer systemType, HttpServletRequest request) {
        log.info("用户登录，账号: {}, 系统类型: {}", account, systemType);

        // 1. 查询用户信息
        KwsUser kwsUser = getKwsUser(account, systemType);
        password = PasswordUtils.md5(password);
        // 3. 校验密码
        checkPassword(account, password, kwsUser.getPassword(), kwsUser.getSalt());

        // 4. 查询用户角色
        List<RoleInfoDto> roleInfoList = kwsUserRoleDao.queryRoleList(kwsUser.getId());
        if (CollUtil.isEmpty(roleInfoList)) {
            throw new SystemException(HttpStatus.CODE_60603, "该用户没有分配角色");
        }
        List<String> roleNames = Arrays.asList("铲车司机", "门卫");
        roleInfoList = roleInfoList.stream().filter(x -> roleNames.contains(x.getRoleName()))
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(roleInfoList)) {
            throw new SystemException(HttpStatus.CODE_60603, "你没有登录该系统权限");
        }

        String roleName = roleInfoList.stream()
                .map(RoleInfoDto::getRoleName)
                .collect(Collectors.joining(","));
        Long roleId = roleInfoList.get(0).getRoleId();

        // 5. 获取客户端类型
        String clientType = request != null ? request.getHeader(RequestConstant.CLIENT_TYPE) : null;
        if (StringUtils.isBlank(clientType)) {
            clientType = ClientTypeEnum.app.getValue(); // 默认使用app
        }

        // 6. 生成token并缓存

        String token = generateToken(kwsUser.getId(), account, clientType, systemType);
        log.info("生成token成功，用户ID: {}, token: {}", kwsUser.getId(), token);
        // 7. 缓存用户登录信息
        saveUserToCache(kwsUser, systemType, clientType, roleId);

        // 8. 缓存企业信息
        KwsEnterprise kwsEnterprise = null;
        if (kwsUser.getEntId() != null) {
            kwsEnterprise = saveEntToCache(kwsUser.getEntId());
        }

        // 9. 缓存菜单权限
        List<KwsMenuResVo> kwsMenuResVos = saveMenusToCache(kwsUser.getId(), systemType, roleId);

        // 10. 组装返回结果
        LoginResVo result = LoginResVo.builder()
                .userId(kwsUser.getId())
                .name(kwsUser.getName())
                .account(kwsUser.getAccount())
                .phone(kwsUser.getPhone())
                .photo(kwsUser.getPhoto())
                .roleId(roleId)
                .roleName(roleName)
                .token(token)
                .entId(kwsUser.getEntId())
                .enterpriseName(Optional.ofNullable(kwsEnterprise).map(KwsEnterprise::getFirmName).orElse(""))
                .menuList(kwsMenuResVos)
                .systemType(kwsUser.getSystemType())
                .build();

        // 11. 记录登录日志（首次登录）
        if (request != null) {
            saveLoginLogs(kwsUser.getId(), request, 1);
        }

        log.info("登录成功，用户ID: {}", kwsUser.getId());
        return result;
    }

    /**
     * 切换账号（叉车APP）
     *
     * @param account    账号
     * @param password   密码
     * @param systemType 系统类型
     * @param request    HTTP请求（可选，用于记录登录日志）
     * @return SwitchAccountResVo
     */
    public SwitchAccountResVo switchAccount(String account, String password, Integer systemType, HttpServletRequest request) {
        log.info("切换账号，账号: {}, 系统类型: {}", account, systemType);

        // 1. 查询用户信息
        KwsUser kwsUser = getKwsUser(account, systemType);

        // 3. 校验密码
        password = PasswordUtils.md5(password);
        checkPassword(account, password, kwsUser.getPassword(), kwsUser.getSalt());

        // 4. 查询用户角色
        List<RoleInfoDto> roleInfoList = kwsUserRoleDao.queryRoleList(kwsUser.getId());
        if (CollUtil.isEmpty(roleInfoList)) {
            throw new SystemException(HttpStatus.CODE_60603, "该用户没有分配角色");
        }
        List<String> roleNames = Arrays.asList("铲车司机", "门卫");
        roleInfoList = roleInfoList.stream().filter(x -> roleNames.contains(x.getRoleName()))
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(roleInfoList)) {
            throw new SystemException(HttpStatus.CODE_60603, "你没有登录该系统权限");
        }

        String roleName = roleInfoList.stream()
                .map(RoleInfoDto::getRoleName)
                .collect(Collectors.joining(","));
        Long roleId = roleInfoList.get(0).getRoleId();


        // 5. 获取客户端类型
        String clientType = request != null ? request.getHeader(RequestConstant.CLIENT_TYPE) : null;
        if (StringUtils.isBlank(clientType)) {
            // 默认使用app
            clientType = ClientTypeEnum.app.getValue();
        }

        // 6. 生成token并缓存
        String token = generateToken(kwsUser.getId(), account, clientType, systemType);
        log.info("生成token成功，用户ID: {}, token: {}", kwsUser.getId(), token);

        // 7. 缓存用户登录信息
        saveUserToCache(kwsUser, systemType, clientType, roleId);

        // 8. 缓存企业信息
        KwsEnterprise kwsEnterprise = null;
        if (kwsUser.getEntId() != null) {
            kwsEnterprise = saveEntToCache(kwsUser.getEntId());
        }

        // 9. 缓存菜单权限
        List<KwsMenuResVo> kwsMenuResVos = saveMenusToCache(kwsUser.getId(), systemType, roleId);

        // 10. 组装返回结果
        SwitchAccountResVo result = SwitchAccountResVo.builder()
                .userId(kwsUser.getId())
                .name(kwsUser.getName())
                .account(kwsUser.getAccount())
                .phone(kwsUser.getPhone())
                .photo(kwsUser.getPhoto())
                .roleId(roleId)
                .roleName(roleName)
                .token(token)
                .entId(kwsUser.getEntId())
                .enterpriseName(Optional.ofNullable(kwsEnterprise).map(KwsEnterprise::getFirmName).orElse(""))
                .menuList(kwsMenuResVos)
                .systemType(kwsUser.getSystemType())
                .build();

        // 11. 记录切换账号登录日志
        if (request != null) {
            saveLoginLogs(kwsUser.getId(), request, 2);
        }

        log.info("切换账号成功，用户ID: {}", kwsUser.getId());
        return result;
    }

    @NotNull
    private KwsUser getKwsUser(String account, Integer systemType) {
        KwsUser kwsUser = getUserByAccount(account, systemType);
        if (Objects.isNull(kwsUser)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, "账号不存在");
        }

        // 2. 检查用户状态
        if (kwsUser.getStatus() != null && kwsUser.getStatus() == Global.YES) {
            throw new SystemException(HttpStatus.CODE_10301, "账号已被锁定");
        }
        return kwsUser;
    }

    /**
     * 退出登录（叉车APP）
     *
     * @param userId 用户ID
     */
    public void logout(Long userId) {
        log.info("退出登录，用户ID: {}", userId);

        // 1. 校验用户是否存在
        KwsUser kwsUser = kwsUserRepository.getById(userId);
        if (Objects.isNull(kwsUser)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, "用户不存在");
        }

        // 2. 清除所有客户端类型的 Token
        for (ClientTypeEnum value : ClientTypeEnum.values()) {
            String fullUserTokenKey = Global.getFullUserTokenKey(value.getValue(), userId);
            RedissonUtils.delete(fullUserTokenKey);
        }

        // 3. 清除用户登录信息
        for (SystemTypeEnum systemTypeEnum : SystemTypeEnum.values()) {
            String fullUserLoginKey = Global.getFullUserLoginKey(systemTypeEnum.getCode(), userId);
            RedissonUtils.remove(fullUserLoginKey);
        }

        //4.清除企业缓存
        String key = Global.getFullUserEntKey(kwsUser.getEntId());
        RedissonUtils.remove(key);
        //5.清除菜单缓存
        String menuKey = Global.REDIS_SYS_MENU_PREFIX + userId;
        RedissonUtils.remove(menuKey);

        log.info("退出登录成功，用户ID: {}", userId);
    }

    /**
     * 生成token并缓存
     *
     * @param userId     用户ID
     * @param account    账号
     * @param clientType 客户端类型
     * @param systemType 系统类型
     */
    private String generateToken(Long userId, String account, String clientType, Integer systemType) {
        Map<String, Object> info = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        info.put("userId", userId);
        info.put("account", account);
        info.put("clientType", clientType);
        info.put("systemType", systemType);
        String key = Global.getFullUserTokenKey(clientType, userId);
        String token = EncryUtil.encryV1(Global.PRI_KEY, JSON.toJSONString(info));
        int expireTime = ClientTypeEnum.expireTime(clientType);
        RedissonUtils.putString(key, token, expireTime);
        return token;
    }

    /**
     * 缓存用户登录信息
     *
     * @param kwsUser    用户信息
     * @param systemType 系统类型
     * @param clientType 客户端类型
     * @param roleId     角色ID
     */
    private void saveUserToCache(KwsUser kwsUser, Integer systemType, String clientType, Long roleId) {
        try {
            LoginUserInfo loginUserInfo = new LoginUserInfo();
            loginUserInfo.setId(kwsUser.getId());
            loginUserInfo.setSystemType(systemType);
            loginUserInfo.setClientType(clientType);
            loginUserInfo.setAccount(kwsUser.getAccount());
            loginUserInfo.setUserName(kwsUser.getName());
            loginUserInfo.setPhone(kwsUser.getPhone());
            loginUserInfo.setStatus(kwsUser.getStatus());
            loginUserInfo.setIsMain(kwsUser.getIsMain() != null ? kwsUser.getIsMain() : Global.NO);
            loginUserInfo.setEntId(kwsUser.getEntId());
            loginUserInfo.setUseRoleId(roleId);
            loginUserInfo.setUseEntId(kwsUser.getEntId());

            // 查询企业信息
            if (kwsUser.getEntId() != null) {
                EntCacheResDto enterprise = remoteSystemService.queryEntDetails(kwsUser.getEntId());
                if (enterprise != null) {
                    loginUserInfo.setEntName(enterprise.getFirmName());
                }
            }

            // 查询数据权限（暂时不实现，需要时可以通过RemoteUserService调用）
            // 如果需要数据权限，可以通过Dubbo调用RemoteUserService.queryAuthUserList

            String key = Global.getFullUserLoginKey(systemType, kwsUser.getId());
            RedissonUtils.putString(key, JSON.toJSONString(loginUserInfo), Global.APP_TOKEN_EXPIRE);
        } catch (Exception e) {
            log.error("缓存用户登录信息失败，用户ID: {}", kwsUser.getId(), e);
        }
    }

    /**
     * 缓存企业信息
     *
     * @param entId 企业ID
     */
    private KwsEnterprise saveEntToCache(Long entId) {
        try {
            //企业信息
            KwsEnterprise enterprise = kwsEnterpriseDao.selectByKey(entId);
            if (enterprise != null) {
                String key = Global.getFullUserEntKey(entId);
                RedissonUtils.putString(key, JSON.toJSONString(enterprise), Global.APP_TOKEN_EXPIRE);
            }
            return enterprise;
        } catch (Exception e) {
            log.error("缓存企业信息失败，企业ID: {}", entId, e);
        }
        return null;
    }

    /**
     * 缓存菜单权限
     *
     * @param userId     用户ID
     * @param systemType 系统类型
     * @param roleId     角色ID
     */
    private List<KwsMenuResVo> saveMenusToCache(Long userId, Integer systemType, Long roleId) {
        if (Objects.isNull(roleId)) {
            return List.of();
        }
        try {
            // 使用本地服务查询菜单
            com.sckw.system.model.pojo.FindMenuTreePojo findMenuTreePojo = new com.sckw.system.model.pojo.FindMenuTreePojo();
            findMenuTreePojo.setRoleIds(Collections.singletonList(roleId));

            List<KwsMenuResVo> kwsMenuResVos = kwsMenuService.findList(findMenuTreePojo);
            if (CollectionUtils.isEmpty(kwsMenuResVos)) {
                RedissonUtils.delete(Global.REDIS_SYS_MENU_PREFIX + systemType + Global.COLON + userId);
                log.warn("未查询到角色{}的菜单权限", roleId);
                return List.of();
            }

            List<String> menus = new ArrayList<>();
            for (KwsMenuResVo menuResVo : kwsMenuResVos) {
                String links = menuResVo.getLinks();
                if (StringUtils.isNotBlank(links)) {
                    menus.addAll(Arrays.asList(links.split(",")));
                }
            }
            RedissonUtils.putSet(Global.REDIS_SYS_MENU_PREFIX + userId, menus);
            return kwsMenuResVos;
        } catch (Exception e) {
            log.error("缓存菜单权限失败，用户ID: {}, 角色ID: {}", userId, roleId, e);
        }
        return List.of();
    }

    /**
     * 保存登录日志
     *
     * @param userId    用户ID
     * @param request   HTTP请求
     * @param loginType 登录类型: 1-首次登录, 2-切换账号登录
     */
    public void saveLoginLogs(Long userId, HttpServletRequest request, Integer loginType) {
        try {
            // 获取登录IP
            String loginIp = RequestUtil.getClientIp(request);

            // 获取设备信息
            String userAgentStr = request.getHeader("User-Agent");
            String deviceInfo = "";
            if (userAgentStr != null && !userAgentStr.isEmpty()) {
                try {
                    UserAgent userAgent = UserAgentUtil.parse(userAgentStr);
                    String browser = userAgent.getBrowser().getName();
                    String browserVersion = userAgent.getVersion();
                    String os = userAgent.getOs().getName();
                    String device = userAgent.getPlatform().getName();
                    deviceInfo = String.format("%s %s / %s / %s", browser, browserVersion, os, device);
                } catch (Exception e) {
                    deviceInfo = userAgentStr.length() > 100 ? userAgentStr.substring(0, 100) : userAgentStr;
                }
            }

            LoginLogs loginLogs = new LoginLogs();
            loginLogs.setId(new IdWorker(1).nextId());
            loginLogs.setUserId(userId);
            loginLogs.setLoginIp(loginIp != null ? loginIp : "");
            loginLogs.setDeviceInfo(deviceInfo);
            loginLogs.setLoginType(loginType);
            loginLogs.setLoginTime(new Date());
            loginLogsService.save(loginLogs);
        } catch (Exception e) {
            // 记录日志失败不影响主流程
            log.error("保存登录日志失败，用户ID: {}", userId, e);
        }
    }
}
