feat(project): 实现AI项目初始化及查询功能
- 新增ProjectService接口及实现,实现基于AI解析项目文档生成结构化项目数据 - 使用聊天机器人接口和OSS服务支持文件内容读取与AI解析 - 实现项目基本信息、里程碑、任务、成员、资源、风险及时间节点的持久化保存 - 支持任务层级关系和依赖关系的存储与管理 - 提供项目列表、项目详情、项目甘特图及项目统计接口 - 项目列表支持管理员与普通用户视角不同的数据访问权限 - 统计功能覆盖项目状态分布、本月新增、即将到期、平均进度及高风险项目数 - 项目编号自动生成,状态初始化为规划中 - 采用分页查询支持大数据量高效访问
This commit is contained in:
@@ -4,6 +4,7 @@ import cn.yinlihupo.common.core.BaseResponse;
|
|||||||
import cn.yinlihupo.common.page.TableDataInfo;
|
import cn.yinlihupo.common.page.TableDataInfo;
|
||||||
import cn.yinlihupo.common.util.ResultUtils;
|
import cn.yinlihupo.common.util.ResultUtils;
|
||||||
import cn.yinlihupo.common.util.SecurityUtils;
|
import cn.yinlihupo.common.util.SecurityUtils;
|
||||||
|
import cn.yinlihupo.domain.vo.ProjectDetailVO;
|
||||||
import cn.yinlihupo.domain.vo.ProjectGanttVO;
|
import cn.yinlihupo.domain.vo.ProjectGanttVO;
|
||||||
import cn.yinlihupo.domain.vo.ProjectListVO;
|
import cn.yinlihupo.domain.vo.ProjectListVO;
|
||||||
import cn.yinlihupo.domain.vo.ProjectStatisticsVO;
|
import cn.yinlihupo.domain.vo.ProjectStatisticsVO;
|
||||||
@@ -66,6 +67,30 @@ public class ProjectQueryController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取项目详情(全量信息)
|
||||||
|
* 包括基本信息、参与人员、里程碑、任务、资源、风险、时间节点等
|
||||||
|
*
|
||||||
|
* @param projectId 项目ID
|
||||||
|
* @return 项目详情
|
||||||
|
*/
|
||||||
|
@GetMapping("/{projectId}")
|
||||||
|
public BaseResponse<ProjectDetailVO> getProjectDetail(@PathVariable Long projectId) {
|
||||||
|
log.info("获取项目详情, projectId: {}", projectId);
|
||||||
|
|
||||||
|
if (projectId == null || projectId <= 0) {
|
||||||
|
return ResultUtils.error("项目ID不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ProjectDetailVO result = projectService.getProjectDetail(projectId);
|
||||||
|
return ResultUtils.success("查询成功", result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取项目详情失败: {}", e.getMessage(), e);
|
||||||
|
return ResultUtils.error("查询失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取项目甘特图数据
|
* 获取项目甘特图数据
|
||||||
*
|
*
|
||||||
|
|||||||
645
src/main/java/cn/yinlihupo/domain/vo/ProjectDetailVO.java
Normal file
645
src/main/java/cn/yinlihupo/domain/vo/ProjectDetailVO.java
Normal file
@@ -0,0 +1,645 @@
|
|||||||
|
package cn.yinlihupo.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目详情VO
|
||||||
|
* 包含项目全量信息:基本信息、参与人员、预算进度、物料资源等
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ProjectDetailVO {
|
||||||
|
|
||||||
|
// ==================== 项目基本信息 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目编号
|
||||||
|
*/
|
||||||
|
private String projectCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目名称
|
||||||
|
*/
|
||||||
|
private String projectName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目类型
|
||||||
|
*/
|
||||||
|
private String projectType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目目标
|
||||||
|
*/
|
||||||
|
private String objectives;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目经理ID
|
||||||
|
*/
|
||||||
|
private Long managerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目经理名称
|
||||||
|
*/
|
||||||
|
private String managerName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目发起人ID
|
||||||
|
*/
|
||||||
|
private Long sponsorId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划开始日期
|
||||||
|
*/
|
||||||
|
private LocalDate planStartDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划结束日期
|
||||||
|
*/
|
||||||
|
private LocalDate planEndDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际开始日期
|
||||||
|
*/
|
||||||
|
private LocalDate actualStartDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际结束日期
|
||||||
|
*/
|
||||||
|
private LocalDate actualEndDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目预算
|
||||||
|
*/
|
||||||
|
private BigDecimal budget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已花费金额
|
||||||
|
*/
|
||||||
|
private BigDecimal cost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 币种
|
||||||
|
*/
|
||||||
|
private String currency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进度百分比
|
||||||
|
*/
|
||||||
|
private Integer progress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优先级
|
||||||
|
*/
|
||||||
|
private String priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风险等级
|
||||||
|
*/
|
||||||
|
private String riskLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 可见性
|
||||||
|
*/
|
||||||
|
private Integer visibility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签列表
|
||||||
|
*/
|
||||||
|
private List<String> tags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
// ==================== 统计汇总信息 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成员数量
|
||||||
|
*/
|
||||||
|
private Integer memberCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务总数
|
||||||
|
*/
|
||||||
|
private Integer taskCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已完成任务数
|
||||||
|
*/
|
||||||
|
private Integer completedTaskCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 里程碑总数
|
||||||
|
*/
|
||||||
|
private Integer milestoneCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源总数
|
||||||
|
*/
|
||||||
|
private Integer resourceCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风险总数
|
||||||
|
*/
|
||||||
|
private Integer riskCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高风险数量
|
||||||
|
*/
|
||||||
|
private Integer highRiskCount;
|
||||||
|
|
||||||
|
// ==================== 关联数据列表 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目成员列表
|
||||||
|
*/
|
||||||
|
private List<MemberInfo> members;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 里程碑列表
|
||||||
|
*/
|
||||||
|
private List<MilestoneInfo> milestones;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务列表
|
||||||
|
*/
|
||||||
|
private List<TaskInfo> tasks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源列表
|
||||||
|
*/
|
||||||
|
private List<ResourceInfo> resources;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风险列表
|
||||||
|
*/
|
||||||
|
private List<RiskInfo> risks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间节点列表
|
||||||
|
*/
|
||||||
|
private List<TimelineInfo> timelineNodes;
|
||||||
|
|
||||||
|
// ==================== 内部类定义 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成员信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class MemberInfo {
|
||||||
|
/**
|
||||||
|
* 成员记录ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名
|
||||||
|
*/
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 真实姓名
|
||||||
|
*/
|
||||||
|
private String realName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 头像
|
||||||
|
*/
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目角色
|
||||||
|
*/
|
||||||
|
private String roleCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门
|
||||||
|
*/
|
||||||
|
private String department;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 职责描述
|
||||||
|
*/
|
||||||
|
private String responsibility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每周投入小时数
|
||||||
|
*/
|
||||||
|
private BigDecimal weeklyHours;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加入日期
|
||||||
|
*/
|
||||||
|
private LocalDate joinDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 里程碑信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class MilestoneInfo {
|
||||||
|
/**
|
||||||
|
* 里程碑ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 里程碑名称
|
||||||
|
*/
|
||||||
|
private String milestoneName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划日期
|
||||||
|
*/
|
||||||
|
private LocalDate planDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际日期
|
||||||
|
*/
|
||||||
|
private LocalDate actualDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成进度
|
||||||
|
*/
|
||||||
|
private Integer progress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否关键里程碑
|
||||||
|
*/
|
||||||
|
private Integer isKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交付物列表
|
||||||
|
*/
|
||||||
|
private List<String> deliverables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序
|
||||||
|
*/
|
||||||
|
private Integer sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class TaskInfo {
|
||||||
|
/**
|
||||||
|
* 任务ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务编号
|
||||||
|
*/
|
||||||
|
private String taskCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务名称
|
||||||
|
*/
|
||||||
|
private String taskName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务类型
|
||||||
|
*/
|
||||||
|
private String taskType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所属里程碑ID
|
||||||
|
*/
|
||||||
|
private Long milestoneId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行人ID
|
||||||
|
*/
|
||||||
|
private Long assigneeId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行人姓名
|
||||||
|
*/
|
||||||
|
private String assigneeName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划开始日期
|
||||||
|
*/
|
||||||
|
private LocalDate planStartDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划结束日期
|
||||||
|
*/
|
||||||
|
private LocalDate planEndDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际开始日期
|
||||||
|
*/
|
||||||
|
private LocalDate actualStartDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际结束日期
|
||||||
|
*/
|
||||||
|
private LocalDate actualEndDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划工时
|
||||||
|
*/
|
||||||
|
private BigDecimal planHours;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际工时
|
||||||
|
*/
|
||||||
|
private BigDecimal actualHours;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进度百分比
|
||||||
|
*/
|
||||||
|
private Integer progress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优先级
|
||||||
|
*/
|
||||||
|
private String priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序
|
||||||
|
*/
|
||||||
|
private Integer sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class ResourceInfo {
|
||||||
|
/**
|
||||||
|
* 资源ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源编号
|
||||||
|
*/
|
||||||
|
private String resourceCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源类型
|
||||||
|
*/
|
||||||
|
private String resourceType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源名称
|
||||||
|
*/
|
||||||
|
private String resourceName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 规格型号
|
||||||
|
*/
|
||||||
|
private String specification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单位
|
||||||
|
*/
|
||||||
|
private String unit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划数量
|
||||||
|
*/
|
||||||
|
private BigDecimal planQuantity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际数量
|
||||||
|
*/
|
||||||
|
private BigDecimal actualQuantity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单价
|
||||||
|
*/
|
||||||
|
private BigDecimal unitPrice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 币种
|
||||||
|
*/
|
||||||
|
private String currency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 供应商
|
||||||
|
*/
|
||||||
|
private String supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划到位日期
|
||||||
|
*/
|
||||||
|
private LocalDate planArriveDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际到位日期
|
||||||
|
*/
|
||||||
|
private LocalDate actualArriveDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 负责人ID
|
||||||
|
*/
|
||||||
|
private Long responsibleId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存放位置
|
||||||
|
*/
|
||||||
|
private String location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签
|
||||||
|
*/
|
||||||
|
private List<String> tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风险信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class RiskInfo {
|
||||||
|
/**
|
||||||
|
* 风险ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风险编号
|
||||||
|
*/
|
||||||
|
private String riskCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风险分类
|
||||||
|
*/
|
||||||
|
private String category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风险名称
|
||||||
|
*/
|
||||||
|
private String riskName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风险描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发生概率
|
||||||
|
*/
|
||||||
|
private BigDecimal probability;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 影响程度
|
||||||
|
*/
|
||||||
|
private BigDecimal impact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风险得分
|
||||||
|
*/
|
||||||
|
private BigDecimal riskScore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风险等级
|
||||||
|
*/
|
||||||
|
private String riskLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 负责人ID
|
||||||
|
*/
|
||||||
|
private Long ownerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓解措施
|
||||||
|
*/
|
||||||
|
private String mitigationPlan;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预期解决日期
|
||||||
|
*/
|
||||||
|
private LocalDate dueDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发现时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime discoverTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间节点信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class TimelineInfo {
|
||||||
|
/**
|
||||||
|
* 节点ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点名称
|
||||||
|
*/
|
||||||
|
private String nodeName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点类型
|
||||||
|
*/
|
||||||
|
private String nodeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划日期
|
||||||
|
*/
|
||||||
|
private LocalDate planDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际日期
|
||||||
|
*/
|
||||||
|
private LocalDate actualDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序
|
||||||
|
*/
|
||||||
|
private Integer sortOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 知识库范围
|
||||||
|
*/
|
||||||
|
private List<String> kbScope;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package cn.yinlihupo.service.project;
|
package cn.yinlihupo.service.project;
|
||||||
|
|
||||||
import cn.yinlihupo.common.page.TableDataInfo;
|
import cn.yinlihupo.common.page.TableDataInfo;
|
||||||
|
import cn.yinlihupo.domain.vo.ProjectDetailVO;
|
||||||
import cn.yinlihupo.domain.vo.ProjectGanttVO;
|
import cn.yinlihupo.domain.vo.ProjectGanttVO;
|
||||||
import cn.yinlihupo.domain.vo.ProjectInitResult;
|
import cn.yinlihupo.domain.vo.ProjectInitResult;
|
||||||
import cn.yinlihupo.domain.vo.ProjectListVO;
|
import cn.yinlihupo.domain.vo.ProjectListVO;
|
||||||
@@ -90,4 +91,12 @@ public interface ProjectService {
|
|||||||
*/
|
*/
|
||||||
TableDataInfo<ProjectListVO> getAllProjectList(Integer pageNum, Integer pageSize,
|
TableDataInfo<ProjectListVO> getAllProjectList(Integer pageNum, Integer pageSize,
|
||||||
String keyword, String status);
|
String keyword, String status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取项目详情(全量信息)
|
||||||
|
*
|
||||||
|
* @param projectId 项目ID
|
||||||
|
* @return 项目详情
|
||||||
|
*/
|
||||||
|
ProjectDetailVO getProjectDetail(Long projectId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ public class ProjectServiceImpl implements ProjectService {
|
|||||||
private final ResourceMapper resourceMapper;
|
private final ResourceMapper resourceMapper;
|
||||||
private final RiskMapper riskMapper;
|
private final RiskMapper riskMapper;
|
||||||
private final ProjectTimelineMapper projectTimelineMapper;
|
private final ProjectTimelineMapper projectTimelineMapper;
|
||||||
|
private final SysUserMapper sysUserMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 项目初始化系统提示词模板
|
* 项目初始化系统提示词模板
|
||||||
@@ -825,4 +826,289 @@ public class ProjectServiceImpl implements ProjectService {
|
|||||||
vo.setSortOrder(task.getSortOrder());
|
vo.setSortOrder(task.getSortOrder());
|
||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 项目详情相关实现 ====================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProjectDetailVO getProjectDetail(Long projectId) {
|
||||||
|
log.info("查询项目详情, projectId: {}", projectId);
|
||||||
|
|
||||||
|
// 1. 查询项目基本信息
|
||||||
|
Project project = projectMapper.selectById(projectId);
|
||||||
|
if (project == null || project.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("项目不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectDetailVO detailVO = new ProjectDetailVO();
|
||||||
|
|
||||||
|
// 2. 设置项目基本信息
|
||||||
|
detailVO.setId(project.getId());
|
||||||
|
detailVO.setProjectCode(project.getProjectCode());
|
||||||
|
detailVO.setProjectName(project.getProjectName());
|
||||||
|
detailVO.setProjectType(project.getProjectType());
|
||||||
|
detailVO.setDescription(project.getDescription());
|
||||||
|
detailVO.setObjectives(project.getObjectives());
|
||||||
|
detailVO.setManagerId(project.getManagerId());
|
||||||
|
detailVO.setSponsorId(project.getSponsorId());
|
||||||
|
detailVO.setPlanStartDate(project.getPlanStartDate());
|
||||||
|
detailVO.setPlanEndDate(project.getPlanEndDate());
|
||||||
|
detailVO.setActualStartDate(project.getActualStartDate());
|
||||||
|
detailVO.setActualEndDate(project.getActualEndDate());
|
||||||
|
detailVO.setBudget(project.getBudget());
|
||||||
|
detailVO.setCost(project.getCost());
|
||||||
|
detailVO.setCurrency(project.getCurrency());
|
||||||
|
detailVO.setProgress(project.getProgress());
|
||||||
|
detailVO.setStatus(project.getStatus());
|
||||||
|
detailVO.setPriority(project.getPriority());
|
||||||
|
detailVO.setRiskLevel(project.getRiskLevel());
|
||||||
|
detailVO.setVisibility(project.getVisibility());
|
||||||
|
detailVO.setTags(project.getTags());
|
||||||
|
detailVO.setCreateTime(project.getCreateTime());
|
||||||
|
detailVO.setUpdateTime(project.getUpdateTime());
|
||||||
|
|
||||||
|
// 查询项目经理名称
|
||||||
|
if (project.getManagerId() != null) {
|
||||||
|
SysUser manager = sysUserMapper.selectById(project.getManagerId());
|
||||||
|
if (manager != null) {
|
||||||
|
detailVO.setManagerName(manager.getRealName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 查询项目成员
|
||||||
|
List<ProjectMember> members = projectMemberMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<ProjectMember>()
|
||||||
|
.eq(ProjectMember::getProjectId, projectId)
|
||||||
|
.eq(ProjectMember::getDeleted, 0)
|
||||||
|
.orderByAsc(ProjectMember::getId)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 查询成员用户信息
|
||||||
|
List<Long> userIds = members.stream()
|
||||||
|
.map(ProjectMember::getUserId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
Map<Long, SysUser> userMap = new HashMap<>();
|
||||||
|
if (!userIds.isEmpty()) {
|
||||||
|
List<SysUser> users = sysUserMapper.selectBatchIds(userIds);
|
||||||
|
userMap = users.stream()
|
||||||
|
.collect(Collectors.toMap(SysUser::getId, u -> u, (a, b) -> a));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换成员信息
|
||||||
|
final Map<Long, SysUser> finalUserMap = userMap;
|
||||||
|
List<ProjectDetailVO.MemberInfo> memberVOList = members.stream()
|
||||||
|
.map(member -> {
|
||||||
|
ProjectDetailVO.MemberInfo memberInfo = new ProjectDetailVO.MemberInfo();
|
||||||
|
memberInfo.setId(member.getId());
|
||||||
|
memberInfo.setUserId(member.getUserId());
|
||||||
|
memberInfo.setRoleCode(member.getRoleCode());
|
||||||
|
memberInfo.setResponsibility(member.getResponsibility());
|
||||||
|
memberInfo.setWeeklyHours(member.getWeeklyHours());
|
||||||
|
memberInfo.setJoinDate(member.getJoinDate());
|
||||||
|
memberInfo.setStatus(member.getStatus());
|
||||||
|
|
||||||
|
// 填充用户信息
|
||||||
|
if (member.getUserId() != null) {
|
||||||
|
SysUser user = finalUserMap.get(member.getUserId());
|
||||||
|
if (user != null) {
|
||||||
|
memberInfo.setUserName(user.getUsername());
|
||||||
|
memberInfo.setRealName(user.getRealName());
|
||||||
|
memberInfo.setAvatar(user.getAvatar());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return memberInfo;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
detailVO.setMembers(memberVOList);
|
||||||
|
detailVO.setMemberCount(memberVOList.size());
|
||||||
|
|
||||||
|
// 4. 查询里程碑
|
||||||
|
List<ProjectMilestone> milestones = projectMilestoneMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<ProjectMilestone>()
|
||||||
|
.eq(ProjectMilestone::getProjectId, projectId)
|
||||||
|
.eq(ProjectMilestone::getDeleted, 0)
|
||||||
|
.orderByAsc(ProjectMilestone::getSortOrder)
|
||||||
|
);
|
||||||
|
|
||||||
|
List<ProjectDetailVO.MilestoneInfo> milestoneVOList = milestones.stream()
|
||||||
|
.map(milestone -> {
|
||||||
|
ProjectDetailVO.MilestoneInfo milestoneInfo = new ProjectDetailVO.MilestoneInfo();
|
||||||
|
milestoneInfo.setId(milestone.getId());
|
||||||
|
milestoneInfo.setMilestoneName(milestone.getMilestoneName());
|
||||||
|
milestoneInfo.setDescription(milestone.getDescription());
|
||||||
|
milestoneInfo.setPlanDate(milestone.getPlanDate());
|
||||||
|
milestoneInfo.setActualDate(milestone.getActualDate());
|
||||||
|
milestoneInfo.setStatus(milestone.getStatus());
|
||||||
|
milestoneInfo.setProgress(milestone.getProgress());
|
||||||
|
milestoneInfo.setIsKey(milestone.getIsKey());
|
||||||
|
milestoneInfo.setDeliverables(milestone.getDeliverables());
|
||||||
|
milestoneInfo.setSortOrder(milestone.getSortOrder());
|
||||||
|
return milestoneInfo;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
detailVO.setMilestones(milestoneVOList);
|
||||||
|
detailVO.setMilestoneCount(milestoneVOList.size());
|
||||||
|
|
||||||
|
// 5. 查询任务
|
||||||
|
List<Task> tasks = taskMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<Task>()
|
||||||
|
.eq(Task::getProjectId, projectId)
|
||||||
|
.eq(Task::getDeleted, 0)
|
||||||
|
.orderByAsc(Task::getSortOrder)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 查询任务执行人信息
|
||||||
|
List<Long> assigneeIds = tasks.stream()
|
||||||
|
.map(Task::getAssigneeId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
Map<Long, SysUser> assigneeMap = new HashMap<>();
|
||||||
|
if (!assigneeIds.isEmpty()) {
|
||||||
|
List<SysUser> assignees = sysUserMapper.selectBatchIds(assigneeIds);
|
||||||
|
assigneeMap = assignees.stream()
|
||||||
|
.collect(Collectors.toMap(SysUser::getId, u -> u, (a, b) -> a));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换任务信息
|
||||||
|
final Map<Long, SysUser> finalAssigneeMap = assigneeMap;
|
||||||
|
List<ProjectDetailVO.TaskInfo> taskVOList = tasks.stream()
|
||||||
|
.map(task -> {
|
||||||
|
ProjectDetailVO.TaskInfo taskInfo = new ProjectDetailVO.TaskInfo();
|
||||||
|
taskInfo.setId(task.getId());
|
||||||
|
taskInfo.setTaskCode(task.getTaskCode());
|
||||||
|
taskInfo.setTaskName(task.getTaskName());
|
||||||
|
taskInfo.setDescription(task.getDescription());
|
||||||
|
taskInfo.setTaskType(task.getTaskType());
|
||||||
|
taskInfo.setMilestoneId(task.getMilestoneId());
|
||||||
|
taskInfo.setAssigneeId(task.getAssigneeId());
|
||||||
|
taskInfo.setPlanStartDate(task.getPlanStartDate());
|
||||||
|
taskInfo.setPlanEndDate(task.getPlanEndDate());
|
||||||
|
taskInfo.setActualStartDate(task.getActualStartDate());
|
||||||
|
taskInfo.setActualEndDate(task.getActualEndDate());
|
||||||
|
taskInfo.setPlanHours(task.getPlanHours());
|
||||||
|
taskInfo.setActualHours(task.getActualHours());
|
||||||
|
taskInfo.setProgress(task.getProgress());
|
||||||
|
taskInfo.setPriority(task.getPriority());
|
||||||
|
taskInfo.setStatus(task.getStatus());
|
||||||
|
taskInfo.setSortOrder(task.getSortOrder());
|
||||||
|
|
||||||
|
// 填充执行人姓名
|
||||||
|
if (task.getAssigneeId() != null) {
|
||||||
|
SysUser assignee = finalAssigneeMap.get(task.getAssigneeId());
|
||||||
|
if (assignee != null) {
|
||||||
|
taskInfo.setAssigneeName(assignee.getRealName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return taskInfo;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
detailVO.setTasks(taskVOList);
|
||||||
|
detailVO.setTaskCount(taskVOList.size());
|
||||||
|
|
||||||
|
// 统计已完成任务数
|
||||||
|
int completedCount = (int) tasks.stream()
|
||||||
|
.filter(t -> "completed".equals(t.getStatus()))
|
||||||
|
.count();
|
||||||
|
detailVO.setCompletedTaskCount(completedCount);
|
||||||
|
|
||||||
|
// 6. 查询资源
|
||||||
|
List<Resource> resources = resourceMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<Resource>()
|
||||||
|
.eq(Resource::getProjectId, projectId)
|
||||||
|
.eq(Resource::getDeleted, 0)
|
||||||
|
.orderByAsc(Resource::getId)
|
||||||
|
);
|
||||||
|
|
||||||
|
List<ProjectDetailVO.ResourceInfo> resourceVOList = resources.stream()
|
||||||
|
.map(resource -> {
|
||||||
|
ProjectDetailVO.ResourceInfo resourceInfo = new ProjectDetailVO.ResourceInfo();
|
||||||
|
resourceInfo.setId(resource.getId());
|
||||||
|
resourceInfo.setResourceCode(resource.getResourceCode());
|
||||||
|
resourceInfo.setResourceType(resource.getResourceType());
|
||||||
|
resourceInfo.setResourceName(resource.getResourceName());
|
||||||
|
resourceInfo.setDescription(resource.getDescription());
|
||||||
|
resourceInfo.setSpecification(resource.getSpecification());
|
||||||
|
resourceInfo.setUnit(resource.getUnit());
|
||||||
|
resourceInfo.setPlanQuantity(resource.getPlanQuantity());
|
||||||
|
resourceInfo.setActualQuantity(resource.getActualQuantity());
|
||||||
|
resourceInfo.setUnitPrice(resource.getUnitPrice());
|
||||||
|
resourceInfo.setCurrency(resource.getCurrency());
|
||||||
|
resourceInfo.setSupplier(resource.getSupplier());
|
||||||
|
resourceInfo.setStatus(resource.getStatus());
|
||||||
|
resourceInfo.setPlanArriveDate(resource.getPlanArriveDate());
|
||||||
|
resourceInfo.setActualArriveDate(resource.getActualArriveDate());
|
||||||
|
resourceInfo.setResponsibleId(resource.getResponsibleId());
|
||||||
|
resourceInfo.setLocation(resource.getLocation());
|
||||||
|
resourceInfo.setTags(resource.getTags());
|
||||||
|
return resourceInfo;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
detailVO.setResources(resourceVOList);
|
||||||
|
detailVO.setResourceCount(resourceVOList.size());
|
||||||
|
|
||||||
|
// 7. 查询风险
|
||||||
|
List<Risk> risks = riskMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<Risk>()
|
||||||
|
.eq(Risk::getProjectId, projectId)
|
||||||
|
.eq(Risk::getDeleted, 0)
|
||||||
|
.orderByDesc(Risk::getRiskScore)
|
||||||
|
);
|
||||||
|
|
||||||
|
List<ProjectDetailVO.RiskInfo> riskVOList = risks.stream()
|
||||||
|
.map(risk -> {
|
||||||
|
ProjectDetailVO.RiskInfo riskInfo = new ProjectDetailVO.RiskInfo();
|
||||||
|
riskInfo.setId(risk.getId());
|
||||||
|
riskInfo.setRiskCode(risk.getRiskCode());
|
||||||
|
riskInfo.setCategory(risk.getCategory());
|
||||||
|
riskInfo.setRiskName(risk.getRiskName());
|
||||||
|
riskInfo.setDescription(risk.getDescription());
|
||||||
|
riskInfo.setProbability(risk.getProbability());
|
||||||
|
riskInfo.setImpact(risk.getImpact());
|
||||||
|
riskInfo.setRiskScore(risk.getRiskScore());
|
||||||
|
riskInfo.setRiskLevel(risk.getRiskLevel());
|
||||||
|
riskInfo.setStatus(risk.getStatus());
|
||||||
|
riskInfo.setOwnerId(risk.getOwnerId());
|
||||||
|
riskInfo.setMitigationPlan(risk.getMitigationPlan());
|
||||||
|
riskInfo.setDueDate(risk.getDueDate());
|
||||||
|
riskInfo.setDiscoverTime(risk.getDiscoverTime());
|
||||||
|
return riskInfo;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
detailVO.setRisks(riskVOList);
|
||||||
|
detailVO.setRiskCount(riskVOList.size());
|
||||||
|
|
||||||
|
// 统计高风险数量
|
||||||
|
int highRiskCount = (int) risks.stream()
|
||||||
|
.filter(r -> "high".equals(r.getRiskLevel()) || "critical".equals(r.getRiskLevel()))
|
||||||
|
.count();
|
||||||
|
detailVO.setHighRiskCount(highRiskCount);
|
||||||
|
|
||||||
|
// 8. 查询时间节点
|
||||||
|
List<ProjectTimeline> timelines = projectTimelineMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<ProjectTimeline>()
|
||||||
|
.eq(ProjectTimeline::getProjectId, projectId)
|
||||||
|
.eq(ProjectTimeline::getDeleted, 0)
|
||||||
|
.orderByAsc(ProjectTimeline::getSortOrder)
|
||||||
|
);
|
||||||
|
|
||||||
|
List<ProjectDetailVO.TimelineInfo> timelineVOList = timelines.stream()
|
||||||
|
.map(timeline -> {
|
||||||
|
ProjectDetailVO.TimelineInfo timelineInfo = new ProjectDetailVO.TimelineInfo();
|
||||||
|
timelineInfo.setId(timeline.getId());
|
||||||
|
timelineInfo.setNodeName(timeline.getNodeName());
|
||||||
|
timelineInfo.setNodeType(timeline.getNodeType());
|
||||||
|
timelineInfo.setPlanDate(timeline.getPlanDate());
|
||||||
|
timelineInfo.setActualDate(timeline.getActualDate());
|
||||||
|
timelineInfo.setDescription(timeline.getDescription());
|
||||||
|
timelineInfo.setStatus(timeline.getStatus());
|
||||||
|
timelineInfo.setSortOrder(timeline.getSortOrder());
|
||||||
|
timelineInfo.setKbScope(timeline.getKbScope());
|
||||||
|
return timelineInfo;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
detailVO.setTimelineNodes(timelineVOList);
|
||||||
|
|
||||||
|
return detailVO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user