From 42c8b75721df9eee7200a64476a7b1af24da186b Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Thu, 6 Nov 2025 18:09:57 +0800 Subject: [PATCH 01/11] =?UTF-8?q?docs:=20=E5=AE=8C=E5=96=84=E5=8D=95?= =?UTF-8?q?=E4=BD=8D=E8=BD=AC=E6=8D=A2=E7=B3=BB=E7=BB=9F=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=96=87=E6=A1=A3=EF=BC=8C=E6=B7=BB=E5=8A=A0Feign=E8=B7=A8?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E8=B0=83=E7=94=A8=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 补充Feign客户端接口定义示例 - 补充跨服务调用的具体实现示例 - 修正常见问题Q1中的API端点路径为正确的 /unt-info/page 🤖 Generated with Claude Code Co-Authored-By: Claude --- .../doctemplate/DocumentRenderApiService.java | 72 +++++ .../DocumentRenderApiServiceImpl.java | 257 ++++++++++++++++++ 单位转换系统使用文档.md | 224 +++++++++++++++ 3 files changed, 553 insertions(+) create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiService.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiServiceImpl.java create mode 100644 单位转换系统使用文档.md diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiService.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiService.java new file mode 100644 index 0000000..b918cbc --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiService.java @@ -0,0 +1,72 @@ +package com.zt.plat.module.base.service.doctemplate; + +import java.util.Map; + +/** + * 文档渲染API服务 + * 供业务模块调用,支持多种渲染方式 + * + * @author system + */ +public interface DocumentRenderApiService { + + /** + * 根据模板ID渲染 (方式1:直接模板渲染) + * + * @param templateId 模板ID + * @param dataMap 数据Map + * @return 渲染后的HTML + */ + String renderByTemplate(Long templateId, Map dataMap); + + /** + * 根据实例ID渲染 (方式2:实例渲染) + * 优先使用实例的editedContent,如果为空则使用模板内容 + * + * @param instanceId 实例ID + * @param dataMap 数据Map + * @return 渲染后的HTML + */ + String renderByInstance(Long instanceId, Map dataMap); + + /** + * 根据业务类型渲染 (方式3:业务接入渲染) + * 业务系统可根据业务类型自定义数据集和渲染逻辑 + * + * @param instanceId 实例ID + * @param businessType 业务类型 (如: 'PURCHASE_ORDER', 'SALES_ORDER' 等) + * @param businessDataMap 业务数据Map (由业务系统自己组织) + * @return 渲染后的HTML + */ + String renderByBusinessType(Long instanceId, String businessType, Map businessDataMap); + + /** + * 根据直接内容渲染 (方式4:前端预览) + * 用于前端编辑时的实时预览,使用标签默认值 + * + * @param content 模板内容 (HTML/Velocity语法) + * @param dataMap 数据Map (标签默认值) + * @return 渲染后的HTML + */ + String renderByContent(String content, Map dataMap); + + /** + * 将HTML导出为Word文档 + * + * @param html HTML内容 + * @param fileName 文件名 (不需要后缀,自动添加.docx) + * @return Word文件字节数组 + */ + byte[] exportToWord(String html, String fileName); + + /** + * 渲染并导出为Word (一步完成) + * + * @param instanceId 实例ID + * @param dataMap 数据Map + * @param fileName 导出文件名 + * @return Word文件字节数组 + */ + byte[] renderAndExportToWord(Long instanceId, Map dataMap, String fileName); + +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiServiceImpl.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiServiceImpl.java new file mode 100644 index 0000000..f599b5d --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiServiceImpl.java @@ -0,0 +1,257 @@ +package com.zt.plat.module.base.service.doctemplate; + +import cn.hutool.core.util.StrUtil; +import com.zt.plat.module.base.dal.dataobject.doctemplate.DocTemplateDO; +import com.zt.plat.module.base.dal.dataobject.doctemplate.DocTemplateInstanceDO; +import com.zt.plat.module.base.dal.dao.doctemplate.DocTemplateMapper; +import com.zt.plat.module.base.dal.dao.doctemplate.DocTemplateInstanceMapper; +import lombok.extern.slf4j.Slf4j; +import org.docx4j.Docx4J; +import org.docx4j.openpackaging.packages.WordprocessingMLPackage; +import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; +import org.docx4j.wml.*; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.Node; +import org.jsoup.nodes.TextNode; +import org.jsoup.select.Elements; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.io.ByteArrayOutputStream; +import java.util.Map; + +import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.zt.plat.module.base.enums.ErrorCodeConstants.*; + +/** + * 文档渲染API服务实现类 + * 使用 docx4j 库处理 Word 导出,支持多种渲染方式 + * + * @author system + */ +@Service +@Slf4j +public class DocumentRenderApiServiceImpl implements DocumentRenderApiService { + + @Resource + private DocTemplateRenderService templateRenderService; + + @Resource + private DocTemplateMapper templateMapper; + + @Resource + private DocTemplateInstanceMapper instanceMapper; + + @Override + public String renderByTemplate(Long templateId, Map dataMap) { + if (templateId == null) { + throw new IllegalArgumentException("模板ID不能为空"); + } + DocTemplateDO template = templateMapper.selectById(templateId); + if (template == null) { + throw exception(TEMPLATE_NOT_EXISTS); + } + return templateRenderService.render(templateId, null, null, dataMap); + } + + @Override + public String renderByInstance(Long instanceId, Map dataMap) { + if (instanceId == null) { + throw new IllegalArgumentException("实例ID不能为空"); + } + DocTemplateInstanceDO instance = instanceMapper.selectById(instanceId); + if (instance == null) { + throw exception(TEMPLATE_INSTANCE_NOT_EXISTS); + } + return templateRenderService.render(null, instanceId, null, dataMap); + } + + @Override + public String renderByBusinessType(Long instanceId, String businessType, Map businessDataMap) { + if (instanceId == null) { + throw new IllegalArgumentException("实例ID不能为空"); + } + if (StrUtil.isBlank(businessType)) { + throw new IllegalArgumentException("业务类型不能为空"); + } + + // 获取实例信息 + DocTemplateInstanceDO instance = instanceMapper.selectById(instanceId); + if (instance == null) { + throw exception(TEMPLATE_INSTANCE_NOT_EXISTS); + } + + // 业务系统自己组织的dataMap,可以包含SQL查询结果、业务数据等 + // 直接使用该dataMap进行渲染 + if (businessDataMap == null || businessDataMap.isEmpty()) { + log.warn("业务数据集为空,instanceId: {}, businessType: {}", instanceId, businessType); + businessDataMap = Map.of(); + } + + return templateRenderService.render(null, instanceId, null, businessDataMap); + } + + @Override + public String renderByContent(String content, Map dataMap) { + if (StrUtil.isBlank(content)) { + throw new IllegalArgumentException("模板内容不能为空"); + } + return templateRenderService.render(null, null, content, dataMap); + } + + @Override + public byte[] exportToWord(String html, String fileName) { + if (StrUtil.isBlank(html)) { + throw new IllegalArgumentException("HTML内容不能为空"); + } + if (StrUtil.isBlank(fileName)) { + fileName = "document"; + } + + try { + // 创建 Word 文档 + WordprocessingMLPackage wordPackage = WordprocessingMLPackage.createPackage(); + MainDocumentPart mainDocumentPart = wordPackage.getMainDocumentPart(); + + // 解析 HTML + Document htmlDoc = Jsoup.parse(html); + + // 处理 HTML 内容并添加到 Word 文档 + processHtmlToWord(mainDocumentPart, htmlDoc.body()); + + // 转换为字节数组 + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + wordPackage.save(baos); + + log.info("Word导出成功,文件名: {}.docx, 大小: {} bytes", fileName, baos.size()); + return baos.toByteArray(); + + } catch (Exception e) { + log.error("Word导出失败,fileName: {}", fileName, e); + throw new RuntimeException("Word导出失败: " + e.getMessage(), e); + } + } + + @Override + public byte[] renderAndExportToWord(Long instanceId, Map dataMap, String fileName) { + // 先渲染获取HTML + String html = renderByInstance(instanceId, dataMap); + // 再导出为Word + return exportToWord(html, fileName); + } + + /** + * 将 HTML 转换为 Word 文档内容 + * 递归处理 HTML 节点,使用 docx4j API 构建完整的 Word 文档 + */ + private void processHtmlToWord(MainDocumentPart mainDocumentPart, Element element) throws Exception { + for (Node node : element.childNodes()) { + if (node instanceof TextNode) { + String text = ((TextNode) node).getWholeText(); + if (StrUtil.isNotBlank(text.trim())) { + mainDocumentPart.addStyledParagraphOfText("Normal", text.trim()); + } + } else if (node instanceof Element) { + Element element1 = (Element) node; + String tagName = element1.tagName().toLowerCase(); + + switch (tagName) { + case "h1", "h2", "h3", "h4", "h5", "h6" -> { + String styleId = "Heading" + tagName.substring(1); + mainDocumentPart.addStyledParagraphOfText(styleId, element1.text()); + } + case "p" -> { + mainDocumentPart.addStyledParagraphOfText("Normal", element1.text()); + } + case "br" -> { + mainDocumentPart.addParagraphOfText(""); + } + case "table" -> { + processTable(mainDocumentPart, (Element) node); + } + case "ul", "ol" -> { + processHtmlToWord(mainDocumentPart, element1); + } + case "li" -> { + mainDocumentPart.addParagraphOfText("• " + element1.text()); + } + case "strong", "b" -> { + mainDocumentPart.addStyledParagraphOfText("Normal", element1.text()); + } + case "i", "em" -> { + mainDocumentPart.addStyledParagraphOfText("Normal", element1.text()); + } + case "div", "section", "article" -> { + processHtmlToWord(mainDocumentPart, element1); + } + default -> { + processHtmlToWord(mainDocumentPart, element1); + } + } + } + } + } + + /** + * 处理表格 + * 使用 docx4j 的 Table 和 Tbl API 创建 Word 表格 + */ + private void processTable(MainDocumentPart mainDocumentPart, Element tableElement) throws Exception { + Elements rows = tableElement.select("tr"); + if (rows.isEmpty()) { + return; + } + + try { + ObjectFactory factory = new ObjectFactory(); + Tbl tbl = factory.createTbl(); + + // 设置表格属性 + TblPr tblPr = factory.createTblPr(); + tbl.setTblPr(tblPr); + + // 处理每一行 + for (Element row : rows) { + Elements cells = row.select("td, th"); + Tr tr = factory.createTr(); + + for (Element cell : cells) { + Tc tc = factory.createTc(); + TcPr tcPr = factory.createTcPr(); + tc.setTcPr(tcPr); + + // 添加单元格内容 + P cellParagraph = factory.createP(); + R cellRun = factory.createR(); + Text cellText = factory.createText(); + cellText.setValue(cell.text()); + cellRun.getContent().add(cellText); + cellParagraph.getContent().add(cellRun); + tc.getContent().add(cellParagraph); + + tr.getContent().add(tc); + } + + tbl.getContent().add(tr); + } + + // 将表格添加到文档 + mainDocumentPart.getContent().add(tbl); + + } catch (Exception e) { + log.warn("表格处理失败,跳过表格内容", e); + // 降级处理:将表格内容作为文本添加 + for (Element row : rows) { + Elements cells = row.select("td, th"); + StringBuilder rowText = new StringBuilder(); + for (Element cell : cells) { + rowText.append(cell.text()).append(" | "); + } + mainDocumentPart.addParagraphOfText(rowText.toString()); + } + } + } + +} diff --git a/单位转换系统使用文档.md b/单位转换系统使用文档.md new file mode 100644 index 0000000..9defe88 --- /dev/null +++ b/单位转换系统使用文档.md @@ -0,0 +1,224 @@ +# 单位转换系统业务使用文档 + +## 一、系统概述 + +单位转换系统提供统一的计量单位转换服务,支持同一量纲内的单位自动转换。采用**单向配置、双向生效**机制,只需配置"非基准单位 → 基准单位"的转换规则,系统自动推导反向和间接转换。 + +**核心特性**: +- 单向配置、双向生效的转换机制 +- 支持按单位ID、符号、名称进行转换 +- 高精度计算,支持批量操作 +- 跨模块统一服务 + +## 二、内容配置 + +### 2.1 管理菜单路径 +后台管理 → 基础管理 → 计量单位 → 计量单位管理 + +### 2.2 配置功能 + +#### 计量量纲管理 +- **功能**:创建和管理不同的量纲类型(如重量、长度、体积等) +- **操作**:新增量纲、编辑量纲信息、删除量纲 +- **每个量纲只能设置一个基准单位** + +#### 计量单位管理 +- **功能**:创建和管理具体的计量单位 +- **操作**:新增单位、编辑单位信息、删除单位 +- **关联量纲**:将单位归属到具体的量纲下 + +#### 转换规则配置 +- **功能**:配置单位间的转换规则 +- **配置原则**:只需配置"非基准单位 → 基准单位" +- **自动推导**:系统自动推导反向转换和间接转换 + +#### 预置数据 +系统已预置常用量纲和单位: +- **重量量纲**:千克(基准)、吨、克 +- **长度量纲**:米(基准)、千米、厘米、毫米 +- **体积量纲**:立方米(基准)、升、毫升 +- **面积量纲**:平方米(基准)、平方千米、公顷 +- **时间量纲**:秒(基准)、分钟、小时、天 + +### 2.3 配置建议 + +1. **量纲规划**:提前规划好业务需要的量纲类型 +2. **基准单位选择**:选择业务中最常用、最稳定的单位作为基准 +3. **转换规则**:优先使用整数转换系数,提高计算精度 +4. **定期校验**:使用转换路径校验功能确保配置正确性 +5. **转换完整性校验**:系统提供同一量纲内所有单位能否互相转换的校验功能,确保转换配置的完整性 + +## 三、API接口清单 + +### 3.1 单位管理接口 + +| 接口 | 方法 | 路径 | 说明 | API文档 | +|------|------|------|------|---------| +| 获取量纲树 | GET | `/admin-api/base/unit-management/unit-quantity/tree` | 获取量纲和单位树形结构 | [文档](http://172.16.46.63:30081/doc.html#/base-server/%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%20-%20%E8%AE%A1%E9%87%8F%E5%8D%95%E4%BD%8D%E9%87%8F/getTree) | +| 获取单位列表 | GET | `/admin-api/base/unit-management/unt-info/page` | 获取单位列表(用于下拉选择) | [文档](http://172.16.46.63:30081/doc.html#/base-server/%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%20-%20%E8%AE%A1%E9%87%8F%E5%8D%95%E4%BD%8D/getPage) | + +### 3.2 单位转换接口 + +| 接口 | 方法 | 路径 | 说明 | API文档 | +|------|------|------|------|---------| +| 按ID转换单位 | POST | `/admin-api/base/unit-management/unit-conversion/convert` | 通过单位ID转换 | [文档](http://172.16.46.63:30081/doc.html#/base-server/%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%20-%20%E5%8D%95%E4%BD%8D%E8%BD%AC%E6%8D%A2/convert) | +| 按符号转换单位 | POST | `/admin-api/base/unit-management/unit-conversion/convert-by-symbol` | 通过单位符号转换 | [文档](http://172.16.46.63:30081/doc.html#/base-server/%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%20-%20%E5%8D%95%E4%BD%8D%E8%BD%AC%E6%8D%A2/convertBySymbol) | +| 按名称转换单位 | POST | `/admin-api/base/unit-management/unit-conversion/convert-by-name` | 通过单位名称转换 | [文档](http://172.16.46.63:30081/doc.html#/base-server/%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%20-%20%E5%8D%95%E4%BD%8D%E8%BD%AC%E6%8D%A2/convertByName) | +| 批量ID转换 | POST | `/admin-api/base/unit-management/unit-conversion/batch-convert` | 按ID批量转换 | [文档](http://172.16.46.63:30081/doc.html#/base-server/%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%20-%20%E5%8D%95%E4%BD%8D%E8%BD%AC%E6%8D%A2/batchConvert) | +| 批量符号转换 | POST | `/admin-api/base/unit-management/unit-conversion/batch-convert-by-symbol` | 按符号批量转换 | [文档](http://172.16.46.63:30081/doc.html#/base-server/%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%20-%20%E5%8D%95%E4%BD%8D%E8%BD%AC%E6%8D%A2/batchConvertBySymbol) | +| 批量名称转换 | POST | `/admin-api/base/unit-management/unit-conversion/batch-convert-by-name` | 按名称批量转换 | [文档](http://172.16.46.63:30081/doc.html#/base-server/%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%20-%20%E5%8D%95%E4%BD%8D%E8%BD%AC%E6%8D%A2/batchConvertByName) | + + +--- + +## 三、业务调用示例 + +### 合同订单模块使用 + +```java +@Service +public class PurchaseOrderServiceImpl { + + @Resource + private UnitConversionService unitConversionService; + + /** + * 处理采购订单,统一转换为千克计算 + */ + public void processPurchaseOrder(PurchaseOrderSaveReqVO orderVO) { + for (PurchaseOrderDetailVO detail : orderVO.getDetails()) { + // 方式1:按符号转换 + UnitConvertBySymbolReqVO convertReq = new UnitConvertBySymbolReqVO(); + convertReq.setSrcUnitSymbol(detail.getUnt()); + convertReq.setTgtUnitSymbol("kg"); + convertReq.setValue(detail.getQty()); + convertReq.setPrecision(6); + + UnitConvertRespVO result = unitConversionService.convertBySymbol(convertReq); + BigDecimal standardQuantity = result.getConvertedValue(); + + // 方式2:按ID转换(如果有单位ID) + // UnitConvertReqVO convertReq = new UnitConvertReqVO(); + // convertReq.setSrcUntId(detail.getUntId()); + // convertReq.setTgtUntId(kgUnitId); + // ... + } + } +} +``` + +--- + +## 四、跨模块调用 + +### 4.1 直接Service调用(推荐) + +在同一服务内直接注入使用: +```java +@Resource +private UnitConversionService unitConversionService; +``` + +### 4.2 跨服务调用(按需使用) + +**1. 在 API 模块中定义 Feign 接口:** + +```java +package com.zt.plat.module.base.api; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.base.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +@FeignClient(name = ApiConstants.NAME) +@Tag(name = "RPC 服务 - 单位转换") +public interface UnitConversionApi { + + String PREFIX = ApiConstants.PREFIX + "/unit-conversion"; + + @PostMapping(PREFIX + "/convert") + @Operation(summary = "按ID转换单位") + CommonResult convert(@RequestBody UnitConvertReqVO reqVO); + + @PostMapping(PREFIX + "/convert-by-symbol") + @Operation(summary = "按符号转换单位") + CommonResult convertBySymbol(@RequestBody UnitConvertBySymbolReqVO reqVO); +} +``` + +**2. 在其他服务中调用:** + +```java +@Service +public class PurchaseServiceImpl { + + @Resource + private UnitConversionApi unitConversionApi; + + public void processPurchase(PurchaseVO purchase) { + UnitConvertBySymbolReqVO convertReq = new UnitConvertBySymbolReqVO(); + convertReq.setSrcUnitSymbol(purchase.getUnit()); + convertReq.setTgtUnitSymbol("kg"); + convertReq.setValue(purchase.getQuantity()); + convertReq.setPrecision(6); + + CommonResult result = unitConversionApi.convertBySymbol(convertReq); + if (result.isSuccess()) { + BigDecimal standardQty = result.getData().getConvertedValue(); + // 业务处理 + } + } +} +``` + +--- + +## 五、前端使用 + +### 5.1 基本API调用 + +```typescript +// 获取量纲树 +export const getUnitQuantityTree = () => { + return request.get('/admin-api/base/unit-management/unit-quantity/tree') +} + +// 获取单位列表 +export const getUntInfoPage = (params: any) => { + return request.get('/admin-api/base/unit-management/unt-info/page', { params }) +} + +// 单位转换 +export const convertUnitBySymbol = (data: any) => { + return request.post('/admin-api/base/unit-management/unit-conversion/convert-by-symbol', data) +} +``` + +--- + +## 六、常见问题 + +**Q1: 前端如何获取单位选项?** + +A: 使用 `/admin-api/base/unit-management/unit-quantity/tree` 获取量纲树,然后根据选择的量纲调用 `/admin-api/base/unit-management/unt-info/page` 获取单位列表。 + +**Q2: 按ID转换和按符号转换哪个更好?** + +A: 按ID转换更稳定,因为数据库ID不会变化。建议在前端保存单位ID,在业务转换时使用ID调用。 + +**Q3: 跨服务调用需要特殊配置吗?** + +A: 不需要,项目已经统一配置好。所有Feign客户端都使用 `name = "base-server"`,路径使用 `/rpc-api` 前缀。 + +**Q4: 批量转换性能问题?** + +A: 使用批量接口,设置ignoreErrors=true。 + +--- + +**更新时间**: 2025-11-06 +**版本**: v6.0 (修正版) \ No newline at end of file From e757aa49049912ca10d333f29080ee6158360835 Mon Sep 17 00:00:00 2001 From: guojunyun Date: Fri, 7 Nov 2025 17:40:46 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=85=B1=E4=BA=AB?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/RestTemplateConfig.java | 34 ++ .../module/contractorder/util/RedisUtil.java | 565 ++++++++++++++++++ .../contractorder/util/ShareServiceUtil.java | 129 ++++ 3 files changed, 728 insertions(+) create mode 100644 zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/config/RestTemplateConfig.java create mode 100644 zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/RedisUtil.java create mode 100644 zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/ShareServiceUtil.java diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/config/RestTemplateConfig.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/config/RestTemplateConfig.java new file mode 100644 index 0000000..b382726 --- /dev/null +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/config/RestTemplateConfig.java @@ -0,0 +1,34 @@ +package com.zt.plat.module.contractorder.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.web.client.RestTemplate; + +import java.nio.charset.Charset; + +/** + * RestTemplate配置类 + * @author ChenZhaoxue + * @date 2025/3/27 + */ +@Configuration +public class RestTemplateConfig { + + @Bean + public RestTemplate restTemplate(ClientHttpRequestFactory factory){ + RestTemplate restTemplate = new RestTemplate(factory); + restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("UTF-8"))); + return restTemplate; + } + + @Bean + public ClientHttpRequestFactory simpleClientHttpRequestFactory(){ + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setConnectTimeout(10000);//单位为ms + factory.setReadTimeout(30000);//单位为ms + return factory; + } +} diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/RedisUtil.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/RedisUtil.java new file mode 100644 index 0000000..5b925b3 --- /dev/null +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/RedisUtil.java @@ -0,0 +1,565 @@ +package com.zt.plat.module.contractorder.util; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * redis 工具类 + * + */ +@Slf4j +@Component +public class RedisUtil { + + @Autowired + private RedisTemplate redisTemplate; + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + * @return + */ + public boolean expire(String key, long time) { + try { + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 根据key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public long getExpire(String key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + /** + * 判断key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public boolean hasKey(String key) { + try { + return redisTemplate.hasKey(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + @SuppressWarnings("unchecked") + public void del(String key) { + redisTemplate.delete(key); + } + + // ============================String============================= + /** + * 普通缓存获取 + * + * @param key 键 + * @return 值 + */ + public Object get(String key) { + return key == null ? null : redisTemplate.opsForValue().get(key); + } + + /** + * 普通缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public boolean set(String key, Object value) { + try { + redisTemplate.opsForValue().set(key, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + public boolean set(String key, Object value, long time) { + try { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 递增 + * + * @param key 键 + * @param by 要增加几(大于0) + * @return + */ + public long incr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递增因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, delta); + } + + /** + * 递减 + * + * @param key 键 + * @param by 要减少几(小于0) + * @return + */ + public long decr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递减因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, -delta); + } + + // ================================Map================================= + /** + * HashGet + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return 值 + */ + public Object hget(String key, String item) { + return redisTemplate.opsForHash().get(key, item); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + public Map hmget(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map map) { + try { + redisTemplate.opsForHash().putAll(key, map); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * HashSet 并设置时间 + * + * @param key 键 + * @param map 对应多个键值 + * @param time 时间(秒) + * @return true成功 false失败 + */ + public boolean hmset(String key, Map map, long time) { + try { + redisTemplate.opsForHash().putAll(key, map); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value) { + try { + redisTemplate.opsForHash().put(key, item, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value, long time) { + try { + redisTemplate.opsForHash().put(key, item, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 删除hash表中的值 + * + * @param key 键 不能为null + * @param item 项 可以使多个 不能为null + */ + public void hdel(String key, Object... item) { + redisTemplate.opsForHash().delete(key, item); + } + + /** + * 判断hash表中是否有该项的值 + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return true 存在 false不存在 + */ + public boolean hHasKey(String key, String item) { + return redisTemplate.opsForHash().hasKey(key, item); + } + + /** + * hash递增 如果不存在,就会创建一个 并把新增后的值返回 + * + * @param key 键 + * @param item 项 + * @param by 要增加几(大于0) + * @return + */ + public double hincr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, by); + } + + /** + * hash递减 + * + * @param key 键 + * @param item 项 + * @param by 要减少记(小于0) + * @return + */ + public double hdecr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, -by); + } + + // ============================set============================= + /** + * 根据key获取Set中的所有值 + * + * @param key 键 + * @return + */ + public Set sGet(String key) { + try { + return redisTemplate.opsForSet().members(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * 根据value从一个set中查询,是否存在 + * + * @param key 键 + * @param value 值 + * @return true 存在 false不存在 + */ + public boolean sHasKey(String key, Object value) { + try { + return redisTemplate.opsForSet().isMember(key, value); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将数据放入set缓存 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSet(String key, Object... values) { + try { + return redisTemplate.opsForSet().add(key, values); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 将set数据放入缓存 + * + * @param key 键 + * @param time 时间(秒) + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSetAndTime(String key, long time, Object... values) { + try { + Long count = redisTemplate.opsForSet().add(key, values); + if (time > 0) { + expire(key, time); + } + return count; + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 获取set缓存的长度 + * + * @param key 键 + * @return + */ + public long sGetSetSize(String key) { + try { + return redisTemplate.opsForSet().size(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 移除值为value的 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 移除的个数 + */ + public long setRemove(String key, Object... values) { + try { + Long count = redisTemplate.opsForSet().remove(key, values); + return count; + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + // ===============================list================================= + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + * @return + */ + public List lGet(String key, long start, long end) { + try { + return redisTemplate.opsForList().range(key, start, end); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * 获取list缓存的长度 + * + * @param key 键 + * @return + */ + public long lGetListSize(String key) { + try { + return redisTemplate.opsForList().size(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 通过索引 获取list中的值 + * + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + * @return + */ + public Object lGetIndex(String key, long index) { + try { + return redisTemplate.opsForList().index(key, index); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, Object value) { + try { + redisTemplate.opsForList().rightPush(key, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, Object value, long time) { + try { + redisTemplate.opsForList().rightPush(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List value) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List value, long time) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 根据索引修改list中的某条数据 + * + * @param key 键 + * @param index 索引 + * @param value 值 + * @return + */ + public boolean lUpdateIndex(String key, long index, Object value) { + try { + redisTemplate.opsForList().set(key, index, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 移除N个值为value + * + * @param key 键 + * @param count 移除多少个 + * @param value 值 + * @return 移除的个数 + */ + public long lRemove(String key, long count, Object value) { + try { + Long remove = redisTemplate.opsForList().remove(key, count, value); + return remove; + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } +} diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/ShareServiceUtil.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/ShareServiceUtil.java new file mode 100644 index 0000000..5565b4e --- /dev/null +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/ShareServiceUtil.java @@ -0,0 +1,129 @@ +package com.zt.plat.module.contractorder.util; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +/** + * ePlat共享服务调用工具类 + * @author ChenZhaoxue + * @date 2025/3/27 + */ +@Slf4j +@Configuration +@Component +public class ShareServiceUtil { + private static final String SHARE_TOKEN_KEY = "eplat:cache:shareToken"; + private static final String SHARE_REFRESH_TOKEN_KEY = "eplat:cache:shareRefreshToken"; + private static final int TOKEN_TIME_OUT = 5000; // token过期时间,默认7200秒,这里设置建议小一些,如7000秒 + + @Value("${eplat.share.urlPrex}") + private String urlPrex; + @Value("${eplat.share.clientId}") + private String clientId; + @Value("${eplat.share.clientSecret}") + private String clientSecret; + + + @Resource + private RestTemplate restTemplate; + @Resource + private RedisUtil redisUtil; + + + /** + * ePlat共享服务调用 + * @param serviceNo 服务号 + * @param request 请求json字符串 + * @return + */ + public String callShareService(String serviceNo, String request) { + String url = String.format("%s/service/%s", urlPrex, serviceNo); + log.info("ePlat共享服务调用url:[" + url + "],request:[" + request + "]"); + String token = generateToken(); + log.info("目标token:" + token); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON_UTF8); + headers.add("Xplat-Token", token); + HttpEntity entity = new HttpEntity<>(request, headers); + ResponseEntity result = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); + return result.getBody(); + } + + private String generateToken() { + // 先从redis中获取未过期token + String token = (String) redisUtil.get(SHARE_TOKEN_KEY); + if (token == null) { + synchronized (ShareServiceUtil.class) { + token = (String) redisUtil.get(SHARE_TOKEN_KEY); + if (token == null) { + try { + token = refreshToken(); + } catch (Exception e) { + log.warn("生成token出错,可能刷新token有问题,重新尝试下", e); + redisUtil.del(SHARE_REFRESH_TOKEN_KEY); + token = refreshToken(); + } + } + } + } + return token; + } + + private String refreshToken() { + // 先从redis中获取未过期的刷新token + String refreshToken = (String) redisUtil.get(SHARE_REFRESH_TOKEN_KEY); + if (refreshToken == null) { + // 重新创建token和刷新token + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + // 构造form表单 + MultiValueMap paramsMap = new LinkedMultiValueMap<>(); + paramsMap.set("client_id", clientId); + paramsMap.set("client_secret", clientSecret); + paramsMap.set("grant_type", "client_credentials"); + paramsMap.set("scope", "read"); + String url = String.format("%s/eplat/oauth/token", urlPrex); + // 构造请求的实体。包含body和headers的内容 + HttpEntity> entity = new HttpEntity<>(paramsMap, headers); + log.info("获取token调用url:[" + url + "],request:[" + paramsMap + "]"); + ResponseEntity result = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); + JSONObject json = JSONUtil.parseObj(result.getBody()); + String accessToken = json.getStr("access_token"); + refreshToken = json.getStr("refresh_token"); + // 缓存token、刷新token(刷新token过期时间为2倍token过期时间) + redisUtil.set(SHARE_TOKEN_KEY, accessToken, TOKEN_TIME_OUT); + redisUtil.set(SHARE_REFRESH_TOKEN_KEY, refreshToken, TOKEN_TIME_OUT * 2); + return accessToken; + } else { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + // 构造form表单 + MultiValueMap paramsMap = new LinkedMultiValueMap<>(); + paramsMap.set("client_id", clientId); + paramsMap.set("client_secret", clientSecret); + paramsMap.set("grant_type", "refresh_token"); + paramsMap.set("refresh_token", refreshToken); + String url = String.format("%s/eplat/oauth/token", urlPrex); + // 构造请求的实体。包含body和headers的内容 + HttpEntity> entity = new HttpEntity<>(paramsMap, headers); + log.info("刷新token调用url:[" + url + "],request:[" + paramsMap + "]"); + ResponseEntity result = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); + JSONObject json = JSONUtil.parseObj(result.getBody()); + String accessToken = json.getStr("access_token"); + refreshToken = json.getStr("refresh_token"); + // 缓存token、刷新token(刷新token过期时间为2倍token过期时间) + redisUtil.set(SHARE_TOKEN_KEY, accessToken, TOKEN_TIME_OUT); + redisUtil.set(SHARE_REFRESH_TOKEN_KEY, refreshToken, TOKEN_TIME_OUT * 2); + return accessToken; + } + } +} From 65d11fdc47783f0eb9327aeb8b0e5daa5c4d8985 Mon Sep 17 00:00:00 2001 From: guojunyun Date: Mon, 10 Nov 2025 11:21:30 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E5=9B=BD=E8=B4=B82.0=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E5=90=88=E5=90=8C=EF=BC=9A=E5=A4=84=E7=90=86?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E5=BC=82=E6=AD=A5=E8=BF=94=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/contractorder/api/ContractApi.java | 3 +- .../international/IntPushContractReqVO.java | 24 ++ .../international/IntPushContractRespVO.java | 29 +++ .../contractorder/api/ContractApiImpl.java | 211 ++++++++++-------- .../admin/contract/ContractController.java | 7 +- .../contractorder/util/ShareServiceUtil.java | 4 +- 6 files changed, 182 insertions(+), 96 deletions(-) create mode 100644 zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/international/IntPushContractReqVO.java create mode 100644 zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/international/IntPushContractRespVO.java diff --git a/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/ContractApi.java b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/ContractApi.java index 217a20d..55b7e76 100644 --- a/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/ContractApi.java +++ b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/ContractApi.java @@ -9,6 +9,7 @@ import com.zt.plat.module.contractorder.api.dto.order.PurchaseOrderWithDetailsDT import com.zt.plat.module.contractorder.api.dto.order.SalesOrdDtlDTO; import com.zt.plat.module.contractorder.api.vo.contract.international.IntContract; import com.zt.plat.module.contractorder.api.vo.contract.international.IntContractPageReq; +import com.zt.plat.module.contractorder.api.vo.contract.international.IntPushContractReqVO; import com.zt.plat.module.contractorder.enums.ApiConstants; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -44,7 +45,7 @@ public interface ContractApi { @PostMapping(PREFIX + "/push") @Operation(summary = "国贸2.0系统推送合同") - CommonResult push(@Valid @RequestBody IntContract reqVO); + void push(@Valid @RequestBody IntPushContractReqVO pushReqVO); @GetMapping(PREFIX + "/logistics/list/page") @Operation(summary = "国贸2.0系统合同分页查询") diff --git a/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/international/IntPushContractReqVO.java b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/international/IntPushContractReqVO.java new file mode 100644 index 0000000..4758570 --- /dev/null +++ b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/international/IntPushContractReqVO.java @@ -0,0 +1,24 @@ +package com.zt.plat.module.contractorder.api.vo.contract.international; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "国贸2.0系统推送合同 Request VO") +@Data +public class IntPushContractReqVO { + + @Schema(description = "接口请求号") + private String __requestId_; + @Schema(description = "接口类型") + private String __interfaceType__; + @Schema(description = "操作标志") + private String operateFlag; + @Schema(description = "发送时间 yyyyMMddHHmmss") + private String datetime; + @Schema(description = "单据号") + private String busiBillCode; + @Schema(description = "发送方系统") + private String system; + @Schema(description = "发送数据") + private IntContract data; +} diff --git a/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/international/IntPushContractRespVO.java b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/international/IntPushContractRespVO.java new file mode 100644 index 0000000..c26f9bf --- /dev/null +++ b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/international/IntPushContractRespVO.java @@ -0,0 +1,29 @@ +package com.zt.plat.module.contractorder.api.vo.contract.international; + +import cn.hutool.json.JSONObject; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "国贸2.0系统推送合同 Response VO") +@Data +public class IntPushContractRespVO { + + @Schema(description = "接口请求号") + private String __requestId_; + @Schema(description = "接口类型") + private String __interfaceType__; + @Schema(description = "单据号") + private String busiBillCode; + @Schema(description = "返回状态") + private Integer code; + @Schema(description = "返回信息") + private String message; + @Schema(description = "返回时间 yyyyMMddHHmmss") + private String datetime; + @Schema(description = "返回方系统") + private String system; + @Schema(description = "操作标志") + private String operateFlag; + @Schema(description = "返回数据") + private JSONObject data; +} diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java index cd3efdb..72ed16c 100644 --- a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java @@ -11,9 +11,7 @@ import com.zt.plat.module.contractorder.api.dto.contract.ContractRespDTO; import com.zt.plat.module.contractorder.api.dto.order.PrchOrdDtlDTO; import com.zt.plat.module.contractorder.api.dto.order.PurchaseOrderWithDetailsDTO; import com.zt.plat.module.contractorder.api.dto.order.SalesOrdDtlDTO; -import com.zt.plat.module.contractorder.api.vo.contract.international.IntContract; -import com.zt.plat.module.contractorder.api.vo.contract.international.IntContractPageReq; -import com.zt.plat.module.contractorder.api.vo.contract.international.Partner; +import com.zt.plat.module.contractorder.api.vo.contract.international.*; import com.zt.plat.module.contractorder.controller.admin.purchaseorder.vo.PurchaseOrderDetailsRespVO; import com.zt.plat.module.contractorder.dal.dataobject.contract.ContractMainDO; import com.zt.plat.module.contractorder.dal.dataobject.contract.ContractOtherFieldDO; @@ -33,10 +31,12 @@ import com.zt.plat.module.contractorder.dal.mysql.salesorder.SalesOrderMapper; import com.zt.plat.module.contractorder.enums.contract.DictEnum; import com.zt.plat.module.contractorder.service.contract.ContractService; import com.zt.plat.module.contractorder.service.purchaseorder.PurchaseOrderService; +import com.zt.plat.module.contractorder.util.ShareServiceUtil; import com.zt.plat.module.erp.controller.admin.erp.vo.ErpContractSaveReqVO; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RequestBody; @@ -73,6 +73,8 @@ public class ContractApiImpl implements ContractApi { private ContractOtherFieldMapper contractOtherFieldMapper; @Resource private SystemRelativityMapper systemRelativityMapper; + @Autowired + private ShareServiceUtil shareServiceUtil; @Override public ContractRespDTO getContractByPaperNumber(String contractPaperNumber) { @@ -158,100 +160,105 @@ public class ContractApiImpl implements ContractApi { @Transactional @Override - public CommonResult push(@RequestBody IntContract reqVO) { + public void push(@RequestBody IntPushContractReqVO pushReqVO) { - // 合同主信息表映射 - ContractMainDO contractMainDO = internationalToMainDO(reqVO); + log.info("接受到国贸2.0系统推送合同数据:{}", new JSONObject(pushReqVO)); + try { + // 合同主信息表映射 + ContractMainDO contractMainDO = internationalToMainDO(pushReqVO.getData()); - // 逻辑处理 - // 操作标志 I 新增/更新;D 删除 - String operateFlag = reqVO.getOperateFlag(); - // 合同唯一键 - String externalId = reqVO.getContractId(); - // 系统合同ID - Long contractId = null; - // 查询系统关联合同 - SystemRelativityDO systemRelativityDO = systemRelativityMapper.selectOne("UP_ID", externalId); - if ("I".equals(operateFlag)) { - if (systemRelativityDO != null && systemRelativityDO.getDownId() != null) { // 修改合同 + // 逻辑处理 + // 操作标志 I 新增/更新;D 删除 + String operateFlag = pushReqVO.getData().getOperateFlag(); + // 合同唯一键 + String externalId = pushReqVO.getData().getContractId(); + // 系统合同ID + Long contractId = null; + // 查询系统关联合同 + SystemRelativityDO systemRelativityDO = systemRelativityMapper.selectOne("UP_ID", externalId); + if ("I".equals(operateFlag)) { + if (systemRelativityDO != null && systemRelativityDO.getDownId() != null) { // 修改合同 + contractId = systemRelativityDO.getDownId(); + contractMainDO.setId(contractId); + contractMainMapper.updateById(contractMainDO); + } else { // 新增合同 + contractMainMapper.insert(contractMainDO); + contractId = contractMainDO.getId(); + + // 生成关联数据 + SystemRelativityDO saveRelation = new SystemRelativityDO(); + saveRelation.setUpId(Long.parseLong(externalId)); + saveRelation.setDownId(contractId); + saveRelation.setWay(DictEnum.BSE_SYS_REL_WY_EXTERNAL.getCode()); + saveRelation.setStatus(DictEnum.BSE_SYS_REL_TP_CONTRACT.getCode()); + systemRelativityMapper.insert(saveRelation); + } + } else if ("D".equals(operateFlag)) { + if (systemRelativityDO == null || systemRelativityDO.getDownId() == null) throw exception(CONTRACT_NOT_EXISTS); contractId = systemRelativityDO.getDownId(); - contractMainDO.setId(contractId); - contractMainMapper.updateById(contractMainDO); - } else { // 新增合同 - contractMainMapper.insert(contractMainDO); - contractId = contractMainDO.getId(); - - // 生成关联数据 - SystemRelativityDO saveRelation = new SystemRelativityDO(); - saveRelation.setUpId(Long.parseLong(externalId)); - saveRelation.setDownId(contractId); - saveRelation.setWay(DictEnum.BSE_SYS_REL_WY_EXTERNAL.getCode()); - saveRelation.setStatus(DictEnum.BSE_SYS_REL_TP_CONTRACT.getCode()); - systemRelativityMapper.insert(saveRelation); + contractMainMapper.deleteById(contractId); + // 删除动态条款信息 + contractOtherFormMapper.delete("CTRT_MAIN_ID", contractId.toString()); + contractOtherFieldMapper.delete("CTRT_MAIN_ID", contractId.toString()); + pushResult(pushReqVO, 1, null); + } else { + throw exception(CONTRACT_UNKNOWN_OPERATE); } - } else if ("D".equals(operateFlag)) { - if (systemRelativityDO == null || systemRelativityDO.getDownId() == null) throw exception(CONTRACT_NOT_EXISTS); - contractId = systemRelativityDO.getDownId(); - contractMainMapper.deleteById(contractId); + + // 根据客商信息列表提交多个合同映射到erp + if (pushReqVO.getData().getPartnerList() == null || pushReqVO.getData().getPartnerList().isEmpty()) { + throw exception(CONTRACT_PARTNER_NOT_EXISTS); + } + + // 合同主信息-合同编号 + String contractPaperNumber = contractMainDO.getContractPaperNumber(); + // 合同主信息-合同名称 + String contractName = contractMainDO.getContractName(); + for (int i = 0; i < pushReqVO.getData().getPartnerList().size(); i++) { + Partner partner = pushReqVO.getData().getPartnerList().get(i); + + // 根据客商信息设置合同信息 + // 合同编号 + contractMainDO.setContractPaperNumber(contractPaperNumber + "_" + String.format("%03d", (i+1))); + pushReqVO.getData().getPartnerList().get(i) + .setErpContractPaperNumber(contractPaperNumber + "_" + String.format("%03d", (i+1))); + // 合同名称 + contractMainDO.setContractName(contractName + "_" + String.format("%03d", (i+1))); + // 境内/境外 -> 客商信息:境内/外 + contractMainDO.setIsDomestic(partner.getDomesticOrOverseas()); + // 乙方公司编号(销售方) -> 客商信息:供应商代码 + contractMainDO.setSalesCompanyNumber(partner.getPartnerCode()); + // ERP乙方公司编码 + contractMainDO.setErpSalesCompanyNumber(partner.getPartnerCode()); + // 乙方公司名称 -> 客商信息:供应商名称 + contractMainDO.setSalesCompanyName(partner.getPartnerName()); + // ERP乙方公司名称 + contractMainDO.setErpSalesCompanyName(partner.getPartnerName()); + + // 生成ERP合同映射表 + ErpContractSaveReqVO erpContractVO = contractService.getErpContract(contractMainDO); + + // 调用ERP模块 + JSONObject erpResult = contractService.sendToErp(erpContractVO); + log.info("合同提交ERP结果:{}", erpResult); + + // 调用ERP失败 + if (!erpResult.getBool("success")) { + throw exception(CONTRACT_SUBMIT_ERP_FAIL, erpResult.getStr("errMsg")); + } + } + // 删除动态条款信息 contractOtherFormMapper.delete("CTRT_MAIN_ID", contractId.toString()); contractOtherFieldMapper.delete("CTRT_MAIN_ID", contractId.toString()); - return success(true); - } else { - throw exception(CONTRACT_UNKNOWN_OPERATE); + + // 请求参数保存到动态条款 + saveIntContractFields(pushReqVO.getData(), contractId); + + pushResult(pushReqVO, 1, null); + } catch (Exception e) { + pushResult(pushReqVO, -1, e.getMessage()); } - - // 根据客商信息列表提交多个合同映射到erp - if (reqVO.getPartnerList() == null || reqVO.getPartnerList().isEmpty()) { - throw exception(CONTRACT_PARTNER_NOT_EXISTS); - } - - // 合同主信息-合同编号 - String contractPaperNumber = contractMainDO.getContractPaperNumber(); - // 合同主信息-合同名称 - String contractName = contractMainDO.getContractName(); - for (int i = 0; i < reqVO.getPartnerList().size(); i++) { - Partner partner = reqVO.getPartnerList().get(i); - - // 根据客商信息设置合同信息 - // 合同编号 - contractMainDO.setContractPaperNumber(contractPaperNumber + "_" + String.format("%03d", (i+1))); - reqVO.getPartnerList().get(i) - .setErpContractPaperNumber(contractPaperNumber + "_" + String.format("%03d", (i+1))); - // 合同名称 - contractMainDO.setContractName(contractName + "_" + String.format("%03d", (i+1))); - // 境内/境外 -> 客商信息:境内/外 - contractMainDO.setIsDomestic(partner.getDomesticOrOverseas()); - // 乙方公司编号(销售方) -> 客商信息:供应商代码 - contractMainDO.setSalesCompanyNumber(partner.getPartnerCode()); - // ERP乙方公司编码 - contractMainDO.setErpSalesCompanyNumber(partner.getPartnerCode()); - // 乙方公司名称 -> 客商信息:供应商名称 - contractMainDO.setSalesCompanyName(partner.getPartnerName()); - // ERP乙方公司名称 - contractMainDO.setErpSalesCompanyName(partner.getPartnerName()); - - // 生成ERP合同映射表 - ErpContractSaveReqVO erpContractVO = contractService.getErpContract(contractMainDO); - - // 调用ERP模块 - JSONObject erpResult = contractService.sendToErp(erpContractVO); - log.info("合同提交ERP结果:{}", erpResult); - - // 调用ERP失败 - if (!erpResult.getBool("success")) { - throw exception(CONTRACT_SUBMIT_ERP_FAIL, erpResult.getStr("errMsg")); - } - } - - // 删除动态条款信息 - contractOtherFormMapper.delete("CTRT_MAIN_ID", contractId.toString()); - contractOtherFieldMapper.delete("CTRT_MAIN_ID", contractId.toString()); - - // 请求参数保存到动态条款 - saveIntContractFields(reqVO, contractId); - - return success(true); } /** @@ -365,6 +372,32 @@ public class ContractApiImpl implements ContractApi { } } + private void pushResult(IntPushContractReqVO pushReqVO, Integer code, String msg) { + + // 返回数据 + IntPushContractRespVO body = new IntPushContractRespVO(); + body.set__requestId_(pushReqVO.get__requestId_()); + body.set__interfaceType__(pushReqVO.get__interfaceType__()); + body.setBusiBillCode(pushReqVO.getBusiBillCode()); + body.setCode(code); + body.setMessage(String.format("推送合同[%s]%s", pushReqVO.getData().getContractCode(), code >= 0 ? "成功" : "失败:" + msg)); + body.setDatetime(DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now())); + body.setSystem("JYGK"); + body.setOperateFlag(pushReqVO.getOperateFlag()); + + // 回调参数 + JSONObject req = new JSONObject(); + req.set("messageKey", pushReqVO.getBusiBillCode()); + req.set("messageBody", body.toString()); + try { + log.info("国贸2.0系统推送合同回调参数:{}",req); + String res = shareServiceUtil.callShareService("S_EPLAT_04", req.toString()); + log.info("国贸2.0系统推送合同回调成功:{}",res); + } catch (Exception e) { + log.error("国贸2.0系统推送合同回调失败:{}",e.getMessage(), e); + } + } + @Override public CommonResult> logisticsListPage(IntContractPageReq pageReq) { diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contract/ContractController.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contract/ContractController.java index 7373558..052c138 100644 --- a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contract/ContractController.java +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contract/ContractController.java @@ -9,6 +9,7 @@ import com.zt.plat.module.contractorder.api.ContractApi; import com.zt.plat.module.contractorder.api.vo.contract.*; import com.zt.plat.module.contractorder.api.vo.contract.international.IntContract; import com.zt.plat.module.contractorder.api.vo.contract.international.IntContractPageReq; +import com.zt.plat.module.contractorder.api.vo.contract.international.IntPushContractReqVO; import com.zt.plat.module.contractorder.dal.dataobject.contract.ContractMainDO; import com.zt.plat.module.contractorder.service.contract.ContractService; import io.swagger.v3.oas.annotations.Operation; @@ -195,14 +196,14 @@ public class ContractController implements BusinessControllerMarker { @PostMapping("/push") @Operation(summary = "国贸2.0系统推送合同") @PreAuthorize("@ss.hasPermission('base:contract:create')") - CommonResult push(@Valid @RequestBody IntContract reqVO) { - return contractApi.push(reqVO); + public void push(@Valid @RequestBody IntPushContractReqVO pushReqVO) { + contractApi.push(pushReqVO); } @PostMapping("/logistics/list/page") @Operation(summary = "国贸2.0系统合同分页查询") @PreAuthorize("@ss.hasPermission('base:contract:query')") - CommonResult> logisticsListPage(IntContractPageReq pageReq) { + public CommonResult> logisticsListPage(IntContractPageReq pageReq) { return contractApi.logisticsListPage(pageReq); } } diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/ShareServiceUtil.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/ShareServiceUtil.java index 5565b4e..4ee6cb0 100644 --- a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/ShareServiceUtil.java +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/util/ShareServiceUtil.java @@ -14,8 +14,6 @@ import org.springframework.web.client.RestTemplate; /** * ePlat共享服务调用工具类 - * @author ChenZhaoxue - * @date 2025/3/27 */ @Slf4j @Configuration @@ -43,7 +41,7 @@ public class ShareServiceUtil { * ePlat共享服务调用 * @param serviceNo 服务号 * @param request 请求json字符串 - * @return + * @return 调用结果 */ public String callShareService(String serviceNo, String request) { String url = String.format("%s/service/%s", urlPrex, serviceNo); From 712ce5606d097f64aae26f21af3784b257e1ff8e Mon Sep 17 00:00:00 2001 From: guojunyun Date: Mon, 10 Nov 2025 14:23:02 +0800 Subject: [PATCH 04/11] =?UTF-8?q?=E5=9B=BD=E8=B4=B82.0=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E5=90=88=E5=90=8C=EF=BC=9A=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plat/module/contractorder/api/ContractApiImpl.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java index 72ed16c..e4cc53b 100644 --- a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java @@ -162,7 +162,7 @@ public class ContractApiImpl implements ContractApi { @Override public void push(@RequestBody IntPushContractReqVO pushReqVO) { - log.info("接受到国贸2.0系统推送合同数据:{}", new JSONObject(pushReqVO)); + log.info("接受到国贸系统推送的合同数据:{}", new JSONObject(pushReqVO)); try { // 合同主信息表映射 ContractMainDO contractMainDO = internationalToMainDO(pushReqVO.getData()); @@ -257,6 +257,7 @@ public class ContractApiImpl implements ContractApi { pushResult(pushReqVO, 1, null); } catch (Exception e) { + log.info("国贸系统推送合同异常:{}", e.getMessage(), e); pushResult(pushReqVO, -1, e.getMessage()); } } @@ -390,11 +391,11 @@ public class ContractApiImpl implements ContractApi { req.set("messageKey", pushReqVO.getBusiBillCode()); req.set("messageBody", body.toString()); try { - log.info("国贸2.0系统推送合同回调参数:{}",req); + log.info("国贸系统推送合同回调参数:{}",req); String res = shareServiceUtil.callShareService("S_EPLAT_04", req.toString()); - log.info("国贸2.0系统推送合同回调成功:{}",res); + log.info("国贸系统推送合同回调成功:{}",res); } catch (Exception e) { - log.error("国贸2.0系统推送合同回调失败:{}",e.getMessage(), e); + log.error("国贸系统推送合同回调失败:{}",e.getMessage(), e); } } From 1c11f52636fe368ae66f192b09da68983abb100f Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Mon, 10 Nov 2025 15:04:38 +0800 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=E9=9B=86=E6=88=90seata?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- base-server/pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/base-server/pom.xml b/base-server/pom.xml index b2c88ee..d78949c 100644 --- a/base-server/pom.xml +++ b/base-server/pom.xml @@ -82,6 +82,16 @@ + + org.apache.seata + seata-spring-boot-starter + + + com.alibaba + druid + + + From bb5375d2568537a3393fd91f4cfbe65709b8ccc6 Mon Sep 17 00:00:00 2001 From: liss <1780094091@qq.com> Date: Mon, 10 Nov 2025 15:37:51 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E9=87=91=E5=B1=9E=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/base/vo/ElementPageReqVO.java | 2 ++ .../controller/admin/base/vo/ElementRespVO.java | 2 ++ .../controller/admin/base/vo/ElementSaveReqVO.java | 3 +++ .../module/base/dal/dataobject/base/ElementDO.java | 3 +++ .../module/base/dal/mysql/base/ElementMapper.java | 5 +++-- .../admin/contract/ContractController.java | 8 ++++++++ .../contractorder/ContractOrderController.java | 13 +++++++++---- 7 files changed, 30 insertions(+), 6 deletions(-) diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementPageReqVO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementPageReqVO.java index 459d019..c69b2d3 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementPageReqVO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementPageReqVO.java @@ -35,4 +35,6 @@ public class ElementPageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; + @Schema(description = "排序") + private Integer sort; } \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementRespVO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementRespVO.java index 549daf7..dc5f688 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementRespVO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementRespVO.java @@ -44,4 +44,6 @@ public class ElementRespVO { @ExcelProperty("创建时间") private LocalDateTime createTime; + @Schema(description = "排序") + private Integer sort; } \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementSaveReqVO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementSaveReqVO.java index 5d5c8e7..b632998 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementSaveReqVO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/base/vo/ElementSaveReqVO.java @@ -34,4 +34,7 @@ public class ElementSaveReqVO { @NotEmpty(message = "品位单位不能为空") private String gradeUnit; + @Schema(description = "排序") + private Integer sort; + } \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/base/ElementDO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/base/ElementDO.java index 32ed81b..357af72 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/base/ElementDO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/base/ElementDO.java @@ -94,4 +94,7 @@ public class ElementDO extends BusinessBaseDO { @TableField("UPDATER_NAME") private String updaterName; + @TableField("SORT") + private Integer sort; + } \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/mysql/base/ElementMapper.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/mysql/base/ElementMapper.java index 83b90bb..766d73c 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/mysql/base/ElementMapper.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/mysql/base/ElementMapper.java @@ -26,13 +26,14 @@ public interface ElementMapper extends BaseMapperX { .likeIfPresent(ElementDO::getCoding, reqVO.getCoding()) .eqIfPresent(ElementDO::getGradeUnit, reqVO.getGradeUnit()) .betweenIfPresent(ElementDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(ElementDO::getId)); + .orderByDesc(ElementDO::getSort)); } String selectMaxCode(); default List getElementNoPage() { return selectList(new LambdaQueryWrapperX() - .orderByDesc(ElementDO::getId)); + .eq(ElementDO::getIsEnable, 1) + .orderByDesc(ElementDO::getSort)); } } \ No newline at end of file diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contract/ContractController.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contract/ContractController.java index 052c138..4857d3c 100644 --- a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contract/ContractController.java +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contract/ContractController.java @@ -6,6 +6,7 @@ import com.zt.plat.framework.common.pojo.CommonResult; import com.zt.plat.framework.common.pojo.PageResult; import com.zt.plat.framework.common.util.object.BeanUtils; import com.zt.plat.module.contractorder.api.ContractApi; +import com.zt.plat.module.contractorder.api.dto.order.PurchaseOrderWithDetailsDTO; import com.zt.plat.module.contractorder.api.vo.contract.*; import com.zt.plat.module.contractorder.api.vo.contract.international.IntContract; import com.zt.plat.module.contractorder.api.vo.contract.international.IntContractPageReq; @@ -206,4 +207,11 @@ public class ContractController implements BusinessControllerMarker { public CommonResult> logisticsListPage(IntContractPageReq pageReq) { return contractApi.logisticsListPage(pageReq); } + + @PostMapping("/order-by-order-no") + @Operation(summary = "通过订单编号获取订单信息", description = "通过订单编号获取订单信息") + @PreAuthorize("@ss.hasPermission('base:contract:query')") + public CommonResult> getOrderByOrderNo(@RequestBody List orderNoS){ + return contractApi.getOrderByOrderNo(orderNoS); + }; } diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contractorder/ContractOrderController.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contractorder/ContractOrderController.java index 6245150..d18a421 100644 --- a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contractorder/ContractOrderController.java +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/controller/admin/contractorder/ContractOrderController.java @@ -1,13 +1,16 @@ package com.zt.plat.module.contractorder.controller.admin.contractorder; +import com.zt.plat.module.contractorder.api.dto.order.PurchaseOrderWithDetailsDTO; +import com.zt.plat.module.contractorder.service.contract.ContractService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.*; import com.zt.plat.framework.common.pojo.CommonResult; +import java.util.List; + import static com.zt.plat.framework.common.pojo.CommonResult.success; /** @@ -20,10 +23,12 @@ import static com.zt.plat.framework.common.pojo.CommonResult.success; @RequestMapping("/admin/contract-order/contract-order") public class ContractOrderController { + @Resource + private ContractService contractService; + @GetMapping("/hello") @Operation(summary = "Hello ContractOrder") public CommonResult hello() { return success("Hello, ContractOrder!"); } - } From c2fdfee1499d1833637e09e39e6a9c23bd21cdff Mon Sep 17 00:00:00 2001 From: guojunyun Date: Mon, 10 Nov 2025 16:56:31 +0800 Subject: [PATCH 07/11] =?UTF-8?q?=E5=9B=BD=E8=B4=B82.0=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E5=90=88=E5=90=8C=EF=BC=9A=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E5=8F=82=E6=95=B0=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/zt/plat/module/contractorder/api/ContractApiImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java index e4cc53b..f718bef 100644 --- a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java @@ -389,7 +389,7 @@ public class ContractApiImpl implements ContractApi { // 回调参数 JSONObject req = new JSONObject(); req.set("messageKey", pushReqVO.getBusiBillCode()); - req.set("messageBody", body.toString()); + req.set("messageBody", body); try { log.info("国贸系统推送合同回调参数:{}",req); String res = shareServiceUtil.callShareService("S_EPLAT_04", req.toString()); From 34ca30bb8b7f620a3e1684795f0364b132e68f16 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Tue, 11 Nov 2025 09:27:22 +0800 Subject: [PATCH 08/11] =?UTF-8?q?update:=E5=AE=8C=E5=96=84=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E6=A8=A1=E6=9D=BF=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/base/enums/ErrorCodeConstants.java | 4 + zt-module-base/zt-module-base-server/pom.xml | 15 +- .../DocTemplateInstanceController.java | 38 +++ .../render/DocTemplateRenderController.java | 223 ++++++++++++++++ .../render/vo/BusinessExportRequest.java | 19 ++ .../render/vo/BusinessPreviewRequest.java | 19 ++ .../render/vo/CustomExportRequest.java | 17 ++ .../render/vo/CustomPreviewRequest.java | 17 ++ .../vo/DocTemplateCategoryRespVO.java | 14 +- .../vo/DocTemplateInstanceRespVO.java | 18 ++ .../vo/DocTemplateInstanceSaveReqVO.java | 21 +- .../doctemplate/vo/DocTemplatePageReqVO.java | 7 +- .../doctemplate/vo/DocTemplateRespVO.java | 8 +- .../doctemplate/vo/DocTemplateSaveReqVO.java | 9 +- .../dao/doctemplate/DocTemplateMapper.java | 3 +- .../dataobject/doctemplate/DocTemplateDO.java | 12 +- .../doctemplate/DocTemplateInstanceDO.java | 36 +++ .../DocTemplateInstanceServiceImpl.java | 31 +++ .../doctemplate/DocTemplateServiceImpl.java | 46 +++- .../DocumentRenderApiServiceImpl.java | 245 +++++++++++++++++- .../render/DefaultSqlConfigProvider.java | 60 +++++ .../DocTemplateAdvancedRenderService.java | 186 +++++++++++++ .../DocTemplateDataSourceProviderFactory.java | 111 ++++++++ .../render/DocTemplateDataSourceType.java | 38 +++ .../render/IBusinessDataProvider.java | 30 +++ .../render/IDataSourceProvider.java | 28 ++ .../render/ISqlConfigProvider.java | 20 ++ .../render/IVelocityRenderEngine.java | 20 ++ .../render/TemplateRenderRequest.java | 21 ++ .../render/VelocityRenderEngineImpl.java | 99 +++++++ .../DocTemplateAbstractExportStrategy.java | 79 ++++++ .../DocTemplateExportStrategyFactory.java | 58 +++++ .../doctemplate/render/export/ExportType.java | 38 +++ .../render/export/HtmlPreviewResult.java | 36 +++ ...tmlPreviewTemplateStrategyDocTemplate.java | 39 +++ .../render/export/IExportStrategy.java | 26 ++ .../render/export/WordExportResult.java | 48 ++++ ...WordExportTemplateStrategyDocTemplate.java | 68 +++++ .../render/provider/ContractDataProvider.java | 90 +++++++ ...mplateBusinessFieldDataSourceProvider.java | 49 ++++ ...emplateDefaultFieldDataSourceProvider.java | 31 +++ ...emplateRequestFieldDataSourceProvider.java | 52 ++++ ...plateSqlConfigFieldDataSourceProvider.java | 60 +++++ .../render/provider/OrderDataProvider.java | 90 +++++++ 44 files changed, 2134 insertions(+), 45 deletions(-) create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/DocTemplateRenderController.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/BusinessExportRequest.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/BusinessPreviewRequest.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/CustomExportRequest.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/CustomPreviewRequest.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DefaultSqlConfigProvider.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateAdvancedRenderService.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateDataSourceProviderFactory.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateDataSourceType.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IBusinessDataProvider.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IDataSourceProvider.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/ISqlConfigProvider.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IVelocityRenderEngine.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/TemplateRenderRequest.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/VelocityRenderEngineImpl.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/DocTemplateAbstractExportStrategy.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/DocTemplateExportStrategyFactory.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/ExportType.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/HtmlPreviewResult.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/HtmlPreviewTemplateStrategyDocTemplate.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/IExportStrategy.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/WordExportResult.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/WordExportTemplateStrategyDocTemplate.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/ContractDataProvider.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateBusinessFieldDataSourceProvider.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateDefaultFieldDataSourceProvider.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateRequestFieldDataSourceProvider.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateSqlConfigFieldDataSourceProvider.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/OrderDataProvider.java diff --git a/zt-module-base/zt-module-base-api/src/main/java/com/zt/plat/module/base/enums/ErrorCodeConstants.java b/zt-module-base/zt-module-base-api/src/main/java/com/zt/plat/module/base/enums/ErrorCodeConstants.java index 906d7c2..e019d7d 100644 --- a/zt-module-base/zt-module-base-api/src/main/java/com/zt/plat/module/base/enums/ErrorCodeConstants.java +++ b/zt-module-base/zt-module-base-api/src/main/java/com/zt/plat/module/base/enums/ErrorCodeConstants.java @@ -46,6 +46,10 @@ public interface ErrorCodeConstants { ErrorCode TEMPLATE_INSTANCE_NOT_EXISTS = new ErrorCode(1_006_004_001, "模板实例不存在"); ErrorCode TEMPLATE_INSTANCE_CODE_DUPLICATE = new ErrorCode(1_006_004_002, "实例编码已存在"); + // 模板导出 1-006-005-xxx + ErrorCode TEMPLATE_EXPORT_TYPE_ERROR = new ErrorCode(1_006_005_001, "不支持的导出类型"); + ErrorCode TEMPLATE_EXPORT_FAILED = new ErrorCode(1_006_005_002, "模板导出失败"); + // ========== 物料属性 ========== ErrorCode MATERIAL_PROPERTIES_NOT_EXISTS = new ErrorCode(1_027_101_001, "物料属性不存在"); ErrorCode MATERIAL_HAS_PROPERTIES_NOT_EXISTS = new ErrorCode(1_027_101_002, "物料持有属性不存在"); diff --git a/zt-module-base/zt-module-base-server/pom.xml b/zt-module-base/zt-module-base-server/pom.xml index 431837b..c921c70 100644 --- a/zt-module-base/zt-module-base-server/pom.xml +++ b/zt-module-base/zt-module-base-server/pom.xml @@ -126,7 +126,20 @@ org.apache.velocity velocity-engine-core - 2.3 + + + + + org.docx4j + docx4j-core + 11.4.11 + + + + + org.docx4j + docx4j-JAXB-ReferenceImpl + 11.4.11 diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/DocTemplateInstanceController.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/DocTemplateInstanceController.java index 4b3b513..654d1ac 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/DocTemplateInstanceController.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/DocTemplateInstanceController.java @@ -7,15 +7,19 @@ import com.zt.plat.module.base.controller.admin.doctemplate.vo.DocTemplateInstan import com.zt.plat.module.base.controller.admin.doctemplate.vo.DocTemplateInstanceSaveReqVO; import com.zt.plat.module.base.service.doctemplate.DocTemplateInstanceService; import com.zt.plat.module.base.service.doctemplate.DocTemplateRenderService; +import com.zt.plat.module.base.service.doctemplate.DocumentRenderApiService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; @@ -38,6 +42,9 @@ public class DocTemplateInstanceController { @Resource private DocTemplateRenderService renderService; + @Resource + private DocumentRenderApiService documentRenderApiService; + @PostMapping("/create") @Operation(summary = "创建模板实例") @PreAuthorize("@ss.hasPermission('base:template-instance:create')") @@ -104,4 +111,35 @@ public class DocTemplateInstanceController { return success(true); } + @PostMapping("/render-and-export-word") + @Operation(summary = "渲染实例并导出为Word") + @PreAuthorize("@ss.hasPermission('base:template-instance:query')") + public ResponseEntity renderAndExportToWord( + @Parameter(name = "instanceId", description = "实例ID", required = true) @RequestParam("instanceId") Long instanceId, + @Parameter(name = "fileName", description = "文件名") @RequestParam(value = "fileName", required = false) String fileName, + @Parameter(name = "dataMap", description = "数据Map") @RequestBody(required = false) Map dataMap) { + byte[] fileContent = documentRenderApiService.renderAndExportToWord(instanceId, dataMap, fileName); + String actualFileName = (fileName != null ? fileName : "document") + ".docx"; + String encodedFileName = URLEncoder.encode(actualFileName, StandardCharsets.UTF_8).replace("+", "%20"); + return ResponseEntity.ok() + .header("Content-Disposition", "attachment; filename=\"document.docx\"; filename*=UTF-8''" + encodedFileName) + .header("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document") + .body(fileContent); + } + + @PostMapping("/export-html-to-word") + @Operation(summary = "导出HTML为Word文档") + @PreAuthorize("@ss.hasPermission('base:template-instance:query')") + public ResponseEntity exportHtmlToWord( + @Parameter(name = "html", description = "HTML内容", required = true) @RequestBody String html, + @Parameter(name = "fileName", description = "文件名") @RequestParam(value = "fileName", required = false) String fileName) { + byte[] fileContent = documentRenderApiService.exportToWord(html, fileName); + String actualFileName = (fileName != null ? fileName : "document") + ".docx"; + String encodedFileName = URLEncoder.encode(actualFileName, StandardCharsets.UTF_8).replace("+", "%20"); + return ResponseEntity.ok() + .header("Content-Disposition", "attachment; filename=\"document.docx\"; filename*=UTF-8''" + encodedFileName) + .header("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document") + .body(fileContent); + } + } diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/DocTemplateRenderController.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/DocTemplateRenderController.java new file mode 100644 index 0000000..8ccb28d --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/DocTemplateRenderController.java @@ -0,0 +1,223 @@ +package com.zt.plat.module.base.controller.admin.doctemplate.render; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.base.controller.admin.doctemplate.render.vo.*; +import com.zt.plat.module.base.service.doctemplate.render.DocTemplateAdvancedRenderService; +import com.zt.plat.module.base.service.doctemplate.render.DocTemplateDataSourceType; +import com.zt.plat.module.base.service.doctemplate.render.TemplateRenderRequest; +import com.zt.plat.module.base.service.doctemplate.render.export.ExportType; +import com.zt.plat.module.base.service.doctemplate.render.export.WordExportResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.zt.plat.module.base.enums.ErrorCodeConstants.*; + +/** + * 文档模板渲染控制器 + */ +@RestController +@RequestMapping("/base/doc-template-instance") +@Tag(name = "管理后台 - 文档模板渲染") +@Slf4j +public class DocTemplateRenderController { + + @Resource + private DocTemplateAdvancedRenderService advancedRenderService; + + @PostMapping("/preview/default") + @Operation(summary = "默认值预览") + @PreAuthorize("@ss.hasPermission('base:doctemplate:render')") + public CommonResult previewWithDefaultValues( + @RequestParam("templateInstanceId") Long templateInstanceId) { + log.info("默认值预览: {}", templateInstanceId); + try { + TemplateRenderRequest request = new TemplateRenderRequest(); + request.setTemplateInstanceId(templateInstanceId); + request.setExportType(ExportType.HTML_PREVIEW); + Object result = advancedRenderService.renderAndExport(request); + return CommonResult.success(result.toString()); + } catch (Exception e) { + log.error("预览失败", e); + return CommonResult.error(500, "预览失败: " + e.getMessage()); + } + } + + @PostMapping("/preview/business") + @Operation(summary = "业务数据预览") + @PreAuthorize("@ss.hasPermission('base:doctemplate:render')") + public CommonResult previewWithBusinessData(@RequestBody BusinessPreviewRequest request) { + log.info("业务预览: {}", request.getTemplateInstanceId()); + try { + Map fieldDataSources = new HashMap<>(); + if (request.getFieldMappings() != null) { + for (String key : request.getFieldMappings().keySet()) { + fieldDataSources.put(key, DocTemplateDataSourceType.BUSINESS); + } + } + + TemplateRenderRequest renderRequest = new TemplateRenderRequest(); + renderRequest.setTemplateInstanceId(request.getTemplateInstanceId()); + renderRequest.setBusinessType(request.getBusinessType()); + renderRequest.setDataSourceContext(request.getBusinessId()); + renderRequest.setFieldDataSources(fieldDataSources); + renderRequest.setExportType(ExportType.HTML_PREVIEW); + + Object result = advancedRenderService.renderAndExport(renderRequest); + return CommonResult.success(result.toString()); + } catch (Exception e) { + log.error("业务预览失败", e); + return CommonResult.error(500, "预览失败: " + e.getMessage()); + } + } + + @PostMapping("/preview/custom") + @Operation(summary = "自定义数据预览") + @PreAuthorize("@ss.hasPermission('base:doctemplate:render')") + public CommonResult previewWithCustomData(@RequestBody CustomPreviewRequest request) { + log.info("自定义预览: {}", request.getTemplateInstanceId()); + try { + Map fieldDataSources = new HashMap<>(); + if (request.getCustomData() != null) { + for (String key : request.getCustomData().keySet()) { + fieldDataSources.put(key, DocTemplateDataSourceType.REQUEST); + } + } + + TemplateRenderRequest renderRequest = new TemplateRenderRequest(); + renderRequest.setTemplateInstanceId(request.getTemplateInstanceId()); + renderRequest.setFieldDataSources(fieldDataSources); + renderRequest.setDataSourceContext(request.getCustomData()); + renderRequest.setExportType(ExportType.HTML_PREVIEW); + + Object result = advancedRenderService.renderAndExport(renderRequest); + return CommonResult.success(result.toString()); + } catch (Exception e) { + log.error("自定义预览失败", e); + return CommonResult.error(500, "预览失败: " + e.getMessage()); + } + } + + @PostMapping("/export/default") + @Operation(summary = "默认值导出Word") + @PreAuthorize("@ss.hasPermission('base:doctemplate:render')") + public ResponseEntity exportWithDefaultValues( + @RequestParam("templateInstanceId") Long templateInstanceId) { + log.info("默认值导出: {}", templateInstanceId); + try { + TemplateRenderRequest request = new TemplateRenderRequest(); + request.setTemplateInstanceId(templateInstanceId); + request.setExportType(ExportType.WORD); + + Object result = advancedRenderService.renderAndExport(request); + + if (result instanceof WordExportResult) { + WordExportResult wordResult = (WordExportResult) result; + String encodedFileName = URLEncoder.encode(wordResult.getFileName(), StandardCharsets.UTF_8).replace("+", "%20"); + + return ResponseEntity.ok() + .header("Content-Disposition", "attachment; filename=\"document.docx\"; filename*=UTF-8''" + encodedFileName) + .header("Content-Type", wordResult.getContentType()) + .body(wordResult.getFileContent()); + } + + throw exception(TEMPLATE_EXPORT_TYPE_ERROR); + } catch (Exception e) { + log.error("默认值导出失败", e); + throw exception(TEMPLATE_EXPORT_FAILED); + } + } + + @PostMapping("/export/business") + @Operation(summary = "业务数据导出Word") + @PreAuthorize("@ss.hasPermission('base:doctemplate:render')") + public ResponseEntity exportWithBusinessData(@RequestBody BusinessExportRequest request) { + log.info("业务导出: {}", request.getTemplateInstanceId()); + try { + Map fieldDataSources = new HashMap<>(); + if (request.getFieldMappings() != null) { + for (String key : request.getFieldMappings().keySet()) { + fieldDataSources.put(key, DocTemplateDataSourceType.BUSINESS); + } + } + + TemplateRenderRequest renderRequest = new TemplateRenderRequest(); + renderRequest.setTemplateInstanceId(request.getTemplateInstanceId()); + renderRequest.setBusinessType(request.getBusinessType()); + renderRequest.setDataSourceContext(request.getBusinessId()); + renderRequest.setFieldDataSources(fieldDataSources); + renderRequest.setExportType(ExportType.WORD); + + Object result = advancedRenderService.renderAndExport(renderRequest); + + if (result instanceof WordExportResult) { + WordExportResult wordResult = (WordExportResult) result; + String encodedFileName = URLEncoder.encode(wordResult.getFileName(), StandardCharsets.UTF_8).replace("+", "%20"); + + return ResponseEntity.ok() + .header("Content-Disposition", "attachment; filename=\"document.docx\"; filename*=UTF-8''" + encodedFileName) + .header("Content-Type", wordResult.getContentType()) + .body(wordResult.getFileContent()); + } + + throw exception(TEMPLATE_EXPORT_TYPE_ERROR); + } catch (Exception e) { + log.error("业务数据导出失败", e); + throw exception(TEMPLATE_EXPORT_FAILED); + } + } + + @PostMapping("/export/custom") + @Operation(summary = "自定义数据导出Word") + @PreAuthorize("@ss.hasPermission('base:doctemplate:render')") + public void exportWithCustomData( + @RequestBody CustomExportRequest request, + jakarta.servlet.http.HttpServletResponse response) throws Exception { + log.info("自定义导出: {}", request.getTemplateInstanceId()); + try { + Map fieldDataSources = new HashMap<>(); + if (request.getCustomData() != null) { + for (String key : request.getCustomData().keySet()) { + fieldDataSources.put(key, DocTemplateDataSourceType.REQUEST); + } + } + + TemplateRenderRequest renderRequest = new TemplateRenderRequest(); + renderRequest.setTemplateInstanceId(request.getTemplateInstanceId()); + renderRequest.setFieldDataSources(fieldDataSources); + renderRequest.setDataSourceContext(request.getCustomData()); + renderRequest.setExportType(ExportType.WORD); + + Object result = advancedRenderService.renderAndExport(renderRequest); + + if (result instanceof WordExportResult) { + WordExportResult wordResult = (WordExportResult) result; + + // 先设置响应头 + response.addHeader("Content-Disposition", "attachment;filename=" + + com.zt.plat.framework.common.util.http.HttpUtils.encodeUtf8(wordResult.getFileName())); + response.setContentType(wordResult.getContentType()); + + // 再写入数据到输出流 + response.getOutputStream().write(wordResult.getFileContent()); + response.getOutputStream().flush(); + return; + } + + throw exception(TEMPLATE_EXPORT_TYPE_ERROR); + } catch (Exception e) { + log.error("自定义数据导出失败", e); + throw exception(TEMPLATE_EXPORT_FAILED); + } + } +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/BusinessExportRequest.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/BusinessExportRequest.java new file mode 100644 index 0000000..5d15b70 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/BusinessExportRequest.java @@ -0,0 +1,19 @@ +package com.zt.plat.module.base.controller.admin.doctemplate.render.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BusinessExportRequest { + private Long templateInstanceId; + private String businessType; + private Long businessId; + private Map fieldMappings; +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/BusinessPreviewRequest.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/BusinessPreviewRequest.java new file mode 100644 index 0000000..6691611 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/BusinessPreviewRequest.java @@ -0,0 +1,19 @@ +package com.zt.plat.module.base.controller.admin.doctemplate.render.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BusinessPreviewRequest { + private Long templateInstanceId; + private String businessType; + private Long businessId; + private Map fieldMappings; +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/CustomExportRequest.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/CustomExportRequest.java new file mode 100644 index 0000000..2fcb9c0 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/CustomExportRequest.java @@ -0,0 +1,17 @@ +package com.zt.plat.module.base.controller.admin.doctemplate.render.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CustomExportRequest { + private Long templateInstanceId; + private Map customData; +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/CustomPreviewRequest.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/CustomPreviewRequest.java new file mode 100644 index 0000000..9cbd8ae --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/render/vo/CustomPreviewRequest.java @@ -0,0 +1,17 @@ +package com.zt.plat.module.base.controller.admin.doctemplate.render.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CustomPreviewRequest { + private Long templateInstanceId; + private Map customData; +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateCategoryRespVO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateCategoryRespVO.java index fe74244..754e669 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateCategoryRespVO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateCategoryRespVO.java @@ -34,9 +34,21 @@ public class DocTemplateCategoryRespVO { @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; - @Schema(description = "创建人", example = "admin") + @Schema(description = "创建人ID", example = "1") private String creator; + @Schema(description = "创建人名称", example = "管理员") + private String creatorName; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "更新人ID", example = "1") + private String updater; + + @Schema(description = "更新人名称", example = "管理员") + private String updaterName; + @Schema(description = "子分类列表") private List children; diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateInstanceRespVO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateInstanceRespVO.java index b27bab0..8eafe4c 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateInstanceRespVO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateInstanceRespVO.java @@ -42,6 +42,24 @@ public class DocTemplateInstanceRespVO { @Schema(description = "状态", example = "draft") private String status; + @Schema(description = "SQL配置(JSON格式)", example = "{}") + private String sqlConfig; + + @Schema(description = "数据源标识", example = "default") + private String dataSource; + + @Schema(description = "分类ID", example = "1") + private Long categoryId; + + @Schema(description = "图标", example = "icon-file") + private String icon; + + @Schema(description = "描述", example = "采购合同模板实例") + private String description; + + @Schema(description = "版本号", example = "v1.0") + private String version; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateInstanceSaveReqVO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateInstanceSaveReqVO.java index 49e0a13..33d917a 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateInstanceSaveReqVO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateInstanceSaveReqVO.java @@ -33,8 +33,7 @@ public class DocTemplateInstanceSaveReqVO { @Schema(description = "业务关联标签", example = "PC-2025-001") private String businessLabel; - @Schema(description = "用户编辑后的内容", requiredMode = Schema.RequiredMode.REQUIRED) - @NotBlank(message = "内容不能为空") + @Schema(description = "用户编辑后的内容(创建时可为空,将自动从模板复制)") private String editedContent; @Schema(description = "渲染后的最终内容") @@ -46,4 +45,22 @@ public class DocTemplateInstanceSaveReqVO { @Schema(description = "状态", example = "draft") private String status; + @Schema(description = "SQL配置(JSON格式)", example = "{}") + private String sqlConfig; + + @Schema(description = "数据源标识", example = "default") + private String dataSource; + + @Schema(description = "分类ID", example = "1") + private Long categoryId; + + @Schema(description = "图标", example = "icon-file") + private String icon; + + @Schema(description = "描述", example = "采购合同模板实例") + private String description; + + @Schema(description = "版本号", example = "v1.0") + private String version; + } diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplatePageReqVO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplatePageReqVO.java index ee8f37c..849d28b 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplatePageReqVO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplatePageReqVO.java @@ -23,11 +23,8 @@ public class DocTemplatePageReqVO extends PageParam { @Schema(description = "模板编码", example = "PO_CONTRACT_001") private String tmplCode; - @Schema(description = "所属大类", example = "1") - private Long bigCategoryId; - - @Schema(description = "所属小类", example = "11") - private Long smallCategoryId; + @Schema(description = "所属分类", example = "1") + private Long categoryId; @Schema(description = "状态(1=启用,0=停用,2=草稿)", example = "1") private String enabled; diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateRespVO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateRespVO.java index 3a86c8e..d142891 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateRespVO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateRespVO.java @@ -21,11 +21,11 @@ public class DocTemplateRespVO { @Schema(description = "模板图标", example = "📄") private String icon; - @Schema(description = "所属大类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Long bigCategoryId; + @Schema(description = "所属分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long categoryId; - @Schema(description = "所属小类", example = "11") - private Long smallCategoryId; + @Schema(description = "分类名称", example = "合同信息/采购合同") + private String categoryName; @Schema(description = "版本号", example = "v1.2") private String version; diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateSaveReqVO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateSaveReqVO.java index 19003af..7d0cc41 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateSaveReqVO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/doctemplate/vo/DocTemplateSaveReqVO.java @@ -24,12 +24,9 @@ public class DocTemplateSaveReqVO { @Schema(description = "模板图标", example = "📄") private String icon; - @Schema(description = "所属大类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "所属大类不能为空") - private Long bigCategoryId; - - @Schema(description = "所属小类", example = "11") - private Long smallCategoryId; + @Schema(description = "所属分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "所属分类不能为空") + private Long categoryId; @Schema(description = "版本号", example = "v1.2") private String version; diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dao/doctemplate/DocTemplateMapper.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dao/doctemplate/DocTemplateMapper.java index 8de6f6b..932df34 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dao/doctemplate/DocTemplateMapper.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dao/doctemplate/DocTemplateMapper.java @@ -19,8 +19,7 @@ public interface DocTemplateMapper extends BaseMapperX { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(DocTemplateDO::getTmplName, reqVO.getTmplName()) .likeIfPresent(DocTemplateDO::getTmplCode, reqVO.getTmplCode()) - .eqIfPresent(DocTemplateDO::getBigCategoryId, reqVO.getBigCategoryId()) - .eqIfPresent(DocTemplateDO::getSmallCategoryId, reqVO.getSmallCategoryId()) + .eqIfPresent(DocTemplateDO::getCategoryId, reqVO.getCategoryId()) .eqIfPresent(DocTemplateDO::getEnabled, reqVO.getEnabled()) .betweenIfPresent(DocTemplateDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(DocTemplateDO::getId)); diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/doctemplate/DocTemplateDO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/doctemplate/DocTemplateDO.java index 344835a..0c2faff 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/doctemplate/DocTemplateDO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/doctemplate/DocTemplateDO.java @@ -43,16 +43,10 @@ public class DocTemplateDO extends BusinessBaseDO { private String icon; /** - * 所属大类 + * 所属分类ID(支持任意级别分类) */ - @TableField("big_category_id") - private Long bigCategoryId; - - /** - * 所属小类 - */ - @TableField("small_category_id") - private Long smallCategoryId; + @TableField("category_id") + private Long categoryId; /** * 版本号 diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/doctemplate/DocTemplateInstanceDO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/doctemplate/DocTemplateInstanceDO.java index 88621fd..b809b43 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/doctemplate/DocTemplateInstanceDO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/doctemplate/DocTemplateInstanceDO.java @@ -84,4 +84,40 @@ public class DocTemplateInstanceDO extends BusinessBaseDO { @TableField("status") private String status; + /** + * SQL配置 + */ + @TableField("sql_config") + private String sqlConfig; + + /** + * 数据源标识 + */ + @TableField("data_source") + private String dataSource; + + /** + * 分类ID + */ + @TableField("category_id") + private Long categoryId; + + /** + * 图标 + */ + @TableField("icon") + private String icon; + + /** + * 描述 + */ + @TableField("description") + private String description; + + /** + * 版本号 + */ + @TableField("version") + private String version; + } diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocTemplateInstanceServiceImpl.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocTemplateInstanceServiceImpl.java index 17100c4..55824e5 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocTemplateInstanceServiceImpl.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocTemplateInstanceServiceImpl.java @@ -49,6 +49,37 @@ public class DocTemplateInstanceServiceImpl implements DocTemplateInstanceServic // 插入实例 DocTemplateInstanceDO templateInstance = DocTemplateInstanceConvert.INSTANCE.convert(createReqVO); + + // 深拷贝模板内容到editedContent(实例完全独立于模板) + if (StrUtil.isBlank(templateInstance.getEditedContent()) && StrUtil.isNotBlank(template.getContent())) { + templateInstance.setEditedContent(template.getContent()); + } + + // 从模板复制快照字段(实例创建时获取模板的快照,后续修改模板不影响实例) + if (templateInstance.getSqlConfig() == null) { + templateInstance.setSqlConfig(template.getSqlConfig()); + } + if (templateInstance.getDataSource() == null) { + templateInstance.setDataSource(template.getDataSource()); + } + if (templateInstance.getCategoryId() == null) { + templateInstance.setCategoryId(template.getCategoryId()); + } + if (templateInstance.getIcon() == null) { + templateInstance.setIcon(template.getIcon()); + } + if (templateInstance.getDescription() == null) { + templateInstance.setDescription(template.getDescription()); + } + if (templateInstance.getVersion() == null) { + templateInstance.setVersion(template.getVersion()); + } + + // 设置默认状态为草稿 + if (templateInstance.getStatus() == null) { + templateInstance.setStatus("draft"); + } + docTemplateInstanceMapper.insert(templateInstance); // 更新模板使用次数 diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocTemplateServiceImpl.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocTemplateServiceImpl.java index b5e353b..2f8d422 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocTemplateServiceImpl.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocTemplateServiceImpl.java @@ -30,6 +30,9 @@ public class DocTemplateServiceImpl implements DocTemplateService { @Resource private DocTemplateMapper templateMapper; + @Resource + private DocTemplateCategoryService templateCategoryService; + @Override public Long createTemplate(DocTemplateSaveReqVO createReqVO) { // 校验模板编码唯一性 @@ -37,12 +40,13 @@ public class DocTemplateServiceImpl implements DocTemplateService { // 插入 DocTemplateDO template = DocTemplateConvert.INSTANCE.convert(createReqVO); + // 设置默认值 if (template.getUseCount() == null) { template.setUseCount(0); } if (template.getEnabled() == null) { - template.setEnabled("2"); // 默认为草稿状态 + template.setEnabled("0"); // 默认为禁用状态 (0=禁用, 1=启用) } templateMapper.insert(template); // 返回 @@ -97,19 +101,43 @@ public class DocTemplateServiceImpl implements DocTemplateService { @Override public DocTemplateRespVO getTemplate(Long id) { DocTemplateDO template = templateMapper.selectById(id); - return DocTemplateConvert.INSTANCE.convert(template); - } - - @Override - public PageResult getTemplatePage(DocTemplatePageReqVO pageReqVO) { - PageResult pageResult = templateMapper.selectPage(pageReqVO); - return DocTemplateConvert.INSTANCE.convertPage(pageResult); + DocTemplateRespVO respVO = DocTemplateConvert.INSTANCE.convert(template); + // 填充分类名称 + fillCategoryName(respVO); + return respVO; } @Override public List getTemplateList() { List list = templateMapper.selectList(); - return DocTemplateConvert.INSTANCE.convertList(list); + List result = DocTemplateConvert.INSTANCE.convertList(list); + // 填充分类名称 + result.forEach(this::fillCategoryName); + return result; + } + + @Override + public PageResult getTemplatePage(DocTemplatePageReqVO reqVO) { + PageResult pageResult = templateMapper.selectPage(reqVO); + PageResult result = DocTemplateConvert.INSTANCE.convertPage(pageResult); + // 填充分类名称 + result.getList().forEach(this::fillCategoryName); + return result; + } + + /** + * 填充分类名称(包含父级路径) + * + * @param respVO 模板响应VO + */ + private void fillCategoryName(DocTemplateRespVO respVO) { + if (respVO == null || respVO.getCategoryId() == null) { + return; + } + + // 调用分类Service获取完整路径 + String categoryPath = templateCategoryService.getCategoryFullPath(respVO.getCategoryId()); + respVO.setCategoryName(categoryPath); } } diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiServiceImpl.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiServiceImpl.java index f599b5d..31bd9b0 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiServiceImpl.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/DocumentRenderApiServiceImpl.java @@ -145,6 +145,7 @@ public class DocumentRenderApiServiceImpl implements DocumentRenderApiService { /** * 将 HTML 转换为 Word 文档内容 * 递归处理 HTML 节点,使用 docx4j API 构建完整的 Word 文档 + * 增强版本:支持CSS样式保留(颜色、对齐、字体等) */ private void processHtmlToWord(MainDocumentPart mainDocumentPart, Element element) throws Exception { for (Node node : element.childNodes()) { @@ -159,11 +160,11 @@ public class DocumentRenderApiServiceImpl implements DocumentRenderApiService { switch (tagName) { case "h1", "h2", "h3", "h4", "h5", "h6" -> { - String styleId = "Heading" + tagName.substring(1); - mainDocumentPart.addStyledParagraphOfText(styleId, element1.text()); + // 使用带样式的段落处理,而不是使用预定义样式 + addStyledParagraph(mainDocumentPart, element1, true); } case "p" -> { - mainDocumentPart.addStyledParagraphOfText("Normal", element1.text()); + addStyledParagraph(mainDocumentPart, element1, false); } case "br" -> { mainDocumentPart.addParagraphOfText(""); @@ -175,13 +176,13 @@ public class DocumentRenderApiServiceImpl implements DocumentRenderApiService { processHtmlToWord(mainDocumentPart, element1); } case "li" -> { - mainDocumentPart.addParagraphOfText("• " + element1.text()); + addStyledParagraph(mainDocumentPart, element1, false); } case "strong", "b" -> { - mainDocumentPart.addStyledParagraphOfText("Normal", element1.text()); + addStyledParagraph(mainDocumentPart, element1, false); } case "i", "em" -> { - mainDocumentPart.addStyledParagraphOfText("Normal", element1.text()); + addStyledParagraph(mainDocumentPart, element1, false); } case "div", "section", "article" -> { processHtmlToWord(mainDocumentPart, element1); @@ -194,6 +195,238 @@ public class DocumentRenderApiServiceImpl implements DocumentRenderApiService { } } + /** + * 添加带样式的段落(支持CSS样式解析) + * @param mainDocumentPart Word文档主体部分 + * @param element HTML元素 + * @param isHeading 是否是标题 + */ + private void addStyledParagraph(MainDocumentPart mainDocumentPart, Element element, boolean isHeading) throws Exception { + ObjectFactory factory = new ObjectFactory(); + P paragraph = factory.createP(); + + // 创建段落属性 + PPr pPr = factory.createPPr(); + paragraph.setPPr(pPr); + + // 解析并应用段落级样式(对齐方式) + String styleAttr = element.attr("style"); + if (StrUtil.isNotBlank(styleAttr)) { + // 解析对齐方式 + String textAlign = extractCssProperty(styleAttr, "text-align"); + if (StrUtil.isNotBlank(textAlign)) { + Jc jc = factory.createJc(); + switch (textAlign.toLowerCase()) { + case "center" -> jc.setVal(JcEnumeration.CENTER); + case "right" -> jc.setVal(JcEnumeration.RIGHT); + case "justify" -> jc.setVal(JcEnumeration.BOTH); + default -> jc.setVal(JcEnumeration.LEFT); + } + pPr.setJc(jc); + } + } + + // 创建文本运行 + R run = factory.createR(); + Text text = factory.createText(); + text.setValue(element.text()); + run.getContent().add(text); + + // 创建文本运行属性 + RPr rPr = factory.createRPr(); + run.setRPr(rPr); + + // 应用字体样式 + if (StrUtil.isNotBlank(styleAttr)) { + // 解析颜色 + String color = extractCssProperty(styleAttr, "color"); + if (StrUtil.isNotBlank(color)) { + Color colorObj = factory.createColor(); + String hexColor = convertColorToHex(color); + if (hexColor != null) { + colorObj.setVal(hexColor); + rPr.setColor(colorObj); + } + } + + // 解析字体大小 + String fontSize = extractCssProperty(styleAttr, "font-size"); + if (StrUtil.isNotBlank(fontSize)) { + HpsMeasure hpsMeasure = factory.createHpsMeasure(); + // 将px转换为half-points (1px ≈ 1.5半点) + try { + int pxValue = Integer.parseInt(fontSize.replaceAll("[^0-9]", "")); + int halfPoints = pxValue * 2; // 简化转换 + hpsMeasure.setVal(java.math.BigInteger.valueOf(halfPoints)); + rPr.setSz(hpsMeasure); + rPr.setSzCs(hpsMeasure); // 复杂脚本字体大小 + } catch (NumberFormatException e) { + log.warn("无法解析字体大小: {}", fontSize); + } + } + + // 解析字体 + String fontFamily = extractCssProperty(styleAttr, "font-family"); + if (StrUtil.isNotBlank(fontFamily)) { + RFonts rFonts = factory.createRFonts(); + fontFamily = fontFamily.replaceAll("['\"]", "").split(",")[0].trim(); + rFonts.setAscii(fontFamily); + rFonts.setHAnsi(fontFamily); + rFonts.setCs(fontFamily); + rFonts.setEastAsia(fontFamily); + rPr.setRFonts(rFonts); + } + + // 解析粗体 + String fontWeight = extractCssProperty(styleAttr, "font-weight"); + if ("bold".equalsIgnoreCase(fontWeight) || "700".equals(fontWeight) || "800".equals(fontWeight) || "900".equals(fontWeight)) { + BooleanDefaultTrue bold = factory.createBooleanDefaultTrue(); + bold.setVal(true); + rPr.setB(bold); + rPr.setBCs(bold); + } + + // 解析斜体 + String fontStyle = extractCssProperty(styleAttr, "font-style"); + if ("italic".equalsIgnoreCase(fontStyle) || "oblique".equalsIgnoreCase(fontStyle)) { + BooleanDefaultTrue italic = factory.createBooleanDefaultTrue(); + italic.setVal(true); + rPr.setI(italic); + rPr.setICs(italic); + } + + // 背景色支持 - 暂时注释掉因为 docx4j API 兼容性问题 + // 如果需要可以后续使用 CTShd 重新实现 + } + + // 处理标签自身的样式(strong, b, i, em) + String tagName = element.tagName().toLowerCase(); + if ("strong".equals(tagName) || "b".equals(tagName)) { + BooleanDefaultTrue bold = factory.createBooleanDefaultTrue(); + bold.setVal(true); + rPr.setB(bold); + rPr.setBCs(bold); + } + if ("i".equals(tagName) || "em".equals(tagName)) { + BooleanDefaultTrue italic = factory.createBooleanDefaultTrue(); + italic.setVal(true); + rPr.setI(italic); + rPr.setICs(italic); + } + + // 标题默认加粗且增大字号 + if (isHeading) { + BooleanDefaultTrue bold = factory.createBooleanDefaultTrue(); + bold.setVal(true); + rPr.setB(bold); + rPr.setBCs(bold); + + // 根据标题级别设置字号(如果没有显式指定) + if (rPr.getSz() == null) { + HpsMeasure hpsMeasure = factory.createHpsMeasure(); + String tag = element.tagName().toLowerCase(); + int size = switch (tag) { + case "h1" -> 32; // 16pt + case "h2" -> 28; // 14pt + case "h3" -> 24; // 12pt + case "h4" -> 22; // 11pt + case "h5" -> 20; // 10pt + case "h6" -> 18; // 9pt + default -> 22; + }; + hpsMeasure.setVal(java.math.BigInteger.valueOf(size)); + rPr.setSz(hpsMeasure); + rPr.setSzCs(hpsMeasure); + } + } + + paragraph.getContent().add(run); + mainDocumentPart.getContent().add(paragraph); + } + + /** + * 从CSS样式字符串中提取指定属性的值 + * @param styleAttr CSS样式字符串,例如 "color: black; text-align: center;" + * @param property 要提取的属性名,例如 "color" + * @return 属性值,例如 "black",如果不存在则返回null + */ + private String extractCssProperty(String styleAttr, String property) { + if (StrUtil.isBlank(styleAttr) || StrUtil.isBlank(property)) { + return null; + } + + // 分割样式声明 + String[] declarations = styleAttr.split(";"); + for (String declaration : declarations) { + String[] parts = declaration.split(":", 2); + if (parts.length == 2) { + String key = parts[0].trim().toLowerCase(); + String value = parts[1].trim(); + if (key.equals(property.toLowerCase())) { + return value; + } + } + } + return null; + } + + /** + * 将CSS颜色值转换为十六进制格式(用于Word) + * 支持:#rrggbb, rgb(r,g,b), 颜色名称 + * @param cssColor CSS颜色值 + * @return 十六进制颜色(不带#),例如 "000000",如果无法解析则返回null + */ + private String convertColorToHex(String cssColor) { + if (StrUtil.isBlank(cssColor)) { + return null; + } + + cssColor = cssColor.trim().toLowerCase(); + + // 已经是十六进制格式 + if (cssColor.startsWith("#")) { + return cssColor.substring(1); + } + + // rgb/rgba格式 + if (cssColor.startsWith("rgb")) { + try { + String rgbValues = cssColor.substring(cssColor.indexOf('(') + 1, cssColor.indexOf(')')); + String[] parts = rgbValues.split(","); + int r = Integer.parseInt(parts[0].trim()); + int g = Integer.parseInt(parts[1].trim()); + int b = Integer.parseInt(parts[2].trim()); + return String.format("%02X%02X%02X", r, g, b); + } catch (Exception e) { + log.warn("无法解析RGB颜色: {}", cssColor); + return null; + } + } + + // 颜色名称映射 + return switch (cssColor) { + case "black" -> "000000"; + case "white" -> "FFFFFF"; + case "red" -> "FF0000"; + case "green" -> "008000"; + case "blue" -> "0000FF"; + case "yellow" -> "FFFF00"; + case "cyan" -> "00FFFF"; + case "magenta" -> "FF00FF"; + case "gray", "grey" -> "808080"; + case "silver" -> "C0C0C0"; + case "maroon" -> "800000"; + case "olive" -> "808000"; + case "lime" -> "00FF00"; + case "aqua" -> "00FFFF"; + case "teal" -> "008080"; + case "navy" -> "000080"; + case "fuchsia" -> "FF00FF"; + case "purple" -> "800080"; + default -> null; + }; + } + /** * 处理表格 * 使用 docx4j 的 Table 和 Tbl API 创建 Word 表格 diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DefaultSqlConfigProvider.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DefaultSqlConfigProvider.java new file mode 100644 index 0000000..1c1e4db --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DefaultSqlConfigProvider.java @@ -0,0 +1,60 @@ +package com.zt.plat.module.base.service.doctemplate.render; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 默认SQL配置数据提供者实现 + * 这是一个临时的实现,实际项目中应该根据具体的SQL配置管理来实现 + * + * @author hwc + */ +@Component +@Slf4j +public class DefaultSqlConfigProvider implements ISqlConfigProvider { + + @Override + public List> querySqlConfig(String sqlConfigId) { + log.debug("查询SQL配置: {}", sqlConfigId); + + // TODO: 实际实现应该: + // 1. 从数据库中根据 sqlConfigId 查询SQL脚本 + // 2. 执行SQL脚本并返回结果 + // 3. 处理异常情况 + + // 临时实现:返回一些示例数据 + List> result = new ArrayList<>(); + + switch (sqlConfigId) { + case "CONTRACT_INFO": + Map contractData = new HashMap<>(); + contractData.put("contractName", "示例合同名称"); + contractData.put("supplier", "示例供应商"); + contractData.put("amount", "1000000"); + contractData.put("deliveryDate", "2025-12-31"); + result.add(contractData); + break; + + case "ORDER_INFO": + Map orderData = new HashMap<>(); + orderData.put("orderNumber", "ORD-2025-001"); + orderData.put("customer", "示例客户"); + orderData.put("totalAmount", "500000"); + orderData.put("orderDate", "2025-01-15"); + result.add(orderData); + break; + + default: + log.warn("未知的SQL配置ID: {}", sqlConfigId); + break; + } + + log.debug("SQL配置查询结果数量: {}", result.size()); + return result; + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateAdvancedRenderService.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateAdvancedRenderService.java new file mode 100644 index 0000000..a9b2556 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateAdvancedRenderService.java @@ -0,0 +1,186 @@ +package com.zt.plat.module.base.service.doctemplate.render; + +import com.zt.plat.framework.common.exception.ServiceException; +import com.zt.plat.module.base.controller.admin.doctemplate.vo.DocTemplateInstanceRespVO; +import com.zt.plat.module.base.dal.dataobject.doctemplate.DocTemplateTagDO; +import com.zt.plat.module.base.dal.dao.doctemplate.DocTemplateTagMapper; +import com.zt.plat.module.base.service.doctemplate.DocTemplateInstanceService; +import com.zt.plat.module.base.service.doctemplate.render.export.DocTemplateExportStrategyFactory; +import com.zt.plat.module.base.service.doctemplate.render.export.IExportStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 增强版模板实例渲染服务(核心服务) + * 基于现有 DocTemplateRenderService 扩展,支持多数据源和策略模式 + * + * @author hwc + */ +@Service +@Slf4j +public class DocTemplateAdvancedRenderService { + + + @Resource + private DocTemplateInstanceService docTemplateInstanceService; + + @Resource + private DocTemplateTagMapper docTemplateTagMapper; + + @Resource + private IVelocityRenderEngine velocityRenderEngine; + + @Resource + private DocTemplateDataSourceProviderFactory dataSourceProviderFactory; + + @Resource + private DocTemplateExportStrategyFactory exportStrategyFactory; + + /** + * 渲染模板实例并导出 + */ + public Object renderAndExport(TemplateRenderRequest request) { + log.info("开始渲染和导出,模板实例ID: {}, 导出类型: {}", + request.getTemplateInstanceId(), request.getExportType()); + + // 1. 加载模板实例 + DocTemplateInstanceRespVO instance = docTemplateInstanceService + .getTemplateInstance(request.getTemplateInstanceId()); + + if (instance == null) { + throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR.value(),"模板实例不存在: " + request.getTemplateInstanceId()); + } + + // 2. 加载标签定义(用于获取标签的默认值) + List tags = getTemplateTags(instance); + + if (tags == null || tags.isEmpty()) { + log.warn("模板实例 {} 没有关联的标签定义", request.getTemplateInstanceId()); + } + + Map tagMap = tags.stream() + .collect(Collectors.toMap(DocTemplateTagDO::getTagCode, t -> t)); + + // 3. 收集所有需要填充的字段值 + Map fillData = new HashMap<>(); + for (DocTemplateTagDO tag : tags) { + Object value = getFieldValue(tag, request, instance.getInstanceName()); + fillData.put(tag.getTagCode(), value != null ? value : ""); + } + + // 4. Velocity 渲染 + String templateContent = instance.getEditedContent(); + if (templateContent == null || templateContent.trim().isEmpty()) { + throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "模板实例内容为空"); + } + + String htmlContent = velocityRenderEngine.render(templateContent, fillData); + + // 5. 获取导出策略并执行导出 + IExportStrategy exportStrategy = exportStrategyFactory + .createStrategy(request.getExportType()); + + Object result = exportStrategy.export(htmlContent, instance.getInstanceName()); + + log.info("渲染和导出完成,模板实例ID: {}", request.getTemplateInstanceId()); + return result; + } + + /** + * 获取单个字段的值 + * 优先级:调用方覆盖 > 默认值 + */ + private Object getFieldValue(DocTemplateTagDO tag, TemplateRenderRequest request, + String templateName) { + String fieldName = tag.getTagCode(); + + // 判断是否有字段级的数据源覆盖 + DocTemplateDataSourceType sourceType = null; + if (request.getFieldDataSources() != null) { + sourceType = request.getFieldDataSources().get(fieldName); + } + + // 如果有覆盖,从指定的数据源获取值 + if (sourceType != null) { + try { + IDataSourceProvider provider = dataSourceProviderFactory + .createProvider( + sourceType, + request.getDataSourceContext(), + templateName, + request.getBusinessType() != null ? + request.getBusinessType() : templateName + ); + + Map data = provider.getData( + request.getDataSourceContext(), + java.util.List.of(fieldName) + ); + + if (data.containsKey(fieldName)) { + Object value = data.get(fieldName); + if (value != null) { + log.debug("从数据源 {} 获取字段值: {} = {}", sourceType, fieldName, value); + return value; + } + } + } catch (Exception e) { + log.warn("从数据源获取字段值失败,使用默认值: {}, 数据源: {}", fieldName, sourceType, e); + } + } + + // 使用默认值(从标签的defaultValue字段获取) + String defaultValue = extractDefaultValue(tag); + log.debug("使用标签默认值: {} = {}", fieldName, defaultValue); + return defaultValue; + } + + /** + * 从标签定义中提取默认值 + */ + private String extractDefaultValue(DocTemplateTagDO tag) { + if (tag.getDefaultValue() != null && !tag.getDefaultValue().trim().isEmpty()) { + return tag.getDefaultValue(); + } + return ""; + } + + /** + * 获取模板实例关联的标签列表 + * 通过实例的 categoryId 查询该分类下的所有标签定义 + */ + private List getTemplateTags(DocTemplateInstanceRespVO instance) { + if (instance.getCategoryId() == null) { + log.warn("模板实例 {} 没有关联分类ID", instance.getId()); + return List.of(); + } + + try { + // 通过 categoryId 查询该分类下的所有标签 + List tags = docTemplateTagMapper.selectList( + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(DocTemplateTagDO::getCategoryId, instance.getCategoryId()) + .eq(DocTemplateTagDO::getEnabled, "1") // 只查询启用的标签 + .orderByAsc(DocTemplateTagDO::getSort) + ); + + if (tags == null || tags.isEmpty()) { + log.warn("分类ID {} 下没有找到标签定义", instance.getCategoryId()); + return List.of(); + } + + log.debug("从分类ID {} 获取到 {} 个标签定义", instance.getCategoryId(), tags.size()); + return tags; + } catch (Exception e) { + log.error("查询分类 {} 的标签列表失败", instance.getCategoryId(), e); + return List.of(); + } + } +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateDataSourceProviderFactory.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateDataSourceProviderFactory.java new file mode 100644 index 0000000..928441a --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateDataSourceProviderFactory.java @@ -0,0 +1,111 @@ +package com.zt.plat.module.base.service.doctemplate.render; + +import com.zt.plat.module.base.service.doctemplate.render.provider.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import jakarta.annotation.Resource; + +/** + * 文档模板数据源提供者工厂(工厂模式) + * + * @author hwc + */ +@Component +@Slf4j +public class DocTemplateDataSourceProviderFactory { + + @Resource + private ApplicationContext applicationContext; + + @Resource + private ISqlConfigProvider sqlConfigProvider; + + /** + * 创建数据源提供者 + * + * @param sourceType 数据源类型 + * @param context 数据源上下文(含义由sourceType决定) + * @param templateName 模板名称(用于查找业务数据提供者) + * @param businessType 业务类型(当sourceType=BUSINESS时使用,如"contract"、"order"等) + * @return 数据源提供者实例 + */ + public IDataSourceProvider createProvider( + DocTemplateDataSourceType sourceType, + Object context, + String templateName, + String businessType) { + + log.debug("创建数据源提供者,类型: {}, 业务类型: {}", sourceType, businessType); + + switch (sourceType) { + case DEFAULT: + return new DocTemplateDefaultFieldDataSourceProvider(); + + case BUSINESS: + return createBusinessDataProvider(businessType); + + case REQUEST: + // context 应该是 Map 类型的请求数据 + return new DocTemplateRequestFieldDataSourceProvider((java.util.Map) context); + + case SQL_CONFIG: + // context 应该是 sqlConfigId + return new DocTemplateSqlConfigFieldDataSourceProvider(sqlConfigProvider, (String) context); + + default: + throw new IllegalArgumentException("不支持的数据源类型: " + sourceType); + } + } + + /** + * 创建业务数据提供者 + * + * @param businessType 业务类型 + * @return 数据源提供者 + */ + private IDataSourceProvider createBusinessDataProvider(String businessType) { + if (businessType == null || businessType.trim().isEmpty()) { + throw new IllegalArgumentException("使用BUSINESS数据源时,businessType不能为空"); + } + + // 业务数据提供者的Bean名称约定:{businessType}DataProvider + // 示例:contractDataProvider、orderDataProvider、purchaseOrderDataProvider等 + String providerBeanName = businessType + "DataProvider"; + + try { + IBusinessDataProvider businessDataProvider = applicationContext.getBean( + providerBeanName, + IBusinessDataProvider.class + ); + + log.debug("找到业务数据提供者: {}", providerBeanName); + return new DocTemplateBusinessFieldDataSourceProvider(businessDataProvider); + + } catch (NoSuchBeanDefinitionException e) { + throw new IllegalArgumentException( + "未找到业务数据提供者: " + providerBeanName + + "(业务类型:" + businessType + ")" + + "。请确保实现了 " + IBusinessDataProvider.class.getSimpleName() + + " 接口并注册为名为 '" + providerBeanName + "' 的Spring Bean。", e); + } + } + + /** + * 重载方法:不指定businessType时的调用 + * 此时将使用templateName作为businessType(向后兼容) + * + * @param sourceType 数据源类型 + * @param context 数据源上下文 + * @param templateName 模板名称 + * @return 数据源提供者实例 + */ + public IDataSourceProvider createProvider( + DocTemplateDataSourceType sourceType, + Object context, + String templateName) { + return createProvider(sourceType, context, templateName, templateName); + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateDataSourceType.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateDataSourceType.java new file mode 100644 index 0000000..76c34e2 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/DocTemplateDataSourceType.java @@ -0,0 +1,38 @@ +package com.zt.plat.module.base.service.doctemplate.render; + +/** + * 数据源类型枚举 + * + * @author hwc + */ +public enum DocTemplateDataSourceType { + /** + * 标签默认值 + */ + DEFAULT("标签默认值"), + + /** + * 业务策略 + */ + BUSINESS("业务策略"), + + /** + * 前端入参 + */ + REQUEST("前端入参"), + + /** + * SQL配置 + */ + SQL_CONFIG("SQL配置"); + + private final String description; + + DocTemplateDataSourceType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IBusinessDataProvider.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IBusinessDataProvider.java new file mode 100644 index 0000000..424a4da --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IBusinessDataProvider.java @@ -0,0 +1,30 @@ +package com.zt.plat.module.base.service.doctemplate.render; + +import java.util.Map; + +/** + * 业务数据提供者接口 + * 不同的业务类型实现此接口来提供数据 + * + *

命名约定:{业务类型}DataProvider + *

示例: + *

    + *
  • ContractDataProvider (合同数据提供者)
  • + *
  • OrderDataProvider (订单数据提供者)
  • + *
  • PurchaseOrderDataProvider (采购单数据提供者)
  • + *
  • SalesOrderDataProvider (销售单数据提供者)
  • + *
+ * + * @author hwc + */ +public interface IBusinessDataProvider { + + /** + * 获取业务数据 + * + * @param context 业务上下文(通常是业务ID,如contractId、orderId等) + * @param fieldNames 需要填充的字段名列表 + * @return 字段值映射表 + */ + Map provideData(Object context, java.util.List fieldNames); +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IDataSourceProvider.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IDataSourceProvider.java new file mode 100644 index 0000000..803c79b --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IDataSourceProvider.java @@ -0,0 +1,28 @@ +package com.zt.plat.module.base.service.doctemplate.render; + +import java.util.Map; + +/** + * 文档模板数据源提供者接口(策略模式) + * 所有数据源实现都遵循此接口 + * + * @author hwc + */ +public interface IDataSourceProvider { + + /** + * 获取指定字段的值 + * + * @param context 上下文信息(内容因数据源类型而异) + * @param fieldNames 需要获取的字段名列表 + * @return 字段值映射表 + */ + Map getData(Object context, java.util.List fieldNames); + + /** + * 获取此数据源的类型 + * + * @return 数据源类型 + */ + DocTemplateDataSourceType getType(); +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/ISqlConfigProvider.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/ISqlConfigProvider.java new file mode 100644 index 0000000..6fa14b8 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/ISqlConfigProvider.java @@ -0,0 +1,20 @@ +package com.zt.plat.module.base.service.doctemplate.render; + +import java.util.List; +import java.util.Map; + +/** + * SQL配置数据提供者接口 + * + * @author hwc + */ +public interface ISqlConfigProvider { + + /** + * 查询SQL配置结果 + * + * @param sqlConfigId SQL配置ID + * @return 查询结果列表,每个Map代表一行数据 + */ + List> querySqlConfig(String sqlConfigId); +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IVelocityRenderEngine.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IVelocityRenderEngine.java new file mode 100644 index 0000000..749534a --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/IVelocityRenderEngine.java @@ -0,0 +1,20 @@ +package com.zt.plat.module.base.service.doctemplate.render; + +import java.util.Map; + +/** + * Velocity 渲染引擎接口 + * + * @author hwc + */ +public interface IVelocityRenderEngine { + + /** + * 渲染模板内容 + * + * @param templateContent 模板内容 + * @param data 数据映射 + * @return 渲染后的内容 + */ + String render(String templateContent, Map data); +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/TemplateRenderRequest.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/TemplateRenderRequest.java new file mode 100644 index 0000000..5684aed --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/TemplateRenderRequest.java @@ -0,0 +1,21 @@ +package com.zt.plat.module.base.service.doctemplate.render; + +import com.zt.plat.module.base.service.doctemplate.render.export.ExportType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TemplateRenderRequest { + private Long templateInstanceId; + private Map fieldDataSources; + private Object dataSourceContext; + private ExportType exportType = ExportType.WORD; + private String businessType; +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/VelocityRenderEngineImpl.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/VelocityRenderEngineImpl.java new file mode 100644 index 0000000..5d70f23 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/VelocityRenderEngineImpl.java @@ -0,0 +1,99 @@ +package com.zt.plat.module.base.service.doctemplate.render; + +import lombok.extern.slf4j.Slf4j; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.resource.loader.StringResourceLoader; +import org.springframework.stereotype.Component; + +import jakarta.annotation.PostConstruct; +import java.io.StringWriter; +import java.util.Map; +import java.util.Properties; + +/** + * Velocity 渲染引擎实现 + */ +@Component +@Slf4j +public class VelocityRenderEngineImpl implements IVelocityRenderEngine { + + private static volatile boolean velocityInitialized = false; + + @PostConstruct + public synchronized void initVelocity() { + if (velocityInitialized) { + return; + } + + try { + Properties props = new Properties(); + props.setProperty("input.encoding", "UTF-8"); + props.setProperty("output.encoding", "UTF-8"); + props.setProperty("resource.loader", "string"); + props.setProperty("string.resource.loader.class", StringResourceLoader.class.getName()); + props.setProperty("runtime.log.logsystem.class", + "org.apache.velocity.runtime.log.NullLogChute"); + props.setProperty("eventhandler.referenceinsertion.class", + "org.apache.velocity.app.event.implement.EscapeHtmlReference"); + props.setProperty("eventhandler.escape.html.match", "true"); + + Velocity.init(props); + velocityInitialized = true; + log.info("Velocity 模板引擎初始化成功"); + } catch (Exception e) { + log.error("Velocity 模板引擎初始化失败", e); + throw new RuntimeException("Velocity 模板引擎初始化失败", e); + } + } + + @Override + public String render(String templateContent, Map data) { + if (templateContent == null || templateContent.trim().isEmpty()) { + log.warn("模板内容为空"); + return ""; + } + + if (!velocityInitialized) { + initVelocity(); + } + + // 转换模板语法:{{variableName}} -> ${variableName} + // 支持Mustache/Handlebars风格的模板兼容Velocity语法 + String velocityTemplate = convertToVelocitySyntax(templateContent); + + VelocityContext context = new VelocityContext(); + if (data != null && !data.isEmpty()) { + data.forEach(context::put); + } + + try { + StringWriter writer = new StringWriter(); + Velocity.evaluate(context, writer, "TemplateRender", velocityTemplate); + String result = writer.toString(); + + log.debug("模板渲染成功,数据量: {}, 内容长度: {}", + data != null ? data.size() : 0, result.length()); + + return result; + } catch (Exception e) { + log.error("模板渲染失败,模板长度: {}", templateContent.length(), e); + throw new RuntimeException("模板渲染失败: " + e.getMessage(), e); + } + } + + /** + * 将 Mustache/Handlebars 语法 {{variableName}} 转换为 Velocity 语法 ${variableName} + * + * @param template 原始模板内容 + * @return 转换后的 Velocity 语法模板 + */ + private String convertToVelocitySyntax(String template) { + if (template == null) { + return null; + } + // 使用正则表达式替换 {{variable}} 为 ${variable} + // 匹配 {{ 和 }} 之间的内容(非贪婪模式) + return template.replaceAll("\\{\\{\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\}\\}", "\\${$1}"); + } +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/DocTemplateAbstractExportStrategy.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/DocTemplateAbstractExportStrategy.java new file mode 100644 index 0000000..8577bd5 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/DocTemplateAbstractExportStrategy.java @@ -0,0 +1,79 @@ +package com.zt.plat.module.base.service.doctemplate.render.export; + +import lombok.extern.slf4j.Slf4j; + +/** + * 抽象导出策略(模板方法模式) + * 定义导出的标准流程框架 + * + * @author hwc + */ +@Slf4j +public abstract class DocTemplateAbstractExportStrategy implements IExportStrategy { + + /** + * 模板方法:定义导出流程骨架 + */ + @Override + public final Object export(String htmlContent, String templateName) { + // 1. 验证输入 + validateInput(htmlContent, templateName); + + // 2. 生成文件名 + String fileName = generateFileName(templateName); + + // 3. 执行具体的导出逻辑 + Object result = doExport(htmlContent, fileName); + + // 4. 后处理(如日志、监控等) + postProcess(fileName, result); + + return result; + } + + /** + * 验证输入 + */ + protected void validateInput(String htmlContent, String templateName) { + if (htmlContent == null || htmlContent.isEmpty()) { + throw new IllegalArgumentException("HTML内容为空"); + } + if (templateName == null || templateName.isEmpty()) { + throw new IllegalArgumentException("模板名称为空"); + } + } + + /** + * 生成文件名 + */ + protected String generateFileName(String templateName) { + return templateName + "_" + System.currentTimeMillis() + getFileExtension(); + } + + /** + * 具体的导出逻辑(由子类实现) + * + * @param htmlContent HTML内容 + * @param fileName 文件名 + * @return 导出结果 + */ + protected abstract Object doExport(String htmlContent, String fileName); + + /** + * 获取文件扩展名 + * + * @return 文件扩展名 + */ + protected abstract String getFileExtension(); + + /** + * 后处理逻辑(可选,子类可覆盖) + * + * @param fileName 文件名 + * @param result 导出结果 + */ + protected void postProcess(String fileName, Object result) { + // 默认实现:记录日志 + log.info("导出完成: {}, 类型: {}", fileName, getExportType().getDescription()); + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/DocTemplateExportStrategyFactory.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/DocTemplateExportStrategyFactory.java new file mode 100644 index 0000000..a2f3fb5 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/DocTemplateExportStrategyFactory.java @@ -0,0 +1,58 @@ +package com.zt.plat.module.base.service.doctemplate.render.export; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import jakarta.annotation.Resource; + +/** + * 文档模板导出策略工厂(工厂模式) + * + * @author hwc + */ +@Component +@Slf4j +public class DocTemplateExportStrategyFactory { + + @Resource(name = "docTemplateWordExportTemplateStrategy") + private IExportStrategy wordExportStrategy; + + @Resource(name = "docTemplateHtmlPreviewTemplateStrategy") + private IExportStrategy htmlPreviewStrategy; + + // TODO: 添加其他导出策略的注入 + // @Resource(name = "docTemplateExcelExportTemplateStrategy") + // private IExportStrategy excelExportStrategy; + // + // @Resource(name = "docTemplatePdfExportTemplateStrategy") + // private IExportStrategy pdfExportStrategy; + + /** + * 创建导出方式策略 + * + * @param exportType 导出类型 + * @return 导出策略实例 + */ + public IExportStrategy createStrategy(ExportType exportType) { + log.debug("创建导出策略,类型: {}", exportType); + + switch (exportType) { + case WORD: + return wordExportStrategy; + + case EXCEL: + // TODO: 实现Excel导出策略 + throw new UnsupportedOperationException("Excel导出功能尚未实现"); + + case PDF: + // TODO: 实现PDF导出策略 + throw new UnsupportedOperationException("PDF导出功能尚未实现"); + + case HTML_PREVIEW: + return htmlPreviewStrategy; + + default: + throw new IllegalArgumentException("不支持的导出方式: " + exportType); + } + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/ExportType.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/ExportType.java new file mode 100644 index 0000000..5c22a94 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/ExportType.java @@ -0,0 +1,38 @@ +package com.zt.plat.module.base.service.doctemplate.render.export; + +/** + * 导出方式枚举 + * + * @author hwc + */ +public enum ExportType { + /** + * Word文档 + */ + WORD("Word"), + + /** + * Excel表格 + */ + EXCEL("Excel"), + + /** + * PDF文档 + */ + PDF("PDF"), + + /** + * HTML预览 + */ + HTML_PREVIEW("HTML预览"); + + private final String description; + + ExportType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/HtmlPreviewResult.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/HtmlPreviewResult.java new file mode 100644 index 0000000..477d2df --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/HtmlPreviewResult.java @@ -0,0 +1,36 @@ +package com.zt.plat.module.base.service.doctemplate.render.export; + +import lombok.*; + +/** + * HTML预览结果 + * + * @author hwc + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class HtmlPreviewResult { + /** + * HTML内容 + */ + private String htmlContent; + + /** + * 文件名 + */ + private String fileName; + + /** + * 内容类型 + */ + @Builder.Default + private String contentType = "text/html"; + + @Override + public String toString() { + return htmlContent; + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/HtmlPreviewTemplateStrategyDocTemplate.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/HtmlPreviewTemplateStrategyDocTemplate.java new file mode 100644 index 0000000..188df1f --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/HtmlPreviewTemplateStrategyDocTemplate.java @@ -0,0 +1,39 @@ +package com.zt.plat.module.base.service.doctemplate.render.export; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * HTML预览策略实现 + * 直接返回HTML内容用于前端预览 + * + * @author hwc + */ +@Component("docTemplateHtmlPreviewTemplateStrategy") +@Slf4j +public class HtmlPreviewTemplateStrategyDocTemplate extends DocTemplateAbstractExportStrategy { + + @Override + protected Object doExport(String htmlContent, String fileName) { + log.debug("HTML预览,内容长度: {}", htmlContent.length()); + + // 直接返回HTML内容 + HtmlPreviewResult result = HtmlPreviewResult.builder() + .htmlContent(htmlContent) + .fileName(fileName) + .build(); + + log.debug("HTML预览完成"); + return result; + } + + @Override + protected String getFileExtension() { + return ".html"; + } + + @Override + public ExportType getExportType() { + return ExportType.HTML_PREVIEW; + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/IExportStrategy.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/IExportStrategy.java new file mode 100644 index 0000000..c1507b2 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/IExportStrategy.java @@ -0,0 +1,26 @@ +package com.zt.plat.module.base.service.doctemplate.render.export; + +/** + * 导出方式策略接口(策略模式) + * 定义所有导出方式的标准接口 + * + * @author hwc + */ +public interface IExportStrategy { + + /** + * 执行导出 + * + * @param htmlContent 渲染后的HTML内容 + * @param templateName 模板名称(用于生成文件名) + * @return 导出结果 + */ + Object export(String htmlContent, String templateName); + + /** + * 获取导出方式类型 + * + * @return 导出类型 + */ + ExportType getExportType(); +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/WordExportResult.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/WordExportResult.java new file mode 100644 index 0000000..d7068f4 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/WordExportResult.java @@ -0,0 +1,48 @@ +package com.zt.plat.module.base.service.doctemplate.render.export; + +import lombok.*; + +import java.io.InputStream; + +/** + * Word 导出结果 + * + * @author hwc + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString(exclude = "fileContent") +public class WordExportResult { + /** + * 文件路径(如果保存到服务器) + */ + private String filePath; + + /** + * 文件流(如果直接返回) + */ + private InputStream fileStream; + + /** + * 文件内容(字节数组) + */ + private byte[] fileContent; + + /** + * 文件名 + */ + private String fileName; + + /** + * 文件大小(字节) + */ + private Long fileSize; + + /** + * 内容类型 + */ + @Builder.Default + private String contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/WordExportTemplateStrategyDocTemplate.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/WordExportTemplateStrategyDocTemplate.java new file mode 100644 index 0000000..e0433eb --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/export/WordExportTemplateStrategyDocTemplate.java @@ -0,0 +1,68 @@ +package com.zt.plat.module.base.service.doctemplate.render.export; + +import com.zt.plat.module.base.service.doctemplate.DocumentRenderApiService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import jakarta.annotation.Resource; + +import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.zt.plat.module.base.enums.ErrorCodeConstants.*; + +/** + * Word 导出策略实现 + * 基于现有的 DocumentRenderApiService 进行扩展 + * + * @author hwc + */ +@Component("docTemplateWordExportTemplateStrategy") +@Slf4j +public class WordExportTemplateStrategyDocTemplate extends DocTemplateAbstractExportStrategy { + + @Resource + private DocumentRenderApiService documentRenderApiService; + + @Override + protected Object doExport(String htmlContent, String fileName) { + try { + log.debug("开始导出Word文档,文件名: {}", fileName); + + // 调用 DocumentRenderApiService 将HTML转换为Word + byte[] wordContent = documentRenderApiService.exportToWord(htmlContent, fileName); + + // 构建导出结果 + WordExportResult result = WordExportResult.builder() + .fileName(fileName + getFileExtension()) + .fileContent(wordContent) + .fileSize((long) wordContent.length) + .contentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document") + .build(); + + log.info("Word导出完成,文件名: {}, 大小: {} bytes", fileName, wordContent.length); + return result; + + } catch (Exception e) { + log.error("Word导出失败,文件名: {}", fileName, e); + throw exception(TEMPLATE_EXPORT_FAILED); + } + } + + @Override + protected String getFileExtension() { + return ".docx"; + } + + @Override + public ExportType getExportType() { + return ExportType.WORD; + } + + @Override + protected void postProcess(String fileName, Object result) { + // Word导出特定的后处理逻辑 + if (result instanceof WordExportResult) { + WordExportResult wordResult = (WordExportResult) result; + log.info("Word导出后处理完成: {}, 文件大小: {}字节", fileName, wordResult.getFileSize()); + } + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/ContractDataProvider.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/ContractDataProvider.java new file mode 100644 index 0000000..0784eec --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/ContractDataProvider.java @@ -0,0 +1,90 @@ +package com.zt.plat.module.base.service.doctemplate.render.provider; + +import com.zt.plat.module.base.service.doctemplate.render.IBusinessDataProvider; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 合同数据提供者 + * 提供合同相关的业务数据 + * + * @author hwc + */ +@Component("contractDataProvider") +@Slf4j +public class ContractDataProvider implements IBusinessDataProvider { + + @Override + public Map provideData(Object context, List fieldNames) { + Long contractId = null; + if (context instanceof Long) { + contractId = (Long) context; + } else if (context instanceof String) { + try { + contractId = Long.valueOf((String) context); + } catch (NumberFormatException e) { + log.warn("无效的合同ID格式: {}", context); + return Map.of(); + } + } + + if (contractId == null) { + log.warn("合同ID为空"); + return Map.of(); + } + + log.debug("获取合同数据,合同ID: {}, 请求字段: {}", contractId, fieldNames); + + // TODO: 实际实现应该: + // 1. 根据合同ID从数据库或服务中查询合同信息 + // 2. 根据请求的字段名返回对应的数据 + // 3. 处理数据类型转换 + + // 临时实现:返回一些示例数据 + Map data = new HashMap<>(); + + // 模拟合同数据 + for (String fieldName : fieldNames) { + switch (fieldName) { + case "contractName": + case "contract_name": + data.put(fieldName, "中铜采购合同-" + contractId); + break; + case "supplier": + case "supplier_name": + data.put(fieldName, "上海金属贸易有限公司"); + break; + case "amount": + case "total_amount": + data.put(fieldName, 5000000.00); + break; + case "deliveryDate": + case "delivery_date": + data.put(fieldName, "2025-06-30"); + break; + case "contractNumber": + case "contract_number": + data.put(fieldName, "HT-2025-" + String.format("%04d", contractId % 10000)); + break; + case "signDate": + case "sign_date": + data.put(fieldName, "2025-01-15"); + break; + case "paymentTerms": + case "payment_terms": + data.put(fieldName, "预付30%,发货付60%,验收付10%"); + break; + default: + log.debug("未处理的合同字段: {}", fieldName); + break; + } + } + + log.debug("返回合同数据: {}", data.keySet()); + return data; + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateBusinessFieldDataSourceProvider.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateBusinessFieldDataSourceProvider.java new file mode 100644 index 0000000..bbf63a6 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateBusinessFieldDataSourceProvider.java @@ -0,0 +1,49 @@ +package com.zt.plat.module.base.service.doctemplate.render.provider; + +import com.zt.plat.module.base.service.doctemplate.render.DocTemplateDataSourceType; +import com.zt.plat.module.base.service.doctemplate.render.IBusinessDataProvider; +import com.zt.plat.module.base.service.doctemplate.render.IDataSourceProvider; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.Map; + +/** + * 业务数据源提供者实现 + * 包装业务数据提供者,提供统一的数据源接口 + * + * @author hwc + */ +@Slf4j +public class DocTemplateBusinessFieldDataSourceProvider implements IDataSourceProvider { + + private final IBusinessDataProvider businessDataProvider; + + public DocTemplateBusinessFieldDataSourceProvider(IBusinessDataProvider businessDataProvider) { + this.businessDataProvider = businessDataProvider; + log.debug("创建业务数据源提供者: {}", businessDataProvider.getClass().getSimpleName()); + } + + @Override + public Map getData(Object context, List fieldNames) { + if (businessDataProvider == null) { + log.warn("业务数据提供者为空"); + return Map.of(); + } + + try { + log.debug("调用业务数据提供者获取数据,上下文: {}, 字段数量: {}", context, fieldNames.size()); + Map data = businessDataProvider.provideData(context, fieldNames); + log.debug("业务数据提供者返回数据: {}", data.keySet()); + return data; + } catch (Exception e) { + log.error("业务数据提供者获取数据失败", e); + return Map.of(); + } + } + + @Override + public DocTemplateDataSourceType getType() { + return DocTemplateDataSourceType.BUSINESS; + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateDefaultFieldDataSourceProvider.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateDefaultFieldDataSourceProvider.java new file mode 100644 index 0000000..eaead68 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateDefaultFieldDataSourceProvider.java @@ -0,0 +1,31 @@ +package com.zt.plat.module.base.service.doctemplate.render.provider; + +import com.zt.plat.module.base.service.doctemplate.render.DocTemplateDataSourceType; +import com.zt.plat.module.base.service.doctemplate.render.IDataSourceProvider; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 标签默认值数据源实现 + * 返回空数据,表示使用字段自身的默认值 + * + * @author hwc + */ +@Slf4j +public class DocTemplateDefaultFieldDataSourceProvider implements IDataSourceProvider { + + @Override + public Map getData(Object context, List fieldNames) { + // 默认值由调用方在外层处理,这里返回空,表示不提供覆盖数据 + log.debug("默认值数据源被调用,字段数量: {}", fieldNames != null ? fieldNames.size() : 0); + return new HashMap<>(); + } + + @Override + public DocTemplateDataSourceType getType() { + return DocTemplateDataSourceType.DEFAULT; + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateRequestFieldDataSourceProvider.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateRequestFieldDataSourceProvider.java new file mode 100644 index 0000000..f919c02 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateRequestFieldDataSourceProvider.java @@ -0,0 +1,52 @@ +package com.zt.plat.module.base.service.doctemplate.render.provider; + +import com.zt.plat.module.base.service.doctemplate.render.DocTemplateDataSourceType; +import com.zt.plat.module.base.service.doctemplate.render.IDataSourceProvider; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 前端入参数据源提供者实现 + * 从传入的请求数据中提取字段值 + * + * @author hwc + */ +@Slf4j +public class DocTemplateRequestFieldDataSourceProvider implements IDataSourceProvider { + + private final Map requestData; + + public DocTemplateRequestFieldDataSourceProvider(Map requestData) { + this.requestData = requestData != null ? requestData : Map.of(); + log.debug("创建前端入参数据源提供者,数据量: {}", this.requestData.size()); + } + + @Override + public Map getData(Object context, List fieldNames) { + Map result = new HashMap<>(); + + if (requestData == null || requestData.isEmpty()) { + log.debug("前端入参数据为空"); + return result; + } + + for (String fieldName : fieldNames) { + if (requestData.containsKey(fieldName)) { + Object value = requestData.get(fieldName); + result.put(fieldName, value); + log.debug("从前端入参获取字段值: {} = {}", fieldName, value); + } + } + + log.debug("前端入参数据源提供结果: {}", result.keySet()); + return result; + } + + @Override + public DocTemplateDataSourceType getType() { + return DocTemplateDataSourceType.REQUEST; + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateSqlConfigFieldDataSourceProvider.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateSqlConfigFieldDataSourceProvider.java new file mode 100644 index 0000000..dfd246b --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/DocTemplateSqlConfigFieldDataSourceProvider.java @@ -0,0 +1,60 @@ +package com.zt.plat.module.base.service.doctemplate.render.provider; + +import com.zt.plat.module.base.service.doctemplate.render.DocTemplateDataSourceType; +import com.zt.plat.module.base.service.doctemplate.render.IDataSourceProvider; +import com.zt.plat.module.base.service.doctemplate.render.ISqlConfigProvider; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.Map; + +/** + * SQL配置数据源提供者实现 + * 执行SQL配置查询并返回结果 + * + * @author hwc + */ +@Slf4j +public class DocTemplateSqlConfigFieldDataSourceProvider implements IDataSourceProvider { + + private final ISqlConfigProvider sqlConfigProvider; + private final String sqlConfigId; + + public DocTemplateSqlConfigFieldDataSourceProvider(ISqlConfigProvider sqlConfigProvider, String sqlConfigId) { + this.sqlConfigProvider = sqlConfigProvider; + this.sqlConfigId = sqlConfigId; + log.debug("创建SQL配置数据源提供者: {}", sqlConfigId); + } + + @Override + public Map getData(Object context, List fieldNames) { + if (sqlConfigProvider == null) { + log.warn("SQL配置提供者为空"); + return Map.of(); + } + + try { + log.debug("执行SQL配置查询: {}", sqlConfigId); + List> results = sqlConfigProvider.querySqlConfig(sqlConfigId); + + if (results == null || results.isEmpty()) { + log.debug("SQL配置查询无结果"); + return Map.of(); + } + + // 返回第一行结果(通常SQL配置查询应该返回单行) + Map result = results.get(0); + log.debug("SQL配置查询结果字段: {}", result.keySet()); + return result; + + } catch (Exception e) { + log.error("SQL配置查询失败: {}", sqlConfigId, e); + return Map.of(); + } + } + + @Override + public DocTemplateDataSourceType getType() { + return DocTemplateDataSourceType.SQL_CONFIG; + } +} \ No newline at end of file diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/OrderDataProvider.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/OrderDataProvider.java new file mode 100644 index 0000000..37839a8 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/doctemplate/render/provider/OrderDataProvider.java @@ -0,0 +1,90 @@ +package com.zt.plat.module.base.service.doctemplate.render.provider; + +import com.zt.plat.module.base.service.doctemplate.render.IBusinessDataProvider; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 订单数据提供者 + * 提供订单相关的业务数据 + * + * @author hwc + */ +@Component("orderDataProvider") +@Slf4j +public class OrderDataProvider implements IBusinessDataProvider { + + @Override + public Map provideData(Object context, List fieldNames) { + Long orderId = null; + if (context instanceof Long) { + orderId = (Long) context; + } else if (context instanceof String) { + try { + orderId = Long.valueOf((String) context); + } catch (NumberFormatException e) { + log.warn("无效的订单ID格式: {}", context); + return Map.of(); + } + } + + if (orderId == null) { + log.warn("订单ID为空"); + return Map.of(); + } + + log.debug("获取订单数据,订单ID: {}, 请求字段: {}", orderId, fieldNames); + + // TODO: 实际实现应该: + // 1. 根据订单ID从数据库或服务中查询订单信息 + // 2. 根据请求的字段名返回对应的数据 + // 3. 处理数据类型转换 + + // 临时实现:返回一些示例数据 + Map data = new HashMap<>(); + + // 模拟订单数据 + for (String fieldName : fieldNames) { + switch (fieldName) { + case "orderNumber": + case "order_number": + data.put(fieldName, "ORD-2025-" + String.format("%06d", orderId % 100000)); + break; + case "customer": + case "customer_name": + data.put(fieldName, "中铜制造有限公司"); + break; + case "totalAmount": + case "total_amount": + data.put(fieldName, 2500000.00); + break; + case "orderDate": + case "order_date": + data.put(fieldName, "2025-01-20"); + break; + case "deliveryAddress": + case "delivery_address": + data.put(fieldName, "上海市浦东新区金桥路123号"); + break; + case "contactPerson": + case "contact_person": + data.put(fieldName, "张经理"); + break; + case "contactPhone": + case "contact_phone": + data.put(fieldName, "13800138000"); + break; + default: + log.debug("未处理的订单字段: {}", fieldName); + break; + } + } + + log.debug("返回订单数据: {}", data.keySet()); + return data; + } +} \ No newline at end of file From e6aa0042d9c6e9aa1636fae6e10d375b050fb0ee Mon Sep 17 00:00:00 2001 From: guojunyun Date: Tue, 11 Nov 2025 09:35:41 +0800 Subject: [PATCH 09/11] =?UTF-8?q?=E5=9B=BD=E8=B4=B82.0=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E5=90=88=E5=90=8C=E5=9B=9E=E8=B0=83=EF=BC=9A?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=9B=BA=E5=AE=9AR=5FJG=5FMY=5F00=E5=BA=94?= =?UTF-8?q?=E7=AD=94=EF=BC=8C=5FinterfaceType=5F=5F=E5=9B=BA=E5=AE=9A?= =?UTF-8?q?=E4=BC=A0R=5FMY=5FJG=5F10=20=E5=90=88=E5=90=8C=E4=B8=BB?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E6=B7=BB=E5=8A=A0=E8=B4=A7=E6=9D=83=E8=BD=AC?= =?UTF-8?q?=E7=A7=BB=E7=B1=BB=E5=9E=8B(=E5=AD=97=E5=85=B8=EF=BC=9AASY=5FMT?= =?UTF-8?q?NG=5FTP)=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/dto/contract/ContractRespDTO.java | 3 + .../api/vo/contract/ContractRespVO.java | 3 + .../api/vo/contract/ContractSaveReqVO.java | 3 + .../contractorder/api/ContractApiImpl.java | 4 +- .../dataobject/contract/ContractMainDO.java | 468 ++++++------------ 5 files changed, 174 insertions(+), 307 deletions(-) diff --git a/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/dto/contract/ContractRespDTO.java b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/dto/contract/ContractRespDTO.java index 4def12c..24dd339 100644 --- a/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/dto/contract/ContractRespDTO.java +++ b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/dto/contract/ContractRespDTO.java @@ -236,6 +236,9 @@ public class ContractRespDTO { @Schema(description = "代理方名称") private String agentName; + @Schema(description = "货权转移类型(字典:ASY_MTNG_TP)") + private String meteringType; + // 物料信息 private List detail; diff --git a/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/ContractRespVO.java b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/ContractRespVO.java index 1c1bbc1..5baf2a7 100644 --- a/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/ContractRespVO.java +++ b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/ContractRespVO.java @@ -242,6 +242,9 @@ public class ContractRespVO { @Schema(description = "代理方名称") private String agentName; + @Schema(description = "货权转移类型(字典:ASY_MTNG_TP)") + private String meteringType; + // 物料信息 private List detail; diff --git a/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/ContractSaveReqVO.java b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/ContractSaveReqVO.java index 6b0bd4c..a6adf69 100644 --- a/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/ContractSaveReqVO.java +++ b/zt-module-contract-order/zt-module-contract-order-api/src/main/java/com/zt/plat/module/contractorder/api/vo/contract/ContractSaveReqVO.java @@ -211,6 +211,9 @@ public class ContractSaveReqVO { @Schema(description = "代理方名称") private String agentName; + @Schema(description = "货权转移类型(字典:ASY_MTNG_TP)") + private String meteringType; + // 物料信息 private List detail; diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java index f718bef..42ed6c4 100644 --- a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/api/ContractApiImpl.java @@ -378,7 +378,7 @@ public class ContractApiImpl implements ContractApi { // 返回数据 IntPushContractRespVO body = new IntPushContractRespVO(); body.set__requestId_(pushReqVO.get__requestId_()); - body.set__interfaceType__(pushReqVO.get__interfaceType__()); + body.set__interfaceType__("R_MY_JG_10"); body.setBusiBillCode(pushReqVO.getBusiBillCode()); body.setCode(code); body.setMessage(String.format("推送合同[%s]%s", pushReqVO.getData().getContractCode(), code >= 0 ? "成功" : "失败:" + msg)); @@ -388,7 +388,7 @@ public class ContractApiImpl implements ContractApi { // 回调参数 JSONObject req = new JSONObject(); - req.set("messageKey", pushReqVO.getBusiBillCode()); + req.set("messageKey", "R_JG_MY_00"); req.set("messageBody", body); try { log.info("国贸系统推送合同回调参数:{}",req); diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java index f5d9681..f0c32d3 100644 --- a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java @@ -6,6 +6,8 @@ import lombok.*; import java.math.BigDecimal; import java.time.LocalDateTime; +import static com.zt.plat.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + /** * 合同主信息 DO * @@ -24,379 +26,235 @@ import java.time.LocalDateTime; */ public class ContractMainDO extends BusinessBaseDO { - /** - * 主键 - */ - @TableId(type = IdType.ASSIGN_ID) - private Long id; - /** - * 模板实例主键 - */ - @TableField("INSC_ID") + @Schema(description = "模板实例主键", example = "2571") private Long instanceId; - /** - * 系统合同编号;自动生成,校验唯一 - */ - @TableField("SYS_CTRT_NUM") + + @Schema(description = "系统合同编号;自动生成,校验唯一") private String systemContractNumber; - /** - * 状态(字典: BSE_CTRT_STS) - */ - @TableField("STS") + + @Schema(description = "状态(字典: BSE_CTRT_STS)", example = "1") private String status; - /** - * 合同名称;与ERP(HTMC)对应,校验唯一 - */ - @TableField("CTRT_NAME") + + @Schema(description = "合同名称;与ERP(HTMC)对应,校验唯一", example = "李四") private String contractName; - /** - * 合同编号;与ERP(HTBH)对应,校验唯一 - */ - @TableField("CTRT_PPR_NUM") + + @Schema(description = "合同编号;与ERP(HTBH)对应,校验唯一") private String contractPaperNumber; - /** - * 是否虚拟合同;与ERP(SFXNHT)对应 - */ - @TableField("CTRT_VRTL") + + @Schema(description = "是否虚拟合同;与ERP(SFXNHT)对应") private String contractVirtual; - /** - * 交易方式(字典: HS_PYBL_TP) - */ - @TableField("HS_PYBL") + + @Schema(description = "交易方式(字典: HS_PYBL_TP)") private String hasPayable; - /** - * 收支性质;与ERP(SZXZ)对应 - */ - @TableField("DRCT") + + @Schema(description = "收支性质;与ERP(SZXZ)对应") private String direction; - /** - * 合同类型 - */ - @TableField("CTRT_TP") + + @Schema(description = "合同类型", example = "1") private String contractType; - /** - * 签署日期;与ERP(HTQDRQ)对应 - */ - @TableField("SGN_DT") - private LocalDateTime signDate; - /** - * 开始日期;与ERP(HTQSRQ)对应 - */ - @TableField("STRT_DT") - private LocalDateTime startDate; - /** - * 结束日期;与ERP(HTZZRQ)对应 - */ - @TableField("END_DT") - private LocalDateTime endDate; - /** - * 签署地 - */ - @TableField("SGN_PLCE") + + @Schema(description = "签署日期;与ERP(HTQDRQ)对应") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] signDate; + + @Schema(description = "开始日期;与ERP(HTQSRQ)对应") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] startDate; + + @Schema(description = "结束日期;与ERP(HTZZRQ)对应") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] endDate; + + @Schema(description = "签署地") private String signPlace; - /** - * 甲方公司编号;如果是采购合同,查询组织机构自动带出,且与ERP(HTQDZTBH)对应,如果是销售合同,手动选择,且与ERP(WLDWBH)对应。 - */ - @TableField("PRCH_CPN_NUM") + + @Schema(description = "甲方公司编号;如果是采购合同,查询组织机构自动带出,且与ERP(HTQDZTBH)对应,如果是销售合同,手动选择,且与ERP(WLDWBH)对应。") private String purchaseCompanyNumber; - /** - * 甲方公司名称 - */ - @TableField("PRCH_CPN_NAME") + + @Schema(description = "甲方公司名称", example = "芋艿") private String purchaseCompanyName; - /** - * 甲方地址 - */ - @TableField("PRCH_ADR") + + @Schema(description = "甲方地址") private String purchaseAddress; - /** - * 甲方法定代表人 - */ - @TableField("PRCH_LDR") + + @Schema(description = "甲方法定代表人") private String purchaseLeader; - /** - * 乙方公司编号;如果是销售合同,查询组织机构自动带出,且与ERP(HTQDZTBH)对应,如果是采购合同,手动选择,且与ERP(WLDWBH)对应。 - */ - @TableField("SALE_CPN_NUM") + + @Schema(description = "乙方公司编号;如果是销售合同,查询组织机构自动带出,且与ERP(HTQDZTBH)对应,如果是采购合同,手动选择,且与ERP(WLDWBH)对应。") private String salesCompanyNumber; - /** - * 乙方公司名称 - */ - @TableField("SALE_CPN_NAME") + + @Schema(description = "乙方公司名称", example = "赵六") private String salesCompanyName; - /** - * 乙方地址 - */ - @TableField("SALE_ADR") + + @Schema(description = "乙方地址") private String salesAddress; - /** - * 乙方企业负责人 - */ - @TableField("SALE_PRCH_LDR") + + @Schema(description = "乙方企业负责人") private String salesPurchaseLeader; - /** - * 币种;与ERP(BZBH)对应 - */ - @TableField("CUR") + + @Schema(description = "币种;与ERP(BZBH)对应") private String currency; - /** - * 原币金额;与ERP(HTYBZJE)对应,币种不是人民币时,显示并手动填写,如果是人民币,隐藏且等于本币金额 - */ - @TableField("COO_AMT") + + @Schema(description = "原币金额;与ERP(HTYBZJE)对应,币种不是人民币时,显示并手动填写,如果是人民币,隐藏且等于本币金额") private BigDecimal cooAmount; - /** - * 本币金额;与ERP(HTBWBZJE)对应 - */ - @TableField("BSC_AMT") + + @Schema(description = "本币金额;与ERP(HTBWBZJE)对应") private BigDecimal basicAmount; - /** - * 是否有履约保证金;为是,则保证金必填。 - */ - @TableField("HS_DPST") + + @Schema(description = "是否有履约保证金;为是,则保证金必填。") private String hasDeposit; - /** - * 原币履约保证金;与ERP(LYBZJBGQYB)对应,币种不是人民币时,显示并手动填写,如果是人民币,隐藏且等于本币金额 - */ - @TableField("COO_AMT_DPST") + + @Schema(description = "原币履约保证金;与ERP(LYBZJBGQYB)对应,币种不是人民币时,显示并手动填写,如果是人民币,隐藏且等于本币金额") private BigDecimal cooAmountDeposit; - /** - * 本币履约保证金;与ERP(LYBZJBGQBWB)对应 - */ - @TableField("BSC_AMT_DPST") + + @Schema(description = "本币履约保证金;与ERP(LYBZJBGQBWB)对应") private BigDecimal basicAmountDeposit; - /** - * 是否有预付款;与ERP(SFYYFK)对应 - */ - @TableField("HS_PPYM") + + @Schema(description = "是否有预付款;与ERP(SFYYFK)对应") private String hasPrepayment; - /** - * 预付款比例;与ERP(YFKBL)对应 - */ - @TableField("PPYM_RTIO") + + @Schema(description = "预付款比例;与ERP(YFKBL)对应") private BigDecimal prepaymentRatio; - /** - * 预付款金额;与ERP(YFKJE)对应 - */ - @TableField("PPYM_AMT") + + @Schema(description = "预付款金额;与ERP(YFKJE)对应") private BigDecimal prepaymentAmount; - /** - * 是否有质保金;与ERP(SFHZBJ)对应 - */ - @TableField("HS_QLT_AMT") + + @Schema(description = "是否有质保金;与ERP(SFHZBJ)对应") private String hasQualityAmount; - /** - * 质保金比例;与ERP(ZBJBL)对应 - */ - @TableField("QLT_RTIO") + + @Schema(description = "质保金比例;与ERP(ZBJBL)对应") private BigDecimal qualityRatio; - /** - * 质保金金额;与ERP(BZJJE)对应 - */ - @TableField("QLT_AMT") + + @Schema(description = "质保金金额;与ERP(BZJJE)对应") private BigDecimal qualityAmount; - /** - * 补充协议类型;变更协议/增加条款 - */ - @TableField("RPL_AGR_TP") + + @Schema(description = "补充协议类型;变更协议/增加条款", example = "1") private String replenishAgreementType; - /** - * 备注;与ERP(BZXX)对应 - */ - @TableField("RMK") + + @Schema(description = "备注;与ERP(BZXX)对应") private String remark; - /** - * 施工类型编号;与ERP(HTLXBH)对应,拓展信息 - */ - @TableField("CON_TP_NUM") + + @Schema(description = "施工类型编号(字典:ERP_CTRT_HTLXBH);与ERP(HTLXBH)对应,拓展信息") private String constructionTypeNumber; - /** - * 施工类型名称;与ERP(HTLXMC)对应,拓展信息 - */ - @TableField("CON_TP_NAME") + + @Schema(description = "施工类型名称(字典:ERP_CTRT_HTLXBH);与ERP(HTLXMC)对应,拓展信息", example = "芋艿") private String constructionTypeName; - /** - * 代理方;与ERP(ZLIFNR)对应,拓展信息 - */ - @TableField("AGT") + + @Schema(description = "代理方;与ERP(ZLIFNR)对应,拓展信息") private String agent; - /** - * 类别;与ERP(HTLB)对应,拓展信息 - */ - @TableField("CTGR") + + @Schema(description = "类别;与ERP(HTLB)对应,拓展信息") private String category; - /** - * 原币金额-变更后;与ERP(BGHHTYBZJE)对应,拓展信息 - */ - @TableField("CHG_COO_AMT") + + @Schema(description = "原币金额-变更后;与ERP(BGHHTYBZJE)对应,拓展信息") private BigDecimal changeCooAmount; - /** - * 本币金额-变更后;与ERP(BGHHTBWBZJE)对应,拓展信息 - */ - @TableField("CHG_BSC_AMT") + + @Schema(description = "本币金额-变更后;与ERP(BGHHTBWBZJE)对应,拓展信息") private BigDecimal changeBasicAmount; - /** - * 原币履约保证金-变更后;与ERP(LYBZJBGHYB)对应,拓展信息 - */ - @TableField("CHG_COO_AMT_DPST") + + @Schema(description = "原币履约保证金-变更后;与ERP(LYBZJBGHYB)对应,拓展信息") private BigDecimal changeCooAmountDeposit; - /** - * 本币履约保证金-变更后;与ERP(LYBZJBGHBWB)对应,拓展信息 - */ - @TableField("CHG_BSC_AMT_DPST") + + @Schema(description = "本币履约保证金-变更后;与ERP(LYBZJBGHBWB)对应,拓展信息") private BigDecimal changeBasicAmountDeposit; - /** - * 是否框架合同;与ERP(SFKJHT)对应,拓展信息 - */ - @TableField("IS_FMWK") + + @Schema(description = "是否框架合同;与ERP(SFKJHT)对应,拓展信息") private String isFramework; - /** - * 境内/境外;与ERP(JNJW)对应,拓展信息 - */ - @TableField("IS_DOM") + + @Schema(description = "境内/境外;与ERP(JNJW)对应,拓展信息") private String isDomestic; - /** - * 建筑服务发生地;与ERP(JZFWFSD)对应,拓展信息,销售合同,且类型为SAP02COSR必填 - */ - @TableField("ARCH_SVC_PLCE") - private String architectureServicePlace; - /** - * 达到收款条件金额;与ERP(DDSKJE)对应,拓展信息,销售合同,且类型为SAP02COSR必填 - */ - @TableField("PYEE_CND_AMT") + + @Schema(description = "建筑服务发生地;与ERP(JZFWFSD)对应,拓展信息,销售合同,且类型为SAP02COSR必填") + private String architectureService‌Place; + + @Schema(description = "达到收款条件金额;与ERP(DDSKJE)对应,拓展信息,销售合同,且类型为SAP02COSR必填") private BigDecimal payeeConditionAmount; - /** - * 步骤 - */ - @TableField("STP") + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "步骤") private Integer step; - /** - * ERP请求状态(字典: ERP_REQ_STS) - */ - @TableField("ERP_STS") + + @Schema(description = "ERP请求状态(字典: ERP_REQ_STS)", example = "1") private String erpStatus; - /** - * ERP请求失败原因 - */ - @TableField("CAUS") + + @Schema(description = "ERP请求失败原因") private String cause; - /** - * 流程实例编号 - */ - @TableField("PRCS_INSC_ID") + + @Schema(description = "流程实例编号", example = "9043") private String processInstanceId; - /** - * 审批意见 - */ - @TableField("RVW_ONN") + + @Schema(description = "审批意见") private String reviewOpinion; - /** - * 任务节点主键 - */ - @TableField("TSK_NDE_ID") + + @Schema(description = "任务节点主键", example = "32486") private String taskNodeId; - /** - * 交货地点 - */ - @TableField("DLVY_ADR") + + @Schema(description = "交货地点") private String deliveryAddress; - /** - * 交货方式(字典:FRCST_ASN) - */ - @TableField("DLVY_WY") + + @Schema(description = "交货方式(字典:FRCST_ASN)") private String deliveryWay; - /** - * 甲方联系人 - */ - @TableField("PRCH_HMN") + + @Schema(description = "甲方联系人") private String purchaseHuman; - /** - * 甲方电话 - */ - @TableField("PRCH_TEL") + + @Schema(description = "甲方电话") private String purchaseTel; - /** - * 甲方邮箱 - */ - @TableField("PRCH_EM") + + @Schema(description = "甲方邮箱") private String purchaseEmail; - /** - * 甲方传真 - */ - @TableField("PRCH_FAX") + + @Schema(description = "甲方传真") private String purchaseFax; - /** - * 甲方联系地址 - */ - @TableField("PRCH_CTCT_ADR") + + @Schema(description = "甲方联系地址") private String purchaseContactAddress; - /** - * 乙方联系人 - */ - @TableField("SALE_HMN") + + @Schema(description = "乙方联系人") private String salesHuman; - /** - * 乙方电话 - */ - @TableField("SALE_TEL") + + @Schema(description = "乙方电话") private String salesTel; - /** - * 乙方邮箱 - */ - @TableField("SALE_EM") + + @Schema(description = "乙方邮箱") private String salesEmail; - /** - * 乙方传真 - */ - @TableField("SALE_FAX") + + @Schema(description = "乙方传真") private String salesFax; - /** - * 乙方联系地址 - */ - @TableField("SALE_CTCT_ADR") + + @Schema(description = "乙方联系地址") private String salesContactAddress; - /** - * ERP甲方公司编号 - */ - @TableField("ERP_PRCH_CPN_NUM") + + @Schema(description = "ERP甲方公司编号") private String erpPurchaseCompanyNumber; - /** - * ERP甲方公司名称 - */ - @TableField("ERP_PRCH_CPN_NAME") + + @Schema(description = "ERP甲方公司名称", example = "芋艿") private String erpPurchaseCompanyName; - /** - * ERP乙方公司编码 - */ - @TableField("ERP_SALE_CPN_NUM") + + @Schema(description = "ERP乙方公司编码") private String erpSalesCompanyNumber; - /** - * ERP乙方公司名称 - */ - @TableField("ERP_SALE_CPN_NAME") + + @Schema(description = "ERP乙方公司名称", example = "赵六") private String erpSalesCompanyName; - /** - * 是否内部企业(字典:ERP_CTRT_YN) - */ - @TableField("IS_INTL") + + @Schema(description = "是否内部企业(字典:ERP_CTRT_YN)") private String isInternal; - /** - * 其它附件对象存储 - */ - @TableField("FILE_OBJ_OTH") + + @Schema(description = "其它附件对象存储") private String fileObjectOther; - /** - * 模板附件对象存储 - */ - @TableField("FILE_OBJ") + + @Schema(description = "模板附件对象存储") private String fileObject; - /** - * 合同分类(字典:SPLY_BSN_TP) - */ - @TableField("BSN_TP") + + @Schema(description = "合同分类(字典:SPLY_BSN_TP)", example = "2") private String businessType; - /** - * 代理方名称 - */ - @TableField("AGT_NAME") + + @Schema(description = "代理方名称", example = "王五") private String agentName; + + @Schema(description = "货权转移类型(字典:ASY_MTNG_TP)", example = "1") + private String meteringType; } \ No newline at end of file From 10dd7966fac057e737c26961ade1f1488f07b0a6 Mon Sep 17 00:00:00 2001 From: guojunyun Date: Tue, 11 Nov 2025 09:37:29 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E5=90=88=E5=90=8C=E4=B8=BB=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E6=B7=BB=E5=8A=A0=E7=A1=AE=E5=AE=9E=E5=8C=85=E5=AF=BC?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/dataobject/contract/ContractMainDO.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java index f0c32d3..e49758a 100644 --- a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java @@ -1,8 +1,12 @@ package com.zt.plat.module.contractorder.dal.dataobject.contract; -import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; import com.zt.plat.framework.mybatis.core.dataobject.BusinessBaseDO; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; +import org.springframework.format.annotation.DateTimeFormat; + import java.math.BigDecimal; import java.time.LocalDateTime; From 83c1f318e1c4ee6468f8e034cda09d6addc3b777 Mon Sep 17 00:00:00 2001 From: guojunyun Date: Tue, 11 Nov 2025 09:41:41 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E5=90=88=E5=90=8C=E4=B8=BB=E4=BF=A1?= =?UTF-8?q?=E6=81=AFdo=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dataobject/contract/ContractMainDO.java | 474 ++++++++++++------ 1 file changed, 309 insertions(+), 165 deletions(-) diff --git a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java index e49758a..7066416 100644 --- a/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java +++ b/zt-module-contract-order/zt-module-contract-order-server/src/main/java/com/zt/plat/module/contractorder/dal/dataobject/contract/ContractMainDO.java @@ -1,17 +1,12 @@ package com.zt.plat.module.contractorder.dal.dataobject.contract; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.*; import com.zt.plat.framework.mybatis.core.dataobject.BusinessBaseDO; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; -import org.springframework.format.annotation.DateTimeFormat; import java.math.BigDecimal; import java.time.LocalDateTime; -import static com.zt.plat.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - /** * 合同主信息 DO * @@ -30,235 +25,384 @@ import static com.zt.plat.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH */ public class ContractMainDO extends BusinessBaseDO { - @Schema(description = "模板实例主键", example = "2571") + /** + * 主键 + */ + @TableId(type = IdType.ASSIGN_ID) + private Long id; + /** + * 模板实例主键 + */ + @TableField("INSC_ID") private Long instanceId; - - @Schema(description = "系统合同编号;自动生成,校验唯一") + /** + * 系统合同编号;自动生成,校验唯一 + */ + @TableField("SYS_CTRT_NUM") private String systemContractNumber; - - @Schema(description = "状态(字典: BSE_CTRT_STS)", example = "1") + /** + * 状态(字典: BSE_CTRT_STS) + */ + @TableField("STS") private String status; - - @Schema(description = "合同名称;与ERP(HTMC)对应,校验唯一", example = "李四") + /** + * 合同名称;与ERP(HTMC)对应,校验唯一 + */ + @TableField("CTRT_NAME") private String contractName; - - @Schema(description = "合同编号;与ERP(HTBH)对应,校验唯一") + /** + * 合同编号;与ERP(HTBH)对应,校验唯一 + */ + @TableField("CTRT_PPR_NUM") private String contractPaperNumber; - - @Schema(description = "是否虚拟合同;与ERP(SFXNHT)对应") + /** + * 是否虚拟合同;与ERP(SFXNHT)对应 + */ + @TableField("CTRT_VRTL") private String contractVirtual; - - @Schema(description = "交易方式(字典: HS_PYBL_TP)") + /** + * 交易方式(字典: HS_PYBL_TP) + */ + @TableField("HS_PYBL") private String hasPayable; - - @Schema(description = "收支性质;与ERP(SZXZ)对应") + /** + * 收支性质;与ERP(SZXZ)对应 + */ + @TableField("DRCT") private String direction; - - @Schema(description = "合同类型", example = "1") + /** + * 合同类型 + */ + @TableField("CTRT_TP") private String contractType; - - @Schema(description = "签署日期;与ERP(HTQDRQ)对应") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] signDate; - - @Schema(description = "开始日期;与ERP(HTQSRQ)对应") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] startDate; - - @Schema(description = "结束日期;与ERP(HTZZRQ)对应") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] endDate; - - @Schema(description = "签署地") + /** + * 签署日期;与ERP(HTQDRQ)对应 + */ + @TableField("SGN_DT") + private LocalDateTime signDate; + /** + * 开始日期;与ERP(HTQSRQ)对应 + */ + @TableField("STRT_DT") + private LocalDateTime startDate; + /** + * 结束日期;与ERP(HTZZRQ)对应 + */ + @TableField("END_DT") + private LocalDateTime endDate; + /** + * 签署地 + */ + @TableField("SGN_PLCE") private String signPlace; - - @Schema(description = "甲方公司编号;如果是采购合同,查询组织机构自动带出,且与ERP(HTQDZTBH)对应,如果是销售合同,手动选择,且与ERP(WLDWBH)对应。") + /** + * 甲方公司编号;如果是采购合同,查询组织机构自动带出,且与ERP(HTQDZTBH)对应,如果是销售合同,手动选择,且与ERP(WLDWBH)对应。 + */ + @TableField("PRCH_CPN_NUM") private String purchaseCompanyNumber; - - @Schema(description = "甲方公司名称", example = "芋艿") + /** + * 甲方公司名称 + */ + @TableField("PRCH_CPN_NAME") private String purchaseCompanyName; - - @Schema(description = "甲方地址") + /** + * 甲方地址 + */ + @TableField("PRCH_ADR") private String purchaseAddress; - - @Schema(description = "甲方法定代表人") + /** + * 甲方法定代表人 + */ + @TableField("PRCH_LDR") private String purchaseLeader; - - @Schema(description = "乙方公司编号;如果是销售合同,查询组织机构自动带出,且与ERP(HTQDZTBH)对应,如果是采购合同,手动选择,且与ERP(WLDWBH)对应。") + /** + * 乙方公司编号;如果是销售合同,查询组织机构自动带出,且与ERP(HTQDZTBH)对应,如果是采购合同,手动选择,且与ERP(WLDWBH)对应。 + */ + @TableField("SALE_CPN_NUM") private String salesCompanyNumber; - - @Schema(description = "乙方公司名称", example = "赵六") + /** + * 乙方公司名称 + */ + @TableField("SALE_CPN_NAME") private String salesCompanyName; - - @Schema(description = "乙方地址") + /** + * 乙方地址 + */ + @TableField("SALE_ADR") private String salesAddress; - - @Schema(description = "乙方企业负责人") + /** + * 乙方企业负责人 + */ + @TableField("SALE_PRCH_LDR") private String salesPurchaseLeader; - - @Schema(description = "币种;与ERP(BZBH)对应") + /** + * 币种;与ERP(BZBH)对应 + */ + @TableField("CUR") private String currency; - - @Schema(description = "原币金额;与ERP(HTYBZJE)对应,币种不是人民币时,显示并手动填写,如果是人民币,隐藏且等于本币金额") + /** + * 原币金额;与ERP(HTYBZJE)对应,币种不是人民币时,显示并手动填写,如果是人民币,隐藏且等于本币金额 + */ + @TableField("COO_AMT") private BigDecimal cooAmount; - - @Schema(description = "本币金额;与ERP(HTBWBZJE)对应") + /** + * 本币金额;与ERP(HTBWBZJE)对应 + */ + @TableField("BSC_AMT") private BigDecimal basicAmount; - - @Schema(description = "是否有履约保证金;为是,则保证金必填。") + /** + * 是否有履约保证金;为是,则保证金必填。 + */ + @TableField("HS_DPST") private String hasDeposit; - - @Schema(description = "原币履约保证金;与ERP(LYBZJBGQYB)对应,币种不是人民币时,显示并手动填写,如果是人民币,隐藏且等于本币金额") + /** + * 原币履约保证金;与ERP(LYBZJBGQYB)对应,币种不是人民币时,显示并手动填写,如果是人民币,隐藏且等于本币金额 + */ + @TableField("COO_AMT_DPST") private BigDecimal cooAmountDeposit; - - @Schema(description = "本币履约保证金;与ERP(LYBZJBGQBWB)对应") + /** + * 本币履约保证金;与ERP(LYBZJBGQBWB)对应 + */ + @TableField("BSC_AMT_DPST") private BigDecimal basicAmountDeposit; - - @Schema(description = "是否有预付款;与ERP(SFYYFK)对应") + /** + * 是否有预付款;与ERP(SFYYFK)对应 + */ + @TableField("HS_PPYM") private String hasPrepayment; - - @Schema(description = "预付款比例;与ERP(YFKBL)对应") + /** + * 预付款比例;与ERP(YFKBL)对应 + */ + @TableField("PPYM_RTIO") private BigDecimal prepaymentRatio; - - @Schema(description = "预付款金额;与ERP(YFKJE)对应") + /** + * 预付款金额;与ERP(YFKJE)对应 + */ + @TableField("PPYM_AMT") private BigDecimal prepaymentAmount; - - @Schema(description = "是否有质保金;与ERP(SFHZBJ)对应") + /** + * 是否有质保金;与ERP(SFHZBJ)对应 + */ + @TableField("HS_QLT_AMT") private String hasQualityAmount; - - @Schema(description = "质保金比例;与ERP(ZBJBL)对应") + /** + * 质保金比例;与ERP(ZBJBL)对应 + */ + @TableField("QLT_RTIO") private BigDecimal qualityRatio; - - @Schema(description = "质保金金额;与ERP(BZJJE)对应") + /** + * 质保金金额;与ERP(BZJJE)对应 + */ + @TableField("QLT_AMT") private BigDecimal qualityAmount; - - @Schema(description = "补充协议类型;变更协议/增加条款", example = "1") + /** + * 补充协议类型;变更协议/增加条款 + */ + @TableField("RPL_AGR_TP") private String replenishAgreementType; - - @Schema(description = "备注;与ERP(BZXX)对应") + /** + * 备注;与ERP(BZXX)对应 + */ + @TableField("RMK") private String remark; - - @Schema(description = "施工类型编号(字典:ERP_CTRT_HTLXBH);与ERP(HTLXBH)对应,拓展信息") + /** + * 施工类型编号(字典:ERP_CTRT_HTLXBH);与ERP(HTLXBH)对应,拓展信息 + */ + @TableField("CON_TP_NUM") private String constructionTypeNumber; - - @Schema(description = "施工类型名称(字典:ERP_CTRT_HTLXBH);与ERP(HTLXMC)对应,拓展信息", example = "芋艿") + /** + * 施工类型名称(字典:ERP_CTRT_HTLXBH);与ERP(HTLXMC)对应,拓展信息 + */ + @TableField("CON_TP_NAME") private String constructionTypeName; - - @Schema(description = "代理方;与ERP(ZLIFNR)对应,拓展信息") + /** + * 代理方;与ERP(ZLIFNR)对应,拓展信息 + */ + @TableField("AGT") private String agent; - - @Schema(description = "类别;与ERP(HTLB)对应,拓展信息") + /** + * 类别;与ERP(HTLB)对应,拓展信息 + */ + @TableField("CTGR") private String category; - - @Schema(description = "原币金额-变更后;与ERP(BGHHTYBZJE)对应,拓展信息") + /** + * 原币金额-变更后;与ERP(BGHHTYBZJE)对应,拓展信息 + */ + @TableField("CHG_COO_AMT") private BigDecimal changeCooAmount; - - @Schema(description = "本币金额-变更后;与ERP(BGHHTBWBZJE)对应,拓展信息") + /** + * 本币金额-变更后;与ERP(BGHHTBWBZJE)对应,拓展信息 + */ + @TableField("CHG_BSC_AMT") private BigDecimal changeBasicAmount; - - @Schema(description = "原币履约保证金-变更后;与ERP(LYBZJBGHYB)对应,拓展信息") + /** + * 原币履约保证金-变更后;与ERP(LYBZJBGHYB)对应,拓展信息 + */ + @TableField("CHG_COO_AMT_DPST") private BigDecimal changeCooAmountDeposit; - - @Schema(description = "本币履约保证金-变更后;与ERP(LYBZJBGHBWB)对应,拓展信息") + /** + * 本币履约保证金-变更后;与ERP(LYBZJBGHBWB)对应,拓展信息 + */ + @TableField("CHG_BSC_AMT_DPST") private BigDecimal changeBasicAmountDeposit; - - @Schema(description = "是否框架合同;与ERP(SFKJHT)对应,拓展信息") + /** + * 是否框架合同;与ERP(SFKJHT)对应,拓展信息 + */ + @TableField("IS_FMWK") private String isFramework; - - @Schema(description = "境内/境外;与ERP(JNJW)对应,拓展信息") + /** + * 境内/境外;与ERP(JNJW)对应,拓展信息 + */ + @TableField("IS_DOM") private String isDomestic; - - @Schema(description = "建筑服务发生地;与ERP(JZFWFSD)对应,拓展信息,销售合同,且类型为SAP02COSR必填") + /** + * 建筑服务发生地;与ERP(JZFWFSD)对应,拓展信息,销售合同,且类型为SAP02COSR必填 + */ + @TableField("ARCH_SVC_PLCE") private String architectureService‌Place; - - @Schema(description = "达到收款条件金额;与ERP(DDSKJE)对应,拓展信息,销售合同,且类型为SAP02COSR必填") + /** + * 达到收款条件金额;与ERP(DDSKJE)对应,拓展信息,销售合同,且类型为SAP02COSR必填 + */ + @TableField("PYEE_CND_AMT") private BigDecimal payeeConditionAmount; - - @Schema(description = "创建时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] createTime; - - @Schema(description = "步骤") + /** + * 步骤 + */ + @TableField("STP") private Integer step; - - @Schema(description = "ERP请求状态(字典: ERP_REQ_STS)", example = "1") + /** + * ERP请求状态(字典: ERP_REQ_STS) + */ + @TableField("ERP_STS") private String erpStatus; - - @Schema(description = "ERP请求失败原因") + /** + * ERP请求失败原因 + */ + @TableField("CAUS") private String cause; - - @Schema(description = "流程实例编号", example = "9043") + /** + * 流程实例编号 + */ + @TableField("PRCS_INSC_ID") private String processInstanceId; - - @Schema(description = "审批意见") + /** + * 审批意见 + */ + @TableField("RVW_ONN") private String reviewOpinion; - - @Schema(description = "任务节点主键", example = "32486") + /** + * 任务节点主键 + */ + @TableField("TSK_NDE_ID") private String taskNodeId; - - @Schema(description = "交货地点") + /** + * 交货地点 + */ + @TableField("DLVY_ADR") private String deliveryAddress; - - @Schema(description = "交货方式(字典:FRCST_ASN)") + /** + * 交货方式(字典:FRCST_ASN) + */ + @TableField("DLVY_WY") private String deliveryWay; - - @Schema(description = "甲方联系人") + /** + * 甲方联系人 + */ + @TableField("PRCH_HMN") private String purchaseHuman; - - @Schema(description = "甲方电话") + /** + * 甲方电话 + */ + @TableField("PRCH_TEL") private String purchaseTel; - - @Schema(description = "甲方邮箱") + /** + * 甲方邮箱 + */ + @TableField("PRCH_EM") private String purchaseEmail; - - @Schema(description = "甲方传真") + /** + * 甲方传真 + */ + @TableField("PRCH_FAX") private String purchaseFax; - - @Schema(description = "甲方联系地址") + /** + * 甲方联系地址 + */ + @TableField("PRCH_CTCT_ADR") private String purchaseContactAddress; - - @Schema(description = "乙方联系人") + /** + * 乙方联系人 + */ + @TableField("SALE_HMN") private String salesHuman; - - @Schema(description = "乙方电话") + /** + * 乙方电话 + */ + @TableField("SALE_TEL") private String salesTel; - - @Schema(description = "乙方邮箱") + /** + * 乙方邮箱 + */ + @TableField("SALE_EM") private String salesEmail; - - @Schema(description = "乙方传真") + /** + * 乙方传真 + */ + @TableField("SALE_FAX") private String salesFax; - - @Schema(description = "乙方联系地址") + /** + * 乙方联系地址 + */ + @TableField("SALE_CTCT_ADR") private String salesContactAddress; - - @Schema(description = "ERP甲方公司编号") + /** + * ERP甲方公司编号 + */ + @TableField("ERP_PRCH_CPN_NUM") private String erpPurchaseCompanyNumber; - - @Schema(description = "ERP甲方公司名称", example = "芋艿") + /** + * ERP甲方公司名称 + */ + @TableField("ERP_PRCH_CPN_NAME") private String erpPurchaseCompanyName; - - @Schema(description = "ERP乙方公司编码") + /** + * ERP乙方公司编码 + */ + @TableField("ERP_SALE_CPN_NUM") private String erpSalesCompanyNumber; - - @Schema(description = "ERP乙方公司名称", example = "赵六") + /** + * ERP乙方公司名称 + */ + @TableField("ERP_SALE_CPN_NAME") private String erpSalesCompanyName; - - @Schema(description = "是否内部企业(字典:ERP_CTRT_YN)") + /** + * 是否内部企业(字典:ERP_CTRT_YN) + */ + @TableField("IS_INTL") private String isInternal; - - @Schema(description = "其它附件对象存储") + /** + * 其它附件对象存储 + */ + @TableField("FILE_OBJ_OTH") private String fileObjectOther; - - @Schema(description = "模板附件对象存储") + /** + * 模板附件对象存储 + */ + @TableField("FILE_OBJ") private String fileObject; - - @Schema(description = "合同分类(字典:SPLY_BSN_TP)", example = "2") + /** + * 合同分类(字典:SPLY_BSN_TP) + */ + @TableField("BSN_TP") private String businessType; - - @Schema(description = "代理方名称", example = "王五") + /** + * 代理方名称 + */ + @TableField("AGT_NAME") private String agentName; - - @Schema(description = "货权转移类型(字典:ASY_MTNG_TP)", example = "1") + /** + * 货权转移类型(字典:ASY_MTNG_TP) + */ + @TableField("MTNG_TP") private String meteringType; } \ No newline at end of file