feat:项目个人置顶
This commit is contained in:
@@ -7,7 +7,8 @@ public enum NodeMemberTypeEnum {
|
||||
|
||||
|
||||
MANAGER("项目经理", 0),
|
||||
ATTENTION("项目关注人", 1);
|
||||
ATTENTION("项目关注人", 1),
|
||||
PINNED("项目置顶人", 2);
|
||||
|
||||
|
||||
private final String name;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -116,6 +116,16 @@ public class SpdmNodeVo extends BaseEntity {
|
||||
*/
|
||||
private Integer attentionFlag = 0;
|
||||
|
||||
/**
|
||||
* 置顶类型:0-未置顶,1-个人置顶
|
||||
*/
|
||||
private Integer pinnedType = 0;
|
||||
|
||||
/**
|
||||
* 置顶时间
|
||||
*/
|
||||
private String pinnedTime;
|
||||
|
||||
/**
|
||||
* 任务总数
|
||||
*/
|
||||
|
||||
@@ -100,6 +100,11 @@ public interface INodeService extends IService<SimulationNode> {
|
||||
*/
|
||||
SdmResponse followProject(String nodeId);
|
||||
|
||||
/**
|
||||
* 设置/取消个人置顶
|
||||
*/
|
||||
SdmResponse togglePinProject(String nodeId, Boolean pinned);
|
||||
|
||||
/**
|
||||
* 取消关注项目(批量为多个用户删除项目关注关系)
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user