➕ socket.io
This commit is contained in:
parent
1239a951e8
commit
b6767f3b31
@ -76,9 +76,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Vue from 'vue'
|
import Vue from 'vue';
|
||||||
import {mapState} from 'vuex'
|
import {mapState} from 'vuex';
|
||||||
import {isBrowser} from '~/environment'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Comment",
|
name: "Comment",
|
||||||
|
28
io/index.js
Normal file
28
io/index.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import http from 'http'
|
||||||
|
import socketIO from 'socket.io'
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
this.nuxt.hook('render:before', (renderer) => {
|
||||||
|
const server = http.createServer(this.nuxt.renderer.app)
|
||||||
|
const io = socketIO(server)
|
||||||
|
|
||||||
|
// overwrite nuxt.server.listen()
|
||||||
|
this.nuxt.server.listen = (port, host) => new Promise(resolve => server.listen(port || 3000, host || 'localhost', resolve))
|
||||||
|
// close this server on 'close' event
|
||||||
|
this.nuxt.hook('close', () => new Promise(server.close))
|
||||||
|
|
||||||
|
// Add socket.io events
|
||||||
|
const messages = []
|
||||||
|
io.on('connection', (socket) => {
|
||||||
|
socket.on('last-messages', function (fn) {
|
||||||
|
console.log('messages-client', messages);
|
||||||
|
fn(messages.slice(-50))
|
||||||
|
})
|
||||||
|
socket.on('all', function (message) {
|
||||||
|
console.log('message-client', message);
|
||||||
|
messages.push(message)
|
||||||
|
socket.broadcast.emit('new-message', message)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
@ -65,6 +65,7 @@ export default {
|
|||||||
** Nuxt.js modules
|
** Nuxt.js modules
|
||||||
*/
|
*/
|
||||||
modules: [
|
modules: [
|
||||||
|
'~/io',
|
||||||
'@nuxtjs/axios',
|
'@nuxtjs/axios',
|
||||||
'@nuxtjs/proxy',
|
'@nuxtjs/proxy',
|
||||||
'js-cookie',
|
'js-cookie',
|
||||||
|
816
package-lock.json
generated
816
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,12 +12,13 @@
|
|||||||
"@chenfengyuan/vue-qrcode": "^1.0.2",
|
"@chenfengyuan/vue-qrcode": "^1.0.2",
|
||||||
"@nuxtjs/axios": "^5.12.0",
|
"@nuxtjs/axios": "^5.12.0",
|
||||||
"cookieparser": "^0.1.0",
|
"cookieparser": "^0.1.0",
|
||||||
"cross-env": "^7.0.2",
|
|
||||||
"element-ui": "^2.13.2",
|
"element-ui": "^2.13.2",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"js-cookie": "^2.2.1",
|
"js-cookie": "^2.2.1",
|
||||||
"nuxt": "^2.14.0",
|
"nuxt": "^2.14.0",
|
||||||
"save-svg-as-png": "^1.4.17",
|
"save-svg-as-png": "^1.4.17",
|
||||||
|
"socket.io": "^2.3.0",
|
||||||
|
"socket.io-client": "^2.3.0",
|
||||||
"vditor": "^3.4.1",
|
"vditor": "^3.4.1",
|
||||||
"vuejs-avataaars": "^4.0.1"
|
"vuejs-avataaars": "^4.0.1"
|
||||||
},
|
},
|
||||||
|
276
pages/chats/_nickname.vue
Normal file
276
pages/chats/_nickname.vue
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
<template>
|
||||||
|
<el-row class="wrapper">
|
||||||
|
<el-col>
|
||||||
|
<div id="contentEditor"></div>
|
||||||
|
</el-col>
|
||||||
|
<el-col style="margin-top: 1rem;padding-right:3rem;text-align: right;">
|
||||||
|
<el-button type="primary" :loading="loading" @click="send">发送</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col style="margin-top: 2rem;">
|
||||||
|
<el-col v-for="message in messages" :key="message.dataId">
|
||||||
|
<el-col v-if="message.from === user.nickname">
|
||||||
|
<el-col :span="22" style="text-align: right;">
|
||||||
|
<div class="from-message">{{message.content}}</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="2" style="text-align: right;">
|
||||||
|
<el-avatar :src="user.avatarURL"></el-avatar>
|
||||||
|
</el-col>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-else>
|
||||||
|
<el-col :span="2">
|
||||||
|
<el-avatar :src="to.avatarURL"></el-avatar>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="22" style="text-align: left;">
|
||||||
|
<div class="to-message">{{message.content}}</div>
|
||||||
|
</el-col>
|
||||||
|
</el-col>
|
||||||
|
</el-col>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Vue from 'vue';
|
||||||
|
import {mapState} from 'vuex';
|
||||||
|
import socket from '~/plugins/socket.io.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Chat",
|
||||||
|
asyncData() {
|
||||||
|
return new Promise(resolve =>
|
||||||
|
socket.emit('last-messages', messages => resolve({messages}))
|
||||||
|
)
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
user: state => state.userInfo
|
||||||
|
})
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
contentEditor: null,
|
||||||
|
tokenURL: {},
|
||||||
|
drawer: false,
|
||||||
|
direction: 'btt',
|
||||||
|
initEditor: false,
|
||||||
|
isShow: true,
|
||||||
|
loading: false,
|
||||||
|
to: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
messages(value) {
|
||||||
|
console.log(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
socket.on('new-message', (message) => {
|
||||||
|
this.messages.push(message)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
_initEditor(data) {
|
||||||
|
let _ts = this;
|
||||||
|
let toolbar;
|
||||||
|
if (window.innerWidth < 768) {
|
||||||
|
toolbar = [
|
||||||
|
'emoji',
|
||||||
|
'headings',
|
||||||
|
'bold',
|
||||||
|
'italic',
|
||||||
|
'strike',
|
||||||
|
'link',
|
||||||
|
'|',
|
||||||
|
'list',
|
||||||
|
'ordered-list',
|
||||||
|
'check',
|
||||||
|
'outdent',
|
||||||
|
'indent',
|
||||||
|
'|',
|
||||||
|
'quote',
|
||||||
|
'line',
|
||||||
|
'code',
|
||||||
|
'inline-code',
|
||||||
|
'insert-before',
|
||||||
|
'insert-after',
|
||||||
|
'|',
|
||||||
|
'upload',
|
||||||
|
'record',
|
||||||
|
'table',
|
||||||
|
'|',
|
||||||
|
'undo',
|
||||||
|
'redo',
|
||||||
|
'|',
|
||||||
|
'edit-mode',
|
||||||
|
'content-theme',
|
||||||
|
'code-theme',
|
||||||
|
{
|
||||||
|
name: 'more',
|
||||||
|
toolbar: [
|
||||||
|
'fullscreen',
|
||||||
|
'both',
|
||||||
|
'format',
|
||||||
|
'preview',
|
||||||
|
'info',
|
||||||
|
'help',
|
||||||
|
],
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
return new Vue.Vditor(data.id, {
|
||||||
|
toolbar,
|
||||||
|
mode: 'sv',
|
||||||
|
tab: '\t',
|
||||||
|
cache: {
|
||||||
|
enable: this.postId ? false : true,
|
||||||
|
id: this.postId ? this.postId : '',
|
||||||
|
},
|
||||||
|
after() {
|
||||||
|
_ts.contentEditor.setValue(data.value ? data.value : '');
|
||||||
|
},
|
||||||
|
preview: {
|
||||||
|
markdown: {
|
||||||
|
toc: true,
|
||||||
|
},
|
||||||
|
delay: 500,
|
||||||
|
mode: data.mode,
|
||||||
|
/*url: `${process.env.Server}/api/console/markdown`,*/
|
||||||
|
parse: (element) => {
|
||||||
|
if (element.style.display === 'none') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// LazyLoadImage();
|
||||||
|
// Vue.Vditor.highlightRender({style:'github'}, element, document);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
upload: {
|
||||||
|
max: 10 * 1024 * 1024,
|
||||||
|
url: this.tokenURL?.URL,
|
||||||
|
linkToImgUrl: this.tokenURL?.URL,
|
||||||
|
token: this.tokenURL?.token,
|
||||||
|
filename: name => name.replace(/\?|\\|\/|:|\||<|>|\*|\[|\]|\s+/g, '-')
|
||||||
|
},
|
||||||
|
height: data.height,
|
||||||
|
counter: 102400,
|
||||||
|
resize: {
|
||||||
|
enable: data.resize,
|
||||||
|
},
|
||||||
|
lang: this.$store.state.locale,
|
||||||
|
placeholder: data.placeholder,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
send() {
|
||||||
|
let _ts = this;
|
||||||
|
const message = {
|
||||||
|
to: _ts.to.nickname,
|
||||||
|
from: _ts.user.nickname,
|
||||||
|
dataType: 1,
|
||||||
|
dataId: new Date().getTime(),
|
||||||
|
content: _ts.contentEditor.getValue()
|
||||||
|
}
|
||||||
|
_ts.messages.push(message);
|
||||||
|
_ts.contentEditor.setValue('')
|
||||||
|
socket.emit('all', message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
let _ts = this;
|
||||||
|
_ts.$store.commit('setActiveMenu', 'post-article');
|
||||||
|
if (_ts.user) {
|
||||||
|
const responseData = await _ts.$axios.$get('/api/upload/token');
|
||||||
|
if (responseData) {
|
||||||
|
_ts.$set(_ts, 'tokenURL', {
|
||||||
|
token: responseData.uploadToken || '',
|
||||||
|
URL: responseData.uploadURL || '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_ts.initEditor) {
|
||||||
|
_ts.$set(_ts, 'initEditor', true);
|
||||||
|
setTimeout(function () {
|
||||||
|
_ts.contentEditor = _ts._initEditor({
|
||||||
|
id: 'contentEditor',
|
||||||
|
mode: 'both',
|
||||||
|
height: 200,
|
||||||
|
placeholder: '', //this.$t('inputContent', this.$store.state.locale)
|
||||||
|
resize: false,
|
||||||
|
value: ''
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
let to = {
|
||||||
|
nickname: _ts.$route.params.nickname,
|
||||||
|
avatarURL: _ts.$route.params.avatarURL,
|
||||||
|
}
|
||||||
|
_ts.$set(_ts, 'to', to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~vditor/src/assets/scss/index.scss";
|
||||||
|
|
||||||
|
.from-message {
|
||||||
|
float: right;
|
||||||
|
width: 200px;
|
||||||
|
min-height: 40px;
|
||||||
|
margin: 10px;
|
||||||
|
background-color: skyblue;
|
||||||
|
border-bottom-color: skyblue;
|
||||||
|
/*为了给after伪元素自动继承*/
|
||||||
|
color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
padding: 5px 12px 5px 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 6px;
|
||||||
|
position: relative;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.to-message {
|
||||||
|
float: left;
|
||||||
|
width: 200px;
|
||||||
|
min-height: 40px;
|
||||||
|
margin: 10px;
|
||||||
|
background-color: skyblue;
|
||||||
|
border-bottom-color: skyblue;
|
||||||
|
/*为了给after伪元素自动继承*/
|
||||||
|
color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
padding: 5px 12px 5px 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 6px;
|
||||||
|
position: relative;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.from-message::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: -5px;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin-top: -5px;
|
||||||
|
background: inherit;
|
||||||
|
/*自动继承父元素的背景*/
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 通过对小正方形旋转45度解决 **/
|
||||||
|
.to-message::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: -5px;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin-top: -5px;
|
||||||
|
background: inherit;
|
||||||
|
/*自动继承父元素的背景*/
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
</style>
|
@ -11,6 +11,9 @@
|
|||||||
<img v-else class="card-profile-img" src="https://static.rymcu.com/article/1578475481946.png">
|
<img v-else class="card-profile-img" src="https://static.rymcu.com/article/1578475481946.png">
|
||||||
<h3 class="mb-3">{{user.nickname}}</h3>
|
<h3 class="mb-3">{{user.nickname}}</h3>
|
||||||
<p class="mb-4" v-html="user.signature"></p>
|
<p class="mb-4" v-html="user.signature"></p>
|
||||||
|
<div v-if="oauth && oauth.idUser !== user.idUser">
|
||||||
|
<el-button @click="gotoChats">聊天</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -58,7 +61,8 @@
|
|||||||
...mapState({
|
...mapState({
|
||||||
user: state => state.user.data,
|
user: state => state.user.data,
|
||||||
articles: state => state.user.articles,
|
articles: state => state.user.articles,
|
||||||
portfolios: state => state.user.portfolios
|
portfolios: state => state.user.portfolios,
|
||||||
|
oauth: state => state.oauth
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -75,6 +79,12 @@
|
|||||||
},
|
},
|
||||||
handleToggleTab(key) {
|
handleToggleTab(key) {
|
||||||
this.$set(this, 'activeTab', key);
|
this.$set(this, 'activeTab', key);
|
||||||
|
},
|
||||||
|
gotoChats() {
|
||||||
|
let _ts = this;
|
||||||
|
_ts.$router.push({
|
||||||
|
path: `/chats/${_ts.user.nickname}`
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
plugins/socket.io.js
Normal file
8
plugins/socket.io.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import io from 'socket.io-client'
|
||||||
|
import apiConfig from '~/config/api.config'
|
||||||
|
|
||||||
|
const socket = io(apiConfig.SOCKET, {
|
||||||
|
transports: ['websocket']
|
||||||
|
})
|
||||||
|
|
||||||
|
export default socket
|
@ -1,6 +1,8 @@
|
|||||||
const { Nuxt, Builder } = require('nuxt')
|
const { Nuxt, Builder } = require('nuxt')
|
||||||
|
|
||||||
|
const http = require('http')
|
||||||
const app = require('express')()
|
const app = require('express')()
|
||||||
|
const socketio = require('socket.io')
|
||||||
const isProd = (process.env.NODE_ENV === 'production')
|
const isProd = (process.env.NODE_ENV === 'production')
|
||||||
const port = process.env.PORT || 3000
|
const port = process.env.PORT || 3000
|
||||||
|
|
||||||
@ -8,6 +10,8 @@ const port = process.env.PORT || 3000
|
|||||||
const config = require('./nuxt.config.js')
|
const config = require('./nuxt.config.js')
|
||||||
config.dev = !isProd
|
config.dev = !isProd
|
||||||
const nuxt = new Nuxt(config)
|
const nuxt = new Nuxt(config)
|
||||||
|
const server = new http.Server(app)
|
||||||
|
const io = socketio(server, { transports: ['websocket'] })
|
||||||
|
|
||||||
// 用 Nuxt.js 渲染每个路由
|
// 用 Nuxt.js 渲染每个路由
|
||||||
app.use(nuxt.render)
|
app.use(nuxt.render)
|
||||||
@ -26,3 +30,19 @@ function listen () {
|
|||||||
app.listen(port, '0.0.0.0')
|
app.listen(port, '0.0.0.0')
|
||||||
console.log('Server listening on `localhost:' + port + '`.')
|
console.log('Server listening on `localhost:' + port + '`.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Socket.io
|
||||||
|
const messages = []
|
||||||
|
io.on('connection', (socket) => {
|
||||||
|
socket.on('last-messages', function (fn) {
|
||||||
|
console.log('messages-server', messages);
|
||||||
|
fn(messages.slice(-50))
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('all', function (message) {
|
||||||
|
console.log('message-server', message);
|
||||||
|
messages.push(message)
|
||||||
|
socket.broadcast.emit('new-message', message)
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user