💩 websocket
This commit is contained in:
parent
267f05fd25
commit
cd95f0f9a0
@ -107,6 +107,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import {mapState} from 'vuex';
|
import {mapState} from 'vuex';
|
||||||
import {isBrowser} from '~/environment';
|
import {isBrowser} from '~/environment';
|
||||||
|
import sockClient from '~/plugins/sockjs';
|
||||||
|
|
||||||
const Cookie = process.client ? require('js-cookie') : undefined
|
const Cookie = process.client ? require('js-cookie') : undefined
|
||||||
export default {
|
export default {
|
||||||
@ -270,6 +271,7 @@ export default {
|
|||||||
let user = this.user;
|
let user = this.user;
|
||||||
if (user) {
|
if (user) {
|
||||||
this.getUnreadNotifications();
|
this.getUnreadNotifications();
|
||||||
|
sockClient.initSocket(this.$store.state.userInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ const apisMap = {
|
|||||||
BASE: 'http://localhost:8099/forest',
|
BASE: 'http://localhost:8099/forest',
|
||||||
CDN: '',
|
CDN: '',
|
||||||
PROXY: '/proxy',
|
PROXY: '/proxy',
|
||||||
SOCKET: 'http://localhost:3000',
|
SOCKET: 'http://localhost:3000/ws',
|
||||||
GRAVATAR: '/proxy/static.rymcu.com/avatar'
|
GRAVATAR: '/proxy/static.rymcu.com/avatar'
|
||||||
},
|
},
|
||||||
production: {
|
production: {
|
||||||
@ -14,7 +14,7 @@ const apisMap = {
|
|||||||
BASE: 'https://rymcu.com',
|
BASE: 'https://rymcu.com',
|
||||||
CDN: 'https://static.rymcu.com',
|
CDN: 'https://static.rymcu.com',
|
||||||
PROXY: 'https://static.rymcu.com/proxy',
|
PROXY: 'https://static.rymcu.com/proxy',
|
||||||
SOCKET: 'https://rymcu.com',
|
SOCKET: 'https://rymcu.com/ws',
|
||||||
GRAVATAR: 'https://static.rymcu.com/avatar'
|
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
|
** Nuxt.js modules
|
||||||
*/
|
*/
|
||||||
modules: [
|
modules: [
|
||||||
'~/io',
|
|
||||||
'@nuxtjs/axios',
|
'@nuxtjs/axios',
|
||||||
'@nuxtjs/proxy',
|
'@nuxtjs/proxy',
|
||||||
'js-cookie',
|
'js-cookie',
|
||||||
@ -83,6 +82,9 @@ export default {
|
|||||||
['/api', {
|
['/api', {
|
||||||
target: apiConfig.BASE, //api请求路径
|
target: apiConfig.BASE, //api请求路径
|
||||||
pathRewrite: {'^/api': isDevMode ? '/api/v1' : '/api'} //重定向请求路径,防止路由、api路径的冲突
|
pathRewrite: {'^/api': isDevMode ? '/api/v1' : '/api'} //重定向请求路径,防止路由、api路径的冲突
|
||||||
|
}],
|
||||||
|
['/ws', {
|
||||||
|
target: apiConfig.BASE //api请求路径
|
||||||
}]
|
}]
|
||||||
],
|
],
|
||||||
/*
|
/*
|
||||||
|
21
package.json
21
package.json
@ -11,10 +11,10 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chenfengyuan/vue-qrcode": "^1.0.2",
|
"@chenfengyuan/vue-qrcode": "^1.0.2",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.34",
|
"@fortawesome/fontawesome-svg-core": "^1.2.35",
|
||||||
"@fortawesome/free-brands-svg-icons": "^5.15.2",
|
"@fortawesome/free-brands-svg-icons": "^5.15.3",
|
||||||
"@fortawesome/free-regular-svg-icons": "^5.15.1",
|
"@fortawesome/free-regular-svg-icons": "^5.15.3",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.2",
|
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||||
"@fortawesome/vue-fontawesome": "^2.0.2",
|
"@fortawesome/vue-fontawesome": "^2.0.2",
|
||||||
"@nuxtjs/axios": "^5.13.1",
|
"@nuxtjs/axios": "^5.13.1",
|
||||||
"babel-plugin-lodash": "^3.3.4",
|
"babel-plugin-lodash": "^3.3.4",
|
||||||
@ -23,19 +23,20 @@
|
|||||||
"element-ui": "^2.15.1",
|
"element-ui": "^2.15.1",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"js-cookie": "^2.2.1",
|
"js-cookie": "^2.2.1",
|
||||||
"nuxt": "^2.15.2",
|
"net": "^1.0.2",
|
||||||
|
"nuxt": "^2.15.3",
|
||||||
"raw-loader": "^4.0.2",
|
"raw-loader": "^4.0.2",
|
||||||
"save-svg-as-png": "^1.4.17",
|
"save-svg-as-png": "^1.4.17",
|
||||||
"socket.io": "^2.4.1",
|
"sockjs-client": "^1.5.0",
|
||||||
"socket.io-client": "^2.4.0",
|
"stompjs": "^2.3.3",
|
||||||
"vditor": "^3.8.2",
|
"vditor": "^3.8.3",
|
||||||
"vue-cropperjs": "^4.2.0",
|
"vue-cropperjs": "^4.2.0",
|
||||||
"vuejs-avataaars": "^4.0.1"
|
"vuejs-avataaars": "^4.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxtjs/proxy": "^2.1.0",
|
"@nuxtjs/proxy": "^2.1.0",
|
||||||
"lodash-webpack-plugin": "^0.11.6",
|
"lodash-webpack-plugin": "^0.11.6",
|
||||||
"node-sass": "^4.12.0",
|
"node-sass": "^5.0.0",
|
||||||
"sass-loader": "^9.0.3"
|
"sass-loader": "^10.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,8 @@ export default {
|
|||||||
tagIconPath: '',
|
tagIconPath: '',
|
||||||
loading: false,
|
loading: false,
|
||||||
isEdit: false,
|
isEdit: false,
|
||||||
tag: {}
|
tag: {},
|
||||||
|
notificationFlag: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -233,21 +234,27 @@ export default {
|
|||||||
message: title + '成功!'
|
message: title + '成功!'
|
||||||
});
|
});
|
||||||
_ts.$set(_ts, 'loading', false);
|
_ts.$set(_ts, 'loading', false);
|
||||||
// _ts.getData();
|
_ts.$set(_ts, 'notificationFlag', false);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeRouteLeave(to, from, next) {
|
beforeRouteLeave(to, from, next) {
|
||||||
this.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
let _ts = this;
|
||||||
confirmButtonText: '确定',
|
if (_ts.notificationFlag) {
|
||||||
cancelButtonText: '取消',
|
_ts.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||||
type: 'warning'
|
confirmButtonText: '确定',
|
||||||
}).then(() => {
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
next();
|
||||||
|
}).catch(() => {
|
||||||
|
_ts.$store.commit("setActiveMenu", "admin-tag-post");
|
||||||
|
return false
|
||||||
|
});
|
||||||
|
} else {
|
||||||
next();
|
next();
|
||||||
}).catch(() => {
|
}
|
||||||
return false
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
window.onbeforeunload = null;
|
window.onbeforeunload = null;
|
||||||
@ -265,7 +272,7 @@ export default {
|
|||||||
return '关闭提示';
|
return '关闭提示';
|
||||||
});
|
});
|
||||||
let _ts = this;
|
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) {
|
this.$axios.$get('/api/upload/simple/token').then(function (res) {
|
||||||
if (res) {
|
if (res) {
|
||||||
_ts.$store.commit('setUploadHeaders', res.uploadToken);
|
_ts.$store.commit('setUploadHeaders', res.uploadToken);
|
||||||
|
@ -106,7 +106,8 @@ export default {
|
|||||||
token: ''
|
token: ''
|
||||||
},
|
},
|
||||||
topicIconPath: '',
|
topicIconPath: '',
|
||||||
isEdit: false
|
isEdit: false,
|
||||||
|
notificationFlag: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -246,6 +247,7 @@ export default {
|
|||||||
message: title + '成功!'
|
message: title + '成功!'
|
||||||
});
|
});
|
||||||
_ts.$set(_ts, 'loading', false);
|
_ts.$set(_ts, 'loading', false);
|
||||||
|
_ts.$set(_ts, 'notificationFlag', false);
|
||||||
_ts.contentEditor.setValue('');
|
_ts.contentEditor.setValue('');
|
||||||
_ts.$router.push({
|
_ts.$router.push({
|
||||||
path: `/admin/topic/${data.topicUri}`
|
path: `/admin/topic/${data.topicUri}`
|
||||||
@ -255,15 +257,21 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeRouteLeave(to, from, next) {
|
beforeRouteLeave(to, from, next) {
|
||||||
this.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
let _ts = this;
|
||||||
confirmButtonText: '确定',
|
if (_ts.notificationFlag) {
|
||||||
cancelButtonText: '取消',
|
_ts.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||||
type: 'warning'
|
confirmButtonText: '确定',
|
||||||
}).then(() => {
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
next();
|
||||||
|
}).catch(() => {
|
||||||
|
_ts.$store.commit("setActiveMenu", "admin-topic-post");
|
||||||
|
return false
|
||||||
|
});
|
||||||
|
} else {
|
||||||
next();
|
next();
|
||||||
}).catch(() => {
|
}
|
||||||
return false
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
window.onbeforeunload = null;
|
window.onbeforeunload = null;
|
||||||
|
@ -87,7 +87,8 @@
|
|||||||
list: [],
|
list: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
doLoading: false,
|
doLoading: false,
|
||||||
isEdit: false
|
isEdit: false,
|
||||||
|
notificationFlag: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -232,6 +233,7 @@
|
|||||||
localStorage.removeItem('article-title');
|
localStorage.removeItem('article-title');
|
||||||
localStorage.removeItem('article-tags');
|
localStorage.removeItem('article-tags');
|
||||||
_ts.contentEditor.setValue('');
|
_ts.contentEditor.setValue('');
|
||||||
|
_ts.$set(_ts, 'notificationFlag', false);
|
||||||
_ts.$router.push({
|
_ts.$router.push({
|
||||||
name: 'index'
|
name: 'index'
|
||||||
})
|
})
|
||||||
@ -271,6 +273,7 @@
|
|||||||
localStorage.removeItem('article-tags');
|
localStorage.removeItem('article-tags');
|
||||||
_ts.contentEditor.setValue('');
|
_ts.contentEditor.setValue('');
|
||||||
_ts.$store.commit('article/clearDetailData')
|
_ts.$store.commit('article/clearDetailData')
|
||||||
|
_ts.$set(_ts, 'notificationFlag', false);
|
||||||
_ts.$router.push({
|
_ts.$router.push({
|
||||||
path: `/article/${res.id}`
|
path: `/article/${res.id}`
|
||||||
})
|
})
|
||||||
@ -307,6 +310,7 @@
|
|||||||
localStorage.removeItem('article-title');
|
localStorage.removeItem('article-title');
|
||||||
localStorage.removeItem('article-tags');
|
localStorage.removeItem('article-tags');
|
||||||
_ts.contentEditor.setValue('');
|
_ts.contentEditor.setValue('');
|
||||||
|
_ts.$set(_ts, 'notificationFlag', false);
|
||||||
_ts.$router.push({
|
_ts.$router.push({
|
||||||
path: `/draft/${res.id}`
|
path: `/draft/${res.id}`
|
||||||
})
|
})
|
||||||
@ -323,15 +327,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeRouteLeave(to, from, next) {
|
beforeRouteLeave(to, from, next) {
|
||||||
this.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
let _ts = this;
|
||||||
confirmButtonText: '确定',
|
if (_ts.notificationFlag) {
|
||||||
cancelButtonText: '取消',
|
_ts.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||||
type: 'warning'
|
confirmButtonText: '确定',
|
||||||
}).then(() => {
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
next();
|
||||||
|
}).catch(() => {
|
||||||
|
return false
|
||||||
|
});
|
||||||
|
_ts.$store.commit("setActiveMenu", "article-post");
|
||||||
|
} else {
|
||||||
next();
|
next();
|
||||||
}).catch(() => {
|
}
|
||||||
return false
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
window.onbeforeunload = null;
|
window.onbeforeunload = null;
|
||||||
@ -349,7 +359,7 @@
|
|||||||
return '关闭提示';
|
return '关闭提示';
|
||||||
});
|
});
|
||||||
let _ts = this;
|
let _ts = this;
|
||||||
_ts.$store.commit('setActiveMenu', 'post-article');
|
_ts.$store.commit('setActiveMenu', 'article-post');
|
||||||
const responseData = await _ts.$axios.$get('/api/upload/token');
|
const responseData = await _ts.$axios.$get('/api/upload/token');
|
||||||
if (responseData) {
|
if (responseData) {
|
||||||
_ts.$set(_ts, 'tokenURL', {
|
_ts.$set(_ts, 'tokenURL', {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
template>
|
<template>
|
||||||
<client-only>
|
<client-only>
|
||||||
<el-row class="wrapper" v-if="user">
|
<el-row class="wrapper" v-if="user">
|
||||||
<el-col>
|
<el-col>
|
||||||
@ -36,249 +36,238 @@ template>
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import {mapState} from 'vuex';
|
import {mapState} from 'vuex';
|
||||||
import socket from '~/plugins/socket.io.js';
|
import sockClient from '~/plugins/sockjs';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Chat",
|
name: "Chat",
|
||||||
asyncData() {
|
computed: {
|
||||||
return new Promise(resolve =>
|
...mapState({
|
||||||
socket.emit('last-messages', messages => resolve({messages}))
|
user: state => state.userInfo
|
||||||
)
|
})
|
||||||
},
|
},
|
||||||
computed: {
|
data() {
|
||||||
...mapState({
|
return {
|
||||||
user: state => state.userInfo
|
contentEditor: null,
|
||||||
})
|
tokenURL: {
|
||||||
},
|
URL: '',
|
||||||
data() {
|
linkToImageURL: '',
|
||||||
return {
|
token: ''
|
||||||
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,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
async send() {
|
drawer: false,
|
||||||
let _ts = this;
|
direction: 'btt',
|
||||||
const message = {
|
initEditor: false,
|
||||||
to: _ts.to.nickname,
|
isShow: true,
|
||||||
from: _ts.user.nickname,
|
loading: false,
|
||||||
dataType: 1,
|
to: {},
|
||||||
dataId: new Date().getTime(),
|
messages: []
|
||||||
content: await _ts.contentEditor.getHTML()
|
}
|
||||||
}
|
},
|
||||||
_ts.messages.push(message);
|
watch: {
|
||||||
_ts.contentEditor.setValue('')
|
messages(value) {
|
||||||
socket.emit('all', message);
|
console.log(value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
methods: {
|
||||||
|
_initEditor(data) {
|
||||||
let _ts = this;
|
let _ts = this;
|
||||||
_ts.$store.commit('setActiveMenu', 'post-article');
|
|
||||||
|
|
||||||
let to = {
|
let toolbar = [
|
||||||
nickname: _ts.$route.params?.nickname
|
'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) {
|
_ts.$set(_ts, 'to', to);
|
||||||
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) {
|
if (_ts.user) {
|
||||||
_ts.$set(_ts, 'initEditor', true);
|
const responseData = await _ts.$axios.$get('/api/upload/token');
|
||||||
setTimeout(function () {
|
if (responseData) {
|
||||||
_ts.contentEditor = _ts._initEditor({
|
_ts.$set(_ts, 'tokenURL', {
|
||||||
id: 'contentEditor',
|
token: responseData.uploadToken || '',
|
||||||
mode: 'both',
|
URL: responseData.uploadURL || '',
|
||||||
height: 200,
|
linkToImageURL: responseData.linkToImageURL || ''
|
||||||
placeholder: '', //this.$t('inputContent', this.$store.state.locale)
|
})
|
||||||
resize: false,
|
|
||||||
value: ''
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "~vditor/src/assets/scss/index.scss";
|
@import "~vditor/src/assets/scss/index.scss";
|
||||||
|
|
||||||
.from-message {
|
.from-message {
|
||||||
float: right;
|
float: right;
|
||||||
width: auto;
|
width: auto;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
background-color: skyblue;
|
background-color: skyblue;
|
||||||
border-bottom-color: skyblue;
|
border-bottom-color: skyblue;
|
||||||
/*为了给after伪元素自动继承*/
|
/*为了给after伪元素自动继承*/
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
padding: 5px 12px 5px 12px;
|
padding: 5px 12px 5px 12px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
position: relative;
|
position: relative;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.to-message {
|
.to-message {
|
||||||
float: left;
|
float: left;
|
||||||
width: auto;
|
width: auto;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
background-color: skyblue;
|
background-color: skyblue;
|
||||||
border-bottom-color: skyblue;
|
border-bottom-color: skyblue;
|
||||||
/*为了给after伪元素自动继承*/
|
/*为了给after伪元素自动继承*/
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
padding: 5px 12px 5px 12px;
|
padding: 5px 12px 5px 12px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
position: relative;
|
position: relative;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.from-message::after {
|
.from-message::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
right: -5px;
|
right: -5px;
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
margin-top: -5px;
|
margin-top: -5px;
|
||||||
background: inherit;
|
background: inherit;
|
||||||
/*自动继承父元素的背景*/
|
/*自动继承父元素的背景*/
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 通过对小正方形旋转45度解决 **/
|
/** 通过对小正方形旋转45度解决 **/
|
||||||
.to-message::before {
|
.to-message::before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: -5px;
|
left: -5px;
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
margin-top: -5px;
|
margin-top: -5px;
|
||||||
background: inherit;
|
background: inherit;
|
||||||
/*自动继承父元素的背景*/
|
/*自动继承父元素的背景*/
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -138,7 +138,8 @@ export default {
|
|||||||
headImgUrl: '',
|
headImgUrl: '',
|
||||||
cropImg: '',
|
cropImg: '',
|
||||||
isEdit: false,
|
isEdit: false,
|
||||||
autoCrop: true
|
autoCrop: true,
|
||||||
|
notificationFlag: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -282,6 +283,7 @@ export default {
|
|||||||
type: 'success',
|
type: 'success',
|
||||||
message: title + '成功!'
|
message: title + '成功!'
|
||||||
});
|
});
|
||||||
|
_ts.$set(_ts, 'notificationFlag', false);
|
||||||
_ts.$router.push({
|
_ts.$router.push({
|
||||||
path: '/portfolio/' + res.idPortfolio
|
path: '/portfolio/' + res.idPortfolio
|
||||||
})
|
})
|
||||||
@ -305,6 +307,7 @@ export default {
|
|||||||
if (res.message) {
|
if (res.message) {
|
||||||
_ts.$message(res.message);
|
_ts.$message(res.message);
|
||||||
} else {
|
} else {
|
||||||
|
_ts.$set(_ts, 'notificationFlag', false);
|
||||||
_ts.$router.push({
|
_ts.$router.push({
|
||||||
path: '/user/' + _ts.$store.state.userInfo?.nickname
|
path: '/user/' + _ts.$store.state.userInfo?.nickname
|
||||||
})
|
})
|
||||||
@ -339,15 +342,21 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeRouteLeave(to, from, next) {
|
beforeRouteLeave(to, from, next) {
|
||||||
this.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
let _ts = this;
|
||||||
confirmButtonText: '确定',
|
if (_ts.notificationFlag) {
|
||||||
cancelButtonText: '取消',
|
_ts.$confirm('系统可能不会保存您所做的更改。', '离开此网站?', {
|
||||||
type: 'warning'
|
confirmButtonText: '确定',
|
||||||
}).then(() => {
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
next();
|
||||||
|
}).catch(() => {
|
||||||
|
_ts.$store.commit("setActiveMenu", "portfolio-post");
|
||||||
|
return false
|
||||||
|
});
|
||||||
|
} else {
|
||||||
next();
|
next();
|
||||||
}).catch(() => {
|
}
|
||||||
return false
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
window.onbeforeunload = null;
|
window.onbeforeunload = null;
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
<div v-if="oauth.idUser !== user.idUser">
|
<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-if="isFollow" @click="cancelFollowUser(user.idUser)" plain>取消关注</el-button>
|
||||||
<el-button type="primary" v-else @click="followUser(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>
|
</div>
|
||||||
<div v-else>
|
<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 { 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
|
||||||
|
|
||||||
@ -10,8 +8,6 @@ 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)
|
||||||
@ -28,21 +24,5 @@ if (config.dev) {
|
|||||||
function listen () {
|
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