From b879ad4f7c1790ab264b2a617d36ea3826e4d889 Mon Sep 17 00:00:00 2001 From: yourname Date: Thu, 15 May 2025 07:29:09 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0socketio=20server=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HISTORY.md | 1 + deno.json | 3 +- deno.lock | 68 +++++++++++++++++++++++++++++++++++++++ server/routes_socketio.ts | 15 +++++++++ server/run_app.ts | 62 +++++++++++++++++++++-------------- 5 files changed, 124 insertions(+), 25 deletions(-) create mode 100644 server/routes_socketio.ts diff --git a/HISTORY.md b/HISTORY.md index 910a0b5..6b5f64f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,6 +3,7 @@ 迁移管理页面,在正式环境中,需要验证env中配置的密码参数才能打开 2025.05.15 0.1.6 +增加socketio server 支持 修正文件分类后端api路由查询表名为file_categories 将react版本降为18.3.1 diff --git a/deno.json b/deno.json index 0241c83..1bed6f7 100644 --- a/deno.json +++ b/deno.json @@ -28,7 +28,8 @@ "@ant-design/plots": "https://esm.d8d.fun/@ant-design/plots@2.1.13?dev&deps=react@18.3.1,react-dom@18.3.1", "react-hook-form": "https://esm.d8d.fun/react-hook-form@7.55.0?dev&deps=react@18.3.1,react-dom@18.3.1", "@heroicons/react/24/outline": "https://esm.d8d.fun/@heroicons/react@2.1.1/24/outline?dev&deps=react@18.3.1,react-dom@18.3.1", - "@heroicons/react/24/solid": "https://esm.d8d.fun/@heroicons/react@2.1.1/24/solid?dev&deps=react@18.3.1,react-dom@18.3.1" + "@heroicons/react/24/solid": "https://esm.d8d.fun/@heroicons/react@2.1.1/24/solid?dev&deps=react@18.3.1,react-dom@18.3.1", + "socket.io": "https://deno.land/x/socket_io@0.2.1/mod.ts" }, "compilerOptions": { "lib": ["dom", "dom.iterable", "esnext", "deno.ns"] diff --git a/deno.lock b/deno.lock index 4551dc2..93f2aeb 100644 --- a/deno.lock +++ b/deno.lock @@ -2575,9 +2575,32 @@ "https://esm.d8d.fun/xmlhttprequest-ssl@~2.1.1?target=denonext": "https://esm.d8d.fun/xmlhttprequest-ssl@2.1.2?target=denonext" }, "remote": { + "https://deno.land/std@0.150.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74", + "https://deno.land/std@0.150.0/bytes/bytes_list.ts": "aba5e2369e77d426b10af1de0dcc4531acecec27f9b9056f4f7bfbf8ac147ab4", + "https://deno.land/std@0.150.0/bytes/equals.ts": "3c3558c3ae85526f84510aa2b48ab2ad7bdd899e2e0f5b7a8ffc85acb3a6043a", + "https://deno.land/std@0.150.0/bytes/mod.ts": "763f97d33051cc3f28af1a688dfe2830841192a9fea0cbaa55f927b49d49d0bf", + "https://deno.land/std@0.150.0/fmt/colors.ts": "6f9340b7fb8cc25a993a99e5efc56fe81bb5af284ff412129dd06df06f53c0b4", + "https://deno.land/std@0.150.0/fs/exists.ts": "cb734d872f8554ea40b8bff77ad33d4143c1187eac621a55bf37781a43c56f6d", + "https://deno.land/std@0.150.0/io/buffer.ts": "bd0c4bf53db4b4be916ca5963e454bddfd3fcd45039041ea161dbf826817822b", + "https://deno.land/std@0.150.0/log/handlers.ts": "b88c24df61eaeee8581dbef3622f21aebfd061cd2fda49affc1711c0e54d57da", + "https://deno.land/std@0.150.0/log/levels.ts": "82c965b90f763b5313e7595d4ba78d5095a13646d18430ebaf547526131604d1", + "https://deno.land/std@0.150.0/log/logger.ts": "4d25581bc02dfbe3ad7e8bb480e1f221793a85be5e056185a0cea134f7a7fdf4", + "https://deno.land/std@0.150.0/log/mod.ts": "65d2702785714b8d41061426b5c279f11b3dcbc716f3eb5384372a430af63961", "https://deno.land/std@0.150.0/media_types/_util.ts": "ce9b4fc4ba1c447dafab619055e20fd88236ca6bdd7834a21f98bd193c3fbfa1", "https://deno.land/std@0.150.0/media_types/mod.ts": "2d4b6f32a087029272dc59e0a55ae3cc4d1b27b794ccf528e94b1925795b3118", "https://deno.land/std@0.150.0/media_types/vendor/mime-db.v1.52.0.ts": "724cee25fa40f1a52d3937d6b4fbbfdd7791ff55e1b7ac08d9319d5632c7f5af", + "https://deno.land/std@0.150.0/testing/_diff.ts": "029a00560b0d534bc0046f1bce4bd36b3b41ada3f2a3178c85686eb2ff5f1413", + "https://deno.land/std@0.150.0/testing/_format.ts": "0d8dc79eab15b67cdc532826213bbe05bccfd276ca473a50a3fc7bbfb7260642", + "https://deno.land/std@0.150.0/testing/_test_suite.ts": "ad453767aeb8c300878a6b7920e20370f4ce92a7b6c8e8a5d1ac2b7c14a09acb", + "https://deno.land/std@0.150.0/testing/asserts.ts": "0ee58a557ac764e762c62bb21f00e7d897e3919e71be38b2d574fb441d721005", + "https://deno.land/std@0.150.0/testing/bdd.ts": "182bb823e09bd75b76063ecf50722870101b7cfadf97a09fa29127279dc21128", + "https://deno.land/std@0.158.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74", + "https://deno.land/std@0.158.0/async/deferred.ts": "c01de44b9192359cebd3fe93273fcebf9e95110bf3360023917da9a2d1489fae", + "https://deno.land/std@0.158.0/async/delay.ts": "0419dfc993752849692d1f9647edf13407c7facc3509b099381be99ffbc9d699", + "https://deno.land/std@0.158.0/bytes/bytes_list.ts": "aba5e2369e77d426b10af1de0dcc4531acecec27f9b9056f4f7bfbf8ac147ab4", + "https://deno.land/std@0.158.0/bytes/equals.ts": "3c3558c3ae85526f84510aa2b48ab2ad7bdd899e2e0f5b7a8ffc85acb3a6043a", + "https://deno.land/std@0.158.0/bytes/mod.ts": "763f97d33051cc3f28af1a688dfe2830841192a9fea0cbaa55f927b49d49d0bf", + "https://deno.land/std@0.158.0/io/buffer.ts": "fae02290f52301c4e0188670e730cd902f9307fb732d79c4aa14ebdc82497289", "https://deno.land/std@0.217.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", "https://deno.land/std@0.217.0/assert/_diff.ts": "dcc63d94ca289aec80644030cf88ccbf7acaa6fbd7b0f22add93616b36593840", "https://deno.land/std@0.217.0/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", @@ -2654,6 +2677,51 @@ "https://deno.land/x/deno_dom@v0.1.48/src/dom/utils-types.ts": "96db30e3e4a75b194201bb9fa30988215da7f91b380fca6a5143e51ece2a8436", "https://deno.land/x/deno_dom@v0.1.48/src/dom/utils.ts": "4c6206516fb8f61f37a209c829e812c4f5a183e46d082934dd14c91bde939263", "https://deno.land/x/deno_dom@v0.1.48/src/parser.ts": "e06b2300d693e6ae7564e53dfa5c9a9e97fdb8c044c39c52c8b93b5d60860be3", + "https://deno.land/x/socket_io@0.2.1/deps.ts": "2c9c7fd0f00c9f8774a7cbf6bea2e73b274989aacb3ebfbd289a3c1bbe632bcb", + "https://deno.land/x/socket_io@0.2.1/mod.ts": "29050911ca6f9605623c672238bb209ca37ed23606c596d199e6e33de04168f9", + "https://deno.land/x/socket_io@0.2.1/packages/engine.io-parser/base64-arraybuffer.ts": "57ccea6679609df5416159fcc8a47936ad28ad6fe32235ef78d9223a3a823407", + "https://deno.land/x/socket_io@0.2.1/packages/engine.io-parser/mod.ts": "27d35094e2159ba49f6e74f11ed83b6208a6adb5a2d5ab3cbbdcdc9dc0e36ae7", + "https://deno.land/x/socket_io@0.2.1/packages/engine.io/lib/cors.ts": "e39b530dc3526ef85f288766ce592fa5cce2ec38b3fa19922041a7885b79b67c", + "https://deno.land/x/socket_io@0.2.1/packages/engine.io/lib/server.ts": "2faf79492858e532ad199c32b565bb04528fa9ea55d167e223dc9d019ef9315f", + "https://deno.land/x/socket_io@0.2.1/packages/engine.io/lib/socket.ts": "feb50d196decd7b1fc79af2706465cc7b4b8b18ebb7ca3dc8cedadb0a393103e", + "https://deno.land/x/socket_io@0.2.1/packages/engine.io/lib/transport.ts": "b09c589a099d539cd0b61f7b3be0b9d2d9ba7b8cbafdf4824425176ecf8d89c9", + "https://deno.land/x/socket_io@0.2.1/packages/engine.io/lib/transports/polling.ts": "5650189f6cd742ec0fd45f8c262105f07463b24e8183da6ffb2bf775baf21395", + "https://deno.land/x/socket_io@0.2.1/packages/engine.io/lib/transports/websocket.ts": "4a868e73d3b8b207d822d358f14723bd8d1cd80c6926be9c4bf6c4234e8a0d00", + "https://deno.land/x/socket_io@0.2.1/packages/engine.io/lib/util.ts": "9f396a141422c8a2e2ef4cbb31c8b7ec96665d8f1ca397888eaaa9ad28ca8c65", + "https://deno.land/x/socket_io@0.2.1/packages/engine.io/mod.ts": "3f7d85ebd3bee6e17838f4867927d808f35090a71e088fd4dd802e3255d44c4a", + "https://deno.land/x/socket_io@0.2.1/packages/event-emitter/mod.ts": "dcb2cb9c0b409060cf15a6306a8dbebea844aa3c58f782ed1d4bc3ccef7c2835", + "https://deno.land/x/socket_io@0.2.1/packages/msgpack/lib/decode.ts": "5906fa37474130b09fe308adb53c95e40d2484a015891be3249fb2f626c462bb", + "https://deno.land/x/socket_io@0.2.1/packages/msgpack/lib/encode.ts": "15dab78be56d539c03748c9d57086f7fd580eb8fbe2f8209c28750948c7d962e", + "https://deno.land/x/socket_io@0.2.1/packages/msgpack/mod.ts": "c7f4a9859af3e0b23794b400546d93475b19ba5110a02245112a0a994a31d309", + "https://deno.land/x/socket_io@0.2.1/packages/socket.io-parser/mod.ts": "44479cf563b0ad80efedd1059cd40114bc5db199b45e623c2764e80f4a264f8c", + "https://deno.land/x/socket_io@0.2.1/packages/socket.io-redis-adapter/mod.ts": "45d6b7f077f94fec385152bda7fda5ac3153c2ca3548cf4859891af673fa97cc", + "https://deno.land/x/socket_io@0.2.1/packages/socket.io/lib/adapter.ts": "594fbe748497ce346e8b783065cb19b284f27d702ff661d872971d14ccf6cf29", + "https://deno.land/x/socket_io@0.2.1/packages/socket.io/lib/broadcast-operator.ts": "d842eb933acc996a05ac701f6d83ffee49ee9c905c9adbdee70832776045bf63", + "https://deno.land/x/socket_io@0.2.1/packages/socket.io/lib/client.ts": "5e5d8e39d58cc5eb14f219e85ae6eef8fe6dd5f685f4c73496531aa48529c2c6", + "https://deno.land/x/socket_io@0.2.1/packages/socket.io/lib/namespace.ts": "d9ec734c8b45f4204c40382e1d3a8fb4d1b8bffab4bca4d2d69baece0703d4f8", + "https://deno.land/x/socket_io@0.2.1/packages/socket.io/lib/parent-namespace.ts": "9628cbf54e35bea01956825f557b4a82a37c8f1343423c0e7d952d475bf68ea0", + "https://deno.land/x/socket_io@0.2.1/packages/socket.io/lib/server.ts": "19b10d05e09e436fda0d8d205ba1ce06bb5877f516176b8148de8a3c26b37688", + "https://deno.land/x/socket_io@0.2.1/packages/socket.io/lib/socket.ts": "c448032d0f819d40d6dc30eb312c391c5d902eeeeb67bfd4f4f4c3499545eb7e", + "https://deno.land/x/socket_io@0.2.1/packages/socket.io/mod.ts": "dfd465bdcf23161af0c4d79fb8fc8912418c46a20d15e8b314cec6d9fb508196", + "https://deno.land/x/socket_io@0.2.1/test_deps.ts": "42e6bff240c54a2d7ade82154f8655650664a65ad9228623a0fdb3d0cde11ef0", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/backoff.ts": "33e4a6e245f8743fbae0ce583993a671a3ac2ecee433a3e7f0bd77b5dd541d84", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/command.ts": "802df3a1f49f6c49fe3e8fcf13fd0cc360b8a02369de0310a72d7f0c8e4ceaab", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/connection.ts": "b325d5b720af8132cd81d6d8b6a2e61936631b36d0dd08907d5421107bf50723", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/errors.ts": "bc8f7091cb9f36cdd31229660e0139350b02c26851e3ac69d592c066745feb27", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/executor.ts": "03e5f43df4e0c9c62b0e1be778811d45b6a1966ddf406e21ed5a227af70b7183", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/mod.ts": "20908f005f5c102525ce6aa9261648c95c5f61c6cf782b2cbb2fce88b1220f69", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/pipeline.ts": "80cc26a881149264d51dd019f1044c4ec9012399eca9f516057dc81c9b439370", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/protocol/_util.ts": "0525f7f444a96b92cd36423abdfe221f8d8de4a018dc5cb6750a428a5fc897c2", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/protocol/command.ts": "b1efd3b62fe5d1230e6d96b5c65ba7de1592a1eda2cc927161e5997a15f404ac", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/protocol/mod.ts": "f2601df31d8adc71785b5d19f6a7e43dfce94adbb6735c4dafc1fb129169d11a", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/protocol/reply.ts": "beac2061b03190bada179aef1a5d92b47a5104d9835e8c7468a55c24812ae9e4", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/protocol/types.ts": "40b0a568cb7fd4dc9107997062584d24e5c6ffa1f21acb6410aa19c92f89e9e1", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/pubsub.ts": "324b87dae0700e4cb350780ce3ae5bc02780f79f3de35e01366b894668b016c6", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/redis.ts": "a5c2cf8c72e7c92c9c8c6911f98227062649f6cba966938428c5414200f3aa54", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/stream.ts": "f116d73cfe04590ff9fa8a3c08be8ff85219d902ef2f6929b8c1e88d92a07810", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/vendor/https/deno.land/std/async/deferred.ts": "7391210927917113e04247ef013d800d54831f550e9a0b439244675c56058c55", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/vendor/https/deno.land/std/async/delay.ts": "c7e2604f7cb5ef00d595de8dd600604902d5be03a183b515b3d6d4bbb48e1700", + "https://deno.land/x/socket_io@0.2.1/vendor/deno.land/x/redis@v0.27.1/vendor/https/deno.land/std/io/buffer.ts": "8c5f84b7ecf71bc3e12aa299a9fae9e72e495db05281fcdd62006ecd3c5ed3f3", "https://deno.land/x/xhr@0.3.0/mod.ts": "094aacd627fd9635cd942053bf8032b5223b909858fa9dc8ffa583752ff63b20", "https://esm.d8d.fun/@ant-design/charts-util@0.0.1-alpha.5/X-ZHJlYWN0LWRvbUAxOS4wLjAscmVhY3RAMTkuMC4w/denonext/charts-util.development.mjs": "92a5ac00883b6b3b33b5498616d35fdd262d6ecbca85914aaaa1612d501c33a4", "https://esm.d8d.fun/@ant-design/charts-util@0.0.1-alpha.5/X-ZHJlYWN0LWRvbUAxOS4wLjAscmVhY3RAMTkuMC4w/denonext/charts-util.mjs": "2b5590c1c3b095fd2cc95448c174aa747dd187929dd0f0ecf79a19a95e2f48ba", diff --git a/server/routes_socketio.ts b/server/routes_socketio.ts new file mode 100644 index 0000000..6f5bd57 --- /dev/null +++ b/server/routes_socketio.ts @@ -0,0 +1,15 @@ +import { Socket, Server } from "socket.io"; + +export function setupSocketIO(io: Server) { + io.on("connection", (socket: Socket) => { + console.log(`socket ${socket.id} connected`); + + socket.emit("hello", "world"); + + socket.on("disconnect", (reason) => { + console.log(`socket ${socket.id} disconnected due to ${reason}`); + }); + + // 可在此添加更多socket事件处理 + }); +} \ No newline at end of file diff --git a/server/run_app.ts b/server/run_app.ts index 4683712..20e0f76 100644 --- a/server/run_app.ts +++ b/server/run_app.ts @@ -3,6 +3,9 @@ import { Hono } from 'hono' import { APIClient } from '@d8d-appcontainer/api' import debug from "debug" import { cors } from 'hono/cors' +import { Server } from "socket.io" +import httpServer from './app.tsx' +import { setupSocketIO } from './routes_socketio.ts' // 初始化debug实例 const log = { @@ -37,41 +40,52 @@ const getApiClient = async (workspaceKey: string, serverUrl?: string) => { } } +// 初始化API Client +// 注意:WORKSPACE_KEY 需要在 多八多(www.d8d.fun) 平台注册并开通工作空间后获取 +const workspaceKey = Deno.env.get('WORKSPACE_KEY') || '' +if (!workspaceKey) { + console.warn('未设置WORKSPACE_KEY,请前往 多八多(www.d8d.fun) 注册并开通工作空间以获取密钥') +} +const apiClient = await getApiClient(workspaceKey) + // 创建Hono应用实例 const app = new Hono() // 注册CORS中间件 app.use('/*', cors()) +// 创建Socket.IO实例 +const io = new Server({ + cors: { + origin: "*", + methods: ["GET", "POST"], + credentials: true + } +}) + +setupSocketIO(io); + // 动态加载并运行模板 const runTemplate = async () => { try { // 创建基础app实例 const moduleApp = new Hono() - - // 初始化API Client - // 注意:WORKSPACE_KEY 需要在 多八多(www.d8d.fun) 平台注册并开通工作空间后获取 - const workspaceKey = Deno.env.get('WORKSPACE_KEY') || '' - if (!workspaceKey) { - console.warn('未设置WORKSPACE_KEY,请前往 多八多(www.d8d.fun) 注册并开通工作空间以获取密钥') - } - const apiClient = await getApiClient(workspaceKey) - - // 导入模板主模块 - const templateModule = await import('./app.tsx') - - if (templateModule.default) { - // 传入必要参数并初始化应用 - const appInstance = templateModule.default({ - apiClient: apiClient, - app: moduleApp, - moduleDir: './' - }) - - // 启动服务器 - Deno.serve({ port: 8080 }, appInstance.fetch) - console.log('应用已启动,监听端口: 8080') - } + + // 传入必要参数并初始化应用 + const appInstance = httpServer({ + apiClient: apiClient, + app: moduleApp, + moduleDir: './' + }) + // 启动服务器 + Deno.serve({ + handler: io.handler(async (req) => { + return await appInstance.fetch(req) || new Response(null, { status: 404 }); + }), + port: 8080 + }) + + console.log('应用已启动,监听端口: 8080') } catch (error) { console.error('模板加载失败:', error) } From dea7ec5316b5cd7fd91e743b2e75ead87f804e9e Mon Sep 17 00:00:00 2001 From: yourname Date: Thu, 15 May 2025 08:40:09 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0socketio=20=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=20=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HISTORY.md | 1 + server/app.tsx | 8 +- server/middlewares.ts | 36 +----- server/router.ts | 5 +- server/router_io.ts | 73 +++++++++++ server/routes_io_messages.ts | 226 +++++++++++++++++++++++++++++++++++ server/routes_socketio.ts | 15 --- server/run_app.ts | 44 ++++++- 8 files changed, 350 insertions(+), 58 deletions(-) create mode 100644 server/router_io.ts create mode 100644 server/routes_io_messages.ts delete mode 100644 server/routes_socketio.ts diff --git a/HISTORY.md b/HISTORY.md index 6b5f64f..554b73b 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,6 +3,7 @@ 迁移管理页面,在正式环境中,需要验证env中配置的密码参数才能打开 2025.05.15 0.1.6 +增加socketio 路由 支持 增加socketio server 支持 修正文件分类后端api路由查询表名为file_categories 将react版本降为18.3.1 diff --git a/server/app.tsx b/server/app.tsx index 9fe35cc..7d4d17a 100644 --- a/server/app.tsx +++ b/server/app.tsx @@ -4,6 +4,7 @@ import React from 'hono/jsx' import type { Context as HonoContext } from 'hono' import { serveStatic } from 'hono/deno' import { APIClient } from '@d8d-appcontainer/api' +import { Auth } from '@d8d-appcontainer/auth'; import debug from "debug" import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; @@ -54,16 +55,17 @@ interface EsmScriptConfig { // 定义模块参数接口 interface ModuleParams { - apiClient: APIClient + apiClient: APIClient, + auth: Auth, app: Hono moduleDir: string } -export default function({ apiClient, app, moduleDir }: ModuleParams) { +export default function({ apiClient, app, moduleDir , auth}: ModuleParams) { const honoApp = app // 创建路由 - const router = createRouter(apiClient, moduleDir) + const router = createRouter(apiClient, moduleDir, auth) honoApp.route('/', router) // 首页路由 - SSR diff --git a/server/middlewares.ts b/server/middlewares.ts index 4fad3f5..546673c 100644 --- a/server/middlewares.ts +++ b/server/middlewares.ts @@ -45,11 +45,11 @@ export const withAuth = async (c: HonoContext<{ Variables: Variables }>, next: ( export type WithAuth = typeof withAuth; // 环境变量设置中间件 -export const setEnvVariables = (apiClient: APIClient, moduleDir: string) => { +export const setEnvVariables = (apiClient: APIClient, moduleDir: string, auth: Auth) => { return async (c: HonoContext<{ Variables: Variables }>, next: () => Promise) => { c.set('apiClient', apiClient) c.set('moduleDir', moduleDir) - c.set('auth', await initAuth(apiClient)) + c.set('auth', auth) c.set('systemSettings', await initSystemSettings(apiClient)) await next() } @@ -58,37 +58,7 @@ export const setEnvVariables = (apiClient: APIClient, moduleDir: string) => { // CORS中间件 export const corsMiddleware = cors() -// 初始化Auth实例 -const initAuth = async (apiClient: APIClient) => { - try { - log.auth('正在初始化Auth实例') - - const auth = new Auth(apiClient as any, { - jwtSecret: Deno.env.get("JWT_SECRET") || 'your-jwt-secret-key', - initialUsers: [], - storagePrefix: '', - userTable: 'users', - fieldNames: { - id: 'id', - username: 'username', - password: 'password', - phone: 'phone', - email: 'email', - is_disabled: 'is_disabled', - is_deleted: 'is_deleted' - }, - tokenExpiry: 24 * 60 * 60, - refreshTokenExpiry: 7 * 24 * 60 * 60 - }) - - log.auth('Auth实例初始化完成') - return auth - - } catch (error) { - log.auth('Auth初始化失败:', error) - throw error - } -} + // 初始化系统设置 const initSystemSettings = async (apiClient: APIClient) => { diff --git a/server/router.ts b/server/router.ts index b601883..9a78777 100644 --- a/server/router.ts +++ b/server/router.ts @@ -2,6 +2,7 @@ import { Hono } from 'hono' import { corsMiddleware, withAuth, setEnvVariables } from './middlewares.ts' import type { APIClient } from '@d8d-appcontainer/api' +import { Auth } from '@d8d-appcontainer/auth'; // 导入路由模块 import { createAuthRoutes } from "./routes_auth.ts" @@ -17,7 +18,7 @@ import { createMessagesRoutes } from "./routes_messages.ts" import { createMigrationsRoutes } from "./routes_migrations.ts" import { createHomeRoutes } from "./routes_home.ts" -export function createRouter(apiClient: APIClient, moduleDir: string) { +export function createRouter(apiClient: APIClient, moduleDir: string , auth: Auth) { const router = new Hono() // 添加CORS中间件 @@ -27,7 +28,7 @@ export function createRouter(apiClient: APIClient, moduleDir: string) { const api = new Hono() // 设置环境变量 - api.use('*', setEnvVariables(apiClient, moduleDir)) + api.use('*', setEnvVariables(apiClient, moduleDir, auth)) // 注册所有路由 api.route('/auth', createAuthRoutes(withAuth)) diff --git a/server/router_io.ts b/server/router_io.ts new file mode 100644 index 0000000..f942046 --- /dev/null +++ b/server/router_io.ts @@ -0,0 +1,73 @@ +import { Socket, Server } from "socket.io"; +import { Auth } from '@d8d-appcontainer/auth'; +import type { User as AuthUser } from '@d8d-appcontainer/auth'; +import { APIClient } from '@d8d-appcontainer/api'; +import { setupMessageEvents } from './routes_io_messages.ts'; +import debug from "debug"; + +const log = debug('socketio:auth'); + +interface SetupSocketIOProps { + io: Server, auth: Auth, apiClient: APIClient +} + +export interface SocketWithUser extends Socket { + user?: AuthUser; +} + +// 定义自定义上下文类型 +export interface Variables { + socket: SocketWithUser + auth: Auth + user: AuthUser + apiClient: APIClient + // moduleDir: string + // systemSettings?: SystemSettingRecord +} + +export function setupSocketIO({ io, auth, apiClient }:SetupSocketIOProps) { + // Socket.IO认证中间件 + io.use(async (socket: SocketWithUser) => { + try { + const token = socket.handshake.query.get('socket_token'); + if (!token) { + log(`未提供token,拒绝连接: ${socket.id}`); + throw new Error('未授权') + } + + const userData = await auth.verifyToken(token); + if (!userData) { + log(`无效token,拒绝连接: ${socket.id}`); + throw new Error('无效凭证') + } + + socket.user = userData; + log(`认证成功: ${socket.id} 用户: ${userData.username}`); + } catch (error) { + log(`认证错误: ${socket.id}`, error); + } + }); + + io.on("connection", (socket: SocketWithUser) => { + if (!socket.user) { + socket.disconnect(true); + return; + } + + console.log(`socket ${socket.id} 已连接,用户: ${socket.user.username}`); + + socket.on("disconnect", (reason) => { + console.log(`socket ${socket.id} 断开连接,原因: ${reason}`); + }); + + const context: Variables = { + socket, + auth, + apiClient, + user: socket.user, + } + + // 初始化消息路由 + setupMessageEvents(context); + }); +} \ No newline at end of file diff --git a/server/routes_io_messages.ts b/server/routes_io_messages.ts new file mode 100644 index 0000000..9812707 --- /dev/null +++ b/server/routes_io_messages.ts @@ -0,0 +1,226 @@ +import { SocketWithUser , Variables} from './router_io.ts'; +import { MessageType, MessageStatus } from '../client/share/types.ts' +import { APIClient } from "@d8d-appcontainer/api"; + +interface MessageSendData { + title: string; + content: string; + type: MessageType; + receiver_ids: number[]; +} + +interface MessageListData { + page?: number; + pageSize?: number; + type?: MessageType; + status?: MessageStatus; +} + +export function setupMessageEvents({ socket , apiClient }:Variables) { + // 发送消息 + socket.on('message:send', async (data: MessageSendData) => { + try { + const { title, content, type, receiver_ids } = data; + + if (!title || !content || !type || !receiver_ids?.length) { + socket.emit('error', '缺少必要参数'); + return; + } + + const user = socket.user; + if (!user) { + socket.emit('error', '未授权访问'); + return; + } + + // 创建消息 + const [messageId] = await apiClient.database.table('messages').insert({ + title, + content, + type, + sender_id: user.id, + sender_name: user.username, + created_at: apiClient.database.fn.now(), + updated_at: apiClient.database.fn.now() + }); + + // 关联用户消息 + const userMessages = receiver_ids.map((userId: number) => ({ + user_id: userId, + message_id: messageId, + status: MessageStatus.UNREAD, + created_at: apiClient.database.fn.now(), + updated_at: apiClient.database.fn.now() + })); + + await apiClient.database.table('user_messages').insert(userMessages); + + socket.emit('message:sent', { + message: '消息发送成功', + data: { id: messageId } + }); + } catch (error) { + console.error('发送消息失败:', error); + socket.emit('error', '发送消息失败'); + } + }); + + // 获取消息列表 + socket.on('message:list', async (data: MessageListData) => { + try { + const { page = 1, pageSize = 20, type, status } = data; + const user = socket.user; + if (!user) { + socket.emit('error', '未授权访问'); + return; + } + + const query = apiClient.database.table('user_messages as um') + .select('m.*', 'um.status as user_status', 'um.read_at', 'um.id as user_message_id') + .leftJoin('messages as m', 'um.message_id', 'm.id') + .where('um.user_id', user.id) + .where('um.is_deleted', 0) + .orderBy('m.created_at', 'desc') + .limit(pageSize) + .offset((page - 1) * pageSize); + + if (type) query.where('m.type', type); + if (status) query.where('um.status', status); + + const countQuery = query.clone(); + const messages = await query; + + // 获取总数用于分页 + const total = await countQuery.count(); + const totalCount = Number(total); + const totalPages = Math.ceil(totalCount / pageSize); + + socket.emit('message:list', { + data: messages, + pagination: { + total: totalCount, + current: page, + pageSize, + totalPages + } + }); + } catch (error) { + console.error('获取消息列表失败:', error); + socket.emit('error', '获取消息列表失败'); + } + }); + + // 获取消息详情 + socket.on('message:detail', async (messageId: number) => { + try { + const user = socket.user; + if (!user) { + socket.emit('error', '未授权访问'); + return; + } + + const message = await apiClient.database.table('user_messages as um') + .select('m.*', 'um.status as user_status', 'um.read_at') + .leftJoin('messages as m', 'um.message_id', 'm.id') + .where('um.user_id', user.id) + .where('um.message_id', messageId) + .first(); + + if (!message) { + socket.emit('error', '消息不存在或无权访问'); + return; + } + + // 标记为已读 + if (message.user_status === MessageStatus.UNREAD) { + await apiClient.database.table('user_messages') + .where('user_id', user.id) + .where('message_id', messageId) + .update({ + status: MessageStatus.READ, + read_at: apiClient.database.fn.now(), + updated_at: apiClient.database.fn.now() + }); + } + + socket.emit('message:detail', { + message: '获取消息成功', + data: message + }); + } catch (error) { + console.error('获取消息详情失败:', error); + socket.emit('error', '获取消息详情失败'); + } + }); + + // 删除消息 + socket.on('message:delete', async (messageId: number) => { + try { + const user = socket.user; + if (!user) { + socket.emit('error', '未授权访问'); + return; + } + + await apiClient.database.table('user_messages') + .where('user_id', user.id) + .where('message_id', messageId) + .update({ + is_deleted: 1, + updated_at: apiClient.database.fn.now() + }); + + socket.emit('message:deleted', { message: '消息已删除' }); + } catch (error) { + console.error('删除消息失败:', error); + socket.emit('error', '删除消息失败'); + } + }); + + // 获取未读消息数 + socket.on('message:count', async () => { + try { + const user = socket.user; + if (!user) { + socket.emit('error', '未授权访问'); + return; + } + + const count = await apiClient.database.table('user_messages') + .where('user_id', user.id) + .where('status', MessageStatus.UNREAD) + .where('is_deleted', 0) + .count(); + + socket.emit('message:count', { count: Number(count) }); + } catch (error) { + console.error('获取未读消息数失败:', error); + socket.emit('error', '获取未读消息数失败'); + } + }); + + // 标记消息为已读 + socket.on('message:read', async (messageId: number) => { + try { + const user = socket.user; + if (!user) { + socket.emit('error', '未授权访问'); + return; + } + + await apiClient.database.table('user_messages') + .where('user_id', user.id) + .where('message_id', messageId) + .update({ + status: MessageStatus.READ, + read_at: apiClient.database.fn.now(), + updated_at: apiClient.database.fn.now() + }); + + socket.emit('message:read', { message: '消息已标记为已读' }); + } catch (error) { + console.error('标记消息为已读失败:', error); + socket.emit('error', '标记消息为已读失败'); + } + }); +} \ No newline at end of file diff --git a/server/routes_socketio.ts b/server/routes_socketio.ts deleted file mode 100644 index 6f5bd57..0000000 --- a/server/routes_socketio.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Socket, Server } from "socket.io"; - -export function setupSocketIO(io: Server) { - io.on("connection", (socket: Socket) => { - console.log(`socket ${socket.id} connected`); - - socket.emit("hello", "world"); - - socket.on("disconnect", (reason) => { - console.log(`socket ${socket.id} disconnected due to ${reason}`); - }); - - // 可在此添加更多socket事件处理 - }); -} \ No newline at end of file diff --git a/server/run_app.ts b/server/run_app.ts index 20e0f76..b168123 100644 --- a/server/run_app.ts +++ b/server/run_app.ts @@ -1,11 +1,12 @@ // 导入所需模块 import { Hono } from 'hono' import { APIClient } from '@d8d-appcontainer/api' +import { Auth } from '@d8d-appcontainer/auth'; import debug from "debug" import { cors } from 'hono/cors' import { Server } from "socket.io" import httpServer from './app.tsx' -import { setupSocketIO } from './routes_socketio.ts' +import { setupSocketIO } from './router_io.ts' // 初始化debug实例 const log = { @@ -39,6 +40,37 @@ const getApiClient = async (workspaceKey: string, serverUrl?: string) => { throw error } } +// 初始化Auth实例 +const initAuth = async (apiClient: APIClient) => { + try { + log.auth('正在初始化Auth实例') + + const auth = new Auth(apiClient as any, { + jwtSecret: Deno.env.get("JWT_SECRET") || 'your-jwt-secret-key', + initialUsers: [], + storagePrefix: '', + userTable: 'users', + fieldNames: { + id: 'id', + username: 'username', + password: 'password', + phone: 'phone', + email: 'email', + is_disabled: 'is_disabled', + is_deleted: 'is_deleted' + }, + tokenExpiry: 24 * 60 * 60, + refreshTokenExpiry: 7 * 24 * 60 * 60 + }) + + log.auth('Auth实例初始化完成') + return auth + + } catch (error) { + log.auth('Auth初始化失败:', error) + throw error + } +} // 初始化API Client // 注意:WORKSPACE_KEY 需要在 多八多(www.d8d.fun) 平台注册并开通工作空间后获取 @@ -47,6 +79,7 @@ if (!workspaceKey) { console.warn('未设置WORKSPACE_KEY,请前往 多八多(www.d8d.fun) 注册并开通工作空间以获取密钥') } const apiClient = await getApiClient(workspaceKey) +const auth = await initAuth(apiClient); // 创建Hono应用实例 const app = new Hono() @@ -63,10 +96,10 @@ const io = new Server({ } }) -setupSocketIO(io); +setupSocketIO({io, auth, apiClient}); // 动态加载并运行模板 -const runTemplate = async () => { +const runTemplate = () => { try { // 创建基础app实例 const moduleApp = new Hono() @@ -75,7 +108,8 @@ const runTemplate = async () => { const appInstance = httpServer({ apiClient: apiClient, app: moduleApp, - moduleDir: './' + moduleDir: './', + auth }) // 启动服务器 Deno.serve({ @@ -92,4 +126,4 @@ const runTemplate = async () => { } // 执行模板 -runTemplate() \ No newline at end of file +runTemplate() \ No newline at end of file From 2f171d43352e010c54c617906cb846a390ebb159 Mon Sep 17 00:00:00 2001 From: yourname Date: Thu, 15 May 2025 09:18:21 +0000 Subject: [PATCH 3/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0admin,=20mobile=20?= =?UTF-8?q?=E6=B6=88=E6=81=AFio=E8=BF=9E=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HISTORY.md | 1 + client/admin/pages_messages.tsx | 66 ++++++++++++++++++++++++--- client/mobile/pages_messages.tsx | 62 ++++++++++++++++++++++++- deno.json | 3 +- server/routes_io_messages.ts | 77 ++++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+), 8 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 554b73b..d21b76c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,6 +3,7 @@ 迁移管理页面,在正式环境中,需要验证env中配置的密码参数才能打开 2025.05.15 0.1.6 +增加admin, mobile 消息io连接 增加socketio 路由 支持 增加socketio server 支持 修正文件分类后端api路由查询表名为file_categories diff --git a/client/admin/pages_messages.tsx b/client/admin/pages_messages.tsx index 0e8cdf3..577febd 100644 --- a/client/admin/pages_messages.tsx +++ b/client/admin/pages_messages.tsx @@ -1,6 +1,7 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Button, Table, Space, Modal, Form, Input, Select, message } from 'antd'; +import { io, Socket } from 'socket.io-client'; import type { TableProps } from 'antd'; import dayjs from 'dayjs'; import 'dayjs/locale/zh-cn'; @@ -8,8 +9,12 @@ import 'dayjs/locale/zh-cn'; import { MessageAPI , UserAPI } from './api/index.ts'; import type { UserMessage } from '../share/types.ts'; import { MessageStatusNameMap , MessageStatus} from '../share/types.ts'; +import { useAuth } from "./hooks_sys.tsx"; -export const MessagesPage = () => { +export const MessagesPage = () => { + const { token } = useAuth(); + const [socket, setSocket] = useState(null); + const [isSocketConnected, setIsSocketConnected] = useState(false); const queryClient = useQueryClient(); const [form] = Form.useForm(); const [isModalVisible, setIsModalVisible] = useState(false); @@ -59,8 +64,58 @@ export const MessagesPage = () => { }); // 发送消息 + // 初始化Socket.IO连接 + useEffect(() => { + if (!token) return; + + const newSocket = io('/', { + path: '/socket.io', + transports: ['websocket'], + autoConnect: false, + query: { + socket_token: token + } + }); + + newSocket.on('connect', () => { + setIsSocketConnected(true); + message.success('实时消息连接已建立'); + }); + + newSocket.on('disconnect', () => { + setIsSocketConnected(false); + message.warning('实时消息连接已断开'); + }); + + newSocket.on('error', (err) => { + message.error(`实时消息错误: ${err}`); + }); + + newSocket.connect(); + setSocket(newSocket); + + return () => { + newSocket.disconnect(); + }; + }, [token]); + const sendMessageMutation = useMutation({ - mutationFn: (data: any) => MessageAPI.sendMessage(data), + mutationFn: async (data: any) => { + // 优先使用Socket.IO发送 + if (isSocketConnected && socket) { + return new Promise((resolve, reject) => { + socket.emit('message:send', data, (response: any) => { + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + }); + }); + } + // 回退到HTTP API + return MessageAPI.sendMessage(data); + }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['messages'] }); queryClient.invalidateQueries({ queryKey: ['unreadCount'] }); @@ -266,10 +321,11 @@ export const MessagesPage = () => { - diff --git a/client/mobile/pages_messages.tsx b/client/mobile/pages_messages.tsx index a476c41..724d9fa 100644 --- a/client/mobile/pages_messages.tsx +++ b/client/mobile/pages_messages.tsx @@ -1,16 +1,20 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import dayjs from 'dayjs'; import 'dayjs/locale/zh-cn'; import { BellIcon } from '@heroicons/react/24/outline'; import { MessageStatus } from '../share/types.ts'; - +import { io, Socket } from 'socket.io-client'; // 添加通知页面组件 import { MessageAPI } from './api/index.ts'; +import { useAuth } from "./hooks.tsx"; export const NotificationsPage = () => { + const { token , user} = useAuth(); const queryClient = useQueryClient(); + const [socket, setSocket] = React.useState(null); + const [isSubscribed, setIsSubscribed] = React.useState(false); // 获取消息列表 const { data: messages, isLoading } = useQuery({ @@ -18,6 +22,60 @@ export const NotificationsPage = () => { queryFn: () => MessageAPI.getMessages(), }); + // 初始化Socket.IO连接 + useEffect(() => { + if (!token || !user) return; + + const newSocket = io('/', { + path: '/socket.io', + transports: ['websocket'], + withCredentials: true, + query: { + socket_token: token + } + }); + + setSocket(newSocket); + + // 订阅消息频道 + newSocket.on('connect', () => { + newSocket.emit('message:subscribe', `user_${user.id}`); + setIsSubscribed(true); + }); + + // 处理实时消息 + newSocket.on('message:broadcasted', (newMessage) => { + queryClient.setQueryData(['messages'], (oldData: any) => { + if (!oldData) return oldData; + return { + ...oldData, + data: [newMessage, ...oldData.data] + }; + }); + + // 更新未读计数 + queryClient.setQueryData(['unreadCount'], (oldData: any) => { + if (!oldData) return oldData; + return { + ...oldData, + count: oldData.count + 1 + }; + }); + }); + + // 错误处理 + newSocket.on('error', (error) => { + console.error('Socket error:', error); + }); + + return () => { + if (newSocket) { + newSocket.emit('message:unsubscribe', `user_${user.id}`); + newSocket.disconnect(); + } + }; + }, [queryClient, token]); + // 获取未读消息数量 const { data: unreadCount } = useQuery({ queryKey: ['unreadCount'], diff --git a/deno.json b/deno.json index 1bed6f7..e95dfac 100644 --- a/deno.json +++ b/deno.json @@ -29,7 +29,8 @@ "react-hook-form": "https://esm.d8d.fun/react-hook-form@7.55.0?dev&deps=react@18.3.1,react-dom@18.3.1", "@heroicons/react/24/outline": "https://esm.d8d.fun/@heroicons/react@2.1.1/24/outline?dev&deps=react@18.3.1,react-dom@18.3.1", "@heroicons/react/24/solid": "https://esm.d8d.fun/@heroicons/react@2.1.1/24/solid?dev&deps=react@18.3.1,react-dom@18.3.1", - "socket.io": "https://deno.land/x/socket_io@0.2.1/mod.ts" + "socket.io": "https://deno.land/x/socket_io@0.2.1/mod.ts", + "socket.io-client": "https://esm.d8d.fun/socket.io-client@4.8.1" }, "compilerOptions": { "lib": ["dom", "dom.iterable", "esnext", "deno.ns"] diff --git a/server/routes_io_messages.ts b/server/routes_io_messages.ts index 9812707..f40b5f7 100644 --- a/server/routes_io_messages.ts +++ b/server/routes_io_messages.ts @@ -17,6 +17,83 @@ interface MessageListData { } export function setupMessageEvents({ socket , apiClient }:Variables) { + // 订阅频道 + socket.on('message:subscribe', (channel: string) => { + try { + socket.join(channel); + socket.emit('message:subscribed', { + message: `成功订阅频道: ${channel}`, + channel + }); + } catch (error) { + console.error('订阅频道失败:', error); + socket.emit('error', '订阅频道失败'); + } + }); + + // 取消订阅 + socket.on('message:unsubscribe', (channel: string) => { + try { + socket.leave(channel); + socket.emit('message:unsubscribed', { + message: `已取消订阅频道: ${channel}`, + channel + }); + } catch (error) { + console.error('取消订阅失败:', error); + socket.emit('error', '取消订阅失败'); + } + }); + + // 广播消息 + socket.on('message:broadcast', async (data: { + channel?: string; + title: string; + content: string; + type: MessageType; + }) => { + try { + const { channel, title, content, type } = data; + const user = socket.user; + if (!user) { + socket.emit('error', '未授权访问'); + return; + } + + // 创建广播消息 + const [messageId] = await apiClient.database.table('messages').insert({ + title, + content, + type, + sender_id: user.id, + sender_name: user.username, + is_broadcast: 1, + created_at: apiClient.database.fn.now(), + updated_at: apiClient.database.fn.now() + }); + + // 广播到所有客户端或特定频道 + const broadcastTarget = channel ? socket.to(channel) : socket.broadcast; + broadcastTarget.emit('message:broadcasted', { + id: messageId, + title, + content, + type, + sender_id: user.id, + sender_name: user.username, + created_at: new Date().toISOString() + }); + + socket.emit('message:broadcasted', { + message: '广播消息发送成功', + data: { id: messageId } + }); + } catch (error) { + console.error('广播消息失败:', error); + socket.emit('error', '广播消息失败'); + } + }); + // 发送消息 socket.on('message:send', async (data: MessageSendData) => { try { From f3042583df9e172a35c7d3f8a3d50fc8bb0ed676 Mon Sep 17 00:00:00 2001 From: yourname Date: Thu, 15 May 2025 12:06:17 +0000 Subject: [PATCH 4/5] =?UTF-8?q?=E7=AB=99=E5=86=85=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=B8=89=E7=A7=8D=E7=B1=BB=E5=9E=8B=EF=BC=8C?= =?UTF-8?q?admin=E5=8F=91=E9=80=81=EF=BC=8Cmobile=E8=AE=A2=E9=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/admin/pages_messages.tsx | 18 +++--- client/mobile/pages_messages.tsx | 16 ++++- docs/message-system-architecture.md | 99 +++++++++++++++++++++++++++++ server/routes_io_messages.ts | 21 ++++++ 4 files changed, 143 insertions(+), 11 deletions(-) create mode 100644 docs/message-system-architecture.md diff --git a/client/admin/pages_messages.tsx b/client/admin/pages_messages.tsx index 577febd..c6b6248 100644 --- a/client/admin/pages_messages.tsx +++ b/client/admin/pages_messages.tsx @@ -8,7 +8,7 @@ import 'dayjs/locale/zh-cn'; import { MessageAPI , UserAPI } from './api/index.ts'; import type { UserMessage } from '../share/types.ts'; -import { MessageStatusNameMap , MessageStatus} from '../share/types.ts'; +import { MessageStatusNameMap , MessageStatus, MessageType } from '../share/types.ts'; import { useAuth } from "./hooks_sys.tsx"; export const MessagesPage = () => { @@ -222,9 +222,9 @@ export const MessagesPage = () => { style={{ width: 120 }} allowClear options={[ - { value: 'SYSTEM', label: '系统消息' }, - { value: 'NOTICE', label: '公告' }, - { value: 'PERSONAL', label: '个人消息' }, + { value: MessageType.SYSTEM, label: '系统消息' }, + { value: MessageType.ANNOUNCE, label: '公告' }, + { value: MessageType.PRIVATE, label: '个人消息' }, ]} /> @@ -233,8 +233,8 @@ export const MessagesPage = () => { style={{ width: 120 }} allowClear options={[ - { value: 'UNREAD', label: '未读' }, - { value: 'READ', label: '已读' }, + { value: MessageStatus.UNREAD, label: '未读' }, + { value: MessageStatus.READ, label: '已读' }, ]} /> @@ -290,9 +290,9 @@ export const MessagesPage = () => { >