diff --git a/smart-admin-api/pom.xml b/smart-admin-api/pom.xml index e77cdd42..8b39586e 100644 --- a/smart-admin-api/pom.xml +++ b/smart-admin-api/pom.xml @@ -39,6 +39,7 @@ 2.12.0 3.3.2 5.2.4 + 1.4 1.11.842 2.17.2 5.7.22 @@ -288,6 +289,12 @@ ${poi.version} + + org.apache.poi + ooxml-schemas + ${ooxml-schemas.version} + + com.fasterxml.jackson.datatype jackson-datatype-jsr310 diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/controller/GoodsController.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/controller/GoodsController.java index e9b938a4..dc1c7bf0 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/controller/GoodsController.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/controller/GoodsController.java @@ -1,9 +1,8 @@ package net.lab1024.sa.admin.module.business.goods.controller; import cn.dev33.satoken.annotation.SaCheckPermission; -import com.alibaba.excel.EasyExcel; -import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; import net.lab1024.sa.admin.module.business.goods.domain.form.GoodsAddForm; import net.lab1024.sa.admin.module.business.goods.domain.form.GoodsQueryForm; @@ -14,7 +13,7 @@ import net.lab1024.sa.admin.module.business.goods.service.GoodsService; import net.lab1024.sa.base.common.domain.PageResult; import net.lab1024.sa.base.common.domain.ResponseDTO; import net.lab1024.sa.base.common.domain.ValidateList; -import net.lab1024.sa.base.common.util.SmartResponseUtil; +import net.lab1024.sa.base.common.util.SmartExcelUtil; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -88,17 +87,8 @@ public class GoodsController { @GetMapping("/goods/exportGoods") @SaCheckPermission("goods:exportGoods") public void exportGoods(HttpServletResponse response) throws IOException { - List goodsList = goodsService.getAllGoods(); - - // 设置下载消息头 - SmartResponseUtil.setDownloadFileHeader(response, "商品列表.xls", null); - - // 下载 - EasyExcel.write(response.getOutputStream(), GoodsExcelVO.class) - .autoCloseStream(Boolean.FALSE) - .sheet("商品") - .doWrite(goodsList); + SmartExcelUtil.exportExcel(response,"商品列表.xlsx","商品",GoodsExcelVO.class, goodsList); } } diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/EnterpriseController.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/EnterpriseController.java index 7b3d3f4a..211a1140 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/EnterpriseController.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/EnterpriseController.java @@ -1,7 +1,6 @@ package net.lab1024.sa.admin.module.business.oa.enterprise; import cn.dev33.satoken.annotation.SaCheckPermission; -import com.alibaba.excel.EasyExcel; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; @@ -11,11 +10,11 @@ import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseEm import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseExcelVO; import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseListVO; import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseVO; +import net.lab1024.sa.admin.util.AdminRequestUtil; import net.lab1024.sa.base.common.domain.PageResult; import net.lab1024.sa.base.common.domain.RequestUser; import net.lab1024.sa.base.common.domain.ResponseDTO; -import net.lab1024.sa.base.common.util.SmartRequestUtil; -import net.lab1024.sa.base.common.util.SmartResponseUtil; +import net.lab1024.sa.base.common.util.*; import net.lab1024.sa.base.module.support.operatelog.annotation.OperateLog; import org.apache.commons.collections.CollectionUtils; import org.springframework.web.bind.annotation.*; @@ -24,6 +23,7 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; +import java.time.LocalDateTime; import java.util.List; /** @@ -60,14 +60,11 @@ public class EnterpriseController { return; } - // 设置下载消息头 - SmartResponseUtil.setDownloadFileHeader(response, "企业基本信息.xls", null); + String watermark = AdminRequestUtil.getRequestUser().getActualName(); + watermark += SmartLocalDateUtil.format(LocalDateTime.now(), SmartDateFormatterEnum.YMD_HMS); + + SmartExcelUtil.exportExcelWithWatermark(response,"企业基本信息.xlsx","企业信息",EnterpriseExcelVO.class,data,watermark); - // 下载 - EasyExcel.write(response.getOutputStream(), EnterpriseExcelVO.class) - .autoCloseStream(Boolean.FALSE) - .sheet("企业信息") - .doWrite(data); } @Operation(summary = "查询企业详情 @author 开云") diff --git a/smart-admin-api/sa-base/pom.xml b/smart-admin-api/sa-base/pom.xml index a2fd27f7..ac20877c 100644 --- a/smart-admin-api/sa-base/pom.xml +++ b/smart-admin-api/sa-base/pom.xml @@ -248,6 +248,11 @@ poi-scratchpad + + org.apache.poi + ooxml-schemas + + com.fasterxml.jackson.datatype jackson-datatype-jsr310 diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartExcelUtil.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartExcelUtil.java new file mode 100644 index 00000000..47dad555 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartExcelUtil.java @@ -0,0 +1,226 @@ +package net.lab1024.sa.base.common.util; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.openxml4j.opc.PackagePartName; +import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.poi.openxml4j.opc.TargetMode; +import org.apache.poi.xssf.usermodel.XSSFPictureData; +import org.apache.poi.xssf.usermodel.XSSFRelation; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletResponse; +import javax.swing.*; +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Collection; + +/** + * + * excel 工具类 + * + * @Author 1024创新实验室-主任:卓大 + * @Date 2024/4/22 22:49:07 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2024 + */ +public final class SmartExcelUtil { + + /** + * 通用单sheet导出 + */ + public static void exportExcel(HttpServletResponse response, String fileName, String sheetName, Class head,Collection data) throws IOException { + // 设置下载消息头 + SmartResponseUtil.setDownloadFileHeader(response, fileName, null); + // 下载 + EasyExcel.write(response.getOutputStream(), head) + .autoCloseStream(Boolean.FALSE) + .sheet(sheetName) + .doWrite(data); + } + + /** + * 通用单 sheet水印 导出 + */ + public static void exportExcelWithWatermark(HttpServletResponse response, String fileName, String sheetName, Class head,Collection data, String watermarkString) throws IOException { + // 设置下载消息头 + SmartResponseUtil.setDownloadFileHeader(response, fileName, null); + // 水印 + Watermark watermark = new Watermark(watermarkString); + // 一定要inMemory + EasyExcel.write(response.getOutputStream(), head) + .inMemory(true) + .sheet(sheetName) + .registerWriteHandler(new CustomWaterMarkHandler(watermark)) + .doWrite(data); + } + + + @Slf4j + private static class CustomWaterMarkHandler implements SheetWriteHandler { + + private final Watermark watermark; + + public CustomWaterMarkHandler(Watermark watermark) { + this.watermark = watermark; + } + + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + BufferedImage bufferedImage = createWatermarkImage(); + XSSFWorkbook workbook = (XSSFWorkbook) writeSheetHolder.getParentWriteWorkbookHolder().getWorkbook(); + try { + // 添加水印的具体操作 + addWatermarkToSheet(workbook, bufferedImage); + } catch (Exception e) { + log.error("添加水印出错:", e); + } + + } + + /** + * 创建水印图片 + * + * @return + */ + private BufferedImage createWatermarkImage() { + // 获取水印相关参数 + Font font = watermark.getFont(); + int width = watermark.getWidth(); + int height = watermark.getHeight(); + Color color = watermark.getColor(); + String text = watermark.getContent(); + + // 创建带有透明背景的 BufferedImage + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + + // 设置画笔字体、平滑、颜色 + g.setFont(font); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setColor(color); + + // 计算水印位置和角度 + int y = watermark.getYAxis(); + int x = watermark.getXAxis(); + AffineTransform transform = AffineTransform.getRotateInstance(Math.toRadians(-watermark.getAngle()), 0, y); + g.setTransform(transform); + // 绘制水印文字 + g.drawString(text, x, y); + + // 释放资源 + g.dispose(); + + return image; + } + + private void addWatermarkToSheet(XSSFWorkbook workbook, BufferedImage watermarkImage) { + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + ImageIO.write(watermarkImage, "png", os); + int pictureIdx = workbook.addPicture(os.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG); + XSSFPictureData pictureData = workbook.getAllPictures().get(pictureIdx); + for (int i = 0; i < workbook.getNumberOfSheets(); i++) { + // 获取每个Sheet表 + XSSFSheet sheet = workbook.getSheetAt(i); + PackagePartName ppn = pictureData.getPackagePart().getPartName(); + String relType = XSSFRelation.IMAGES.getRelation(); + PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null); + sheet.getCTWorksheet().addNewPicture().setId(pr.getId()); + } + } catch (Exception e) { + // 处理ImageIO.write可能抛出的异常 + log.error("添加水印图片时发生错误", e); + } + } + } + + @Data + private static class Watermark { + + public Watermark(String content) { + this.content = content; + init(); + } + + public Watermark(String content, Color color, Font font, double angle) { + this.content = content; + this.color = color; + this.font = font; + this.angle = angle; + init(); + } + + /** + * 根据水印内容长度自适应水印图片大小,简单的三角函数 + */ + private void init() { + FontMetrics fontMetrics = new JLabel().getFontMetrics(this.font); + int stringWidth = fontMetrics.stringWidth(this.content); + int charWidth = fontMetrics.charWidth('A'); + this.width = (int) Math.abs(stringWidth * Math.cos(Math.toRadians(this.angle))) + 5 * charWidth; + this.height = (int) Math.abs(stringWidth * Math.sin(Math.toRadians(this.angle))) + 5 * charWidth; + this.yAxis = this.height; + this.xAxis = charWidth; + } + + /** + * 水印内容 + */ + private String content; + + /** + * 画笔颜色 + */ + private Color color = new Color(239,239,239); + + /** + * 字体样式 + */ + private Font font = new Font("Microsoft YaHei", Font.BOLD, 26); + + /** + * 水印宽度 + */ + private int width; + + /** + * 水印高度 + */ + private int height; + + /** + * 倾斜角度,非弧度制 + */ + private double angle = 25; + + /** + * 字体的y轴位置 + */ + private int yAxis = 50; + + /** + * 字体的X轴位置 + */ + private int xAxis; + + /** + * 水平倾斜度 + */ + private double shearX = 0.1; + + /** + * 垂直倾斜度 + */ + private double shearY = -0.26; + } +} diff --git a/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml index b563a4d1..62069872 100644 --- a/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml @@ -3,7 +3,7 @@ spring: datasource: url: jdbc:p6spy:mysql://127.0.0.1:3306/smart_admin_v3?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai username: root - password: Zhuoda.123 + password: Zhuoda1024lab initial-size: 2 min-idle: 2 max-active: 10 @@ -120,8 +120,6 @@ reload: sa-token: # token 名称(同时也是 cookie 名称) token-name: x-access-token - # token 前缀 例如:Bear - token-prefix: # token 有效期(单位:秒) 默认30天(2592000秒),-1 代表永久有效 timeout: 2592000 # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 diff --git a/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml index ee6cb459..b60bb994 100644 --- a/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml @@ -122,8 +122,6 @@ reload: sa-token: # token 名称(同时也是 cookie 名称) token-name: x-access-token - # token 前缀 例如:Bear - token-prefix: # token 有效期(单位:秒) 默认30天(2592000秒),-1 代表永久有效 timeout: 2592000 # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 diff --git a/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml index 3307563c..4ae563f4 100644 --- a/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml @@ -122,8 +122,6 @@ reload: sa-token: # token 名称(同时也是 cookie 名称) token-name: x-access-token - # token 前缀 例如:Bear - token-prefix: # token 有效期(单位:秒) 默认30天(2592000秒),-1 代表永久有效 timeout: 2592000 # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 diff --git a/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml index 9021ea9b..f1c8d04a 100644 --- a/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml @@ -122,8 +122,6 @@ reload: sa-token: # token 名称(同时也是 cookie 名称) token-name: x-access-token - # token 前缀 例如:Bear - token-prefix: # token 有效期(单位:秒) 默认30天(2592000秒),-1 代表永久有效 timeout: 2592000 # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 diff --git a/smart-admin-web/javascript-ant-design-vue3/package.json b/smart-admin-web/javascript-ant-design-vue3/package.json index 023b0d66..fcf1f31a 100644 --- a/smart-admin-web/javascript-ant-design-vue3/package.json +++ b/smart-admin-web/javascript-ant-design-vue3/package.json @@ -19,7 +19,7 @@ "dependencies": { "@wangeditor/editor": "5.1.14", "@wangeditor/editor-for-vue": "5.1.12", - "ant-design-vue": "4.1.2", + "ant-design-vue": "4.2.0", "axios": "1.6.8", "clipboard": "2.0.11", "crypto-js": "4.1.1", diff --git a/smart-admin-web/javascript-ant-design-vue3/src/api/support/file-api.js b/smart-admin-web/javascript-ant-design-vue3/src/api/support/file-api.js index 5b4aba4e..cb56652f 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/api/support/file-api.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/api/support/file-api.js @@ -32,7 +32,7 @@ export const fileApi = { /** * 下载文件流(根据fileKey) @author 胡克 */ - downLoadFile: (fileName, fileKey) => { + downLoadFile: (fileKey) => { return getDownload('/support/file/downLoad', { fileKey }); }, }; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/components/support/file-preview-modal/index.vue b/smart-admin-web/javascript-ant-design-vue3/src/components/support/file-preview-modal/index.vue index 540faab3..d42d2efc 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/components/support/file-preview-modal/index.vue +++ b/smart-admin-web/javascript-ant-design-vue3/src/components/support/file-preview-modal/index.vue @@ -24,7 +24,6 @@ diff --git a/smart-admin-web/javascript-ant-design-vue3/src/lib/axios.js b/smart-admin-web/javascript-ant-design-vue3/src/lib/axios.js index 76b575e5..e77c4419 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/lib/axios.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/lib/axios.js @@ -23,6 +23,12 @@ const smartAxios = axios.create({ baseURL: import.meta.env.VITE_APP_API_URL, }); +// 退出系统 +function logout() { + localClear(); + location.href = '/'; +} + // ================================= 请求拦截器 ================================= smartAxios.interceptors.request.use( @@ -73,10 +79,7 @@ smartAxios.interceptors.response.use( if (res.code === 30007 || res.code === 30008) { message.destroy(); message.error('您没有登录,请重新登录'); - localClear(); - setTimeout(() => { - location.href = '/'; - }, 300); + setTimeout(logout, 300); return Promise.reject(response); } @@ -94,15 +97,9 @@ smartAxios.interceptors.response.use( Modal.error({ title: '重要提醒', content: res.msg, - onOk() { - return new Promise((resolve, reject) => { - localClear(); - setTimeout(() => { - location.href = '/'; - }, 300); - }).catch(() => console.log('Oops errors!')); - }, + onOk: logout, }); + setTimeout(logout, 3000); return Promise.reject(response); } message.destroy(); diff --git a/smart-admin-web/javascript-ant-design-vue3/src/theme/color.js b/smart-admin-web/javascript-ant-design-vue3/src/theme/color.js index e909b2fa..179efbf6 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/theme/color.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/theme/color.js @@ -5,12 +5,13 @@ export const themeColors = [ activeColor: '#0958d9', hoverColor: '#bae0ff', }, - // 紫色 + // 绿色 { - primaryColor: '#722ED1', - activeColor: '#531dab', - hoverColor: '#9254de', + primaryColor: '#00b96b', + activeColor: '#00945b', + hoverColor: '#20c77c', }, + // 红色 { primaryColor: '#F5222D', @@ -29,10 +30,10 @@ export const themeColors = [ activeColor: '#c41d7f', hoverColor: '#f759ab', }, - // 绿色 + // 紫色 { - primaryColor: '#52C41A', - activeColor: '#389e0d', - hoverColor: '#73d13d', + primaryColor: '#722ED1', + activeColor: '#531dab', + hoverColor: '#9254de', }, ]; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/views/business/oa/enterprise/enterprise-detail.vue b/smart-admin-web/javascript-ant-design-vue3/src/views/business/oa/enterprise/enterprise-detail.vue index 66a657cf..4ce4aa17 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/views/business/oa/enterprise/enterprise-detail.vue +++ b/smart-admin-web/javascript-ant-design-vue3/src/views/business/oa/enterprise/enterprise-detail.vue @@ -24,7 +24,7 @@ {{ detail.createTime }} {{ detail.createUserName }} - + diff --git a/smart-admin-web/javascript-ant-design-vue3/src/views/business/oa/enterprise/enterprise-list.vue b/smart-admin-web/javascript-ant-design-vue3/src/views/business/oa/enterprise/enterprise-list.vue index f6003b87..a959df56 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/views/business/oa/enterprise/enterprise-list.vue +++ b/smart-admin-web/javascript-ant-design-vue3/src/views/business/oa/enterprise/enterprise-list.vue @@ -1,11 +1,11 @@ diff --git a/smart-admin-web/javascript-ant-design-vue3/src/views/support/feedback/feedback-list.vue b/smart-admin-web/javascript-ant-design-vue3/src/views/support/feedback/feedback-list.vue index 5d9c1d09..5884cffb 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/views/support/feedback/feedback-list.vue +++ b/smart-admin-web/javascript-ant-design-vue3/src/views/support/feedback/feedback-list.vue @@ -45,7 +45,7 @@