chat
This commit is contained in:
parent
2906012920
commit
e3db4d2f29
45
assets/js/socket.js
Normal file
45
assets/js/socket.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
const that = {
|
||||||
|
controller: new Map(),
|
||||||
|
connection: null,
|
||||||
|
onclose: null,
|
||||||
|
onerror: null,
|
||||||
|
onopen: null,
|
||||||
|
onmessage: null,
|
||||||
|
delay: 0,
|
||||||
|
init: (link) => {
|
||||||
|
that.connection = new WebSocket(link)
|
||||||
|
that.connection.onopen = (event) => {
|
||||||
|
that.delay = 0
|
||||||
|
console.log("Open connection")
|
||||||
|
that.connection.send(JSON.stringify({ fm: "chat", data: `Link Start! ${that.delay}` }))
|
||||||
|
// 检查消息版本, 从最后时间向前查20条
|
||||||
|
// 当向上滚动时, 从本地最早时间向前查询20条
|
||||||
|
// 落日志与合并日志
|
||||||
|
if (that.onopen) that.onopen();
|
||||||
|
}
|
||||||
|
that.connection.onmessage = (event) => {
|
||||||
|
console.log("[message]", event.data)
|
||||||
|
let data = JSON.parse(event.data)
|
||||||
|
console.log(event.data, "xxxxxxxxxxxxxx")
|
||||||
|
let call = that.controller.get(data.fm)
|
||||||
|
if (call) call(data)
|
||||||
|
if (that.onmessage) that.onmessage();
|
||||||
|
}
|
||||||
|
that.connection.onclose = (event) => {
|
||||||
|
if (event.wasClean) {
|
||||||
|
console.log(`[close] code=${event.code} reason=${event.reason}`);
|
||||||
|
} else {
|
||||||
|
that.delay++
|
||||||
|
console.log(`[close] 连接中断${that.delay}第次, 尝试重连(延时${that.delay} s)`);
|
||||||
|
setTimeout(that.init(link), that.delay * 1000)
|
||||||
|
}
|
||||||
|
if (that.onclose) that.onclose()
|
||||||
|
};
|
||||||
|
that.connection.onerror = (error) => {
|
||||||
|
console.log(`[error] ${error.message}`);
|
||||||
|
if (that.onerror) that.onerror()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default that
|
@ -21,7 +21,11 @@ button
|
|||||||
color: #ffffff
|
color: #ffffff
|
||||||
border: none
|
border: none
|
||||||
border-radius: .25rem
|
border-radius: .25rem
|
||||||
|
cursor: pointer
|
||||||
|
padding-left: 1rem
|
||||||
|
padding-right: 1rem
|
||||||
|
min-height: 2rem
|
||||||
|
font-weight: 600
|
||||||
a
|
a
|
||||||
text-decoration: none
|
text-decoration: none
|
||||||
a:link //未访问的
|
a:link //未访问的
|
||||||
|
50
components/DialogueList.vue
Normal file
50
components/DialogueList.vue
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.dialogue-list
|
||||||
|
.post(v-for="item in data", :key="item._id")
|
||||||
|
.left
|
||||||
|
.avatar
|
||||||
|
.right
|
||||||
|
.name Last
|
||||||
|
.message {{ item.data }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: ["data"],
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
.dialogue-list
|
||||||
|
.post
|
||||||
|
display: flex
|
||||||
|
margin: 1rem 0
|
||||||
|
.left
|
||||||
|
justify-content: center
|
||||||
|
align-items: center
|
||||||
|
.avatar
|
||||||
|
width: 2rem
|
||||||
|
height: 2rem
|
||||||
|
background: #ccc
|
||||||
|
border-radius: 50%
|
||||||
|
margin: .5rem auto
|
||||||
|
.right
|
||||||
|
padding: 0 2rem
|
||||||
|
.name
|
||||||
|
color: #999
|
||||||
|
font-size: .8rem
|
||||||
|
.message
|
||||||
|
background: #ffffff
|
||||||
|
padding: 1rem
|
||||||
|
border-radius: 1rem
|
||||||
|
position: relative
|
||||||
|
|
||||||
|
&::before
|
||||||
|
content: ""
|
||||||
|
position: absolute
|
||||||
|
top: 10px
|
||||||
|
left: -1rem
|
||||||
|
border-top: 20px solid #ffffff
|
||||||
|
border-left: 1rem solid transparent
|
||||||
|
border-right: 1rem solid transparent
|
||||||
|
</style>
|
@ -1,32 +1,56 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.main
|
.main
|
||||||
header.header
|
header.header
|
||||||
nav.navbar.main-width
|
.circumscription
|
||||||
NuxtLink.navbar-logo(to="/") Kana
|
.logo Kana
|
||||||
NuxtLink.navbar-item(to="/") 主页
|
nav.navbar
|
||||||
.expnone
|
NuxtLink.navbar-item(to="/") 论坛
|
||||||
.navbar-user(v-if="account.online")
|
NuxtLink.navbar-item(to="/docs") 文档
|
||||||
NuxtLink.userinfo(to="/account")
|
NuxtLink.navbar-item(to="/chat") 聊天室
|
||||||
img.avatar(:src="account.avatar")
|
.online
|
||||||
span.name {{ account.name }}
|
.navbar-user(v-if="account.online")
|
||||||
.navbar-sign(v-else)
|
NuxtLink.userinfo(to="/account")
|
||||||
NuxtLink.button(to="/account/signin") Signin
|
img.avatar(:src="account.avatar")
|
||||||
NuxtLink.button(to="/account/create") Login
|
span.name {{ account.name }}
|
||||||
|
.navbar-sign(v-else)
|
||||||
|
NuxtLink.button(to="/account/signin") Signin
|
||||||
|
NuxtLink.button(to="/account/create") Login
|
||||||
|
.websocket(:class="{ on: websocket }")
|
||||||
Nuxt
|
Nuxt
|
||||||
footer.footer
|
footer.footer
|
||||||
b Kana
|
p
|
||||||
|
b Kana
|
||||||
|
.github
|
||||||
|
a(href="https://github.com/InvisibleFuture/kana")
|
||||||
|
span.fab.fa-github
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import "assets/sass/main.sass";
|
import "@/assets/sass/main.sass";
|
||||||
import "assets/sass/default.sass";
|
import "@/assets/sass/default.sass";
|
||||||
|
|
||||||
|
import socket from "@/assets/js/socket.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
data: () => ({
|
||||||
|
websocket: false,
|
||||||
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
account() {
|
account() {
|
||||||
return this.$store.state.account;
|
return this.$store.state.account;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
beforeMount() {
|
||||||
|
// 如果掉线调用变红, 如果上线调用变绿
|
||||||
|
socket.onclose = () => {
|
||||||
|
this.websocket = false;
|
||||||
|
};
|
||||||
|
socket.onopen = () => {
|
||||||
|
this.websocket = true;
|
||||||
|
};
|
||||||
|
let protocol = location.protocol === "https:" ? "wss:" : "ws:";
|
||||||
|
socket.init(`${protocol}//${location.host}/api/`);
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
console.log(
|
console.log(
|
||||||
"%c こめいじ さとり %c satori.love ",
|
"%c こめいじ さとり %c satori.love ",
|
||||||
@ -39,57 +63,51 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
.block
|
.websocket
|
||||||
padding-top: 10rem
|
background: red
|
||||||
padding-bottom: 10rem
|
border-radius: 50%
|
||||||
|
width: 1rem
|
||||||
|
height: 1rem
|
||||||
|
margin: .25rem .5rem
|
||||||
|
.websocket.on
|
||||||
|
background: green
|
||||||
|
|
||||||
@media (min-width: 480px)
|
.main
|
||||||
.main-width
|
>header.header>div
|
||||||
margin: 0 2rem
|
|
||||||
|
|
||||||
@media (min-width: 1280px)
|
|
||||||
.main-width
|
|
||||||
max-width: 1200px
|
|
||||||
margin: auto
|
|
||||||
|
|
||||||
header.header
|
|
||||||
//background-color: rgba(0, 0, 0, .8)
|
|
||||||
nav.navbar
|
|
||||||
display: flex
|
display: flex
|
||||||
align-items: center
|
align-items: flex-end
|
||||||
.navbar-logo
|
padding-top: .5rem
|
||||||
//color: #fff
|
>.logo
|
||||||
margin: 0 1rem
|
font-size: 2rem
|
||||||
font-size: 1.2rem
|
font-weight: 900
|
||||||
font-weight: 600
|
margin-right: 1.5rem
|
||||||
.navbar-item
|
>nav.navbar
|
||||||
//color: #eee
|
|
||||||
padding: 1rem
|
|
||||||
font-size: 1.2rem
|
|
||||||
font-weight: 600
|
|
||||||
.navbar-item:hover
|
|
||||||
//color: #fff
|
|
||||||
.expnone
|
|
||||||
flex: 1
|
flex: 1
|
||||||
.userinfo
|
|
||||||
//color: #ffffff
|
|
||||||
font-weight: 600
|
|
||||||
display: flex
|
display: flex
|
||||||
align-items: center
|
align-items: center
|
||||||
.avatar
|
//justify-content: center
|
||||||
width: 24px
|
.navbar-item
|
||||||
height: 24px
|
margin: 0 .25rem
|
||||||
border-radius: 50%
|
padding: 0 .75rem
|
||||||
margin-right: .5rem
|
height: 2rem
|
||||||
|
line-height: 2rem
|
||||||
|
text-align: center
|
||||||
|
font-weight: 600
|
||||||
|
>.online
|
||||||
|
.navbar-user
|
||||||
|
.userinfo
|
||||||
|
font-weight: 600
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
.avatar
|
||||||
|
width: 24px
|
||||||
|
height: 24px
|
||||||
|
border-radius: 50%
|
||||||
|
margin-right: .5rem
|
||||||
|
|
||||||
footer.footer
|
footer.footer
|
||||||
text-align: center
|
text-align: center
|
||||||
margin: 4rem
|
padding: 4rem
|
||||||
|
.github
|
||||||
a.button
|
font-size: 2rem
|
||||||
border: none
|
|
||||||
border-radius: .25rem
|
|
||||||
padding: .5rem 1rem
|
|
||||||
margin: 1rem .5rem
|
|
||||||
background-color: #007bff
|
|
||||||
color: #ffffff
|
|
||||||
</style>
|
</style>
|
||||||
|
64
pages/chat/index.vue
Normal file
64
pages/chat/index.vue
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.chat-index
|
||||||
|
.circumscription
|
||||||
|
p Chat 频道列表 {{ chatlist.length }}
|
||||||
|
ul(v-if="chatlist.length")
|
||||||
|
li(v-for="item in chatlist", :key="item._id")
|
||||||
|
p {{ item.name }}
|
||||||
|
button(@click="create") 创建频道
|
||||||
|
.ceremony
|
||||||
|
.circumscription
|
||||||
|
span chat
|
||||||
|
DialogueList(:data="chatactive")
|
||||||
|
textarea.dialogue(v-model="chat.data", rows="12")
|
||||||
|
button.submit(@click="submit") 发表
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import socket from "@/assets/js/socket.js";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
asyncData({ $axios }) {
|
||||||
|
return $axios("/api/chat").then((res) => {
|
||||||
|
return {
|
||||||
|
chatlist: res.data,
|
||||||
|
chat: { data: "" },
|
||||||
|
chatactive: [{ _id: "2333", data: "cacd" }],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
socket.controller.set("chat", (data) => {
|
||||||
|
this.chatactive.push(data);
|
||||||
|
console.log(data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
create() {
|
||||||
|
let data = { name: "FM DEMO", data: "23333" };
|
||||||
|
this.$axios.post("/api/chat", data).then((res) => {
|
||||||
|
console.log(res.data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
submit() {
|
||||||
|
socket.connection.send(
|
||||||
|
JSON.stringify({
|
||||||
|
fm: "chat",
|
||||||
|
data: this.chat.data,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.chat.data = "";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass">
|
||||||
|
.chat-index
|
||||||
|
textarea.dialogue
|
||||||
|
width: 100%
|
||||||
|
padding: 1rem
|
||||||
|
border: 1px solid #eee
|
||||||
|
border-radius: .5rem
|
||||||
|
box-sizing: border-box
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user