新增收资清单模板导出接口
This commit is contained in:
		@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据实体获取替换数据
 | 
			
		||||
 | 
			
		||||
@ -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());
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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查询用户账户
 | 
			
		||||
     *
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user