From ec76c5defdd8018ce4efcc8795508498a84de4b7 Mon Sep 17 00:00:00 2001
From: mitao <2763622819@qq.com>
Date: 星期二, 09 四月 2024 19:09:33 +0800
Subject: [PATCH] 平台历史数据 导入导出接口

---
 ruoyi-system/src/main/java/com/ruoyi/system/domain/TbScore.java                           |   14 
 ruoyi-system/src/main/java/com/ruoyi/system/service/TbBasicDataService.java               |   17 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbBasicDataServiceImpl.java      |  761 +++++++++-----
 ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml                           |  852 +++++++++------
 ruoyi-common/src/main/java/com/ruoyi/common/enums/UserTypeEnum.java                       |   32 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/TbQuestion.java                        |   16 
 ruoyi-system/src/main/java/com/ruoyi/system/query/QuestionQuery.java                      |    8 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbQuestionServiceImpl.java       |    5 
 ruoyi-system/src/main/java/com/ruoyi/system/listener/HistoryDataListener.java             |  343 ++++++
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/HistoryGroup.java                  |   16 
 ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java    |   96 -
 ruoyi-system/src/main/java/com/ruoyi/system/service/TbFieldService.java                   |    3 
 ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/api/CurrentQuarterController.java |   21 
 ruoyi-system/src/main/java/com/ruoyi/system/listener/BasicDataListener.java               |  178 ++-
 ruoyi-system/src/main/java/com/ruoyi/system/query/ScoreCalculateQuery.java                |    9 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbFieldServiceImpl.java          |  229 +++
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TbFieldController.java             |   45 
 /dev/null                                                                                 |    8 
 ruoyi-system/src/main/java/com/ruoyi/system/query/CurrentFieldsQuery.java                 |    9 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/HistoryDataController.java         |  113 +
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/lisenter/DeptImportListener.java       |   45 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/TbBasicData.java                       |   18 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java               |  276 ++--
 ruoyi-system/src/main/java/com/ruoyi/system/handler/SelectedSheetWriteHandler.java        |   20 
 24 files changed, 2,099 insertions(+), 1,035 deletions(-)

diff --git a/ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/api/CurrentQuarterController.java b/ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/api/CurrentQuarterController.java
index f1b72e4..67e1049 100644
--- a/ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/api/CurrentQuarterController.java
+++ b/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();
         }
     }
diff --git a/ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java b/ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
index 04dd3f5..ef6f082 100644
--- a/ruoyi-admin-dept/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
+++ b/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));
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/HistoryDataController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/HistoryDataController.java
index a7b738b..9282397 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/HistoryDataController.java
+++ b/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);
+        }
+    }
 }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TbFieldController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TbFieldController.java
index a2472cc..69f100f 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TbFieldController.java
+++ b/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("模板下载失败,请联系管理员!");
+        }
+    }
 }
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/lisenter/DeptImportListener.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/lisenter/DeptImportListener.java
index 61e7071..4e40fb3 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/lisenter/DeptImportListener.java
+++ b/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());
     }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/HistoryGroup.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/HistoryGroup.java
new file mode 100644
index 0000000..633f051
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/HistoryGroup.java
@@ -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 {
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
index 6f9439e..b789bea 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
+++ b/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();
     }
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserTypeEnum.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserTypeEnum.java
index aa3827e..72b10bf 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserTypeEnum.java
+++ b/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;
+    }
 } 
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/validate/HistoryGroup.java b/ruoyi-common/src/main/java/com/ruoyi/common/validate/HistoryGroup.java
deleted file mode 100644
index 1ac9397..0000000
--- a/ruoyi-common/src/main/java/com/ruoyi/common/validate/HistoryGroup.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.ruoyi.common.validate;
-
-/**
- * @author mitao
- * @date 2024/4/8
- */
-public interface HistoryGroup {
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TbBasicData.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TbBasicData.java
index 3fd566a..1796921 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TbBasicData.java
+++ b/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代表删除)")
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TbQuestion.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TbQuestion.java
index f3aa3aa..72733cf 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TbQuestion.java
+++ b/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代表删除)")
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TbScore.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TbScore.java
index ff3fb99..3357184 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TbScore.java
+++ b/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 = "创建者")
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/handler/SelectedSheetWriteHandler.java b/ruoyi-system/src/main/java/com/ruoyi/system/handler/SelectedSheetWriteHandler.java
index d21bc69..1cd9e01 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/handler/SelectedSheetWriteHandler.java
+++ b/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) {
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/listener/BasicDataListener.java b/ruoyi-system/src/main/java/com/ruoyi/system/listener/BasicDataListener.java
index e94143e..ffc2ece 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/listener/BasicDataListener.java
+++ b/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);
     }
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/listener/HistoryDataListener.java b/ruoyi-system/src/main/java/com/ruoyi/system/listener/HistoryDataListener.java
new file mode 100644
index 0000000..f084ed3
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/listener/HistoryDataListener.java
@@ -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);
+        }
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/query/CurrentFieldsQuery.java b/ruoyi-system/src/main/java/com/ruoyi/system/query/CurrentFieldsQuery.java
index c4e2ae9..601ccc8 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/query/CurrentFieldsQuery.java
+++ b/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 = "填报部门")
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/query/QuestionQuery.java b/ruoyi-system/src/main/java/com/ruoyi/system/query/QuestionQuery.java
index 3d87273..80040c4 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/query/QuestionQuery.java
+++ b/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;
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/query/ScoreCalculateQuery.java b/ruoyi-system/src/main/java/com/ruoyi/system/query/ScoreCalculateQuery.java
index 48fc202..5c73469 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/query/ScoreCalculateQuery.java
+++ b/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 = "类型名称")
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/TbBasicDataService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/TbBasicDataService.java
index 4756baa..fc350b1 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/TbBasicDataService.java
+++ b/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;
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/TbFieldService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/TbFieldService.java
index 7b17094..30491d4 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/TbFieldService.java
+++ b/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;
+
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbBasicDataServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbBasicDataServiceImpl.java
index 0100e39..083b8fd 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbBasicDataServiceImpl.java
+++ b/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;
+    }
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbFieldServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbFieldServiceImpl.java
index 4534eac..e485974 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbFieldServiceImpl.java
+++ b/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;
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbQuestionServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbQuestionServiceImpl.java
index 761ed2e..9110645 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TbQuestionServiceImpl.java
+++ b/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);
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
index 30ce199..211b23f 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
+++ b/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> 
\ No newline at end of file

--
Gitblit v1.7.1