Bläddra i källkod

Merge branch 'feature-refactor' of yeshijie/im.doctor into feature-refactor

yeshijie 6 år sedan
förälder
incheckning
45c0b8730e

+ 41 - 18
readme.md

@ -120,34 +120,38 @@ REST API遵循REST最佳实践,规范命名URL中的每个部分。注意POST
    Sessions: {
        Base: '/api/v2/sessions',
        Session: '/:session_id/session',                                //获取会话
        Session: '/:session_id/session',                                // 获取会话
        SessionListByType: '/sessionListByType',                        // 按会话类型获取会话
        SessionCountByType: '/sessionCountByType',                      // 按会话类型获取会话数量
        SessionSticky: '/:session_id/sticky',                           // 会话置顶,置顶使用PUT,取消置顶使用DELETE
        SessionStatus: '/:session_id/status',                           //更新状态
        SessionStatus: '/:session_id/status',                           // 更新状态
        SessionName: '/:session_id/name',                               // 更新会话名称
        RecentSessions: '/recent',                                      // 最近会话,使用类型过滤出'患者'或'医生'会话
        IsExist: '/isExist',                                            // 判断会话是否存在(i健康发送muc的im消息会话前会先调用创建会话的方法,这个方法会更新redis中每个成员的最后获取时间,导致未读消息不准)
        Topics: '/:topic_id/topics',
        Topic: '/topics/:topic_id',                          // 议题,指定ID的议题将返回其信息
        Topics: '/:topic_id/topics',                                    // 获取单个议题
        Topic: '/topics/:topic_id',                                     // 议题,指定ID的议题将返回其信息
        TopicEnded: '/:session_id/topics/:topic_id/ended',              // 议题是否已结束,若top_id为current,则检查最后一个议题的状态
        TopicInto: '/:session_id/topics/:topic_id/into',              // 居民进入议题
        TopicList:'/topics',                                          // 议题列表
        HealthTopicList:'/healthTopics',                           //健康咨询
        TopicListByType:'/topicListByType',                  //按类型查找咨询(未回复,进行中,已回复)
        topicListCountByType:'/topicListCountByType',            //按类型查找咨询(未回复,进行中,已回复)的数量
        HealthTeamTopicList:'/healthTeamTopics',                  //健康咨询(区分团队)
        TopicReplyCount:"/topics/count/reply",                        //议题回复数统计
        TopicMessages:'/topic/:topic_id/messages',                    //获取议题消息
        Messages: '/:session_id/messages',                             // 会话消息
        TopicInto: '/:session_id/topics/:topic_id/into',                // 居民进入议题
        TopicList:'/topics',                                            //获取议题列表
        HealthTopicList:'/healthTopics',                                //健康咨询
        TopicListByType:'/topicListByType',                             //按类型查找咨询(未回复,进行中,已回复)
        TopicListCountByType:'/topicListCountByType',                   //按类型查找咨询(未回复,进行中,已回复)的数量
        HealthTeamTopicList:'/healthTeamTopics',                        //健康咨询(区分团队)
        TopicReplyCount:"/topics/count/reply",                          //议题回复数统计
        TopicMessages:'/topic/:topic_id/messages',                      //议题消息
        Messages: '/:session_id/messages',                              // 会话消息
        MessagesByTopic: '/:session_id/topics/:topic_id/messages',      // 议题消息
        Message: '/:session_id/messages/:message_id',                   // 单条消息
        SessionsUnreadMessageCount: '/unread_message_count',            // 所有会话的未读消息数
        SessionUnreadMessageCount: '/:session_id/unread_message_count', // 指定会话的未读消息数
        SessionUnreadMessages: '/:session_id/messages/unread',           // 会话未读消息
        SessionUnreadMessages: '/:session_id/messages/unread',          // 会话未读消息
        ParticipantUpdate:'/:session_id/participant/update',//更新成员=删除旧成员,新增新成员
        ParticipantUpdate:'/:session_id/participant/update',            //更新成员=删除旧成员,新增新成员
        Participants: '/:session_id/participants',                      // 会话所有成员
        ParticipantsAvatar: '/:session_id/participants/avatars',        // 会话所有成员头像
        Participant: '/:session_id/participants/:participant_id',       // 会话单个成员
        Participant: '/:session_id/participants/:participant_id',       // 会话单个成员(多个participant_id 用英文逗号间隔)
        ParticipantAvatar: '/:session_id/participants/:participant_id/avatars'  // 会话单个成员头像
    }
### 业务分析
@ -169,7 +173,11 @@ REST API遵循REST最佳实践,规范命名URL中的每个部分。注意POST
            11、预留
            12、小视频消息
            13、预留
            
            14、进入议题 系统发送的会话消息
            15、续方审核消息消息
            16、续方咨询血糖血压咨询消息
            17、续方咨询随访问卷消息
    **会话类型** 
    
        sessions的type字段
@ -180,7 +188,11 @@ REST API遵循REST最佳实践,规范命名URL中的每个部分。注意POST
            c、type =3 消息保存group_messages、行政团队聊天会话
            
            d、type =0 消息保存system_messages 系统聊天会话
            
            e、type =4 临时讨论组
            f、type =5 专科医生和家庭医生的固定组
            g、type =8 续方咨询
        sessions的business_type字段
        
            a、business_type =1 此会话不包含患者
@ -260,6 +272,17 @@ select w.* from  muc_messages w ,(
select m.`timestamp` as begin_date,m2.`timestamp` as end_date,t.session_id from topics t,muc_messages m, muc_messages m2 where m.id = t.start_message_id and m2.id = t.end_message_id and  t.session_id = '4d5be29f8ba0413d8658441902b958ff_c7a121954a3a4fae84852fd5668b590d_2'
) s where w.session_id = s.session_id and w.`timestamp` >= s.begin_date and w.`timestamp`<=s.end_date;
-- 系统不稳定的时候会出现wlyy和im库其中一个数据库的数据没有新增,目前是手动处理,后续可以考虑写job定时处理脏数据
SELECT * from wlyy.wlyy_patient WHERE mobile = '';-- 查找居民
SELECT * from wlyy.wlyy_consult WHERE patient = '';-- 查找居民咨询
SELECT * from wlyy.wlyy_consult_team WHERE patient = '';-- 查找居民咨询
SELECT * from im.topics WHERE id = ''; -- 查找议题
SELECT * from im.sessions WHERE id = ''; -- 查找会话
SELECT * from im.muc_messages WHERE session_id = '' ORDER BY `timestamp` desc;-- 查找聊天记录
(ps:大部分是im库有数据,wlyy库没有数据,此时只需要吧wlyy_consult和wlyy_consult_team的数据手动插入即可)
###更改NODE插件数据源在安装完成NODE及配置完成环境变量后执行
    npm config set registry https://registry.npm.taobao.org
    设置完成后执行npm install 即可安装相对于的插件。

+ 2 - 0
src/server/endpoints/url.initializer.js

@ -16,6 +16,7 @@ let socket = require('../controllers/socket');
// endpoints
let application = require('./v2/application.endpoint');
let message = require('./v2/message.endpoint');
let users = require('./v2/user.endpoint');
let sessions = require('./v2/session.endpoint');
let topics = require('./v2/topic.endpoint');
@ -51,6 +52,7 @@ class UrlInitializer {
        });
        app.use(APIv2.Application.Base, application);
        app.use(APIv2.Message.Base, message);
        app.use(APIv2.Management.Base, management);
        app.use(APIv2.Users.Base, users);
        app.use(APIv2.Sessions.Base, sessions);

+ 33 - 0
src/server/endpoints/v2/message.endpoint.js

@ -0,0 +1,33 @@
/**
 * 独立的发送消息接口
 */
"use strict";
let express = require('express');
let router = express.Router();
let ObjectUtil = require('../../util/object.util');
let ControllerUtil = require('../../util/controller.util');
let APIv2 = require('../../include/endpoints').APIv2;
let MODEL_EVENTS = require('../../include/commons').MODEL_EVENTS;
let Messages = require('../../models/messages/messages');
/**
 * 发送消息
 */
router.post(APIv2.Message.Send, function (req, res) {
    let payload = req.body;
    let testing = ObjectUtil.fieldsCheck(payload, "sender_id", "sender_name", "content_type", "content");
    if (!testing.pass) {
        throw {httpStatus: 406, message: testing.message}
    }
    // 消息的发送时间由服务端决定
    payload.timestamp = new Date((new Date().getTime()));
    let messages = new Messages();
    ControllerUtil.regModelEventHandler(messages, res);
    messages.sendMessage(payload);
});
module.exports = router;

+ 1 - 1
src/server/endpoints/v2/topic.endpoint.js

@ -84,7 +84,7 @@ router.get(APIv2.Sessions.TopicListByType,function (req,res) {
});
router.get(APIv2.Sessions.topicListCountByType,function (req,res) {
router.get(APIv2.Sessions.TopicListCountByType,function (req,res) {
    let user = req.query.user;
    let status = req.query.status;
    let type = req.query.type;

+ 6 - 1
src/server/include/endpoints.js

@ -13,6 +13,11 @@ const APIv2 = {
        Health: '/health',
        DbStatus: '/db'
    },
    Message: {
        Base: '/api/v2/message',
        Send: '/send'                                                  //发送消息,和会话无关,内外网通信
    },
    Users: {
        Base: '/api/v2/users',
@ -42,7 +47,7 @@ const APIv2 = {
        TopicList:'/topics',                                            //获取议题列表
        HealthTopicList:'/healthTopics',                                //健康咨询
        TopicListByType:'/topicListByType',                             //按类型查找咨询(未回复,进行中,已回复)
        topicListCountByType:'/topicListCountByType',                   //按类型查找咨询(未回复,进行中,已回复)的数量
        TopicListCountByType:'/topicListCountByType',                   //按类型查找咨询(未回复,进行中,已回复)的数量
        HealthTeamTopicList:'/healthTeamTopics',                        //健康咨询(区分团队)
        TopicReplyCount:"/topics/count/reply",                          //议题回复数统计
        TopicMessages:'/topic/:topic_id/messages',                      //议题消息

+ 41 - 0
src/server/models/messages/messages.js

@ -9,12 +9,16 @@ let SessionRepo = require('../../repository/mysql/session.repo');
let RedisClient = require('../../repository/redis/redis.client.js');
let ModelUtil = require('../../util/model.util');
var ObjectUtil = require("../../util/object.util.js");
let WechatClient = require("../client/wechat.client.js");
let AppClient = require("../client/app.client.js");
let mongoose = require('mongoose');
let redis = RedisClient.redisClient().connection;
let log = require('../../util/log.js');
let configFile = require('../../include/commons').CONFIG_FILE;
let config = require('../../resources/config/' + configFile);
let logger = require('../../util/log');
let pubSub = require("../redis/pubSub.js");
const REDIS_KEYS = require('../../include/commons').REDIS_KEYS;
@ -152,6 +156,43 @@ class Messages extends RedisModel {
    /**
     * 内外网通信。
     * 消息内容 存系统表
     * @param message
     */
    sendMessage(message) {
        let self = this;
        let messages = new Messages();
        let messageId = mongoose.Types.ObjectId().toString();
        let sessionType =0;
        message.id = messageId;
        message.session_id = "system";
        messages.saveMessageToMysql("system", sessionType, messageId, message, function (err, res) {
            if (err) {
                ModelUtil.emitError(self.eventEmitter, {message: "Failed to save message to mysql: " + err});
            } else {
                message.timestamp = message.timestamp.getTime();
                let targetUserId = message.sender_name;
                //告知医生新消息
                WechatClient.sendSocketMessageToDoctor(targetUserId,message);
                if(config.environment!='local'){//pc版不推送个推,通过redis的publish
                    AppClient.sendNotification(targetUserId, message,sessionType,1);
                }
                //外网pcim通过socket推送
                WechatClient.sendPcImSocket(targetUserId,message,sessionType);
                //redis发布消息
                if(config.pubSubSwitch) {//接收订阅消息处理开关,本地运行和测试库单独运行时防止用户接收消息2次
                    pubSub.publish(config.pubChannel,JSON.stringify(message));
                }
                ModelUtil.emitOK(self.eventEmitter, {status: 200});
            }
        });
    }
    /**
     * 保存Message 到mysql
     * @param message 消息对象

+ 0 - 3
src/server/models/sessions/sessions.js

@ -1504,9 +1504,6 @@ class Sessions extends RedisModel {
        }
    }
    static getMessagesBySessionId(){
    }
    sendTopicMessages(topicId, message) {
        let self = this;

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

@ -39,7 +39,7 @@ class PatientRepo {
     */
    static findWechatOpenIds(code, handler){
        var sql = "SELECT m.family_member code,p.name,p.openid from wlyy.wlyy_patient p,wlyy.wlyy_patient_family_member m" +
            "  WHERE m.patient = ? and m.family_member=p.code and p.openid is not null" +
            "  WHERE m.patient = ? and m.family_member=p.code and p.openid is not null and m.is_authorize = 1 " +
            " UNION ALL" +
            "  SELECT p.code,p.name,p.openid  from wlyy.wlyy_patient p WHERE p.code = ?";
        ImDb.execQuery({

+ 3 - 3
src/server/repository/mysql/search.repo.js

@ -24,7 +24,7 @@ class SearchRepo {
            " UNION " +
            "SELECT s.id " +
            "FROM sessions s, participants p " +
            "WHERE p.participant_id = ? AND p.session_id = s.id AND s.`type` IN (2, 3)";
            "WHERE p.participant_id = ? AND p.session_id = s.id AND s.`type` IN (2, 3, 4)";
        ImDb.execQuery({
            sql: sql,
@ -46,7 +46,7 @@ class SearchRepo {
            " UNION " +
            "SELECT s.id " +
            "FROM sessions s, participants p " +
            "WHERE p.participant_id = ? AND p.session_id = s.id  AND s.`type` IN (2,3)  and s.id not in(" +
            "WHERE p.participant_id = ? AND p.session_id = s.id  AND s.`type` IN (2,3,4)  and s.id not in(" +
            " select DISTINCT p1.session_id from  participants p1 ,topics t where p1.participant_id = ? and  t.session_id = p1.session_id  " +
            ") ";
        ImDb.execQuery({
@ -141,7 +141,7 @@ class SearchRepo {
        let sql = "SELECT * FROM(" +
            "SELECT s.id, s.name, s.type, s.create_date, s.business_type,GROUP_CONCAT(u. NAME) as participant_name " +
            "FROM sessions s,  doctors u ,participants p " +
            "WHERE s.id IN (?) and s.type in (3,5) AND s.id = p.session_id AND p.participant_id = u.id and p.participant_id<>? AND (u.name like ? or s.name like ?) group by s.id " +
            "WHERE s.id IN (?) and s.type in (3,4) AND s.id = p.session_id AND p.participant_id = u.id and p.participant_id<>? AND (u.name like ? or s.name like ?) group by s.id " +
            ") X LIMIT ?, ?";
        keyword = '%' + keyword + '%';

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

@ -8,6 +8,8 @@
let log = require('../../util/log');
let ImDb = require('../mysql/db/im.db');
let configFile = require('../../include/commons').CONFIG_FILE;
let config = require('../../resources/config/' + configFile);
class WeChatTokenRepo {
    constructor() {
@ -20,7 +22,7 @@ class WeChatTokenRepo {
     */
    static findOne(handler) {
        ImDb.execQuery({
            "sql": "select access_token, expires_in, add_timestamp from wlyy.wx_access_token where acc_id = 'gh_ffd64560fb21' order by add_timestamp desc limit 0, 1"
            "sql": "select access_token, expires_in, add_timestamp from wlyy.wx_access_token where acc_id = '"+config.wechatConfig.accId+"' order by add_timestamp desc limit 0, 1"
            , "handler": handler
        });
    };
@ -35,7 +37,7 @@ class WeChatTokenRepo {
     */
    static save(accessToken, expireIn, createTime, handler) {
        ImDb.execQuery({
            "sql": "insert into wlyy.wx_access_token (acc_id,access_token, expires_in, add_timestamp) values ('gh_ffd64560fb21',?,?,?)"
            "sql": "insert into wlyy.wx_access_token (acc_id,access_token, expires_in, add_timestamp) values ('"+config.wechatConfig.accId+"',?,?,?)"
            , "args": [accessToken, expireIn, createTime.getTime()]
            , "handler": handler
        });

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

@ -50,13 +50,13 @@ let getTuiConfig = {
// 微信配置
let wechatConfig = {
    appId: 'wx1f129f7b51701428',
    appSecret: '988f005d8309ed1795939e0f042431fb',
    appId: 'wxddece6347fe7fe87',
    appSecret: '41ade403de3d0e2e450f54a324ec013a',
    token: '27eb3bb24f149a7760cf1bb154b08040',
    accId: 'gh_ffd64560fb21',
    accId: 'gh_710bf0b315a1',
    baseUrl: 'ehr.yihu.com/wlyy',
    template: {
        consultTemplate: '-dr4QNyFoRvVsf8uWxXMC1dRyjwnbUuJwJ21vBLhf18'  // 咨询回复模板
        consultTemplate: 'oGFfTWPEYvwwfmcIK1hquZ4-cVXdNomV3bCMLfj97Jc'  // 咨询回复模板
    }
};

+ 1 - 0
src/server/resources/config/config.local.js

@ -51,6 +51,7 @@ let wechatConfig = {
    appId: 'wxad04e9c4c5255acf',
    appSecret: 'ae77c48ccf1af5d07069f5153d1ac8d3',
    token: '27eb3bb24f149a7760cf1bb154b08040',
    accId: 'gh_ffd64560fb21',
    baseUrl: 'www.xmtyw.cn/wlyy',
    template: {
        consultTemplate: '0mF_vHj-ILx8EH8DwzmAi7LqzjqYiU9IrSRRmziTZyc'  // 咨询回复模板

+ 4 - 4
src/server/resources/config/config.test.js

@ -50,13 +50,13 @@ let getTuiConfig = {
// 微信配置
let wechatConfig = {
    appId: 'wx1f129f7b51701428',
    appSecret: '988f005d8309ed1795939e0f042431fb',
    appId: 'wxddece6347fe7fe87',
    appSecret: '41ade403de3d0e2e450f54a324ec013a',
    token: '27eb3bb24f149a7760cf1bb154b08040',
    accId: 'gh_ffd64560fb21',
    accId: 'gh_710bf0b315a1',
    baseUrl: 'ehr.yihu.com/wlyy',
    template: {
        consultTemplate: '-dr4QNyFoRvVsf8uWxXMC1dRyjwnbUuJwJ21vBLhf18'  // 咨询回复模板
        consultTemplate: 'oGFfTWPEYvwwfmcIK1hquZ4-cVXdNomV3bCMLfj97Jc'  // 咨询回复模板
    }
};