Commit 4494f71092a6129b9a5e682da1fd3f2acb23429b

Authored by 房远帅
1 parent 48256f23

采购-供应商报价看板:供应商报价项目看板未结束实时推送服务

Showing 12 changed files with 409 additions and 5 deletions
  1 +package com.lframework.xingyun.sc.listeners.app;
  2 +
  3 +import com.lframework.xingyun.sc.events.quotation.CommonChangedEvent;
  4 +import com.lframework.xingyun.sc.procurement.impl.quotation.SupplierQuotationProjectQuoteServiceImpl;
  5 +import com.lframework.xingyun.sc.procurement.impl.quotation.SupplierQuotationProjectServiceImpl;
  6 +import com.lframework.xingyun.sc.procurement.websocket.quotation.project.SupplierQuotationProjectRealtimePushService;
  7 +import javax.annotation.Resource;
  8 +import org.springframework.stereotype.Component;
  9 +import org.springframework.transaction.event.TransactionPhase;
  10 +import org.springframework.transaction.event.TransactionalEventListener;
  11 +
  12 +/**
  13 + * 供应商报价项目看板实时推送监听器
  14 + */
  15 +@Component
  16 +public class SupplierQuotationProjectRealtimeListener {
  17 +
  18 + @Resource
  19 + private SupplierQuotationProjectRealtimePushService realtimePushService;
  20 +
  21 + /**
  22 + * 报价项目或供应商报价变更后,广播当日完整看板数据
  23 + *
  24 + * @param event 变更事件
  25 + */
  26 + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
  27 + public void handleChanged(CommonChangedEvent event) {
  28 + if (!(event.getSource() instanceof SupplierQuotationProjectServiceImpl)
  29 + && !(event.getSource() instanceof SupplierQuotationProjectQuoteServiceImpl)) {
  30 + return;
  31 + }
  32 + realtimePushService.broadcastCurrentDayFullData(event.getEventType());
  33 + }
  34 +}
  1 +package com.lframework.xingyun.sc.procurement.dto.quotation;
  2 +
  3 +import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProject;
  4 +import java.io.Serializable;
  5 +import java.time.LocalDate;
  6 +import java.time.LocalDateTime;
  7 +import java.util.List;
  8 +import lombok.Data;
  9 +
  10 +@Data
  11 +public class SupplierQuotationProjectRealtimeMessage implements Serializable {
  12 +
  13 + private static final long serialVersionUID = 1L;
  14 +
  15 + /**
  16 + * 消息类型
  17 + */
  18 + private String messageType;
  19 +
  20 + /**
  21 + * 事件类型
  22 + */
  23 + private String eventType;
  24 +
  25 + /**
  26 + * 业务日期
  27 + */
  28 + private LocalDate businessDate;
  29 +
  30 + /**
  31 + * 推送时间
  32 + */
  33 + private LocalDateTime pushTime;
  34 +
  35 + /**
  36 + * 项目列表(内含供应商报价子表)
  37 + */
  38 + private List<SupplierQuotationProject> records;
  39 +}
  40 +
@@ -17,6 +17,7 @@ import com.lframework.starter.web.inner.service.system.SysRoleService; @@ -17,6 +17,7 @@ import com.lframework.starter.web.inner.service.system.SysRoleService;
17 import com.lframework.starter.web.inner.service.system.SysUserService; 17 import com.lframework.starter.web.inner.service.system.SysUserService;
18 import com.lframework.xingyun.basedata.entity.BreedRelationship; 18 import com.lframework.xingyun.basedata.entity.BreedRelationship;
19 import com.lframework.xingyun.basedata.service.breed.BreedRelationshipService; 19 import com.lframework.xingyun.basedata.service.breed.BreedRelationshipService;
  20 +import com.lframework.xingyun.sc.events.quotation.CommonChangedEvent;
20 import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProject; 21 import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProject;
21 import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProjectQuote; 22 import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProjectQuote;
22 import com.lframework.xingyun.sc.procurement.mappers.quotation.SupplierQuotationProjectMapper; 23 import com.lframework.xingyun.sc.procurement.mappers.quotation.SupplierQuotationProjectMapper;
@@ -32,6 +33,7 @@ import java.util.Set; @@ -32,6 +33,7 @@ import java.util.Set;
32 import java.util.stream.Collectors; 33 import java.util.stream.Collectors;
33 import javax.annotation.Resource; 34 import javax.annotation.Resource;
34 import org.apache.commons.lang3.StringUtils; 35 import org.apache.commons.lang3.StringUtils;
  36 +import org.springframework.context.ApplicationEventPublisher;
35 import org.springframework.stereotype.Service; 37 import org.springframework.stereotype.Service;
36 import org.springframework.transaction.annotation.Transactional; 38 import org.springframework.transaction.annotation.Transactional;
37 39
@@ -63,6 +65,8 @@ public class SupplierQuotationProjectQuoteServiceImpl @@ -63,6 +65,8 @@ public class SupplierQuotationProjectQuoteServiceImpl
63 private SysRoleService sysRoleService; 65 private SysRoleService sysRoleService;
64 @Resource 66 @Resource
65 private BreedRelationshipService breedRelationshipService; 67 private BreedRelationshipService breedRelationshipService;
  68 + @Resource
  69 + private ApplicationEventPublisher applicationEventPublisher;
66 70
67 @OpLog(type = OtherOpLogType.class, name = "供应商报价项目报价,项目ID:{}", params = {"#vo.projectId"}) 71 @OpLog(type = OtherOpLogType.class, name = "供应商报价项目报价,项目ID:{}", params = {"#vo.projectId"})
68 @Transactional(rollbackFor = Exception.class) 72 @Transactional(rollbackFor = Exception.class)
@@ -102,6 +106,7 @@ public class SupplierQuotationProjectQuoteServiceImpl @@ -102,6 +106,7 @@ public class SupplierQuotationProjectQuoteServiceImpl
102 .eq(SupplierQuotationProjectQuote::getId, exist.getId()); 106 .eq(SupplierQuotationProjectQuote::getId, exist.getId());
103 getBaseMapper().update(updateWrapper); 107 getBaseMapper().update(updateWrapper);
104 } 108 }
  109 + publishChangedEvent(vo.getProjectId(), "QUOTE");
105 110
106 OpLogUtil.setExtra(vo); 111 OpLogUtil.setExtra(vo);
107 } 112 }
@@ -114,18 +119,21 @@ public class SupplierQuotationProjectQuoteServiceImpl @@ -114,18 +119,21 @@ public class SupplierQuotationProjectQuoteServiceImpl
114 119
115 @Override 120 @Override
116 public List<SupplierQuotationProjectQuote> listByProject(String projectId) { 121 public List<SupplierQuotationProjectQuote> listByProject(String projectId) {
  122 + String currentUserId = SecurityUtil.getCurrentUser().getId();
  123 + return listByProject(projectId, currentUserId);
  124 + }
  125 +
  126 + @Override
  127 + public List<SupplierQuotationProjectQuote> listByProject(String projectId, String userId) {
117 SupplierQuotationProject project = supplierQuotationProjectMapper.selectById(projectId); 128 SupplierQuotationProject project = supplierQuotationProjectMapper.selectById(projectId);
118 if (project == null) { 129 if (project == null) {
119 throw new DefaultClientException("报价项目不存在!"); 130 throw new DefaultClientException("报价项目不存在!");
120 } 131 }
121 132
122 - List<SysRole> sysRoleList = sysRoleService.getByUserId(SecurityUtil.getCurrentUser().getId());  
123 - Set<String> roleCodeSet = sysRoleList.stream()  
124 - .map(SysRole::getCode)  
125 - .collect(Collectors.toSet()); 133 + Set<String> roleCodeSet = getRoleCodeSet(userId);
126 134
127 if (roleCodeSet.contains("gys")) { 135 if (roleCodeSet.contains("gys")) {
128 - SupplierQuotationProjectQuote supplierQuotationProjectQuote = getMyQuote(projectId); 136 + SupplierQuotationProjectQuote supplierQuotationProjectQuote = getBaseMapper().findByProjectAndSupplier(projectId, userId);
129 if (supplierQuotationProjectQuote == null) { 137 if (supplierQuotationProjectQuote == null) {
130 return Collections.emptyList(); 138 return Collections.emptyList();
131 } 139 }
@@ -166,6 +174,7 @@ public class SupplierQuotationProjectQuoteServiceImpl @@ -166,6 +174,7 @@ public class SupplierQuotationProjectQuoteServiceImpl
166 .set(SupplierQuotationProjectQuote::getBidStatus, bidStatus) 174 .set(SupplierQuotationProjectQuote::getBidStatus, bidStatus)
167 .eq(SupplierQuotationProjectQuote::getId, exist.getId()); 175 .eq(SupplierQuotationProjectQuote::getId, exist.getId());
168 getBaseMapper().update(updateWrapper); 176 getBaseMapper().update(updateWrapper);
  177 + publishChangedEvent(vo.getProjectId(), "BID_STATUS_UPDATE");
169 178
170 OpLogUtil.setExtra(vo); 179 OpLogUtil.setExtra(vo);
171 } 180 }
@@ -217,6 +226,17 @@ public class SupplierQuotationProjectQuoteServiceImpl @@ -217,6 +226,17 @@ public class SupplierQuotationProjectQuoteServiceImpl
217 throw new DefaultClientException("中标状态不合法!"); 226 throw new DefaultClientException("中标状态不合法!");
218 } 227 }
219 228
  229 + private void publishChangedEvent(String id, String eventType) {
  230 + applicationEventPublisher.publishEvent(new CommonChangedEvent(this, id, eventType));
  231 + }
  232 +
  233 + private Set<String> getRoleCodeSet(String userId) {
  234 + List<SysRole> sysRoleList = sysRoleService.getByUserId(userId);
  235 + return sysRoleList.stream()
  236 + .map(SysRole::getCode)
  237 + .collect(Collectors.toSet());
  238 + }
  239 +
220 private boolean isCentralBid(String projectType) { 240 private boolean isCentralBid(String projectType) {
221 if (StringUtils.isBlank(projectType)) { 241 if (StringUtils.isBlank(projectType)) {
222 return false; 242 return false;
@@ -17,6 +17,7 @@ import com.lframework.starter.web.core.utils.PageResultUtil; @@ -17,6 +17,7 @@ import com.lframework.starter.web.core.utils.PageResultUtil;
17 import com.lframework.starter.web.inner.components.oplog.OtherOpLogType; 17 import com.lframework.starter.web.inner.components.oplog.OtherOpLogType;
18 import com.lframework.xingyun.basedata.entity.BreedRelationship; 18 import com.lframework.xingyun.basedata.entity.BreedRelationship;
19 import com.lframework.xingyun.basedata.service.breed.BreedRelationshipService; 19 import com.lframework.xingyun.basedata.service.breed.BreedRelationshipService;
  20 +import com.lframework.xingyun.sc.events.quotation.CommonChangedEvent;
20 import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProject; 21 import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProject;
21 import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProjectQuote; 22 import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProjectQuote;
22 import com.lframework.xingyun.sc.procurement.mappers.quotation.SupplierQuotationProjectMapper; 23 import com.lframework.xingyun.sc.procurement.mappers.quotation.SupplierQuotationProjectMapper;
@@ -32,6 +33,7 @@ import java.time.format.DateTimeFormatter; @@ -32,6 +33,7 @@ import java.time.format.DateTimeFormatter;
32 import java.util.List; 33 import java.util.List;
33 import javax.annotation.Resource; 34 import javax.annotation.Resource;
34 import org.apache.commons.lang3.StringUtils; 35 import org.apache.commons.lang3.StringUtils;
  36 +import org.springframework.context.ApplicationEventPublisher;
35 import org.springframework.stereotype.Service; 37 import org.springframework.stereotype.Service;
36 import org.springframework.transaction.annotation.Transactional; 38 import org.springframework.transaction.annotation.Transactional;
37 39
@@ -59,6 +61,8 @@ public class SupplierQuotationProjectServiceImpl @@ -59,6 +61,8 @@ public class SupplierQuotationProjectServiceImpl
59 private BreedRelationshipService breedRelationshipService; 61 private BreedRelationshipService breedRelationshipService;
60 @Resource 62 @Resource
61 private SupplierQuotationProjectQuoteService supplierQuotationProjectQuoteService; 63 private SupplierQuotationProjectQuoteService supplierQuotationProjectQuoteService;
  64 + @Resource
  65 + private ApplicationEventPublisher applicationEventPublisher;
62 66
63 @Override 67 @Override
64 public PageResult<SupplierQuotationProject> query(Integer pageIndex, Integer pageSize, QuerySupplierQuotationProjectVo vo) { 68 public PageResult<SupplierQuotationProject> query(Integer pageIndex, Integer pageSize, QuerySupplierQuotationProjectVo vo) {
@@ -78,6 +82,20 @@ public class SupplierQuotationProjectServiceImpl @@ -78,6 +82,20 @@ public class SupplierQuotationProjectServiceImpl
78 } 82 }
79 83
80 @Override 84 @Override
  85 + public List<SupplierQuotationProject> queryCurrentDayBoardList(LocalDate day, String userId) {
  86 + List<SupplierQuotationProject> datas = getBaseMapper().queryCurrentDayList(day);
  87 + fillComputedStatus(datas);
  88 + if (datas == null || datas.isEmpty()) {
  89 + return datas;
  90 + }
  91 + for (SupplierQuotationProject data : datas) {
  92 + List<SupplierQuotationProjectQuote> quoteList = supplierQuotationProjectQuoteService.listByProject(data.getId(), userId);
  93 + data.setSupplierQuotationProjectQuoteList(quoteList);
  94 + }
  95 + return datas;
  96 + }
  97 +
  98 + @Override
81 public SupplierQuotationProject findById(String id) { 99 public SupplierQuotationProject findById(String id) {
82 SupplierQuotationProject data = getBaseMapper().findById(id); 100 SupplierQuotationProject data = getBaseMapper().findById(id);
83 if (data != null) { 101 if (data != null) {
@@ -109,6 +127,7 @@ public class SupplierQuotationProjectServiceImpl @@ -109,6 +127,7 @@ public class SupplierQuotationProjectServiceImpl
109 data.setStatus(null); 127 data.setStatus(null);
110 128
111 getBaseMapper().insert(data); 129 getBaseMapper().insert(data);
  130 + publishChangedEvent(data.getId(), "CREATE");
112 131
113 OpLogUtil.setVariable("id", data.getId()); 132 OpLogUtil.setVariable("id", data.getId());
114 OpLogUtil.setExtra(vo); 133 OpLogUtil.setExtra(vo);
@@ -139,6 +158,7 @@ public class SupplierQuotationProjectServiceImpl @@ -139,6 +158,7 @@ public class SupplierQuotationProjectServiceImpl
139 .eq(SupplierQuotationProject::getId, vo.getId()); 158 .eq(SupplierQuotationProject::getId, vo.getId());
140 159
141 getBaseMapper().update(updateWrapper); 160 getBaseMapper().update(updateWrapper);
  161 + publishChangedEvent(vo.getId(), "UPDATE");
142 162
143 OpLogUtil.setVariable("id", vo.getId()); 163 OpLogUtil.setVariable("id", vo.getId());
144 OpLogUtil.setExtra(vo); 164 OpLogUtil.setExtra(vo);
@@ -149,6 +169,7 @@ public class SupplierQuotationProjectServiceImpl @@ -149,6 +169,7 @@ public class SupplierQuotationProjectServiceImpl
149 @Override 169 @Override
150 public void delete(String id) { 170 public void delete(String id) {
151 getBaseMapper().deleteById(id); 171 getBaseMapper().deleteById(id);
  172 + publishChangedEvent(id, "DELETE");
152 173
153 OpLogUtil.setVariable("id", id); 174 OpLogUtil.setVariable("id", id);
154 OpLogUtil.setExtra(id); 175 OpLogUtil.setExtra(id);
@@ -168,6 +189,7 @@ public class SupplierQuotationProjectServiceImpl @@ -168,6 +189,7 @@ public class SupplierQuotationProjectServiceImpl
168 .eq(SupplierQuotationProject::getId, id); 189 .eq(SupplierQuotationProject::getId, id);
169 190
170 getBaseMapper().update(updateWrapper); 191 getBaseMapper().update(updateWrapper);
  192 + publishChangedEvent(id, "STATUS_UPDATE");
171 193
172 OpLogUtil.setVariable("id", id); 194 OpLogUtil.setVariable("id", id);
173 OpLogUtil.setExtra(status); 195 OpLogUtil.setExtra(status);
@@ -257,5 +279,9 @@ public class SupplierQuotationProjectServiceImpl @@ -257,5 +279,9 @@ public class SupplierQuotationProjectServiceImpl
257 return data.getStatus(); 279 return data.getStatus();
258 } 280 }
259 281
  282 + private void publishChangedEvent(String id, String eventType) {
  283 + applicationEventPublisher.publishEvent(new CommonChangedEvent(this, id, eventType));
  284 + }
  285 +
260 } 286 }
261 287
@@ -2,6 +2,7 @@ package com.lframework.xingyun.sc.procurement.mappers.quotation; @@ -2,6 +2,7 @@ package com.lframework.xingyun.sc.procurement.mappers.quotation;
2 2
3 import com.lframework.starter.web.core.mapper.BaseMapper; 3 import com.lframework.starter.web.core.mapper.BaseMapper;
4 import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProject; 4 import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProject;
  5 +import java.time.LocalDate;
5 import com.lframework.xingyun.sc.procurement.vo.quotation.QuerySupplierQuotationProjectVo; 6 import com.lframework.xingyun.sc.procurement.vo.quotation.QuerySupplierQuotationProjectVo;
6 import java.util.List; 7 import java.util.List;
7 import org.apache.ibatis.annotations.Param; 8 import org.apache.ibatis.annotations.Param;
@@ -13,5 +14,7 @@ public interface SupplierQuotationProjectMapper extends BaseMapper<SupplierQuota @@ -13,5 +14,7 @@ public interface SupplierQuotationProjectMapper extends BaseMapper<SupplierQuota
13 SupplierQuotationProject findById(@Param("id") String id); 14 SupplierQuotationProject findById(@Param("id") String id);
14 15
15 String getMaxCodeByDay(@Param("dayPrefix") String dayPrefix); 16 String getMaxCodeByDay(@Param("dayPrefix") String dayPrefix);
  17 +
  18 + List<SupplierQuotationProject> queryCurrentDayList(@Param("day") LocalDate day);
16 } 19 }
17 20
@@ -14,6 +14,8 @@ public interface SupplierQuotationProjectQuoteService extends BaseMpService<Supp @@ -14,6 +14,8 @@ public interface SupplierQuotationProjectQuoteService extends BaseMpService<Supp
14 14
15 List<SupplierQuotationProjectQuote> listByProject(String projectId); 15 List<SupplierQuotationProjectQuote> listByProject(String projectId);
16 16
  17 + List<SupplierQuotationProjectQuote> listByProject(String projectId, String userId);
  18 +
17 void updateBidStatus(UpdateSupplierQuotationProjectQuoteBidStatusVo vo); 19 void updateBidStatus(UpdateSupplierQuotationProjectQuoteBidStatusVo vo);
18 } 20 }
19 21
@@ -6,6 +6,7 @@ import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProject; @@ -6,6 +6,7 @@ import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProject;
6 import com.lframework.xingyun.sc.procurement.vo.quotation.CreateSupplierQuotationProjectVo; 6 import com.lframework.xingyun.sc.procurement.vo.quotation.CreateSupplierQuotationProjectVo;
7 import com.lframework.xingyun.sc.procurement.vo.quotation.QuerySupplierQuotationProjectVo; 7 import com.lframework.xingyun.sc.procurement.vo.quotation.QuerySupplierQuotationProjectVo;
8 import com.lframework.xingyun.sc.procurement.vo.quotation.UpdateSupplierQuotationProjectVo; 8 import com.lframework.xingyun.sc.procurement.vo.quotation.UpdateSupplierQuotationProjectVo;
  9 +import java.time.LocalDate;
9 import java.util.List; 10 import java.util.List;
10 11
11 public interface SupplierQuotationProjectService extends BaseMpService<SupplierQuotationProject> { 12 public interface SupplierQuotationProjectService extends BaseMpService<SupplierQuotationProject> {
@@ -22,6 +23,8 @@ public interface SupplierQuotationProjectService extends BaseMpService<SupplierQ @@ -22,6 +23,8 @@ public interface SupplierQuotationProjectService extends BaseMpService<SupplierQ
22 23
23 void delete(String id); 24 void delete(String id);
24 25
  26 + List<SupplierQuotationProject> queryCurrentDayBoardList(LocalDate day, String userId);
  27 +
25 /** 28 /**
26 * 更新项目状态 29 * 更新项目状态
27 * 30 *
  1 +package com.lframework.xingyun.sc.procurement.websocket.quotation.project;
  2 +
  3 +import com.lframework.starter.web.core.utils.JsonUtil;
  4 +import com.lframework.xingyun.sc.procurement.dto.quotation.SupplierQuotationProjectRealtimeMessage;
  5 +import com.lframework.xingyun.sc.procurement.entity.SupplierQuotationProject;
  6 +import com.lframework.xingyun.sc.procurement.service.quotation.SupplierQuotationProjectService;
  7 +import java.io.IOException;
  8 +import java.time.LocalDate;
  9 +import java.time.LocalDateTime;
  10 +import java.util.List;
  11 +import java.util.Map;
  12 +import java.util.concurrent.ConcurrentHashMap;
  13 +import javax.annotation.Resource;
  14 +import lombok.extern.slf4j.Slf4j;
  15 +import org.apache.commons.lang3.StringUtils;
  16 +import org.springframework.stereotype.Service;
  17 +import org.springframework.web.socket.TextMessage;
  18 +import org.springframework.web.socket.WebSocketSession;
  19 +
  20 +/**
  21 + * 供应商报价项目看板实时推送服务
  22 + */
  23 +@Slf4j
  24 +@Service
  25 +public class SupplierQuotationProjectRealtimePushService {
  26 +
  27 + /**
  28 + * 当前在线连接
  29 + */
  30 + private final Map<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();
  31 +
  32 + @Resource
  33 + private SupplierQuotationProjectService supplierQuotationProjectService;
  34 +
  35 + /**
  36 + * 注册连接
  37 + *
  38 + * @param session WebSocket 会话
  39 + */
  40 + public void register(WebSocketSession session) {
  41 + sessionMap.put(session.getId(), session);
  42 + }
  43 +
  44 + /**
  45 + * 注销连接
  46 + *
  47 + * @param session WebSocket 会话
  48 + */
  49 + public void unregister(WebSocketSession session) {
  50 + if (session != null) {
  51 + sessionMap.remove(session.getId());
  52 + }
  53 + }
  54 +
  55 + /**
  56 + * 广播当日完整报价项目看板数据
  57 + *
  58 + * @param eventType 事件类型
  59 + */
  60 + public void broadcastCurrentDayFullData(String eventType) {
  61 + if (sessionMap.isEmpty()) {
  62 + return;
  63 + }
  64 +
  65 + for (WebSocketSession session : sessionMap.values()) {
  66 + replayCurrentDayFullData(session, eventType);
  67 + }
  68 + }
  69 +
  70 + /**
  71 + * 向单个连接补推当日完整报价项目看板数据
  72 + *
  73 + * @param session WebSocket 会话
  74 + * @param eventType 事件类型
  75 + */
  76 + public void replayCurrentDayFullData(WebSocketSession session, String eventType) {
  77 + if (session == null) {
  78 + return;
  79 + }
  80 + sendMessage(session, JsonUtil.toJsonString(buildCurrentDayMessage(session, eventType)));
  81 + }
  82 +
  83 + /**
  84 + * 构建当日完整数据消息
  85 + *
  86 + * @param session WebSocket 会话
  87 + * @param eventType 事件类型
  88 + * @return 推送消息
  89 + */
  90 + private SupplierQuotationProjectRealtimeMessage buildCurrentDayMessage(WebSocketSession session, String eventType) {
  91 + LocalDate today = LocalDate.now();
  92 + String userId = getUserId(session);
  93 + List<SupplierQuotationProject> records = supplierQuotationProjectService.queryCurrentDayBoardList(today, userId);
  94 +
  95 + SupplierQuotationProjectRealtimeMessage message = new SupplierQuotationProjectRealtimeMessage();
  96 + message.setMessageType("FULL_SYNC");
  97 + message.setEventType(eventType);
  98 + message.setBusinessDate(today);
  99 + message.setPushTime(LocalDateTime.now());
  100 + message.setRecords(records);
  101 + return message;
  102 + }
  103 +
  104 + /**
  105 + * 发送消息
  106 + *
  107 + * @param session WebSocket 会话
  108 + * @param payload 消息体
  109 + */
  110 + private void sendMessage(WebSocketSession session, String payload) {
  111 + if (session == null || !session.isOpen()) {
  112 + unregister(session);
  113 + return;
  114 + }
  115 +
  116 + try {
  117 + synchronized (session) {
  118 + session.sendMessage(new TextMessage(payload));
  119 + }
  120 + } catch (IOException e) {
  121 + log.warn("供应商报价项目看板实时推送失败,sessionId={}", session.getId(), e);
  122 + unregister(session);
  123 + }
  124 + }
  125 +
  126 + /**
  127 + * 获取连接用户ID
  128 + *
  129 + * @param session WebSocket 会话
  130 + * @return 用户ID
  131 + */
  132 + private String getUserId(WebSocketSession session) {
  133 + Object userId = session.getAttributes().get(SupplierQuotationProjectWebSocketHandshakeInterceptor.ATTR_USER_ID);
  134 + return userId == null ? StringUtils.EMPTY : String.valueOf(userId);
  135 + }
  136 +}
  137 +
  1 +package com.lframework.xingyun.sc.procurement.websocket.quotation.project;
  2 +
  3 +import javax.annotation.Resource;
  4 +import org.springframework.context.annotation.Configuration;
  5 +import org.springframework.web.socket.config.annotation.EnableWebSocket;
  6 +import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
  7 +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
  8 +
  9 +/**
  10 + * 供应商报价项目看板 WebSocket 配置
  11 + */
  12 +@Configuration
  13 +@EnableWebSocket
  14 +public class SupplierQuotationProjectWebSocketConfig implements WebSocketConfigurer {
  15 +
  16 + /**
  17 + * WebSocket 路径
  18 + */
  19 + public static final String ENDPOINT = "/ws/procurement/supplierQuotationProject/realtime";
  20 +
  21 + @Resource
  22 + private SupplierQuotationProjectWebSocketHandler webSocketHandler;
  23 + @Resource
  24 + private SupplierQuotationProjectWebSocketHandshakeInterceptor handshakeInterceptor;
  25 +
  26 + @Override
  27 + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  28 + registry.addHandler(webSocketHandler, ENDPOINT)
  29 + .addInterceptors(handshakeInterceptor)
  30 + .setAllowedOrigins("*");
  31 + }
  32 +}
  33 +
  1 +package com.lframework.xingyun.sc.procurement.websocket.quotation.project;
  2 +
  3 +import javax.annotation.Resource;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.apache.commons.lang3.StringUtils;
  6 +import org.springframework.stereotype.Component;
  7 +import org.springframework.web.socket.CloseStatus;
  8 +import org.springframework.web.socket.TextMessage;
  9 +import org.springframework.web.socket.WebSocketSession;
  10 +import org.springframework.web.socket.handler.TextWebSocketHandler;
  11 +
  12 +/**
  13 + * 供应商报价项目看板 WebSocket 处理器
  14 + */
  15 +@Slf4j
  16 +@Component
  17 +public class SupplierQuotationProjectWebSocketHandler extends TextWebSocketHandler {
  18 +
  19 + @Resource
  20 + private SupplierQuotationProjectRealtimePushService realtimePushService;
  21 +
  22 + @Override
  23 + public void afterConnectionEstablished(WebSocketSession session) {
  24 + realtimePushService.register(session);
  25 + realtimePushService.replayCurrentDayFullData(session, "INIT");
  26 + }
  27 +
  28 + @Override
  29 + protected void handleTextMessage(WebSocketSession session, TextMessage message) {
  30 + String payload = StringUtils.trimToEmpty(message.getPayload());
  31 + if ("SYNC_TODAY".equalsIgnoreCase(payload) || "RESYNC".equalsIgnoreCase(payload)) {
  32 + realtimePushService.replayCurrentDayFullData(session, "RESYNC");
  33 + }
  34 + }
  35 +
  36 + @Override
  37 + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
  38 + realtimePushService.unregister(session);
  39 + }
  40 +
  41 + @Override
  42 + public void handleTransportError(WebSocketSession session, Throwable exception) {
  43 + log.warn("供应商报价项目看板 WebSocket 连接异常,sessionId={}", session.getId(), exception);
  44 + realtimePushService.unregister(session);
  45 + }
  46 +}
  47 +
  1 +package com.lframework.xingyun.sc.procurement.websocket.quotation.project;
  2 +
  3 +import com.lframework.starter.web.inner.entity.SysUser;
  4 +import com.lframework.xingyun.sc.procurement.websocket.quotation.CommonWebSocketAuthService;
  5 +import java.util.Map;
  6 +import javax.annotation.Resource;
  7 +import org.springframework.http.HttpStatus;
  8 +import org.springframework.http.server.ServerHttpRequest;
  9 +import org.springframework.http.server.ServerHttpResponse;
  10 +import org.springframework.stereotype.Component;
  11 +import org.springframework.web.socket.WebSocketHandler;
  12 +import org.springframework.web.socket.server.HandshakeInterceptor;
  13 +
  14 +/**
  15 + * 供应商报价项目看板 WebSocket 握手鉴权拦截器
  16 + */
  17 +@Component
  18 +public class SupplierQuotationProjectWebSocketHandshakeInterceptor implements HandshakeInterceptor {
  19 +
  20 + /**
  21 + * 用户ID属性名
  22 + */
  23 + public static final String ATTR_USER_ID = "userId";
  24 +
  25 + /**
  26 + * 用户名称属性名
  27 + */
  28 + public static final String ATTR_USER_NAME = "userName";
  29 +
  30 + @Resource
  31 + private CommonWebSocketAuthService authService;
  32 +
  33 + @Override
  34 + public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
  35 + WebSocketHandler wsHandler, Map<String, Object> attributes) {
  36 + try {
  37 + SysUser user = authService.authenticateCurrentUser();
  38 + attributes.put(ATTR_USER_ID, user.getId());
  39 + attributes.put(ATTR_USER_NAME, user.getName());
  40 + return true;
  41 + } catch (Exception e) {
  42 + response.setStatusCode(HttpStatus.FORBIDDEN);
  43 + return false;
  44 + }
  45 + }
  46 +
  47 + @Override
  48 + public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
  49 + WebSocketHandler wsHandler, Exception exception) {
  50 + }
  51 +}
  52 +
@@ -89,5 +89,12 @@ @@ -89,5 +89,12 @@
89 ORDER BY CAST(RIGHT(tb.code, 2) AS UNSIGNED) DESC 89 ORDER BY CAST(RIGHT(tb.code, 2) AS UNSIGNED) DESC
90 LIMIT 1 90 LIMIT 1
91 </select> 91 </select>
  92 +
  93 + <select id="queryCurrentDayList" resultMap="SupplierQuotationProject">
  94 + <include refid="SupplierQuotationProjectSql"/>
  95 + WHERE DATE(tb.create_time) = #{day}
  96 + AND tb.status='PUBLISHED'
  97 + ORDER BY tb.create_time DESC, tb.id DESC
  98 + </select>
92 </mapper> 99 </mapper>
93 100