/** * 用户微信客户端。 */ "use strict"; let RedisClient = require('../../repository/redis/redis.client'); let RedisModel = require('../redis.model'); let ObjectUtil = require("../../util/object.util.js"); let ModelUtil = require('../../util/model.util'); let WechatSDK = require('../../util/wechat.sdk'); let PatientRepo = require('../../repository/mysql/patient.repo'); let TopicRepo = require("../../repository/mysql/topics.repo.js"); let ParticipantRepo = require("../../repository/mysql/participant.repo"); let redisConn = RedisClient.redisClient().connection; let clientCache = require('../socket.io/client.cache').clientCache(); let configFile = require('../../include/commons').CONFIG_FILE; let config = require('../../resources/config/' + configFile); let log = require("../../util/log.js"); let https = require('https'); let async = require('async'); const CONTENT_TYPES = require('../../include/commons').CONTENT_TYPES; const SOCKET_TYPES = require('../../include/commons').SOCKET_TYPES; const REDIS_KEYS = require('../../include/commons').REDIS_KEYS; class WechatClient extends RedisModel { constructor() { super(); } /** * 取得用户微信端状态。若Redis中找不到,则从MySQL中查找。 * * @param userId * @param handler */ static getWechatStatus(userId, handler) { redisConn.hgetallAsync(RedisModel.makeRedisKey(REDIS_KEYS.UserWechatStatus, userId)) .then(function (status) { if (status == null) { PatientRepo.findWechatOpenId(userId, handler); } else { handler(null, {openid: status.openid}); } }) .catch(function (err) { handler(err, null); }); } /** * 向微信端用户发送消息。若用户微信端在线,通过Web Socket推送给患者,如果不在线则通过微信的模板消息。 * * 只推送文本、图片及语音消息 * * @param targetUserId * @param message 消息体 */ static sendMessage(targetUserId, targetUserName, message) { if (message&&(message.content_type == CONTENT_TYPES.PlainText || message.content_type == CONTENT_TYPES.Image || message.content_type == CONTENT_TYPES.Audio)) { let patientClient = clientCache.findById(targetUserId); let doctorClient = clientCache.findByIdAndType(message.sender_id,SOCKET_TYPES.DOCTOR); if (patientClient) { log.warn("User's wechat endpoint is online, sending via web socket. User id: ", targetUserId); WechatClient.sendViaWebSocket(patientClient.socket, message); if(doctorClient){ log.error("doctor sessionid "+doctorClient.sessionId); log.error("patient sessionid "+patientClient.sessionId); if(patientClient.sessionId==doctorClient.sessionId){ //用户socket在线,推送给用户后,告知医生此消息已读 WechatClient.updateParticipantLastFetchTime(doctorClient.sessionId, targetUserId, ObjectUtil.timestampToLong(message.timestamp)); WechatClient.sendReadDoctor(doctorClient.socket, message); } }else{ log.error("doctor client not found"); } } else { log.info("User's wechat endpoint is not online, sending via wechat template message. User id: ", targetUserId); WechatClient.sendViaMessageTemplate(targetUserId, targetUserName, message); } } else if(message.content_type == CONTENT_TYPES.TopicEnd){ let patientClient = clientCache.findById(targetUserId); if(patientClient)//结束咨询的告知患者 WechatClient.sendViaWebSocket(patientClient.socket, message); } }; static sendViaWebSocket(socket, message) { socket.emit('message', { id: message.id, session_id: message.session_id, sender_id: message.sender_id, sender_name: message.sender_name, content_type: message.content_type, content: message.content, timestamp: ObjectUtil.timestampToLong(message.timestamp), type: message.content_type, // legacy support name: message.sender_name, sender_img : message.sender_img }); } static sendAllRead(doctorId,sessionId){ let doctorClient = clientCache.findByIdAndType(doctorId,SOCKET_TYPES.DOCTOR); if(doctorClient){ if(doctorClient.sessionId==sessionId){ doctorClient.socket.emit('message',{ read:"all"}); }else{ log.warn(" doctor not in the same session "); } }else{ log.warn(doctorId+" target doctor is not online!"); } } static sendMucAllRead(doctorId,loginUserId,sessionId){ let loginClinet = clientCache.findByIdAndType(loginUserId,SOCKET_TYPES.DOCTOR); if(loginClinet){ //muc是医生来获取数据不能更新成已读 log.warn("type is muc login is doctor not send all read to other doctor!") return; } let doctorClient = clientCache.findByIdAndType(doctorId,SOCKET_TYPES.DOCTOR); if(doctorClient){ if(doctorClient.sessionId==sessionId){ doctorClient.socket.emit('message',{ read:"all"}); }else{ log.warn(" doctor not in the same session "); } }else{ log.warn(doctorId+" target doctor is not online!"); } } static sendReadDoctor(socket, message) { socket.emit('message', { id: message.id, session_id: message.session_id, sender_id: message.sender_id, sender_name: message.sender_name, content_type: message.content_type, content: message.content, timestamp: ObjectUtil.timestampToLong(message.timestamp), type: message.content_type, // legacy support name: message.sender_name, read:"one" }); } static sendReadDoctorByDoctorId(doctorId, message) { let doctorClient = clientCache.findByIdAndType(doctorId,SOCKET_TYPES.DOCTOR); // let pc_doctorClient = clientCache.findByIdAndType("pc_"+doctorId,SOCKET_TYPES.PC_DOCTOR); if(!doctorClient){ log.warn("target doctor is not online!"); return; } let sendDoctorClient = clientCache.findByIdAndType(message.sender_id,SOCKET_TYPES.DOCTOR); // let pc_sendDoctorClient = clientCache.findByIdAndType("pc_"+message.sender_id,SOCKET_TYPES.PC_DOCTOR); if(sendDoctorClient&&sendDoctorClient.sessionId==doctorClient.sessionId){ WechatClient.updateParticipantLastFetchTime(doctorClient.sessionId, doctorId, ObjectUtil.timestampToLong(message.timestamp)); sendDoctorClient.socket.emit('message', { id: message.id, session_id: message.session_id, sender_id: message.sender_id, sender_name: message.sender_name, content_type: message.content_type, content: message.content, timestamp: ObjectUtil.timestampToLong(message.timestamp), type: message.content_type, // legacy support name: message.sender_name, read:"one" }); }else{ log.warn("doctor is not in the same session or not online"); } //发送pc版医生端 // if(pc_doctorClient&&pc_sendDoctorClient&&pc_sendDoctorClient.sessionId==pc_doctorClient.sessionId){ // WechatClient.updateParticipantLastFetchTime(pc_doctorClient.sessionId, doctorId, ObjectUtil.timestampToLong(message.timestamp)); // pc_sendDoctorClient.socket.emit('message', { // id: message.id, // session_id: message.session_id, // sender_id: message.sender_id, // sender_name: message.sender_name, // content_type: message.content_type, // content: message.content, // timestamp: ObjectUtil.timestampToLong(message.timestamp), // type: message.content_type, // legacy support // name: message.sender_name, // read:"one" // }); // }else{ // log.warn("doctor is not in the same session or not online"); // } } static sendSocketMessageToDoctor(doctorId, message) { let doctorClient = clientCache.findByIdAndType(doctorId,SOCKET_TYPES.DOCTOR); // let pc_doctorClient = clientCache.findByIdAndType("pc_"+doctorId,SOCKET_TYPES.PC_DOCTOR); if(!doctorClient){ log.warn("target doctor is not online!"); return; } let sendClient = clientCache.findByIdAndType(message.sender_id,SOCKET_TYPES.DOCTOR);//app医生发送的消息 // if(!sendClient){//pc医生发送的消息 // sendClient = clientCache.findByIdAndType("pc_"+message.sender_id,SOCKET_TYPES.PC_DOCTOR); // } if(!sendClient){//居民发送的消息 sendClient = clientCache.findByIdAndType(message.sender_id,SOCKET_TYPES.PATIENT); } if(sendClient&&sendClient.sessionId==doctorClient.sessionId){ WechatClient.updateParticipantLastFetchTime(doctorClient.sessionId, doctorId, ObjectUtil.timestampToLong(message.timestamp)); doctorClient.socket.emit('message', { id: message.id, session_id: message.session_id, sender_id: message.sender_id, sender_name: message.sender_name, content_type: message.content_type, content: message.content, timestamp: ObjectUtil.timestampToLong(message.timestamp), type: message.content_type, // legacy support name: message.sender_name, }); }else{ log.warn("doctor is not in the same session or is not online"); } //发送pc端 // if(pc_doctorClient&&sendClient&&sendClient.sessionId==pc_doctorClient.sessionId){ // WechatClient.updateParticipantLastFetchTime(pc_doctorClient.sessionId, doctorId, ObjectUtil.timestampToLong(message.timestamp)); // pc_doctorClient.socket.emit('message', { // id: message.id, // session_id: message.session_id, // sender_id: message.sender_id, // sender_name: message.sender_name, // content_type: message.content_type, // content: message.content, // timestamp: ObjectUtil.timestampToLong(message.timestamp), // type: message.content_type, // legacy support // name: message.sender_name, // }); // }else{ // log.warn("doctor is not in the same session or is not online"); // } } /** * 发送微信模板消息给居民 * * @param targetUserId * @param message */ static sendViaMessageTemplate(targetUserId, targetUserName, message) { async.waterfall([ // 获取微信openid function (callback) { PatientRepo.findWechatOpenIds(targetUserId, function (err, res) { if (err) { ModelUtil.logError("Get wechat openid failed", err); return; } var map = new Map(); res.forEach(function (participant) { let openid = participant.openid; if (targetUserId==participant.code) { if (!openid) { ModelUtil.logError("User haven't bound with wechat, user id: " + targetUserId); } map.set("openid",participant); }else { if(!map.has(openid)){ map.set(openid,participant); } } }) // // let openid = result && result.length > 0 ? result[0].openid : null; // if (!openid) { // ModelUtil.logError("User haven't bound with wechat, user id: " + targetUserId); // return; // } // // log.warn("Send via wechat message template, user id: " + targetUserId + ", openid: " + openid); callback(null, map); }); }, // 获取议题信息 function (map, callback) { TopicRepo.findLastTopicStatusAndType(message.session_id, function (err, res) { if (err) { ModelUtil.logError("Get topic failed", err); return; } if (!res || res.length == 0) { ModelUtil.logError("Unable to find session last topic"); return; } callback(null, map, message.sender_name, res[0]); }); }, // 发送消息 function (map, senderName, topic,callback) { let replyContent = message.content; switch (Number.parseInt(message.content_type)) { case CONTENT_TYPES.Image: replyContent = "[图片]"; break; case CONTENT_TYPES.Audio: replyContent = "[语音]"; break; default: break; } var patient = map.get("openid"); map.delete("openid"); let agent = topic.agent; let consultTitle = topic.type==8?"续方":"健康"; let description = topic.type==8?"续方咨询":topic.description; let url = config.wechatConfig.baseUrl + "/wx/html/yszx/html/consulting-doctor.html"; if(agent){//代理人发起的议题 var agentOpenid = ""; if(map.size>0){ for(var key of map.keys()){ var member = map.get(key); if(agent == member.code){ agentOpenid = key; var openid = key; var first = "您的家人("+patient.name+")的"+consultTitle+"咨询有新的回复"; // 发送模板消息 WechatSDK.sendTemplateMessage({ touser: openid, template_id: config.wechatConfig.template.consultTemplate, url: url + "?openid=" + openid + "&type="+topic.type+"&doctor="+message.sender_id+ "&consult=" + topic.id + "&toUser=" + member.code + "&toName=" + member.name+"&represented="+patient.code, data: { first: {value: first, color: "#000000"} , remark: {value: "", color: "#000000"} , keyword1: {value: description, color: "#000000"} , keyword2: {value: replyContent, color: "#000000"} , keyword3: {value: senderName, color: "#000000"} } }, function (err, res) { err ? log.error(err) : log.info(res); }); } } } if(patient.openid&&patient.openid!=agentOpenid){ var first = "您的"+consultTitle+"咨询有新的回复"; // 发送模板消息 WechatSDK.sendTemplateMessage({ touser: patient.openid, template_id: config.wechatConfig.template.consultTemplate, url: url + "?openid=" + patient.openid +"&type="+topic.type+"&doctor="+message.sender_id+ "&consult=" + topic.id + "&toUser=" + targetUserId + "&toName=" + targetUserName+"&represented="+patient.code, data: { first: {value: first, color: "#000000"} , remark: {value: "", color: "#000000"} , keyword1: {value: description, color: "#000000"} , keyword2: {value: replyContent, color: "#000000"} , keyword3: {value: senderName, color: "#000000"} } }, function (err, res) { err ? log.error(err) : log.info(res); }); } }else {//自己发起的议题 // 发送模板消息 if(patient.openid){ WechatSDK.sendTemplateMessage({ touser: patient.openid, template_id: config.wechatConfig.template.consultTemplate, url: url + "?openid=" + patient.openid +"&type="+topic.type+"&doctor="+message.sender_id+ "&consult=" + topic.id + "&toUser=" + targetUserId + "&toName=" + targetUserName+"&represented="+patient.code, data: { first: {value: "您的"+consultTitle+"咨询有新的回复", color: "#000000"} , remark: {value: "", color: "#000000"} , keyword1: {value: description, color: "#000000"} , keyword2: {value: replyContent, color: "#000000"} , keyword3: {value: senderName, color: "#000000"} } }, function (err, res) { err ? log.error(err) : log.info(res); }); } if(map.size>0){ for(var key of map.keys()){ if(!patient.openid||key!=patient.openid){ var member = map.get(key); var openid = key; var first = "您的家人("+patient.name+")的"+consultTitle+"咨询有新的回复"; // 发送模板消息 WechatSDK.sendTemplateMessage({ touser: openid, template_id: config.wechatConfig.template.consultTemplate, url: url + "?openid=" + openid +"&type="+topic.type+"&doctor="+message.sender_id+ "&consult=" + topic.id + "&toUser=" + member.code + "&toName=" + member.name+"&represented="+patient.code, data: { first: {value: first, color: "#000000"} , remark: {value: "", color: "#000000"} , keyword1: {value: description, color: "#000000"} , keyword2: {value: replyContent, color: "#000000"} , keyword3: {value: senderName, color: "#000000"} } }, function (err, res) { err ? log.error(err) : log.info(res); }); } } } } callback(null, null); } ], function (err, res) { if (!err) { log.info("Send via wechat template message, DONE!"); } }); }; static updateParticipantLastFetchTime(sessionId, userId, score) { score = score + 1000; let participantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId); redisConn.zaddAsync(participantsKey, score, userId) .then(function (res) { ParticipantRepo.updateLastFetchTime(new Date(score), sessionId, userId, function (err, res) { if (err) { log.error("Update participant last fetch time failed: ", err); } }); }) .catch(function (err) { log.error("Update participant last fetch time failed: ", err); }); } } module.exports = WechatClient;