wechat.client.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /**
  2. * 用户微信客户端。
  3. */
  4. "use strict";
  5. let RedisClient = require('../../repository/redis/redis.client');
  6. let RedisModel = require('../redis.model');
  7. let ObjectUtil = require("../../util/object.util.js");
  8. let ModelUtil = require('../../util/model.util');
  9. let WechatSDK = require('../../util/wechat.sdk');
  10. let PatientRepo = require('../../repository/mysql/patient.repo');
  11. let TopicRepo = require("../../repository/mysql/topics.repo.js");
  12. let ParticipantRepo = require("../../repository/mysql/participant.repo");
  13. let redisConn = RedisClient.redisClient().connection;
  14. let clientCache = require('../socket.io/client.cache').clientCache();
  15. let configFile = require('../../include/commons').CONFIG_FILE;
  16. let config = require('../../resources/config/' + configFile);
  17. let log = require("../../util/log.js");
  18. let https = require('https');
  19. let async = require('async');
  20. const CONTENT_TYPES = require('../../include/commons').CONTENT_TYPES;
  21. const SOCKET_TYPES = require('../../include/commons').SOCKET_TYPES;
  22. const REDIS_KEYS = require('../../include/commons').REDIS_KEYS;
  23. class WechatClient extends RedisModel {
  24. constructor() {
  25. super();
  26. }
  27. /**
  28. * 取得用户微信端状态。若Redis中找不到,则从MySQL中查找。
  29. *
  30. * @param userId
  31. * @param handler
  32. */
  33. static getWechatStatus(userId, handler) {
  34. redisConn.hgetallAsync(RedisModel.makeRedisKey(REDIS_KEYS.UserWechatStatus, userId))
  35. .then(function (status) {
  36. if (status == null) {
  37. PatientRepo.findWechatOpenId(userId, handler);
  38. } else {
  39. handler(null, {openid: status.openid});
  40. }
  41. })
  42. .catch(function (err) {
  43. handler(err, null);
  44. });
  45. }
  46. /**
  47. * 向微信端用户发送消息。若用户微信端在线,通过Web Socket推送给患者,如果不在线则通过微信的模板消息。
  48. *
  49. * 只推送文本、图片及语音消息
  50. *
  51. * @param targetUserId
  52. * @param message 消息体
  53. */
  54. static sendMessage(targetUserId, targetUserName, message) {
  55. if (message&&(message.content_type == CONTENT_TYPES.PlainText ||
  56. message.content_type == CONTENT_TYPES.Image ||
  57. message.content_type == CONTENT_TYPES.Audio)) {
  58. let patientClient = clientCache.findById(targetUserId);
  59. let doctorClient = clientCache.findByIdAndType(message.sender_id,SOCKET_TYPES.DOCTOR);
  60. if (patientClient) {
  61. log.warn("User's wechat endpoint is online, sending via web socket. User id: ", targetUserId);
  62. WechatClient.sendViaWebSocket(patientClient.socket, message);
  63. if(doctorClient){
  64. log.error("doctor sessionid "+doctorClient.sessionId);
  65. log.error("patient sessionid "+patientClient.sessionId);
  66. if(patientClient.sessionId==doctorClient.sessionId){
  67. //用户socket在线,推送给用户后,告知医生此消息已读
  68. WechatClient.updateParticipantLastFetchTime(doctorClient.sessionId, targetUserId, ObjectUtil.timestampToLong(message.timestamp));
  69. WechatClient.sendReadDoctor(doctorClient.socket, message);
  70. }
  71. }else{
  72. log.error("doctor client not found");
  73. }
  74. } else {
  75. log.info("User's wechat endpoint is not online, sending via wechat template message. User id: ", targetUserId);
  76. WechatClient.sendViaMessageTemplate(targetUserId, targetUserName, message);
  77. }
  78. } else if(message.content_type == CONTENT_TYPES.TopicEnd){
  79. let patientClient = clientCache.findById(targetUserId);
  80. if(patientClient)//结束咨询的告知患者
  81. WechatClient.sendViaWebSocket(patientClient.socket, message);
  82. }
  83. };
  84. static sendViaWebSocket(socket, message) {
  85. socket.emit('message', {
  86. id: message.id,
  87. session_id: message.session_id,
  88. sender_id: message.sender_id,
  89. sender_name: message.sender_name,
  90. content_type: message.content_type,
  91. content: message.content,
  92. timestamp: ObjectUtil.timestampToLong(message.timestamp),
  93. type: message.content_type, // legacy support
  94. name: message.sender_name,
  95. sender_img : message.sender_img
  96. });
  97. }
  98. static sendAllRead(doctorId,sessionId){
  99. let doctorClient = clientCache.findByIdAndType(doctorId,SOCKET_TYPES.DOCTOR);
  100. if(doctorClient){
  101. if(doctorClient.sessionId==sessionId){
  102. doctorClient.socket.emit('message',{ read:"all"});
  103. }else{
  104. log.warn(" doctor not in the same session ");
  105. }
  106. }else{
  107. log.warn(doctorId+" target doctor is not online!");
  108. }
  109. }
  110. static sendMucAllRead(doctorId,loginUserId,sessionId){
  111. let loginClinet = clientCache.findByIdAndType(loginUserId,SOCKET_TYPES.DOCTOR);
  112. if(loginClinet){
  113. //muc是医生来获取数据不能更新成已读
  114. log.warn("type is muc login is doctor not send all read to other doctor!")
  115. return;
  116. }
  117. let doctorClient = clientCache.findByIdAndType(doctorId,SOCKET_TYPES.DOCTOR);
  118. if(doctorClient){
  119. if(doctorClient.sessionId==sessionId){
  120. doctorClient.socket.emit('message',{ read:"all"});
  121. }else{
  122. log.warn(" doctor not in the same session ");
  123. }
  124. }else{
  125. log.warn(doctorId+" target doctor is not online!");
  126. }
  127. }
  128. static sendReadDoctor(socket, message) {
  129. socket.emit('message', {
  130. id: message.id,
  131. session_id: message.session_id,
  132. sender_id: message.sender_id,
  133. sender_name: message.sender_name,
  134. content_type: message.content_type,
  135. content: message.content,
  136. timestamp: ObjectUtil.timestampToLong(message.timestamp),
  137. type: message.content_type, // legacy support
  138. name: message.sender_name,
  139. read:"one"
  140. });
  141. }
  142. static sendReadDoctorByDoctorId(doctorId, message) {
  143. let doctorClient = clientCache.findByIdAndType(doctorId,SOCKET_TYPES.DOCTOR);
  144. // let pc_doctorClient = clientCache.findByIdAndType("pc_"+doctorId,SOCKET_TYPES.PC_DOCTOR);
  145. if(!doctorClient){
  146. log.warn("target doctor is not online!");
  147. return;
  148. }
  149. let sendDoctorClient = clientCache.findByIdAndType(message.sender_id,SOCKET_TYPES.DOCTOR);
  150. // let pc_sendDoctorClient = clientCache.findByIdAndType("pc_"+message.sender_id,SOCKET_TYPES.PC_DOCTOR);
  151. if(sendDoctorClient&&sendDoctorClient.sessionId==doctorClient.sessionId){
  152. WechatClient.updateParticipantLastFetchTime(doctorClient.sessionId, doctorId, ObjectUtil.timestampToLong(message.timestamp));
  153. sendDoctorClient.socket.emit('message', {
  154. id: message.id,
  155. session_id: message.session_id,
  156. sender_id: message.sender_id,
  157. sender_name: message.sender_name,
  158. content_type: message.content_type,
  159. content: message.content,
  160. timestamp: ObjectUtil.timestampToLong(message.timestamp),
  161. type: message.content_type, // legacy support
  162. name: message.sender_name,
  163. read:"one"
  164. });
  165. }else{
  166. log.warn("doctor is not in the same session or not online");
  167. }
  168. //发送pc版医生端
  169. // if(pc_doctorClient&&pc_sendDoctorClient&&pc_sendDoctorClient.sessionId==pc_doctorClient.sessionId){
  170. // WechatClient.updateParticipantLastFetchTime(pc_doctorClient.sessionId, doctorId, ObjectUtil.timestampToLong(message.timestamp));
  171. // pc_sendDoctorClient.socket.emit('message', {
  172. // id: message.id,
  173. // session_id: message.session_id,
  174. // sender_id: message.sender_id,
  175. // sender_name: message.sender_name,
  176. // content_type: message.content_type,
  177. // content: message.content,
  178. // timestamp: ObjectUtil.timestampToLong(message.timestamp),
  179. // type: message.content_type, // legacy support
  180. // name: message.sender_name,
  181. // read:"one"
  182. // });
  183. // }else{
  184. // log.warn("doctor is not in the same session or not online");
  185. // }
  186. }
  187. static sendSocketMessageToDoctor(doctorId, message) {
  188. let doctorClient = clientCache.findByIdAndType(doctorId,SOCKET_TYPES.DOCTOR);
  189. // let pc_doctorClient = clientCache.findByIdAndType("pc_"+doctorId,SOCKET_TYPES.PC_DOCTOR);
  190. if(!doctorClient){
  191. log.warn("target doctor is not online!");
  192. return;
  193. }
  194. let sendClient = clientCache.findByIdAndType(message.sender_id,SOCKET_TYPES.DOCTOR);//app医生发送的消息
  195. // if(!sendClient){//pc医生发送的消息
  196. // sendClient = clientCache.findByIdAndType("pc_"+message.sender_id,SOCKET_TYPES.PC_DOCTOR);
  197. // }
  198. if(!sendClient){//居民发送的消息
  199. sendClient = clientCache.findByIdAndType(message.sender_id,SOCKET_TYPES.PATIENT);
  200. }
  201. if(sendClient&&sendClient.sessionId==doctorClient.sessionId){
  202. WechatClient.updateParticipantLastFetchTime(doctorClient.sessionId, doctorId, ObjectUtil.timestampToLong(message.timestamp));
  203. doctorClient.socket.emit('message', {
  204. id: message.id,
  205. session_id: message.session_id,
  206. sender_id: message.sender_id,
  207. sender_name: message.sender_name,
  208. content_type: message.content_type,
  209. content: message.content,
  210. timestamp: ObjectUtil.timestampToLong(message.timestamp),
  211. type: message.content_type, // legacy support
  212. name: message.sender_name,
  213. });
  214. }else{
  215. log.warn("doctor is not in the same session or is not online");
  216. }
  217. //发送pc端
  218. // if(pc_doctorClient&&sendClient&&sendClient.sessionId==pc_doctorClient.sessionId){
  219. // WechatClient.updateParticipantLastFetchTime(pc_doctorClient.sessionId, doctorId, ObjectUtil.timestampToLong(message.timestamp));
  220. // pc_doctorClient.socket.emit('message', {
  221. // id: message.id,
  222. // session_id: message.session_id,
  223. // sender_id: message.sender_id,
  224. // sender_name: message.sender_name,
  225. // content_type: message.content_type,
  226. // content: message.content,
  227. // timestamp: ObjectUtil.timestampToLong(message.timestamp),
  228. // type: message.content_type, // legacy support
  229. // name: message.sender_name,
  230. // });
  231. // }else{
  232. // log.warn("doctor is not in the same session or is not online");
  233. // }
  234. }
  235. /**
  236. * 发送微信模板消息给居民
  237. *
  238. * @param targetUserId
  239. * @param message
  240. */
  241. static sendViaMessageTemplate(targetUserId, targetUserName, message) {
  242. async.waterfall([
  243. // 获取微信openid
  244. function (callback) {
  245. PatientRepo.findWechatOpenIds(targetUserId, function (err, res) {
  246. if (err) {
  247. ModelUtil.logError("Get wechat openid failed", err);
  248. return;
  249. }
  250. var map = new Map();
  251. res.forEach(function (participant) {
  252. let openid = participant.openid;
  253. if (targetUserId==participant.code) {
  254. if (!openid) {
  255. ModelUtil.logError("User haven't bound with wechat, user id: " + targetUserId);
  256. }
  257. map.set("openid",participant);
  258. }else {
  259. if(!map.has(openid)){
  260. map.set(openid,participant);
  261. }
  262. }
  263. })
  264. //
  265. // let openid = result && result.length > 0 ? result[0].openid : null;
  266. // if (!openid) {
  267. // ModelUtil.logError("User haven't bound with wechat, user id: " + targetUserId);
  268. // return;
  269. // }
  270. //
  271. // log.warn("Send via wechat message template, user id: " + targetUserId + ", openid: " + openid);
  272. callback(null, map);
  273. });
  274. },
  275. // 获取议题信息
  276. function (map, callback) {
  277. TopicRepo.findLastTopicStatusAndType(message.session_id, function (err, res) {
  278. if (err) {
  279. ModelUtil.logError("Get topic failed", err);
  280. return;
  281. }
  282. if (!res || res.length == 0) {
  283. ModelUtil.logError("Unable to find session last topic");
  284. return;
  285. }
  286. callback(null, map, message.sender_name, res[0]);
  287. });
  288. },
  289. // 发送消息
  290. function (map, senderName, topic,callback) {
  291. let replyContent = message.content;
  292. switch (Number.parseInt(message.content_type)) {
  293. case CONTENT_TYPES.Image:
  294. replyContent = "[图片]";
  295. break;
  296. case CONTENT_TYPES.Audio:
  297. replyContent = "[语音]";
  298. break;
  299. default:
  300. break;
  301. }
  302. var patient = map.get("openid");
  303. map.delete("openid");
  304. let agent = topic.agent;
  305. let consultTitle = topic.type==8?"续方":"健康";
  306. let description = topic.type==8?"续方咨询":topic.description;
  307. let url = config.wechatConfig.baseUrl + "/wx/html/yszx/html/consulting-doctor.html";
  308. if(agent){//代理人发起的议题
  309. var agentOpenid = "";
  310. if(map.size>0){
  311. for(var key of map.keys()){
  312. var member = map.get(key);
  313. if(agent == member.code){
  314. agentOpenid = key;
  315. var openid = key;
  316. var first = "您的家人("+patient.name+")的"+consultTitle+"咨询有新的回复";
  317. // 发送模板消息
  318. WechatSDK.sendTemplateMessage({
  319. touser: openid,
  320. template_id: config.wechatConfig.template.consultTemplate,
  321. url: url + "?openid=" + openid + "&type="+topic.type+"&doctor="+message.sender_id+
  322. "&consult=" + topic.id + "&toUser=" + member.code + "&toName=" + member.name+"&represented="+patient.code,
  323. data: {
  324. first: {value: first, color: "#000000"}
  325. , remark: {value: "", color: "#000000"}
  326. , keyword1: {value: description, color: "#000000"}
  327. , keyword2: {value: replyContent, color: "#000000"}
  328. , keyword3: {value: senderName, color: "#000000"}
  329. }
  330. }, function (err, res) {
  331. err ? log.error(err) : log.info(res);
  332. });
  333. }
  334. }
  335. }
  336. if(patient.openid&&patient.openid!=agentOpenid){
  337. var first = "您的"+consultTitle+"咨询有新的回复";
  338. // 发送模板消息
  339. WechatSDK.sendTemplateMessage({
  340. touser: patient.openid,
  341. template_id: config.wechatConfig.template.consultTemplate,
  342. url: url + "?openid=" + patient.openid +"&type="+topic.type+"&doctor="+message.sender_id+
  343. "&consult=" + topic.id + "&toUser=" + targetUserId + "&toName=" + targetUserName+"&represented="+patient.code,
  344. data: {
  345. first: {value: first, color: "#000000"}
  346. , remark: {value: "", color: "#000000"}
  347. , keyword1: {value: description, color: "#000000"}
  348. , keyword2: {value: replyContent, color: "#000000"}
  349. , keyword3: {value: senderName, color: "#000000"}
  350. }
  351. }, function (err, res) {
  352. err ? log.error(err) : log.info(res);
  353. });
  354. }
  355. }else {//自己发起的议题
  356. // 发送模板消息
  357. if(patient.openid){
  358. WechatSDK.sendTemplateMessage({
  359. touser: patient.openid,
  360. template_id: config.wechatConfig.template.consultTemplate,
  361. url: url + "?openid=" + patient.openid +"&type="+topic.type+"&doctor="+message.sender_id+
  362. "&consult=" + topic.id + "&toUser=" + targetUserId + "&toName=" + targetUserName+"&represented="+patient.code,
  363. data: {
  364. first: {value: "您的"+consultTitle+"咨询有新的回复", color: "#000000"}
  365. , remark: {value: "", color: "#000000"}
  366. , keyword1: {value: description, color: "#000000"}
  367. , keyword2: {value: replyContent, color: "#000000"}
  368. , keyword3: {value: senderName, color: "#000000"}
  369. }
  370. }, function (err, res) {
  371. err ? log.error(err) : log.info(res);
  372. });
  373. }
  374. if(map.size>0){
  375. for(var key of map.keys()){
  376. if(!patient.openid||key!=patient.openid){
  377. var member = map.get(key);
  378. var openid = key;
  379. var first = "您的家人("+patient.name+")的"+consultTitle+"咨询有新的回复";
  380. // 发送模板消息
  381. WechatSDK.sendTemplateMessage({
  382. touser: openid,
  383. template_id: config.wechatConfig.template.consultTemplate,
  384. url: url + "?openid=" + openid +"&type="+topic.type+"&doctor="+message.sender_id+
  385. "&consult=" + topic.id + "&toUser=" + member.code + "&toName=" + member.name+"&represented="+patient.code,
  386. data: {
  387. first: {value: first, color: "#000000"}
  388. , remark: {value: "", color: "#000000"}
  389. , keyword1: {value: description, color: "#000000"}
  390. , keyword2: {value: replyContent, color: "#000000"}
  391. , keyword3: {value: senderName, color: "#000000"}
  392. }
  393. }, function (err, res) {
  394. err ? log.error(err) : log.info(res);
  395. });
  396. }
  397. }
  398. }
  399. }
  400. callback(null, null);
  401. }
  402. ],
  403. function (err, res) {
  404. if (!err) {
  405. log.info("Send via wechat template message, DONE!");
  406. }
  407. });
  408. };
  409. static updateParticipantLastFetchTime(sessionId, userId, score) {
  410. score = score + 1000;
  411. let participantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  412. redisConn.zaddAsync(participantsKey, score, userId)
  413. .then(function (res) {
  414. ParticipantRepo.updateLastFetchTime(new Date(score), sessionId, userId, function (err, res) {
  415. if (err) {
  416. log.error("Update participant last fetch time failed: ", err);
  417. }
  418. });
  419. })
  420. .catch(function (err) {
  421. log.error("Update participant last fetch time failed: ", err);
  422. });
  423. }
  424. }
  425. module.exports = WechatClient;