diff --git a/backend/ruoyi-modules/ruoyi-aihr/pom.xml b/backend/ruoyi-modules/ruoyi-aihr/pom.xml
index 81e0155a..60d566c5 100644
--- a/backend/ruoyi-modules/ruoyi-aihr/pom.xml
+++ b/backend/ruoyi-modules/ruoyi-aihr/pom.xml
@@ -60,6 +60,12 @@
3.0.5
+
+ org.apache.poi
+ poi-ooxml
+ 5.4.1
+
+
org.springframework.boot
spring-boot-starter-test
diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/controller/PersonalAssistantController.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/controller/PersonalAssistantController.java
index f5c45489..3f2eedaf 100644
--- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/controller/PersonalAssistantController.java
+++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/controller/PersonalAssistantController.java
@@ -7,6 +7,7 @@ import org.dromara.aihr.personal.domain.PersonalAssistantDto.DownloadUrlResponse
import org.dromara.aihr.personal.domain.PersonalAssistantDto.ExportOutlineCreateRequest;
import org.dromara.aihr.personal.domain.PersonalAssistantDto.ExportOutlineResponse;
import org.dromara.aihr.personal.domain.PersonalAssistantDto.ExportOutlineUpdateRequest;
+import org.dromara.aihr.personal.domain.PersonalAssistantDto.ExportPptRequest;
import org.dromara.aihr.personal.domain.PersonalAssistantDto.ItemCreatedResponse;
import org.dromara.aihr.personal.domain.PersonalAssistantDto.ItemResponse;
import org.dromara.aihr.personal.domain.PersonalAssistantDto.OcrProgressResponse;
@@ -179,6 +180,17 @@ public class PersonalAssistantController {
return R.ok();
}
+ @PostMapping("/exports/{id}/pptx")
+ public R enqueuePpt(@PathVariable long id, @RequestBody(required = false) ExportPptRequest request) {
+ exportService.enqueuePpt(owner(), id, request == null ? null : request.templateCode());
+ return R.ok();
+ }
+
+ @GetMapping("/exports/{id}/download-url")
+ public R exportDownloadUrl(@PathVariable long id) {
+ return R.ok(exportService.downloadUrl(owner(), id));
+ }
+
private PersonalOwner owner() {
return ownerProvider.current();
}
diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/domain/PersonalAssistantDto.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/domain/PersonalAssistantDto.java
index 498f173d..e5513ea1 100644
--- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/domain/PersonalAssistantDto.java
+++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/domain/PersonalAssistantDto.java
@@ -99,6 +99,9 @@ public final class PersonalAssistantDto {
public record ExportOutlineUpdateRequest(String title, List sections) {
}
+ public record ExportPptRequest(String templateCode) {
+ }
+
public record ExportOutlineSource(String domain, String sourceId, Long itemId, String title, String excerpt) {
}
diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/service/PersonalExportService.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/service/PersonalExportService.java
index b6f62318..b4c968f2 100644
--- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/service/PersonalExportService.java
+++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/personal/service/PersonalExportService.java
@@ -9,12 +9,33 @@ import org.dromara.aihr.personal.domain.PersonalAssistantDto.ExportOutlineRespon
import org.dromara.aihr.personal.domain.PersonalAssistantDto.ExportOutlineSection;
import org.dromara.aihr.personal.domain.PersonalAssistantDto.ExportOutlineSource;
import org.dromara.aihr.personal.domain.PersonalAssistantDto.ExportOutlineUpdateRequest;
+import org.dromara.aihr.personal.domain.PersonalAssistantDto.DownloadUrlResponse;
+import org.dromara.aihr.personal.support.PersonalKnowledgeProperties;
import org.dromara.aihr.personal.support.PersonalOwner;
import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.oss.core.OssClient;
+import org.dromara.common.oss.entity.UploadResult;
+import org.dromara.common.oss.enums.AccessPolicyType;
+import org.dromara.common.oss.factory.OssFactory;
+import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.time.Duration;
+import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -27,21 +48,31 @@ public class PersonalExportService {
private final JdbcTemplate jdbc;
private final ObjectMapper objectMapper;
private final LongSupplier idSupplier;
+ private final ExportStorage storage;
@Autowired
- public PersonalExportService(JdbcTemplate jdbc, ObjectMapper objectMapper) {
- this(jdbc, objectMapper, IdWorker::getId);
+ public PersonalExportService(JdbcTemplate jdbc, ObjectMapper objectMapper,
+ PersonalKnowledgeProperties properties) {
+ this(jdbc, objectMapper, IdWorker::getId,
+ new DefaultExportStorage(jdbc, properties, PersonalExportService::ossClient));
}
- private PersonalExportService(JdbcTemplate jdbc, ObjectMapper objectMapper, LongSupplier idSupplier) {
+ private PersonalExportService(JdbcTemplate jdbc, ObjectMapper objectMapper, LongSupplier idSupplier,
+ ExportStorage storage) {
this.jdbc = jdbc;
this.objectMapper = objectMapper;
this.idSupplier = idSupplier;
+ this.storage = storage;
}
public static PersonalExportService forTest(JdbcTemplate jdbc, ObjectMapper objectMapper,
LongSupplier idSupplier) {
- return new PersonalExportService(jdbc, objectMapper, idSupplier);
+ return new PersonalExportService(jdbc, objectMapper, idSupplier, new UnavailableExportStorage());
+ }
+
+ public static PersonalExportService forTest(JdbcTemplate jdbc, ObjectMapper objectMapper,
+ LongSupplier idSupplier, ExportStorage storage) {
+ return new PersonalExportService(jdbc, objectMapper, idSupplier, storage);
}
public ExportOutlineResponse createOutline(PersonalOwner owner, ExportOutlineCreateRequest request) {
@@ -115,6 +146,129 @@ public class PersonalExportService {
if (changed != 1) throw new ServiceException("PERSONAL_EXPORT_NOT_FOUND");
}
+ public void enqueuePpt(PersonalOwner owner, long exportId, String templateCode) {
+ ExportOutlineResponse outline = load(owner, exportId);
+ if (!outline.confirmed() || !("CONFIRMED".equals(outline.status()) || "FAILED".equals(outline.status()))) {
+ throw new ServiceException("PERSONAL_OUTLINE_NOT_CONFIRMED");
+ }
+ String template = clean(templateCode);
+ if (template.isEmpty()) template = "standard";
+ int changed = jdbc.update("""
+ update aihr_personal_export_task
+ set template_code = ?, status = 'PENDING', oss_id = null, error_message = null, update_time = now()
+ where binary tenant_id = binary ? and owner_user_id = ? and id = ?
+ and outline_confirmed = 1 and status in ('CONFIRMED','FAILED')
+ """, truncate(template, 50), owner.tenantId(), owner.userId(), exportId);
+ if (changed != 1) throw new ServiceException("PERSONAL_EXPORT_NOT_FOUND");
+ }
+
+ public DownloadUrlResponse downloadUrl(PersonalOwner owner, long exportId) {
+ ExportOutlineResponse outline = load(owner, exportId);
+ if (!"READY".equals(outline.status()) || outline.ossId() == null) {
+ throw new ServiceException("PERSONAL_EXPORT_NOT_READY");
+ }
+ return storage.download(owner, exportId);
+ }
+
+ @Scheduled(fixedDelayString = "${aihr.personal.export-delay-ms:2000}", scheduler = "personalTaskScheduler")
+ public void processPending() {
+ List