瀏覽代碼

增加微信token视图;修复微信模板消息发送失败bug

Sand 8 年之前
父節點
當前提交
baad081d00

+ 2 - 1
src/client/im.client.js

@ -220,8 +220,9 @@ var imClient = {
        // TEST!PASS 创建P2P会话
        createP2pSession: function (userId, peerId, success, failure) {
            var json = '{"' + userId + '": "0", "' + peerId + '": "0"}';
            httpClient.post(ENDPOINTS.Sessions.Sessions,
                {session_type: 2, session_name: "P2P", participants: [userId + ":0", peerId + ":0"]},
                {session_type: 2, session_name: "P2P", participants: json},
                success,
                failure);
        },

+ 8 - 5
src/server/endpoints/v2/session.endpoint.js

@ -52,6 +52,7 @@ router.post("/", function (req, res) {
    for (let j in participants) {
        participantArray.push(j + ":" + participants[j]);
    }
    ControllerUtil.regModelEventHandler(sessions, res);
    sessions.createSession(sessionId, sessionName, sessionType, participantArray);
});
@ -186,7 +187,6 @@ router.put(APIv2.Sessions.Participant, function (req, res) {
});
/**
 * 增加成员
 * user_id:增加的人员
@ -201,11 +201,10 @@ router.post(APIv2.Sessions.ParticipantUpdate, function (req, res) {
    }
    let participants = new Participants();
    ControllerUtil.regModelEventHandler(participants, res);
    participants.updateSessionUser(payload.user_id,payload.old_user_id,payload.session_id);
    participants.updateSessionUser(payload.user_id, payload.old_user_id, payload.session_id);
});
/**
 * 移除成员
 * user:移除的人员
@ -247,9 +246,13 @@ router.post(APIv2.Sessions.Messages, function (req, res) {
    if (!testing.pass) {
        throw {httpStatus: 406, message: testing.message}
    }
    // 消息的发送时间由服务端决定
    payload.timestamp = new Date((new Date().getTime() + 1000));
    let sessions = new Sessions();
    ControllerUtil.regModelEventHandler(sessions, res);
    payload.timestamp = new Date((new Date().getTime()+1000));
    sessions.saveMessageBySession(req.params.session_id, payload);
});
@ -261,7 +264,7 @@ router.post(APIv2.Sessions.TopicMessages, function (req, res) {
    }
    let sessions = new Sessions();
    ControllerUtil.regModelEventHandler(sessions, res);
    payload.timestamp = new Date((new Date().getTime()+1000));
    payload.timestamp = new Date((new Date().getTime() + 1000));
    sessions.sendTopicMessages(req.params.topic_id, payload);
})

+ 17 - 2
src/server/handlers/socket.handler.js

@ -10,7 +10,10 @@ let clientCache = require('../models/socket.io/client.cache').clientCache();
let PatientClient = require('./../models/socket.io/patient.client');
let Sessions = require('../models/sessions/sessions');
let Users = require('../models/user/users');
let sessions = new Sessions();
let users = new Users();
class SocketHandler {
    constructor(socketServer) {
@ -28,7 +31,12 @@ class SocketHandler {
                if (!data.userId) {
                    socketServer.sockets.emit('error', {message: 'Missing fields(s): userId.'});
                } else {
                    log.info('User login: ' + data.userId);
                    if(clientCache.removeByUserId(data.userId)){
                        log.info("User " + data.userId + " already login");
                        return;
                    }
                    log.info('User ' + data.userId + ' login');
                    let patientClient = new PatientClient(socket, socketServer);
                    patientClient.userId = data.userId;
@ -36,16 +44,23 @@ class SocketHandler {
                    clientCache.addClient(patientClient);
                    users.login(data.userId, 10, '', '');
                    socketServer.sockets.emit('ack', {});
                }
            });
            // 接收客户端消息
            socket.on('message', function (data) {
                log.debug('Got message from ' + clientCache.findBySocket(socket).userId);
                log.info('Got message from ' + clientCache.findBySocket(socket).userId);
                let sessionId = data.session_id;
                let message = data.message;
                message.timestamp = new Date();
                /*sessions.createSession(sessionId, "Let's talk!", 1, ['504a0bcddb1e4e37a0306b39c51900b5', 'cd92414c-5b06-11e6-8344-fa163e8aee56'], function (err, res) {
                    sessions.saveMessageBySession(sessionId, message);
                });*/
                sessions.saveMessageBySession(sessionId, message);
            });

+ 1 - 1
src/server/models/client/app.client.js

@ -100,7 +100,7 @@ class AppClient extends RedisModel {
                return;
            }
            if(!userStatus){
                log.warn("User of app endpoint is not online, user id: " + targetId);
                log.warn("User's app endpoint is not online, user id: " + targetId);
                return;
            }
            let tipMessage = CONTENT_TYPES.typeToDescription(parseInt(message.content_type), "您有一条新消息") || message.content;

+ 95 - 70
src/server/models/client/wechat.client.js

@ -7,9 +7,9 @@ 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 DoctorRepo = require('../../repository/mysql/doctor.repo');
let WechatSDK = require('../../util/wechat.sdk');
let PatientRepo = require('../../repository/mysql/patient.repo');
let TopicRepo = require("../../repository/mysql/topics.repo.js");
let redisConn = RedisClient.redisClient().connection;
let clientCache = require('../socket.io/client.cache').clientCache();
@ -17,6 +17,7 @@ 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 REDIS_KEYS = require('../../include/commons').REDIS_KEYS;
@ -38,7 +39,7 @@ class WechatClient extends RedisModel {
                if (status == null) {
                    PatientRepo.findWechatOpenId(userId, handler);
                } else {
                    handler(null, {open_id: status.open_id});
                    handler(null, {openid: status.openid});
                }
            })
            .catch(function (err) {
@ -49,95 +50,119 @@ class WechatClient extends RedisModel {
    /**
     * 向微信端用户发送消息。若用户微信端在线,通过Web Socket推送给患者,如果不在线则通过微信的模板消息。
     *
     * @param targetUserId
     * @param message 消息
     */
    static sendMessage(message) {
        let patientClient = clientCache.findById(message.to);
    static sendMessage(targetUserId, message) {
        let patientClient = clientCache.findById(targetUserId);
        if (patientClient) {
            WechatClient.sendViaWebSocket(patientClient.socket, message);
        } else {
            log.info("User of wechat endpoint is not online, user id: ", message.to, ", sending via wechat template message.");
            log.info("User's wechat endpoint is not online, sending via wechat template message. User id: ", targetUserId);
            WechatClient.sendViaTemplateMessage(message);
            WechatClient.sendViaTemplateMessage(targetUserId, message);
        }
    };
    static sendViaWebSocket(socket, message){
        message.timestamp = ObjectUtil.timestampToLong(message.timestamp);
        socket.emit('message', 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)
        });
    }
    /**
     * 发送微信模板消息给居民
     *
     * @param targetUserId
     * @param message
     */
    static sendViaTemplateMessage(message) {
        function sendWxMessage(openid, name, topic) {
            let replyContent = message.content;
            switch (Number.parseInt(message.contentType)) {
                case CONTENT_TYPES.Image:
                    replyContent = "[图片]";
                    break;
                case CONTENT_TYPES.Audio:
                    replyContent = "[语音]";
                    break;
                case 0:
                case CONTENT_TYPES.Article:
                case CONTENT_TYPES.GoTo:
                case CONTENT_TYPES.TopicBegin:
                case CONTENT_TYPES.TopicEnd:
                    return;
                default:
                    break;
            }
            // 发送模板消息
            WechatSDK.sendTemplateMessage({
                touser: openid,
                template_id: config.wechatConfig.template.consultTemplate,
                url: config.wechatConfig.baseUrl + "/wx/html/yszx/html/consulting-doctor.html?openid=" + openid +
                "&consult=" + topic.name + "&toUser=" + message.to,
                data: {
                    first: {value: "您的健康咨询有新的回复", color: "#000000"}
                    , remark: {value: "", color: "#000000"}
                    , keyword1: {value: topic.description, color: "#000000"}
                    , keyword2: {value: replyContent, color: "#000000"}
                    , keyword3: {value: name, color: "#000000"}
                }
            });
        }
    static sendViaTemplateMessage(targetUserId, message) {
        async.waterfall([
                // 获取微信openid
                function (callback) {
                    PatientRepo.findWechatOpenId(targetUserId, function (err, result) {
                        if (err) {
                            ModelUtil.logError("Get wechat openid failed", err);
                            return;
                        }
        // 查询微信OpenId及医生信息,用于构建微信模板消息
        PatientRepo.findWechatOpenId(message.to, function (err, result) {
            if (err) {
                ModelUtil.logError("Get wechat openid failed", err);
                return;
            }
            let openid = result && result.length > 0 ? result[0].openid : "";
            if (openid) {
                DoctorRepo.findOne(message.from, function (err, result) {
                    if (err) {
                        ModelUtil.logError("Get doctor info failed", err);
                        return;
                    }
                        let openid = result && result.length > 0 ? result[0].openid : null;
                        if (!openid) {
                            ModelUtil.logError("User haven't bound with wechat, user id: " + targetUserId);
                            return;
                        }
                        callback(null, openid);
                    });
                },
                // 获取议题信息
                function (openid, callback) {
                    TopicRepo.findLastTopicStatus(message.session_id, function (err, res) {
                        if (err) {
                            ModelUtil.logError("Get topic failed", err);
                            return;
                        }
                    if (result && result.length > 0) {
                        let name = result[0].name;
                        let topic = result && result.length > 0 ? result[0] : "";
                        if (topic) {
                            sendWxMessage(openid, name, topic);
                        if (!res || res.length == 0) {
                            ModelUtil.logError("Unable to find session last topic");
                            return;
                        }
                    } else {
                        ModelUtil.logError("Can not find user info", err);
                        callback(null, openid, message.sender_name, res[0]);
                    });
                },
                // 发送消息
                function (openid, senderName, topic, callback) {
                    let replyContent = message.content;
                    switch (Number.parseInt(message.contentType)) {
                        case CONTENT_TYPES.Image:
                            replyContent = "[图片]";
                            break;
                        case CONTENT_TYPES.Audio:
                            replyContent = "[语音]";
                            break;
                        case 0:
                        case CONTENT_TYPES.Article:
                        case CONTENT_TYPES.GoTo:
                        case CONTENT_TYPES.TopicBegin:
                        case CONTENT_TYPES.TopicEnd:
                            return;
                        default:
                            break;
                    }
                });
            } else {
                ModelUtil.logError("User haven't bound with wechat, user id: " + message.to, err);
            }
        });
                    // 发送模板消息
                    WechatSDK.sendTemplateMessage({
                        touser: openid,
                        template_id: config.wechatConfig.template.consultTemplate,
                        url: config.wechatConfig.baseUrl + "/wx/html/yszx/html/consulting-doctor.html?openid=" + openid +
                        "&consult=" + topic.name + "&toUser=" + targetUserId,
                        data: {
                            first: {value: "您的健康咨询有新的回复", color: "#000000"}
                            , remark: {value: "", color: "#000000"}
                            , keyword1: {value: topic.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!");
                }
            });
    };
}

+ 7 - 7
src/server/models/sessions/sessions.js

@ -799,10 +799,11 @@ class Sessions extends RedisModel {
        let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
        let messageId = mongoose.Types.ObjectId().toString();
        message.id = messageId;
        // 检查会话中是否存在此成员
        participants.existsParticipant(sessionId, message.sender_id, function (err, res) {
            if (err) {
                ModelUtil.emitError(self.eventEmitter, "Check session paticipant failed: ", err);
                ModelUtil.emitError(self.eventEmitter, "Check session participant failed: ", err);
                return;
            }
@ -811,18 +812,17 @@ class Sessions extends RedisModel {
                    let sessionType = res[0];
                    let sessionName = res[1];
                    if (sessionType == null) {
                        ModelUtil.emitError(self.eventEmitter, "Session with id " + sessionId + " not found.");
                        ModelUtil.emitError(self.eventEmitter, "Session " + sessionId + " is not found.");
                        return;
                    }
                    //消息保存到REDIS
                    // 消息保存到Redis,并更新会话最后状态、用户最后消息获取时间
                    messages.saveMessageToRedis(sessionId, sessionType, messageId, message);
                    //更新REDIS最后一条消息
                    Messages.updateLastContent(sessionKey, sessionType, sessionName, message);
                    //更新用户最后一次获取消息的时间
                    Sessions.updateParticipantLastFetchTime(sessionId, message.sender_id, message.timestamp.getTime());
                    //更新最后一条消息到数据库
                    // 更新MYSQL中会话的最新状态,并保存消息
                    SessionRepo.updateSessionLastStatus(message.sender_id, message.sender_name, message.timestamp, message.content, message.content_type, sessionId);
                    //将消息保存到数据库
                    messages.saveMessageToMysql(sessionId, sessionType, messageId, message, function (err, res) {
                        if (err) {
                            ModelUtil.emitError(self.eventEmitter, {message: "Failed to save message to mysql: " + err});

+ 22 - 10
src/server/models/user/users.js

@ -53,12 +53,14 @@ class Users extends RedisModel {
            function (isPatientId) {
                let repoProto = isPatientId ? PatientRepo : DoctorRepo;
                repoProto.findOne(userId, function (err, res) {
                    let user = isPatientId ? new Doctor() : new Patient();
                    let user = isPatientId ? new Patient() : new Doctor();
                    if (res.length > 0) {
                        user.name = res[0].name;
                        user.sex = res[0].sex;
                        user.birthdate = res[0].birthdate;
                        user.avatar = res[0].avatar;
                        if(res[0].openid) user.openid = res[0].openid;
                    }
                    outCallback(null, user);
@ -76,12 +78,12 @@ class Users extends RedisModel {
     *
     * @param userId
     * @param platform
     * @param token
     * @param deviceToken
     * @param clientId
     *
     * @return 用户token
     */
    login(userId, platform, token, clientId) {
    login(userId, platform, deviceToken, clientId) {
        let self = this;
        let loginFromApp = platform !== PLATFORMS.Wechat;
@ -94,7 +96,7 @@ class Users extends RedisModel {
                // get user info from mysql
                function (callback) {
                    self.getUserFromMySQL(userId, function (err, userInfo) {
                        if (userInfo === null) {
                        if (!userInfo) {
                            ModelUtil.emitDataNotFound(self, 'User not exists.');
                            return;
                        }
@ -102,20 +104,30 @@ class Users extends RedisModel {
                        callback(null, userInfo);
                    })
                },
                // cache user app/wechat status
                // cache user and app/wechat status
                function (userInfo, callback) {
                    let multi = redisConn.multi()
                        .zadd(usersKey, lastLoginTime.getTime(), userId);
                    //.hmset(userKey, 'avatar', userInfo.avatar ? userInfo.avatar : '', 'birthdate', userInfo.birthdate ? userInfo.birthdate : '',
                    //    'name', userInfo.name, 'role', loginFromApp ? 'doctor' : 'patient');
                        /*.hmset(userKey,
                            'avatar', userInfo.avatar ? userInfo.avatar : '',
                            'birthdate', userInfo.birthdate ? ObjectUtil.timestampToLong(userInfo.birthdate) : '',
                            'name', userInfo.name,
                            'role', loginFromApp ? 'doctor' : 'patient');*/
                    if (loginFromApp) {
                        // cache app status
                        multi = multi.hmset(userStatusKey, 'platform', platform, 'app_in_bg', 0, 'client_id', clientId,
                            'token', token, 'last_login_time', lastLoginTime.getTime());
                        multi = multi.hmset(userStatusKey,
                            'app_in_bg', 0,
                            'client_id', clientId,
                            'device_token', deviceToken,
                            'last_login_time', lastLoginTime.getTime(),
                            'platform', platform);
                    } else {
                        // cache wechat status
                        multi = multi.hmset(userKey, 'open_id', userInfo.open_id, 'last_login_time', lastLoginTime.getTime());
                        multi = multi.hmset(userStatusKey,
                            'last_login_time', lastLoginTime.getTime(),
                            'openid', userInfo.openid,
                            'platform', platform);
                    }
                    multi.execAsync()

+ 29 - 14
src/server/public/html/socket/test.html

@ -12,7 +12,7 @@
<h2>Patient Login</h2>
<form id="patient_register">
    <label for="patient_id">Patient Id: </label>
    <input type="text" id="patient_id"/>
    <input type="text" id="patient_id" value="504a0bcddb1e4e37a0306b39c51900b5"/>
    <p></p>
@ -25,24 +25,24 @@
</form>
<h2>Chat with doctors</h2>
<form>
    <label for="doctor_id">Doctor Id: </label>
    <input type="text" id="doctor_id"/>
<label for="doctor_id">Doctor Id: </label>
<input type="text" id="doctor_id" value="cd92414c-5b06-11e6-8344-fa163e8aee56"/>
    <p><label for="message">Message: </label></p>
    <p><textarea cols="25" id="message"></textarea></p>
<p><label for="message">Message: </label></p>
<p><textarea cols="25" id="message"></textarea></p>
    <input id="send" type="submit" value="Send"/>
<input id="send" type="button" value="Send"/>
    <p><label for="history">History: </label></p>
    <p><textarea cols="25" id="history"></textarea></p>
</form>
<p><label for="history">History: </label></p>
<p><textarea cols="25" id="history"></textarea></p>
<script src="//cdn.bootcss.com/jquery/1.9.0/jquery.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
    var socket = io.connect();
    socket.emit('login', {userId: $('#patient_id').val(), password: $('#password').val()});
    socket.on('message', function (data) {
        console.log(data.message);
    });
@ -52,26 +52,41 @@
    });
    socket.on('ack', function (data) {
        $('#patient_id').prop("disabled",true);
        $('#password').prop("disabled",true);
        $('#patient_id').prop("disabled", true);
        $('#password').prop("disabled", true);
        $('#login').hide();
        $('#logout').show();
    });
</script>
<script>
    $('#login').click(function () {
    });
    $('#send').click(function () {
        socket.emit('message', {
            session_id: 'd5cbe9d10669f8741bc0805b20697ad1254c8e90',
            message: {
                sender_id: $('#patient_id').val(),
                sender_name: '陈爱珍',
                content_type: '1',
                content: '医生,你好'
            }
        });
    });
    $('#logout').click(function () {
        socket.emit('logout', {userId: $('#patient_id').val()});
        $('#patient_id').prop("disabled",false);
        $('#password').prop("disabled",false);
        $('#patient_id').prop("disabled", false);
        $('#password').prop("disabled", false);
        $('#login').show();
        $('#logout').hide();
    });
</script>
</body>
</html>

+ 2 - 2
src/server/repository/mysql/patient.repo.js

@ -8,7 +8,7 @@
 */
"use strict";
var ImDb = require('./db/im.db');
let ImDb = require('./db/im.db');
class PatientRepo {
    constructor() {
@ -16,7 +16,7 @@ class PatientRepo {
    static findOne(patientId, handler){
        ImDb.execQuery({
            "sql": "select id, name, sex, birthdate, avatar from patients where id = ? ",
            "sql": "select id, name, sex, birthdate, avatar, openid from patients where id = ? ",
            "args": [patientId],
            "handler": handler
        });

+ 1 - 1
src/server/repository/mysql/topics.repo.js

@ -47,7 +47,7 @@ class TopicRepo {
    }
    static findTopicStatus(topicId, handler) {
        let sql = "select id, status from " + DB_TABLES.Topics + " where id = ?";
        let sql = "select id, name, description, status from " + DB_TABLES.Topics + " where id = ?";
        ImDb.execQuery({
            sql: sql,

+ 6 - 4
src/server/repository/mysql/wechat.token.repo.js

@ -20,7 +20,7 @@ class WeChatTokenRepo {
     */
    static findOne(handler) {
        ImDb.execQuery({
            "sql": "select access_token, expiry_date, create_time from wechat_access_tokens order by create_time desc limit 0, 1"
            "sql": "select access_token, expires_in, add_timestamp from wechat_access_tokens order by add_timestamp desc limit 0, 1"
            , "handler": handler
        });
    };
@ -29,12 +29,14 @@ class WeChatTokenRepo {
     * 保存AccessToken
     *
     * @param accessToken 微信AccessToken
     * @param expireIn
     * @param createTime
     * @param handler 回调函数
     */
    static save(accessToken, expiryDate, createTime, handler) {
    static save(accessToken, expireIn, createTime, handler) {
        ImDb.execQuery({
            "sql": "insert into wechat_access_tokens (access_token, expiry_date, create_time) values (?,?,?)"
            , "args": [accessToken, expiryDate, createTime]
            "sql": "insert into wechat_access_tokens (access_token, expires_in, add_timestamp) values (?,?,?)"
            , "args": [accessToken, expireIn, createTime.getTime()]
            , "handler": handler
        });
    }

+ 1 - 1
src/server/resources/config/config.dev.js

@ -62,7 +62,7 @@ let sessionConfig = {
// 议题配置
let topicConfig = {
    TTL: 24,                            // 议题的存活时间,TTL = Time To Live
    TERMINATING_CRON: "2 * * * * *"     // 议题自动关闭的任务执行时间间隔
    TERMINATING_CRON: "* 0 * * * *"     // 议题自动关闭的任务执行时间间隔
};
exports.app = 'IM.Server';

+ 5 - 2
src/server/resources/schema/ichat_1.2.8_view_schema.sql

@ -1,4 +1,4 @@
/* 用户视图:医生、患者、用户微信状态*/
/* 用户视图:医生、患者、用户微信状态、微信系统access_token*/
create or replace view doctors as 
select code id, name, sex, birthday birthdate, photo avatar, hospital_name, level
from wlyy.wlyy_doctor;
@ -12,9 +12,12 @@ SELECT id, user, platform, timeout, imei, token
FROM wlyy.wlyy_token;
create or replace view wechat_status as
select code user_id, openid open_id
select code user_id, openid openid
from wlyy.wlyy_patient;
create or replace view wechat_access_tokens as
select access_token, expires_in, add_timestamp from wlyy.wx_access_token;
/*三师后台咨询消息ID字段类型修改*/
ALTER TABLE wlyy.wlyy_consult_team
  MODIFY COLUMN `end_msg_id`  varchar(50) NULL DEFAULT NULL AFTER `guidance`,

+ 60 - 66
src/server/util/wechat.sdk.js

@ -12,11 +12,66 @@ let configFile = require('../include/commons').CONFIG_FILE;
let config = require('../resources/config/' + configFile);
let log = require('./log');
let https = require('https');
let async = require("async");
class WechatSDK {
    constructor() {
    }
    /**
     * 发送微信模板消息
     */
    static sendTemplateMessage(message, handler) {
        async.waterfall([
            function (callback) {
                WechatSDK.getAccessToken(function (err, res) {
                    if (err) return handler(err, null);
                    callback(null, res);
                });
            },
            function (accessToken, callback) {
                // 发送模板消息
                let messageJSON = JSON.stringify(message);
                let request = https.request({
                        host: 'api.weixin.qq.com',
                        path: '/cgi-bin/message/template/send?access_token=' + accessToken,
                        method: 'POST'
                    },
                    function (res) {
                        res.setEncoding('utf8');
                        let data = "";
                        res.on('data', (d) => {
                            data += d;
                        });
                        res.on('end', () => {
                            let wechatEcho = JSON.parse(data);
                            if (wechatEcho && wechatEcho.errcode === 0) {
                                log.info("Send wechat template message successfully: " + messageJSON);
                                handler(null, wechatEcho);
                            } else {
                                log.error("Send wechat template message failed: " + messageJSON);
                                handler(wechatEcho, null);
                            }
                        });
                        res.on('error', function (err) {
                            log.error('Send wechat template message failed: ' + err.message);
                            handler(err, null);
                        });
                    })
                    .on('error', (e) => {
                        log.error("Send wechat template message failed:" + e.message);
                        handler(e, null);
                    });
                request.end(messageJSON);
            }
        ]);
    };
    /**
     * 获取微信access_token
     */
@ -55,82 +110,21 @@ class WechatSDK {
                            accessToken = data.access_token;
                            WechatTokenRepo.save(accessToken, data.expires_in, new Date(), function (err, result) {
                                if (err) {
                                    if (handler) handler(err, null);
                                    handler(err, null);
                                } else {
                                    if (handler) handler(null, accessToken);
                                    handler(null, accessToken);
                                }
                            });
                        } else {
                            if (handler) handler(Error("Get access_token from wechat failed"), null);
                            handler(Error("Get access_token from wechat failed"), null);
                        }
                    });
                }).on('error', (e) => {
                    if (handler) handler(Error("Get access_token from wechat failed: " + e.message), null);
                    handler(Error("Get access_token from wechat failed: " + e.message), null);
                });
            } else {
                if (handler) handler(data, null);
            }
        });
    };
    /**
     * 发送微信模板消息
     */
    static sendTemplateMessage(message, handler) {
        WechatSDK.getAccessToken(function (err, token) {
            if (err) {
                log.error(err);
                handler(err, null);
                return;
                handler(null, accessToken);
            }
            // 发送模板消息
            let messageJSON = JSON.stringify(message);
            let request = https.request({
                    host: 'api.weixin.qq.com',
                    path: '/cgi-bin/message/template/send?access_token=' + token,
                    method: 'POST'
                },
                function (res) {
                    res.setEncoding('utf8');
                    let data = "";
                    res.on('data', (d) => {
                        data += d;
                    });
                    res.on('end', () => {
                        let result = JSON.parse(data);
                        if (result && result.errcode === 0) {
                            log.info("send wechat template message success:" + messageJSON);
                            if (handler) {
                                handler(null, result);
                            }
                        } else {
                            log.error("send wechat template message failed:" + messageJSON);
                            if (handler) {
                                handler(result, null);
                            }
                        }
                    });
                    res.on('error', function (err) {
                        log.error('send wechat template message failed: ' + err.message);
                        if (handler) {
                            handler(err, null);
                        }
                    });
                })
                .on('error', (e) => {
                    log.error("send wechat template message failed:" + e.message);
                    if (handler) {
                        handler(e, null);
                    }
                });
            request.end(messageJSON);
        });
    };
}

+ 9 - 5
test/client/im.client.session.p2p.Test.js

@ -13,7 +13,7 @@ let imClient = require('../../src/client/im.client');
// 测试会话用的数据, test data
let TD = {
    SessionId: 'b07e8c4eabcb0c6fe790843026424afb2fb64d80',
    SessionId: 'd5cbe9d10669f8741bc0805b20697ad1254c8e90', //'b07e8c4eabcb0c6fe790843026424afb2fb64d80',
    UnreadMessageCount: 0,
    P2P: {
        DoctorA: {
@ -29,6 +29,10 @@ let TD = {
            token: "0PFWlKmLBN9YzhCfFWVgYA",
            clientId: "8fc0fb1d53b725aa7406b8fae66c0a5b",
            platform: 1
        },
        PatientA: {
            id: "d5cbe9d10669f8741bc0805b20697ad1254c8e90",
            name: "陈爱珍"
        }
    }
};
@ -79,24 +83,24 @@ describe("Session P2P", function () {
            // 创建会话并发送消息
            imClient.Sessions.createP2pSession(TD.P2P.DoctorA.id, TD.P2P.DoctorB.id,
                function (session) {
                    assert.ok(session.id.length > 0, "Create session failed.");
                    assert.ok(session.data.id.length > 0, "Create session failed.");
                    TD.SessionId = session.id;
                    imClient.Sessions.sendMessage(session.id, TD.P2P.DoctorA.id, TD.P2P.DoctorA.name, "李医生,你好", 1,
                    imClient.Sessions.sendMessage(session.data.id, TD.P2P.DoctorA.id, TD.P2P.DoctorA.name, "李医生,你好", 1,
                        function (data) {
                            assert.ok(Object.keys(data).length > 0, "Send message failed.");
                        }, function (xhr, status, error) {
                            assert.ok(false, xhr.responseJSON.message)
                        });
                    imClient.Sessions.sendMessage(session.id, TD.P2P.DoctorA.id, TD.P2P.DoctorA.name, "莲前社区糖尿病患者已进入随访跟踪状态", 1,
                    imClient.Sessions.sendMessage(session.data.id, TD.P2P.DoctorA.id, TD.P2P.DoctorA.name, "莲前社区糖尿病患者已进入随访跟踪状态", 1,
                        function (data) {
                            assert.ok(Object.keys(data).length > 0, "Send message failed.");
                        }, function (xhr, status, error) {
                            assert.ok(false, xhr.responseJSON.message)
                        });
                    imClient.Sessions.sendMessage(session.id, TD.P2P.DoctorA.id, TD.P2P.DoctorA.name, "但处方信息还需要您的确认,请尽快回复,谢谢!", 1,
                    imClient.Sessions.sendMessage(session.data.id, TD.P2P.DoctorA.id, TD.P2P.DoctorA.name, "但处方信息还需要您的确认,请尽快回复,谢谢!", 1,
                        function (data) {
                            assert.ok(Object.keys(data).length > 0, "Send message failed.");
                            done();