Browse Source

开发完成

Sand 8 years ago
parent
commit
28cee5783c

+ 40 - 28
readme.md

@ -25,34 +25,6 @@ Node.js支持同步与异步调用,也导致了异常错误处理与众不同
实际上,使用throw并且期望调用者使用 try/catch 是很罕见的,因为 NodeJS里的同步函数通常不会产生运行失败(主要的例外是类似于JSON.parse的用户输入验证函数)。
## 消息格式
客户端向服务端发送:
    
    {
        channel: 0, 1, 2,
        body: {
            from: sand,
            to: Rose,
            contentType: "text/plain",
            content: "abc"
        }
    }
服务端向客户端发送:
    {
        time: 2016-11-08 12:12:01
        channel: 0, 1, 2,
        body: {
            from: sand,
            to: Rose,
            contentType: "text/plain",
            content: "abc"
        }
    }
    
## 测试
测试框架使用mocha。REST客户端使用supertest, should模块。
@ -68,3 +40,43 @@ IM提供了开发SDK,一个JS脚本。客户端可以通过引用此脚本或
客户端通过以下链接引用SDK文件
    <script src='http://host:port/sdk/im.client.js'></script>
## API
### 发送系统消息
### 发送P2P消息
URL: http://192.168.131.115:3000/api/v1/chats/pm
请求方式:POST
参数格式:
    {
        from: 发送人ID,
        to: 接收人ID,
        contentType: 内容类型,1为普通文本,2为图片,3为语音,4为超链接,
        content: "消息内容"
    }
    
### 发送群消息
URL: http://192.168.131.115:3000/api/v1/chats/gm
请求方式:POST
参数格式:
    {
        from: 发送人ID,
        at: at对象ID,
        group: 组ID,
        groupType: 组类别
        contentType: 内容类型,1为普通文本,2为图片,3为语音,4为超链接,
        content: "消息内容"
    }
    
### 获取消息
URL: http://192.168.131.115:3000/api/v1/chats/pm?user_id=xxx
请求试:GET
参数:
- user_id: 用户ID

+ 27 - 0
src/doctor/app.js

@ -4,6 +4,7 @@
// general dependencies
var express = require('express');
var swagger = require("swagger-node-express");
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
@ -23,8 +24,10 @@ var index = require('./controllers/index');
var application = require('./endpoints/application.endpoint');
var users = require('./endpoints/users.endpoint');
var groups = require('./endpoints/groups.endpoint');
var chats = require('./endpoints/chats.endpoint');
var management = require('./endpoints/management.endpoint');
var push = require('./endpoints/push.endpoint');
// Application entry point
var app = express();
@ -45,7 +48,31 @@ app.use(PAGES.Home.Index, index);
app.use(APIv1.Application.Base, application);
app.use(APIv1.Chats.Base, chats);
app.use(APIv1.Users.Base, users);
app.use(APIv1.Groups.Base, groups);
app.use(APIv1.Management.Base, management);
app.use(APIv1.Push.Base, push);
/*
swagger.setAppHandler(app);
swagger.configure("http://petstore.swagger.wordnik.com", "0.1");
swagger.addValidator(
    function validate(req, path, httpMethod) {
        //  example, only allow POST for api_key="special-key"
        if ("POST" == httpMethod || "DELETE" == httpMethod || "PUT" == httpMethod) {
            var apiKey = req.headers["api_key"];
            if (!apiKey) {
                apiKey = url.parse(req.url,true).query["api_key"];
            }
            if ("special-key" == apiKey) {
                return true;
            }
            return false;
        }
        return true;
    }
);
*/
// Error handler, only handle the sync call exception
app.use(function (err, req, res, next) {

+ 699 - 139
src/doctor/endpoints/chats.endpoint.js

@ -3,14 +3,14 @@
 *
 * 此控制器处理点对点,组及消息消息。为三类消息提供发送及查询功能。
 */
var express = require('express');
var router = express.Router();
var http = require('http');
var getui = require('getui');
var log = require('../util/log.js');
var objectUtil = require('../util/objectUtil');
var express = require('express');
var router = express.Router();
var systemMsg = require("../models/msg.system");
var privateMsg = require('../models/msg.private');
var groupMsg = require("../models/msg.group");
@ -18,13 +18,18 @@ var notifyMsg = require("../models/msg.notify");
var msgStats = require("../models/msg.stat");
var user = require("../models/user");
var group = require("../models/group");
var search = require('../models/search');
var dbUtils = require("../util/objectUtil.js");
var APIv1 = require('../include/endpoints').APIv1;
var CHANNELS = require('../include/commons').CHANNELS;
var CONTENT_TYPES = require('../include/commons').CONTENT_TYPE;
var GROUP_TYPE = require('../include/commons').GROUP_TYPE;
var PLATFORMS = require('../include/commons').PLATFORM;
var MAX_INT = 9007199254740992;
var DEFAULT_PAGE_SIZE = 100;
//--------------------------------------------------------------//
//----------------------------消息发送----------------------------//
//--------------------------------------------------------------//
@ -32,6 +37,9 @@ var MAX_INT = 9007199254740992;
/**
 * 发送System消息。
 *
 * 请求URL:
 *  /chats/sm
 *
 * 消息格式:
 *  {
 *      to: "Rose",
@ -138,11 +146,14 @@ router.post(APIv1.Chats.SM, function (req, res) {
 * 2 更新消息统计数据
 * 3 获取目标的状态并构建通知消息,如果用户在线就推送通知消息
 *
 * 请求URL:
 *  /chats/pm
 *
 * 消息格式:
 *  {
 *      from: sand,
 *      to: Rose,
 *      contentType: "1",
 *      contentType: "1,2,3,4",
 *      content: "Please follow the patient as soon as possible."
 *  }
 *
@ -176,22 +187,30 @@ router.post(APIv1.Chats.PM, function (req, res) {
        }
        // 保存消息
        privateMsg.save(message.to, message.from, message.contentType, message.content, function (err, result) {
        var tempContent = message.contentType === CONTENT_TYPES.Article ? JSON.stringify(message.content) : message.content;
        privateMsg.save(message.to, message.from, message.contentType, tempContent, function (err, result) {
            if (err) {
                res.status(500).send({message: 'Save private message failed.'});
                return;
            }
            // 结束网络连接,后续操作继续执行
            res.status(200).send();
            privateMsg.findOneMessage(result.insertId, function (err, msg) {
                if (err) {
                    res.status(500).send("Save private message success, but return last message failed.");
                } else {
                    var message = fillMessages(msg);
                    res.status(200).send(message);
                }
            });
            // 更新自身的聊天统计信息
            msgStats.updateP2PChatInfo(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
            msgStats.updatePrivateChatSummary(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
                if (err) log.error(err);
            });
            // 更新对端的聊天统计信息
            msgStats.updateP2PChatInfo(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
            msgStats.updatePrivateChatSummary(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
                if (err) log.error(err);
            });
@ -205,11 +224,11 @@ router.post(APIv1.Chats.PM, function (req, res) {
                // 构建通知消息
                var title = '新消息';
                var content = '';
                if (message.contentType == 1) {
                if (message.contentType === CONTENT_TYPES.PlainText) {
                    content = message.content;
                } else if (message.contentType == 2) {
                } else if (message.contentType === CONTENT_TYPES.Image) {
                    content = '[图片]';
                } else if (message.contentType == 3) {
                } else if (message.contentType === CONTENT_TYPES.Audio) {
                    content = '[语音]';
                } else {
                    content = '接收到一条新消息';
@ -247,7 +266,7 @@ router.post(APIv1.Chats.PM, function (req, res) {
                                        }
                                    });
                            } else if (target.platform === PLATFORMS.Android) {
                                getui.pushAndroid(data.client_id,
                                getui.pushAndroid(target.client_id,
                                    message.contentType,
                                    title,
                                    content,
@ -272,6 +291,9 @@ router.post(APIv1.Chats.PM, function (req, res) {
/**
 * 处理讨论组消息。
 *
 * 请求URL:
 *  /chats/gm
 *
 * 消息格式:
 *  {
 *      from: "sand",                       // 发送者id
@ -320,11 +342,18 @@ router.post(APIv1.Chats.GM, function (req, res) {
                return;
            }
            // 关闭网络连接后执行后续操作
            res.status(200).send();
            groupMsg.findOneMessage(result.insertId, function (err, groupMsg) {
                if (err) {
                    log.error("Save group message success, but return this message failed.");
                    res.status(500).send({message: "Save group message success, but return this message failed."});
                }
                // 关闭网络连接后执行后续操作
                res.status(200).send(fillMessages(groupMsg));
            });
            // 更新组内统计信息
            msgStats.updateGroupChatInfo(message.from, message.group, message.from, 0, message.contentType, message.content, false, function (err, result) {
            msgStats.updateGroupChatSummary(message.from, message.group, message.from, 0, message.contentType, message.content, false, function (err, result) {
                if (err) log.error(err);
            });
@ -343,8 +372,8 @@ router.post(APIv1.Chats.GM, function (req, res) {
                }
                // 逐个推送通知
                for (var nIndex = 0; nIndex < result.length; nIndex++) {
                    var member = result[nIndex];
                for (var i = 0; i < result.length; i++) {
                    var member = result[i];
                    if (member.user_id === message.from) continue;
                    user.getUserStatus(member.user_id, function (err, result) {
@ -355,13 +384,13 @@ router.post(APIv1.Chats.GM, function (req, res) {
                        var title = '';
                        var content = '';
                        if (message.contentType === 1) {
                        if (message.contentType === CONTENT_TYPES.PlainText) {
                            title = '群组消息';
                            content = message.content;
                        } else if (message.contentType === 2) {
                        } else if (message.contentType === CONTENT_TYPES.Image) {
                            title = '群组消息';
                            content = '[图片]';
                        } else if (message.contentType === 3) {
                        } else if (message.contentType === CONTENT_TYPES.Audio) {
                            title = '群组消息';
                            content = '[语音]';
                        } else {
@ -449,7 +478,7 @@ router.post(APIv1.Chats.GM, function (req, res) {
                    var at = 0;
                    if (message.at == member.user_id) at = 1;
                    msgStats.updateGroupChatInfo(member.user_id,
                    msgStats.updateGroupChatSummary(member.user_id,
                        message.group,
                        message.from,
                        at,
@ -466,54 +495,338 @@ router.post(APIv1.Chats.GM, function (req, res) {
});
//--------------------------------------------------------------//
//----------------------------消息获取----------------------------//
//----------------------------消息提取----------------------------//
//--------------------------------------------------------------//
/**
 * 按时间倒序获取私信。
 * 获取参与的聊天列表,包括:点对点,@我,参与的讨论组,系统消息等。
 *
 * 请求URL:
 *  /chats/list?user_id=sand
 */
router.get(APIv1.Chats.List, function (req, res) {
    var userId = req.query.user_id;
    if (userId === null) {
        throw {httpStatus: 406, message: 'Missing fields.'};
    }
    msgStats.getChatList(userId, function (err, rows) {
        if (err) {
            log.error('Get user chat list failed: ', err);
            res.status(500).send({message: 'Get user chat list failed.'});
            return;
        }
        if (rows.length == 0) {
            res.status(200).send([]);
            return;
        }
        var chats = new Array(rows.length);
        for (var i = 0; i < rows.length; i++) {
            var row = rows[i];
            chats[i] = {
                userId: row.uid,
                peerId: row.from_uid,
                groupId: row.from_gid === undefined ? "" : row.from_gid,
                atMe: row.at_me === 1,
                messageType: row.msg_type,
                lastContentType: row.last_content_type,
                lastContent: row.last_content,
                newMessageCount: row.new_msg_count,
                timestamp: objectUtil.timestampToLong(row.timestamp)
            };
        }
        res.status(200).send(chats);
    });
});
/**
 * 获取与患者的聊天列表,包括:P2P,参与的讨论组和行政团队。
 *
 * 请求URL:
 *  /chats/list/patient
 */
router.get(APIv1.Chats.ListWithPatient, function (req, res) {
    var userId = req.query.user_id;
    if (userId === null) {
        throw {httpStatus: 406, message: 'Missing fields.'};
    }
    privateMsg.findAllP2PWithPatient(userId, function (err, patients) {
        if (err) {
            log.error('Get chat list with patient failed: ', err);
            res.status(500).send({message: 'Get chat list with patient failed.'});
            return;
        }
        var chats = {patients: [], groups: []};
        for (var i = 0; i < patients.length; i++) {
            var patient = patients[i];
            chats.patients.push({
                code: patient.code,
                name: patient.name,
                birthday: patient.birthday,
                sex: patient.sex,
                avatar: patient.photo == null ? "" : patient.photo,
                newMessageCount: patient.new_msg_count,
                lastContentType: patient.last_content_type,
                lastContent: patient.last_content,
                timestamp: objectUtil.timestampToLong(patient.timestamp)
            });
        }
        groupMsg.findAllGroupsWithPatient(userId, function (err, groups) {
            if (err) {
                log.error('Get group list with patient failed: ', err);
                res.status(500).send({message: 'Get group list with patient failed.'});
                return;
            }
            for (var i = 0; i < groups.length; i++) {
                var group = groups[i];
                chats.groups.push({
                    code: group.code,
                    name: group.name,
                    groupType: group.msg_type,
                    newMessageCount: group.new_msg_count,
                    lastContentType: group.last_content_type,
                    lastContent: group.last_content,
                    timestamp: objectUtil.timestampToLong(group.timestamp)
                });
            }
            res.status(200).send(chats);
        })
    });
});
/**
 * 获取与医生的聊天列表,包括:点对点,参与的讨论组。
 *
 * 请求URL:
 *  /chats/list/doctor
 */
router.get(APIv1.Chats.ListWithDoctor, function (req, res) {
    var userId = req.query.user_id;
    if (userId === null) {
        throw {httpStatus: 406, message: 'Missing fields.'};
    }
    // 先获取医生间的私聊
    privateMsg.findAllP2PWithDoctor(userId, function (err, doctors) {
        if (err) {
            log.error('Get chat list with doctor failed: ', err);
            res.status(500).send({message: 'Get chat list with doctor failed.'});
            return;
        }
        var chats = {doctors: [], groups: []};
        for (var i = 0; i < doctors.length; i++) {
            var doctor = doctors[i];
            chats.doctors.push({
                code: doctor.code,
                name: doctor.name,
                sex: doctor.sex,
                avatar: doctor.photo === null ? "" : doctor.photo,
                newMessageCount: doctor.new_msg_count,
                lastContentType: doctor.last_content_type,
                lastContent: doctor.last_content,
                timestamp: objectUtil.timestampToLong(doctor.timestamp)
            });
        }
        // 再获取医生间的组
        groupMsg.findAllGroupsWithDoctor(userId, function (err, groups) {
            if (err) {
                log.error('Get group list with doctor failed: ', err);
                res.status(500).send({message: 'Get group list with doctor failed.'});
                return;
            }
            for (var i = 0; i < groups.length; i++) {
                var group = groups[i];
                chats.groups.push({
                    code: group.code,
                    name: group.name,
                    groupType: group.type,
                    newMessageCount: group.new_msg_count,
                    lastContentType: group.last_content_type,
                    lastContent: group.last_content,
                    timestamp: objectUtil.timestampToLong(group.timestamp)
                });
            }
            res.status(200).send(chats);
        });
    });
});
/**
 * 获取最近聊天对象:包括患者,医生与讨论组。客户端自行根据需要提取患者、落花生或讨论组数据。
 *
 * 请求URL:
 *  /chats/recent?user_id=0de7295862dd11e69faffa163e8aee56&days=7
 *
 * 参数:
 *  user_id: 用户ID
 *  target_type: 对象类型,1患者,2医生,3讨论组
 *  days: 最近天数
 */
router.get(APIv1.Chats.Recent, function (req, res) {
    var userId = req.query.user_id;
    var days = req.query.days;
    if (userId === null) {
        throw {httpStatus: 406, message: 'Missing field: user_id'};
    }
    if (days === null) {
        throw {httpStatus: 406, message: 'Missing field: days'};
    }
    msgStats.getRecentChats(userId, days, function (err, result) {
        if (err) {
            log.error('Get recent chat objects failed: ', err);
            res.status(500).send({message: 'Get recent chat objects failed.'});
            return;
        }
        var data = {patients: [], doctors: [], groups: []};
        if (result.length === 0) {
            res.status(200).send(data);
            return;
        }
        for (var i = 0; i < result.length; ++i) {
            var row = result[i];
            if (row.type.indexOf('patient') > -1) {
                data.patients.push({
                    code: row.code,
                    name: row.name,
                    birthday: row.birthday === null ? "" : row.birthday,
                    sex: row.sex,
                    avatar: row.photo === null ? "" : row.photo
                });
            } else if (row.type.indexOf('doctor') > -1) {
                data.doctors.push({
                    code: row.code,
                    name: row.name,
                    birthday: row.birthday === null ? "" : row.birthday,
                    sex: row.sex,
                    avatar: row.photo === null ? "" : row.photo
                });
            } else if (row.type.indexOf('group') > -1) {
                data.groups.push({
                    code: row.code,
                    name: row.name
                });
            }
        }
        res.status(200).send(data);
    });
});
/**
 * 获取私信。倒序排列。
 *
 * 参数:
 *  user_id 必须,医生ID
 *  peer_id 必须,对方医生ID
 *  content_type 必须,消息类型
 *  message_start_id 可选,消息的起始ID,如果为空从最新的一条开始获取
 *  count 可选,消息数量,如果不指定、小于零或大于50,默认为50条
 *  message_end_id 可选,消息的结束ID,如果为空从第一条开始获取
 *  count 可选,消息数量,如果不指定、小于零或大于50,默认为100条。若message_start_id与message_end_id均不为空,则此参数无效,方法是设置为10000条。
 *
 * 请求URL:
 *  /pm?user_id=sand&peer_id=Rose&message_start_id=0&count=20
 *  /chats/pm?user_id=sand&peer_id=Rose&content_type=2&message_start_id=10000&message_end_id=0&count=20
 */
router.get(APIv1.Chats.PM, function (req, res) {
    var userId = req.query.user_id;
    var peerId = req.query.peer_id;
    var msgStartId = req.query.message_start_id === null ? MAX_INT : parseInt(req.query.message_start_id);
    var count = req.query.count == null ? 50 : parsetInt(req.query.count);
    var contentType = req.query.content_type;
    var msgStartId = !req.query.message_start_id ? MAX_INT : parseInt(req.query.message_start_id);
    var msgEndId = !req.query.message_end_id ? 0 : parseInt(req.query.message_end_id);
    var count = req.query.count === undefined ? DEFAULT_PAGE_SIZE : parseInt(req.query.count);
    if (userId == null) {
    if (contentType !== undefined && parseInt(contentType) === CONTENT_TYPES.Image) count = DEFAULT_PAGE_SIZE;
    if (req.query.message_start_id && req.query.message_end_id) count = 10000;
    if (userId === undefined) {
        throw {httpStatus: 400, message: "Missing field."};
    }
    privateMsg.findByGroupId(userId, peerId, msgStartId, count, function (err, rows) {
    privateMsg.findAllMessages(userId, peerId, contentType === undefined ? "1,2,3,5,6" : contentType, msgStartId, msgEndId, count, function (err, rows) {
        if (err) {
            log.error("Get private message failed, ", err);
            throw {httpStatus: 500, message: "Get private messages failed."};
        }
        var messages = {};
        messages.startId = msgStartId;
        messages.count = rows.length;
        messages.records = [];
        for (var nIndex = 0; nIndex < rows.length; nIndex++) {
            rows[nIndex].timestamp = Date.parse(new Date(rows[nIndex].timestamp));
            messages.records.notifyMsg(rows[nIndex]);
            res.status(500).send({message: "Get private messages failed."});
            return;
        }
        res.writeHead(200);
        res.write(messages);
        var messages = fillMessages(rows);
        // 清空统计信息
        msgStats.clearP2PChatInfo(userId, peerId, function (err, result) {
        msgStats.clearPrivateChatSummary(userId, peerId, function (err, result) {
            if (err) console.log(err);
        });
        res.status(200).send(messages);
    });
});
/**
 * 获取未读私信。倒序排列。
 *
 * 参数:
 *  user_id 必须,医生ID
 *  peer_id 必须,对方医生ID
 *
 * 请求URL:
 *  /chats/pm/unread?user_id=sand&peer_id=Rose
 */
router.get(APIv1.Chats.PMUnread, function (req, res) {
    var userId = req.query.user_id;
    var peerId = req.query.peer_id;
    if (userId === undefined) {
        throw {httpStatus: 400, message: "Missing field: user_id."};
    }
    msgStats.getPrivateChatSummary(userId, peerId, function (err, summary) {
        if (err) {
            log.error("Get unread private messages failed: ", err);
            res.status(500).send({message: "Get unread private messages failed."});
            return;
        }
        // 没有未读消息,直接返回
        if (summary.length == 0 || summary[0].new_msg_count === 0) {
            res.status(200).send({startId: 0, count: 0, records: []});
            return;
        }
        privateMsg.findUnread(peerId, userId, MAX_INT, summary[0].new_msg_count, function (err, rows) {
            if (err) {
                log.error("Get unread private messages failed: ", err);
                res.status(500).send({message: "Get unread private messages failed."});
                return;
            }
            var messages = fillMessages(rows);
            res.status(200).send(messages);
        });
    });
});
@ -521,108 +834,134 @@ router.get(APIv1.Chats.PM, function (req, res) {
 * 按时间倒序获取群消息。
 *
 * 参数:
 *  group_id 必须,组ID
 *  user_id 必须,医生ID
 *  group_id 必须,组ID
 *  message_start_id 可选,消息的起始ID,如果为空从最新的一条开始获取
 *  count 可选,消息数量,如果不指定、小于零或大于50,默认为50条
 *
 * 请求URL:
 *  /gm?user_id=sand&group_id=discussionGroup&message_start_id=0&count=20
 *  /chats/gm?user_id=D2016008240002&group_id=494&content_type=2&message_start_id=0&message_end_id=0&count=20
 */
router.get(APIv1.Chats.GM, function (req, res) {
    var groupId = req.query.group_id;
    var userId = req.query.user_id;
    var msgStartId = req.query.message_start_id === null ? MAX_INT : parseInt(req.query.message_start_id);
    var count = req.query.count == null ? 50 : parsetInt(req.query.count);
    var contentType = req.query.content_type;
    var msgStartId = !req.query.message_start_id ? MAX_INT : parseInt(req.query.message_start_id);
    var msgEndId = !req.query.message_end_id ? 0 : parseInt(req.query.message_end_id);
    var count = req.query.count === undefined ? DEFAULT_PAGE_SIZE : parseInt(req.query.count);
    if (groupId == null) {
        throw {httpStatus: 400, message: "Missing field."};
    if (groupId === undefined) {
        throw {httpStatus: 400, message: "Missing field: group_id."};
    }
    groupMsg.findByGroupId(groupId, msgStartId, count, function (err, rows) {
    if (contentType !== undefined && parseInt(contentType) === CONTENT_TYPES.Image) count = DEFAULT_PAGE_SIZE;
    if (req.query.message_start_id && req.query.message_end_id) count = 100000;
    groupMsg.findAllMessages(groupId, !contentType ? "1,2,3,5,6" : contentType, msgStartId, msgEndId, count, function (err, rows) {
        if (err) {
            console.log('Get group message failed: ', err);
            throw {httpStatus: 500, message: 'Get group message failed.'};
        }
        var messages = {};
        messages.startId = msgStartId;
        messages.count = rows.length;
        messages.records = [];
        for (var nIndex = 0; nIndex < rows.length; nIndex++) {
            rows[nIndex].timestamp = Date.parse(new Date(rows[nIndex].timestamp));
            messages.records.push(rows[nIndex]);
            res.status(500).send({message: 'Get group message failed.'});
            return;
        }
        res.writeHead(200);
        res.write(messages);
        var messages = fillMessages(rows);
        // 清空统计信息
        msgStats.clearGroupChatInfo(req.query.uid,
            userId,
            function (err, result) {
                if (err) console.log(err);
            });
        msgStats.clearGroupChatSummary(req.query.uid, userId, function (err, result) {
            if (err) console.log(err);
        });
        res.status(200).send(messages);
    });
});
//--------------------------------------------------------------//
//----------------------------消息统计----------------------------//
//--------------------------------------------------------------//
/**
 * 获取参与的聊天列表,包括:点对点,@我,参与的讨论组。
 * 获取未读群消息。
 *
 * 请求URL:
 *  /api/v1/chats?user_id=sand
 * 请求URL:
 *  /chats/gm/unread?group_id=discussionGroupId&user_id=sand
 */
router.get(APIv1.Chats.List, function (req, res) {
router.get(APIv1.Chats.GMUnread, function (req, res) {
    var userId = req.query.user_id;
    if (userId === null) {
        throw {httpStatus: 406, message: 'Missing fields.'};
    var groupId = req.query.group_id;
    if (userId === undefined) {
        throw {httpStatus: 400, message: "Missing field: user_id."};
    }
    msgStats.getChatList(userId, function (err, rows) {
    if (groupId === undefined) {
        throw {httpStatus: 400, message: "Missing field: group_id."};
    }
    msgStats.getGroupChatSummary(userId, groupId, function (err, summary) {
        if (err) {
            log.error('Get users chat list failed: ', err);
            log.error("Get unread group messages failed: ", err);
            res.status(500).send({message: 'Get users chat list failed.'});
            res.status(500).send({message: "Get unread group messages failed."});
            return;
        }
        if (rows.length == 0) {
            res.status(200).send([]);
        var messages = {startId: 0, count: 0, records: []};
        if (summary.length == 0 || summary[0].new_msg_count === 0) {
            res.status(200).send(messages);
            return;
        }
        var chats = new Array(rows.length);
        for (var i = 0; i < rows.length; i++) {
            var row = rows[i];
            var element = {
                userId: row.uid,
                peerId: row.from_uid,
                groupId: row.from_gid === undefined ? "" : row.from_gid,
                atMe: row.at_me === 1,
                messageType: row.msg_type,
                lastContentType: row.last_content_type,
                lastContent: row.last_content,
                newMessageCount: row.new_msg_count,
                timestamp: Date.parse(new Date(row.timestamp))
            };
        messages.count = summary[0].new_msg_count;
        groupMsg.findUnread(groupId, MAX_INT, messages.count, function (err, rows) {
            if (err) {
                log.error("Get unread group messages failed: ", err);
            chats[i] = element;
        }
                res.status(500).send({message: "Get unread group messages failed."});
                return;
            }
        res.status(200).send(chats);
            var messages = fillMessages(rows);
            res.status(200).send(messages);
        });
    });
});
/**
 * 将消息的返回结果合并成JSON。
 *
 * @param rows
 *
 * @returns {startId: 0, count: 0, records: []}
 */
function fillMessages(rows) {
    var messages = {startId: rows.length > 0 ? rows[0].msg_id : '', count: rows.length, records: []};
    for (var i = 0; i < rows.length; i++) {
        var row = rows[i];
        var record = {
            id: row.msg_id,
            from: row.from_uid,
            contentType: row.type,
            content: row.content,
            timestamp: objectUtil.timestampToLong(row.timestamp)
        };
        if (row.to_uid !== undefined) record.to = row.to_uid;
        if (row.at_uid !== undefined) record.at = row.at_uid;
        messages.records.push(record);
    }
    return messages;
}
//--------------------------------------------------------------//
//----------------------------消息统计----------------------------//
//--------------------------------------------------------------//
/**
 * 获取所有群组未读消息总数。
 *
 * 请求URL:
 *  /gm/unread_count?user_id=sand
 *  /chats/gm/unread_count?user_id=sand
 *
 * 参数:
 *  user_id:医生ID
@ -633,7 +972,7 @@ router.get(APIv1.Chats.GMUnreadCount, function (req, res) {
        throw {httpStatus: 406, message: 'Missing fields.'};
    }
    msgStats.getGroupChatAllUnRead(userId, function (err, result) {
    msgStats.getGroupChatAllUnReadCount(userId, function (err, result) {
        if (err) {
            console.log('Get all unread messages failed: ', err);
@ -659,7 +998,7 @@ router.get(APIv1.Chats.GMUnreadCount, function (req, res) {
/**
 * 获取特定群组消息统计情况。
 *
 * /gm/statistic?group_id=GGG&&user_id=sand
 * /chats/gm/statistic?group_id=GGG&&user_id=sand
 *
 * 参数:
 *  user_id:信息所有者id
@ -672,38 +1011,44 @@ router.get(APIv1.Chats.GMStats, function (req, res) {
        throw {httpStatus: 406, message: 'Miss fields.'};
    }
    msgStats.getGroupChatInfo(userId, groupId, function (err, result) {
    msgStats.getGroupChatSummary(userId, groupId, function (err, result) {
        if (err) {
            console.log('Get group stats failed: ', err);
            throw {httpStatus: 500, message: 'Get group stats failed.'};
            res.status(500).send({message: 'Get group stats failed.'});
            return;
        }
        if (result.length == 0) {
            var data = {
                "userId": userId,
                "from": "",
                "groupId": groupId,
                "atMe": 0,
                "lastContentType": 1,
                "lastContent": "",
                "newMessageCount": 0,
                "timestamp": 0
            };
        var data = {
            userId: userId,
            from: "",
            groupId: groupId,
            atMe: 0,
            lastContentType: 1,
            lastContent: "",
            newMessageCount: 0,
            timestamp: 0
        };
            res.write(data);
            return;
        if (result.length > 0) {
            var row = result[0];
            data.from = row.from_uid;
            data.groupId = row.gid;
            data.atMe = row.at_me;
            data.lastContentType = row.last_content_type;
            data.lastContent = row.lastContent;
            data.newMessageCount = row.new_msg_count;
            data.timestamp = objectUtil.timestampToLong(row.timestamp)
        }
        result[0].timestamp = Date.parse(new Date(result[0].timestamp));
        res.write(result[0]);
        res.status(200).send(data);
    });
});
/**
 * 获取与某人的私信统计。
 *
 * /pm/statistic?user_id=sand&&peer_id=rose
 * /chats/pm/statistic?user_id=sand&&peer_id=rose
 *
 * 参数:
 *  user_id:信息所有者id
@ -716,35 +1061,41 @@ router.get(APIv1.Chats.PMStats, function (req, res) {
        throw {httpStatus: 406, message: "Missing fields."};
    }
    msgStats.getP2PChatInfo(userId, peerId, function (err, result) {
    msgStats.getPrivateChatSummary(userId, peerId, function (err, result) {
        if (err) {
            console.log("Get private messages stats failed: ", err);
            throw {httpStatus: 500, message: "Get private messages stats failed."};
            res.status(500).send({message: "Get private messages stats failed."});
        }
        if (result.length == 0) {
            var data = {
                "userId": userId,
                "peerId": peerId,
                "lastCContentType": 1,
                "lastContent": "",
                "newMessageCount": 0,
                "timestamp": 0
            };
            res.write(data);
            return;
        var data = {
            userId: userId,
            peerId: peerId,
            lastCContentType: 1,
            lastContent: "",
            newMessageCount: 0,
            timestamp: 0
        };
        if (result.length > 0) {
            var row = result[0];
            data.userId = row.uid;
            data.peerId = row.from_uid;
            data.lastContentType = row.last_content_type;
            data.lastContent = row.last_content;
            data.newMessageCount = row.new_msg_count;
            data.timestamp = objectUtil.timestampToLong(row.timestamp)
        }
        result[0].timestamp = Date.parse(new Date(result[0].timestamp));
        res.write(result[0]);
        res.status(0).send(data);
    });
});
/**
 * 获取所有未读私信总数。
 *
 * /pm/unread_count?user_id=sand
 * /chats/pm/unread_count?user_id=sand
 *
 * 参数:
 * uid:信息所有者id
@ -752,7 +1103,7 @@ router.get(APIv1.Chats.PMStats, function (req, res) {
router.get(APIv1.Chats.PMUnreadCount, function (req, res) {
    var userId = req.query.user_id;
    msgStats.getP2PChatAllUnRead(userId, function (err, result) {
    msgStats.getPrivateChatAllUnReadCount(userId, function (err, result) {
        if (err) {
            console.log("Get unread private message count failed: ", err);
@ -774,7 +1125,7 @@ router.get(APIv1.Chats.PMUnreadCount, function (req, res) {
 * 所有聊天消息未读数。
 *
 * 请求URL:
 *  /chats/unread_count?user_id=sand
 *  /chats/chats/unread_count?user_id=sand
 *
 * 参数:
 *  user_id:信息所有者id
@ -785,7 +1136,7 @@ router.get(APIv1.Chats.UnreadMsgCount, function (req, res) {
        throw {httpStatus: 406, message: "Missing fields."};
    }
    msgStats.getChatAllUnRead(userId, function (err, result) {
    msgStats.getChatAllUnReadCount(userId, function (err, result) {
        if (err) {
            console.error("Get all unread message count failed: ", err);
@ -803,4 +1154,213 @@ router.get(APIv1.Chats.UnreadMsgCount, function (req, res) {
    });
});
/**
 * 搜索患者相关的数据,包括患者信息与相关的私信记录。关键词不支持空格拆分。
 *
 * 请求URL:
 *  /search/patient?user_id=3b723bb8699a11e69f7c005056850d66&user_role=1&keyword=庄
 *
 * 参数:
 *  keywords: 关键词
 */
router.get(APIv1.Chats.SearchAboutPatient, function (req, res) {
    var userId = req.query.user_id;
    var userRole = req.query.user_role;
    var keyword = req.query.keyword;
    if (!userId) throw {httpStatus: 406, message: "Missing fields: user_id."};
    if (!userRole) throw {httpStatus: 406, message: "Missing fields: user_role."};
    if (!keyword) throw {httpStatus: 406, message: "Missing fields: keyword."};
    search.searchPatients(userId, userRole, keyword, function (err, patients) {
        if (err) {
            log.error("Search patient on basic information failed: ", err);
            res.status(500).send({message: "Search patient on basic information failed."});
            return;
        }
        var data = {patients: [], chats: []};
        for (var i = 0; i < patients.length; ++i) {
            var patient = patients[i];
            data.patients.push({
                code: patient.code,
                name: patient.name,
                sex: patient.sex,
                birthday: dbUtils.timestampToLong(patient.birthday),
                avatar: patient.photo === null ? "" : patient.photo
            });
        }
        search.searchPatientPM(userId, keyword, function (err, chats) {
            if (err) {
                log.error("Search patient on private messages failed: ", err);
                res.status(500).send({message: "Search patient on private messages failed."});
                return;
            }
            var lastPatientCode = '';
            var lastPatient = {code: '', name: '', sex: '', avatar: '', messages: []};
            for (var i = 0; i < chats.length; ++i) {
                var chat = chats[i];
                if (lastPatientCode !== chat.code) {
                    lastPatientCode = chat.code;
                    lastPatient.code = chat.code;
                    lastPatient.name = chat.name;
                    lastPatient.sex = chat.sex;
                    lastPatient.birthday = dbUtils.timestampToLong(patient.birthday);
                    lastPatient.avatar = chat.photo === null ? "" : chat.photo;
                    data.chats.push(lastPatient);
                }
                lastPatient.messages.push({
                    id: chat.msg_id,
                    content: chat.content
                });
            }
            res.status(200).send(data);
        });
    });
});
/**
 * 搜索医生相关的数据,包括医生信息与相关的聊天记录,包括私信与群信。
 *
 * 请求URL:
 *  /search/doctor?user_id=5fa5e88f7a4111e69f7c005056850d66&keyword=丘
 *
 * 参数:
 *  keywords: 关键词
 */
router.get(APIv1.Chats.SearchAboutDoctor, function (req, res) {
    var userId = req.query.user_id;
    var keyword = req.query.keyword;
    if (!userId) throw {httpStatus: 406, message: "Missing fields: user_id."};
    if (!keyword) throw {httpStatus: 406, message: "Missing fields: keyword."};
    // 搜索医生
    search.searchDoctors(userId, keyword, function (err, doctors) {
        if (err) {
            log.error("Search doctor on basic information failed: ", err);
            res.status(500).send({message: "Search doctor on basic information failed."});
            return;
        }
        var data = {doctors: [], groups: [], chats: {doctors: [], groups: []}};
        for (var i = 0; i < doctors.length; ++i) {
            var doctor = doctors[i];
            data.doctors.push({
                code: doctor.code,
                name: doctor.name,
                sex: doctor.sex,
                avatar: doctor.photo === null ? "" : doctor.photo
            });
        }
        // 搜索讨论组名称及成员名称
        search.searchGroups(userId, keyword, function (err, groups) {
            if (err) {
                log.error("Search talk group failed: ", err);
                res.status(500).send({message: "Search talk group failed."});
                return;
            }
            var lastGroupCode = '';
            var lastGroup = null;
            for (var i = 0; i < groups.length; ++i) {
                var group = groups[i];
                if (lastGroupCode !== group.code) {
                    lastGroupCode = group.code;
                    lastGroup = {
                        code: group.code,
                        name: group.name,
                        type: GROUP_TYPE.DiscussionGroup,
                        members: []
                    };
                    data.groups.push(lastGroup);
                }
                lastGroup.members.push({
                    code: group.member_code,
                    name: group.member_name
                });
            }
            // 搜索医生间的私信
            search.searchDoctorMessages(userId, keyword, function (err, messages) {
                if (err) {
                    log.error("Search doctor private messages failed: ", err);
                    res.status(500).send({message: "Search doctor private messages failed."});
                    return;
                }
                var lastDoctor;
                var lastDoctorCode = '';
                for (var i = 0; i < messages.length; ++i) {
                    var message = messages[i];
                    if (lastDoctorCode !== message.code) {
                        lastDoctorCode = message.code;
                        lastDoctor = {
                            code: message.code,
                            name: message.name,
                            photo: message.photo === null ? "" : message.photo,
                            messages: []
                        };
                        data.chats.doctors.push(lastDoctor);
                    }
                    lastDoctor.messages.push({
                        id: message.msg_id,
                        content: message.content
                    });
                }
                // 搜索医生间的讨论组消息
                search.searchGroupMessages(userId, keyword, function (err, messages) {
                    if (err) {
                        log.error("Search doctor group messages failed: ", err);
                        res.status(500).send({message: "Search doctor group messages failed."});
                        return;
                    }
                    // g.code, g.name, gm.msg_id, gm.content
                    var lastGroup;
                    var lastGroupCode = '';
                    for (var i = 0; i < messages.length; ++i) {
                        var message = messages[i];
                        if (lastGroupCode !== message.code) {
                            lastGroupCode = message.code;
                            lastGroup = {
                                code: message.code,
                                name: message.name,
                                messages: []
                            }
                            data.chats.groups.push(lastGroup);
                        }
                        lastGroup.messages.push({
                            id: message.msg_id,
                            content: message.content
                        });
                    }
                    res.status(200).send(data);
                });
            });
        });
    });
});
module.exports = router;

+ 68 - 0
src/doctor/endpoints/groups.endpoint.js

@ -0,0 +1,68 @@
/**
 * Created by Sand on 2016/11/14.
 */
"use strict";
var express = require("express");
var router = express.Router();
var APIv1 = require('../include/endpoints').APIv1;
var group = require('../models/group');
/**
 * 获取成员头像。每个组最多返回5个成员的头像。
 *
 * 请求URL:
 *  /groups/member/avatars?groups=433,10,63
 */
router.get(APIv1.Groups.MembersAvatar, function (req, res) {
    var groups = req.query.groups;
    if (!groups) {
        throw {httpStatus: 406, message: "Missing field: groups"};
    }
    var tokens = groups.split(",");
    groups = "'" + tokens.join("', '") + "'";
    var avatars = [];
    group.getMembersAvatar(groups, function (err, rows) {
        if(err){
            console.log("Get group member's avatar list failed: ", err);
            res.status(500).send({message: "Get group member's avatar list failed."});
            return;
        }
        var indexInGroup = 0;
        var lastGroupCode = '';
        var lastGroup;
        for (var i = 0; i < rows.length; ++i) {
            if(indexInGroup >= 5) continue;
            var row = rows[i];
            var groupCode = row.g_code;
            if (lastGroupCode !== groupCode) {
                indexInGroup = 0;
                lastGroupCode = groupCode;
                lastGroup = {groupCode: groupCode, avatars: []};
                if(lastGroupCode !== ''){
                    avatars.push(lastGroup);
                }
            }
            lastGroup.avatars.push({
                code: row.dr_code,
                name: row.dr_name,
                avatar: row.dr_photo.length === 0 ? "" : row.dr_photo
            });
            indexInGroup = indexInGroup + 1;
        }
        res.status(200).send(avatars);
    });
});
module.exports = router;

+ 19 - 0
src/doctor/endpoints/push.endpoint.js

@ -0,0 +1,19 @@
/**
 * 推送REST客户端。此处包装供其他系统使用,例如家庭医生平台调用此接口向个推发送数据。
 *
 * 推送可能会有多种实现,API根据多种实现做了封装,可以根据需要调用相应的推送API。
 */
var express = require('express');
var router = express.Router();
var http = require('http');
var ENDPOINTS = require('../include/endpoints').APIv1;
/**
 * 通过'个推'实现推送服务。
 */
router.post(ENDPOINTS.Push.Getui, function (req, res) {
});
module.exports = router;

+ 2 - 2
src/doctor/endpoints/users.endpoint.js

@ -81,13 +81,13 @@ router.get(APIv1.Users.Login, function (req, res) {
 */
router.get(APIv1.Users.Logout, function (req, res) {
    if (req.query.user_id == null) {
        throw {httpStatus: 406, message: 'Validation Failed. Missing user id field.'};
        throw {httpStatus: 406, message: 'Logout Failed. Missing field: user_id.'};
    }
    user.logout(req.query.user_id,
        function (err, result) {
            if (err) {
                log.error(err.message);
                log.error("Logout failed: ", err);
                res.status(416).send({message: 'Logout failed.'});
            }

+ 16 - 11
src/doctor/include/commons.js

@ -18,18 +18,26 @@ if (process.env.prod !== undefined) {
}
/**
 *  消息类型定义。
 *  消息内容类型。
 */
var channels = {
    System: "0",
    Private: "1",
    Group: "2"
exports.CONTENT_TYPE = {
    PlainText: 1,   // 信息
    Image: 2,       // 图片信息
    Audio: 3,       // 主音信息
    Article: 4,     // 文章信息
    GoTo: 5,        // 跳转信息
    SessionBegin: 6,// 咨询开始
    SessionEnd: 7,  // 咨询结束
    commaValues: function () {
        return "1,2,3,4,5,6,7";
    }
};
/**
 * 客户端平台。
 */
var platform = {
exports.PLATFORM = {
    iOS: 0,
    Android: 1
};
@ -37,12 +45,9 @@ var platform = {
/**
 * 组类型。
 */
var groupType = {
exports.GROUP_TYPE = {
    AdminTeam: 1,
    DiscussionGroup: 2
};
exports.CHANNELS = channels;
exports.CONFIG_FILE = configFile;
exports.PLATFORM = platform;
exports.GROUP_TYPE = groupType;
exports.CONFIG_FILE = configFile;

+ 23 - 3
src/doctor/include/endpoints.js

@ -14,18 +14,26 @@ var APIv1 = {
        Base: "/api/v1/chats",
        List: "/list",
        ListWithPatient: "/list/patient",
        ListWithDoctor: "/list/doctor",
        // 未读消息数
        Recent: '/recent',
        SearchAboutPatient: '/search/patient',
        SearchAboutDoctor: '/search/doctor',
        // 所有未读消息数
        UnreadMsgCount: '/unread_count',
        // 私信
        PM: '/pm',
        PMUnreadCount: '/pm/unread_count',
        PMUnread: '/pm/unread',
        PMUnreadCount: '/pm/unread/count',
        PMStats: '/pm/statistic',
        // 组信
        GM: '/gm',
        GMUnreadCount: '/gm/unread_count',
        GMUnread: '/gm/unread',
        GMUnreadCount: '/gm/unread/count',
        GMStats: '/gm/statistic',
        //系统消息
@ -42,11 +50,23 @@ var APIv1 = {
        UserStatus: '/:user_id/status'
    },
    Groups: {
        Base: '/api/v1/groups',
        MembersAvatar: '/member/avatars'
    },
    Management: {
        Base: '/api/v1/management',
        Health: '/health',
        DbStatus: '/db'
    },
    Push: {
        Base: '/api/v1/push',
        Getui: '/getui'
    }
};

+ 23 - 8
src/doctor/models/group.js

@ -17,8 +17,8 @@ var GROUP_TYPE = require('../include/commons').GROUP_TYPE;
 * @param doctorId
 * @param handler
 */
function isGroupMember(groupId, groupType, doctorId, handler){
    if(groupType === GROUP_TYPE.AdminTeam) {
exports.isGroupMember = function(groupId, groupType, doctorId, handler){
    if(groupType == GROUP_TYPE.AdminTeam) {
        wlyyRepo.execQuery({
            "sql": "SELECT doctor_code user_id from wlyy_admin_team_member WHERE team_id=? and doctor_code=?",
            "args": [groupId, doctorId],
@ -31,7 +31,7 @@ function isGroupMember(groupId, groupType, doctorId, handler){
            "handler": handler
        });
    }
}
};
/**
 * 获取团队成员。
@ -40,8 +40,8 @@ function isGroupMember(groupId, groupType, doctorId, handler){
 * @param groupType
 * @param handler
 */
function getMembers(groupId, groupType, handler) {
    if(groupType === GROUP_TYPE.AdminTeam) {
exports.getMembers = function(groupId, groupType, handler) {
    if(groupType == GROUP_TYPE.AdminTeam) {
        wlyyRepo.execQuery({
            "sql": "SELECT doctor_code user_id from wlyy_admin_team_member WHERE team_id=? AND available = 1",
            "args": [groupId],
@ -54,7 +54,22 @@ function getMembers(groupId, groupType, handler) {
            "handler": handler
        });
    }
}
};
exports.isGroupMember = isGroupMember;
exports.getMembers = getMembers;
exports.getMembersAvatar = function (groups, handler) {
    var sql = "SELECT * FROM(" +
        "SELECT g.code g_code, d.code dr_code, d.name dr_name, d.photo dr_photo " +
        "FROM wlyy.wlyy_talk_group g, wlyy.wlyy_talk_group_member m, wlyy.wlyy_doctor d " +
        "WHERE g.code = m.group_code AND m.member_code = d.code AND g.code in(" + groups + ") AND d.photo is NOT null " +
        " UNION " +
        "SELECT g.id g_code, d.code dr_code, d.name dr_name, d.photo dr_photo " +
        "FROM wlyy.wlyy_admin_team g, wlyy.wlyy_admin_team_member m, wlyy.wlyy_doctor d " +
        "WHERE g.id = m.team_id AND m.doctor_code = d.code AND g.id in(" + groups + ") AND d.photo is NOT null " +
        ") x ORDER BY x.g_code";
    wlyyRepo.execQuery({
        "sql": sql,
        "args": [],
        "handler": handler
    });
};

+ 100 - 22
src/doctor/models/msg.group.js

@ -2,25 +2,103 @@
var imRepo = require("../repository/im.repo");
function save(from, groupId, at, contentType, content, handler) {
	imRepo.execQuery({
		"sql": "INSERT INTO msg_group (to_gid,from_uid,at_uid,type,content) VALUES (?,?,?,?,?)",
		"args": [groupId, from, at, contentType, content],
		"handler": handler
	});
}
function findByGroupId(groupId, start, count, handler) {
	var sql = "SELECT from_uid,at_uid,type,content,timestamp from msg_group WHERE to_gid = ? GROUP BY timestamp DESC LIMIT ";
	sql += start;
	sql += ",";
	sql += count;
	imRepo.execQuery({
		"sql": sql,
		"args": [groupId],
		"handler": handler
	});
}
exports.save = save;
exports.findByGroupId = findByGroupId;
exports.save = function (from, groupId, at, contentType, content, handler) {
    imRepo.execQuery({
        "sql": "INSERT INTO msg_group (to_gid,from_uid,at_uid,type,content) VALUES (?,?,?,?,?)",
        "args": [groupId, from, at, contentType, content],
        "handler": handler
    });
};
exports.findAllMessages = function (groupId, contentType, start, end, count, handler) {
    var sql = "SELECT to_gid, msg_id, from_uid, at_uid, type, content, timestamp " +
        "FROM msg_group " +
        "WHERE to_gid = ? AND type in(" + contentType + ") AND msg_id BETWEEN ? AND ? GROUP BY timestamp DESC LIMIT ?";
    imRepo.execQuery({
        "sql": sql,
        "args": [groupId, end + 1, start - 1, count],
        "handler": handler
    });
};
/**
 * 查找用户参与的组列表,包括行政与求助。
 *
 * @param userId 指定的用户
 * @param handler
 */
exports.findAllGroupsWithDoctor = function (userId, handler) {
    var sql = "SELECT DISTINCT g.id, g.name, '', '', ms.last_content_type, ms.last_content, ms.timestamp, ms.new_msg_count " +
        "FROM wlyy.wlyy_admin_team g, wlyy.wlyy_admin_team_member m, wlyy.wlyy_doctor d, msg_statistic ms " +
        "WHERE d.code = ? AND d.code = m.doctor_code AND m.team_id = g.id AND g.id = ms.from_gid AND ms.last_content_type IN (1,2,3,5,6) GROUP BY g.id , g.name " +
        " UNION " +
        "SELECT m.group_code, m.group_name, '', '', ms.last_content_type, ms.last_content, ms.timestamp, ms.new_msg_count " +
        "FROM wlyy.wlyy_talk_group_member m, wlyy.wlyy_doctor d, msg_statistic ms " +
        "WHERE d.code = ? AND d.code = m.member_code AND m.group_code = ms.from_gid GROUP BY m.group_code , m.group_name";
    imRepo.execQuery({
        "sql": sql,
        "args": [userId, userId],
        "handler": handler
    });
};
/**
 * 查找用户参与的讨论组,且含有患者的讨论组。直接从wlyy_talk_group中查找即可。
 *
 * @param userId
 * @param handler
 */
exports.findAllGroupsWithPatient = function (userId, handler) {
    var sql = "SELECT g.code, g.name, '', '', '', ms.last_content_type, ms.last_content, ms.timestamp, ms.new_msg_count, g.type msg_type " +
        "FROM msg_statistic ms, (" +
        " SELECT g.code code, g.name name, g.type type FROM wlyy.wlyy_talk_group g, wlyy.wlyy_talk_group_member m " +
        " WHERE g.code = m.group_code and m.member_code = ?) g, wlyy.wlyy_patient p " +
        "WHERE ((ms.uid = ? and ms.peer_uid = p.code) OR (ms.uid = p.code and ms.peer_uid = ?)) " +
        "and ms.from_gid = g.code and ms.msg_type = 2 AND ms.last_content_type in (1,2,3,5,6) ";
    imRepo.execQuery({
        "sql": sql,
        "args": [userId, userId, userId],
        "handler": handler
    });
};
/**
 * 查找指定的消息。
 *
 * @param messageId
 * @param handler
 */
exports.findOneMessage = function (messageId, handler) {
    var sql = "SELECT to_gid, msg_id, from_uid, at_uid, type, content, timestamp " +
        "FROM msg_group " +
        "WHERE msg_id = ?";
    imRepo.execQuery({
        "sql": sql,
        "args": [messageId],
        "handler": handler
    });
};
/**
 * 查找未读消息。
 *
 * @param groupId
 * @param start
 * @param count
 * @param handler
 */
exports.findUnread = function (groupId, start, count, handler) {
    var sql = "SELECT msg_id, to_gid, from_uid, at_uid, type, content, timestamp " +
        "FROM msg_group " +
        "WHERE to_gid = ? AND msg_id < ? ORDER BY timestamp DESC LIMIT ?";
    imRepo.execQuery({
        "sql": sql,
        "args": [groupId, start, count],
        "handler": handler
    });
};

+ 3 - 3
src/doctor/models/msg.notify.js

@ -7,12 +7,12 @@
var log = require('../util/log');
var imRepo = require("../repository/im.repo");
function save(to, contentType, title, content, message, has_pushed, handler) {
exports.save = function(to, contentType, title, content, message, has_pushed, handler) {
    imRepo.execQuery({
        "sql": "INSERT INTO push_notify (to_uid,type,title,content,data,has_pushed) VALUES (?,?,?,?,?,?)",
        "args": [to, contentType, title, content, message, has_pushed],
        "handler": handler
    });
}
};
exports.save = save;
//exports.save = save;

+ 106 - 21
src/doctor/models/msg.private.js

@ -2,24 +2,109 @@
var imRepo = require("../repository/im.repo");
function save(to, from, type, content, handler) {
	imRepo.execQuery({
		"sql": "INSERT INTO msg_p2p (to_uid,from_uid,type,content) VALUES (?,?,?,?)",
		"args": [to, from, type, content],
		"handler": handler
	});
}
function findMessage(to, from, start, count, handler) {
	var sql = "SELECT id, to_uid, from_uid, type, content, timestamp from msg_p2p " +
        "WHERE (to_uid=? AND from_uid=?) OR (to_uid=? AND from_uid=?) AND id < ? GROUP BY timestamp DESC LIMIT ?";
	imRepo.execQuery({
		"sql": sql,
		"args": [to, from, from, to, start, count],
		"handler": handler
	});
}
exports.save = save;
exports.findByGroupId = findMessage;
/**
 * 保存消息。
 *
 * @param to
 * @param from
 * @param type
 * @param content
 * @param handler
 */
exports.save = function (to, from, type, content, handler) {
    imRepo.execQuery({
        "sql": "INSERT INTO msg_p2p (to_uid,from_uid,type,content) VALUES (?,?,?,?)",
        "args": [to, from, type, content],
        "handler": handler
    });
};
exports.findOneMessage = function (messageId, handler) {
  imRepo.execQuery({
      "sql": "SELECT msg_id, to_uid, from_uid, type, content, timestamp from msg_p2p where msg_id = ?",
      "args": [messageId],
      "handler": handler
  });
};
/**
 * 查找所有消息。
 *
 * @param to
 * @param from
 * @param contentType
 * @param start
 * @param count
 * @param handler
 */
exports.findAllMessages = function (to, from, contentType, start, end, count, handler) {
    var sql = "SELECT msg_id, to_uid, from_uid, type, content, timestamp from msg_p2p " +
        "WHERE ((to_uid=? AND from_uid=?) OR (to_uid=? AND from_uid=?)) " +
        "   AND type in (" + contentType + ") AND msg_id between ? and ? GROUP BY timestamp DESC LIMIT ?";
    imRepo.execQuery({
        "sql": sql,
        "args": [to, from, from, to, end + 1, start - 1, count],
        "handler": handler
    });
};
/**
 * 查找用户聊天过的医生列表。
 *
 * @param userId 指定的用户
 * @param handler
 */
exports.findAllP2PWithDoctor = function (userId, handler) {
    var sql = "SELECT DISTINCT d.code, d.name, d.sex, d.photo, ms3.last_content_type, ms3.last_content, ms3.timestamp, ms3.new_msg_count " +
        "FROM (SELECT DISTINCT CASE WHEN ms1.timestamp > ms2.timestamp THEN ms1.id ELSE ms2.id END id " +
        "      FROM msg_statistic ms1, msg_statistic ms2 " +
        "      WHERE ms1.from_gid IS NULL AND ms2.from_gid IS NULL " +
        "            AND ms1.uid = ms2.peer_uid AND ms1.peer_uid = ms2.uid) x, msg_statistic ms3, wlyy.wlyy_doctor d " +
        "WHERE x.id = ms3.id AND ms3.last_content_type in (1,2,3,5,6) AND " +
        "((ms3.uid = d.code AND ms3.peer_uid = ?) OR (ms3.uid = ? AND ms3.peer_uid = d.code)) GROUP BY d.code, d.name ORDER BY d.code";
    imRepo.execQuery({
        "sql": sql,
        "args": [userId, userId],
        "handler": handler
    });
};
/**
 * 查找用户聊天过的患者列表。
 *
 * @param userId
 * @param handler
 */
exports.findAllP2PWithPatient = function (userId, handler) {
    var sql = "SELECT p.code, p.name, p.birthday, p.sex, p.photo, ms.last_content_type, ms.last_content, ms.timestamp, ms.new_msg_count " +
        "FROM msg_statistic ms, wlyy.wlyy_patient p " +
        "WHERE ms.msg_type = 1 AND ms.last_content_type in (1,2,3,5,6) AND (ms.from_uid = ? AND ms.uid = p.code) OR (ms.uid = ? AND ms.from_uid = p.code)";
    imRepo.execQuery({
        "sql": sql,
        "args": [userId, userId],
        "handler": handler
    });
};
/**
 * 查找未读消息。
 *
 * @param from
 * @param to
 * @param start
 * @param count
 * @param handler
 */
exports.findUnread = function(from, to, start, count, handler) {
    var sql = "SELECT msg_id, to_uid, from_uid, type, content, timestamp from msg_p2p " +
        "WHERE from_uid = ? AND to_uid = ? AND msg_id < ? ORDER BY timestamp DESC LIMIT ?";
    imRepo.execQuery({
        "sql": sql,
        "args": [from, to, start, count],
        "handler": handler
    });
};

+ 183 - 119
src/doctor/models/msg.stat.js

@ -1,124 +1,198 @@
"use strict";
/**
 * 消息统计。方便前端获取聊天的状态。
 */
"use strict";
var http = require('http');
var qs = require('querystring');
var async = require('async');
var config = require('../include/commons').CONFIG_FILE;
var configFile = require('../include/commons').CONFIG_FILE;
var config = require('../resources/config/' + configFile);
var log = require('../util/log');
var wlyyRepo = require("../repository/wlyy.repo");
var imRepo = require("../repository/im.repo");
function updateGroupChatInfo(user_id, group_id, from_uid, at_me, type, content, msg_count_plus_one, handler) {
	var uuid = user_id + '_' + group_id;
    if (msg_count_plus_one) {
//--------------------About all chats--------------------
/**
 * 所有聊天列表。
 *
 * @param userId
 * @param handler
 */
exports.getChatList = function (userId, handler) {
    imRepo.execQuery({
        "sql": "SELECT uid,from_uid,from_gid,peer_uid,at_me,msg_type,last_content_type,last_content,new_msg_count,timestamp from msg_statistic WHERE uid = ?",
        "args": [userId],
        "handler": handler
    });
};
/**
 * 所有未读聊天记录数。
 *
 * @param userId
 * @param handler
 */
exports.getChatAllUnReadCount = function (userId, handler) {
    imRepo.execQuery({
        "sql": "SELECT new_msg_count from msg_statistic WHERE uid=? AND new_msg_count>0",
        "args": [userId],
        "handler": handler
    });
};
//--------------------About private chat summary--------------------
exports.updatePrivateChatSummary = function (userId, peerId, from, type, content, handler) {
    var uuid = userId + '_' + peerId;
    if (userId == from) {
        // 更新自身的统计信息
        var sql = "INSERT INTO msg_statistic (uid,uuid,from_uid,peer_uid,msg_type,last_content_type,last_content,new_msg_count) " +
            "VALUES (?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE peer_uid=?,last_content_type=?,last_content=?";
        imRepo.execQuery({
            "sql": "INSERT INTO msg_statistic (uid,uuid,from_uid,from_gid,at_me,msg_type,last_content_type,last_content,new_msg_count) VALUES (?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE from_uid=?,at_me=?,last_content_type=?,last_content=?,new_msg_count=new_msg_count+1",
            "args": [user_id, uuid, from_uid, group_id, at_me, 2, type, content, 1, from_uid, at_me, type, content],
            "sql": sql,
            "args": [userId, uuid, from, peerId, 1, type, content, 0, peerId, type, content],
            "handler": handler
        });
    } else {
        var sql = "INSERT INTO msg_statistic (uid,uuid,from_uid,peer_uid,msg_type,last_content_type,last_content,new_msg_count) " +
            "VALUES (?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE peer_uid=?,last_content_type=?,last_content=?,new_msg_count=new_msg_count+1";
        // 更新对端的统计信息
        imRepo.execQuery({
            "sql": "INSERT INTO msg_statistic (uid,uuid,from_uid,from_gid,at_me,msg_type,last_content_type,last_content,new_msg_count) VALUES (?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE from_uid=?,at_me=?,last_content_type=?,last_content=?",
            "args": [user_id, uuid, from_uid, group_id, at_me, 2, type, content, 0, from_uid, at_me, type, content],
            "sql": sql,
            "args": [userId, uuid, from, peerId, 1, type, content, 1, peerId, type, content],
            "handler": handler
        });
    }
}
};
function updateP2PChatInfo(user_id, peer_uid, from_uid, type, content, handler) {
    var uuid = user_id + '_' + peer_uid;
    if (user_id == from_uid) {
        // 更新自身的统计信息
exports.clearPrivateChatSummary = function (userId, peerId, handler) {
    var uuid = userId + '_' + peerId;
    imRepo.execQuery({
        "sql": "UPDATE msg_statistic SET new_msg_count='0' WHERE uuid=?",
        "args": [uuid],
        "handler": handler
    });
};
exports.getPrivateChatSummary = function (userId, peerId, handler) {
    var uuid = userId + '_' + peerId;
    imRepo.execQuery({
        "sql": "SELECT uid,from_uid,last_content_type,last_content,new_msg_count,timestamp from msg_statistic WHERE uuid = ?",
        "args": [uuid],
        "handler": handler
    });
};
exports.getPrivateChatAllUnReadCount = function (userId, handler) {
    imRepo.execQuery({
        "sql": "SELECT new_msg_count from msg_statistic WHERE uid=? AND msg_type=1 AND new_msg_count>0",
        "args": [userId],
        "handler": handler
    });
};
/**
 * 最近聊天对象,如患者,医生与群等基本信息。
 *
 * @param userId
 * @param days
 * @param handler
 */
exports.getRecentChats = function (userId, days, handler) {
    var timespan = 60 * 60 * 24 * days; // 多少天内的联系对象
    var sql = "SELECT * FROM(" +
        "SELECT DISTINCT p.code code, p.name name, p.birthday birthday, p.sex sex, p.photo photo, ms.timestamp timestamp, 'patient' type " +
        "FROM im_new.msg_statistic ms, wlyy.wlyy_patient p " +
        "WHERE ms.uid = ? AND ms.uid = p.code AND " +
        "UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(ms.timestamp) < ? AND msg_type = 1" +
        " UNION " +
        "SELECT DISTINCT d.code code, d.name name, d.birthday birthday, d.sex sex, d.photo photo, ms.timestamp timestamp,'doctor' type " +
        "FROM im_new.msg_statistic ms, wlyy.wlyy_doctor d, (SELECT CASE WHEN ms1.timestamp > ms2.timestamp THEN ms1.id ELSE ms2.id END id " +
        "                                                   FROM msg_statistic ms1, msg_statistic ms2 " +
        "                                                   WHERE ms1.from_gid IS NULL AND ms2.from_gid IS NULL AND ms1.uid = ms2.peer_uid AND ms1.peer_uid = ms2.uid) x " +
        "WHERE x.id = ms.id AND ((ms.uid = ? AND ms.peer_uid = d.code) OR (ms.uid = d.code AND ms.peer_uid = ?)) AND UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(ms.timestamp) < ?" +
        " UNION " +
        "SELECT g.id code, g.name name, '' birthday, '' sex, '' photo, max(ms.timestamp) timestamp, 'type' ':group' " +
        "FROM im_new.msg_statistic ms, wlyy.wlyy_admin_team g, wlyy.wlyy_admin_team_member m, wlyy.wlyy_doctor d " +
        "WHERE d.code = ? AND d.code = m.doctor_code AND m.team_id = g.id AND g.id = ms.from_gid " +
        "   AND (ms.uid = d.code or ms.from_uid = d.code) AND UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(ms.timestamp) < ? group by g.id, g.name " +
        ") x ORDER BY timestamp DESC";
    imRepo.execQuery({
        "sql": sql,
        "args": [userId, timespan, userId, userId, timespan, userId, timespan],
        "handler": handler
    });
};
//--------------------About group chat summary--------------------
/**
 * 更新群聊统计摘要。
 *
 * @param userId
 * @param groupId
 * @param from
 * @param atMe
 * @param type
 * @param content
 * @param msgCountPlusOne
 * @param handler
 */
exports.updateGroupChatSummary = function (userId, groupId, from, atMe, type, content, msgCountPlusOne, handler) {
    var uuid = userId + '_' + groupId;
    if (msgCountPlusOne) {
        imRepo.execQuery({
            "sql": "INSERT INTO msg_statistic (uid,uuid,from_uid,peer_uid,msg_type,last_content_type,last_content,new_msg_count) VALUES (?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE peer_uid=?,last_content_type=?,last_content=?",
            "args": [user_id, uuid, from_uid, peer_uid, 1, type, content, 0, peer_uid, type, content],
            "sql": "INSERT INTO msg_statistic (uid,uuid,from_uid,from_gid,at_me,msg_type,last_content_type,last_content,new_msg_count) VALUES (?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE from_uid=?,at_me=?,last_content_type=?,last_content=?,new_msg_count=new_msg_count+1",
            "args": [userId, uuid, from, groupId, atMe, 2, type, content, 1, from, atMe, type, content],
            "handler": handler
        });
    } else {
        // 更新对端的统计信息
        imRepo.execQuery({
            "sql": "INSERT INTO msg_statistic (uid,uuid,from_uid,peer_uid,msg_type,last_content_type,last_content,new_msg_count) VALUES (?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE peer_uid=?,last_content_type=?,last_content=?,new_msg_count=new_msg_count+1",
            "args": [user_id, uuid, from_uid, peer_uid, 1, type, content, 1, peer_uid, type, content],
            "sql": "INSERT INTO msg_statistic (uid,uuid,from_uid,from_gid,at_me,msg_type,last_content_type,last_content,new_msg_count) VALUES (?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE from_uid=?,at_me=?,last_content_type=?,last_content=?",
            "args": [userId, uuid, from, groupId, atMe, 2, type, content, 0, from, atMe, type, content],
            "handler": handler
        });
    }
}
function clearGroupChatInfo(user_id, group_id, handler) {
	var uuid = user_id + '_' + group_id;
	imRepo.execQuery({
		"sql": "UPDATE msg_statistic SET new_msg_count='0' WHERE uuid=?",
		"args": [uuid],
		"handler": handler
	});
}
function clearP2PChatInfo(user_id, peer_uid, handler) {
	var uuid = user_id + '_' + peer_uid;
	imRepo.execQuery({
		"sql": "UPDATE msg_statistic SET new_msg_count='0' WHERE uuid=?",
		"args": [uuid],
		"handler": handler
	});
}
function getGroupChatInfo(user_id, group_id, handler) {
	var uuid = user_id + '_' + group_id;
	imRepo.execQuery({
		"sql": "SELECT uid,from_uid,from_gid,at_me,last_content_type,last_content,new_msg_count,timestamp from msg_statistic WHERE uuid = ?",
		"args": [uuid],
		"handler": handler
	});
}
function getP2PChatInfo(user_id, peer_uid, handler) {
	var uuid = user_id + '_' + peer_uid;
	imRepo.execQuery({
		"sql": "SELECT uid,from_uid,last_content_type,last_content,new_msg_count,timestamp from msg_statistic WHERE uuid = ?",
		"args": [uuid],
		"handler": handler
	});
}
function getChatList(user_id, handler) {
};
exports.getGroupChatAllUnReadCount = function (userId, handler) {
    imRepo.execQuery({
        "sql": "SELECT uid,from_uid,from_gid,peer_uid,at_me,msg_type,last_content_type,last_content,new_msg_count,timestamp from msg_statistic WHERE uid = ?",
        "args": [user_id],
        "sql": "SELECT new_msg_count from msg_statistic WHERE uid=? AND msg_type=2 AND new_msg_count>0",
        "args": [userId],
        "handler": handler
    });
}
function getGroupChatAllUnRead(user_id, handler) {
	imRepo.execQuery({
		"sql": "SELECT new_msg_count from msg_statistic WHERE uid=? AND msg_type=2 AND new_msg_count>0",
		"args": [user_id],
		"handler": handler
	});
}
function getP2PChatAllUnRead(user_id, handler) {
	imRepo.execQuery({
		"sql": "SELECT new_msg_count from msg_statistic WHERE uid=? AND msg_type=1 AND new_msg_count>0",
		"args": [user_id],
		"handler": handler
	});
}
function getChatAllUnRead(user_id, handler) {
	imRepo.execQuery({
		"sql": "SELECT new_msg_count from msg_statistic WHERE uid=? AND new_msg_count>0",
		"args": [user_id],
		"handler": handler
	});
}
function getAppMsgAmount(user_id, handler) {
};
exports.getGroupChatSummary = function (userId, groupId, handler) {
    var uuid = userId + '_' + groupId;
    imRepo.execQuery({
        "sql": "SELECT uid,from_uid,from_gid,at_me,last_content_type,last_content,new_msg_count,timestamp from msg_statistic WHERE uuid = ?",
        "args": [uuid],
        "handler": handler
    });
};
exports.clearGroupChatSummary = function clearGroupChatInfo(userId, groupId, handler) {
    var uuid = userId + '_' + groupId;
    imRepo.execQuery({
        "sql": "UPDATE msg_statistic SET new_msg_count='0' WHERE uuid=?",
        "args": [uuid],
        "handler": handler
    });
};
//--------------------Others--------------------
exports.getAppMsgAmount = function (userId, handler) {
    wlyyRepo.execQuery({
        "sql": "SELECT imei,token from wlyy_token WHERE user=?",
        "args": [user_id],
        "handler": function(err, result) {
        "args": [userId],
        "handler": function (err, result) {
            if (err) {
                handler(null, 0);
                return;
@ -128,41 +202,44 @@ function getAppMsgAmount(user_id, handler) {
                return;
            }
            var options = {
                hostname: config.app_serer_cfg.hostname,
                port: config.app_serer_cfg.port,
                path: config.app_serer_cfg.path,
                method: config.app_serer_cfg.method,
                hostname: config.wlyyServerConfig.hostname,
                port: config.wlyyServerConfig.port,
                path: config.wlyyServerConfig.path,
                method: config.wlyyServerConfig.method,
                headers: {
                    'userAgent': '{"token":"'+ result[0].token +'","uid":"'+ user_id +'","imei":"'+ result[0].imei +'"}'
                    'userAgent': '{"token":"' + result[0].token + '","uid":"' + userId + '","imei":"' + result[0].imei + '"}'
                }
            };
            var req = http.request(options, function (res) {
                res.setEncoding('utf8');
                res.on('data', function (chunk) {
                    console.log('BODY: ' + chunk);
                    var data = JSON.parse(chunk);
                    handler(null, data);
                    log.info('请求家庭医生平台: ', options.hostname + ":" + options.port + options.path);
                    log.info('家庭医生平台返回: ', chunk);
                    handler(null, JSON.parse(chunk));
                });
            });
            req.on('error', function (e) {
                console.log('problem with request: ' + e.message);
                log.error('家庭医生平台接口调用出错: ', e.message);
                handler(e, null);
            });
            req.end();
        }
    });
}
};
function getBadgeNumber(user_id, handler) {
exports.getBadgeNumber = function (userId, handler) {
    var self = this;
    async.parallel([
            function(callback) {
            function (callback) {
                callback(null, 0);
            },
            function(callback) {
                getAppMsgAmount(user_id, function(err, result) {
            function (callback) {
                self.getAppMsgAmount(userId, function (err, result) {
                    if (err) {
                        callback(null, 0);
                    } else {
@ -179,7 +256,7 @@ function getBadgeNumber(user_id, handler) {
                });
            }],
        function(err, results) {
        function (err, results) {
            var badge = 0;
            for (var index = 0; index < results.length; index++) {
                badge += results[index];
@ -187,17 +264,4 @@ function getBadgeNumber(user_id, handler) {
            handler(null, badge);
        });
}
exports.updateGroupChatInfo = updateGroupChatInfo;
exports.updateP2PChatInfo = updateP2PChatInfo;
exports.clearGroupChatInfo = clearGroupChatInfo;
exports.clearP2PChatInfo = clearP2PChatInfo;
exports.getGroupChatInfo = getGroupChatInfo;
exports.getP2PChatInfo = getP2PChatInfo;
exports.getChatList = getChatList;
exports.getGroupChatAllUnRead = getGroupChatAllUnRead;
exports.getP2PChatAllUnRead = getP2PChatAllUnRead;
exports.getChatAllUnRead = getChatAllUnRead;
exports.getAppMsgAmount = getAppMsgAmount;
exports.getBadgeNumber = getBadgeNumber;
};

+ 3 - 3
src/doctor/models/msg.system.js

@ -3,12 +3,12 @@
var log = require('../util/log');
var imRepo = require("../repository/im.repo");
function save(to, contentType, title, summary, content, handler) {
exports.save = function(to, contentType, title, summary, content, handler) {
    imRepo.execQuery({
        "sql": "INSERT INTO msg_system (to_uid,type,title,content,data) VALUES (?,?,?,?,?)",
        "args": [to, contentType, title, summary, content],
        "handler": handler
    });
}
};
exports.save = save;
//exports.save = save;

+ 123 - 0
src/doctor/models/search.js

@ -0,0 +1,123 @@
/**
 * 搜索功能。
 */
"use strict";
var imRepo = require('../repository/im.repo');
/**
 * 搜索与医生签约过的患者,条件:患者姓名。
 */
module.exports.searchPatients = function (userId, userRole, keyword, handler) {
    var sql = "SELECT p.code, p.name, p.birthday, p.sex, p.photo " +
        "FROM wlyy.wlyy_sign_family f, wlyy.wlyy_patient p " +
        "WHERE f.patient = p.code AND p.name LIKE ? ";
    if(userRole == 1){
        // 全科医生
        sql += "AND f.doctor = ?"
    } else if(userRole == 2){
        // 健康管理师
        sql += "AND f.doctor_health = ?"
    }
    imRepo.execQuery({
        "sql": sql,
        "args": ["%" + keyword + "%", userId],
        "handler": handler
    });
};
/**
 * 搜索与患者的私信。
 */
module.exports.searchPatientPM = function (userId, keyword, handler) {
    var sql = "SELECT p.code, p.name, p.birthday, p.sex, p.photo, m.msg_id, m.content " +
        "FROM (SELECT CASE WHEN msg.from_uid = ? THEN msg.to_uid ELSE msg.from_uid END peer_id, msg.msg_id, msg.content " +
        "      FROM msg_p2p msg " +
        "      WHERE (msg.from_uid = ? OR msg.to_uid = ?) AND msg.content LIKE ? AND type = 1) m, wlyy.wlyy_patient p " +
        "WHERE m.peer_id = p.code ORDER BY p.code";
    imRepo.execQuery({
        "sql": sql,
        "args": [userId, userId, userId, "%" + keyword + "%", userId],
        "handler": handler
    });
};
/**
 * 搜索聊天过的医生及行政团队内成员,条件:医生姓名。
 */
module.exports.searchDoctors = function (userId, keyword, handler) {
    var sql = "SELECT DISTINCT d.code, d.name, d.photo, d.hospital " +
        "FROM msg_statistic ms, wlyy.wlyy_doctor d " +
        "WHERE d.code = ? AND ms.from_gid IS NULL AND (ms.peer_uid = d.code OR ms.uid = d.code) AND d.name like ?" +
        "UNION " +
        "SELECT d.code, d.name, d.photo, d.hospital " +
        "FROM wlyy.wlyy_admin_team_member m1, wlyy.wlyy_admin_team_member m2, wlyy.wlyy_doctor d " +
        "WHERE m1.doctor_code = ? AND m1.team_id = m2.team_id AND m2.doctor_code = d.code AND d.name like ?";
    imRepo.execQuery({
        "sql": sql,
        "args": [userId, "%" + keyword + "%", userId, "%" + keyword + "%"],
        "handler": handler
    });
};
/**
 * 搜索医生消息内容。
 */
module.exports.searchDoctorMessages = function (userId, keyword, handler) {
    var sql = "SELECT d.code, d.name, d.photo, m.msg_id, m.content " +
        "FROM (SELECT CASE WHEN msg.from_uid = ? THEN msg.to_uid ELSE msg.from_uid END peer_id, msg.msg_id, msg.content " +
        "      FROM msg_p2p msg " +
        "      WHERE (msg.from_uid = ? OR msg.to_uid = ?) AND msg.content LIKE ? AND type = 1) m, wlyy.wlyy_doctor d " +
        "WHERE m.peer_id = d.code ORDER BY d.name ASC, m.msg_id DESC";
    imRepo.execQuery({
        "sql": sql,
        "args": [userId, userId, userId, "%" + keyword + "%"],
        "handler": handler
    });
};
/**
 * 搜索医生的讨论组,使用名称。
 */
module.exports.searchGroups = function (userId, keyword, handler) {
    var sql = "SELECT g.code, g.name, m.member_code, m.member_name " +
        "FROM wlyy.wlyy_talk_group g left join wlyy.wlyy_talk_group_member m on g.code = m.group_code " +
        "WHERE g.name like ? OR m.member_name LIKE ? AND m.member_code = ?";
    imRepo.execQuery({
        "sql": sql,
        "args": ["%" + keyword + "%", "%" + keyword + "%", userId],
        "handler": handler
    });
};
/**
 * 搜索医生的讨论组消息,使用消息内容。
 */
module.exports.searchGroupMessages = function (userId, keyword, handler) {
    var sql = "SELECT g.code, g.name, gm.msg_id, gm.content FROM msg_group gm, " +
        "   (SELECT t.id code, t.name name " +
        "    FROM wlyy.wlyy_admin_team t, wlyy.wlyy_admin_team_member m " +
        "    WHERE m.doctor_code = ? AND t.id = m.team_id " +
        "    UNION " +
        "    SELECT m.group_code code, m.group_name name " +
        "    FROM wlyy.wlyy_talk_group_member m " +
        "    WHERE m.member_code = ?) g " +
        "WHERE g.code = gm.to_gid AND gm.type = 1 AND gm.content LIKE ? ORDER BY g.name ASC, gm.msg_id DESC";
    imRepo.execQuery({
        "sql": sql,
        "args": [userId, userId, "%" + keyword + "%"],
        "handler": handler
    });
};

+ 20 - 20
src/doctor/models/user.js

@ -14,60 +14,60 @@ var wlyyRepo = require("../repository/wlyy.repo");
 * @param user
 * @param handler
 */
function isExist(user, handler) {
exports.isExist = function(user, handler) {
    wlyyRepo.execQuery({
        "sql": "SELECT count(*) from wlyy_doctor WHERE code=?",
        "args": [user],
        "handler": handler
    });
}
};
function getUserStatus(userId, handler) {
exports.getUserStatus = function(userId, handler) {
    imRepo.execQuery({
        "sql": "SELECT platform,token,client_id,is_online,status from user WHERE user_id = ?",
        "args": [userId],
        "handler": handler
    });
}
};
function login(userId, token, client_id, platform, handler) {
exports.login = function(userId, token, client_id, platform, handler) {
    imRepo.execQuery({
        "sql": "INSERT INTO user (user_id,token,client_id,platform,is_online,status) VALUES (?,?,?,?,1,1) ON" +
        " DUPLICATE KEY UPDATE token=?,client_id=?,platform=?,is_online=1,status=1",
        "args": [userId, token, client_id, platform, token, client_id, platform],
        "handler": handler
    });
}
};
function logout(userId, handler) {
exports.logout = function(userId, handler) {
    imRepo.execQuery({
        "sql": "UPDATE user SET is_online='0',status='0' WHERE user_id=?",
        "args": [userId],
        "handler": handler
    });
}
};
function deleteToken(token, handler) {
exports.deleteToken = function(token, handler) {
    imRepo.execQuery({
        "sql": "DELETE FROM user WHERE token=?",
        "args": [token],
        "handler": handler
    });
}
};
function updateStatus(userId, status, handler) {
exports.updateStatus = function(userId, status, handler) {
    imRepo.execQuery({
        "sql": "UPDATE user SET status=? WHERE user_id=?",
        "args": [status, userId],
        "handler": handler
    });
}
};
exports.isExist = isExist;
exports.getUserStatus = getUserStatus;
exports.login = login;
exports.logout = logout;
exports.deleteToken = deleteToken;
exports.updateStatus = updateStatus;
//exports.isExist = isExist;
//exports.getUserStatus = getUserStatus;
//
//exports.login = login;
//exports.logout = logout;
//
//exports.deleteToken = deleteToken;
//exports.updateStatus = updateStatus;//

+ 1 - 0
src/doctor/package.json

@ -18,6 +18,7 @@
    "mocha": "~3.1.2",
    "morgan": "~1.5.3",
    "mysql": "~2.5.3",
    "swagger-node-express": "~2.0",
    "serve-favicon": "~2.2.1",
    "socket.io": "~1.5.1",
    "underscore": "~1.8.3"

+ 57 - 36
src/doctor/public/javascripts/sdk/im.client.js

@ -1,27 +1,31 @@
/*
    IM客户端SDK。此SDK可以连接开发、测试或生产环境,根据需要配置环境参数以连接到不同的服务器。
 IM客户端SDK。此SDK可以连接开发、测试或生产环境,根据需要配置环境参数以连接到不同的服务器。
 */
var isProd = false;     // 连接生产环境
var isDemo = false;     // 连接公司演示或开发测试环境
// 服务器列表
var servers = {
    dev: "http://172.19.103.76:3000",
    dev: "http://192.168.131.115:3000",
    demo: "http://ehr.yihu.com",
    prod: "http://120.41.253.95:3000"
};
// REST接口相对路径
var restPath = {
    login: "/users/login.im",
    logout: "/users/logout.im",
    updateStatus: "/users/updatestatus.im",
    sendGroup: "/group/sendmsg.im",
    getGroupMsg: "/group/getmsg.im",
    sendOneByOne: "/p2p/sendmsg.im",
    getOneByOneMsg: "/p2p/getmsg.im",
    getNewMsgCount: "/statistic/getgroupchatinfo.im",
    getBadgeNumber: "/statistic/getbadgenum.im"
    login: "/api/v1/users/login",
    logout: "/api/v1/users/logout",
    status: "/api/v1/users/:user_id/status",
    sendGroup: "/api/v1/chats/gm",
    getGroupMsg: "/api/v1/chats/gm",
    sendOneByOne: "/api/v1/chats/pm",
    getOneByOneMsg: "/api/v1/chats/pm",
    getGroupStatistic: "/api/v1/chats/gm/statistic",
    getBadgeNumber: "/api/v1/application/badge_no"
};
var actualServer;
@ -38,20 +42,25 @@ var endpoints = {
    login: actualServer + restPath.login,
    logout: actualServer + restPath.logout,
    updateStatus: actualServer + restPath.updateStatus,
    sendGroup: actualServer + restPath.sendGroupMsg,
    getGroupMsg: actualServer + restPath.getGroupMsg,
    sendOneByOne: actualServer + restPath.sendPrivateMsg,
    getOneByOneMsg: actualServer + restPath.getPrivateMsg,
    getNewMsgCount: actualServer + restPath.getNewMsgCount,
    sendGroup: actualServer + restPath.sendGroupMsg,
    getGroupMsg: actualServer + restPath.getGroupMsg,
    getGroupStatistic: actualServer + restPath.getGroupStatistic,
    getBadgeNumber: actualServer + restPath.getBadgeNumber
};
// 本地临时缓存Key
var plusStorageKey = {
    userId: "im.user.id"
    userId: "im_userid"
};
var im = {
    // 登录
    login: function (userId, token, client_id, platform) {
        console.log("IM - Login: " + userId);
        plus.storage.setItem(plusStorageKey.userId, userId);
@ -68,6 +77,7 @@ var im = {
            }
        });
    },
    // 退出
    logout: function (userId) {
        plus.storage.removeItem(plusStorageKey.userId);
        $.ajax({
@ -84,11 +94,11 @@ var im = {
            }
        });
    },
    // 更新用户在线状态
    updateStatus: function (userId, status) {
        // 更新用户在线状态
        $.ajax({
            type: "get",
            url: endpoints.updateStatus,
            url: endpoints.updateStatus.replace(':user_id', userId),
            data: {user_id: userId, status: status},
            async: true,
            dataType: "json",
@ -99,12 +109,13 @@ var im = {
            }
        });
    },
    // 发送群组消息
    sendGroupMsg: function (userId, groupId, content, type, handler, group_type) {
        function send() {
            $.ajax({
                type: "get",
                type: "post",
                url: endpoints.sendGroupMsg,
                data: {from_uid: userId, to_gid: groupId, content: content, type: type, group_type: group_type},
                data: {from: userId, group: groupId, groupType: group_type, contentType: type, content: content},
                async: true,
                dataType: "json",
                success: function (data) {
@ -119,11 +130,12 @@ var im = {
        checkLogin(send);
    },
    // 获取组消息
    getGroupMsg: function (uid, groupId, start, count, handler) {
        $.ajax({
            type: "get",
            url: endpoints.getGroupMsg,
            data: {uid: uid, gid: groupId, start: start, count: count},
            data: {user_id: uid, group_id: groupId, message_start_id: start, count: count},
            async: true,
            dataType: "json",
            success: function (data) {
@ -135,11 +147,12 @@ var im = {
            }
        });
    },
    // 获取组消息数
    getGroupInfo: function (uid, gid, handler) {
        $.ajax({
            type: "get",
            url: endpoints.getNewMsgCount,
            data: {uid: uid, gid: gid},
            url: endpoints.getGroupStatistic,
            data: {user_id: uid, group_id: gid},
            async: true,
            dataType: "json",
            success: function (data) {
@ -151,12 +164,13 @@ var im = {
        });
    },
    // 发送私信
    sendPrivateMsg: function (from_uid, to_uid, content, type) {
        function send() {
            $.ajax({
                type: "get",
                type: "post",
                url: endpoints.sendPrivateMsg,
                data: {from_uid: from_uid, to_uid: to_uid, content: content, type: type},
                data: {from: from_uid, to: to_uid, content: content, contentType: type},
                async: true,
                dataType: "json",
                success: function (data) {
@ -171,12 +185,13 @@ var im = {
        checkLogin(send);
    },
    // 发送私信
    sendPrivateMsgWithCallback: function (from_uid, to_uid, content, type, msgCallback, errCallback) {
        function send() {
            $.ajax({
                type: "get",
                type: "post",
                url: endpoints.sendPrivateMsg,
                data: {from_uid: from_uid, to_uid: to_uid, content: content, type: type},
                data: {from: from_uid, to: to_uid, content: contentType, type: type},
                async: true,
                dataType: "json",
                success: function (msg) {
@ -190,11 +205,12 @@ var im = {
        checkLogin(send);
    },
    // 获取私信
    getPrivateMsg: function (uid, peer_uid, start, count) {
        $.ajax({
            type: "get",
            url: endpoints.getPrivateMsg,
            data: {gid: groupId, start: start, count: count},
            data: {user_id: uid, peer_id: peer_uid, message_start_id: start, count: count},
            async: true,
            dataType: "json",
            success: function (data) {
@ -206,11 +222,12 @@ var im = {
            }
        });
    },
    getPagedPrivateMsg: function (uid, peer_uid, start, count, handler) {
    // 获取私信
    getPrivateMsgWithCallback: function (uid, peer_uid, start, count, handler) {
        $.ajax({
            type: "get",
            url: endpoints.getPrivateMsg,
            data: {uid: uid, peer_uid: peer_uid, start: start, count: count},
            data: {user_id: uid, peer_id: peer_uid, message_start_id: start, count: count},
            async: true,
            dataType: "json",
            success: function (data) {
@ -221,19 +238,22 @@ var im = {
            }
        });
    },
    // 获取应用角标数
    getBadgeNumber: function (userId, handler) {
        $.ajax({
            type: "get",
            url: endpoints.getBadgeNumber,
            data: {uid: userId},
            data: {user_id: userId},
            async: true,
            dataType: "json",
            success: function (data) {
                console.log(JSON.stringify(data));
                if (handler) handler(data);
            },
            error: function (msg) {
                console.log('error');
                if (handler) handler(msg);
            }
        });
@ -241,12 +261,13 @@ var im = {
};
/*
    执行业务接口前,调用此函数判断当前用户是否在线。
 执行业务接口前,调用此函数判断当前用户是否在线。
 */
function checkLogin(callback) {
    sendPost("/doctor/islive", {}, null, function (res) {
        if (res.status == 200) {
            callback();
        }
    })
    /*sendPost("/doctor/islive", {}, null, function (res) {
     if (res.status == 200) {
     callback();
     }
     })*/
    callback();
}

+ 14 - 2
src/doctor/resources/config/config.dev.js

@ -21,7 +21,7 @@ var geTuiConfig = {
    HOST: 'https://api.getui.com/apiex.htm',
    APPID: 'qWmRh2X88l7HuE36z3qBe8',
    APPKEY: 'EzERfV8c849lBkZqHWzQG1',
    MASTERSECRET: 'veXiajQrId6iojy7Qv8kZ2'
    MASTERSECRET: 'RpEO1Ot8nA6uwvJFirRFp5'
};
// AppStore版的推送App配置
@ -32,12 +32,24 @@ var geTuiAppStoreCfg = {
    MASTERSECRET : 'pvjCGtRZJx9SRVODkxc816'
};
// 三师后台
var wlyyServerConfig = {
    hostname: '172.19.103.87',
    port: 9092,
    path: '/wlyy/doctor/message/amount',
    method: 'POST'
};
exports.app = 'IM.Server';
exports.version = '1.0.5.20161107';
exports.debug = true;
exports.httpPort = 3000;
exports.sessionExpire = 1800;
exports.showSQL = true;
exports.wlyyDbConfig = wlyyDbConfig;
exports.imDbConfig = imDbConfig;
exports.geTuiConfig = geTuiConfig;
exports.geTuiAppStoreCfg = geTuiAppStoreCfg;
exports.geTuiAppStoreCfg = geTuiAppStoreCfg;
exports.wlyyServerConfig = wlyyServerConfig;

+ 14 - 2
src/doctor/resources/config/config.pro.js

@ -21,7 +21,7 @@ var geTuiConfig = {
    HOST: 'https://api.getui.com/apiex.htm',
    APPID: 'qWmRh2X88l7HuE36z3qBe8',
    APPKEY: 'EzERfV8c849lBkZqHWzQG1',
    MASTERSECRET: 'veXiajQrId6iojy7Qv8kZ2'
    MASTERSECRET: 'RpEO1Ot8nA6uwvJFirRFp5'
};
//AppStore版的推送App配置
@ -32,12 +32,24 @@ var geTuiAppStoreCfg = {
    MASTERSECRET : 'pvjCGtRZJx9SRVODkxc816'
};
// 三师后台
var wlyyServerConfig = {
    hostname: '172.19.103.87',
    port: 9090,
    path: '/wlyy/doctor/message/amount',
    method: 'POST'
};
exports.app = 'im.server';
exports.version = '1.0.2.20160805';
exports.debug = true;
exports.httpPort = 3000;
exports.sessionExpire = 1800;
exports.showSQL.sql.show = false;
exports.wlyyDbConfig = wlyyDbConfig;
exports.imDbConfig = imDbConfig;
exports.geTuiConfig = geTuiConfig;
exports.geTuiAppStoreCfg = geTuiAppStoreCfg;
exports.geTuiAppStoreCfg = geTuiAppStoreCfg;
exports.wlyyServerConfig = wlyyServerConfig;

+ 14 - 2
src/doctor/resources/config/config.test.js

@ -21,7 +21,7 @@ var geTuiConfig = {
    HOST: 'https://api.getui.com/apiex.htm',
    APPID: 'qWmRh2X88l7HuE36z3qBe8',
    APPKEY: 'EzERfV8c849lBkZqHWzQG1',
    MASTERSECRET: 'veXiajQrId6iojy7Qv8kZ2'
    MASTERSECRET: 'RpEO1Ot8nA6uwvJFirRFp5'
};
//AppStore版的推送App配置
@ -32,12 +32,24 @@ var geTuiAppStoreCfg = {
    MASTERSECRET : 'pvjCGtRZJx9SRVODkxc816'
};
// 三师后台
var wlyyServerConfig = {
    hostname: '172.19.103.87',
    port: 9090,
    path: '/wlyy/doctor/message/amount',
    method: 'POST'
};
exports.app = 'im.server';
exports.version = '1.0.2.20160805';
exports.debug = true;
exports.httpPort = 3030;
exports.sessionExpire = 1800;
exports.showSQL= true;
exports.wlyyDbConfig = wlyyDbConfig;
exports.imDbConfig = imDbConfig;
exports.geTuiConfig = geTuiConfig;
exports.geTuiAppStoreCfg = geTuiAppStoreCfg;
exports.geTuiAppStoreCfg = geTuiAppStoreCfg;
exports.wlyyServerConfig = wlyyServerConfig;

+ 5 - 0
src/doctor/util/dbUtil.js

@ -1,11 +1,16 @@
"use strict";
var configFile = require('../include/commons').CONFIG_FILE;
var config = require('../resources/config/' + configFile);
var log = require('./log');
/**
 * 数据库查询工具,使用数据库连接池获取连接,执行查询,之后将连接返回连接池。
 */
exports.execQuery = function (pool, options) {
    if(config.showSQL) log.info(options.sql);
    pool.getConnection(function (err, connection) {
        // 查询参数
        var sql = options['sql'];

+ 4 - 0
src/doctor/util/objectUtil.js

@ -47,4 +47,8 @@ exports.fieldsCheck = function(){
    if(ret.pass) ret.message = null;
    return ret;
};
exports.timestampToLong = function(tm){
    return Date.parse(new Date(tm));
};

+ 1 - 1
test/doctor/endpoints/application.endpoint.Test.js

@ -8,7 +8,7 @@ var restTemplate = require('supertest').agent(testConfig.host);
var userId = '48832ecc339111e6badcfa163e789456';
describe('Chat api', function () {
describe('API: App info', function () {
    // 获取角标数
    describe('when get badge number', function () {
        it('shout return 200 and badge number', function (done) {

+ 107 - 12
test/doctor/endpoints/chats.endpoint.Test.js

@ -14,7 +14,7 @@ var consultGroupId = 'bcfd47c57ea74ba19fa049222c76befd';    // 讨论组ID
var at = '';
describe('Chat api', function () {
describe('API: Chat', function () {
    // 发送系统消息
    describe('when send SYSTEM message correctly', function () {
        it('should return 200', function (done) {
@ -28,7 +28,7 @@ describe('Chat api', function () {
                    content: "患者已经签约,可以制定随访计划。"
                })
                .end(function (err, response) {
                    if(response.status !== 200){
                    if(response.status === 200){
                        console.log(response.body);
                    }
@ -91,7 +91,7 @@ describe('Chat api', function () {
                    content: "请问:居民签约人数是否达标"
                })
                .end(function (err, response) {
                    if(response.status !== 200){
                    if(response.status === 200){
                        console.log(response.body);
                    }
@ -116,7 +116,7 @@ describe('Chat api', function () {
                    content: "庄医生,患者体征数据是否正常?"
                })
                .end(function (err, response) {
                    if(response.status !== 200){
                    if(response.status === 200){
                        console.log(response.body);
                    }
@ -133,7 +133,9 @@ describe('Chat api', function () {
            var path = APIv1.Chats.Base + APIv1.Chats.List + "?user_id=" + userId;
            restTemplate.get(path)
                .end(function (err, response) {
                    console.log("User " + userId + "'s all chat list: \n", response.body);
                    if(response.status === 200){
                        console.log("User " + userId + "'s all chat list: \n", response.body);
                    }
                    response.status.should.equal(200);
@ -142,13 +144,66 @@ describe('Chat api', function () {
        });
    });
    // 未读组数量
    // 最近联系对象
    describe('when get recent chat list, including ', function () {
        it('should return 200 and recent chat list in date span', function (done) {
            var path = APIv1.Chats.Base + APIv1.Chats.Recent + "?user_id=" + userId + "&days=7";
            restTemplate.get(path)
                .end(function (err, response) {
                    if(response.status === 200){
                        console.log("User " + userId + "'s recent chats: \n", response.body);
                    }
                    response.status.should.equal(200);
                    done();
                })
        });
    });
    // 与居民的聊天列表,包括含有居民的群
    describe('when get patient contained chat list', function () {
        it('should return 200 and chat list with patients', function (done) {
            var path = APIv1.Chats.Base + APIv1.Chats.ListWithPatient + "?user_id=" + 'D2016082203';
            restTemplate.get(path)
                .end(function (err, response) {
                    if(response.status === 200){
                        console.log("User " + userId + "'s chats with patients: \n", response.body);
                    }
                    response.status.should.equal(200);
                    done();
                })
        });
    });
    // 与医生的聊天列表,不包含有居民的群
    describe('when get doctor contained only chat list', function () {
        it('should return 200 and chat list with doctors', function (done) {
            var path = APIv1.Chats.Base + APIv1.Chats.ListWithDoctor + "?user_id=0de7421c62dd11e69faffa163e8aee56";
            restTemplate.get(path)
                .end(function (err, response) {
                    if(response.status === 200){
                        console.log("User " + userId + "'s chats with doctors: \n", response.body);
                    }
                    response.status.should.equal(200);
                    done();
                })
        });
    });
    // 所有未读组消息数
    describe('when get ALL GROUP unread chat count', function () {
        it('should return 200 and group chat count', function (done) {
            var path = APIv1.Chats.Base + APIv1.Chats.GMUnreadCount + "?user_id=" + userId;
            restTemplate.get(path)
                .end(function (err, response) {
                    console.log("User " + userId + "'s group chat count: \n", response.body);
                    if(response.status === 200) {
                        console.log("User " + userId + "'s group chat count: \n", response.body);
                    }
                    response.status.should.equal(200);
@ -157,13 +212,15 @@ describe('Chat api', function () {
        })
    });
    // 未读私信数量
    // 所有未读私信数
    describe('when get ALL PRIVATE unread chat list', function () {
        it('should return 200 and private chat count', function (done) {
            var path = APIv1.Chats.Base + APIv1.Chats.PMUnreadCount + "?user_id=" + userId;
            restTemplate.get(path)
                .end(function (err, response) {
                    console.log("User " + userId + "'s private chat count: \n", response.body);
                    if(response.status === 200){
                        console.log("User " + userId + "'s private chat count: \n", response.body);
                    }
                    response.status.should.equal(200);
@ -172,13 +229,15 @@ describe('Chat api', function () {
        })
    });
    // 所有未读消息数量
    // 所有未读消息数
    describe('when get ALL unread message count', function () {
        it('should return 200 and all unread message count', function (done) {
            var path = APIv1.Chats.Base + APIv1.Chats.UnreadMsgCount + "?user_id=" + userId;
            restTemplate.get(path)
                .end(function (err, response) {
                    console.log("User " + userId + "'s all unread message count: \n", response.body);
                    if(response.status === 200){
                        console.log("User " + userId + "'s all unread message count: \n", response.body);
                    }
                    response.status.should.equal(200);
@ -187,13 +246,49 @@ describe('Chat api', function () {
        });
    });
    // 获取未读私信
    describe('when get unread private messages', function () {
        it('should return 200 and unread private messages', function (done) {
            var path = APIv1.Chats.Base + APIv1.Chats.PMUnread + "?user_id=D2016008240002&peer_id=D2016008240003";
            restTemplate.get(path)
                .end(function (err, response) {
                    if(response.status === 200){
                        console.log("User D2016008240002's unread private message with D2016008240003: \n", response.body);
                    }
                    response.status.should.equal(200);
                    done();
                });
        })
    });
    // 获取未群消息
    describe('when get unread group messages', function () {
        it('should return 200 and unread group messages', function (done) {
            var path = APIv1.Chats.Base + APIv1.Chats.GMUnread + "?group_id=2&user_id=D20160322000003";
            restTemplate.get(path)
                .end(function (err, response) {
                    if(response.status === 200){
                        console.log("User D20160322000003's unread messages in group 2: \n", response.body);
                    }
                    response.status.should.equal(200);
                    done();
                });
        })
    });
    // 获取角标数
    describe('when get badge number', function () {
        it('shout return 200 and badge number', function (done) {
            var path = APIv1.Application.Base + APIv1.Application.BadgeNo + "?user_id=" + userId;
            restTemplate.get(path)
                .end(function (err, response) {
                    console.log("User " + userId + "'s badge number: \n", response.body);
                    if(response.status === 200){
                        console.log("User " + userId + "'s badge number: \n", response.body);
                    }
                    response.status.should.equal(200);

+ 1 - 1
test/doctor/endpoints/management.endpoint.Test.js

@ -6,7 +6,7 @@ var APIv1 = require('../../../src/doctor/include/endpoints').APIv1;
var should = require("should");
var server = require('supertest').agent(testConfig.host);
describe('Management api', function () {
describe('API: Management', function () {
    describe('when require /db', function(){
        it('should return 200', function (done) {
            var path = APIv1.Management.Base + APIv1.Management.DbStatus;

+ 1 - 1
test/doctor/endpoints/users.endpoint.Test.js

@ -6,7 +6,7 @@ var APIv1 = require('../../../src/doctor/include/endpoints').APIv1;
var should = require("should");
var server = require('supertest').agent(testConfig.host);
describe('User api', function () {
describe('API: User', function () {
    describe('when login with correct params', function () {
        it('should return 200', function (done) {
            var path = APIv1.Users.Base + APIv1.Users.Login + "?user_id=0de7295862dd11e69faffa163e8aee56&token=0PFWlKmLBN9YzhCfFWVgYA&client_id=H6FYbDejks6VjMmW3uH7V6&platform=0";

+ 11 - 1
test/doctor/util/objectUtil.Test.js

@ -36,7 +36,8 @@ describe('Object utilities', function () {
            var testing = objectUtil.fieldsCheck({
                    from: 'Sand',
                    to: 'Rose',
                    content: 'Hello world.'},
                    content: 'Hello world.'
                },
                'from',
                'to',
                'timestamp',
@ -48,4 +49,13 @@ describe('Object utilities', function () {
            assert.strictEqual(true, testing.message.indexOf('location') > -1);
        });
    });
    describe('When test timestampToLong', function () {
        it('should return 200.', function () {
            var now = new Date(1479028394000);
            var val = objectUtil.timestampToLong(now);
            assert.strictEqual(1479028394000, val);
        });
    });
});