From 12830b7cf60a70ed66f906873e689aaea4ff7b42 Mon Sep 17 00:00:00 2001 From: ayou <550244300@qq.com> Date: Wed, 3 Dec 2025 21:21:24 +0800 Subject: [PATCH] =?UTF-8?q?fix(router):=20=E4=BF=AE=E5=A4=8D=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E9=87=8D=E5=AE=9A=E5=90=91=E5=85=BC=E5=AE=B9hash?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=E5=92=8C=E6=99=AE=E9=80=9A=E8=B7=AF=E7=94=B1?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加对hash路由的识别处理,优先尝试使用hash路由跳转,失败时回退到普通pathname跳转 docs: 添加Flow架构与执行流程文档 --- .trae/documents/Flow 架构与执行图产出计划.md | 61 ++++++++++++++++++++ frontend/src/utils/axios.ts | 15 ++++- 2 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 .trae/documents/Flow 架构与执行图产出计划.md diff --git a/.trae/documents/Flow 架构与执行图产出计划.md b/.trae/documents/Flow 架构与执行图产出计划.md new file mode 100644 index 0000000..81ed1a1 --- /dev/null +++ b/.trae/documents/Flow 架构与执行图产出计划.md @@ -0,0 +1,61 @@ +## 输出物 +- 一份详细的 Flow 架构与执行流程文档,包含可视化图示与文字说明 +- 以 Mermaid 图(可直接在 IDE/Markdown 预览)呈现;同时提供 ASCII 简版便于纯文本查看 + +## 文档与图的组织 +- 文件:`docs/flow_architecture.md` +- 结构:分章节“模块架构”“请求/运行编排”“引擎执行图”“数据模型”“事件与日志”“DSL 与 Design 转换”“执行器生态” +- 图格式:Mermaid(flowchart、sequence、class、er);每个图下配文字说明与代码引用(file:line) + +## 图示清单与内容要点 +1. 模块架构图(Graph LR) + - 节点:`flow/{dsl,domain,context,engine,task,executors,mappers,log_handler}`、`services/{flow_service,flow_run_log_service}`、`routes/{flows,flow_run_logs}`、`middlewares/{sse,ws,jwt,http_client}`、`db,redis,models/{flow,flow_run_log}` + - 边:解析→构建→驱动→事件→日志入库;路由→服务→引擎;执行器←上下文补充 + +2. 请求/运行编排时序图(Sequence) + - 参与者:客户端、`routes.flows`、`flow_service`、`dsl/mappers`、`FlowEngine`、`log_handler`、`middlewares.sse/ws`、`models` + - 关键步骤:加载流程→解析 YAML/design_json→构造 `ChainDef/ctx`→`drive(...)`→推送事件→写入运行日志→返回结果 + +3. 引擎执行图(Flowchart) + - 图块:选起点→合流屏障检查→任务执行(Sync/AsyncFireAndForget/Queued/Bounded)→分支选择(条件 JSON/Rhai)→组内追踪与等待(BranchExit/FlowEnd)→结束与事件推送 + - 特别展示:`group` 信号量(队列/限并发)与写回策略(variable/http/db) + +4. DSL/Design 转换图(Flowchart) + - `DesignSyntax` 校验→条件端口兼容→推断 `kind/task/name`→组装 `groups/members/await_policy`→生成 `ChainDef` + - 同时展示 `mappers.ctx_from_design_json` 将节点配置落到 `ctx.nodes..` + +5. 数据模型图(ER/Class) + - 表:`flows(id,name,yaml,design_json,code,remark,created_at,updated_at)`、`flow_run_logs(id,flow_id,flow_code,input,output,ok,logs,user_id,username,started_at,duration_ms,created_at)` + - 关系:`flow_run_logs.flow_id → flows.id` + +6. 事件与日志通道图(Graph LR) + - SSE/WS:`engine.push_and_emit → middlewares.sse/ws → client` + - 入库:`FlowLogHandler(Database|Sse)` → `flow_run_log_service.create` + +7. 执行器生态图(Graph LR) + - 节点:`http/db/variable/script_rhai/script_js/script_python/condition` + - 输入来源:`ctx.nodes..*` 与顶层 `ctx.*`;输出写回策略与幂等注意点 + +## 信息来源与代码引用 +- DSL/Design:`backend/src/flow/dsl.rs:60-93,138-170,172-203,246-303` +- 领域模型:`backend/src/flow/domain.rs:20-28,31-36,39-47,60-68` +- 上下文与事件:`backend/src/flow/context.rs:29-45` +- 引擎:`backend/src/flow/engine.rs:117-209,213-577` +- 服务编排:`backend/src/services/flow_service.rs:285-305,342-349,351-365,366-399` +- 路由:`backend/src/routes/flows.rs:26-35,101-133` +- 日志服务:`backend/src/services/flow_run_log_service.rs:46-63,74-131` + +## 实施步骤 +1. 生成 `docs/flow_architecture.md` 骨架,按章节填入概要说明 +2. 为每个章节插入 Mermaid 图代码块,并补充 2-4 条关键解释 +3. 在图下添加代码引用(`file_path:line_number`) +4. 预览并调整布局(节点命名统一、边方向一致、避免交叉线) +5. 输出 ASCII 简版(备选)供纯文本环境查看 + +## 验证 +- 在 IDE/Markdown 预览验证所有 Mermaid 图可渲染 +- 随机抽取 3 处代码引用跳转验证准确性 + +## 后续维护 +- 当新增执行器或模式,更新“执行器生态图”和“引擎执行图” +- 当模型字段变更,更新 ER 图并在“请求/运行编排时序图”同步最新流程 \ No newline at end of file diff --git a/frontend/src/utils/axios.ts b/frontend/src/utils/axios.ts index 004bc8a..e27e60c 100644 --- a/frontend/src/utils/axios.ts +++ b/frontend/src/utils/axios.ts @@ -16,8 +16,19 @@ let pendingQueue: { resolve: () => void; reject: (e: unknown) => void; config: R function redirectToLogin(msg?: string): Promise { clearToken() - if (typeof window !== 'undefined' && window.location.pathname !== '/login') { - window.location.href = '/login' + if (typeof window !== 'undefined') { + const isHashRouter = (window.location.hash || '').startsWith('#/') + if (isHashRouter) { + if (window.location.hash !== '#/login') { + window.location.hash = '#/login' + } + } else { + if (window.location.pathname !== '/login') { + // 兼容浏览器路由与生产静态部署:优先使用 hash 入口,无法识别时再回退 pathname + try { window.location.hash = '#/login' } catch {} + try { window.location.href = '/login' } catch {} + } + } } return Promise.reject(new Error(msg || '未登录或登录已过期')) }