This commit is contained in:
2022-05-04 11:13:09 +08:00
parent 3d331ee10d
commit 0b76b5935d
68 changed files with 38788 additions and 1 deletions

23
frontend/src/App.vue Normal file
View File

@@ -0,0 +1,23 @@
<script lang="ts">
import { defineComponent } from "vue";
import Chatroom from "./Chatroom.vue";
export default defineComponent({
name: "app",
components: {
Chatroom,
},
});
</script>
<template>
<Chatroom title="Client #1" />
<Chatroom title="Client #2" />
</template>
<style>
#app {
display: flex;
justify-content: center;
}
</style>

236
frontend/src/Chatroom.vue Normal file
View File

@@ -0,0 +1,236 @@
<template>
<div class="Chatroom">
<header>{{ title }}</header>
<ul class="list" ref="ul">
<li v-for="(v, i) in list" :key="i">
<div class="content">{{ v.content }}</div>
<div class="time">{{ v.time.toLocaleTimeString() }}</div>
</li>
</ul>
<div> <button @click="connect">Connect</button><button @click="start">Start</button> </div>
<div class="send">
<input placeholder="Say something..." v-model="input" @keypress.enter="send" />
<button @click="send">Send</button>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, nextTick } from "vue";
import { getClient } from "./getClient";
import { Msgstart } from "./shared/protocols/lobby/Msgstart";
import { MsgChat } from "./shared/protocols/MsgChat";
export default defineComponent({
name: "Chatroom",
props: {
title: String,
},
data() {
return {
input: "",
list: [] as MsgChat[],
client: getClient(),
};
},
mounted(): void {
// Listen Msg
this.client.listenMsg("Chat", (v: MsgChat) => {
console.log("Chat")
this.list.push(v);
// Scroll the list to the bottom
nextTick(() => {
const ul = this.$refs.ul as HTMLElement;
ul.scrollTo(0, ul.scrollHeight);
});
});
// Listen Msg
this.client.listenMsg("lobby/B_start", (v: Msgstart) => {
console.log("lobby/B_start")
let listdata: MsgChat = {
time: v.time,
content: v.data.content,
};
this.list.push(listdata);
// Scroll the list to the bottom
nextTick(() => {
const ul = this.$refs.ul as HTMLElement;
ul.scrollTo(0, ul.scrollHeight);
});
});
// When disconnected
this.client.flows.postDisconnectFlow.push((v) => {
// alert("Server disconnected");
let listdata: MsgChat = {
time: new Date(),
content: "Server disconnected",
};
this.list.push(listdata);
return v;
});
},
methods: {
async connect(): Promise<void> {
// this.client = getClient();
// let listdata: MsgChat = {
// time: new Date(),
// content: `connect`,
// };
// this.list.push(listdata);
this.client.connect().then((v) => {
if (!v.isSucc) {
// alert("= Client Connect Error =\n" + v.errMsg);
let listdata: MsgChat = {
time: new Date(),
content: "= Client Connect Error =\n" + v.errMsg,
};
this.list.push(listdata);
} else {
// alert("= Client Connect Error =\n" + v.errMsg);
let listdata: MsgChat = {
time: new Date(),
content: "Server Connect",
};
this.list.push(listdata);
}
});
},
async start(): Promise<void> {
let ret = await this.client.callApi("lobby/start", {});
// Error
if (!ret.isSucc) {
// alert(ret.err.message);
let listdata: MsgChat = {
time: new Date(),
content: ret.err.message,
};
this.list.push(listdata);
return;
}
// Success
this.input = "";
},
// Send input message
async send(): Promise<void> {
let ret = await this.client.callApi("Send", {
content: this.input,
});
// Error
if (!ret.isSucc) {
// alert(ret.err.message);
let listdata: MsgChat = {
time: new Date(),
content: ret.err.message,
};
this.list.push(listdata);
return;
}
// Success
this.input = "";
},
},
});
</script>
<style scoped lang="less">
// .div .Chatroom {
// display: inline-block;
// }
.Chatroom {
// display: inline-block;
display: flex;
flex-direction: column;
width: 460px;
height: 480px;
margin: 20px;
background: #f7f7f7;
border: 1px solid #454545;
border-radius: 5px;
overflow: hidden;
>header {
background: #454545;
color: white;
text-align: center;
padding: 10px;
}
>.send {
flex: 0 0 40px;
display: flex;
border-top: 1px solid #454545;
>* {
border: none;
outline: none;
height: 100%;
font-size: 16px;
}
>input {
flex: 1;
background: #fff;
padding: 0 10px;
}
>button {
flex: 0 0 100px;
background: #215fa4;
color: white;
cursor: pointer;
&:hover {
background: #4b80bb;
}
}
}
>.list {
flex: 1;
overflow-y: auto;
list-style: none;
border-radius: 5px;
padding: 10px;
padding-bottom: 20px;
background: #f2f2f2;
>li {
margin-bottom: 10px;
padding: 10px;
background: #fff;
line-height: 1.5em;
border-radius: 5px;
>.content {
font-size: 14px;
text-align: left;
white-space: pre-wrap;
word-wrap: break-word;
}
>.time {
font-size: 12px;
color: #4b80bb;
text-align: right;
}
&:last-child {
border-bottom: none;
margin-bottom: 0;
}
}
}
}
</style>

View File

@@ -0,0 +1,100 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body>h1 {
text-align: center;
margin-top: 20px;
}
.app {
display: flex;
justify-content: center;
}
.Chatroom {
display: flex;
flex-direction: column;
width: 460px;
height: 480px;
margin: 20px;
background: #f7f7f7;
border: 1px solid #454545;
border-radius: 5px;
overflow: hidden;
}
.chat-room>header {
background: #454545;
color: white;
text-align: center;
padding: 10px;
}
.send {
flex: 0 0 40px;
display: flex;
border-top: 1px solid #454545;
}
.send>* {
border: none;
outline: none;
height: 100%;
font-size: 16px;
}
.send>input {
flex: 1;
background: #fff;
padding: 0 10px;
}
.send>button {
flex: 0 0 100px;
background: #215fa4;
color: white;
cursor: pointer;
}
.send>button:hover {
background: #4b80bb;
}
.list {
flex: 1;
overflow-y: auto;
list-style: none;
border-radius: 5px;
padding: 10px;
padding-bottom: 20px;
background: #f2f2f2;
}
.list>li {
margin-bottom: 10px;
padding: 10px;
background: #fff;
line-height: 1.5em;
border-radius: 5px;
}
.list>li>.content {
font-size: 14px;
text-align: left;
white-space: pre-wrap;
word-wrap: break-word;
}
.list>li>.time {
font-size: 12px;
color: #4b80bb;
text-align: right;
}
.list>li:last-child {
border-bottom: none;
margin-bottom: 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,52 @@
<script setup lang="ts">
import { ref } from 'vue'
defineProps<{ msg: string }>()
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<p>
Recommended IDE setup:
<a href="https://code.visualstudio.com/" target="_blank">VS Code</a>
+
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
</p>
<p>See <code>README.md</code> for more information.</p>
<p>
<a href="https://vitejs.dev/guide/features.html" target="_blank">
Vite Docs
</a>
|
<a href="https://v3.vuejs.org/" target="_blank">Vue 3 Docs</a>
</p>
<button type="button" @click="count++">count is: {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test hot module replacement.
</p>
</template>
<style scoped>
a {
color: #42b983;
}
label {
margin: 0 0.5em;
font-weight: bold;
}
code {
background-color: #eee;
padding: 2px 4px;
border-radius: 4px;
color: #304455;
}
</style>

16
frontend/src/env.d.ts vendored Normal file
View File

@@ -0,0 +1,16 @@
/* eslint-disable */
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
// TSRPC would decode ObjectId as string in frontend.
declare module 'mongodb' {
export type ObjectId = string;
export type ObjectID = string;
}
declare module 'bson' {
export type ObjectId = string;
export type ObjectID = string;
}

11
frontend/src/getClient.ts Normal file
View File

@@ -0,0 +1,11 @@
import { WsClient } from "tsrpc-browser";
import { serviceProto, ServiceType } from "./shared/protocols/serviceProto";
export function getClient(): WsClient<ServiceType> {
return new WsClient(serviceProto, {
server: "ws://127.0.0.1:4000",
// Remove this to use binary mode (remove from the server too)
json: true,
logger: console,
})
}

4
frontend/src/main.ts Normal file
View File

@@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

1
frontend/src/shared Symbolic link
View File

@@ -0,0 +1 @@
D:/Project/Test/Test_NodeJS/TSRPC_Badminton-Scoreboard/backend/src/shared