mitao
2024-04-09 ec76c5defdd8018ce4efcc8795508498a84de4b7
平台历史数据 导入导出接口
21个文件已修改
1个文件已删除
2个文件已添加
3134 ■■■■■ 已修改文件
ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/api/CurrentQuarterController.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/HistoryDataController.java 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TbFieldController.java 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/lisenter/DeptImportListener.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/annotation/HistoryGroup.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java 276 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/enums/UserTypeEnum.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/validate/HistoryGroup.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/TbBasicData.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/TbQuestion.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/TbScore.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/handler/SelectedSheetWriteHandler.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/listener/BasicDataListener.java 178 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/listener/HistoryDataListener.java 343 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/query/CurrentFieldsQuery.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/query/QuestionQuery.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/query/ScoreCalculateQuery.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/TbBasicDataService.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/TbFieldService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbBasicDataServiceImpl.java 761 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbFieldServiceImpl.java 229 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbQuestionServiceImpl.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml 852 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/api/CurrentQuarterController.java
@@ -6,6 +6,7 @@
import com.ruoyi.system.dto.BasicDataDTO;
import com.ruoyi.system.query.ScoreQuery;
import com.ruoyi.system.service.TbBasicDataService;
import com.ruoyi.system.service.TbFieldService;
import com.ruoyi.system.vo.BasicDataReportingVO;
import com.ruoyi.system.vo.ScoreVO;
import io.swagger.annotations.Api;
@@ -13,7 +14,12 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
@@ -28,6 +34,7 @@
public class CurrentQuarterController {
    private final TbBasicDataService tbBasicDataService;
    private final TbFieldService tbFieldService;
    /**
     * 获取基础数据填报相关信息
@@ -50,6 +57,7 @@
    /**
     * 保存当前季度数据
     *
     * @param dto 当前季度基础数据数据传输对象
     * @return R<Void>
     */
@@ -67,6 +75,7 @@
        }
        return R.ok();
    }
    /**
     * 导入模板下载
     */
@@ -74,15 +83,16 @@
    @ApiOperation("模板下载")
    public void downloadImportTemplate() {
        try {
            tbBasicDataService.downloadImportTemplate();
            tbFieldService.downloadImportTemplate();
        } catch (Exception e) {
            log.error("模板下载异常",e);
            log.error("模板下载异常", e);
            throw new ServiceException("模板下载失败,请联系管理员!");
        }
    }
    /**
     * 基础数据导入
     *
     * @param file file
     * @return R<Void>
     */
@@ -95,7 +105,7 @@
            if (e instanceof ServiceException) {
                return R.fail(e.getMessage());
            }
            log.error("基础数据导入异常",e);
            log.error("基础数据导入异常", e);
            return R.fail("基础数据导入失败,请联系管理员!");
        }
        return R.ok();
@@ -103,6 +113,7 @@
    /**
     * 得分计算分页查询
     *
     * @param query 得分计算条件查询对象
     * @return R<PageDTO < ScoreVO>>
     */
@@ -115,7 +126,7 @@
            if (e instanceof ServiceException) {
                return R.fail(e.getMessage());
            }
            log.error("查询得分计算异常",e);
            log.error("查询得分计算异常", e);
            return R.fail();
        }
    }
ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -1,6 +1,5 @@
package com.ruoyi.web.controller.system;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
@@ -10,33 +9,34 @@
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.domain.TbDept;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.TbDeptService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
 * 登录验证
 *
 *
 * @author ruoyi
 */
@Api(tags = "登录")
@RestController
public class SysLoginController
{
public class SysLoginController {
    @Autowired
    private SysLoginService loginService;
@@ -53,31 +53,32 @@
    private ISysRoleService roleService;
    @Autowired
    private TbDeptService tbDeptService;
    /**
     * 账号密码登录
     *
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @ApiOperation(value = "账号密码登录",notes = "账号密码登录")
        @PostMapping("/login")
    public AjaxResult login(@RequestBody LoginBody loginBody)
    {
//    @ApiOperation(value = "账号密码登录", notes = "账号密码登录")
    @PostMapping("/login")
    public AjaxResult login(@RequestBody LoginBody loginBody) {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        LoginUser loginUser = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
        LoginUser loginUser = loginService.login(loginBody.getUsername(), loginBody.getPassword(),
                loginBody.getCode(),
                loginBody.getUuid());
        ajax.put(Constants.TOKEN, tokenService.createToken(loginUser));
        List<SysRole> roles = loginUser.getUser().getRoles();
        if(CollectionUtils.isEmpty(roles)){
        if (CollectionUtils.isEmpty(roles)) {
            return AjaxResult.error("请关联角色!");
        }
        List<SysMenu> menus = roleService.roleInfoFromUserId(loginUser.getUserId());
        ajax.put("menus",menus);
        ajax.put("roleName",roles.get(0).getRoleName());
        ajax.put("userInfo",loginUser);
        ajax.put("menus", menus);
        ajax.put("roleName", roles.get(0).getRoleName());
        ajax.put("userInfo", loginUser);
        return ajax;
    }
@@ -87,53 +88,38 @@
     * @param loginBody 登录信息
     * @return 结果
     */
    @ApiOperation(value = "短信登录",notes = "短信登录")
//    @ApiOperation(value = "短信登录", notes = "短信登录")
    @PostMapping("/loginCode")
    public AjaxResult loginCode(@RequestBody LoginBody loginBody)
    {
    public AjaxResult loginCode(@RequestBody LoginBody loginBody) {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        LoginUser loginUser = loginService.loginCode(loginBody.getUsername(), loginBody.getCode());
        ajax.put(Constants.TOKEN, tokenService.createToken(loginUser));
        List<SysRole> roles = loginUser.getUser().getRoles();
        if(CollectionUtils.isEmpty(roles)){
        if (CollectionUtils.isEmpty(roles)) {
            return AjaxResult.error("请关联角色!");
        }
        List<SysMenu> menus = roleService.roleInfoFromUserId(loginUser.getUserId());
        ajax.put("menus",menus);
        ajax.put("roleName",roles.get(0).getRoleName());
        ajax.put("userInfo",loginUser);
        ajax.put("menus", menus);
        ajax.put("roleName", roles.get(0).getRoleName());
        ajax.put("userInfo", loginUser);
        return ajax;
    }
    @ApiOperation(value = "初始化账号",notes = "初始化账号")
    @PostMapping("/genAccount")
    public AjaxResult genAccount(String account,String password)
    {
        AjaxResult ajax = AjaxResult.success();
        TbDept dept = tbDeptService.getOne(Wrappers.<TbDept>lambdaQuery().eq(TbDept::getAccount, account));
        if (StringUtils.isNotNull(dept)) {
            String pwd = SecurityUtils.encryptPassword(password);
            dept.setPassword(pwd);
            ajax.put("password",pwd );
            tbDeptService.updateById(dept);
        }
        return ajax;
    }
    /**
     * 账号密码登录
     *
     * @param loginBody 部门管理后台登录
     * @return 结果
     */
    @ApiOperation(value = "部门管理后台登录",notes = "部门管理后台登录")
    @ApiOperation(value = "部门管理后台登录", notes = "部门管理后台登录")
    @PostMapping("/loginPwd")
    public AjaxResult loginPwd(@RequestBody LoginBody loginBody)
    {
    public AjaxResult loginPwd(@RequestBody LoginBody loginBody) {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        LoginUser loginUser = loginService.loginPwd(loginBody.getUsername(), loginBody.getPassword(),loginBody.getCode(),loginBody.getUuid());
        LoginUser loginUser = loginService.loginPwd(loginBody.getUsername(),
                loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid());
        ajax.put(Constants.TOKEN, tokenService.createToken(loginUser));
        //List<SysRole> roles = loginUser.getUser().getRoles();
        //if(CollectionUtils.isEmpty(roles)){
@@ -143,31 +129,30 @@
        //ajax.put("menus",menus);
        //ajax.put("roleName",roles.get(0).getRoleName());
        ajax.put("userInfo",loginUser);
        ajax.put("userInfo", loginUser);
        return ajax;
    }
    /**
     * 获取验证码
     *
     * @param phone 手机号
     * @return 结果
     */
    @ApiOperation(value = "获取验证码",notes = "获取验证码")
//    @ApiOperation(value = "获取验证码",notes = "获取验证码")
    @GetMapping("/getCode")
    public AjaxResult getCode(@RequestParam String phone)
    {
        redisCache.setCacheObject(phone,"123456",5, TimeUnit.MINUTES);
    public AjaxResult getCode(@RequestParam String phone) {
        redisCache.setCacheObject(phone, "123456", 5, TimeUnit.MINUTES);
        return AjaxResult.success();
    }
    /**
     * 获取用户信息
     *
     *
     * @return 用户信息
     */
    @GetMapping("getInfo")
    public AjaxResult getInfo()
    {
    public AjaxResult getInfo() {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
@@ -182,12 +167,11 @@
    /**
     * 获取路由信息
     *
     *
     * @return 路由信息
     */
    @GetMapping("getRouters")
    public AjaxResult getRouters()
    {
    public AjaxResult getRouters() {
        Long userId = SecurityUtils.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return AjaxResult.success(menuService.buildMenus(menus));
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/HistoryDataController.java
@@ -1,29 +1,45 @@
package com.ruoyi.web.controller.api;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.HistoryGroup;
import com.ruoyi.common.basic.PageDTO;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.enums.ReportingStatusEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.validate.HistoryGroup;
import com.ruoyi.system.domain.TbBasicData;
import com.ruoyi.system.query.CurrentFieldsQuery;
import com.ruoyi.system.query.HistoryDataQuery;
import com.ruoyi.system.query.QuestionQuery;
import com.ruoyi.system.query.ScoreCalculateDetailQuery;
import com.ruoyi.system.query.ScoreCalculateQuery;
import com.ruoyi.system.service.TbBasicDataService;
import com.ruoyi.system.service.TbQuestionService;
import com.ruoyi.system.service.TbScoreService;
import com.ruoyi.system.vo.*;
import com.ruoyi.system.vo.BasicDataVO;
import com.ruoyi.system.vo.CurrentFieldsAllVO;
import com.ruoyi.system.vo.CurrentFieldsDetailVO;
import com.ruoyi.system.vo.CurrentFieldsVO;
import com.ruoyi.system.vo.QuestionVO;
import com.ruoyi.system.vo.ScoreCalculateDetailVO;
import com.ruoyi.system.vo.ScoreCalculateVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.Objects;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
 * @author mitao
@@ -35,8 +51,10 @@
@RequiredArgsConstructor
@Api(tags = "历史数据相关接口")
public class HistoryDataController {
    private final TbBasicDataService tbBasicDataService;
    private final TbScoreService tbScoreService;
    private final TbQuestionService tbQuestionService;
    /**
     * 历史数据分页查询
@@ -50,12 +68,14 @@
        Date startTime = dto.getStartTime();
        Date endTime = dto.getEndTime();
        boolean flag = Objects.nonNull(startTime) && Objects.nonNull(endTime);
        Page<TbBasicData> page = tbBasicDataService.lambdaQuery()
                .eq(TbBasicData::getStatus, ReportingStatusEnum.FILLED)
                .between(flag, TbBasicData::getCreateTime, startTime, endTime)
                .groupBy(TbBasicData::getQuarter)
                .orderByDesc(TbBasicData::getCreateTime)
                .page(new Page<>(dto.getPageNum(), dto.getPageSize()));
        Page<TbBasicData> page =
                tbBasicDataService
                        .lambdaQuery()
                        .eq(TbBasicData::getStatus, ReportingStatusEnum.FILLED)
                        .between(flag, TbBasicData::getCreateTime, startTime, endTime)
                        .groupBy(TbBasicData::getQuarter)
                        .orderByDesc(TbBasicData::getCreateTime)
                        .page(new Page<>(dto.getPageNum(), dto.getPageSize()));
        return R.ok(PageDTO.of(page, BasicDataVO.class));
    }
@@ -66,7 +86,8 @@
     */
    @ApiOperation(value = "字段统计", notes = "字段统计")
    @PostMapping("/fields-statics")
    public R<PageDTO<CurrentFieldsVO>> historyFieldsStatics(@Validated({HistoryGroup.class}) @RequestBody CurrentFieldsQuery dto) {
    public R<PageDTO<CurrentFieldsVO>> historyFieldsStatics(
            @Validated({HistoryGroup.class}) @RequestBody CurrentFieldsQuery dto) {
        try {
            return tbBasicDataService.historyFieldsStatics(dto);
        } catch (Exception e) {
@@ -83,7 +104,13 @@
     */
    @GetMapping("/fields-details")
    @ApiOperation(value = "查看详情", notes = "字段统计")
    @ApiImplicitParam(name = "id", value = "基础数据id", required = true, dataType = "int", paramType = "query", dataTypeClass = Long.class)
    @ApiImplicitParam(
            name = "id",
            value = "基础数据id",
            required = true,
            dataType = "int",
            paramType = "query",
            dataTypeClass = Long.class)
    public R<CurrentFieldsDetailVO> fieldsDetails(@RequestParam("id") Long id) {
        try {
            return tbBasicDataService.fieldsDetails(id);
@@ -103,7 +130,13 @@
     */
    @GetMapping("/fields-statics-all")
    @ApiOperation(value = "查看全部", notes = "字段统计")
    @ApiImplicitParam(name = "quarter", value = "季度", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
    @ApiImplicitParam(
            name = "quarter",
            value = "季度",
            required = true,
            dataType = "string",
            paramType = "query",
            dataTypeClass = String.class)
    public R<CurrentFieldsAllVO> fieldsStaticsAll(@RequestParam("quarter") String quarter) {
        try {
            return R.ok(tbBasicDataService.fieldsStaticsAll(quarter));
@@ -124,7 +157,8 @@
     */
    @PostMapping("/score-calculate")
    @ApiOperation("得分计算")
    public R<PageDTO<ScoreCalculateVO>> scoreCalculate(@Validated({HistoryGroup.class}) @RequestBody ScoreCalculateQuery query) {
    public R<PageDTO<ScoreCalculateVO>> scoreCalculate(
            @Validated({HistoryGroup.class}) @RequestBody ScoreCalculateQuery query) {
        return R.ok(tbBasicDataService.scoreCalculatePage(query));
    }
@@ -136,7 +170,52 @@
     */
    @PostMapping("/score-calculate-detail")
    @ApiOperation("得分计算-查看详情")
    public R<ScoreCalculateDetailVO> scoreCalculateDetail(@Validated @RequestBody ScoreCalculateDetailQuery query) {
    public R<ScoreCalculateDetailVO> scoreCalculateDetail(
            @Validated @RequestBody ScoreCalculateDetailQuery query) {
        return R.ok(tbScoreService.scoreCalculateDetail(query));
    }
    /**
     * 分页查询问题
     *
     * @param dto 发现问题分页数据传输对象
     * @return R<PageDTO < QuestionVO>>
     */
    @PostMapping("/page-question")
    @ApiOperation(value = "问题查看-分页查询问题", notes = "问题查看")
    public R<PageDTO<QuestionVO>> pageQuestion(
            @Validated({HistoryGroup.class}) @RequestBody QuestionQuery dto) {
        return R.ok(tbQuestionService.pageQuestion(dto));
    }
    @PostMapping("/import")
    @ApiOperation("导入历史数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "文件", required = true, dataType = "file", paramType = "form"),
            @ApiImplicitParam(name = "quarter", value = "季度 e.g. 2024年一季度", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
    })
    public R<Void> importData(@RequestPart("file") MultipartFile file,
            @RequestParam("quarter") String quarter) {
        try {
            tbBasicDataService.importData(file, quarter);
        } catch (Exception e) {
            if (e instanceof ServiceException) {
                return R.fail(e.getMessage());
            }
            log.error("导入历史数据异常", e);
            return R.fail();
        }
        return R.ok();
    }
    @PostMapping("/export")
    @ApiOperation("导出")
    @ApiImplicitParam(name = "quarterList", value = "quarterList", allowMultiple = true, dataTypeClass = List.class, paramType = "query")
    public void exportData(@RequestParam("quarterList") List<String> quarterList) {
        try {
            tbBasicDataService.exportData(quarterList);
        } catch (Exception e) {
            log.error("导出历史数据异常", e);
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TbFieldController.java
@@ -16,12 +16,17 @@
import com.ruoyi.system.vo.FieldVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
 * <p>
@@ -39,15 +44,16 @@
public class TbFieldController {
    private final TbFieldService tbFieldService;
    private final TbFieldCategoryService  tbFieldCategoryService;
    private final TbFieldCategoryService tbFieldCategoryService;
    /**
     * 获取分类列表
     *
     * @param id 分类id
     * @return 分类列表
     */
    @GetMapping("/categories")
    @ApiOperation(value = "获取分类列表",notes = "一级分类id传0,二级分类传一级分类id,三级分类同理")
    @ApiOperation(value = "获取分类列表", notes = "一级分类id传0,二级分类传一级分类id,三级分类同理")
    public R<List<FieldCategoryVO>> queryFieldCategories(@RequestParam Long id) {
        try {
            return R.ok(tbFieldCategoryService.queryFieldCategories(id));
@@ -62,12 +68,13 @@
    /**
     * 添加字段
     *
     * @param dto 字段数据传输对象
     * @return 响应状态
     */
    @PostMapping("/add")
    @ApiOperation("添加字段")
    public R<Void> add(@RequestBody @Validated FieldDTO dto){
    public R<Void> add(@RequestBody @Validated FieldDTO dto) {
        try {
            tbFieldService.add(dto);
        } catch (Exception e) {
@@ -93,8 +100,10 @@
            return R.fail();
        }
    }
    /**
     * 隐藏显示操作
     *
     * @param dto 显示隐藏操作数据传输对象
     * @return R
     */
@@ -115,12 +124,13 @@
    /**
     * 编辑字段
     *
     * @param dto 字段数据传输对象
     * @return 响应状态
     */
    @PostMapping("/edit")
    @ApiOperation("编辑字段")
    public R<Void> add(@RequestBody @Validated FieldUpdateDTO dto){
    public R<Void> add(@RequestBody @Validated FieldUpdateDTO dto) {
        try {
            tbFieldService.update(dto);
        } catch (Exception e) {
@@ -135,6 +145,7 @@
    /**
     * 分页条件查询
     *
     * @param query 部门条件查询对象
     * @return PageVO<FieldCategoryDetailVO>
     */
@@ -154,12 +165,13 @@
    /**
     * 获取详情
     *
     * @param id id
     * @return FieldVO
     */
    @GetMapping("/get-details")
    @ApiOperation("获取详情")
    public R<FieldVO> getDetails(@RequestParam Long id){
    public R<FieldVO> getDetails(@RequestParam Long id) {
        try {
            TbField field = tbFieldService.getById(id);
            return R.ok(BeanUtils.copyBean(field, FieldVO.class));
@@ -174,12 +186,13 @@
    /**
     * 删除
     *
     * @param id id
     * @return 响应状态
     */
    @DeleteMapping("/delete")
    @ApiOperation("删除")
    public R<Void> delete(@RequestParam Long id){
    public R<Void> delete(@RequestParam Long id) {
        try {
            tbFieldService.removeById(id);
        } catch (Exception e) {
@@ -191,5 +204,19 @@
        }
        return R.ok();
    }
    /**
     * 模板下载
     */
    @GetMapping("/download")
    @ApiOperation("模板下载")
    public void downloadImportTemplate() {
        try {
            tbFieldService.downloadImportTemplate();
        } catch (Exception e) {
            log.error("模板下载异常", e);
            throw new ServiceException("模板下载失败,请联系管理员!");
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/lisenter/DeptImportListener.java
@@ -13,9 +13,8 @@
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.web.controller.excel.DeptExcel;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
/**
 * @author mitao
@@ -23,6 +22,7 @@
 */
@Slf4j
public class DeptImportListener implements ReadListener<DeptExcel> {
    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
@@ -46,22 +46,35 @@
    public void invoke(DeptExcel data, AnalysisContext context) {
        log.info("解析到一条数据:{}", JSON.toJSONString(data));
        if (StringUtils.isEmpty(data.getAreaName()) || StringUtils.isEmpty(data.getAreaCode()) ||
                StringUtils.isEmpty(data.getAreaLevel()) || StringUtils.isNull(data.getCountyFlag()) ||
                StringUtils.isEmpty(data.getPersonInCharge()) || StringUtils.isEmpty(data.getUserName()) ||
                StringUtils.isEmpty(data.getPhoneNumber()) || StringUtils.isEmpty(data.getPassword())) {
            throw new ServiceException(String.format("数据校验失败,请检查第%d行内容填写是否完整", cachedDataList.size()+1));
                StringUtils.isEmpty(data.getAreaLevel()) || StringUtils.isNull(data.getCountyFlag())
                ||
                StringUtils.isEmpty(data.getPersonInCharge()) || StringUtils.isEmpty(
                data.getUserName()) ||
                StringUtils.isEmpty(data.getPhoneNumber()) || StringUtils.isEmpty(
                data.getPassword())) {
            throw new ServiceException(String.format("数据校验失败,请检查第%d行内容填写是否完整",
                    cachedDataList.size() + 1));
        }
        boolean flag = sysUserService.lambdaQuery().eq(SysUser::getUserType,UserTypeEnum.PLATFORM.getCode()).eq(SysUser::getUserName, data.getUserName()).oneOpt().isPresent();
        boolean flag = sysUserService.lambdaQuery()
                .eq(SysUser::getUserType, UserTypeEnum.PLATFORM.getCode())
                .eq(SysUser::getUserName, data.getUserName()).oneOpt().isPresent();
        if (flag) {
            throw new ServiceException(String.format("数据校验失败,第%d行的登录账号:%s已存在", cachedDataList.size()+1,data.getUserName()));
            throw new ServiceException(String.format("数据校验失败,第%d行的登录账号:%s已存在",
                    cachedDataList.size() + 1, data.getUserName()));
        }
        flag = cachedDataList.stream().anyMatch(item -> item.getAreaCode().equals(data.getAreaCode()));
        flag = cachedDataList.stream()
                .anyMatch(item -> item.getAreaCode().equals(data.getAreaCode()));
        if (flag) {
            throw new ServiceException(String.format("数据校验失败,第%d行区划代码%s重复", cachedDataList.size()+1,data.getAreaCode()));
            throw new ServiceException(
                    String.format("数据校验失败,第%d行区划代码%s重复", cachedDataList.size() + 1,
                            data.getAreaCode()));
        }
        flag = cachedDataList.stream().anyMatch(item -> item.getUserName().equals(data.getUserName()));
        flag = cachedDataList.stream()
                .anyMatch(item -> item.getUserName().equals(data.getUserName()));
        if (flag) {
            throw new ServiceException(String.format("数据校验失败,第%d行登录账号%s重复", cachedDataList.size()+1,data.getAreaCode()));
            throw new ServiceException(
                    String.format("数据校验失败,第%d行登录账号%s重复", cachedDataList.size() + 1,
                            data.getAreaCode()));
        }
        cachedDataList.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
@@ -78,15 +91,17 @@
        log.info("所有数据解析完成!");
        saveData();
    }
    private void saveData() {
        log.info("{}条数据,开始存储数据库!", cachedDataList.size());
        List<SysUser> sysUsers = BeanUtils.copyList(cachedDataList, SysUser.class);
        sysUsers.forEach(item->{
        sysUsers.forEach(item -> {
            item.setPassword(SecurityUtils.encryptPassword(item.getPassword()));
            item.setNickName(item.getAreaName());
            item.setUserType("2");
            item.setUserType(UserTypeEnum.DEPARTMENT);
        });
        sysUserService.remove(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserType, UserTypeEnum.DEPARTMENT.getCode()));
        sysUserService.remove(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getUserType, UserTypeEnum.DEPARTMENT.getCode()));
        sysUserService.saveBatch(sysUsers);
        log.info("{}条数据,导入成功!", cachedDataList.size());
    }
ruoyi-common/src/main/java/com/ruoyi/common/annotation/HistoryGroup.java
New file
@@ -0,0 +1,16 @@
package com.ruoyi.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * @author mitao
 * @date 2024/4/8
 */
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface HistoryGroup {
}
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
@@ -3,40 +3,45 @@
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.enums.DisabledEnum;
import com.ruoyi.common.enums.UserTypeEnum;
import com.ruoyi.common.xss.Xss;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import java.util.List;
import javax.validation.constraints.Email;
import javax.validation.constraints.Size;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.Email;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.List;
/**
 * 用户对象 sys_user
 *
 *
 * @author ruoyi
 */
@Data
@TableName("sys_user")
public class SysUser extends BaseEntity
{
public class SysUser extends BaseEntity {
    private static final long serialVersionUID = 1L;
    /** 用户ID */
    /**
     * 用户ID
     */
    //@Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号")
    @ApiModelProperty(value = "用户id")
    @TableId(value = "user_id", type = IdType.AUTO)
    @TableField("user_id")
    private Long userId;
    /** 部门ID */
    /**
     * 部门ID
     */
    //@Excel(name = "部门编号", type = Type.IMPORT)
    @ApiModelProperty(value = "部门id")
    @TableField("dept_id")
@@ -44,97 +49,130 @@
    @ApiModelProperty(value = "用户类型")
    @TableField("user_type")
    private String userType;
    private UserTypeEnum userType;
    /** 用户账号 */
    /**
     * 用户账号
     */
    //@Excel(name = "登录名称")
    @ApiModelProperty(value = "登录名称")
    @TableField("user_name")
    private String userName;
    /** 用户昵称 */
    /**
     * 用户昵称
     */
    //@Excel(name = "用户名称")
    @ApiModelProperty(value = "用户名称")
    @TableField("nick_name")
    private String nickName;
    /** 用户邮箱 */
    /**
     * 用户邮箱
     */
    //@Excel(name = "用户邮箱")
    @ApiModelProperty(value = "用户邮箱")
    @TableField("email")
    private String email;
    /** 手机号码 */
    /**
     * 手机号码
     */
    //@Excel(name = "手机号码")
    @ApiModelProperty(value = "手机号码")
    @TableField("phone_number")
    private String phoneNumber;
    /** 用户性别 */
    /**
     * 用户性别
     */
    //@Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
    @ApiModelProperty(value = "用户性别 0=男,1=女,2=未知")
    @TableField("sex")
    private String sex;
    /** 用户头像 */
    /**
     * 用户头像
     */
    @ApiModelProperty(value = "用户头像")
    @TableField("avatar")
    private String avatar;
    /** 密码 */
    /**
     * 密码
     */
    @ApiModelProperty(value = "密码")
    @TableField("password")
    private String password;
    /** 帐号状态(0正常 1停用) */
    /**
     * 帐号状态(0正常 1停用)
     */
    //@Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
    @ApiModelProperty(value = "帐号状态  0=正常,1=停用")
    @TableField("status")
    private String status;
    /** 删除标志(0代表存在 2代表删除) */
    /**
     * 删除标志(0代表存在 2代表删除)
     */
    @ApiModelProperty(value = "删除标志(0代表存在 2代表删除)")
    @TableField("del_flag")
    @TableLogic
    private String delFlag;
    /** 最后登录IP */
    /**
     * 最后登录IP
     */
    //@Excel(name = "最后登录IP", type = Type.EXPORT)
    @ApiModelProperty(value = "最后登录IP")
    @TableField("login_ip")
    private String loginIp;
    /** 最后登录时间 */
    /**
     * 最后登录时间
     */
    //@Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty(value = "最后登录时间")
    @TableField("login_date")
    private Date loginDate;
    /** 部门对象 */
    /**
     * 部门对象
     */
    //@Excels({
        //@Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
        //@Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
    //@Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
    //@Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
//    })
    @TableField(exist = false)
    @ApiModelProperty(value = "部门对象")
    private SysDept dept;
    /** 角色对象 */
    /**
     * 角色对象
     */
    @TableField(exist = false)
    @ApiModelProperty(value = "角色对象")
    private List<SysRole> roles;
    /** 角色组 */
    /**
     * 角色组
     */
    @TableField(exist = false)
    @ApiModelProperty(value = "角色组")
    private Long[] roleIds;
    /** 岗位组 */
    /**
     * 岗位组
     */
    @TableField(exist = false)
    @ApiModelProperty(value = "岗位组")
    private Long[] postIds;
    /** 角色ID */
    /**
     * 角色ID
     */
    @TableField(exist = false)
    @ApiModelProperty(value = "角色ID")
    private Long roleId;
@@ -182,236 +220,196 @@
        this.roleName = roleName;
    }
    public SysUser()
    {
    public SysUser() {
    }
    public SysUser(Long userId)
    {
    public SysUser(Long userId) {
        this.userId = userId;
    }
    public Long getUserId()
    {
        return userId;
    }
    public void setUserId(Long userId)
    {
        this.userId = userId;
    }
    public boolean isAdmin()
    {
        return isAdmin(this.userId);
    }
    public static boolean isAdmin(Long userId)
    {
    public static boolean isAdmin(Long userId) {
        return userId != null && 1L == userId;
    }
    public Long getDeptId()
    {
    public Long getUserId() {
        return userId;
    }
    public void setUserId(Long userId) {
        this.userId = userId;
    }
    public boolean isAdmin() {
        return isAdmin(this.userId);
    }
    public Long getDeptId() {
        return deptId;
    }
    public void setDeptId(Long deptId)
    {
    public void setDeptId(Long deptId) {
        this.deptId = deptId;
    }
    @Xss(message = "用户昵称不能包含脚本字符")
    @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
    public String getNickName()
    {
    public String getNickName() {
        return nickName;
    }
    public void setNickName(String nickName)
    {
    public void setNickName(String nickName) {
        this.nickName = nickName;
    }
    @Xss(message = "用户账号不能包含脚本字符")
    @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
    public String getUserName()
    {
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName)
    {
    public void setUserName(String userName) {
        this.userName = userName;
    }
    @Email(message = "邮箱格式不正确")
    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
    public String getEmail()
    {
    public String getEmail() {
        return email;
    }
    public void setEmail(String email)
    {
    public void setEmail(String email) {
        this.email = email;
    }
    @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
    public String getPhoneNumber()
    {
    public String getPhoneNumber() {
        return phoneNumber;
    }
    public void setPhoneNumber(String phoneNumber)
    {
    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }
    public String getSex()
    {
    public String getSex() {
        return sex;
    }
    public void setSex(String sex)
    {
    public void setSex(String sex) {
        this.sex = sex;
    }
    public String getAvatar()
    {
    public String getAvatar() {
        return avatar;
    }
    public void setAvatar(String avatar)
    {
    public void setAvatar(String avatar) {
        this.avatar = avatar;
    }
    public String getPassword()
    {
    public String getPassword() {
        return password;
    }
    public void setPassword(String password)
    {
    public void setPassword(String password) {
        this.password = password;
    }
    public String getStatus()
    {
    public String getStatus() {
        return status;
    }
    public void setStatus(String status)
    {
    public void setStatus(String status) {
        this.status = status;
    }
    public String getDelFlag()
    {
    public String getDelFlag() {
        return delFlag;
    }
    public void setDelFlag(String delFlag)
    {
    public void setDelFlag(String delFlag) {
        this.delFlag = delFlag;
    }
    public String getLoginIp()
    {
    public String getLoginIp() {
        return loginIp;
    }
    public void setLoginIp(String loginIp)
    {
    public void setLoginIp(String loginIp) {
        this.loginIp = loginIp;
    }
    public Date getLoginDate()
    {
    public Date getLoginDate() {
        return loginDate;
    }
    public void setLoginDate(Date loginDate)
    {
    public void setLoginDate(Date loginDate) {
        this.loginDate = loginDate;
    }
    public SysDept getDept()
    {
    public SysDept getDept() {
        return dept;
    }
    public void setDept(SysDept dept)
    {
    public void setDept(SysDept dept) {
        this.dept = dept;
    }
    public List<SysRole> getRoles()
    {
    public List<SysRole> getRoles() {
        return roles;
    }
    public void setRoles(List<SysRole> roles)
    {
    public void setRoles(List<SysRole> roles) {
        this.roles = roles;
    }
    public Long[] getRoleIds()
    {
    public Long[] getRoleIds() {
        return roleIds;
    }
    public void setRoleIds(Long[] roleIds)
    {
    public void setRoleIds(Long[] roleIds) {
        this.roleIds = roleIds;
    }
    public Long[] getPostIds()
    {
    public Long[] getPostIds() {
        return postIds;
    }
    public void setPostIds(Long[] postIds)
    {
    public void setPostIds(Long[] postIds) {
        this.postIds = postIds;
    }
    public Long getRoleId()
    {
    public Long getRoleId() {
        return roleId;
    }
    public void setRoleId(Long roleId)
    {
    public void setRoleId(Long roleId) {
        this.roleId = roleId;
    }
    @Override
    public String toString() {
        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
            .append("userId", getUserId())
            .append("deptId", getDeptId())
            .append("userName", getUserName())
            .append("nickName", getNickName())
            .append("email", getEmail())
            .append("phoneNumber", getPhoneNumber())
            .append("sex", getSex())
            .append("avatar", getAvatar())
            .append("password", getPassword())
            .append("status", getStatus())
            .append("delFlag", getDelFlag())
            .append("loginIp", getLoginIp())
            .append("loginDate", getLoginDate())
            .append("createBy", getCreateBy())
            .append("createTime", getCreateTime())
            .append("updateBy", getUpdateBy())
            .append("updateTime", getUpdateTime())
            .append("remark", getRemark())
            .append("dept", getDept())
            .toString();
        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
                .append("userId", getUserId())
                .append("deptId", getDeptId())
                .append("userName", getUserName())
                .append("nickName", getNickName())
                .append("email", getEmail())
                .append("phoneNumber", getPhoneNumber())
                .append("sex", getSex())
                .append("avatar", getAvatar())
                .append("password", getPassword())
                .append("status", getStatus())
                .append("delFlag", getDelFlag())
                .append("loginIp", getLoginIp())
                .append("loginDate", getLoginDate())
                .append("createBy", getCreateBy())
                .append("createTime", getCreateTime())
                .append("updateBy", getUpdateBy())
                .append("updateTime", getUpdateTime())
                .append("remark", getRemark())
                .append("dept", getDept())
                .toString();
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/enums/UserTypeEnum.java
@@ -1,22 +1,26 @@
package com.ruoyi.common.enums;
import lombok.Getter;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum UserTypeEnum {
    PLATFORM("1", "平台"),
    DEPARTMENT("2", "部门");
    PLATFORM("1", "平台"),
    DEPARTMENT("2", "部门");
    @EnumValue
    private final String code;
    @JsonValue
    private final String desc;
    private final String code;
    private final String desc;
    public static UserTypeEnum getEnumByCode(String code) {
        for (UserTypeEnum e : UserTypeEnum.values()) {
            if (e.code.equals(code)) {
                return e;
            }
        }
        return null;
    }
    public static UserTypeEnum getEnumByCode(String code) {
        for (UserTypeEnum e : UserTypeEnum.values()) {
            if (e.code.equals(code)) {
                return e;
            }
        }
        return null;
    }
ruoyi-common/src/main/java/com/ruoyi/common/validate/HistoryGroup.java
File was deleted
ruoyi-system/src/main/java/com/ruoyi/system/domain/TbBasicData.java
@@ -1,14 +1,18 @@
package com.ruoyi.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.enums.ReportingStatusEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * <p>
@@ -21,7 +25,7 @@
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("tb_basic_data")
@ApiModel(value="TbBasicData对象", description="基础数据表")
@ApiModel(value = "TbBasicData对象", description = "基础数据表")
public class TbBasicData implements Serializable {
    private static final long serialVersionUID = 1L;
@@ -31,7 +35,7 @@
    private Long id;
    @ApiModelProperty(value = "季度")
    @TableField("quarter")
    @TableField("`quarter`")
    private String quarter;
    @ApiModelProperty(value = "区划代码")
@@ -51,7 +55,7 @@
    private String remark;
    @ApiModelProperty(value = "填报状态(1=未填报 2=数据缺失 3=已填报)")
    @TableField("status")
    @TableField("`status`")
    private ReportingStatusEnum status;
    @ApiModelProperty(value = "删除标志(0代表存在 1代表删除)")
ruoyi-system/src/main/java/com/ruoyi/system/domain/TbQuestion.java
@@ -1,13 +1,17 @@
package com.ruoyi.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * <p>
@@ -20,7 +24,7 @@
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("tb_question")
@ApiModel(value="TbQuestion对象", description="发现问题表")
@ApiModel(value = "TbQuestion对象", description = "发现问题表")
public class TbQuestion implements Serializable {
    private static final long serialVersionUID = 1L;
@@ -38,7 +42,7 @@
    private String content;
    @ApiModelProperty(value = "季度")
    @TableField("quarter")
    @TableField("`quarter`")
    private String quarter;
    @ApiModelProperty(value = "删除标志(0代表存在 1代表删除)")
ruoyi-system/src/main/java/com/ruoyi/system/domain/TbScore.java
@@ -1,13 +1,16 @@
package com.ruoyi.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * <p>
@@ -20,7 +23,7 @@
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("tb_score")
@ApiModel(value="TbScore对象", description="得分表")
@ApiModel(value = "TbScore对象", description = "得分表")
public class TbScore implements Serializable {
    private static final long serialVersionUID = 1L;
@@ -43,7 +46,6 @@
    @ApiModelProperty(value = "删除标志(0代表存在 1代表删除)")
    @TableField("del_flag")
    @TableLogic
    private String delFlag;
    @ApiModelProperty(value = "创建者")
ruoyi-system/src/main/java/com/ruoyi/system/handler/SelectedSheetWriteHandler.java
@@ -3,6 +3,7 @@
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import java.util.Map;
import lombok.Data;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
@@ -11,28 +12,33 @@
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import java.util.Map;
@Data
public class SelectedSheetWriteHandler implements SheetWriteHandler {
    private Map<Integer, String[]> selectedMap;
    public SelectedSheetWriteHandler(Map<Integer, String[]> selectedMap) {
    private Map<Integer, String[]> selectedMap;
    private int rows;
    public SelectedSheetWriteHandler(Map<Integer, String[]> selectedMap, int rows) {
        this.selectedMap = selectedMap;
        this.rows = rows;
    }
    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder,
            WriteSheetHolder writeSheetHolder) {
        //获取sheet页
        Sheet sheet = writeSheetHolder.getSheet();
        int firstRow = writeSheetHolder.getHead().get(0).size() + 1;
        int lastRow = writeSheetHolder.getHead().get(0).size() + rows;
        ///开始设置下拉框
        DataValidationHelper helper = sheet.getDataValidationHelper();
        for (Map.Entry<Integer, String[]> entry : selectedMap.entrySet()) {
            /***起始行、终止行、起始列、终止列**/
            CellRangeAddressList addressList = new CellRangeAddressList(firstRow, firstRow, entry.getKey(), entry.getKey());
            CellRangeAddressList addressList = new CellRangeAddressList(firstRow, lastRow,
                    entry.getKey(), entry.getKey());
            /***设置下拉框数据**/
            DataValidationConstraint constraint = helper.createExplicitListConstraint(entry.getValue());
            DataValidationConstraint constraint = helper.createExplicitListConstraint(
                    entry.getValue());
            DataValidation dataValidation = helper.createValidation(constraint, addressList);
            /***处理Excel兼容性问题**/
            if (dataValidation instanceof XSSFDataValidation) {
ruoyi-system/src/main/java/com/ruoyi/system/listener/BasicDataListener.java
@@ -4,43 +4,65 @@
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.ruoyi.common.enums.*;
import com.ruoyi.common.enums.CalculateTypeEnum;
import com.ruoyi.common.enums.FieldInputTypeEnum;
import com.ruoyi.common.enums.FieldTypeEnum;
import com.ruoyi.common.enums.ReportingStatusEnum;
import com.ruoyi.common.enums.ShowStatusEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.CalculateUtil;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.service.*;
import lombok.extern.slf4j.Slf4j;
import com.ruoyi.common.utils.CollUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.domain.TbBasicData;
import com.ruoyi.system.domain.TbBasicDataConfig;
import com.ruoyi.system.domain.TbBasicDataConfigDetail;
import com.ruoyi.system.domain.TbBasicDataField;
import com.ruoyi.system.domain.TbField;
import com.ruoyi.system.domain.TbScore;
import com.ruoyi.system.service.TbBasicDataConfigDetailService;
import com.ruoyi.system.service.TbBasicDataConfigService;
import com.ruoyi.system.service.TbBasicDataFieldService;
import com.ruoyi.system.service.TbBasicDataService;
import com.ruoyi.system.service.TbFieldService;
import com.ruoyi.system.service.TbScoreService;
import java.time.LocalDate;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class BasicDataListener extends AnalysisEventListener<Map<Integer, String>> {
    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     * 每隔5条存储数据库,实际使用中可以1000条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    private List<Map<Integer, String>> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private static final int BATCH_COUNT = 1000;
    private List<Map<Integer, String>> cachedDataList = ListUtils.newArrayListWithExpectedSize(
            BATCH_COUNT);
    public TbBasicDataService tbBasicDataService;
    public List<TbField> fieldList;
    public TbFieldService tbFieldService;
    public String areaCode;
    public TbBasicDataFieldService tbBasicDataFieldService;
    public TbBasicDataConfigService tbBasicDataConfigService;
    public TbBasicDataConfigDetailService tbBasicDataConfigDetailService;
    public TbScoreService tbScoreService;
    public BasicDataListener() {
    }
    public BasicDataListener(TbBasicDataService tbBasicDataService, List<TbField> fieldList,TbFieldService tbFieldService,
                             String areaCode,TbBasicDataFieldService tbBasicDataFieldService,TbBasicDataConfigService tbBasicDataConfigService,
                             TbBasicDataConfigDetailService tbBasicDataConfigDetailService,TbScoreService tbScoreService ) {
    public BasicDataListener(TbBasicDataService tbBasicDataService,
            TbFieldService tbFieldService,
            String areaCode, TbBasicDataFieldService tbBasicDataFieldService,
            TbBasicDataConfigService tbBasicDataConfigService,
            TbBasicDataConfigDetailService tbBasicDataConfigDetailService,
            TbScoreService tbScoreService) {
        this.tbBasicDataService = tbBasicDataService;
        this.fieldList = fieldList;
        this.tbFieldService = tbFieldService;
        this.areaCode = areaCode;
        this.tbBasicDataFieldService = tbBasicDataFieldService;
@@ -80,21 +102,61 @@
        log.info("所有数据解析完成!");
    }
    private static String validateFields(Map.Entry<Integer, String> integerStringEntry,
            Map<Integer, String> dataMap, TbField field) {
        String value = dataMap.get(integerStringEntry.getKey());
        if (FieldTypeEnum.NUMBER.equals(field.getFieldType())) {
            Integer numMin = field.getNumMin();
            Integer numMax = field.getNumMax();
            if (Objects.nonNull(numMin) && Objects.nonNull(numMax)) {
                if (numMin > Integer.parseInt(value) || numMax < Integer.parseInt(value)) {
                    throw new ServiceException(
                            String.format("字段(%s)的内容不在%d~%d范围内", field.getFieldName(),
                                    numMin, numMax));
                }
            }
        }
        if (FieldInputTypeEnum.MANUAL_INPUT.equals(field.getTextInputType())
                && FieldTypeEnum.TEXT.equals(field.getFieldType())) {
            Integer textMinNum = field.getTextMinNum();
            Integer textMaxNum = field.getTextMaxNum();
            if (Objects.nonNull(textMinNum) && Objects.nonNull(textMaxNum)) {
                if (textMinNum > value.length() || textMaxNum < value.length()) {
                    throw new ServiceException(
                            String.format("字段(%s)的内容长度超出%d~%d的范围", field.getFieldName(),
                                    textMinNum, textMaxNum));
                }
            }
        }
        if (FieldTypeEnum.PERCENTAGE.equals(field.getFieldType())) {
            if (0 > Double.parseDouble(value) || 100 < Double.parseDouble(value)) {
                throw new ServiceException(
                        String.format("字段(%s)的内容不在0~100范围内", field.getFieldName()));
            }
        }
        return value;
    }
    /**
     * 加上存储数据库
     */
    private TbBasicData saveData() {
        Map<Integer, String> headMap = cachedDataList.get(cachedDataList.size()-3);
        Map<Integer, String> dataMap = cachedDataList.get(cachedDataList.size()-1);
    private TbBasicData saveData() throws Exception {
        // 查询需要填写的动态字段
        List<TbField> fieldList =
                tbFieldService.lambdaQuery().eq(TbField::getStatus, ShowStatusEnum.SHOW).list();
        Map<Integer, String> headMap = cachedDataList.get(cachedDataList.size() - 3);
        Map<Integer, String> dataMap = cachedDataList.get(cachedDataList.size() - 1);
        log.info("{}条数据,开始存储数据库!", cachedDataList.size());
        log.info("表头:{}", JSON.toJSONString(headMap));
        log.info("填写的数据:{}", JSON.toJSONString(dataMap));
        int remarkIndex = headMap.size() - 1;
        Map<Integer, String> dynamicFieldsMap = headMap.entrySet().stream()
                .filter(entry -> !(Lists.newArrayList(0, 1, 2, 3).contains(entry.getKey()) || entry.getKey() == remarkIndex))
                .filter(entry -> !(Lists.newArrayList(0, 1, 2, 3).contains(entry.getKey())
                        || entry.getKey() == remarkIndex))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        List<String> dynamicFields = new ArrayList<>(dynamicFieldsMap.values());
        List<String> collect = fieldList.stream().map(TbField::getFieldName).collect(Collectors.toList());
        List<String> collect = fieldList.stream().map(TbField::getFieldName)
                .collect(Collectors.toList());
        boolean flag = new ArrayList<>(dynamicFields).containsAll(collect);
        if (dynamicFields.size() != collect.size() || !flag) {
            throw new ServiceException("导入失败,请下载最新的导入模板");
@@ -105,14 +167,15 @@
                eq(TbBasicData::getQuarter, String.format("%s年%s", now.getYear(), dataMap.get(1)))
                .eq(TbBasicData::getDeptAreaCode, areaCode).oneOpt();
        tbBasicData = tbBasicDataOpt.orElseGet(TbBasicData::new);
        tbBasicData.setQuarter(String.format("%s年%s", now.getYear(), dataMap.get(1)));
        tbBasicData.setQuarter(DateUtils.getNowQuarter());
        tbBasicData.setTransferPaymentScale(dataMap.get(2));
        tbBasicData.setCurrentGdp(dataMap.get(3));
        tbBasicData.setDeptAreaCode(areaCode);
        tbBasicData.setRemark(dataMap.get(remarkIndex));
        tbBasicData.setStatus(ReportingStatusEnum.MISSING_DATA);
        tbBasicDataService.saveOrUpdate(tbBasicData);
        tbBasicDataFieldService.remove(Wrappers.<TbBasicDataField>lambdaQuery().eq(TbBasicDataField::getBasicDataId, tbBasicData.getId()));
        tbBasicDataFieldService.remove(Wrappers.<TbBasicDataField>lambdaQuery()
                .eq(TbBasicDataField::getBasicDataId, tbBasicData.getId()));
        List<TbBasicDataField> fields = new ArrayList<>();
        //添加固定字段 转移支付规模、当期GDP
        TbBasicDataField transferPaymentScale = new TbBasicDataField();
@@ -130,7 +193,8 @@
        fields.add(currentGdp);
        //遍历动态字段map
        for (Map.Entry<Integer, String> integerStringEntry : dynamicFieldsMap.entrySet()) {
            Optional<TbField> tbField = tbFieldService.lambdaQuery().eq(TbField::getFieldName, integerStringEntry.getValue())
            Optional<TbField> tbField = tbFieldService.lambdaQuery()
                    .eq(TbField::getFieldName, integerStringEntry.getValue())
                    .eq(TbField::getStatus, ShowStatusEnum.SHOW).oneOpt();
            if (tbField.isPresent()) {
                TbField field = tbField.get();
@@ -149,34 +213,9 @@
        log.info(String.format("%s导入基础数据成功!", dataMap.get(0)));
        return tbBasicData;
    }
    private static String validateFields(Map.Entry<Integer, String> integerStringEntry, Map<Integer, String> dataMap, TbField field) {
        String value = dataMap.get(integerStringEntry.getKey());
        if (FieldTypeEnum.NUMBER.equals(field.getFieldType())) {
            Integer numMin = field.getNumMin();
            Integer numMax = field.getNumMax();
            if (Objects.nonNull(numMin) && Objects.nonNull(numMax)) {
                if (numMin > Integer.parseInt(value) || numMax < Integer.parseInt(value)) {
                    throw new ServiceException(String.format("字段%s的内容不在%d~%d范围内", field.getFieldName(),numMin,numMax));
                }
            }
        }
        if (FieldInputTypeEnum.MANUAL_INPUT.equals(field.getTextInputType()) && FieldTypeEnum.TEXT.equals(field.getFieldType())) {
            Integer textMinNum = field.getTextMinNum();
            Integer textMaxNum = field.getTextMaxNum();
            if (Objects.nonNull(textMinNum) && Objects.nonNull(textMaxNum)) {
                if (textMinNum > value.length() || textMaxNum < value.length()) {
                    throw new ServiceException(String.format("字段%s的内容长度超出%d~%d的范围", field.getFieldName(),textMinNum,textMaxNum));
                }
            }
        }
        if (FieldTypeEnum.PERCENTAGE.equals(field.getFieldType())) {
            if (0 > Double.parseDouble(value) || 100 < Double.parseDouble(value)) {
                throw new ServiceException(String.format("字段%s的内容不在0~100范围内", field.getFieldName()));
            }
        }
        return value;
    }
    private void calculateScore(TbBasicData tbBasicData) {
        List<TbScore> scoreList = new ArrayList<>();
        //计算得分
        List<TbBasicDataConfig> list = tbBasicDataConfigService.lambdaQuery()
                .eq(TbBasicDataConfig::getStatus, ShowStatusEnum.SHOW).list();
@@ -189,33 +228,41 @@
        List<TbBasicDataConfig> textAndPercentages = list.stream()
                .filter(item -> !CalculateTypeEnum.NUMBER.equals(item.getCalculateType()))
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(numCalculates)) {
            numCalculates.forEach(item -> {
        tbScoreService.remove(
                new LambdaQueryWrapper<TbScore>().eq(TbScore::getBasicDataId, tbBasicData.getId()));
        if (CollUtils.isNotEmpty(numCalculates)) {
            for (TbBasicDataConfig item : numCalculates) {
                Map<String, Object> valueMap = new HashMap<>();
                String numberCalculateFormula = item.getNumberCalculateFormula();
                Map<String, Integer> fieldsAndValue = CalculateUtil.getFieldsAndValue(numberCalculateFormula);
                Map<String, Integer> fieldsAndValue = CalculateUtil.getFieldsAndValue(
                        numberCalculateFormula);
                for (Map.Entry<String, Integer> stringIntegerEntry : fieldsAndValue.entrySet()) {
                    Optional<TbBasicDataField> tbBasicDataField = tbBasicDataFieldService.lambdaQuery()
                            .eq(TbBasicDataField::getBasicDataId, tbBasicData.getId())
                            .eq(TbBasicDataField::getFieldId, stringIntegerEntry.getValue())
                            .oneOpt();
                    tbBasicDataField.ifPresent(basicDataField -> valueMap.put(stringIntegerEntry.getKey(), basicDataField.getFieldValue()));
                    tbBasicDataField.ifPresent(
                            basicDataField -> valueMap.put(stringIntegerEntry.getKey(),
                                    basicDataField.getFieldValue()));
                }
                double score = CalculateUtil.calculate(numberCalculateFormula, valueMap);
                TbScore tbScore = new TbScore();
                tbScore.setBasicDataId(tbBasicData.getId());
                tbScore.setScore(score);
                tbScore.setBasicDataConfigId(item.getId());
                tbScoreService.save(tbScore);
            });
                scoreList.add(tbScore);
            }
        }
        if (CollectionUtils.isNotEmpty(textAndPercentages)) {
        if (CollUtils.isNotEmpty(textAndPercentages)) {
            for (TbBasicDataConfig textAndPercentage : textAndPercentages) {
                TbScore tbScore = new TbScore();
                List<TbBasicDataConfigDetail> details = tbBasicDataConfigDetailService.lambdaQuery()
                        .eq(TbBasicDataConfigDetail::getBasicDataConfigId, textAndPercentage.getId())
                        .eq(TbBasicDataConfigDetail::getBasicDataConfigId,
                                textAndPercentage.getId())
                        .list();
                Map<String, String> scoreMap = details.stream().collect(Collectors.toMap(TbBasicDataConfigDetail::getKey, TbBasicDataConfigDetail::getValue));
                Map<String, String> scoreMap = details.stream().collect(
                        Collectors.toMap(TbBasicDataConfigDetail::getKey,
                                TbBasicDataConfigDetail::getValue));
                if (CollectionUtils.isNotEmpty(details)) {
                    Optional<TbBasicDataField> tbBasicDataFieldOptional = tbBasicDataFieldService.lambdaQuery()
                            .eq(TbBasicDataField::getBasicDataId, tbBasicData.getId())
@@ -228,25 +275,28 @@
                            tbScore.setBasicDataId(tbBasicData.getId());
                            tbScore.setScore(Double.parseDouble(score));
                            tbScore.setBasicDataConfigId(textAndPercentage.getId());
                            tbScoreService.save(tbScore);
                            scoreList.add(tbScore);
                        }
                        if (CalculateTypeEnum.PERCENTAGE.equals(textAndPercentage.getCalculateType())) {
                        if (CalculateTypeEnum.PERCENTAGE.equals(
                                textAndPercentage.getCalculateType())) {
                            for (Map.Entry<String, String> stringStringEntry : scoreMap.entrySet()) {
                                String[] split = stringStringEntry.getKey().split("-");
                                double v = Double.parseDouble(tbBasicDataField.getFieldValue());
                                double min = Double.parseDouble(split[0]);
                                double max = Double.parseDouble(split[1]);
                                if (v >= min && v <= max) {
                                    tbScore.setScore(Double.parseDouble(stringStringEntry.getValue()));
                                    tbScore.setScore(
                                            Double.parseDouble(stringStringEntry.getValue()));
                                }
                            }
                            tbScore.setBasicDataId(tbBasicData.getId());
                            tbScore.setBasicDataConfigId(textAndPercentage.getId());
                            tbScoreService.save(tbScore);
                            scoreList.add(tbScore);
                        }
                    }
                }
            }
        }
        tbScoreService.saveBatch(scoreList);
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/listener/HistoryDataListener.java
New file
@@ -0,0 +1,343 @@
package com.ruoyi.system.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.CalculateTypeEnum;
import com.ruoyi.common.enums.FieldInputTypeEnum;
import com.ruoyi.common.enums.FieldTypeEnum;
import com.ruoyi.common.enums.ReportingStatusEnum;
import com.ruoyi.common.enums.ShowStatusEnum;
import com.ruoyi.common.enums.UserTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.CalculateUtil;
import com.ruoyi.common.utils.CollUtils;
import com.ruoyi.system.domain.TbBasicData;
import com.ruoyi.system.domain.TbBasicDataConfig;
import com.ruoyi.system.domain.TbBasicDataConfigDetail;
import com.ruoyi.system.domain.TbBasicDataField;
import com.ruoyi.system.domain.TbField;
import com.ruoyi.system.domain.TbScore;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.TbBasicDataConfigDetailService;
import com.ruoyi.system.service.TbBasicDataConfigService;
import com.ruoyi.system.service.TbBasicDataFieldService;
import com.ruoyi.system.service.TbBasicDataService;
import com.ruoyi.system.service.TbFieldService;
import com.ruoyi.system.service.TbScoreService;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class HistoryDataListener extends AnalysisEventListener<Map<Integer, String>> {
    /**
     * 每隔5条存储数据库,实际使用中可以1000条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 1000;
    public TbBasicDataService tbBasicDataService;
    public TbFieldService tbFieldService;
    public TbBasicDataFieldService tbBasicDataFieldService;
    public TbBasicDataConfigService tbBasicDataConfigService;
    public TbBasicDataConfigDetailService tbBasicDataConfigDetailService;
    public TbScoreService tbScoreService;
    public ISysUserService sysUserService;
    public String quarter;
    private List<Map<Integer, String>> cachedDataList = ListUtils.newArrayListWithExpectedSize(
            BATCH_COUNT);
    public HistoryDataListener(TbBasicDataService tbBasicDataService,
            TbFieldService tbFieldService,
            TbBasicDataFieldService tbBasicDataFieldService,
            TbBasicDataConfigService tbBasicDataConfigService,
            TbBasicDataConfigDetailService tbBasicDataConfigDetailService,
            TbScoreService tbScoreService, ISysUserService sysUserService, String quarter) {
        this.tbBasicDataService = tbBasicDataService;
        this.tbFieldService = tbFieldService;
        this.tbBasicDataFieldService = tbBasicDataFieldService;
        this.tbBasicDataConfigService = tbBasicDataConfigService;
        this.tbBasicDataConfigDetailService = tbBasicDataConfigDetailService;
        this.tbScoreService = tbScoreService;
        this.sysUserService = sysUserService;
        this.quarter = quarter;
    }
    private static String validateFields(Map.Entry<Integer, String> integerStringEntry,
            Map<Integer, String> dataMap, TbField field) {
        String value = dataMap.get(integerStringEntry.getKey());
        if (FieldTypeEnum.NUMBER.equals(field.getFieldType())) {
            Integer numMin = field.getNumMin();
            Integer numMax = field.getNumMax();
            if (Objects.nonNull(numMin) && Objects.nonNull(numMax)) {
                if (numMin > Integer.parseInt(value) || numMax < Integer.parseInt(value)) {
                    throw new ServiceException(
                            String.format("字段(%s)的内容不在%d~%d范围内", field.getFieldName(),
                                    numMin, numMax));
                }
            }
        }
        if (FieldInputTypeEnum.MANUAL_INPUT.equals(field.getTextInputType())
                && FieldTypeEnum.TEXT.equals(field.getFieldType())) {
            Integer textMinNum = field.getTextMinNum();
            Integer textMaxNum = field.getTextMaxNum();
            if (Objects.nonNull(textMinNum) && Objects.nonNull(textMaxNum)) {
                if (textMinNum > value.length() || textMaxNum < value.length()) {
                    throw new ServiceException(
                            String.format("字段(%s)的内容长度超出%d~%d的范围",
                                    field.getFieldName(),
                                    textMinNum, textMaxNum));
                }
            }
        }
        if (FieldTypeEnum.PERCENTAGE.equals(field.getFieldType())) {
            if (0 > Double.parseDouble(value) || 100 < Double.parseDouble(value)) {
                throw new ServiceException(
                        String.format("字段(%s)的内容不在0~100范围内", field.getFieldName()));
            }
        }
        return value;
    }
    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        log.info("解析到一条数据:{}", JSON.toJSONString(data));
        cachedDataList.add(data);
        if (cachedDataList.size() >= BATCH_COUNT) {
            try {
                saveData();
            } catch (Exception e) {
                if (e instanceof ServiceException) {
                    throw new ServiceException(e.getMessage());
                }
                throw new RuntimeException(e);
            }
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        try {
            List<TbBasicData> tbBasicDataList = saveData();
            calculateScore(tbBasicDataList);
        } catch (Exception e) {
            if (e instanceof ServiceException) {
                throw new ServiceException(e.getMessage());
            }
            throw new RuntimeException(e);
        }
        log.info("所有数据解析完成!");
    }
    /**
     * 加上存储数据库
     */
    private List<TbBasicData> saveData() {
        List<TbBasicData> tbBasicDataList = new ArrayList<>();
        // 查询需要填写的动态字段
        List<TbField> fieldList =
                tbFieldService.lambdaQuery().eq(TbField::getStatus, ShowStatusEnum.SHOW).list();
        Map<Integer, String> headMap = getHeadMap();
        List<Map<Integer, String>> dataMapList = getMapList();
        if (headMap == null || dataMapList == null) {
            throw new ServiceException("导入失败,请下载最新的导入模板");
        }
        log.info("{}条数据,开始存储数据库!", dataMapList.size());
        log.info("表头:{}", JSON.toJSONString(headMap));
        log.info("填写的数据:{}", JSON.toJSONString(dataMapList));
        for (Map<Integer, String> dataMap : dataMapList) {
            Optional<SysUser> sysUser = sysUserService.lambdaQuery()
                    .eq(SysUser::getUserType, UserTypeEnum.DEPARTMENT)
                    .eq(SysUser::getAreaName, dataMap.get(0)).oneOpt();
            if (!sysUser.isPresent()) {
                throw new ServiceException("该地区不存在,请修改后重新导入!");
            }
            String areaCode = sysUser.get().getAreaCode();
            int remarkIndex = headMap.size() - 1;
            Map<Integer, String> dynamicFieldsMap = headMap.entrySet().stream()
                    .filter(entry -> !(Lists.newArrayList(0, 1, 2, 3).contains(entry.getKey())
                            || entry.getKey() == remarkIndex))
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            List<String> dynamicFields = new ArrayList<>(dynamicFieldsMap.values());
            List<String> collect = fieldList.stream().map(TbField::getFieldName)
                    .collect(Collectors.toList());
            boolean flag = new ArrayList<>(dynamicFields).containsAll(collect);
            if (dynamicFields.size() != collect.size() || !flag) {
                throw new ServiceException("导入失败,请下载最新的导入模板");
            }
            LocalDate now = LocalDate.now();
            TbBasicData tbBasicData;
            Optional<TbBasicData> tbBasicDataOpt = tbBasicDataService.lambdaQuery().
                    eq(TbBasicData::getQuarter, quarter)
                    .eq(TbBasicData::getDeptAreaCode, areaCode).oneOpt();
            tbBasicData = tbBasicDataOpt.orElseGet(TbBasicData::new);
            tbBasicData.setQuarter(quarter);
            tbBasicData.setTransferPaymentScale(dataMap.get(2));
            tbBasicData.setCurrentGdp(dataMap.get(3));
            tbBasicData.setDeptAreaCode(areaCode);
            tbBasicData.setRemark(dataMap.get(remarkIndex));
            tbBasicData.setStatus(ReportingStatusEnum.MISSING_DATA);
            tbBasicDataService.saveOrUpdate(tbBasicData);
            tbBasicDataFieldService.remove(Wrappers.<TbBasicDataField>lambdaQuery()
                    .eq(TbBasicDataField::getBasicDataId, tbBasicData.getId()));
            List<TbBasicDataField> fields = new ArrayList<>();
            //添加固定字段 转移支付规模、当期GDP
            TbBasicDataField transferPaymentScale = new TbBasicDataField();
            transferPaymentScale.setBasicDataId(tbBasicData.getId());
            transferPaymentScale.setFieldId(-1L);
            transferPaymentScale.setFieldName("转移支付规模");
            transferPaymentScale.setFieldValue(tbBasicData.getTransferPaymentScale());
            fields.add(transferPaymentScale);
            TbBasicDataField currentGdp = new TbBasicDataField();
            currentGdp.setBasicDataId(tbBasicData.getId());
            currentGdp.setFieldId(-2L);
            currentGdp.setFieldName("当期GDP");
            currentGdp.setFieldValue(tbBasicData.getCurrentGdp());
            fields.add(currentGdp);
            //遍历动态字段map
            for (Map.Entry<Integer, String> integerStringEntry : dynamicFieldsMap.entrySet()) {
                Optional<TbField> tbField = tbFieldService.lambdaQuery()
                        .eq(TbField::getFieldName, integerStringEntry.getValue())
                        .eq(TbField::getStatus, ShowStatusEnum.SHOW).oneOpt();
                if (tbField.isPresent()) {
                    TbField field = tbField.get();
                    String value = validateFields(integerStringEntry, dataMap, field);
                    TbBasicDataField tbBasicDataField = new TbBasicDataField();
                    tbBasicDataField.setBasicDataId(tbBasicData.getId());
                    tbBasicDataField.setFieldId(field.getId());
                    tbBasicDataField.setFieldName(field.getFieldName());
                    tbBasicDataField.setFieldValue(value);
                    fields.add(tbBasicDataField);
                }
            }
            tbBasicDataFieldService.saveBatch(fields);
            tbBasicData.setStatus(ReportingStatusEnum.FILLED);
            tbBasicDataService.updateById(tbBasicData);
            tbBasicDataList.add(tbBasicData);
        }
        log.info(String.format("%s导入基础数据成功!", JSON.toJSONString(dataMapList)));
        return tbBasicDataList;
    }
    private List<Map<Integer, String>> getMapList() {
        for (int i = 0; i < cachedDataList.size(); i++) {
            if (cachedDataList.get(i).get(0).equals("栏号")) {
                return cachedDataList.subList(i + 1, cachedDataList.size());
            }
        }
        return null;
    }
    private Map<Integer, String> getHeadMap() {
        for (int i = 0; i < cachedDataList.size(); i++) {
            if (cachedDataList.get(i).get(0).equals("栏号")) {
                return cachedDataList.get(i - 1);
            }
        }
        return null;
    }
    private void calculateScore(List<TbBasicData> tbBasicDataList) {
        for (TbBasicData tbBasicData : tbBasicDataList) {
            List<TbScore> scoreList = new ArrayList<>();
            //计算得分
            List<TbBasicDataConfig> list = tbBasicDataConfigService.lambdaQuery()
                    .eq(TbBasicDataConfig::getStatus, ShowStatusEnum.SHOW).list();
            if (CollectionUtils.isEmpty(list)) {
                throw new ServiceException("计算得分失败,平台未配置得分计算规则");
            }
            List<TbBasicDataConfig> numCalculates = list.stream()
                    .filter(item -> CalculateTypeEnum.NUMBER.equals(item.getCalculateType()))
                    .collect(Collectors.toList());
            List<TbBasicDataConfig> textAndPercentages = list.stream()
                    .filter(item -> !CalculateTypeEnum.NUMBER.equals(item.getCalculateType()))
                    .collect(Collectors.toList());
            tbScoreService.remove(
                    new LambdaQueryWrapper<TbScore>().eq(TbScore::getBasicDataId,
                            tbBasicData.getId()));
            if (CollUtils.isNotEmpty(numCalculates)) {
                for (TbBasicDataConfig item : numCalculates) {
                    Map<String, Object> valueMap = new HashMap<>();
                    String numberCalculateFormula = item.getNumberCalculateFormula();
                    Map<String, Integer> fieldsAndValue = CalculateUtil.getFieldsAndValue(
                            numberCalculateFormula);
                    for (Map.Entry<String, Integer> stringIntegerEntry : fieldsAndValue.entrySet()) {
                        Optional<TbBasicDataField> tbBasicDataField = tbBasicDataFieldService.lambdaQuery()
                                .eq(TbBasicDataField::getBasicDataId, tbBasicData.getId())
                                .eq(TbBasicDataField::getFieldId, stringIntegerEntry.getValue())
                                .oneOpt();
                        tbBasicDataField.ifPresent(
                                basicDataField -> valueMap.put(stringIntegerEntry.getKey(),
                                        basicDataField.getFieldValue()));
                    }
                    double score = CalculateUtil.calculate(numberCalculateFormula, valueMap);
                    TbScore tbScore = new TbScore();
                    tbScore.setBasicDataId(tbBasicData.getId());
                    tbScore.setScore(score);
                    tbScore.setBasicDataConfigId(item.getId());
                    scoreList.add(tbScore);
                }
            }
            if (CollUtils.isNotEmpty(textAndPercentages)) {
                for (TbBasicDataConfig textAndPercentage : textAndPercentages) {
                    TbScore tbScore = new TbScore();
                    List<TbBasicDataConfigDetail> details = tbBasicDataConfigDetailService.lambdaQuery()
                            .eq(TbBasicDataConfigDetail::getBasicDataConfigId,
                                    textAndPercentage.getId())
                            .list();
                    Map<String, String> scoreMap = details.stream().collect(
                            Collectors.toMap(TbBasicDataConfigDetail::getKey,
                                    TbBasicDataConfigDetail::getValue));
                    if (CollectionUtils.isNotEmpty(details)) {
                        Optional<TbBasicDataField> tbBasicDataFieldOptional = tbBasicDataFieldService.lambdaQuery()
                                .eq(TbBasicDataField::getBasicDataId, tbBasicData.getId())
                                .eq(TbBasicDataField::getFieldId, textAndPercentage.getFieldIdStr())
                                .oneOpt();
                        if (tbBasicDataFieldOptional.isPresent()) {
                            TbBasicDataField tbBasicDataField = tbBasicDataFieldOptional.get();
                            if (CalculateTypeEnum.TEXT.equals(
                                    textAndPercentage.getCalculateType())) {
                                String score = scoreMap.get(tbBasicDataField.getFieldValue());
                                tbScore.setBasicDataId(tbBasicData.getId());
                                tbScore.setScore(Double.parseDouble(score));
                                tbScore.setBasicDataConfigId(textAndPercentage.getId());
                                scoreList.add(tbScore);
                            }
                            if (CalculateTypeEnum.PERCENTAGE.equals(
                                    textAndPercentage.getCalculateType())) {
                                for (Map.Entry<String, String> stringStringEntry : scoreMap.entrySet()) {
                                    String[] split = stringStringEntry.getKey().split("-");
                                    double v = Double.parseDouble(tbBasicDataField.getFieldValue());
                                    double min = Double.parseDouble(split[0]);
                                    double max = Double.parseDouble(split[1]);
                                    if (v >= min && v <= max) {
                                        tbScore.setScore(
                                                Double.parseDouble(stringStringEntry.getValue()));
                                    }
                                }
                                tbScore.setBasicDataId(tbBasicData.getId());
                                tbScore.setBasicDataConfigId(textAndPercentage.getId());
                                scoreList.add(tbScore);
                            }
                        }
                    }
                }
            }
            tbScoreService.saveBatch(scoreList);
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/query/CurrentFieldsQuery.java
@@ -1,14 +1,13 @@
package com.ruoyi.system.query;
import com.ruoyi.common.annotation.HistoryGroup;
import com.ruoyi.common.core.domain.BasePage;
import com.ruoyi.common.enums.ReportingStatusEnum;
import com.ruoyi.common.validate.HistoryGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
/**
 * @author mitao
@@ -22,7 +21,9 @@
    private static final long serialVersionUID = 3808984599047049282L;
    @ApiModelProperty(value = "季度", notes = "当前季度数据不传,历史数据必传")
    @NotBlank(message = "季度不能为空", groups = {HistoryGroup.class})
    @NotBlank(
            message = "季度不能为空",
            groups = {HistoryGroup.class})
    private String quarter;
    @ApiModelProperty(value = "填报部门")
ruoyi-system/src/main/java/com/ruoyi/system/query/QuestionQuery.java
@@ -1,8 +1,10 @@
package com.ruoyi.system.query;
import com.ruoyi.common.annotation.HistoryGroup;
import com.ruoyi.common.core.domain.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -14,7 +16,13 @@
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "发现问题分页条件查询对象")
public class QuestionQuery extends BasePage {
    private static final long serialVersionUID = -7645166269898895715L;
    @ApiModelProperty("问题标题")
    private String title;
    @ApiModelProperty(value = "季度", notes = "历史数据必传")
    @NotBlank(message = "季度不能为空", groups = HistoryGroup.class)
    private String quarter;
}
ruoyi-system/src/main/java/com/ruoyi/system/query/ScoreCalculateQuery.java
@@ -1,14 +1,13 @@
package com.ruoyi.system.query;
import com.ruoyi.common.annotation.HistoryGroup;
import com.ruoyi.common.core.domain.BasePage;
import com.ruoyi.common.enums.FieldTypeEnum;
import com.ruoyi.common.validate.HistoryGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
/**
 * @author mitao
@@ -22,7 +21,9 @@
    private static final long serialVersionUID = -1055887500656271053L;
    @ApiModelProperty(value = "季度", notes = "当前季度数据不传,历史数据必传")
    @NotBlank(message = "季度不能为空", groups = {HistoryGroup.class})
    @NotBlank(
            message = "季度不能为空",
            groups = {HistoryGroup.class})
    private String quarter;
    @ApiModelProperty(value = "类型名称")
ruoyi-system/src/main/java/com/ruoyi/system/service/TbBasicDataService.java
@@ -8,13 +8,18 @@
import com.ruoyi.system.query.CurrentFieldsQuery;
import com.ruoyi.system.query.ScoreCalculateQuery;
import com.ruoyi.system.query.ScoreQuery;
import com.ruoyi.system.vo.*;
import com.ruoyi.system.vo.BasicDataReportingVO;
import com.ruoyi.system.vo.CurrentFieldsAllVO;
import com.ruoyi.system.vo.CurrentFieldsDetailVO;
import com.ruoyi.system.vo.CurrentFieldsVO;
import com.ruoyi.system.vo.ScoreCalculateVO;
import com.ruoyi.system.vo.ScoreVO;
import java.io.IOException;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
/**
 * <p>
 * 基础数据表 服务类
 * </p>
 *
 * @author mitao
 * @since 2024-03-13
@@ -24,8 +29,6 @@
    R<BasicDataReportingVO> getBasicFields() throws Exception;
    void saveBasicData(BasicDataDTO dto);
    void downloadImportTemplate() throws Exception;
    void importBasicData(MultipartFile file) throws Exception;
@@ -42,4 +45,8 @@
    PageDTO<ScoreCalculateVO> scoreCalculatePage(ScoreCalculateQuery query);
    CurrentFieldsAllVO fieldsStaticsAll(String quarter);
    void importData(MultipartFile file, String quarter) throws IOException;
    void exportData(List<String> quarterList) throws Exception;
}
ruoyi-system/src/main/java/com/ruoyi/system/service/TbFieldService.java
@@ -31,4 +31,7 @@
    void update(FieldUpdateDTO dto);
    BasicDataFieldVO getHistoryFields(Long id);
    void downloadImportTemplate() throws Exception;
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbBasicDataServiceImpl.java
@@ -1,6 +1,8 @@
package com.ruoyi.system.service.impl;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -10,41 +12,73 @@
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.*;
import com.ruoyi.common.enums.CalculateTypeEnum;
import com.ruoyi.common.enums.ReportingStatusEnum;
import com.ruoyi.common.enums.ShowStatusEnum;
import com.ruoyi.common.enums.UserTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.*;
import com.ruoyi.system.domain.*;
import com.ruoyi.common.utils.BeanUtils;
import com.ruoyi.common.utils.CalculateUtil;
import com.ruoyi.common.utils.CollUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.EasyExcelUtil;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.TbBasicData;
import com.ruoyi.system.domain.TbBasicDataConfig;
import com.ruoyi.system.domain.TbBasicDataConfigDetail;
import com.ruoyi.system.domain.TbBasicDataField;
import com.ruoyi.system.domain.TbDept;
import com.ruoyi.system.domain.TbField;
import com.ruoyi.system.domain.TbScore;
import com.ruoyi.system.dto.BasicDataDTO;
import com.ruoyi.system.handler.CustomerHandler;
import com.ruoyi.system.handler.SelectedSheetWriteHandler;
import com.ruoyi.system.listener.BasicDataListener;
import com.ruoyi.system.listener.HistoryDataListener;
import com.ruoyi.system.mapper.TbBasicDataMapper;
import com.ruoyi.system.mapper.TbDeptMapper;
import com.ruoyi.system.query.CurrentFieldsQuery;
import com.ruoyi.system.query.ScoreCalculateQuery;
import com.ruoyi.system.query.ScoreQuery;
import com.ruoyi.system.service.*;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.TbBasicDataConfigDetailService;
import com.ruoyi.system.service.TbBasicDataConfigService;
import com.ruoyi.system.service.TbBasicDataFieldService;
import com.ruoyi.system.service.TbBasicDataService;
import com.ruoyi.system.service.TbFieldService;
import com.ruoyi.system.service.TbScoreService;
import com.ruoyi.system.utils.FieldBuildUtil;
import com.ruoyi.system.vo.*;
import com.ruoyi.system.vo.BasicDataReportingVO;
import com.ruoyi.system.vo.CurrentFieldsAllVO;
import com.ruoyi.system.vo.CurrentFieldsDetailVO;
import com.ruoyi.system.vo.CurrentFieldsVO;
import com.ruoyi.system.vo.FieldsTreeVO;
import com.ruoyi.system.vo.ScoreCalculateVO;
import com.ruoyi.system.vo.ScoreVO;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
 * <p>
 * 基础数据表 服务实现类
 * </p>
 *
 * @author mitao
 * @since 2024-03-13
@@ -52,7 +86,8 @@
@Slf4j
@Service
@RequiredArgsConstructor
public class TbBasicDataServiceImpl extends ServiceImpl<TbBasicDataMapper, TbBasicData> implements TbBasicDataService {
public class TbBasicDataServiceImpl extends ServiceImpl<TbBasicDataMapper, TbBasicData>
        implements TbBasicDataService {
    private final TbDeptMapper tbDeptMapper;
    private final HttpServletResponse response;
@@ -63,11 +98,13 @@
    private final TbScoreService tbScoreService;
    private final ISysUserService sysUserService;
    public static void setFieldValues(List<FieldsTreeVO> fields, Map<Long, TbBasicDataField> fieldMap) {
    public static void setFieldValues(
            List<FieldsTreeVO> fields, Map<Long, TbBasicDataField> fieldMap) {
        for (FieldsTreeVO field : fields) {
            TbBasicDataField tbBasicDataField = fieldMap.get(field.getId());
            if (tbBasicDataField != null) {
                field.setValue(FieldBuildUtil.formatNumberWithCommas(tbBasicDataField.getFieldValue()));
                field.setValue(
                        FieldBuildUtil.formatNumberWithCommas(tbBasicDataField.getFieldValue()));
            }
            if (field.getChildren() != null && !field.getChildren().isEmpty()) {
                setFieldValues(field.getChildren(), fieldMap);
@@ -80,34 +117,39 @@
        SysUser user = SecurityUtils.getLoginUser().getUser();
        String deptAreaCode = user.getAreaCode();
        BasicDataReportingVO vo = new BasicDataReportingVO();
        //校验区划代码
        TbDept dept = tbDeptMapper.selectOne(Wrappers.<TbDept>lambdaQuery().eq(TbDept::getAreaCode, deptAreaCode));
        // 校验区划代码
        TbDept dept =
                tbDeptMapper.selectOne(
                        Wrappers.<TbDept>lambdaQuery().eq(TbDept::getAreaCode, deptAreaCode));
        if (Objects.isNull(dept)) {
            throw new ServiceException(String.format("区划代码%s不存在", deptAreaCode));
        }
        Date date = new Date();
        Map<String, Date> quarterDate = DateUtils.getQuarterDate(date);
        //当前季度开始
        // 当前季度开始
        Date quarterStart = quarterDate.get("first");
        //当前季度结束
        // 当前季度结束
        Date quarterEnd = quarterDate.get("last");
        //判断当前时间是否在季度初1-15号
        // 判断当前时间是否在季度初1-15号
        Instant instant = quarterStart.toInstant();
        LocalDate quarterStartLocalDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate fifteenDaysLimit = quarterStartLocalDate.plusDays(15);
        LocalDate now = LocalDate.now();
        vo.setQuarter(DateUtils.getNowQuarter());
        vo.setStatus(ReportingStatusEnum.UNFILLED);
        //如果当前时间不在规定范围内:季度初1-15号
        // 如果当前时间不在规定范围内:季度初1-15号
        if (now.isBefore(quarterStartLocalDate) || now.isAfter(fifteenDaysLimit)) {
            return R.ok(vo, "请于季度初1-15号上传季度数据。");
        }
        //查询是否有当前季度的填报记录
        TbBasicData basicData = this.getOne(Wrappers.<TbBasicData>lambdaQuery()
                .eq(TbBasicData::getDeptAreaCode, dept.getAreaCode())
                .between(TbBasicData::getCreateTime, quarterStart, quarterEnd));
        //查询需要填写的字段
        List<TbField> list = tbFieldService.lambdaQuery().eq(TbField::getStatus, ShowStatusEnum.SHOW).list();
        // 查询是否有当前季度的填报记录
        TbBasicData basicData =
                this.getOne(
                        Wrappers.<TbBasicData>lambdaQuery()
                                .eq(TbBasicData::getDeptAreaCode, dept.getAreaCode())
                                .between(TbBasicData::getCreateTime, quarterStart, quarterEnd));
        // 查询需要填写的字段
        List<TbField> list =
                tbFieldService.lambdaQuery().eq(TbField::getStatus, ShowStatusEnum.SHOW).list();
        List<FieldsTreeVO> roots = new ArrayList<>();
        FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
        fieldsTreeVO.setId(-1L);
@@ -133,13 +175,18 @@
            return R.ok(vo);
        } else {
            vo.setStatus(basicData.getStatus());
            //查询已填报数据 包含数据缺失和已填报
            List<TbBasicDataField> basicDataFields = tbBasicDataFieldService.lambdaQuery()
                    .eq(TbBasicDataField::getBasicDataId, basicData.getId()).list();
            // 查询已填报数据 包含数据缺失和已填报
            List<TbBasicDataField> basicDataFields =
                    tbBasicDataFieldService
                            .lambdaQuery()
                            .eq(TbBasicDataField::getBasicDataId, basicData.getId())
                            .list();
            if (CollUtils.isNotEmpty(basicDataFields)) {
                Map<Long, TbBasicDataField> fieldMap = basicDataFields.stream()
                        .collect(Collectors.toMap(TbBasicDataField::getFieldId, Function.identity()));
                Map<Long, TbBasicDataField> fieldMap =
                        basicDataFields.stream()
                                .collect(Collectors.toMap(TbBasicDataField::getFieldId,
                                        Function.identity()));
                setFieldValues(vo.getFields(), fieldMap);
                return R.ok(vo);
            }
@@ -152,7 +199,7 @@
    public void saveBasicData(BasicDataDTO dto) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String areaCode = loginUser.getUser().getAreaCode();
        //数据校验
        // 数据校验
        if (Objects.isNull(dto) || CollUtils.isEmpty(dto.getFields())) {
            return;
        }
@@ -160,19 +207,23 @@
        tbBasicData.setDeptAreaCode(areaCode);
        tbBasicData.setStatus(ReportingStatusEnum.MISSING_DATA);
        this.saveOrUpdate(tbBasicData);
        //保存基础数据动态字段数据
        List<TbBasicDataField> tbBasicDataFields = BeanUtils.copyList(dto.getFields(), TbBasicDataField.class);
        //查询需要填写的动态字段
        List<TbField> fieldList = tbFieldService.lambdaQuery().eq(TbField::getStatus, ShowStatusEnum.SHOW).list();
        Map<Long, TbField> fieldMap = fieldList.stream().collect(Collectors.toMap(TbField::getId, e -> e));
        tbBasicDataFields.forEach(item -> {
            item.setBasicDataId(tbBasicData.getId());
            TbField tbField = fieldMap.get(item.getFieldId());
            if (Objects.nonNull(tbField)) {
                item.setFieldName(tbField.getFieldName());
            }
        });
        //添加固定字段 转移支付规模、当期GDP
        // 保存基础数据动态字段数据
        List<TbBasicDataField> tbBasicDataFields =
                BeanUtils.copyList(dto.getFields(), TbBasicDataField.class);
        // 查询需要填写的动态字段
        List<TbField> fieldList =
                tbFieldService.lambdaQuery().eq(TbField::getStatus, ShowStatusEnum.SHOW).list();
        Map<Long, TbField> fieldMap =
                fieldList.stream().collect(Collectors.toMap(TbField::getId, e -> e));
        tbBasicDataFields.forEach(
                item -> {
                    item.setBasicDataId(tbBasicData.getId());
                    TbField tbField = fieldMap.get(item.getFieldId());
                    if (Objects.nonNull(tbField)) {
                        item.setFieldName(tbField.getFieldName());
                    }
                });
        // 添加固定字段 转移支付规模、当期GDP
        TbBasicDataField transferPaymentScale = new TbBasicDataField();
        transferPaymentScale.setBasicDataId(tbBasicData.getId());
        transferPaymentScale.setFieldId(-1L);
@@ -188,14 +239,21 @@
        remark.setFieldId(-3L);
        remark.setFieldValue(tbBasicData.getRemark());
        tbBasicDataFields.add(remark);
        //将该基础数据的动态字段数据全部删除
        tbBasicDataFieldService.remove(Wrappers.<TbBasicDataField>lambdaQuery().eq(TbBasicDataField::getBasicDataId, tbBasicData.getId()));
        // 将该基础数据的动态字段数据全部删除
        tbBasicDataFieldService.remove(
                Wrappers.<TbBasicDataField>lambdaQuery()
                        .eq(TbBasicDataField::getBasicDataId, tbBasicData.getId()));
        tbBasicDataFieldService.saveBatch(tbBasicDataFields);
        //需要填写的动态字段
        // 需要填写的动态字段
        Set<Long> fieldIds = fieldList.stream().map(TbField::getId).collect(Collectors.toSet());
        //用户填写的动态字段
        Set<Long> deptFieldIds = tbBasicDataFields.stream().map(TbBasicDataField::getFieldId).collect(Collectors.toSet());
        boolean flag = deptFieldIds.containsAll(fieldIds) && (StringUtils.isNotEmpty(dto.getTransferPaymentScale()) && StringUtils.isNotEmpty(dto.getCurrentGdp()));
        // 用户填写的动态字段
        Set<Long> deptFieldIds =
                tbBasicDataFields.stream().map(TbBasicDataField::getFieldId)
                        .collect(Collectors.toSet());
        boolean flag =
                deptFieldIds.containsAll(fieldIds)
                        && (StringUtils.isNotEmpty(dto.getTransferPaymentScale())
                        && StringUtils.isNotEmpty(dto.getCurrentGdp()));
        if (flag) {
            tbBasicData.setStatus(ReportingStatusEnum.FILLED);
            this.updateById(tbBasicData);
@@ -206,141 +264,94 @@
    }
    @Override
    public void downloadImportTemplate() throws Exception {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = "地方财政运行及“三保”情况统计表";
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
        //查询需要填写的动态字段
        List<TbField> list = tbFieldService.lambdaQuery().eq(TbField::getStatus, ShowStatusEnum.SHOW).list();
        List<List<String>> head = head(list);
        List<TbField> collect = list.stream()
                .filter(item -> FieldTypeEnum.TEXT.equals(item.getFieldType()))
                .filter(item -> FieldInputTypeEnum.FIXED_CONTENT.equals(item.getTextInputType()))
                .collect(Collectors.toList());
        Map<Integer, String[]> selectedMap = new HashMap<>();
        if (CollUtils.isNotEmpty(collect)) {
            selectedMap = new HashMap<>();
            for (TbField tbField : collect) {
                int outerListIndex = getOuterListIndex(head, tbField.getFieldName());
                String[] selectStr = tbField.getTextContent().split(",");
                selectedMap.put(outerListIndex, selectStr);
            }
        }
        // 这里需要设置不关闭流
        EasyExcel.write(response.getOutputStream()).head(head)
                .autoCloseStream(Boolean.TRUE).sheet("模板")
                .registerWriteHandler(new SelectedSheetWriteHandler(selectedMap))
                .registerWriteHandler(new CustomerHandler())
                .registerWriteHandler(EasyExcelUtil.getStyleStrategy())
                .doWrite(dataList(list));
    }
    /**
     * 根据字段名获取该字段下标
     *
     * @param list  表头
     * @param value 字段名
     * @return 下标
     */
    public int getOuterListIndex(List<List<String>> list, String value) {
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).contains(value)) {
                return i;
            }
        }
        return -1; // 返回-1表示未找到
    }
    private List<List<Object>> dataList(List<TbField> list) throws Exception {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String areaName = loginUser.getUser().getAreaName();
        List<List<Object>> excellist = new ArrayList<List<Object>>();
        List<List<String>> head = head(list);
        List<Object> columnNo = Lists.newArrayList("栏号");
        for (int i = 1; i < head.size(); i++) {
            columnNo.add(String.valueOf(i));
        }
        excellist.add(columnNo);
        excellist.add(Lists.newArrayList(areaName, DateUtils.getNowQuarter()));
        return excellist;
    }
    private List<List<String>> head(List<TbField> list) {
        List<List<String>> headTitles = Lists.newArrayList();
        //固定字段
        headTitles.add(Lists.newArrayList("地区"));
        headTitles.add(Lists.newArrayList("填报季度"));
        headTitles.add(Lists.newArrayList("转移支付规模"));
        headTitles.add(Lists.newArrayList("当期GDP"));
        list.forEach(item -> {
            String levelOneCategory = item.getLevelOneCategory();
            String levelTwoCategory = item.getLevelTwoCategory();
            String levelThreeCategory = item.getLevelThreeCategory();
            String fieldName = item.getFieldName();
            headTitles.add(Lists.newArrayList(levelOneCategory, StringUtils.isBlank(levelTwoCategory) ? fieldName : levelTwoCategory, StringUtils.isBlank(levelThreeCategory) ? fieldName : levelThreeCategory, fieldName));
        });
        headTitles.add(Lists.newArrayList("备注"));
        return headTitles;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importBasicData(MultipartFile file) throws Exception {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String areaCode = loginUser.getUser().getAreaCode();
        //查询需要填写的动态字段
        List<TbField> fieldList = tbFieldService.lambdaQuery().eq(TbField::getStatus, ShowStatusEnum.SHOW).list();
        EasyExcel.read(file.getInputStream(), new BasicDataListener(this, fieldList,
                tbFieldService, areaCode, tbBasicDataFieldService, tbBasicDataConfigService,
                tbBasicDataConfigDetailService, tbScoreService)).sheet().doRead();
        EasyExcel.read(
                        file.getInputStream(),
                        new BasicDataListener(
                                this,
                                tbFieldService,
                                areaCode,
                                tbBasicDataFieldService,
                                tbBasicDataConfigService,
                                tbBasicDataConfigDetailService,
                                tbScoreService))
                .sheet()
                .doRead();
    }
    private void calculateScore(TbBasicData tbBasicData) {
        //计算得分
        List<TbBasicDataConfig> list = tbBasicDataConfigService.lambdaQuery().eq(TbBasicDataConfig::getStatus, ShowStatusEnum.SHOW).list();
        // 计算得分
        List<TbBasicDataConfig> list =
                tbBasicDataConfigService
                        .lambdaQuery()
                        .eq(TbBasicDataConfig::getStatus, ShowStatusEnum.SHOW)
                        .list();
        if (CollectionUtils.isEmpty(list)) {
            throw new ServiceException("计算得分失败,平台未配置得分计算规则");
        }
        List<TbBasicDataConfig> numCalculates = list.stream()
                .filter(item -> CalculateTypeEnum.NUMBER.equals(item.getCalculateType()))
                .collect(Collectors.toList());
        List<TbBasicDataConfig> textAndPercentages = list.stream()
                .filter(item -> !CalculateTypeEnum.NUMBER.equals(item.getCalculateType()))
                .collect(Collectors.toList());
        List<TbBasicDataConfig> numCalculates =
                list.stream()
                        .filter(item -> CalculateTypeEnum.NUMBER.equals(item.getCalculateType()))
                        .collect(Collectors.toList());
        List<TbBasicDataConfig> textAndPercentages =
                list.stream()
                        .filter(item -> !CalculateTypeEnum.NUMBER.equals(item.getCalculateType()))
                        .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(numCalculates)) {
            numCalculates.forEach(item -> {
                Map<String, Object> valueMap = new HashMap<>();
                String numberCalculateFormula = item.getNumberCalculateFormula();
                Map<String, Integer> fieldsAndValue = CalculateUtil.getFieldsAndValue(numberCalculateFormula);
                for (Map.Entry<String, Integer> stringIntegerEntry : fieldsAndValue.entrySet()) {
                    Optional<TbBasicDataField> tbBasicDataField = tbBasicDataFieldService.lambdaQuery()
                            .eq(TbBasicDataField::getBasicDataId, tbBasicData.getId())
                            .eq(TbBasicDataField::getFieldId, stringIntegerEntry.getValue())
                            .oneOpt();
                    tbBasicDataField.ifPresent(basicDataField -> valueMap.put(stringIntegerEntry.getKey(), basicDataField.getFieldValue()));
                }
                double score = CalculateUtil.calculate(numberCalculateFormula, valueMap);
                TbScore tbScore = new TbScore();
                tbScore.setBasicDataId(tbBasicData.getId());
                tbScore.setScore(score);
                tbScore.setBasicDataConfigId(item.getId());
                tbScoreService.save(tbScore);
            });
            numCalculates.forEach(
                    item -> {
                        Map<String, Object> valueMap = new HashMap<>();
                        String numberCalculateFormula = item.getNumberCalculateFormula();
                        Map<String, Integer> fieldsAndValue =
                                CalculateUtil.getFieldsAndValue(numberCalculateFormula);
                        for (Map.Entry<String, Integer> stringIntegerEntry : fieldsAndValue.entrySet()) {
                            Optional<TbBasicDataField> tbBasicDataField =
                                    tbBasicDataFieldService
                                            .lambdaQuery()
                                            .eq(TbBasicDataField::getBasicDataId,
                                                    tbBasicData.getId())
                                            .eq(TbBasicDataField::getFieldId,
                                                    stringIntegerEntry.getValue())
                                            .oneOpt();
                            tbBasicDataField.ifPresent(
                                    basicDataField ->
                                            valueMap.put(stringIntegerEntry.getKey(),
                                                    basicDataField.getFieldValue()));
                        }
                        double score = CalculateUtil.calculate(numberCalculateFormula, valueMap);
                        TbScore tbScore = new TbScore();
                        tbScore.setBasicDataId(tbBasicData.getId());
                        tbScore.setScore(score);
                        tbScore.setBasicDataConfigId(item.getId());
                        tbScoreService.save(tbScore);
                    });
        }
        if (CollectionUtils.isNotEmpty(textAndPercentages)) {
            for (TbBasicDataConfig textAndPercentage : textAndPercentages) {
                TbScore tbScore = new TbScore();
                List<TbBasicDataConfigDetail> details = tbBasicDataConfigDetailService.lambdaQuery()
                        .eq(TbBasicDataConfigDetail::getBasicDataConfigId, textAndPercentage.getId())
                        .list();
                Map<String, String> scoreMap = details.stream().collect(Collectors.toMap(TbBasicDataConfigDetail::getKey, TbBasicDataConfigDetail::getValue));
                List<TbBasicDataConfigDetail> details =
                        tbBasicDataConfigDetailService
                                .lambdaQuery()
                                .eq(TbBasicDataConfigDetail::getBasicDataConfigId,
                                        textAndPercentage.getId())
                                .list();
                Map<String, String> scoreMap =
                        details.stream()
                                .collect(
                                        Collectors.toMap(
                                                TbBasicDataConfigDetail::getKey,
                                                TbBasicDataConfigDetail::getValue));
                if (CollectionUtils.isNotEmpty(details)) {
                    Optional<TbBasicDataField> tbBasicDataFieldOptional = tbBasicDataFieldService.lambdaQuery()
                            .eq(TbBasicDataField::getBasicDataId, tbBasicData.getId())
                            .eq(TbBasicDataField::getFieldId, textAndPercentage.getFieldIdStr())
                            .oneOpt();
                    Optional<TbBasicDataField> tbBasicDataFieldOptional =
                            tbBasicDataFieldService
                                    .lambdaQuery()
                                    .eq(TbBasicDataField::getBasicDataId, tbBasicData.getId())
                                    .eq(TbBasicDataField::getFieldId,
                                            textAndPercentage.getFieldIdStr())
                                    .oneOpt();
                    if (tbBasicDataFieldOptional.isPresent()) {
                        TbBasicDataField tbBasicDataField = tbBasicDataFieldOptional.get();
                        if (CalculateTypeEnum.TEXT.equals(textAndPercentage.getCalculateType())) {
@@ -350,14 +361,16 @@
                            tbScore.setBasicDataConfigId(textAndPercentage.getId());
                            tbScoreService.save(tbScore);
                        }
                        if (CalculateTypeEnum.PERCENTAGE.equals(textAndPercentage.getCalculateType())) {
                        if (CalculateTypeEnum.PERCENTAGE.equals(
                                textAndPercentage.getCalculateType())) {
                            for (Map.Entry<String, String> stringStringEntry : scoreMap.entrySet()) {
                                String[] split = stringStringEntry.getKey().split("-");
                                double v = Double.parseDouble(tbBasicDataField.getFieldValue());
                                double min = Double.parseDouble(split[0]);
                                double max = Double.parseDouble(split[1]);
                                if (v >= min && v <= max) {
                                    tbScore.setScore(Double.parseDouble(stringStringEntry.getValue()));
                                    tbScore.setScore(
                                            Double.parseDouble(stringStringEntry.getValue()));
                                }
                            }
                            tbScore.setBasicDataId(tbBasicData.getId());
@@ -376,19 +389,21 @@
        SysUser user = SecurityUtils.getLoginUser().getUser();
        String areaCode = user.getAreaCode();
        Map<String, Date> quarterDate = DateUtils.getQuarterDate(new Date());
        //当前季度开始
        // 当前季度开始
        Date quarterStart = quarterDate.get("first");
        //当前季度结束
        // 当前季度结束
        Date quarterEnd = quarterDate.get("last");
        //查询是否有当前季度的填报记录
        TbBasicData basicData = this.getOne(Wrappers.<TbBasicData>lambdaQuery()
                .eq(TbBasicData::getDeptAreaCode, areaCode)
                .between(TbBasicData::getCreateTime, quarterStart, quarterEnd));
        // 查询是否有当前季度的填报记录
        TbBasicData basicData =
                this.getOne(
                        Wrappers.<TbBasicData>lambdaQuery()
                                .eq(TbBasicData::getDeptAreaCode, areaCode)
                                .between(TbBasicData::getCreateTime, quarterStart, quarterEnd));
        if (Objects.isNull(basicData)) {
            return PageDTO.empty(page);
        }
        query.setBasicDataId(basicData.getId());
        //查询对应的基础数据配置
        // 查询对应的基础数据配置
        Page<ScoreVO> pageVO = tbScoreService.pageScore(query, page);
        return PageDTO.of(pageVO);
    }
@@ -401,60 +416,82 @@
            throw new ServiceException("非法参数");
        }
        CurrentFieldsDetailVO vo = BeanUtils.copyBean(basicData, CurrentFieldsDetailVO.class);
        //查询用户信息
        sysUserService.lambdaQuery()
        // 查询用户信息
        sysUserService
                .lambdaQuery()
                .eq(SysUser::getAreaCode, basicData.getDeptAreaCode())
                .eq(SysUser::getUserType, UserTypeEnum.DEPARTMENT.getCode())
                .oneOpt()
                .ifPresent(item -> {
                    vo.setAreaName(item.getAreaName());
                    vo.setPhoneNumber(item.getPhoneNumber());
                    vo.setPersonInCharge(item.getPersonInCharge());
                });
                .ifPresent(
                        item -> {
                            vo.setAreaName(item.getAreaName());
                            vo.setPhoneNumber(item.getPhoneNumber());
                            vo.setPersonInCharge(item.getPersonInCharge());
                        });
        // 查询动态字段
        List<TbBasicDataField> basicDataFields = tbBasicDataFieldService.lambdaQuery().eq(TbBasicDataField::getBasicDataId, basicData.getId()).list();
        List<TbBasicDataField> basicDataFields =
                tbBasicDataFieldService
                        .lambdaQuery()
                        .eq(TbBasicDataField::getBasicDataId, basicData.getId())
                        .list();
        // 获取所有字段ID
        Set<Long> fieldIds = basicDataFields.stream().map(TbBasicDataField::getFieldId).collect(Collectors.toSet());
        Set<Long> fieldIds =
                basicDataFields.stream().map(TbBasicDataField::getFieldId)
                        .collect(Collectors.toSet());
        // 根据字段ID查询字段信息并构建字段ID到字段对象的映射
        Map<Long, TbField> fieldMap = tbFieldService.lambdaQuery()
                .in(!fieldIds.isEmpty(), TbField::getId, fieldIds)
                .list().stream()
                .collect(Collectors.toMap(TbField::getId, e -> e));
        Map<Long, TbField> fieldMap =
                tbFieldService
                        .lambdaQuery()
                        .in(!fieldIds.isEmpty(), TbField::getId, fieldIds)
                        .list()
                        .stream()
                        .collect(Collectors.toMap(TbField::getId, e -> e));
        // 根节点
        List<FieldsTreeVO> root = new ArrayList<>();
        basicDataFields.stream().filter(item -> item.getFieldId() == -1).findFirst().ifPresent(item -> {
            FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
            fieldsTreeVO.setId(item.getFieldId());
            fieldsTreeVO.setName("转移支付规模");
            fieldsTreeVO.setValue(item.getFieldValue());
            fieldsTreeVO.setCategory(Boolean.FALSE);
            root.add(fieldsTreeVO);
        });
        basicDataFields.stream().filter(item -> item.getFieldId() == -2).findFirst().ifPresent(item -> {
            FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
            fieldsTreeVO.setId(item.getFieldId());
            fieldsTreeVO.setName("当期GDP");
            fieldsTreeVO.setValue(item.getFieldValue());
            fieldsTreeVO.setCategory(Boolean.FALSE);
            root.add(fieldsTreeVO);
        });
        basicDataFields.stream()
                .filter(item -> item.getFieldId() == -1)
                .findFirst()
                .ifPresent(
                        item -> {
                            FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
                            fieldsTreeVO.setId(item.getFieldId());
                            fieldsTreeVO.setName("转移支付规模");
                            fieldsTreeVO.setValue(item.getFieldValue());
                            fieldsTreeVO.setCategory(Boolean.FALSE);
                            root.add(fieldsTreeVO);
                        });
        basicDataFields.stream()
                .filter(item -> item.getFieldId() == -2)
                .findFirst()
                .ifPresent(
                        item -> {
                            FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
                            fieldsTreeVO.setId(item.getFieldId());
                            fieldsTreeVO.setName("当期GDP");
                            fieldsTreeVO.setValue(item.getFieldValue());
                            fieldsTreeVO.setCategory(Boolean.FALSE);
                            root.add(fieldsTreeVO);
                        });
        FieldBuildUtil.buildTreeStructure(basicDataFields, fieldMap, root);
        basicDataFields.stream().filter(item -> item.getFieldId() == -3).findFirst().ifPresent(item -> {
            FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
            fieldsTreeVO.setId(item.getFieldId());
            fieldsTreeVO.setName("备注");
            fieldsTreeVO.setValue(item.getFieldValue());
            fieldsTreeVO.setCategory(Boolean.FALSE);
            root.add(fieldsTreeVO);
        });
        basicDataFields.stream()
                .filter(item -> item.getFieldId() == -3)
                .findFirst()
                .ifPresent(
                        item -> {
                            FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
                            fieldsTreeVO.setId(item.getFieldId());
                            fieldsTreeVO.setName("备注");
                            fieldsTreeVO.setValue(item.getFieldValue());
                            fieldsTreeVO.setCategory(Boolean.FALSE);
                            root.add(fieldsTreeVO);
                        });
        vo.setFields(root);
        return R.ok(vo);
    }
    @Override
    public R<PageDTO<CurrentFieldsVO>> fieldsStatics(CurrentFieldsQuery dto) throws Exception {
    public R<PageDTO<CurrentFieldsVO>> fieldsStatics(CurrentFieldsQuery dto) {
        Page<CurrentFieldsVO> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        String nowQuarter = DateUtils.getNowQuarter();
        return R.ok(PageDTO.of(baseMapper.fieldsStatics(page, dto)));
    }
@@ -462,7 +499,7 @@
    public CurrentFieldsAllVO fieldsStaticsAll() throws Exception {
        CurrentFieldsAllVO vo = new CurrentFieldsAllVO();
        List<FieldsTreeVO> roots = new ArrayList<>();
        //获取表头
        // 获取表头
        FieldsTreeVO area = new FieldsTreeVO();
        area.setCategory(Boolean.FALSE);
        area.setName("地区");
@@ -478,8 +515,9 @@
        roots.add(quarter);
        roots.add(transferPaymentScale);
        roots.add(currentGdp);
        //查询当前季度填写字段
        List<TbField> fieldList = tbFieldService.lambdaQuery().eq(TbField::getStatus, ShowStatusEnum.SHOW).list();
        // 查询当前季度填写字段
        List<TbField> fieldList =
                tbFieldService.lambdaQuery().eq(TbField::getStatus, ShowStatusEnum.SHOW).list();
        FieldBuildUtil.buildTreeFromTbFieldList(fieldList, roots);
        FieldsTreeVO remark = new FieldsTreeVO();
        remark.setCategory(Boolean.FALSE);
@@ -487,25 +525,30 @@
        roots.add(remark);
        vo.setFields(roots);
        String nowQuarter = DateUtils.getNowQuarter();
        //查询上报的基础数据
        List<TbBasicData> basicDataList = this.lambdaQuery()
                .eq(TbBasicData::getQuarter, nowQuarter)
                .eq(TbBasicData::getStatus, ReportingStatusEnum.FILLED)
                .list();
        // 查询上报的基础数据
        List<TbBasicData> basicDataList =
                this.lambdaQuery()
                        .eq(TbBasicData::getQuarter, nowQuarter)
                        .eq(TbBasicData::getStatus, ReportingStatusEnum.FILLED)
                        .list();
        if (CollUtils.isNotEmpty(basicDataList)) {
            Set<String> areaCodeList = basicDataList.stream()
                    .map(TbBasicData::getDeptAreaCode)
                    .collect(Collectors.toSet());
            Map<String, SysUser> userMap = sysUserService.lambdaQuery()
                    .in(SysUser::getAreaCode, areaCodeList)
                    .list()
                    .stream()
                    .collect(Collectors.toMap(SysUser::getAreaCode, e -> e));
            Set<Long> basicDataIds = basicDataList.stream().map(TbBasicData::getId).collect(Collectors.toSet());
            Map<Long, TbBasicDataField> basicDataFieldMap = tbBasicDataFieldService.lambdaQuery()
                    .in(TbBasicDataField::getBasicDataId, basicDataIds).list().stream()
                    .collect(Collectors.toMap(TbBasicDataField::getFieldId, e -> e));
            //值
            Set<String> areaCodeList =
                    basicDataList.stream().map(TbBasicData::getDeptAreaCode)
                            .collect(Collectors.toSet());
            Map<String, SysUser> userMap =
                    sysUserService.lambdaQuery().in(SysUser::getAreaCode, areaCodeList).list()
                            .stream()
                            .collect(Collectors.toMap(SysUser::getAreaCode, e -> e));
            Set<Long> basicDataIds =
                    basicDataList.stream().map(TbBasicData::getId).collect(Collectors.toSet());
            Map<Long, TbBasicDataField> basicDataFieldMap =
                    tbBasicDataFieldService
                            .lambdaQuery()
                            .in(TbBasicDataField::getBasicDataId, basicDataIds)
                            .list()
                            .stream()
                            .collect(Collectors.toMap(TbBasicDataField::getFieldId, e -> e));
            // 值
            List<Object> result = new ArrayList<>();
            for (TbBasicData tbBasicData : basicDataList) {
                SysUser user = userMap.get(tbBasicData.getDeptAreaCode());
@@ -516,7 +559,11 @@
                item.add(tbBasicData.getCurrentGdp());
                for (TbField tbField : fieldList) {
                    TbBasicDataField tbBasicDataField = basicDataFieldMap.get(tbField.getId());
                    item.add(Objects.nonNull(tbBasicDataField) ? FieldBuildUtil.formatNumberWithCommas(tbBasicDataField.getFieldValue()) : "");
                    item.add(
                            Objects.nonNull(tbBasicDataField)
                                    ? FieldBuildUtil.formatNumberWithCommas(
                                    tbBasicDataField.getFieldValue())
                                    : "");
                }
                item.add(tbBasicData.getRemark());
                result.add(item);
@@ -529,7 +576,7 @@
    @Override
    public R<PageDTO<CurrentFieldsVO>> historyFieldsStatics(CurrentFieldsQuery dto) {
        Page<CurrentFieldsVO> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        //当前所在季度
        // 当前所在季度
        return R.ok(PageDTO.of(baseMapper.fieldsStatics(page, dto)));
    }
@@ -544,7 +591,7 @@
    public CurrentFieldsAllVO fieldsStaticsAll(String quarterStr) {
        CurrentFieldsAllVO vo = new CurrentFieldsAllVO();
        List<FieldsTreeVO> roots = new ArrayList<>();
        //获取表头
        // 获取表头
        FieldsTreeVO area = new FieldsTreeVO();
        area.setCategory(Boolean.FALSE);
        area.setName("地区");
@@ -560,19 +607,25 @@
        roots.add(quarter);
        roots.add(transferPaymentScale);
        roots.add(currentGdp);
        List<TbBasicData> basicDataList = this.lambdaQuery()
                .eq(TbBasicData::getQuarter, quarterStr)
                .eq(TbBasicData::getStatus, ReportingStatusEnum.FILLED)
                .list();
        if (CollUtils.isNotEmpty(basicDataList)) {
        List<TbBasicData> basicDataList =
                this.lambdaQuery()
                        .eq(TbBasicData::getQuarter, quarterStr)
                        .eq(TbBasicData::getStatus, ReportingStatusEnum.FILLED)
                        .list();
        if (CollUtils.isEmpty(basicDataList)) {
            throw new ServiceException("非法参数");
        }
        Long basicDataId = basicDataList.get(0).getId();
        Set<Long> fieldIds = tbBasicDataFieldService.lambdaQuery()
                .eq(TbBasicDataField::getBasicDataId, basicDataId)
                .ne(TbBasicDataField::getFieldId, -1L)
                .ne(TbBasicDataField::getFieldId, -2L)
                .list().stream().map(TbBasicDataField::getFieldId).collect(Collectors.toSet());
        Set<Long> fieldIds =
                tbBasicDataFieldService
                        .lambdaQuery()
                        .eq(TbBasicDataField::getBasicDataId, basicDataId)
                        .ne(TbBasicDataField::getFieldId, -1L)
                        .ne(TbBasicDataField::getFieldId, -2L)
                        .list()
                        .stream()
                        .map(TbBasicDataField::getFieldId)
                        .collect(Collectors.toSet());
        List<TbField> fieldList = tbFieldService.lambdaQuery().in(TbField::getId, fieldIds).list();
        if (CollUtils.isEmpty(fieldList)) {
            FieldsTreeVO remark = new FieldsTreeVO();
@@ -588,21 +641,24 @@
        remark.setName("备注");
        roots.add(remark);
        vo.setFields(roots);
        Set<String> areaCodeList = basicDataList.stream()
                .map(TbBasicData::getDeptAreaCode)
                .collect(Collectors.toSet());
        Map<String, SysUser> userMap = sysUserService.lambdaQuery()
                .in(SysUser::getAreaCode, areaCodeList)
                .list()
                .stream()
                .collect(Collectors.toMap(SysUser::getAreaCode, e -> e));
        Set<Long> basicDataIds = basicDataList.stream().map(TbBasicData::getId).collect(Collectors.toSet());
        Map<Long, TbBasicDataField> basicDataFieldMap = tbBasicDataFieldService.lambdaQuery()
                .in(TbBasicDataField::getBasicDataId, basicDataIds).list().stream()
                .collect(Collectors.toMap(TbBasicDataField::getFieldId, e -> e));
        //值
        Set<String> areaCodeList =
                basicDataList.stream().map(TbBasicData::getDeptAreaCode)
                        .collect(Collectors.toSet());
        Map<String, SysUser> userMap =
                sysUserService.lambdaQuery().in(SysUser::getAreaCode, areaCodeList).list().stream()
                        .collect(Collectors.toMap(SysUser::getAreaCode, e -> e));
        Set<Long> basicDataIds =
                basicDataList.stream().map(TbBasicData::getId).collect(Collectors.toSet());
        List<TbBasicDataField> basicDataFieldList = tbBasicDataFieldService
                .lambdaQuery()
                .in(TbBasicDataField::getBasicDataId, basicDataIds)
                .list();
        // 值
        List<Object> result = new ArrayList<>();
        for (TbBasicData tbBasicData : basicDataList) {
            Map<Long, TbBasicDataField> basicDataFieldMap = basicDataFieldList.stream()
                    .filter(item -> tbBasicData.getId().equals(item.getBasicDataId()))
                    .collect(Collectors.toMap(TbBasicDataField::getFieldId, e -> e));
            SysUser user = userMap.get(tbBasicData.getDeptAreaCode());
            List<String> item = new ArrayList<>();
            item.add(Objects.nonNull(user) ? user.getAreaName() : "");
@@ -611,7 +667,11 @@
            item.add(tbBasicData.getCurrentGdp());
            for (TbField tbField : fieldList) {
                TbBasicDataField tbBasicDataField = basicDataFieldMap.get(tbField.getId());
                item.add(Objects.nonNull(tbBasicDataField) ? FieldBuildUtil.formatNumberWithCommas(tbBasicDataField.getFieldValue()) : "");
                item.add(
                        Objects.nonNull(tbBasicDataField)
                                ? FieldBuildUtil.formatNumberWithCommas(
                                tbBasicDataField.getFieldValue())
                                : "");
            }
            item.add(tbBasicData.getRemark());
            result.add(item);
@@ -619,4 +679,161 @@
        vo.setValue(result);
        return vo;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importData(MultipartFile file, String quarter) throws IOException {
        EasyExcel.read(
                        file.getInputStream(),
                        new HistoryDataListener(
                                this,
                                tbFieldService,
                                tbBasicDataFieldService,
                                tbBasicDataConfigService,
                                tbBasicDataConfigDetailService,
                                tbScoreService, sysUserService, quarter))
                .sheet()
                .doRead();
    }
    @Override
    public void exportData(List<String> quarterList) throws Exception {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = "地方财政运行及“三保”情况统计表";
        response.setHeader(
                "Content-disposition",
                "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
        //季度数据,用于反查字段
        List<TbBasicData> tbBasicDataList = this.lambdaQuery()
                .in(TbBasicData::getQuarter, quarterList)
                .eq(TbBasicData::getStatus, ReportingStatusEnum.FILLED)
                .groupBy(TbBasicData::getQuarter).list();
        //符合导出条件的基础数据
        List<TbBasicData> tbBasicDataListAll = this.lambdaQuery()
                .in(TbBasicData::getQuarter, quarterList)
                .eq(TbBasicData::getStatus, ReportingStatusEnum.FILLED)
                .list();
        //基础数据id列表
        Set<Long> basicDataIdList = tbBasicDataListAll.stream().map(TbBasicData::getId)
                .collect(Collectors.toSet());
        //涉及到的部门编码
        Set<String> userAreaCodeList = tbBasicDataListAll.stream().map(TbBasicData::getDeptAreaCode)
                .collect(Collectors.toSet());
        //用户信息map
        Map<String, SysUser> userMap = sysUserService.lambdaQuery()
                .in(SysUser::getAreaCode, userAreaCodeList).list().stream()
                .collect(Collectors.toMap(SysUser::getAreaCode, e -> e));
        //基础数据对应的字段值列表
        List<TbBasicDataField> tbBasicDataFieldList = tbBasicDataFieldService.lambdaQuery()
                .in(TbBasicDataField::getBasicDataId, basicDataIdList)
                .list();
        //构建Excel写对象
        try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
                .registerWriteHandler(new CustomerHandler())
                .registerWriteHandler(EasyExcelUtil.getStyleStrategy()).build()) {
            WriteSheet writeSheet;
            //遍历季度基础数据
            for (TbBasicData tbBasicData : tbBasicDataList) {
                //该季度的动态字段id列表
                Set<Long> fieldIdList = tbBasicDataFieldList.stream()
                        .filter(item -> tbBasicData.getId().equals(item.getBasicDataId()))
                        .map(TbBasicDataField::getFieldId)
                        .collect(Collectors.toSet());
                //字段列表
                List<TbField> fieldList = tbFieldService.lambdaQuery()
                        .in(TbField::getId, fieldIdList)
                        .list();
                //表头
                List<List<String>> head = head(fieldList);
                //过滤基础数据为遍历元素的季度
                List<TbBasicData> list = tbBasicDataListAll.stream()
                        .filter(item -> tbBasicData.getQuarter().equals(item.getQuarter()))
                        .collect(Collectors.toList());
                List<List<Object>> dataList = dataList(fieldList, list, tbBasicDataFieldList,
                        userMap,
                        head);
                // 构建sheet对象
                writeSheet = EasyExcel.writerSheet(tbBasicData.getQuarter()).head(head).build();
                // 写出sheet数据
                excelWriter.write(dataList, writeSheet);
            }
        }
    }
    private List<List<Object>> dataList(List<TbField> fieldList, List<TbBasicData> list,
            List<TbBasicDataField> tbBasicDataFieldList, Map<String, SysUser> userMap,
            List<List<String>> head) {
        //所有数据集合
        List<List<Object>> excellist = new ArrayList<>();
        //构建栏号行
        List<Object> columnNo = Lists.newArrayList("栏号");
        for (int i = 1; i < head.size(); i++) {
            columnNo.add(String.valueOf(i));
        }
        excellist.add(columnNo);
        //动态字段数据行
        for (TbBasicData tbBasicData : list) {
            //转换为map,方便遍历的时候取
            Map<Long, TbBasicDataField> basicDataFieldMap = tbBasicDataFieldList.stream()
                    .filter(item -> tbBasicData.getId().equals(item.getBasicDataId()))
                    .collect(Collectors.toMap(TbBasicDataField::getFieldId, e -> e));
            SysUser sysUser = userMap.get(tbBasicData.getDeptAreaCode());
            if (CollUtils.isEmpty(basicDataFieldMap) || Objects.isNull(sysUser)) {
                continue;
            }
            List<Object> valueList = Lists.newArrayList(sysUser.getAreaName(),
                    tbBasicData.getQuarter());
            TbBasicDataField transferPaymentScale = basicDataFieldMap.get(-1L);
            valueList.add(
                    Objects.nonNull(transferPaymentScale)
                            ? FieldBuildUtil.formatNumberWithCommas(
                            transferPaymentScale.getFieldValue())
                            : "");
            TbBasicDataField currentGdp = basicDataFieldMap.get(-2L);
            valueList.add(
                    Objects.nonNull(currentGdp)
                            ? FieldBuildUtil.formatNumberWithCommas(
                            currentGdp.getFieldValue())
                            : "");
            for (TbField tbField : fieldList) {
                TbBasicDataField tbBasicDataField = basicDataFieldMap.get(tbField.getId());
                valueList.add(
                        Objects.nonNull(tbBasicDataField)
                                ? FieldBuildUtil.formatNumberWithCommas(
                                tbBasicDataField.getFieldValue())
                                : "");
            }
            excellist.add(valueList);
            valueList.add(tbBasicData.getRemark());
        }
        return excellist;
    }
    private List<List<String>> head(List<TbField> list) {
        List<List<String>> headTitles = Lists.newArrayList();
        // 固定字段
        headTitles.add(Lists.newArrayList("地区"));
        headTitles.add(Lists.newArrayList("填报季度"));
        headTitles.add(Lists.newArrayList("转移支付规模"));
        headTitles.add(Lists.newArrayList("当期GDP"));
        list.forEach(
                item -> {
                    String levelOneCategory = item.getLevelOneCategory();
                    String levelTwoCategory = item.getLevelTwoCategory();
                    String levelThreeCategory = item.getLevelThreeCategory();
                    String fieldName = item.getFieldName();
                    headTitles.add(
                            Lists.newArrayList(
                                    levelOneCategory,
                                    StringUtils.isBlank(levelTwoCategory) ? fieldName
                                            : levelTwoCategory,
                                    StringUtils.isBlank(levelThreeCategory) ? fieldName
                                            : levelThreeCategory,
                                    fieldName));
                });
        headTitles.add(Lists.newArrayList("备注"));
        return headTitles;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbFieldServiceImpl.java
@@ -1,22 +1,36 @@
package com.ruoyi.system.service.impl;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.ruoyi.common.basic.PageDTO;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.FieldInputTypeEnum;
import com.ruoyi.common.enums.FieldTypeEnum;
import com.ruoyi.common.enums.ShowStatusEnum;
import com.ruoyi.common.enums.UserTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.BeanUtils;
import com.ruoyi.common.utils.CollUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.EasyExcelUtil;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.TbBasicData;
import com.ruoyi.system.domain.TbBasicDataConfig;
import com.ruoyi.system.domain.TbBasicDataField;
import com.ruoyi.system.domain.TbField;
import com.ruoyi.system.domain.TbFieldCategory;
import com.ruoyi.system.dto.FieldDTO;
import com.ruoyi.system.dto.ShowHideDTO;
import com.ruoyi.system.dto.update.FieldUpdateDTO;
import com.ruoyi.system.handler.CustomerHandler;
import com.ruoyi.system.handler.SelectedSheetWriteHandler;
import com.ruoyi.system.mapper.TbBasicDataMapper;
import com.ruoyi.system.mapper.TbFieldMapper;
import com.ruoyi.system.query.FieldQuery;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.TbBasicDataConfigService;
import com.ruoyi.system.service.TbBasicDataFieldService;
import com.ruoyi.system.service.TbFieldCategoryService;
@@ -25,13 +39,20 @@
import com.ruoyi.system.vo.BasicDataFieldVO;
import com.ruoyi.system.vo.FieldVO;
import com.ruoyi.system.vo.FieldsTreeVO;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
 * <p>
@@ -44,11 +65,15 @@
@Slf4j
@Service
@RequiredArgsConstructor
public class TbFieldServiceImpl extends ServiceImpl<TbFieldMapper, TbField> implements TbFieldService {
public class TbFieldServiceImpl extends ServiceImpl<TbFieldMapper, TbField> implements
        TbFieldService {
    private final TbFieldCategoryService tbFieldCategoryService;
    private final TbBasicDataConfigService tbBasicDataConfigService;
    private final TbBasicDataMapper tbBasicDataMapper;
    private final TbBasicDataFieldService tbBasicDataFieldService;
    private final HttpServletResponse response;
    private final ISysUserService sysUserService;
    @Override
    public void add(FieldDTO dto) {
@@ -58,7 +83,8 @@
        if (FieldTypeEnum.TEXT.equals(fieldType)) {
            if (StringUtils.isNull(dto.getTextInputType())) {
                throw new ServiceException("输入类型不能为空");
            } else if (FieldInputTypeEnum.FIXED_CONTENT.equals(dto.getTextInputType()) && StringUtils.isBlank(dto.getTextContent())) {
            } else if (FieldInputTypeEnum.FIXED_CONTENT.equals(dto.getTextInputType())
                    && StringUtils.isBlank(dto.getTextContent())) {
                throw new ServiceException("内容设置不能为空");
            }
        }
@@ -70,7 +96,8 @@
            tbField.setLevelTwoCategory(category2.getFieldCategoryName());
        }
        if (StringUtils.isNotNull(dto.getLevelThreeCategoryId())) {
            TbFieldCategory category3 = tbFieldCategoryService.getById(dto.getLevelThreeCategoryId());
            TbFieldCategory category3 = tbFieldCategoryService.getById(
                    dto.getLevelThreeCategoryId());
            tbField.setLevelThreeCategory(category3.getFieldCategoryName());
        }
        this.save(tbField);
@@ -78,19 +105,22 @@
    @Override
    public void showHide(ShowHideDTO dto) {
        log.info("======主线程执行showHide{}",Thread.currentThread().getName() );
        log.info("======主线程执行showHide{}", Thread.currentThread().getName());
        TbField field = this.getById(dto.getId());
        if (StringUtils.isNull(field)) {
            throw new ServiceException("非法参数");
        }
        //隐藏字段
        this.lambdaUpdate().set(TbField::getStatus, dto.getStatus()).eq(TbField::getId, dto.getId()).update();
        this.lambdaUpdate().set(TbField::getStatus, dto.getStatus()).eq(TbField::getId, dto.getId())
                .update();
        //异步隐藏基础数据配置
        CompletableFuture.runAsync(() -> handleDataConfig(dto, field));
    }
    private void handleDataConfig(ShowHideDTO dto, TbField field) {
        log.info("======子线程执行handleDataConfig{}",Thread.currentThread().getName() );
        List<TbBasicDataConfig> list = tbBasicDataConfigService.lambdaQuery().eq(TbBasicDataConfig::getStatus, ShowStatusEnum.SHOW.getCode()).list();
        log.info("======子线程执行handleDataConfig{}", Thread.currentThread().getName());
        List<TbBasicDataConfig> list = tbBasicDataConfigService.lambdaQuery()
                .eq(TbBasicDataConfig::getStatus, ShowStatusEnum.SHOW.getCode()).list();
        if (CollUtils.isNotEmpty(list)) {
            List<Long> ids = list.stream().map(config -> {
                String fieldIdStr = config.getFieldIdStr();
@@ -102,19 +132,26 @@
                }
                return null;
            }).collect(Collectors.toList());
            tbBasicDataConfigService.lambdaUpdate().set(TbBasicDataConfig::getStatus, dto.getStatus()).in(TbBasicDataConfig::getId, ids).update();
            tbBasicDataConfigService.lambdaUpdate()
                    .set(TbBasicDataConfig::getStatus, dto.getStatus())
                    .in(TbBasicDataConfig::getId, ids).update();
        }
    }
    @Override
    public PageDTO<FieldVO> queryPage(FieldQuery query) {
        Page<TbField> page = this.lambdaQuery()
                .like(StringUtils.isNotEmpty(query.getFieldName()), TbField::getFieldName, query.getFieldName())
                .like(StringUtils.isNotEmpty(query.getLevelOneCategory()), TbField::getLevelOneCategory, query.getLevelOneCategory())
                .like(StringUtils.isNotEmpty(query.getLevelTwoCategory()), TbField::getLevelTwoCategory, query.getLevelTwoCategory())
                .like(StringUtils.isNotEmpty(query.getLevelThreeCategory()), TbField::getLevelThreeCategory, query.getLevelThreeCategory())
                .like(StringUtils.isNotEmpty(query.getFieldName()), TbField::getFieldName,
                        query.getFieldName())
                .like(StringUtils.isNotEmpty(query.getLevelOneCategory()),
                        TbField::getLevelOneCategory, query.getLevelOneCategory())
                .like(StringUtils.isNotEmpty(query.getLevelTwoCategory()),
                        TbField::getLevelTwoCategory, query.getLevelTwoCategory())
                .like(StringUtils.isNotEmpty(query.getLevelThreeCategory()),
                        TbField::getLevelThreeCategory, query.getLevelThreeCategory())
                .eq(StringUtils.isNotNull(query.getStatus()), TbField::getStatus, query.getStatus())
                .eq(StringUtils.isNotNull(query.getFieldType()), TbField::getFieldType, query.getFieldType())
                .eq(StringUtils.isNotNull(query.getFieldType()), TbField::getFieldType,
                        query.getFieldType())
                .orderByDesc(TbField::getCreateTime)
                .page(new Page<>(query.getPageNum(), query.getPageSize()));
        if (CollUtils.isEmpty(page.getRecords())) {
@@ -125,7 +162,8 @@
    @Override
    public String influencedData(Long id) {
        List<TbBasicDataConfig> list = tbBasicDataConfigService.lambdaQuery().eq(TbBasicDataConfig::getStatus, ShowStatusEnum.SHOW).list();
        List<TbBasicDataConfig> list = tbBasicDataConfigService.lambdaQuery()
                .eq(TbBasicDataConfig::getStatus, ShowStatusEnum.SHOW).list();
        if (CollUtils.isEmpty(list)) {
            return "";
        }
@@ -164,29 +202,35 @@
        }
        BasicDataFieldVO vo = BeanUtils.copyBean(basicData, BasicDataFieldVO.class);
        // 查询动态字段
        List<TbBasicDataField> basicDataFields = tbBasicDataFieldService.lambdaQuery().eq(TbBasicDataField::getBasicDataId, basicData.getId()).list();
        List<TbBasicDataField> basicDataFields = tbBasicDataFieldService.lambdaQuery()
                .eq(TbBasicDataField::getBasicDataId, basicData.getId()).list();
        // 获取所有字段ID
        Set<Long> fieldIds = basicDataFields.stream().map(TbBasicDataField::getFieldId).collect(Collectors.toSet());
        Set<Long> fieldIds = basicDataFields.stream().map(TbBasicDataField::getFieldId)
                .collect(Collectors.toSet());
        // 根据字段ID查询字段信息并构建字段ID到字段对象的映射
        Map<Long, TbField> fieldMap = this.lambdaQuery().in(!fieldIds.isEmpty(), TbField::getId, fieldIds).list().stream().collect(Collectors.toMap(TbField::getId, e -> e));
        Map<Long, TbField> fieldMap = this.lambdaQuery()
                .in(!fieldIds.isEmpty(), TbField::getId, fieldIds).list().stream()
                .collect(Collectors.toMap(TbField::getId, e -> e));
        // 根节点
        List<FieldsTreeVO> root = new ArrayList<>();
        basicDataFields.stream().filter(item -> item.getFieldId()==-1).findFirst().ifPresent(item ->{
            FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
            fieldsTreeVO.setId(item.getFieldId());
            fieldsTreeVO.setName("转移支付规模");
            fieldsTreeVO.setValue(item.getFieldValue());
            fieldsTreeVO.setCategory(Boolean.FALSE);
            root.add(fieldsTreeVO);
        });
        basicDataFields.stream().filter(item -> item.getFieldId()==-2).findFirst().ifPresent(item ->{
            FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
            fieldsTreeVO.setId(item.getFieldId());
            fieldsTreeVO.setName("当期GDP");
            fieldsTreeVO.setValue(item.getFieldValue());
            fieldsTreeVO.setCategory(Boolean.FALSE);
            root.add(fieldsTreeVO);
        });
        basicDataFields.stream().filter(item -> item.getFieldId() == -1).findFirst()
                .ifPresent(item -> {
                    FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
                    fieldsTreeVO.setId(item.getFieldId());
                    fieldsTreeVO.setName("转移支付规模");
                    fieldsTreeVO.setValue(item.getFieldValue());
                    fieldsTreeVO.setCategory(Boolean.FALSE);
                    root.add(fieldsTreeVO);
                });
        basicDataFields.stream().filter(item -> item.getFieldId() == -2).findFirst()
                .ifPresent(item -> {
                    FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
                    fieldsTreeVO.setId(item.getFieldId());
                    fieldsTreeVO.setName("当期GDP");
                    fieldsTreeVO.setValue(item.getFieldValue());
                    fieldsTreeVO.setCategory(Boolean.FALSE);
                    root.add(fieldsTreeVO);
                });
        FieldBuildUtil.buildTreeStructure(basicDataFields, fieldMap, root);
        FieldsTreeVO fieldsTreeVO = new FieldsTreeVO();
        fieldsTreeVO.setId(-3L);
@@ -197,4 +241,113 @@
        vo.setFields(root);
        return vo;
    }
    @Override
    public void downloadImportTemplate() throws Exception {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = "地方财政运行及“三保”情况统计表";
        response.setHeader(
                "Content-disposition",
                "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
        SysUser user = SecurityUtils.getLoginUser().getUser();
        // 查询需要填写的动态字段
        List<TbField> list =
                this.lambdaQuery().eq(TbField::getStatus, ShowStatusEnum.SHOW).list();
        List<List<String>> head = head(list);
        List<TbField> collect =
                list.stream()
                        .filter(item -> FieldTypeEnum.TEXT.equals(item.getFieldType()))
                        .filter(item -> FieldInputTypeEnum.FIXED_CONTENT.equals(
                                item.getTextInputType()))
                        .collect(Collectors.toList());
        Map<Integer, String[]> selectedMap = new HashMap<>();
        if (CollUtils.isNotEmpty(collect)) {
            selectedMap = new HashMap<>();
            for (TbField tbField : collect) {
                int outerListIndex = getOuterListIndex(head, tbField.getFieldName());
                String[] selectStr = tbField.getTextContent().split(",");
                selectedMap.put(outerListIndex, selectStr);
            }
        }
        boolean isPlatform = UserTypeEnum.PLATFORM.equals(user.getUserType());
        //默认生成下拉框的行数为1
        int rows = 1;
        if (isPlatform) {
            //查询所有的地区
            List<SysUser> userList = sysUserService.lambdaQuery()
                    .eq(SysUser::getUserType, UserTypeEnum.DEPARTMENT).list();
            String[] userNameArr = userList.stream().map(SysUser::getAreaName)
                    .toArray(String[]::new);
            selectedMap.put(0, userNameArr);
            //生成下拉框的行数为部门的数量
            rows = userList.size();
        }
        // 这里需要设置不关闭流
        EasyExcel.write(response.getOutputStream())
                .head(head)
                .autoCloseStream(Boolean.TRUE)
                .sheet("模板")
                .registerWriteHandler(new SelectedSheetWriteHandler(selectedMap, rows))
                .registerWriteHandler(new CustomerHandler())
                .registerWriteHandler(EasyExcelUtil.getStyleStrategy())
                .doWrite(dataList(list, user));
    }
    /**
     * 根据字段名获取该字段下标
     *
     * @param list  表头
     * @param value 字段名
     * @return 下标
     */
    public int getOuterListIndex(List<List<String>> list, String value) {
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).contains(value)) {
                return i;
            }
        }
        return -1; // 返回-1表示未找到
    }
    private List<List<Object>> dataList(List<TbField> list, SysUser user) throws Exception {
        String areaName = "";
        boolean isDept = UserTypeEnum.DEPARTMENT.equals(user.getUserType());
        areaName = isDept ? user.getAreaName() : areaName;
        List<List<Object>> excellist = new ArrayList<>();
        List<List<String>> head = head(list);
        List<Object> columnNo = Lists.newArrayList("栏号");
        for (int i = 1; i < head.size(); i++) {
            columnNo.add(String.valueOf(i));
        }
        excellist.add(columnNo);
        excellist.add(Lists.newArrayList(areaName, isDept ? DateUtils.getNowQuarter() : ""));
        return excellist;
    }
    private List<List<String>> head(List<TbField> list) {
        List<List<String>> headTitles = Lists.newArrayList();
        // 固定字段
        headTitles.add(Lists.newArrayList("地区"));
        headTitles.add(Lists.newArrayList("填报季度"));
        headTitles.add(Lists.newArrayList("转移支付规模"));
        headTitles.add(Lists.newArrayList("当期GDP"));
        list.forEach(
                item -> {
                    String levelOneCategory = item.getLevelOneCategory();
                    String levelTwoCategory = item.getLevelTwoCategory();
                    String levelThreeCategory = item.getLevelThreeCategory();
                    String fieldName = item.getFieldName();
                    headTitles.add(
                            Lists.newArrayList(
                                    levelOneCategory,
                                    StringUtils.isBlank(levelTwoCategory) ? fieldName
                                            : levelTwoCategory,
                                    StringUtils.isBlank(levelThreeCategory) ? fieldName
                                            : levelThreeCategory,
                                    fieldName));
                });
        headTitles.add(Lists.newArrayList("备注"));
        return headTitles;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbQuestionServiceImpl.java
@@ -24,7 +24,8 @@
 * @since 2024-03-13
 */
@Service
public class TbQuestionServiceImpl extends ServiceImpl<TbQuestionMapper, TbQuestion> implements TbQuestionService {
public class TbQuestionServiceImpl extends ServiceImpl<TbQuestionMapper, TbQuestion> implements
        TbQuestionService {
    @Override
    public void addQuestion(QuestionDTO dto) throws Exception {
@@ -42,6 +43,8 @@
    @Override
    public PageDTO<QuestionVO> pageQuestion(QuestionQuery dto) {
        Page<TbQuestion> page = this.lambdaQuery()
                .eq(StringUtils.isNotBlank(dto.getQuarter()), TbQuestion::getQuarter,
                        dto.getQuarter())
                .like(StringUtils.isNotBlank(dto.getTitle()), TbQuestion::getTitle, dto.getTitle())
                .page(new Page<>(dto.getPageNum(), dto.getPageSize()));
        return PageDTO.of(page, QuestionVO.class);
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -1,366 +1,502 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.SysUserMapper">
    <resultMap type="SysUser" id="SysUserResult">
        <id     property="userId"       column="user_id"      />
        <result property="deptId"       column="dept_id"      />
        <result property="userName"     column="user_name"    />
        <result property="nickName"     column="nick_name"    />
        <result property="email"        column="email"        />
        <result property="phoneNumber"  column="phone_number"  />
        <result property="sex"          column="sex"          />
        <result property="avatar"       column="avatar"       />
        <result property="password"     column="password"     />
        <result property="status"       column="status"       />
        <result property="delFlag"      column="del_flag"     />
        <result property="loginIp"      column="login_ip"     />
        <result property="loginDate"    column="login_date"   />
        <result property="createBy"     column="create_by"    />
        <result property="createTime"   column="create_time"  />
        <result property="updateBy"     column="update_by"    />
        <result property="updateTime"   column="update_time"  />
        <result property="remark"       column="remark"       />
        <result property="ifBlack"       column="ifBlack"       />
        <result property="areaName"     column="area_name" />
        <result property="areaAlias"     column="area_alias" />
        <result property="areaCode"     column="area_code" />
        <result property="areaLevel"     column="area_level" />
        <result property="countyFlag"     column="county_flag" />
        <result property="personInCharge"     column="person_in_charge" />
        <result property="focussed"     column="focussed" />
        <association property="dept"    javaType="SysDept"         resultMap="deptResult" />
        <collection  property="roles"   javaType="java.util.List"  resultMap="RoleResult" />
    </resultMap>
    <resultMap id="deptResult" type="SysDept">
        <id     property="deptId"    column="dept_id"     />
        <result property="parentId"  column="parent_id"   />
        <result property="deptName"  column="dept_name"   />
        <result property="ancestors" column="ancestors"   />
        <result property="orderNum"  column="order_num"   />
        <result property="leader"    column="leader"      />
        <result property="status"    column="dept_status" />
    </resultMap>
    <resultMap id="RoleResult" type="SysRole">
        <id     property="roleId"       column="role_id"        />
        <result property="roleName"     column="role_name"      />
        <result property="roleKey"      column="role_key"       />
        <result property="roleSort"     column="role_sort"      />
        <result property="dataScope"    column="data_scope"     />
        <result property="status"       column="role_status"    />
    </resultMap>
    <sql id="selectUserVo">
        select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phone_number, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
        d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
        r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status,u.area_name,u.area_alias,u.area_code,
               u.area_level,u.county_flag,u.person_in_charge,u.focussed
        from sys_user u
            left join sys_dept d on u.dept_id = d.dept_id
            left join sys_user_role ur on u.user_id = ur.user_id
            left join sys_role r on r.role_id = ur.role_id
    </sql>
    <sql id="selectDeptUserVo">
        select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phone_number, u.password, u.sex, u.status,
               u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,u.area_name,u.area_alias,u.area_code,
               u.area_level,u.county_flag,u.person_in_charge,u.focussed
        from sys_user u
    </sql>
    <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
        select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phone_number, u.sex, u.status, u.del_flag, u.login_ip, u.login_date,
               u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
        left join sys_dept d on u.dept_id = d.dept_id
        where u.del_flag = '0'
        <if test="userId != null and userId != 0">
            AND u.user_id = #{userId}
        </if>
        <if test="userName != null and userName != ''">
            AND u.user_name like concat('%', #{userName}, '%')
        </if>
        <if test="status != null and status != ''">
            AND u.status = #{status}
        </if>
        <if test="phoneNumber != null and phoneNumber != ''">
            AND u.phone_number like concat('%', #{phoneNumber}, '%')
        </if>
        <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
            AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
        </if>
        <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
            AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
        </if>
        <if test="deptId != null and deptId != 0">
            AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))
        </if>
        <!-- 数据范围过滤 -->
        ${params.dataScope}
    </select>
    <select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
        select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phone_number, u.status, u.create_time
        from sys_user u
             left join sys_dept d on u.dept_id = d.dept_id
             left join sys_user_role ur on u.user_id = ur.user_id
             left join sys_role r on r.role_id = ur.role_id
        where u.del_flag = '0' and r.role_id = #{roleId}
        <if test="userName != null and userName != ''">
            AND u.user_name like concat('%', #{userName}, '%')
        </if>
        <if test="phoneNumber != null and phoneNumber != ''">
            AND u.phone_number like concat('%', #{phoneNumber}, '%')
        </if>
        <!-- 数据范围过滤 -->
        ${params.dataScope}
    </select>
    <select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult">
        select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phone_number, u.status, u.create_time
        from sys_user u
             left join sys_dept d on u.dept_id = d.dept_id
             left join sys_user_role ur on u.user_id = ur.user_id
             left join sys_role r on r.role_id = ur.role_id
        where u.del_flag = '0' and (r.role_id != #{roleId} or r.role_id IS NULL)
        and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and ur.role_id = #{roleId})
        <if test="userName != null and userName != ''">
            AND u.user_name like concat('%', #{userName}, '%')
        </if>
        <if test="phoneNumber != null and phoneNumber != ''">
            AND u.phone_number like concat('%', #{phoneNumber}, '%')
        </if>
        <!-- 数据范围过滤 -->
        ${params.dataScope}
    </select>
    <select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
        <include refid="selectUserVo"/>
        where u.user_name = #{userName} and u.del_flag = '0'
    </select>
    <select id="selectUserById" parameterType="Long" resultType="com.ruoyi.common.core.domain.entity.SysUser">
        select u.user_id AS userId, u.dept_id AS deptId, u.user_name AS userName, u.nick_name AS nickName, u.email AS email, u.avatar AS avatar,
               u.phone_number AS phoneNumber, u.sex AS sex, u.status AS status, u.del_flag AS delFlag, u.login_ip AS loginIp,
               u.login_date AS loginDate, u.create_by AS createBy, u.create_time AS createTime, u.remark AS remark,/*u.ifBlack AS ifBlack,u.districtId AS districtId,*/
               ur.role_id AS roleId,sr.role_name AS roleName,u.deptName as deptName
        from sys_user u
        left join sys_user_role ur on u.user_id = ur.user_id
        left join sys_role sr on ur.role_id = sr.role_id
        left join sys_dept sd on u.dept_id = sd.dept_id
        where u.user_id = #{userId} and u.del_flag = 0 group by u.user_id
    </select>
    <select id="checkUserNameUnique" parameterType="String" resultMap="SysUserResult">
        select user_id, user_name from sys_user where user_name = #{userName} and del_flag = '0' limit 1
    </select>
    <select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult">
        select user_id, phoneNumber from sys_user where phone_number = #{phoneNumber} and del_flag = '0' limit 1
    </select>
    <select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult">
        select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1
    </select>
    <select id="selectUserByIds" resultType="com.ruoyi.common.core.domain.entity.SysUser">
        select user_id AS userId, dept_id AS deptId, user_name AS userName, nick_name AS nickName, email AS email, avatar AS avatar, phone_number AS phoneNumber
        from sys_user where user_id in
        <foreach collection="userIds" separator="," item="userId" open="(" close=")">
            #{userId}
        </foreach>
    </select>
    <select id="queryList" resultType="com.ruoyi.common.core.domain.entity.SysUser">
        select u.user_id AS userId, u.dept_id AS deptId, u.user_name AS userName, u.nick_name AS nickName, u.email AS email, u.avatar AS avatar,
               u.phone_number AS phoneNumber, u.sex AS sex, u.status AS status, u.del_flag AS delFlag, u.login_ip AS loginIp,
               u.login_date AS loginDate, u.create_by AS createBy, u.create_time AS createTime, u.remark AS remark
        from sys_user u
        WHERE u.del_flag = 0
    </select>
    <select id="selectCount" resultType="java.lang.Integer">
        select  count(*) from sys_user
        <where>
            <if test="status != null">
                AND status = #{status}
            </if>
            AND del_flag = 0
        </where>
    </select>
    <select id="selectListByNamePhone" resultType="com.ruoyi.common.core.domain.entity.SysUser">
        select u.user_id AS userId, u.dept_id AS deptId, u.user_name AS userName, u.nick_name AS nickName, u.email AS email, u.avatar AS avatar,
        u.phone_number AS phoneNumber, u.sex AS sex, u.status AS status, u.del_flag AS delFlag, u.login_ip AS loginIp,
        u.login_date AS loginDate, u.create_by AS createBy, u.create_time AS createTime, u.remark AS remark,/*u.ifBlack AS ifBlack,u.districtId AS districtId*/
        from sys_user u
        WHERE u.del_flag = 0
        <if test="name != null and name != ''">
            AND (u.nick_name LIKE concat('%',#{name},'%')
            OR u.phone_number LIKE concat('%',#{name},'%'))
        </if>
    </select>
    <select id="selectUserByUserNameList" resultType="com.ruoyi.common.core.domain.entity.SysUser">
        select u.user_id AS userId, u.dept_id AS deptId, u.user_name AS userName, u.nick_name AS nickName, u.email AS email, u.avatar AS avatar,
               u.phone_number AS phoneNumber
        from sys_user u
        WHERE u.del_flag = 0
        <if test="names != null and names.size()>0">
            AND u.nick_name IN
            <foreach collection="names" close=")" open="(" item="name" separator=",">
                #{name}
            </foreach>
        </if>
    </select>
    <select id="userInfo" resultType="com.ruoyi.system.vo.UserInfoVo">
        select t1.*,t2.companyName,t2.companyType ,tq.qrcodeLink from sys_user t1
        left join t_company t2 on t2.id = t1.companyId
        left join t_qrcode tq on t1.user_id = tq.otherId and tq.type=1
        where t1.user_id = #{id}
    </select>
    <select id="selectByPhone" resultType="com.ruoyi.common.core.domain.entity.SysUser">
        select u.user_id AS userId, u.dept_id AS deptId, u.user_name AS userName, u.nick_name AS nickName, u.email AS email, u.avatar AS avatar,
               u.phone_number AS phoneNumber, u.sex AS sex, u.status AS status, u.del_flag AS delFlag, u.login_ip AS loginIp,
               u.login_date AS loginDate, u.create_by AS createBy, u.create_time AS createTime, u.remark AS remark
        from sys_user u where u.phone_number = #{phoneNumber} and u.status = 0 and u.del_flag = 0
    </select>
    <select id="getUserInfoBy" resultType="com.ruoyi.system.vo.UserInfoVo">
        select t1.*,t2.companyName,t2.companyType from sys_user t1
        left join t_company t2 on t2.id = t1.companyId
        where t1.singleNum = #{singleNum}
    </select>
    <select id="getUserRole" resultType="java.lang.Long">
        select role_id from sys_user_role where sys_user_role.user_id = #{userId}
    </select>
    <select id="selectAllList" resultType="com.ruoyi.common.core.domain.entity.SysUser">
        select * from sys_user
    </select>
    <select id="pageList" resultType="com.ruoyi.system.vo.SysUserVO">
        select u.user_id AS userId, u.dept_id AS deptId, u.user_name AS userName, u.nick_name AS nickName, u.email AS email, u.avatar AS avatar,
               u.phone_number AS phoneNumber, u.sex AS sex, u.status AS status, u.del_flag AS delFlag, u.login_ip AS loginIp,
               u.login_date AS loginDate, u.create_by AS createBy, u.create_time AS createTime, u.remark AS remark,/*u.ifBlack AS ifBlack, u.districtId AS districtId,*/
               r.role_id AS roleId, r.role_name AS roleName, r.role_key AS roleKey, r.role_sort AS roleSort, r.data_scope AS dataScope, r.status as role_status,u.deptName as deptName
        from sys_user u
        left join sys_user_role ur on u.user_id = ur.user_id
        left join sys_role r on r.role_id = ur.role_id
        WHERE u.del_flag = 0
        <if test="query.nickName != null and query.nickName != ''">
            AND u.nick_name LIKE concat('%',#{query.nickName},'%')
        </if>
        <if test="query.roleId != null">
            AND r.role_id = #{query.roleId}
        </if>
        <if test="query.phoneNumber != null and query.phoneNumber != ''">
            AND u.phone_number LIKE concat('%',#{query.phoneNumber},'%')
        </if>
        <if test="query.status != null and query.status != ''">
            AND u.status = #{query.status}
        </if>
        ORDER BY u.create_time DESC
    </select>
    <select id="selectIdByPhone" resultType="java.lang.Long">
        select user_id from sys_user where phone_number = #{phoneNumber} and status = 0 and del_flag = 0
    </select>
    <select id="selectDeptUserByUserName" resultType="com.ruoyi.common.core.domain.entity.SysUser"
            parameterType="java.lang.String">
        <include refid="selectUserVo"/>
        where u.user_name = #{userName} and u.del_flag = '0' and u.user_type = '2'
    </select>
    <select id="selectPlatUserByUserName" resultType="com.ruoyi.common.core.domain.entity.SysUser"
            parameterType="java.lang.String">
        <include refid="selectUserVo"/>
        where u.user_name = #{userName} and u.del_flag = '0' and u.user_type = '1'
    </select>
  <delete id="deleteUserById" parameterType="Long">
    update sys_user
    set del_flag = '2'
    where user_id = #{userId}
  </delete>
    <insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
         insert into sys_user(
             <if test="userId != null and userId != 0">user_id,</if>
             <if test="deptId != null and deptId != 0">dept_id,</if>
             <if test="userName != null and userName != ''">user_name,</if>
             <if test="deptName != null and deptName != ''">deptName,</if>
             <if test="nickName != null and nickName != ''">nick_name,</if>
             <if test="email != null and email != ''">email,</if>
             <if test="avatar != null and avatar != ''">avatar,</if>
             <if test="phoneNumber != null and phoneNumber != ''">phone_number,</if>
             <if test="sex != null and sex != ''">sex,</if>
             <if test="password != null and password != ''">password,</if>
             <if test="status != null and status != ''">status,</if>
             <if test="createBy != null and createBy != ''">create_by,</if>
             <if test="remark != null and remark != ''">remark,</if>
<!--             <if test="ifBlack != null">ifBlack,</if>-->
<!--             <if test="districtId != null">districtId,</if>-->
             create_time
         )values(
             <if test="userId != null and userId != ''">#{userId},</if>
             <if test="deptId != null and deptId != ''">#{deptId},</if>
             <if test="userName != null and userName != ''">#{userName},</if>
        <if test="deptName != null and deptName != ''">#{deptName},</if>
  <delete id="deleteUserByIds" parameterType="Long">
    update sys_user set del_flag = '2' where user_id in
    <foreach close=")" collection="ids" item="userId" open="(" separator=",">
      #{userId}
    </foreach>
  </delete>
        <if test="nickName != null and nickName != ''">#{nickName},</if>
             <if test="email != null and email != ''">#{email},</if>
             <if test="avatar != null and avatar != ''">#{avatar},</if>
             <if test="phoneNumber != null and phoneNumber != ''">#{phone_number},</if>
        <if test="sex != null and sex != ''">#{sex},</if>
             <if test="password != null and password != ''">#{password},</if>
             <if test="status != null and status != ''">#{status},</if>
             <if test="createBy != null and createBy != ''">#{createBy},</if>
             <if test="remark != null and remark != ''">#{remark},</if>
<!--            <if test="ifBlack != null">#{ifBlack},</if>-->
<!--            <if test="districtId != null">#{districtId},</if>-->
             sysdate()
         )
    </insert>
    <update id="updateUser" parameterType="SysUser">
         update sys_user
         <set>
             <if test="deptId != null and deptId != 0">dept_id = #{deptId},</if>
             <if test="userName != null and userName != ''">user_name = #{userName},</if>
             <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
             <if test="deptName != null and deptName != ''">deptName = #{deptName},</if>
             <if test="email != null ">email = #{email},</if>
             <if test="phoneNumber != null ">phone_number = #{phoneNumber},</if>
             <if test="sex != null and sex != ''">sex = #{sex},</if>
             <if test="avatar != null and avatar != ''">avatar = #{avatar},</if>
             <if test="password != null and password != ''">password = #{password},</if>
             <if test="status != null and status != ''">status = #{status},</if>
             <if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if>
             <if test="loginDate != null">login_date = #{loginDate},</if>
             <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
             <if test="remark != null">remark = #{remark},</if>
             update_time = sysdate()
         </set>
         where user_id = #{userId}
    </update>
    <update id="updateUserStatus" parameterType="SysUser">
         update sys_user set status = #{status} where user_id = #{userId}
    </update>
    <update id="updateUserAvatar" parameterType="SysUser">
         update sys_user set avatar = #{avatar} where user_name = #{userName}
    </update>
    <update id="resetUserPwd" parameterType="SysUser">
         update sys_user set password = #{password} where user_name = #{userName}
    </update>
    <update id="updateUserIfBlack">
        update sys_user set ifBlack = 0,safetyPoints = 12,update_time = sysdate()
        where user_id IN
        <foreach collection="ids" separator="," item="userId" open="(" close=")">
            #{userId}
        </foreach>
    </update>
    <update id="updatePassword">
        update sys_user set password = #{s} where user_id = #{id}
    </update>
  <insert id="insertUser" keyProperty="userId" parameterType="SysUser" useGeneratedKeys="true">
    insert into sys_user(
    <if test="userId != null and userId != 0">user_id,</if>
    <if test="deptId != null and deptId != 0">dept_id,</if>
    <if test="userName != null and userName != ''">user_name,</if>
    <if test="deptName != null and deptName != ''">deptName,</if>
    <if test="nickName != null and nickName != ''">nick_name,</if>
    <if test="email != null and email != ''">email,</if>
    <if test="avatar != null and avatar != ''">avatar,</if>
    <if test="phoneNumber != null and phoneNumber != ''">phone_number,</if>
    <if test="sex != null and sex != ''">sex,</if>
    <if test="password != null and password != ''">password,</if>
    <if test="status != null and status != ''">status,</if>
    <if test="createBy != null and createBy != ''">create_by,</if>
    <if test="remark != null and remark != ''">remark,</if>
    <!--             <if test="ifBlack != null">ifBlack,</if>-->
    <!--             <if test="districtId != null">districtId,</if>-->
    create_time
    )values(
    <if test="userId != null and userId != ''">#{userId},</if>
    <if test="deptId != null and deptId != ''">#{deptId},</if>
    <if test="userName != null and userName != ''">#{userName},</if>
    <if test="deptName != null and deptName != ''">#{deptName},</if>
    <delete id="deleteUserById" parameterType="Long">
         update sys_user set del_flag = '2' where user_id = #{userId}
     </delete>
     <delete id="deleteUserByIds" parameterType="Long">
         update sys_user set del_flag = '2' where user_id in
         <foreach collection="ids" item="userId" open="(" separator="," close=")">
             #{userId}
        </foreach>
     </delete>
    <if test="nickName != null and nickName != ''">#{nickName},</if>
    <if test="email != null and email != ''">#{email},</if>
    <if test="avatar != null and avatar != ''">#{avatar},</if>
    <if test="phoneNumber != null and phoneNumber != ''">#{phone_number},</if>
    <if test="sex != null and sex != ''">#{sex},</if>
    <if test="password != null and password != ''">#{password},</if>
    <if test="status != null and status != ''">#{status},</if>
    <if test="createBy != null and createBy != ''">#{createBy},</if>
    <if test="remark != null and remark != ''">#{remark},</if>
    <!--            <if test="ifBlack != null">#{ifBlack},</if>-->
    <!--            <if test="districtId != null">#{districtId},</if>-->
    sysdate()
    )
  </insert>
  <resultMap id="SysUserResult" type="SysUser">
    <association javaType="SysDept" property="dept" resultMap="deptResult"/>
    <collection javaType="java.util.List" property="roles" resultMap="RoleResult"/>
    <id column="user_id" property="userId"/>
    <result column="dept_id" property="deptId"/>
    <result column="user_name" property="userName"/>
    <result column="nick_name" property="nickName"/>
    <result column="user_type" property="userType"/>
    <result column="email" property="email"/>
    <result column="phone_number" property="phoneNumber"/>
    <result column="sex" property="sex"/>
    <result column="avatar" property="avatar"/>
    <result column="password" property="password"/>
    <result column="status" property="status"/>
    <result column="del_flag" property="delFlag"/>
    <result column="login_ip" property="loginIp"/>
    <result column="login_date" property="loginDate"/>
    <result column="create_by" property="createBy"/>
    <result column="create_time" property="createTime"/>
    <result column="update_by" property="updateBy"/>
    <result column="update_time" property="updateTime"/>
    <result column="remark" property="remark"/>
    <result column="area_name" property="areaName"/>
    <result column="area_alias" property="areaAlias"/>
    <result column="area_code" property="areaCode"/>
    <result column="area_level" property="areaLevel"/>
    <result column="county_flag" property="countyFlag"/>
    <result column="person_in_charge" property="personInCharge"/>
    <result column="focussed" property="focussed"/>
  </resultMap>
  <resultMap id="deptResult" type="SysDept">
    <id column="dept_id" property="deptId"/>
    <result column="parent_id" property="parentId"/>
    <result column="dept_name" property="deptName"/>
    <result column="ancestors" property="ancestors"/>
    <result column="order_num" property="orderNum"/>
    <result column="leader" property="leader"/>
    <result column="dept_status" property="status"/>
  </resultMap>
  <resultMap id="RoleResult" type="SysRole">
    <id column="role_id" property="roleId"/>
    <result column="role_name" property="roleName"/>
    <result column="role_key" property="roleKey"/>
    <result column="role_sort" property="roleSort"/>
    <result column="data_scope" property="dataScope"/>
    <result column="role_status" property="status"/>
  </resultMap>
  <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
    select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phone_number, u.sex,
    u.status, u.del_flag, u.login_ip, u.login_date,
    u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
    left join sys_dept d on u.dept_id = d.dept_id
    where u.del_flag = '0'
    <if test="userId != null and userId != 0">
      AND u.user_id = #{userId}
    </if>
    <if test="userName != null and userName != ''">
      AND u.user_name like concat('%', #{userName}, '%')
    </if>
    <if test="status != null and status != ''">
      AND u.status = #{status}
    </if>
    <if test="phoneNumber != null and phoneNumber != ''">
      AND u.phone_number like concat('%', #{phoneNumber}, '%')
    </if>
    <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
      AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
    </if>
    <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
      AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
    </if>
    <if test="deptId != null and deptId != 0">
      AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE
      find_in_set(#{deptId}, ancestors) ))
    </if>
    <!-- 数据范围过滤 -->
    ${params.dataScope}
  </select>
  <select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phone_number,
    u.status, u.create_time
    from sys_user u
    left join sys_dept d on u.dept_id = d.dept_id
    left join sys_user_role ur on u.user_id = ur.user_id
    left join sys_role r on r.role_id = ur.role_id
    where u.del_flag = '0' and r.role_id = #{roleId}
    <if test="userName != null and userName != ''">
      AND u.user_name like concat('%', #{userName}, '%')
    </if>
    <if test="phoneNumber != null and phoneNumber != ''">
      AND u.phone_number like concat('%', #{phoneNumber}, '%')
    </if>
    <!-- 数据范围过滤 -->
    ${params.dataScope}
  </select>
  <select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult">
    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phone_number,
    u.status, u.create_time
    from sys_user u
    left join sys_dept d on u.dept_id = d.dept_id
    left join sys_user_role ur on u.user_id = ur.user_id
    left join sys_role r on r.role_id = ur.role_id
    where u.del_flag = '0' and (r.role_id != #{roleId} or r.role_id IS NULL)
    and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id
    = ur.user_id and ur.role_id = #{roleId})
    <if test="userName != null and userName != ''">
      AND u.user_name like concat('%', #{userName}, '%')
    </if>
    <if test="phoneNumber != null and phoneNumber != ''">
      AND u.phone_number like concat('%', #{phoneNumber}, '%')
    </if>
    <!-- 数据范围过滤 -->
    ${params.dataScope}
  </select>
  <select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
    <include refid="selectUserVo"/>
    where u.user_name = #{userName} and u.del_flag = '0'
  </select>
  <select id="selectUserById" parameterType="Long"
    resultType="com.ruoyi.common.core.domain.entity.SysUser">
    select u.user_id      AS userId,
           u.dept_id      AS deptId,
           u.user_name    AS userName,
           u.nick_name    AS nickName,
           u.email        AS email,
           u.avatar       AS avatar,
           u.phone_number AS phoneNumber,
           u.sex          AS sex,
           u.status       AS status,
           u.del_flag     AS delFlag,
           u.login_ip     AS loginIp,
           u.login_date   AS loginDate,
           u.create_by    AS createBy,
           u.create_time  AS createTime,
           u.remark       AS remark,/*u.ifBlack AS ifBlack,u.districtId AS districtId,*/
           ur.role_id     AS roleId,
           sr.role_name   AS roleName,
           u.deptName     as deptName
    from sys_user u
           left join sys_user_role ur on u.user_id = ur.user_id
           left join sys_role sr on ur.role_id = sr.role_id
           left join sys_dept sd on u.dept_id = sd.dept_id
    where u.user_id = #{userId}
      and u.del_flag = 0
    group by u.user_id
  </select>
  <select id="checkUserNameUnique" parameterType="String" resultMap="SysUserResult">
    select user_id, user_name
    from sys_user
    where user_name = #{userName}
      and del_flag = '0'
    limit 1
  </select>
  <select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult">
    select user_id, phone_number
    from sys_user
    where phone_number = #{phoneNumber}
      and del_flag = '0'
    limit 1
  </select>
  <select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult">
    select user_id, email
    from sys_user
    where email = #{email}
      and del_flag = '0'
    limit 1
  </select>
  <select id="selectUserByIds" resultType="com.ruoyi.common.core.domain.entity.SysUser">
    select user_id AS userId, dept_id AS deptId, user_name AS userName, nick_name AS nickName, email
    AS email, avatar AS avatar, phone_number AS phoneNumber
    from sys_user where user_id in
    <foreach close=")" collection="userIds" item="userId" open="(" separator=",">
      #{userId}
    </foreach>
  </select>
  <select id="queryList" resultType="com.ruoyi.common.core.domain.entity.SysUser">
    select u.user_id      AS userId,
           u.dept_id      AS deptId,
           u.user_name    AS userName,
           u.nick_name    AS nickName,
           u.email        AS email,
           u.avatar       AS avatar,
           u.phone_number AS phoneNumber,
           u.sex          AS sex,
           u.status       AS status,
           u.del_flag     AS delFlag,
           u.login_ip     AS loginIp,
           u.login_date   AS loginDate,
           u.create_by    AS createBy,
           u.create_time  AS createTime,
           u.remark       AS remark
    from sys_user u
    WHERE u.del_flag = 0
  </select>
  <select id="selectCount" resultType="java.lang.Integer">
    select count(*) from sys_user
    <where>
      <if test="status != null">
        AND status = #{status}
      </if>
      AND del_flag = 0
    </where>
  </select>
  <select id="selectListByNamePhone" resultType="com.ruoyi.common.core.domain.entity.SysUser">
    select u.user_id AS userId, u.dept_id AS deptId, u.user_name AS userName, u.nick_name AS
    nickName, u.email AS email, u.avatar AS avatar,
    u.phone_number AS phoneNumber, u.sex AS sex, u.status AS status, u.del_flag AS delFlag,
    u.login_ip AS loginIp,
    u.login_date AS loginDate, u.create_by AS createBy, u.create_time AS createTime, u.remark AS
    remark,/*u.ifBlack AS ifBlack,u.districtId AS districtId*/
    from sys_user u
    WHERE u.del_flag = 0
    <if test="name != null and name != ''">
      AND (u.nick_name LIKE concat('%',#{name},'%')
      OR u.phone_number LIKE concat('%',#{name},'%'))
    </if>
  </select>
  <select id="selectUserByUserNameList" resultType="com.ruoyi.common.core.domain.entity.SysUser">
    select u.user_id AS userId, u.dept_id AS deptId, u.user_name AS userName, u.nick_name AS
    nickName, u.email AS email, u.avatar AS avatar,
    u.phone_number AS phoneNumber
    from sys_user u
    WHERE u.del_flag = 0
    <if test="names != null and names.size()>0">
      AND u.nick_name IN
      <foreach close=")" collection="names" item="name" open="(" separator=",">
        #{name}
      </foreach>
    </if>
  </select>
  <select id="userInfo" resultType="com.ruoyi.system.vo.UserInfoVo">
    select t1.*, t2.companyName, t2.companyType, tq.qrcodeLink
    from sys_user t1
           left join t_company t2 on t2.id = t1.companyId
           left join t_qrcode tq on t1.user_id = tq.otherId and tq.type = 1
    where t1.user_id = #{id}
  </select>
  <select id="selectByPhone" resultType="com.ruoyi.common.core.domain.entity.SysUser">
    select u.user_id      AS userId,
           u.dept_id      AS deptId,
           u.user_name    AS userName,
           u.nick_name    AS nickName,
           u.email        AS email,
           u.avatar       AS avatar,
           u.phone_number AS phoneNumber,
           u.sex          AS sex,
           u.status       AS status,
           u.del_flag     AS delFlag,
           u.login_ip     AS loginIp,
           u.login_date   AS loginDate,
           u.create_by    AS createBy,
           u.create_time  AS createTime,
           u.remark       AS remark
    from sys_user u
    where u.phone_number = #{phoneNumber}
      and u.status = 0
      and u.del_flag = 0
  </select>
  <select id="getUserInfoBy" resultType="com.ruoyi.system.vo.UserInfoVo">
    select t1.*, t2.companyName, t2.companyType
    from sys_user t1
           left join t_company t2 on t2.id = t1.companyId
    where t1.singleNum = #{singleNum}
  </select>
  <select id="getUserRole" resultType="java.lang.Long">
    select role_id
    from sys_user_role
    where sys_user_role.user_id = #{userId}
  </select>
  <select id="selectAllList" resultType="com.ruoyi.common.core.domain.entity.SysUser">
    select *
    from sys_user
  </select>
  <select id="pageList" resultType="com.ruoyi.system.vo.SysUserVO">
    select u.user_id AS userId, u.dept_id AS deptId, u.user_name AS userName, u.nick_name AS
    nickName, u.email AS email, u.avatar AS avatar,
    u.phone_number AS phoneNumber, u.sex AS sex, u.status AS status, u.del_flag AS delFlag,
    u.login_ip AS loginIp,
    u.login_date AS loginDate, u.create_by AS createBy, u.create_time AS createTime, u.remark AS
    remark,/*u.ifBlack AS ifBlack, u.districtId AS districtId,*/
    r.role_id AS roleId, r.role_name AS roleName, r.role_key AS roleKey, r.role_sort AS roleSort,
    r.data_scope AS dataScope, r.status as role_status,u.deptName as deptName
    from sys_user u
    left join sys_user_role ur on u.user_id = ur.user_id
    left join sys_role r on r.role_id = ur.role_id
    WHERE u.del_flag = 0
    <if test="query.nickName != null and query.nickName != ''">
      AND u.nick_name LIKE concat('%',#{query.nickName},'%')
    </if>
    <if test="query.roleId != null">
      AND r.role_id = #{query.roleId}
    </if>
    <if test="query.phoneNumber != null and query.phoneNumber != ''">
      AND u.phone_number LIKE concat('%',#{query.phoneNumber},'%')
    </if>
    <if test="query.status != null and query.status != ''">
      AND u.status = #{query.status}
    </if>
    ORDER BY u.create_time DESC
  </select>
  <select id="selectIdByPhone" resultType="java.lang.Long">
    select user_id
    from sys_user
    where phone_number = #{phoneNumber}
      and status = 0
      and del_flag = 0
  </select>
  <select id="selectDeptUserByUserName" parameterType="java.lang.String"
    resultType="com.ruoyi.common.core.domain.entity.SysUser">
    <include refid="selectUserVo"/>
    where u.user_name = #{userName} and u.del_flag = '0' and u.user_type = '2'
  </select>
  <select id="selectPlatUserByUserName" parameterType="java.lang.String"
    resultType="com.ruoyi.common.core.domain.entity.SysUser">
    <include refid="selectUserVo"/>
    where u.user_name = #{userName} and u.del_flag = '0' and u.user_type = '1'
  </select>
  <sql id="selectUserVo">
    select u.user_id,
           u.dept_id,
           u.user_name,
           u.nick_name,
           u.user_type,
           u.email,
           u.avatar,
           u.phone_number,
           u.password,
           u.sex,
           u.status,
           u.del_flag,
           u.login_ip,
           u.login_date,
           u.create_by,
           u.create_time,
           u.remark,
           d.dept_id,
           d.parent_id,
           d.ancestors,
           d.dept_name,
           d.order_num,
           d.leader,
           d.status as dept_status,
           r.role_id,
           r.role_name,
           r.role_key,
           r.role_sort,
           r.data_scope,
           r.status as role_status,
           u.area_name,
           u.area_alias,
           u.area_code,
           u.area_level,
           u.county_flag,
           u.person_in_charge,
           u.focussed
    from sys_user u
           left join sys_dept d on u.dept_id = d.dept_id
           left join sys_user_role ur on u.user_id = ur.user_id
           left join sys_role r on r.role_id = ur.role_id
  </sql>
  <sql id="selectDeptUserVo">
    select u.user_id,
           u.dept_id,
           u.user_name,
           u.nick_name,
           u.email,
           u.avatar,
           u.phone_number,
           u.password,
           u.sex,
           u.status,
           u.del_flag,
           u.login_ip,
           u.login_date,
           u.create_by,
           u.create_time,
           u.remark,
           u.area_name,
           u.area_alias,
           u.area_code,
           u.area_level,
           u.county_flag,
           u.person_in_charge,
           u.focussed
    from sys_user u
  </sql>
  <update id="updateUser" parameterType="SysUser">
    update sys_user
    <set>
      <if test="deptId != null and deptId != 0">dept_id = #{deptId},</if>
      <if test="userName != null and userName != ''">user_name = #{userName},</if>
      <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
      <if test="deptName != null and deptName != ''">deptName = #{deptName},</if>
      <if test="email != null ">email = #{email},</if>
      <if test="phoneNumber != null ">phone_number = #{phoneNumber},</if>
      <if test="sex != null and sex != ''">sex = #{sex},</if>
      <if test="avatar != null and avatar != ''">avatar = #{avatar},</if>
      <if test="password != null and password != ''">password = #{password},</if>
      <if test="status != null and status != ''">status = #{status},</if>
      <if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if>
      <if test="loginDate != null">login_date = #{loginDate},</if>
      <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
      <if test="remark != null">remark = #{remark},</if>
      update_time = sysdate()
    </set>
    where user_id = #{userId}
  </update>
  <update id="updateUserStatus" parameterType="SysUser">
    update sys_user
    set status = #{status}
    where user_id = #{userId}
  </update>
  <update id="updateUserAvatar" parameterType="SysUser">
    update sys_user
    set avatar = #{avatar}
    where user_name = #{userName}
  </update>
  <update id="resetUserPwd" parameterType="SysUser">
    update sys_user
    set password = #{password}
    where user_name = #{userName}
  </update>
  <update id="updatePassword">
    update sys_user
    set password = #{s}
    where user_id = #{id}
  </update>
</mapper>