# Conflicts:
#	core/src/main/java/com/dite/znpt/domain/entity/ProjectBudgetInfoEntity.java
#	core/src/main/java/com/dite/znpt/domain/vo/ProjectBudgetInfoReq.java
#	core/src/main/java/com/dite/znpt/domain/vo/ProjectBudgetInfoResp.java
#	core/src/main/java/com/dite/znpt/service/impl/ProjectBudgetInfoServiceImpl.java
#	core/src/main/resources/mapper/ProjectBudgetInfoMapper.xml
#	web/src/main/java/com/dite/znpt/web/controller/PostController.java
This commit is contained in:
郝彬 2025-08-06 16:50:51 +08:00
commit 14ee89c4af
13 changed files with 261 additions and 17 deletions

View File

@ -32,6 +32,10 @@ public class PostEntity extends AuditableEntity implements Serializable {
@TableId(value = "post_id", type = IdType.ASSIGN_UUID)
private String postId;
@ApiModelProperty("部门id")
@TableField("dept_id")
private String deptId;
@ApiModelProperty("岗位名称")
@TableField("post_name")
private String postName;

View File

@ -0,0 +1,29 @@
package com.dite.znpt.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author Bear.G
* @date 2025/8/6/周三 14:37
* @description
*/
@Data
@ApiModel("项目预算信息列表请求实体")
public class PostListReq implements Serializable {
@Serial
private static final long serialVersionUID = -3911963210474319099L;
@ApiModelProperty("岗位名称")
private String postName;
@ApiModelProperty("部门id")
private String deptId;
@ApiModelProperty("是否包含部门子节点")
private Boolean includeDeptChildren;
}

View File

@ -22,6 +22,10 @@ public class PostReq implements Serializable {
@Serial
private static final long serialVersionUID = -149328762675637911L;
@ApiModelProperty("部门id")
@NotBlank(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "部门id不能为空")
private String deptId;
@NotBlank(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "岗位名称不能为空")
@Size(max = 30, groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "岗位名称长度不能超过30个字符")
@ApiModelProperty("岗位名称")

View File

@ -24,6 +24,12 @@ public class PostResp implements Serializable {
@ApiModelProperty("岗位id")
private String postId;
@ApiModelProperty("部门id")
private String deptId;
@ApiModelProperty("部门名称")
private String deptName;
@ApiModelProperty("岗位名称")
private String postName;

View File

@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
@ -70,12 +71,31 @@ public class ProjectDetailResp {
@ApiModelProperty("结束时间")
private LocalDate endDate;
@ApiModelProperty("计划开始时间")
private LocalDate plannedStartDate;
@ApiModelProperty("创建时间")
private String createTime;
@ApiModelProperty("更新时间")
private String updateTime;
// 新增字段 - 对应前端ProjectCard接口
@ApiModelProperty("项目预算(万元)")
private BigDecimal budget;
@ApiModelProperty("项目经理")
private String manager;
@ApiModelProperty("团队规模")
private Integer teamSize;
@ApiModelProperty("准备进度百分比")
private Integer preparationProgress;
@ApiModelProperty("项目进度百分比")
private Integer progress;
// 项目人员信息从新关联表获取
@ApiModelProperty("项目人员列表")
private List<ProjectMemberResp> projectMembers;
@ -152,9 +172,6 @@ public class ProjectDetailResp {
@ApiModelProperty("预算名称")
private String budgetName;
@ApiModelProperty("预算类型")
private String budgetType;
@ApiModelProperty("预算金额(万元)")
private Double budgetAmount;

View File

@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
@ -71,6 +72,9 @@ public class ProjectKanbanDataResp {
@ApiModelProperty("结束时间")
private LocalDate endDate;
@ApiModelProperty("计划开始时间")
private LocalDate plannedStartDate;
@ApiModelProperty("项目经理")
private String projectManagerName;
@ -103,5 +107,67 @@ public class ProjectKanbanDataResp {
@ApiModelProperty("更新时间")
private String updateTime;
// 新增字段 - 对应前端ProjectCard接口
@ApiModelProperty("项目预算(万元)")
private BigDecimal budget;
@ApiModelProperty("项目经理")
private String manager;
@ApiModelProperty("团队规模")
private Integer teamSize;
@ApiModelProperty("准备进度百分比")
private Integer preparationProgress;
@ApiModelProperty("项目进度百分比")
private Integer progress;
@ApiModelProperty("团队成员列表")
private List<TeamMemberResp> teamMembers;
@Data
@ApiModel(value="TeamMemberResp对象", description="团队成员响应")
public static class TeamMemberResp {
@ApiModelProperty("成员ID")
private String memberId;
@ApiModelProperty("用户ID")
private String userId;
@ApiModelProperty("用户姓名")
private String userName;
@ApiModelProperty("用户账号")
private String userAccount;
@ApiModelProperty("用户头像")
private String userAvatar;
@ApiModelProperty("角色类型")
private String roleType;
@ApiModelProperty("角色类型描述")
private String roleTypeDesc;
@ApiModelProperty("岗位代码")
private String jobCode;
@ApiModelProperty("岗位代码描述")
private String jobCodeDesc;
@ApiModelProperty("岗位描述")
private String jobDesc;
@ApiModelProperty("加入时间")
private LocalDate joinDate;
@ApiModelProperty("离开时间")
private LocalDate leaveDate;
@ApiModelProperty("状态")
private String status;
}
}
}

View File

@ -2,6 +2,10 @@ package com.dite.znpt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dite.znpt.domain.entity.PostEntity;
import com.dite.znpt.domain.vo.PostListReq;
import com.dite.znpt.domain.vo.PostResp;
import java.util.List;
/**
* @author Bear.G
@ -9,4 +13,6 @@ import com.dite.znpt.domain.entity.PostEntity;
* @description
*/
public interface PostMapper extends BaseMapper<PostEntity> {
List<PostResp> selectPostResp(PostListReq req);
}

View File

@ -2,6 +2,7 @@ package com.dite.znpt.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.dite.znpt.domain.entity.PostEntity;
import com.dite.znpt.domain.vo.PostListReq;
import com.dite.znpt.domain.vo.PostReq;
import com.dite.znpt.domain.vo.PostResp;
@ -14,9 +15,9 @@ import java.util.List;
*/
public interface PostService extends IService<PostEntity> {
List<PostResp> page(String postName);
List<PostResp> page(PostListReq req);
List<PostResp> list(String postName);
List<PostResp> list(PostListReq req);
PostResp detail(String postId);

View File

@ -5,16 +5,20 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dite.znpt.constant.Message;
import com.dite.znpt.converts.Converts;
import com.dite.znpt.domain.entity.DeptEntity;
import com.dite.znpt.domain.entity.PostEntity;
import com.dite.znpt.domain.vo.PostListReq;
import com.dite.znpt.domain.vo.PostReq;
import com.dite.znpt.domain.vo.PostResp;
import com.dite.znpt.exception.ServiceException;
import com.dite.znpt.mapper.DeptMapper;
import com.dite.znpt.mapper.PostMapper;
import com.dite.znpt.service.PostService;
import com.dite.znpt.util.PageUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
/**
@ -25,15 +29,18 @@ import java.util.List;
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, PostEntity> implements PostService {
@Resource
private DeptMapper deptMapper;
@Override
public List<PostResp> page(String postName) {
public List<PostResp> page(PostListReq req) {
PageUtil.startPage();
return this.list(postName);
return this.list(req);
}
@Override
public List<PostResp> list(String postName) {
return Converts.INSTANCE.toPostResp(this.list(Wrappers.lambdaQuery(PostEntity.class).like(StrUtil.isNotBlank(postName), PostEntity::getPostName, postName)));
public List<PostResp> list(PostListReq req) {
return this.baseMapper.selectPostResp(req);
}
@Override

View File

@ -19,6 +19,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@ -293,7 +294,51 @@ public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, P
resp.setStatusLabel(ProjectStatusEnum.getDescByCode(resp.getStatus()));
// 获取项目人员信息
resp.setProjectMembers(selectByProjectId(projectId));
List<ProjectMemberResp> projectMembers = selectByProjectId(projectId);
resp.setProjectMembers(projectMembers);
// 计算团队规模
resp.setTeamSize(projectMembers.size());
// 获取项目经理信息
String managerName = projectMembers.stream()
.filter(member -> "PROJECT_MANAGER".equals(member.getRoleType()))
.map(ProjectMemberResp::getUserName)
.findFirst()
.orElse("");
resp.setManager(managerName);
// 计算项目预算从预算信息中汇总
List<ProjectBudgetInfoEntity> budgets = projectBudgetInfoService.lambdaQuery()
.eq(ProjectBudgetInfoEntity::getProjectId, projectId)
.list();
BigDecimal totalBudget = budgets.stream()
.map(budget -> BigDecimal.valueOf(budget.getBudgetAmount()))
.reduce(BigDecimal.ZERO, BigDecimal::add);
resp.setBudget(totalBudget);
// 计算项目进度
List<ProjectTaskEntity> tasks = projectTaskService.lambdaQuery()
.eq(ProjectTaskEntity::getProjectId, projectId)
.list();
if (!tasks.isEmpty()) {
long completedTasks = tasks.stream()
.filter(task -> task.getStatus() != null && task.getStatus() == 2)
.count();
resp.setProgress((int) (completedTasks * 100 / tasks.size()));
} else {
resp.setProgress(0);
}
// 计算准备进度基于任务状态
if (!tasks.isEmpty()) {
long preparedTasks = tasks.stream()
.filter(task -> task.getStatus() != null && task.getStatus() >= 1)
.count();
resp.setPreparationProgress((int) (preparedTasks * 100 / tasks.size()));
} else {
resp.setPreparationProgress(0);
}
// 获取项目机组信息
List<TurbineEntity> turbines = turbineService.lambdaQuery()
@ -307,9 +352,6 @@ public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, P
}).collect(Collectors.toList()));
// 获取项目任务信息
List<ProjectTaskEntity> tasks = projectTaskService.lambdaQuery()
.eq(ProjectTaskEntity::getProjectId, projectId)
.list();
resp.setTasks(tasks.stream().map(task -> {
ProjectDetailResp.TaskInfo info = new ProjectDetailResp.TaskInfo();
BeanUtil.copyProperties(task, info);
@ -318,9 +360,6 @@ public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, P
}).collect(Collectors.toList()));
// 获取项目预算信息
List<ProjectBudgetInfoEntity> budgets = projectBudgetInfoService.lambdaQuery()
.eq(ProjectBudgetInfoEntity::getProjectId, projectId)
.list();
resp.setBudgets(budgets.stream().map(budget -> {
ProjectDetailResp.BudgetInfo info = new ProjectDetailResp.BudgetInfo();
BeanUtil.copyProperties(budget, info);
@ -381,6 +420,22 @@ public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, P
item.setConstructionTeamLeaderName(memberNames.get("TEAM_LEADER"));
item.setConstructorNames(memberNames.get("CONSTRUCTOR"));
// 设置项目经理
item.setManager(memberNames.get("PROJECT_MANAGER"));
// 设置团队规模
item.setTeamSize(members.size());
// 转换为团队成员列表
List<ProjectKanbanDataResp.ProjectKanbanItem.TeamMemberResp> teamMembers = members.stream()
.map(member -> {
ProjectKanbanDataResp.ProjectKanbanItem.TeamMemberResp teamMember = new ProjectKanbanDataResp.ProjectKanbanItem.TeamMemberResp();
BeanUtil.copyProperties(member, teamMember);
return teamMember;
})
.collect(Collectors.toList());
item.setTeamMembers(teamMembers);
// 统计机组数量
Long turbineCount = turbineService.lambdaQuery()
.eq(TurbineEntity::getProjectId, project.getProjectId())
@ -403,10 +458,32 @@ public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, P
// 计算项目进度百分比
if (taskCount > 0) {
item.setProgressPercentage((int) (completedTaskCount * 100 / taskCount));
item.setProgress((int) (completedTaskCount * 100 / taskCount));
} else {
item.setProgressPercentage(0);
item.setProgress(0);
}
// 计算准备进度基于任务状态
if (taskCount > 0) {
Long preparedTasks = projectTaskService.lambdaQuery()
.eq(ProjectTaskEntity::getProjectId, project.getProjectId())
.ge(ProjectTaskEntity::getStatus, 1)
.count();
item.setPreparationProgress((int) (preparedTasks * 100 / taskCount));
} else {
item.setPreparationProgress(0);
}
// 计算项目预算从预算信息中汇总
List<ProjectBudgetInfoEntity> budgets = projectBudgetInfoService.lambdaQuery()
.eq(ProjectBudgetInfoEntity::getProjectId, project.getProjectId())
.list();
BigDecimal totalBudget = budgets.stream()
.map(budget -> BigDecimal.valueOf(budget.getBudgetAmount()))
.reduce(BigDecimal.ZERO, BigDecimal::add);
item.setBudget(totalBudget);
return item;
}).collect(Collectors.toList());
}

View File

@ -2,4 +2,30 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dite.znpt.mapper.PostMapper">
<select id="selectPostResp" resultType="com.dite.znpt.domain.vo.PostResp">
SELECT p.*, d.dept_name FROM post p
LEFT JOIN dept d ON p.dept_id = d.dept_id
<where>
<if test="postName != null and postName != ''">
AND p.post_name LIKE concat('%',#{postName}, '%')
</if>
<if test="deptId != null and deptId != ''">
<choose >
<when test="includeDeptChildren">
AND p.dept_id IN (
WITH RECURSIVE SubDepts AS (
SELECT * FROM dept WHERE del_flag = '0' AND dept_id = #{deptId}
UNION ALL
SELECT d.* FROM dept d INNER JOIN SubDepts sd ON d.parent_id = sd.dept_id WHERE d.del_flag = '0'
) SELECT dept_id FROM SubDepts
)
</when>
<otherwise>
AND p.dept_id = #{deptId}
</otherwise>
</choose>
AND d.del_flag = '0'
</if>
</where>
</select>
</mapper>

View File

@ -24,6 +24,7 @@ import java.util.List;
* @date 2025/08/05
* @Description: 项目人员管理Controller
*/
@Api(tags = "项目人员管理")
@RestController
@RequestMapping("/project-member")

View File

@ -30,7 +30,7 @@ spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://39.99.201.243:3306/test01?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
url: jdbc:mysql://39.99.201.243:3306/znpt_dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: BUw8YW6%@^8q
druid: