代码修改部分重新提交

This commit is contained in:
wangna0328 2025-08-05 20:31:52 +08:00
parent ec5cca1dab
commit ade816ab3f
19 changed files with 2155 additions and 5 deletions

View File

@ -91,24 +91,31 @@ public class ProjectEntity extends AuditableEntity implements Serializable {
@TableField("turbine_model") @TableField("turbine_model")
private String turbineModel; private String turbineModel;
@ApiModelProperty("施工人员id") // 人员管理已迁移到 project_member
// 以下字段保留用于向后兼容但建议使用 ProjectMemberService 进行人员管理
@ApiModelProperty("施工人员id已废弃请使用ProjectMemberService")
@TableField("constructor_ids") @TableField("constructor_ids")
@Deprecated
private String constructorIds; private String constructorIds;
@ApiModelProperty("安全员id") @ApiModelProperty("安全员id已废弃请使用ProjectMemberService")
@TableField("auditor_id") @TableField("auditor_id")
@Deprecated
private String auditorId; private String auditorId;
@ApiModelProperty("质量员id") @ApiModelProperty("质量员id已废弃请使用ProjectMemberService")
@TableField("quality_officer_id") @TableField("quality_officer_id")
@Deprecated
private String qualityOfficerId; private String qualityOfficerId;
@ApiModelProperty("项目经理id") @ApiModelProperty("项目经理id已废弃请使用ProjectMemberService")
@TableField("project_manager_id") @TableField("project_manager_id")
@Deprecated
private String projectManagerId; private String projectManagerId;
@ApiModelProperty("施工组长id") @ApiModelProperty("施工组长id已废弃请使用ProjectMemberService")
@TableField("construct_team_leader_id") @TableField("construct_team_leader_id")
@Deprecated
private String constructTeamLeaderId; private String constructTeamLeaderId;
@ApiModelProperty("技术方案图片,多个用逗号隔开") @ApiModelProperty("技术方案图片,多个用逗号隔开")

View File

@ -0,0 +1,99 @@
package com.dite.znpt.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.dite.znpt.domain.AuditableEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDate;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目人员关联表实体类
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("project_member")
@ApiModel(value="ProjectMemberEntity对象", description="项目人员关联表")
public class ProjectMemberEntity extends AuditableEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@ApiModelProperty("关联ID")
@TableId(value = "member_id", type = IdType.ASSIGN_UUID)
private String memberId;
@ApiModelProperty("项目ID")
@TableField("project_id")
private String projectId;
@ApiModelProperty("机组ID可选关联到具体机组")
@TableField("turbine_id")
private String turbineId;
@ApiModelProperty("任务组ID可选关联到具体任务组")
@TableField("task_group_id")
private String taskGroupId;
@ApiModelProperty("任务ID可选关联到具体任务")
@TableField("task_id")
private String taskId;
@ApiModelProperty("用户ID")
@TableField("user_id")
private String userId;
@ApiModelProperty("项目角色类型PROJECT_MANAGER-项目经理SAFETY_OFFICER-安全员QUALITY_OFFICER-质量员CONSTRUCTOR-施工人员TEAM_LEADER-施工组长")
@TableField("role_type")
private String roleType;
@ApiModelProperty("具体岗位代码GROUND_SERVICE-地勤DRIVER-司机ASCENDING-登高等)")
@TableField("job_code")
private String jobCode;
@ApiModelProperty("岗位描述")
@TableField("job_desc")
private String jobDesc;
@ApiModelProperty("加入时间")
@TableField("join_date")
private LocalDate joinDate;
@ApiModelProperty("离开时间")
@TableField("leave_date")
private LocalDate leaveDate;
@ApiModelProperty("状态ACTIVE-在职INACTIVE-离职SUSPENDED-暂停")
@TableField("status")
private String status;
@ApiModelProperty("备注")
@TableField("remark")
private String remark;
// 非数据库字段用于显示
@TableField(exist = false)
@ApiModelProperty("用户姓名")
private String userName;
@TableField(exist = false)
@ApiModelProperty("用户账号")
private String userAccount;
@TableField(exist = false)
@ApiModelProperty("角色类型描述")
private String roleTypeDesc;
@TableField(exist = false)
@ApiModelProperty("岗位代码描述")
private String jobCodeDesc;
}

View File

@ -0,0 +1,180 @@
package com.dite.znpt.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目详情响应VO
*/
@Data
@ApiModel(value="ProjectDetailResp对象", description="项目详情响应")
public class ProjectDetailResp {
@ApiModelProperty("项目ID")
private String projectId;
@ApiModelProperty("项目名称")
private String projectName;
@ApiModelProperty("项目封面")
private String coverUrl;
@ApiModelProperty("风场名称")
private String farmName;
@ApiModelProperty("风场地址")
private String farmAddress;
@ApiModelProperty("委托单位")
private String client;
@ApiModelProperty("委托单位联系人")
private String clientContact;
@ApiModelProperty("委托单位联系电话")
private String clientPhone;
@ApiModelProperty("检查单位")
private String inspectionUnit;
@ApiModelProperty("检查单位联系人")
private String inspectionContact;
@ApiModelProperty("检查单位联系电话")
private String inspectionPhone;
@ApiModelProperty("项目规模")
private String scale;
@ApiModelProperty("总工期(天数)")
private Integer duration;
@ApiModelProperty("风机型号")
private String turbineModel;
@ApiModelProperty("项目状态")
private Integer status;
@ApiModelProperty("项目状态描述")
private String statusLabel;
@ApiModelProperty("开始时间")
private LocalDate startDate;
@ApiModelProperty("结束时间")
private LocalDate endDate;
@ApiModelProperty("创建时间")
private String createTime;
@ApiModelProperty("更新时间")
private String updateTime;
// 项目人员信息从新关联表获取
@ApiModelProperty("项目人员列表")
private List<ProjectMemberResp> projectMembers;
// 项目机组信息
@ApiModelProperty("项目机组列表")
private List<TurbineInfo> turbines;
// 项目任务信息
@ApiModelProperty("项目任务列表")
private List<TaskInfo> tasks;
// 项目预算信息
@ApiModelProperty("项目预算列表")
private List<BudgetInfo> budgets;
// 项目日报信息
@ApiModelProperty("项目日报列表")
private List<DailyReportInfo> dailyReports;
@Data
@ApiModel(value="TurbineInfo对象", description="机组信息")
public static class TurbineInfo {
@ApiModelProperty("机组ID")
private String turbineId;
@ApiModelProperty("机组名称")
private String turbineName;
@ApiModelProperty("机组编码")
private String turbineCode;
@ApiModelProperty("机组状态")
private Integer status;
@ApiModelProperty("机组状态描述")
private String statusLabel;
}
@Data
@ApiModel(value="TaskInfo对象", description="任务信息")
public static class TaskInfo {
@ApiModelProperty("任务ID")
private String taskId;
@ApiModelProperty("任务名称")
private String taskName;
@ApiModelProperty("任务状态")
private Integer status;
@ApiModelProperty("任务状态描述")
private String statusLabel;
@ApiModelProperty("计划开始时间")
private LocalDate planStartDate;
@ApiModelProperty("计划结束时间")
private LocalDate planEndDate;
@ApiModelProperty("实际开始时间")
private LocalDate actualStartDate;
@ApiModelProperty("实际结束时间")
private LocalDate actualEndDate;
}
@Data
@ApiModel(value="BudgetInfo对象", description="预算信息")
public static class BudgetInfo {
@ApiModelProperty("预算ID")
private String budgetId;
@ApiModelProperty("预算名称")
private String budgetName;
@ApiModelProperty("预算类型")
private String budgetType;
@ApiModelProperty("预算金额(万元)")
private Double budgetAmount;
@ApiModelProperty("预算说明")
private String budgetDesc;
}
@Data
@ApiModel(value="DailyReportInfo对象", description="日报信息")
public static class DailyReportInfo {
@ApiModelProperty("日报ID")
private String reportId;
@ApiModelProperty("日报日期")
private LocalDate reportDate;
@ApiModelProperty("日报提交人")
private String submitUserName;
@ApiModelProperty("创建时间")
private String createTime;
}
}

View File

@ -0,0 +1,107 @@
package com.dite.znpt.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目看板数据响应VO
*/
@Data
@ApiModel(value="ProjectKanbanDataResp对象", description="项目看板数据响应")
public class ProjectKanbanDataResp {
@ApiModelProperty("待施工项目列表")
private List<ProjectKanbanItem> pendingProjects;
@ApiModelProperty("施工中项目列表")
private List<ProjectKanbanItem> inProgressProjects;
@ApiModelProperty("已完工项目列表")
private List<ProjectKanbanItem> completedProjects;
@ApiModelProperty("已审核项目列表")
private List<ProjectKanbanItem> auditedProjects;
@ApiModelProperty("已验收项目列表")
private List<ProjectKanbanItem> acceptedProjects;
@Data
@ApiModel(value="ProjectKanbanItem对象", description="项目看板项目项")
public static class ProjectKanbanItem {
@ApiModelProperty("项目ID")
private String projectId;
@ApiModelProperty("项目名称")
private String projectName;
@ApiModelProperty("项目封面")
private String coverUrl;
@ApiModelProperty("风场名称")
private String farmName;
@ApiModelProperty("风场地址")
private String farmAddress;
@ApiModelProperty("项目规模")
private String scale;
@ApiModelProperty("总工期(天数)")
private Integer duration;
@ApiModelProperty("风机型号")
private String turbineModel;
@ApiModelProperty("项目状态")
private Integer status;
@ApiModelProperty("项目状态描述")
private String statusLabel;
@ApiModelProperty("开始时间")
private LocalDate startDate;
@ApiModelProperty("结束时间")
private LocalDate endDate;
@ApiModelProperty("项目经理")
private String projectManagerName;
@ApiModelProperty("安全员")
private String safetyOfficerName;
@ApiModelProperty("质量员")
private String qualityOfficerName;
@ApiModelProperty("施工组长")
private String constructionTeamLeaderName;
@ApiModelProperty("施工人员")
private String constructorNames;
@ApiModelProperty("机组数量")
private Long turbineCount;
@ApiModelProperty("任务数量")
private Long taskCount;
@ApiModelProperty("已完成任务数量")
private Long completedTaskCount;
@ApiModelProperty("项目进度百分比")
private Integer progressPercentage;
@ApiModelProperty("创建时间")
private String createTime;
@ApiModelProperty("更新时间")
private String updateTime;
}
}

View File

@ -0,0 +1,81 @@
package com.dite.znpt.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目看板统计数据响应VO
*/
@Data
@ApiModel(value="ProjectKanbanStatsResp对象", description="项目看板统计数据响应")
public class ProjectKanbanStatsResp {
@ApiModelProperty("总项目数")
private Long totalProjectsCount;
@ApiModelProperty("待施工项目数")
private Long pendingProjectCount;
@ApiModelProperty("施工中项目数")
private Long inProgressProjectCount;
@ApiModelProperty("已完工项目数")
private Long completedProjectCount;
@ApiModelProperty("已审核项目数")
private Long auditedProjectCount;
@ApiModelProperty("已验收项目数")
private Long acceptedProjectCount;
@ApiModelProperty("总机组数")
private Long totalTurbineCount;
@ApiModelProperty("待施工机组数")
private Long pendingTurbineCount;
@ApiModelProperty("施工中机组数")
private Long inProgressTurbineCount;
@ApiModelProperty("已完工机组数")
private Long completedTurbineCount;
@ApiModelProperty("已审核机组数")
private Long auditedTurbineCount;
@ApiModelProperty("已验收机组数")
private Long acceptedTurbineCount;
@ApiModelProperty("总任务数")
private Long totalTaskCount;
@ApiModelProperty("未开始任务数")
private Long pendingTaskCount;
@ApiModelProperty("进行中任务数")
private Long inProgressTaskCount;
@ApiModelProperty("已完成任务数")
private Long completedTaskCount;
@ApiModelProperty("总人员数")
private Long totalMemberCount;
@ApiModelProperty("项目经理数")
private Long projectManagerCount;
@ApiModelProperty("安全员数")
private Long safetyOfficerCount;
@ApiModelProperty("质量员数")
private Long qualityOfficerCount;
@ApiModelProperty("施工人员数")
private Long constructorCount;
@ApiModelProperty("施工组长数")
private Long teamLeaderCount;
}

View File

@ -0,0 +1,45 @@
package com.dite.znpt.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目人员查询请求VO
*/
@Data
@ApiModel(value="ProjectMemberListReq对象", description="项目人员查询请求")
public class ProjectMemberListReq {
@ApiModelProperty("项目ID")
private String projectId;
@ApiModelProperty("机组ID")
private String turbineId;
@ApiModelProperty("任务组ID")
private String taskGroupId;
@ApiModelProperty("任务ID")
private String taskId;
@ApiModelProperty("用户ID")
private String userId;
@ApiModelProperty("角色类型")
private String roleType;
@ApiModelProperty("岗位代码")
private String jobCode;
@ApiModelProperty("状态")
private String status;
@ApiModelProperty("用户姓名(模糊查询)")
private String userName;
@ApiModelProperty("用户账号(模糊查询)")
private String userAccount;
}

View File

@ -0,0 +1,62 @@
package com.dite.znpt.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目人员请求VO
*/
@Data
@ApiModel(value="ProjectMemberReq对象", description="项目人员请求")
public class ProjectMemberReq {
@ApiModelProperty("关联ID更新时必填")
private String memberId;
@NotBlank(message = "项目ID不能为空")
@ApiModelProperty("项目ID")
private String projectId;
@ApiModelProperty("机组ID可选")
private String turbineId;
@ApiModelProperty("任务组ID可选")
private String taskGroupId;
@ApiModelProperty("任务ID可选")
private String taskId;
@NotBlank(message = "用户ID不能为空")
@ApiModelProperty("用户ID")
private String userId;
@NotBlank(message = "角色类型不能为空")
@ApiModelProperty("角色类型")
private String roleType;
@ApiModelProperty("岗位代码")
private String jobCode;
@ApiModelProperty("岗位描述")
private String jobDesc;
@NotNull(message = "加入时间不能为空")
@ApiModelProperty("加入时间")
private LocalDate joinDate;
@ApiModelProperty("离开时间")
private LocalDate leaveDate;
@ApiModelProperty("状态")
private String status;
@ApiModelProperty("备注")
private String remark;
}

View File

@ -0,0 +1,83 @@
package com.dite.znpt.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDate;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目人员响应VO
*/
@Data
@ApiModel(value="ProjectMemberResp对象", description="项目人员响应")
public class ProjectMemberResp {
@ApiModelProperty("关联ID")
private String memberId;
@ApiModelProperty("项目ID")
private String projectId;
@ApiModelProperty("项目名称")
private String projectName;
@ApiModelProperty("机组ID")
private String turbineId;
@ApiModelProperty("机组名称")
private String turbineName;
@ApiModelProperty("任务组ID")
private String taskGroupId;
@ApiModelProperty("任务组名称")
private String taskGroupName;
@ApiModelProperty("任务ID")
private String taskId;
@ApiModelProperty("任务名称")
private String taskName;
@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;
@ApiModelProperty("备注")
private String remark;
}

View File

@ -0,0 +1,72 @@
package com.dite.znpt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目岗位代码枚举
*/
@Getter
@AllArgsConstructor
public enum ProjectJobCodeEnum {
// 地勤相关岗位
GROUND_SERVICE("GROUND_SERVICE", "地勤"),
GROUND_SERVICE_LEADER("GROUND_SERVICE_LEADER", "地勤组长"),
// 司机相关岗位
DRIVER("DRIVER", "司机"),
DRIVER_LEADER("DRIVER_LEADER", "司机组长"),
// 登高相关岗位
ASCENDING("ASCENDING", "登高"),
ASCENDING_LEADER("ASCENDING_LEADER", "登高组长"),
// 防雷相关岗位
ANTI_THUNDER("ANTI_THUNDER", "防雷"),
ANTI_THUNDER_LEADER("ANTI_THUNDER_LEADER", "防雷组长"),
// 外部工作相关岗位
OUT_WORK("OUT_WORK", "外部工作"),
OUT_WORK_LEADER("OUT_WORK_LEADER", "外部工作组长"),
// 管理岗位
PROJECT_MANAGER("PROJECT_MANAGER", "项目经理"),
SAFETY_MANAGER("SAFETY_MANAGER", "安全经理"),
QUALITY_MANAGER("QUALITY_MANAGER", "质量经理"),
SITE_MANAGER("SITE_MANAGER", "现场经理"),
// 其他岗位
TECHNICIAN("TECHNICIAN", "技术员"),
SUPERVISOR("SUPERVISOR", "监理"),
COORDINATOR("COORDINATOR", "协调员");
private final String code;
private final String desc;
/**
* 根据代码获取描述
*/
public static String getDescByCode(String code) {
for (ProjectJobCodeEnum jobCode : values()) {
if (jobCode.getCode().equals(code)) {
return jobCode.getDesc();
}
}
return "";
}
/**
* 根据代码获取枚举
*/
public static ProjectJobCodeEnum getByCode(String code) {
for (ProjectJobCodeEnum jobCode : values()) {
if (jobCode.getCode().equals(code)) {
return jobCode;
}
}
return null;
}
}

View File

@ -0,0 +1,53 @@
package com.dite.znpt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目角色类型枚举
*/
@Getter
@AllArgsConstructor
public enum ProjectRoleTypeEnum {
PROJECT_MANAGER("PROJECT_MANAGER", "项目经理"),
SAFETY_OFFICER("SAFETY_OFFICER", "安全员"),
QUALITY_OFFICER("QUALITY_OFFICER", "质量员"),
CONSTRUCTOR("CONSTRUCTOR", "施工人员"),
TEAM_LEADER("TEAM_LEADER", "施工组长"),
SENIOR_PROJECT_MANAGER("SENIOR_PROJECT_MANAGER", "大项目经理"),
REMOTE_ADVISOR("REMOTE_ADVISOR", "项目远程顾问"),
EXTERNAL_COLLABORATOR("EXTERNAL_COLLABORATOR", "外部协作者"),
FINANCIAL_MANAGER("FINANCIAL_MANAGER", "财务经理"),
BUSINESS_MANAGER("BUSINESS_MANAGER", "商务经理"),
SITE_MANAGER("SITE_MANAGER", "现场经理");
private final String code;
private final String desc;
/**
* 根据代码获取描述
*/
public static String getDescByCode(String code) {
for (ProjectRoleTypeEnum roleType : values()) {
if (roleType.getCode().equals(code)) {
return roleType.getDesc();
}
}
return "";
}
/**
* 根据代码获取枚举
*/
public static ProjectRoleTypeEnum getByCode(String code) {
for (ProjectRoleTypeEnum roleType : values()) {
if (roleType.getCode().equals(code)) {
return roleType;
}
}
return null;
}
}

View File

@ -0,0 +1,54 @@
package com.dite.znpt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dite.znpt.domain.entity.ProjectMemberEntity;
import com.dite.znpt.domain.vo.ProjectMemberListReq;
import com.dite.znpt.domain.vo.ProjectMemberResp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目人员关联表Mapper接口
*/
@Mapper
public interface ProjectMemberMapper extends BaseMapper<ProjectMemberEntity> {
/**
* 根据条件查询项目人员列表
*/
List<ProjectMemberResp> queryBySelective(ProjectMemberListReq req);
/**
* 根据项目ID查询项目人员列表
*/
List<ProjectMemberResp> queryByProjectId(@Param("projectId") String projectId);
/**
* 根据机组ID查询机组人员列表
*/
List<ProjectMemberResp> queryByTurbineId(@Param("turbineId") String turbineId);
/**
* 根据任务组ID查询任务组人员列表
*/
List<ProjectMemberResp> queryByTaskGroupId(@Param("taskGroupId") String taskGroupId);
/**
* 根据任务ID查询任务人员列表
*/
List<ProjectMemberResp> queryByTaskId(@Param("taskId") String taskId);
/**
* 根据用户ID查询用户参与的项目列表
*/
List<ProjectMemberResp> queryByUserId(@Param("userId") String userId);
/**
* 根据项目ID和角色类型查询人员列表
*/
List<ProjectMemberResp> queryByProjectIdAndRoleType(@Param("projectId") String projectId, @Param("roleType") String roleType);
}

View File

@ -0,0 +1,107 @@
package com.dite.znpt.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.dite.znpt.domain.entity.ProjectMemberEntity;
import com.dite.znpt.domain.vo.*;
import java.util.List;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目人员关联表服务接口
*/
public interface ProjectMemberService extends IService<ProjectMemberEntity> {
/**
* 查询项目人员列表
*/
List<ProjectMemberResp> selectList(ProjectMemberListReq req);
/**
* 根据项目ID查询项目人员列表
*/
List<ProjectMemberResp> selectByProjectId(String projectId);
/**
* 根据机组ID查询机组人员列表
*/
List<ProjectMemberResp> selectByTurbineId(String turbineId);
/**
* 根据任务组ID查询任务组人员列表
*/
List<ProjectMemberResp> selectByTaskGroupId(String taskGroupId);
/**
* 根据任务ID查询任务人员列表
*/
List<ProjectMemberResp> selectByTaskId(String taskId);
/**
* 根据用户ID查询用户参与的项目列表
*/
List<ProjectMemberResp> selectByUserId(String userId);
/**
* 根据项目ID和角色类型查询人员列表
*/
List<ProjectMemberResp> selectByProjectIdAndRoleType(String projectId, String roleType);
/**
* 新增项目人员
*/
void saveData(ProjectMemberReq req);
/**
* 更新项目人员
*/
void updateData(ProjectMemberReq req);
/**
* 删除项目人员
*/
void deleteById(String memberId);
/**
* 批量添加项目人员
*/
void batchAddMembers(List<ProjectMemberReq> reqList);
/**
* 根据项目ID删除所有项目人员
*/
void deleteByProjectId(String projectId);
/**
* 根据机组ID删除所有机组人员
*/
void deleteByTurbineId(String turbineId);
/**
* 根据任务组ID删除所有任务组人员
*/
void deleteByTaskGroupId(String taskGroupId);
/**
* 根据任务ID删除所有任务人员
*/
void deleteByTaskId(String taskId);
// ========================== 项目看板相关方法 ==========================
/**
* 获取项目看板统计数据
*/
ProjectKanbanStatsResp getProjectKanbanStats();
/**
* 获取项目看板数据
*/
ProjectKanbanDataResp getProjectKanbanData();
/**
* 获取项目详情
*/
ProjectDetailResp getProjectDetail(String projectId);
}

View File

@ -0,0 +1,431 @@
package com.dite.znpt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dite.znpt.constant.Message;
import com.dite.znpt.domain.entity.ProjectMemberEntity;
import com.dite.znpt.domain.entity.UserEntity;
import com.dite.znpt.domain.entity.ProjectEntity;
import com.dite.znpt.domain.entity.TurbineEntity;
import com.dite.znpt.domain.entity.ProjectTaskEntity;
import com.dite.znpt.domain.entity.ProjectBudgetInfoEntity;
import com.dite.znpt.domain.entity.ProjectDailyReportEntity;
import com.dite.znpt.domain.vo.ProjectMemberListReq;
import com.dite.znpt.domain.vo.ProjectMemberReq;
import com.dite.znpt.domain.vo.ProjectMemberResp;
import com.dite.znpt.domain.vo.ProjectKanbanStatsResp;
import com.dite.znpt.domain.vo.ProjectKanbanDataResp;
import com.dite.znpt.domain.vo.ProjectDetailResp;
import com.dite.znpt.enums.ProjectJobCodeEnum;
import com.dite.znpt.enums.ProjectRoleTypeEnum;
import com.dite.znpt.enums.ProjectStatusEnum;
import com.dite.znpt.enums.ProjectTaskStateEnum;
import com.dite.znpt.exception.ServiceException;
import com.dite.znpt.mapper.ProjectMemberMapper;
import com.dite.znpt.service.ProjectMemberService;
import com.dite.znpt.service.UserService;
import com.dite.znpt.service.ProjectService;
import com.dite.znpt.service.TurbineService;
import com.dite.znpt.service.ProjectTaskService;
import com.dite.znpt.service.ProjectBudgetInfoService;
import com.dite.znpt.service.ProjectDailyReportService;
import com.dite.znpt.util.PageUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目人员关联表服务实现类
*/
@Service
@RequiredArgsConstructor
public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, ProjectMemberEntity> implements ProjectMemberService {
private final UserService userService;
// 添加其他服务依赖
private final ProjectService projectService;
private final TurbineService turbineService;
private final ProjectTaskService projectTaskService;
private final ProjectBudgetInfoService projectBudgetInfoService;
private final ProjectDailyReportService projectDailyReportService;
@Override
public List<ProjectMemberResp> selectList(ProjectMemberListReq req) {
PageUtil.startPage();
List<ProjectMemberResp> list = this.baseMapper.queryBySelective(req);
enrichMemberInfo(list);
return list;
}
@Override
public List<ProjectMemberResp> selectByProjectId(String projectId) {
List<ProjectMemberResp> list = this.baseMapper.queryByProjectId(projectId);
enrichMemberInfo(list);
return list;
}
@Override
public List<ProjectMemberResp> selectByTurbineId(String turbineId) {
List<ProjectMemberResp> list = this.baseMapper.queryByTurbineId(turbineId);
enrichMemberInfo(list);
return list;
}
@Override
public List<ProjectMemberResp> selectByTaskGroupId(String taskGroupId) {
List<ProjectMemberResp> list = this.baseMapper.queryByTaskGroupId(taskGroupId);
enrichMemberInfo(list);
return list;
}
@Override
public List<ProjectMemberResp> selectByTaskId(String taskId) {
List<ProjectMemberResp> list = this.baseMapper.queryByTaskId(taskId);
enrichMemberInfo(list);
return list;
}
@Override
public List<ProjectMemberResp> selectByUserId(String userId) {
List<ProjectMemberResp> list = this.baseMapper.queryByUserId(userId);
enrichMemberInfo(list);
return list;
}
@Override
public List<ProjectMemberResp> selectByProjectIdAndRoleType(String projectId, String roleType) {
List<ProjectMemberResp> list = this.baseMapper.queryByProjectIdAndRoleType(projectId, roleType);
enrichMemberInfo(list);
return list;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void saveData(ProjectMemberReq req) {
// 验证用户是否存在
UserEntity user = userService.getById(req.getUserId());
if (user == null) {
throw new ServiceException(Message.USER_ID_NOT_EXIST_OR_ILLEGAL);
}
// 检查是否已存在相同的关联
boolean exists = lambdaQuery()
.eq(ProjectMemberEntity::getProjectId, req.getProjectId())
.eq(ProjectMemberEntity::getUserId, req.getUserId())
.eq(StrUtil.isNotEmpty(req.getTurbineId()), ProjectMemberEntity::getTurbineId, req.getTurbineId())
.eq(StrUtil.isNotEmpty(req.getTaskGroupId()), ProjectMemberEntity::getTaskGroupId, req.getTaskGroupId())
.eq(StrUtil.isNotEmpty(req.getTaskId()), ProjectMemberEntity::getTaskId, req.getTaskId())
.eq(ProjectMemberEntity::getRoleType, req.getRoleType())
.exists();
if (exists) {
throw new ServiceException("该用户在此项目中已存在相同角色");
}
ProjectMemberEntity entity = BeanUtil.copyProperties(req, ProjectMemberEntity.class);
if (StrUtil.isEmpty(entity.getStatus())) {
entity.setStatus("ACTIVE");
}
save(entity);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateData(ProjectMemberReq req) {
if (StrUtil.isEmpty(req.getMemberId())) {
throw new ServiceException("关联ID不能为空");
}
ProjectMemberEntity entity = getById(req.getMemberId());
if (entity == null) {
throw new ServiceException(Message.PROJECT_ID_IS_NOT_EXIST);
}
BeanUtil.copyProperties(req, entity);
updateById(entity);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteById(String memberId) {
removeById(memberId);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void batchAddMembers(List<ProjectMemberReq> reqList) {
if (CollUtil.isEmpty(reqList)) {
return;
}
for (ProjectMemberReq req : reqList) {
saveData(req);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteByProjectId(String projectId) {
lambdaUpdate()
.eq(ProjectMemberEntity::getProjectId, projectId)
.remove();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteByTurbineId(String turbineId) {
lambdaUpdate()
.eq(ProjectMemberEntity::getTurbineId, turbineId)
.remove();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteByTaskGroupId(String taskGroupId) {
lambdaUpdate()
.eq(ProjectMemberEntity::getTaskGroupId, taskGroupId)
.remove();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteByTaskId(String taskId) {
lambdaUpdate()
.eq(ProjectMemberEntity::getTaskId, taskId)
.remove();
}
/**
* 丰富成员信息用户信息角色描述岗位描述
*/
private void enrichMemberInfo(List<ProjectMemberResp> list) {
if (CollUtil.isEmpty(list)) {
return;
}
// 获取所有用户ID
List<String> userIds = list.stream()
.map(ProjectMemberResp::getUserId)
.distinct()
.collect(Collectors.toList());
// 查询用户信息
Map<String, UserEntity> userMap = userService.listByIds(userIds)
.stream()
.collect(Collectors.toMap(UserEntity::getUserId, Function.identity()));
// 填充用户信息和描述
list.forEach(member -> {
// 填充用户信息
UserEntity user = userMap.get(member.getUserId());
if (user != null) {
member.setUserName(user.getName());
member.setUserAccount(user.getAccount());
member.setUserAvatar(user.getAvatar());
}
// 填充角色类型描述
member.setRoleTypeDesc(ProjectRoleTypeEnum.getDescByCode(member.getRoleType()));
// 填充岗位代码描述
if (StrUtil.isNotEmpty(member.getJobCode())) {
member.setJobCodeDesc(ProjectJobCodeEnum.getDescByCode(member.getJobCode()));
}
});
}
// ========================== 项目看板相关方法实现 ==========================
@Override
public ProjectKanbanStatsResp getProjectKanbanStats() {
ProjectKanbanStatsResp resp = new ProjectKanbanStatsResp();
// 统计项目数量
resp.setTotalProjectsCount(projectService.count());
resp.setPendingProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 0).count());
resp.setInProgressProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 1).count());
resp.setCompletedProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 2).count());
resp.setAuditedProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 3).count());
resp.setAcceptedProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 4).count());
// 统计机组数量
resp.setTotalTurbineCount(turbineService.count());
resp.setPendingTurbineCount(turbineService.lambdaQuery().eq(TurbineEntity::getStatus, 0).count());
resp.setInProgressTurbineCount(turbineService.lambdaQuery().eq(TurbineEntity::getStatus, 1).count());
resp.setCompletedTurbineCount(turbineService.lambdaQuery().eq(TurbineEntity::getStatus, 2).count());
resp.setAuditedTurbineCount(turbineService.lambdaQuery().eq(TurbineEntity::getStatus, 3).count());
resp.setAcceptedTurbineCount(turbineService.lambdaQuery().eq(TurbineEntity::getStatus, 4).count());
// 统计任务数量
resp.setTotalTaskCount(projectTaskService.count());
resp.setPendingTaskCount(projectTaskService.lambdaQuery().eq(ProjectTaskEntity::getStatus, 0).count());
resp.setInProgressTaskCount(projectTaskService.lambdaQuery().eq(ProjectTaskEntity::getStatus, 1).count());
resp.setCompletedTaskCount(projectTaskService.lambdaQuery().eq(ProjectTaskEntity::getStatus, 2).count());
// 统计人员数量
resp.setTotalMemberCount(this.count());
resp.setProjectManagerCount(this.lambdaQuery().eq(ProjectMemberEntity::getRoleType, "PROJECT_MANAGER").count());
resp.setSafetyOfficerCount(this.lambdaQuery().eq(ProjectMemberEntity::getRoleType, "SAFETY_OFFICER").count());
resp.setQualityOfficerCount(this.lambdaQuery().eq(ProjectMemberEntity::getRoleType, "QUALITY_OFFICER").count());
resp.setConstructorCount(this.lambdaQuery().eq(ProjectMemberEntity::getRoleType, "CONSTRUCTOR").count());
resp.setTeamLeaderCount(this.lambdaQuery().eq(ProjectMemberEntity::getRoleType, "TEAM_LEADER").count());
return resp;
}
@Override
public ProjectKanbanDataResp getProjectKanbanData() {
ProjectKanbanDataResp resp = new ProjectKanbanDataResp();
// 获取各状态的项目列表
resp.setPendingProjects(getProjectKanbanItems(0));
resp.setInProgressProjects(getProjectKanbanItems(1));
resp.setCompletedProjects(getProjectKanbanItems(2));
resp.setAuditedProjects(getProjectKanbanItems(3));
resp.setAcceptedProjects(getProjectKanbanItems(4));
return resp;
}
@Override
public ProjectDetailResp getProjectDetail(String projectId) {
// 获取项目基本信息
ProjectEntity project = projectService.getById(projectId);
if (project == null) {
throw new ServiceException(Message.PROJECT_ID_IS_NOT_EXIST);
}
ProjectDetailResp resp = new ProjectDetailResp();
BeanUtil.copyProperties(project, resp);
resp.setStatusLabel(ProjectStatusEnum.getDescByCode(resp.getStatus()));
// 获取项目人员信息
resp.setProjectMembers(selectByProjectId(projectId));
// 获取项目机组信息
List<TurbineEntity> turbines = turbineService.lambdaQuery()
.eq(TurbineEntity::getProjectId, projectId)
.list();
resp.setTurbines(turbines.stream().map(turbine -> {
ProjectDetailResp.TurbineInfo info = new ProjectDetailResp.TurbineInfo();
BeanUtil.copyProperties(turbine, info);
info.setStatusLabel(ProjectStatusEnum.getDescByCode(info.getStatus()));
return info;
}).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);
info.setStatusLabel(ProjectTaskStateEnum.getDescByCode(info.getStatus()));
return info;
}).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);
return info;
}).collect(Collectors.toList()));
// 获取项目日报信息
List<ProjectDailyReportEntity> dailyReports = projectDailyReportService.lambdaQuery()
.eq(ProjectDailyReportEntity::getProjectId, projectId)
.orderByDesc(ProjectDailyReportEntity::getReportDate)
.last("LIMIT 10")
.list();
resp.setDailyReports(dailyReports.stream().map(report -> {
ProjectDetailResp.DailyReportInfo info = new ProjectDetailResp.DailyReportInfo();
BeanUtil.copyProperties(report, info);
// 获取提交人姓名
UserEntity user = userService.getById(report.getSubmitUser());
info.setSubmitUserName(user != null ? user.getName() : "");
return info;
}).collect(Collectors.toList()));
return resp;
}
/**
* 获取项目看板项目项列表
*/
private List<ProjectKanbanDataResp.ProjectKanbanItem> getProjectKanbanItems(Integer status) {
List<ProjectEntity> projects = projectService.lambdaQuery()
.eq(ProjectEntity::getStatus, status)
.orderByDesc(ProjectEntity::getCreateTime)
.list();
return projects.stream().map(project -> {
ProjectKanbanDataResp.ProjectKanbanItem item = new ProjectKanbanDataResp.ProjectKanbanItem();
BeanUtil.copyProperties(project, item);
item.setStatusLabel(ProjectStatusEnum.getDescByCode(item.getStatus()));
// 获取项目人员信息
List<ProjectMemberResp> members = selectByProjectId(project.getProjectId());
// 按角色类型分组并去重用户名
Map<String, String> memberNames = members.stream()
.collect(Collectors.groupingBy(
ProjectMemberResp::getRoleType,
Collectors.mapping(
ProjectMemberResp::getUserName,
Collectors.collectingAndThen(
Collectors.toSet(), // 使用Set去重
set -> String.join(",", set)
)
)
));
item.setProjectManagerName(memberNames.get("PROJECT_MANAGER"));
item.setSafetyOfficerName(memberNames.get("SAFETY_OFFICER"));
item.setQualityOfficerName(memberNames.get("QUALITY_OFFICER"));
item.setConstructionTeamLeaderName(memberNames.get("TEAM_LEADER"));
item.setConstructorNames(memberNames.get("CONSTRUCTOR"));
// 统计机组数量
Long turbineCount = turbineService.lambdaQuery()
.eq(TurbineEntity::getProjectId, project.getProjectId())
.count();
item.setTurbineCount(turbineCount);
// 统计任务数量
Long taskCount = projectTaskService.lambdaQuery()
.eq(ProjectTaskEntity::getProjectId, project.getProjectId())
.count();
item.setTaskCount(taskCount);
// 统计已完成任务数量
Long completedTaskCount = projectTaskService.lambdaQuery()
.eq(ProjectTaskEntity::getProjectId, project.getProjectId())
.eq(ProjectTaskEntity::getStatus, 2)
.count();
item.setCompletedTaskCount(completedTaskCount);
// 计算项目进度百分比
if (taskCount > 0) {
item.setProgressPercentage((int) (completedTaskCount * 100 / taskCount));
} else {
item.setProgressPercentage(0);
}
return item;
}).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,314 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dite.znpt.mapper.ProjectMemberMapper">
<!-- 基础结果映射 -->
<resultMap id="BaseResultMap" type="com.dite.znpt.domain.vo.ProjectMemberResp">
<id column="member_id" property="memberId" jdbcType="VARCHAR"/>
<result column="project_id" property="projectId" jdbcType="VARCHAR"/>
<result column="project_name" property="projectName" jdbcType="VARCHAR"/>
<result column="turbine_id" property="turbineId" jdbcType="VARCHAR"/>
<result column="turbine_name" property="turbineName" jdbcType="VARCHAR"/>
<result column="task_group_id" property="taskGroupId" jdbcType="VARCHAR"/>
<result column="task_group_name" property="taskGroupName" jdbcType="VARCHAR"/>
<result column="task_id" property="taskId" jdbcType="VARCHAR"/>
<result column="task_name" property="taskName" jdbcType="VARCHAR"/>
<result column="user_id" property="userId" jdbcType="VARCHAR"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="user_account" property="userAccount" jdbcType="VARCHAR"/>
<result column="user_avatar" property="userAvatar" jdbcType="VARCHAR"/>
<result column="role_type" property="roleType" jdbcType="VARCHAR"/>
<result column="role_type_desc" property="roleTypeDesc" jdbcType="VARCHAR"/>
<result column="job_code" property="jobCode" jdbcType="VARCHAR"/>
<result column="job_code_desc" property="jobCodeDesc" jdbcType="VARCHAR"/>
<result column="job_desc" property="jobDesc" jdbcType="VARCHAR"/>
<result column="join_date" property="joinDate" jdbcType="DATE"/>
<result column="leave_date" property="leaveDate" jdbcType="DATE"/>
<result column="status" property="status" jdbcType="VARCHAR"/>
<result column="remark" property="remark" jdbcType="VARCHAR"/>
</resultMap>
<!-- 根据条件查询项目人员列表 -->
<select id="queryBySelective" resultMap="BaseResultMap">
SELECT
pm.member_id,
pm.project_id,
p.project_name,
pm.turbine_id,
t.turbine_name,
pm.task_group_id,
ptg.group_name as task_group_name,
pm.task_id,
pt.task_name,
pm.user_id,
u.name as user_name,
u.account as user_account,
u.avatar as user_avatar,
pm.role_type,
pm.role_type as role_type_desc,
pm.job_code,
pm.job_code as job_code_desc,
pm.job_desc,
pm.join_date,
pm.leave_date,
pm.status,
pm.remark
FROM project_member pm
LEFT JOIN project p ON pm.project_id COLLATE utf8mb4_general_ci = p.project_id COLLATE utf8mb4_general_ci
LEFT JOIN turbine t ON pm.turbine_id COLLATE utf8mb4_general_ci = t.turbine_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task_group ptg ON pm.task_group_id COLLATE utf8mb4_general_ci = ptg.group_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task pt ON pm.task_id COLLATE utf8mb4_general_ci = pt.task_id COLLATE utf8mb4_general_ci
LEFT JOIN user u ON pm.user_id COLLATE utf8mb4_general_ci = u.user_id COLLATE utf8mb4_general_ci
<where>
<if test="projectId != null and projectId != ''">
AND pm.project_id = #{projectId}
</if>
<if test="turbineId != null and turbineId != ''">
AND pm.turbine_id = #{turbineId}
</if>
<if test="taskGroupId != null and taskGroupId != ''">
AND pm.task_group_id = #{taskGroupId}
</if>
<if test="taskId != null and taskId != ''">
AND pm.task_id = #{taskId}
</if>
<if test="userId != null and userId != ''">
AND pm.user_id = #{userId}
</if>
<if test="roleType != null and roleType != ''">
AND pm.role_type = #{roleType}
</if>
<if test="jobCode != null and jobCode != ''">
AND pm.job_code = #{jobCode}
</if>
<if test="status != null and status != ''">
AND pm.status = #{status}
</if>
<if test="userName != null and userName != ''">
AND u.name LIKE CONCAT('%', #{userName}, '%')
</if>
<if test="userAccount != null and userAccount != ''">
AND u.account LIKE CONCAT('%', #{userAccount}, '%')
</if>
</where>
ORDER BY pm.create_time DESC
</select>
<!-- 根据项目ID查询项目人员列表 -->
<select id="queryByProjectId" resultMap="BaseResultMap">
SELECT
pm.member_id,
pm.project_id,
p.project_name,
pm.turbine_id,
t.turbine_name,
pm.task_group_id,
ptg.group_name as task_group_name,
pm.task_id,
pt.task_name,
pm.user_id,
u.name as user_name,
u.account as user_account,
u.avatar as user_avatar,
pm.role_type,
pm.role_type as role_type_desc,
pm.job_code,
pm.job_code as job_code_desc,
pm.job_desc,
pm.join_date,
pm.leave_date,
pm.status,
pm.remark
FROM project_member pm
LEFT JOIN project p ON pm.project_id COLLATE utf8mb4_general_ci = p.project_id COLLATE utf8mb4_general_ci
LEFT JOIN turbine t ON pm.turbine_id COLLATE utf8mb4_general_ci = t.turbine_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task_group ptg ON pm.task_group_id COLLATE utf8mb4_general_ci = ptg.group_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task pt ON pm.task_id COLLATE utf8mb4_general_ci = pt.task_id COLLATE utf8mb4_general_ci
LEFT JOIN user u ON pm.user_id COLLATE utf8mb4_general_ci = u.user_id COLLATE utf8mb4_general_ci
WHERE pm.project_id = #{projectId}
AND pm.status = 'ACTIVE'
ORDER BY pm.create_time DESC
</select>
<!-- 根据机组ID查询机组人员列表 -->
<select id="queryByTurbineId" resultMap="BaseResultMap">
SELECT
pm.member_id,
pm.project_id,
p.project_name,
pm.turbine_id,
t.turbine_name,
pm.task_group_id,
ptg.group_name as task_group_name,
pm.task_id,
pt.task_name,
pm.user_id,
u.name as user_name,
u.account as user_account,
u.avatar as user_avatar,
pm.role_type,
pm.role_type as role_type_desc,
pm.job_code,
pm.job_code as job_code_desc,
pm.job_desc,
pm.join_date,
pm.leave_date,
pm.status,
pm.remark
FROM project_member pm
LEFT JOIN project p ON pm.project_id COLLATE utf8mb4_general_ci = p.project_id COLLATE utf8mb4_general_ci
LEFT JOIN turbine t ON pm.turbine_id COLLATE utf8mb4_general_ci = t.turbine_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task_group ptg ON pm.task_group_id COLLATE utf8mb4_general_ci = ptg.group_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task pt ON pm.task_id COLLATE utf8mb4_general_ci = pt.task_id COLLATE utf8mb4_general_ci
LEFT JOIN user u ON pm.user_id COLLATE utf8mb4_general_ci = u.user_id COLLATE utf8mb4_general_ci
WHERE pm.turbine_id = #{turbineId}
AND pm.status = 'ACTIVE'
ORDER BY pm.create_time DESC
</select>
<!-- 根据任务组ID查询任务组人员列表 -->
<select id="queryByTaskGroupId" resultMap="BaseResultMap">
SELECT
pm.member_id,
pm.project_id,
p.project_name,
pm.turbine_id,
t.turbine_name,
pm.task_group_id,
ptg.group_name as task_group_name,
pm.task_id,
pt.task_name,
pm.user_id,
u.name as user_name,
u.account as user_account,
u.avatar as user_avatar,
pm.role_type,
pm.role_type as role_type_desc,
pm.job_code,
pm.job_code as job_code_desc,
pm.job_desc,
pm.join_date,
pm.leave_date,
pm.status,
pm.remark
FROM project_member pm
LEFT JOIN project p ON pm.project_id COLLATE utf8mb4_general_ci = p.project_id COLLATE utf8mb4_general_ci
LEFT JOIN turbine t ON pm.turbine_id COLLATE utf8mb4_general_ci = t.turbine_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task_group ptg ON pm.task_group_id COLLATE utf8mb4_general_ci = ptg.group_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task pt ON pm.task_id COLLATE utf8mb4_general_ci = pt.task_id COLLATE utf8mb4_general_ci
LEFT JOIN user u ON pm.user_id COLLATE utf8mb4_general_ci = u.user_id COLLATE utf8mb4_general_ci
WHERE pm.task_group_id = #{taskGroupId}
AND pm.status = 'ACTIVE'
ORDER BY pm.create_time DESC
</select>
<!-- 根据任务ID查询任务人员列表 -->
<select id="queryByTaskId" resultMap="BaseResultMap">
SELECT
pm.member_id,
pm.project_id,
p.project_name,
pm.turbine_id,
t.turbine_name,
pm.task_group_id,
ptg.group_name as task_group_name,
pm.task_id,
pt.task_name,
pm.user_id,
u.name as user_name,
u.account as user_account,
u.avatar as user_avatar,
pm.role_type,
pm.role_type as role_type_desc,
pm.job_code,
pm.job_code as job_code_desc,
pm.job_desc,
pm.join_date,
pm.leave_date,
pm.status,
pm.remark
FROM project_member pm
LEFT JOIN project p ON pm.project_id COLLATE utf8mb4_general_ci = p.project_id COLLATE utf8mb4_general_ci
LEFT JOIN turbine t ON pm.turbine_id COLLATE utf8mb4_general_ci = t.turbine_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task_group ptg ON pm.task_group_id COLLATE utf8mb4_general_ci = ptg.group_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task pt ON pm.task_id COLLATE utf8mb4_general_ci = pt.task_id COLLATE utf8mb4_general_ci
LEFT JOIN user u ON pm.user_id COLLATE utf8mb4_general_ci = u.user_id COLLATE utf8mb4_general_ci
WHERE pm.task_id = #{taskId}
AND pm.status = 'ACTIVE'
ORDER BY pm.create_time DESC
</select>
<!-- 根据用户ID查询用户参与的项目列表 -->
<select id="queryByUserId" resultMap="BaseResultMap">
SELECT
pm.member_id,
pm.project_id,
p.project_name,
pm.turbine_id,
t.turbine_name,
pm.task_group_id,
ptg.group_name as task_group_name,
pm.task_id,
pt.task_name,
pm.user_id,
u.name as user_name,
u.account as user_account,
u.avatar as user_avatar,
pm.role_type,
pm.role_type as role_type_desc,
pm.job_code,
pm.job_code as job_code_desc,
pm.job_desc,
pm.join_date,
pm.leave_date,
pm.status,
pm.remark
FROM project_member pm
LEFT JOIN project p ON pm.project_id COLLATE utf8mb4_general_ci = p.project_id COLLATE utf8mb4_general_ci
LEFT JOIN turbine t ON pm.turbine_id COLLATE utf8mb4_general_ci = t.turbine_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task_group ptg ON pm.task_group_id COLLATE utf8mb4_general_ci = ptg.group_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task pt ON pm.task_id COLLATE utf8mb4_general_ci = pt.task_id COLLATE utf8mb4_general_ci
LEFT JOIN user u ON pm.user_id COLLATE utf8mb4_general_ci = u.user_id COLLATE utf8mb4_general_ci
WHERE pm.user_id = #{userId}
AND pm.status = 'ACTIVE'
ORDER BY pm.create_time DESC
</select>
<!-- 根据项目ID和角色类型查询人员列表 -->
<select id="queryByProjectIdAndRoleType" resultMap="BaseResultMap">
SELECT
pm.member_id,
pm.project_id,
p.project_name,
pm.turbine_id,
t.turbine_name,
pm.task_group_id,
ptg.group_name as task_group_name,
pm.task_id,
pt.task_name,
pm.user_id,
u.name as user_name,
u.account as user_account,
u.avatar as user_avatar,
pm.role_type,
pm.role_type as role_type_desc,
pm.job_code,
pm.job_code as job_code_desc,
pm.job_desc,
pm.join_date,
pm.leave_date,
pm.status,
pm.remark
FROM project_member pm
LEFT JOIN project p ON pm.project_id COLLATE utf8mb4_general_ci = p.project_id COLLATE utf8mb4_general_ci
LEFT JOIN turbine t ON pm.turbine_id COLLATE utf8mb4_general_ci = t.turbine_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task_group ptg ON pm.task_group_id COLLATE utf8mb4_general_ci = ptg.group_id COLLATE utf8mb4_general_ci
LEFT JOIN project_task pt ON pm.task_id COLLATE utf8mb4_general_ci = pt.task_id COLLATE utf8mb4_general_ci
LEFT JOIN user u ON pm.user_id COLLATE utf8mb4_general_ci = u.user_id COLLATE utf8mb4_general_ci
WHERE pm.project_id = #{projectId}
AND pm.role_type = #{roleType}
AND pm.status = 'ACTIVE'
ORDER BY pm.create_time DESC
</select>
</mapper>

View File

@ -0,0 +1,107 @@
-- =============================================
-- 项目人员表扩展测试数据
-- 使用多个真实用户ID和项目ID使用UUID()生成member_id
-- @author AI Assistant
-- @date 2025/01/27
-- =============================================
-- 清空现有数据(可选)
-- DELETE FROM project_member WHERE project_id IN ('0b71a1259c49918c6595c9720ad1db5d', '7f321271c13483aa31cb743d604603a5', '8e0da59bd0c640b5b65dccd72606ea39', '96e0debf78187300f144d7f3450a2477', 'bbd28ed8627d6bd9fd8fa7476af6242a', 'd446d998d7c40005bf9af53ac264ef6e', 'd6c5b8408a42a8390297751756ecff23', 'eb64015cf2d0b40574c1d6f476876822', 'fb7e3b731ee496cec46ca1db64117676');
-- 插入项目人员测试数据
INSERT INTO project_member (
member_id,
project_id,
user_id,
role_type,
job_code,
job_desc,
join_date,
status,
remark
) VALUES
-- 项目1: 0b71a1259c49918c6595c9720ad1db5d
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '0ab4a72af4184a1614d4c25a5bb65ece', 'PROJECT_MANAGER', 'PROJECT_MANAGER', '项目经理', '2025-01-15', 'ACTIVE', '项目总负责人'),
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '0bc98a66761915e31fbf86e468d6ba20', 'SAFETY_OFFICER', 'SAFETY_MANAGER', '安全经理', '2025-01-15', 'ACTIVE', '负责项目安全管理'),
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '149c94f937a7d36cda70a81f343d090a', 'QUALITY_OFFICER', 'QUALITY_MANAGER', '质量经理', '2025-01-15', 'ACTIVE', '负责项目质量管理'),
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '15129b4764ced7900ef5d51c20cefa35', 'TEAM_LEADER', 'SITE_MANAGER', '现场经理', '2025-01-15', 'ACTIVE', '负责现场施工管理'),
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '1632433c2073532a074b0079cca5eb18', 'CONSTRUCTOR', 'GROUND_SERVICE', '地勤人员', '2025-01-15', 'ACTIVE', '负责地面施工工作'),
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '1995a0da943d188506548bd42a2ee39d', 'CONSTRUCTOR', 'DRIVER', '司机', '2025-01-15', 'ACTIVE', '负责设备运输和人员接送'),
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '1b2641edb4c9a8f14658edaa8e6a36e3', 'CONSTRUCTOR', 'ASCENDING', '登高人员', '2025-01-15', 'ACTIVE', '负责高空作业'),
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '1d476bc4de6d71f6a43497d943adec9c', 'CONSTRUCTOR', 'ANTI_THUNDER', '防雷人员', '2025-01-15', 'ACTIVE', '负责防雷设施安装'),
-- 项目2: 7f321271c13483aa31cb743d604603a5
(UUID(), '7f321271c13483aa31cb743d604603a5', '1dae46a6ecbc2408c8b137187fc13d06', 'PROJECT_MANAGER', 'PROJECT_MANAGER', '项目经理', '2025-01-16', 'ACTIVE', '项目总负责人'),
(UUID(), '7f321271c13483aa31cb743d604603a5', '1f319a6f25b65ebd50711707e5e08d1a', 'SAFETY_OFFICER', 'SAFETY_MANAGER', '安全经理', '2025-01-16', 'ACTIVE', '负责项目安全管理'),
(UUID(), '7f321271c13483aa31cb743d604603a5', '22ff9d065f3ad826f5e22ba18a20248c', 'QUALITY_OFFICER', 'QUALITY_MANAGER', '质量经理', '2025-01-16', 'ACTIVE', '负责项目质量管理'),
(UUID(), '7f321271c13483aa31cb743d604603a5', '2fd0581e10f4c4f70e5148de3d61bc06', 'TEAM_LEADER', 'SITE_MANAGER', '现场经理', '2025-01-16', 'ACTIVE', '负责现场施工管理'),
(UUID(), '7f321271c13483aa31cb743d604603a5', '3042cb085eb41721faa8f4d985921424', 'CONSTRUCTOR', 'GROUND_SERVICE', '地勤人员', '2025-01-16', 'ACTIVE', '负责地面施工工作'),
(UUID(), '7f321271c13483aa31cb743d604603a5', '3169163eb58fff961955179fbdc22507', 'CONSTRUCTOR', 'DRIVER', '司机', '2025-01-16', 'ACTIVE', '负责设备运输和人员接送'),
-- 项目3: 8e0da59bd0c640b5b65dccd72606ea39
(UUID(), '8e0da59bd0c640b5b65dccd72606ea39', '324afaf4e89213b6f5fcf1fa57663940', 'PROJECT_MANAGER', 'PROJECT_MANAGER', '项目经理', '2025-01-17', 'ACTIVE', '项目总负责人'),
(UUID(), '8e0da59bd0c640b5b65dccd72606ea39', '375f87a103e5bcad6e6a402177044891', 'SAFETY_OFFICER', 'SAFETY_MANAGER', '安全经理', '2025-01-17', 'ACTIVE', '负责项目安全管理'),
(UUID(), '8e0da59bd0c640b5b65dccd72606ea39', '3b5f2db9bac776be536d893f726deeba', 'QUALITY_OFFICER', 'QUALITY_MANAGER', '质量经理', '2025-01-17', 'ACTIVE', '负责项目质量管理'),
(UUID(), '8e0da59bd0c640b5b65dccd72606ea39', '44d335410542c5fd4989780dd11dca66', 'TEAM_LEADER', 'SITE_MANAGER', '现场经理', '2025-01-17', 'ACTIVE', '负责现场施工管理'),
(UUID(), '8e0da59bd0c640b5b65dccd72606ea39', '4e171ce81c18183bc8f06da8bd47a3d8', 'CONSTRUCTOR', 'GROUND_SERVICE', '地勤人员', '2025-01-17', 'ACTIVE', '负责地面施工工作'),
-- 项目4: 96e0debf78187300f144d7f3450a2477
(UUID(), '96e0debf78187300f144d7f3450a2477', '0ab4a72af4184a1614d4c25a5bb65ece', 'PROJECT_MANAGER', 'PROJECT_MANAGER', '项目经理', '2025-01-18', 'ACTIVE', '项目总负责人'),
(UUID(), '96e0debf78187300f144d7f3450a2477', '0bc98a66761915e31fbf86e468d6ba20', 'SAFETY_OFFICER', 'SAFETY_MANAGER', '安全经理', '2025-01-18', 'ACTIVE', '负责项目安全管理'),
(UUID(), '96e0debf78187300f144d7f3450a2477', '149c94f937a7d36cda70a81f343d090a', 'QUALITY_OFFICER', 'QUALITY_MANAGER', '质量经理', '2025-01-18', 'ACTIVE', '负责项目质量管理'),
(UUID(), '96e0debf78187300f144d7f3450a2477', '15129b4764ced7900ef5d51c20cefa35', 'CONSTRUCTOR', 'ASCENDING', '登高人员', '2025-01-18', 'ACTIVE', '负责高空作业'),
(UUID(), '96e0debf78187300f144d7f3450a2477', '1632433c2073532a074b0079cca5eb18', 'CONSTRUCTOR', 'ANTI_THUNDER', '防雷人员', '2025-01-18', 'ACTIVE', '负责防雷设施安装'),
-- 项目5: bbd28ed8627d6bd9fd8fa7476af6242a
(UUID(), 'bbd28ed8627d6bd9fd8fa7476af6242a', '1995a0da943d188506548bd42a2ee39d', 'PROJECT_MANAGER', 'PROJECT_MANAGER', '项目经理', '2025-01-19', 'ACTIVE', '项目总负责人'),
(UUID(), 'bbd28ed8627d6bd9fd8fa7476af6242a', '1b2641edb4c9a8f14658edaa8e6a36e3', 'SAFETY_OFFICER', 'SAFETY_MANAGER', '安全经理', '2025-01-19', 'ACTIVE', '负责项目安全管理'),
(UUID(), 'bbd28ed8627d6bd9fd8fa7476af6242a', '1d476bc4de6d71f6a43497d943adec9c', 'QUALITY_OFFICER', 'QUALITY_MANAGER', '质量经理', '2025-01-19', 'ACTIVE', '负责项目质量管理'),
(UUID(), 'bbd28ed8627d6bd9fd8fa7476af6242a', '1dae46a6ecbc2408c8b137187fc13d06', 'TEAM_LEADER', 'SITE_MANAGER', '现场经理', '2025-01-19', 'ACTIVE', '负责现场施工管理'),
(UUID(), 'bbd28ed8627d6bd9fd8fa7476af6242a', '1f319a6f25b65ebd50711707e5e08d1a', 'CONSTRUCTOR', 'GROUND_SERVICE', '地勤人员', '2025-01-19', 'ACTIVE', '负责地面施工工作'),
-- 项目6: d446d998d7c40005bf9af53ac264ef6e
(UUID(), 'd446d998d7c40005bf9af53ac264ef6e', '22ff9d065f3ad826f5e22ba18a20248c', 'PROJECT_MANAGER', 'PROJECT_MANAGER', '项目经理', '2025-01-20', 'ACTIVE', '项目总负责人'),
(UUID(), 'd446d998d7c40005bf9af53ac264ef6e', '2fd0581e10f4c4f70e5148de3d61bc06', 'SAFETY_OFFICER', 'SAFETY_MANAGER', '安全经理', '2025-01-20', 'ACTIVE', '负责项目安全管理'),
(UUID(), 'd446d998d7c40005bf9af53ac264ef6e', '3042cb085eb41721faa8f4d985921424', 'QUALITY_OFFICER', 'QUALITY_MANAGER', '质量经理', '2025-01-20', 'ACTIVE', '负责项目质量管理'),
(UUID(), 'd446d998d7c40005bf9af53ac264ef6e', '3169163eb58fff961955179fbdc22507', 'CONSTRUCTOR', 'DRIVER', '司机', '2025-01-20', 'ACTIVE', '负责设备运输和人员接送'),
-- 项目7: d6c5b8408a42a8390297751756ecff23
(UUID(), 'd6c5b8408a42a8390297751756ecff23', '324afaf4e89213b6f5fcf1fa57663940', 'PROJECT_MANAGER', 'PROJECT_MANAGER', '项目经理', '2025-01-21', 'ACTIVE', '项目总负责人'),
(UUID(), 'd6c5b8408a42a8390297751756ecff23', '375f87a103e5bcad6e6a402177044891', 'SAFETY_OFFICER', 'SAFETY_MANAGER', '安全经理', '2025-01-21', 'ACTIVE', '负责项目安全管理'),
(UUID(), 'd6c5b8408a42a8390297751756ecff23', '3b5f2db9bac776be536d893f726deeba', 'CONSTRUCTOR', 'ASCENDING', '登高人员', '2025-01-21', 'ACTIVE', '负责高空作业'),
(UUID(), 'd6c5b8408a42a8390297751756ecff23', '44d335410542c5fd4989780dd11dca66', 'CONSTRUCTOR', 'ANTI_THUNDER', '防雷人员', '2025-01-21', 'ACTIVE', '负责防雷设施安装'),
-- 项目8: eb64015cf2d0b40574c1d6f476876822
(UUID(), 'eb64015cf2d0b40574c1d6f476876822', '4e171ce81c18183bc8f06da8bd47a3d8', 'PROJECT_MANAGER', 'PROJECT_MANAGER', '项目经理', '2025-01-22', 'ACTIVE', '项目总负责人'),
(UUID(), 'eb64015cf2d0b40574c1d6f476876822', '0ab4a72af4184a1614d4c25a5bb65ece', 'SAFETY_OFFICER', 'SAFETY_MANAGER', '安全经理', '2025-01-22', 'ACTIVE', '负责项目安全管理'),
(UUID(), 'eb64015cf2d0b40574c1d6f476876822', '0bc98a66761915e31fbf86e468d6ba20', 'QUALITY_OFFICER', 'QUALITY_MANAGER', '质量经理', '2025-01-22', 'ACTIVE', '负责项目质量管理'),
(UUID(), 'eb64015cf2d0b40574c1d6f476876822', '149c94f937a7d36cda70a81f343d090a', 'TEAM_LEADER', 'SITE_MANAGER', '现场经理', '2025-01-22', 'ACTIVE', '负责现场施工管理'),
-- 项目9: fb7e3b731ee496cec46ca1db64117676
(UUID(), 'fb7e3b731ee496cec46ca1db64117676', '15129b4764ced7900ef5d51c20cefa35', 'PROJECT_MANAGER', 'PROJECT_MANAGER', '项目经理', '2025-01-23', 'ACTIVE', '项目总负责人'),
(UUID(), 'fb7e3b731ee496cec46ca1db64117676', '1632433c2073532a074b0079cca5eb18', 'SAFETY_OFFICER', 'SAFETY_MANAGER', '安全经理', '2025-01-23', 'ACTIVE', '负责项目安全管理'),
(UUID(), 'fb7e3b731ee496cec46ca1db64117676', '1995a0da943d188506548bd42a2ee39d', 'QUALITY_OFFICER', 'QUALITY_MANAGER', '质量经理', '2025-01-23', 'ACTIVE', '负责项目质量管理'),
(UUID(), 'fb7e3b731ee496cec46ca1db64117676', '1b2641edb4c9a8f14658edaa8e6a36e3', 'CONSTRUCTOR', 'GROUND_SERVICE', '地勤人员', '2025-01-23', 'ACTIVE', '负责地面施工工作'),
(UUID(), 'fb7e3b731ee496cec46ca1db64117676', '1d476bc4de6d71f6a43497d943adec9c', 'CONSTRUCTOR', 'DRIVER', '司机', '2025-01-23', 'ACTIVE', '负责设备运输和人员接送');
-- =============================================
-- 查询示例
-- =============================================
-- 查询所有项目的在职人员
-- SELECT * FROM project_member WHERE status = 'ACTIVE';
-- 查询特定项目的所有人员
-- SELECT * FROM project_member WHERE project_id = '0b71a1259c49918c6595c9720ad1db5d' AND status = 'ACTIVE';
-- 查询所有项目经理
-- SELECT * FROM project_member WHERE role_type = 'PROJECT_MANAGER' AND status = 'ACTIVE';
-- 按项目统计人员数量
-- SELECT project_id, COUNT(*) as member_count FROM project_member WHERE status = 'ACTIVE' GROUP BY project_id;
-- 按角色类型统计人员数量
-- SELECT role_type, COUNT(*) as count FROM project_member WHERE status = 'ACTIVE' GROUP BY role_type;
-- 查询特定用户参与的所有项目
-- SELECT DISTINCT project_id FROM project_member WHERE user_id = '0ab4a72af4184a1614d4c25a5bb65ece' AND status = 'ACTIVE';

View File

@ -0,0 +1,137 @@
-- =============================================
-- 项目人员关联表
-- 用于管理项目、机组、任务组、任务的人员关系
-- @author wangna
-- @date 2025/08/05
-- =============================================
-- 项目人员关联表
CREATE TABLE `project_member` (
`member_id` varchar(64) NOT NULL COMMENT '关联ID',
`project_id` varchar(64) NOT NULL COMMENT '项目ID',
`turbine_id` varchar(64) DEFAULT NULL COMMENT '机组ID可选关联到具体机组',
`task_group_id` varchar(64) DEFAULT NULL COMMENT '任务组ID可选关联到具体任务组',
`task_id` varchar(64) DEFAULT NULL COMMENT '任务ID可选关联到具体任务',
`user_id` varchar(64) NOT NULL COMMENT '用户ID',
`role_type` varchar(50) NOT NULL COMMENT '项目角色类型',
`job_code` varchar(50) DEFAULT NULL COMMENT '具体岗位代码',
`job_desc` varchar(500) DEFAULT NULL COMMENT '岗位描述',
`join_date` date NOT NULL COMMENT '加入时间',
`leave_date` date DEFAULT NULL COMMENT '离开时间',
`status` varchar(20) DEFAULT 'ACTIVE' COMMENT '状态ACTIVE-在职INACTIVE-离职SUSPENDED-暂停',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`member_id`),
KEY `idx_project_id` (`project_id`),
KEY `idx_turbine_id` (`turbine_id`),
KEY `idx_task_group_id` (`task_group_id`),
KEY `idx_task_id` (`task_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_role_type` (`role_type`),
KEY `idx_status` (`status`),
UNIQUE KEY `uk_project_user_role` (`project_id`, `user_id`, `role_type`, `turbine_id`, `task_group_id`, `task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目人员关联表';
-- 添加复合索引以提高查询性能
CREATE INDEX `idx_project_member_composite` ON `project_member` (`project_id`, `status`, `role_type`);
CREATE INDEX `idx_project_member_user_status` ON `project_member` (`user_id`, `status`);
CREATE INDEX `idx_project_member_turbine_status` ON `project_member` (`turbine_id`, `status`);
CREATE INDEX `idx_project_member_task_status` ON `project_member` (`task_id`, `status`);
-- =============================================
-- 数据迁移脚本(可选)
-- 将现有项目的人员数据迁移到新表
-- =============================================
-- 迁移项目经理数据
INSERT INTO project_member (member_id, project_id, user_id, role_type, job_code, join_date, status, create_time)
SELECT
UUID() as member_id,
project_id,
project_manager_id as user_id,
'PROJECT_MANAGER' as role_type,
'PROJECT_MANAGER' as job_code,
create_time as join_date,
'ACTIVE' as status,
create_time
FROM project
WHERE project_manager_id IS NOT NULL AND project_manager_id != '';
-- 迁移安全员数据
INSERT INTO project_member (member_id, project_id, user_id, role_type, job_code, join_date, status, create_time)
SELECT
UUID() as member_id,
project_id,
auditor_id as user_id,
'SAFETY_OFFICER' as role_type,
'SAFETY_MANAGER' as job_code,
create_time as join_date,
'ACTIVE' as status,
create_time
FROM project
WHERE auditor_id IS NOT NULL AND auditor_id != '';
-- 迁移质量员数据
INSERT INTO project_member (member_id, project_id, user_id, role_type, job_code, join_date, status, create_time)
SELECT
UUID() as member_id,
project_id,
quality_officer_id as user_id,
'QUALITY_OFFICER' as role_type,
'QUALITY_MANAGER' as job_code,
create_time as join_date,
'ACTIVE' as status,
create_time
FROM project
WHERE quality_officer_id IS NOT NULL AND quality_officer_id != '';
-- 迁移施工组长数据
INSERT INTO project_member (member_id, project_id, user_id, role_type, job_code, join_date, status, create_time)
SELECT
UUID() as member_id,
project_id,
construct_team_leader_id as user_id,
'TEAM_LEADER' as role_type,
'TEAM_LEADER' as job_code,
create_time as join_date,
'ACTIVE' as status,
create_time
FROM project
WHERE construct_team_leader_id IS NOT NULL AND construct_team_leader_id != '';
-- 迁移施工人员数据需要处理逗号分隔的多个ID
-- 注意这个脚本需要根据实际情况调整因为constructor_ids是逗号分隔的字符串
-- 建议在应用层处理这个迁移逻辑
-- =============================================
-- 示例数据插入
-- =============================================
-- 插入示例项目人员数据
INSERT INTO project_member (member_id, project_id, user_id, role_type, job_code, job_desc, join_date, status, remark) VALUES
('pm001', 'project001', 'user001', 'PROJECT_MANAGER', 'PROJECT_MANAGER', '项目经理', '2025-01-01', 'ACTIVE', '项目负责人'),
('pm002', 'project001', 'user002', 'SAFETY_OFFICER', 'SAFETY_MANAGER', '安全经理', '2025-01-01', 'ACTIVE', '负责项目安全'),
('pm003', 'project001', 'user003', 'QUALITY_OFFICER', 'QUALITY_MANAGER', '质量经理', '2025-01-01', 'ACTIVE', '负责项目质量'),
('pm004', 'project001', 'user004', 'CONSTRUCTOR', 'GROUND_SERVICE', '地勤人员', '2025-01-01', 'ACTIVE', '地勤工作'),
('pm005', 'project001', 'user005', 'CONSTRUCTOR', 'DRIVER', '司机', '2025-01-01', 'ACTIVE', '负责运输'),
('pm006', 'project001', 'user006', 'CONSTRUCTOR', 'ASCENDING', '登高人员', '2025-01-01', 'ACTIVE', '高空作业');
-- =============================================
-- 查询示例
-- =============================================
-- 查询项目所有人员
-- SELECT * FROM project_member WHERE project_id = 'project001' AND status = 'ACTIVE';
-- 查询项目的项目经理
-- SELECT * FROM project_member WHERE project_id = 'project001' AND role_type = 'PROJECT_MANAGER' AND status = 'ACTIVE';
-- 查询用户参与的所有项目
-- SELECT DISTINCT project_id FROM project_member WHERE user_id = 'user001' AND status = 'ACTIVE';
-- 查询机组人员
-- SELECT * FROM project_member WHERE turbine_id = 'turbine001' AND status = 'ACTIVE';
CREATE INDEX `idx_project_member_task_status` ON `project_member` (`task_id`, `status`);

View File

@ -0,0 +1,53 @@
-- =============================================
-- 项目人员表测试数据
-- 基于项目ID: 0b71a1259c49918c6595c9720ad1db5d
-- 使用真实用户ID使用UUID()生成member_id
-- @author AI Assistant
-- @date 2025/01/27
-- =============================================
-- 清空现有数据(可选)
-- DELETE FROM project_member WHERE project_id = '0b71a1259c49918c6595c9720ad1db5d';
-- 插入项目人员测试数据
INSERT INTO project_member (
member_id,
project_id,
user_id,
role_type,
job_code,
job_desc,
join_date,
status,
remark
) VALUES
-- 项目经理
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '008ecfac153be83890c42f9fed0a48cd', 'PROJECT_MANAGER', 'PROJECT_MANAGER', '项目经理', '2025-01-15', 'ACTIVE', '项目总负责人'),
-- 安全员
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '014d6fd83182ac03d05967e16748ab80', 'SAFETY_OFFICER', 'SAFETY_MANAGER', '安全经理', '2025-01-15', 'ACTIVE', '负责项目安全管理'),
-- 质量员
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '0465342288d0637398b64ca73da76090', 'QUALITY_OFFICER', 'QUALITY_MANAGER', '质量经理', '2025-01-15', 'ACTIVE', '负责项目质量管理'),
-- 施工组长
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '008ecfac153be83890c42f9fed0a48cd', 'TEAM_LEADER', 'SITE_MANAGER', '现场经理', '2025-01-15', 'ACTIVE', '负责现场施工管理'),
-- 地勤人员
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '014d6fd83182ac03d05967e16748ab80', 'CONSTRUCTOR', 'GROUND_SERVICE', '地勤人员', '2025-01-15', 'ACTIVE', '负责地面施工工作'),
-- 司机
(UUID(), '0b71a1259c49918c6595c9720ad1db5d', '0465342288d0637398b64ca73da76090', 'CONSTRUCTOR', 'DRIVER', '司机', '2025-01-15', 'ACTIVE', '负责设备运输和人员接送');
-- =============================================
-- 查询示例
-- =============================================
-- 查询项目所有在职人员
-- SELECT * FROM project_member WHERE project_id = '0b71a1259c49918c6595c9720ad1db5d' AND status = 'ACTIVE';
-- 查询项目的项目经理
-- SELECT * FROM project_member WHERE project_id = '0b71a1259c49918c6595c9720ad1db5d' AND role_type = 'PROJECT_MANAGER' AND status = 'ACTIVE';
-- 按角色类型统计人员数量
-- SELECT role_type, COUNT(*) as count FROM project_member WHERE project_id = '0b71a1259c49918c6595c9720ad1db5d' AND status = 'ACTIVE' GROUP BY role_type;

View File

@ -0,0 +1,153 @@
package com.dite.znpt.web.controller;
import com.dite.znpt.domain.PageResult;
import com.dite.znpt.domain.Result;
import com.dite.znpt.domain.vo.ProjectMemberListReq;
import com.dite.znpt.domain.vo.ProjectMemberReq;
import com.dite.znpt.domain.vo.ProjectMemberResp;
import com.dite.znpt.domain.vo.ProjectKanbanStatsResp;
import com.dite.znpt.domain.vo.ProjectKanbanDataResp;
import com.dite.znpt.domain.vo.ProjectDetailResp;
import com.dite.znpt.service.ProjectMemberService;
import com.dite.znpt.util.PageUtil;
import com.dite.znpt.util.ValidationGroup;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* @author wangna
* @date 2025/08/05
* @Description: 项目人员管理Controller
*/
@Api(tags = "项目人员管理")
@RestController
@RequestMapping("/project-member")
public class ProjectMemberController {
@Resource
private ProjectMemberService projectMemberService;
@ApiOperation(value = "查询项目人员列表", httpMethod = "GET")
@GetMapping("/list")
public PageResult<ProjectMemberResp> list(ProjectMemberListReq req) {
PageUtil.startPage();
return PageResult.ok(projectMemberService.selectList(req));
}
@ApiOperation(value = "根据项目ID查询项目人员", httpMethod = "GET")
@GetMapping("/project/{projectId}")
public Result<List<ProjectMemberResp>> getByProjectId(@PathVariable String projectId) {
return Result.ok(projectMemberService.selectByProjectId(projectId));
}
@ApiOperation(value = "根据机组ID查询机组人员", httpMethod = "GET")
@GetMapping("/turbine/{turbineId}")
public Result<List<ProjectMemberResp>> getByTurbineId(@PathVariable String turbineId) {
return Result.ok(projectMemberService.selectByTurbineId(turbineId));
}
@ApiOperation(value = "根据任务组ID查询任务组人员", httpMethod = "GET")
@GetMapping("/task-group/{taskGroupId}")
public Result<List<ProjectMemberResp>> getByTaskGroupId(@PathVariable String taskGroupId) {
return Result.ok(projectMemberService.selectByTaskGroupId(taskGroupId));
}
@ApiOperation(value = "根据任务ID查询任务人员", httpMethod = "GET")
@GetMapping("/task/{taskId}")
public Result<List<ProjectMemberResp>> getByTaskId(@PathVariable String taskId) {
return Result.ok(projectMemberService.selectByTaskId(taskId));
}
@ApiOperation(value = "根据用户ID查询用户参与的项目", httpMethod = "GET")
@GetMapping("/user/{userId}")
public Result<List<ProjectMemberResp>> getByUserId(@PathVariable String userId) {
return Result.ok(projectMemberService.selectByUserId(userId));
}
@ApiOperation(value = "根据项目ID和角色类型查询人员", httpMethod = "GET")
@GetMapping("/project/{projectId}/role/{roleType}")
public Result<List<ProjectMemberResp>> getByProjectIdAndRoleType(@PathVariable String projectId, @PathVariable String roleType) {
return Result.ok(projectMemberService.selectByProjectIdAndRoleType(projectId, roleType));
}
@ApiOperation(value = "新增项目人员", httpMethod = "POST")
@PostMapping
public Result<?> add(@Validated(ValidationGroup.Insert.class) @RequestBody ProjectMemberReq req) {
projectMemberService.saveData(req);
return Result.ok();
}
@ApiOperation(value = "修改项目人员", httpMethod = "PUT")
@PutMapping
public Result<?> edit(@Validated(ValidationGroup.Update.class) @RequestBody ProjectMemberReq req) {
projectMemberService.updateData(req);
return Result.ok();
}
@ApiOperation(value = "删除项目人员", httpMethod = "DELETE")
@DeleteMapping("/{memberId}")
public Result<?> remove(@PathVariable String memberId) {
projectMemberService.deleteById(memberId);
return Result.ok();
}
@ApiOperation(value = "批量添加项目人员", httpMethod = "POST")
@PostMapping("/batch")
public Result<?> batchAdd(@RequestBody List<ProjectMemberReq> reqList) {
projectMemberService.batchAddMembers(reqList);
return Result.ok();
}
@ApiOperation(value = "根据项目ID删除所有项目人员", httpMethod = "DELETE")
@DeleteMapping("/project/{projectId}")
public Result<?> removeByProjectId(@PathVariable String projectId) {
projectMemberService.deleteByProjectId(projectId);
return Result.ok();
}
@ApiOperation(value = "根据机组ID删除所有机组人员", httpMethod = "DELETE")
@DeleteMapping("/turbine/{turbineId}")
public Result<?> removeByTurbineId(@PathVariable String turbineId) {
projectMemberService.deleteByTurbineId(turbineId);
return Result.ok();
}
@ApiOperation(value = "根据任务组ID删除所有任务组人员", httpMethod = "DELETE")
@DeleteMapping("/task-group/{taskGroupId}")
public Result<?> removeByTaskGroupId(@PathVariable String taskGroupId) {
projectMemberService.deleteByTaskGroupId(taskGroupId);
return Result.ok();
}
@ApiOperation(value = "根据任务ID删除所有任务人员", httpMethod = "DELETE")
@DeleteMapping("/task/{taskId}")
public Result<?> removeByTaskId(@PathVariable String taskId) {
projectMemberService.deleteByTaskId(taskId);
return Result.ok();
}
// ========================== 项目看板相关接口 ==========================
@ApiOperation(value = "获取项目看板统计数据", httpMethod = "GET")
@GetMapping("/kanban/stats")
public Result<ProjectKanbanStatsResp> getProjectKanbanStats() {
return Result.ok(projectMemberService.getProjectKanbanStats());
}
@ApiOperation(value = "获取项目看板数据", httpMethod = "GET")
@GetMapping("/kanban/data")
public Result<ProjectKanbanDataResp> getProjectKanbanData() {
return Result.ok(projectMemberService.getProjectKanbanData());
}
@ApiOperation(value = "获取项目详情", httpMethod = "GET")
@GetMapping("/project/{projectId}/detail")
public Result<ProjectDetailResp> getProjectDetail(@PathVariable String projectId) {
return Result.ok(projectMemberService.getProjectDetail(projectId));
}
}

View File

@ -3,6 +3,11 @@ server:
# 服务器的HTTP端口默认为8080 # 服务器的HTTP端口默认为8080
port: 8888 port: 8888
address : 0.0.0.0 # 监听所有网络接口 address : 0.0.0.0 # 监听所有网络接口
servlet:
encoding:
enabled: true
charset: UTF-8
force: true
# 数据源配置 # 数据源配置
spring: spring: