From d5e38a8167b39df6c415cbae1c3d6e850952b7ad Mon Sep 17 00:00:00 2001 From: CrescentLeaf Date: Sat, 6 Sep 2025 01:51:57 +0800 Subject: [PATCH] feat: Client calling server API --- client/api/ApiCallbackMessage.ts | 1 + client/api/ApiDeclare.ts | 4 ++ client/api/Client.ts | 34 ++++++++--- client/ui/App.jsx | 100 +++++++++++-------------------- 4 files changed, 68 insertions(+), 71 deletions(-) diff --git a/client/api/ApiCallbackMessage.ts b/client/api/ApiCallbackMessage.ts index 185651b..e94b2df 100644 --- a/client/api/ApiCallbackMessage.ts +++ b/client/api/ApiCallbackMessage.ts @@ -10,5 +10,6 @@ type ApiCallbackMessage = { * 501: 伺服器端不支持請求的功能 */ code: 200 | 400 | 401 | 403 | 404 | 500 | 501, + data?: { [key: string]: unknown }, } export default ApiCallbackMessage diff --git a/client/api/ApiDeclare.ts b/client/api/ApiDeclare.ts index a907e67..fc84148 100644 --- a/client/api/ApiDeclare.ts +++ b/client/api/ApiDeclare.ts @@ -1,3 +1,7 @@ export type CallMethod = + "User.auth" | "User.register" | "User.login" + +export type ClientEvent = + "Client.onMessage" diff --git a/client/api/Client.ts b/client/api/Client.ts index 55a7d14..4c272bc 100644 --- a/client/api/Client.ts +++ b/client/api/Client.ts @@ -1,21 +1,41 @@ import { io, Socket } from 'https://unpkg.com/socket.io-client@4.8.1/dist/socket.io.esm.min.js' -import { CallMethod } from './ApiDeclare.ts' +import { CallMethod, ClientEvent } from './ApiDeclare.ts' import ApiCallbackMessage from './ApiCallbackMessage.ts' +type UnknownObject = { [key: string]: unknown } + class Client { - static socket: Socket + static socket?: Socket + static events: { [key: string]: (data: UnknownObject) => UnknownObject } = {} static connect() { - this.socket && this.socket.disconnect() + this.socket?.disconnect() + this.socket && delete this.socket this.socket = io() + this.socket!.on("The_White_Silk", (name: string, data: UnknownObject, callback: (ret: UnknownObject) => void) => { + try { + if (name == null || data == null) return + const re = this.events[name]?.(data) + re && callback(re) + } catch (e) { + console.error(e) + } + }) } - static call(method: CallMethod, args: {}, timeout: number = 5000) { + static invoke(method: CallMethod, args: UnknownObject = {}, timeout: number = 5000): Promise { + if (this.socket == null) throw new Error("客戶端未與伺服器端建立連接!") return new Promise((resolve, reject) => { - this.socket.timeout().emit("The_White_Silk", (err, res: ApiCallbackMessage) => { - if (err) return reject(err) - + this.socket!.timeout(timeout).emit("The_White_Silk", method, args, (err: string, res: ApiCallbackMessage) => { + if (err) return reject(err) + resolve(res) }) }) } + static on(eventName: ClientEvent, func: (data: UnknownObject) => UnknownObject) { + this.events[eventName] = func + } + static off(eventName: ClientEvent){ + delete this.events[eventName] + } } export default Client diff --git a/client/ui/App.jsx b/client/ui/App.jsx index 4d7ad1b..d75624b 100644 --- a/client/ui/App.jsx +++ b/client/ui/App.jsx @@ -1,12 +1,15 @@ -import Message from "./chat/Message.jsx" -import MessageContainer from "./chat/MessageContainer.jsx" +import Client from "../api/Client.ts"; +import data from "../Data.ts"; +import ChatFragment from "./chat/ChatFragment.jsx" +import LoginDialog from "./dialog/LoginDialog.jsx" import ContactsListItem from "./main/ContactsListItem.jsx" import RecentsListItem from "./main/RecentsListItem.jsx" +import snackbar from "./snackbar.js"; import useEventListener from './useEventListener.js' export default function App() { const [recentsList, setRecentsList] = React.useState([ - { + /* { userId: 0, avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png", nickName: "麻油衣酱", @@ -17,11 +20,11 @@ export default function App() { avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png", nickName: "Maya Fey", content: "我是绫里真宵, 是一名灵媒师~" - }, + }, */ ]) const [contactsMap, setContactsMap] = React.useState({ 所有: [ - { + /* { userId: 0, avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png", nickName: "麻油衣酱", @@ -30,7 +33,7 @@ export default function App() { userId: 0, avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png", nickName: "Maya Fey", - }, + }, */ ], }) const [navigationItemSelected, setNavigationItemSelected] = React.useState('Recents') @@ -40,6 +43,25 @@ export default function App() { setNavigationItemSelected(event.target.value) }) + const [ + loginDialogRef, + inputAccountRef, + inputPasswordRef, + registerButtonRef, + loginButtonRef + ] = [React.useRef(null), React.useRef(null), React.useRef(null), React.useRef(null), React.useRef(null)] + + React.useEffect(async () => { + Client.connect() + const re = await Client.invoke("User.auth", { + access_token: data.access_token, + }) + if (re.code == 401) + loginDialogRef.current.show() + else if (re.code != 200) + snackbar("驗證失敗: " + re.msg) + }) + return (
+ { // 移动端用 页面调试 // 換個地方弄 @@ -91,7 +119,7 @@ export default function App() { display: navigationItemSelected == "Contacts" ? null : 'none' }}> - { + { Object.keys(contactsMap).map((v) => {v} @@ -122,63 +150,7 @@ export default function App() { { // 聊天页面 } -
- - - Title - - -
-
- 加載更多 -
- - - Test - - - { - // 输入框 - } -
- - - -
-
-
+
) } \ No newline at end of file