💩 websocket
This commit is contained in:
parent
267f05fd25
commit
cd95f0f9a0
@ -107,6 +107,7 @@
|
||||
<script>
|
||||
import {mapState} from 'vuex';
|
||||
import {isBrowser} from '~/environment';
|
||||
import sockClient from '~/plugins/sockjs';
|
||||
|
||||
const Cookie = process.client ? require('js-cookie') : undefined
|
||||
export default {
|
||||
@ -270,6 +271,7 @@ export default {
|
||||
let user = this.user;
|
||||
if (user) {
|
||||
this.getUnreadNotifications();
|
||||
sockClient.initSocket(this.$store.state.userInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ const apisMap = {
|
||||
BASE: 'http://localhost:8099/forest',
|
||||
CDN: '',
|
||||
PROXY: '/proxy',
|
||||
SOCKET: 'http://localhost:3000',
|
||||
SOCKET: 'http://localhost:3000/ws',
|
||||
GRAVATAR: '/proxy/static.rymcu.com/avatar'
|
||||
},
|
||||
production: {
|
||||
@ -14,7 +14,7 @@ const apisMap = {
|
||||
BASE: 'https://rymcu.com',
|
||||
CDN: 'https://static.rymcu.com',
|
||||
PROXY: 'https://static.rymcu.com/proxy',
|
||||
SOCKET: 'https://rymcu.com',
|
||||
SOCKET: 'https://rymcu.com/ws',
|
||||
GRAVATAR: 'https://static.rymcu.com/avatar'
|
||||
}
|
||||
}
|
||||
|
28
io/index.js
28
io/index.js
@ -1,28 +0,0 @@
|
||||
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)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
@ -70,7 +70,6 @@ export default {
|
||||
** Nuxt.js modules
|
||||
*/
|
||||
modules: [
|
||||
'~/io',
|
||||
'@nuxtjs/axios',
|
||||
'@nuxtjs/proxy',
|
||||
'js-cookie',
|
||||
@ -83,6 +82,9 @@ export default {
|
||||
['/api', {
|
||||
target: apiConfig.BASE, //api请求路径
|
||||
pathRewrite: {'^/api': isDevMode ? '/api/v1' : '/api'} //重定向请求路径,防止路由、api路径的冲突
|
||||
}],
|
||||
['/ws', {
|
||||
target: apiConfig.BASE //api请求路径
|
||||
}]
|
||||
],
|
||||
/*
|
||||
|
21
package.json
21
package.json
@ -11,10 +11,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@chenfengyuan/vue-qrcode": "^1.0.2",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.34",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.15.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.2",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.35",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.3",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.15.3",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"@fortawesome/vue-fontawesome": "^2.0.2",
|
||||
"@nuxtjs/axios": "^5.13.1",
|
||||
"babel-plugin-lodash": "^3.3.4",
|
||||
@ -23,19 +23,20 @@
|
||||
"element-ui": "^2.15.1",
|
||||
"express": "^4.17.1",
|
||||
"js-cookie": "^2.2.1",
|
||||
"nuxt": "^2.15.2",
|
||||
"net": "^1.0.2",
|
||||
"nuxt": "^2.15.3",
|
||||
"raw-loader": "^4.0.2",
|
||||
"save-svg-as-png": "^1.4.17",
|
||||
"socket.io": "^2.4.1",
|
||||
"socket.io-client": "^2.4.0",
|
||||
"vditor": "^3.8.2",
|
||||
"sockjs-client": "^1.5.0",
|
||||
"stompjs": "^2.3.3",
|
||||
"vditor": "^3.8.3",
|
||||
"vue-cropperjs": "^4.2.0",
|
||||
"vuejs-avataaars": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxtjs/proxy": "^2.1.0",
|
||||
"lodash-webpack-plugin": "^0.11.6",
|
||||
"node-sass": "^4.12.0",
|
||||
"sass-loader": "^9.0.3"
|
||||
"node-sass": "^5.0.0",
|
||||
"sass-loader": "^10.1.1"
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,8 @@ export default {
|
||||
tagIconPath: '',
|
||||
loading: false,
|
||||
isEdit: false,
|
||||
tag: {}
|
||||
tag: {},
|
||||
notificationFlag: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -233,21 +234,27 @@ export default {
|
||||
message: title + '成功!'
|
||||
});
|
||||
_ts.$set(_ts, 'loading', false);
|
||||
// _ts.getData();
|
||||
_ts.$set(_ts, 'notificationFlag', false);
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
this.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
let _ts = this;
|
||||
if (_ts.notificationFlag) {
|
||||
_ts.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
next();
|
||||
}).catch(() => {
|
||||
_ts.$store.commit("setActiveMenu", "admin-tag-post");
|
||||
return false
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}).catch(() => {
|
||||
return false
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.onbeforeunload = null;
|
||||
@ -265,7 +272,7 @@ export default {
|
||||
return '关闭提示';
|
||||
});
|
||||
let _ts = this;
|
||||
this.$store.commit('setActiveMenu', 'postAdminTag');
|
||||
this.$store.commit('setActiveMenu', 'admin-tag-post');
|
||||
this.$axios.$get('/api/upload/simple/token').then(function (res) {
|
||||
if (res) {
|
||||
_ts.$store.commit('setUploadHeaders', res.uploadToken);
|
||||
|
@ -106,7 +106,8 @@ export default {
|
||||
token: ''
|
||||
},
|
||||
topicIconPath: '',
|
||||
isEdit: false
|
||||
isEdit: false,
|
||||
notificationFlag: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -246,6 +247,7 @@ export default {
|
||||
message: title + '成功!'
|
||||
});
|
||||
_ts.$set(_ts, 'loading', false);
|
||||
_ts.$set(_ts, 'notificationFlag', false);
|
||||
_ts.contentEditor.setValue('');
|
||||
_ts.$router.push({
|
||||
path: `/admin/topic/${data.topicUri}`
|
||||
@ -255,15 +257,21 @@ export default {
|
||||
}
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
this.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
let _ts = this;
|
||||
if (_ts.notificationFlag) {
|
||||
_ts.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
next();
|
||||
}).catch(() => {
|
||||
_ts.$store.commit("setActiveMenu", "admin-topic-post");
|
||||
return false
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}).catch(() => {
|
||||
return false
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.onbeforeunload = null;
|
||||
|
@ -87,7 +87,8 @@
|
||||
list: [],
|
||||
loading: false,
|
||||
doLoading: false,
|
||||
isEdit: false
|
||||
isEdit: false,
|
||||
notificationFlag: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -232,6 +233,7 @@
|
||||
localStorage.removeItem('article-title');
|
||||
localStorage.removeItem('article-tags');
|
||||
_ts.contentEditor.setValue('');
|
||||
_ts.$set(_ts, 'notificationFlag', false);
|
||||
_ts.$router.push({
|
||||
name: 'index'
|
||||
})
|
||||
@ -271,6 +273,7 @@
|
||||
localStorage.removeItem('article-tags');
|
||||
_ts.contentEditor.setValue('');
|
||||
_ts.$store.commit('article/clearDetailData')
|
||||
_ts.$set(_ts, 'notificationFlag', false);
|
||||
_ts.$router.push({
|
||||
path: `/article/${res.id}`
|
||||
})
|
||||
@ -307,6 +310,7 @@
|
||||
localStorage.removeItem('article-title');
|
||||
localStorage.removeItem('article-tags');
|
||||
_ts.contentEditor.setValue('');
|
||||
_ts.$set(_ts, 'notificationFlag', false);
|
||||
_ts.$router.push({
|
||||
path: `/draft/${res.id}`
|
||||
})
|
||||
@ -323,15 +327,21 @@
|
||||
}
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
this.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
let _ts = this;
|
||||
if (_ts.notificationFlag) {
|
||||
_ts.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
next();
|
||||
}).catch(() => {
|
||||
return false
|
||||
});
|
||||
_ts.$store.commit("setActiveMenu", "article-post");
|
||||
} else {
|
||||
next();
|
||||
}).catch(() => {
|
||||
return false
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.onbeforeunload = null;
|
||||
@ -349,7 +359,7 @@
|
||||
return '关闭提示';
|
||||
});
|
||||
let _ts = this;
|
||||
_ts.$store.commit('setActiveMenu', 'post-article');
|
||||
_ts.$store.commit('setActiveMenu', 'article-post');
|
||||
const responseData = await _ts.$axios.$get('/api/upload/token');
|
||||
if (responseData) {
|
||||
_ts.$set(_ts, 'tokenURL', {
|
||||
|
@ -1,4 +1,4 @@
|
||||
template>
|
||||
<template>
|
||||
<client-only>
|
||||
<el-row class="wrapper" v-if="user">
|
||||
<el-col>
|
||||
@ -36,249 +36,238 @@ template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import {mapState} from 'vuex';
|
||||
import socket from '~/plugins/socket.io.js';
|
||||
import Vue from 'vue';
|
||||
import {mapState} from 'vuex';
|
||||
import sockClient from '~/plugins/sockjs';
|
||||
|
||||
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: {
|
||||
URL: '',
|
||||
linkToImageURL: '',
|
||||
token: ''
|
||||
},
|
||||
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 = [
|
||||
'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',
|
||||
{
|
||||
name: 'more',
|
||||
toolbar: [
|
||||
'fullscreen',
|
||||
'both',
|
||||
'preview',
|
||||
'info'
|
||||
],
|
||||
}]
|
||||
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.linkToImageURL,
|
||||
token: this.tokenURL.token,
|
||||
filename: name => name.replace(/[^(a-zA-Z0-9\u4e00-\u9fa5\.)]/g, '').
|
||||
replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, '').
|
||||
replace('/\\s/g', '')
|
||||
},
|
||||
height: data.height,
|
||||
counter: 102400,
|
||||
resize: {
|
||||
enable: data.resize,
|
||||
},
|
||||
lang: this.$store.state.locale,
|
||||
placeholder: data.placeholder,
|
||||
})
|
||||
export default {
|
||||
name: "Chat",
|
||||
computed: {
|
||||
...mapState({
|
||||
user: state => state.userInfo
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
contentEditor: null,
|
||||
tokenURL: {
|
||||
URL: '',
|
||||
linkToImageURL: '',
|
||||
token: ''
|
||||
},
|
||||
async send() {
|
||||
let _ts = this;
|
||||
const message = {
|
||||
to: _ts.to.nickname,
|
||||
from: _ts.user.nickname,
|
||||
dataType: 1,
|
||||
dataId: new Date().getTime(),
|
||||
content: await _ts.contentEditor.getHTML()
|
||||
}
|
||||
_ts.messages.push(message);
|
||||
_ts.contentEditor.setValue('')
|
||||
socket.emit('all', message);
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
drawer: false,
|
||||
direction: 'btt',
|
||||
initEditor: false,
|
||||
isShow: true,
|
||||
loading: false,
|
||||
to: {},
|
||||
messages: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
messages(value) {
|
||||
console.log(value);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
_initEditor(data) {
|
||||
let _ts = this;
|
||||
_ts.$store.commit('setActiveMenu', 'post-article');
|
||||
|
||||
let to = {
|
||||
nickname: _ts.$route.params?.nickname
|
||||
let 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',
|
||||
{
|
||||
name: 'more',
|
||||
toolbar: [
|
||||
'fullscreen',
|
||||
'both',
|
||||
'preview',
|
||||
'info'
|
||||
],
|
||||
}]
|
||||
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.linkToImageURL,
|
||||
token: this.tokenURL.token,
|
||||
filename: name => name.replace(/[^(a-zA-Z0-9\u4e00-\u9fa5\.)]/g, '').replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, '').replace('/\\s/g', '')
|
||||
},
|
||||
height: data.height,
|
||||
counter: 102400,
|
||||
resize: {
|
||||
enable: data.resize,
|
||||
},
|
||||
lang: this.$store.state.locale,
|
||||
placeholder: data.placeholder,
|
||||
})
|
||||
},
|
||||
async send() {
|
||||
let _ts = this;
|
||||
const message = {
|
||||
to: _ts.to.nickname,
|
||||
from: _ts.user.nickname,
|
||||
dataType: 1,
|
||||
dataId: new Date().getTime(),
|
||||
content: await _ts.contentEditor.getHTML()
|
||||
}
|
||||
_ts.messages.push(message);
|
||||
_ts.contentEditor.setValue('')
|
||||
sockClient.sendMessage(message)
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
let _ts = this;
|
||||
_ts.$store.commit('setActiveMenu', 'post-article');
|
||||
|
||||
_ts.$set(_ts, 'to', to);
|
||||
let to = {
|
||||
nickname: _ts.$route.params?.nickname
|
||||
}
|
||||
|
||||
if (_ts.user) {
|
||||
const responseData = await _ts.$axios.$get('/api/upload/token');
|
||||
if (responseData) {
|
||||
_ts.$set(_ts, 'tokenURL', {
|
||||
token: responseData.uploadToken || '',
|
||||
URL: responseData.uploadURL || '',
|
||||
linkToImageURL: responseData.linkToImageURL || ''
|
||||
})
|
||||
}
|
||||
}
|
||||
_ts.$set(_ts, 'to', to);
|
||||
|
||||
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);
|
||||
if (_ts.user) {
|
||||
const responseData = await _ts.$axios.$get('/api/upload/token');
|
||||
if (responseData) {
|
||||
_ts.$set(_ts, 'tokenURL', {
|
||||
token: responseData.uploadToken || '',
|
||||
URL: responseData.uploadURL || '',
|
||||
linkToImageURL: responseData.linkToImageURL || ''
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~vditor/src/assets/scss/index.scss";
|
||||
@import "~vditor/src/assets/scss/index.scss";
|
||||
|
||||
.from-message {
|
||||
float: right;
|
||||
width: auto;
|
||||
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 {
|
||||
float: right;
|
||||
width: auto;
|
||||
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: auto;
|
||||
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: auto;
|
||||
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);
|
||||
}
|
||||
.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);
|
||||
}
|
||||
/** 通过对小正方形旋转45度解决 **/
|
||||
.to-message::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: -5px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-top: -5px;
|
||||
background: inherit;
|
||||
/*自动继承父元素的背景*/
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
</style>
|
||||
|
@ -138,7 +138,8 @@ export default {
|
||||
headImgUrl: '',
|
||||
cropImg: '',
|
||||
isEdit: false,
|
||||
autoCrop: true
|
||||
autoCrop: true,
|
||||
notificationFlag: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -282,6 +283,7 @@ export default {
|
||||
type: 'success',
|
||||
message: title + '成功!'
|
||||
});
|
||||
_ts.$set(_ts, 'notificationFlag', false);
|
||||
_ts.$router.push({
|
||||
path: '/portfolio/' + res.idPortfolio
|
||||
})
|
||||
@ -305,6 +307,7 @@ export default {
|
||||
if (res.message) {
|
||||
_ts.$message(res.message);
|
||||
} else {
|
||||
_ts.$set(_ts, 'notificationFlag', false);
|
||||
_ts.$router.push({
|
||||
path: '/user/' + _ts.$store.state.userInfo?.nickname
|
||||
})
|
||||
@ -339,15 +342,21 @@ export default {
|
||||
}
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
this.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
let _ts = this;
|
||||
if (_ts.notificationFlag) {
|
||||
_ts.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
next();
|
||||
}).catch(() => {
|
||||
_ts.$store.commit("setActiveMenu", "portfolio-post");
|
||||
return false
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}).catch(() => {
|
||||
return false
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.onbeforeunload = null;
|
||||
|
@ -35,7 +35,7 @@
|
||||
<div v-if="oauth.idUser !== user.idUser">
|
||||
<el-button type="primary" v-if="isFollow" @click="cancelFollowUser(user.idUser)" plain>取消关注</el-button>
|
||||
<el-button type="primary" v-else @click="followUser(user.idUser)" plain>关注</el-button>
|
||||
<el-button v-show="false" @click="gotoChats" plain>聊天</el-button>
|
||||
<el-button @click="gotoChats" plain>聊天</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
|
@ -1,8 +0,0 @@
|
||||
import io from 'socket.io-client'
|
||||
import apiConfig from '~/config/api.config'
|
||||
|
||||
const socket = io(apiConfig.SOCKET, {
|
||||
transports: ['websocket']
|
||||
})
|
||||
|
||||
export default socket
|
72
plugins/sockjs.js
Normal file
72
plugins/sockjs.js
Normal file
@ -0,0 +1,72 @@
|
||||
import SockJS from 'sockjs-client'
|
||||
import Stomp from 'stompjs'
|
||||
|
||||
import apiConfig from '~/config/api.config'
|
||||
|
||||
export default {
|
||||
socket: null,
|
||||
stompClient: null,
|
||||
headers: null,
|
||||
successCallback() {
|
||||
let _ts = this;
|
||||
_ts.stompClient.subscribe(`/user/${_ts.headers.id}/message`, (msg) => {
|
||||
let message = JSON.parse(msg.body);
|
||||
console.log(message.dataType)
|
||||
switch (message.dataType) {
|
||||
case 0:
|
||||
console.log(message.content)
|
||||
break;
|
||||
case 1:
|
||||
console.log(message.to)
|
||||
break;
|
||||
default:
|
||||
console.log(message)
|
||||
}
|
||||
}, _ts.headers);
|
||||
_ts.stompClient.subscribe('/topic/greening', (msg) => {
|
||||
console.log('pub', JSON.parse(msg.body));
|
||||
});
|
||||
},
|
||||
initSocket: function (user) {
|
||||
let _ts = this;
|
||||
_ts.socket = new SockJS(apiConfig.SOCKET);
|
||||
_ts.stompClient = Stomp.over(_ts.socket);
|
||||
let headers = {
|
||||
id: user.nickname
|
||||
}
|
||||
_ts.headers = headers;
|
||||
_ts.stompClient.connect(_ts.headers, () => {
|
||||
_ts.successCallback();
|
||||
}, (err) => {
|
||||
console.log(err)
|
||||
_ts.reconnect(apiConfig.SOCKET, _ts.successCallback)
|
||||
})
|
||||
},
|
||||
// 断开重连使用定时器定时连接服务器
|
||||
reconnect(socketUrl, successCallback) {
|
||||
console.info('in reconnect function')
|
||||
let connected = false
|
||||
let _ts = this
|
||||
const reconInv = setInterval(() => {
|
||||
console.info('in interval' + Math.random())
|
||||
_ts.socket = new SockJS(socketUrl)
|
||||
_ts.stompClient = Stomp.over(this.socket)
|
||||
_ts.stompClient.connect({}, (frame) => {
|
||||
console.info('reconnected success')
|
||||
// 连接成功,清除定时器
|
||||
clearInterval(reconInv)
|
||||
connected = true
|
||||
successCallback()
|
||||
}, () => {
|
||||
console.info('reconnect failed')
|
||||
console.info('connected:' + connected)
|
||||
if (connected) {
|
||||
console.info('connect .... what?')
|
||||
}
|
||||
})
|
||||
}, 2000)
|
||||
},
|
||||
sendMessage: function (message) {
|
||||
this.stompClient.send('/app/message', {}, JSON.stringify(message))
|
||||
}
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
const { Nuxt, Builder } = require('nuxt')
|
||||
|
||||
const http = require('http')
|
||||
const app = require('express')()
|
||||
const socketio = require('socket.io')
|
||||
const isProd = (process.env.NODE_ENV === 'production')
|
||||
const port = process.env.PORT || 3000
|
||||
|
||||
@ -10,8 +8,6 @@ const port = process.env.PORT || 3000
|
||||
const config = require('./nuxt.config.js')
|
||||
config.dev = !isProd
|
||||
const nuxt = new Nuxt(config)
|
||||
const server = new http.Server(app)
|
||||
const io = socketio(server, { transports: ['websocket'] })
|
||||
|
||||
// 用 Nuxt.js 渲染每个路由
|
||||
app.use(nuxt.render)
|
||||
@ -28,21 +24,5 @@ if (config.dev) {
|
||||
function listen () {
|
||||
// 服务端监听
|
||||
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