feat(open-api): 新增对外开放接口及项目日报同步功能
- 新增项目日报表及其防重唯一索引,支持外部系统同步日报数据 - 添加项目日报实体类及对应 Mapper 和 XML 配置 - 新增对外开放接口控制器 OpenApiController,实现项目列表查询及日报同步接口 - 实现 OpenApiService 服务及其实现类,包含用户项目查询和日报防重同步逻辑 - 扩展 ProjectMapper,支持根据用户名查询用户关联项目列表 - 配置 SaToken 过滤白名单,放行 /api/open/** 路径无登录验证 - 引入 spring-boot-starter-validation 依赖,支持请求参数校验 - 创建数据传输对象 DailyReportSyncDTO,带参数校验注解 - 日志记录和异常处理增强,保证数据同步和查询的健壮性
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
package cn.yinlihupo.service.open.impl;
|
||||
|
||||
import cn.yinlihupo.common.exception.BusinessException;
|
||||
import cn.yinlihupo.domain.dto.DailyReportSyncDTO;
|
||||
import cn.yinlihupo.domain.entity.Project;
|
||||
import cn.yinlihupo.domain.entity.ProjectDailyReport;
|
||||
import cn.yinlihupo.domain.entity.SysUser;
|
||||
import cn.yinlihupo.domain.vo.OpenProjectVO;
|
||||
import cn.yinlihupo.mapper.ProjectDailyReportMapper;
|
||||
import cn.yinlihupo.mapper.ProjectMapper;
|
||||
import cn.yinlihupo.mapper.ProjectMemberMapper;
|
||||
import cn.yinlihupo.mapper.SysUserMapper;
|
||||
import cn.yinlihupo.service.open.OpenApiService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 开放接口服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class OpenApiServiceImpl implements OpenApiService {
|
||||
|
||||
private final SysUserMapper sysUserMapper;
|
||||
private final ProjectMapper projectMapper;
|
||||
private final ProjectMemberMapper projectMemberMapper;
|
||||
private final ProjectDailyReportMapper projectDailyReportMapper;
|
||||
|
||||
/**
|
||||
* 根据用户标识 (sys_user.username) 查询用户所在的项目列表
|
||||
*/
|
||||
@Override
|
||||
public List<OpenProjectVO> getProjectsByUserId(String userId) {
|
||||
if (!StringUtils.hasText(userId)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 1. 先验证用户是否存在
|
||||
SysUser user = sysUserMapper.selectByUsername(userId);
|
||||
if (user == null) {
|
||||
log.warn("[OpenApi] 用户不存在, username={}", userId);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 2. 联查用户所在的项目列表(通过 username 关联 sys_user -> project/project_member)
|
||||
List<Project> projects = projectMapper.selectProjectsByUsername(userId);
|
||||
if (projects == null || projects.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 3. 转换为 OpenProjectVO 并填充用户角色
|
||||
List<OpenProjectVO> result = new ArrayList<>();
|
||||
for (Project project : projects) {
|
||||
OpenProjectVO vo = new OpenProjectVO();
|
||||
vo.setId(project.getId());
|
||||
vo.setProjectCode(project.getProjectCode());
|
||||
vo.setProjectName(project.getProjectName());
|
||||
vo.setProjectType(project.getProjectType());
|
||||
vo.setStatus(project.getStatus());
|
||||
vo.setPriority(project.getPriority());
|
||||
vo.setPlanStartDate(project.getPlanStartDate());
|
||||
vo.setPlanEndDate(project.getPlanEndDate());
|
||||
vo.setProgress(project.getProgress());
|
||||
|
||||
// 4. 填充用户在该项目的角色
|
||||
if (project.getManagerId() != null && project.getManagerId().equals(user.getId())) {
|
||||
vo.setMyRole("manager");
|
||||
} else {
|
||||
String role = projectMemberMapper.selectRoleByUserAndProject(project.getId(), user.getId());
|
||||
vo.setMyRole(role);
|
||||
}
|
||||
result.add(vo);
|
||||
}
|
||||
|
||||
log.info("[OpenApi] 查询用户项目列表成功, username={}, 项目数={}", userId, result.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步日报数据到库(带防重设计)
|
||||
*/
|
||||
@Override
|
||||
public String syncDailyReport(DailyReportSyncDTO dto) {
|
||||
String username = dto.getUserId();
|
||||
|
||||
// 1. 校验用户是否存在
|
||||
SysUser user = sysUserMapper.selectByUsername(username);
|
||||
if (user == null) {
|
||||
log.warn("[OpenApi] 日报同步失败,用户不存在, username={}", username);
|
||||
throw new BusinessException("用户不存在: " + username);
|
||||
}
|
||||
|
||||
// 2. 校验项目是否存在
|
||||
Project project = projectMapper.selectById(dto.getProjectId());
|
||||
if (project == null || project.getDeleted() == 1) {
|
||||
log.warn("[OpenApi] 日报同步失败,项目不存在, projectId={}", dto.getProjectId());
|
||||
throw new BusinessException("项目不存在: " + dto.getProjectId());
|
||||
}
|
||||
|
||||
// 3. 防重检查:同一用户同一天同一项目只能提交一条日报
|
||||
int count = projectDailyReportMapper.countByUniqueKey(
|
||||
dto.getProjectId(), dto.getReportDate(), username);
|
||||
if (count > 0) {
|
||||
log.warn("[OpenApi] 日报重复提交, projectId={}, reportDate={}, username={}",
|
||||
dto.getProjectId(), dto.getReportDate(), username);
|
||||
throw new BusinessException("日报已提交,请勿重复提交(项目ID: "
|
||||
+ dto.getProjectId() + ",日期: " + dto.getReportDate() + ")");
|
||||
}
|
||||
|
||||
// 4. 入库保存
|
||||
ProjectDailyReport report = new ProjectDailyReport();
|
||||
report.setProjectId(dto.getProjectId());
|
||||
report.setSubmitterUsername(username);
|
||||
report.setSubmitterId(user.getId());
|
||||
report.setReportDate(dto.getReportDate());
|
||||
report.setWorkContent(dto.getWorkContent());
|
||||
report.setTomorrowPlan(dto.getTomorrowPlan());
|
||||
report.setWorkIntensity(dto.getWorkIntensity());
|
||||
report.setNeedHelp(dto.getNeedHelp());
|
||||
report.setHelpContent(dto.getHelpContent());
|
||||
|
||||
projectDailyReportMapper.insert(report);
|
||||
|
||||
log.info("[OpenApi] 日报同步成功, projectId={}, reportDate={}, username={}",
|
||||
dto.getProjectId(), dto.getReportDate(), username);
|
||||
return "日报同步成功";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user