Fix PDF font loading for project overview reports
This commit is contained in:
3
assets/图谱.txt
Normal file
3
assets/图谱.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
关系图谱:http://64.202.65.112:8082/atlas/refactor/#/home/graph/downloadService?id=lanxitest&mode=K_EXPAND&type=NORMAL&atlasToken=2C914E5E1FBFBC4AD15163E0AB03B800¶ms={"vId":"rel_node/15942f5b84bada01ccd25f5e5678ac22"}
|
||||
|
||||
资金流图谱:http://64.202.65.112:8082/atlas/refactor/#/home/graph/downloadService?id=ccdi_lanxi_trans&mode=K_EXPAND&type=NORMAL&atlasToken=F4BBA291A285858BAF4526C6EC312388¶ms={"vId":"idno_node/f2f797081494c5c0555a3bbf0f57c5e7"}
|
||||
@@ -14,9 +14,11 @@ import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.file.FileUtils;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.awt.Color;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.file.Files;
|
||||
import java.text.DecimalFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
@@ -32,6 +34,7 @@ import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -43,6 +46,11 @@ public class CcdiProjectOverviewReportPdfExporter {
|
||||
private static final String CONTENT_TYPE = "application/pdf";
|
||||
private static final DateTimeFormatter EXPORT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||
private static final DecimalFormat MONEY_FORMAT = new DecimalFormat("#,##0.00");
|
||||
private final String pdfFontPath;
|
||||
|
||||
public CcdiProjectOverviewReportPdfExporter(@Value("${ccdi.report.pdf-font-path:}") String pdfFontPath) {
|
||||
this.pdfFontPath = pdfFontPath;
|
||||
}
|
||||
|
||||
public void export(HttpServletResponse response, CcdiProjectOverviewReportVO report) throws IOException {
|
||||
response.setContentType(CONTENT_TYPE);
|
||||
@@ -51,9 +59,8 @@ public class CcdiProjectOverviewReportPdfExporter {
|
||||
safeFileName(report.getProject().getProjectName()) + "_初核结果报告.pdf"
|
||||
);
|
||||
|
||||
try (PDDocument document = new PDDocument()) {
|
||||
PDType0Font font = loadChineseFont(document);
|
||||
PdfPageWriter writer = new PdfPageWriter(document, font);
|
||||
try (PDDocument document = new PDDocument(); LoadedChineseFont loadedFont = loadChineseFont(document)) {
|
||||
PdfPageWriter writer = new PdfPageWriter(document, loadedFont.font());
|
||||
writer.newPage();
|
||||
writeCover(writer, report);
|
||||
writeUploadSubjects(writer, report.getUploadSubjects());
|
||||
@@ -204,44 +211,113 @@ public class CcdiProjectOverviewReportPdfExporter {
|
||||
);
|
||||
}
|
||||
|
||||
private PDType0Font loadChineseFont(PDDocument document) throws IOException {
|
||||
List<String> candidates = List.of(
|
||||
"C:/Windows/Fonts/NotoSansSC-VF.ttf",
|
||||
"C:/Windows/Fonts/simhei.ttf",
|
||||
"C:/Windows/Fonts/simsunb.ttf",
|
||||
"/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttf",
|
||||
"/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttf",
|
||||
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
|
||||
);
|
||||
for (String path : candidates) {
|
||||
File file = new File(path);
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
continue;
|
||||
}
|
||||
String lowerPath = path.toLowerCase();
|
||||
if (lowerPath.endsWith(".ttf")) {
|
||||
return PDType0Font.load(document, file);
|
||||
}
|
||||
if (lowerPath.endsWith(".ttc")) {
|
||||
PDType0Font font = loadFirstCollectionFont(document, file);
|
||||
if (font != null) {
|
||||
return font;
|
||||
}
|
||||
}
|
||||
private LoadedChineseFont loadChineseFont(PDDocument document) throws IOException {
|
||||
if (pdfFontPath == null || pdfFontPath.isBlank()) {
|
||||
throw new ServiceException("未配置PDF中文字体路径,无法导出PDF报告");
|
||||
}
|
||||
throw new ServiceException("未找到可用中文字体,无法导出PDF报告");
|
||||
String path = pdfFontPath.trim();
|
||||
File file = new File(path);
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
throw new ServiceException("配置的PDF中文字体路径不可用:" + path);
|
||||
}
|
||||
|
||||
String lowerPath = path.toLowerCase();
|
||||
if (lowerPath.endsWith(".ttf")) {
|
||||
return new LoadedChineseFont(PDType0Font.load(document, file), null);
|
||||
}
|
||||
if (lowerPath.endsWith(".ttc")) {
|
||||
LoadedChineseFont loadedFont = loadPreferredCollectionFont(document, file);
|
||||
if (loadedFont != null) {
|
||||
return loadedFont;
|
||||
}
|
||||
throw new ServiceException("配置的PDF中文字体不支持导出:" + path);
|
||||
}
|
||||
if (lowerPath.endsWith(".otf")) {
|
||||
return new LoadedChineseFont(loadOpenTypeFont(document, file), null);
|
||||
}
|
||||
|
||||
throw new ServiceException("配置的PDF中文字体格式不支持:" + path);
|
||||
}
|
||||
|
||||
private PDType0Font loadFirstCollectionFont(PDDocument document, File file) throws IOException {
|
||||
private PDType0Font loadOpenTypeFont(PDDocument document, File file) throws IOException {
|
||||
try (var inputStream = Files.newInputStream(file.toPath())) {
|
||||
return PDType0Font.load(document, inputStream, false);
|
||||
}
|
||||
}
|
||||
|
||||
private LoadedChineseFont loadPreferredCollectionFont(PDDocument document, File file) throws IOException {
|
||||
LoadedChineseFont font = loadCollectionFontByName(document, file);
|
||||
return font == null ? loadFirstCollectionFont(document, file) : font;
|
||||
}
|
||||
|
||||
private LoadedChineseFont loadCollectionFontByName(PDDocument document, File file) throws IOException {
|
||||
TrueTypeCollection collection = new TrueTypeCollection(file);
|
||||
AtomicReference<PDType0Font> font = new AtomicReference<>();
|
||||
try (TrueTypeCollection collection = new TrueTypeCollection(file)) {
|
||||
try {
|
||||
collection.processAllFonts(typeFont -> {
|
||||
if (font.get() == null) {
|
||||
if (font.get() == null && supportsTrueTypeSubset(typeFont)
|
||||
&& isSimplifiedChineseFont(typeFont.getName())) {
|
||||
font.set(PDType0Font.load(document, typeFont, true));
|
||||
}
|
||||
});
|
||||
if (font.get() != null) {
|
||||
return new LoadedChineseFont(font.get(), collection);
|
||||
}
|
||||
} finally {
|
||||
if (font.get() == null) {
|
||||
collection.close();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isSimplifiedChineseFont(String fontName) {
|
||||
if (fontName == null) {
|
||||
return false;
|
||||
}
|
||||
String lowerName = fontName.toLowerCase();
|
||||
return lowerName.contains("sc")
|
||||
|| lowerName.contains("hans")
|
||||
|| lowerName.contains("gb")
|
||||
|| lowerName.contains("hei")
|
||||
|| lowerName.contains("song")
|
||||
|| lowerName.contains("yahei")
|
||||
|| lowerName.contains("simsun")
|
||||
|| lowerName.contains("simhei");
|
||||
}
|
||||
|
||||
private LoadedChineseFont loadFirstCollectionFont(PDDocument document, File file) throws IOException {
|
||||
TrueTypeCollection collection = new TrueTypeCollection(file);
|
||||
AtomicReference<PDType0Font> font = new AtomicReference<>();
|
||||
try {
|
||||
collection.processAllFonts(typeFont -> {
|
||||
if (font.get() == null && supportsTrueTypeSubset(typeFont)) {
|
||||
font.set(PDType0Font.load(document, typeFont, true));
|
||||
}
|
||||
});
|
||||
if (font.get() != null) {
|
||||
return new LoadedChineseFont(font.get(), collection);
|
||||
}
|
||||
} finally {
|
||||
if (font.get() == null) {
|
||||
collection.close();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean supportsTrueTypeSubset(org.apache.fontbox.ttf.TrueTypeFont typeFont) throws IOException {
|
||||
return typeFont.getTableMap().containsKey("glyf");
|
||||
}
|
||||
|
||||
private record LoadedChineseFont(PDType0Font font, Closeable fontSource) implements Closeable {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (fontSource != null) {
|
||||
fontSource.close();
|
||||
}
|
||||
}
|
||||
return font.get();
|
||||
}
|
||||
|
||||
private List<IndexedUploadSubject> indexedRows(List<CcdiProjectOverviewReportUploadSubjectVO> rows) {
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.ruoyi.ccdi.project.domain.vo.CcdiProjectOverviewDashboardVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectOverviewStatVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskHitTagVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelPeopleItemVO;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
@@ -19,13 +21,14 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class CcdiProjectOverviewReportPdfExporterTest {
|
||||
|
||||
@Test
|
||||
void shouldExportOverviewReportPdf() throws Exception {
|
||||
CcdiProjectOverviewReportPdfExporter exporter = new CcdiProjectOverviewReportPdfExporter();
|
||||
CcdiProjectOverviewReportPdfExporter exporter = new CcdiProjectOverviewReportPdfExporter(resolveTestFontPath());
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
exporter.export(response, buildReport());
|
||||
@@ -36,6 +39,41 @@ class CcdiProjectOverviewReportPdfExporterTest {
|
||||
assertTrue(response.getContentAsByteArray().length > 1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectBlankPdfFontPath() {
|
||||
CcdiProjectOverviewReportPdfExporter exporter = new CcdiProjectOverviewReportPdfExporter("");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
ServiceException exception = assertThrows(ServiceException.class, () -> exporter.export(response, buildReport()));
|
||||
|
||||
assertEquals("未配置PDF中文字体路径,无法导出PDF报告", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectUnavailablePdfFontPath() {
|
||||
String missingPath = "/tmp/ccdi-missing-pdf-font-" + System.nanoTime() + ".ttc";
|
||||
CcdiProjectOverviewReportPdfExporter exporter = new CcdiProjectOverviewReportPdfExporter(missingPath);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
ServiceException exception = assertThrows(ServiceException.class, () -> exporter.export(response, buildReport()));
|
||||
|
||||
assertTrue(exception.getMessage().contains(missingPath));
|
||||
}
|
||||
|
||||
private String resolveTestFontPath() {
|
||||
List<String> candidates = List.of(
|
||||
"/System/Library/Fonts/STHeiti Medium.ttc",
|
||||
"/System/Library/Fonts/STHeiti Light.ttc",
|
||||
"/System/Library/Fonts/Hiragino Sans GB.ttc",
|
||||
"/System/Library/Fonts/Supplemental/Songti.ttc",
|
||||
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
|
||||
);
|
||||
return candidates.stream()
|
||||
.filter(path -> new File(path).isFile())
|
||||
.findFirst()
|
||||
.orElse(candidates.get(0));
|
||||
}
|
||||
|
||||
private CcdiProjectOverviewReportVO buildReport() {
|
||||
CcdiProjectOverviewReportVO report = new CcdiProjectOverviewReportVO();
|
||||
CcdiProject project = new CcdiProject();
|
||||
|
||||
@@ -2,6 +2,10 @@ FROM eclipse-temurin:21-jre-jammy
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends fontconfig fonts-wqy-microhei \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY backend/ruoyi-admin.jar /app/ruoyi-admin.jar
|
||||
|
||||
RUN mkdir -p /app/data/ruoyi /app/logs
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# 2026-05-07 NAS Docker 部署实施记录
|
||||
|
||||
## 保存路径确认
|
||||
|
||||
- 目标目录:`docs/reports/implementation/`
|
||||
- 文档用途:记录本次 NAS Docker 部署操作、影响范围与验证结果
|
||||
- 路径检查结果:符合仓库实施记录归档规范
|
||||
|
||||
## 本次操作
|
||||
|
||||
- 在本地仓库 `/Users/wkc/Desktop/ccdi/ccdi` 执行 NAS Docker 部署。
|
||||
- 按仓库前端规则先执行 `source ~/.nvm/nvm.sh && nvm use`,确认 Node 版本为 `v14.21.3`、npm 版本为 `6.14.18`。
|
||||
- 执行部署脚本:`deploy/deploy-to-nas.sh`。
|
||||
- 脚本自动完成:
|
||||
- 后端打包:`mvn clean package -DskipTests`
|
||||
- 前端打包:`npm run build:prod`
|
||||
- 组装部署目录:`.deploy/ccdi-package`
|
||||
- 上传到 NAS 并执行远端 `docker compose up -d --build`
|
||||
- 部署目标:
|
||||
- SSH:`116.62.17.81:9444`
|
||||
- 远端目录:`/volume1/webapp/ccdi`
|
||||
|
||||
## 影响范围
|
||||
|
||||
- 远端部署目录 `/volume1/webapp/ccdi` 已刷新为本次构建产物。
|
||||
- 远端 Docker 服务已重建并启动:
|
||||
- `ccdi-backend`
|
||||
- `ccdi-frontend`
|
||||
- `ccdi-lsfx-mock`
|
||||
- 本次操作未修改业务代码。
|
||||
|
||||
## 验证结果
|
||||
|
||||
### 本地构建验证
|
||||
|
||||
- Maven 聚合打包成功,`ruoyi-admin/target/ruoyi-admin.jar` 已生成。
|
||||
- Vue 生产构建成功,`ruoyi-ui/dist` 已生成。
|
||||
- 前端构建存在资源体积告警,未出现构建失败。
|
||||
|
||||
### 远端容器验证
|
||||
|
||||
- `docker compose ps` 结果:
|
||||
- `ccdi-backend`:`Up About a minute`
|
||||
- `ccdi-frontend`:`Up About a minute`
|
||||
- `ccdi-lsfx-mock`:`Up About a minute`
|
||||
- 端口映射结果:
|
||||
- `62318 -> backend:8080`
|
||||
- `62319 -> frontend:80`
|
||||
- `62320 -> mock:8000`
|
||||
|
||||
### NAS 本机访问验证
|
||||
|
||||
- `http://127.0.0.1:62319/` 返回 `200`
|
||||
- `http://127.0.0.1:62318/swagger-ui/index.html` 返回 `200`
|
||||
- `http://127.0.0.1:62320/docs` 返回 `200`
|
||||
|
||||
### 公网访问验证
|
||||
|
||||
- `http://116.62.17.81:62319/` 返回 `200`
|
||||
- `http://116.62.17.81:62318/swagger-ui/index.html` 返回 `200`
|
||||
- `http://116.62.17.81:62320/docs` 返回 `200`
|
||||
|
||||
### 后端日志验证
|
||||
|
||||
- 后端启动 profile:`nas`
|
||||
- TongWeb `8080` 已启动
|
||||
- `RuoYiApplication` 启动完成
|
||||
- 日志输出“若依启动成功”
|
||||
@@ -0,0 +1,31 @@
|
||||
# 生产 MySQL 初始化文件同步实施记录
|
||||
|
||||
## 保存路径确认
|
||||
|
||||
- 实施记录保存路径:`docs/reports/implementation/2026-05-07-production-mysql-init-sync.md`
|
||||
- 本次为生产 MySQL 初始化 SQL 同步,使用实施记录目录保存。
|
||||
|
||||
## 修改内容
|
||||
|
||||
1. 更新 `sql/ccdi_prod_init_20260428.sql`,补入招聘信息维护所需的 `ccdi_recruit_type` 字典类型。
|
||||
2. 补入 `ccdi_recruit_type` 字典数据:
|
||||
- `SOCIAL`:社招
|
||||
- `CAMPUS`:校招
|
||||
3. 核对招聘信息相关结构,确认生产初始化 SQL 中已包含:
|
||||
- `ccdi_staff_recruitment.id` 自增主键
|
||||
- `ccdi_staff_recruitment.recruit_id` 普通索引
|
||||
- `ccdi_staff_recruitment_work.recruitment_id` 非空字段
|
||||
- `idx_recruitment_id` 与 `idx_recruitment_id_sort_order` 索引
|
||||
|
||||
## 影响范围
|
||||
|
||||
- 影响生产空库初始化脚本。
|
||||
- 新生产环境导入初始化 SQL 后,招聘信息导入模板可直接读取招聘类型字典下拉数据。
|
||||
- 不影响现有数据库的增量迁移脚本;存量库仍按 `sql/migration/2026-05-07-add-staff-recruitment-type-dict.sql` 执行。
|
||||
|
||||
## 验证情况
|
||||
|
||||
- 已检查生产初始化 SQL 中包含 `ccdi_recruit_type` 字典类型与 `SOCIAL`、`CAMPUS` 两条字典数据。
|
||||
- 已检查招聘主从表结构已同步最新主键与关联字段形态。
|
||||
- 已执行 `git diff --check`,未发现空白或补丁格式问题。
|
||||
- 本次未执行数据库导入验证,避免误将生产初始化脚本导入当前开发库造成清库风险。
|
||||
@@ -0,0 +1,51 @@
|
||||
# 项目总览 PDF 中文字体配置化修复实施记录
|
||||
|
||||
## 保存路径确认
|
||||
|
||||
- 文档类型:实施记录
|
||||
- 保存路径:`docs/reports/implementation/`
|
||||
|
||||
## 问题说明
|
||||
|
||||
- 异常信息:`com.ruoyi.common.exception.ServiceException: 未找到可用中文字体,无法导出PDF报告`
|
||||
- 触发链路:结果总览导出 PDF 时,`CcdiProjectOverviewReportPdfExporter` 需要通过 PDFBox 加载中文字体;原实现依赖代码内置候选路径,部署环境字体路径不可控时会导致导出失败。
|
||||
|
||||
## 修改内容
|
||||
|
||||
- 修改 `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewReportPdfExporter.java`
|
||||
- 删除 Java 代码内置多路径候选列表。
|
||||
- 通过 `ccdi.report.pdf-font-path` 读取 profile 配置中的单个字体路径。
|
||||
- 配置为空时提示 `未配置PDF中文字体路径,无法导出PDF报告`。
|
||||
- 配置文件不存在、格式不支持或字体不可导出时,错误信息包含配置路径。
|
||||
- `.ttc` 字体集合优先选择支持 TrueType 子集化的简体中文字体名,未命中时再使用集合内首个支持子集化的字体。
|
||||
- 字体集合源在 `document.save()` 完成后再关闭,避免 PDFBox 保存阶段继续读取字体时源文件已关闭。
|
||||
- 增加 `.otf` 字体文件加载支持。
|
||||
- 修改 `ruoyi-admin/src/main/resources/application-dev.yml`
|
||||
- 增加本地 macOS 字体路径:`/System/Library/Fonts/STHeiti Medium.ttc`。
|
||||
- 修改 `ruoyi-admin/src/main/resources/application-nas.yml`
|
||||
- 修改 `ruoyi-admin/src/main/resources/application-uat.yml`
|
||||
- 修改 `ruoyi-admin/src/main/resources/application-pro.yml`
|
||||
- 增加 Linux 字体路径:`/usr/share/fonts/truetype/wqy/wqy-microhei.ttc`。
|
||||
- 未修改 `application.yml`,不提供全局默认值。
|
||||
- 修改 `docker/backend/Dockerfile`
|
||||
- 后端镜像安装 `fontconfig` 与 `fonts-wqy-microhei`,确保 NAS Docker 部署环境具备可用中文字体。
|
||||
- 修改 `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewReportPdfExporterTest.java`
|
||||
- 正常导出用例显式传入测试环境字体路径。
|
||||
- 新增空配置与不存在路径的异常覆盖。
|
||||
|
||||
## 影响范围
|
||||
|
||||
- 影响结果总览 PDF 导出功能。
|
||||
- 不改变报告数据组装、表格内容、前端下载接口和文件名规则。
|
||||
- 不在 `application.yml` 增加默认配置,缺少 profile 配置时导出时报错。
|
||||
- Docker 镜像构建会新增中文字体包安装步骤。
|
||||
|
||||
## 验证记录
|
||||
|
||||
- 已执行:`mvn -pl ccdi-project -Dtest=CcdiProjectOverviewReportPdfExporterTest -Dsurefire.failIfNoSpecifiedTests=false test`
|
||||
- 结果:失败,失败原因是当前工作区已有其他源码编译错误,未进入 PDF 导出测试。
|
||||
- 主要错误包括:`getDataTable` 调用参数不匹配、流水接口字段和方法签名不匹配。
|
||||
- 已执行:手工编译 PDF 导出器及其依赖 VO 到 `ccdi-project/target/classes` 后,运行 `mvn -pl ccdi-project -Dtest=CcdiProjectOverviewReportPdfExporterTest -Dsurefire.failIfNoSpecifiedTests=false -Dmaven.main.skip=true test`
|
||||
- 结果:失败,失败原因是 Maven 仍尝试编译 `ccdi-project` 下全量测试类,而当前 `target/classes` 缺少其他测试依赖的业务类。
|
||||
- 已执行:手工编译 `CcdiProjectOverviewReportPdfExporterTest` 后,通过 JUnit Platform Launcher 指定运行该测试类
|
||||
- 结果:通过,`Tests found: 3`,`Tests succeeded: 3`,`Tests failed: 0`。
|
||||
@@ -0,0 +1,70 @@
|
||||
# 2026-05-08 NAS Docker 部署实施记录
|
||||
|
||||
## 保存路径确认
|
||||
|
||||
- 目标目录:`docs/reports/implementation/`
|
||||
- 文档用途:记录本次 NAS Docker 部署操作、影响范围与验证结果
|
||||
- 路径检查结果:符合仓库实施记录归档规范
|
||||
|
||||
## 本次操作
|
||||
|
||||
- 在本地仓库 `/Users/wkc/Desktop/ccdi/ccdi` 执行 NAS Docker 部署。
|
||||
- 按前端规则执行 `source ~/.nvm/nvm.sh && nvm use`,确认 Node 版本为 `v14.21.3`、npm 版本为 `6.14.18`。
|
||||
- 执行部署脚本:`deploy/deploy-to-nas.sh`。
|
||||
- 脚本完成以下动作:
|
||||
- 后端打包:`mvn clean package -DskipTests`
|
||||
- 前端打包:`npm run build:prod`
|
||||
- 组装部署目录:`.deploy/ccdi-package`
|
||||
- 上传到 NAS:`/volume1/webapp/ccdi`
|
||||
- 远端执行 `docker compose up -d --build`
|
||||
- 部署目标:
|
||||
- SSH:`116.62.17.81:9444`
|
||||
- 远端目录:`/volume1/webapp/ccdi`
|
||||
|
||||
## 影响范围
|
||||
|
||||
- 远端部署目录 `/volume1/webapp/ccdi` 已刷新为本次构建产物。
|
||||
- 远端 Docker 镜像已重新构建。
|
||||
- 远端 Docker 服务已重建并启动:
|
||||
- `ccdi-backend`
|
||||
- `ccdi-frontend`
|
||||
- `ccdi-lsfx-mock`
|
||||
|
||||
## 验证结果
|
||||
|
||||
### 本地构建验证
|
||||
|
||||
- Maven 聚合打包成功,`ruoyi-admin/target/ruoyi-admin.jar` 已生成。
|
||||
- Vue 生产构建成功,`ruoyi-ui/dist` 已生成。
|
||||
- 前端构建存在资源体积告警,未出现构建失败。
|
||||
|
||||
### 远端容器验证
|
||||
|
||||
- `docker compose ps` 结果:
|
||||
- `ccdi-backend`:`Up`
|
||||
- `ccdi-frontend`:`Up`
|
||||
- `ccdi-lsfx-mock`:`Up`
|
||||
- 端口映射结果:
|
||||
- `62318 -> backend:8080`
|
||||
- `62319 -> frontend:80`
|
||||
- `62320 -> mock:8000`
|
||||
|
||||
### NAS 本机访问验证
|
||||
|
||||
- `http://127.0.0.1:62319/` 返回 `200`
|
||||
- `http://127.0.0.1:62318/swagger-ui/index.html` 返回 `200`
|
||||
- `http://127.0.0.1:62320/docs` 返回 `200`
|
||||
|
||||
### 公网访问验证
|
||||
|
||||
- `http://116.62.17.81:62319/` 返回 `200`
|
||||
- `http://116.62.17.81:62318/swagger-ui/index.html` 返回 `200`
|
||||
- `http://116.62.17.81:62320/docs` 返回 `200`
|
||||
- `POST http://116.62.17.81:62318/login/test?username=admin&password=admin123` 返回 `200`
|
||||
|
||||
### 后端日志验证
|
||||
|
||||
- 后端启动 profile:`nas`
|
||||
- TongWeb `8080` 已启动。
|
||||
- `RuoYiApplication` 启动完成。
|
||||
- 日志输出“若依启动成功”。
|
||||
@@ -3,6 +3,10 @@ ruoyi:
|
||||
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
|
||||
profile: D:/ruoyi/uploadPath
|
||||
|
||||
ccdi:
|
||||
report:
|
||||
pdf-font-path: /System/Library/Fonts/STHeiti Medium.ttc
|
||||
|
||||
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为8080
|
||||
|
||||
@@ -3,6 +3,10 @@ ruoyi:
|
||||
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
|
||||
profile: backend/uploadPath
|
||||
|
||||
ccdi:
|
||||
report:
|
||||
pdf-font-path: /usr/share/fonts/truetype/wqy/wqy-microhei.ttc
|
||||
|
||||
|
||||
# 开发环境配置
|
||||
server:
|
||||
|
||||
@@ -3,6 +3,10 @@ ruoyi:
|
||||
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
|
||||
profile: backend/uploadPath
|
||||
|
||||
ccdi:
|
||||
report:
|
||||
pdf-font-path: /usr/share/fonts/truetype/wqy/wqy-microhei.ttc
|
||||
|
||||
|
||||
# 开发环境配置
|
||||
server:
|
||||
@@ -31,9 +35,9 @@ spring:
|
||||
druid:
|
||||
# 主库数据源
|
||||
master:
|
||||
url: jdbc:mysql://158.234.199.250:3306/ccdi?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: dbicm
|
||||
password: Kfcx@1234
|
||||
url: jdbc:mysql://64.116.19.156:3306/ccdi?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: lx_ai
|
||||
password: lx-ai@9520
|
||||
# 从库数据源
|
||||
slave:
|
||||
# 从数据源开关/默认关闭
|
||||
@@ -88,7 +92,7 @@ spring:
|
||||
# redis 配置
|
||||
redis:
|
||||
# 地址
|
||||
host: r-kz640f6b20dac724.redis.rds.ops.dc-tst-zj96596.com
|
||||
host: 64.116.19.155
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
@@ -111,10 +115,8 @@ spring:
|
||||
# 流水分析平台配置
|
||||
lsfx:
|
||||
api:
|
||||
|
||||
base-url: http://158.234.196.5:82/c4c3
|
||||
# 生产环境
|
||||
# base-url: http://64.202.32.176/c4c3
|
||||
base-url: http://64.202.32.176/c4c3
|
||||
|
||||
# 认证配置
|
||||
app-id: remote_app
|
||||
@@ -143,4 +145,4 @@ lsfx:
|
||||
|
||||
credit-parse:
|
||||
api:
|
||||
url: http://192.168.0.111:62320/xfeature-mngs/conversation/htmlEval
|
||||
url: http://64.202.94.120:8081/xfeature-mngs/conversation/htmlEval
|
||||
|
||||
@@ -3,6 +3,10 @@ ruoyi:
|
||||
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
|
||||
profile: backend/uploadPath
|
||||
|
||||
ccdi:
|
||||
report:
|
||||
pdf-font-path: /usr/share/fonts/truetype/wqy/wqy-microhei.ttc
|
||||
|
||||
|
||||
# 开发环境配置
|
||||
server:
|
||||
|
||||
@@ -1655,6 +1655,16 @@ INSERT INTO `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `cre
|
||||
/*!40000 ALTER TABLE `sys_dict_type` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Supplemental bootstrap data for table `sys_dict_type`
|
||||
--
|
||||
|
||||
LOCK TABLES `sys_dict_type` WRITE;
|
||||
/*!40000 ALTER TABLE `sys_dict_type` DISABLE KEYS */;
|
||||
INSERT INTO `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (118,'招聘类型','ccdi_recruit_type','0','admin','2026-05-07 00:05:00','',NULL,'招聘信息-招聘类型');
|
||||
/*!40000 ALTER TABLE `sys_dict_type` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Dumping data for table `sys_dict_data`
|
||||
--
|
||||
@@ -1665,6 +1675,16 @@ INSERT INTO `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value
|
||||
/*!40000 ALTER TABLE `sys_dict_data` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Supplemental bootstrap data for table `sys_dict_data`
|
||||
--
|
||||
|
||||
LOCK TABLES `sys_dict_data` WRITE;
|
||||
/*!40000 ALTER TABLE `sys_dict_data` DISABLE KEYS */;
|
||||
INSERT INTO `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (174,1,'社招','SOCIAL','ccdi_recruit_type','','success','Y','0','admin','2026-05-07 00:05:00','',NULL,'社会招聘'),(175,2,'校招','CAMPUS','ccdi_recruit_type','','info','N','0','admin','2026-05-07 00:05:00','',NULL,'校园招聘');
|
||||
/*!40000 ALTER TABLE `sys_dict_data` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Dumping data for table `sys_post`
|
||||
--
|
||||
|
||||
Reference in New Issue
Block a user