From cb8723c172177128b02c96e3733ebf09c74e772b Mon Sep 17 00:00:00 2001 From: abearxiong Date: Sat, 3 Jan 2026 01:54:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20@kevisual/api=20=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E8=87=B3=200.0.16=EF=BC=8C=E5=A2=9E=E5=BC=BA=20Router?= =?UTF-8?q?ViewItem=20=E7=B1=BB=E5=9E=8B=EF=BC=8C=E6=B7=BB=E5=8A=A0=20ques?= =?UTF-8?q?tion=E3=80=81response=20=E5=92=8C=20action=20=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=EF=BC=8C=E9=87=8D=E6=9E=84=20initRouterViewQuery=20=E5=92=8C?= =?UTF-8?q?=20callWorker=20=E6=96=B9=E6=B3=95=E4=BB=A5=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=E8=A7=86=E5=9B=BE=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E5=92=8C=E5=B7=A5=E4=BD=9C=E7=BA=BF=E7=A8=8B=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- query/query-proxy/index.ts | 230 +++++++++++++++++++++++++------------ 2 files changed, 158 insertions(+), 74 deletions(-) diff --git a/package.json b/package.json index a76b205..a4df259 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/api", - "version": "0.0.15", + "version": "0.0.16", "description": "", "main": "mod.ts", "scripts": { diff --git a/query/query-proxy/index.ts b/query/query-proxy/index.ts index 8b9d19b..8793698 100644 --- a/query/query-proxy/index.ts +++ b/query/query-proxy/index.ts @@ -4,13 +4,26 @@ import { filter } from '@kevisual/js-filter' import { EventEmitter } from 'eventemitter3'; export const RouteTypeList = ['api', 'context', 'worker', 'page'] as const; -export type RouterViewItem = RouterViewApi | RouterViewContext | RouterViewWorker | RouteViewPage; +export type RouterViewItemInfo = RouterViewApi | RouterViewContext | RouterViewWorker | RouteViewPage; +export type RouterViewItem = RouterViewItemInfo & T; type RouteViewBase = { id: string; title: string; description: string; enabled?: boolean; + /** + * 提示问题 + */ + question?: string; + /** + * 响应数据 + */ + response?: any; + /** + * 默认动作配置 + */ + action?: { path?: string; key?: string; id?: string; payload?: any;[key: string]: any }; } export type RouterViewApi = { type: 'api', @@ -46,6 +59,30 @@ export type RouterViewWorker = { } } & RouteViewBase; +/** + * 去掉不需要保存都服务器的数据 + * @param item + * @returns + */ +export const pickRouterViewData = (item: RouterViewItem) => { + const { question, action, response, ...rest } = item; + if (rest.type === 'api') { + if (rest.api) { + delete rest.api.query; + } + } + if (rest.type === 'worker') { + if (rest.worker) { + delete rest.worker.worker; + } + } + if (rest.type === 'context') { + if (rest.context) { + delete rest.context.router; + } + } + return rest +} /** * 注入 js 的url地址,使用importScripts加载 */ @@ -91,58 +128,63 @@ export class QueryProxy { return undefined; } } - async initRouterViewQuery() { + initRouterViewQuery() { this.routerViewItems = this.routerViewItems.map(item => { - if (item.type === 'api' && item.api?.url) { - const url = item.api.url; - if (item?.api?.query) return item; - item['api'] = { url: url, query: new Query({ url: url }) }; - } - if (item.type === 'worker' && item.worker?.url) { - let viewItem = item as RouterViewWorker; - if (!item.worker?.workerOptions?.type) { - item.worker.workerOptions = { ...item.worker.workerOptions, type: 'module' }; - } - if (item.worker.worker) { - return item; - } - let worker: Worker | SharedWorker | ServiceWorker | undefined = undefined; - if (item.worker.type === 'SharedWorker') { - worker = new SharedWorker(item.worker.url, item.worker.workerOptions); - worker.port.start(); - } else if (viewItem.worker.type === 'serviceWorker') { - if ('serviceWorker' in navigator) { - navigator.serviceWorker.register(viewItem.worker.url, item.worker.workerOptions).then(function (registration) { - console.debug('注册serviceWorker成功 ', registration.scope); - }, function (err) { - console.debug('注册 serviceWorker 失败: ', err); - }); - } else { - console.warn('当前浏览器不支持serviceWorker'); - } - } else { - worker = new Worker(viewItem.worker.url, item.worker.workerOptions); - } - viewItem['worker']['worker'] = worker; - } - if (item.type === 'context' && item.context?.key) { - if (item.context?.router) { - return item; - } - // @ts-ignore - const context = globalThis['context'] || {} - const router = context[item.context.key] as QueryRouterServer; - if (router) { - item['context']['router'] = router; - } - } - return item; + return this.initRouterView(item); }).filter(item => { const enabled = item.enabled ?? true; return enabled; }); } + initRouterView(item: RouterViewItem) { + if (item.type === 'api' && item.api?.url) { + const url = item.api.url; + if (item?.api?.query) return item; + item['api'] = { url: url, query: new Query({ url: url }) }; + } + if (item.type === 'worker' && item.worker?.url) { + let viewItem = item as RouterViewWorker; + if (!item.worker?.workerOptions?.type) { + item.worker.workerOptions = { ...item.worker.workerOptions, type: 'module' }; + } + if (item.worker.worker) { + return item; + } + let worker: Worker | SharedWorker | ServiceWorker | undefined = undefined; + if (item.worker.type === 'SharedWorker') { + worker = new SharedWorker(item.worker.url, item.worker.workerOptions); + worker.port.start(); + } else if (viewItem.worker.type === 'serviceWorker') { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.register(viewItem.worker.url, item.worker.workerOptions).then(function (registration) { + console.debug('注册serviceWorker成功 ', registration.scope); + }, function (err) { + console.debug('注册 serviceWorker 失败: ', err); + }); + } else { + console.warn('当前浏览器不支持serviceWorker'); + } + } else { + worker = new Worker(viewItem.worker.url, item.worker.workerOptions); + } + viewItem['worker']['worker'] = worker; + } + if (item.type === 'context' && item.context?.key) { + if (item.context?.router) { + return item; + } + // @ts-ignore + const context = globalThis['context'] || {} + const router = context[item.context.key] as QueryRouterServer; + if (router) { + item['context']['router'] = router; + } + } + return item; + + } + /** * 初始化路由 * @returns @@ -248,7 +290,35 @@ export class QueryProxy { generateId() { return 'route_' + Math.random().toString(36).substring(2, 9); } - async initWorker(item?: RouterViewWorker) { + async callWorker(msg: any, viewItem: RouterViewWorker['worker']): Promise { + const that = this; + const requestId = this.generateId(); + const worker = viewItem?.worker; + if (!worker) { + return { code: 500, message: 'Worker未初始化' }; + } + let port: MessagePort | Worker | ServiceWorker; + if (viewItem.type === 'SharedWorker') { + port = (worker as SharedWorker).port; + } else { + port = worker as Worker | ServiceWorker; + } + port.postMessage({ + ...msg, + requestId: requestId, + }) + return new Promise((resolve) => { + const timer = setTimeout(() => { + that.emitter.removeAllListeners(requestId); + resolve({ code: 500, message: '请求超时' }); + }, 3 * 60 * 1000); // 3分钟超时 + that.emitter.once(requestId, (res: any) => { + clearTimeout(timer); + resolve(res); + }); + }); + } + async initWorker(item?: RouterViewWorker, initRoutes: boolean = true) { const that = this; if (!item?.worker?.url) { console.warn('Worker URL not provided'); @@ -278,33 +348,10 @@ export class QueryProxy { } else { (worker as Worker).onmessage = callResponse; } - const callWorker = async (msg: any, viewItem: RouterViewWorker['worker']): Promise => { - const requestId = this.generateId(); - const worker = viewItem?.worker; - if (!worker) { - return { code: 500, message: 'Worker未初始化' }; - } - let port: MessagePort | Worker | ServiceWorker; - if (viewItem.type === 'SharedWorker') { - port = (worker as SharedWorker).port; - } else { - port = worker as Worker | ServiceWorker; - } - port.postMessage({ - ...msg, - requestId: requestId, - }) - return new Promise((resolve) => { - const timer = setTimeout(() => { - that.emitter.removeAllListeners(requestId); - resolve({ code: 500, message: '请求超时' }); - }, 3 * 60 * 1000); // 3分钟超时 - that.emitter.once(requestId, (res: any) => { - clearTimeout(timer); - resolve(res); - }); - }); + if (!initRoutes) { + return; } + const callWorker = this.callWorker.bind(this); const res = await callWorker({ path: "router", @@ -393,6 +440,43 @@ export class QueryProxy { async run(msg: { id?: string, path?: string, key?: string }) { return await this.router.run(msg); } + + async runByRouteView(routeView: RouterViewItem) { + if (routeView.response) { + return routeView; + } + const item = this.initRouterView(routeView); + if (item.type === 'api' && item.api?.url) { + const query = item.api.query!; + const res = await query.post(item.action || {}); + item.response = res; + return item; + } else if (item.type === 'api') { + item.response = { code: 500, message: 'API URL未配置' }; + return item; + } + if (item.type === 'context' && item.context?.router) { + const router = item.context.router; + const res = await router.run(item.action || {}); + item.response = res; + return item; + } + if (item.type === 'page') { + await this.initPage(item); + const res = await this.router.run(item.action || {}); + item.response = res; + return item; + } + if (item.type === 'worker' && item.worker?.worker) { + await this.initWorker(item, false); + const callWorker = this.callWorker.bind(this); + const res = await callWorker(item.action || {}, item.worker); + item.response = res; + return item; + } + item.response = { code: 500, message: '无法处理的路由类型' }; + return item; + } } type RouterItem = {