|
|
@@ -0,0 +1,285 @@
|
|
|
+package com.lingyue.extract.service;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.lingyue.extract.dto.request.CreateProjectRequest;
|
|
|
+import com.lingyue.extract.dto.request.UpdateProjectRequest;
|
|
|
+import com.lingyue.extract.dto.response.ProjectDetailResponse;
|
|
|
+import com.lingyue.extract.dto.response.ProjectListResponse;
|
|
|
+import com.lingyue.extract.dto.response.SourceDocumentResponse;
|
|
|
+import com.lingyue.extract.entity.Project;
|
|
|
+import com.lingyue.extract.repository.ExtractResultRepository;
|
|
|
+import com.lingyue.extract.repository.ExtractRuleRepository;
|
|
|
+import com.lingyue.extract.repository.ProjectRepository;
|
|
|
+import com.lingyue.extract.repository.SourceDocumentRepository;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.UUID;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 项目服务
|
|
|
+ *
|
|
|
+ * @author lingyue
|
|
|
+ * @since 2026-01-22
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class ProjectService {
|
|
|
+
|
|
|
+ private final ProjectRepository projectRepository;
|
|
|
+ private final SourceDocumentRepository sourceDocumentRepository;
|
|
|
+ private final ExtractRuleRepository extractRuleRepository;
|
|
|
+ private final ExtractResultRepository extractResultRepository;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建项目
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public Project create(String userId, CreateProjectRequest request) {
|
|
|
+ Project project = new Project();
|
|
|
+ project.setId(UUID.randomUUID().toString());
|
|
|
+ project.setUserId(userId);
|
|
|
+ project.setName(request.getName());
|
|
|
+ project.setDescription(request.getDescription());
|
|
|
+ project.setStatus(Project.STATUS_DRAFT);
|
|
|
+ project.setConfig(request.getConfig());
|
|
|
+ project.setCreateTime(new Date());
|
|
|
+ project.setCreateBy(userId);
|
|
|
+
|
|
|
+ projectRepository.insert(project);
|
|
|
+ log.info("创建项目成功: projectId={}, name={}", project.getId(), project.getName());
|
|
|
+ return project;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取项目详情
|
|
|
+ */
|
|
|
+ public Project getById(String id) {
|
|
|
+ return projectRepository.selectById(id);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取项目详情(含统计信息)
|
|
|
+ */
|
|
|
+ public ProjectDetailResponse getProjectDetail(String id) {
|
|
|
+ Project project = projectRepository.selectById(id);
|
|
|
+ if (project == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ ProjectDetailResponse response = ProjectDetailResponse.fromEntity(project);
|
|
|
+
|
|
|
+ // 统计来源文档数量
|
|
|
+ int docCount = sourceDocumentRepository.countByProjectId(id);
|
|
|
+ response.setDocumentCount(docCount);
|
|
|
+
|
|
|
+ // 统计规则数量
|
|
|
+ int ruleCount = extractRuleRepository.countByProjectId(id);
|
|
|
+ response.setRuleCount(ruleCount);
|
|
|
+
|
|
|
+ // 统计已完成规则数量
|
|
|
+ List<Map<String, Object>> statusCounts = extractRuleRepository.countByProjectIdGroupByStatus(id);
|
|
|
+ int completedCount = 0;
|
|
|
+ for (Map<String, Object> item : statusCounts) {
|
|
|
+ String status = (String) item.get("status");
|
|
|
+ if ("extracted".equals(status) || "confirmed".equals(status)) {
|
|
|
+ completedCount += ((Number) item.get("count")).intValue();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ response.setCompletedRuleCount(completedCount);
|
|
|
+
|
|
|
+ return response;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取项目详情(含来源文档列表)
|
|
|
+ */
|
|
|
+ public ProjectDetailResponse getProjectWithDocuments(String id, SourceDocumentService sourceDocumentService) {
|
|
|
+ ProjectDetailResponse response = getProjectDetail(id);
|
|
|
+ if (response == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取来源文档列表
|
|
|
+ List<SourceDocumentResponse> docs = sourceDocumentService.listByProjectId(id);
|
|
|
+ response.setSourceDocuments(docs);
|
|
|
+
|
|
|
+ return response;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分页查询用户的项目
|
|
|
+ */
|
|
|
+ public Page<ProjectListResponse> listByUserId(String userId, int pageNum, int pageSize) {
|
|
|
+ Page<Project> page = new Page<>(pageNum, pageSize);
|
|
|
+
|
|
|
+ LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<>();
|
|
|
+ wrapper.eq(Project::getUserId, userId)
|
|
|
+ .orderByDesc(Project::getCreateTime);
|
|
|
+
|
|
|
+ Page<Project> resultPage = projectRepository.selectPage(page, wrapper);
|
|
|
+
|
|
|
+ // 转换为响应对象
|
|
|
+ Page<ProjectListResponse> responsePage = new Page<>();
|
|
|
+ responsePage.setCurrent(resultPage.getCurrent());
|
|
|
+ responsePage.setSize(resultPage.getSize());
|
|
|
+ responsePage.setTotal(resultPage.getTotal());
|
|
|
+ responsePage.setPages(resultPage.getPages());
|
|
|
+
|
|
|
+ List<ProjectListResponse> records = resultPage.getRecords().stream()
|
|
|
+ .map(project -> {
|
|
|
+ ProjectListResponse resp = ProjectListResponse.fromEntity(project);
|
|
|
+ // 统计来源文档和规则数量
|
|
|
+ resp.setDocumentCount(sourceDocumentRepository.countByProjectId(project.getId()));
|
|
|
+ resp.setRuleCount(extractRuleRepository.countByProjectId(project.getId()));
|
|
|
+ // 计算进度
|
|
|
+ resp.setProgress(calculateProgress(project.getId()));
|
|
|
+ return resp;
|
|
|
+ })
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ responsePage.setRecords(records);
|
|
|
+
|
|
|
+ return responsePage;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按状态查询用户的项目
|
|
|
+ */
|
|
|
+ public List<ProjectListResponse> listByUserIdAndStatus(String userId, String status) {
|
|
|
+ List<Project> projects = projectRepository.findByUserIdAndStatus(userId, status);
|
|
|
+ return projects.stream()
|
|
|
+ .map(ProjectListResponse::fromEntity)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新项目
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public Project update(String id, UpdateProjectRequest request, String operatorId) {
|
|
|
+ Project project = projectRepository.selectById(id);
|
|
|
+ if (project == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (request.getName() != null) {
|
|
|
+ project.setName(request.getName());
|
|
|
+ }
|
|
|
+ if (request.getDescription() != null) {
|
|
|
+ project.setDescription(request.getDescription());
|
|
|
+ }
|
|
|
+ if (request.getStatus() != null) {
|
|
|
+ project.setStatus(request.getStatus());
|
|
|
+ }
|
|
|
+ if (request.getConfig() != null) {
|
|
|
+ project.setConfig(request.getConfig());
|
|
|
+ }
|
|
|
+
|
|
|
+ project.setUpdateTime(new Date());
|
|
|
+ project.setUpdateBy(operatorId);
|
|
|
+
|
|
|
+ projectRepository.updateById(project);
|
|
|
+ log.info("更新项目成功: projectId={}", id);
|
|
|
+ return project;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除项目(级联删除关联数据)
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public boolean delete(String id) {
|
|
|
+ Project project = projectRepository.selectById(id);
|
|
|
+ if (project == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("开始删除项目及关联数据: projectId={}", id);
|
|
|
+
|
|
|
+ // 1. 删除提取结果
|
|
|
+ int resultCount = extractResultRepository.deleteByProjectId(id);
|
|
|
+ log.debug("删除提取结果: {} 条", resultCount);
|
|
|
+
|
|
|
+ // 2. 删除提取规则
|
|
|
+ int ruleCount = extractRuleRepository.deleteByProjectId(id);
|
|
|
+ log.debug("删除提取规则: {} 条", ruleCount);
|
|
|
+
|
|
|
+ // 3. 删除来源文档
|
|
|
+ int docCount = sourceDocumentRepository.deleteByProjectId(id);
|
|
|
+ log.debug("删除来源文档: {} 条", docCount);
|
|
|
+
|
|
|
+ // 4. 删除项目
|
|
|
+ projectRepository.deleteById(id);
|
|
|
+
|
|
|
+ log.info("删除项目完成: projectId={}, 删除规则={}, 删除结果={}, 删除文档={}",
|
|
|
+ id, ruleCount, resultCount, docCount);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 归档项目
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public Project archive(String id, String operatorId) {
|
|
|
+ Project project = projectRepository.selectById(id);
|
|
|
+ if (project == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ project.setStatus(Project.STATUS_ARCHIVED);
|
|
|
+ project.setUpdateTime(new Date());
|
|
|
+ project.setUpdateBy(operatorId);
|
|
|
+
|
|
|
+ projectRepository.updateById(project);
|
|
|
+ log.info("归档项目成功: projectId={}", id);
|
|
|
+ return project;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算项目进度(百分比)
|
|
|
+ */
|
|
|
+ private int calculateProgress(String projectId) {
|
|
|
+ int totalRules = extractRuleRepository.countByProjectId(projectId);
|
|
|
+ if (totalRules == 0) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Map<String, Object>> statusCounts = extractRuleRepository.countByProjectIdGroupByStatus(projectId);
|
|
|
+ int completedCount = 0;
|
|
|
+ for (Map<String, Object> item : statusCounts) {
|
|
|
+ String status = (String) item.get("status");
|
|
|
+ if ("extracted".equals(status) || "confirmed".equals(status)) {
|
|
|
+ completedCount += ((Number) item.get("count")).intValue();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return (int) Math.round((double) completedCount / totalRules * 100);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查用户是否有权访问项目
|
|
|
+ */
|
|
|
+ public boolean hasAccess(String projectId, String userId) {
|
|
|
+ Project project = projectRepository.selectById(projectId);
|
|
|
+ return project != null && project.getUserId().equals(userId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户项目统计
|
|
|
+ */
|
|
|
+ public Map<String, Integer> getProjectStatistics(String userId) {
|
|
|
+ List<Map<String, Object>> counts = projectRepository.countByUserIdGroupByStatus(userId);
|
|
|
+ return counts.stream()
|
|
|
+ .collect(Collectors.toMap(
|
|
|
+ m -> (String) m.get("status"),
|
|
|
+ m -> ((Number) m.get("count")).intValue()
|
|
|
+ ));
|
|
|
+ }
|
|
|
+}
|