1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/wuywd-Vchat

В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
README.md 16 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 25.11.2024 23:54 c367544

💘🍦🙈Vchat — 从头到脚,撸一个社交聊天系统(vue + node + mongodb)

说明

分支代码为线上版,做了相应改动。如默认加入聊天群、后端为适应linux部分代码调整等,建议拉取master。

Проект запуска

注意必须要有node、npm以及mongodb,项目默认mongodb IP地址为127.0.0.1:27017,可以在配置文件中修改。(chatServer\utils\database.js)

    cd chatRoom
    npm install 安装前端依赖
    npm run build 编译前端代码
    cd ..
    cd chatServer
    npm install 安装后端依�канть
    npm run create 初始化数据库(号码池、表情包)
    npm start 启动服务
    在浏览器中打开 localhost:9988 即可

前言


项目开始是因为工作需要一个聊天室功能,但是因为某些原因最终选用的是基于xmpp协议的Strophe.js写的。于是就想用node自己写一套,本来只是想简单的写个聊天页面,但是写完了又不满意,所以不断的重构(似乎可以理解产品经理为什么老是改需求了๑乛◡乛๑)。

很多东西,比如mongodb,我也是第一次用,以前只接触过mysql。所以都是一边学一边写,利用工作之余的时间,断断续续的写了几个月(这次讲的是V0.9.0版本,项目还在更新中···),包含了一整套的前后端交互。uI是按照自己的感觉来的,没有设计天分(话说主题切换到现在还只有一套主题,实在是不好设计啊~),轻喷---。项目还有很多需要优化完善的地方,欢迎大家提到issues(文末有q群,欢迎一起学习交流)。

闲话少说,本文主要讲项目的设计流程,以及部分功能实现思路。对项目感兴趣的同学请移步源码 Vchat — 从头到脚,撸一个在线聊天的web应用(vue + node + mongodb)

*这是分隔线---------------------------------------深夜码字,最近真冷

相关地址

项目架构

  • 技术栈

前端主要采用了vue全家桶,没什么多说的,脚手架构建项目,vuex状态管理,vue-router控制路由,axios进行前后端交互。后端是基于node搭的服务,用的是express。我为什么不用koa呢,纯粹是图方便,因为koa不熟(捂脸)。聊天最重要的当然是通信,项目用socket.io来进行前后端通信。

数据库是mongoDB,主要有用户、好友、群聊、消息、表情、号码池等。

  • 功能概览

  • 目录结构

    // 前端
    ├─build
    ├─config
    ├─src
      ├─api                                  // 接口api
      ├─assets                               // 静态资源
        └─img
      ├─directives                           // 全局指令
      ├─libs                                 // 全局组件
        ├─bscroll
        ├─dropdown
        ├─icon
        ├─nodata
        ├─PhotoSwipe
        ├─uploadPopover
        └─vScroll
      ├─router                                // 路由
      ├─store                                 // 状态管理
      ├─utils                                 // 方法
      └─views
          ├─applicationModel
            ├─games                          // 游戏
            
            └─sub                            // 应用
          ├─components                        // 组件
            ├─APlayer
            ├─chat
            ├─cropper
            ├─DPlayer
            └─header
          └─personalModel                     // 主页
              ├─appModel                       // 天气等
              ├─friendModel                    // 好友
              └─groupModel                     // 群聊
    └─static
        ├─css                                  // 样式文件
        ├─font                                 // 字体文件
        └─theme                                // 主题
            └─vchat

功能设计

  • 登录注册

Vchat中用户注册时,会随机指定一个code号码,而这个code号是从预先生成的一个号码池(号码池存在mongodb)中取的。初始指定10000001-10001999的号码段为用户code, 100001-100999的号码段为群聊code。用户可以凭借code号或者账号登录。

    // 号码池设计
    * code 号码
    * status 1 已使用 0 未使用
    * type  1 用户 2 群聊
    * random   随机数索引用于随机查找某一条
    // user表主要字段
    * name 账号
    * pass 密码
    * avatar 头像
    * signature 个性签名
    * nickname 昵称
    * email 邮件
    * phone 手机
    * sex 性别
    * bubble 气泡
    * projectTheme 项目主题
    * wallpaper 聊天壁纸
    * signUpTime 注册时间
    * lastLoginTime 最后一次登录时间
    * chatColor 聊天文字颜色
    * province 
    * city 
    * town 
    * conversationsList 会话列表
    * cover 封面列表

注册时,需要判断账号是否已存在,以及随机取得的code需要在号码池中标记为已被使用,用户密码用md5加密等。

    // md5 密码加密
    const md5 = pass => { // 避免多次调用MD5报错
        let md5 = crypto.createHash('md5');
        return md5.update(pass).digest("hex");
    };

登录同样需要判断用户是否已注册,以及支持账号和code两种方式登录。 ``` const login = (params, callback) => { // 登录 baseList.users .find({ // mongodb中可以直接用$or表示或关系 $or: [{"name": params.name}, {"code": params.name}] }) .then(r => { if (r.length) { let pass = md5(params.pass); if (r[0]['pass'] === pass) { //更新最后一次登录时间 此处直接写Date.now 会报错 需要Date.now()!!!; baseList.users.update({name: params.name}, {lastLoginTime: Date.now()}).then(raw => { console.log(raw); }); callback({code: 0, data: {name: r[0].name, photo: r[0].photo}}); } else { callback({code: -1}); } } else { callback({code: -1}); } }) };


**> 登录权限管理**

1. 后端设置全局中间件,将没有登录的api请求统一返回status: 0
``` javascript
app.use('/v*', (req, res, next) => {
    if (req.session.login) {
        next();
    } else {
        if (req.originalUrl === '/v/user/login' || req.originalUrl === '/v/user/signUp') {
            next();
        } else {
            res.json({
                status: 0
            });
        }
    }
});
  1. 前端用axios统一设置拦截器
// http response 服务器响应拦截器,这里拦截未登录和401错误,并重新跳入登页重新获取token
instance.interceptors.response.use(
    response => { // 拦截未登录
        if (response.data.status === 0) {
            router.replace('/');
        }
        return response;
    },
    error => {
        if (error.response) {
            switch (error.response.status) {
                case 401:
                    // 这里写清除token的代码
                    router.replace('/');
            }
        }
        return Promise.reject(error.response.data)
    });
  • Сообщение

vchat中,消息种类包括好友或者加群申请、回复申请(同意or拒绝)、入群通知、聊天消息(文字、图片、表情、文件)

// 代码 и ключи в парах ключ-значение оставлены без перевода, переведено только значение ключа.

在实现消息发送之前,需要大体的了解一些socket.io的api。详细api文档可以查看socket.io

    // 所有的消息请求都是建立在已连接的基础上的
    io.on('connect', onConnect);
    // 发送给当前客户端
    socket.emit('hello', 'can you hear me?', 1, 2, 'abc');
    // 发送给所有客户端,除了发送者
    socket.broadcast.emit('broadcast', 'hello friends!');
    // 发送给同在 'game' 房间的所有客户端,除了发送者
    socket.to('game').emit('nice game', "let's play a game");
    // 发送给同在 'game' 房间的所有客户端,包括发送者
    io.in('game').emit('big-announcement', 'the game will start soon');
  1. Присоединиться к комнате

Присоединиться к списку сеансов в комнате, список сеансов будет автоматически добавлен при успешном запросе на добавление друга или запрос на присоединение к группе. Однако вы также можете вручную удалить или добавить, после удаления вы больше не будете получать сообщения от удалённой сессии (аналогично блокировке).

    // 前端 发起加入房间的请求
    this.conversationsList.forEach(v => {
        let val = {
            name: this.user.name,
            time: utils.formatTime(new Date()),
            avatar: this.user.photo,
            roomid: v.id
        };
        this.$socket.emit('join', val);
    });
    // 后端 接受请求后执行加入操作,记录每个房间加入的成员,以及回信告知指定房间已上线成员
    socket.on('join', (val) => {
        socket.join(val.roomid, () => {
            if (OnlineUser[val.name]) {
                return;
            }
            OnlineUser[val.name] = socket.id;
            io.in(val.roomid).emit('joined', OnlineUser); // 包括发送者
        });
    });
  1. Несколько комнат

При одновременном присоединении к нескольким чатам возникает проблема, socket может присоединиться к нескольким комнатам и отправлять сообщения в указанную комнату, но не будет различать сообщения при получении. Другими словами, все сообщения комнаты будут отправлены клиенту. Поэтому нам нужно самостоятельно различать, какое сообщение из какой комнаты, и распространять его. Для этого нам нужен идентификатор комнаты для фильтрации, Vchat использует идентификатор комнаты.

    mes(r) { // 只有本房间的消息才展示
        if (r.roomid === this.currSation.id) {
            this.chatList.push(Object.assign({}, r, {type: 'other'}));
        }
    }
  1. Отправка сообщений
    // 前端
    send(params, type = 'mess') { // 发送消息
        if (!this.message && !params) {
            return;
        }
        let val = {
            name: this.user.name,
            mes: this.message,
            time: utils.formatTime(new Date()),
            avatar: this.user.photo,
            nickname: this.user.nickname,
            read:
``` **4. Запись сообщений**

Все сообщения сохраняются в MongoDB. При переключении комнат происходит получение истории сообщений. В то же время, когда пользователь находится в текущей комнате, только последние сообщения добавляются в DOM, без извлечения из базы данных. По умолчанию окно чата отображает только 100 последних сообщений, но можно просмотреть больше сообщений в журнале чата.

```javascript
// Получение истории сообщений для указанной комнаты на стороне клиента
this.$socket.emit('getHistoryMessages', {roomid: v.id, offset: 1, limit: 100});

// Серверная сторона: связь с таблицей, разбиение на страницы, сортировка
messages.find({roomid: params.roomid})
    .populate({path: 'userM', select: 'signature photo nickname'}) // Связь с основной информацией о пользователе
    .sort({'time': -1})
    .skip((params.offset - 1) * params.limit)
    .limit(params.limit)
    .then(r => {
        r.forEach(v => { // Предотвращение ситуации, когда информация пользователя изменяется после обновления, а данные не обновляются
            if (v.userM) {
                v.nickname = v.userM.nickname;
                v.photo = v.userM.photo;
                v.signature = v.userM.signature;
            }
        });
        r.reverse();
        callback({code: 0, data: r, count: count});
    }).catch(err => {
    console.log(err);
    callback({code: -1});
});

Проектный показ

  • Главная страница

На главной странице нет переведённого текста.

  • Окно чата, можно перетаскивать или масштабировать, есть настройки обоев и цвета текста.

На этом изображении нет переведённого текста.

  • Личные настройки

На этой иллюстрации нет переведённого текста.

  • Пространство приложения

На этом изображении нет переведённого текста.

Дополнительная литература

  • Основы работы с Mongoose
  • Документация socket.io
  • Решение для переключения тем Vchat основано на d2-admin

Группа общения

На изображении нет переведённого текста.

Заключение

В этой статье в основном рассказывается об общем дизайне Vchat и реализации некоторых основных функций. На самом деле, при написании проекта было много проблем, таких как объединение таблиц в mongoose и загрузка файлов. Здесь мы не будем вдаваться в подробности, и я обновлю информацию позже, если будет время. Если Vchat вам полезен, не забудьте поставить звезду.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/wuywd-Vchat.git
git@api.gitlife.ru:oschina-mirror/wuywd-Vchat.git
oschina-mirror
wuywd-Vchat
wuywd-Vchat
master