├── .env
├── .eslintignore
├── .gitignore
├── .prettierignore
├── ChangeLog.md
├── JSDOC.md
├── LICENCE-MAXIM.md
├── README-project.md
├── README.md
├── babel.config.js
├── config
├── rollup.sdk.config.js
├── webpack.dev.config.js
├── webpack.prod.config.js
└── webpack.sdk.config.js
├── floo.sh
├── jsdoc.config.json
├── package.json
├── prettier.config.js
├── public
├── audio
│ └── phone_ring.mp3
├── favicon.ico
├── image
│ ├── about_us-s.png
│ ├── about_us.png
│ ├── add.png
│ ├── audio.png
│ ├── audio_call.png
│ ├── audio_call_switch.png
│ ├── camera_off.png
│ ├── camera_on.png
│ ├── close.png
│ ├── close_no_circle.png
│ ├── contact-s.png
│ ├── contact.png
│ ├── conv-s.png
│ ├── conv.png
│ ├── edit.png
│ ├── file.png
│ ├── file2.png
│ ├── group.png
│ ├── hangup.png
│ ├── im_closer.png
│ ├── im_packup.png
│ ├── im_popover.png
│ ├── im_send_empty.png
│ ├── im_send_full.png
│ ├── im_tips.png
│ ├── im_wechat.png
│ ├── interaction.png
│ ├── loc.png
│ ├── loc2.png
│ ├── logo4.png
│ ├── logob.png
│ ├── mic_off.png
│ ├── mic_on.png
│ ├── minimize.png
│ ├── more.png
│ ├── pickup.png
│ ├── picture.png
│ ├── play.png
│ ├── qr.png
│ ├── roster.png
│ ├── search.png
│ ├── setting-s.png
│ ├── setting.png
│ ├── speaker_off.png
│ ├── speaker_on.png
│ ├── splash.png
│ ├── sw_off.png
│ ├── sw_on.png
│ ├── unverified.png
│ ├── verify_failed.png
│ └── verifyed.png
└── index.html
├── src
├── App.vue
├── css
│ ├── contact.css
│ ├── content.css
│ ├── header.css
│ ├── index.css
│ ├── layers.css
│ ├── login.css
│ ├── reg.css
│ ├── setting.css
│ ├── snackbar.css
│ ├── support.css
│ └── util.css
├── main.js
├── sdk
│ ├── core
│ │ ├── base
│ │ │ ├── dataLogics.js
│ │ │ ├── index.js
│ │ │ ├── io
│ │ │ │ ├── httpIo.js
│ │ │ │ └── index.js
│ │ │ ├── messageMaker.js
│ │ │ └── messageReceiver.js
│ │ ├── protocol
│ │ │ ├── class
│ │ │ │ ├── conversation.js
│ │ │ │ ├── conversationunread.js
│ │ │ │ ├── frame.js
│ │ │ │ ├── groupnotice.js
│ │ │ │ ├── index.js
│ │ │ │ ├── info.js
│ │ │ │ ├── messagebody.js
│ │ │ │ ├── meta.js
│ │ │ │ ├── notice.js
│ │ │ │ ├── provision.js
│ │ │ │ ├── rosternotice.js
│ │ │ │ ├── rtcsignal.js
│ │ │ │ ├── status.js
│ │ │ │ ├── syncdl.js
│ │ │ │ ├── syncul.js
│ │ │ │ ├── unreaddl.js
│ │ │ │ ├── usernotice.js
│ │ │ │ └── xid.js
│ │ │ ├── conversation.js
│ │ │ ├── groupnotice.js
│ │ │ ├── index.js
│ │ │ ├── info.js
│ │ │ ├── make.sh
│ │ │ ├── messagebody.js
│ │ │ ├── rosternotice.js
│ │ │ ├── rtcsignal.js
│ │ │ ├── usernotice.js
│ │ │ ├── xid.js
│ │ │ └── xsync.js
│ │ └── rtc
│ │ │ ├── janus.js
│ │ │ └── socketCls.js
│ ├── index.js
│ ├── manage
│ │ ├── dnsManager.js
│ │ ├── groupManage.js
│ │ ├── rosterManage.js
│ │ ├── rtcManager.js
│ │ ├── sysManage.js
│ │ └── userManage.js
│ ├── model
│ │ ├── conversation.js
│ │ ├── frame.js
│ │ ├── index.js
│ │ ├── message.js
│ │ ├── meta.js
│ │ ├── provision.js
│ │ ├── rtcmessage.js
│ │ ├── syncdl.js
│ │ ├── syncul.js
│ │ └── xid.js
│ └── utils
│ │ ├── cusEvent.js
│ │ ├── encrypt.js
│ │ ├── log.js
│ │ ├── request.js
│ │ ├── static.js
│ │ ├── store.js
│ │ ├── store
│ │ ├── groupStore.js
│ │ ├── infoStore.js
│ │ ├── messageStore.js
│ │ ├── noticeStore.js
│ │ ├── recentStore.js
│ │ ├── rosterStore.js
│ │ └── storeBase.js
│ │ ├── tools.js
│ │ └── types.js
└── ui
│ ├── chatting
│ ├── contact
│ │ ├── conContact.vue
│ │ ├── conConversation.vue
│ │ └── index.vue
│ ├── content
│ │ ├── group
│ │ │ ├── chat.vue
│ │ │ ├── forward.vue
│ │ │ ├── header.vue
│ │ │ ├── index.vue
│ │ │ ├── info.vue
│ │ │ ├── inputer.vue
│ │ │ ├── memberList.vue
│ │ │ └── renderMsg.vue
│ │ ├── index.vue
│ │ ├── notice
│ │ │ ├── groupApplyNotice.vue
│ │ │ ├── groupInvitationNotice.vue
│ │ │ ├── groupNotice.vue
│ │ │ ├── index.vue
│ │ │ ├── rosterNotice.vue
│ │ │ └── systemNotice.vue
│ │ ├── roster
│ │ │ ├── chat.vue
│ │ │ ├── forward.vue
│ │ │ ├── header.vue
│ │ │ ├── index.vue
│ │ │ ├── info.vue
│ │ │ ├── inputer.vue
│ │ │ └── renderMsg.vue
│ │ ├── setting
│ │ │ └── index.vue
│ │ └── verification
│ │ │ └── index.vue
│ ├── header
│ │ └── index.vue
│ └── index.vue
│ ├── index.vue
│ ├── layers
│ ├── addfriend.vue
│ ├── addpop.vue
│ ├── audiocall.vue
│ ├── callinvite.vue
│ ├── changeappid.vue
│ ├── creategroup.vue
│ ├── groupsetting.vue
│ ├── image2.vue
│ ├── index.vue
│ ├── joingroup.vue
│ ├── linklogin.vue
│ ├── qrcode.vue
│ ├── search.vue
│ ├── video.vue
│ └── videocall.vue
│ ├── login
│ ├── bind.vue
│ ├── bindacc.vue
│ ├── bindreg.vue
│ ├── codelogin.vue
│ ├── index.vue
│ ├── login.vue
│ ├── qrlogin.vue
│ ├── regedit.vue
│ └── verifyinfo.vue
│ ├── store
│ ├── contact.js
│ ├── content.js
│ ├── forward.js
│ ├── header.js
│ ├── index.js
│ ├── layer.js
│ ├── login.js
│ └── setting.js
│ ├── support
│ ├── content
│ │ ├── group
│ │ │ ├── chat.vue
│ │ │ ├── index.vue
│ │ │ ├── info.vue
│ │ │ ├── inputer.vue
│ │ │ └── renderMsg.vue
│ │ ├── index.vue
│ │ └── roster
│ │ │ ├── chat.vue
│ │ │ ├── index.vue
│ │ │ ├── info.vue
│ │ │ ├── inputer.vue
│ │ │ └── renderMsg.vue
│ ├── header
│ │ └── index.vue
│ ├── index.vue
│ ├── loading
│ │ └── index.vue
│ ├── minimize
│ │ └── index.vue
│ ├── navigation
│ │ └── index.vue
│ └── skipping
│ │ └── index.vue
│ └── third
│ ├── base64.js
│ ├── crypto1.js
│ ├── events.js
│ ├── marked.min.js
│ └── tools.js
└── vue.config.js
/.env:
--------------------------------------------------------------------------------
1 | # vue environment file, for sdk development
2 | sdk=source
3 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /src/sdk/core/rtc/janus.js
2 | /src/ui/third/marked.min.js
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | .DS_Store
3 | node_modules
4 | /dist
5 | dist.tar.gz
6 | test/unit/coverage
7 | test/e2e/reports
8 | selenium-debug.log
9 | package-lock.json
10 | /lanying-im-web
11 | lanying-im-web.tar.gz
12 |
13 | # wasm temp
14 | wasm/floo.ts
15 | build
16 |
17 | # local env files
18 | .env.local
19 | .env.*.local
20 |
21 | # Log files
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 | yarn.lock
26 | .hintrc
27 |
28 | # Editor directories and files
29 | .idea
30 | *.suo
31 | *.ntvs*
32 | *.njsproj
33 | *.sln
34 | .vscode
35 | *.sw*
36 |
37 | # jsdoc output html dir
38 | docs/
39 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # src/sdk/core/protocol
2 | src/im/
3 | build
4 | dist
5 | node_modules
6 | lanying-im-web
7 | *.md
8 |
--------------------------------------------------------------------------------
/LICENCE-MAXIM.md:
--------------------------------------------------------------------------------
1 | Maxim Licence
2 | Version 1.0, December 2018
3 |
4 | This software is part of MaxIM's new generation instant messaging (IM) system.
5 |
6 | You must make sure you have the right privilleges to use it.
7 |
8 | Copyright (C) 2018-2023 MaxIM.Top
9 |
10 | You may obtain a copy of the licence at http://www.maxim.top/LICENCE-MAXIM.md
11 |
12 | As an IM technology company, we are giving IM technologies and sources as well to our customers,
13 |
14 | we would dedicate ourselves to helping them.
15 |
16 | Max professional IM is our MaxIM
17 |
18 | Please contact eva@bmxlabs.com for more information.
19 |
--------------------------------------------------------------------------------
/README-project.md:
--------------------------------------------------------------------------------
1 | ## 蓝莺IM web 版
2 |
3 | 蓝莺IM,是由[美信拓扑](https://www.lanyingim.com/)团队研发的新一代即时通讯云服务,SDK 设计简单集成方便,服务采用云原生技术和多云架构,私有云也可按月付费。
4 |
5 | 蓝莺IM APP 为方便体验试用蓝莺IMSDK 的 DemoApp。开发者可直接[在线试用](https://chat.lanyingim.com),也可在官网[下载页面](https://www.lanyingim.com/downloads/)选择试用所有客户端。
6 |
7 | DemoApp 是为了演示 IM SDK 调用而开发,也因此最好的开发方式为根据 DemoApp 找到功能,然后直接查看使用示例。
8 |
9 | [](https://awesome.re) [](https://github.com/maxim-top/lanying-im-web/) [](https://github.com/maxim-top/lanying-im-web/)
10 |
11 | ## 构建
12 |
13 | 本工程为标准 web 工程,推荐使用 yarn 来操作:
14 |
15 | 1. 构建工程
16 | ```
17 | yarn build
18 | ```
19 | 2. 本地运行
20 |
21 | 配置本地 `/etc/hosts` 表,增加一行
22 |
23 | ```
24 | 127.0.0.1 dev.lanyingim.com
25 | ```
26 |
27 | 然后再运行
28 |
29 | ```
30 | yarn dev
31 | ```
32 |
33 | 3. 打包应用
34 | ```
35 | yarn pack
36 | ```
37 |
38 | ## 开发自己的应用
39 |
40 | 请先修改蓝莺IM AppID
41 |
42 | 打开文件 `./src/App.vue`, 将默认 AppID: welovemaxim 更改为你的应用 AppID,此 AppID 为在[蓝莺IM 后台](https://console.lanyingim.com/)创建应用后获取。
43 |
44 | ## 代码风格
45 |
46 | 代码风格选择的 ESLint + Prettier,基本规则如下:
47 |
48 | 1. 所有缩进设置为 2 ,包括 Style Sheets 中的各种 css 语言文件、html 文件、JavaScript 文件和其它类型文件。
49 | 2. HTML 文件中 script 标签和 style 标签后的首行代码不缩进。
50 | 3. 函数名和花括号的空格
51 | - 函数声明时,函数名后不加括号;
52 | - 在函数表达式中 function 后面括号前不加空格;
53 | - 花括号中(插值表达式/解构赋值)首尾要增加空格。
54 |
55 | Webstorm 设置可参考[这里](https://www.wenyuanblog.com/blogs/webstorm-eslint-prettier-reformat-code.html)。
56 |
57 | ## 常见问题
58 |
59 | 1. 无法导入 flooim,提示
60 |
61 | ```
62 | export 'flooim' was not found in '../im/floo-3.0.0'
63 | ```
64 |
65 | 参考修改 babel.config.js,增加 sourceType: 'unambiguous' 设置:
66 |
67 | ```
68 | module.exports = {
69 | presets: ["@vue/app", {sourceType: 'unambiguous'}],
70 | };
71 | ```
72 |
73 | 2. 找不到 long 模块,提示
74 |
75 | ```
76 | module "third/long" is not defined
77 | ```
78 |
79 | 这是因为 fsevent1 的问题,在 windows 下安装会失败,导致 npm 失败,可参考[这里](https://github.com/angular/angular/issues/13935),解决方法:
80 |
81 | ```
82 | npm i -f
83 | ```
84 |
85 | 3. vue3适配问题
86 |
87 | ```
88 | The requested module '/src/im/floo-3.0.0.js' does not provide an export named 'default'
89 | ```
90 |
91 | 需要通过 yarn 安装 vite-plugin-commonjs 和 vite-plugin-require-transform 两个插件。
92 | 
93 |
94 | ## 其他
95 |
96 | 了解更多信息可以阅读[在线文档](https://docs.lanyingim.com/),或者在本仓库提问,好好玩 :)
97 |
98 | ---
99 |
100 | **蓝莺IM 专业 SDK,私有云按月付费**
101 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 蓝莺IM SDK web 版
2 |
3 | 蓝莺IM,是由[美信拓扑](https://www.lanyingim.com/)团队研发的新一代即时通讯云服务,SDK 设计简单集成方便,服务采用云原生技术和多云架构,私有云也可按月付费。
4 |
5 | 本仓库是 IMSDK 的源码仓库,如果你只是开发自己的聊天 App,建议直接使用蓝莺IM web 版仓库 [lanying-im-web](https://github.com/maxim-top/lanying-im-web),也可以直接[在线试用](https://chat.lanyingim.com)。
6 |
7 | [](https://awesome.re) [](https://github.com/maxim-top/floo-web/) [](https://github.com/maxim-top/floo-web/)
8 |
9 | ## 开发
10 |
11 | 本工程为典型 yarn web 工程,开发时使用以下命令:
12 |
13 | 1. 安装所需依赖
14 | ```
15 | yarn
16 | ```
17 | 2. 启动本地服务
18 | ```
19 | yarn dev
20 | ```
21 | 3. 打包 SDK
22 | ```
23 | yarn sdk
24 | ```
25 |
26 | ## 发布
27 |
28 | 如要同步更新发布到 lanying-im-web,可先 clone lanying-im-web 仓库在本地根目录,运行命令
29 |
30 | ```
31 | yarn release
32 | ```
33 |
34 | 此命令会将打包后的 SDK 文件 floo-x.x.js 和其他 UI 代码更新到 lanying-im-web 文件夹,
35 | 然后进入 lanying-im-web 文件夹提交即可。
36 |
37 | ```
38 | cd lanying-im-web && git commit -a
39 | ```
40 |
41 | ## 代码风格
42 |
43 | 代码风格选择的 ESLint + Prettier,基本规则如下:
44 |
45 | 1. 所有缩进设置为 2 ,包括 Style Sheets 中的各种 css 语言文件、html 文件、JavaScript 文件和其它类型文件。
46 | 2. HTML 文件中 script 标签和 style 标签后的首行代码不缩进。
47 | 3. 函数名和花括号的空格
48 | - 函数声明时,函数名后不加括号;
49 | - 在函数表达式中 function 后面括号前不加空格;
50 | - 花括号中(插值表达式/解构赋值)首尾要增加空格。
51 |
52 | Webstorm 设置可参考[这里](https://www.wenyuanblog.com/blogs/webstorm-eslint-prettier-reformat-code.html)。
53 |
54 | ## 生成文档
55 |
56 | ```
57 | yarn doc
58 | ```
59 |
60 | ## 其他
61 |
62 | 了解更多信息可以阅读[在线文档](https://docs.lanyingim.com/quick-start/floo-web-quick-start.html),或者在本仓库提问,好好玩 :)
63 |
64 | ---
65 |
66 | **蓝莺IM 专业 SDK,私有云按月付费**
67 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | // let projectDir = path.join(__dirname, '.');
4 | module.exports = {
5 | presets: ['@vue/app', { sourceType: 'unambiguous' }],
6 | plugins: [
7 | [
8 | 'component',
9 | {
10 | libraryName: 'element-ui',
11 | styleLibraryName: 'theme-chalk'
12 | }
13 | ],
14 | [
15 | 'module-resolver',
16 | {
17 | alias: {
18 | // vue: path.join('vue', 'dist', 'vue.js'),
19 | '/': path.resolve(__dirname, '/'),
20 | '@src': path.resolve(__dirname, 'src'),
21 | '@proj': path.resolve(__dirname),
22 | components: path.resolve(__dirname, 'src/components/'),
23 | models: path.resolve(__dirname, 'src/models/'),
24 | services: path.resolve(__dirname, 'src/services/'),
25 | utils: path.resolve(__dirname, 'src/utils/')
26 | },
27 | extensions: ['', '.js', '.json', '.vue', '.scss', '.css']
28 | }
29 | ]
30 | ]
31 | };
32 |
--------------------------------------------------------------------------------
/config/rollup.sdk.config.js:
--------------------------------------------------------------------------------
1 | import resolve from '@rollup/plugin-node-resolve';
2 | import cjs from '@rollup/plugin-commonjs';
3 | import json from '@rollup/plugin-json';
4 | import builtins from 'rollup-plugin-node-builtins';
5 | import path from 'path';
6 |
7 | const projectDir = path.join(__dirname, '..');
8 | const srcDir = path.join(projectDir, 'src/sdk');
9 | const buildDir = path.join(projectDir, 'build/sdk');
10 | // const dependencies = Object.keys(require('../package.json').dependencies);
11 |
12 | export default [
13 | {
14 | input: path.resolve(srcDir, 'index.js'),
15 | output: [
16 | {
17 | file: path.resolve(buildDir, 'floo-3.0.0.u.js'),
18 | name: 'flooim',
19 | format: 'umd',
20 | sourcemap: false,
21 | globals: {
22 | 'socket.io-client': 'io',
23 | axios: 'axios',
24 | long: 'Long',
25 | 'query-string': 'queryString',
26 | 'protobufjs/light': '$protobuf',
27 | bufferutil: 'bufferutil',
28 | 'utf-8-validate': 'utf8Validate'
29 | }
30 | },
31 | {
32 | file: path.resolve(buildDir, 'floo-3.0.0.c.js'),
33 | format: 'cjs'
34 | },
35 | {
36 | file: path.resolve(buildDir, 'floo-3.0.0.e.js'),
37 | format: 'es'
38 | }
39 | ],
40 | // external: dependencies,
41 | onwarn: function (warning, warn) {
42 | // suppress eval warnings
43 | if (warning.code === 'EVAL' || (warning.code === 'CIRCULAR_DEPENDENCY' && !warning.importer.indexOf(path.normalize('node_modules/')))) {
44 | return;
45 | }
46 | warn(warning);
47 | },
48 | plugins: [
49 | resolve({ preferBuiltins: false }),
50 | cjs({
51 | // include: /node_modules/,
52 | namedExports: {
53 | 'process/index.js': ['nextTick'],
54 | 'events/events.js': ['EventEmitter'],
55 | 'buffer/index.js': ['isBuffer'],
56 | 'axios/index.js': ['defaults', 'interceptors'],
57 | 'protobufjs/light.js': ['roots', 'Root']
58 | }
59 | }),
60 | json(),
61 | builtins()
62 | ]
63 | }
64 | ];
65 |
--------------------------------------------------------------------------------
/config/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 | const CleanWebpackPlugin = require('clean-webpack-plugin');
4 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
5 | const HtmlWebpackPlugin = require('html-webpack-plugin');
6 |
7 | const projectDir = path.join(__dirname, '..');
8 | module.exports = (env) => {
9 | return {
10 | entry: {
11 | vendors: ['vue', 'vuex', 'axios', 'lodash'],
12 | app: path.join(projectDir, 'src', 'main.js')
13 | },
14 | module: {
15 | rules: [
16 | {
17 | test: /\.js$/,
18 | exclude: /(node_modules|lib)/,
19 | loader: 'eslint-loader',
20 | options: {
21 | // eslint options (if necessary)
22 | }
23 | },
24 | {
25 | test: /\.js$/,
26 | exclude: /node_modules/,
27 | use: {
28 | loader: 'babel-loader',
29 | options: {
30 | presets: ['@babel/preset-env']
31 | }
32 | }
33 | }
34 | ]
35 | },
36 | plugins: [
37 | new webpack.HotModuleReplacementPlugin({}),
38 | new CleanWebpackPlugin(['dist'], {
39 | root: projectDir
40 | }),
41 |
42 | new webpack.DefinePlugin({
43 | 'process.env.NODE_ENV': '"development"'
44 | }),
45 |
46 | new MiniCssExtractPlugin({
47 | filename: '[name].css',
48 | chunkFilename: '[id].css'
49 | }),
50 |
51 | new HtmlWebpackPlugin({
52 | template: path.join(projectDir, 'public', 'index.html'),
53 | filename: 'index.html',
54 | inject: 'body',
55 | minify: {
56 | removeComments: true,
57 | collapseWhitespace: true,
58 | removeAttributeQuotes: true
59 | },
60 | favicon: path.join(projectDir, 'public', 'favicon.ico')
61 | }),
62 |
63 | new webpack.HotModuleReplacementPlugin(),
64 |
65 | new webpack.ProvidePlugin({ adapter: ['webrtc-adapter', 'default'] })
66 | ],
67 |
68 | devServer: {
69 | port: 443,
70 | // inline: true,
71 | hot: true,
72 | open: true,
73 | host: '0.0.0.0' || 'dev.lanyingim.com',
74 | disableHostCheck: true,
75 | https: true
76 | // proxy: {
77 | // "**/*.do": {
78 | // target: devConfig.apiUrl,
79 | // onProxyReq (proxyReq) {
80 | // proxyReq.setHeader("host", url.parse(devConfig.apiUrl).host);
81 | // },
82 | // },
83 | // },
84 | },
85 |
86 | optimization: {
87 | splitChunks: {
88 | cacheGroups: {
89 | vendors: {
90 | name: 'vendors',
91 | chunks: 'initial',
92 | minChunks: 2
93 | },
94 | manifest: {
95 | name: 'manifest',
96 | chunks: 'initial',
97 | minChunks: 2
98 | }
99 | }
100 | }
101 | },
102 |
103 | stats: 'normal'
104 | };
105 | };
106 |
--------------------------------------------------------------------------------
/config/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 |
4 | const CleanWebpackPlugin = require('clean-webpack-plugin');
5 | // const ExtractTextWebpackPlugin = require("extract-text-webpack-plugin");
6 | const HtmlWebpackPlugin = require('html-webpack-plugin');
7 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
8 | const TerserPlugin = require('terser-webpack-plugin');
9 | const EncodingPlugin = require('webpack-encoding-plugin');
10 |
11 | const projectDir = path.join(__dirname, '..');
12 | module.exports = (env) => {
13 | return {
14 | entry: {
15 | vendors: ['vue', 'vuex', 'axios', 'lodash'],
16 | app: path.join(projectDir, 'src', 'main.js')
17 | },
18 | module: {
19 | rules: [
20 | {
21 | test: /\.js$/,
22 | exclude: /(node_modules|lib)/,
23 | loader: 'eslint-loader',
24 | options: {
25 | // eslint options (if necessary)
26 | }
27 | },
28 | {
29 | test: /\.js$/,
30 | exclude: /node_modules/,
31 | use: {
32 | loader: 'babel-loader',
33 | options: {
34 | presets: ['@babel/preset-env']
35 | }
36 | }
37 | }
38 | ]
39 | },
40 |
41 | plugins: [
42 | new CleanWebpackPlugin(['dist'], {
43 | root: projectDir
44 | }),
45 |
46 | new webpack.DefinePlugin({
47 | 'process.env.NODE_ENV': '"production"'
48 | }),
49 |
50 | new MiniCssExtractPlugin({
51 | filename: '[name].css',
52 | chunkFilename: '[id].css'
53 | }),
54 |
55 | new HtmlWebpackPlugin({
56 | template: path.join(projectDir, 'public', 'index.html'),
57 | filename: 'index.html',
58 | inject: 'body',
59 | minify: {
60 | removeComments: true,
61 | collapseWhitespace: true,
62 | removeAttributeQuotes: true
63 | },
64 | favicon: path.join(projectDir, 'public', 'favicon.ico')
65 | }),
66 |
67 | new EncodingPlugin({
68 | encoding: 'utf8'
69 | }),
70 |
71 | new webpack.ProvidePlugin({ adapter: ['webrtc-adapter', 'default'] })
72 | ],
73 | optimization: {
74 | splitChunks: {
75 | cacheGroups: {
76 | vendors: {
77 | name: 'vendors',
78 | chunks: 'initial',
79 | minChunks: 2
80 | },
81 | manifest: {
82 | name: 'manifest',
83 | chunks: 'initial',
84 | minChunks: 2
85 | }
86 | }
87 | },
88 | minimize: true,
89 | minimizer: [
90 | new TerserPlugin({
91 | extractComments: {
92 | condition: /^\**!|@preserve|@license|@cc_on/i,
93 | filename: (file, fileData) => {
94 | return file.replace(/\.(\w+)($|\?)/, '.$1.LICENSE$2');
95 | },
96 | banner: (licenseFile) => {
97 | return `License information can be found in ${licenseFile}`;
98 | }
99 | }
100 | })
101 | ]
102 | }
103 | };
104 | };
105 |
--------------------------------------------------------------------------------
/config/webpack.sdk.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const CleanWebpackPlugin = require('clean-webpack-plugin');
3 | const TerserPlugin = require('terser-webpack-plugin');
4 |
5 | const projectDir = path.join(__dirname, '..');
6 | const srcDir = path.join(projectDir, 'src');
7 |
8 | module.exports = (env) => {
9 | return {
10 | entry: './src/sdk/index.js',
11 | output: {
12 | path: path.resolve(projectDir, './build/sdk'),
13 | filename: 'floo-3.0.0.js',
14 | libraryTarget: 'umd',
15 | globalObject: 'this'
16 | },
17 | module: {
18 | rules: [
19 | {
20 | test: /\.js$/,
21 | exclude: /(node_modules|lib)/,
22 | loader: 'eslint-loader',
23 | options: {
24 | // eslint options (if necessary)
25 | }
26 | },
27 | {
28 | test: /\.js$/,
29 | exclude: /(node_modules|bower_components)/,
30 | loader: 'babel-loader',
31 | options: {
32 | presets: ['@babel/preset-env']
33 | }
34 | }
35 | ]
36 | },
37 | plugins: [
38 | new CleanWebpackPlugin(['build'], {
39 | verbose: false,
40 | exclude: ['img'] //不删除img静态资源
41 | })
42 | ],
43 | devServer: {
44 | host: 'dev.lanyingim.com',
45 | port: '443',
46 | // open: true,//自动拉起浏览器
47 | hot: false, //热加载
48 | https: true,
49 | disableHostCheck: true,
50 | headers: {
51 | 'Access-Control-Allow-Origin': '*'
52 | }
53 | },
54 |
55 | resolve: {
56 | alias: {
57 | '@src': path.join(projectDir, 'src'),
58 | '@model': path.join(projectDir, 'src/sdk/model'),
59 | '@utils': path.join(projectDir, 'src/sdk/utils'),
60 | '@core': path.join(projectDir, 'src/sdk/core')
61 | }
62 | },
63 |
64 | optimization: {
65 | minimize: true,
66 | minimizer: [
67 | new TerserPlugin({
68 | extractComments: {
69 | condition: /^\**!|@preserve|@license|@cc_on/i,
70 | filename: (file, fileData) => {
71 | return file.replace(/\.(\w+)($|\?)/, '.$1.LICENSE$2');
72 | },
73 | banner: (licenseFile) => {
74 | return `License information can be found in ${licenseFile}`;
75 | }
76 | }
77 | })
78 | ]
79 | }
80 | };
81 | };
82 |
--------------------------------------------------------------------------------
/floo.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | test ! -n "$1" && echo "Please specify project name" && exit 1
4 |
5 | project=$1
6 | echo "Creating new project: $project"
7 |
8 | pdir="./$project"
9 | mkdir -p $pdir
10 | im_dir="$pdir/src/im"
11 |
12 | cp LICENCE-MAXIM.md $pdir/
13 | cp README-project.md $pdir/README.md
14 | cp ChangeLog.md $pdir/
15 | cp .gitignore $pdir/
16 | cp prettier.config.js $pdir/
17 | cp .prettierignore $pdir/
18 | cp babel.config.js $pdir/
19 | cp vue.config.js $pdir/
20 |
21 | cp package.json $pdir/
22 |
23 | cp -R ./src $pdir/
24 | cp -R ./public $pdir/
25 |
26 | rm -rf $pdir/src/sdk
27 |
28 | mkdir -p $pdir/config
29 | mkdir -p $im_dir
30 | cp ./build/sdk/floo-*.js $im_dir
31 | gsed -i'' -E "s/(.*)\/sdk\/index(.*)/\1\/im\/floo-3.0.0\2/g" $pdir/src/ui/index.vue
32 |
33 | cp ./config/webpack.prod.config.js $pdir/config/
34 | cp ./config/webpack.dev.config.js $pdir/config/
35 |
36 | echo "done."
37 |
--------------------------------------------------------------------------------
/jsdoc.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "source": {
3 | "includePattern": ".+\\.(js|md)$", // Only process file ending in .js, .jsdoc or .jsx
4 | "include": ["src/sdk", "JSDOC.md"], // Check all folders.
5 | "exclude": ["node_modules"] // Be gone, node_modules.
6 | },
7 | "recurseDepth": 10, // Only go 10 levels deep.
8 | "opts": {
9 | "destination": "./docs/", // Where I want my docs to be generated.
10 | "recurse": true // Same as using -r or --recurse
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lanying-im-web",
3 | "version": "3.0.15",
4 | "private": true,
5 | "scripts": {
6 | "prebuild": "yarn",
7 | "build": "vue-cli-service build",
8 | "serve": "vue-cli-service serve",
9 | "lint": "vue-cli-service lint",
10 | "dev": "vue-cli-service serve --fix",
11 | "prod": "vue-cli-service build --mode production --fix",
12 | "prepackage": "yarn prod",
13 | "package": "tar zcvf lanying-im-web.tar.gz dist",
14 | "format": "yarn prettier -w .",
15 | "presdk": "yarn",
16 | "sdk": "webpack --mode production --config ./config/webpack.sdk.config.js",
17 | "sdk2": "rollup --config ./config/rollup.sdk.config.js",
18 | "prerelease": "yarn sdk",
19 | "release": "./floo.sh lanying-im-web",
20 | "doc": "./node_modules/.bin/jsdoc -c ./jsdoc.config.json",
21 | "doc-md": "node_modules/jsdoc-to-markdown/bin/cli.js src/*/*/*.js src/*/*/*/*.js > doc.md"
22 | },
23 | "dependencies": {
24 | "core-js": "2",
25 | "jquery": "3.6.1",
26 | "vue-js-popover": "^1.2.1",
27 | "vuex": "^3.0.1",
28 | "webrtc-adapter": "^8.1.2",
29 | "crypto-js": "4.1.1"
30 | },
31 | "devDependencies": {
32 | "@babel/core": "^7.16.0",
33 | "@babel/plugin-transform-modules-commonjs": "^7.9.0",
34 | "@babel/plugin-transform-runtime": "^7.6.2",
35 | "@babel/preset-env": "^7.16.4",
36 | "@rollup/plugin-commonjs": "^11.1.0",
37 | "@rollup/plugin-json": "^4.0.3",
38 | "@rollup/plugin-node-resolve": "^7.1.3",
39 | "@vue/cli-plugin-babel": "^3.11.0",
40 | "@vue/cli-plugin-eslint": "^4.1.2",
41 | "@vue/cli-service": "^3.11.0",
42 | "@vue/eslint-config-prettier": "^5.0.0",
43 | "assemblyscript": "^0.8.1",
44 | "axios": "^0.26.1",
45 | "babel-core": "^6.26.3",
46 | "babel-eslint": "^10.0.3",
47 | "babel-loader": "^8.2.3",
48 | "babel-plugin-component": "^1.1.1",
49 | "babel-plugin-module-resolver": "^3.2.0",
50 | "babel-preset-env": "^1.7.0",
51 | "babel-preset-es2015": "^6.24.1",
52 | "babel-preset-stage-0": "^6.24.1",
53 | "bufferutil": "^4.0.1",
54 | "clean-webpack-plugin": "^1.0.1",
55 | "element-ui": "^2.12.0",
56 | "eslint": "^6.4.0",
57 | "eslint-config-prettier": "^7.1.0",
58 | "eslint-loader": "^3.0.3",
59 | "eslint-plugin-html": "^5.0.3",
60 | "eslint-plugin-vue": "^6.1.2",
61 | "highlight.js": "^11.8.0",
62 | "html-webpack-plugin": "^4.2.0",
63 | "husky": "^4.3.7",
64 | "jsdoc": "^3.6.10",
65 | "jsdoc-to-markdown": "^7.1.1",
66 | "json-bigint": "1.0.0",
67 | "lodash": "^4.17.11",
68 | "long": "^4.0.0",
69 | "marked-highlight": "^2.0.6",
70 | "mini-css-extract-plugin": "^0.9.0",
71 | "moment": "^2.24.0",
72 | "prettier": "^2.2.1",
73 | "pretty-quick": "^3.1.0",
74 | "protobufjs": "^6.10.1",
75 | "qrcode": "^1.3.3",
76 | "query-string": "^6.2.0",
77 | "rollup-plugin-node-builtins": "^2.1.2",
78 | "socket.io-client": "^2.2.0",
79 | "strip-ansi": "^6.0.0",
80 | "terser-webpack-plugin": "^2.3.5",
81 | "typescript": "^3.7.4",
82 | "uglifyjs-webpack-plugin": "^2.2.0",
83 | "utf-8-validate": "^5.0.2",
84 | "vue": "^2.6.11",
85 | "vue-template-compiler": "^2.6.10",
86 | "webpack": "^4.43.0",
87 | "webpack-cli": "^3.3.11",
88 | "webpack-encoding-plugin": "^0.3.1",
89 | "wrapper-webpack-plugin": "^2.1.0"
90 | },
91 | "eslintConfig": {
92 | "root": true,
93 | "env": {
94 | "node": true
95 | },
96 | "extends": [
97 | "plugin:vue/essential",
98 | "eslint:recommended",
99 | "prettier"
100 | ],
101 | "rules": {
102 | "no-unused-vars": "off"
103 | },
104 | "parserOptions": {
105 | "parser": "babel-eslint"
106 | }
107 | },
108 | "eslintIgnore": [
109 | "/src/im/",
110 | "/dist/",
111 | "/node_modules/"
112 | ],
113 | "husky": {
114 | "hooks": {
115 | "pre-commit": "pretty-quick --staged"
116 | }
117 | },
118 | "postcss": {
119 | "plugins": {
120 | "autoprefixer": {}
121 | }
122 | },
123 | "browserslist": [
124 | "> 1%",
125 | "last 2 versions",
126 | "not ie <= 8"
127 | ]
128 | }
129 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | printWidth: 180,
3 | semi: true,
4 | tabWidth: 2,
5 | useTabs: false,
6 | singleQuote: true,
7 | trailingComma: 'none',
8 | bracketSpacing: true,
9 | htmlWhitespaceSensitivity: 'ignore'
10 | };
11 |
--------------------------------------------------------------------------------
/public/audio/phone_ring.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/audio/phone_ring.mp3
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/favicon.ico
--------------------------------------------------------------------------------
/public/image/about_us-s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/about_us-s.png
--------------------------------------------------------------------------------
/public/image/about_us.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/about_us.png
--------------------------------------------------------------------------------
/public/image/add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/add.png
--------------------------------------------------------------------------------
/public/image/audio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/audio.png
--------------------------------------------------------------------------------
/public/image/audio_call.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/audio_call.png
--------------------------------------------------------------------------------
/public/image/audio_call_switch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/audio_call_switch.png
--------------------------------------------------------------------------------
/public/image/camera_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/camera_off.png
--------------------------------------------------------------------------------
/public/image/camera_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/camera_on.png
--------------------------------------------------------------------------------
/public/image/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/close.png
--------------------------------------------------------------------------------
/public/image/close_no_circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/close_no_circle.png
--------------------------------------------------------------------------------
/public/image/contact-s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/contact-s.png
--------------------------------------------------------------------------------
/public/image/contact.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/contact.png
--------------------------------------------------------------------------------
/public/image/conv-s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/conv-s.png
--------------------------------------------------------------------------------
/public/image/conv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/conv.png
--------------------------------------------------------------------------------
/public/image/edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/edit.png
--------------------------------------------------------------------------------
/public/image/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/file.png
--------------------------------------------------------------------------------
/public/image/file2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/file2.png
--------------------------------------------------------------------------------
/public/image/group.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/group.png
--------------------------------------------------------------------------------
/public/image/hangup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/hangup.png
--------------------------------------------------------------------------------
/public/image/im_closer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/im_closer.png
--------------------------------------------------------------------------------
/public/image/im_packup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/im_packup.png
--------------------------------------------------------------------------------
/public/image/im_popover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/im_popover.png
--------------------------------------------------------------------------------
/public/image/im_send_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/im_send_empty.png
--------------------------------------------------------------------------------
/public/image/im_send_full.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/im_send_full.png
--------------------------------------------------------------------------------
/public/image/im_tips.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/im_tips.png
--------------------------------------------------------------------------------
/public/image/im_wechat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/im_wechat.png
--------------------------------------------------------------------------------
/public/image/interaction.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/interaction.png
--------------------------------------------------------------------------------
/public/image/loc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/loc.png
--------------------------------------------------------------------------------
/public/image/loc2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/loc2.png
--------------------------------------------------------------------------------
/public/image/logo4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/logo4.png
--------------------------------------------------------------------------------
/public/image/logob.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/logob.png
--------------------------------------------------------------------------------
/public/image/mic_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/mic_off.png
--------------------------------------------------------------------------------
/public/image/mic_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/mic_on.png
--------------------------------------------------------------------------------
/public/image/minimize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/minimize.png
--------------------------------------------------------------------------------
/public/image/more.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/more.png
--------------------------------------------------------------------------------
/public/image/pickup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/pickup.png
--------------------------------------------------------------------------------
/public/image/picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/picture.png
--------------------------------------------------------------------------------
/public/image/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/play.png
--------------------------------------------------------------------------------
/public/image/qr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/qr.png
--------------------------------------------------------------------------------
/public/image/roster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/roster.png
--------------------------------------------------------------------------------
/public/image/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/search.png
--------------------------------------------------------------------------------
/public/image/setting-s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/setting-s.png
--------------------------------------------------------------------------------
/public/image/setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/setting.png
--------------------------------------------------------------------------------
/public/image/speaker_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/speaker_off.png
--------------------------------------------------------------------------------
/public/image/speaker_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/speaker_on.png
--------------------------------------------------------------------------------
/public/image/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/splash.png
--------------------------------------------------------------------------------
/public/image/sw_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/sw_off.png
--------------------------------------------------------------------------------
/public/image/sw_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/sw_on.png
--------------------------------------------------------------------------------
/public/image/unverified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/unverified.png
--------------------------------------------------------------------------------
/public/image/verify_failed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/verify_failed.png
--------------------------------------------------------------------------------
/public/image/verifyed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/public/image/verifyed.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 蓝莺IM - 专业SDK,私有云按月付费
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/css/contact.css:
--------------------------------------------------------------------------------
1 | .contact {
2 | float: left;
3 | background: white;
4 | overflow: hidden;
5 | width: 240px;
6 | height: 100%;
7 | border-radius: 10px 0px 0px 10px;
8 | }
9 |
10 | .contact-root {
11 | height: 100%;
12 | overflow-y: auto;
13 | }
14 |
15 | .contact .header {
16 | height: 22px;
17 | padding: 10px 20px;
18 | font-size: 16px;
19 | line-height: 22px;
20 | background: white;
21 | border: none;
22 | }
23 |
24 | .contact .header span {
25 | float: right;
26 | line-height: 22px;
27 | color: #83898f;
28 | }
29 |
30 | .contact .list .item {
31 | height: 24px;
32 | line-height: 24px;
33 | padding: 8px 12px;
34 | }
35 |
36 | .contact .list .item:hover {
37 | background: rgba(176, 208, 253, 0.3);
38 | }
39 |
40 | .contact .list .item .avatar {
41 | width: 24px;
42 | height: 24px;
43 | overflow: hidden;
44 | border-radius: 3px;
45 | float: left;
46 | }
47 |
48 | .contact .list .item .name {
49 | float: left;
50 | height: 24px;
51 | line-height: 22px;
52 | font-size: 14px;
53 | margin-left: 15px;
54 | color: #333;
55 | text-overflow: ellipsis;
56 | overflow: hidden;
57 | max-width: 66.6%;
58 | }
59 |
60 | .contact .l_conversation {
61 | width: 240px;
62 | height: 100%;
63 | overflow-y: auto;
64 | }
65 |
66 | .contact .l_conversation .sel {
67 | background: rgba(176, 208, 253, 0.3);
68 | }
69 |
70 | .contact .l_conversation .item {
71 | height: 60px;
72 | font-size: 12px;
73 | position: relative;
74 | border-bottom: 1px solid #ececec;
75 | }
76 |
77 | .contact .l_conversation .item .unread_number {
78 | position: absolute;
79 | top: 8px;
80 | left: 36px;
81 | height: 14px;
82 | color: white;
83 | background: red;
84 | font-size: 10px;
85 | font-weight: bold;
86 | padding: 0 3px;
87 | border-radius: 7px;
88 | line-height: 14px;
89 | min-width: 8px;
90 | text-align: center;
91 | }
92 |
93 | .contact .l_conversation .item .avatar {
94 | height: 32px;
95 | width: 32px;
96 | border-radius: 3px;
97 | margin: 14px 10px 0px 10px;
98 | float: left;
99 | }
100 |
101 | .contact .l_conversation .item .name {
102 | margin-left: 60px;
103 | line-height: 20px;
104 | padding-top: 12px;
105 | color: #000;
106 | text-overflow: ellipsis;
107 | overflow: hidden;
108 | max-width: 40%;
109 | white-space: nowrap;
110 | }
111 |
112 | .contact .l_conversation .item .last_msg_time {
113 | position: absolute;
114 | right: 10px;
115 | line-height: 10px;
116 | margin-top: -14px;
117 | font-size: 10px;
118 | color: #8798a4;
119 | }
120 |
121 | .contact .l_conversation .item .last_msg {
122 | height: 20px;
123 | line-height: 20px;
124 | margin-left: 60px;
125 | color: #8798a4;
126 | text-overflow: ellipsis;
127 | white-space: nowrap;
128 | overflow: hidden;
129 | max-width: 66.6%;
130 | }
131 |
132 | .contact .l_conversation .item .last_msg .at_tips {
133 | color: red;
134 | }
135 |
--------------------------------------------------------------------------------
/src/css/header.css:
--------------------------------------------------------------------------------
1 | .header {
2 | height: 48px;
3 | background: #47b6ff;
4 | border-radius: 10px 10px 0px 0px;
5 | text-overflow: ellipsis;
6 | overflow: hidden;
7 | border-bottom: 1px solid #e6e6e6;
8 | }
9 |
10 | .header .searchArea {
11 | height: 48px;
12 | width: 280px;
13 | float: left;
14 | }
15 |
16 | .header .searchArea input {
17 | width: 180px;
18 | height: 24px;
19 | float: left;
20 | margin-left: 10px;
21 | margin-top: 11px;
22 | border: 1px solid rgba(255, 255, 255, 0.5);
23 | border-radius: 100px;
24 | background-image: url(/image/search.png);
25 | filter: brightness(0) invert(1);
26 | background-repeat: no-repeat;
27 | background-size: 17px 17px;
28 | background-position: 8px center;
29 | background-color: rgba(255, 255, 255, 0);
30 | text-indent: 40px;
31 | font-size: 14px;
32 | }
33 |
34 | .header .searchArea .addBtn {
35 | float: left;
36 | width: 20px;
37 | height: 20px;
38 | background-image: url(/image/add.png);
39 | cursor: pointer;
40 | margin: 14px 0px 0px 20px;
41 | background-size: 20px 20px;
42 | filter: brightness(0) invert(1);
43 | }
44 |
45 | .header .tab {
46 | height: 48px;
47 | float: left;
48 | }
49 |
50 | .header .tab .stab {
51 | float: left;
52 | margin: 14px 36px 0px 0px;
53 | }
54 |
55 | .header .tab .stab .unread_number {
56 | position: relative;
57 | left: -5px;
58 | color: white;
59 | background: red;
60 | font-size: 10px;
61 | font-weight: bold;
62 | padding: 0 5px;
63 | border-radius: 10px;
64 | line-height: 14px;
65 | min-width: 8px;
66 | text-align: center;
67 | }
68 |
69 | .header .tab .stab img {
70 | width: 20px;
71 | height: 20px;
72 | filter: brightness(0) invert(1);
73 | }
74 |
75 | .header .profile {
76 | height: 48px;
77 | float: right;
78 | }
79 |
80 | .header .profile .proAvater {
81 | float: right;
82 | width: 30px;
83 | height: 30px;
84 | border-radius: 15px;
85 | background-size: 30px 30px;
86 | background-repeat: no-repeat;
87 | margin-right: 10px;
88 | margin-top: 9px;
89 | }
90 |
91 | .header .profile .proname {
92 | float: right;
93 | margin-right: 20px;
94 | line-height: 20px;
95 | margin-top: 14px;
96 | font-size: 16px;
97 | color: white;
98 | text-overflow: ellipsis;
99 | overflow: hidden;
100 | max-width: 155px;
101 | }
102 |
103 | .header .supportname {
104 | float: right;
105 | margin-right: 20px;
106 | line-height: 20px;
107 | margin-left: 6px;
108 | font-size: 16px;
109 | color: white;
110 | }
111 |
--------------------------------------------------------------------------------
/src/css/index.css:
--------------------------------------------------------------------------------
1 | @import './util.css';
2 | @import './login.css';
3 | @import './reg.css';
4 |
5 | @import './header.css';
6 | @import './contact.css';
7 | @import './content.css';
8 | @import './support.css';
9 | @import './setting.css';
10 | @import './layers.css';
11 | @import './snackbar.css';
12 |
13 | /**** log 的css 先放这里 ***/
14 | #slog {
15 | position: absolute;
16 | top: 5px;
17 | left: 5px;
18 | font-size: 8px;
19 | height: 55px;
20 | line-height: 11px;
21 | color: #eee;
22 | }
23 |
--------------------------------------------------------------------------------
/src/css/reg.css:
--------------------------------------------------------------------------------
1 | .rege {
2 | position: absolute;
3 | top: 50%;
4 | left: 50%;
5 | width: 300px;
6 | height: 500px;
7 | margin-left: -200px;
8 | margin-top: -250px;
9 | padding: 50px 30px;
10 | box-shadow: 0 8px 10px 0 #f0f2f5;
11 | border-radius: 20px;
12 | background: #fff;
13 | }
14 |
15 | .rege .reg_header {
16 | height: 30px;
17 | font-size: 16px;
18 | }
19 |
20 | .rege .reg_header .text1 {
21 | margin-left: 38px;
22 | color: #333;
23 | margin-top: 8px;
24 | line-height: 28px;
25 | font-size: 20px;
26 | }
27 |
28 | .rege .reg_header .text2 {
29 | margin-left: 38px;
30 | color: #8d8300;
31 | line-height: 17px;
32 | font-size: 12px;
33 | }
34 |
35 | .rege .tab {
36 | height: 330x;
37 | margin-top: 30px;
38 | line-height: 33px;
39 | font-size: 24px;
40 | }
41 |
42 | .rege .tab .reg {
43 | margin-left: 26px;
44 | font-size: 14px;
45 | }
46 |
47 | .rege .iptFrame {
48 | background: #fafbfc;
49 | border: 1px solid #e6e8eb;
50 | border-radius: 12px;
51 | height: 28px;
52 | margin-top: 20px;
53 | overflow: hidden;
54 | }
55 |
56 | .rege .iptFrame input {
57 | background: #fafbfc;
58 | border: none;
59 | width: 100%;
60 | height: 100%;
61 | font-size: 14px;
62 | text-indent: 10px;
63 | outline: none;
64 | }
65 |
66 | .rege .regBtn {
67 | line-height: 48px;
68 | background: #f7e700;
69 | border-radius: 12px;
70 | font-size: 16px;
71 | text-align: center;
72 | margin-top: 20px;
73 | }
74 |
--------------------------------------------------------------------------------
/src/css/setting.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/src/css/setting.css
--------------------------------------------------------------------------------
/src/css/snackbar.css:
--------------------------------------------------------------------------------
1 | #lanying-snackbar {
2 | visibility: hidden;
3 | min-width: 250px;
4 | margin-left: -125px;
5 | bottom: 30px;
6 | background-color: #333;
7 | color: #fff;
8 | text-align: center;
9 | border-radius: 2px;
10 | padding: 16px;
11 | position: fixed;
12 | z-index: 1;
13 | left: 50%;
14 | font-size: 17px;
15 | }
16 |
17 | #lanying-snackbar.show {
18 | visibility: visible;
19 | -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
20 | animation: fadein 0.5s, fadeout 0.5s 2.5s;
21 | }
22 |
23 | @-webkit-keyframes fadein {
24 | from {
25 | bottom: 0;
26 | opacity: 0;
27 | }
28 | to {
29 | bottom: 30px;
30 | opacity: 1;
31 | }
32 | }
33 |
34 | @keyframes fadein {
35 | from {
36 | bottom: 0;
37 | opacity: 0;
38 | }
39 | to {
40 | bottom: 30px;
41 | opacity: 1;
42 | }
43 | }
44 |
45 | @-webkit-keyframes fadeout {
46 | from {
47 | bottom: 30px;
48 | opacity: 1;
49 | }
50 | to {
51 | bottom: 0;
52 | opacity: 0;
53 | }
54 | }
55 |
56 | @keyframes fadeout {
57 | from {
58 | bottom: 30px;
59 | opacity: 1;
60 | }
61 | to {
62 | bottom: 0;
63 | opacity: 0;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import App from './App.vue';
3 |
4 | import store from './ui/store';
5 | import axios from 'axios';
6 |
7 | import './css/index.css';
8 |
9 | import ElementUI from 'element-ui';
10 |
11 | Vue.config.productionTip = false;
12 | Vue.prototype.axios = axios;
13 | Vue.use(ElementUI);
14 |
15 | import VPopover from 'vue-js-popover';
16 | Vue.use(VPopover, { tooltip: true });
17 |
18 | Vue.prototype.serr = (err) => {
19 | let msg = '操作失败';
20 | if (err.message) {
21 | msg = err.code ? '错误码:' + err.code + '\n错误:' + err.message : '错误:' + err.message;
22 | }
23 | alert(msg);
24 | };
25 |
26 | new Vue({
27 | render: (h) => h(App),
28 | store
29 | }).$mount('#app');
30 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/conversation.js:
--------------------------------------------------------------------------------
1 | import jsonDescriptor from '../conversation';
2 | import protobuf from 'protobufjs/light';
3 |
4 | var root = protobuf.Root.fromJSON(jsonDescriptor);
5 | const Conv = root.lookupType('im.floo.protobuf.Conversation');
6 |
7 | const decode = (bytes) => Conv.decode(bytes);
8 |
9 | const encode = (obj) => Conv.encode(obj).finish();
10 |
11 | export { decode, encode };
12 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/conversationunread.js:
--------------------------------------------------------------------------------
1 | import { decode as xidDecode } from './xid';
2 |
3 | import protobuf from 'protobufjs/light';
4 | import jsonDescriptor from '../xsync';
5 |
6 | var root = protobuf.Root.fromJSON(jsonDescriptor);
7 | const ConversationUnread = root.lookupType('im.floo.protobuf.ConversationUnread');
8 |
9 | const decode = (bytes) => {
10 | if (typeof bytes === 'undefined') {
11 | return bytes;
12 | }
13 | const ret = ConversationUnread.decode(bytes);
14 | ret.xid && (ret.xid = xidDecode(ret.xid));
15 | return ret;
16 | };
17 |
18 | export { decode };
19 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/frame.js:
--------------------------------------------------------------------------------
1 | // 有其他调用
2 | import protobuf from 'protobufjs/light';
3 | import jsonDescriptor from '../xsync';
4 | import { STATIC_FRAME_COMMAND } from '../../../utils/static';
5 | import { decode as unreadDecode, encode as unreaddlEncode } from './unreaddl';
6 | import { decode as syncdlDecode } from './syncdl';
7 | import { encode as synculEncode } from './syncul';
8 | import { decode as noticeDecode, encode as noticeEncode } from './notice';
9 | import { decode as provisionDecode, encode as provisionEncode } from './provision';
10 |
11 | var root = protobuf.Root.fromJSON(jsonDescriptor);
12 | const Frame = root.lookupType('im.floo.protobuf.Frame');
13 |
14 | // const pubkey = infoStore.getAesKey();
15 |
16 | const decode = (bytes) => {
17 | bytes = new Uint8Array(bytes);
18 | const ret = Frame.decode(bytes);
19 | const { command, payload } = ret;
20 | if (command === STATIC_FRAME_COMMAND.UNREAD) {
21 | ret.payload = unreadDecode(payload);
22 | } else if (command === STATIC_FRAME_COMMAND.SYNC) {
23 | ret.payload = syncdlDecode(payload);
24 | } else if (command === STATIC_FRAME_COMMAND.NOTICE) {
25 | ret.payload = noticeDecode(payload);
26 | } else if (command === STATIC_FRAME_COMMAND.PROVISION) {
27 | ret.payload = provisionDecode(payload);
28 | }
29 | return ret;
30 | };
31 |
32 | const encode = (obj) => {
33 | const { payload, command } = obj;
34 | if (payload) {
35 | if (command === STATIC_FRAME_COMMAND.UNREAD) {
36 | obj.payload = unreaddlEncode(payload);
37 | } else if (command === STATIC_FRAME_COMMAND.SYNC) {
38 | obj.payload = synculEncode(payload);
39 | } else if (command === STATIC_FRAME_COMMAND.NOTICE) {
40 | obj.payload = noticeEncode(payload);
41 | } else if (command === STATIC_FRAME_COMMAND.PROVISION) {
42 | obj.payload = provisionEncode(payload);
43 | }
44 | }
45 | const ret = Frame.encode(obj).finish();
46 | return ret;
47 | };
48 |
49 | export { decode, encode };
50 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/groupnotice.js:
--------------------------------------------------------------------------------
1 | import { encode as xidEncode } from './xid';
2 | import protobuf from 'protobufjs/light';
3 | import jsonDescriptor from '../groupnotice';
4 | // import { encode as statusEncode, decode as statusDecode } from './status';
5 |
6 | var root = protobuf.Root.fromJSON(jsonDescriptor);
7 | const GroupNotice = root.lookupType('im.floo.protobuf.GroupNotice');
8 |
9 | const decode = (bytes) => {
10 | const ret = GroupNotice.decode(bytes); // 也都已经搞好了。。
11 | // ret.from = xidDecode(ret.from);
12 | // ret.xid = xidDecode(ret.xid);
13 | // const sto = ret.to || [];
14 | // const toArr = [];
15 | // sto.forEach(item => {
16 | // toArr.push(xidDecode(item));
17 | // })
18 | // ret.to = toArr;
19 | return ret;
20 | };
21 |
22 | const encode = (obj) => {
23 | // obj.xid = xidEncode(obj.xid);
24 | obj.from = xidEncode(obj.from);
25 | const toArr = [];
26 | const sto = obj.to || [];
27 | sto.forEach((item) => {
28 | toArr.push(xidEncode(item));
29 | });
30 | obj.to = toArr;
31 | return GroupNotice.encode(obj).finish();
32 | };
33 |
34 | export { decode, encode };
35 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/index.js:
--------------------------------------------------------------------------------
1 | import * as provision from './provision';
2 | // import * as syncdl from './syncdl';
3 | import * as syncul from './syncul';
4 | // import * as unreaddl from './unreaddl';
5 | import * as frame from './frame';
6 | // import { decode as xidDecode } from './xid';
7 | // import { decode as noticeDecode } from './notice';
8 | // import { STATIC_FRAME_COMMAND } from '@utils/static';
9 |
10 | // use int64 as long in protobuf
11 | import protobuf from 'protobufjs/light';
12 | import Long from 'long';
13 | protobuf.util.Long = Long;
14 | protobuf.configure();
15 |
16 | const { encode: provisionEncode } = provision;
17 | const { encode: frameEncode, decode: frameDecode } = frame;
18 | // const { decode: unreaddlDecode } = unreaddl;
19 | // const { decode: syncdlDecode } = syncdl;
20 | const { encode: synculEncode } = syncul;
21 |
22 | const packProvision = (provisionObj) => {
23 | const payload = provisionObj.payload;
24 | const bytes = provisionEncode(payload);
25 | provisionObj.payload = bytes;
26 | return frameEncode(provisionObj);
27 | };
28 |
29 | // 消息,等,meta定
30 | const packSyncul = (synculObj) => {
31 | const { payload } = synculObj;
32 | const bytes = synculEncode(payload);
33 | synculObj.payload = bytes;
34 | return frameEncode(synculObj);
35 | };
36 |
37 | const packUnreadul = () => {
38 | const obj = {
39 | vsn: 0,
40 | compress_method: 0,
41 | command: 0
42 | };
43 | return frameEncode(obj);
44 | };
45 |
46 | const unpack = (bytes) => {
47 | const frmObj = frameDecode(bytes);
48 | return frmObj;
49 | };
50 |
51 | export { packSyncul, packProvision, unpack, packUnreadul, frameEncode };
52 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/info.js:
--------------------------------------------------------------------------------
1 | import jsonDescriptor from '../info';
2 | import protobuf from 'protobufjs/light';
3 |
4 | var root = protobuf.Root.fromJSON(jsonDescriptor);
5 | const Info = root.lookupType('im.floo.protobuf.Info');
6 |
7 | const decode = (bytes) => Info.decode(bytes);
8 |
9 | const encode = (obj) => Info.encode(obj).finish();
10 |
11 | export { decode, encode };
12 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/messagebody.js:
--------------------------------------------------------------------------------
1 | import { constr as xidConstr } from './xid';
2 | import protobuf from 'protobufjs/light';
3 | import jsonDescriptor from '../messagebody';
4 |
5 | var root = protobuf.Root.fromJSON(jsonDescriptor);
6 | const MessageBody = root.lookupType('im.floo.protobuf.MessageBody');
7 | // const MessageOperation = root.lookupType("top.maxim.protobuf.MessageOperation");
8 |
9 | const decode = (bytes) => {
10 | const ret = MessageBody.decode(bytes);
11 | //里边其他东西已经解析了。。
12 | return ret;
13 | };
14 |
15 | const encode = (obj) => {
16 | // 其他已经encode了,这里不需要额外处理了,都是坑啊。。
17 | // obj.operation = MessageOperation.encode(obj.operation).finish();
18 | // obj.from = xidEncode(obj.from);
19 | // obj.to = xidEncode(obj.to);
20 | return MessageBody.encode(obj).finish();
21 | };
22 |
23 | const constr = (obj) => {
24 | obj.xid = xidConstr(obj.xid);
25 | return MessageBody.create(obj);
26 | };
27 |
28 | export { decode, encode, constr };
29 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/meta.js:
--------------------------------------------------------------------------------
1 | import protobuf from 'protobufjs/light';
2 | import jsonDescriptor from '../xsync';
3 | import { STATIC_META_NAMESPACE } from '../../../utils/static';
4 | import { decode as msgBodyDecode, encode as msgBodyEncode } from './messagebody';
5 | import { decode as groupnoticeDecode, encode as groupnoticeEncode } from './groupnotice';
6 | import { decode as rosternoticeDecode, encode as rosternoticeEncode } from './rosternotice';
7 | import { decode as usernoticeDecode, encode as usernoticeEncode } from './usernotice';
8 | import { decode as infoDecode, encode as infoEncode } from './info';
9 | import { decode as convDecode, encode as convEncode } from './conversation';
10 | import { decode as rtcSignalDecode, encode as rtcSignalEncode } from './rtcsignal';
11 |
12 | var root = protobuf.Root.fromJSON(jsonDescriptor);
13 | const Meta = root.lookupType('im.floo.protobuf.Meta');
14 |
15 | const decode = (bytes) => {
16 | const ret = Meta.decode(bytes);
17 | const { ns, payload } = ret;
18 | if (ns === STATIC_META_NAMESPACE.MESSAGE) {
19 | ret.payload = msgBodyDecode(payload);
20 | }
21 | if (ns === STATIC_META_NAMESPACE.GROUP_NOTICE) {
22 | ret.payload = groupnoticeDecode(payload);
23 | }
24 | if (ns === STATIC_META_NAMESPACE.ROSTER_NOTICE) {
25 | ret.payload = rosternoticeDecode(payload);
26 | }
27 | if (ns === STATIC_META_NAMESPACE.USER_NOTICE) {
28 | ret.payload = usernoticeDecode(payload);
29 | }
30 | if (ns === STATIC_META_NAMESPACE.INFO) {
31 | ret.payload = infoDecode(payload);
32 | }
33 | if (ns === STATIC_META_NAMESPACE.CONVERSATION) {
34 | ret.payload = convDecode(payload);
35 | }
36 | if (ns === STATIC_META_NAMESPACE.PUSH) {
37 | ret.payload = msgBodyDecode(payload);
38 | }
39 | if (ns === STATIC_META_NAMESPACE.RTC_SIGNAL) {
40 | ret.payload = rtcSignalDecode(payload);
41 | }
42 | return ret;
43 | };
44 |
45 | const encode = (obj) => {
46 | const { ns, payload } = obj;
47 | // typeof ns !== 'undefined' && smeta.setNs(ns);
48 |
49 | if (ns === STATIC_META_NAMESPACE.MESSAGE) {
50 | obj.payload = msgBodyEncode(payload);
51 | }
52 | if (ns === STATIC_META_NAMESPACE.GROUP_NOTICE) {
53 | obj.payload = groupnoticeEncode(payload);
54 | }
55 | if (ns === STATIC_META_NAMESPACE.ROSTER_NOTICE) {
56 | obj.payload = rosternoticeEncode(payload);
57 | }
58 | if (ns === STATIC_META_NAMESPACE.USER_NOTICE) {
59 | obj.payload = usernoticeEncode(payload);
60 | }
61 | if (ns === STATIC_META_NAMESPACE.INFO) {
62 | obj.payload = infoEncode(payload);
63 | }
64 | if (ns === STATIC_META_NAMESPACE.CONVERSATION) {
65 | obj.payload = convEncode(payload);
66 | }
67 | if (ns === STATIC_META_NAMESPACE.PUSH) {
68 | obj.payload = msgBodyEncode(payload);
69 | }
70 | if (ns === STATIC_META_NAMESPACE.RTC_SIGNAL) {
71 | obj.payload = rtcSignalEncode(payload);
72 | }
73 | return Meta.encode(obj).finish();
74 | };
75 |
76 | const constr = (obj) => {
77 | const { ns, payload } = obj;
78 |
79 | if (ns === STATIC_META_NAMESPACE.MESSAGE) {
80 | obj.payload = msgBodyEncode(payload);
81 | }
82 | if (ns === STATIC_META_NAMESPACE.GROUP_NOTICE) {
83 | obj.payload = groupnoticeEncode(payload);
84 | }
85 | if (ns === STATIC_META_NAMESPACE.ROSTER_NOTICE) {
86 | obj.payload = rosternoticeEncode(payload);
87 | }
88 | if (ns === STATIC_META_NAMESPACE.USER_NOTICE) {
89 | obj.payload = usernoticeEncode(payload);
90 | }
91 | if (ns === STATIC_META_NAMESPACE.INFO) {
92 | obj.payload = infoEncode(payload);
93 | }
94 | if (ns === STATIC_META_NAMESPACE.CONVERSATION) {
95 | obj.payload = convEncode(payload);
96 | }
97 | if (ns === STATIC_META_NAMESPACE.PUSH) {
98 | obj.payload = msgBodyEncode(payload);
99 | }
100 | if (ns === STATIC_META_NAMESPACE.RTC_SIGNAL) {
101 | obj.payload = rtcSignalEncode(payload);
102 | }
103 | return Meta.create(obj);
104 | };
105 |
106 | export { decode, encode, constr };
107 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/notice.js:
--------------------------------------------------------------------------------
1 | import { decode as xidDecode } from './xid';
2 | import protobuf from 'protobufjs/light';
3 | import jsonDescriptor from '../xsync';
4 |
5 | var root = protobuf.Root.fromJSON(jsonDescriptor);
6 | const Notice = root.lookupType('im.floo.protobuf.Notice');
7 |
8 | const decode = (bytes) => {
9 | const xid = xidDecode(bytes);
10 | // const ret = Notice.decode(bytes);
11 | return { xid };
12 | };
13 |
14 | const encode = (obj) => Notice.encode(obj).finish();
15 |
16 | export { decode, encode };
17 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/provision.js:
--------------------------------------------------------------------------------
1 | import protobuf from 'protobufjs/light';
2 | import jsonDescriptor from '../xsync';
3 |
4 | var root = protobuf.Root.fromJSON(jsonDescriptor);
5 | const Provision = root.lookupType('im.floo.protobuf.Provision');
6 |
7 | const decode = (bytes) => {
8 | const ret = Provision.decode(bytes);
9 | return ret;
10 | };
11 |
12 | const encode = (obj) => {
13 | return Provision.encode(obj).finish();
14 | };
15 |
16 | export { decode, encode };
17 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/rosternotice.js:
--------------------------------------------------------------------------------
1 | import protobuf from 'protobufjs/light';
2 | import jsonDescriptor from '../rosternotice';
3 |
4 | var root = protobuf.Root.fromJSON(jsonDescriptor);
5 | const RosterNotice = root.lookupType('im.floo.protobuf.RosterNotice');
6 |
7 | const decode = (bytes) => {
8 | const ret = RosterNotice.decode(bytes);
9 | return ret;
10 | };
11 |
12 | const encode = (obj) => {
13 | return RosterNotice.encode(obj).finish();
14 | };
15 |
16 | export { decode, encode };
17 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/rtcsignal.js:
--------------------------------------------------------------------------------
1 | import protobuf from 'protobufjs/light';
2 | import jsonDescriptor from '../rtcsignal';
3 |
4 | var root = protobuf.Root.fromJSON(jsonDescriptor);
5 | const RtcSignal = root.lookupType('im.floo.protobuf.RtcSignal');
6 |
7 | const decode = (bytes) => RtcSignal.decode(bytes);
8 |
9 | const encode = (obj) => RtcSignal.encode(obj).finish();
10 |
11 | export { decode, encode };
12 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/status.js:
--------------------------------------------------------------------------------
1 | import protobuf from 'protobufjs/light';
2 | import jsonDescriptor from '../xsync';
3 |
4 | var root = protobuf.Root.fromJSON(jsonDescriptor);
5 | const Status = root.lookupType('im.floo.protobuf.Status');
6 |
7 | const decode = (bytes) => bytes && Status.decode(bytes);
8 |
9 | const encode = (obj) => obj && Status.encode(obj).finish();
10 |
11 | const constr = (obj) => Status.create(obj);
12 |
13 | export { decode, encode, constr };
14 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/syncdl.js:
--------------------------------------------------------------------------------
1 | import { encode as metaEncode } from './meta';
2 | import { decode as msgBodyDecode } from './messagebody';
3 | import { decode as groupnoticeDecode } from './groupnotice';
4 | import { decode as rosternoticeDecode } from './rosternotice';
5 | import { decode as usernoticeDecode } from './usernotice';
6 | import { decode as infoDecode } from './info';
7 | import { decode as convDecode } from './conversation';
8 | import { decode as rtcSignalDecode } from './rtcsignal';
9 | import { STATIC_META_NAMESPACE } from '../../../utils/static';
10 | import protobuf from 'protobufjs/light';
11 | import jsonDescriptor from '../xsync';
12 |
13 | const SyncDL = protobuf.Root.fromJSON(jsonDescriptor).lookupType('im.floo.protobuf.SyncDL');
14 |
15 | const decode = (bytes) => {
16 | const ret = SyncDL.decode(bytes); //metas直接就给解了。。。。
17 | const { metas = [] } = ret; // meta中的payload这里不解析。。。额
18 | const metaRet = [];
19 | metas.forEach((meta) => {
20 | const { ns, payload } = meta;
21 | if (ns === STATIC_META_NAMESPACE.MESSAGE) {
22 | meta.payload = msgBodyDecode(payload);
23 | }
24 | if (ns === STATIC_META_NAMESPACE.GROUP_NOTICE) {
25 | meta.payload = groupnoticeDecode(payload);
26 | }
27 | if (ns === STATIC_META_NAMESPACE.ROSTER_NOTICE) {
28 | meta.payload = rosternoticeDecode(payload);
29 | }
30 | if (ns === STATIC_META_NAMESPACE.USER_NOTICE) {
31 | meta.payload = usernoticeDecode(payload);
32 | }
33 | if (ns === STATIC_META_NAMESPACE.INFO) {
34 | meta.payload = infoDecode(payload);
35 | }
36 | if (ns === STATIC_META_NAMESPACE.CONVERSATION) {
37 | meta.payload = convDecode(payload);
38 | }
39 | if (ns === STATIC_META_NAMESPACE.PUSH) {
40 | meta.payload = msgBodyDecode(payload);
41 | }
42 | if (ns === STATIC_META_NAMESPACE.RTC_SIGNAL) {
43 | meta.payload = rtcSignalDecode(payload);
44 | }
45 | metaRet.push(meta);
46 | });
47 | ret.metas = metaRet;
48 | return ret;
49 | };
50 |
51 | const encode = (obj) => {
52 | const arr = [];
53 | const { metas = [] } = obj;
54 | metas.forEach((item) => {
55 | arr.push(metaEncode(item));
56 | });
57 | obj.metas = arr;
58 | return SyncDL.encode(obj).finish();
59 | };
60 |
61 | export { decode, encode };
62 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/syncul.js:
--------------------------------------------------------------------------------
1 | import protobuf from 'protobufjs/light';
2 | import jsonDescriptor from '../xsync';
3 | import { constr as metaConstr } from './meta';
4 |
5 | var root = protobuf.Root.fromJSON(jsonDescriptor);
6 | const SyncUL = root.lookupType('im.floo.protobuf.SyncUL');
7 |
8 | const decode = (bytes) => {
9 | return SyncUL.decode(bytes);
10 | };
11 |
12 | const encode = (obj) => {
13 | obj.meta && (obj.meta = metaConstr(obj.meta));
14 | const ret = SyncUL.encode(obj).finish();
15 | return ret;
16 | };
17 |
18 | export { decode, encode };
19 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/unreaddl.js:
--------------------------------------------------------------------------------
1 | import protobuf from 'protobufjs/light';
2 | import jsonDescriptor from '../xsync';
3 |
4 | var root = protobuf.Root.fromJSON(jsonDescriptor);
5 | const UnreadDL = root.lookupType('im.floo.protobuf.UnreadDL');
6 |
7 | const decode = (bytes) => {
8 | const ret = UnreadDL.decode(bytes);
9 | return ret;
10 | };
11 |
12 | const encode = (obj) => {
13 | return UnreadDL.encode(obj).finish();
14 | };
15 |
16 | export { decode, encode };
17 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/usernotice.js:
--------------------------------------------------------------------------------
1 | import protobuf from 'protobufjs/light';
2 | import jsonDescriptor from '../usernotice';
3 |
4 | var root = protobuf.Root.fromJSON(jsonDescriptor);
5 | const UserNotice = root.lookupType('im.floo.protobuf.UserNotice');
6 |
7 | const decode = (bytes) => UserNotice.decode(bytes);
8 |
9 | const encode = (obj) => UserNotice.encode(obj).finish();
10 |
11 | export { decode, encode };
12 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/class/xid.js:
--------------------------------------------------------------------------------
1 | import protobuf from 'protobufjs/light';
2 | import jsonDescriptor from '../xsync';
3 |
4 | var root = protobuf.Root.fromJSON(jsonDescriptor);
5 | const XID = root.lookupType('im.floo.protobuf.XID');
6 |
7 | const decode = (bytes) => XID.decode(bytes);
8 |
9 | const encode = (obj) => {
10 | const ret = XID.encode(obj).finish();
11 | return ret;
12 | };
13 |
14 | const constr = (obj) => XID.create(obj);
15 |
16 | export { decode, encode, constr };
17 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/conversation.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
2 | (function (global, factory) {
3 | /* global define, require, module */
4 |
5 | /* AMD */ if (typeof define === 'function' && define.amd) define(['protobufjs/light'], factory);
6 | /* CommonJS */ else if (typeof require === 'function' && typeof module === 'object' && module && module.exports) module.exports = factory(require('protobufjs/light'));
7 | })(this, function ($protobuf) {
8 | 'use strict';
9 |
10 | const $root = ($protobuf.roots.conversation || ($protobuf.roots.conversation = new $protobuf.Root())).addJSON({
11 | im: {
12 | nested: {
13 | floo: {
14 | nested: {
15 | protobuf: {
16 | nested: {
17 | Conversation: {
18 | fields: {
19 | type: {
20 | type: 'Type',
21 | id: 1
22 | },
23 | operation: {
24 | type: 'ConversationOperation',
25 | id: 2
26 | }
27 | },
28 | nested: {
29 | Type: {
30 | values: {
31 | UNKNOWN: 0,
32 | OPER: 1
33 | }
34 | }
35 | }
36 | },
37 | ConversationOperation: {
38 | fields: {
39 | type: {
40 | type: 'OpType',
41 | id: 1
42 | },
43 | xid: {
44 | type: 'XID',
45 | id: 2
46 | }
47 | },
48 | nested: {
49 | OpType: {
50 | values: {
51 | UNKNOWN: 0,
52 | DELETE: 1,
53 | DELETE_EVERYWHERE: 2
54 | }
55 | }
56 | }
57 | },
58 | XID: {
59 | fields: {
60 | uid: {
61 | type: 'uint64',
62 | id: 1
63 | },
64 | deviceSN: {
65 | type: 'uint32',
66 | id: 2
67 | }
68 | }
69 | }
70 | }
71 | }
72 | }
73 | }
74 | }
75 | }
76 | });
77 |
78 | return $root;
79 | });
80 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/groupnotice.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
2 | (function (global, factory) {
3 | /* global define, require, module */
4 |
5 | /* AMD */ if (typeof define === 'function' && define.amd) define(['protobufjs/light'], factory);
6 | /* CommonJS */ else if (typeof require === 'function' && typeof module === 'object' && module && module.exports) module.exports = factory(require('protobufjs/light'));
7 | })(this, function ($protobuf) {
8 | 'use strict';
9 |
10 | const $root = ($protobuf.roots.groupnotice || ($protobuf.roots.groupnotice = new $protobuf.Root())).addJSON({
11 | im: {
12 | nested: {
13 | floo: {
14 | nested: {
15 | protobuf: {
16 | nested: {
17 | GroupNotice: {
18 | fields: {
19 | type: {
20 | type: 'Type',
21 | id: 1
22 | },
23 | gid: {
24 | type: 'XID',
25 | id: 2
26 | },
27 | from: {
28 | type: 'XID',
29 | id: 3
30 | },
31 | to: {
32 | rule: 'repeated',
33 | type: 'XID',
34 | id: 4
35 | },
36 | content: {
37 | type: 'string',
38 | id: 5
39 | }
40 | },
41 | nested: {
42 | Type: {
43 | values: {
44 | UNKNOWN: 0,
45 | PRESENCE: 1,
46 | ABSENCE: 2,
47 | CREATED: 3,
48 | DESTROYED: 4,
49 | JOINED: 5,
50 | LEAVED: 6,
51 | APPLYED: 7,
52 | APPLY_ACCEPTED: 8,
53 | APPLY_DECLINED: 9,
54 | INVITED: 10,
55 | INVITE_ACCEPTED: 11,
56 | INVITE_DECLINED: 12,
57 | KICKED: 13,
58 | BLOCKED: 14,
59 | UNBLOCKED: 15,
60 | OWNER_ASSIGNED: 16,
61 | ADMIN_GRANTED: 17,
62 | ADMIN_REVOKED: 18,
63 | MUTED: 19,
64 | UNMUTED: 20,
65 | BANNED: 21,
66 | UNBANNED: 22,
67 | INFO_UPDATED: 23,
68 | ANNOUNCEMENT_UPDATED: 24,
69 | MESSAGE_SETTING: 25,
70 | FILE_UPLOADED: 26,
71 | FILE_DELETED: 27,
72 | FILE_UPDATED: 28
73 | }
74 | }
75 | }
76 | },
77 | XID: {
78 | fields: {
79 | uid: {
80 | type: 'uint64',
81 | id: 1
82 | },
83 | deviceSN: {
84 | type: 'uint32',
85 | id: 2
86 | }
87 | }
88 | }
89 | }
90 | }
91 | }
92 | }
93 | }
94 | }
95 | });
96 |
97 | return $root;
98 | });
99 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/index.js:
--------------------------------------------------------------------------------
1 | import { frameEncode, packProvision, packSyncul, packUnreadul, unpack } from './class/index';
2 | export { packSyncul, packProvision, unpack, packUnreadul, frameEncode };
3 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/info.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
2 | (function (global, factory) {
3 | /* global define, require, module */
4 |
5 | /* AMD */ if (typeof define === 'function' && define.amd) define(['protobufjs/light'], factory);
6 | /* CommonJS */ else if (typeof require === 'function' && typeof module === 'object' && module && module.exports) module.exports = factory(require('protobufjs/light'));
7 | })(this, function ($protobuf) {
8 | 'use strict';
9 |
10 | const $root = ($protobuf.roots.info || ($protobuf.roots.info = new $protobuf.Root())).addJSON({
11 | im: {
12 | nested: {
13 | floo: {
14 | nested: {
15 | protobuf: {
16 | nested: {
17 | Info: {
18 | fields: {
19 | sdk_vsn: {
20 | type: 'string',
21 | id: 1
22 | },
23 | network: {
24 | type: 'Network',
25 | id: 2
26 | },
27 | content: {
28 | type: 'string',
29 | id: 3
30 | }
31 | },
32 | nested: {
33 | Network: {
34 | values: {
35 | WIRE: 0,
36 | WIFI: 1,
37 | NET_2G: 2,
38 | NET_3G: 3,
39 | NET_4G: 4,
40 | NET_5G: 5,
41 | UNKNOWN: 6
42 | }
43 | }
44 | }
45 | }
46 | }
47 | }
48 | }
49 | }
50 | }
51 | }
52 | });
53 |
54 | return $root;
55 | });
56 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/make.sh:
--------------------------------------------------------------------------------
1 | # /etc/bash/bashrc
2 |
3 | # https://www.npmjs.com/package/protobufjs#pbjs-for-javascript
4 | # install pbjs by:
5 | # yarn global add protobufjs
6 |
7 | echo "====== deleting old files ======="
8 | find . -path ./class -prune -false -o -name "*.js" ! -name "index.js" -exec rm {} \;
9 |
10 | echo "==== starting making pb files ..."
11 | xsync_dir=$1
12 | for proto_file in `find $xsync_dir -type f -name "*.proto"`;
13 | do
14 | proto_filename=`basename ${proto_file}`
15 | proto_name=${proto_filename%%.proto}
16 | js_file=${proto_name}.js
17 | echo "generate ${js_file} from ${proto_file}"
18 | pbjs -t json-module ${proto_file} -o ${js_file} -r ${proto_name} --keep-case --es6
19 | done
20 |
21 | echo "==== pb file make over......"
22 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/rosternotice.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
2 | (function (global, factory) {
3 | /* global define, require, module */
4 |
5 | /* AMD */ if (typeof define === 'function' && define.amd) define(['protobufjs/light'], factory);
6 | /* CommonJS */ else if (typeof require === 'function' && typeof module === 'object' && module && module.exports) module.exports = factory(require('protobufjs/light'));
7 | })(this, function ($protobuf) {
8 | 'use strict';
9 |
10 | const $root = ($protobuf.roots.rosternotice || ($protobuf.roots.rosternotice = new $protobuf.Root())).addJSON({
11 | im: {
12 | nested: {
13 | floo: {
14 | nested: {
15 | protobuf: {
16 | nested: {
17 | RosterNotice: {
18 | fields: {
19 | type: {
20 | type: 'Type',
21 | id: 1
22 | },
23 | from: {
24 | type: 'XID',
25 | id: 2
26 | },
27 | to: {
28 | rule: 'repeated',
29 | type: 'XID',
30 | id: 3
31 | },
32 | content: {
33 | type: 'string',
34 | id: 4
35 | },
36 | roster_vsn: {
37 | type: 'string',
38 | id: 5
39 | }
40 | },
41 | nested: {
42 | Type: {
43 | values: {
44 | UNKNOWN: 0,
45 | ADDED: 1,
46 | REMOVED: 2,
47 | ACCEPTED: 3,
48 | DECLINED: 4,
49 | BLOCKED: 5,
50 | UNBLOCKED: 6,
51 | APPLIED: 7,
52 | INFO_UPDATED: 8,
53 | MUTED: 9,
54 | UNMUTED: 10
55 | }
56 | }
57 | }
58 | },
59 | XID: {
60 | fields: {
61 | uid: {
62 | type: 'uint64',
63 | id: 1
64 | },
65 | deviceSN: {
66 | type: 'uint32',
67 | id: 2
68 | }
69 | }
70 | }
71 | }
72 | }
73 | }
74 | }
75 | }
76 | }
77 | });
78 |
79 | return $root;
80 | });
81 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/rtcsignal.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
2 | (function (global, factory) {
3 | /* global define, require, module */
4 |
5 | /* AMD */ if (typeof define === 'function' && define.amd) define(['protobufjs/light'], factory);
6 | /* CommonJS */ else if (typeof require === 'function' && typeof module === 'object' && module && module.exports) module.exports = factory(require('protobufjs/light'));
7 | })(this, function ($protobuf) {
8 | 'use strict';
9 |
10 | const $root = ($protobuf.roots.rtcsignal || ($protobuf.roots.rtcsignal = new $protobuf.Root())).addJSON({
11 | im: {
12 | nested: {
13 | floo: {
14 | nested: {
15 | protobuf: {
16 | nested: {
17 | RtcSignal: {
18 | fields: {
19 | type: {
20 | type: 'Type',
21 | id: 1
22 | },
23 | content: {
24 | type: 'string',
25 | id: 2
26 | },
27 | media_server: {
28 | type: 'string',
29 | id: 3
30 | }
31 | },
32 | nested: {
33 | Type: {
34 | values: {
35 | UNKNOWN: 0,
36 | VIDEO_ROOM: 1
37 | }
38 | }
39 | }
40 | }
41 | }
42 | }
43 | }
44 | }
45 | }
46 | }
47 | });
48 |
49 | return $root;
50 | });
51 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/usernotice.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
2 | (function (global, factory) {
3 | /* global define, require, module */
4 |
5 | /* AMD */ if (typeof define === 'function' && define.amd) define(['protobufjs/light'], factory);
6 | /* CommonJS */ else if (typeof require === 'function' && typeof module === 'object' && module && module.exports) module.exports = factory(require('protobufjs/light'));
7 | })(this, function ($protobuf) {
8 | 'use strict';
9 |
10 | const $root = ($protobuf.roots.usernotice || ($protobuf.roots.usernotice = new $protobuf.Root())).addJSON({
11 | im: {
12 | nested: {
13 | floo: {
14 | nested: {
15 | protobuf: {
16 | nested: {
17 | UserNotice: {
18 | fields: {
19 | type: {
20 | type: 'Type',
21 | id: 1
22 | },
23 | content: {
24 | type: 'string',
25 | id: 2
26 | }
27 | },
28 | nested: {
29 | Type: {
30 | values: {
31 | UNKNOWN: 0,
32 | PASSWORD_CHANGED: 1,
33 | FROZEN: 2,
34 | REMOVED: 3,
35 | KICK_BY_SAME_DEVICE: 4,
36 | KICKED_BY_OTHER_DEVICE: 5,
37 | INFO_UPDATED: 6,
38 | DEVICE_LOGIN: 7,
39 | DEVICE_LOGOUT: 8,
40 | DEVICE_ADDED: 9,
41 | DEVICE_REMOVED: 10,
42 | CLUSTER_CHANGED: 11,
43 | DNS_UPDATE: 12,
44 | TRAFFIC_LIMIT_EXCEEDED: 13
45 | }
46 | }
47 | }
48 | }
49 | }
50 | }
51 | }
52 | }
53 | }
54 | }
55 | });
56 |
57 | return $root;
58 | });
59 |
--------------------------------------------------------------------------------
/src/sdk/core/protocol/xid.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
2 | (function (global, factory) {
3 | /* global define, require, module */
4 |
5 | /* AMD */ if (typeof define === 'function' && define.amd) define(['protobufjs/light'], factory);
6 | /* CommonJS */ else if (typeof require === 'function' && typeof module === 'object' && module && module.exports) module.exports = factory(require('protobufjs/light'));
7 | })(this, function ($protobuf) {
8 | 'use strict';
9 |
10 | const $root = ($protobuf.roots.xid || ($protobuf.roots.xid = new $protobuf.Root())).addJSON({
11 | im: {
12 | nested: {
13 | floo: {
14 | nested: {
15 | protobuf: {
16 | nested: {
17 | XID: {
18 | fields: {
19 | uid: {
20 | type: 'uint64',
21 | id: 1
22 | },
23 | deviceSN: {
24 | type: 'uint32',
25 | id: 2
26 | }
27 | }
28 | }
29 | }
30 | }
31 | }
32 | }
33 | }
34 | }
35 | });
36 |
37 | return $root;
38 | });
39 |
--------------------------------------------------------------------------------
/src/sdk/index.js:
--------------------------------------------------------------------------------
1 | import rosterManage from './manage/rosterManage';
2 | import groupManage from './manage/groupManage';
3 | import userManage from './manage/userManage';
4 | import sysManage from './manage/sysManage';
5 | import rtcManage from './manage/rtcManager';
6 | import webim from './core/base/index';
7 |
8 | webim.rosterManage = rosterManage;
9 | webim.groupManage = groupManage;
10 | webim.userManage = userManage;
11 | webim.sysManage = sysManage;
12 | webim.rtcManage = rtcManage;
13 |
14 | export function flooim(config) {
15 | new webim(config);
16 | return webim;
17 | }
18 |
19 | export default flooim;
20 |
21 | window.flooIM = (config) => flooim(config);
22 |
--------------------------------------------------------------------------------
/src/sdk/model/conversation.js:
--------------------------------------------------------------------------------
1 | function conversation(params) {
2 | typeof params.type !== 'undefined' && (this.type = params.type);
3 | typeof params.operation !== 'undefined' && (this.operation = params.operation);
4 | }
5 |
6 | conversation.prototype = {
7 | setType: function (type) {
8 | this.type = type;
9 | },
10 | setOperation: function (operation) {
11 | this.operation = operation;
12 | }
13 | };
14 |
15 | export default conversation;
16 |
--------------------------------------------------------------------------------
/src/sdk/model/frame.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | VSN vsn = 1;
4 | CompressMethod compress_method = 2;
5 | Command command = 3;
6 | bytes payload = 4;
7 |
8 | */
9 | import { STATIC_FRAME_COMPRESS_METHOD, STATIC_FRAME_VSN } from '../utils/static';
10 |
11 | function frame(params) {
12 | params = Object.assign(
13 | {},
14 | {
15 | vsn: STATIC_FRAME_VSN.XSYNC_V1,
16 | compress_method: STATIC_FRAME_COMPRESS_METHOD.NONE
17 | },
18 | params
19 | );
20 | typeof params.vsn !== 'undefined' && (this.vsn = params.vsn);
21 | typeof params.compress_method !== 'undefined' && (this.compress_method = params.compress_method);
22 | typeof params.command !== 'undefined' && (this.command = params.command);
23 | typeof params.payload !== 'undefined' && (this.payload = params.payload);
24 | typeof params.encrypt_method !== 'undefined' && (this.encrypt_method = params.encrypt_method);
25 | typeof params.encrypt_key !== 'undefined' && (this.encrypt_key = params.encrypt_key);
26 | typeof params.check_sum !== 'undefined' && (this.check_sum = params.check_sum);
27 | typeof params.tag !== 'undefined' && (this.tag = params.tag);
28 | }
29 |
30 | frame.prototype = {
31 | setVsn: function (vsn) {
32 | this.vsn = vsn;
33 | },
34 | setCompressmethod: function (compress_method) {
35 | this.compress_method = compress_method;
36 | },
37 | setCommond: function (command) {
38 | this.command = command;
39 | },
40 | setPayload: function (payload) {
41 | this.payload = payload;
42 | },
43 | setEncryptmethod: function (encrypt_method) {
44 | this.encrypt_method = encrypt_method;
45 | },
46 | setEncryptkey: function (encrypt_key) {
47 | this.encrypt_key = encrypt_key;
48 | },
49 | setChecksum: function (check_sum) {
50 | this.check_sum = check_sum;
51 | },
52 | setTag: function (tag) {
53 | this.tag = tag;
54 | }
55 | };
56 |
57 | export default frame;
58 |
--------------------------------------------------------------------------------
/src/sdk/model/index.js:
--------------------------------------------------------------------------------
1 | import xid from './xid';
2 | import message from './message';
3 | import frame from './frame';
4 | import provision from './provision';
5 | import syncdl from './syncdl';
6 | import syncul from './syncul';
7 | import meta from './meta';
8 | import conversation from './conversation';
9 | import rtcmessage from './rtcmessage';
10 |
11 | export { xid, message, frame, provision, syncdl, syncul, meta, conversation, rtcmessage };
12 |
--------------------------------------------------------------------------------
/src/sdk/model/message.js:
--------------------------------------------------------------------------------
1 | /**
2 | Type type = 1;
3 | XID from = 2;
4 | XID to = 3;
5 | string content = 4;
6 | ContentType ctype = 5;
7 | MessageOperation operation = 6;
8 | string config = 7;
9 | string attachment = 8;
10 | string ext = 9;
11 | QoS qos = 10;
12 | string sender_name = 11;
13 | bool is_system = 12; // system message
14 | uint32 priority = 13;
15 | Status status = 14;
16 | uint64 edit_timestamp = 15;
17 | */
18 | // import xid from './xid';
19 | import { STATIC_MESSAGE_CONTENT_TYPE, STATIC_MESSAGE_OPTYPE, STATIC_MESSAGE_TYPE } from '../utils/static';
20 |
21 | function message(params) {
22 | const {
23 | operation = {
24 | type: STATIC_MESSAGE_OPTYPE.UNKNOWN,
25 | mid: 0
26 | }
27 | } = params;
28 | params = Object.assign(
29 | {},
30 | {
31 | type: STATIC_MESSAGE_TYPE.NORMAL,
32 | ctype: STATIC_MESSAGE_CONTENT_TYPE.TEXT,
33 | content: '',
34 | operation
35 | },
36 | params
37 | );
38 | typeof params.type !== 'undefined' && (this.type = params.type);
39 | typeof params.from !== 'undefined' && (this.from = params.from);
40 | typeof params.to !== 'undefined' && (this.to = params.to);
41 | typeof params.content !== 'undefined' && (this.content = params.content);
42 | typeof params.ctype !== 'undefined' && (this.ctype = params.ctype);
43 | typeof params.operation !== 'undefined' && (this.operation = params.operation);
44 | typeof params.config !== 'undefined' && (this.config = params.config);
45 | typeof params.attachment !== 'undefined' && (this.attachment = params.attachment);
46 | typeof params.ext !== 'undefined' && (this.ext = params.ext);
47 | typeof params.qos !== 'undefined' && (this.qos = params.qos);
48 | typeof params.sender_name !== 'undefined' && (this.sender_name = params.sender_name);
49 | typeof params.is_system != 'undefined' && (this.is_system = params.is_system);
50 | typeof params.priority != 'undefined' && (this.priority = params.priority);
51 | typeof params.status != 'undefined' && (this.status = params.status);
52 | typeof params.edit_timestamp != 'undefined' && (this.edit_timestamp = params.edit_timestamp);
53 | }
54 |
55 | message.prototype = {
56 | setType: function (type) {
57 | this.type = type;
58 | },
59 | setFrom: function (from) {
60 | this.from = from;
61 | },
62 | setTo: function (to) {
63 | this.to = to;
64 | },
65 | setContent: function (content) {
66 | this.content = content;
67 | },
68 | setCtype: function (ctype) {
69 | this.ctype = ctype;
70 | },
71 | setOperation: function (operation) {
72 | this.operation = operation;
73 | },
74 | setConfig: function (config) {
75 | this.config = config;
76 | },
77 | setAttachment: function (attachment) {
78 | this.attachment = attachment;
79 | },
80 | setExt: function (ext) {
81 | this.ext = ext;
82 | },
83 | setQos: function (qos) {
84 | this.qos = qos;
85 | },
86 | setSendername: function (sender_name) {
87 | this.sender_name = sender_name;
88 | },
89 | setIssystem: function (is_system) {
90 | this.is_system = is_system;
91 | },
92 | setPriority: function (priority) {
93 | this.priority = priority;
94 | },
95 | setStatus: function (status) {
96 | this.status = status;
97 | },
98 | setEditTimestamp: function (edit_timestamp) {
99 | this.edit_timestamp = edit_timestamp;
100 | }
101 | };
102 |
103 | export default message;
104 |
--------------------------------------------------------------------------------
/src/sdk/model/meta.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | uint64 id = 1;
4 | XID from = 2;
5 | XID to = 3;
6 | uint64 timestamp = 4;
7 | NameSpace ns = 5;
8 | bytes payload = 6;
9 |
10 | */
11 | // import xid from './xid';
12 |
13 | function meta(params) {
14 | params = Object.assign({}, params);
15 | typeof params.id !== 'undefined' && (this.id = params.id);
16 | typeof params.from !== 'undefined' && (this.from = params.from);
17 | typeof params.to !== 'undefined' && (this.to = params.to);
18 | typeof params.timestamp !== 'undefined' && (this.timestamp = params.timestamp);
19 | typeof params.ns !== 'undefined' && (this.ns = params.ns);
20 | typeof params.payload !== 'undefined' && (this.payload = params.payload);
21 | }
22 |
23 | meta.prototype = {
24 | setId: function (id) {
25 | this.id = id;
26 | },
27 | setFrom: function (from) {
28 | this.from = from;
29 | },
30 | setTo: function (to) {
31 | this.to = to;
32 | },
33 | setTimestamp: function (timestamp) {
34 | this.timestamp = timestamp;
35 | },
36 | setNs: function (ns) {
37 | this.ns = ns;
38 | },
39 | setPayload: function (payload) {
40 | this.payload = payload;
41 | }
42 | };
43 |
44 | export default meta;
45 |
--------------------------------------------------------------------------------
/src/sdk/model/provision.js:
--------------------------------------------------------------------------------
1 | /**
2 | Status status = 1;
3 | XID xid = 2;
4 | EncryptMethod encrypt_method = 3;
5 | string encrypt_key = 4;
6 | string password = 5;
7 | string token = 6;
8 | OsType os_type = 7;
9 | string sdk_vsn = 8;
10 | bool is_manual_login = 9;
11 | string device_guid = 10; // Device Global Unique Id
12 | string device_notifier = 11; // offline msg push use this
13 | string device_token = 12;
14 | string device_info = 13; // User Agent or others
15 | uint64 last_login_time = 14; // last login time in millisecond
16 | */
17 | // import xid from './xid';
18 | import { STATIC_FRAME_ENCRYPTMETHOD, STATIC_FRAME_OSTYPE } from '../utils/static';
19 |
20 | function provision(params) {
21 | params = Object.assign(
22 | {},
23 | {
24 | encrypt_method: STATIC_FRAME_ENCRYPTMETHOD.ENCRYPT_NONE,
25 | os_type: STATIC_FRAME_OSTYPE.WEB
26 | // device_guid: infoStore.getDeviceGuid(),
27 | },
28 | params
29 | );
30 | typeof params.status !== 'undefined' && (this.status = params.status);
31 | typeof params.xid !== 'undefined' && (this.xid = params.xid);
32 | typeof params.encrypt_method !== 'undefined' && (this.encrypt_method = params.encrypt_method);
33 | typeof params.encrypt_key !== 'undefined' && (this.encrypt_key = params.encrypt_key);
34 | typeof params.password !== 'undefined' && (this.password = params.password);
35 | typeof params.token !== 'undefined' && (this.token = params.token);
36 | typeof params.os_type !== 'undefined' && (this.os_type = params.os_type);
37 | typeof params.sdk_vsn !== 'undefined' && (this.sdk_vsn = params.sdk_vsn);
38 | typeof params.is_manual_login !== 'undefined' && (this.is_manual_login = params.is_manual_login);
39 | typeof params.device_guid !== 'undefined' && (this.device_guid = params.device_guid);
40 | typeof params.device_notifier !== 'undefined' && (this.device_notifier = params.device_notifier);
41 | typeof params.device_token !== 'undefined' && (this.device_token = params.device_token);
42 | typeof params.device_info !== 'undefined' && (this.device_info = params.device_info);
43 | typeof params.last_login_time !== 'undefined' && (this.last_login_time = params.last_login_time);
44 | }
45 |
46 | provision.prototype = {
47 | setStatus: function (status) {
48 | this.status = status;
49 | },
50 | setXid: function (xid) {
51 | this.xid = xid;
52 | },
53 | setEncryptmethod: function (encrypt_method) {
54 | this.encrypt_method = encrypt_method;
55 | },
56 | setEncryptkey: function (encrypt_key) {
57 | this.encrypt_key = encrypt_key;
58 | },
59 | setPassword: function (password) {
60 | this.password = password;
61 | },
62 | setToken: function (token) {
63 | this.token = token;
64 | },
65 | setOstype: function (os_type) {
66 | this.os_type = os_type;
67 | },
68 | setSdkvsn: function (sdk_vsn) {
69 | this.sdk_vsn = sdk_vsn;
70 | },
71 | setIsmanuallogin: function (is_manual_login) {
72 | this.is_manual_login = is_manual_login;
73 | },
74 | setDeviceguid: function (device_guid) {
75 | this.device_guid = device_guid;
76 | },
77 | setDevicenotifier: function (device_notifier) {
78 | this.device_notifier = device_notifier;
79 | },
80 | setDevicetoken: function (device_token) {
81 | this.device_token = device_token;
82 | },
83 | setDeviceinfo: function (device_info) {
84 | this.device_info = device_info;
85 | },
86 | setLastlogintime: function (last_login_time) {
87 | this.last_login_time = last_login_time;
88 | }
89 | };
90 |
91 | export default provision;
92 |
--------------------------------------------------------------------------------
/src/sdk/model/rtcmessage.js:
--------------------------------------------------------------------------------
1 | /*
2 | Type type = 1;
3 | string content = 2;
4 | string media_server = 3;
5 | **/
6 | import { STATIC_RTC_SIGNAL_TYPE } from '../utils/static';
7 |
8 | function rtcmessage(params) {
9 | params = Object.assign(
10 | {},
11 | {
12 | type: STATIC_RTC_SIGNAL_TYPE.VIDEO_ROOM,
13 | content: ''
14 | },
15 | params
16 | );
17 | typeof params.type !== 'undefined' && (this.type = params.type);
18 | typeof params.content !== 'undefined' && (this.content = params.content);
19 | typeof params.media_server !== 'undefined' && (this.media_server = params.media_server);
20 | }
21 |
22 | rtcmessage.prototype = {
23 | setType: function (type) {
24 | this.type = type;
25 | },
26 | setContent: function (content) {
27 | this.content = content;
28 | },
29 | setMediaServer: function (media_server) {
30 | this.media_server = media_server;
31 | }
32 | };
33 |
34 | export default rtcmessage;
35 |
--------------------------------------------------------------------------------
/src/sdk/model/syncdl.js:
--------------------------------------------------------------------------------
1 | /***
2 | Status status = 1;
3 | repeated Meta metas = 2;
4 | uint64 next_key = 3;
5 | XID xid = 4;
6 | uint64 client_mid = 5;
7 | uint64 server_mid = 6;
8 | uint64 server_time = 7;
9 | bool is_full_sync = 8;
10 | uint64 prev_mid = 9;
11 | bool is_eager_sync = 10;
12 | uint64 edit_timestamp = 11;
13 | */
14 | function syncdl(params) {
15 | params = Object.assign({}, params);
16 | typeof params.status !== 'undefined' && (this.status = params.status);
17 | typeof params.metas !== 'undefined' && (this.metas = params.metas);
18 | typeof params.next_key !== 'undefined' && (this.next_key = params.next_key);
19 | typeof params.xid !== 'undefined' && (this.xid = params.xid);
20 | typeof params.client_mid !== 'undefined' && (this.client_mid = params.client_mid);
21 | typeof params.server_mid !== 'undefined' && (this.server_mid = params.server_mid);
22 | typeof params.server_time !== 'undefined' && (this.server_time = params.server_time);
23 | typeof params.is_full_sync !== 'undefined' && (this.is_full_sync = params.is_full_sync);
24 | typeof params.prev_mid !== 'undefined' && (this.prev_mid = params.prev_mid);
25 | typeof params.is_eager_sync !== 'undefined' && (this.is_eager_sync = params.is_eager_sync);
26 | typeof params.edit_timestamp !== 'undefined' && (this.edit_timestamp = params.edit_timestamp);
27 | }
28 |
29 | syncdl.prototype = {
30 | setStatus: function (status) {
31 | this.status = status;
32 | },
33 | setMetas: function (metas) {
34 | this.metas = metas;
35 | },
36 | setNextkey: function (next_key) {
37 | this.next_key = next_key;
38 | },
39 | setXid: function (xid) {
40 | this.xid = xid;
41 | },
42 | setClientmid: function (client_mid) {
43 | this.client_mid = client_mid;
44 | },
45 | setServermid: function (server_mid) {
46 | this.server_mid = server_mid;
47 | },
48 | setServertime: function (server_time) {
49 | this.server_time = server_time;
50 | },
51 | setIsfullsync: function (is_full_sync) {
52 | this.is_full_sync = is_full_sync;
53 | },
54 | setPrevmid: function (prev_mid) {
55 | this.prev_mid = prev_mid;
56 | },
57 | setIseagersync: function (is_eager_sync) {
58 | this.is_eager_sync = is_eager_sync;
59 | },
60 | setEditTimestamp: function (edit_timestamp) {
61 | this.edit_timestamp = edit_timestamp;
62 | }
63 | };
64 |
65 | export default syncdl;
66 |
--------------------------------------------------------------------------------
/src/sdk/model/syncul.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | XID xid = 1;
4 | uint64 key = 2;
5 | Meta meta = 3; // for send message
6 | bool is_full_sync = 4;
7 | uint32 full_sync_num = 5;
8 |
9 | */
10 | function syncul(params) {
11 | params = Object.assign({}, params);
12 | typeof params.xid !== 'undefined' && (this.xid = params.xid);
13 | typeof params.key !== 'undefined' && (this.key = params.key);
14 | typeof params.meta !== 'undefined' && (this.meta = params.meta);
15 | typeof params.is_full_sync !== 'undefined' && (this.is_full_sync = params.is_full_sync);
16 | typeof params.full_sync_num !== 'undefined' && (this.full_sync_num = params.full_sync_num);
17 | }
18 |
19 | syncul.prototype = {
20 | setXid: function (xid) {
21 | this.xid = xid;
22 | },
23 | setKey: function (key) {
24 | this.key = key;
25 | },
26 | setMeta: function (meta) {
27 | this.meta = meta;
28 | },
29 | setIsfullsync: function (is_full_sync) {
30 | this.is_full_sync = is_full_sync;
31 | },
32 | setFullsyncnum: function (full_sync_num) {
33 | this.full_sync_num = full_sync_num;
34 | }
35 | };
36 |
37 | export default syncul;
38 |
--------------------------------------------------------------------------------
/src/sdk/model/xid.js:
--------------------------------------------------------------------------------
1 | /*
2 | uint64 uid = 1; // or gid
3 | uint32 deviceSN = 2; // device serial number
4 | **/
5 | import { infoStore } from '../utils/store';
6 |
7 | const xid = function (params = {}) {
8 | this.uid = params.uid || 0;
9 | const deviceSN = typeof params.deviceSN === 'undefined' ? infoStore.getDeviceSN() : params.deviceSN;
10 | this.deviceSN = deviceSN;
11 | };
12 |
13 | xid.prototype.setUid = function (uid) {
14 | this.uid = uid;
15 | };
16 |
17 | xid.prototype.setDeviceSN = function (sn) {
18 | this.deviceSN = sn;
19 | };
20 |
21 | export default xid;
22 |
--------------------------------------------------------------------------------
/src/sdk/utils/cusEvent.js:
--------------------------------------------------------------------------------
1 | const __events = {};
2 |
3 | const __judgeEvent = (name) => {
4 | if (typeof __events[name] === 'undefined') {
5 | __events[name] = [];
6 | }
7 | return __events[name];
8 | };
9 |
10 | const bind = (name, func) => {
11 | const judge = __judgeEvent(name);
12 | const idx = judge.findIndex((f) => f.toString() === func.toString());
13 | if (idx > -1) {
14 | __judgeEvent(name).splice(idx, 1);
15 | }
16 | __judgeEvent(name).push(func);
17 | };
18 |
19 | const unBind = (name, func) => {
20 | const index = __judgeEvent(name).findIndex((item) => item.toString() === func.toString());
21 | if (index >= 0) {
22 | __events[name].splice(index, 1);
23 | }
24 | };
25 |
26 | const unBindAll = (name) => {
27 | __events[name] = null;
28 | };
29 |
30 | const fire = (name, param) => {
31 | __judgeEvent(name).forEach((func) => {
32 | func(param);
33 | });
34 | };
35 |
36 | export { bind, unBind, unBindAll, fire };
37 |
--------------------------------------------------------------------------------
/src/sdk/utils/encrypt.js:
--------------------------------------------------------------------------------
1 | import CryptoJS from 'crypto-js';
2 |
3 | function mapKey(key) {
4 | const seed = Number(toUint8(key).join(''));
5 | const dict = new Array(256);
6 |
7 | for (let i = 0; i < 256; i++) {
8 | const temp = dict[i] || i;
9 | const rand = ((seed % (i + 1)) + i) % 256;
10 | dict[i] = dict[rand] || rand;
11 | dict[rand] = temp;
12 | }
13 |
14 | return dict;
15 | }
16 |
17 | function toUint8(str) {
18 | return str
19 | .toString()
20 | .split('')
21 | .map((char) => char.charCodeAt(0));
22 | }
23 |
24 | function byteIn(keyMap, val, index) {
25 | for (let i = 0; i < keyMap.length; i++) {
26 | if (keyMap[i] === val) return (i + keyMap[index]) % 256;
27 | }
28 | }
29 |
30 | function byteOut(keyMap, val, index) {
31 | const diff = val - keyMap[index];
32 | return keyMap[diff < 0 ? 256 + diff : diff];
33 | }
34 |
35 | function encrypt(bytes, key) {
36 | if (typeof bytes === 'string') bytes = toUint8(bytes);
37 | return bytes.map(byteIn.bind(null, mapKey(String(key))));
38 | }
39 |
40 | function decrypt(bytes, key) {
41 | return bytes.map(byteOut.bind(null, mapKey(String(key))));
42 | }
43 |
44 | const cryptoEncrypt = (str, key) => {
45 | return CryptoJS.AES.encrypt(str, key);
46 | };
47 |
48 | const cryptoDecript = (str, key) => {
49 | return CryptoJS.AES.decrypt(str, key);
50 | };
51 |
52 | // tools from wasm
53 | /*
54 | function Encrypt (plainText, key, iv) {
55 | var key = CryptoJS.enc.Utf8.parse(key);
56 | var iv = CryptoJS.enc.Utf8.parse(iv);
57 | var encrypted = CryptoJS.AES.encrypt(plainText, key, {
58 | iv: iv,
59 | mode: CryptoJS.mode.CBC,
60 | padding: CryptoJS.pad.Pkcs7
61 | });
62 | return encrypted.toString(); //返回的是base64格式的密文
63 | }
64 |
65 | function Decrypt (encryptedText, key, iv) {
66 | var key = CryptoJS.enc.Utf8.parse(key);
67 | var iv = CryptoJS.enc.Utf8.parse(iv);
68 | var decrypted = CryptoJS.AES.decrypt(encryptedText, key, {
69 | iv: iv,
70 | mode: CryptoJS.mode.CBC,
71 | padding: CryptoJS.pad.Pkcs7
72 | });
73 | const ret = decrypted.toString(CryptoJS.enc.Utf8);
74 | return ret;
75 | }
76 | */
77 |
78 | export { encrypt, decrypt, cryptoEncrypt, cryptoDecript };
79 |
--------------------------------------------------------------------------------
/src/sdk/utils/log.js:
--------------------------------------------------------------------------------
1 | const isProduction = process.env.NODE_ENV === 'production';
2 | var logLevel = 'debug';
3 | const errList = [];
4 | const empty = () => {};
5 | const requestLog = (info) => {
6 | errList.push(info);
7 | if (errList.length > 5) {
8 | errList.splice(-5);
9 | }
10 | document.querySelector('#slog').innerHTML = errList.join('
');
11 | };
12 |
13 | function formatDate(date) {
14 | let y = date.getFullYear();
15 | let m = (date.getMonth() + 1).toString().padStart(2, '0');
16 | let d = date.getDate().toString().padStart(2, '0');
17 | let h = date.getHours().toString().padStart(2, '0');
18 | let f = date.getMinutes().toString().padStart(2, '0');
19 | let s = date.getSeconds().toString().padStart(2, '0');
20 | let ss = date.getMilliseconds().toString().padStart(3, '0');
21 | return y + '-' + m + '-' + d + ' ' + h + ':' + f + ':' + s + '.' + ss;
22 | }
23 |
24 | const timestamp = () => `${formatDate(new Date())}`;
25 |
26 | const log = (...args) => {
27 | if (logLevel == 'debug') {
28 | console.log(timestamp(), '[debug]', ...args);
29 | }
30 | };
31 |
32 | const info = (...args) => {
33 | if (logLevel == 'debug' || logLevel == 'info') {
34 | console.info(timestamp(), '[info]', ...args);
35 | }
36 | };
37 |
38 | const warn = (...args) => {
39 | if (logLevel == 'debug' || logLevel == 'info' || logLevel == 'warn') {
40 | console.warn(timestamp(), '[warn]', ...args);
41 | }
42 | };
43 |
44 | const error = (...args) => {
45 | if (logLevel == 'debug' || logLevel == 'info' || logLevel == 'warn' || logLevel == 'error') {
46 | console.error(timestamp(), '[error]', ...args);
47 | }
48 | };
49 |
50 | const dir = (...args) => {
51 | if (logLevel == 'debug') {
52 | console.dir(timestamp(), '[dir]', ...args);
53 | }
54 | };
55 |
56 | const req = isProduction ? empty : requestLog;
57 | const setLogLevel = (level) => {
58 | logLevel = level;
59 | };
60 | export default {
61 | error,
62 | log,
63 | info,
64 | warn,
65 | dir,
66 | req,
67 | setLogLevel
68 | };
69 |
--------------------------------------------------------------------------------
/src/sdk/utils/store.js:
--------------------------------------------------------------------------------
1 | import groupStore from './store/groupStore';
2 | import infoStore from './store/infoStore';
3 | import messageStore from './store/messageStore';
4 | import noticeStore from './store/noticeStore';
5 | import recentStore from './store/recentStore';
6 | import rosterStore from './store/rosterStore';
7 |
8 | export { groupStore, infoStore, messageStore, noticeStore, recentStore, rosterStore };
9 |
--------------------------------------------------------------------------------
/src/sdk/utils/store/groupStore.js:
--------------------------------------------------------------------------------
1 | import { getItem, removeItem, saveItem } from './storeBase';
2 |
3 | const groupStore = {
4 | saveJoinedGroups: (groups) => {
5 | if (!groups) return;
6 | if (!Array.isArray(groups)) {
7 | groups = [groups];
8 | }
9 | const gids = groups.map((item) => item.group_id || item);
10 | const savedIds = getItem('key_group_lists') || [];
11 | const ret = Array.from(new Set(gids.concat(savedIds)));
12 | saveItem('key_group_lists', ret);
13 | },
14 |
15 | removeGroup: (gid) => {
16 | const allList = getItem('key_group_lists') || [];
17 | const index = allList.findIndex((item) => item === gid);
18 | if (index >= 0) {
19 | allList.splice(index, 1);
20 | saveItem('key_group_lists', allList);
21 | }
22 | },
23 |
24 | getJoinedGroups: () => getItem('key_group_lists'),
25 | saveGroupInfo: (groups) => {
26 | if (!Array.isArray(groups)) {
27 | groups = [groups];
28 | }
29 | const allGroupInfos = getItem('key_group_infos') || {};
30 | groups.forEach((group) => {
31 | const sobj = {};
32 | const { group_id } = group;
33 | Object.keys(group).forEach((key) => {
34 | const v = group[key];
35 | typeof v !== 'undefined' && (sobj[key] = group[key]);
36 | });
37 | allGroupInfos[group_id] = allGroupInfos[group_id] || {};
38 | Object.assign(allGroupInfos[group_id], sobj);
39 | });
40 | saveItem('key_group_infos', allGroupInfos);
41 | },
42 |
43 | getGroupInfo: (group_id) => {
44 | const groupInfos = getItem('key_group_infos');
45 | const ret = groupInfos[group_id] || {};
46 | return Object.assign(ret, {
47 | group_id
48 | });
49 | },
50 |
51 | getGroupInfoList: () => {
52 | const groupIds = groupStore.getJoinedGroups() || [];
53 | const allInfos = groupStore.getAllGroupInfos() || {};
54 | const ret = [];
55 | groupIds.forEach((gid) => {
56 | const ginfo = allInfos[gid] || {};
57 | ret.push(
58 | Object.assign({}, ginfo, {
59 | group_id: gid
60 | })
61 | );
62 | });
63 | return ret;
64 | },
65 |
66 | getAllGroupInfos: () => getItem('key_group_infos') || {},
67 |
68 | saveGroupMembers: (gid, members, replace) => {
69 | //replace 表示强制的代替, 强制存新的,用于不是增加的时候。
70 | if (!Array.isArray(members)) members = [members];
71 | const allMap = getItem('key_group_members') || {};
72 | const savedMembers = allMap[gid] || [];
73 | if (replace) {
74 | // 这个是第一次取,全量替换旧的
75 | allMap[gid] = members;
76 | saveItem('key_group_members', allMap);
77 | return;
78 | }
79 | members.forEach((uid) => {
80 | // 这个是来通知后的追加
81 | const index = savedMembers.findIndex((x) => x === uid);
82 | index < 0 && savedMembers.push(uid);
83 | });
84 | allMap[gid] = savedMembers;
85 | },
86 |
87 | removeGroupMembers: (gid, members) => {
88 | const allMap = getItem('key_group_members') || {};
89 | const savedMembers = allMap[gid] || [];
90 | members.forEach((uid) => {
91 | const index = savedMembers.findIndex((x) => x === uid);
92 | index >= 0 && savedMembers.splice(index, 1);
93 | });
94 | allMap[gid] = savedMembers;
95 | saveItem('key_group_members', allMap);
96 | },
97 |
98 | getGroupMembers: (gid) => {
99 | const allMap = getItem('key_group_members') || {};
100 | return allMap[gid] || [];
101 | },
102 |
103 | clear: () => {
104 | removeItem('key_group_infos');
105 | removeItem('key_group_members');
106 | removeItem('key_group_lists');
107 | }
108 | };
109 |
110 | export default groupStore;
111 |
--------------------------------------------------------------------------------
/src/sdk/utils/store/infoStore.js:
--------------------------------------------------------------------------------
1 | import log from '../log';
2 | import { getItem, removeItem, saveItem } from './storeBase';
3 |
4 | const saveUid = (uid) => {
5 | if (uid) {
6 | saveItem('key_user_id', uid + '', false, -1, true);
7 | } else {
8 | log.error('uid error:', uid);
9 | throw new Error('uid is error ...');
10 | }
11 | };
12 |
13 | const getUid = () => {
14 | let uid = getItem('key_user_id', false, -1, true);
15 | if (uid) return uid - 0;
16 | };
17 |
18 | const saveAppid = (appid) => {
19 | if (appid) {
20 | saveItem('key_app_id', appid + '', false, -1, true);
21 | } else {
22 | log.error('Invalid appid :', appid);
23 | throw new Error('Invalid appid ...');
24 | }
25 | };
26 |
27 | const getAppid = () => {
28 | return getItem('key_app_id', false, -1, true);
29 | };
30 |
31 | const removeUid = () => {
32 | removeItem('key_user_id');
33 | };
34 |
35 | const deleteToken = () => {
36 | removeItem('key_user_token');
37 | };
38 |
39 | const deleteLinkServer = () => {
40 | removeItem('key_user_link_server');
41 | };
42 |
43 | const deleteAesKey = () => {
44 | removeItem('key_user_aes_key');
45 | };
46 |
47 | const deleteDeviceSN = () => {
48 | removeItem('key_user_device_sn');
49 | };
50 |
51 | const deleteDeviceGuid = () => {
52 | removeItem('key_user_device_guid');
53 | };
54 |
55 | const deleteTokenAppId = () => {
56 | removeItem('key_user_token_app_id');
57 | };
58 |
59 | const infoStore = {
60 | saveToken: (token) => saveItem('key_user_token', token),
61 | getToken: () => getItem('key_user_token'),
62 | deleteToken,
63 | saveTokenAppId: (appId) => saveItem('key_user_token_app_id', appId),
64 | getTokenAppId: () => getItem('key_user_token_app_id'),
65 | deleteTokenAppId,
66 | saveLinkServer: (linkServer) => saveItem('key_user_link_server', linkServer),
67 | getLinkServer: () => getItem('key_user_link_server'),
68 | deleteLinkServer,
69 | getAesKey: () => getItem('key_user_aes_key'),
70 | saveAesKey: (key) => saveItem('key_user_aes_key', key),
71 | deleteAesKey,
72 | saveDeviceSN: (deviceSN) => saveItem('key_user_device_sn', deviceSN),
73 | getDeviceSN: () => {
74 | let ret = getItem('key_user_device_sn');
75 | if (!ret) {
76 | ret = 999999999 + Math.floor(Math.random() * 2140000) + '';
77 | }
78 | return ret - 0;
79 | },
80 | deleteDeviceSN,
81 | saveUid,
82 | getUid,
83 | removeUid,
84 | getDeviceGuid: () => {
85 | const uid = getUid();
86 | if (!uid) return '';
87 | let ret = getItem('key_user_device_guid');
88 | if (!ret) {
89 | ret = getUid() + '_' + Math.floor(Math.random() * 2147483648) + '';
90 | saveItem('key_user_device_guid', ret);
91 | }
92 | return ret;
93 | },
94 | deleteDeviceGuid,
95 | saveProfile: (profile) => saveItem('key_user_profile', profile),
96 | getProfile: () => getItem('key_user_profile'),
97 |
98 | clear: () => {
99 | deleteDeviceSN();
100 | deleteAesKey();
101 | deleteToken();
102 | removeUid();
103 | deleteDeviceGuid();
104 | deleteTokenAppId();
105 | deleteLinkServer();
106 | },
107 |
108 | saveAppid,
109 | getAppid
110 | };
111 |
112 | export default infoStore;
113 |
--------------------------------------------------------------------------------
/src/sdk/utils/store/noticeStore.js:
--------------------------------------------------------------------------------
1 | import { getItem } from './storeBase';
2 |
3 | const noticeStore = {
4 | saveNotice: (/*meta*/) => {
5 | /*const items = getItem('key_notice_store') || [];
6 | items.push(meta);
7 | const len = items.length;
8 | if (len > 50) {
9 | items.splice(0, len - 50);
10 | }
11 | saveItem('key_notice_store', items);*/
12 | },
13 | getNotice: () => getItem('key_notice_store') || [],
14 | removeNotice: (/*meta*/) => {
15 | //
16 | }
17 | };
18 |
19 | export default noticeStore;
20 |
--------------------------------------------------------------------------------
/src/sdk/utils/store/rosterStore.js:
--------------------------------------------------------------------------------
1 | import { getItem, removeItem, saveItem } from './storeBase';
2 |
3 | const rosterStore = {
4 | saveRosterList: (rosters = []) => {
5 | if (!Array.isArray(rosters)) {
6 | rosters = [rosters];
7 | }
8 | const ids = rosters.map((item) => item.roster_user_id || item.user_id || item);
9 | const old_roster = rosterStore.getRosterList() || [];
10 | let new_roster;
11 | if (Array.isArray(old_roster)) {
12 | new_roster = Array.from(new Set(old_roster.concat(ids)));
13 | } else {
14 | // old roster is in bad format, abandon it.
15 | new_roster = ids;
16 | }
17 | saveItem('key_roster_lists', new_roster);
18 |
19 | rosterStore.saveRosterInfo(rosters);
20 | },
21 |
22 | getRosterList: () => getItem('key_roster_lists'),
23 |
24 | getRosterInfoList: () => {
25 | const userids = rosterStore.getRosterList() || [];
26 | const allInfos = rosterStore.getAllRosterInfos() || {};
27 | const ret = [];
28 | userids.forEach((uid) => {
29 | const uinfo = allInfos[uid] || {};
30 | ret.push(
31 | Object.assign({}, uinfo, {
32 | user_id: uid
33 | })
34 | );
35 | });
36 | return ret;
37 | },
38 | removeRoster: (uid) => {
39 | const userids = rosterStore.getRosterList();
40 | const index = userids.indexOf(uid);
41 | index >= 0 && userids.splice(index, 1);
42 | saveItem('key_roster_lists', userids);
43 | },
44 | removeRosterList: () => removeItem('key_roster_lists'),
45 | saveRosterInfo: (rosters = []) => {
46 | if (!Array.isArray(rosters)) {
47 | rosters = [rosters];
48 | }
49 | const allSavedMap = rosterStore.getAllRosterInfos() || {};
50 | rosters.forEach((roster) => {
51 | const { user_id } = roster;
52 | const sobj = {};
53 | Object.keys(roster).forEach((key) => {
54 | const v = roster[key];
55 | typeof v !== 'undefined' && (sobj[key] = v);
56 | });
57 | if (user_id) {
58 | allSavedMap[user_id] = allSavedMap[user_id] || {};
59 | Object.assign(allSavedMap[user_id], sobj);
60 | // if (typeof relation !== 'undefined') { // 从 rosterlist 接口取的
61 | // Object.assign(allSavedMap[uid], { relation, alias })
62 | // } else if (typeof username !== 'undefined') { // 从rost list 详情 取的
63 | // }
64 | }
65 | });
66 | saveItem('key_roster_infos', allSavedMap);
67 | },
68 |
69 | getRosterInfo: (uid) => {
70 | const userMap = getItem('key_roster_infos') || {};
71 | let user = userMap[uid] || { user_id: uid };
72 | return (
73 | user &&
74 | Object.assign(user, {
75 | user_id: uid
76 | })
77 | );
78 | },
79 | getAllRosterInfos: () => {
80 | const ret = getItem('key_roster_infos');
81 | return ret;
82 | },
83 |
84 | clear: () => {
85 | removeItem('key_roster_infos');
86 | removeItem('key_roster_lists');
87 | }
88 | };
89 |
90 | export default rosterStore;
91 |
--------------------------------------------------------------------------------
/src/sdk/utils/store/storeBase.js:
--------------------------------------------------------------------------------
1 | import log from '../log';
2 | import { transferToLong } from '../tools';
3 |
4 | const PARTITION_NUMBER = 31;
5 |
6 | const getUid = () => {
7 | let uid = window.sessionStorage.getItem('key_user_id');
8 | if (uid) {
9 | return uid - 0;
10 | } else {
11 | uid = window.localStorage.getItem('key_user_id');
12 | if (uid) return uid - 0;
13 | }
14 | return;
15 | };
16 |
17 | const partitionId = (key) => {
18 | return key % PARTITION_NUMBER;
19 | };
20 |
21 | const saveItem = (key, item, hasuid = true, partition_key = -1, sessionStore = false) => {
22 | if (typeof item === 'undefined' || typeof key === 'undefined') {
23 | log.error('localstorage save error:', key, item);
24 | return;
25 | }
26 |
27 | var skey = key;
28 | if (hasuid) {
29 | const uid = getUid();
30 | skey = uid + '_' + key;
31 | }
32 | if (partition_key >= 0) {
33 | skey = skey + '_' + partitionId(partition_key);
34 | }
35 |
36 | if (typeof item === 'string') {
37 | if (sessionStore) {
38 | window.sessionStorage.setItem(skey, item);
39 | }
40 | window.localStorage.setItem(skey, item);
41 | return;
42 | }
43 |
44 | let ret;
45 | if (Array.isArray(item)) {
46 | ret = {
47 | data: item
48 | };
49 | } else {
50 | ret = item;
51 | }
52 | try {
53 | const itemString = JSON.stringify(ret);
54 | if (itemString) {
55 | if (sessionStore) {
56 | window.sessionStorage.setItem(skey, itemString);
57 | }
58 | window.localStorage.setItem(skey, itemString);
59 | }
60 | } catch (ex) {
61 | log.error('stringify error:', ex, skey, item);
62 | }
63 | };
64 |
65 | const getItem = (key, hasuid = true, partition_key = -1, sessionStore = false) => {
66 | if (typeof key === 'undefined') {
67 | log.error('localstorage get error:', key);
68 | return;
69 | }
70 |
71 | var skey = key;
72 | if (hasuid) {
73 | const uid = getUid();
74 | skey = uid + '_' + key;
75 | }
76 | if (partition_key >= 0) {
77 | skey = skey + '_' + partitionId(partition_key);
78 | }
79 |
80 | let itemString = null;
81 | if (sessionStore) {
82 | itemString = window.sessionStorage.getItem(skey);
83 | if (!itemString) {
84 | itemString = window.localStorage.getItem(skey);
85 | }
86 | } else {
87 | itemString = window.localStorage.getItem(skey);
88 | }
89 | if (!itemString) return undefined;
90 | let ret = itemString;
91 | try {
92 | ret = JSON.parse(itemString);
93 | } catch (ex) {
94 | //
95 | }
96 | ret = transferToLong(ret);
97 | return ret.data || ret;
98 | };
99 |
100 | const removeItem = (key, hasuid = true, partition_key = -1) => {
101 | let skey = key;
102 | if (hasuid) {
103 | const uid = getUid();
104 | skey = uid + '_' + key;
105 | }
106 | if (partition_key >= 0) {
107 | skey = skey + '_' + partitionId(partition_key);
108 | }
109 | window.localStorage.removeItem(skey);
110 | };
111 |
112 | const removeAllItems = (key, hasuid = true) => {
113 | var i;
114 | for (i = 0; i < PARTITION_NUMBER; i++) {
115 | removeItem(key, hasuid, i);
116 | }
117 | removeItem(key, hasuid);
118 | };
119 |
120 | export { saveItem, getItem, removeItem, removeAllItems };
121 |
--------------------------------------------------------------------------------
/src/ui/chatting/contact/conConversation.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ conversation.unread }}
5 |
6 |
7 |
![]()
8 |
{{ system_roster.name }}
9 |
10 |
11 |
![]()
12 |
{{ conversation.name }}
13 |
14 |
15 |
16 | {{ formatTimeString(conversation.timestamp) }}
17 |
18 |
19 | [有人@我]
20 | {{ conversation.content }}
21 |
22 |
23 |
24 |
25 |
26 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/src/ui/chatting/contact/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/ui/chatting/content/group/header.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/src/ui/chatting/content/group/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/src/ui/chatting/content/group/memberList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 群组成员
5 | {{ getMemberList.length }}人
6 |
7 | 设置
8 |
9 |
10 |
13 |
21 |
22 |
23 |
24 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/src/ui/chatting/content/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/ui/chatting/content/notice/groupApplyNotice.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 你同意了 {{ notice.user_name }} 申请加入 {{ notice.group_name }} 群的请求
5 | 你拒绝了 {{ notice.user_name }} 申请加入 {{ notice.group_name }} 群的请求
6 | {{ notice.user_name }} 想要加入群 {{ notice.group_name }} ,请求已过期
7 |
8 | {{ notice.user_name }} 请求加入群 {{ notice.group_name }}
9 | 同意
10 | 或者
11 | 拒绝
12 |
13 |
14 |
15 |
16 |
17 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/src/ui/chatting/content/notice/groupNotice.vue:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/src/ui/chatting/content/notice/groupNotice.vue
--------------------------------------------------------------------------------
/src/ui/chatting/content/notice/index.vue:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/src/ui/chatting/content/notice/index.vue
--------------------------------------------------------------------------------
/src/ui/chatting/content/notice/rosterNotice.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 你同意了 {{ notice.user_name }} 的好友申请
5 | 你拒绝觉了 {{ notice.user_name }} 的好友申请
6 | {{ notice.user_name }} 想加您为好友,请求已过期
7 |
8 | {{ notice.user_name }} 想加您为好友,
9 | 同意
10 | 或者
11 | 拒绝
12 |
13 |
14 |
15 |
16 |
17 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/ui/chatting/content/notice/systemNotice.vue:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxim-top/floo-web/ac066b227567f6c7bb1584b09b7862f65aa8c823/src/ui/chatting/content/notice/systemNotice.vue
--------------------------------------------------------------------------------
/src/ui/chatting/content/roster/header.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/src/ui/chatting/content/roster/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/src/ui/chatting/content/roster/info.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
![]()
5 |
6 |
7 |
8 |
用户id
9 |
{{ userInfo.user_id }}
10 |
11 |
12 |
13 |
用户名称
14 |
{{ rosterName }}
15 |
16 |
17 |
18 |
用户昵称
19 |
{{ nickName }}
20 |
21 |
22 |
删除好友
23 |
添加好友
24 |
开始聊天
25 |
26 |
27 |
28 |
106 |
107 |
112 |
--------------------------------------------------------------------------------
/src/ui/chatting/content/verification/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 本APP(APPID:{{ appid }})由
5 |
6 | {{ verification_description }}
7 |
8 | {{ verification_status }}
9 |
10 | 提供服务
11 |
12 |
13 |
14 |
15 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/src/ui/layers/addfriend.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 | 搜索name
12 |
13 |
14 |
15 | 搜索id
16 |
17 |
18 |
{{ searchResult.username }} (已是好友)
19 |
20 |
{{ searchResult.username }}
21 |
22 |
23 | 添加好友
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/src/ui/layers/addpop.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/ui/layers/callinvite.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
![]()
6 |
7 |
8 |
{{ rosterName }}
9 |
您收到一个视频通话请求
10 |
您收到一个语音通话请求
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/src/ui/layers/changeappid.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/ui/layers/image2.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
![]()
4 |
5 |
6 |
7 |
42 |
43 |
53 |
--------------------------------------------------------------------------------
/src/ui/layers/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/src/ui/layers/joingroup.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 | 搜索
12 |
13 |
14 |
15 | {{ searchObj.name }}
16 | 已加入
17 |
18 |
19 | {{ searchObj.name }}
20 | 申请
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/src/ui/layers/search.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
![]()
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
![]()
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/src/ui/layers/video.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
42 |
43 |
53 |
--------------------------------------------------------------------------------
/src/ui/login/bindacc.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |

8 |
9 |
绑定已有账户
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
绑定
18 |
19 | 注册并绑定
20 |
21 |
22 |
23 |
24 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/src/ui/login/bindreg.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |

8 |
9 |
继续注册,请绑定账户
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
注册
18 |
19 | 已有账户,直接绑定
20 |
21 |
22 |
23 |
24 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/src/ui/login/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/src/ui/login/regedit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |

9 |
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
注册
23 |
26 |
27 | 已有账号,去登录
28 |
29 |
30 |
31 |
32 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/src/ui/login/verifyinfo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
本APP(APPID:{{ appid }})由
8 |
9 |
{{ verification_description }}
10 |
11 |
12 |
13 | {{ verification_status }}
14 |
15 |
16 |
提供服务
17 |
18 |
19 |
20 | 已有账号,去登录
21 |
22 |
23 |
24 |
25 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/ui/store/header.js:
--------------------------------------------------------------------------------
1 | //collection.js
2 |
3 | const state = {
4 | headerStatus: 'contact',
5 | userProfile: {},
6 | supportSafariAudio: false
7 | };
8 |
9 | const headerRequestFlag = {
10 | profile: false
11 | };
12 |
13 | const getters = {
14 | getHeaderStatus(state) {
15 | return state.headerStatus;
16 | },
17 | getUserProfile(state) {
18 | return state.userProfile;
19 | },
20 | getSupportSafariAudio(state) {
21 | return state.supportSafariAudio;
22 | }
23 | };
24 |
25 | const mutations = {
26 | changeHeaderStatus(state, status) {
27 | state.headerStatus = status;
28 | },
29 |
30 | changeHeaderUserProfile(state, profile) {
31 | state.userProfile = profile;
32 | },
33 |
34 | changeSupportSafariAudio(state, status) {
35 | state.supportSafariAudio = status;
36 | }
37 | };
38 |
39 | const actions = {
40 | actionChangeHeaderStatus(context, status) {
41 | context.commit('changeHeaderStatus', status);
42 | },
43 | actionChangeHeaderUserProfile(context, profile) {
44 | context.commit('changeHeaderUserProfile', profile);
45 | },
46 | actionGetHeaderProfile(context) {
47 | const { rootState } = context;
48 | rootState.im.userManage.asyncGetProfile(true).then((profile) => {
49 | context.commit('changeHeaderUserProfile', profile);
50 | });
51 | },
52 | actionLazyGetHeaderProfile(context) {
53 | const { state, rootState } = context;
54 | if (!state.userProfile.user_id && !headerRequestFlag.profile) {
55 | headerRequestFlag.profile = true;
56 | rootState.im.userManage.asyncGetProfile().then((profile) => {
57 | context.commit('changeHeaderUserProfile', profile);
58 | headerRequestFlag.profile = false;
59 | });
60 | }
61 | },
62 | actionChangeSupportSafariAudio(context, status) {
63 | context.commit('changeSupportSafariAudio', status);
64 | }
65 | };
66 | export default {
67 | namespaced: true, //用于在全局引用此文件里的方法时标识这一个的文件名
68 | state,
69 | getters,
70 | mutations,
71 | actions
72 | };
73 |
--------------------------------------------------------------------------------
/src/ui/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuex from 'vuex';
3 |
4 | import Login from './login';
5 | import header from './header';
6 | import contact from './contact';
7 | import chat from './content';
8 | import content from './content';
9 | import forward from './forward';
10 | import setting from './setting';
11 | import layer from './layer';
12 |
13 | Vue.use(Vuex);
14 |
15 | export default new Vuex.Store({
16 | modules: {
17 | login: Login,
18 | header,
19 | contact,
20 | chat,
21 | content,
22 | forward,
23 | setting,
24 | layer
25 | },
26 |
27 | state: {
28 | appID: '',
29 | im: {}
30 | },
31 |
32 | getters: {
33 | getAppID(state) {
34 | return state.appID;
35 | },
36 |
37 | wim(state) {
38 | return state.im;
39 | },
40 | im(state) {
41 | return state.im;
42 | }
43 | },
44 |
45 | mutations: {
46 | changeAppID(state, newAppID) {
47 | state.appID = newAppID;
48 | },
49 |
50 | saveIm(state, pim) {
51 | state.im = pim;
52 | }
53 | },
54 |
55 | actions: {
56 | actionChangeAppID(context, appID) {
57 | context.commit('changeAppID', appID);
58 | },
59 |
60 | actionSaveIm(context, pim) {
61 | context.commit('saveIm', pim);
62 | }
63 | }
64 | });
65 |
--------------------------------------------------------------------------------
/src/ui/store/layer.js:
--------------------------------------------------------------------------------
1 | //collection.js
2 | // import { toNumber } from '../third/tools';
3 |
4 | const state = {
5 | // groupsetting, addfriend, creategroup, joingroup, search, addpop // qrlogin, qrprofile, qrgroup
6 | showing: '',
7 | showmask: false,
8 | imageUrl: '',
9 | videoUrl: '',
10 | appID: ''
11 | };
12 |
13 | const getters = {
14 | getShowing(state) {
15 | return state.showing;
16 | },
17 | getShowmask(state) {
18 | return state.showmask;
19 | },
20 |
21 | gettingqrcode(state) {
22 | return state.qrcode;
23 | },
24 | getImageUrl(state) {
25 | return state.imageUrl;
26 | },
27 | getVideoUrl(state) {
28 | return state.videoUrl;
29 | },
30 | getAppID(state) {
31 | return state.appID;
32 | }
33 | };
34 |
35 | const mutations = {
36 | setShowing(state, x) {
37 | state.showing = x;
38 | },
39 | setShowmask(state, x) {
40 | state.showmask = x;
41 | },
42 |
43 | setImageUrl(state, x) {
44 | state.imageUrl = x;
45 | },
46 | setVideoUrl(state, x) {
47 | state.videoUrl = x;
48 | },
49 |
50 | setAppID(state, x) {
51 | state.appID = x;
52 | }
53 | };
54 |
55 | const actions = {
56 | actionSetShowing(context, x) {
57 | if (x === 'addpop' && state.showing === 'addpop') {
58 | x = '';
59 | }
60 | context.commit('setShowing', x);
61 | },
62 | actionSetShowmask(context, x) {
63 | context.commit('setShowmask', x);
64 | },
65 |
66 | actionSetQrcode(context, x) {
67 | context.commit('setQrcode', x);
68 | },
69 |
70 | actionSetAppID(context, x) {
71 | context.commit('setAppID', x);
72 | },
73 |
74 | actionSetImageUrl(context, x) {
75 | context.commit('setImageUrl', x);
76 | },
77 |
78 | actionSetVideoUrl(context, x) {
79 | context.commit('setVideoUrl', x);
80 | }
81 | };
82 |
83 | export default {
84 | namespaced: true,
85 | state,
86 | getters,
87 | mutations,
88 | actions
89 | };
90 |
--------------------------------------------------------------------------------
/src/ui/store/login.js:
--------------------------------------------------------------------------------
1 | //collection.js
2 |
3 | const state = {
4 | // appStatus: 'login', //初始化一个colects数组
5 | appStatus: 'login', //初始化一个colects数组
6 | login: false,
7 | loginLog: ['这里是登录日志..'],
8 | mobileSign: '',
9 | signMobile: '',
10 | loginInfo: {},
11 | loginInfoList: []
12 | };
13 |
14 | const getters = {
15 | getAppStatus(state) {
16 | return state.appStatus;
17 | },
18 | getLoginInStatus(state) {
19 | return state.login;
20 | },
21 | getLoginLog(state) {
22 | return state.loginLog;
23 | },
24 | getMobileSign(state) {
25 | return state.mobileSign;
26 | },
27 | getSignMobile(state) {
28 | return state.signMobile;
29 | },
30 | getLoginInfo(state) {
31 | return state.loginInfo;
32 | },
33 | getLoginInfoList(state) {
34 | return state.loginInfoList;
35 | }
36 | };
37 |
38 | const mutations = {
39 | changeAppStatus(state, status) {
40 | //如何变化collects,插入items
41 | state.appStatus = status;
42 | },
43 |
44 | changeLoginStatus(state, status) {
45 | //如何变化collects,插入items
46 | state.login = status;
47 | },
48 |
49 | addLoginLog(state, log) {
50 | let sr = [].concat(state.loginLog);
51 | sr.push(log);
52 | if (sr.length > 3) {
53 | sr = sr.slice(-3); // 只保留3条
54 | }
55 | state.loginLog = sr;
56 | },
57 | setMobileSigh(state, sign) {
58 | state.mobileSign = sign;
59 | },
60 | setSighMobile(state, mobile) {
61 | state.signMobile = mobile;
62 | },
63 | setLoginInfo(state, info) {
64 | state.loginInfo = info;
65 | },
66 | setLoginInfoList(state, list) {
67 | state.loginInfoList = list;
68 | }
69 | };
70 |
71 | const actions = {
72 | actionChangeAppStatus(context, status) {
73 | //触发mutations里面的pushCollects ,传入数据形参item 对应到items
74 | context.commit('changeAppStatus', status);
75 | },
76 |
77 | actionChangeLoginStatus(context, status) {
78 | context.commit('changeLoginStatus', status);
79 | },
80 |
81 | actionAddLoginLog(context, log) {
82 | context.commit('addLoginLog', log);
83 | },
84 | actionSetMobileSign(context, sign) {
85 | context.commit('setMobileSigh', sign);
86 | },
87 | actionSetSignMobile(context, mobile) {
88 | context.commit('setSighMobile', mobile);
89 | },
90 | actionSetLoginInfo(context, info) {
91 | context.commit('setLoginInfo', info);
92 | },
93 | actionSetLoginInfoList(context, list) {
94 | context.commit('setLoginInfoList', list);
95 | }
96 | };
97 | export default {
98 | namespaced: true, //用于在全局引用此文件里的方法时标识这一个的文件名
99 | state,
100 | getters,
101 | mutations,
102 | actions
103 | };
104 |
--------------------------------------------------------------------------------
/src/ui/store/setting.js:
--------------------------------------------------------------------------------
1 | //collection.js
2 | // import { toNumber } from '../third/tools';
3 |
4 | const state = {
5 | settingInfo: {},
6 | profileInfo: {},
7 | callStatus: false
8 | };
9 |
10 | const getters = {
11 | getSettingInfo(state) {
12 | return state.settingInfo;
13 | },
14 |
15 | getProfileInfo(state) {
16 | return state.profileInfo;
17 | }
18 | };
19 |
20 | const mutations = {
21 | setSettingInfo(state, x) {
22 | state.settingInfo = x;
23 | },
24 |
25 | setProfileInfo(state, x) {
26 | state.profileInfo = x;
27 | }
28 | };
29 |
30 | const actions = {
31 | actionGetProfile(context) {
32 | const { rootState } = context;
33 | rootState.im.userManage.asyncGetProfile(true).then((res) => {
34 | context.commit('setProfileInfo', res);
35 | });
36 | },
37 | actionGetSettingInfo(context) {
38 | const { rootState } = context;
39 | rootState.im.userManage.asyncGetSettings().then((res) => {
40 | context.commit('setSettingInfo', res);
41 | });
42 | }
43 | };
44 |
45 | export default {
46 | namespaced: true,
47 | state,
48 | getters,
49 | mutations,
50 | actions
51 | };
52 |
--------------------------------------------------------------------------------
/src/ui/support/content/group/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/ui/support/content/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
33 |
--------------------------------------------------------------------------------
/src/ui/support/content/roster/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
46 |
--------------------------------------------------------------------------------
/src/ui/support/content/roster/info.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
![]()
5 |
6 |
7 |
8 |
用户id
9 |
{{ userInfo.user_id }}
10 |
11 |
12 |
13 |
用户名称
14 |
{{ rosterName }}
15 |
16 |
17 |
18 |
用户昵称
19 |
{{ nickName }}
20 |
21 |
22 |
删除好友
23 |
添加好友
24 |
开始聊天
25 |
26 |
27 |
28 |
106 |
107 |
112 |
--------------------------------------------------------------------------------
/src/ui/support/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
77 |
--------------------------------------------------------------------------------
/src/ui/support/loading/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
51 |
52 |
62 |
--------------------------------------------------------------------------------
/src/ui/support/minimize/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
![]()
5 |
6 |
7 |
8 |
9 |
93 |
94 |
114 |
--------------------------------------------------------------------------------
/src/ui/support/skipping/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |

6 |
7 |
即将跳转到小程序
8 |
{{ count }}s...
9 |
10 |
取消
11 |
12 |
13 |
14 |
15 |
16 |
71 |
72 |
113 |
--------------------------------------------------------------------------------
/src/ui/third/base64.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | var Base64 = {
3 | // private property
4 | _keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
5 |
6 | // public method for encoding
7 | encode: function (input) {
8 | var output = '';
9 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
10 | var i = 0;
11 |
12 | input = Base64._utf8_encode(input);
13 |
14 | while (i < input.length) {
15 | chr1 = input.charCodeAt(i++);
16 | chr2 = input.charCodeAt(i++);
17 | chr3 = input.charCodeAt(i++);
18 |
19 | enc1 = chr1 >> 2;
20 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
21 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
22 | enc4 = chr3 & 63;
23 |
24 | if (isNaN(chr2)) {
25 | enc3 = enc4 = 64;
26 | } else if (isNaN(chr3)) {
27 | enc4 = 64;
28 | }
29 |
30 | output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
31 | }
32 |
33 | return output;
34 | },
35 |
36 | // public method for decoding
37 | decode: function (input) {
38 | var output = '';
39 | var chr1, chr2, chr3;
40 | var enc1, enc2, enc3, enc4;
41 | var i = 0;
42 |
43 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
44 |
45 | while (i < input.length) {
46 | enc1 = this._keyStr.indexOf(input.charAt(i++));
47 | enc2 = this._keyStr.indexOf(input.charAt(i++));
48 | enc3 = this._keyStr.indexOf(input.charAt(i++));
49 | enc4 = this._keyStr.indexOf(input.charAt(i++));
50 |
51 | chr1 = (enc1 << 2) | (enc2 >> 4);
52 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
53 | chr3 = ((enc3 & 3) << 6) | enc4;
54 |
55 | output = output + String.fromCharCode(chr1);
56 |
57 | if (enc3 != 64) {
58 | output = output + String.fromCharCode(chr2);
59 | }
60 | if (enc4 != 64) {
61 | output = output + String.fromCharCode(chr3);
62 | }
63 | }
64 |
65 | output = Base64._utf8_decode(output);
66 |
67 | return output;
68 | },
69 |
70 | // private method for UTF-8 encoding
71 | _utf8_encode: function (string) {
72 | string = string.replace(/\r\n/g, '\n');
73 | var utftext = '';
74 |
75 | for (var n = 0; n < string.length; n++) {
76 | var c = string.charCodeAt(n);
77 |
78 | if (c < 128) {
79 | utftext += String.fromCharCode(c);
80 | } else if (c > 127 && c < 2048) {
81 | utftext += String.fromCharCode((c >> 6) | 192);
82 | utftext += String.fromCharCode((c & 63) | 128);
83 | } else {
84 | utftext += String.fromCharCode((c >> 12) | 224);
85 | utftext += String.fromCharCode(((c >> 6) & 63) | 128);
86 | utftext += String.fromCharCode((c & 63) | 128);
87 | }
88 | }
89 |
90 | return utftext;
91 | },
92 |
93 | // private method for UTF-8 decoding
94 | _utf8_decode: function (utftext) {
95 | var string = '';
96 | var i = 0;
97 | var c = 0;
98 | var c2 = 0;
99 | var c3 = 0;
100 |
101 | while (i < utftext.length) {
102 | c = utftext.charCodeAt(i);
103 |
104 | if (c < 128) {
105 | string += String.fromCharCode(c);
106 | i++;
107 | } else if (c > 191 && c < 224) {
108 | c2 = utftext.charCodeAt(i + 1);
109 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
110 | i += 2;
111 | } else {
112 | c2 = utftext.charCodeAt(i + 1);
113 | c3 = utftext.charCodeAt(i + 2);
114 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
115 | i += 3;
116 | }
117 | }
118 | return string;
119 | }
120 | };
121 |
122 | export default Base64;
123 |
--------------------------------------------------------------------------------
/src/ui/third/events.js:
--------------------------------------------------------------------------------
1 | const __ui_events = {};
2 | window.__ui_events = __ui_events;
3 |
4 | const __judgeEvent = (name) => {
5 | if (typeof __ui_events[name] === 'undefined') {
6 | __ui_events[name] = [];
7 | }
8 | return __ui_events[name];
9 | };
10 |
11 | const bind = (name, func) => {
12 | const judge = __judgeEvent(name);
13 | const idx = judge.findIndex((f) => f.toString() === func.toString());
14 | if (idx > -1) {
15 | __judgeEvent(name).splice(idx, 1);
16 | }
17 | __judgeEvent(name).push(func);
18 | };
19 |
20 | const unBind = (name, func) => {
21 | const index = __judgeEvent(name).findIndex((item) => item.toString() === func.toString());
22 | if (index >= 0) {
23 | __ui_events[name].splice(index, 1);
24 | }
25 | };
26 |
27 | const unBindAll = (name) => {
28 | __ui_events[name] = null;
29 | };
30 |
31 | const fire = (name, param) => {
32 | __judgeEvent(name).forEach((func) => {
33 | func(param);
34 | });
35 | };
36 |
37 | export { bind, unBind, unBindAll, fire };
38 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | const webpack = require('webpack');
3 | const path = require('path');
4 |
5 | const devEnv = require('./config/webpack.dev.config');
6 | const pordEnv = require('./config/webpack.prod.config');
7 |
8 | let env = {};
9 | if (process.env.NODE_ENV === 'development') {
10 | env = devEnv;
11 | } else if (process.env.NODE_ENV === 'production') {
12 | env = pordEnv;
13 | }
14 |
15 | module.exports = {
16 | lintOnSave: true,
17 | productionSourceMap: false,
18 | // outputDir: path.resolve(__dirname, 'dist'), // 默认dist
19 | chainWebpack: (config) => {
20 | config.resolve.alias
21 | .set('@src', path.join(__dirname, 'src'))
22 | // .set('vue', path.join('vue', 'dist', 'vue.js'))
23 | .set('/', path.join(__dirname, '/'))
24 | .set('@proj', path.resolve(__dirname))
25 | .set('@build', path.join(__dirname, 'build'))
26 | .set('models', path.resolve(__dirname, 'src/models/'))
27 | .set('services', path.resolve(__dirname, 'src/services/'))
28 | .set('utils', path.resolve(__dirname, 'src/utils/'));
29 | },
30 |
31 | configureWebpack: env
32 | };
33 |
--------------------------------------------------------------------------------