diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/pdf/HtmlToPdfInterceptor.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/pdf/HtmlToPdfInterceptor.java new file mode 100644 index 0000000..75a37c0 --- /dev/null +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/pdf/HtmlToPdfInterceptor.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.framework.common.util.pdf; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * html转pdf拦截器 + * @author liqiang + * @date 2021/05/12 + */ +public class HtmlToPdfInterceptor extends Thread { + /** + * 输入流对象 + */ + private InputStream is; + + public HtmlToPdfInterceptor(InputStream is){ + this.is = is; + } + + @Override + public void run(){ + try{ + InputStreamReader isr = new InputStreamReader(is, "utf-8"); + BufferedReader br = new BufferedReader(isr); + String line = null; + while ((line = br.readLine()) != null) { + //输出内容 + System.out.println(line.toString()); + } + }catch (IOException e){ + e.printStackTrace(); + } + } +} diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/pdf/WkHtmlToPdfUtil.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/pdf/WkHtmlToPdfUtil.java new file mode 100644 index 0000000..cd4281b --- /dev/null +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/pdf/WkHtmlToPdfUtil.java @@ -0,0 +1,207 @@ +package cn.iocoder.yudao.framework.common.util.pdf; + +import java.io.File; + +/** + * Input表单或JavaScript脚本支持:--enable-forms,下面这些是网友整理的参数说明 + * wkhtmltopdf [OPTIONS]... [More input files] + * 常规选项 + * --allow 允许加载从指定的文件夹中的文件或文件(可重复) + * --book* 设置一会打印一本书的时候,通常设置的选项 + * --collate 打印多份副本时整理 + * --cookie 设置一个额外的cookie(可重复) + * --cookie-jar 读取和写入的Cookie,并在提供的cookie jar文件 + * --copies 复印打印成pdf文件数(默认为1) + * --cover* 使用HTML文件作为封面。它会带页眉和页脚的TOC之前插入 + * --custom-header 设置一个附加的HTTP头(可重复) + * --debug-javascript 显示的javascript调试输出 + * --default-header* 添加一个缺省的头部,与页面的左边的名称,页面数到右边,例如: --header-left '[webpage]' --header-right '[page]/[toPage]' --header-line + * --disable-external-links* 禁止生成链接到远程网页 + * --disable-internal-links* 禁止使用本地链接 + * --disable-javascript 禁止让网页执行JavaScript + * --disable-pdf-compression* 禁止在PDF对象使用无损压缩 + * --disable-smart-shrinking* 禁止使用WebKit的智能战略收缩,使像素/ DPI比没有不变 + * --disallow-local-file-access 禁止允许转换的本地文件读取其他本地文件,除非explecitily允许用 --allow + * --dpi 显式更改DPI(这对基于X11的系统没有任何影响) + * --enable-plugins 启用已安装的插件(如Flash + * --encoding 设置默认的文字编码 + * --extended-help 显示更广泛的帮助,详细介绍了不常见的命令开关 + * --forms* 打开HTML表单字段转换为PDF表单域 + * --grayscale PDF格式将在灰阶产生 + * --help Display help + * --htmldoc 输出程序HTML帮助 + * --ignore-load-errors 忽略claimes加载过程中已经遇到了一个错误页面 + * --lowquality 产生低品质的PDF/ PS。有用缩小结果文档的空间 + * --manpage 输出程序手册页 + * --margin-bottom 设置页面下边距 (default 10mm) + * --margin-left 将左边页边距 (default 10mm) + * --margin-right 设置页面右边距 (default 10mm) + * --margin-top 设置页面上边距 (default 10mm) + * --minimum-font-size <) + * --no-background 不打印背景 + * --orientation 设置方向为横向或纵向 + * --page-height 页面高度 (default unit millimeter) + * --page-offset* 设置起始页码 (default ) + * --page-size 设置纸张大小: A4, Letter, etc. + * --page-width 页面宽度 (default unit millimeter) + * --password HTTP验证密码 + * --post Add an additional post field (repeatable) + * --post-file Post an aditional file (repeatable) + * --print-media-type* 使用的打印介质类型,而不是屏幕 + * --proxy 使用代理 + * --quiet Be less verbose + * --read-args-from-stdin 读取标准输入的命令行参数 + * --readme 输出程序自述 + * --redirect-delay 等待几毫秒为JS-重定向(default ) + * --replace* 替换名称,值的页眉和页脚(可重复) + * --stop-slow-scripts 停止运行缓慢的JavaScripts + * --title 生成的PDF文件的标题(第一个文档的标题使用,如果没有指定) + * --toc* 插入的内容的表中的文件的开头 + * --use-xserver* 使用X服务器(一些插件和其他的东西没有X11可能无法正常工作) + * --user-style-sheet 指定用户的样式表,加载在每一页中 + * --username HTTP认证的用户名 + * --version 输出版本信息退出 + * --zoom <) + *

+ * 页眉和页脚选项 + * --header-center* (设置在中心位置的页眉内容) + * --header-font-name* (default Arial)(设置页眉的字体名称) + * --header-font-size* (设置页眉的字体大小) + * --header-html* (添加一个HTML页眉,后面是网址) + * --header-left* (左对齐的页眉文本) + * --header-line* (显示一条线在页眉下) + * --header-right* (右对齐页眉文本) + * --header-spacing* (设置页眉和内容的距离,默认0) + * --footer-center* (设置在中心位置的页脚内容) + * --footer-font-name* (设置页脚的字体名称) + * --footer-font-size* (设置页脚的字体大小default ) + * --footer-html* (添加一个HTML页脚,后面是网址) + * --footer-left* (左对齐的页脚文本) + * --footer-line* 显示一条线在页脚内容上) + * --footer-right* (右对齐页脚文本) + * --footer-spacing* (设置页脚和内容的距离) + *

+ * 页脚和页眉 + * [page] 由当前正在打印的页的数目代替 + * [frompage] 由要打印的第一页的数量取代 + * [topage] 由最后一页要打印的数量取代 + * [webpage] 通过正在打印的页面的URL替换 + * [section] 由当前节的名称替换 + * [subsection] 由当前小节的名称替换 + * [date] 由当前日期系统的本地格式取代 + * [time] 由当前时间,系统的本地格式取代 + *

+ * 轮廓选项 + * --dump-outline 转储目录到一个文件 + * --outline 显示目录(文章中h1,h2来定) + * --outline-depth 设置目录的深度(默认为4) + *

+ * 表内容选项中 + * --toc-depth* Set the depth of the toc (default) + * --toc-disable-back-links* Do not link from section header to toc + * --toc-disable-links* Do not link from toc to sections + * --toc-font-name* Set the font used for the toc (default Arial) + * --toc-header-font-name* The font of the toc header (if unset use --toc-font-name) + * --toc-header-font-size* The font size of the toc header (default) + * --toc-header-text* The header text of the toc (default Table Of Contents) + * --toc-l1-font-size* Set the font size on level of the toc (default) + * --toc-l1-indentation* Set indentation on level of the toc (default) + * --toc-l2-font-size* Set the font size on level of the toc (default) + * --toc-l2-indentation* Set indentation on level of the toc (default) + * --toc-l3-font-size* Set the font size on level of the toc (default) + * --toc-l3-indentation* Set indentation on level of the toc (default) + * --toc-l4-font-size* Set the font size on level of the toc (default) + * --toc-l4-indentation* Set indentation on level of the toc (default) + * --toc-l5-font-size* Set the font size on level of the toc (default) + * --toc-l5-indentation* Set indentation on level of the toc (default) + * --toc-l6-font-size* Set the font size on level of the toc (default) + * --toc-l6-indentation* Set indentation on level of the toc (default) + * --toc-l7-font-size* Set the font size on level of the toc (default) + * --toc-l7-indentation* Set indentation on level of the toc (default) + * --toc-no-dots* Do not use dots, in the toc + * ------------------------------------------------------------------------------------------------------------ + * @author liqiang + * @date 2021/05/12 + */ +public class WkHtmlToPdfUtil { + + /** + * 页面大小 + */ + public static String PAGE_SIZE_A4 = " --page-size A4 "; + /** + * 页码数字 + */ + public static String FOOTER_CENTER = " --footer-center \"第[page]页\" "; + + /** + * 页码大小 + */ + public static String FOOTER_FONT_SIZE =" --footer-font-size 10 "; + + /** + * 页码字体 + */ + public static String FOOTER_FONT_NAME =" --footer-font-name \"Microsoft YaHei\" "; + + /** + * 打印参数 + */ + public static String DPI = " --dpi 300 "; + + + public static String LOAD_ERROR_HANDLING_IGNORE = " --load-error-handling ignore "; + /** + * 关闭缩放 + */ + public static String DISABLE_SMART_SHRINKING = " --disable-smart-shrinking "; + + /** + * html转pdf + * + * @param srcPath html路径,可以是硬盘上的路径,也可以是网络路径 + * @param file pdf文件 + * @return 转换成功返回true + */ + public static boolean convert(String srcPath, File file,String toPdfTool,String params) { + + File parent = file.getParentFile(); + // 如果pdf保存路径不存在,则创建路径 + if (!parent.exists()) { + parent.mkdirs(); + } + StringBuilder cmd = new StringBuilder(); +// String toPdfTool; +// if (!System.getProperty("os.name").contains("Windows")) { +// // 根据系统 +// // 非windows 系统 +// toPdfTool = "/usr/local/bin/wkhtmltopdf"; +// } else { +// toPdfTool = "D:/htmlTopdf/wkhtmltopdf/bin/wkhtmltopdf.exe"; +// } + toPdfTool += "wkhtmltopdf "; + // 这里可以拼接页眉页脚等参数 参数详情在上方 + cmd.append(toPdfTool); + cmd.append(params); + cmd.append(srcPath); + cmd.append(" "); + cmd.append(file.getAbsolutePath()); + + boolean result = true; + try { + + Process proc = Runtime.getRuntime().exec(cmd.toString()); + HtmlToPdfInterceptor error = new HtmlToPdfInterceptor(proc.getErrorStream()); + HtmlToPdfInterceptor output = new HtmlToPdfInterceptor(proc.getInputStream()); + error.start(); + output.start(); + proc.waitFor(); + } catch (Exception e) { + result = false; + e.printStackTrace(); + } + return result; + } + + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java index 5c76e1a..29cc7e2 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java @@ -42,6 +42,7 @@ public class S3FileClient extends AbstractFileClient { client = (AmazonS3Client)AmazonS3ClientBuilder.standard() .withCredentials(buildCredentials()) .withEndpointConfiguration(buildEndpointConfiguration()) + .withPathStyleAccessEnabled(true) .build(); } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index 360e961..b542e0b 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -211,4 +211,6 @@ public interface ErrorCodeConstants { ErrorCode ROLE_ERROR = new ErrorCode(1-003-005-004, "请分配角色后再查看"); ErrorCode POLICY_NOT_EXISTS = new ErrorCode(1-003-006-001, "政策法规不存在"); + + ErrorCode JOB_INFO_NOT_EXISTS = new ErrorCode(1-003-007-001, "工作汇报不存在"); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/JobInfoController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/JobInfoController.java new file mode 100644 index 0000000..a47ff18 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/JobInfoController.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.system.controller.admin.jobinfo; + +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + + +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.system.controller.admin.jobinfo.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.jobinfo.JobInfoDO; +import cn.iocoder.yudao.module.system.service.jobinfo.JobInfoService; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; + +@Tag(name = "管理后台 - 工作汇报") +@RestController +@RequestMapping("/system/job-info") +@Validated +public class JobInfoController { + + @Resource + private JobInfoService jobInfoService; + + @PostMapping("/create") + @Operation(summary = "创建工作汇报") + public CommonResult createJobInfo(@Valid @RequestBody JobInfoSaveReqVO createReqVO) { + return success(jobInfoService.createJobInfo(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新工作汇报") + public CommonResult updateJobInfo(@Valid @RequestBody JobInfoSaveReqVO updateReqVO) { + jobInfoService.updateJobInfo(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除工作汇报") + @Parameter(name = "id", description = "编号", required = true) + public CommonResult deleteJobInfo(@RequestParam("id") Long id) { + jobInfoService.deleteJobInfo(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得工作汇报") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult getJobInfo(@RequestParam("id") Long id) { + JobInfoDO jobInfo = jobInfoService.getJobInfo(id); + return success(BeanUtils.toBean(jobInfo, JobInfoRespDetailVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得工作汇报分页") + public CommonResult> getJobInfoPage(@Valid JobInfoPageReqVO pageReqVO) { + PageResult pageResult = jobInfoService.getJobInfoPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, JobInfoRespVO.class)); + } + + @GetMapping("/jobDetail") + @Operation(summary = "获取详细信息") + public CommonResult getJobDetail(Long id) { + String s = jobInfoService.htmlToPdf(id); + return success(s); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出工作汇报 Excel") + @ApiAccessLog(operateType = EXPORT) + public void exportJobInfoExcel(@Valid JobInfoPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = jobInfoService.getJobInfoPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "工作汇报.xls", "数据", JobInfoRespVO.class, + BeanUtils.toBean(list, JobInfoRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoPageReqVO.java new file mode 100644 index 0000000..4ace346 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoPageReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.controller.admin.jobinfo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 工作汇报分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class JobInfoPageReqVO extends PageParam { + + @Schema(description = "汇报标题") + private String title; + + @Schema(description = "汇报人姓名", example = "赵六") + private String jobName; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "pdfURl") + private String pdfUrl; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoRespDetailVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoRespDetailVO.java new file mode 100644 index 0000000..e44b07f --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoRespDetailVO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.system.controller.admin.jobinfo.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 工作汇报 Response VO") +@Data +@ExcelIgnoreUnannotated +public class JobInfoRespDetailVO { + + @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26792") + @ExcelProperty("id") + private Long id; + + @Schema(description = "汇报标题") + @ExcelProperty("汇报标题") + private String title; + + @Schema(description = "汇报详情") + private String content; + + @Schema(description = "汇报日期") + @ExcelProperty("汇报日期") + @JsonSerialize(using = LocalDateSerializer.class) // 序列化(响应) + @JsonDeserialize(using = LocalDateDeserializer.class) // 反序列化(请求) + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate jobDate; + + @Schema(description = "汇报人姓名", example = "赵六") + @ExcelProperty("汇报人姓名") + private String jobName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "pdfURl") + private String pdfUrl; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoRespVO.java new file mode 100644 index 0000000..7a50749 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoRespVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.system.controller.admin.jobinfo.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDate; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - 工作汇报 Response VO") +@Data +@ExcelIgnoreUnannotated +public class JobInfoRespVO { + + @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26792") + @ExcelProperty("id") + private Long id; + + @Schema(description = "汇报标题") + @ExcelProperty("汇报标题") + private String title; + + @Schema(description = "汇报日期") + @ExcelProperty("汇报日期") + @JsonSerialize(using = LocalDateSerializer.class) // 序列化(响应) + @JsonDeserialize(using = LocalDateDeserializer.class) // 反序列化(请求) + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate jobDate; + + @Schema(description = "汇报人姓名", example = "赵六") + @ExcelProperty("汇报人姓名") + private String jobName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "pdfURl") + private String pdfUrl; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoSaveReqVO.java new file mode 100644 index 0000000..a72e31d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/jobinfo/vo/JobInfoSaveReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.controller.admin.jobinfo.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDate; +import java.util.*; + +@Schema(description = "管理后台 - 工作汇报新增/修改 Request VO") +@Data +public class JobInfoSaveReqVO { + + @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26792") + private Long id; + + @Schema(description = "汇报标题") + private String title; + + @Schema(description = "汇报内容") + private String content; + + @Schema(description = "汇报日期") + @JsonSerialize(using = LocalDateSerializer.class) // 序列化(响应) + @JsonDeserialize(using = LocalDateDeserializer.class) // 反序列化(请求) + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate jobDate; + + @Schema(description = "汇报人姓名", example = "赵六") + private String jobName; + + @Schema(description = "pdfURl") + private String pdfUrl; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/jobinfo/JobInfoDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/jobinfo/JobInfoDO.java new file mode 100644 index 0000000..62b5f97 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/jobinfo/JobInfoDO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.jobinfo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDate; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 工作汇报 DO + * + * @author 芋道源码 + */ +@TableName("hb_job_info") +@KeySequence("hb_job_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class JobInfoDO extends BaseDO { + + /** + * id + */ + @TableId + private Long id; + /** + * 汇报标题 + */ + private String title; + /** + * 汇报内容 + */ + private String content; + /** + * 汇报日期 + */ + private LocalDate jobDate; + /** + * 汇报人姓名 + */ + private String jobName; + + /** + * pdfUrl + */ + private String pdfUrl; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/jobinfo/JobInfoMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/jobinfo/JobInfoMapper.java new file mode 100644 index 0000000..28b7566 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/jobinfo/JobInfoMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.dal.mysql.jobinfo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.system.dal.dataobject.jobinfo.JobInfoDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.system.controller.admin.jobinfo.vo.*; + +/** + * 工作汇报 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface JobInfoMapper extends BaseMapperX { + + default PageResult selectPage(JobInfoPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(JobInfoDO::getTitle, reqVO.getTitle()) + .likeIfPresent(JobInfoDO::getJobName, reqVO.getJobName()) + .betweenIfPresent(JobInfoDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(JobInfoDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/jobinfo/JobInfoService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/jobinfo/JobInfoService.java new file mode 100644 index 0000000..d087b86 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/jobinfo/JobInfoService.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.system.service.jobinfo; + +import java.util.*; +import cn.iocoder.yudao.module.system.controller.admin.jobinfo.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.jobinfo.JobInfoDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +import javax.validation.Valid; + +/** + * 工作汇报 Service 接口 + * + * @author 芋道源码 + */ +public interface JobInfoService { + + /** + * 创建工作汇报 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createJobInfo(@Valid JobInfoSaveReqVO createReqVO); + + /** + * 更新工作汇报 + * + * @param updateReqVO 更新信息 + */ + void updateJobInfo(@Valid JobInfoSaveReqVO updateReqVO); + + /** + * 删除工作汇报 + * + * @param id 编号 + */ + void deleteJobInfo(Long id); + + /** + * 获得工作汇报 + * + * @param id 编号 + * @return 工作汇报 + */ + JobInfoDO getJobInfo(Long id); + + /** + * 获得工作汇报分页 + * + * @param pageReqVO 分页查询 + * @return 工作汇报分页 + */ + PageResult getJobInfoPage(JobInfoPageReqVO pageReqVO); + + //使用胡tool的TemplateEngine 填充jobTemp 并保存到本地 + String htmlToPdf(Long id); +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/jobinfo/JobInfoServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/jobinfo/JobInfoServiceImpl.java new file mode 100644 index 0000000..9ae3f1a --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/jobinfo/JobInfoServiceImpl.java @@ -0,0 +1,139 @@ +package cn.iocoder.yudao.module.system.service.jobinfo; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Dict; +import cn.hutool.extra.template.Template; +import cn.hutool.extra.template.TemplateConfig; +import cn.hutool.extra.template.TemplateEngine; +import cn.hutool.extra.template.TemplateUtil; +import cn.iocoder.yudao.framework.common.util.pdf.WkHtmlToPdfUtil; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import cn.iocoder.yudao.module.infra.api.file.dto.InfraFileInfoDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import cn.iocoder.yudao.module.system.controller.admin.jobinfo.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.jobinfo.JobInfoDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.system.dal.mysql.jobinfo.JobInfoMapper; + +import javax.annotation.Resource; + +import java.io.File; +import java.io.IOException; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 工作汇报 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class JobInfoServiceImpl implements JobInfoService { + + @Value("${yudao.htmlToPdf.tools}") + private String htmlToPdfTools; + + @Value("${yudao.htmlToPdf.jobTemp}") + private String htmlToPdfJobTemp; + + + @Resource + private FileApi fileApi; + + @Resource + private JobInfoMapper jobInfoMapper; + + @Override + public Long createJobInfo(JobInfoSaveReqVO createReqVO) { + // 插入 + JobInfoDO jobInfo = BeanUtils.toBean(createReqVO, JobInfoDO.class); + jobInfoMapper.insert(jobInfo); + // 返回 + return jobInfo.getId(); + } + + @Override + public void updateJobInfo(JobInfoSaveReqVO updateReqVO) { + // 校验存在 + validateJobInfoExists(updateReqVO.getId()); + // 更新 + JobInfoDO updateObj = BeanUtils.toBean(updateReqVO, JobInfoDO.class); + jobInfoMapper.updateById(updateObj); + } + + @Override + public void deleteJobInfo(Long id) { + // 校验存在 + validateJobInfoExists(id); + // 删除 + jobInfoMapper.deleteById(id); + } + + private void validateJobInfoExists(Long id) { + if (jobInfoMapper.selectById(id) == null) { + throw exception(JOB_INFO_NOT_EXISTS); + } + } + + @Override + public JobInfoDO getJobInfo(Long id) { + return jobInfoMapper.selectById(id); + } + + @Override + public PageResult getJobInfoPage(JobInfoPageReqVO pageReqVO) { + return jobInfoMapper.selectPage(pageReqVO); + } + + //使用胡tool的TemplateEngine 填充jobTemp 并保存到本地 + @Override + public String htmlToPdf(Long id) { + JobInfoDO jobInfo = getJobInfo(id); + //根据jobTemp 打开文件 + TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig(htmlToPdfJobTemp, TemplateConfig.ResourceMode.FILE)); + + Template template = engine.getTemplate("jobTemp.html"); + Dict content1 = Dict.create().set("content", jobInfo.getContent()); + content1.set("jobName",jobInfo.getJobName()); + content1.set("jobDate", DateUtil.format(jobInfo.getJobDate().atStartOfDay(),"YYYY.MM.DD")); + + String content = template.render(content1); + + // 写入文件并返回File对象 + File file = FileUtil.writeUtf8String(content, htmlToPdfJobTemp + jobInfo.getTitle()+".html"); + // 调用wkhtmltopdf工具转换为pdf + // 这里的htmlToPdfTools是wkhtmltopdf的工具路径,htmlToPdfJobTemp是html文件路径,test.pdf是输出pdf文件路径 + File file1 = new File(htmlToPdfJobTemp + jobInfo.getTitle()+".pdf"); + + String params = WkHtmlToPdfUtil.DPI + WkHtmlToPdfUtil.PAGE_SIZE_A4 + WkHtmlToPdfUtil.DISABLE_SMART_SHRINKING+WkHtmlToPdfUtil.LOAD_ERROR_HANDLING_IGNORE; + + WkHtmlToPdfUtil.convert(htmlToPdfJobTemp + jobInfo.getTitle()+".html", file1, "",params); + + try{ + InfraFileInfoDTO file2 = fileApi.createFile(FileUtil.readBytes(file1)); + jobInfo.setPdfUrl(file2.getUrl()); + jobInfoMapper.updateById(jobInfo); + //等待3秒后异步删除 + FileUtil.del(file); + FileUtil.del(file1); + + }catch (Exception e) { + + log.info(e.toString()); + } + + return content; + } + + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/jobinfo/JobInfoMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/jobinfo/JobInfoMapper.xml new file mode 100644 index 0000000..4385de6 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/jobinfo/JobInfoMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index a65e886..038087f 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -176,6 +176,9 @@ yudao: transfer-notify-url: https://yunai.natapp1.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址 demo: false # 开启演示模式 tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc + htmlToPdf: + tools: D:\Program Files\wkhtmltopdf\bin #wkhtmltopdf 的安装路径 + jobTemp: D:\demo\ #模板文件路径 justauth: enabled: true diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 863011f..d598a75 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -228,6 +228,9 @@ yudao: wxa-subscribe-message: miniprogram-state: developer # 跳转小程序类型:开发版为 “developer”;体验版为 “trial”为;正式版为 “formal” tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc + htmlToPdf: + tools: D:\Program Files\wkhtmltopdf\bin #wkhtmltopdf 的安装路径 + jobTemp: D:\demo\ #模板文件路径 justauth: enabled: true