前端

1、按钮

              <el-buttontype="text"size="mini"@click="handleExport">导出</el-button>

2、方法

 //导出async handleExport() {if (!this.activityId) {this.$message.warning('活动ID不存在');return;}try {this.loading = true;const res = await exportSignSheet({activityId: this.activityId});//文件名let fileName = `活动签到表_${this.activity?.activityTitle || '未知活动'}_${Date.now()}.xlsx`;//创建下载链接const blob = new Blob([res.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});const url = window.URL.createObjectURL(blob);const link = document.createElement('a');link.href = url;link.download = fileName;document.body.appendChild(link);link.click();// 清理setTimeout(() => {document.body.removeChild(link);window.URL.revokeObjectURL(url);}, 100);this.$message.success('签到表下载已开始');} catch (error) {console.error('导出失败:', error);this.$message.error(`导出失败: ${error.message}`);} finally {this.loading = false;}},

3、路由

export function exportSignSheet(data) {return request({url: '/association/detail/signSheet',//后端接口地址method: 'post',data,responseType: 'blob',//一定要指定类型为blob// 确保能获取到headerstransformResponse: (data, headers) => {return {data,headers: headers || {}};}});
}

4、后端

      <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency>
 @PostMapping("/signSheet")public void exportSignSheet(@RequestBody Map<String, Long> request, // 前端参数HttpServletResponse response) throws IOException {// 设置CORS头(如果存在跨域问题)response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");// 1. 验证活动IDLong activityId = request.get("activityId");if (activityId == null) {throw new IllegalArgumentException("活动ID不能为空");}// 2. 获取活动完整信息(复用已有查询方法)ActivityDetailVO activityVO = activityDetailService.getActivityDetail(activityId);if (activityVO == null) {throw new RuntimeException("活动不存在或已删除");}// 3. 处理文件名String activityName = activityVO.getActivityTitle() != null ? activityVO.getActivityTitle() : "未知活动";String fileName = "活动签到表_" + activityName + "_" + System.currentTimeMillis() + ".xlsx";// 4. 处理文件名避免乱码String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replace("+", "%20"); // 替换空格编码// 5. 设置请求头        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setHeader("Content-Disposition","attachment; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName);// 6. 创建并填充Exceltry (XSSFWorkbook workbook = new XSSFWorkbook()) {buildExcelContent(workbook, activityVO);//可以将文件存入本地进行调试//workbook.write(Files.newOutputStream(Paths.get("debug.xlsx")));workbook.write(response.getOutputStream());} catch (Exception e) {response.reset();response.setContentType("application/json");response.setCharacterEncoding("UTF-8");response.getWriter().write("{\"error\":\"" + e.getMessage() + "\"}");}}
private void buildExcelContent(XSSFWorkbook workbook, ActivityDetailVO activityVO) {Sheet sheet = workbook.createSheet("活动签到表");sheet.setDefaultColumnWidth(15);// 创建样式(保持不变)CellStyle titleStyle = createTitleStyle(workbook);CellStyle borderStyle = createBorderStyle(workbook);CellStyle headerStyle = createHeaderStyle(workbook);// 标题行(第0行)- 修复合并单元格边框Row titleRow = sheet.createRow(0);Cell titleCell = titleRow.createCell(0);titleCell.setCellValue("活动签到表");CellRangeAddress titleRegion = new CellRangeAddress(0, 0, 0, 5);sheet.addMergedRegion(titleRegion);titleCell.setCellStyle(titleStyle);setRegionBorder(BorderStyle.THIN, titleRegion, sheet, workbook); // 新增:设置合并区域边框// 第二行:活动名称(第1行)- 修复合并单元格边框Row nameRow = sheet.createRow(1);Cell nameCell = nameRow.createCell(0);nameCell.setCellValue(activityVO.getActivityTitle() != null ? activityVO.getActivityTitle() : "未设置");CellRangeAddress nameRegion = new CellRangeAddress(1, 1, 0, 5);sheet.addMergedRegion(nameRegion);nameCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, nameRegion, sheet, workbook); // 新增:设置合并区域边框// 第三行:活动地点和活动时间(第2行)- 修复合并单元格边框Row locationTimeRow = sheet.createRow(2);// 活动地点标签Cell locationLabelCell = locationTimeRow.createCell(0);locationLabelCell.setCellValue("活动地点");locationLabelCell.setCellStyle(borderStyle);// 活动地点内容(合并1-2列)Cell locationCell = locationTimeRow.createCell(1);locationCell.setCellValue(getFirstActivityLocation(activityVO));CellRangeAddress locationRegion = new CellRangeAddress(2, 2, 1, 2);sheet.addMergedRegion(locationRegion);locationCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, locationRegion, sheet, workbook); // 新增:设置合并区域边框// 活动时间标签Cell timeLabelCell = locationTimeRow.createCell(3);timeLabelCell.setCellValue("活动时间");timeLabelCell.setCellStyle(borderStyle);// 活动时间内容(合并4-5列)Cell timeCell = locationTimeRow.createCell(4);timeCell.setCellValue(formatActivityTimeRange(activityVO.getStartTime(), activityVO.getEndTime()));CellRangeAddress timeRegion = new CellRangeAddress(2, 2, 4, 5);sheet.addMergedRegion(timeRegion);timeCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, timeRegion, sheet, workbook); // 新增:设置合并区域边框// 第四行:活动召集人和报名人数(第3行)- 修复合并单元格边框Row organizerCountRow = sheet.createRow(3);// 活动召集人标签Cell organizerLabelCell = organizerCountRow.createCell(0);organizerLabelCell.setCellValue("活动召集人");organizerLabelCell.setCellStyle(borderStyle);// 活动召集人内容(合并1-2列)Cell organizerCell = organizerCountRow.createCell(1);organizerCell.setCellValue(activityVO.getEntrepreneurNames() != null ? activityVO.getEntrepreneurNames() : "未设置");CellRangeAddress organizerRegion = new CellRangeAddress(3, 3, 1, 2);sheet.addMergedRegion(organizerRegion);organizerCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, organizerRegion, sheet, workbook); // 新增:设置合并区域边框// 报名人数标签Cell countLabelCell = organizerCountRow.createCell(3);countLabelCell.setCellValue("报名人数");countLabelCell.setCellStyle(borderStyle);// 报名人数内容(合并4-5列)Cell countCell = organizerCountRow.createCell(4);countCell.setCellValue(String.valueOf(getParticipantCount(activityVO)));CellRangeAddress countRegion = new CellRangeAddress(3, 3, 4, 5);sheet.addMergedRegion(countRegion);countCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, countRegion, sheet, workbook); // 新增:设置合并区域边框// 第五行:签到处(第4行)- 修复合并单元格边框Row signRow = sheet.createRow(4);Cell signCell = signRow.createCell(0);signCell.setCellValue("签到处");CellRangeAddress signRegion = new CellRangeAddress(4, 4, 0, 5);sheet.addMergedRegion(signRegion);signCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, signRegion, sheet, workbook); // 新增:设置合并区域边框// 表头行(第5行)- 保持不变Row headerRow = sheet.createRow(5);String[] headers = {"序号", "报名人", "联系电话", "序号", "报名人", "联系电话"};for (int i = 0; i < headers.length; i++) {Cell cell = headerRow.createCell(i);cell.setCellValue(headers[i]);cell.setCellStyle(headerStyle);}}// 带边框的样式private CellStyle createBorderStyle(XSSFWorkbook workbook) {CellStyle style = workbook.createCellStyle();// 设置边框style.setBorderTop(BorderStyle.THIN);style.setBorderBottom(BorderStyle.THIN);style.setBorderLeft(BorderStyle.THIN);style.setBorderRight(BorderStyle.THIN);// 设置边框颜色(黑色)style.setTopBorderColor(IndexedColors.BLACK.getIndex());style.setBottomBorderColor(IndexedColors.BLACK.getIndex());style.setLeftBorderColor(IndexedColors.BLACK.getIndex());style.setRightBorderColor(IndexedColors.BLACK.getIndex());// 居中对齐style.setAlignment(HorizontalAlignment.CENTER);style.setVerticalAlignment(VerticalAlignment.CENTER);return style;}// 标题样式(继承边框样式并加大字体)private CellStyle createTitleStyle(XSSFWorkbook workbook) {CellStyle style = createBorderStyle(workbook);Font font = workbook.createFont();font.setBold(true);font.setFontHeightInPoints((short) 16);style.setFont(font);return style;}// 表头样式(继承边框样式并加粗)private CellStyle createHeaderStyle(XSSFWorkbook workbook) {CellStyle style = createBorderStyle(workbook);Font font = workbook.createFont();font.setBold(true);style.setFont(font);return style;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/95528.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/95528.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/95528.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JMeter性能测试详细版(适合0基础小白学习--非常详细)

01性能测试的概念 02性能测试的概念 基准测试 负载测试 稳定性测试 其他&#xff1a;并发测试、压力测试、回归测试等 压力测试就是在系统强负载的情况下&#xff0c;是否会出现功能隐患问题&#xff0c;出现问题后是否可以尽快恢复 负载测试和压力测试的区别: 1,核心目标不…

QT6(创建第一个QT项目)

编写第一个QT项目 QT官网 安装完QT后的界面 创建第一个项目 这里我们选择第一个就好 下一步 下一步 选择CMake&#xff0c;QMake是QT的CMAKE&#xff08;现在官方自己都不推荐了&#xff09; 下一步 选择QWidget我们先创建一个最简单的窗口程序 QMainWindow&#xff1a;主窗…

Golang指针操作

在 Go 语言&#xff08;Golang&#xff09;中&#xff0c;* 和 & 是与指针相关的两个重要操作符。 理解它们对于掌握 Go 的内存管理和函数参数传递机制非常关键。 文章目录一、& 操作符&#xff1a;取地址&#xff08;Address-of&#xff09;示例&#xff1a;二、* 操…

微服务从0到1

微服务从0到1实施步骤与注意事项一、核心实施步骤‌‌需求分析与架构设计‌‌明确业务边界‌&#xff1a;根据业务模块&#xff08;如用户管理、订单系统&#xff09;划分服务职责&#xff0c;避免服务职责重叠或耦合‌。‌定义接口契约‌&#xff1a;通过 OpenAPI/Swagger 规范…

小程序排名优化:功能迭代如何助力排名攀升

小程序的功能不是一成不变的&#xff0c;持续的功能迭代不仅能满足用户不断变化的需求&#xff0c;也是提升排名的重要途径。平台更倾向于推荐那些不断更新、功能完善的小程序&#xff0c;因为它们能为用户提供更优质的服务。合理规划功能迭代方向和节奏&#xff0c;能让小程序…

Unity TextMeshPro(二)优化

文章目录前言一、字体打包优化二、ab打包冗余1、问题1、解决方法三、字体静态优化四、扩展总结前言 优化TextMeshPro包体大小的方法记录。 一、字体打包优化 游戏开发阶段通常使用Fast打包方式&#xff0c;在正式项目发布的时候需要切换一下打包方式&#xff0c;重新将字体打…

C++ 之 【简介 set、multiset、map、multimap 的使用】

目录 1.序列式、关联式容器 2.键值对 3.set 3.1set的简介 3.2set的常用函数 4.multiset 5.map 5.1map的简介 5.2map的常用函数 6.multimap 7.练习题 1.序列式、关联式容器 vector、deque、list、forward_list、array等是CSTL中的序列式容器 其核心特性是 元素按插入…

数据结构——排序(升级篇:快速排序、堆排序、希尔排序、计数排序)

1. 快速排序&#xff08;Quick Sort&#xff09; 原理&#xff1a; 选择一个基准值&#xff08;pivot&#xff09;将数组分成两部分&#xff1a;小于 pivot 的放左边&#xff0c;大于 pivot 的放右边。然后递归处理 工作过程示例&#xff1a; 示例数组&#xff1a;[5, 3, 8, 4,…

C++:浅尝gdb

hp window11 wsl ubuntu what is gdb&#xff1f; GNU调试器&#xff08;英语&#xff1a;GNU Debugger&#xff0c;缩写&#xff1a;GDB&#xff09;&#xff0c;是GNU软件系统中的标准调试器&#xff0c;此外GDB也是个具有移携性的调试器&#xff0c;经过移携需求的调修与…

Android输入法一些常用的命令

Android开发过程可能会遇到Android输入法异常的问题&#xff0c;可以通过如下命令来查看和修改系统的输入法。方便调试。 获取当下系统的所有输入法 adb shell ime list获取当前的可用输入法 adb shell ime list -s获取当前的输入法 adb shell settings get secure default_inp…

Sklearn 机器学习 手写数字识别 加载并查看数据

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Sklearn 机器学习 手写数字识别:加载并查看数据 在机器学习入门案例中,手写数字识别…

卫星通信链路预算之七:上行载噪比计算

在前面的文章中我们介绍了卫星通信链路计算的基础知识&#xff0c;包括&#xff1a; 信噪比分配&#xff1b; 带宽和功带平衡原则&#xff1b; EIRP和G/T&#xff1b; 输入回退&#xff1b; 输入饱和通量密度SFD&#xff1b; 输出回退&#xff1b; 这次我们正式进入正题…

一文读懂PDB格式

最近在做分子对接和分子模拟&#xff0c;涉及到了一些盲区&#xff0c;必去pdb文件是按照列位数储存信息的&#xff0c;跟其他文件的空格或者制表符分割很不同&#xff0c;所以也可能出现一些错误&#xff0c;比如信息错位&#xff0c;因此有必要了深入解下结构相关的格式pdb、…

进阶:PGCE中级专家认证精要

PGCE中级认证的核心价值技术深度&#xff1a;掌控未来生态PostgreSQL不仅是传统关系型数据库的标杆&#xff0c;更是云原生、AI大模型训练、物联网平台等前沿场景的核心支撑。通过PGCE认证&#xff0c;你将掌握&#xff1a;万亿级数据性能调优&#xff1a;从查询优化器原理到执…

AI增强SEO关键词表现

内容概要 随着人工智能技术的不断演进&#xff0c;其在搜索引擎优化领域展现出显著潜力&#xff0c;尤其在关键词表现优化方面发挥着核心作用。本文将从基础概念入手&#xff0c;系统探讨AI如何智能提升关键词的搜索可见性、流量吸引力和转化效率&#xff0c;从而驱动整体SEO策…

PG靶机 - PayDay

一、 初步侦察与服务探测 1.1 端口扫描与服务识别 首先&#xff0c;对目标主机 192.168.163.39 进行一次全面的端口扫描&#xff0c;以识别其上运行的各项服务。 sudo nmap 192.168.163.39 -p- --min-rate5000 -A图 1: Nmap 扫描结果&#xff0c;显示开放 80、445 和 995 等端口…

MySQLl中OFFSET 的使用方法

MySQLl中OFFSET 的使用方法基本语法SELECT column1, column2, ... FROM table_name LIMIT number_of_rows OFFSET offset_value;number_of_rows&#xff1a;指定返回的记录数量。offset_value&#xff1a;从第几条记录开始返回&#xff08;偏移量从 0 开始计数&#xff09;。示…

监管科技(RegTech)应用:技术驱动的合规革命

目录 监管科技(RegTech)应用:技术驱动的合规革命 1. 监管科技革命:数字化合规新范式 2. 技术架构全景 2.1 现代RegTech架构 2.2 合规效率公式 3. 核心技术实现 3.1 智能合约自动化合规 3.2 AI驱动的风险监测引擎 4. 核心应用场景 4.1 KYC/AML全流程自动化 4.2 实时交易监控系…

解决SQL Server连接失败:Connection refused: connect

今天创建数据库&#xff0c;本地连接SQL Server报错&#xff1a;“通过端口 1433 连接到主机 127.0.0.1 的 TCP/IP 连接失败。错误&#xff1a;Connection refused: connect”报错图如下&#xff1a;查了一圈&#xff0c;问题出在&#xff1a;TCP/IP 没启用。如果问题和我一样&…

Windows bypassUAC 提权技法详解(一)

引言 用户账户控制&#xff08;User Account Control, 简称 UAC&#xff09;是微软自 Windows Vista 起引入的一项安全功能&#xff0c;旨在通过要求用户在执行需要管理员权限的操作时进行确认&#xff0c;从而防止未经授权的系统更改。UAC 的设计初衷是提高系统安全性&#xf…