diff --git a/stdiet-admin/src/main/java/com/stdiet/web/controller/custom/WebSocketController.java b/stdiet-admin/src/main/java/com/stdiet/web/controller/custom/WebSocketController.java
new file mode 100644
index 000000000..4ae0335ec
--- /dev/null
+++ b/stdiet-admin/src/main/java/com/stdiet/web/controller/custom/WebSocketController.java
@@ -0,0 +1,53 @@
+package com.stdiet.web.controller.custom;
+
+import com.alibaba.fastjson.JSONObject;
+import com.stdiet.common.core.controller.BaseController;
+import com.stdiet.custom.utils.WsUtils;
+import com.stdiet.custom.server.WebSocketServer;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+@Controller
+@EnableScheduling
+@RequestMapping("/ws/api")
+public class WebSocketController extends BaseController {
+
+ @ResponseBody
+ @RequestMapping("/push/{cid}")
+ public Map pushToWeb(@PathVariable String cid, String message) {
+ if (message == null) {
+ message = "我是消息44";
+ }
+ Map result = new HashMap();
+ try {
+ WebSocketServer.sendInfo(message, cid);
+ result.put("code", 200);
+ result.put("msg", "success");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return result;
+
+ }
+
+// @Scheduled(fixedRate = 30000)
+// public void boardCast() {
+// try {
+// JSONObject heartBeat = new JSONObject();
+// heartBeat.put("type", WsUtils.WS_TYPE_HEART_BEAT);
+// heartBeat.put("msg", "ping");
+//
+// WebSocketServer.sendInfo(heartBeat.toJSONString(), null);
+// } catch (IOException e) {
+// e.printStackTrace();
+// }
+// }
+}
diff --git a/stdiet-custom/pom.xml b/stdiet-custom/pom.xml
index 5db28a2cc..a7e81b668 100644
--- a/stdiet-custom/pom.xml
+++ b/stdiet-custom/pom.xml
@@ -99,6 +99,11 @@
ikanalyzer
2012_u6
+
+ org.apache.tomcat.embed
+ tomcat-embed-websocket
+
+
\ No newline at end of file
diff --git a/stdiet-custom/src/main/java/com/stdiet/custom/domain/SysServicesTopic.java b/stdiet-custom/src/main/java/com/stdiet/custom/domain/SysServicesTopic.java
index f465d7522..ca31d6095 100644
--- a/stdiet-custom/src/main/java/com/stdiet/custom/domain/SysServicesTopic.java
+++ b/stdiet-custom/src/main/java/com/stdiet/custom/domain/SysServicesTopic.java
@@ -85,8 +85,15 @@ public class SysServicesTopic {
String toName;
String name;
+ String avatar;
+ String fromAvatar;
+ String toAvatar;
+
+
List comments;
List replys;
+ Integer count;
+
}
diff --git a/stdiet-custom/src/main/java/com/stdiet/custom/mapper/SysServicesTopicMapper.java b/stdiet-custom/src/main/java/com/stdiet/custom/mapper/SysServicesTopicMapper.java
index 333417f81..0217a94e8 100644
--- a/stdiet-custom/src/main/java/com/stdiet/custom/mapper/SysServicesTopicMapper.java
+++ b/stdiet-custom/src/main/java/com/stdiet/custom/mapper/SysServicesTopicMapper.java
@@ -18,4 +18,6 @@ public interface SysServicesTopicMapper {
int inserSysServicesTopicReply(SysServicesTopic topic);
List selectSysServicesTopicSessionByTopicId(String topicId);
+
+ List selectUnreadTopicCount(List topics);
}
diff --git a/stdiet-custom/src/main/java/com/stdiet/custom/server/WebSocketServer.java b/stdiet-custom/src/main/java/com/stdiet/custom/server/WebSocketServer.java
new file mode 100644
index 000000000..7bc506c04
--- /dev/null
+++ b/stdiet-custom/src/main/java/com/stdiet/custom/server/WebSocketServer.java
@@ -0,0 +1,143 @@
+package com.stdiet.custom.server;
+
+import com.alibaba.fastjson.JSONObject;
+import com.stdiet.common.core.domain.model.LoginUser;
+import com.stdiet.common.utils.spring.SpringUtils;
+import com.stdiet.custom.domain.SysServicesTopic;
+import com.stdiet.custom.service.ISysServicesTopicService;
+import com.stdiet.custom.utils.WsUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.stereotype.Component;
+
+import javax.websocket.*;
+import javax.websocket.server.ServerEndpoint;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+@ServerEndpoint(value = "/ws")
+@Component
+@Slf4j
+public class WebSocketServer {
+ // concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
+ private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet();
+
+ //private static ConcurrentHashMap websocketList = new ConcurrentHashMap<>();
+ // 与某个客户端的连接会话,需要通过它来给客户端发送数据
+ private Session session;
+ // 接收sid
+ private String sid = "";
+
+ public static CopyOnWriteArraySet getWebSocketSet() {
+ return webSocketSet;
+ }
+
+ /**
+ * 群发自定义消息
+ */
+ public static void sendInfo(String message, String sid) throws IOException {
+ log.info("推送消息到窗口" + sid + ",推送内容:" + message + "目标:" + webSocketSet.size());
+ for (WebSocketServer item : webSocketSet) {
+ try {
+ // 这里可以设定只推送给这个sid的,为null则全部推送
+ if (sid == null) {
+ item.sendMessage(message);
+ } else if (item.sid.equals(sid)) {
+ item.sendMessage(message);
+ }
+ } catch (IOException e) {
+ // 清理断开的连接
+ webSocketSet.remove(item);
+ continue;
+ }
+ }
+ }
+
+ // * 连接建立成功调用的方法*
+ @OnOpen
+ public void onOpen(Session session) {
+ this.session = session;
+ this.sid = String.valueOf(getUserId(session));
+
+ webSocketSet.add(this); // 加入set中
+
+ try {
+ JSONObject object = new JSONObject();
+ object.put("type", WsUtils.WS_TYPE_SYSTEM_MESSAGE);
+ object.put("msg", "连接成功");
+ sendMessage(object.toJSONString());
+ } catch (IOException e) {
+ log.error("websocket IO异常");
+ }
+ }
+
+ @OnClose
+ public void onClose() {
+ webSocketSet.remove(this); // 从set中删除
+ log.info("有一连接关闭!");
+ }
+
+
+ /**
+ * @param session
+ * @param error
+ */
+ @OnError
+ public void onError(Session session, Throwable error) {
+ log.error("发生错误");
+ error.printStackTrace();
+ }
+
+ /**
+ * 实现服务器主动推送
+ */
+ public void sendMessage(String message) throws IOException {
+ log.info("服务器消息推送:" + message);
+ this.session.getBasicRemote().sendText(message);
+ }
+
+ public Long getUserId(Session session) {
+ try {
+ return ((LoginUser) ((UsernamePasswordAuthenticationToken) session.getUserPrincipal()).getPrincipal()).getUser().getUserId();
+ } catch (Exception e) {
+ return 0L;
+ }
+ }
+
+ @OnMessage
+ public void onMessage(String message, Session session) {
+ log.info("收到来自窗口" + sid + "的信息:" + message);
+ try {
+ String sid = String.valueOf(getUserId(session));
+ if (sid.equals("0")) {
+ return;
+ }
+ JSONObject resultObj = new JSONObject();
+ if (message.equals(WsUtils.WS_GET_UNREAD_COUNT)) {
+ SysServicesTopic topic = new SysServicesTopic();
+ topic.setUid(sid);
+ List statusList = new ArrayList<>();
+ statusList.add(topic);
+ ISysServicesTopicService servicesTopicService = SpringUtils.getBean(ISysServicesTopicService.class);
+ List result = servicesTopicService.selectUnreadTopicCount(statusList);
+
+ JSONObject dataObj = new JSONObject();
+ dataObj.put("count", result.get(0).getCount());
+
+ resultObj.put("type", WsUtils.WS_TYPE_MESSAGE_COUNT);
+ resultObj.put("msg", "未读消息数");
+ resultObj.put("data", dataObj);
+
+ } else if (message.equals(WsUtils.WS_PING)) {
+
+ }
+ WebSocketServer.sendInfo(resultObj.toJSONString(), sid);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/stdiet-custom/src/main/java/com/stdiet/custom/service/ISysServicesTopicService.java b/stdiet-custom/src/main/java/com/stdiet/custom/service/ISysServicesTopicService.java
index 1b9b14291..054424584 100644
--- a/stdiet-custom/src/main/java/com/stdiet/custom/service/ISysServicesTopicService.java
+++ b/stdiet-custom/src/main/java/com/stdiet/custom/service/ISysServicesTopicService.java
@@ -17,4 +17,6 @@ public interface ISysServicesTopicService {
SysServicesTopic inserSysServicesTopicComment(SysServicesTopic topic);
List selectSysServicesTopicSessionByTopicId(String topicId);
+
+ List selectUnreadTopicCount(List topic);
}
diff --git a/stdiet-custom/src/main/java/com/stdiet/custom/service/impl/SysServicesTopicServiceImp.java b/stdiet-custom/src/main/java/com/stdiet/custom/service/impl/SysServicesTopicServiceImp.java
index dcecfdd49..1e57ffabd 100644
--- a/stdiet-custom/src/main/java/com/stdiet/custom/service/impl/SysServicesTopicServiceImp.java
+++ b/stdiet-custom/src/main/java/com/stdiet/custom/service/impl/SysServicesTopicServiceImp.java
@@ -1,15 +1,19 @@
package com.stdiet.custom.service.impl;
+import com.alibaba.fastjson.JSONObject;
import com.stdiet.common.utils.DateUtils;
import com.stdiet.common.utils.uuid.UUID;
import com.stdiet.custom.domain.SysCustomer;
import com.stdiet.custom.domain.SysServicesTopic;
import com.stdiet.custom.mapper.SysCustomerMapper;
import com.stdiet.custom.mapper.SysServicesTopicMapper;
+import com.stdiet.custom.server.WebSocketServer;
import com.stdiet.custom.service.ISysServicesTopicService;
+import com.stdiet.custom.utils.WsUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -40,35 +44,58 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
List statusList = new ArrayList<>();
+ String customerId = String.valueOf(customer.getId());
SysServicesTopic customerStatus = new SysServicesTopic();
- customerStatus.setUid(String.valueOf(customer.getId()));
+ customerStatus.setUid(customerId);
customerStatus.setRole("customer");
customerStatus.setRead(1);
customerStatus.setTopicId(topic.getTopicId());
statusList.add(customerStatus);
+ String dieticianId = String.valueOf(customer.getMainDietitian());
SysServicesTopic dieticianStatus = new SysServicesTopic();
- dieticianStatus.setUid(String.valueOf(customer.getMainDietitian()));
+ dieticianStatus.setUid(dieticianId);
dieticianStatus.setRole("dietician");
dieticianStatus.setRead(0);
dieticianStatus.setTopicId(topic.getTopicId());
statusList.add(dieticianStatus);
+ String afterSaleId = String.valueOf(customer.getAfterDietitian());
SysServicesTopic afterSaleStatus = new SysServicesTopic();
- afterSaleStatus.setUid(String.valueOf(customer.getAfterDietitian()));
+ afterSaleStatus.setUid(afterSaleId);
afterSaleStatus.setRole("after_sale");
afterSaleStatus.setRead(0);
afterSaleStatus.setTopicId(topic.getTopicId());
statusList.add(afterSaleStatus);
+ String dieticianAssistantId = String.valueOf(customer.getAssistantDietitian());
SysServicesTopic dieticianAssistantStatus = new SysServicesTopic();
- dieticianAssistantStatus.setUid(String.valueOf(customer.getAssistantDietitian()));
+ dieticianAssistantStatus.setUid(dieticianAssistantId);
dieticianAssistantStatus.setRole("dietician_assistant");
dieticianAssistantStatus.setRead(0);
dieticianAssistantStatus.setTopicId(topic.getTopicId());
statusList.add(dieticianAssistantStatus);
- servicesTopicMapper.insertSysServicesTopicStatus(statusList);
+ int rows = servicesTopicMapper.insertSysServicesTopicStatus(statusList);
+ if (rows > 0) {
+ try {
+ List counts = servicesTopicMapper.selectUnreadTopicCount(statusList);
+ for (int i = 0; i < counts.size(); i++) {
+ topic.setId(statusList.get(i).getId());
+ JSONObject dataObj = new JSONObject();
+ dataObj.put("count", counts.get(i).getCount());
+ dataObj.put("data", topic);
+
+ JSONObject msgObj = new JSONObject();
+ msgObj.put("type", WsUtils.WS_TYPE_MESSAGE_COUNT);
+ msgObj.put("msg", "未读消息数");
+ msgObj.put("data", dataObj);
+ WebSocketServer.sendInfo(msgObj.toJSONString(), counts.get(i).getUid());
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
topic.setId(customerStatus.getId());
topic.setUid(null);
@@ -94,10 +121,13 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
status.setTopicId(topic.getTopicId());
status.setRole(topic.getRole());
servicesTopicMapper.updateSysServicesTopicStatus(status);
+
+ afterReply(topic);
}
return topic;
}
+
@Override
public SysServicesTopic inserSysServicesTopicComment(SysServicesTopic topic) {
String uuid = java.util.UUID.randomUUID().toString().replace("-", "");
@@ -110,12 +140,51 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
status.setTopicId(topic.getTopicId());
status.setRole(topic.getRole());
servicesTopicMapper.updateSysServicesTopicStatus(status);
+
+ afterReply(topic);
}
return topic;
}
+ public void afterReply(SysServicesTopic topic) {
+ SysCustomer customer = sysCustomerMapper.selectSysCustomerById(Long.parseLong(topic.getFromUid()));
+
+ List statusList = new ArrayList<>();
+ SysServicesTopic dieticianStatus = new SysServicesTopic();
+ dieticianStatus.setUid(String.valueOf(customer.getMainDietitian()));
+ statusList.add(dieticianStatus);
+ SysServicesTopic afterSaleStatus = new SysServicesTopic();
+ afterSaleStatus.setUid(String.valueOf(customer.getAfterDietitian()));
+ statusList.add(afterSaleStatus);
+ SysServicesTopic dieticianAssistantStatus = new SysServicesTopic();
+ dieticianAssistantStatus.setUid(String.valueOf(customer.getAssistantDietitian()));
+ statusList.add(dieticianAssistantStatus);
+
+ try {
+ List counts = servicesTopicMapper.selectUnreadTopicCount(statusList);
+ for (int i = 0; i < counts.size(); i++) {
+ JSONObject dataObj = new JSONObject();
+ dataObj.put("count", counts.get(i).getCount());
+ dataObj.put("topicId", topic.getTopicId());
+
+ JSONObject msgObj = new JSONObject();
+ msgObj.put("type", WsUtils.WS_TYPE_NEW_CUSTOMER_REPLY);
+ msgObj.put("msg", "新客户回复");
+ msgObj.put("data", dataObj);
+ WebSocketServer.sendInfo(msgObj.toJSONString(), statusList.get(i).getUid());
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
@Override
public List selectSysServicesTopicSessionByTopicId(String topicId) {
return servicesTopicMapper.selectSysServicesTopicSessionByTopicId(topicId);
}
+
+ @Override
+ public List selectUnreadTopicCount(List statusList) {
+ return servicesTopicMapper.selectUnreadTopicCount(statusList);
+ }
}
diff --git a/stdiet-custom/src/main/java/com/stdiet/custom/utils/WsUtils.java b/stdiet-custom/src/main/java/com/stdiet/custom/utils/WsUtils.java
new file mode 100644
index 000000000..a1b2286bf
--- /dev/null
+++ b/stdiet-custom/src/main/java/com/stdiet/custom/utils/WsUtils.java
@@ -0,0 +1,16 @@
+package com.stdiet.custom.utils;
+
+public class WsUtils {
+
+ public static final String WS_TYPE_HEART_BEAT = "WS_TYPE_HEART_BEAT";
+
+ public static final String WS_TYPE_SYSTEM_MESSAGE = "WS_TYPE_SYSTEM_MESSAGE";
+
+ public static final String WS_TYPE_MESSAGE_COUNT = "WS_TYPE_MESSAGE_COUNT";
+
+ public static final String WS_TYPE_NEW_CUSTOMER_REPLY = "WS_TYPE_NEW_CUSTOMER_REPLY";
+
+ public static final String WS_GET_UNREAD_COUNT = "GET_UNREAD_COUNT";
+
+ public static final String WS_PING = "ping";
+}
diff --git a/stdiet-custom/src/main/resources/mapper/custom/SysServicesTopicMapper.xml b/stdiet-custom/src/main/resources/mapper/custom/SysServicesTopicMapper.xml
index 688494714..4afeb6edb 100644
--- a/stdiet-custom/src/main/resources/mapper/custom/SysServicesTopicMapper.xml
+++ b/stdiet-custom/src/main/resources/mapper/custom/SysServicesTopicMapper.xml
@@ -22,11 +22,22 @@
@@ -39,6 +50,7 @@
+
@@ -53,7 +65,9 @@
+
+
@@ -71,7 +85,9 @@
+
+
@@ -103,6 +119,19 @@
+
+
+
@@ -225,5 +254,23 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/stdiet-custom/src/main/resources/mapper/custom/SysWxFanStatisticsMapper.xml b/stdiet-custom/src/main/resources/mapper/custom/SysWxFanStatisticsMapper.xml
index 0e8f7664e..ce3a124cf 100644
--- a/stdiet-custom/src/main/resources/mapper/custom/SysWxFanStatisticsMapper.xml
+++ b/stdiet-custom/src/main/resources/mapper/custom/SysWxFanStatisticsMapper.xml
@@ -67,7 +67,7 @@
) AS wfs ON wd.wechat_account = wfs.wx_id
LEFT JOIN (SELECT id, wx_account, wx_phone FROM sys_wx_sale_account) AS wsa ON wd.wechat_account = wsa.id
- LEFT JOIN (SELECT dict_label, dict_value FROM sys_dict_data WHERE dict_type = 'fan_channel') AS cn ON cn.dict_value = wd.account_id
+ LEFT JOIN (SELECT dict_label, dict_value FROM sys_dict_data WHERE dict_type = 'cus_account') AS cn ON cn.dict_value = wd.account_id
LEFT JOIN sys_user AS su ON su.user_id = wd.user_id
WHERE wd.del_flag = 0
ORDER BY wd.sale_group_id, wd.user_id, wd.wechat_account ASC
diff --git a/stdiet-framework/pom.xml b/stdiet-framework/pom.xml
index 6db2e7872..c94845c5d 100644
--- a/stdiet-framework/pom.xml
+++ b/stdiet-framework/pom.xml
@@ -59,6 +59,23 @@
stdiet-system
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
\ No newline at end of file
diff --git a/stdiet-framework/src/main/java/com/stdiet/framework/config/SecurityConfig.java b/stdiet-framework/src/main/java/com/stdiet/framework/config/SecurityConfig.java
index af34f5aa1..07f5dc900 100644
--- a/stdiet-framework/src/main/java/com/stdiet/framework/config/SecurityConfig.java
+++ b/stdiet-framework/src/main/java/com/stdiet/framework/config/SecurityConfig.java
@@ -102,6 +102,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
"/custom/wxUserInfo/wx/**",
"/custom/wxUserLog/wx/**",
"/wx/**",
+// "/ws/**",
"/wap/**",
"/investigate/**",
"/common/customerUploadFile",
diff --git a/stdiet-framework/src/main/java/com/stdiet/framework/config/WebsocketConfig.java b/stdiet-framework/src/main/java/com/stdiet/framework/config/WebsocketConfig.java
new file mode 100644
index 000000000..795c5a971
--- /dev/null
+++ b/stdiet-framework/src/main/java/com/stdiet/framework/config/WebsocketConfig.java
@@ -0,0 +1,18 @@
+package com.stdiet.framework.config;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+@Configuration
+@ConditionalOnWebApplication
+public class WebsocketConfig {
+
+ @Bean
+ public ServerEndpointExporter serverEndpointExporter() {
+ return new ServerEndpointExporter();
+ }
+
+
+}
diff --git a/stdiet-ui/src/components/RecipesPlanDrawer/index.vue b/stdiet-ui/src/components/RecipesPlanDrawer/index.vue
index 66535901b..60e7b60b1 100644
--- a/stdiet-ui/src/components/RecipesPlanDrawer/index.vue
+++ b/stdiet-ui/src/components/RecipesPlanDrawer/index.vue
@@ -75,14 +75,14 @@
{{ `${scope.row.startDate} 至 ${scope.row.endDate}` }}
-
+
{{ scope.row.subscribed ? "已订阅" : "未订阅" }}
-
+
-
+