feat(project): 实现AI项目初始化及查询功能

- 新增ProjectService接口及实现,实现基于AI解析项目文档生成结构化项目数据
- 使用聊天机器人接口和OSS服务支持文件内容读取与AI解析
- 实现项目基本信息、里程碑、任务、成员、资源、风险及时间节点的持久化保存
- 支持任务层级关系和依赖关系的存储与管理
- 提供项目列表、项目详情、项目甘特图及项目统计接口
- 项目列表支持管理员与普通用户视角不同的数据访问权限
- 统计功能覆盖项目状态分布、本月新增、即将到期、平均进度及高风险项目数
- 项目编号自动生成,状态初始化为规划中
- 采用分页查询支持大数据量高效访问
This commit is contained in:
2026-03-28 18:53:36 +08:00
parent 32bff3aabc
commit cd56e2e987
4 changed files with 965 additions and 0 deletions

View File

@@ -1,6 +1,7 @@
package cn.yinlihupo.service.project;
import cn.yinlihupo.common.page.TableDataInfo;
import cn.yinlihupo.domain.vo.ProjectDetailVO;
import cn.yinlihupo.domain.vo.ProjectGanttVO;
import cn.yinlihupo.domain.vo.ProjectInitResult;
import cn.yinlihupo.domain.vo.ProjectListVO;
@@ -90,4 +91,12 @@ public interface ProjectService {
*/
TableDataInfo<ProjectListVO> getAllProjectList(Integer pageNum, Integer pageSize,
String keyword, String status);
/**
* 获取项目详情(全量信息)
*
* @param projectId 项目ID
* @return 项目详情
*/
ProjectDetailVO getProjectDetail(Long projectId);
}

View File

@@ -45,6 +45,7 @@ public class ProjectServiceImpl implements ProjectService {
private final ResourceMapper resourceMapper;
private final RiskMapper riskMapper;
private final ProjectTimelineMapper projectTimelineMapper;
private final SysUserMapper sysUserMapper;
/**
* 项目初始化系统提示词模板
@@ -825,4 +826,289 @@ public class ProjectServiceImpl implements ProjectService {
vo.setSortOrder(task.getSortOrder());
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;
}
}