Procházet zdrojové kódy

增加token生成,为V2版本API做准备;将Model与repo份控制器分开,提高复用性

Sand před 8 roky
rodič
revize
5b50710f65

+ 30 - 30
src/doctor/app.js

@ -1,38 +1,40 @@
/**
 * 应用程序入口。
 */
var express = require('express');
var swagger = require("swagger-node-express");
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var log = require('./util/log');
"use strict";
let express = require('express');
let swagger = require("swagger-node-express");
let path = require('path');
let favicon = require('serve-favicon');
let logger = require('morgan');
let cookieParser = require('cookie-parser');
let bodyParser = require('body-parser');
let log = require('./util/log');
// server configurations
var APIv1 = require('./include/endpoints').APIv1;
var PAGES = require('./include/endpoints').PAGES;
let APIv1 = require('./include/endpoints').APIv1;
let PAGES = require('./include/endpoints').PAGES;
var configFile = require('./include/commons').CONFIG_FILE;
var config = require('./resources/config/' + configFile);
let configFile = require('./include/commons').CONFIG_FILE;
let config = require('./resources/config/' + configFile);
// pages
var index = require('./controllers/index');
var socket = require('./controllers/socket');
let index = require('./controllers/index');
let socket = require('./controllers/socket');
// endpoints
var application = require('./endpoints/application.endpoint');
var users = require('./endpoints/users.endpoint');
var groups = require('./endpoints/groups.endpoint');
var chats = require('./endpoints/chats.endpoint');
var management = require('./endpoints/management.endpoint');
let application = require('./endpoints/application.endpoint');
let users = require('./endpoints/users.endpoint');
let groups = require('./endpoints/groups.endpoint');
let chats = require('./endpoints/chats.endpoint');
let management = require('./endpoints/management.endpoint');
// handlers
var SocketHandler = require('./handlers/socket.handler');
let SocketHandler = require('./handlers/socket.handler');
// initialize express application
var app = express();
let app = express();
app.set('port', config.serverPort);
// view engine
@ -84,8 +86,8 @@ process.on('uncaughtException', function (err) {
});
// now enable http server and socket.io
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
let server = require('http').createServer(app);
let io = require('socket.io').listen(server);
server.listen(config.serverPort);
@ -93,7 +95,7 @@ server.listen(config.serverPort);
server.on('error', function (error) {
    if (error.syscall !== 'listen') throw error;
    var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
    let bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
    // handle specific listen errors with friendly messages
    switch (error.code) {
@ -112,15 +114,13 @@ server.on('error', function (error) {
// event listener for HTTP server "listening" event
server.on('listening', function onListening() {
    var addr = server.address();
    var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
    let addr = server.address();
    let bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
});
//io.sockets.on('connection', socketHandler.onConnection);
var socketHandler = new SocketHandler(io);
let socketHandler = new SocketHandler(io);
socketHandler.start();
log.info('Starting IM server, version ' + config.version + ', running on port ' + server.address().port + ', start at ' + new Date().toLocaleString());
log.info('Starting IM server, version ' + config.version + ', running on port ' + server.address().port + ', ' + new Date().toLocaleString());
log.info('Configuration profile: ' + configFile.split('.')[1]);
module.exports = app;

+ 5 - 3
src/doctor/controllers/index.js

@ -1,10 +1,12 @@
/**
 * 主页控制器。
 */
var express = require('express');
var router = express.Router();
"use strict";
var pages = require('../include/endpoints').PAGES;
const express = require('express');
const router = express.Router();
const pages = require('../include/endpoints').PAGES;
router.get(pages.Home.Index, function(req, res) {
  res.render('index', { title: 'IM.User' });

+ 5 - 5
src/doctor/controllers/socket.js

@ -3,12 +3,12 @@
 */
"use strict";
var express = require('express');
var router = express.Router();
var fs = require('fs');
var path = require('path');
const express = require('express');
const router = express.Router();
const fs = require('fs');
const path = require('path');
var PAGES = require('../include/endpoints').PAGES;
const PAGES = require('../include/endpoints').PAGES;
/**
 * socket.io测试页面。

+ 10 - 8
src/doctor/endpoints/application.endpoint.js

@ -1,11 +1,13 @@
var express = require('express');
var router = express.Router();
"use strict";
var log = require('../util/log.js');
let express = require('express');
let router = express.Router();
var APIv1 = require('../include/endpoints').APIv1;
let log = require('../util/log.js');
var msgStats = require("../repository/stats.msg.repo.js");
let APIv1 = require('../include/endpoints').APIv1;
let statsRepo = require("../repository/stats.msg.repo.js");
/**
 * 获取应用角标数。
@ -16,9 +18,9 @@ var msgStats = require("../repository/stats.msg.repo.js");
 * uid:用户id
 */
router.get(APIv1.Application.BadgeNo, function (req, res) {
    var userId = req.query.user_id;
    let userId = req.query.user_id;
    msgStats.getBadgeNumber(userId, function (err, result) {
    statsRepo.getBadgeNumber(userId, function (err, result) {
        if (err) {
            console.error("Get badge number failed: ", err);
@ -26,7 +28,7 @@ router.get(APIv1.Application.BadgeNo, function (req, res) {
            return;
        }
        var data = {userId: userId, badge: result};
        let data = {userId: userId, badge: result};
        res.send(data);
    });
});

+ 2 - 0
src/doctor/endpoints/chats.endpoint.js

@ -3,6 +3,8 @@
 *
 * 此控制器处理点对点,组及消息消息。为三类消息提供发送及查询功能。
 */
"use strict";
let express = require('express');
let router = express.Router();

+ 12 - 59
src/doctor/endpoints/management.endpoint.js

@ -1,74 +1,27 @@
/**
 * 管理端点。负责数据库,服务器状态等内容反馈。
 */
var express = require('express');
var router = express.Router();
"use strict";
var configFile = require('../include/commons').CONFIG_FILE;
var config = require('../resources/config/' + configFile);
let express = require('express');
let router = express.Router();
var wlyyRepo = require('../repository/database/wlyy.db.js');
var imRepo = require('../repository/database/im.db.js');
let APIv1 = require('../include/endpoints').APIv1;
let MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
var log = require('../util/log');
var APIv1 = require('../include/endpoints').APIv1;
var _ = require('underscore');
function getWlyyTables(handler) {
    wlyyRepo.execQuery({
        "sql": "SELECT table_name FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?",
        "args": [config.wlyyDbConfig.database],
        "handler": handler
    });
}
function getImTables(handler) {
    imRepo.execQuery({
        "sql": "SELECT table_name FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?",
        "args": [config.imDbConfig.database],
        "handler": handler
    });
}
function makeResponse(dbStatus, dbName, err, result) {
    if (err) {
        dbStatus.push({
            name: dbName,
            status: 'Failed',
            message: err
        });
    } else {
        var tableList = new Array();
        _.each(result, function (row) {
            tableList.push(row.table_name);
        });
        var status = {
            name: dbName,
            status: 'OK',
            tables: tableList
        };
        dbStatus.push(status);
    }
}
let Management = require('../models/server/management');
/**
 * 数据库检查,包括所有表,连接状态。
 */
router.get(APIv1.Management.DbStatus, function (req, res, next) {
    var dbStatus = new Array(0);
    getImTables(function (err, result) {
        makeResponse(dbStatus, config.imDbConfig.database, err, result);
router.get(APIv1.Management.DbStatus, function (req, res) {
    let management = new Management();
        getWlyyTables(function (err, result) {
            makeResponse(dbStatus, config.wlyyDbConfig.database, err, result);
            res.json(dbStatus);
        });
    management.on(MODEL_EVENTS.OK, function (data) {
        res.status(200).send(data);
    });
    management.getDatabaseTables();
});
module.exports = router;

+ 53 - 57
src/doctor/endpoints/users.endpoint.js

@ -1,17 +1,21 @@
/**
 * 用户端点。
 */
var express = require('express');
var router = express.Router();
var user = require("../repository/doctor.repo.js");
var http = require('http');
"use strict";
var configFile = require('../include/commons').CONFIG_FILE;
var config = require('../resources/config/' + configFile);
var log = require("../util/log.js");
var objectUtil = require('../util/objectUtil');
let express = require('express');
let router = express.Router();
let http = require('http');
var APIv1 = require('../include/endpoints').APIv1;
let configFile = require('../include/commons').CONFIG_FILE;
let config = require('../resources/config/' + configFile);
let log = require("../util/log.js");
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;
/**
 * 登录。用户登录后,更新数据库中的在线状态。
@ -26,48 +30,37 @@ var APIv1 = require('../include/endpoints').APIv1;
 *  platform:平台类型,0为iOS,1为Android
 */
router.get(APIv1.Users.Login, function (req, res) {
    var userId = req.query.user_id;
    var token = req.query.token;
    var clientId = req.query.client_id;
    var platform = req.query.platform;
    let userId = req.query.user_id;
    let token = req.query.token;
    let clientId = req.query.client_id;
    let platform = req.query.platform;
    if (userId == null) {
        throw {httpStatus: 406, message: 'Missing field "user_id".'};
        throw {httpStatus: 406, message: 'Missing field: user_id.'};
    }
    if (token == null) {
        throw {httpStatus: 406, message: 'Missing field "token".'};
        throw {httpStatus: 406, message: 'Missing field: token.'};
    }
    if (clientId == null) {
        throw {httpStatus: 406, message: 'Missing field "client_id".'};
        throw {httpStatus: 406, message: 'Missing field: client_id.'};
    }
    if (platform == null) {
        throw {httpStatus: 406, message: 'Missing field "platform".'};
        throw {httpStatus: 406, message: 'Missing field: platform.'};
    }
    user.deleteToken(token, function (err, result) {
        if (err) {
            log.error('Error occurs when user login and delete token: ', err);
            res.status(500).send({message: 'Error occurs when user login and delete token.'});
        } else {
            user.login(userId,
                token,
                clientId,
                platform,
                function (err, result) {
                    if (err) {
                        log.error('Error occurs when user login and delete token: ', err);
                        res.status(500).send({message: 'Error occurs when user login.'})
                        return;
                    }
                    res.status(200).end();
                });
        }
    let userStatus = new UserStatus();
    userStatus.on(MODEL_EVENTS.OK, function (message) {
        res.status(200).send(message);
    });
    userStatus.on(MODEL_EVENTS.Error, function (message) {
        res.status(500).send(message);
    });
    userStatus.login(userId, token, clientId, platform);
});
/**
@ -80,20 +73,22 @@ router.get(APIv1.Users.Login, function (req, res) {
 *  user_id:用户ID
 */
router.get(APIv1.Users.Logout, function (req, res) {
    if (req.query.user_id == null) {
    let userId = req.query.user_id;
    if (userId == null) {
        throw {httpStatus: 406, message: 'Logout Failed. Missing field: user_id.'};
    }
    user.logout(req.query.user_id,
        function (err, result) {
            if (err) {
                log.error("Logout failed: ", err);
    let userStatus = new UserStatus();
                res.status(416).send({message: 'Logout failed.'});
            }
    userStatus.on(MODEL_EVENTS.OK, function (message) {
        res.status(200).send(message);
    });
    userStatus.on(MODEL_EVENTS.Error, function (message) {
        res.status(500).send(message);
    });
            res.status(200).end();
        });
    userStatus.logout(userId);
});
/**
@ -106,8 +101,8 @@ router.get(APIv1.Users.Logout, function (req, res) {
 *  {status: 1}, app状态,0在后台,1在前台
 */
router.post(APIv1.Users.UserStatus, function (req, res) {
    var userId = req.param('user_id');
    var status = req.body;
    let userId = req.param('user_id');
    let status = req.body;
    if (!objectUtil.isJsonObject(status)) {
        throw {httpStatus: 406, message: "Problems parsing json."};
    }
@ -116,16 +111,17 @@ router.post(APIv1.Users.UserStatus, function (req, res) {
        throw {httpStatus: 406, message: 'Validation Failed. Missing fields.'};
    }
    user.updateStatus(userId, status.status,
        function (err, result) {
            if (err) {
                log.error("Update user status failed: ", err.message);
    let userStatus = new UserStatus();
                res.status(500).send({message: 'Update users status failed.'});
            }
    userStatus.on(MODEL_EVENTS.OK, function (message) {
        res.status(200).send(message);
    });
    userStatus.on(MODEL_EVENTS.Error, function (message) {
        res.status(500).send(message);
    });
            res.status(200).end();
        });
    userStatus.updateStatus(userId, status.status);
});
module.exports = router;

+ 13 - 11
src/doctor/handlers/socket.handler.js

@ -15,8 +15,8 @@ let doctor = new Doctor();
let Group = require('../models/group');
let group = new Group();
class SocketHandler{
    constructor(socketServer){
class SocketHandler {
    constructor(socketServer) {
        this._socketServer = socketServer;
    }
@ -25,14 +25,14 @@ class SocketHandler{
     *
     * @param socket
     */
    start(){
    start() {
        let socketServer = this._socketServer;
        socketServer.sockets.on('connection', function (socket) {
            // 客户端注册
            socket.on('login', function (data) {
                if(!data.userId){
                if (!data.userId) {
                    socketServer.sockets.emit('error', {message: 'Missing fields(s): userId.'});
                } else{
                } else {
                    log.info('User login: ' + data.userId);
                    let patientClient = new PatientClient(socket, socketServer);
@ -52,7 +52,7 @@ class SocketHandler{
                let targetType = data.targetType;
                let message = data.message;
                if(targetType == 1){
                if (targetType == 1) {
                    doctor.sendMessage(message);
                } else {
                    group.sendMessage(message);
@ -61,16 +61,18 @@ class SocketHandler{
            // 客户端退出
            socket.on('logout', function (data) {
                let userId = clientCache.findBySocket(socket).userId;
                log.info('User logout: ' + userId);
                clientCache.removeByUserId(userId);
                let client = clientCache.findBySocket(socket);
                if (client) {
                    log.info('User logout: ' + client.userId);
                    clientCache.removeByUserId(client.userId);
                }
            });
            // 客户端断开
            socket.on('disconnect', function () {
                let patientClient = clientCache.findBySocket(socket);
                if(patientClient){log.info("User disconnect: ", patientClient.userId);
                if (patientClient) {
                    log.info("User disconnect: ", patientClient.userId);
                    clientCache.removeByUserSocket(socket);
                }
            });

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

@ -3,7 +3,7 @@
 *
 * 若想访问包含页面的内容,请在相应的API后面添加.html。
 */
var APIv1 = {
const APIv1 = {
    Application: {
        Base: '/api/v1/application',
@ -74,7 +74,7 @@ var APIv1 = {
    }
};
var pages = {
const pages = {
    Home: {
        Index: '/'
    },

+ 46 - 0
src/doctor/models/auth/token.js

@ -0,0 +1,46 @@
/**
 * 服务端token。token用于校验客户端权限。
 *
 * 此类暂时未使用,V1版本API暂时未传递此参数,V2版本API可计划增加此功能,提高系统安全性。
 *
 * HMAC: keyed-Hash Message Authentication Code
 *
 * author: Sand
 * since: 2016/11/21
 */
"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 cipherText = hmac.digest('hex');
        this._userId = userId;
        this._clientId = clientId;
        this._platform = platform;
        this._value = cipherText;
    }
    get userId(){
        return this._userId;
    }
    get clientId(){
        return this._clientId;
    }
    get platform(){
        return this._platform;
    }
    get value(){
        return this._value;
    }
}
module.exports = Token;

+ 27 - 0
src/doctor/models/base.model.js

@ -0,0 +1,27 @@
/**
 * 模型基类。
 *
 * 模型基于异步模型,提供事件抽象。
 *
 * author: Sand
 * since: 2016.11.20
 */
"use strict";
let EventEmitter = require('events').EventEmitter;
class BaseModel{
    constructor() {
        this._eventEmitter = new EventEmitter();
    }
    get eventEmitter(){
        return this._eventEmitter;
    }
    on(event, handler){
        this._eventEmitter.on(event, handler);
    }
}
module.exports = BaseModel;

+ 328 - 122
src/doctor/models/doctor.js

@ -3,26 +3,24 @@
 */
"use strict";
var EventEmitter = require('events').EventEmitter;
var log = require("../util/log.js");
var modelUtil = require('../util/modelUtil');
var getui = require('getui');
var userRepo = require('../repository/doctor.repo.js');
var gmRepo = require('../repository/group.msg.repo');
var pmRepo = require('../repository/private.msg.repo');
var nmRepo = require("../repository/notify.msg.repo");
var statsRepo = require("../repository/stats.msg.repo");
var objectUtil = require("../util/objectUtil.js");
var MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
var CONTENT_TYPES = require('../include/commons').CONTENT_TYPE;
var PLATFORMS = require('../include/commons').PLATFORM;
class Doctor{
    constructor(){
        this._eventEmitter = new EventEmitter();
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 gmRepo = require('../repository/group.msg.repo');
let pmRepo = require('../repository/private.msg.repo');
let nmRepo = require("../repository/notify.msg.repo");
let statsRepo = require("../repository/stats.msg.repo");
let objectUtil = require("../util/objectUtil.js");
let CONTENT_TYPES = require('../include/commons').CONTENT_TYPE;
let PLATFORMS = require('../include/commons').PLATFORM;
class Doctor extends BaseModel{
    constructor() {
        super();
    }
    /**
@ -30,56 +28,56 @@ class Doctor{
     *
     * @param message
     */
    sendMessage(message){
        var self = this;
    sendMessage(message) {
        let self = this;
        userRepo.isExist(message.to, function (err, rows) {
            if (err) {
                modelUtil.emitDbError(self, 'Lookup receiving users failed', err);
                modelUtil.emitDbError(self.eventEmitter, 'Lookup receiving users failed', err);
                return;
            }
            if (rows.length == 0) {
                self.emit(MODEL_EVENTS.DataNotFound, {});
                modelUtil.emitDataNotFound(self.eventEmitter, {});
                return;
            }
            // 保存消息
            var tempContent = message.contentType === CONTENT_TYPES.Article ? JSON.stringify(message.content) : message.content;
            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, 'Save private message failed.', err);
                    modelUtil.emitDbError(self.eventEmitter, 'Save private message failed.', err);
                    return;
                }
                // 返回发送成功后的消息记录,控制器可选择结束网络连接
                pmRepo.findOneMessage(result.insertId, function (err, msg) {
                pmRepo.findOneMessage(result.insertId, function (err, rows) {
                    if (err) {
                        modelUtil.emitDbError(self, 'Save private message success, but return last message failed.', err);
                        modelUtil.emitDbError(self.eventEmitter, 'Save private message success, but return last message failed', err);
                    } else {
                        self.emit(MODEL_EVENTS.OK, fillMessages(msg));
                        modelUtil.emitData(self._eventEmitter, fillMessages(rows));
                    }
                });
                // 更新自身的聊天统计信息
                statsRepo.updatePrivateChatSummary(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
                    if (err) modelUtil.logDbError(null, err);
                    if (err) modelUtil.logError(null, err);
                });
                // 更新对端的聊天统计信息
                statsRepo.updatePrivateChatSummary(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
                    if (err) modelUtil.logDbError(null, err);
                    if (err) modelUtil.logError(null, err);
                });
                // 获取对方状态,即对端的系统平台,token等信息,并推送通知消息给对端
                userRepo.getUserStatus(message.to, function (err, result) {
                    if (err) {
                        modelUtil.logDbError('Get target user status for private message failed: ' + message.to, err);
                        modelUtil.logError('Get target user status for private message failed: ' + message.to, err);
                        return;
                    }
                    // 构建通知消息
                    var title = '新消息';
                    var content = '';
                    let title = '新消息';
                    let content = '';
                    if (message.contentType === CONTENT_TYPES.PlainText) {
                        content = message.content;
                    } else if (message.contentType === CONTENT_TYPES.Image) {
@ -90,8 +88,8 @@ class Doctor{
                        content = '接收到一条新消息';
                    }
                    var isOnline = false;
                    var target;
                    let isOnline = false;
                    let target;
                    if (result.length > 0) {
                        target = result[0];
                        if (target.is_online) {
@ -99,7 +97,7 @@ class Doctor{
                        }
                    }
                    var notifyMessage = JSON.stringify({type: 'p2p_msg', from_uid: message.from});
                    let notifyMessage = JSON.stringify({type: 'p2p_msg', from_uid: message.from});
                    // 保存通知消息到数据库中并根据用户在线状态推送此消息
                    nmRepo.save(message.to, message.contentType, title, content, notifyMessage, isOnline, function (err, result) {
@ -147,48 +145,44 @@ class Doctor{
    /**
     * 获取最近聊天的用户,组。
     */
    getRecentChats(){
        statsRepo.getRecentChats(userId, days, function (err, result) {
    getRecentChatList() {
        let self = this;
        statsRepo.getRecentChats(userId, days, function (err, rows) {
            if (err) {
                log.error('Get recent chat objects failed: ', err);
                res.status(500).send({message: 'Get recent chat objects failed.'});
                modelUtil.emitDbError(self.eventEmitter, 'Get recent chat objects failed', err);
                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
                    });
            let data = {patients: [], doctors: [], groups: []};
            if (rows.length > 0) {
                for (let i = 0; i < rows.length; ++i) {
                    let row = rows[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);
            modelUtil.emitData(self.eventEmitter, data);
        });
    }
@ -198,18 +192,18 @@ class Doctor{
     * @param userId
     */
    getChatList(userId) {
        var self = this;
        let self = this;
        // 与患者的私信
        pmRepo.findAllP2PWithPatient(userId, function (err, patients) {
            if (err) {
                modelUtil.emitDbError(self, 'Get chat list with patient failed', err);
                modelUtil.emitDbError(self.eventEmitter, 'Get chat list with patient failed', err);
                return;
            }
            var chats = {patients: [], doctors: [], groups: []};
            for (var i = 0; i < patients.length; i++) {
                var patient = patients[i];
            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,
@ -226,15 +220,15 @@ class Doctor{
            // 含有患者的群
            gmRepo.findAllGroupsWithPatient(userId, function (err, groups) {
                if (err) {
                    modelUtil.emitDbError(self, 'Get group list with patient failed', err);
                    modelUtil.emitDbError(self.eventEmitter, 'Get group list with patient failed', err);
                    return;
                }
                for (var i = 0; i < groups.length; i++) {
                    var group = groups[i];
                for (let i = 0; i < groups.length; i++) {
                    let group = groups[i];
                    // 过滤掉医生间的求助团队
                    if(group.group_type === 2) continue;
                    if (group.group_type === 2) continue;
                    chats.groups.push({
                        code: group.code,
@ -250,12 +244,12 @@ class Doctor{
                // 医生间的私聊
                pmRepo.findAllP2PWithDoctor(userId, function (err, doctors) {
                    if (err) {
                        modelUtil.emitDbError(self, 'Get chat list with doctor failed', err);
                        modelUtil.emitDbError(self.eventEmitter, 'Get chat list with doctor failed', err);
                        return;
                    }
                    for (var i = 0; i < doctors.length; i++) {
                        var doctor = doctors[i];
                    for (let i = 0; i < doctors.length; i++) {
                        let doctor = doctors[i];
                        chats.doctors.push({
                            code: doctor.code,
                            name: doctor.name,
@ -271,12 +265,12 @@ class Doctor{
                    // 获取医生间的组
                    gmRepo.findAllGroupsWithDoctor(userId, function (err, groups) {
                        if (err) {
                            modelUtil.emitDbError(self, 'Get group list with doctor failed', err);
                            modelUtil.emitDbError(self.eventEmitter, 'Get group list with doctor failed', err);
                            return;
                        }
                        for (var i = 0; i < groups.length; i++) {
                            var group = groups[i];
                        for (let i = 0; i < groups.length; i++) {
                            let group = groups[i];
                            chats.groups.push({
                                code: group.code,
                                name: group.name,
@ -288,7 +282,7 @@ class Doctor{
                            });
                        }
                        self.emit(MODEL_EVENTS.OK, chats);
                        modelUtil.emitData(self.eventEmitter, chats);
                    });
                });
            })
@ -300,19 +294,19 @@ class Doctor{
     *
     * @param userId
     */
    getChatListWithDoctor(userId){
    getChatListWithDoctor(userId) {
        let self = this;
        // 先获取医生间的私聊
        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.'});
                modelUtil.emitDbError(self.eventEmitter, 'Get chat list with doctor failed', err);
                return;
            }
            var chats = {doctors: [], groups: []};
            for (var i = 0; i < doctors.length; i++) {
                var doctor = doctors[i];
            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,
@ -328,14 +322,12 @@ class Doctor{
            // 再获取医生间的组
            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.'});
                    modelUtil.emitDbError(self.eventEmitter, 'Get group list with doctor failed', err);
                    return;
                }
                for (var i = 0; i < groups.length; i++) {
                    var group = groups[i];
                for (let i = 0; i < groups.length; i++) {
                    let group = groups[i];
                    chats.groups.push({
                        code: group.code,
                        name: group.name,
@ -347,34 +339,141 @@ class Doctor{
                    });
                }
                res.status(200).send(chats);
                modelUtil.emitData(self.eventEmitter, chats);
            });
        });
    }
    /**
     * 获取与患者的聊天列表。
     */
    getChatsListWithPatient(userId) {
        let self = this;
        pmRepo.findAllP2PWithPatient(userId, function (err, patients) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get chat list with patient 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)
                });
            }
            gmRepo.findAllGroupsWithPatient(userId, function (err, groups) {
                if (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.msg_type,
                        newMessageCount: group.new_msg_count,
                        lastContentType: group.last_content_type,
                        lastContent: group.last_content,
                        timestamp: objectUtil.timestampToLong(group.timestamp)
                    });
                }
                modelUtil.emitData(self.eventEmitter, chats);
            })
        });
    }
    /**
     * 获取与指定用户的聊天记录。
     *
     * @param userId
     * @param peerId
     * @param contentType
     * @param msgStartId
     * @param msgEndId
     * @param count
     * @param closedInterval
     */
    getPrivateMessages(userId, peerId){
    getPrivateMessages(userId, peerId, contentType, msgStartId, msgEndId, count, closedInterval) {
        let self = this;
        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."});
                modelUtil.emitDbError(self.eventEmitter, 'Get private message failed', err);
                return;
            }
            var messages = fillMessages(rows);
            let messages = self.fillMessages(rows);
            modelUtil.emitData(self.eventEmitter, messages);
            // 清空统计信息
            statsRepo.clearPrivateChatSummary(userId, peerId, function (err, result) {
                if (err) console.log(err);
            });
        });
    }
    /**
     * 获取与某人聊天的未读消息数。
     *
     * @param userId
     * @param peerId
     */
    getUnreadMessageCount(userId, peerId) {
        let self = this;
        statsRepo.getPrivateChatAllUnReadCount(userId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Get unread private message count failed", err);
                return;
            }
            let data = {userId: userId, messageType: 1, newMessageCount: 0};
            for (let i = 0; i < result.length; i++) {
                data.newMessageCount += result[i].new_msg_count;
            }
            modelUtil.emitData(self.eventEmitter, data);
        });
    }
    /**
     * 获取所有未读的消息数,包括群。
     *
     * @param userId
     */
    getAllUnreadMessageCount(userId) {
        let self = this;
        statsRepo.getChatAllUnReadCount(userId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Get all unread message count failed", err);
                return;
            }
            let data = {userId: userId, messageType: 0, newMessageCount: 0};
            for (let index = 0; index < result.length; index++) {
                data.newMessageCount += result[index].new_msg_count;
            }
            res.status(200).send(messages);
            modelUtil.emitData(self.eventEmitter, data);
        });
    }
@ -385,37 +484,144 @@ class Doctor{
     * @param peerId
     */
    getUnreadPrivateMessages(userId, peerId) {
        let self = this;
        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."});
                modelUtil.emitDbError(self.eventEmitter, 'Get unread private messages failed', err);
                return;
            }
            // 没有未读消息,直接返回
            if (summary.length == 0 || summary[0].new_msg_count === 0) {
                res.status(200).send({startId: 0, count: 0, records: []});
                modelUtil.emitData(self.eventEmitter, {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);
                    modelUtil.emitDbError(self.eventEmitter, "Get unread private messages failed", err);
                    return;
                }
                let messages = self.fillMessages(rows);
                modelUtil.emitData(self.eventEmitter, messages);
            });
        });
    }
    /**
     * 获取聊天统计摘要。
     *
     * @param userId
     * @param peerId
     */
    getChatSummary(userId, peerId) {
        let self = this;
        statsRepo.getPrivateChatSummary(userId, peerId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Get private messages stats failed", err);
                return;
            }
            let data = {
                userId: userId,
                peerId: peerId,
                lastCContentType: 1,
                lastContent: "",
                newMessageCount: 0,
                timestamp: 0
            };
            if (result.length > 0) {
                let 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)
            }
            modelUtil.emitData(self.eventEmitter, data);
        });
    }
    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);
                    return;
                }
                    res.status(500).send({message: "Get unread private messages failed."});
                if (result.length == 0) {
                    modelUtil.emitDataNotFound(self.eventEmitter, "Message not found.");
                    return;
                }
                var messages = fillMessages(rows);
                modelUtil.emitData(self.eventEmitter, {
                    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) {
                    modelUtil.emitDbError(self.eventEmitter, "Get message failed", err);
                    return;
                }
                res.status(200).send(messages);
                if (result.length == 0) {
                    modelUtil.emitDataNotFound(self.eventEmitter, "Message not found.");
                    return;
                }
                modelUtil.emitData(self.eventEmitter, {
                    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)
                });
            });
        });
        }
    }
    on(message, handler){
        this._eventEmitter.on(message, handler);
    /**
     * 判断与患者的最新咨询会话是否已经结束。
     */
    isConsultFinished(doctorId, patientId) {
        let self = this;
        pmRepo.isCurrentSessionFinished(doctorId, patientId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Get session finish status failed: ", err);
                return;
            }
            let data = {finished: true, consultId: ''};
            if (result.length > 0) {
                let finishRow = result[0];
                data.finished = finishRow.finished === 1;
                if (!data.finished) {
                    data.consultId = finishRow.consult_id;
                }
            }
            modelUtil.emitData(self.eventEmitter, data);
        })
    }
    /**
@ -426,10 +632,10 @@ class Doctor{
     * @returns {startId: 0, count: 0, records: []}
     */
    static 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 = {
        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,

+ 131 - 70
src/doctor/models/group.js

@ -3,71 +3,70 @@
 */
"use strict";
var EventEmitter = require('events').EventEmitter;
var MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
var CONTENT_TYPES = require('../include/commons').CONTENT_TYPE;
var PLATFORMS = require('../include/commons').PLATFORM;
var log = require("../util/log.js");
var modelUtil = require('../util/modelUtil');
var getui = require('getui');
var userRepo = require('../repository/doctor.repo.js');
var groupRepo = require('../repository/group.msg.repo');
var gmRepo = require('../repository/group.msg.repo');
var nmRepo = require("../repository/notify.msg.repo");
var statsRepo = require("../repository/stats.msg.repo");
var objectUtil = require("../util/objectUtil.js");
class GroupMessage {
let CONTENT_TYPES = require('../include/commons').CONTENT_TYPE;
let PLATFORMS = require('../include/commons').PLATFORM;
let BaseModel = require('./base.model');
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 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{
    constructor() {
        this._eventEmitter = new EventEmitter();
        super();
    }
    
    /**
     * 发送消息。
     *
     * @param message
     */
    sendMessage(message) {
        var self = this;
        let self = this;
        groupRepo.isGroupMember(message.group, message.groupType, message.from, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self._eventEmitter, 'Check group member failed', err);
                modelUtil.emitDbError(self.eventEmitter, 'Check group member failed', err);
                return;
            }
            if (result.length == 0) {
                self._eventEmitter.emit(MODEL_EVENTS.DataNotFound, {message: '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);
                    modelUtil.emitDbError(self.eventEmitter, 'Save group message failed', err);
                    return;
                }
                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;
                    }
                    // 返回新增加的消息,控制器可结束网络连接
                    self._eventEmitter.emit(MODEL_EVENTS.OK, GroupMessage.fillMessages(groupMsg));
                    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(null, err);
                    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);
                        modelUtil.emitDbError(self.eventEmitter, 'Get group members failed: ', err);
                        return;
                    }
@ -79,8 +78,8 @@ class GroupMessage {
                    }
                    // 逐个推送通知
                    for (var i = 0; i < members.length; i++) {
                        var member = members[i];
                    for (let i = 0; i < members.length; i++) {
                        let member = members[i];
                        if (member.user_id === message.from) {
                            continue;
                        }
@ -92,8 +91,8 @@ class GroupMessage {
                                    return;
                                }
                                var title = '';
                                var content = '';
                                let title = '';
                                let content = '';
                                if (message.contentType === CONTENT_TYPES.PlainText) {
                                    title = '群组消息';
                                    content = message.content;
@ -108,12 +107,12 @@ class GroupMessage {
                                    content = '接收到一条新消息';
                                }
                                var isOnline = result.length > 0 && result[0].is_online === 1;
                                var notifyMessage = JSON.stringify({type: 'group_msg', gid: message.group});
                                let isOnline = result.length > 0 && result[0].is_online === 1;
                                let notifyMessage = JSON.stringify({type: 'group_msg', gid: message.group});
                                // 发送并保存通知到数据库中
                                if (isOnline) {
                                    var userStatus = result[0];
                                    let userStatus = result[0];
                                    if (userStatus.platform === PLATFORMS.iOS) {
                                        getui.pushAPN(user_id,
                                            userStatus.token,
@ -158,7 +157,7 @@ class GroupMessage {
                                                    err != null ? 0 : 1,
                                                    function (err, result) {
                                                        if (err) {
                                                            modelUtil.logDbError('Save group notify message failed', err);
                                                            modelUtil.logError('Save group notify message failed', err);
                                                        }
                                                    });
                                            });
@ -173,14 +172,14 @@ class GroupMessage {
                                        0,
                                        function (err, result) {
                                            if (err) {
                                                modelUtil.logDbError('Save group notify message failed', err);
                                                modelUtil.logError('Save group notify message failed', err);
                                            }
                                        });
                                }
                            });
                            // 统计'@'信息
                            var at = message.at == user_id ? 1 : 0;
                            let at = message.at == user_id ? 1 : 0;
                            statsRepo.updateGroupChatSummary(user_id,
                                message.group,
@ -190,7 +189,7 @@ class GroupMessage {
                                message.content,
                                true,
                                function (err, result) {
                                    if (err) modelUtil.logDbError('Update group chat summary failed', err);
                                    if (err) modelUtil.logError('Update group chat summary failed', err);
                                });
                        })(member.user_id);
                    }
@ -203,22 +202,21 @@ class GroupMessage {
     * 获取组消息。
     */
    getMessages(groupId, memberId) {
        let self = this;
        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.'});
                modelUtil.emitDbError(self.eventEmitter, 'Get group message failed', err);
                return;
            }
            var messages = GroupMessage.fillMessages(rows);
            // 先给客户端返回数据
            let messages = GroupMessage.fillMessages(rows);
            modelUtil.emitData(self.eventEmitter, messages);
            // 清空统计信息
            statsRepo.clearGroupChatSummary(userId, groupId, function (err, result) {
                if (err) console.log(err);
            });
            res.status(200).send(messages);
        });
    }
@ -227,38 +225,101 @@ class GroupMessage {
     * @param groupId
     */
    getUnreadMessages(groupId, memberId) {
        let seflf = this;
        statsRepo.getGroupChatSummary(userId, groupId, function (err, summary) {
            if (err) {
                log.error("Get unread group messages failed: ", err);
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, "Get unread group messages failed", err);
                    return;
                }
                res.status(500).send({message: "Get unread group messages failed."});
                return;
                let messages = {startId: 0, count: 0, records: []};
                if (summary.length == 0 || summary[0].new_msg_count === 0) {
                    modelUtil.emitData(messages);
                    return;
                }
                messages.count = summary[0].new_msg_count;
                gmRepo.findUnread(groupId, MAX_INT, messages.count, function (err, rows) {
                    if (err) {
                        modelUtil.emitDbError(self.eventEmitter, "Get unread group messages failed", err);
                        return;
                    }
                    let messages = self.fillMessages(rows);
                    modelUtil.emitData(messages);
                });
            }
        )
        ;
    }
            var messages = {startId: 0, count: 0, records: []};
            if (summary.length == 0 || summary[0].new_msg_count === 0) {
                res.status(200).send(messages);
    /**
     * 获取未读消息数量。
     *
     * @param groupId
     * @param memberId
     */
    getUnreadMessageCount(groupId, memberId){
        let self = this;
        statsRepo.getGroupChatAllUnReadCount(userId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get all unread messages failed', err);
                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);
            let data = {
                userId: memberId,
                messageType: 2,
                newMessageCount: 0
            };
                    res.status(500).send({message: "Get unread group messages failed."});
                    return;
            if (result.length > 0) {
                for (let index = 0; index < result.length; index++) {
                    data.newMessageCount += result[index].new_msg_count;
                }
            }
                var messages = fillMessages(rows);
                res.status(200).send(messages);
            });
            modelUtil.emitData(self.eventEmitter, data);
        });
    }
    on(event, handler) {
        this._eventEmitter.on(event, handler);
    /**
     * 获取特定群组消息统计情况.
     *
     * @param groupId
     */
    getChatSummary(groupId, memberId){
        let self = this;
        statsRepo.getGroupChatSummary(memberId, groupId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get group stats failed', err);
                return;
            }
            let data = {
                userId: userId,
                from: "",
                groupId: groupId,
                atMe: 0,
                lastContentType: 1,
                lastContent: "",
                newMessageCount: 0,
                timestamp: 0
            };
            if (result.length > 0) {
                let 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)
            }
            modelUtil.emitData(self.eventEmitter, data);
        });
    }
    /**
@ -266,13 +327,13 @@ class GroupMessage {
     *
     * @param rows
     *
     * @returns {startId: 0, count: 0, records: []}
     * @returns {startId: 0, count: 0, records: [{id: '', from: '', contentType: '', content: '', timestamp: ''}]}
     */
    static 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 = {
    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,

+ 3 - 1
src/doctor/models/patient.js

@ -7,13 +7,15 @@ let configFile = require('../include/commons').CONFIG_FILE;
let config = require('../resources/config/' + configFile);
let log = require("../util/log.js");
let BaseModel = require('./base.model');
let patientRepo = require('../repository/patient.repo');
let objectUtil = require("../util/objectUtil.js");
let clientCache = require('./socket.io/client.cache').clientCache();
class Patient {
class Patient extends BaseModel{
    constructor() {
        super();
    }
    /**

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

@ -0,0 +1,189 @@
/**
 * 患者、讨论组搜索。
 *
 * author: Sand
 * since: 2016.11.20
 */
"use strict";
let BaseModel = require('./base.model');
let searchRepo = require('../repository/search.repo');
let modelUtil = require("../util/modelUtil");
class Search extends BaseModel{
    constructor() {
        super();
    }
    /**
     * 搜索患者相关的数据,包括患者信息与相关的私信记录。关键词不支持空格拆分。
     */
    searchAboutPatient() {
        let self = this;
        searchRepo.searchPatients(userId, userRole, keyword, function (err, patients) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Search patient on basic information failed", err);
                return;
            }
            let data = {patients: [], chats: []};
            for (let i = 0; i < patients.length; ++i) {
                let 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) {
                    modelUtil.emitDbError(self.eventEmitter, "Search patient on private messages failed", err);
                    return;
                }
                let lastPatientCode = '';
                let lastPatient = {code: '', name: '', sex: '', avatar: '', messages: []};
                for (let i = 0; i < chats.length; ++i) {
                    let 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
                    });
                }
                modelUtil.emitData(self.eventEmitter, data);
            });
        });
    }
    /**
     * 搜索医生相关的数据,包括医生信息与相关的聊天记录,包括私信与群信。
     */
    searchAboutDoctor() {
        let self = this;
        searchRepo.searchDoctors(userId, keyword, function (err, doctors) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Search doctor on basic information failed", err);
                return;
            }
            let data = {doctors: [], groups: [], chats: {doctors: [], groups: []}};
            for (let i = 0; i < doctors.length; ++i) {
                let 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) {
                    modelUtil.emitDbError(self.eventEmitter, "Search talk group failed", err);
                    return;
                }
                let lastGroupCode = '';
                let lastGroup = null;
                for (let i = 0; i < groups.length; ++i) {
                    let 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) {
                        modelUtil.emitDbError(self.eventEmitter, "Search doctor private messages failed", err);
                        return;
                    }
                    let lastDoctor;
                    let lastDoctorCode = '';
                    for (let i = 0; i < messages.length; ++i) {
                        let 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) {
                            modelUtil.emitDbError(self.eventEmitter, "Search doctor group messages failed", err);
                            return;
                        }
                        // g.code, g.name, gm.msg_id, gm.content
                        let lastGroup;
                        let lastGroupCode = '';
                        for (let i = 0; i < messages.length; ++i) {
                            let 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
                            });
                        }
                        modelUtil.emitData(self.eventEmitter, data);
                    });
                });
            });
        });
    }
}

+ 70 - 0
src/doctor/models/server/management.js

@ -0,0 +1,70 @@
/**
 * 管理端。
 *
 * author: Sand
 * since: 2016.11.20
 */
"use strict";
let configFile = require('../../include/commons').CONFIG_FILE;
let config = require('../../resources/config/' + configFile);
let wlyyRepo = require('../../repository/database/wlyy.db.js');
let imRepo = require('../../repository/database/im.db.js');
let BaseModel = require('../base.model');
let modeUtil = require("../../util/modelUtil");
class Management extends BaseModel {
    constructor() {
        super();
    }
    getDatabaseTables() {
        let self = this;
        let data = new Array(0);
        imRepo.execQuery({
            "sql": "SELECT table_name FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?",
            "args": [config.imDbConfig.database],
            "handler": function (err, result) {
                Management.makeResponse(data, config.wlyyDbConfig.database, err, result);
                wlyyRepo.execQuery({
                    "sql": "SELECT table_name FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?",
                    "args": [config.wlyyDbConfig.database],
                    "handler": function (err, result) {
                        Management.makeResponse(data, config.imDbConfig.database, err, result);
                        modeUtil.emitData(self.eventEmitter, data);
                    }
                });
            }
        });
    }
    static makeResponse(dbStatus, dbName, err, rows) {
        if (err) {
            dbStatus.push({
                name: dbName,
                status: 'Failed',
                message: err
            });
        } else {
            let tableList = [];
            for (let i = 0; i < rows.length; ++i) {
                tableList.push(rows[i].table_name);
            }
            let status = {
                name: dbName,
                status: 'OK',
                tables: tableList
            };
            dbStatus.push(status);
        }
    }
}
module.exports = Management;

+ 10 - 19
src/doctor/models/stats.js

@ -3,17 +3,14 @@
 */
"use strict";
var EventEmitter = require("events").EventEmitter;
let BaseModel = require('./base.model');
let statsRepo = require("../repository/stats.msg.repo.js");
let log = require("../util/log.js");
let modelUtil = require('../util/modelUtil');
var statsRepo = require("../repository/stats.msg.repo.js");
var log = require("../util/log.js");
var modelUtil = require('../util/modelUtil');
var MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
class StatsMessage{
class StatsMessage extends BaseModel{
    constructor(){
        this._eventEmitter = new EventEmitter();
        super();
    }
    /**
@ -21,23 +18,17 @@ class StatsMessage{
     * @param userId
     */
    getBadgeNumber(userId){
        var self = this;
        let self = this;
        statsRepo.getBadgeNumber(userId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(this, "Get badge number failed: ", err);
                modelUtil.emitDbError(self.eventEmitter, "Get badge number failed: ", err);
                return;
            }
            var data = {userId: userId, badge: result};
            this._evenEmitter.emit(MODEL_EVENTS.OK, data);
            let data = {userId: userId, badge: result};
            modelUtil.emitData(self.eventEmitter, data);
        });
    }
    on(event, handler) {
        this._eventEmitter.on(event, handler);
    }
}
module.exports = StatsMessage;

+ 19 - 25
src/doctor/models/system.js

@ -3,22 +3,20 @@
 */
"use strict";
var EventEmitter = require('events').EventEmitter;
let PLATFORMS = require('../include/commons').PLATFORM;
var MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
var PLATFORMS = require('../include/commons').PLATFORM;
let BaseModel = require('./base.model');
let log = require("../util/log.js");
let modelUtil = require('../util/modelUtil');
let getui = require('getui');
var log = require("../util/log.js");
var modelUtil = require('../util/modelUtil');
var getui = require('getui');
let userRepo = require('../repository/doctor.repo.js');
let smRepo = require("../repository/system.msg.repo.js");
let nmRepo = require("../repository/notify.msg.repo.js");
var userRepo = require('../repository/doctor.repo.js');
var smRepo = require("../repository/system.msg.repo.js");
var nmRepo = require("../repository/notify.msg.repo.js");
class SystemMessage {
class SystemMessage extends BaseModel{
    constructor() {
        this._eventEmitter = new EventEmitter();
        super();
    }
    /**
@ -27,23 +25,23 @@ class SystemMessage {
     * @param message
     */
    send(message) {
        var self = this;
        let self = this;
        userRepo.getUserStatus(message.to, function (err, rows) {
            if (err) {
                console.log("Lookup system message receiver failed: ", err);
                this.emit(MODEL_EVENTS.Error, {message: "Lookup system message receiver failed."});
                modelUtil.emitDbError(self.eventEmitter, "Lookup system message receiver failed.", err);
                return;
            }
            if (rows.length == 0) {
                this.emit(MODEL_EVENTS.DataNotFound, {message: "User not found: " + message.to});
                modelUtil.emitDataNotFound(self.eventEmitter, "User not found: " + message.to);
                return;
            }
            var userStatus = rows[0];
            var isOnline = userStatus.is_online;
            var notifyMessage = JSON.stringify({type: 'system_msg', data: message.content});
            let userStatus = rows[0];
            let isOnline = userStatus.is_online;
            let notifyMessage = JSON.stringify({type: 'system_msg', data: message.content});
            // 保存该条推送信息
            smRepo.save(message.to,
@ -53,12 +51,12 @@ class SystemMessage {
                message.content,
                function (err, result) {
                    if (err) {
                        modelUtil.emitDbError(self._eventEmitter, "Save system notify message failed.", err);
                        modelUtil.emitDbError(self.eventEmitter, "Save system notify message failed.", err);
                        return;
                    }
                    // 先通知外层操作已经完成,再处理后续操作。客户可先结束网络连接,减少客户端等待。
                    self._eventEmitter.emit(MODEL_EVENTS.OK, {});
                    modelUtil.emitData(self.eventEmitter, {});
                    // 保存通知到数据库中
                    nmRepo.save(message.to,
@ -69,7 +67,7 @@ class SystemMessage {
                        isOnline,
                        function (err, result) {
                            if (err) {
                                modelUtil.logDbError("Save system notify message failed", err);
                                modelUtil.logError("Save system notify message failed", err);
                                return;
                            }
@ -90,10 +88,6 @@ class SystemMessage {
                });
        });
    }
    on(event, handler) {
        this._eventEmitter.on(event, handler);
    }
}
module.exports = SystemMessage;

+ 79 - 0
src/doctor/models/user.status.js

@ -0,0 +1,79 @@
/**
 * 用户状态模型。此处状态是指用户移动应用App状态,如用户是否已登录,App是否已打开。
 *
 * 用户状态区分患者与医生。**当前**仅是与医生相关,若需要增加患者相关内容,
 * 需要增加在用户判断。
 *
 * author: Sand
 * since: 2016.11.20
 */
"use strict";
let BaseModel = require('./base.model');
let doctorRepo = require('../repository/doctor.repo');
let modelUtil = require("../util/modelUtil.js");
let Token = require('./auth/token');
class UserStatus extends BaseModel {
    constructor() {
        super();
    }
    /**
     * 登录。
     */
    login(userId, token, clientId, platform) {
        let self = this;
        doctorRepo.deleteToken(token, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Error occurs when user login and delete token', err);
            } else {
                doctorRepo.login(userId, token, clientId, platform,
                    function (err, result) {
                        if (err) {
                            modelUtil.emitDbError(self.eventEmitter, 'Error occurs when user login and delete token', err);
                        }
                        let token = new Token(userId, clientId, platform);
                        modelUtil.emitData(self.eventEmitter, {token: token.value});
                    });
            }
        });
    }
    /**
     * 退出。
     */
    logout(userId) {
        let self = this;
        doctorRepo.logout(userId,
            function (err, result) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Logout failed', err);
                    return;
                }
                modelUtil.emitData(self.eventEmitter, {});
            });
    }
    /**
     * 更新用户状态。
     */
    updateStatus(userId, status) {
        let self = this;
        doctorRepo.updateStatus(userId, status,
            function (err, result) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Update user status failed', err);
                    return;
                }
                modelUtil.emitData(self.eventEmitter, {});
            });
    }
}
module.exports = UserStatus;

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

@ -81,7 +81,7 @@ var im = {
    logout: function (userId) {
        plus.storage.removeItem(plusStorageKey.userId);
        $.ajax({
            type: "get",
            type: "post",
            url: endpoints.logout,
            data: {user_id: userId},
            async: true,

+ 21 - 13
src/doctor/resources/config/config.dev.js

@ -1,5 +1,6 @@
"use strict";
// 三师后台数据库配置
var wlyyDbConfig = {
    host: '172.19.103.77',
    user: 'root',
@ -8,6 +9,7 @@ var wlyyDbConfig = {
    connectionLimit: '50'
};
// IM数据库配置
var imDbConfig = {
    host: '172.19.103.77',
    user: 'root',
@ -16,6 +18,23 @@ var imDbConfig = {
    connectionLimit: '50'
};
// 三师后台
var wlyyServerConfig = {
    host: '172.19.103.87',
    port: 9092
};
// 加密配置
var crypto = {
    algorithm: ''
};
// 透传服务
var transServerConfig = {
    host: '172.19.103.76',
    port: 8000
};
// 企业版的推送配置
var geTuiConfig = {
    HOST: 'https://api.getui.com/apiex.htm',
@ -32,18 +51,6 @@ var geTuiAppStoreCfg = {
    MASTERSECRET : 'pvjCGtRZJx9SRVODkxc816'
};
// 三师后台
var wlyyServerConfig = {
    host: '172.19.103.87',
    port: 9092
};
// 透传服务
var transServerConfig = {
    host: '172.19.103.76',
    port: 8000
};
exports.app = 'IM.Server';
exports.version = '1.0.5.20161107';
exports.debug = true;
@ -57,4 +64,5 @@ exports.imDbConfig = imDbConfig;
exports.geTuiConfig = geTuiConfig;
exports.geTuiAppStoreCfg = geTuiAppStoreCfg;
exports.wlyyServerConfig = wlyyServerConfig;
exports.transServerConfig = transServerConfig;
exports.transServerConfig = transServerConfig;
exports.crypto = crypto;

+ 33 - 12
src/doctor/util/modelUtil.js

@ -1,30 +1,51 @@
/**
 * 模型类模板代码消除工具。
 */
"use strict";
var log = require("./log.js");
var MODEL_EVENTS = require("../include/commons").MODEL_EVENTS;
let log = require("./log.js");
let MODEL_EVENTS = require("../include/commons").MODEL_EVENTS;
function logDbError(description, err) {
    log.error(description, ':', err);
}
/**
 * 发送模型数据成功获取消息。
 *
 * @param eventEmitter
 * @param data
 */
module.exports.emitData = function (eventEmitter, data) {
    eventEmitter.emit(MODEL_EVENTS.OK, data);
};
/**
 * 记录错误,并发送消息。
 * 发送模型未取得数据消息。
 *
 * @param object
 * @param eventEmitter
 * @param description
 */
module.exports.emitDataNotFound = function (eventEmitter, description) {
    eventEmitter.emit(MODEL_EVENTS.DataNotFound, description);
};
/**
 * 发送模型读取数据失败消息。
 *
 * @param eventEmitter
 * @param err
 * @param description
 */
module.exports.emitDbError = function (object, description) {
    logDbError(description, err);
module.exports.emitDbError = function (eventEmitter, description, err) {
    logError(description, err);
    object.emit(MODEL_EVENTS.Error, {message: description});
    eventEmitter.emit(MODEL_EVENTS.Error, {message: description});
};
/**
 * 只记录错误。
 *
 * @type {logDbError}
 * @type {logError}
 */
module.exports.logDbError = logDbError;
function logError(description, err) {
    log.error(description, ':', err);
}
module.exports.logError = logError;