feat:项目个人置顶

This commit is contained in:
2026-03-31 16:21:59 +08:00
parent 4fb61e90a6
commit 061c75b5d6
8 changed files with 173 additions and 12 deletions

View File

@@ -7,7 +7,8 @@ public enum NodeMemberTypeEnum {
MANAGER("项目经理", 0),
ATTENTION("项目关注人", 1);
ATTENTION("项目关注人", 1),
PINNED("项目置顶人", 2);
private final String name;

View File

@@ -156,7 +156,7 @@ public class SimulationNodeController implements ISimulationNodeFeignClient {
*/
@PostMapping("/getAllNodeByNodeType")
@Operation(summary = "根据节点类型获取所有节点", description = "根据节点类型获取所有节点")
public SdmResponse<List<AllNodeByProjectIdAndTypeResp>> getAllNodeByNodeTypeAndUUidsWithKeyWord(@RequestBody GetAllNodeByNodeTypeReq req) {
public SdmResponse<List<AllNodeByProjectIdAndTypeResp>> getAllNodeByNodeTypeAndUUidsWithKeyWord(@RequestBody GetAllNodeByNodeTypeReq req) {
return nodeService.getAllNodeByNodeTypeAndUUidsWithKeyWord(req.getNodeType(), req.getUuids(), req.getKeyword());
}
@@ -448,5 +448,12 @@ public class SimulationNodeController implements ISimulationNodeFeignClient {
return nodeService.unFollowProject(req.getNodeId());
}
@SysLog("置顶/取消置顶项目")
@PostMapping("/togglePinProject")
@Operation(summary = "置顶/取消置顶项目", description = "置顶/取消置顶项目")
public SdmResponse togglePinProject(@RequestBody @Validated NodePinnedReq req) {
return nodeService.togglePinProject(req.getNodeId(), req.getPinned());
}
}

View File

@@ -43,19 +43,19 @@ public interface SimulationNodeMapper extends BaseMapper<SimulationNode> {
List<SpdmNodeVo> getNodeList(@Param("nodeType") String nodeType, @Param("nodeSubType") String nodeSubType, @Param("exeStatus") String exeStatus, @Param("nodeCode") String nodeCode,
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId, @Param("pos") int pos, @Param("limit") int limit);
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId, @Param("pos") int pos, @Param("limit") int limit, @Param("userId") Long userId);
List<SpdmNodeVo> getResponsibleNodeList(@Param("nodeType") String nodeType, @Param("nodeSubType") String nodeSubType, @Param("exeStatus") String exeStatus, @Param("nodeCode") String nodeCode,
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId, @Param("pos") int pos, @Param("limit") int limit);
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId, @Param("pos") int pos, @Param("limit") int limit);
List<SpdmNodeVo> getNodeListNoPermission(@Param("nodeType") String nodeType, @Param("nodeSubType") String nodeSubType, @Param("exeStatus") String exeStatus, @Param("nodeCode") String nodeCode,
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId, @Param("pos") int pos, @Param("limit") int limit);
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId, @Param("pos") int pos, @Param("limit") int limit);
int getNodeListCount(@Param("nodeType") String nodeType, @Param("nodeSubType") String nodeSubType, @Param("exeStatus") String exeStatus, @Param("nodeCode") String nodeCode,
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId);
int getNodeListCountNoPermission(@Param("nodeType") String nodeType, @Param("nodeSubType") String nodeSubType, @Param("exeStatus") String exeStatus, @Param("nodeCode") String nodeCode,
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId);
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId);
List<SpdmNodeExtraVo> getNodeExtraListByNodeIdList(@Param("nodeIdList") List<String> nodeIdList);
@@ -118,7 +118,7 @@ public interface SimulationNodeMapper extends BaseMapper<SimulationNode> {
List<SpdmNodeVo> getNodeListByUserId(@Param("nodeType") String nodeType, @Param("nodeSubType") String nodeSubType, @Param("exeStatus") String exeStatus, @Param("nodeCode") String nodeCode,
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId, @Param("pos") int pos, @Param("limit") int limit, @Param("userId") Long userId,@Param("type") Integer type);
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId, @Param("pos") int pos, @Param("limit") int limit, @Param("userId") Long userId,@Param("type") Integer type);
int getNodeListCountByUserId(@Param("nodeType") String nodeType, @Param("nodeSubType") String nodeSubType, @Param("exeStatus") String exeStatus, @Param("nodeCode") String nodeCode,
@Param("manager") String manager, @Param("nodeName") String nodeName, @Param("tenantId") Long tenantId, @Param("userId") Long userId,@Param("type") Integer type);

View File

@@ -0,0 +1,21 @@
package com.sdm.project.model.req;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class NodePinnedReq {
/**
* 项目节点ID
*/
@NotBlank(message = "项目ID不能为空")
private String nodeId;
/**
* true=置顶false=取消置顶
*/
@NotNull(message = "置顶状态不能为空")
private Boolean pinned;
}

View File

@@ -116,6 +116,16 @@ public class SpdmNodeVo extends BaseEntity {
*/
private Integer attentionFlag = 0;
/**
* 置顶类型0-未置顶1-个人置顶
*/
private Integer pinnedType = 0;
/**
* 置顶时间
*/
private String pinnedTime;
/**
* 任务总数
*/

View File

@@ -100,6 +100,11 @@ public interface INodeService extends IService<SimulationNode> {
*/
SdmResponse followProject(String nodeId);
/**
* 设置/取消个人置顶
*/
SdmResponse togglePinProject(String nodeId, Boolean pinned);
/**
* 取消关注项目(批量为多个用户删除项目关注关系)
*

View File

@@ -517,7 +517,7 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
// type=0查询所有使用原有查询逻辑
if (type == null || type == 0) {
nodeList = nodeMapper.getNodeList(req.getNodeType(), req.getNodeSubType(), req.getExeStatus(), req.getNodeCode(), req.getManager(), req.getNodeName(),
tenantId, pos, limit);
tenantId, pos, limit, userId);
// 设置关注标签
if (CollectionUtils.isNotEmpty(nodeList)) {
List<String> nodeIdList = nodeList.stream().map(SpdmNodeVo::getUuid).toList();
@@ -675,18 +675,81 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
spdmNodeVo.setCreatorObj(userMap.get(creator));
}
}
// 将当前阶段放到项目对象中返回
setCurrentPhase(nodeList);
// 获取项目下的任务完成情况统计
setTaskCompleteStatistics(nodeList, req.getFilterDiscipline());
// 置顶排序已在SQL中完成无需内存排序
JSONObject jsonObject = new JSONObject();
jsonObject.put("data", nodeList);
jsonObject.put("total", total);
return SdmResponse.success(jsonObject);
}
/**
* 设置项目的置顶信息并排序(置顶项目排在前面,按置顶时间倒序)
*/
private void setPinnedInfoAndSort(List<SpdmNodeVo> nodeList) {
if (CollectionUtils.isEmpty(nodeList)) {
return;
}
Long userId = ThreadLocalContext.getUserId();
// 查询当前用户的所有置顶记录
LambdaQueryWrapper<SimulationNodeMember> queryWrapper = new LambdaQueryWrapper<SimulationNodeMember>()
.eq(SimulationNodeMember::getUserId, userId)
.eq(SimulationNodeMember::getType, NodeMemberTypeEnum.PINNED.getCode());
List<SimulationNodeMember> pinnedList = simulationNodeMemberService.list(queryWrapper);
if (CollectionUtils.isNotEmpty(pinnedList)) {
// 构建 nodeId -> createTime 的映射
Map<String, String> pinnedMap = pinnedList.stream()
.collect(Collectors.toMap(
SimulationNodeMember::getNodeId,
SimulationNodeMember::getCreateTime,
(a, b) -> a
));
// 设置置顶信息
for (SpdmNodeVo node : nodeList) {
String pinnedTime = pinnedMap.get(node.getUuid());
if (pinnedTime != null) {
node.setPinnedType(1);
node.setPinnedTime(pinnedTime);
}
}
}
// 排序:置顶项目排前面(按置顶时间倒序),非置顶项目保持原有顺序
nodeList.sort((a, b) -> {
int typeA = a.getPinnedType() != null ? a.getPinnedType() : 0;
int typeB = b.getPinnedType() != null ? b.getPinnedType() : 0;
// 置顶的排前面
if (typeA != typeB) {
return typeB - typeA;
}
// 都置顶,按置顶时间倒序
if (typeA == 1) {
String timeA = a.getPinnedTime();
String timeB = b.getPinnedTime();
if (timeA != null && timeB != null) {
return timeB.compareTo(timeA);
}
if (timeA != null) return -1;
if (timeB != null) return 1;
}
return 0;
});
}
/**
* 设置项目当前阶段信息
* @param nodeList
@@ -4696,6 +4759,49 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
return SdmResponse.success(UNFOLLOW_SUCCESS_MSG);
}
@Override
@Transactional(rollbackFor = Exception.class)
public SdmResponse togglePinProject(String nodeId, Boolean pinned) {
Long userId = ThreadLocalContext.getUserId();
// 查询项目节点是否存在
SimulationNode projectNode = this.lambdaQuery().eq(SimulationNode::getUuid, nodeId).one();
if (projectNode == null) {
return SdmResponse.failed("项目不存在");
}
if (Boolean.TRUE.equals(pinned)) {
// 置顶:检查是否已置顶
LambdaQueryWrapper<SimulationNodeMember> queryWrapper = new LambdaQueryWrapper<SimulationNodeMember>()
.eq(SimulationNodeMember::getNodeId, nodeId)
.eq(SimulationNodeMember::getUserId, userId)
.eq(SimulationNodeMember::getType, NodeMemberTypeEnum.PINNED.getCode());
SimulationNodeMember existing = simulationNodeMemberService.getOne(queryWrapper);
if (existing != null) {
return SdmResponse.success("已置顶");
}
// 添加置顶记录
SimulationNodeMember member = new SimulationNodeMember();
member.setNodeId(nodeId);
member.setUserId(userId);
member.setType(NodeMemberTypeEnum.PINNED.getCode());
member.setCreator(userId);
member.setCreateTime(LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.NORM_DATETIME_PATTERN));
simulationNodeMemberService.save(member);
return SdmResponse.success("置顶成功");
} else {
// 取消置顶
simulationNodeMemberService.lambdaUpdate()
.eq(SimulationNodeMember::getNodeId, nodeId)
.eq(SimulationNodeMember::getUserId, userId)
.eq(SimulationNodeMember::getType, NodeMemberTypeEnum.PINNED.getCode())
.remove();
return SdmResponse.success("取消置顶成功");
}
}
@Override
public SdmResponse exportProjectByScript(HttpServletResponse httpServletResponse, ProjectExportExcelFormat projectExportExcelFormat) {
SpdmNodeListReq req = new SpdmNodeListReq();

View File

@@ -227,7 +227,13 @@
</delete>
<select id="getNodeList" resultType="com.sdm.project.model.vo.SpdmNodeVo">
select * from simulation_node sn
select sn.*, IFNULL(pin.pinnedType, 0) as pinnedType, pin.pinnedTime
from simulation_node sn
LEFT JOIN (
SELECT nodeId, 1 as pinnedType, create_time as pinnedTime
FROM simulation_node_member
WHERE user_id = #{userId} AND type = 2
) pin ON sn.uuid = pin.nodeId
where sn.tenantId = #{tenantId}
<if test="nodeType != null and nodeType != ''">
and sn.nodeType = #{nodeType}
@@ -250,7 +256,7 @@
<bind name="searchKey3" value="'%' + nodeName + '%'"/>
and sn.nodeName like #{searchKey3}
</if>
order by create_time desc
order by IFNULL(pin.pinnedType, 0) desc, pin.pinnedTime desc, sn.create_time desc
limit #{pos},#{limit}
</select>
@@ -877,10 +883,15 @@
</select>
<select id="getNodeListByUserId" resultType="com.sdm.project.model.vo.SpdmNodeVo">
SELECT distinct sn.*
SELECT distinct sn.*, IFNULL(pin.pinnedType, 0) as pinnedType, pin.pinnedTime
FROM simulation_node sn
LEFT JOIN simulation_node_member snm ON sn.uuid = snm.nodeId
and snm.user_id = #{userId}
LEFT JOIN (
SELECT nodeId, 1 as pinnedType, create_time as pinnedTime
FROM simulation_node_member
WHERE user_id = #{userId} AND type = 2
) pin ON sn.uuid = pin.nodeId
where sn.tenantId = #{tenantId}
<choose>
<!-- 我关注的 -->
@@ -913,7 +924,7 @@
<bind name="searchKey3" value="'%' + nodeName + '%'"/>
and sn.nodeName like #{searchKey3}
</if>
order by create_time desc
order by IFNULL(pin.pinnedType, 0) desc, pin.pinnedTime desc, sn.create_time desc
limit #{pos},#{limit}
</select>