From e68b77f87166553d012c1468b01cf39e26425cf1 Mon Sep 17 00:00:00 2001 From: abearxiong Date: Mon, 9 Mar 2026 02:37:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=A0=E9=99=A4studio-app-list?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96proxy.ts=E5=92=8Cf?= =?UTF-8?q?lowme=E8=B7=AF=E7=94=B1=E7=9A=84=E7=BB=93=E6=9E=84=E4=B8=8E?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/html/studio-app-list/index.ts | 354 ---------------------- src/modules/v1-ws-proxy/proxy.ts | 1 - src/routes/flowme/list.ts | 143 ++++++--- 3 files changed, 96 insertions(+), 402 deletions(-) delete mode 100644 src/modules/html/studio-app-list/index.ts diff --git a/src/modules/html/studio-app-list/index.ts b/src/modules/html/studio-app-list/index.ts deleted file mode 100644 index 042b4bf..0000000 --- a/src/modules/html/studio-app-list/index.ts +++ /dev/null @@ -1,354 +0,0 @@ -type StudioOpts = { - user: string, - userAppKey?: string; - appIds: string[] - infoList?: { - user: string; - id: string; - status: 'waiting' | 'connected' | 'closed'; - }[] -} -export const createStudioAppListHtml = (opts: StudioOpts) => { - const user = opts.user!; - const userAppKey = opts?.userAppKey; - let showUserAppKey = userAppKey; - const infos = opts.infoList || []; - if (showUserAppKey && showUserAppKey.startsWith(user + '--')) { - showUserAppKey = showUserAppKey.replace(user + '--', ''); - } - const pathApps = opts?.appIds?.map(appId => { - const shortAppId = appId.replace(opts!.user + '--', '') - return { - appId, - shortAppId, - pathname: `/${user}/v1/${shortAppId}` - }; - }) || [] - - // 应用列表内容 - const appListContent = ` -
-

Studio 应用列表

- -
- -
- ${pathApps.map((app, index) => ` - -
-
-

${app.shortAppId}

-

${app.pathname}

-
-
-
- `).join('')} -
- - ${pathApps.length === 0 ? ` -
-
📭
-

暂无应用

-
- ` : ''} - ` - - return ` - - - - - - Studio - ${user} 的应用 - - - -
- ${showUserAppKey ? ` -
- -

应用不存在

-

抱歉,您访问的应用 ${showUserAppKey || ''} 不存在。

-

请检查应用 Key 是否正确,或联系管理员。

- ← 返回应用列表 -
- ` : ''} - ${appListContent} -
${JSON.stringify(infos, null, 2)}
- -
- - - `; -}; diff --git a/src/modules/v1-ws-proxy/proxy.ts b/src/modules/v1-ws-proxy/proxy.ts index fdba8e0..83cde89 100644 --- a/src/modules/v1-ws-proxy/proxy.ts +++ b/src/modules/v1-ws-proxy/proxy.ts @@ -4,7 +4,6 @@ import { wsProxyManager } from './index.ts'; import { App } from '@kevisual/router'; import { logger } from '../logger.ts'; import { getLoginUser } from '@/modules/auth.ts'; -import { createStudioAppListHtml } from '../html/studio-app-list/index.ts'; import { omit } from 'es-toolkit'; import { baseProxyUrl, proxyDomain } from '../domain.ts'; import { renderServerHtml } from '../html/render-server-html.ts'; diff --git a/src/routes/flowme/list.ts b/src/routes/flowme/list.ts index 4ffb491..bfc3d02 100644 --- a/src/routes/flowme/list.ts +++ b/src/routes/flowme/list.ts @@ -1,5 +1,6 @@ import { desc, eq, count, or, like, and } from 'drizzle-orm'; import { schema, app, db } from '@/app.ts' +import z from 'zod'; // 获取 flowme 列表 app.route({ @@ -7,6 +8,15 @@ app.route({ key: 'list', middleware: ['auth'], description: '获取 flowme 列表', + metadata: { + args: { + page: z.number().describe('页码, 默认为 1').optional(), + pageSize: z.number().describe('每页数量, 默认为 20').optional(), + search: z.string().describe('搜索关键词').optional(), + channelId: z.string().describe('频道ID').optional(), + sort: z.enum(['ASC', 'DESC']).describe('排序方式,ASC 或 DESC,默认为 DESC').optional(), + } + } }).define(async (ctx) => { const tokenUser = ctx.state.tokenUser; const uid = tokenUser.id; @@ -56,61 +66,93 @@ app.route({ return ctx; }).addTo(app); -// 创建或更新 flowme -const flowmeUpdate = `创建或更新一个 flowme, 参数定义: -title: 标题, 必填 -description: 描述, 选填 -tags: 标签, 数组, 选填 -link: 链接, 选填 -data: 数据, 对象, 选填 -channelId: 频道ID, 选填 -type: 类型, 选填 -source: 来源, 选填 -importance: 重要性等级, 数字, 选填 -`; +// 创建 flowme +app.route({ + path: 'flowme', + key: 'create', + middleware: ['auth'], + description: '创建一个 flowme', + metadata: { + args: { + data: z.object({ + title: z.string().describe('标题').optional(), + description: z.string().describe('描述').optional(), + tags: z.array(z.string()).describe('标签').optional(), + link: z.string().describe('链接').optional(), + data: z.record(z.string(), z.any()).describe('数据').optional(), + channelId: z.string().describe('频道ID').optional(), + type: z.string().describe('类型').optional(), + source: z.string().describe('来源').optional(), + importance: z.number().describe('重要性等级').optional(), + isArchived: z.boolean().describe('是否归档').optional(), + }) + } + } +}).define(async (ctx) => { + const { uid, updatedAt, createdAt, ...rest } = ctx.query.data || {}; + const tokenUser = ctx.state.tokenUser; + const flowmeItem = await db.insert(schema.flowme).values({ + title: rest.title || '', + description: rest.description || '', + tags: rest.tags || [], + link: rest.link || '', + data: rest.data || {}, + channelId: rest.channelId || null, + type: rest.type || '', + source: rest.source || '', + importance: rest.importance || 0, + uid: tokenUser.id, + }).returning(); + ctx.body = flowmeItem; +}).addTo(app); + app.route({ path: 'flowme', key: 'update', middleware: ['auth'], - description: flowmeUpdate, + description: '更新一个 flowme', + metadata: { + args: { + data: z.object({ + id: z.string().describe('ID'), + title: z.string().describe('标题').optional(), + description: z.string().describe('描述').optional(), + tags: z.array(z.string()).describe('标签').optional(), + link: z.string().describe('链接').optional(), + data: z.record(z.string(), z.any()).describe('数据').optional(), + channelId: z.string().describe('频道ID').optional(), + type: z.string().describe('类型').optional(), + source: z.string().describe('来源').optional(), + importance: z.number().describe('重要性等级').optional(), + isArchived: z.boolean().describe('是否归档').optional(), + }) + } + } }).define(async (ctx) => { const { id, uid, updatedAt, createdAt, ...rest } = ctx.query.data || {}; const tokenUser = ctx.state.tokenUser; - let flowmeItem; if (!id) { - flowmeItem = await db.insert(schema.flowme).values({ - title: rest.title || '', - description: rest.description || '', - tags: rest.tags || [], - link: rest.link || '', - data: rest.data || {}, - channelId: rest.channelId || null, - type: rest.type || '', - source: rest.source || '', - importance: rest.importance || 0, - uid: tokenUser.id, - }).returning(); - } else { - const existing = await db.select().from(schema.flowme).where(eq(schema.flowme.id, id)).limit(1); - if (existing.length === 0) { - ctx.throw(404, '没有找到对应的 flowme'); - } - if (existing[0].uid !== tokenUser.id) { - ctx.throw(403, '没有权限更新该 flowme'); - } - flowmeItem = await db.update(schema.flowme).set({ - title: rest.title, - description: rest.description, - tags: rest.tags, - link: rest.link, - data: rest.data, - channelId: rest.channelId, - type: rest.type, - source: rest.source, - importance: rest.importance, - isArchived: rest.isArchived, - }).where(eq(schema.flowme.id, id)).returning(); + ctx.throw(400, 'id 参数缺失'); } + const existing = await db.select().from(schema.flowme).where(eq(schema.flowme.id, id)).limit(1); + if (existing.length === 0) { + ctx.throw(404, '没有找到对应的 flowme'); + } + if (existing[0].uid !== tokenUser.id) { + ctx.throw(403, '没有权限更新该 flowme'); + } + const flowmeItem = await db.update(schema.flowme).set({ + title: rest.title, + description: rest.description, + tags: rest.tags, + link: rest.link, + data: rest.data, + channelId: rest.channelId, + type: rest.type, + source: rest.source, + importance: rest.importance, + isArchived: rest.isArchived, + }).where(eq(schema.flowme.id, id)).returning(); ctx.body = flowmeItem; }).addTo(app); @@ -119,7 +161,14 @@ app.route({ path: 'flowme', key: 'delete', middleware: ['auth'], - description: '删除 flowme, 参数: data.id 必填', + description: '删除 flowme ', + metadata: { + args: { + data: z.object({ + id: z.string().describe('ID'), + }) + } + } }).define(async (ctx) => { const tokenUser = ctx.state.tokenUser; const { id } = ctx.query.data || {};