feat(project): 添加项目查询相关接口与功能
- 新增ProjectQueryController,提供项目列表、甘特图和统计接口 - 支持管理员和普通用户分别查询对应项目数据 - 新增GanttTaskVO、ProjectGanttVO、ProjectListVO和ProjectStatisticsVO数据模型 - ProjectService接口扩展项目查询相关方法定义 - 实现ProjectServiceImpl中项目列表、甘特图、统计信息的业务逻辑 - 项目查询支持分页、关键词和状态筛选 - 甘特图数据包含任务和里程碑详细信息 - 项目统计包括总数、状态分布、本月新增、即将到期和风险统计 - FeishuAuthServiceImpl中新增新用户自动分配“普通成员”角色功能 - 修改开发环境配置,更新Chat模型为google/gemini-3.1-pro-preview
This commit is contained in:
@@ -1,28 +1,28 @@
|
||||
package cn.yinlihupo.service.project.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.yinlihupo.common.page.TableDataInfo;
|
||||
import cn.yinlihupo.domain.entity.*;
|
||||
import cn.yinlihupo.domain.vo.ProjectInitResult;
|
||||
import cn.yinlihupo.domain.vo.*;
|
||||
import cn.yinlihupo.mapper.*;
|
||||
import cn.yinlihupo.service.oss.OssService;
|
||||
import cn.yinlihupo.service.project.ProjectService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.ai.chat.client.ChatClient;
|
||||
import org.springframework.ai.chat.metadata.Usage;
|
||||
import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.time.YearMonth;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* AI项目初始化服务实现类
|
||||
@@ -551,4 +551,278 @@ public class ProjectServiceImpl implements ProjectService {
|
||||
timeline.setKbScope(info.getKbScope());
|
||||
return timeline;
|
||||
}
|
||||
|
||||
// ==================== 项目查询相关实现 ====================
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ProjectListVO> getMyProjectList(Long userId, Integer pageNum, Integer pageSize,
|
||||
String keyword, String status) {
|
||||
log.info("查询我的项目列表, userId: {}, pageNum: {}, pageSize: {}", userId, pageNum, pageSize);
|
||||
|
||||
// 使用分页插件
|
||||
Page<Project> page = new Page<>(pageNum, pageSize);
|
||||
|
||||
// 构建查询条件
|
||||
LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(Project::getDeleted, 0);
|
||||
|
||||
// 关键词搜索
|
||||
if (keyword != null && !keyword.isEmpty()) {
|
||||
wrapper.and(w -> w.like(Project::getProjectName, keyword)
|
||||
.or()
|
||||
.like(Project::getProjectCode, keyword));
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if (status != null && !status.isEmpty()) {
|
||||
wrapper.eq(Project::getStatus, status);
|
||||
}
|
||||
|
||||
// 查询我管理或参与的项目
|
||||
// 先查询我参与的项目ID列表
|
||||
List<Long> myProjectIds = projectMemberMapper.selectList(
|
||||
new LambdaQueryWrapper<ProjectMember>()
|
||||
.eq(ProjectMember::getUserId, userId)
|
||||
.eq(ProjectMember::getDeleted, 0)
|
||||
.eq(ProjectMember::getStatus, 1)
|
||||
).stream().map(ProjectMember::getProjectId).collect(Collectors.toList());
|
||||
|
||||
// 查询条件:我管理的项目 或 我参与的项目
|
||||
wrapper.and(w -> w.eq(Project::getManagerId, userId)
|
||||
.or()
|
||||
.in(!myProjectIds.isEmpty(), Project::getId, myProjectIds));
|
||||
|
||||
wrapper.orderByDesc(Project::getCreateTime);
|
||||
|
||||
Page<Project> projectPage = projectMapper.selectPage(page, wrapper);
|
||||
|
||||
// 转换为VO
|
||||
List<ProjectListVO> voList = projectPage.getRecords().stream()
|
||||
.map(this::convertToProjectListVO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return TableDataInfo.build(new Page<ProjectListVO>(projectPage.getCurrent(), projectPage.getSize(), projectPage.getTotal())
|
||||
.setRecords(voList));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectGanttVO getProjectGantt(Long projectId) {
|
||||
log.info("查询项目甘特图数据, projectId: {}", projectId);
|
||||
|
||||
// 1. 查询项目基本信息
|
||||
Project project = projectMapper.selectById(projectId);
|
||||
if (project == null || project.getDeleted() == 1) {
|
||||
throw new RuntimeException("项目不存在");
|
||||
}
|
||||
|
||||
ProjectGanttVO ganttVO = new ProjectGanttVO();
|
||||
ganttVO.setProjectId(project.getId());
|
||||
ganttVO.setProjectName(project.getProjectName());
|
||||
ganttVO.setProjectStatus(project.getStatus());
|
||||
ganttVO.setProjectStartDate(project.getPlanStartDate());
|
||||
ganttVO.setProjectEndDate(project.getPlanEndDate());
|
||||
ganttVO.setProjectProgress(project.getProgress());
|
||||
|
||||
// 2. 查询里程碑
|
||||
List<ProjectMilestone> milestones = projectMilestoneMapper.selectList(
|
||||
new LambdaQueryWrapper<ProjectMilestone>()
|
||||
.eq(ProjectMilestone::getProjectId, projectId)
|
||||
.eq(ProjectMilestone::getDeleted, 0)
|
||||
.orderByAsc(ProjectMilestone::getSortOrder)
|
||||
);
|
||||
|
||||
List<GanttTaskVO> milestoneVOList = milestones.stream()
|
||||
.map(this::convertMilestoneToGanttTask)
|
||||
.collect(Collectors.toList());
|
||||
ganttVO.setMilestones(milestoneVOList);
|
||||
|
||||
// 3. 查询任务
|
||||
List<Task> tasks = taskMapper.selectList(
|
||||
new LambdaQueryWrapper<Task>()
|
||||
.eq(Task::getProjectId, projectId)
|
||||
.eq(Task::getDeleted, 0)
|
||||
.orderByAsc(Task::getSortOrder)
|
||||
);
|
||||
|
||||
List<GanttTaskVO> taskVOList = tasks.stream()
|
||||
.map(this::convertTaskToGanttTask)
|
||||
.collect(Collectors.toList());
|
||||
ganttVO.setTasks(taskVOList);
|
||||
|
||||
return ganttVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectStatisticsVO getProjectStatistics(Long userId) {
|
||||
log.info("查询项目统计信息, userId: {}", userId);
|
||||
|
||||
ProjectStatisticsVO statistics = new ProjectStatisticsVO();
|
||||
|
||||
// 构建基础查询条件
|
||||
LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(Project::getDeleted, 0);
|
||||
|
||||
// 如果指定了用户ID,只统计该用户的项目
|
||||
if (userId != null) {
|
||||
List<Long> myProjectIds = projectMemberMapper.selectList(
|
||||
new LambdaQueryWrapper<ProjectMember>()
|
||||
.eq(ProjectMember::getUserId, userId)
|
||||
.eq(ProjectMember::getDeleted, 0)
|
||||
.eq(ProjectMember::getStatus, 1)
|
||||
).stream().map(ProjectMember::getProjectId).collect(Collectors.toList());
|
||||
|
||||
wrapper.and(w -> w.eq(Project::getManagerId, userId)
|
||||
.or()
|
||||
.in(!myProjectIds.isEmpty(), Project::getId, myProjectIds));
|
||||
}
|
||||
|
||||
// 1. 查询所有符合条件的项目
|
||||
List<Project> projects = projectMapper.selectList(wrapper);
|
||||
|
||||
// 2. 统计总数
|
||||
statistics.setTotalCount(projects.size());
|
||||
|
||||
// 3. 按状态统计
|
||||
Map<String, Integer> statusCountMap = projects.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
Project::getStatus,
|
||||
Collectors.collectingAndThen(Collectors.counting(), Long::intValue)
|
||||
));
|
||||
statistics.setStatusCountMap(statusCountMap);
|
||||
|
||||
// 设置各状态数量
|
||||
statistics.setDraftCount(statusCountMap.getOrDefault("draft", 0));
|
||||
statistics.setPlanningCount(statusCountMap.getOrDefault("planning", 0));
|
||||
statistics.setOngoingCount(statusCountMap.getOrDefault("ongoing", 0));
|
||||
statistics.setPausedCount(statusCountMap.getOrDefault("paused", 0));
|
||||
statistics.setCompletedCount(statusCountMap.getOrDefault("completed", 0));
|
||||
statistics.setCancelledCount(statusCountMap.getOrDefault("cancelled", 0));
|
||||
|
||||
// 4. 统计本月新增
|
||||
YearMonth thisMonth = YearMonth.now();
|
||||
int newThisMonth = (int) projects.stream()
|
||||
.filter(p -> p.getCreateTime() != null &&
|
||||
YearMonth.from(p.getCreateTime()).equals(thisMonth))
|
||||
.count();
|
||||
statistics.setNewThisMonth(newThisMonth);
|
||||
|
||||
// 5. 统计即将到期(7天内)
|
||||
LocalDate now = LocalDate.now();
|
||||
LocalDate sevenDaysLater = now.plusDays(7);
|
||||
int aboutToExpire = (int) projects.stream()
|
||||
.filter(p -> !"completed".equals(p.getStatus()) && !"cancelled".equals(p.getStatus()))
|
||||
.filter(p -> p.getPlanEndDate() != null &&
|
||||
!p.getPlanEndDate().isBefore(now) &&
|
||||
!p.getPlanEndDate().isAfter(sevenDaysLater))
|
||||
.count();
|
||||
statistics.setAboutToExpireCount(aboutToExpire);
|
||||
|
||||
// 6. 计算平均进度
|
||||
double avgProgress = projects.stream()
|
||||
.filter(p -> p.getProgress() != null)
|
||||
.mapToInt(Project::getProgress)
|
||||
.average()
|
||||
.orElse(0.0);
|
||||
statistics.setAverageProgress(BigDecimal.valueOf(avgProgress).setScale(2, RoundingMode.HALF_UP));
|
||||
|
||||
// 7. 统计高风险项目
|
||||
int highRiskCount = (int) projects.stream()
|
||||
.filter(p -> "high".equals(p.getRiskLevel()) || "critical".equals(p.getRiskLevel()))
|
||||
.count();
|
||||
statistics.setHighRiskCount(highRiskCount);
|
||||
|
||||
return statistics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ProjectListVO> getAllProjectList(Integer pageNum, Integer pageSize,
|
||||
String keyword, String status) {
|
||||
log.info("查询所有项目列表, pageNum: {}, pageSize: {}", pageNum, pageSize);
|
||||
|
||||
Page<Project> page = new Page<>(pageNum, pageSize);
|
||||
|
||||
LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(Project::getDeleted, 0);
|
||||
|
||||
if (keyword != null && !keyword.isEmpty()) {
|
||||
wrapper.and(w -> w.like(Project::getProjectName, keyword)
|
||||
.or()
|
||||
.like(Project::getProjectCode, keyword));
|
||||
}
|
||||
|
||||
if (status != null && !status.isEmpty()) {
|
||||
wrapper.eq(Project::getStatus, status);
|
||||
}
|
||||
|
||||
wrapper.orderByDesc(Project::getCreateTime);
|
||||
|
||||
Page<Project> projectPage = projectMapper.selectPage(page, wrapper);
|
||||
|
||||
List<ProjectListVO> voList = projectPage.getRecords().stream()
|
||||
.map(this::convertToProjectListVO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return TableDataInfo.build(new Page<ProjectListVO>(projectPage.getCurrent(), projectPage.getSize(), projectPage.getTotal())
|
||||
.setRecords(voList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为项目列表VO
|
||||
*/
|
||||
private ProjectListVO convertToProjectListVO(Project project) {
|
||||
ProjectListVO vo = new ProjectListVO();
|
||||
vo.setId(project.getId());
|
||||
vo.setProjectCode(project.getProjectCode());
|
||||
vo.setProjectName(project.getProjectName());
|
||||
vo.setProjectType(project.getProjectType());
|
||||
vo.setManagerId(project.getManagerId());
|
||||
vo.setPlanStartDate(project.getPlanStartDate());
|
||||
vo.setPlanEndDate(project.getPlanEndDate());
|
||||
vo.setProgress(project.getProgress());
|
||||
vo.setStatus(project.getStatus());
|
||||
vo.setPriority(project.getPriority());
|
||||
vo.setRiskLevel(project.getRiskLevel());
|
||||
vo.setTags(project.getTags());
|
||||
vo.setBudget(project.getBudget());
|
||||
vo.setCost(project.getCost());
|
||||
vo.setCreateTime(project.getCreateTime());
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为甘特图任务VO(里程碑)
|
||||
*/
|
||||
private GanttTaskVO convertMilestoneToGanttTask(ProjectMilestone milestone) {
|
||||
GanttTaskVO vo = new GanttTaskVO();
|
||||
vo.setId(milestone.getId());
|
||||
vo.setTaskName(milestone.getMilestoneName());
|
||||
vo.setType("milestone");
|
||||
vo.setStartDate(milestone.getPlanDate());
|
||||
vo.setEndDate(milestone.getPlanDate());
|
||||
vo.setActualStartDate(milestone.getActualDate());
|
||||
vo.setActualEndDate(milestone.getActualDate());
|
||||
vo.setProgress(milestone.getProgress());
|
||||
vo.setStatus(milestone.getStatus());
|
||||
vo.setSortOrder(milestone.getSortOrder());
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为甘特图任务VO(任务)
|
||||
*/
|
||||
private GanttTaskVO convertTaskToGanttTask(Task task) {
|
||||
GanttTaskVO vo = new GanttTaskVO();
|
||||
vo.setId(task.getId());
|
||||
vo.setTaskName(task.getTaskName());
|
||||
vo.setType("task");
|
||||
vo.setStartDate(task.getPlanStartDate());
|
||||
vo.setEndDate(task.getPlanEndDate());
|
||||
vo.setActualStartDate(task.getActualStartDate());
|
||||
vo.setActualEndDate(task.getActualEndDate());
|
||||
vo.setProgress(task.getProgress());
|
||||
vo.setStatus(task.getStatus());
|
||||
vo.setPriority(task.getPriority());
|
||||
vo.setSortOrder(task.getSortOrder());
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user