瀏覽代碼

模型-控制器分开处理;将控制器中的数据库代码转移至模型中

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

+ 0 - 0
docker/DockFile


+ 4 - 0
readme.md

@ -33,6 +33,10 @@ IM_PROFILE值将决定应用加载的配置文件。值为prod, test, dev,仅
为保证服务正常运行,当服务异常退出时自动重启服务,IM服务器使用app.armour.js脚本,对进程添加保护:进程异常退出时,自动重启。为实现此目标,部署时通过appArmour启动服务即可实现进程的守护功能。
### 部署到Docker上
未完工
## 开发SDK
IM提供了开发SDK,一个JS脚本。客户端可以通过引用此脚本或将此脚本打包到资源中。此外,脚本使用jQuery作为基础环境,因此客户端需要预先引用jQuery脚本。客户端通过以下链接引用SDK文件

+ 12 - 14
src/doctor/endpoints/application.endpoint.js

@ -3,16 +3,15 @@
let express = require('express');
let router = express.Router();
let log = require('../util/log.js');
const APIv1 = require('../include/endpoints').APIv1;
const MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
let APIv1 = require('../include/endpoints').APIv1;
let statsRepo = require("../repository/stats.msg.repo.js");
let StatsMessage = require("../models/stats");
/**
 * 获取应用角标数。
 *
 * chats/badge_no?user_id=sand
 * /application/badge_no?user_id=sand
 *
 * 参数:
 * uid:用户id
@ -20,17 +19,16 @@ let statsRepo = require("../repository/stats.msg.repo.js");
router.get(APIv1.Application.BadgeNo, function (req, res) {
    let userId = req.query.user_id;
    statsRepo.getBadgeNumber(userId, function (err, result) {
        if (err) {
            console.error("Get badge number failed: ", err);
            res.status(500).send({message: "Get badge number failed."});
            return;
        }
    let statsMsg = new StatsMessage();
    statsMsg.on(MODEL_EVENTS.OK, function (data) {
        res.status(200).send(data);
    });
        let data = {userId: userId, badge: result};
        res.send(data);
    statsMsg.on(MODEL_EVENTS.Error, function (data) {
        res.status(500).send(data);
    });
    statsMsg.getBadgeNumber(userId);
});
module.exports = router;

+ 126 - 1117
src/doctor/endpoints/chats.endpoint.js

@ -9,30 +9,21 @@ let express = require('express');
let router = express.Router();
let http = require('http');
let getui = require('getui');
let log = require('../util/log.js');
let objectUtil = require("../util/objectUtil.js");
let controllerUtil = require('../util/controllerUtil');
let Patient = new require("../models/patient");
let patient = new Patient();
let Doctor = new require('../models/doctor');
let Group = new require('../models/group');
let Search = require('../models/search');
let smRepo = require("../repository/system.msg.repo.js");
let pmRepo = require('../repository/private.msg.repo.js');
let gmRepo = require("../repository/group.msg.repo.js");
let nmRepo = require("../repository/notify.msg.repo.js");
let statsRepo = require("../repository/stats.msg.repo.js");
let doctorRepo = require("../repository/doctor.repo.js");
let groupRepo = require("../repository/group.repo.js");
let searchRepo = require('../repository/search.repo.js');
const APIv1 = require('../include/endpoints').APIv1;
const CONTENT_TYPES = require('../include/commons').CONTENT_TYPE;
const GROUP_TYPE = require('../include/commons').GROUP_TYPE;
let APIv1 = require('../include/endpoints').APIv1;
let CONTENT_TYPES = require('../include/commons').CONTENT_TYPE;
let GROUP_TYPE = require('../include/commons').GROUP_TYPE;
let PLATFORMS = require('../include/commons').PLATFORM;
let MAX_INT = 9007199254740992;
let DEFAULT_PAGE_SIZE = 100;
const MAX_INT = 9007199254740992;
const DEFAULT_PAGE_SIZE = 100;
//--------------------------------------------------------------//
//----------------------------消息发送----------------------------//
@ -69,69 +60,10 @@ router.post(APIv1.Chats.SM, function (req, res) {
    }
    // 消息处理
    doctorRepo.getUserStatus(message.to, function (err, rows) {
        if (err) {
            console.log("Lookup system message receiver failed: ", err);
            res.status(500).send({message: "Lookup system message receiver failed."});
            return;
        }
        if (rows.length == 0) {
            res.status(404).send({message: "User not found: " + message.to});
            return;
        }
        let pushable = rows.length > 0 && rows[0].is_online;
        let notifyMessage = JSON.stringify({type: 'system_msg', data: message.content});
        let userStatus = rows[0];
        // 保存该条推送信息
        smRepo.save(message.to,
            message.contentType,
            message.title,
            message.summary,
            message.content,
            function (err, result) {
                if (err) {
                    log.error("Save system notify message failed, ", err);
                    res.status(500).send({message: "Save system notify message failed."});
                } else {
                    // 先结束网络连接,再处理后续操作,减少客户端等待
                    res.status(200).send();
                    // 保存通知到数据库中
                    nmRepo.save(message.to,
                        message.contentType,
                        message.title,
                        message.summary,
                        notifyMessage,
                        pushable,
                        function (err, result) {
                            if (err) {
                                log.error("Save system notify message failed, ", err);
                                res.status(500).send({message: "Save system notify message failed."});
                            } else {
                                if (pushable) {
                                    if (userStatus.platform === PLATFORMS.iOS) {
                                        getui.pushAPN(message.to, userStatus.token, message.contentType, message.title, message.content, notifyMessage,
                                            function (err, result) {
                                                err != null ? console.log(err) : console.log(result);
                                            });
                                    } else if (userStatus.platform === PLATFORMS.Android) {
                                        getui.pushAndroid(userStatus.client_id, message.contentType, message.title, message.content, notifyMessage, userStatus.status,
                                            function (err, result) {
                                                err != null ? console.log(err) : console.log(result);
                                            });
                                    }
                                }
                            }
                        });
                }
            });
    });
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    doctor.sendSystemMessage(message);
});
/**
@ -166,119 +98,19 @@ router.post(APIv1.Chats.PM, function (req, res) {
        throw {httpStatus: 406, message: testing.message};
    }
    patient.sendMessage(message.to, message);
    res.status(200).send({});
    return;
    // 保存消息
    let tempContent = message.contentType === CONTENT_TYPES.Article ? JSON.stringify(message.content) : message.content;
    pmRepo.save(message.to, message.from, message.contentType, tempContent, function (err, result) {
        if (err) {
            res.status(500).send({message: 'Save private message failed.'});
            return;
        }
        // 结束网络连接,后续操作继续执行
        pmRepo.findOneMessage(result.insertId, function (err, msg) {
            if (err) {
                res.status(500).send({message: "Save private message success, but return last message failed."});
                return;
            }
            let feedback = fillMessages(msg);
            res.status(200).send(feedback);
            patient.isPatientCode(
                message.to,
                function () {
                    // 推送给患者
                    patient.sendMessage(message.to, 1, feedback);
                },
                function () {
                    // 推送给医生。获取对方状态,即对端的系统平台,token等信息,并推送通知消息给对端
                    doctorRepo.isExist(message.to, function (err, rows) {
                        if (err) {
                            console.log('Lookup receiving users failed or user not found: ', err);
                            return;
                        }
                        doctorRepo.getUserStatus(message.to, function (err, result) {
                            if (err) {
                                log.error('Get target user status for private message failed: ' + message.to);
                                return;
                            }
                            // 构建通知消息
                            let title = '新消息';
                            let content = '';
                            if (message.contentType === CONTENT_TYPES.PlainText) {
                                content = message.content;
                            } else if (message.contentType === CONTENT_TYPES.Image) {
                                content = '[图片]';
                            } else if (message.contentType === CONTENT_TYPES.Audio) {
                                content = '[语音]';
                            } else {
                                content = '接收到一条新消息';
                            }
                            let target = result[0];
                            let isOnline = result.length > 0 && target.is_online === 1;
                            let notifyMessage = JSON.stringify({type: 'p2p_msg', from_uid: message.from});
                            // 保存通知消息到数据库中并根据用户在线状态推送此消息
                            nmRepo.save(message.to, message.contentType, title, content, notifyMessage, isOnline, function (err, result) {
                                if (err) {
                                    log.error('Save private notify message failed, ', err);
                                    return;
                                }
                                if (!isOnline) return;
                                if (target.platform === PLATFORMS.iOS) {
                                    getui.pushAPN(message.to,
                                        target.token,
                                        message.contentType,
                                        title,
                                        content,
                                        notifyMessage,
                                        function (err, result) {
                                            if (err != null) {
                                                console.log(err);
                                            } else {
                                                console.log(result);
                                            }
                                        });
                                } else if (target.platform === PLATFORMS.Android) {
                                    getui.pushAndroid(target.client_id,
                                        message.contentType,
                                        title,
                                        content,
                                        notifyMessage,
                                        target.status,
                                        function (err, result) {
                                            if (err != null) {
                                                console.log(err);
                                            } else {
                                                console.log(result);
                                            }
                                        });
                                }
                            });
                        });
                    });
                });
        });
    // 消息处理,患者与医生分开发送
    Patient.isPatientCode(message.to,
        function () {
            let patient = new Patient();
            controllerUtil.regModelEventHandler(patient, res);
        // 更新自身的聊天统计信息
        statsRepo.updatePrivateChatSummary(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
            if (err) log.error(err);
        });
            patient.sendMessage(message);
        }, function () {
            let doctor = new Doctor();
            controllerUtil.regModelEventHandler(doctor, res);
        // 更新对端的聊天统计信息
        statsRepo.updatePrivateChatSummary(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
            if (err) log.error(err);
            doctor.sendMessage(message);
        });
    });
});
/**
@ -314,186 +146,10 @@ router.post(APIv1.Chats.GM, function (req, res) {
    }
    // 消息处理
    groupRepo.isGroupMember(message.group, message.groupType, message.from, function (err, result) {
        if (err) {
            log.error('Check group member failed: ', err);
            res.status(500).send({message: 'Check group member failed.'});
            return;
        }
        if (result.length == 0) {
            res.status(404).send({message: 'Member with id "' + message.from + '" is not in group "' + message.group + '"'});
            return;
        }
        // 保存群组消息
        gmRepo.save(message.from, message.group, message.at, message.contentType, message.content, function (err, insertedRow) {
            if (err) {
                log.error('Save group message failed: ', err);
                res.status(500).send({message: 'Save group message failed.'});
                return;
            }
            gmRepo.findOneMessage(insertedRow.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."});
                }
                // 关闭网络连接后执行后续操作
                let feedback = fillMessages(groupMsg);
                res.status(200).send(feedback);
                // 推送通知消息给群组成员
                groupRepo.getMembers(message.group, message.groupType, function (err, members) {
                    if (err) {
                        log.error('Get group members failed: ', err);
                        return;
                    }
                    if (members.length == 0) {
                        log.warn('No members in group ', message.group,
                            message.groupType === GROUP_TYPE.AdminTeam ? " of admin team." : "of discussion group.");
                        return;
                    }
                    // 逐个推送通知,患者与医生推送方式不一样
                    for (let i = 0; i < members.length; i++) {
                        let member = members[i];
                        if (member.user_id === message.from) continue;
                        (function (user_id) {
                            patient.isPatientCode(user_id,
                                function () {
                                    patient.sendMessage(user_id, 2, feedback);
                                },
                                function () {
                                    doctorRepo.getUserStatus(user_id, function (err, result) {
                                        if (err) {
                                            console.error('Get group member status failed: ', err);
                                            return;
                                        }
                                        let title = '';
                                        let content = '';
                                        if (message.contentType === CONTENT_TYPES.PlainText) {
                                            title = '群组消息';
                                            content = message.content;
                                        } else if (message.contentType === CONTENT_TYPES.Image) {
                                            title = '群组消息';
                                            content = '[图片]';
                                        } else if (message.contentType === CONTENT_TYPES.Audio) {
                                            title = '群组消息';
                                            content = '[语音]';
                                        } else {
                                            title = '群组消息';
                                            content = '接收到一条新消息';
                                        }
                                        let pushable = result.length > 0 && result[0].is_online === 1;
                                        let notifyMessage = JSON.stringify({type: 'group_msg', gid: message.group});
                                        // 发送并保存通知到数据库中
                                        if (pushable) {
                                            let userStatus = result[0];
                                            if (userStatus.platform === PLATFORMS.iOS) {
                                                getui.pushAPN(user_id,
                                                    userStatus.token,
                                                    message.contentType,
                                                    title,
                                                    content,
                                                    notifyMessage,
                                                    function (err, result) {
                                                        err != null ? console.error(err) : console.log(result);
                                                        // 这段代码重复
                                                        nmRepo.save(user_id,
                                                            message.contentType,
                                                            title,
                                                            content,
                                                            notifyMessage,
                                                            err != null ? 0 : 1,
                                                            function (err, result) {
                                                                if (err) {
                                                                    console.log('Save group notify message failed: ', err);
                                                                } else {
                                                                }
                                                            });
                                                    });
                                            } else if (userStatus.platform === PLATFORMS.Android) {
                                                getui.pushAndroid(data.client_id,
                                                    message.contentType,
                                                    title,
                                                    content,
                                                    notifyMessage,
                                                    userStatus.status,
                                                    function (err, result) {
                                                        err != null ? console.error(err) : console.log(result);
                                                        // 这段代码重复
                                                        nmRepo.save(user_id,
                                                            message.contentType,
                                                            title,
                                                            content,
                                                            notifyMessage,
                                                            err != null ? 0 : 1,
                                                            function (err, result) {
                                                                if (err) {
                                                                    console.log('Save group notify message failed: ', err);
                                                                } else {
                                                                }
                                                            });
                                                    });
                                            }
                                        } else {
                                            // 这段代码重复
                                            nmRepo.save(user_id,
                                                message.contentType,
                                                title,
                                                content,
                                                notifyMessage,
                                                0,
                                                function (err, result) {
                                                    if (err) {
                                                        console.log('Save group notify message failed: ', err);
                                                    } else {
                                                    }
                                                });
                                        }
                                    });
                                    // 统计'@'信息
                                    let at = message.at == user_id ? 1 : 0;
                                    statsRepo.updateGroupChatSummary(user_id,
                                        message.group,
                                        message.from,
                                        at,
                                        message.contentType,
                                        message.content,
                                        true,
                                        function (err, result) {
                                            if (err) console.log(err);
                                        });
                                });
                        })(member.user_id);
                    }
                });
            });
            // 更新组内统计信息
            statsRepo.updateGroupChatSummary(message.from, message.group, message.from, 0, message.contentType, message.content, false, function (err, result) {
                if (err) log.error(err);
            });
        });
    });
    let group = new Group();
    controllerUtil.regModelEventHandler(group, res);
    group.sendMessage(message);
});
//--------------------------------------------------------------//
@ -512,109 +168,10 @@ router.get(APIv1.Chats.List, function (req, res) {
        throw {httpStatus: 406, message: 'Missing fields.'};
    }
    // 与患者的私信
    pmRepo.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;
        }
        let chats = {patients: [], doctors: [], groups: []};
        for (let i = 0; i < patients.length; i++) {
            let 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)
            });
        }
        // 含有患者的群
        gmRepo.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 (let i = 0; i < groups.length; i++) {
                let group = groups[i];
                // 过滤掉医生间的求助团队
                if (group.group_type === 2) continue;
                //查找医生在讨论组的最新的消息记录数
                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)
                });
            }
            // 医生间的私聊
            pmRepo.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;
                }
                for (let i = 0; i < doctors.length; i++) {
                    let 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)
                    });
                }
                // 获取医生间的组
                gmRepo.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 (let i = 0; i < groups.length; i++) {
                        let group = groups[i];
                        chats.groups.push({
                            code: group.code,
                            name: group.name,
                            groupType: group.group_type, // 行政团队 or 求助
                            newMessageCount: group.new_msg_count,
                            lastContentType: group.last_content_type,
                            lastContent: group.last_content,
                            timestamp: objectUtil.timestampToLong(group.timestamp)
                        });
                    }
                    res.status(200).send(chats);
                });
            });
        })
    });
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    doctor.getChatList(userId);
});
/**
@ -629,58 +186,10 @@ router.get(APIv1.Chats.ListWithPatient, function (req, res) {
        throw {httpStatus: 406, message: 'Missing fields.'};
    }
    pmRepo.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;
        }
        let chats = {patients: [], groups: []};
        for (let i = 0; i < patients.length; i++) {
            let 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)
            });
        }
        gmRepo.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 (let i = 0; i < groups.length; i++) {
                let group = groups[i];
                // 过滤掉医生间的求助团队
                if (group.group_type === 2) continue;
                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);
        })
    });
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    doctor.getChatsListWithPatient(userId);
});
/**
@ -695,55 +204,10 @@ router.get(APIv1.Chats.ListWithDoctor, function (req, res) {
        throw {httpStatus: 406, message: 'Missing fields.'};
    }
    // 先获取医生间的私聊
    pmRepo.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;
        }
        let chats = {doctors: [], groups: []};
        for (let i = 0; i < doctors.length; i++) {
            let 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)
            });
        }
        // 再获取医生间的组
        gmRepo.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 (let i = 0; i < groups.length; i++) {
                let group = groups[i];
                chats.groups.push({
                    code: group.code,
                    name: group.name,
                    groupType: group.group_type, // 行政团队 or 求助
                    newMessageCount: group.new_msg_count,
                    lastContentType: group.last_content_type,
                    lastContent: group.last_content,
                    timestamp: objectUtil.timestampToLong(group.timestamp)
                });
            }
            res.status(200).send(chats);
        });
    });
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    doctor.getChatListWithDoctor(userId);
});
/**
@ -758,8 +222,8 @@ router.get(APIv1.Chats.ListWithDoctor, function (req, res) {
 *  days: 最近天数
 */
router.get(APIv1.Chats.Recent, function (req, res) {
    var userId = req.query.user_id;
    var days = req.query.days;
    let userId = req.query.user_id;
    let days = req.query.days;
    if (userId === null) {
        throw {httpStatus: 406, message: 'Missing field: user_id'};
    }
@ -768,48 +232,10 @@ router.get(APIv1.Chats.Recent, function (req, res) {
        throw {httpStatus: 406, message: 'Missing field: days'};
    }
    statsRepo.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);
    });
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    doctor.getRecentChatList(userId);
});
/**
@ -828,13 +254,13 @@ router.get(APIv1.Chats.Recent, function (req, res) {
 *  /chats/pm?user_id=sand&peer_id=Rose&content_type=2&message_start_id=10000&message_end_id=0&count=20&closed_interval=false
 */
router.get(APIv1.Chats.PM, function (req, res) {
    var userId = req.query.user_id;
    var peerId = req.query.peer_id;
    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);
    var closedInterval = (req.query.closed_interval != false && req.query.closed_interval === "true");
    let userId = req.query.user_id;
    let peerId = req.query.peer_id;
    let contentType = req.query.content_type;
    let msgStartId = !req.query.message_start_id ? MAX_INT : parseInt(req.query.message_start_id);
    let msgEndId = !req.query.message_end_id ? 0 : parseInt(req.query.message_end_id);
    let count = req.query.count === undefined ? DEFAULT_PAGE_SIZE : parseInt(req.query.count);
    let closedInterval = (req.query.closed_interval != false && req.query.closed_interval === "true");
    if (contentType !== undefined && parseInt(contentType) === CONTENT_TYPES.Image) count = DEFAULT_PAGE_SIZE;
@ -844,23 +270,10 @@ router.get(APIv1.Chats.PM, function (req, res) {
        throw {httpStatus: 400, message: "Missing field: user_id."};
    }
    pmRepo.findAllMessages(userId, peerId, contentType === undefined ? "1,2,3,5,6" : contentType, msgStartId, msgEndId, count, closedInterval, function (err, rows) {
        if (err) {
            log.error("Get private message failed, ", err);
            res.status(500).send({message: "Get private messages failed."});
            return;
        }
        var messages = fillMessages(rows);
        // 清空统计信息
        statsRepo.clearPrivateChatSummary(userId, peerId, function (err, result) {
            if (err) console.log(err);
        });
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
        res.status(200).send(messages);
    });
    doctor.getPrivateMessages(userId, peerId, contentType, msgStartId, msgEndId, count, closedInterval);
});
/**
@ -874,40 +287,17 @@ router.get(APIv1.Chats.PM, function (req, res) {
 *  /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;
    let userId = req.query.user_id;
    let peerId = req.query.peer_id;
    if (userId === undefined) {
        throw {httpStatus: 400, message: "Missing field: user_id."};
    }
    statsRepo.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;
        }
        pmRepo.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;
            }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
            var messages = fillMessages(rows);
            res.status(200).send(messages);
        });
    });
    doctor.getUnreadPrivateMessages(userId, peerId);
});
/**
@ -923,12 +313,12 @@ router.get(APIv1.Chats.PMUnread, function (req, res) {
 *  /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 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);
    let groupId = req.query.group_id;
    let memberId = req.query.user_id;
    let contentType = req.query.content_type;
    let msgStartId = !req.query.message_start_id ? MAX_INT : parseInt(req.query.message_start_id);
    let msgEndId = !req.query.message_end_id ? 0 : parseInt(req.query.message_end_id);
    let count = req.query.count === undefined ? DEFAULT_PAGE_SIZE : parseInt(req.query.count);
    if (groupId === undefined) {
        throw {httpStatus: 400, message: "Missing field: group_id."};
@ -938,23 +328,10 @@ router.get(APIv1.Chats.GM, function (req, res) {
    if (req.query.message_start_id && req.query.message_end_id) count = 100000;
    gmRepo.findAllMessages(groupId, !contentType ? "1,2,3,5,6" : contentType, msgStartId, msgEndId, count, function (err, rows) {
        if (err) {
            console.log('Get group message failed: ', err);
            res.status(500).send({message: 'Get group message failed.'});
            return;
        }
        var messages = fillMessages(rows);
    let group = new Group();
    controllerUtil.regModelEventHandler(group, res);
        // 清空统计信息
        statsRepo.clearGroupChatSummary(userId, groupId, function (err, result) {
            if (err) console.log(err);
        });
        res.status(200).send(messages);
    });
    group.getMessages(groupId, memberId, contentType, msgStartId, msgEndId, count);
});
/**
@ -964,10 +341,10 @@ router.get(APIv1.Chats.GM, function (req, res) {
 *  /chats/gm/unread?group_id=discussionGroupId&user_id=sand
 */
router.get(APIv1.Chats.GMUnread, function (req, res) {
    var userId = req.query.user_id;
    var groupId = req.query.group_id;
    let memberId = req.query.user_id;
    let groupId = req.query.group_id;
    if (userId === undefined) {
    if (memberId === undefined) {
        throw {httpStatus: 400, message: "Missing field: user_id."};
    }
@ -975,64 +352,12 @@ router.get(APIv1.Chats.GMUnread, function (req, res) {
        throw {httpStatus: 400, message: "Missing field: group_id."};
    }
    statsRepo.getGroupChatSummary(userId, groupId, function (err, summary) {
        if (err) {
            log.error("Get unread group messages failed: ", err);
            res.status(500).send({message: "Get unread group messages failed."});
            return;
        }
        var messages = {startId: 0, count: 0, records: []};
        if (summary.length == 0 || summary[0].new_msg_count === 0) {
            res.status(200).send(messages);
            return;
        }
        messages.count = summary[0].new_msg_count;
        gmRepo.findUnread(groupId, MAX_INT, messages.count, function (err, rows) {
            if (err) {
                log.error("Get unread group messages failed: ", err);
                res.status(500).send({message: "Get unread group messages failed."});
                return;
            }
            var messages = fillMessages(rows);
    let group = new Group();
    controllerUtil.regModelEventHandler(group, res);
            res.status(200).send(messages);
        });
    });
    group.getUnreadMessages(groupId, memberId);
});
/**
 * 将消息的返回结果合并成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;
}
//--------------------------------------------------------------//
//----------------------------消息统计----------------------------//
//--------------------------------------------------------------//
@ -1047,32 +372,15 @@ function fillMessages(rows) {
 *  user_id:医生ID
 */
router.get(APIv1.Chats.GMUnreadCount, function (req, res) {
    var userId = req.query.user_id;
    if (userId === null) {
    let memberId = req.query.user_id;
    if (memberId === null) {
        throw {httpStatus: 406, message: 'Missing fields.'};
    }
    statsRepo.getGroupChatAllUnReadCount(userId, function (err, result) {
        if (err) {
            console.log('Get all unread messages failed: ', err);
    let group = new Group();
    controllerUtil.regModelEventHandler(group, res);
            res.status(500).send({message: 'Get all unread messages failed.'});
        }
        var data = {
            userId: userId,
            messageType: 2,
            newMessageCount: 0
        };
        if (result.length > 0) {
            for (var index = 0; index < result.length; index++) {
                data.newMessageCount += result[index].new_msg_count;
            }
        }
        res.send(data);
    });
    group.getUnreadMessageCount(memberId);
});
/**
@ -1085,44 +393,16 @@ router.get(APIv1.Chats.GMUnreadCount, function (req, res) {
 *  group_id:群组id
 */
router.get(APIv1.Chats.GMStats, function (req, res) {
    var userId = req.query.user_id;
    var groupId = req.query.group_id;
    if (userId === null || groupId === null) {
    let memberId = req.query.user_id;
    let groupId = req.query.group_id;
    if (memberId === null || groupId === null) {
        throw {httpStatus: 406, message: 'Miss fields.'};
    }
    statsRepo.getGroupChatSummary(userId, groupId, function (err, result) {
        if (err) {
            console.log('Get group stats failed: ', err);
            res.status(500).send({message: 'Get group stats failed.'});
            return;
        }
        var data = {
            userId: userId,
            from: "",
            groupId: groupId,
            atMe: 0,
            lastContentType: 1,
            lastContent: "",
            newMessageCount: 0,
            timestamp: 0
        };
        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)
        }
        res.status(200).send(data);
    });
    let group = new Group();
    controllerUtil.regModelEventHandler(group, res);
    group.getChatSummary(groupId, memberId);
});
/**
@ -1135,41 +415,16 @@ router.get(APIv1.Chats.GMStats, function (req, res) {
 *  peer_id:聊天对端id
 */
router.get(APIv1.Chats.PMStats, function (req, res) {
    var userId = req.query.user_id;
    var peerId = req.query.peer_id;
    let userId = req.query.user_id;
    let peerId = req.query.peer_id;
    if (userId == null || peerId == null) {
        throw {httpStatus: 406, message: "Missing fields."};
    }
    statsRepo.getPrivateChatSummary(userId, peerId, function (err, result) {
        if (err) {
            console.log("Get private messages stats failed: ", err);
            res.status(500).send({message: "Get private messages stats failed."});
        }
        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)
        }
        res.status(0).send(data);
    });
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    doctor.getChatSummary(userId, peerId);
});
/**
@ -1181,24 +436,12 @@ router.get(APIv1.Chats.PMStats, function (req, res) {
 * uid:信息所有者id
 */
router.get(APIv1.Chats.PMUnreadCount, function (req, res) {
    var userId = req.query.user_id;
    statsRepo.getPrivateChatAllUnReadCount(userId, function (err, result) {
        if (err) {
            console.log("Get unread private message count failed: ", err);
            res.status(500).send({message: "Get unread private message count failed."});
        }
    let userId = req.query.user_id;
        var data = {userId: userId, messageType: 1, newMessageCount: 0};
        if (result.length > 0) {
            for (var i = 0; i < result.length; i++) {
                data.newMessageCount += result[i].new_msg_count;
            }
        }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
        res.send(data);
    });
    doctor.getUnreadPrivateMessages(userId);
});
/**
@ -1211,27 +454,15 @@ router.get(APIv1.Chats.PMUnreadCount, function (req, res) {
 *  user_id:信息所有者id
 */
router.get(APIv1.Chats.UnreadMsgCount, function (req, res) {
    var userId = req.query.user_id;
    let userId = req.query.user_id;
    if (userId === null) {
        throw {httpStatus: 406, message: "Missing fields."};
    }
    statsRepo.getChatAllUnReadCount(userId, function (err, result) {
        if (err) {
            console.error("Get all unread message count failed: ", err);
            res.status(500).send({message: "Get all unread message count failed."});
        }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
        var data = {userId: userId, messageType: 0, newMessageCount: 0};
        if (result.length > 0) {
            for (var index = 0; index < result.length; index++) {
                data.newMessageCount += result[index].new_msg_count;
            }
        }
        res.send(data);
    });
    doctor.getAllUnreadMessageCount(userId);
});
@ -1245,66 +476,18 @@ router.get(APIv1.Chats.UnreadMsgCount, function (req, res) {
 *  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;
    let userId = req.query.user_id;
    let userRole = req.query.user_role;
    let 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."};
    searchRepo.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: objectUtil.timestampToLong(patient.birthday),
                avatar: patient.photo === null ? "" : patient.photo
            });
        }
        searchRepo.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 = objectUtil.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);
        });
    });
    let search = new Search();
    controllerUtil.regModelEventHandler(search, res);
    search.searchAboutPatient(userId, userRole, keyword);
});
/**
@ -1317,130 +500,16 @@ router.get(APIv1.Chats.SearchAboutPatient, function (req, res) {
 *  keywords: 关键词
 */
router.get(APIv1.Chats.SearchAboutDoctor, function (req, res) {
    var userId = req.query.user_id;
    var keyword = req.query.keyword;
    let userId = req.query.user_id;
    let keyword = req.query.keyword;
    if (!userId) throw {httpStatus: 406, message: "Missing fields: user_id."};
    if (!keyword) throw {httpStatus: 406, message: "Missing fields: keyword."};
    // 搜索医生
    searchRepo.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
            });
        }
        // 搜索讨论组名称及成员名称
        searchRepo.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
                });
            }
            // 搜索医生间的私信
            searchRepo.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
                    });
                }
                // 搜索医生间的讨论组消息
                searchRepo.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);
                });
            });
        });
    });
    let search = new Search();
    controllerUtil.regModelEventHandler(search, res);
    search.searchAboutDoctor(userId, keyword);
});
/**
@ -1450,58 +519,13 @@ router.get(APIv1.Chats.SearchAboutDoctor, function (req, res) {
 *  /chats/message?id=1234&type=1
 */
router.get(APIv1.Chats.Message, function (req, res) {
    var messageId = req.query.id;
    var messageType = req.query.type;
    // 私信
    if (messageType == 1) {
        pmRepo.findOneMessage(messageId, function (err, result) {
            if (err) {
                log.error("Get message failed: ", err);
                res.status(500).send({message: "Get message failed."});
                return;
            }
            if (result.length == 0) {
                res.status(404).send({message: "Message not found."});
                return;
            }
            res.status(200).send({
                id: result[0].msg_id,
                from: result[0].from_uid,
                to: result[0].to_uid,
                contentType: result[0].type,
                content: result[0].content,
                timestamp: objectUtil.timestampToLong(result[0].timestamp)
            });
        })
    } else {
        gmRepo.findOneMessage(messageId, function (err, result) {
            if (err) {
                log.error("Get message failed: ", err);
                res.status(500).send({message: "Get message failed."});
                return;
            }
            if (result.length == 0) {
                res.status(404).send({message: "Message not found."});
                return;
            }
            res.status(200).send({
                id: result[0].msg_id,
                from: result[0].from_uid,
                at: result[0].at_uid,
                groupId: result[0].to_gid,
                contentType: result[0].type,
                content: result[0].content,
                timestamp: objectUtil.timestampToLong(result[0].timestamp)
            });
        });
    }
    let messageId = req.query.id;
    let messageType = req.query.type;
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    doctor.getMessage(messageId, messageType);
});
/**
@ -1511,8 +535,8 @@ router.get(APIv1.Chats.Message, function (req, res) {
 *  /chats/pm/finished?user_id=sand&peer_id=rose
 */
router.get(APIv1.Chats.PMFinished, function (req, res) {
    var doctorId = req.query.doctor_id;
    var patientId = req.query.patient_id;
    let doctorId = req.query.doctor_id;
    let patientId = req.query.patient_id;
    if (!doctorId) {
        throw {httpStatus: 406, message: "Missing field: doctor_id"};
    }
@ -1521,25 +545,10 @@ router.get(APIv1.Chats.PMFinished, function (req, res) {
        throw {httpStatus: 406, message: "Missing field: patient_id"};
    }
    pmRepo.isCurrentSessionFinished(doctorId, patientId, function (err, result) {
        if (err) {
            log.error("Get session finish status failed: ", err);
            throw {httpStatus: 500, message: "Get session finish status failed."};
        }
        var data = {finished: true, consultId: ''};
        if (result.length > 0) {
            var finishRow = result[0];
            data.finished = finishRow.finished === 1;
            if (!data.finished) {
                data.consultId = finishRow.consult_id;
            }
        }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
        res.status(200).send(data);
    })
    doctor.isConsultFinished(doctorId, patientId);
});
module.exports = router;

+ 15 - 36
src/doctor/endpoints/groups.endpoint.js

@ -3,12 +3,14 @@
 */
"use strict";
var express = require("express");
var router = express.Router();
let express = require("express");
let router = express.Router();
var APIv1 = require('../include/endpoints').APIv1;
const APIv1 = require('../include/endpoints').APIv1;
const MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
var groupRepo = require('../repository/group.repo.js');
//let groupRepo = require('../repository/group.repo.js');
let Group = require('../models/group');
/**
 * 获取团队成员。
@ -26,7 +28,7 @@ router.get(APIv1.Groups.Members, function (req, res) {
});
/**
 * 获取成员头像。每个组最多返回5个成员的头像。
 * 获取成员头像。
 *
 * 请求URL:
 *  /groups/member/avatars?groups=433,10,63
@ -40,39 +42,16 @@ router.get(APIv1.Groups.MembersAvatar, function (req, res) {
    var tokens = groups.split(",");
    groups = "'" + tokens.join("', '") + "'";
    var avatars = [];
    groupRepo.getMembersAvatar(groups, function (err, members) {
        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 lastGroup;
        var lastGroupCode = '';
        for (var i = 0; i < members.length; ++i) {
            var member = members[i];
            var groupCode = member.g_code;
            if (lastGroupCode !== groupCode) {
                lastGroupCode = groupCode;
                lastGroup = {groupCode: groupCode, avatars: []};
                if(lastGroupCode !== ''){
                    avatars.push(lastGroup);
                }
            }
            lastGroup.avatars.push({
                code: member.code,
                name: member.name,
                avatar: member.photo === null ? "" : member.photo,
                role: member.type
            });
        }
    let group = new Group();
    group.on(MODEL_EVENTS.OK, function (data) {
        res.status(200).send(data);
    });
        res.status(200).send(avatars);
    group.on(MODEL_EVENTS.Error, function (message) {
        res.status(500).send(message);
    });
    group.getMemberAvatars(groups);
});
module.exports = router;

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

@ -14,8 +14,8 @@ let objectUtil = require('../util/objectUtil');
let UserStatus = require('../models/user.status');
let APIv1 = require('../include/endpoints').APIv1;
let MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
const APIv1 = require('../include/endpoints').APIv1;
const MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
/**
 * 登录。用户登录后,更新数据库中的在线状态。

+ 1 - 1
src/doctor/include/endpoints.js

@ -24,7 +24,7 @@ const APIv1 = {
        // 所有未读消息数
        UnreadMsgCount: '/unread_count',
        Message: '/message',                    // 当条消息
        Message: '/message',                    // 单条消息
        // 私信
        PM: '/pm',

+ 2 - 2
src/doctor/models/auth/token.js

@ -11,13 +11,13 @@
"use strict";
let crypto = require('crypto');
let hmac = crypto.createHmac('sha1', 'theskyisblue');
class Token{
    constructor(userId, clientId, platform){
        if(!userId || !clientId || !platform) throw {message: "Parameters must not be null."};
        hmac.update(userId + "->" + clientId + "->" + platform);
        let hmac = crypto.createHmac('sha1', 'theskyisblue');
        hmac.update(userId + "->" + clientId + "->" + platform + "->" + new Date().toString());
        let cipherText = hmac.digest('hex');
        this._userId = userId;

+ 172 - 146
src/doctor/models/doctor.js

@ -4,21 +4,22 @@
"use strict";
let log = require("../util/log.js");
let modelUtil = require('../util/modelUtil');
let getui = require('getui');
let BaseModel = require('./base.model');
let userRepo = require('../repository/doctor.repo.js');
let doctorRepo = require('../repository/doctor.repo.js');
let gmRepo = require('../repository/group.msg.repo');
let pmRepo = require('../repository/private.msg.repo');
let nmRepo = require("../repository/notify.msg.repo");
let smRepo = require("../repository/system.msg.repo.js");
let statsRepo = require("../repository/stats.msg.repo");
let objectUtil = require("../util/objectUtil.js");
let modelUtil = require('../util/modelUtil');
let CONTENT_TYPES = require('../include/commons').CONTENT_TYPE;
let PLATFORMS = require('../include/commons').PLATFORM;
const CONTENT_TYPES = require('../include/commons').CONTENT_TYPE;
const PLATFORMS = require('../include/commons').PLATFORM;
class Doctor extends BaseModel{
class Doctor extends BaseModel {
    constructor() {
        super();
    }
@ -30,118 +31,143 @@ class Doctor extends BaseModel{
     */
    sendMessage(message) {
        let self = this;
        userRepo.isExist(message.to, function (err, rows) {
        let tempContent = message.contentType === CONTENT_TYPES.Article ? JSON.stringify(message.content) : message.content;
        pmRepo.save(message.to, message.from, message.contentType, tempContent, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Lookup receiving users failed', err);
                modelUtil.emitDbError(self.eventEmitter, 'Save private message failed', err);
                return;
            }
            if (rows.length == 0) {
                modelUtil.emitDataNotFound(self.eventEmitter, {});
                return;
            }
            // 返回新插入的消息数据,并推送
            pmRepo.findOneMessage(result.insertId, function (err, msg) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Save private message success, but return last message failed', err);
                    return;
                }
                // 先结束网络连接,再推送给客户端
                modelUtil.emitData(self.eventEmitter, Doctor.fillMessages(msg));
                Doctor.pushMessage(message, 'p2p_msg');
            });
            // 更新自身的聊天统计信息
            statsRepo.updatePrivateChatSummary(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
                if (err) log.error(err);
            });
            // 更新对端的聊天统计信息
            statsRepo.updatePrivateChatSummary(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
                if (err) log.error(err);
            });
        });
    }
            // 保存消息
            let tempContent = message.contentType === CONTENT_TYPES.Article ? JSON.stringify(message.content) : message.content;
            pmRepo.save(message.to, message.from, message.contentType, tempContent, function (err, result) {
    /**
     * 向医生发送系统消息。
     *
     * @param message
     */
    sendSystemMessage(message) {
        let self = this;
        smRepo.save(message.to,
            message.contentType,
            message.title,
            message.summary,
            message.content,
            function (err, result) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Save private message failed.', err);
                    modelUtil.emitDbError(self.eventEmitter, "Save system message failed", err);
                    return;
                }
                // 返回发送成功后的消息记录,控制器可选择结束网络连接
                pmRepo.findOneMessage(result.insertId, function (err, rows) {
                    if (err) {
                        modelUtil.emitDbError(self.eventEmitter, 'Save private message success, but return last message failed', err);
                    } else {
                        modelUtil.emitData(self._eventEmitter, fillMessages(rows));
                    }
                });
                // 先结束网络连接,再推送给客户端
                modelUtil.emitData(self.eventEmitter, {});
                // 更新自身的聊天统计信息
                statsRepo.updatePrivateChatSummary(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
                    if (err) modelUtil.logError(null, err);
                });
                Doctor.pushMessage(message, 'system_msg');
            });
    }
                // 更新对端的聊天统计信息
                statsRepo.updatePrivateChatSummary(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
                    if (err) modelUtil.logError(null, err);
                });
    /**
     * 推送消息。
     *
     * @param message
     * @param channel
     */
    static pushMessage(message, channel){
        doctorRepo.getUserStatus(message.to, function (err, result) {
            if (err) {
                log.error('Lookup notify message receiver failed: ' + message.to);
                return;
            }
                // 获取对方状态,即对端的系统平台,token等信息,并推送通知消息给对端
                userRepo.getUserStatus(message.to, function (err, result) {
                    if (err) {
                        modelUtil.logError('Get target user status for private message failed: ' + message.to, err);
                        return;
                    }
            if (result.length == 0) {
                log.warn('Notify message receiver is not found: ', message.to);
                return;
            }
                    // 构建通知消息
                    let title = '新消息';
                    let content = '';
                    if (message.contentType === CONTENT_TYPES.PlainText) {
                        content = message.content;
                    } else if (message.contentType === CONTENT_TYPES.Image) {
                        content = '[图片]';
                    } else if (message.contentType === CONTENT_TYPES.Audio) {
                        content = '[语音]';
                    } else {
                        content = '接收到一条新消息';
                    }
            let userStatus = result[0];
            let isOnline = result.length > 0 && userStatus.is_online === 1;
            // 构建通知消息
            let notifyMessage = {type: channel, data: message.content};
            if(message.from) notifyMessage.from_uid = message.from;
            if(message.gid) notifyMessage.gid = message.gid;
            let title = '新消息';
            let content = message.content;
            if (message.contentType === CONTENT_TYPES.Image) {
                content = '[图片]';
            } else if (message.contentType === CONTENT_TYPES.Audio) {
                content = '[语音]';
            } else if(message.contentType > 3) {
                content = '您有一条新消息';
            }
                    let isOnline = false;
                    let target;
                    if (result.length > 0) {
                        target = result[0];
                        if (target.is_online) {
                            isOnline = true;
                        }
                    }
            // 保存通知消息到数据库中,并根据用户在线状态推送此消息
            nmRepo.save(message.to, message.contentType, title, content, JSON.stringify(notifyMessage), isOnline, function (err, result) {
                if (err) {
                    log.error('Save notify message failed, ', err);
                    return;
                }
                    let notifyMessage = JSON.stringify({type: 'p2p_msg', from_uid: message.from});
                if (!isOnline) return;
                    // 保存通知消息到数据库中并根据用户在线状态推送此消息
                    nmRepo.save(message.to, message.contentType, title, content, notifyMessage, isOnline, function (err, result) {
                        if (err) {
                            log.error('Save private notify message failed, ', err);
                Doctor.pushToClient(message.to, userStatus.clientId, userStatus.status, userStatus.token, message.contentType,
                    title, content, notifyMessage, userStatus.platform, function (err, result) {
                        if (err != null) {
                            console.log(err);
                        } else {
                            if (isOnline === true) {
                                if (target.platform === PLATFORMS.iOS) {
                                    getui.pushAPN(message.to,
                                        target.token,
                                        message.contentType,
                                        title,
                                        content,
                                        notifyMessage,
                                        function (err, result) {
                                            if (err != null) {
                                                console.log(err);
                                            } else {
                                                console.log(result);
                                            }
                                        });
                                } else if (target.platform === PLATFORMS.Android) {
                                    getui.pushAndroid(target.client_id,
                                        message.contentType,
                                        title,
                                        content,
                                        notifyMessage,
                                        target.status,
                                        function (err, result) {
                                            if (err != null) {
                                                console.log(err);
                                            } else {
                                                console.log(result);
                                            }
                                        });
                                }
                            }
                            console.log(result);
                        }
                    });
                });
            });
        });
    }
    /**
     * 推送消息给医生客户端。
     *
     * @param userId            用户ID
     * @param clientId          客户端设备ID
     * @param appStatus         客户端App状态
     * @param token
     * @param contentType
     * @param title
     * @param content
     * @param notifyMessage
     * @param platform
     * @param handler
     */
    static pushToClient(userId, clientId, appStatus, token, contentType, title, content, notifyMessage, platform, handler) {
        if (platform === PLATFORMS.iOS) {
            getui.pushAPN(userId, token, contentType, title, content, notifyMessage, handler);
        } else if (platform === PLATFORMS.Android) {
            getui.pushAndroid(clientId, contentType, title, content, notifyMessage, appStatus, handler);
        }
    }
    /**
     * 获取最近聊天的用户,组。
     */
@ -290,48 +316,49 @@ class Doctor extends BaseModel{
    }
    /**
     * 获取与医生的聊天列表,包括:点对点,参与的讨论组。
     *
     * @param userId
     * 获取与患者的聊天列表。
     */
    getChatListWithDoctor(userId) {
    getChatsListWithPatient(userId) {
        let self = this;
        // 先获取医生间的私聊
        pmRepo.findAllP2PWithDoctor(userId, function (err, doctors) {
        pmRepo.findAllP2PWithPatient(userId, function (err, patients) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get chat list with doctor failed', err);
                modelUtil.emitDbError(self.eventEmitter, 'Get chat list with patient failed', err);
                return;
            }
            let chats = {doctors: [], groups: []};
            for (let i = 0; i < doctors.length; i++) {
                let 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)
            let chats = {patients: [], groups: []};
            for (let i = 0; i < patients.length; i++) {
                let 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)
                });
            }
            // 再获取医生间的组
            gmRepo.findAllGroupsWithDoctor(userId, function (err, groups) {
            gmRepo.findAllGroupsWithPatient(userId, function (err, groups) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Get group list with doctor failed', err);
                    modelUtil.emitDbError(self.eventEmitter, 'Get group list with patient failed', err);
                    return;
                }
                for (let i = 0; i < groups.length; i++) {
                    let group = groups[i];
                    // 过滤掉医生间的求助团队
                    if (group.group_type === 2) continue;
                    chats.groups.push({
                        code: group.code,
                        name: group.name,
                        groupType: group.group_type, // 行政团队 or 求助
                        groupType: group.msg_type,
                        newMessageCount: group.new_msg_count,
                        lastContentType: group.last_content_type,
                        lastContent: group.last_content,
@ -340,54 +367,53 @@ class Doctor extends BaseModel{
                }
                modelUtil.emitData(self.eventEmitter, chats);
            });
            })
        });
    }
    /**
     * 获取与患者的聊天列表。
     * 获取与医生的聊天列表,包括:点对点,参与的讨论组。
     *
     * @param userId
     */
    getChatsListWithPatient(userId) {
    getChatListWithDoctor(userId) {
        let self = this;
        pmRepo.findAllP2PWithPatient(userId, function (err, patients) {
        // 先获取医生间的私聊
        pmRepo.findAllP2PWithDoctor(userId, function (err, doctors) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get chat list with patient failed', err);
                modelUtil.emitDbError(self.eventEmitter, 'Get chat list with doctor failed', err);
                return;
            }
            let chats = {patients: [], groups: []};
            for (let i = 0; i < patients.length; i++) {
                let 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)
            let chats = {doctors: [], groups: []};
            for (let i = 0; i < doctors.length; i++) {
                let 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)
                });
            }
            gmRepo.findAllGroupsWithPatient(userId, function (err, groups) {
            // 再获取医生间的组
            gmRepo.findAllGroupsWithDoctor(userId, function (err, groups) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Get group list with patient failed', err);
                    modelUtil.emitDbError(self.eventEmitter, 'Get group list with doctor failed', err);
                    return;
                }
                for (let i = 0; i < groups.length; i++) {
                    let group = groups[i];
                    // 过滤掉医生间的求助团队
                    if (group.group_type === 2) continue;
                    chats.groups.push({
                        code: group.code,
                        name: group.name,
                        groupType: group.msg_type,
                        groupType: group.group_type, // 行政团队 or 求助
                        newMessageCount: group.new_msg_count,
                        lastContentType: group.last_content_type,
                        lastContent: group.last_content,
@ -396,7 +422,7 @@ class Doctor extends BaseModel{
                }
                modelUtil.emitData(self.eventEmitter, chats);
            })
            });
        });
    }
@ -519,7 +545,7 @@ class Doctor extends BaseModel{
        let self = this;
        statsRepo.getPrivateChatSummary(userId, peerId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Get private messages stats failed", err);
                modelUtil.emitDbError(self.eventEmitter, "Get private messages statistic failed", err);
                return;
            }
@ -550,8 +576,8 @@ class Doctor extends BaseModel{
    getMessage(messageId, messageType) {
        let self = this;
        // 私信
        if (messageType == 1) {
            // 私信
            pmRepo.findOneMessage(messageId, function (err, result) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, "Get message failed", err);
@ -573,6 +599,7 @@ class Doctor extends BaseModel{
                });
            })
        } else {
            // 群信
            gmRepo.findOneMessage(messageId, function (err, result) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, "Get message failed", err);
@ -597,7 +624,6 @@ class Doctor extends BaseModel{
        }
    }
    /**
     * 判断与患者的最新咨询会话是否已经结束。
     */

+ 96 - 168
src/doctor/models/group.js

@ -11,14 +11,17 @@ let log = require("../util/log.js");
let modelUtil = require('../util/modelUtil');
let getui = require('getui');
let userRepo = require('../repository/doctor.repo.js');
let groupRepo = require('../repository/group.msg.repo');
let Patient = new require("../models/patient");
let Doctor = new require('../models/doctor');
let doctorRepo = require('../repository/doctor.repo.js');
let groupRepo = require('../repository/group.repo');
let gmRepo = require('../repository/group.msg.repo');
let nmRepo = require("../repository/notify.msg.repo");
let statsRepo = require("../repository/stats.msg.repo");
let objectUtil = require("../util/objectUtil.js");
class GroupMessage extends BaseModel{
class GroupMessage extends BaseModel {
    constructor() {
        super();
    }
@ -30,19 +33,18 @@ class GroupMessage extends BaseModel{
     */
    sendMessage(message) {
        let self = this;
        groupRepo.isGroupMember(message.group, message.groupType, message.from, function (err, result) {
        gmRepo.isGroupMember(message.group, message.groupType, message.from, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Check group member failed', err);
                return;
            }
            if (result.length == 0) {
                modelUtil.emitDataNotFound(self.eventEmitter,
                    'Member with id "' + message.from + '" is not in' + ' group "' + message.group + '"');
                modelUtil.emitDataNotFound(self.eventEmitter, 'Member with id "' + message.from + '" is not in group "' + message.group + '"');
                return;
            }
            // 保存群组消息
            gmRepo.save(message.from, message.group, message.at, message.contentType, message.content, function (err, insertedRow) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Save group message failed', err);
@ -51,148 +53,62 @@ class GroupMessage extends BaseModel{
                gmRepo.findOneMessage(insertedRow.insertId, function (err, groupMsg) {
                    if (err) {
                        modelUtil.emitDbError(self.eventEmitter, "Save group message success, but return this message failed", err);
                        modelUtil.emitDbError(self.eventEmitter, 'Save group message success, but return this message failed', err);
                        return;
                    }
                    // 返回新增加的消息,控制器可结束网络连接
                    modelUtil.emitData(self.eventEmitter, GroupMessage.fillMessages(groupMsg));
                });
                // 更新组内统计信息, 推送通知消息给群组成员
                statsRepo.updateGroupChatSummary(message.from, message.group, message.from, 0, message.contentType, message.content, false, function (err, result) {
                    if (err) modelUtil.emitDbError(self.eventEmitter, null, err);
                });
                groupRepo.getMembers(message.group, message.groupType, function (err, members) {
                    if (err) {
                        modelUtil.emitDbError(self.eventEmitter, 'Get group members failed: ', err);
                        return;
                    }
                    // 关闭网络连接后执行后续操作
                    let feedback = Patient.fillMessages(groupMsg);
                    modelUtil.emitData(self.eventEmitter, feedback);
                    if (members.length == 0) {
                        log.warn('No members in group ', message.group,
                            message.groupType === GROUP_TYPE.AdminTeam ? " of admin team." : "of discussion group.");
                    // 推送通知消息给群组成员
                    groupRepo.getMembers(message.group, message.groupType, function (err, members) {
                        if (err) {
                            log.error('Get group members failed: ', err);
                            return;
                        }
                        return;
                    }
                        if (members.length == 0) {
                            log.warn('No members in group ', message.group,
                                message.groupType === GROUP_TYPE.AdminTeam ? " of admin team." : "of discussion group.");
                    // 逐个推送通知
                    for (let i = 0; i < members.length; i++) {
                        let member = members[i];
                        if (member.user_id === message.from) {
                            continue;
                            return;
                        }
                        (function (user_id) {
                            userRepo.getUserStatus(user_id, function (err, result) {
                                if (err) {
                                    console.error('Get group member status failed: ', err);
                                    return;
                                }
                                let title = '';
                                let content = '';
                                if (message.contentType === CONTENT_TYPES.PlainText) {
                                    title = '群组消息';
                                    content = message.content;
                                } else if (message.contentType === CONTENT_TYPES.Image) {
                                    title = '群组消息';
                                    content = '[图片]';
                                } else if (message.contentType === CONTENT_TYPES.Audio) {
                                    title = '群组消息';
                                    content = '[语音]';
                                } else {
                                    title = '群组消息';
                                    content = '接收到一条新消息';
                                }
                                let isOnline = result.length > 0 && result[0].is_online === 1;
                                let notifyMessage = JSON.stringify({type: 'group_msg', gid: message.group});
                                // 发送并保存通知到数据库中
                                if (isOnline) {
                                    let userStatus = result[0];
                                    if (userStatus.platform === PLATFORMS.iOS) {
                                        getui.pushAPN(user_id,
                                            userStatus.token,
                        // 逐个推送通知,患者与医生推送方式不一样
                        for (let i = 0; i < members.length; i++) {
                            let member = members[i];
                            if (member.user_id === message.from) continue;
                            (function (userId) {
                                Patient.isPatientCode(userId,
                                    function () {
                                        Patient.sendMessage(userId, 2, feedback);
                                    },
                                    function () {
                                        Doctor.pushMessage(message, 'group_msg');
                                        // 更新用户组内消息摘要
                                        let at = message.at == userId ? 1 : 0;
                                        statsRepo.updateGroupChatSummary(userId,
                                            message.group,
                                            message.from,
                                            at,
                                            message.contentType,
                                            title,
                                            content,
                                            notifyMessage,
                                            message.content,
                                            true,
                                            function (err, result) {
                                                err != null ? console.error(err) : console.log(result);
                                                // 这段代码重复
                                                nmRepo.save(user_id,
                                                    message.contentType,
                                                    title,
                                                    content,
                                                    notifyMessage,
                                                    err != null ? 0 : 1,
                                                    function (err, result) {
                                                        if (err) {
                                                            console.log('Save group notify message failed: ', err);
                                                        } else {
                                                        }
                                                    });
                                                if (err) console.log(err);
                                            });
                                    } else if (userStatus.platform === PLATFORMS.Android) {
                                        getui.pushAndroid(data.client_id,
                                            message.contentType,
                                            title,
                                            content,
                                            notifyMessage,
                                            userStatus.status,
                                            function (err, result) {
                                                err != null ? console.error(err) : console.log(result);
                                                // 这段代码重复
                                                nmRepo.save(user_id,
                                                    message.contentType,
                                                    title,
                                                    content,
                                                    notifyMessage,
                                                    err != null ? 0 : 1,
                                                    function (err, result) {
                                                        if (err) {
                                                            modelUtil.logError('Save group notify message failed', err);
                                                        }
                                                    });
                                            });
                                    }
                                } else {
                                    // 这段代码重复
                                    nmRepo.save(user_id,
                                        message.contentType,
                                        title,
                                        content,
                                        notifyMessage,
                                        0,
                                        function (err, result) {
                                            if (err) {
                                                modelUtil.logError('Save group notify message failed', err);
                                            }
                                        });
                                }
                            });
                            // 统计'@'信息
                            let at = message.at == user_id ? 1 : 0;
                            statsRepo.updateGroupChatSummary(user_id,
                                message.group,
                                message.from,
                                at,
                                message.contentType,
                                message.content,
                                true,
                                function (err, result) {
                                    if (err) modelUtil.logError('Update group chat summary failed', err);
                                });
                        })(member.user_id);
                    }
                                    });
                            })(member.user_id);
                        }
                    });
                });
                // 更新组内统计信息
                statsRepo.updateGroupChatSummary(message.from, message.group, message.from, 0, message.contentType, message.content, false, function (err, result) {
                    if (err) log.error(err);
                });
            });
        });
@ -201,7 +117,7 @@ class GroupMessage extends BaseModel{
    /**
     * 获取组消息。
     */
    getMessages(groupId, memberId) {
    getMessages(groupId, memberId, contentType, msgStartId, msgEndId, count) {
        let self = this;
        gmRepo.findAllMessages(groupId, !contentType ? "1,2,3,5,6" : contentType, msgStartId, msgEndId, count, function (err, rows) {
            if (err) {
@ -214,7 +130,7 @@ class GroupMessage extends BaseModel{
            modelUtil.emitData(self.eventEmitter, messages);
            // 清空统计信息
            statsRepo.clearGroupChatSummary(userId, groupId, function (err, result) {
            statsRepo.clearGroupChatSummary(memberId, groupId, function (err, result) {
                if (err) console.log(err);
            });
        });
@ -225,8 +141,8 @@ class GroupMessage extends BaseModel{
     * @param groupId
     */
    getUnreadMessages(groupId, memberId) {
        let seflf = this;
        statsRepo.getGroupChatSummary(userId, groupId, function (err, summary) {
        let self = this;
        statsRepo.getGroupChatSummary(memberId, groupId, function (err, summary) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, "Get unread group messages failed", err);
                    return;
@ -245,8 +161,8 @@ class GroupMessage extends BaseModel{
                        return;
                    }
                    let messages = self.fillMessages(rows);
                    modelUtil.emitData(messages);
                    let feedback = Patient.fillMessages(rows);
                    modelUtil.emitData(feedback);
                });
            }
        )
@ -256,12 +172,11 @@ class GroupMessage extends BaseModel{
    /**
     * 获取未读消息数量。
     *
     * @param groupId
     * @param memberId
     */
    getUnreadMessageCount(groupId, memberId){
    getUnreadMessageCount(memberId) {
        let self = this;
        statsRepo.getGroupChatAllUnReadCount(userId, function (err, result) {
        statsRepo.getGroupChatAllUnReadCount(memberId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get all unread messages failed', err);
                return;
@ -287,8 +202,9 @@ class GroupMessage extends BaseModel{
     * 获取特定群组消息统计情况.
     *
     * @param groupId
     * @param memberId
     */
    getChatSummary(groupId, memberId){
    getChatSummary(groupId, memberId) {
        let self = this;
        statsRepo.getGroupChatSummary(memberId, groupId, function (err, result) {
            if (err) {
@ -323,31 +239,43 @@ class GroupMessage extends BaseModel{
    }
    /**
     * 将消息的返回结果合并成JSON。
     * 获取成员头像。
     *
     * @param rows
     *
     * @returns {startId: 0, count: 0, records: [{id: '', from: '', contentType: '', content: '', timestamp: ''}]}
     * @param groups 要获取的组ID列表。
     */
    fillMessages(rows) {
        let messages = {startId: rows.length > 0 ? rows[0].msg_id : '', count: rows.length, records: []};
        for (let i = 0; i < rows.length; i++) {
            let row = rows[i];
            let record = {
                id: row.msg_id,
                from: row.from_uid,
                contentType: row.type,
                content: row.content,
                timestamp: objectUtil.timestampToLong(row.timestamp)
            };
    getMemberAvatars(groups) {
        let self = this;
        let avatars = [];
        groupRepo.getMembersAvatar(groups, function (err, members) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Get group member's avatar list failed", err);
                return;
            }
            if (row.to_uid !== undefined) record.to = row.to_uid;
            if (row.at_uid !== undefined) record.at = row.at_uid;
            var lastGroup;
            var lastGroupCode = '';
            for (var i = 0; i < members.length; ++i) {
                var member = members[i];
                var groupCode = member.g_code;
                if (lastGroupCode !== groupCode) {
                    lastGroupCode = groupCode;
                    lastGroup = {groupCode: groupCode, avatars: []};
                    if (lastGroupCode !== '') {
                        avatars.push(lastGroup);
                    }
                }
            messages.records.push(record);
        }
                lastGroup.avatars.push({
                    code: member.code,
                    name: member.name,
                    avatar: member.photo === null ? "" : member.photo,
                    role: member.type
                });
            }
        return messages;
            modelUtil.emitData(self.eventEmitter, avatars);
        });
    }
}

+ 52 - 10
src/doctor/models/patient.js

@ -8,8 +8,17 @@ let config = require('../resources/config/' + configFile);
let log = require("../util/log.js");
let BaseModel = require('./base.model');
let patientRepo = require('../repository/patient.repo');
let statsRepo = require("../repository/stats.msg.repo.js");
let pmRepo = require('../repository/private.msg.repo');
let objectUtil = require("../util/objectUtil.js");
let modelUtil = require('../util/modelUtil');
let Doctor = require('../models/doctor');
const CONTENT_TYPES = require('../include/commons').CONTENT_TYPE;
let clientCache = require('./socket.io/client.cache').clientCache();
@ -25,7 +34,7 @@ class Patient extends BaseModel{
     * @param passedCallback 测试通过回调
     * @param failedCallback 测试失败回调
     */
    isPatientCode(code, passedCallback, failedCallback) {
    static isPatientCode(code, passedCallback, failedCallback) {
        patientRepo.isPatientCode(code, function (err, result) {
            if (err) {
                log.error('Send message to patient failed: ', err);
@ -43,17 +52,50 @@ class Patient extends BaseModel{
    /**
     * 向患者发送消息。
     *
     * @param patientId 患者ID
     * 注意:患者消息的保存发送与医生的实现不同。
     *
     * @param message 消息
     */
    sendMessage(patientId, message) {
        let patientClient = clientCache.findById(patientId);
        if (!patientClient) {
            log.warn("User is not online, user id: ", patientId);
            return;
        }
        patientClient.socketServer.sockets.emit('message', message);
    sendMessage(message) {
        // 保存消息
        let self = this;
        let tempContent = message.contentType === CONTENT_TYPES.Article ? JSON.stringify(message.content) : message.content;
        pmRepo.save(message.to, message.from, message.contentType, tempContent, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Save private message failed', err);
                return;
            }
            // 结束网络连接,后续操作继续执行
            pmRepo.findOneMessage(result.insertId, function (err, msg) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Save private message success, but return last message failed', err);
                    return;
                }
                modelUtil.emitData(self.eventEmitter, Doctor.fillMessages(msg));
                // 通过Web Socket推送给患者
                let patientClient = clientCache.findById(message.to);
                if (!patientClient) {
                    log.warn("User is not online, user id: ", message.to);
                    return;
                }
                patientClient.socketServer.sockets.emit('message', message);
            });
            // 更新自身的聊天统计信息
            statsRepo.updatePrivateChatSummary(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
                if (err) log.error(err);
            });
            // 更新对端的聊天统计信息
            statsRepo.updatePrivateChatSummary(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
                if (err) log.error(err);
            });
        });
    };
}

+ 6 - 1
src/doctor/models/search.js

@ -1,6 +1,10 @@
/**
 * 患者、讨论组搜索。
 *
 * 注意:此模型效率堪忧,但为了实现先这样做。更稳妥的方案是使用Solr或Elastic Search
 * 为数据提供索引功能,JS使用搜索接口搜索之后再取得对象的ID进行获取,提高效率。
 * 后续开发都希望看到这段注释,实现此方案。
 *
 * author: Sand
 * since: 2016.11.20
 */
@ -9,6 +13,7 @@
let BaseModel = require('./base.model');
let searchRepo = require('../repository/search.repo');
let modelUtil = require("../util/modelUtil");
let objectUtil = require('../util/objectUtil');
class Search extends BaseModel{
    constructor() {
@ -18,7 +23,7 @@ class Search extends BaseModel{
    /**
     * 搜索患者相关的数据,包括患者信息与相关的私信记录。关键词不支持空格拆分。
     */
    searchAboutPatient() {
    searchAboutPatient(userId, userRole, keyword) {
        let self = this;
        searchRepo.searchPatients(userId, userRole, keyword, function (err, patients) {
            if (err) {

+ 3 - 3
src/doctor/repository/stats.msg.repo.js

@ -106,14 +106,14 @@ 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 " +
        "FROM 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 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) < ?" +
@ -121,7 +121,7 @@ exports.getRecentChats = function (userId, days, handler) {
        " 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 " +
        "FROM 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";

+ 26 - 0
src/doctor/util/controllerUtil.js

@ -0,0 +1,26 @@
/**
 * 控制器辅助函数。
 *
 * author: Sand
 * since: 2016/11/22
 */
"use strict";
let MODEL_EVENTS = require("../include/commons").MODEL_EVENTS;
/**
 * 根据模型事件注册响应返回的代码。
 */
module.exports.regModelEventHandler = function (model, response) {
    model.on(MODEL_EVENTS.OK, function (data) {
        response.status(200).send(data);
    });
    model.on(MODEL_EVENTS.DataNotFound, function (data) {
        response.status(404).send(data);
    });
    model.on(MODEL_EVENTS.Error, function (data) {
        response.status(500).send(data);
    });
};