websocket消息支持 (#188)
* Release (#162) * feat: ✨ websocket server demo * feat: ✨ ws server demo dev * feat: ✨ ws server and mobile page * feat: ✨ 手机端发送消息 * feat: ✨ 手机网页发送消息 * 添加了抽奖中和抽奖完成时的音效 * feat: ✨ 自定义设置弹幕服务器地址 * feat: ✨ ws not done * fix: 🐛 fix pr-185 #185 为播放音效添加控制 * feat: ✨ server worker demo not done * feat: ✨ websocket server * feat: ✨ 全局接收websocket消息并存储到indexdb中 --------- Co-authored-by: Silence@2024 <707261624@qq.com>
This commit is contained in:
32
src/views/Config/Server/index.vue
Normal file
32
src/views/Config/Server/index.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<script setup lang='ts'>
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import PageHeader from '@/components/PageHeader/index.vue'
|
||||
import MsgListContainer from './parts/MsgListContainer.vue'
|
||||
import ServerSetting from './parts/ServerSetting.vue'
|
||||
import { useViewModel } from './useViewModel'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { serverList, currentServerValue, wsStatus, handleConnectWs, closeWs, msgList } = useViewModel()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<PageHeader :title="t('sidebar.server')" />
|
||||
<div>
|
||||
<ServerSetting
|
||||
v-model:current-server="currentServerValue"
|
||||
:server-list="serverList"
|
||||
:ws-status="wsStatus"
|
||||
:open-ws="handleConnectWs"
|
||||
:close-ws="closeWs"
|
||||
/>
|
||||
<MsgListContainer
|
||||
:msg-list="msgList"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
29
src/views/Config/Server/parts/MsgListContainer.vue
Normal file
29
src/views/Config/Server/parts/MsgListContainer.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script setup lang='ts'>
|
||||
import type { WsMsgData } from '@/types/storeType'
|
||||
|
||||
interface Props {
|
||||
msgList: WsMsgData[]
|
||||
}
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-1/2 h-1/2 border rounded-md shadow-lg">
|
||||
<ul>
|
||||
<li v-for="item in msgList" :key="item.id" class="mb-3">
|
||||
<div class="chat chat-end">
|
||||
<div class="chat-header">
|
||||
<time class="text-xs opacity-50">{{ item.dateTime }}</time>
|
||||
</div>
|
||||
<div class="chat-bubble break-all whitespace-normal">
|
||||
{{ item.data }}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
107
src/views/Config/Server/parts/ServerSetting.vue
Normal file
107
src/views/Config/Server/parts/ServerSetting.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<script setup lang='ts'>
|
||||
import type { ServerType } from '@/types/storeType'
|
||||
import { ref, watch } from 'vue'
|
||||
// import { useI18n } from 'vue-i18n'
|
||||
|
||||
interface Props {
|
||||
serverList: ServerType[]
|
||||
wsStatus: { status: WebSocket['readyState'], connected: boolean } | undefined
|
||||
openWs: () => void
|
||||
closeWs: () => void
|
||||
}
|
||||
defineProps<Props>()
|
||||
|
||||
const currentServer = defineModel<ServerType>('currentServer', { required: true })
|
||||
const hostValue = ref('')
|
||||
// const { t } = useI18n()
|
||||
// 监听 currentServer 的 id 变化,重置 hostValue
|
||||
watch(() => currentServer.value?.id, (newId, oldId) => {
|
||||
if (newId !== oldId) {
|
||||
hostValue.value = currentServer.value?.host || ''
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
// 监听 hostValue 变化,同步更新 currentServer.host
|
||||
watch(hostValue, (newHost) => {
|
||||
if (currentServer.value) {
|
||||
currentServer.value.host = newHost
|
||||
}
|
||||
})
|
||||
|
||||
// 初始化 hostValue
|
||||
hostValue.value = currentServer.value?.host || ''
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<fieldset class="p-4 border text-setting fieldset bg-base-200 border-base-300 rounded-box w-xs pb-10">
|
||||
<legend class="fieldset-legend">
|
||||
弹幕服务
|
||||
</legend>
|
||||
|
||||
<label class="flex flex-row items-center form-control">
|
||||
<div class="">
|
||||
<div class="label flex flex-col justify-start items-start">
|
||||
<label class="label">
|
||||
<span class="label-text text-left">弹幕服务地址</span>
|
||||
<div class="tooltip" data-tip="改变弹幕服务地址后会断开连接">
|
||||
<button class="btn btn-circle h-4 hover:bg-base-300">
|
||||
?
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
<div class="radio-group flex gap-9">
|
||||
<ul class="flex gap-3">
|
||||
<li v-for="item in serverList" :key="item.id" class="flex flex-col">
|
||||
<label for="default-server">{{ item.name }}</label>
|
||||
<input id="default-server" type="radio" name="radio-1" class="radio" :checked="currentServer?.value === item.value" @change="currentServer = item">
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="请输入服务地址"
|
||||
:disabled="currentServer.value === 'default'"
|
||||
class="w-full max-w-xs input input-bordered"
|
||||
:value="hostValue"
|
||||
@input="hostValue = ($event.target as HTMLInputElement).value"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<label class="flex flex-row items-center form-control">
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="label">
|
||||
<span class="label-text">弹幕服务器连接状态</span>
|
||||
</div>
|
||||
<div class="flex gap-2 items-center">
|
||||
<div class="ws-status">
|
||||
<div v-if="wsStatus && wsStatus.connected">
|
||||
<div aria-label="success" class="status status-success" />
|
||||
<span>已连接</span>
|
||||
</div>
|
||||
<div v-else-if="wsStatus && wsStatus.connected === false">
|
||||
<div aria-label="error" class="status status-error" />
|
||||
<span>已断开</span>
|
||||
</div>
|
||||
<div v-else-if="wsStatus && wsStatus.status">
|
||||
<div aria-label="error" class="status status-error" />
|
||||
<span>操作中</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div aria-label="warning" class="status status-warning" />
|
||||
<span>未连接</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<button v-if="wsStatus?.connected === true" class="btn btn-error btn-sm" @click="closeWs">断开</button>
|
||||
<button v-else class="btn btn-primary btn-sm" @click="openWs">连接</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</fieldset>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
55
src/views/Config/Server/useViewModel.ts
Normal file
55
src/views/Config/Server/useViewModel.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import type { ServerType, WsMsgData } from '@/types/storeType'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { useWebsocket } from '@/hooks/useWebsocket'
|
||||
import useStore from '@/store'
|
||||
import { getUniqueSignature } from '@/utils/auth'
|
||||
import { IndexDb } from '@/utils/dexie'
|
||||
|
||||
export function useViewModel() {
|
||||
const serverConfig = useStore().serverConfig
|
||||
const { getServerList: serverList, getCurrentServer: currentServer } = storeToRefs(serverConfig)
|
||||
const currentServerValue = ref<ServerType>(cloneDeep(currentServer.value))
|
||||
const wsUrl = ref<string>('ws://localhost:8080/echo')
|
||||
const msgList = ref<WsMsgData[]>([])
|
||||
const { open: openWs, close: closeWs, status: wsStatus } = useWebsocket()
|
||||
const msgListDb = new IndexDb('msgList', ['msgList'], 1, ['createTime'])
|
||||
const handleConnectWs = async () => {
|
||||
const userSignature = await getUniqueSignature()
|
||||
wsUrl.value = `ws://localhost:8080/echo?userSignature=${userSignature}`
|
||||
openWs(wsUrl.value)
|
||||
}
|
||||
const getAllMsg = async () => {
|
||||
msgListDb.getDataSortedByDateTime('msgList', 'dateTime').then((data) => {
|
||||
msgList.value = data
|
||||
})
|
||||
}
|
||||
|
||||
watch(
|
||||
() => currentServerValue.value.id,
|
||||
(newValue) => {
|
||||
serverList.value.forEach((item) => {
|
||||
if (item.id === newValue) {
|
||||
currentServerValue.value = item
|
||||
serverConfig.setCurrentServer(currentServerValue.value)
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
watch(() => currentServer.value.host, (newValue) => {
|
||||
currentServerValue.value.host = newValue
|
||||
serverConfig.updateServerList(currentServerValue.value)
|
||||
})
|
||||
onMounted(() => {
|
||||
getAllMsg()
|
||||
})
|
||||
return {
|
||||
serverList,
|
||||
currentServerValue,
|
||||
wsStatus,
|
||||
handleConnectWs,
|
||||
closeWs,
|
||||
msgList,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user