Merge branch 'master' of https://gitee.com/darlk/ShengTangManage into xzj
This commit is contained in:
commit
06d62ea4a0
@ -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();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
@ -99,6 +99,11 @@
|
|||||||
<artifactId>ikanalyzer</artifactId>
|
<artifactId>ikanalyzer</artifactId>
|
||||||
<version>2012_u6</version>
|
<version>2012_u6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
@ -85,8 +85,15 @@ public class SysServicesTopic {
|
|||||||
String toName;
|
String toName;
|
||||||
String name;
|
String name;
|
||||||
|
|
||||||
|
String avatar;
|
||||||
|
String fromAvatar;
|
||||||
|
String toAvatar;
|
||||||
|
|
||||||
|
|
||||||
List<SysServicesTopic> comments;
|
List<SysServicesTopic> comments;
|
||||||
|
|
||||||
List<SysServicesTopic> replys;
|
List<SysServicesTopic> replys;
|
||||||
|
|
||||||
|
Integer count;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,4 +18,6 @@ public interface SysServicesTopicMapper {
|
|||||||
int inserSysServicesTopicReply(SysServicesTopic topic);
|
int inserSysServicesTopicReply(SysServicesTopic topic);
|
||||||
|
|
||||||
List<SysServicesTopic> selectSysServicesTopicSessionByTopicId(String topicId);
|
List<SysServicesTopic> selectSysServicesTopicSessionByTopicId(String topicId);
|
||||||
|
|
||||||
|
List<SysServicesTopic> selectUnreadTopicCount(List<SysServicesTopic> topics);
|
||||||
}
|
}
|
||||||
|
@ -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<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
|
||||||
|
|
||||||
|
//private static ConcurrentHashMap<String,WebSocketServer> websocketList = new ConcurrentHashMap<>();
|
||||||
|
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
|
||||||
|
private Session session;
|
||||||
|
// 接收sid
|
||||||
|
private String sid = "";
|
||||||
|
|
||||||
|
public static CopyOnWriteArraySet<WebSocketServer> 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<SysServicesTopic> statusList = new ArrayList<>();
|
||||||
|
statusList.add(topic);
|
||||||
|
ISysServicesTopicService servicesTopicService = SpringUtils.getBean(ISysServicesTopicService.class);
|
||||||
|
List<SysServicesTopic> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -17,4 +17,6 @@ public interface ISysServicesTopicService {
|
|||||||
SysServicesTopic inserSysServicesTopicComment(SysServicesTopic topic);
|
SysServicesTopic inserSysServicesTopicComment(SysServicesTopic topic);
|
||||||
|
|
||||||
List<SysServicesTopic> selectSysServicesTopicSessionByTopicId(String topicId);
|
List<SysServicesTopic> selectSysServicesTopicSessionByTopicId(String topicId);
|
||||||
|
|
||||||
|
List<SysServicesTopic> selectUnreadTopicCount(List<SysServicesTopic> topic);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
package com.stdiet.custom.service.impl;
|
package com.stdiet.custom.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.stdiet.common.utils.DateUtils;
|
import com.stdiet.common.utils.DateUtils;
|
||||||
import com.stdiet.common.utils.uuid.UUID;
|
import com.stdiet.common.utils.uuid.UUID;
|
||||||
import com.stdiet.custom.domain.SysCustomer;
|
import com.stdiet.custom.domain.SysCustomer;
|
||||||
import com.stdiet.custom.domain.SysServicesTopic;
|
import com.stdiet.custom.domain.SysServicesTopic;
|
||||||
import com.stdiet.custom.mapper.SysCustomerMapper;
|
import com.stdiet.custom.mapper.SysCustomerMapper;
|
||||||
import com.stdiet.custom.mapper.SysServicesTopicMapper;
|
import com.stdiet.custom.mapper.SysServicesTopicMapper;
|
||||||
|
import com.stdiet.custom.server.WebSocketServer;
|
||||||
import com.stdiet.custom.service.ISysServicesTopicService;
|
import com.stdiet.custom.service.ISysServicesTopicService;
|
||||||
|
import com.stdiet.custom.utils.WsUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -40,35 +44,58 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
|
|||||||
|
|
||||||
List<SysServicesTopic> statusList = new ArrayList<>();
|
List<SysServicesTopic> statusList = new ArrayList<>();
|
||||||
|
|
||||||
|
String customerId = String.valueOf(customer.getId());
|
||||||
SysServicesTopic customerStatus = new SysServicesTopic();
|
SysServicesTopic customerStatus = new SysServicesTopic();
|
||||||
customerStatus.setUid(String.valueOf(customer.getId()));
|
customerStatus.setUid(customerId);
|
||||||
customerStatus.setRole("customer");
|
customerStatus.setRole("customer");
|
||||||
customerStatus.setRead(1);
|
customerStatus.setRead(1);
|
||||||
customerStatus.setTopicId(topic.getTopicId());
|
customerStatus.setTopicId(topic.getTopicId());
|
||||||
statusList.add(customerStatus);
|
statusList.add(customerStatus);
|
||||||
|
|
||||||
|
String dieticianId = String.valueOf(customer.getMainDietitian());
|
||||||
SysServicesTopic dieticianStatus = new SysServicesTopic();
|
SysServicesTopic dieticianStatus = new SysServicesTopic();
|
||||||
dieticianStatus.setUid(String.valueOf(customer.getMainDietitian()));
|
dieticianStatus.setUid(dieticianId);
|
||||||
dieticianStatus.setRole("dietician");
|
dieticianStatus.setRole("dietician");
|
||||||
dieticianStatus.setRead(0);
|
dieticianStatus.setRead(0);
|
||||||
dieticianStatus.setTopicId(topic.getTopicId());
|
dieticianStatus.setTopicId(topic.getTopicId());
|
||||||
statusList.add(dieticianStatus);
|
statusList.add(dieticianStatus);
|
||||||
|
|
||||||
|
String afterSaleId = String.valueOf(customer.getAfterDietitian());
|
||||||
SysServicesTopic afterSaleStatus = new SysServicesTopic();
|
SysServicesTopic afterSaleStatus = new SysServicesTopic();
|
||||||
afterSaleStatus.setUid(String.valueOf(customer.getAfterDietitian()));
|
afterSaleStatus.setUid(afterSaleId);
|
||||||
afterSaleStatus.setRole("after_sale");
|
afterSaleStatus.setRole("after_sale");
|
||||||
afterSaleStatus.setRead(0);
|
afterSaleStatus.setRead(0);
|
||||||
afterSaleStatus.setTopicId(topic.getTopicId());
|
afterSaleStatus.setTopicId(topic.getTopicId());
|
||||||
statusList.add(afterSaleStatus);
|
statusList.add(afterSaleStatus);
|
||||||
|
|
||||||
|
String dieticianAssistantId = String.valueOf(customer.getAssistantDietitian());
|
||||||
SysServicesTopic dieticianAssistantStatus = new SysServicesTopic();
|
SysServicesTopic dieticianAssistantStatus = new SysServicesTopic();
|
||||||
dieticianAssistantStatus.setUid(String.valueOf(customer.getAssistantDietitian()));
|
dieticianAssistantStatus.setUid(dieticianAssistantId);
|
||||||
dieticianAssistantStatus.setRole("dietician_assistant");
|
dieticianAssistantStatus.setRole("dietician_assistant");
|
||||||
dieticianAssistantStatus.setRead(0);
|
dieticianAssistantStatus.setRead(0);
|
||||||
dieticianAssistantStatus.setTopicId(topic.getTopicId());
|
dieticianAssistantStatus.setTopicId(topic.getTopicId());
|
||||||
statusList.add(dieticianAssistantStatus);
|
statusList.add(dieticianAssistantStatus);
|
||||||
|
|
||||||
servicesTopicMapper.insertSysServicesTopicStatus(statusList);
|
int rows = servicesTopicMapper.insertSysServicesTopicStatus(statusList);
|
||||||
|
if (rows > 0) {
|
||||||
|
try {
|
||||||
|
List<SysServicesTopic> 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.setId(customerStatus.getId());
|
||||||
topic.setUid(null);
|
topic.setUid(null);
|
||||||
@ -94,10 +121,13 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
|
|||||||
status.setTopicId(topic.getTopicId());
|
status.setTopicId(topic.getTopicId());
|
||||||
status.setRole(topic.getRole());
|
status.setRole(topic.getRole());
|
||||||
servicesTopicMapper.updateSysServicesTopicStatus(status);
|
servicesTopicMapper.updateSysServicesTopicStatus(status);
|
||||||
|
|
||||||
|
afterReply(topic);
|
||||||
}
|
}
|
||||||
return topic;
|
return topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SysServicesTopic inserSysServicesTopicComment(SysServicesTopic topic) {
|
public SysServicesTopic inserSysServicesTopicComment(SysServicesTopic topic) {
|
||||||
String uuid = java.util.UUID.randomUUID().toString().replace("-", "");
|
String uuid = java.util.UUID.randomUUID().toString().replace("-", "");
|
||||||
@ -110,12 +140,51 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
|
|||||||
status.setTopicId(topic.getTopicId());
|
status.setTopicId(topic.getTopicId());
|
||||||
status.setRole(topic.getRole());
|
status.setRole(topic.getRole());
|
||||||
servicesTopicMapper.updateSysServicesTopicStatus(status);
|
servicesTopicMapper.updateSysServicesTopicStatus(status);
|
||||||
|
|
||||||
|
afterReply(topic);
|
||||||
}
|
}
|
||||||
return topic;
|
return topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void afterReply(SysServicesTopic topic) {
|
||||||
|
SysCustomer customer = sysCustomerMapper.selectSysCustomerById(Long.parseLong(topic.getFromUid()));
|
||||||
|
|
||||||
|
List<SysServicesTopic> 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<SysServicesTopic> 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
|
@Override
|
||||||
public List<SysServicesTopic> selectSysServicesTopicSessionByTopicId(String topicId) {
|
public List<SysServicesTopic> selectSysServicesTopicSessionByTopicId(String topicId) {
|
||||||
return servicesTopicMapper.selectSysServicesTopicSessionByTopicId(topicId);
|
return servicesTopicMapper.selectSysServicesTopicSessionByTopicId(topicId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SysServicesTopic> selectUnreadTopicCount(List<SysServicesTopic> statusList) {
|
||||||
|
return servicesTopicMapper.selectUnreadTopicCount(statusList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
|
}
|
@ -22,11 +22,22 @@
|
|||||||
<!-- 根据userId和角色查询问题列表-->
|
<!-- 根据userId和角色查询问题列表-->
|
||||||
<select id="selectSysServicesTopicByUserIdAndRole" parameterType="SysServicesTopic"
|
<select id="selectSysServicesTopicByUserIdAndRole" parameterType="SysServicesTopic"
|
||||||
resultMap="SysServicesTopicResult">
|
resultMap="SysServicesTopicResult">
|
||||||
SELECT * FROM (
|
<choose>
|
||||||
SELECT topic_id, id, `read`, create_time, update_time, 'customer' AS role FROM sys_services_topic_status WHERE role = #{role} AND uid = #{uid}
|
<when test="role == 'admin' or role == 'manager' or role == 'admin-dev'">
|
||||||
) AS status
|
select topic_id, topic_type, content, uid, create_time, img, 1 as `read`, '0' as id, 'customer' as role
|
||||||
LEFT JOIN sys_services_topic USING(topic_id)
|
from sys_services_topic where del_flag = 0 order by create_time desc
|
||||||
ORDER BY `read` ASC, update_time DESC
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
SELECT * FROM (
|
||||||
|
SELECT topic_id, id, `read`, create_time, update_time, 'customer' AS role FROM sys_services_topic_status
|
||||||
|
WHERE role = #{role} AND uid = #{uid}
|
||||||
|
) AS status
|
||||||
|
LEFT JOIN sys_services_topic USING(topic_id) WHERE del_flag = 0
|
||||||
|
ORDER BY `read` ASC, update_time DESC
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 查询主题-->
|
<!-- 查询主题-->
|
||||||
@ -39,6 +50,7 @@
|
|||||||
<result column="img" property="img" typeHandler="com.stdiet.custom.typehandler.ArrayJsonHandler"/>
|
<result column="img" property="img" typeHandler="com.stdiet.custom.typehandler.ArrayJsonHandler"/>
|
||||||
<result column="create_time" property="createTime"/>
|
<result column="create_time" property="createTime"/>
|
||||||
<association property="name" column="{uid=uid,role=role}" select="selectUserInfo"/>
|
<association property="name" column="{uid=uid,role=role}" select="selectUserInfo"/>
|
||||||
|
<association property="avatar" column="{uid=uid,role=role}" select="selectUserAvatar"/>
|
||||||
<association property="comments" column="topic_id" select="selectServicesTopicCommentByTopicId"/>
|
<association property="comments" column="topic_id" select="selectServicesTopicCommentByTopicId"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
@ -53,7 +65,9 @@
|
|||||||
<result column="img" property="img" typeHandler="com.stdiet.custom.typehandler.ArrayJsonHandler"/>
|
<result column="img" property="img" typeHandler="com.stdiet.custom.typehandler.ArrayJsonHandler"/>
|
||||||
<result column="create_time" property="createTime"/>
|
<result column="create_time" property="createTime"/>
|
||||||
<association property="fromName" column="{uid=from_uid,role=from_role}" select="selectUserInfo"/>
|
<association property="fromName" column="{uid=from_uid,role=from_role}" select="selectUserInfo"/>
|
||||||
|
<association property="fromAvatar" column="{uid=from_uid,role=from_role}" select="selectUserAvatar"/>
|
||||||
<association property="toName" column="{uid=to_uid,role=to_role}" select="selectUserInfo"/>
|
<association property="toName" column="{uid=to_uid,role=to_role}" select="selectUserInfo"/>
|
||||||
|
<!-- <association property="toAvatar" column="{uid=to_uid,role=to_role}" select="selectUserAvatar"/>-->
|
||||||
<association property="replys" column="id"
|
<association property="replys" column="id"
|
||||||
select="selectServicesTopicCommentReplyByCommentId"/>
|
select="selectServicesTopicCommentReplyByCommentId"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
@ -71,7 +85,9 @@
|
|||||||
<result column="img" property="img" typeHandler="com.stdiet.custom.typehandler.ArrayJsonHandler"/>
|
<result column="img" property="img" typeHandler="com.stdiet.custom.typehandler.ArrayJsonHandler"/>
|
||||||
<result column="create_time" property="createTime"/>
|
<result column="create_time" property="createTime"/>
|
||||||
<association property="fromName" column="{uid=from_uid,role=from_role}" select="selectUserInfo"/>
|
<association property="fromName" column="{uid=from_uid,role=from_role}" select="selectUserInfo"/>
|
||||||
|
<association property="fromAvatar" column="{uid=from_uid,role=from_role}" select="selectUserAvatar"/>
|
||||||
<association property="toName" column="{uid=to_uid,role=to_role}" select="selectUserInfo"/>
|
<association property="toName" column="{uid=to_uid,role=to_role}" select="selectUserInfo"/>
|
||||||
|
<!-- <association property="toAvatar" column="{uid=to_uid,role=to_role}" select="selectUserAvatar"/>-->
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
|
|
||||||
@ -103,6 +119,19 @@
|
|||||||
</choose>
|
</choose>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- 查询头像-->
|
||||||
|
<select id="selectUserAvatar" parameterType="java.util.Map" resultType="String">
|
||||||
|
<choose>
|
||||||
|
<when test="_parameter.get('role') == 'customer'">
|
||||||
|
select avatar_url from sys_wx_user_info where cus_id = #{uid}
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
select IF(avatar != '', CONCAT("https://api.stdiet.top/prod-api", avatar), '') as avatar from sys_user
|
||||||
|
where user_id = #{uid}
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</select>
|
||||||
|
|
||||||
<!-- 插入问题-->
|
<!-- 插入问题-->
|
||||||
<insert id="insertSysServicesTopic" parameterType="SysServicesTopic" useGeneratedKeys="true"
|
<insert id="insertSysServicesTopic" parameterType="SysServicesTopic" useGeneratedKeys="true"
|
||||||
keyProperty="id" keyColumn="id">
|
keyProperty="id" keyColumn="id">
|
||||||
@ -225,5 +254,23 @@
|
|||||||
</trim>
|
</trim>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
<resultMap type="SysServicesTopic" id="SysServicesCountResult">
|
||||||
|
<result column="uid" property="uid"/>
|
||||||
|
<result column="count" property="count"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<select id="selectUnreadTopicCount" parameterType="java.util.List" resultMap="SysServicesCountResult">
|
||||||
|
<foreach collection="list" item="status" index="index">
|
||||||
|
<choose>
|
||||||
|
<when test="index == 0">
|
||||||
|
SELECT COUNT(*) AS count, uid FROM sys_services_topic_status WHERE `read` = 0 AND uid =
|
||||||
|
#{status.uid}
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
UNION ALL SELECT COUNT(*) AS count, uid FROM sys_services_topic_status WHERE `read` = 0 AND uid =
|
||||||
|
#{status.uid}
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
@ -67,7 +67,7 @@
|
|||||||
</if>
|
</if>
|
||||||
) AS wfs ON wd.wechat_account = wfs.wx_id
|
) 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 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
|
LEFT JOIN sys_user AS su ON su.user_id = wd.user_id
|
||||||
WHERE wd.del_flag = 0
|
WHERE wd.del_flag = 0
|
||||||
ORDER BY wd.sale_group_id, wd.user_id, wd.wechat_account ASC
|
ORDER BY wd.sale_group_id, wd.user_id, wd.wechat_account ASC
|
||||||
|
@ -59,6 +59,23 @@
|
|||||||
<artifactId>stdiet-system</artifactId>
|
<artifactId>stdiet-system</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- websocket-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -102,6 +102,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
"/custom/wxUserInfo/wx/**",
|
"/custom/wxUserInfo/wx/**",
|
||||||
"/custom/wxUserLog/wx/**",
|
"/custom/wxUserLog/wx/**",
|
||||||
"/wx/**",
|
"/wx/**",
|
||||||
|
// "/ws/**",
|
||||||
"/wap/**",
|
"/wap/**",
|
||||||
"/investigate/**",
|
"/investigate/**",
|
||||||
"/common/customerUploadFile",
|
"/common/customerUploadFile",
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -75,14 +75,14 @@
|
|||||||
{{ `${scope.row.startDate} 至 ${scope.row.endDate}` }}
|
{{ `${scope.row.startDate} 至 ${scope.row.endDate}` }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="订阅情况" align="center">
|
<el-table-column label="订阅情况" align="center" width="80">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag :type="scope.row.subscribed ? 'success' : 'danger'">
|
<el-tag :type="scope.row.subscribed ? 'success' : 'danger'">
|
||||||
{{ scope.row.subscribed ? "已订阅" : "未订阅" }}
|
{{ scope.row.subscribed ? "已订阅" : "未订阅" }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="发送" align="center" width="80">
|
<el-table-column label="发送" align="center" width="60">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-switch
|
<el-switch
|
||||||
v-model="!!scope.row.sendFlag"
|
v-model="!!scope.row.sendFlag"
|
||||||
@ -90,7 +90,7 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" align="center" width="160">
|
<el-table-column label="操作" align="center" width="140">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button
|
||||||
type="text"
|
type="text"
|
||||||
@ -102,7 +102,6 @@
|
|||||||
{{ `${scope.row.recipesId ? "编辑" : "制作"}` }}
|
{{ `${scope.row.recipesId ? "编辑" : "制作"}` }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="scope.row.reviewStatus === 1"
|
|
||||||
type="text"
|
type="text"
|
||||||
icon="el-icon-delete"
|
icon="el-icon-delete"
|
||||||
@click="handleOnDelete(scope.row)"
|
@click="handleOnDelete(scope.row)"
|
||||||
|
@ -11,26 +11,11 @@
|
|||||||
|
|
||||||
<div class="right-menu">
|
<div class="right-menu">
|
||||||
<template v-if="device !== 'mobile'">
|
<template v-if="device !== 'mobile'">
|
||||||
<!-- <search id="header-search" class="right-menu-item" /> -->
|
|
||||||
|
|
||||||
<!-- <el-tooltip content="源码地址" effect="dark" placement="bottom">
|
|
||||||
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
|
|
||||||
</el-tooltip> -->
|
|
||||||
|
|
||||||
<!-- <el-tooltip content="文档地址" effect="dark" placement="bottom">
|
|
||||||
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
|
|
||||||
</el-tooltip> -->
|
|
||||||
|
|
||||||
<!-- <screenfull id="screenfull" class="right-menu-item hover-effect" /> -->
|
|
||||||
|
|
||||||
<!-- <el-tooltip content="布局大小" effect="dark" placement="bottom">
|
|
||||||
<size-select id="size-select" class="right-menu-item hover-effect" />
|
|
||||||
</el-tooltip> -->
|
|
||||||
<div
|
<div
|
||||||
class="right-menu-item hover-effect badge_style"
|
class="right-menu-item hover-effect badge_style"
|
||||||
@click="handleOnMessageClick"
|
@click="handleOnMessageClick"
|
||||||
>
|
>
|
||||||
<el-badge :value="12">
|
<el-badge :value="msgUnreadCount">
|
||||||
<el-tooltip content="消息" effect="dark" placement="bottom">
|
<el-tooltip content="消息" effect="dark" placement="bottom">
|
||||||
<em class="el-icon-message" :style="{ fontSize: '28px' }" />
|
<em class="el-icon-message" :style="{ fontSize: '28px' }" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
@ -44,7 +29,7 @@
|
|||||||
>
|
>
|
||||||
<div class="avatar-wrapper">
|
<div class="avatar-wrapper">
|
||||||
<img :src="avatar" class="user-avatar" />
|
<img :src="avatar" class="user-avatar" />
|
||||||
<i class="el-icon-caret-bottom" />
|
<em class="el-icon-caret-bottom" />
|
||||||
</div>
|
</div>
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
<router-link to="/user/profile">
|
<router-link to="/user/profile">
|
||||||
@ -66,25 +51,32 @@
|
|||||||
import { mapGetters, mapActions } from "vuex";
|
import { mapGetters, mapActions } from "vuex";
|
||||||
import Breadcrumb from "@/components/Breadcrumb";
|
import Breadcrumb from "@/components/Breadcrumb";
|
||||||
import Hamburger from "@/components/Hamburger";
|
import Hamburger from "@/components/Hamburger";
|
||||||
// import Screenfull from "@/components/Screenfull";
|
import { keys, websocketInit, beforeUnmount } from "@/utils/websocket";
|
||||||
// import SizeSelect from "@/components/SizeSelect";
|
|
||||||
// import Search from "@/components/HeaderSearch";
|
|
||||||
// import RuoYiGit from "@/components/RuoYi/Git";
|
|
||||||
// import RuoYiDoc from "@/components/RuoYi/Doc";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Breadcrumb,
|
Breadcrumb,
|
||||||
Hamburger,
|
Hamburger,
|
||||||
// Screenfull,
|
},
|
||||||
// SizeSelect,
|
data() {
|
||||||
// Search,
|
return {
|
||||||
|
msgNum: 0,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.init();
|
this.init();
|
||||||
|
websocketInit();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
window.postMessage({ type: keys.GET_UNREAD_COUNT }, window.location.origin);
|
||||||
|
window.addEventListener("message", this.handleOnMessage);
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
beforeUnmount(1000);
|
||||||
|
window.removeEventListener("message", this.handleOnMessage);
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(["sidebar", "avatar", "device"]),
|
...mapGetters(["sidebar", "avatar", "device", "msgUnreadCount"]),
|
||||||
setting: {
|
setting: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.state.settings.showSettings;
|
return this.$store.state.settings.showSettings;
|
||||||
@ -98,7 +90,14 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(["init"]),
|
...mapActions(["init", "updateUnreadCount"]),
|
||||||
|
handleOnMessage({ data }) {
|
||||||
|
if (data.type === keys.WS_TYPE_MESSAGE_COUNT) {
|
||||||
|
this.updateUnreadCount({
|
||||||
|
msgUnreadCount: data.data.count,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
toggleSideBar() {
|
toggleSideBar() {
|
||||||
this.$store.dispatch("app/toggleSideBar");
|
this.$store.dispatch("app/toggleSideBar");
|
||||||
},
|
},
|
||||||
|
@ -18,12 +18,12 @@ import "./permission"; // permission control
|
|||||||
import { getDicts } from "@/api/system/dict/data";
|
import { getDicts } from "@/api/system/dict/data";
|
||||||
import { getConfigKey } from "@/api/system/config";
|
import { getConfigKey } from "@/api/system/config";
|
||||||
import VueScrollTo from "vue-scrollto";
|
import VueScrollTo from "vue-scrollto";
|
||||||
import VueResource from "vue-resource"
|
import VueResource from "vue-resource";
|
||||||
import HighchartsVue from 'highcharts-vue'
|
import HighchartsVue from "highcharts-vue";
|
||||||
import Highcharts from 'highcharts'
|
import Highcharts from "highcharts";
|
||||||
//图片导出模块
|
//图片导出模块
|
||||||
import exportingInit from 'highcharts/modules/exporting'
|
import exportingInit from "highcharts/modules/exporting";
|
||||||
exportingInit(Highcharts)
|
exportingInit(Highcharts);
|
||||||
|
|
||||||
import {
|
import {
|
||||||
addDateRange,
|
addDateRange,
|
||||||
@ -111,7 +111,7 @@ Vue.use(VueScrollTo, {
|
|||||||
y: true
|
y: true
|
||||||
});
|
});
|
||||||
|
|
||||||
Vue.use(VueResource)
|
Vue.use(VueResource);
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: "#app",
|
el: "#app",
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
const actions = {
|
const actions = {
|
||||||
async init({ dispatch }, payload) {
|
async init({ dispatch }, payload) {
|
||||||
dispatch("global/init", payload);
|
dispatch("global/init", payload);
|
||||||
|
},
|
||||||
|
async updateUnreadCount({ commit }, payload) {
|
||||||
|
commit("global/save", payload);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,12 +9,11 @@ const getters = {
|
|||||||
name: state => state.user.name,
|
name: state => state.user.name,
|
||||||
introduction: state => state.user.introduction,
|
introduction: state => state.user.introduction,
|
||||||
roles: state => state.user.roles,
|
roles: state => state.user.roles,
|
||||||
// roles: state => ["dietician"],
|
|
||||||
permissions: state => state.user.permissions,
|
permissions: state => state.user.permissions,
|
||||||
userId: state => state.user.userId,
|
userId: state => state.user.userId,
|
||||||
// userId: state => 131,
|
|
||||||
userRemark: state => state.user.remark,
|
userRemark: state => state.user.remark,
|
||||||
permission_routes: state => state.permission.routes,
|
permission_routes: state => state.permission.routes,
|
||||||
|
msgUnreadCount: state => state.global.msgUnreadCount,
|
||||||
//
|
//
|
||||||
nutritionistIdOptions: state => state.global.nutritionistIdOptions,
|
nutritionistIdOptions: state => state.global.nutritionistIdOptions,
|
||||||
nutriAssisIdOptions: state => state.global.nutriAssisIdOptions,
|
nutriAssisIdOptions: state => state.global.nutriAssisIdOptions,
|
||||||
|
@ -10,6 +10,7 @@ const oriState = {
|
|||||||
plannerAssisIdOptions: [],
|
plannerAssisIdOptions: [],
|
||||||
operatorIdOptions: [],
|
operatorIdOptions: [],
|
||||||
operatorAssisIdOptions: [],
|
operatorAssisIdOptions: [],
|
||||||
|
msgUnreadCount: 0,
|
||||||
pushPreSaleIdOptions:[]
|
pushPreSaleIdOptions:[]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import { getCustomerPhysicalSignsByCusId } from "@/api/custom/customer";
|
||||||
|
import { dealHealthy } from "@/utils/healthyData";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
fetchTopicList,
|
fetchTopicList,
|
||||||
postTopicReply,
|
postTopicReply,
|
||||||
@ -6,9 +9,14 @@ import {
|
|||||||
} from "@/api/custom/message";
|
} from "@/api/custom/message";
|
||||||
|
|
||||||
const oriState = {
|
const oriState = {
|
||||||
|
pageNum: 1,
|
||||||
topicList: [],
|
topicList: [],
|
||||||
detailData: {},
|
detailData: {},
|
||||||
selTopicId: ""
|
selTopicId: "",
|
||||||
|
healthyData: {},
|
||||||
|
healthDataLoading: false,
|
||||||
|
healthyDataType: 0,
|
||||||
|
avoidFoodIds: []
|
||||||
};
|
};
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
@ -28,28 +36,48 @@ const mutations = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
async init({ rootGetters, commit, dispatch }, payload) {
|
async init({ dispatch }, payload) {
|
||||||
|
dispatch("fetchTopicListApi", {});
|
||||||
|
},
|
||||||
|
async fetchTopicListApi({ dispatch, commit, rootGetters, state }, payload) {
|
||||||
const {
|
const {
|
||||||
roles: [role],
|
roles: [role],
|
||||||
userId
|
userId
|
||||||
} = rootGetters;
|
} = rootGetters;
|
||||||
const result = await fetchTopicList({ role, uid: userId });
|
const { detailData, pageNum, topicList } = state;
|
||||||
|
const result = await fetchTopicList({
|
||||||
|
role,
|
||||||
|
uid: userId,
|
||||||
|
pageSize: 20,
|
||||||
|
pageNum
|
||||||
|
});
|
||||||
if (result.code === 200) {
|
if (result.code === 200) {
|
||||||
const [defTopic] = result.rows;
|
if (!detailData.topicId) {
|
||||||
|
// 默认展示第一个
|
||||||
dispatch("fetchTopicDetailActions", {
|
const [defTopic] = result.rows;
|
||||||
topicId: defTopic.topicId,
|
dispatch("fetchTopicDetailActions", {
|
||||||
id: defTopic.id
|
topicId: defTopic.topicId,
|
||||||
});
|
id: defTopic.id,
|
||||||
|
uid: defTopic.uid
|
||||||
commit("save", {
|
});
|
||||||
topicList: result.rows
|
}
|
||||||
});
|
if (result.rows.length) {
|
||||||
|
commit("save", {
|
||||||
|
pageNum: pageNum + 1,
|
||||||
|
topicList: [...topicList, ...result.rows]
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async fetchTopicDetailActions({ commit }, payload) {
|
async fetchTopicDetailActions({ commit, dispatch, state }, payload) {
|
||||||
const { topicId, id } = payload;
|
const { topicId, id, uid } = payload;
|
||||||
|
const { healthyData } = state;
|
||||||
commit("save", { selTopicId: topicId });
|
commit("save", { selTopicId: topicId });
|
||||||
|
// 客户信息
|
||||||
|
if (healthyData.customerId !== parseInt(uid)) {
|
||||||
|
dispatch("getHealthyData", { cusId: uid, callback: payload.callback });
|
||||||
|
}
|
||||||
|
//
|
||||||
const result = await fetchTopicDetail({ topicId, id });
|
const result = await fetchTopicDetail({ topicId, id });
|
||||||
if (result.code === 200) {
|
if (result.code === 200) {
|
||||||
commit("save", { detailData: result.data[0] });
|
commit("save", { detailData: result.data[0] });
|
||||||
@ -76,11 +104,39 @@ const actions = {
|
|||||||
if (tarTopic) {
|
if (tarTopic) {
|
||||||
dispatch("fetchTopicDetailActions", {
|
dispatch("fetchTopicDetailActions", {
|
||||||
topicId: tarTopic.topicId,
|
topicId: tarTopic.topicId,
|
||||||
id: tarTopic.id
|
id: tarTopic.id,
|
||||||
|
uid: tarTopic.uid
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
},
|
||||||
|
async getHealthyData({ commit }, payload) {
|
||||||
|
commit("save", { healthDataLoading: true });
|
||||||
|
const healthyDataResult = await getCustomerPhysicalSignsByCusId(
|
||||||
|
payload.cusId
|
||||||
|
);
|
||||||
|
const newState = {};
|
||||||
|
if (healthyDataResult.code === 200) {
|
||||||
|
if (!healthyDataResult.data.customerHealthy) {
|
||||||
|
// throw new Error("客户还没填写健康评估表");
|
||||||
|
payload.callback && payload.callback("客户还没填写健康评估表");
|
||||||
|
} else {
|
||||||
|
newState.healthyDataType = healthyDataResult.data.type;
|
||||||
|
newState.healthyData = dealHealthy(
|
||||||
|
healthyDataResult.data.customerHealthy
|
||||||
|
);
|
||||||
|
newState.avoidFoodIds = (newState.healthyData.avoidFood || []).map(
|
||||||
|
obj => obj.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(healthyDataResult.msg);
|
||||||
|
}
|
||||||
|
commit("save", {
|
||||||
|
healthDataLoading: false,
|
||||||
|
...newState
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
84
stdiet-ui/src/utils/websocket.js
Normal file
84
stdiet-ui/src/utils/websocket.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
const { protocol, hostname, origin, port } = window.location;
|
||||||
|
const wsProtocol = protocol.startsWith("https") ? "wss" : "ws";
|
||||||
|
const url = `${wsProtocol}://${hostname}${
|
||||||
|
hostname === "localhost" ? ":8091" : ""
|
||||||
|
}/ws`;
|
||||||
|
let ws = undefined;
|
||||||
|
let intervalRef = undefined;
|
||||||
|
|
||||||
|
function handleOnMessageReceive({ data = {} }) {
|
||||||
|
if (data.type && data.type === keys.GET_UNREAD_COUNT) {
|
||||||
|
ws.send(keys.GET_UNREAD_COUNT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect() {
|
||||||
|
try {
|
||||||
|
ws = new WebSocket(url);
|
||||||
|
|
||||||
|
ws.onopen = event => {
|
||||||
|
console.log("ws连接成功");
|
||||||
|
intervalRef && clearInterval(intervalRef);
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
ws.send("ping");
|
||||||
|
}, 30000);
|
||||||
|
|
||||||
|
window.addEventListener("message", handleOnMessageReceive);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onmessage = event => {
|
||||||
|
// console.log({ event });
|
||||||
|
|
||||||
|
const dataObj = JSON.parse(event.data || "{}");
|
||||||
|
|
||||||
|
if (dataObj.type && dataObj.type !== "WS_TYPE_HEART_BEAT") {
|
||||||
|
window.postMessage(dataObj, origin);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = event => {
|
||||||
|
// console.log({ event });
|
||||||
|
ws.close();
|
||||||
|
ws = undefined;
|
||||||
|
window.removeEventListener("message", handleOnMessageReceive);
|
||||||
|
|
||||||
|
// websocketInit();
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = event => {
|
||||||
|
// console.log(event);
|
||||||
|
ws = undefined;
|
||||||
|
window.removeEventListener("message", handleOnMessageReceive);
|
||||||
|
// if (event.reason !== "unmount") {
|
||||||
|
// websocketInit();
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
// console.log(error);
|
||||||
|
// console.log("浏览器不支持websocket");
|
||||||
|
ws.close();
|
||||||
|
ws = undefined;
|
||||||
|
// websocketInit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function beforeUnmount(code) {
|
||||||
|
ws && ws.close(code, "unmount");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function websocketInit() {
|
||||||
|
!ws && connect();
|
||||||
|
|
||||||
|
!ws &&
|
||||||
|
(intervalRef = setInterval(() => {
|
||||||
|
console.log("尝试连接websocket");
|
||||||
|
!ws && connect();
|
||||||
|
}, 10000));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const keys = {
|
||||||
|
GET_UNREAD_COUNT: "GET_UNREAD_COUNT",
|
||||||
|
WS_TYPE_MESSAGE_COUNT: "WS_TYPE_MESSAGE_COUNT",
|
||||||
|
WS_TYPE_NEW_CUSTOMER_REPLY: "WS_TYPE_NEW_CUSTOMER_REPLY"
|
||||||
|
};
|
@ -27,7 +27,12 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item> -->
|
</el-form-item> -->
|
||||||
<el-form-item label="进粉渠道" prop="channelId">
|
<el-form-item label="进粉渠道" prop="channelId">
|
||||||
<el-select v-model="queryParams.channelId" filterable clearable placeholder="请选择">
|
<el-select
|
||||||
|
v-model="queryParams.channelId"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
placeholder="请选择"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="dict in accountIdOptions"
|
v-for="dict in accountIdOptions"
|
||||||
:key="dict.dictValue"
|
:key="dict.dictValue"
|
||||||
@ -84,24 +89,24 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="病史体征" prop="physicalSignsId">
|
<el-form-item label="病史体征" prop="physicalSignsId">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="queryParams.physicalSignsId"
|
v-model="queryParams.physicalSignsId"
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
allow-create
|
allow-create
|
||||||
default-first-option
|
default-first-option
|
||||||
placeholder="请选择病史体征"
|
placeholder="请选择病史体征"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="physicalSign in physicalSignsList"
|
||||||
|
:key="physicalSign.id"
|
||||||
|
:label="physicalSign.name"
|
||||||
|
:value="physicalSign.id"
|
||||||
>
|
>
|
||||||
<el-option
|
</el-option>
|
||||||
v-for="physicalSign in physicalSignsList"
|
</el-select>
|
||||||
:key="physicalSign.id"
|
</el-form-item>
|
||||||
:label="physicalSign.name"
|
|
||||||
:value="physicalSign.id"
|
|
||||||
>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="cyan" icon="el-icon-search" @click="handleQuery"
|
<el-button type="cyan" icon="el-icon-search" @click="handleQuery"
|
||||||
@ -246,7 +251,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="外食热量统计"
|
label="外食热量"
|
||||||
align="center"
|
align="center"
|
||||||
v-hasPermi="['custom:foodHeatStatistics:list']"
|
v-hasPermi="['custom:foodHeatStatistics:list']"
|
||||||
>
|
>
|
||||||
@ -330,8 +335,18 @@
|
|||||||
<el-row :gutter="15">
|
<el-row :gutter="15">
|
||||||
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="进粉渠道" prop="channelId" style="width:400px">
|
<el-form-item
|
||||||
<el-select v-model="form.channelId" placeholder="请选择" filterable clearable @change="channelAutoSelectNutritionist">
|
label="进粉渠道"
|
||||||
|
prop="channelId"
|
||||||
|
style="width: 400px"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="form.channelId"
|
||||||
|
placeholder="请选择"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
@change="channelAutoSelectNutritionist"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="dict in accountIdOptions"
|
v-for="dict in accountIdOptions"
|
||||||
:key="dict.dictValue"
|
:key="dict.dictValue"
|
||||||
@ -356,12 +371,12 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="客户名字" prop="name" style="width:300px">
|
<el-form-item label="客户名字" prop="name" style="width: 300px">
|
||||||
<el-input v-model.trim="form.name" placeholder="请输入名字" />
|
<el-input v-model.trim="form.name" placeholder="请输入名字" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="手机号" prop="phone" style="width:300px">
|
<el-form-item label="手机号" prop="phone" style="width: 300px">
|
||||||
<el-input v-model.trim="form.phone" placeholder="请输入手机号" />
|
<el-input v-model.trim="form.phone" placeholder="请输入手机号" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -413,8 +428,6 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
|
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-row>
|
</el-row>
|
||||||
<div slot="footer" class="dialog-footer">
|
<div slot="footer" class="dialog-footer">
|
||||||
@ -508,7 +521,7 @@ export default {
|
|||||||
assistantDietitian: null,
|
assistantDietitian: null,
|
||||||
afterDietitian: null,
|
afterDietitian: null,
|
||||||
salesman: null,
|
salesman: null,
|
||||||
physicalSignsId: null
|
physicalSignsId: null,
|
||||||
},
|
},
|
||||||
// 表单参数
|
// 表单参数
|
||||||
form: {},
|
form: {},
|
||||||
@ -551,7 +564,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
//病史体征
|
//病史体征
|
||||||
physicalSignsList:[]
|
physicalSignsList: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@ -573,8 +586,8 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.getList();
|
this.getList();
|
||||||
listPhysicalSigns().then(response => {
|
listPhysicalSigns().then((response) => {
|
||||||
this.physicalSignsList = response.rows;
|
this.physicalSignsList = response.rows;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -789,52 +802,68 @@ export default {
|
|||||||
})
|
})
|
||||||
.catch(function () {});
|
.catch(function () {});
|
||||||
},
|
},
|
||||||
channelAutoSelectNutritionist(channelValue){
|
channelAutoSelectNutritionist(channelValue) {
|
||||||
this.form.fansChannel = channelValue == "" ? null : channelValue;
|
this.form.fansChannel = channelValue == "" ? null : channelValue;
|
||||||
if(channelValue == undefined || channelValue == null || channelValue == ""){
|
if (
|
||||||
this.form.mainDietitian = null;
|
channelValue == undefined ||
|
||||||
return;
|
channelValue == null ||
|
||||||
}
|
channelValue == ""
|
||||||
if(this.form.fansTime == undefined || this.form.fansTime == null){
|
) {
|
||||||
this.form.mainDietitian = null;
|
this.form.mainDietitian = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.autoSelectNutritionist();
|
if (this.form.fansTime == undefined || this.form.fansTime == null) {
|
||||||
|
this.form.mainDietitian = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.autoSelectNutritionist();
|
||||||
},
|
},
|
||||||
fanTimeAutoSelectNutritionist(fansTime){
|
fanTimeAutoSelectNutritionist(fansTime) {
|
||||||
this.form.fansTime = fansTime;
|
this.form.fansTime = fansTime;
|
||||||
if(fansTime == undefined || fansTime == null){
|
if (fansTime == undefined || fansTime == null) {
|
||||||
this.form.mainDietitian = null;
|
this.form.mainDietitian = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(this.form.fansChannel == undefined || this.form.fansChannel == null || this.form.fansChannel == ""){
|
if (
|
||||||
this.form.mainDietitian = null;
|
this.form.fansChannel == undefined ||
|
||||||
return;
|
this.form.fansChannel == null ||
|
||||||
}
|
this.form.fansChannel == ""
|
||||||
this.autoSelectNutritionist();
|
) {
|
||||||
|
this.form.mainDietitian = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.autoSelectNutritionist();
|
||||||
},
|
},
|
||||||
autoSelectNutritionist(){
|
autoSelectNutritionist() {
|
||||||
getLiveSchedulByTime({'fanChannel':this.form.fansChannel,'liveStartTimeString':encodeURIComponent(this.form.fansTime)}).then((response) => {
|
getLiveSchedulByTime({
|
||||||
if (response.code === 200) {
|
fanChannel: this.form.fansChannel,
|
||||||
let live = response.data;
|
liveStartTimeString: encodeURIComponent(this.form.fansTime),
|
||||||
if(live != undefined && live != null && live.liveNutritionistId != null && this.nutritionistIdOptions != null){
|
}).then((response) => {
|
||||||
let mainDietitian = null;
|
if (response.code === 200) {
|
||||||
this.nutritionistIdOptions.forEach((item,index) => {
|
let live = response.data;
|
||||||
if(live.liveNutritionistId == item.dictValue){
|
if (
|
||||||
mainDietitian = live.liveNutritionistId;
|
live != undefined &&
|
||||||
}
|
live != null &&
|
||||||
if(index == this.nutritionistIdOptions.length - 1){
|
live.liveNutritionistId != null &&
|
||||||
this.form.mainDietitian = mainDietitian;
|
this.nutritionistIdOptions != null
|
||||||
}
|
) {
|
||||||
});
|
let mainDietitian = null;
|
||||||
}else{
|
this.nutritionistIdOptions.forEach((item, index) => {
|
||||||
this.form.mainDietitian = null;
|
if (live.liveNutritionistId == item.dictValue) {
|
||||||
}
|
mainDietitian = live.liveNutritionistId;
|
||||||
}else{
|
|
||||||
this.form.mainDietitian = null;
|
|
||||||
}
|
}
|
||||||
});
|
if (index == this.nutritionistIdOptions.length - 1) {
|
||||||
}
|
this.form.mainDietitian = mainDietitian;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.form.mainDietitian = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.form.mainDietitian = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="user_message_wrapper">
|
<div class="user_message_wrapper">
|
||||||
<MessageBrowser />
|
<MessageBrowser />
|
||||||
<div class="info_zone"></div>
|
<UserInfo />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import MessageBrowser from "./messageBrowser/index";
|
import MessageBrowser from "./messageBrowser/index";
|
||||||
|
import UserInfo from "./userInfo/index";
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
MessageBrowser,
|
MessageBrowser,
|
||||||
|
UserInfo,
|
||||||
},
|
},
|
||||||
created() {},
|
created() {},
|
||||||
computed: {},
|
computed: {},
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="topic_comment_item">
|
<div class="topic_comment_item" @click="handOnClick(data)">
|
||||||
<div class="comment_avatar">
|
<div class="comment_avatar">
|
||||||
<el-avatar size="medium">{{ data.fromName.substr(-1) }}</el-avatar>
|
<el-avatar size="medium" :src="data.fromAvatar || ''">{{
|
||||||
|
data.fromName.substr(-1)
|
||||||
|
}}</el-avatar>
|
||||||
</div>
|
</div>
|
||||||
<div class="comment_content">
|
<div class="comment_content">
|
||||||
<div class="content_title">
|
<div class="content_title">
|
||||||
@ -10,11 +12,7 @@
|
|||||||
<div class="content_type">{{ data.content }}</div>
|
<div class="content_type">{{ data.content }}</div>
|
||||||
<div class="content_time">
|
<div class="content_time">
|
||||||
{{ formatDate(data.createTime) }}
|
{{ formatDate(data.createTime) }}
|
||||||
<div
|
<div v-if="data.fromUid !== userId.toString()" class="reply_btn">
|
||||||
v-if="data.fromUid !== userId.toString()"
|
|
||||||
class="reply_btn"
|
|
||||||
@click="handOnClick(data)"
|
|
||||||
>
|
|
||||||
回复
|
回复
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -30,7 +28,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
roleDict: {
|
roleDict: {
|
||||||
customer: "客户",
|
customer: "客户",
|
||||||
dietician: "主营养师",
|
dietician: "主任营养师",
|
||||||
after_sale: "售后营养师",
|
after_sale: "售后营养师",
|
||||||
dietician_assistant: "营养师助理",
|
dietician_assistant: "营养师助理",
|
||||||
},
|
},
|
||||||
@ -61,6 +59,7 @@ export default {
|
|||||||
.topic_comment_item {
|
.topic_comment_item {
|
||||||
margin: 12px;
|
margin: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
.comment_avatar {
|
.comment_avatar {
|
||||||
flex: 0 0 36px;
|
flex: 0 0 36px;
|
||||||
@ -86,7 +85,8 @@ export default {
|
|||||||
|
|
||||||
.reply_btn {
|
.reply_btn {
|
||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
cursor: pointer;
|
color: #1890ff;
|
||||||
|
// cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,49 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="message_browser_wrapper">
|
<div class="message_browser_wrapper">
|
||||||
<div class="topic_list">
|
<div class="topic_list" @scroll="handleOnScroll">
|
||||||
<div
|
<div v-if="topicList && topicList.length">
|
||||||
v-for="topic in topicList"
|
<div
|
||||||
:key="topic.topicId"
|
v-for="topic in topicList"
|
||||||
:class="`topic_item ${
|
:key="topic.topicId"
|
||||||
selTopicId === topic.topicId ? 'topic_item_sel' : ''
|
:class="`topic_item ${
|
||||||
}`"
|
selTopicId === topic.topicId ? 'topic_item_sel' : ''
|
||||||
@click="handleOnTopicClick(topic)"
|
}`"
|
||||||
>
|
@click="handleOnTopicClick(topic)"
|
||||||
<div class="topic_status topic_status_read" />
|
>
|
||||||
<div class="topic_item_content">
|
<div
|
||||||
<div class="topic_content">{{ topic.content }}</div>
|
:class="`topic_status ${
|
||||||
<div class="topic_user_name">by {{ topic.name }}</div>
|
topic.read ? 'topic_status_read' : 'topic_status_unread'
|
||||||
</div>
|
}`"
|
||||||
<div class="topic_info">
|
/>
|
||||||
<el-tag size="small">{{ topicTypeDict[topic.topicType] }}</el-tag>
|
<div class="topic_item_content">
|
||||||
<div class="topic_time">{{ formatDate(topic.createTime) }}</div>
|
<div class="topic_content" :style="{ width: `${itemWidth}px` }">
|
||||||
|
{{ topic.content }}
|
||||||
|
</div>
|
||||||
|
<div class="topic_user_name">by {{ topic.name }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="topic_info">
|
||||||
|
<el-tag size="small">{{ topicTypeDict[topic.topicType] }}</el-tag>
|
||||||
|
<div class="topic_time">{{ formatDate(topic.createTime) }}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else class="topic_list_empty">暂无消息</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="topic_detail">
|
<div class="topic_detail">
|
||||||
<div class="topic_detail_list">
|
<div class="topic_detail_list">
|
||||||
<div class="topic_detail_title">
|
<div
|
||||||
<div>{{ detailData.content }}</div>
|
class="topic_detail_title"
|
||||||
<div class="content_time" :style="{ marginTop: '4px' }">
|
v-if="!!detailData.content"
|
||||||
{{ formatDate(detailData.createTime) }}
|
@click="handleOnReplyTopic(detailData)"
|
||||||
<div class="reply_btn" @click="handleOnReplyTopic(detailData)">
|
>
|
||||||
回复
|
<el-avatar :src="detailData.avatar">{{
|
||||||
|
detailData.name.substr(-1)
|
||||||
|
}}</el-avatar>
|
||||||
|
<div :style="{ marginLeft: '8px' }">
|
||||||
|
<div>{{ detailData.content }}</div>
|
||||||
|
<div class="content_time" :style="{ marginTop: '4px' }">
|
||||||
|
{{ formatDate(detailData.createTime) }}
|
||||||
|
<div class="reply_btn">回复</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -48,9 +64,14 @@
|
|||||||
<div
|
<div
|
||||||
:style="{ marginBottom: '8px', fontSize: '12px', color: '#8c8c8c' }"
|
:style="{ marginBottom: '8px', fontSize: '12px', color: '#8c8c8c' }"
|
||||||
>
|
>
|
||||||
回复:{{ replyTarget }}
|
回复 to:{{ replyTarget }}
|
||||||
</div>
|
</div>
|
||||||
<el-input type="textarea" :rows="3" v-model="replyContent" />
|
<el-input
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
v-model="replyContent"
|
||||||
|
:disabled="!detailData.content"
|
||||||
|
/>
|
||||||
<div class="send_btn_zone">
|
<div class="send_btn_zone">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@ -65,44 +86,113 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { createNamespacedHelpers } from "vuex";
|
import { createNamespacedHelpers, mapActions as globalMapActions } from "vuex";
|
||||||
import Comment from "./Comment";
|
import Comment from "./Comment";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
const {
|
import { keys } from "@/utils/websocket";
|
||||||
mapActions,
|
const { mapActions, mapState, mapMutations, mapGetters } =
|
||||||
mapState,
|
createNamespacedHelpers("message");
|
||||||
mapMutations,
|
|
||||||
mapGetters,
|
|
||||||
} = createNamespacedHelpers("message");
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
topicTypeDict: {
|
topicTypeDict: {
|
||||||
0: "建议",
|
0: "食材",
|
||||||
1: "食谱",
|
1: "身体",
|
||||||
2: "咨询",
|
2: "环境",
|
||||||
},
|
},
|
||||||
replyTarget: "",
|
replyTarget: "",
|
||||||
replyContent: "",
|
replyContent: "",
|
||||||
replyObj: {},
|
replyObj: {},
|
||||||
|
itemWidth: 160,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: { Comment },
|
components: { Comment },
|
||||||
created() {
|
created() {
|
||||||
this.init();
|
this.init();
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
window.addEventListener("message", this.handleOnMessage);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const itemElm = document.querySelector(".topic_item");
|
||||||
|
if (itemElm) {
|
||||||
|
console.log(itemElm);
|
||||||
|
this.itemWidth = itemElm.clientWidth - 32 - 20 - 80;
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
window.removeEventListener("message", this.handleOnMessage);
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["topicList", "selTopicId", "detailData"]),
|
...mapState(["topicList", "selTopicId", "detailData"]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleOnScroll({ target }) {
|
||||||
|
if (
|
||||||
|
target.clientHeight + parseInt(target.scrollTop) ===
|
||||||
|
target.scrollHeight
|
||||||
|
) {
|
||||||
|
this.fetchTopicListApi();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleOnMessage({ data }) {
|
||||||
|
if (data.type === keys.WS_TYPE_MESSAGE_COUNT) {
|
||||||
|
const { data: tData } = data.data;
|
||||||
|
const time = dayjs(tData.createTime).format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
const newTopicList = [
|
||||||
|
{
|
||||||
|
id: tData.id,
|
||||||
|
content: tData.content,
|
||||||
|
createTime: time,
|
||||||
|
img: tData.img,
|
||||||
|
topicId: tData.topicId,
|
||||||
|
role: "customer",
|
||||||
|
uid: tData.uid,
|
||||||
|
updateTime: time,
|
||||||
|
topicType: tData.topicType,
|
||||||
|
read: tData.read,
|
||||||
|
},
|
||||||
|
...this.topicList,
|
||||||
|
];
|
||||||
|
this.save({
|
||||||
|
topicList: newTopicList,
|
||||||
|
});
|
||||||
|
} else if (data.type === keys.WS_TYPE_NEW_CUSTOMER_REPLY) {
|
||||||
|
const { count, topicId } = data.data;
|
||||||
|
this.updateUnreadCount({
|
||||||
|
msgUnreadCount: count,
|
||||||
|
});
|
||||||
|
if (this.selTopicId === topicId) {
|
||||||
|
const tarTopic = this.topicList.find(
|
||||||
|
(obj) => obj.topicId === topicId
|
||||||
|
);
|
||||||
|
if (tarTopic) {
|
||||||
|
console.log({ tarTopic });
|
||||||
|
this.fetchTopicDetailActions({
|
||||||
|
topicId,
|
||||||
|
id: tarTopic.id,
|
||||||
|
uid: tarTopic.uid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
formatDate(date) {
|
formatDate(date) {
|
||||||
return dayjs(date).format("MM-DD HH:mm");
|
return dayjs(date).format("MM-DD HH:mm");
|
||||||
},
|
},
|
||||||
handleOnTopicClick(data) {
|
handleOnTopicClick(data) {
|
||||||
this.replyTarget = "";
|
if (data.topicId !== this.selTopicId) {
|
||||||
this.replyContent = "";
|
this.replyTarget = "";
|
||||||
this.replyObj = {};
|
this.replyContent = "";
|
||||||
this.fetchTopicDetailActions({ topicId: data.topicId, id: data.id });
|
this.replyObj = {};
|
||||||
|
this.fetchTopicDetailActions({
|
||||||
|
topicId: data.topicId,
|
||||||
|
id: data.id,
|
||||||
|
uid: data.uid,
|
||||||
|
callback: (err) => this.$message.error(err),
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleOnReplyTopic(data) {
|
handleOnReplyTopic(data) {
|
||||||
this.replyTarget = "主题";
|
this.replyTarget = "主题";
|
||||||
@ -147,8 +237,14 @@ export default {
|
|||||||
this.$message.error("请选择回复对象");
|
this.$message.error("请选择回复对象");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
...mapActions(["init", "fetchTopicDetailActions", "postTopicReplyActions"]),
|
...mapActions([
|
||||||
...mapMutations(["clean"]),
|
"init",
|
||||||
|
"fetchTopicDetailActions",
|
||||||
|
"postTopicReplyActions",
|
||||||
|
"fetchTopicListApi",
|
||||||
|
]),
|
||||||
|
...mapMutations(["clean", "save"]),
|
||||||
|
...globalMapActions(["updateUnreadCount"]),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@ -157,6 +253,7 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
.topic_list {
|
.topic_list {
|
||||||
flex: 2;
|
flex: 2;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
.topic_item {
|
.topic_item {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -194,7 +291,7 @@ export default {
|
|||||||
flex: 1 0 0;
|
flex: 1 0 0;
|
||||||
|
|
||||||
.topic_content {
|
.topic_content {
|
||||||
width: 260px;
|
width: 100px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@ -223,6 +320,13 @@ export default {
|
|||||||
.topic_item_sel {
|
.topic_item_sel {
|
||||||
background: #dedede;
|
background: #dedede;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.topic_list_empty {
|
||||||
|
height: 100px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 100px;
|
||||||
|
color: #8c8c8c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.topic_detail {
|
.topic_detail {
|
||||||
@ -241,11 +345,14 @@ export default {
|
|||||||
|
|
||||||
.reply_btn {
|
.reply_btn {
|
||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
cursor: pointer;
|
color: #1890ff;
|
||||||
|
// cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.topic_detail_title {
|
.topic_detail_title {
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment_reply_item {
|
.comment_reply_item {
|
||||||
|
38
stdiet-ui/src/views/custom/message/userInfo/index.vue
Normal file
38
stdiet-ui/src/views/custom/message/userInfo/index.vue
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<div v-loading="healthDataLoading">
|
||||||
|
<HealthyView
|
||||||
|
dev
|
||||||
|
:data="healthyDataType === 0 ? healthyData : {}"
|
||||||
|
v-show="healthyDataType === 0"
|
||||||
|
/>
|
||||||
|
<BodySignView
|
||||||
|
dev
|
||||||
|
:data="healthyDataType === 1 ? healthyData : {}"
|
||||||
|
v-show="healthyDataType === 1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { createNamespacedHelpers } from "vuex";
|
||||||
|
import HealthyView from "@/components/HealthyView";
|
||||||
|
import BodySignView from "@/components/BodySignView";
|
||||||
|
const {
|
||||||
|
mapActions,
|
||||||
|
mapState,
|
||||||
|
mapMutations,
|
||||||
|
mapGetters,
|
||||||
|
} = createNamespacedHelpers("message");
|
||||||
|
export default {
|
||||||
|
name: "SignUserInfo",
|
||||||
|
components: {
|
||||||
|
HealthyView,
|
||||||
|
BodySignView,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["healthyData", "healthyDataType", "healthDataLoading"]),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
Loading…
x
Reference in New Issue
Block a user