新增收资清单模板导出接口

This commit is contained in:
2025-09-02 18:57:32 +08:00
parent 9aef0d4b86
commit 8c131cb9a5
6 changed files with 198 additions and 2 deletions

View File

@ -1,12 +1,21 @@
package org.dromara.design.controller;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.alibaba.excel.EasyExcel;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
//import org.dromara.design.converter.UserConverter;
import org.dromara.design.domain.DesCollect;
import org.dromara.design.domain.DesCollectCatalogue;
import org.dromara.design.domain.dto.desCollect.DesCollectBatchDto;
import org.dromara.design.domain.vo.DesCollectCatalogueVo;
//import org.dromara.design.handler.UserDropdownSheetWriteHandler;
import org.dromara.tender.domain.bo.BusBillofquantitiesLimitListBo;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
@ -22,6 +31,7 @@ import org.dromara.design.domain.vo.DesCollectVo;
import org.dromara.design.domain.bo.DesCollectBo;
import org.dromara.design.service.IDesCollectService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.springframework.web.multipart.MultipartFile;
/**
* 收资清单
@ -136,4 +146,16 @@ public class DesCollectController extends BaseController {
desCollectService.exportWordById(id, response);
}
/**
* 收资清单模板导出
*/
@SaCheckPermission("design:collect:exportExcel")
@Log(title = "收资清单", businessType = BusinessType.EXPORT)
@PostMapping("/exportExcel")
public void exportExcelByDeptId(@RequestParam("deptId") Long deptId, HttpServletResponse response){
desCollectService.exportExcelByDeptId(deptId, response);
}
}

View File

@ -88,4 +88,11 @@ public interface IDesCollectService extends IService<DesCollect>{
* 导出Word
*/
void exportWordById(Long id, HttpServletResponse response);
/**
* 导出模板
* @param deptId
* @param response
*/
void exportExcelByDeptId(Long deptId, HttpServletResponse response);
}

View File

@ -13,6 +13,9 @@ import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.dromara.common.core.domain.event.ProcessDeleteEvent;
import org.dromara.common.core.domain.event.ProcessEvent;
import org.dromara.common.core.domain.event.ProcessTaskEvent;
@ -39,6 +42,7 @@ import org.dromara.design.mapper.DesCollectMapper;
import org.dromara.design.service.IDesCollectCatalogueService;
import org.dromara.design.service.IDesCollectService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
@ -77,6 +81,8 @@ public class DesCollectServiceImpl extends ServiceImpl<DesCollectMapper, DesColl
private final DictService dictService;
private final ISysUserService sysUserService;
/**
* 查询收资清单
*
@ -274,6 +280,112 @@ public class DesCollectServiceImpl extends ServiceImpl<DesCollectMapper, DesColl
}
}
@Override
public void exportExcelByDeptId(Long deptId, HttpServletResponse response) {
// 1. 从数据库查询下拉选项
List<String> userNameList = sysUserService.getUserNamesByDept(deptId);
Map<Long, String> userIdToNameMapByDept = sysUserService.getUserIdToNameMapByDept(deptId);
// 2. 设置响应头
// 设置响应头指定Excel格式和下载文件名
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Disposition", "attachment; filename=utf-8''收资清单模板.xlsx");
Workbook workbook = new XSSFWorkbook();
// 创建主 Sheet 和隐藏 Sheet
Sheet mainSheet = workbook.createSheet("收资清单模板");
Sheet dropdownSheet = workbook.createSheet("DropdownData");
workbook.setSheetHidden(workbook.getSheetIndex(dropdownSheet), true);
//设置下拉列表数据
int rowIdx = 0;
for (Map.Entry<Long, String> entry : userIdToNameMapByDept.entrySet()) {
Row row = dropdownSheet.createRow(rowIdx++);
row.createCell(0).setCellValue(entry.getKey());
row.createCell(1).setCellValue(entry.getValue());
}
// 主 Sheet 设置表头
Row sheetRow = mainSheet.createRow(0);
sheetRow.createCell(0).setCellValue("编码");
sheetRow.createCell(1).setCellValue("人员");
sheetRow.createCell(2).setCellValue("目录名");
sheetRow.createCell(3).setCellValue("备注");
// 核心锁定表头第1行和前1列包含ID列
mainSheet.createFreezePane(1, 1, 0, 0);
// 绑定下拉列表(关联隐藏 Sheet
DataValidationHelper helper = mainSheet.getDataValidationHelper(); //为主Sheet第二列设置下拉列表关联隐藏Sheet的B列
String range = "DropdownData!$B$1:$B$" + userNameList.size(); //引用隐藏Sheet的B列数据范围DropdownData!$B$1:$B$
DataValidationConstraint constraint = helper.createFormulaListConstraint(range); //创建下拉约束
CellRangeAddressList addressList = new CellRangeAddressList(1, 300, 1, 1); // 支持100行数据
//添加验证规则
DataValidation validation = helper.createValidation(constraint, addressList);
validation.setShowErrorBox(true);
mainSheet.addValidationData(validation);
// 7. 创建“隐藏公式”的单元格样式
// 样式1第一列专用隐藏公式 + 锁定单元格)
CellStyle hiddenFormulaAndLockedStyle = workbook.createCellStyle();
DataFormat dataFormat = workbook.createDataFormat();
short formatIndex = dataFormat.getFormat("0"); // 匹配“自定义→0”格式
hiddenFormulaAndLockedStyle.setDataFormat(formatIndex);
hiddenFormulaAndLockedStyle.setHidden(true); // 隐藏公式
hiddenFormulaAndLockedStyle.setLocked(true); // 锁定单元格
// 样式2其他列专用不锁定允许操作
CellStyle unlockedStyle = workbook.createCellStyle();
unlockedStyle.setLocked(false); // 不锁定单元格
// 第三列自动填充ID公式
String formulaTemplate = "IFERROR(INDEX(DropdownData!$A$1:$A$" + userIdToNameMapByDept.size() + ", MATCH(B{rowNum}, DropdownData!$B$1:$B$" + userIdToNameMapByDept.size() + ", 0)),\"\")";
for (int i = 1; i <= 300; i++) { // 从第2行开始行索引1
Row row = mainSheet.createRow(i);
int currentRowNum = i + 1; // Excel行号从1开始第2行的行号是2
String formula = formulaTemplate.replace("{rowNum}", String.valueOf(currentRowNum));
// 第一列ID列隐藏公式 + 锁定)
Cell idCell = row.createCell(0);
idCell.setCellFormula(formula);
idCell.setCellStyle(hiddenFormulaAndLockedStyle);
// 第二列:名称列(不锁定,可下拉选择)
Cell nameCell = row.createCell(1);
nameCell.setCellStyle(unlockedStyle);
// 第三列:序号列(不锁定,可编辑)
Cell seqCell = row.createCell(2);
seqCell.setCellStyle(unlockedStyle);
// 第四列:备注列(不锁定,可编辑)
Cell remakerCell = row.createCell(3);
remakerCell.setCellStyle(unlockedStyle);
}
// 保护工作表(使“隐藏公式”生效,可自定义密码)
mainSheet.protectSheet("123456"); // 示例密码123456
// 调整列宽
mainSheet.setColumnWidth(0, 20 * 256);
mainSheet.setColumnWidth(1, 20 * 100);
mainSheet.setColumnWidth(2, 20 * 200);
mainSheet.setColumnWidth(3, 20 * 200);
// 直接写入响应输出流
try {
workbook.write(response.getOutputStream());
workbook.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 根据实体获取替换数据

View File

@ -144,8 +144,8 @@ public class BusFormalitiesAreConsolidatedServiceImpl extends ServiceImpl<BusFor
private LambdaQueryWrapper<BusFormalitiesAreConsolidated> buildQueryWrapper(BusFormalitiesAreConsolidatedBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<BusFormalitiesAreConsolidated> lqw = Wrappers.lambdaQuery();
lqw.orderByDesc(BusFormalitiesAreConsolidated::getCreatePTime);
lqw.orderByDesc(BusFormalitiesAreConsolidated::getCreateTime);
lqw.orderByAsc(BusFormalitiesAreConsolidated::getCreatePTime);
lqw.orderByAsc(BusFormalitiesAreConsolidated::getCreateTime);
lqw.eq(bo.getProjectId() != null, BusFormalitiesAreConsolidated::getProjectId, bo.getProjectId());
lqw.eq(bo.getFormalitiesPid() != null, BusFormalitiesAreConsolidated::getFormalitiesPid, bo.getFormalitiesPid());
lqw.eq(bo.getFormalitiesId() != null, BusFormalitiesAreConsolidated::getFormalitiesId, bo.getFormalitiesId());

View File

@ -9,6 +9,7 @@ import org.dromara.system.domain.vo.SysUserExportVo;
import org.dromara.system.domain.vo.SysUserVo;
import java.util.List;
import java.util.Map;
/**
* 用户 业务层
@ -244,4 +245,17 @@ public interface ISysUserService {
* @return 结果
*/
List<SysUser> findThis();
/**
* 根据部门 ID 获取用户 ID -> 名称 映射
* @param deptId
* @return
*/
Map<Long, String> getUserIdToNameMapByDept(Long deptId);
/**
* 获取指定部门的用户名称列表(用于 Excel 下拉框)
*/
List<String> getUserNamesByDept(Long deptId);
}

View File

@ -732,6 +732,47 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
return baseMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getDeptId, longs));
}
/**
* 根据部门 ID 获取用户 ID -> 名称 映射
* @param deptId
* @return
*/
@Override
public Map<Long, String> getUserIdToNameMapByDept(Long deptId) {
List<SysDept> deptList = deptMapper.selectListByParentId(deptId);
List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
ids.add(deptId);
LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery();
lqw.in(SysUser::getDeptId, ids);
lqw.orderByAsc(SysUser::getUserId);
List<SysUser> sysUsers = baseMapper.selectList(lqw);
return sysUsers.stream()
.collect(Collectors.toMap(
SysUser::getUserId,
SysUser::getNickName
));
}
/**
* 获取指定部门的用户名称列表(用于 Excel 下拉框)
* @param deptId
* @return
*/
@Override
public List<String> getUserNamesByDept(Long deptId) {
List<SysDept> deptList = deptMapper.selectListByParentId(deptId);
List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
ids.add(deptId);
LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery();
lqw.in(SysUser::getDeptId, ids);
lqw.orderByAsc(SysUser::getUserId);
List<SysUser> sysUsers = baseMapper.selectList(lqw);
return sysUsers.stream()
.map(SysUser::getNickName)
.collect(Collectors.toList());
}
/**
* 通过用户ID查询用户账户
*