diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..8c2c35d --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,12 @@ +{ + "permissions": { + "allow": [ + "Bash(*)", + "Read(//d/WorkBuddyMyWorkSpace/Juggle接口编排Net6/JuggleNet6.JS/src/views/suite/**)" + ], + "additionalDirectories": [ + "\\tmp", + "d:\\tmp" + ] + } +} diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..d9b4618 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,16 @@ +{ + "permissions": { + "allow": [ + "Bash(*)", + "Bash(dotnet --version)", + "Bash(dotnet restore *)", + "Bash(npm install *)", + "Bash(dotnet run *)", + "Bash(npm run *)", + "Bash(git add *)", + "Bash(git commit *)", + "Bash(dotnet build *)", + "Bash(taskkill //PID 49488 //F)" + ] + } +} diff --git "a/.codebuddy/rules/git\346\217\220\344\272\244\350\247\204\345\210\231.mdc" "b/.codebuddy/rules/git\346\217\220\344\272\244\350\247\204\345\210\231.mdc" new file mode 100644 index 0000000..a741bf4 --- /dev/null +++ "b/.codebuddy/rules/git\346\217\220\344\272\244\350\247\204\345\210\231.mdc" @@ -0,0 +1,11 @@ +--- +description: +alwaysApply: true +enabled: true +updatedAt: 2026-04-29T09:05:02.109Z +provider: +--- + +git提交规则: +1.每完成一个子任务,修复一个bug都要提交一次git +2.注释使用中文 \ No newline at end of file diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml new file mode 100644 index 0000000..540da69 --- /dev/null +++ b/.github/workflows/docker-build-push.yml @@ -0,0 +1,51 @@ +name: Build and Push Docker Image + +on: + push: + tags: + - 'v*' # 推送任何 v 开头的 tag 时触发,如 v1.0, v1.1 + workflow_dispatch: # 支持手动触发 + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Extract version from tag + id: version + run: | + VERSION=${GITHUB_REF_NAME} + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Building version: $VERSION" + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: true + tags: | + pythonhuang/juggle-net8:${{ steps.version.outputs.version }} + pythonhuang/juggle-net8:latest + # 多平台支持(可选,移除 linux/arm64 可加快构建速度) + platforms: linux/amd64 + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + BUILD_DATE=${{ github.event.repository.updated_at }} + GIT_COMMIT=${{ github.sha }} + + - name: Image digest + run: echo "Image pushed with digest ${{ steps.docker_build.outputs.digest }}" diff --git a/.gitignore b/.gitignore index ab0fd3a..1cb84be 100644 --- a/.gitignore +++ b/.gitignore @@ -352,3 +352,10 @@ wwwroot/ # 前端依赖 node_modules/ dist/ + +# 测试/工具残留 +.playwright-mcp/ +Juggle.Api/.config/ +JuggleNet6.Frontend/.git__/ +JuggleNet6.Frontend/.git___/ +JuggleNet6.Frontend/.git____/ diff --git a/Architecture.md b/Architecture.md index 01e03d4..0618c67 100644 --- a/Architecture.md +++ b/Architecture.md @@ -1,8 +1,8 @@ # Juggle 接口编排平台 - 系统架构文档 -> 版本:v1.0 -> 日期:2026-03-24 -> 基于原项目(Java + Spring Boot + Vue3)重构为 .NET 6 + Vue3 + SQLite 技术栈 +> 版本:v1.6 +> 日期:2026-05-19 +> 基于原项目(Java + Spring Boot + Vue3)重构为 .NET 8 + Vue3 + SQLite 技术栈 --- @@ -21,11 +21,11 @@ ### 1.2 技术栈对比 -| 层次 | 原版(Java) | 重构版(.NET 6) | +| 层次 | 原版(Java) | 重构版(.NET 8) | |------|------------|----------------| -| 后端框架 | Spring Boot 2.7 | ASP.NET Core 6 (Web API) | -| 数据库 | MySQL | SQLite | -| ORM | MyBatis | Entity Framework Core 6 | +| 后端框架 | Spring Boot 2.7 | ASP.NET Core 8 (Web API) | +| 数据库 | MySQL | SQLite / MySQL / PostgreSQL / SQLServer | +| ORM | MyBatis | Entity Framework Core 8 | | 前端框架 | Vue 3 | Vue 3 (Composition API) | | 前端语言 | TypeScript | TypeScript | | UI 组件库 | Element Plus | Element Plus | @@ -100,7 +100,8 @@ Controllers/ │ ├── UserController # 用户登录 │ └── DataTypeInfoController # 数据类型列表 ├── Open/ -│ └── FlowOpenController # 开放接口(触发流程) +│ ├── FlowOpenController # 开放接口(触发流程 + 服务别名) +│ └── WebhookTriggerController # Webhook 触发 └── Example/ ├── UserExampleController # 示例用户接口 ├── GoodsExampleController # 示例商品接口 @@ -214,6 +215,15 @@ console-ui/ | 模板市场 | /market/template | 流程模板市场 | | Token 管理 | /system/token | 访问令牌管理 | | 数据源管理 | /system/datasource | MySQL 数据源配置 | +| 市场 | /market | 五类条目市场(接口/流程/模型助手/Skill/报表)+ 发现/收藏/下载/分享 | +| 模型助手 | /ai/assistant | 自定义模型助手管理 + 流程/接口/报表智能编排 | +| 大模型设置 | /system/ai-provider | 模型供应商(多供应商/能力绑定/模型拉取测试) | +| 知识库 | /knowledge | 知识库管理(文档解析切片/检索/清洗/匹配记录) | +| Skill 管理 | /system/skill | 技能 CRUD / 导入导出 | +| Redis 配置 | /system/redis | Redis 多实例配置与测试 | +| 报表管理 | /report | 数据视图 + 报表设计器 + 报表查询 | + +> 注:报表/知识库/市场/模型助手模块为 v1.8 新增,详见图 4.2 对应的菜单路由配置(`router/index.ts`)。 ### 4.3 核心组件 @@ -251,6 +261,16 @@ console-ui/ | t_flow_version | 流程版本表 | | t_token | 访问令牌表 | | t_data_source | 数据源表 | +| t_ai_provider | AI 模型供应商表(baseUrl/apiKey/models/capabilities 能力绑定) | +| t_ai_assistant | AI 自定义助手表(系统提示词/入出参/快速提示词/图标) | +| t_ai_conversation | AI 对话会话表(多轮消息/输出/历史) | +| t_skill | 技能表(分组/内容/启停,AI 节点拼入提示词) | +| t_kb / t_kb_document / t_kb_chunk / t_kb_match_log | 知识库 4 表(切片/向量/匹配记录) | +| t_redis_config | Redis 多实例配置表 | +| t_market_item | 市场条目表(平台级共享,含官方 ID/图标/作者/版本) | +| t_market_favorite | 市场收藏表(租户级) | +| t_data_view / t_report | 数据视图 / 报表表 | +| t_alert_rule / t_alert_record | 告警规则 / 告警记录表 | ### 5.2 ER 关系 @@ -325,8 +345,26 @@ t_flow_definition ──(部署)──> t_flow_info ──< t_flow_version |---------|------| | START | 开始节点,流程入口 | | END | 结束节点,流程出口 | -| METHOD | 方法节点,调用 HTTP API 接口 | +| METHOD | 方法节点,调用 HTTP API / WebService 接口 | | CONDITION | 条件节点,多分支判断 | +| ASSIGN | 赋值节点,常量/变量/入参/静态→赋值给变量/出参/静态/子对象 | +| CODE | 代码节点,执行 JavaScript 脚本 | +| MYSQL/DB | 数据库节点,执行 SQL 查询/更新 | +| MERGE | 聚合节点,多分支汇聚 | +| SUB_FLOW | 子流程节点,递归调用其他已发布流程 | +| LOOP | 循环节点,遍历数组执行子流程 | +| DELAY | 延迟节点,等待指定时间 | +| PARALLEL | 并行节点,多分支并发执行 | +| NOTIFY | 通知节点,Webhook/邮件通知 | +| TRANSFORM | 模板转换节点,${var|pipe} 语法替换占位符 | +| AI | 大模型节点:供应商/模型/图片输入/模型参数(深度思考/温度/最大输出/随机种子)+ 函数调用工具(接口/流程,最多 4 轮) | +| FILE_PARSE | 文件解析节点:json/csv/xml/text/图片(视觉模型识别) | +| EXCEL_READ | Excel 读取节点 | +| FILE_WRITE | 文件写入节点 | +| REDIS_GET | Redis 查询节点(多实例/变量模板/JSON 解析) | +| REDIS_SET | Redis 设置节点(过期秒数) | +| KB_SEARCH | 知识库检索节点(RAG 上下文) | +| DATA_EXTRACT | 数据提取节点(json/code/keyword/between/length 五种提取类型) | ### 6.3 变量机制 @@ -532,4 +570,71 @@ JuggleNet6/ | v1.2 | 流程调试 + 部署 + 触发 + 开放接口 | P0 | | v1.3 | Token 管理 + 数据源管理 | P1 | | v1.4 | 套件/模板市场(只读展示) | P2 | -| v2.0 | 多租户支持、权限系统 | P3 | +| v1.5-v1.7 | 子流程/监控/静态变量/WSDL/TRANSFORM/报表/AI 助手 | ✅ 已完成 | +| v1.8 | AI 节点增强与工具调用、知识库、Redis 多实例、Skill 管理、市场生态(发现/收藏/分享 GitHub PR)、模型能力绑定 | ✅ 已完成(2026-09) | +| v1.9 | 官方市场运营(GitHub 仓库 index.json 维护)、更多节点类型、AI 多模态扩展 | ⏳ 待规划 | + +--- + +## 十二、AI 能力与开放生态架构(v1.8 新增) + +### 12.1 AI 大模型能力架构 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ 前端 AI 模块(Vue3) │ +│ 大模型设置(供应商/模型/能力绑定) 模型助手管理 流程/接口/报表助手 │ +└──────────────┬───────────────────────────────────────────────────┘ + │ /api/ai/*(JWT) +┌──────────────▼───────────────────────────────────────────────────┐ +│ AiService(Application 层) │ +│ ChatRequestAsync(统一入口: 图片/模型参数/tools/多轮历史) │ +│ ResolveConfigAsync(供应商解析) GenerateFlow/Apis/Report(编排生成) │ +│ Conversation(多轮会话) ExtractJson(代码块剥离) │ +└──────────────┬───────────────────────────────────────────────────┘ + │ Func 回调注入(引擎与配置解耦) +┌──────────────▼───────────────────────────────────────────────────┐ +│ FlowEngine 回调注入体系 │ +│ aiChatFunc → AiChatRequest → AiChatResult(Text+ToolCalls) │ +│ toolsResolver → 接口/流程 → OpenAI tools 定义(含参数说明) │ +│ toolRunner → api:xxx HTTP 调用 / flow:xxx 递归子引擎执行 │ +│ skillResolver → 技能 ID → 提示词拼接 │ +│ kbSearchFunc → 知识库检索上下文 │ +│ redisConnStrs → Redis 多实例连接串(0=默认实例) │ +└───────────────────────────────────────────────────────────────────┘ +``` + +**关键设计**: +1. **能力绑定(Capabilities)**:供应商存 `capabilities` JSON(skills/apis/flows/tools),前端按所选供应商过滤 AI 节点技能下拉。 +2. **函数调用(Tool Calling)**:AI 节点勾选接口/流程 → 执行时经 `toolsResolver` 生成 OpenAI 函数定义 → 模型返回 `tool_calls` → `toolRunner` 执行(接口走 HTTP,流程走递归 FlowEngine)→ 结果以 `role=tool` 消息回传,最多 4 轮;`AiChatRequest` 携带 `History`(多轮 tool_calls 消息)与 `ToolsJson`。 +3. **模型参数**:深度思考(enable_thinking)、温度、max_tokens、seed 经统一请求入口透传 OpenAI 兼容接口。 + +### 12.2 知识库检索架构 + +- **存储**:`t_kb`(库配置:切片大小/重叠/检索类型/向量模型)→ `t_kb_document`(文档)→ `t_kb_chunk`(切片,`vector_json` 存向量)。 +- **检索**:文本模式(SQLite LIKE 关键词打分)与向量模式(调用供应商 embeddings 接口 → 余弦相似度 TopK);`t_kb_match_log` 记录每次检索。 +- **流程接入**:`KB_SEARCH` 节点经 `kbSearchFunc` 回调获取 TopK 上下文文本,供 AI 节点 RAG 问答。 + +### 12.3 市场生态架构(发现 / 收藏 / 分享) + +``` +GitHub 官方仓库 pythonHuang/APIWorkflowCanvasDesignNet + └── market/ + ├── index.json # 条目索引(id/type/name/author/version/file) + ├── flow/1.json ... # 各类型 {id}.json 条目文件 + +① 发现:GET /api/market/discover → 拉取 index.json + 各条目文件 → 本地 market/ 目录 +② 导入:POST /api/market/import-file → 按 (market_item_id, item_type) upsert t_market_item +③ 应用:POST /api/market/import/{id} → 按类型创建业务实体(按名称/code 去重) +④ 收藏:t_market_favorite(租户级)→ 列表过滤 favorite=1 +⑤ 分享:POST /api/market/generate-share-file → 本地生成 {id}.json + 更新 index.json + (同名条目复用原 id)→ 前端 GitHub API:fork → 分支 → 写条目文件 + → 合并官方最新 index.json → Pull Request(管理员审核合并) +``` + +**多租户**:市场条目 `TenantId=null`(平台级共享,宽松隔离);收藏 `TenantId=当前租户`(严格隔离);导入产生的业务实体归属导入方租户。 + +### 12.4 Redis 多实例架构 + +- `t_redis_config` 存多实例(0=默认实例),`RedisConnectionPool` 按连接串缓存 `ConnectionMultiplexer`。 +- 引擎经 `redisConnStrs` 字典(实例 ID → 连接串)注入;节点 `redisId` 解析实例,未配置时抛明确错误。 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..16de0b3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,113 @@ +# CLAUDE.md + +本文件为 Claude Code (claude.ai/code) 在此仓库中工作时提供指引。 + +## 构建与运行命令 + +```bash +# 后端 (ASP.NET Core 8) — 运行在 http://localhost:9127 +cd Juggle.Api && dotnet run + +# 还原并构建整个解决方案 +dotnet restore Juggle.sln && dotnet build Juggle.sln + +# 前端 (Vue3 + Vite) — 运行在 http://localhost:5173 +cd JuggleNet6.Frontend && npm install && npm run dev + +# 前端生产构建 (输出 → Juggle.Api/wwwroot/) +cd JuggleNet6.Frontend && npm run build + +# Docker +docker-compose up -d # 完整部署 +docker build -t pythonhuang/juggle-net8:v1.0 . # 多阶段构建 + +# Windows 一键启动脚本 (交互式菜单) +启动Juggle.bat +``` + +默认账号: `juggle` / `juggle` + +## 架构(DDD 四层) + +``` +Juggle.Api/ # 表示层 — Controllers + Program.cs +Juggle.Application/ # 应用层 — DTO (Request/Response)、FlowExecutionService、JwtService +Juggle.Domain/ # 领域层 — 实体、流程引擎 (FlowEngine + 13个节点执行器) +Juggle.Infrastructure/ # 基础设施层 — JuggleDbContext、JsonHelper、Md5Helper +JuggleNet6.Frontend/ # Vue 3 + Element Plus + @vue-flow/core + Monaco Editor +``` + +**依赖方向**: `Api → Application → Domain ← Infrastructure`(Api 引用所有三个项目;Application 和 Domain 不引用 Infrastructure)。 + +项目引用关系: `Juggle.Api.csproj` 引用其他三个项目;`Juggle.Infrastructure.csproj` 和 `Juggle.Application.csproj` 都引用 `Juggle.Domain.csproj`。 + +## Controller 模式 + +Controller 直接注入 `JuggleDbContext`——CRUD 操作**不走 Service 层**。只有复杂编排逻辑(流程执行、数据源连接、JWT 签发)才抽取到 `Juggle.Application/Services/` 下的 Service 中。所有 Controller 返回 `ApiResult`(code/message/data)或 `PageResult`(code/message/total/data)。 + +## 流程引擎(系统核心) + +流程引擎(`Juggle.Domain/Engine/FlowEngine.cs`)执行 JSON 格式的节点图。以 **Scoped** 生命周期注册在 DI 中,接收 `IHttpClientFactory` + 可选的数据源/静态变量字典。 + +**13 种节点类型**: START、END、METHOD(HTTP调用)、CONDITION(分支判断)、MERGE(分支汇聚)、ASSIGN(赋值)、CODE(JS脚本)、MYSQL/DB(SQL执行)、SUB_FLOW(递归调用子流程)、LOOP(循环)、DELAY(延迟)、PARALLEL(并行)、NOTIFY(通知)。 + +**变量命名约定**(理解数据流转的关键): + +- `input_*` — 流程入参(来自调用方) +- `output_*` — 流程出参(返回给调用方) +- `env_*` — 内部中间变量(流程内使用) +- `_loop_item`、`_loop_index`、`_loop_total`、`_loop_results` — 循环内置变量 + +**METHOD 节点数据流转**: `InputFillRules` 在调用前将变量映射到 API 入参;`OutputFillRules` 在调用后将 API 响应映射回变量。 + +`FlowExecutionService`(`Juggle.Application/Services/Flow/`)是主要的编排器,负责加载数据源、快照静态变量、运行引擎、持久化日志、回写静态变量变更。 + +## 多租户数据隔离 + +`ICurrentTenantProvider`(定义在 Infrastructure 层,在 Api 层由 `HttpContextTenantProvider` 实现)从 JWT Claims 中提取租户 ID。`JuggleDbContext` 通过**全局查询过滤器**(`HasQueryFilter`)使用它: + +- **严格隔离**(`e.TenantId == CurrentTenantId`):流程、数据源、Token、静态变量等 +- **宽松隔离**(`e.TenantId == null || e.TenantId == CurrentTenantId`):套件、API、参数、角色——TenantId 为 null 的记录为"全局"数据,对所有租户可见 + +`ITenantAccessor`(与 `ICurrentTenantProvider` 不同)是应用层的租户上下文,供 Controller 使用;`Program.cs` 中的中间件从 JWT Claims 加载它(`/open/` 和 `/api/health` 路径跳过)。 + +## 数据库配置 + +系统数据库通过 `DB_TYPE` 环境变量(或 appsettings 中的 `Database:Type`)选择。支持: `sqlite`(默认)、`mysql`、`postgresql`、`sqlserver`。参见 `Program.cs:39-82` 的 `ConfigureDbContext` 分支逻辑。 + +业务数据源(供 DB/MySQL 节点使用)通过界面在"系统设置 → 数据源"中配置——支持 6 种类型: SQLite、MySQL、PostgreSQL、SQLServer、Oracle、达梦。 + +## API URL 规范 + + +| 前缀 | 认证方式 | 用途 | +| ------------- | --------------------- | --------------- | +| `/api/` | JWT Bearer | 管理控制台 | +| `/open/` | X-Access-Token 请求头 | 外部流程触发 | +| `/api/health` | 无 | Docker 健康检查 | + +## 关键环境变量 + +- `DB_TYPE` — 系统数据库类型 (sqlite/mysql/postgresql/sqlserver) +- `DB_CONNECTION_STRING` — 完整连接字符串(覆盖各独立参数) +- `DB_PATH` — SQLite 文件路径 +- `DB_HOST`、`DB_PORT`、`DB_NAME`、`DB_USER`、`DB_PASS` — 各独立数据库参数 +- `Jwt__Key` — JWT 签名密钥(≥32 字符) +- `ASPNETCORE_URLS` — 监听地址(默认 `http://+:9127`) + +## 编码约定 + +- **C# DTO**: 使用 `record` 类型 +- **EF Core**: Code First + `EnsureCreated()`(非 Migration);列名通过 `HasColumnName` 映射为 snake_case +- **JSON**: camelCase 输出,中文不转义 +- **日期**: 以 ISO 8601 字符串存储在 TEXT 列中 +- **软删除**: 所有实体使用 `deleted` 列(0/1) +- **前端**: ` + + diff --git a/JuggleNet6.Frontend/src/components/MarketPublishDialog.vue b/JuggleNet6.Frontend/src/components/MarketPublishDialog.vue new file mode 100644 index 0000000..5fb4ad6 --- /dev/null +++ b/JuggleNet6.Frontend/src/components/MarketPublishDialog.vue @@ -0,0 +1,75 @@ + + + diff --git a/JuggleNet6.Frontend/src/components/MarketShareDialog.vue b/JuggleNet6.Frontend/src/components/MarketShareDialog.vue new file mode 100644 index 0000000..b1dfb92 --- /dev/null +++ b/JuggleNet6.Frontend/src/components/MarketShareDialog.vue @@ -0,0 +1,222 @@ + + + diff --git a/JuggleNet6.Frontend/src/components/MdContent.vue b/JuggleNet6.Frontend/src/components/MdContent.vue new file mode 100644 index 0000000..799f0ba --- /dev/null +++ b/JuggleNet6.Frontend/src/components/MdContent.vue @@ -0,0 +1,101 @@ + + + + + diff --git a/JuggleNet6.Frontend/src/components/ReportParams.vue b/JuggleNet6.Frontend/src/components/ReportParams.vue new file mode 100644 index 0000000..5f7222e --- /dev/null +++ b/JuggleNet6.Frontend/src/components/ReportParams.vue @@ -0,0 +1,81 @@ + + + diff --git a/JuggleNet6.Frontend/src/components/SqlTestDialog.vue b/JuggleNet6.Frontend/src/components/SqlTestDialog.vue new file mode 100644 index 0000000..7f86090 --- /dev/null +++ b/JuggleNet6.Frontend/src/components/SqlTestDialog.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/JuggleNet6.Frontend/src/router/index.ts b/JuggleNet6.Frontend/src/router/index.ts index e7834f6..93c62df 100644 --- a/JuggleNet6.Frontend/src/router/index.ts +++ b/JuggleNet6.Frontend/src/router/index.ts @@ -12,6 +12,9 @@ const routes = [ children: [ { path: 'flow/define', component: () => import('../views/flow/FlowDefinitionList.vue') }, { path: 'flow/dashboard', component: () => import('../views/flow/Dashboard.vue') }, + { path: 'monitor/topology', component: () => import('../views/monitor/ApiTopology.vue') }, + { path: 'monitor/alert-rule', component: () => import('../views/monitor/AlertRule.vue') }, + { path: 'monitor/alert-record', component: () => import('../views/monitor/AlertRecord.vue') }, { path: 'flow/list', component: () => import('../views/flow/FlowInfoList.vue') }, { path: 'flow/version/:flowKey', component: () => import('../views/flow/FlowVersionList.vue') }, { path: 'suite/list', component: () => import('../views/suite/SuiteList.vue') }, @@ -32,7 +35,22 @@ const routes = [ { path: 'system/audit-log', component: () => import('../views/system/AuditLog.vue') }, { path: 'flow/log', component: () => import('../views/flow/FlowLog.vue') }, { path: 'flow/async-result', component: () => import('../views/flow/AsyncFlowResult.vue') }, - { path: 'flow/testcase', component: () => import('../views/flow/FlowTestCase.vue') } + { path: 'flow/testcase', component: () => import('../views/flow/FlowTestCase.vue') }, + { path: 'report/dataview', component: () => import('../views/report/DataViewList.vue') }, + { path: 'report/design', component: () => import('../views/report/ReportList.vue') }, + { path: 'report/designer/:id', component: () => import('../views/report/ReportDesigner.vue') }, + { path: 'report/view/:id', component: () => import('../views/report/ReportView.vue') }, + { path: 'system/ai-provider', component: () => import('../views/system/AiProviderList.vue') }, + { path: 'system/redis', component: () => import('../views/system/RedisConfig.vue') }, + { path: 'system/skills', component: () => import('../views/system/SkillList.vue') }, + { path: 'market', component: () => import('../views/market/MarketList.vue') }, + { path: 'kb/list', component: () => import('../views/kb/KnowledgeList.vue') }, + { path: 'kb/detail/:id', component: () => import('../views/kb/KnowledgeDetail.vue') }, + { path: 'ai/flow-assistant', component: () => import('../views/ai/FlowAssistant.vue') }, + { path: 'ai/api-assistant', component: () => import('../views/ai/ApiAssistant.vue') }, + { path: 'ai/assistants', component: () => import('../views/ai/AiAssistantList.vue') }, + { path: 'ai/assistant/:id', component: () => import('../views/ai/AssistantRun.vue') }, + { path: 'ai/report-assistant', component: () => import('../views/ai/ReportAssistant.vue') } ] }, { diff --git a/JuggleNet6.Frontend/src/utils/dbAssist.ts b/JuggleNet6.Frontend/src/utils/dbAssist.ts new file mode 100644 index 0000000..fafc560 --- /dev/null +++ b/JuggleNet6.Frontend/src/utils/dbAssist.ts @@ -0,0 +1,33 @@ +import request from './request' + +/** + * 生成 SQL 字段中文对照(多行文本:字段=中文注释 一行一条)。 + * 单表查询(无 JOIN)→ 取表字段元数据(含中文注释,无注释则 字段=字段); + * 其它情况 → 执行 SQL 按实际查询列生成 字段=字段(有注释用注释)。 + */ +export async function generateColumnMapping(opts: { + dataSourceId: string | number + dataSourceName: string + sql: string + params?: Record +}): Promise { + const sql = (opts.sql || '').trim() + if (!sql) throw new Error('SQL 为空') + + // 单表查询:直接取表字段元数据(含中文注释) + const tableMatch = sql.match(/\bfrom\s+([A-Za-z0-9_\.]+)/i) + const hasJoin = /\bjoin\b/i.test(sql) + if (tableMatch && !hasJoin) { + const res: any = await request.post('/system/datasource/columns', { + dataSourceName: opts.dataSourceName, tableName: tableMatch[1] + }) + const lines = (res.data || []).map((c: any) => `${c.name}=${c.comment || c.name}`) + if (lines.length) return lines + } + + // 其它情况:执行 SQL 取实际查询列 + const res2: any = await request.post('/report/dataview/test-sql', { + dataSourceId: opts.dataSourceId, sql, params: opts.params || {} + }) + return (res2.data?.columns || []).map((c: any) => `${c.name}=${c.comment || c.name}`) +} diff --git a/JuggleNet6.Frontend/src/utils/reportParams.ts b/JuggleNet6.Frontend/src/utils/reportParams.ts new file mode 100644 index 0000000..2ac1216 --- /dev/null +++ b/JuggleNet6.Frontend/src/utils/reportParams.ts @@ -0,0 +1,47 @@ +/** + * 报表查询参数工具: + * - initParamValues:默认值初始化(URL 查询参数优先)并按类型转换 + * - buildParamPayload:查询载荷构建(空值不传;多选/筛选组以逗号拼接) + */ + +/** 初始化查询参数值:默认值 → URL 查询参数覆盖 → 按类型转换 */ +export function initParamValues(params: any[], urlQuery?: Record): Record { + const values: Record = {} + for (const p of params || []) { + let v: any = p.default + if (urlQuery && urlQuery[p.name] !== undefined && urlQuery[p.name] !== '') { + v = urlQuery[p.name] + } + if (p.type === 'switch') v = v === true || v === 'true' || v === '1' + else if (p.type === 'number') v = (v === '' || v === undefined || v === null) ? undefined : Number(v) + else if (p.type === 'checkgroup') { + // 筛选组/多选:支持数组或逗号分隔字符串 + v = Array.isArray(v) ? v : String(v ?? '').split(',').map((s: string) => s.trim()).filter(Boolean) + } else if (p.type === 'select' && p.multiple) { + v = Array.isArray(v) ? v : (v ? String(v).split(',').map((s: string) => s.trim()).filter(Boolean) : []) + } + values[p.name] = v ?? '' + } + return values +} + +/** 构建查询载荷:空值跳过;筛选组/多选以逗号拼接字符串传给 @参数名 */ +export function buildParamPayload(params: any[], values: Record): Record { + const payload: Record = {} + for (const p of params || []) { + let v = values[p.name] + if (v === undefined || v === null || v === '') continue + if (Array.isArray(v) && v.length === 0) continue + if (p.type === 'number') v = Number(v) + if (p.type === 'switch') v = v === true + if (Array.isArray(v)) v = v.join(',') + payload[p.name] = v + } + return payload +} + +/** 固定选项解析:支持逗号/换行分隔字符串或数组 */ +export function parseOptions(p: any): string[] { + if (Array.isArray(p.options)) return p.options + return String(p.options || '').split(/[,,\n]/).map((s: string) => s.trim()).filter(Boolean) +} diff --git a/JuggleNet6.Frontend/src/utils/request.ts b/JuggleNet6.Frontend/src/utils/request.ts index 89dfe96..3bbd5dc 100644 --- a/JuggleNet6.Frontend/src/utils/request.ts +++ b/JuggleNet6.Frontend/src/utils/request.ts @@ -20,6 +20,8 @@ request.interceptors.request.use((config) => { request.interceptors.response.use( (response) => { const data = response.data + // blob 下载(文件导出)直接放行 + if (data instanceof Blob) return response if (data.code === 200) { return data } else if (data.code === 401) { diff --git a/JuggleNet6.Frontend/src/views/Layout.vue b/JuggleNet6.Frontend/src/views/Layout.vue index 9b4cd1b..ae47cb1 100644 --- a/JuggleNet6.Frontend/src/views/Layout.vue +++ b/JuggleNet6.Frontend/src/views/Layout.vue @@ -1,53 +1,108 @@ + + diff --git a/JuggleNet6.Frontend/src/views/ai/ApiAssistant.vue b/JuggleNet6.Frontend/src/views/ai/ApiAssistant.vue new file mode 100644 index 0000000..c3251e5 --- /dev/null +++ b/JuggleNet6.Frontend/src/views/ai/ApiAssistant.vue @@ -0,0 +1,179 @@ + + + + + diff --git a/JuggleNet6.Frontend/src/views/ai/AssistantRun.vue b/JuggleNet6.Frontend/src/views/ai/AssistantRun.vue new file mode 100644 index 0000000..66bc13a --- /dev/null +++ b/JuggleNet6.Frontend/src/views/ai/AssistantRun.vue @@ -0,0 +1,353 @@ + + + + + diff --git a/JuggleNet6.Frontend/src/views/ai/FlowAssistant.vue b/JuggleNet6.Frontend/src/views/ai/FlowAssistant.vue new file mode 100644 index 0000000..ca41b02 --- /dev/null +++ b/JuggleNet6.Frontend/src/views/ai/FlowAssistant.vue @@ -0,0 +1,225 @@ + + + + + diff --git a/JuggleNet6.Frontend/src/views/ai/ReportAssistant.vue b/JuggleNet6.Frontend/src/views/ai/ReportAssistant.vue new file mode 100644 index 0000000..8208ca8 --- /dev/null +++ b/JuggleNet6.Frontend/src/views/ai/ReportAssistant.vue @@ -0,0 +1,207 @@ + + + + + diff --git a/JuggleNet6.Frontend/src/views/flow/FlowDefinitionList.vue b/JuggleNet6.Frontend/src/views/flow/FlowDefinitionList.vue index 368ff1a..976723d 100644 --- a/JuggleNet6.Frontend/src/views/flow/FlowDefinitionList.vue +++ b/JuggleNet6.Frontend/src/views/flow/FlowDefinitionList.vue @@ -58,13 +58,18 @@ - + @@ -77,7 +82,7 @@ - + @@ -88,6 +93,12 @@ 异步 + + +
+ 设置后可通过 GET/POST /open/services/{{ form.serviceAlias || '别名' }} 触发最新版本 +
+
@@ -102,6 +113,16 @@ 确认
+ + + + + + @@ -112,6 +133,37 @@ import { ElMessage, ElMessageBox } from 'element-plus' import request from '../../utils/request' import { Document, Packer, Paragraph, Table, TableRow, TableCell, WidthType, HeadingLevel, AlignmentType, BorderStyle } from 'docx' import { saveAs } from 'file-saver' +import MarketPublishDialog from '../../components/MarketPublishDialog.vue' +import MarketShareDialog from '../../components/MarketShareDialog.vue' + +// 发布到市场 +const publishVisible = ref(false) +const publishForm = ref({ itemName: '', description: '', groupName: '', contentJson: '{}' }) +function openPublish(row: any) { + publishForm.value = { + itemName: row.flowName || '', + description: row.flowDesc || '', + groupName: row.groupName || '', + contentJson: JSON.stringify({ + flowName: row.flowName, flowDesc: row.flowDesc, groupName: row.groupName, flowContent: row.flowContent || '[]' + }) + } + publishVisible.value = true +} + +// 分享到官方市场(GitHub PR) +const shareVisible = ref(false) +const shareForm = ref({ itemName: '', description: '', contentJson: '{}' }) +function openShare(row: any) { + shareForm.value = { + itemName: row.flowName || '', + description: row.flowDesc || '', + contentJson: JSON.stringify({ + flowName: row.flowName, flowDesc: row.flowDesc, groupName: row.groupName, flowContent: row.flowContent || '[]' + }) + } + shareVisible.value = true +} const router = useRouter() const loading = ref(false) @@ -124,7 +176,7 @@ const dialogVisible = ref(false) const isEdit = ref(false) const formRef = ref() const importFileRef = ref() -const form = reactive({ id: 0, flowName: '', flowType: 'sync', flowDesc: '', groupName: '' }) +const form = reactive({ id: 0, flowName: '', flowType: 'sync', flowDesc: '', groupName: '', serviceAlias: '' }) const rules = { flowName: [{ required: true, message: '请输入流程名称', trigger: 'blur' }] } onMounted(() => { loadData(); loadGroups() }) @@ -156,13 +208,13 @@ function reset() { function openAdd() { isEdit.value = false - Object.assign(form, { id: 0, flowName: '', flowType: 'sync', flowDesc: '', groupName: '' }) + Object.assign(form, { id: 0, flowName: '', flowType: 'sync', flowDesc: '', groupName: '', serviceAlias: '' }) dialogVisible.value = true } function openEdit(row: any) { isEdit.value = true - Object.assign(form, { id: row.id, flowName: row.flowName, flowType: row.flowType, flowDesc: row.flowDesc, groupName: row.groupName || '' }) + Object.assign(form, { id: row.id, flowName: row.flowName, flowType: row.flowType, flowDesc: row.flowDesc, groupName: row.groupName || '', serviceAlias: row.serviceAlias || '' }) dialogVisible.value = true } @@ -186,6 +238,11 @@ async function doClone(row: any) { loadData() } +function openServiceWsdl(row: any) { + const baseUrl = window.location.origin + window.open(`${baseUrl}/open/services/${row.serviceAlias}/wsdl`, '_blank') +} + async function doDelete(row: any) { await ElMessageBox.confirm(`确认删除流程「${row.flowName}」?`, '提示', { type: 'warning' }) await request.delete(`/flow/definition/delete/${row.id}`) diff --git a/JuggleNet6.Frontend/src/views/flow/FlowDesign.vue b/JuggleNet6.Frontend/src/views/flow/FlowDesign.vue index 385912b..f6dc40c 100644 --- a/JuggleNet6.Frontend/src/views/flow/FlowDesign.vue +++ b/JuggleNet6.Frontend/src/views/flow/FlowDesign.vue @@ -12,6 +12,7 @@ 自动布局 + AI 生成 流程参数 变量 调试 @@ -117,7 +118,7 @@ -
+
连线属性 @@ -159,6 +160,7 @@ @@ -174,6 +176,7 @@ + + + diff --git a/JuggleNet6.Frontend/src/views/suite/SuiteList.vue b/JuggleNet6.Frontend/src/views/suite/SuiteList.vue index c26733c..d074dfb 100644 --- a/JuggleNet6.Frontend/src/views/suite/SuiteList.vue +++ b/JuggleNet6.Frontend/src/views/suite/SuiteList.vue @@ -32,10 +32,12 @@ - + @@ -65,6 +67,16 @@ 确认 + + + + + +
@@ -73,6 +85,50 @@ import { ref, reactive, onMounted } from 'vue' import { useRouter } from 'vue-router' import { ElMessage, ElMessageBox } from 'element-plus' import request from '../../utils/request' +import MarketPublishDialog from '../../components/MarketPublishDialog.vue' +import MarketShareDialog from '../../components/MarketShareDialog.vue' + +// 发布到市场(套件及其全部接口) +const publishVisible = ref(false) +const publishForm = ref({ itemName: '', description: '', groupName: '', contentJson: '{}' }) + +/** 组装套件内容 JSON(套件 + 全部接口) */ +async function buildSuiteContentJson(row: any) { + const apisRes: any = await request.post('/suite/api/list', { suiteCode: row.suiteCode }) + const apis = (apisRes.data || []).map((a: any) => ({ + suiteCode: a.suiteCode, methodCode: a.methodCode, methodName: a.methodName, + methodDesc: a.methodDesc, url: a.url, requestType: a.requestType || 'POST' + })) + return JSON.stringify({ + suites: [{ suiteCode: row.suiteCode, suiteName: row.suiteName, suiteDesc: row.suiteDesc }], apis + }) +} + +async function openPublish(row: any) { + try { + publishForm.value = { + itemName: row.suiteName || row.suiteCode || '', + description: row.suiteDesc || '', + groupName: '', + contentJson: await buildSuiteContentJson(row) + } + publishVisible.value = true + } catch { /* 拦截器已提示 */ } +} + +// 分享到官方市场(GitHub PR) +const shareVisible = ref(false) +const shareForm = ref({ itemName: '', description: '', contentJson: '{}' }) +async function openShare(row: any) { + try { + shareForm.value = { + itemName: row.suiteName || row.suiteCode || '', + description: row.suiteDesc || '', + contentJson: await buildSuiteContentJson(row) + } + shareVisible.value = true + } catch { /* 拦截器已提示 */ } +} import { Document, Packer, Paragraph, Table, TableRow, TableCell, WidthType, HeadingLevel, AlignmentType, BorderStyle } from 'docx' import { saveAs } from 'file-saver' diff --git a/JuggleNet6.Frontend/src/views/system/AiProviderList.vue b/JuggleNet6.Frontend/src/views/system/AiProviderList.vue new file mode 100644 index 0000000..8858224 --- /dev/null +++ b/JuggleNet6.Frontend/src/views/system/AiProviderList.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/JuggleNet6.Frontend/src/views/system/RedisConfig.vue b/JuggleNet6.Frontend/src/views/system/RedisConfig.vue new file mode 100644 index 0000000..e24f759 --- /dev/null +++ b/JuggleNet6.Frontend/src/views/system/RedisConfig.vue @@ -0,0 +1,114 @@ + + + + + diff --git a/JuggleNet6.Frontend/src/views/system/SkillList.vue b/JuggleNet6.Frontend/src/views/system/SkillList.vue new file mode 100644 index 0000000..7047b45 --- /dev/null +++ b/JuggleNet6.Frontend/src/views/system/SkillList.vue @@ -0,0 +1,249 @@ + + + + + diff --git a/MEMORY.md b/MEMORY.md new file mode 100644 index 0000000..7cd069f --- /dev/null +++ b/MEMORY.md @@ -0,0 +1,187 @@ +# Juggle接口编排Net6 - 项目长期记忆 + +## 项目概述 +将 Java/Spring Boot 的 Juggle 接口编排系统迁移到 .NET 8 + SQLite + Vue3。 + +## Git 仓库 +- **仓库地址**:`https://github.com/pythonHuang/JuggleNet6.git` +- **本地路径**:`d:\WorkBuddyMyWorkSpace\Juggle接口编排Net6\JuggleNet6\`(子目录独立 Git 仓库) +- **用户偏好**:每完成一个 Bug 修复或需求开发,立即单独 git commit + push GitHub(不攒多个) +- **.gitignore 已忽略**:`*.db / *.db-shm / *.db-wal / wwwroot/ / node_modules/ / dist/` + +## 技术栈 +- **后端**: ASP.NET Core 8, EF Core + SQLite, JWT认证, Swagger +- **前端**: Vue3 + Vite + Element Plus + Pinia + Vue Router +- **数据库**: SQLite (文件: juggle.db,位于后端运行目录) + +## 项目目录 +``` +d:\WorkBuddyMyWorkSpace\Juggle接口编排Net6\JuggleNet6\ +├── Juggle.Api\ ← API层(Controllers + Program.cs) +├── Juggle.Application\ ← 应用层(Services + Request/Response DTOs) +├── Juggle.Infrastructure\ ← 基础设施层(JuggleDbContext + JsonHelper + Md5Helper) +├── Juggle.Domain\ ← 领域层(Entities + FlowEngine + NodeExecutors) +└── JuggleNet6.Frontend\ ← Vue3 前端 +``` + +## 运行方式 +```powershell +# 启动后端(端口9127) +cd JuggleNet6\Juggle.Api && dotnet run + +# 构建前端并集成 +cd JuggleNet6\JuggleNet6.Frontend +npm run build +Copy-Item dist\* ..\Juggle.Api\wwwroot\ -Recurse -Force +``` + +## 关键URL +- 前端: http://localhost:9127/ +- Swagger: http://localhost:9127/swagger +- 默认账号: juggle / juggle + +## 重要接口路由 +| 功能 | 路由 | 方法 | +|------|------|------| +| 接口列表 | /api/suite/api/list | POST | +| 流程内容保存 | /api/flow/definition/save | PUT | +| 流程导出 | /api/flow/definition/export/{id} | GET | +| 流程导入 | /api/flow/definition/import | POST | +| 流程克隆 | /api/flow/definition/clone/{id} | POST | +| 数据源测试 | /api/system/datasource/test/{id} | POST | +| 系统配置 | /api/system/config/all | GET | +| 用户分页 | /api/user/page | POST | +| 测试用例 | /api/flow/testcase/run/{id} | POST | + +## 开放接口 +- **触发**:`GET/POST /open/flow/trigger/{key}` + Header: X-Access-Token +- **异步触发**:`POST /open/flow/triggerAsync/{key}` → 返回 `{logId}` +- **Webhook 触发**:`POST/GET /open/webhook/{webhookKey}` + 可选签名 + +## 节点执行器(13种) +START / END / METHOD / CONDITION / MERGE / ASSIGN / CODE / MYSQL(DB) / SUB_FLOW / LOOP / DELAY / PARALLEL / NOTIFY + +## DDD 四层架构 +``` +Juggle.Api(Controllers) + ↓ +Juggle.Application(FlowExecutionService + DataSourceService + JwtService) + ↓ +Juggle.Infrastructure(JuggleDbContext + JsonHelper + Md5Helper) + ↓ +Juggle.Domain(Entities + FlowEngine + NodeExecutors) +``` + +## Controllers 清单(Juggle.Api) +- Api/: ApiController, DataSourceController, FlowDefinitionController, FlowInfoController, + FlowLogController, FlowVersionController, FlowTestCaseController, ObjectController, + ParameterController, StaticVariableController, SuiteController, ScheduleTaskController, + SystemConfigController, TokenController, UserController, VariableInfoController, WebhookController +- Open/: FlowOpenController, WebhookTriggerController + +## 数据库表 +- t_user, t_flow_definition, t_flow_info, t_flow_version, t_flow_log, t_flow_node_log +- t_variable_info, t_static_variable, t_data_source, t_schedule_task +- t_webhook, t_token, t_token_permission, t_suite, t_api, t_parameter, t_object +- t_system_config, t_flow_test_case +- t_role, t_role_menu, t_tenant(需求26),t_audit_log(需求29) + +## 前端模块(完整列表) +- flow/: FlowDefinitionList, FlowDesign, FlowInfoList, FlowVersionList, FlowLog, AsyncFlowResult, Dashboard, FlowTestCase(新) +- suite/: SuiteList, ApiList, ApiDetail +- object/: ObjectList, ObjectAttrList +- system/: TokenList, DataSourceList, StaticVariable, ScheduleTask, WebhookList, UserManage(新), SystemConfig(新) + +## 侧边栏菜单(当前结构) +- 流程管理: 流程定义 / 监控仪表盘 / 流程列表 / 执行日志 / 测试用例 / 异步结果查询 +- 套件管理: 套件列表 +- 对象管理 +- 系统设置: Token管理 / 数据源管理 / 静态变量 / 定时任务 / Webhook管理 / 用户管理 / 角色管理 / 租户管理 / 系统配置 + +## 多租户数据隔离(需求30 - 2026-04-10) +- **BaseEntity** 统一加 `TenantId` 字段,所有业务实体自动继承,原有实体中重复定义的 TenantId 已清理 +- **JuggleDbContext**:新增 `ICurrentTenantProvider` 接口(定义在 Infrastructure),API 层的 `HttpContextTenantProvider` 实现(读 JWT Claims,RoleId=1超管返回null不过滤) +- **全局查询过滤器**:严格隔离(FlowDefinition/Log/TestCase/DataSource/StaticVar/ScheduleTask/Webhook/Token/Object/VariableInfo)+ 宽松隔离(Role/Suite/Api/Parameter,TenantId=null全局数据所有租户可见) +- **所有Controllers** 写入时设置 `TenantId = _tenant.TenantId`(FlowDefinition/DataSource/StaticVariable/Webhook/Token/ScheduleTask/Object/Suite + FlowExecutionService日志) +- **SQLite 补列**:所有 23 张表均已 ALTER TABLE 添加 `tenant_id INTEGER` 列(Python 脚本执行) +- **架构设计**:Infrastructure 不依赖 Web(无 Microsoft.AspNetCore.Http 引用),通过 `ICurrentTenantProvider` 接口解耦 +- 系统数据库:通过 `DB_TYPE` 环境变量切换 sqlite/sqlserver/mysql/postgresql +- 连接配置:`DB_CONNECTION_STRING` 或各数据库专属环境变量(DB_HOST/DB_PORT/DB_NAME/DB_USER/DB_PASS) +- EF Core 统一升级到 8.0.4(Infrastructure/Application/Domain 三层一致) +- JuggleDbContext 大文本字段已标注 `HasColumnType("text")` 确保跨数据库兼容 + +## 数据源类型(需求25 - 已支持6种) +- sqlite / mysql / postgresql / sqlserver / oracle / dm(达梦) +- 默认端口:SQLite=0, MySQL=3306, PostgreSQL=5432, SQLServer=1433, Oracle=1521, DM=5236 +- NuGet:Oracle.ManagedDataAccess.Core 23.6.0, DM.DmProvider 8.3.1 + +## test.html 登录机制(Bug修复) +- 新增 JWT 登录弹窗,登录态存储在 localStorage(与主应用共享) +- 列表请求自动携带 Authorization: Bearer {token} +- Access Token 输入框仅用于触发开放接口(X-Access-Token header) + +## 已实现的完整功能列表(25个需求) +| # | 功能 | Commit | +|---|------|--------| +| 1-5 | 流程设计器/节点/调试/日志 | 早期 | +| 6 | 异步触发+结果查询 | e46995c | +| 7 | Token权限控制 | 401f2dd | +| 8 | 流程/套件导入导出+Word文档 | 5488ae7/42f2d19 | +| 9 | 流程分组管理 | 59db7a1 | +| 10 | 节点超时+重试 | eb88924 | +| 11 | 定时任务调度 | 3d0ecbd | +| 12 | 监控仪表盘 | cae0dd5 | +| 13 | 接口Mock功能 | 3a2d7a9 | +| 14 | LOOP+DELAY节点 | 2db23fe | +| 15 | PARALLEL并行节点 | 7da02e5 | +| 16 | NOTIFY通知节点 | affc5ad | +| 17 | Webhook触发 | 7e0928d | +| 18 | 流程版本对比 | 669a58a | +| 19 | 流程克隆功能 | a5b07fd | +| 20 | 用户管理 | c69b413 | +| 21 | 系统配置中心 | 7e6de5b | +| 22 | 全局异常告警 | 6d8b716 | +| 23 | 流程测试用例 | 543bbab | +| 24 | Monaco Editor | 054268f | +| 25 | 数据源Oracle/达梦+系统多数据库+test.html登录 | 1bfccd8 | +| 26 | 角色管理 + 菜单权限(RBAC) | 169eb8f | +| 27 | 系统数据库配置文件支持(appsettings.json Database节) | 169eb8f | +| 28 | 多租户实现(TenantEntity + ITenantAccessor 中间件) | 169eb8f | +| 29 | 多租户权限增强(角色归属租户+菜单权限约束+用户编辑+审计日志) | 67acf0b | +| 30 | 完整多租户数据隔离(BaseEntity统一TenantId+DbContext全局过滤器+所有Controllers写入TenantId) | 4485fdc | + +## 全局告警机制(v2.0新增) +- 在 FlowExecutionService.RunAsync 末尾,非 debug 触发失败时自动调用 SendAlertAsync +- 从 t_system_config 读取 alert.enabled / alert.on.fail.enabled 配置决定是否告警 +- 支持 Webhook POST 和邮件 SMTP 两种告警通道 + +## Monaco Editor 集成 +- 组件: `src/components/MonacoEditor.vue` +- CDN: `https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs` +- 已集成: CODE节点(JS高亮)、MYSQL节点(SQL高亮) +- 自动补全: $var.getVariableValue / $var.setVariableValue / $static.* / JSON.* + +## 流程测试用例规范 +- 断言 JSON 格式:`{"变量名": "期望值"}` +- 批量执行:`POST /api/flow/testcase/runAll/{flowKey}` +- 执行结果含:status / summary / assertResults / outputs / errorMessage / costMs + +## Bug修复记录 +- **TokenPermission表名映射**:JuggleDbContext.cs 需添加 ToTable + 列名映射(2026-04-02) +- **PARALLEL执行器参数**:FlowNodeLog → NodeLogEntry 类型错误(2026-04-04) +- **alert.body event关键字**:C# 匿名对象不能用 event,改为 eventType(2026-04-04) +- **TryGetValue out var**:在 `if(TryGetValue(..., out var x) == true)` 模式外使用 var 需先初始化 +- **SQLite 数据库缺少新增列/表**:项目未用 EF Core Migrations,新增实体字段(ExpiredAt/MenuKeys)和新表(t_login_log/t_audit_log)需手动 ALTER/CREATE 到 juggle.db(2026-04-05) +- **⚠️ 重要**:后续新增实体或字段,务必同步手动更新 SQLite 数据库,否则运行时 500 错误 +- **LoginLogEntity TenantId 列名遗漏**:DbContext 中 AddTenantIdCol 统一注册时因注释误导跳过了 LoginLogEntity,导致登录 500(2026-04-10 修复) +- **规则**:每新增实体,必须在 AddTenantIdCol 列表中加一行,注释"已在block配置"的实体需要再次核查 + +## 编译/构建命令 +```powershell +# 后端 +Set-Location "...\Juggle.Api"; dotnet build + +# 前端 +Set-Location "...\JuggleNet6.Frontend" +(& "D:\Program Files\nodejsv20_12\npm.cmd" run build 2>&1) -join "`n" +``` diff --git a/README.Docker.md b/README.Docker.md index 9179bde..a7f267c 100644 --- a/README.Docker.md +++ b/README.Docker.md @@ -105,3 +105,19 @@ docker run -d \ -e DB_PATH=/data/juggle.db \ juggle-net8:latest ``` + +--- + +## 更新日志 + +### v1.8(最新) + +- 📊 **报表模块** — 数据视图 + 报表设计器 + 公式引擎(SUM/AVG/COUNT/IF 等) +- 📈 **监控模块** — API 拓扑图(健康检查/访问统计/状态颜色)+ 告警规则/记录 +- 🧮 **表达式引擎** — 条件/赋值节点支持算术 + - * / %、字符串拼接/切片/replace、toString 数字与日期格式化 +- 🗄️ **数据库节点 SQL 辅助** — 表/视图/存储过程浏览一键生成 SQL、单独测试 SQL(更改事务回滚) +- 🔀 **条件节点扩展** — && || 括号、双变量比较、子属性、数组 length/元素取值 +- 🔗 **接口直连访问** — `/open/api/{code}` + 访问别名 + 停用/启用开关 +- 🧩 **WSDL 解析增强** — generatedXSD / xsd:include/import 递归加载 / XSD 内容粘贴 + +> 镜像更新:重新 `docker compose up -d --build` 即可升级(SQLite 数据卷自动保留)。 diff --git a/README.md b/README.md index cf22af6..3e13479 100644 --- a/README.md +++ b/README.md @@ -1,215 +1,605 @@ -# Juggle 接口编排平台 (.NET 8 + Vue3) +
-> 图形化微服务接口编排低代码工具 —— 像积木一样灵活,像魔法一样强大 +# 🎪 Juggle 接口流程编排平台(支持AI自动生成流程) + +

+ Release + License + .NET 8 + Vue 3 +

+ +**中文** | [English](#english) + +
--- -## 项目简介 +## 📖 简介 + +Juggle 中文有"积木、魔法"之意,寓意像积木一样灵活,像魔法一样强大,满足灵活多变的业务需求,助力业务快速落地! + +Juggle 是一个**图形化微服务编排工具**,通过简单的流程编排,快速完成接口开发,大大提高开发效率。 + +### 🎨 流程编排预览 + +![流程编排](./images/flowdesign.png) + +### ✨ 核心能力 -**Juggle** 是一个可视化的接口编排平台,通过拖拽式流程设计器将多个已有的 HTTP API 接口编排为一个复合接口,直接供前端或业务系统调用,极大提升开发效率,无需重复编码。 -本项目为 Java/Spring Boot 原版的 **.NET 8 + SQLite + Vue3 重构版**,实现了完整的 DDD 四层架构。 +| 场景 | 说明 | +| ------------- | ----------------------------------------------- | +| 🧩 微服务编排 | 根据已有基础接口快速编排开发新接口 | +| 🤖 **AI 智能编排** | **对话式描述需求,大模型自动生成接口流程编排** | +| 🔗 系统集成 | 快速打通第三方系统平台,消除系统壁垒 | +| 📦 BFF 层 | 面向前端提供聚合/适配层(Backend for Frontend) | +| 🎨 定制开发 | 私有化标准功能定制,避免污染标准代码 | --- -## 核心功能 +## 🚀 快速开始 -| 功能模块 | 说明 | -|---------|------| -| 🎨 可视化流程设计器 | 拖拽节点、连线建立数据流、自动布局(拓扑排序)、MiniMap 缩略图 | -| 🔧 多种节点类型 | START / END / METHOD / CONDITION / ASSIGN / CODE / MYSQL / MERGE / **SUB_FLOW** | -| ▶️ 流程调试 | 在设计界面直接调试,节点高亮显示(成功绿/失败红)、查看输出结果和节点日志 | -| 📦 套件 & 接口管理 | 组织管理基础 HTTP API,支持导入/导出 JSON 分享移植 | -| 🗄️ 多数据库支持 | SQLite / MySQL / PostgreSQL / SQL Server | -| 📊 执行日志 | 流程执行主日志 + 节点明细日志(含变量快照时间轴) | -| 🔑 Token 管理 | 开放接口访问令牌管理 | -| 📐 全局静态变量 | 跨流程共享变量,支持读写与重置默认值 | -| 📤 导入/导出 | 流程定义和套件支持 JSON 导出/导入,方便分享移植 | -| 🔗 子流程编排 | SUB_FLOW 节点可调用已发布的其他流程,支持入参/出参变量映射 | -| 🔐 JWT 认证 | 控制台登录认证 | +### Docker 一键启动 + +```bash +docker run -d \ + --name juggle \ + -p 9127:9127 \ + -v juggle_data:/data \ + pythonhuang/juggle-net8:v1.0 +``` + +或使用 docker-compose: + +```bash +docker-compose up -d +``` + +- 访问地址:http://localhost:9127 +- 默认账号:`juggle` / `juggle` --- -## 技术栈 +## 🤖 AI 智能编排 + +通过自然语言对话,让大模型自动完成流程编排、接口接入与报表设计,无需手动操作。 + +### 一、大模型设置(模型供应商设置) + +系统设置 → 大模型设置,接入任意 **OpenAI 兼容接口**(DeepSeek / 通义千问 / Kimi / OpenAI / 智谱GLM / Ollama 等): + +- **供应商下拉可选可直接输入**:预置 DeepSeek、通义千问、Kimi、OpenAI、智谱GLM、Ollama,选择后自动填默认接口地址,也支持输入自定义供应商 +- **获取模型 / 配置测试**:填写 API Key 后一键验证密钥有效性(兼作配置测试),成功即拉取该供应商的可用模型列表 +- **默认模型**:从拉取的模型列表下拉选择(也可手动输入);**可用模型**:多选下拉(对话中可切换),保存为模型清单 +- **多供应商并存 + 启停开关**:任一助手对话时可在启用的供应商与模型中自由切换 + +### 二、模型助手管理(自定义模型助手) + +自定义智能助手,可配置: + +| 配置项 | 说明 | +|--------|------| +| 名称 / 描述 | 菜单显示名与用途说明 | +| 系统提示词 | 助手人设与任务要求(如"你是一名文案专家…") | +| 输入参数列表 | 运行页表单,类型支持文本/数字/日期/开关/下拉(下拉可配选项+默认值) | +| 输出参数列表 | 结束对话时要求模型按 JSON 返回并按参数分栏展示 | +| 辅助提问词按钮 | 运行页快捷按钮,点击即填入常用提问(换行追加可组合) | +| 启停 | 启用后自动出现在「模型助手」菜单 | + +运行页支持**多轮对话**:聊天气泡、每轮携带完整历史、回车发送;「结束对话」时模型基于完整对话生成最终 JSON 结果;「新对话」随时重开;「历史」抽屉查看全部会话(继续进行中对话 / 查看已结束结果 / 删除)。 + +### 三、流程智能编排助手 + +对话描述需求,AI 自动完成接口流程编排: + +1. 填写需求与流程名称,选择供应商/模型,点击「生成编排」 +2. AI 从平台已接入的接口清单中选择接口:自动映射入参(流程入参 input_xxx)、出参(env_ 变量)、自动连线,支持条件分支(CONDITION)、数据库节点(MYSQL)等 14 种节点 +3. **预览确认**:展示节点清单(类型/名称/连线/详情)+ **流程入参/出参定义表**(code/名称/类型/必填/说明,与节点映射严格对应) +4. 确认生成:创建流程定义并写入编排内容,入参/出参随流程入库,可跳设计器继续调整后保存部署 + +示例需求: +> 接收用户id,先调用获取用户信息接口,再根据用户id查询该用户的订单列表,最后返回用户名称和订单列表 + +### 四、接口智能接入助手 + +对话描述接入需求,AI 生成套件与接口方案: + +1. 填写接入需求(如"接入用户中心相关接口:查询用户信息、修改昵称、查询收货地址"),选择供应商/模型,点击「生成接口方案」 +2. AI 规划套件(code/名称/描述)与接口(code/名称/描述/路径/GET|POST),并自动设计每个接口的**入参配置**(参数/类型/位置 body|query/必填/说明)、**Header 配置**(如 Authorization 鉴权头)、**出参配置**(响应字段) +3. **预览确认**:套件表 + 接口表(展开行显示入参/Header/出参三段明细) +4. 确认接入:套件与接口写入平台,参数随接口入库;按 code 去重,已存在的自动跳过 + +### 五、报表智能助手 -| 层次 | 技术 | -|------|------| -| 后端框架 | ASP.NET Core 8 Web API | -| 架构模式 | DDD 四层架构(Api / Application / Domain / Infrastructure) | -| 数据库 | SQLite(EF Core 8) | -| 多数据库 | MySqlConnector / Npgsql / Microsoft.Data.SqlClient | -| 认证 | JWT Bearer Token | -| 文档 | Swagger / OpenAPI | -| 前端框架 | Vue 3 (Composition API + TypeScript) | -| UI 组件库 | Element Plus | -| 流程画布 | @vue-flow/core | -| 状态管理 | Pinia | -| 路由 | Vue Router 4 | -| 构建工具 | Vite 8 | +对话描述报表需求,AI 自动完成报表设计: + +1. 填写需求与报表名称(如"生成月度销售统计报表,按日期范围筛选,按销售员汇总订单金额和数量,需要合计行"),点击「生成报表」 +2. **数据集**:优先复用已有数据视图(sourceType=dataview),不满足时用自定义 SQL(自动匹配可用数据源与方言),或复用已发布流程/接口数据 +3. **查询参数**:自动设计筛选参数(text/number/date/select),与数据集 SQL 的 @参数名 对应 +4. **排版**:标题行(合并居中加粗)→ 表头行 → 数据行(绑定数据集自动扩展+斑马纹)→ 汇总行;合计用 `${字段:SUM}` 聚合,条件计算用 `=IF(条件,真,假)` 公式 +5. **生成即预览**:展示数据集/参数清单 + 报表 HTML 实际渲染效果;**确认后才创建报表**,可继续去设计器调整或打开正式访问页 + +### 流程设计器内 AI 生成 + +流程设计器工具栏同样提供「AI 生成」按钮,对话生成后直接替换画布,可继续手工调整。 + +### 支持的节点 + +START / END / METHOD(接口调用)/ CONDITION(条件分支)/ MERGE(汇聚)/ ASSIGN / CODE / MYSQL(SQL)/ LOOP / DELAY / PARALLEL / NOTIFY / TRANSFORM / SUB_FLOW --- -## 目录结构 +## 🛠️ 技术栈 -``` -JuggleNet6/ -├── Juggle.Api/ # 入口层:14个 Controller + Program.cs -│ ├── Controllers/ -│ │ ├── Api/ # 业务 Controller(流程、套件、系统等) -│ │ └── Open/ # 开放接口(外部触发流程) -│ ├── wwwroot/ # 前端构建产物(生产模式集成) -│ ├── juggle.db # SQLite 数据库文件 -│ └── Program.cs -│ -├── Juggle.Application/ # 应用层:Service + DTO -│ ├── Services/ -│ │ ├── Flow/ # 流程执行服务 -│ │ └── Impl/ # DataSourceService、JwtService -│ └── Models/ -│ ├── Request/ # 请求 DTO -│ └── Response/ # ApiResult 统一响应 -│ -├── Juggle.Domain/ # 领域层:实体 + 流程引擎 -│ ├── Entities/ # 15个领域实体 -│ └── Engine/ # FlowEngine + 9个节点执行器 -│ -├── Juggle.Infrastructure/ # 基础设施层 -│ ├── Persistence/ # JuggleDbContext(EF Core) -│ └── Common/ # JsonHelper、Md5Helper -│ -├── JuggleNet6.Frontend/ # Vue3 前端 -│ └── src/views/ # 功能页面(flow/suite/system/object) -│ -├── JuggleNet6.Backend/ # 原单体后端(保留参考,已废弃) -├── Architecture.md # 系统架构文档 -├── DesignDoc.md # 系统详细设计文档 -└── Juggle.sln # Visual Studio 解决方案 -``` + +| 层级 | 技术 | +| ---- | ----------------------------------- | +| 后端 | ASP.NET Core 8 / EF Core 8 / SQLite | +| 前端 | Vue3 / Vite / Element Plus / Pinia | +| 容器 | Docker (multi-stage build) | +| 认证 | JWT + RBAC 角色权限 | --- -## 快速开始 +## 📦 功能特性(30+ 项) -### 环境要求 +### 核心流程 -- [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) -- [Node.js 18+](https://nodejs.org/) +- ✅ 可视化流程设计器(节点画布) +- ✅ **14 种节点**:START / END / METHOD / CONDITION / MERGE / ASSIGN / CODE / DB / SUB_FLOW / LOOP / DELAY / PARALLEL / NOTIFY / TRANSFORM(模板转换) +- ✅ **对象子属性级联选择**(赋值/方法节点支持 object/array 类型属性树形选择) +- ✅ **数组操作**(赋值节点支持分页/取第n个/转JSON) +- ✅ **方法节点参数树**(API 入参/出参递归展开子属性) +- ✅ 节点超时 & 重试策略 +- ✅ 流程版本管理 & 版本对比 +- ✅ 流程克隆 / 导入 / 导出(含 Word 文档) +- ✅ 流程分组管理 -### 启动后端 +### 模型助手(AI) -```powershell -cd JuggleNet6\Juggle.Api -dotnet run -``` +- ✅ **大模型设置** — 多供应商管理(预置下拉/模型拉取/配置测试/启停),支持任意 OpenAI 兼容接口(DeepSeek/通义千问/Kimi/OpenAI/智谱/Ollama) +- ✅ **流程智能编排助手** — 对话生成流程(自动选接口/入参出参映射/条件分支/14 种节点),预览确认入库 +- ✅ **接口智能接入助手** — 对话生成套件与接口(含入参/Header/出参配置),预览确认接入 +- ✅ **报表智能助手** — 对话生成报表(复用数据视图/数据源/流程/接口 + 查询参数 + 排版公式),预览确认创建 +- ✅ **自定义智能助手** — 名称/系统提示词/输入输出参数/辅助提问词,启用后加入菜单;多轮对话 + 结束输出最终结果 + 历史记录 +- ✅ **流程设计器 AI 生成** — 工具栏一键生成并替换画布 -服务启动后访问: -- 应用首页:http://localhost:9127/ -- Swagger 文档:http://localhost:9127/swagger +### 触发方式 -### 启动前端(开发模式) +- ✅ 同步触发 `GET/POST /open/flow/trigger/{key}` +- ✅ 异步触发 + 结果查询 +- ✅ Webhook 触发(含签名验证) +- ✅ 定时任务调度 +- ✅ 服务别名(`/open/services/别名` 快捷访问) +- ✅ **SOAP 调用**(`POST /open/flow/soap/{key}`) +- ✅ **WSDL 自动生成**(`GET /open/flow/wsdl/{key}`,无需认证) -```powershell -cd JuggleNet6\JuggleNet6.Frontend -npm install -npm run dev -``` +### 套件 & 接口 -前端开发服务:http://localhost:5173/ +- ✅ 套件 / 接口 / 对象 / 参数管理 +- ✅ 接口 Mock 功能 +- ✅ WebService(SOAP 1.1 / 1.2)支持 +- ✅ **接口导入 / 导出(JSON 格式)** +- ✅ **批量生成接口**(5 种方式:CURL / Swagger URL / Swagger JSON / WSDL URL / WSDL 内容) +- ✅ **cURL 一键复制**(含 Header + 入参完整配置) +- ✅ 对象子属性级联选择(object/array 类型参数关联全局对象) -### 构建前端并集成到后端(生产模式) +### 监控 & 测试 -```powershell -cd JuggleNet6\JuggleNet6.Frontend -npm run build -Copy-Item dist\* ..\Juggle.Api\wwwroot\ -Recurse -Force -``` +- ✅ 监控仪表盘 +- ✅ **API 拓扑图**(健康检查/访问统计/DB 调用连线) +- ✅ **告警规则 + 告警记录** +- ✅ 执行日志(含节点级日志) +- ✅ 流程测试用例(断言 + 批量执行) +- ✅ Monaco Editor 代码编辑(JS / SQL 高亮 + 自动补全) +- ✅ **报表模块**(数据视图 + 报表设计器 + 公式引擎) + +### 系统管理 + +- ✅ 用户管理 / 角色管理 / 菜单权限(RBAC) +- ✅ 多租户数据隔离(JWT Claims 驱动) +- ✅ 审计日志 / Token 权限管理 +- ✅ 系统配置中心 / 全局异常告警 + +### 数据库支持 + +- **系统数据库**:SQLite / MySQL / PostgreSQL / SQLServer +- **业务数据源**:SQLite / MySQL / PostgreSQL / SQLServer / Oracle / 达梦 --- -## 默认账号 +## 📸 界面预览 -| 用户名 | 密码 | -|--------|------| -| juggle | juggle | +### 流程设计器 + +![流程设计器](./images/flowdesign.png) + +### 流程设计示例 + +![流程设计示例](./images/flowdesign01.png) + +--- + +## 📋 更新日志 + +### v1.8(最新) + +- ⚙️ **大模型设置** — 接入大模型能力(OpenAI 兼容接口,支持 DeepSeek/通义千问/Kimi/OpenAI/智谱GLM/Ollama):供应商预置下拉可直接输入并自动填默认接口地址、获取模型/配置测试一键验证密钥并拉取可用模型、默认模型下拉+可用模型多选、多供应商并存启停 +- 🤖 **模型助手管理(自定义智能助手)** — 名称/描述/系统提示词/输入参数列表(文本/数字/日期/开关/下拉)/输出参数列表/辅助提问词按钮,启用后自动加入模型助手菜单;运行页支持多轮对话(气泡消息/完整历史)、结束对话按输出参数生成最终 JSON 结果、开启新对话、对话历史抽屉(查看/继续/删除) +- 🧩 **流程智能编排助手** — 对话生成接口流程编排:自动选择已有接口、映射入参出参、连线与条件分支、14 种节点,生成**流程入参/出参定义**并在预览中展示,确认后创建流程(参数随流程入库) +- 🔌 **接口智能接入助手** — 对话生成套件与接口方案:自动设计**入参/Header/出参配置**(位置/必填/说明),预览展开三段展示,确认后写入平台(参数入库、按 code 去重) +- 📊 **报表智能助手** — 对话生成报表:数据集优先复用数据视图/数据源/流程/接口,自动设计查询参数与排版(汇总聚合/条件公式),生成即预览 HTML,确认后创建报表 +- 🎨 **设计器 AI 生成** — 流程设计器工具栏一键对话生成并替换画布 +- 📊 **报表模块** — 新增数据视图 + 报表设计器 + 公式引擎(SUM/AVG/COUNT/IF 等);数据集管理支持 4 种数据源与字段树点击填入;A4 分页预览、撤销/重做、单元格直接编辑、行列插入删除 +- 📈 **监控模块** — API 拓扑图(健康检查/访问统计/状态红黄绿/DB 节点与连线/流程过滤)+ 告警规则 + 告警记录 +- 🧮 **表达式引擎** — 条件/赋值节点支持算术运算 + - * / %、字符串拼接/切片([..5]/[2..5])/replace、toString("#.0##") 数字与日期格式化;赋值节点新增 EXPRESSION 表达式来源 +- 🔀 **条件节点扩展** — 支持 && || 括号、双变量比较、子属性、数组 length/元素取值,设计器内置语法帮助弹窗 +- 🗄️ **数据库节点 SQL 辅助** — 表/视图/存储过程浏览一键生成 SQL(自动带 100 行限制)、单独测试 SQL(查询预览/更改事务回滚不污染数据)、帮助弹窗 +- 🔗 **接口直连访问** — 套件接口支持 `/open/api/{code}` 直接调用(Token 授权)+ 访问别名 `/open/api/{alias}` + 停用/启用开关 + 一键复制地址 +- 🧩 **WSDL 解析增强** — 支持 generatedXSD 地址、xsd:include/import schemaLocation 递归加载、粘贴 XSD 内容(解决内网 schemaLocation 无法访问) +- 📚 **安装部署文档** — 新增 Docker/Linux/Windows/Nginx/数据库/升级部署指南 +- 🧠 **大模型节点增强** — 可设置供应商与模型、输入变量可选流程入出参及中间变量、图片输入(多模态视觉识别,多选 data URL 变量)、输出目标可选变量/出参/入参;文件解析节点支持图片类型(视觉模型识别描述) +- 🎛️ **大模型节点模型参数** — 深度思考开关(enable_thinking,deepseek-reasoner/Qwen 思考模式生效)、温度 0-2、最大输出字数(max_tokens)、随机种子(seed) +- 🔧 **大模型节点工具调用** — 勾选接口/流程作为函数调用 tools,模型按需调用工具(接口直接 HTTP 调用/流程递归执行),结果回传后生成最终回答(最多 4 轮) +- 📚 **知识库子系统** — 多知识库 CRUD 与配置(切片大小/重叠、文本或向量检索、向量模型),文档上传自动解析(word/excel/pdf/txt/markdown)切片入库、手动片段、文本关键词检索与向量余弦相似度检索(embeddings)、清洗(去空去重超短)与重新向量化、匹配记录查询;流程设计器新增知识库检索节点(KB_SEARCH)供 AI 节点 RAG 问答 +- ✂️ **数据提取节点** — 输入可选流程入出参与中间变量,提取类型 json(首个对象数组)/code(代码块)/keyword(关键字后到行尾)/between(起止标志)/length(偏移长度),输出可赋值变量/出参/入参 +- 🔎 **Redis 缓存节点** — 查询/设置节点(key 支持变量模板/JSON 自动解析/过期秒数)+ 系统设置 Redis 多实例配置(地址/端口/密码/库/测试连接/默认实例),未配置时节点执行给出明确报错 +- 🛠️ **Skill 管理** — 技能 CRUD(名称/分组/描述/内容/启停)、单个导入(JSON 或 markdown,首个 # 标题为技能名)、批量导入、单个/批量导出;大模型节点可勾选多个技能,执行时拼入系统提示词 +- 🛒 **市场系统** — 接口/流程/模型助手/Skills/报表五个市场:发布后平台级共享,任意租户一键导入(按名称/code 去重 + 下载计数);条目展示图标/名称/描述/作者/版本/更新日期;收藏/取消收藏 + 只看收藏过滤;条目 JSON 下载与直接应用 +- 🔍 **市场发现** — 从 GitHub 官方仓库(pythonHuang/APIWorkflowCanvasDesignNet)market 目录拉取 index.json 及各类型 {id}.json 到本地,按 id 导入(id 相同更新,否则新增) +- 🚀 **市场分享** — 分享到官方 GitHub 市场:填写作者/版本,本地生成 market/{type}/{id}.json 并更新 index.json,GitHub Token 授权后自动 fork → 建分支 → 写条目文件 → 合并官方最新索引 → 生成 Pull Request,管理员审核合并进入官方市场 +- 🔗 **模型能力绑定** — 供应商可设置支持的能力(Skills 多选/接口多选/流程多选/工具列表),流程 AI 节点按所选供应商过滤技能列表 + +### v1.7 + +- 🧩 **WSDL 自动生成** — 流程版本/别名均支持自动生成 WSDL 描述文件,无需认证即可访问;生成端点同步支持 SOAP 1.1 调用 +- 📥 **接口批量生成** — 支持 5 种方式批量创建接口:CURL 命令、Swagger URL、Swagger JSON、WSDL URL、WSDL 内容;WSDL 解析器自动识别 SOAP 1.1/1.2/HTTP GET/HTTP POST 绑定 +- 📦 **接口导入/导出** — 支持多选接口导出为 JSON 文件,可跨项目导入复用 +- 📋 **cURL 一键复制** — 每个接口自动生成含 Header + 入参完整配置的 cURL 命令 +- 🔢 **数组操作** — 赋值节点新增数组操作类型,支持分页/取第n个/转JSON +- 🌳 **对象子属性级联选择** — 赋值节点/方法节点均支持 object/array 类型参数的属性树形浏览和选择 +- 🌲 **方法节点参数树** — API 入参/出参递归展开子属性,下拉框缩进展示层级 + +### v1.6 + +- 🔄 **TRANSFORM 模板转换节点** — 支持 `${var|pipe}` 模板语法,静态方法/实例方法双模式 +- 🌐 **WebService SOAP 1.2** — 支持 SOAP 1.1/1.2 双版本,可配置操作名/命名空间/SOAPAction +- 📍 **参数位置配置** — 入参支持 query/body/rawBody 位置,Debug 调试适配不同位置策略 +- 🔧 **流程变量内联编辑** — 变量管理表格支持直接编辑,无需弹窗 +- 🎯 **来自对象导入** — 流程参数配置支持从全局对象类型一键导入属性作为入参/出参 +- 🔗 **服务别名** — 流程可配置访问别名(`/open/services/alias`),支持 GET/POST + +### v1.5 + +- 📊 **监控仪表盘** — 从流程管理独立为一级菜单 +- 🔀 **赋值节点扩展** — 支持常量/变量/静态变量/入参多种来源 +- 🧪 **版本触发测试** — 版本管理页增加触发测试弹窗 + +### v1.0 + +- 🎨 可视化流程设计器(VueFlow 画布 + 14 种节点) +- 🚀 同步/异步/Webhook/定时 多触发方式 +- 🗄️ 多数据库支持(SQLite/MySQL/PostgreSQL/SQLServer/Oracle/达梦) +- 🔐 JWT + RBAC 权限 + 多租户数据隔离 +- 🐳 Docker 一键部署(含 CI/CD GitHub Actions) --- -## 流程节点类型 +## 📚 文档 -| 节点 | 说明 | -|------|------| -| START | 开始节点,流程入口 | -| END | 结束节点,流程出口 | -| METHOD | 方法节点,调用外部 HTTP API | -| CONDITION | 条件节点,多分支判断 | -| ASSIGN | 赋值节点,变量赋值/类型转换,支持读写全局静态变量 | -| CODE | 代码节点,执行 JavaScript 脚本(`$var`/`$static` 对象) | -| MYSQL | 数据库节点,执行 SQL 查询(支持 `${varName}` 模板替换) | -| MERGE | 聚合节点,多分支汇聚 | -| **SUB_FLOW** | **子流程节点,调用已发布的其他流程,支持入参/出参变量映射** | +- [系统需求文档](./REQUIREMENTS.md) +- [系统架构文档](./Architecture.md) +- [系统详细设计文档](./DesignDoc.md) +- [系统部署文档](./DEPLOY.md) +- [数据库表结构](./docs/表结构/表列表.md) +- [原项目文档](https://juggle.plus/docs/guide/introduce/introduce.html)(Java 版本参考) +- [Release Notes](./RELEASE.md) --- -## API 接口规范 +## 🙏 致谢 -| 前缀 | 用途 | 认证方式 | -|------|------|---------| -| `/api/` | 控制台管理接口 | JWT Token | -| `/open/` | 开放接口(外部触发流程) | API Token | +本项目基于 [Juggle](https://github.com/somta/Juggle) 原始 Java 版本的设计思路与架构进行重构实现。 -统一响应格式: -```json -{ - "code": 200, - "message": "success", - "data": { ... } -} -``` +感谢 [@somta](https://github.com/somta) 及原项目团队! + +--- + +
+ +

+ +--- + +
+ +# 🎪 Juggle - API Orchestration Platform + +

+ Release + License + .NET 8 + Vue 3 +

+ +[中文](#-简介) | **English** + +
+ +--- + +## 📖 Introduction + +Juggle means "building blocks" and "magic" in Chinese, symbolizing flexibility like building blocks and power like magic — meeting flexible business needs and helping you deliver quickly! + +Juggle is a **graphical microservice orchestration tool** that enables rapid API development through simple visual workflow design. + +### ✨ Core Capabilities + + +| Scenario | Description | +| ----------------------------- | --------------------------------------------------------------------------- | +| 🧩 Microservice Orchestration | Quickly build new APIs by orchestrating existing base APIs | +| 🤖 **AI Orchestration** | **Describe requirements in natural language and let LLM auto-generate flow orchestration** | +| 🔗 System Integration | Rapidly integrate with third-party platforms, breaking down system barriers | +| 📦 BFF Layer | Provide aggregation/adaptation layer for frontend (Backend for Frontend) | +| 🎨 Custom Development | Privatized standard function customization without polluting core code | --- -## 开放接口访问方式 +## 🚀 Quick Start + +### Docker One-Click Start -```http -# 带版本号触发(指定某一版本) -POST /open/flow/trigger/v1/sync_abcdefghij -X-Access-Token: your-api-token +```bash +docker run -d \ + --name juggle \ + -p 9127:9127 \ + -v juggle_data:/data \ + pythonhuang/juggle-net8:v1.0 +``` + +Or use docker-compose: -# 不带版本号触发(自动取最新已发布版本) -POST /open/flow/trigger/sync_abcdefghij -X-Access-Token: your-api-token +```bash +docker-compose up -d ``` +- Access: http://localhost:9127 +- Default credentials: `juggle` / `juggle` + +--- + +## 🤖 AI Orchestration + +Use natural language to let the LLM auto-complete flow orchestration, API integration and report design. + +### 1. Model Settings (Providers) + +System Settings → AI Models: connect any **OpenAI-compatible API** (DeepSeek / Qwen / Kimi / OpenAI / GLM / Ollama etc.): + +- **Provider dropdown or free input**: preset DeepSeek, Qwen, Kimi, OpenAI, GLM and Ollama with auto-filled default base URL; custom providers supported +- **Fetch models / Config test**: one click verifies the API key and pulls the provider's available model list +- **Default model** dropdown + **available models** multi-select (switchable during chats) +- **Multiple providers with enable/disable** — switch provider and model freely in any assistant chat + +### 2. Assistant Management (Custom Assistants) + +Create custom assistants with: + +| Config | Description | +|--------|-------------| +| Name / Description | Menu label and purpose | +| System prompt | Persona and task instructions (e.g. "You are a copywriting expert…") | +| Input params | Run-page form: text / number / date / switch / select (options + defaults) | +| Output params | End-conversation JSON fields, shown in the final result panel | +| Quick-prompt buttons | One-click buttons that fill common questions (append with newlines to combine) | +| Enable | Auto-appears in the "AI Assistants" menu | + +The run page supports **multi-turn conversations**: chat bubbles with full history per round; "End Conversation" produces final JSON results from output params; "New Conversation" restarts anytime; the "History" drawer lists all conversations (resume ongoing / review ended / delete). + +### 3. Flow Orchestration Assistant + +Describe requirements and let the LLM build the flow: + +1. Enter the requirement and flow name, pick provider/model, click "Generate" +2. The LLM picks from existing platform APIs: auto-maps inputs (flow input params) and outputs (`env_` variables), wires nodes, supports condition branches (CONDITION), DB nodes (MYSQL) — all 14 node types +3. **Preview & confirm**: node list (type/name/wiring/details) + flow input/output param tables (strictly matching node mappings) +4. Confirm to create the flow definition; params are saved with the flow; continue tuning in the designer + +Example: +> Take a userId, call the get-user-info API, then query the user's order list, finally return the user name and the order list + +### 4. API Integration Assistant + +Describe integration needs and the LLM plans suites & APIs: + +1. Enter the requirement (e.g. "Integrate user-center APIs: query user info, update nickname, list shipping addresses"), pick provider/model, click "Generate API Plan" +2. The LLM plans suites (code/name/desc) and APIs (code/name/desc/path/GET|POST) with **input params** (code/type/position body|query/required/desc), **Header configs** (e.g. Authorization) and **output params** (response fields) +3. **Preview & confirm**: suite table + API table with expandable rows showing input/Header/output details +4. Confirm to import; params saved with the APIs; deduplicated by code (existing ones skipped) + +### 5. Report Assistant + +Describe report needs and the LLM designs the report: + +1. Enter the requirement and report name (e.g. "Monthly sales statistics by seller with date-range filter, amount/qty totals and a grand-total row"), click "Generate Report" +2. **Datasets**: reuse existing data views first (sourceType=dataview); fall back to custom SQL with a matching data source (dialect-aware), or reuse published flows/APIs +3. **Query params**: auto-designed filters (text/number/date/select) bound to `@paramName` in dataset SQL +4. **Layout**: title row (merged, centered, bold) → header row → data rows (dataset-bound auto-expand + zebra) → footer row; totals via `${field:SUM}` aggregates, conditional logic via `=IF(condition, a, b)` formulas +5. **Preview on generation**: dataset/param lists + actual rendered HTML; **confirm to create the report**, then continue in the designer or open the public view page + +### In-Designer AI Generation + +The Flow Designer toolbar also has an "AI Generate" button — chat to generate and replace the canvas, then fine-tune manually. + +### Supported Node Types + +START / END / METHOD / CONDITION / MERGE / ASSIGN / CODE / MYSQL / LOOP / DELAY / PARALLEL / NOTIFY / TRANSFORM / SUB_FLOW + +--- + +## 🛠️ Tech Stack + + +| Layer | Technology | +| --------- | ------------------------------------ | +| Backend | ASP.NET Core 8 / EF Core 8 / SQLite | +| Frontend | Vue3 / Vite / Element Plus / Pinia | +| Container | Docker (multi-stage build) | +| Auth | JWT + RBAC Role-Based Access Control | + --- -## 导入/导出功能 +## 📦 Features (30+) + +### Core Workflow + +- ✅ Visual workflow designer (node canvas) +- ✅ **14 Node Types**: START / END / METHOD / CONDITION / MERGE / ASSIGN / CODE / DB / SUB_FLOW / LOOP / DELAY / PARALLEL / NOTIFY / TRANSFORM +- ✅ **Object sub-property cascading** (ASSIGN/METHOD nodes support object/array tree property selection) +- ✅ **Array operations** (ASSIGN node: paginate / get by index / to JSON) +- ✅ **Method node param tree** (API I/O params recursively expand sub-properties) +- ✅ Node timeout & retry policies +- ✅ Workflow version management & comparison +- ✅ Clone / Import / Export (with Word docs) +- ✅ Workflow grouping -流程定义和套件均支持 JSON 格式的导入/导出,方便在不同环境间分享和移植: +### AI Assistants -| 操作 | 接口 | -|------|------| -| 导出流程定义 | `GET /api/flow/definition/export/{id}` | -| 导入流程定义 | `POST /api/flow/definition/import` | -| 导出套件(含接口+参数) | `GET /api/suite/export/{id}` | -| 导入套件 | `POST /api/suite/import` | +- ✅ **Model settings** — Multi-provider management (preset dropdown / model fetch / config test / enable-disable), any OpenAI-compatible API (DeepSeek/Qwen/Kimi/OpenAI/GLM/Ollama) +- ✅ **Flow orchestration assistant** — Chat to generate flows (auto API selection, I/O param mapping, condition branches, 14 node types), preview then confirm +- ✅ **API integration assistant** — Chat to generate suites & APIs (input / Header / output param configs), preview then confirm +- ✅ **Report assistant** — Chat to generate reports (reuses data views / data sources / flows / APIs + query params + layout formulas), preview then confirm +- ✅ **Custom assistants** — Name / system prompt / I/O params / quick prompts, auto-added to menu; multi-turn chat + final structured outputs + history +- ✅ **In-designer AI generation** — One-click generate and replace the canvas -> 导入时自动生成新的唯一标识(flowKey / suiteCode),不会覆盖已有数据。 +### Trigger Methods + +- ✅ Synchronous trigger `GET/POST /open/flow/trigger/{key}` +- ✅ Asynchronous trigger + result query +- ✅ Webhook trigger (with signature verification) +- ✅ Scheduled task scheduling +- ✅ Service alias (`/open/services/{alias}` quick access) +- ✅ **SOAP trigger** (`POST /open/flow/soap/{key}`) +- ✅ **Auto WSDL generation** (`GET /open/flow/wsdl/{key}`, no auth required) + +### Suite & API Management + +- ✅ Suite / API / Object / Parameter management +- ✅ API Mock functionality +- ✅ WebService (SOAP 1.1 / 1.2) support +- ✅ **API Import / Export (JSON)** +- ✅ **Batch API generation** (5 sources: CURL / Swagger URL / Swagger JSON / WSDL URL / WSDL content) +- ✅ **cURL one-click copy** (with full Headers + Input params) +- ✅ Object sub-property cascading selection (object/array type params linked to global objects) + +### Monitoring & Testing + +- ✅ Monitoring dashboard +- ✅ **API topology map** (health check / visit stats / DB call edges) +- ✅ **Alert rules + alert records** +- ✅ Execution logs (with node-level logs) +- ✅ Workflow test cases (assertions + batch execution) +- ✅ Monaco Editor code editing (JS / SQL highlighting + autocomplete) +- ✅ **Report module** (data views + report designer + formula engine) + +### System Management + +- ✅ User management / Role management / Menu permissions (RBAC) +- ✅ Multi-tenant data isolation (JWT Claims driven) +- ✅ Audit logs / Token permission management +- ✅ System config center / Global exception alerting + +### Database Support + +- **System Database**: SQLite / MySQL / PostgreSQL / SQLServer +- **Business Data Sources**: SQLite / MySQL / PostgreSQL / SQLServer / Oracle / Dameng + +--- + +## 📋 Changelog + +### v1.8(Latest) + +- ⚙️ **Model settings** — LLM integration (OpenAI-compatible API; DeepSeek/Qwen/Kimi/OpenAI/GLM/Ollama): preset provider dropdown with auto-filled base URL (free input supported), fetch-models/config-test to verify keys and pull models, default model dropdown + available models multi-select, multi-provider enable/disable +- 🤖 **Assistant management (custom assistants)** — name/description/system prompt/input params (text/number/date/switch/select)/output params/quick-prompt buttons; enabled assistants auto-join the AI Assistants menu; run page supports multi-turn chats (bubbles + full history), end-conversation with final JSON outputs, new conversation, and a history drawer (view/resume/delete) +- 🧩 **Flow orchestration assistant** — chat to generate flows: auto API selection, I/O mapping, wiring, condition branches, 14 node types, plus flow input/output param definitions shown in preview; confirm to create the flow with params saved +- 🔌 **API integration assistant** — chat to generate suites & APIs with input/Header/output param configs (position/required/desc), expandable three-section preview; confirm to import (params saved, deduplicated by code) +- 📊 **Report assistant** — chat to generate reports: datasets reuse data views/data sources/flows/APIs first, auto query params and layout (aggregates & formulas), instant HTML preview; confirm to create the report +- 🎨 **In-designer AI generation** — one-click chat to generate and replace the canvas +- 📊 **Report module** — Data views + Report designer + Formula engine (SUM/AVG/COUNT/IF etc.); datasets with 4 source types and field-tree click-to-fill; A4 paged preview, undo/redo, inline cell editing, row/column insert & delete +- 📈 **Monitoring module** — API topology map (health check / visit stats / red-yellow-green status / DB nodes & edges / flow filter) + alert rules + alert records +- 🧮 **Expression engine** — CONDITION/ASSIGN nodes support arithmetic + - * / %, string concat / slice ([..5]/[2..5]) / replace, toString("#.0##") number & date formatting; ASSIGN node adds EXPRESSION source type +- 🔀 **Condition node extension** — && || parentheses, variable-vs-variable comparison, sub-properties, array length/element access; built-in syntax help dialog in the designer +- 🗄️ **DB node SQL assist** — Browse tables/views/procedures and one-click generate SQL (auto 100-row limit); standalone SQL test (query preview / transactional rollback for updates); help dialog +- 🔗 **Direct API access** — Suite APIs callable via `/open/api/{code}` (Token auth) + access alias `/open/api/{alias}` + enable/disable switch + one-click copy URL +- 🧩 **WSDL parser enhancements** — generatedXSD location, recursive xsd:include/import schemaLocation loading, paste XSD content (for unreachable internal schemaLocation) +- 📚 **Deployment docs** — Docker / Linux / Windows / Nginx / database / upgrade guides +- 🧠 **LLM node enhancement** — Provider & model selection, input variable from flow in/out/intermediate vars, image input (multimodal vision, multi-select data URLs), output target variable/out-param/in-param; file-parse node supports image type (vision description) +- 🎛️ **LLM node model params** — Deep-thinking switch (enable_thinking for reasoning models), temperature 0-2, max output tokens, random seed +- 🔧 **LLM node tool calling** — Select APIs/flows as function-calling tools; the model calls tools on demand (APIs invoked directly over HTTP, flows run recursively), results are fed back to produce the final answer (max 4 rounds) +- 📚 **Knowledge base subsystem** — Multi-KB CRUD & config (chunk size/overlap, text or vector retrieval, embedding model), auto document parsing (word/excel/pdf/txt/markdown) & chunking, manual chunks, keyword search & vector cosine-similarity search, cleaning & re-embedding, match-log query; new KB_SEARCH flow node for RAG Q&A with AI nodes +- ✂️ **Data-extract node** — json (first object/array) / code (code block) / keyword (text after keyword to line end) / between (start-end markers) / length (offset-length) extraction types; output to variable/out-param/in-param +- 🔎 **Redis cache nodes** — Get/Set nodes (variable templates in key / auto JSON parse / TTL seconds) + multi-instance Redis config page (host/port/password/db/test-connection/default instance); clear error when not configured +- 🛠️ **Skill management** — Skill CRUD (name/group/desc/content/enable), single import (JSON or markdown), batch import, single/batch export; AI nodes can attach multiple skills appended to the system prompt at runtime +- 🛒 **Market system** — Five markets (APIs/flows/assistants/skills/reports): publish for platform-wide sharing, one-click import with dedup & download count; items show icon/name/desc/author/version/date; favorite/unfavorite with filter; JSON download & direct apply +- 🔍 **Market discovery** — Pull index.json and {id}.json files from the official GitHub repo (pythonHuang/APIWorkflowCanvasDesignNet) market directory to local; import by id (update if same id, else insert) +- 🚀 **Market sharing** — Share to the official GitHub market: fill author/version, generate local market/{type}/{id}.json and update index.json, GitHub token auth, then auto fork → branch → write item file → merge latest official index → create Pull Request; admins review and merge into the official market +- 🔗 **Model capability binding** — Providers can set supported capabilities (skills/APIs/flows/tools); the flow AI node filters its skill list by the selected provider + +### v1.7 + +- 🧩 **WSDL auto-generation** — Flow versions & aliases auto-generate WSDL files, publicly accessible without auth; sync SOAP 1.1 call support +- 📥 **Batch API generation** — 5 sources: CURL / Swagger URL / Swagger JSON / WSDL URL / WSDL content; WSDL parser auto-detects SOAP 1.1/1.2/HTTP GET/HTTP POST bindings +- 📦 **API import/export** — Multi-select export to JSON, cross-project import +- 📋 **cURL one-click copy** — Full cURL command with Headers + Input params +- 🔢 **Array operations** — ASSIGN node: paginate / get by index / to JSON +- 🌳 **Object sub-property cascading** — ASSIGN/METHOD nodes support object/array tree property browser and selection +- 🌲 **Method node param tree** — API I/O params recursively expand sub-properties with indented dropdown + +### v1.6 + +- 🔄 **TRANSFORM node** — `${var|pipe}` template syntax, static/instance method transforms +- 🌐 **WebService SOAP 1.2** — Dual SOAP version support, configurable operation/namespace/SOAPAction +- 📍 **Param position** — Input params: query/body/rawBody; debug adapts per position +- 🔧 **Inline variable editing** — Flow variable table supports inline edit +- 🎯 **Import from object** — One-click import properties from global objects to flow params +- 🔗 **Service alias** — Custom access alias for flows (`/open/services/alias`) + +### v1.5 + +- 📊 **Dashboard** — Promoted to independent top-level menu +- 🔀 **ASSIGN node extensions** — CONSTANT/VARIABLE/STATIC/INPUT source types +- 🧪 **Version trigger test** — Inline trigger test dialog in version management + +### v1.0 + +- 🎨 Visual flow designer (VueFlow canvas + 14 node types) +- 🚀 Sync/Async/Webhook/Scheduled triggers +- 🗄️ Multi-database (SQLite/MySQL/PostgreSQL/SQLServer/Oracle/Dameng) +- 🔐 JWT + RBAC + Multi-tenant isolation +- 🐳 Docker one-click deploy (with CI/CD GitHub Actions) --- -## 相关文档 +## 📚 Documentation -- [架构文档](./Architecture.md) - 系统总体架构设计 -- [设计文档](./DesignDoc.md) - 系统详细设计说明 -- [后端 README](./Juggle.Api/README.md) - 后端项目说明 -- [前端 README](./JuggleNet6.Frontend/README.md) - 前端项目说明 +- [Requirements](./REQUIREMENTS.md) / [Architecture](./Architecture.md) / [Detailed Design](./DesignDoc.md) / [Deployment](./DEPLOY.md) / [DB Tables](./docs/表结构/表列表.md)(中文) +- [Original Project Docs](https://juggle.plus/docs/guide/introduce/introduce.html) (Java version reference) +- [Release Notes](./RELEASE.md) --- -## 致谢 +## 🙏 Acknowledgments -本项目基于 [Juggle](https://github.com/somta/Juggle) 原始 Java 版本的设计思路与架构,使用 .NET 8 + Vue3 + SQLite 进行重构实现。 +This project is a .NET 8 reimplementation based on the design and architecture of the original [Juggle](https://github.com/somta/Juggle) Java version. + +Thanks to [@somta](https://github.com/somta) and the original team! + +--- -感谢 [@somta](https://github.com/somta) 及原项目团队提供的思路与支持! +## 📄 License -> 原项目:https://github.com/somta/Juggle +[MIT License](./LICENSE) diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md new file mode 100644 index 0000000..5604a9b --- /dev/null +++ b/REQUIREMENTS.md @@ -0,0 +1,70 @@ +# Juggle 接口编排平台 — 系统需求文档(最近需求包) + +> 版本:v1.8(2026-09) +> 状态说明:✅ 已实现并提交 / 🔄 进行中 / ⏳ 待规划 + +--- + +## 一、需求概述 + +本批次需求围绕 **AI 能力深化**(大模型节点参数化与工具调用)、**知识库与缓存基础设施**(知识库子系统、Redis 多实例)、**生态开放**(Skills、市场发现/收藏/分享到 GitHub 官方市场)展开,共 4 大模块。 + +--- + +## 二、需求明细 + +### 2.1 流程管理 > 流程定义 > 设计(大模型节点增强) + +| 编号 | 需求 | 说明 | 状态 | +|------|------|------|:---:| +| RQ-AI-01 | 大模型节点基础配置 | 可设置供应商与模型、输入变量可选流程入出参及中间变量、图片输入(多模态视觉识别,多选 data URL 变量)、输出目标可选变量/出参/入参 | ✅ | +| RQ-AI-02 | 模型参数 | 可设置是否启用深度思考(enable_thinking,推理模型生效)、温度(0-2)、最大输出字数(max_tokens,0=不限)、随机数种子(seed,0=随机) | ✅ | +| RQ-AI-03 | 工具调用 | 可设置支持的接口、流程等工具(函数调用 tools):模型按需调用工具,执行结果回传后生成最终回答(最多 4 轮);接口按参数位置拼 query/body 直接 HTTP 调用(Mock 优先),流程按入参递归执行子流程并返回出参 JSON | ✅ | +| RQ-AI-04 | 技能附加 | 大模型节点可勾选多个 Skills,执行时技能内容拼入系统提示词 | ✅ | + +### 2.2 模型助手 > 模型助手管理 + +| 编号 | 需求 | 说明 | 状态 | +|------|------|------|:---:| +| RQ-CAP-01 | 模型能力绑定 | 供应商可设置支持的 Skill(多选)、接口(多选)、流程(多选)、工具(列表,JSON 存储);流程 AI 节点按所选供应商过滤技能列表 | ✅ | + +### 2.3 市场(发现 / 收藏 / 分享生态) + +| 编号 | 需求 | 说明 | 状态 | +|------|------|------|:---:| +| RQ-MK-01 | 市场发现 | 拉取 GitHub 仓库 `pythonHuang/APIWorkflowCanvasDesignNet` 下 market 目录的 index.json(各类型文件信息)到本地 market 目录;可导入本地 market 目录各类型目录下以 {id}.json 命名的文件,id 相同则更新,否则增加 | ✅ | +| RQ-MK-02 | 收藏与过滤 | 可收藏市场条目,支持「只看收藏」过滤 | ✅ | +| RQ-MK-03 | 下载与直接应用 | 条目可下载(导出 JSON 文件)、可直接应用(一键导入本租户,按名称/code 去重) | ✅ | +| RQ-MK-04 | 元信息展示 | 条目显示图标、名称、名称描述、作者、版本号及更新日期等 | ✅ | +| RQ-MK-05 | 分享到应用市场 | 可把自己的流程、接口、模型助手、Skills、报表分享到应用市场(5 类条目) | ✅ | +| RQ-MK-06 | 分享到官方 GitHub 市场 | 分享时填写作者,先在本地 market 生成 {id}.json 文件并更新 market/index.json(同名条目复用原 id);登录 GitHub 授权(Personal Access Token),自动完成:校验令牌 → 确保 fork → 创建分支 → 写入条目文件 → 基于官方最新 index.json 合并本条索引 → 生成 Pull Request 到 `pythonHuang/APIWorkflowCanvasDesignNet` 并跳转打开;管理员定期审核 PR,合并到项目 market 目录 | ✅ | + +### 2.4 基础设施(知识库 / Redis / 流程节点) + +| 编号 | 需求 | 说明 | 状态 | +|------|------|------|:---:| +| RQ-KB-01 | 知识库子系统 | 多知识库 CRUD 与配置(切片大小/重叠、文本或向量检索、向量模型)、文档上传自动解析(word/excel/pdf/txt/markdown)切片入库、手动片段、文本关键词检索与向量余弦相似度检索、清洗(去空去重超短)与重新向量化、匹配记录查询 | ✅ | +| RQ-KB-02 | 知识库检索节点 | 流程设计器新增 KB_SEARCH 节点,供 AI 节点 RAG 问答 | ✅ | +| RQ-REDIS-01 | Redis 缓存节点 | 流程设计器新增 Redis 缓存查询/设置节点(key 支持变量模板/JSON 自动解析/过期秒数) | ✅ | +| RQ-REDIS-02 | Redis 多实例配置 | 系统设置新增 Redis 配置页(多实例:地址/端口/密码/库/默认实例 + 测试连接),未配置时节点执行给出明确报错 | ✅ | +| RQ-FLOW-01 | 数据提取节点 | 流程设计器新增 DATA_EXTRACT 节点:输入可选流程入出参与中间变量;提取类型 json(首个对象数组)/code(代码块)/keyword(关键字后到行尾)/between(起止标志)/length(偏移长度);输出可赋值变量/出参/入参 | ✅ | +| RQ-SKILL-01 | Skill 管理 | 技能 CRUD(名称/分组/描述/内容/启停)、单个导入(JSON 或 markdown,首个 # 标题为技能名)、批量导入、单个/批量导出 JSON | ✅ | + +--- + +## 三、验收要点 + +1. **AI 节点**:未配置供应商时执行给出明确报错;模型参数正确透传(enable_thinking/max_tokens/seed);工具调用轮次上限 4 轮,工具异常不中断流程(错误信息回传模型)。 +2. **市场发现**:GitHub 仓库不可达/未建立 market 目录时给出友好提示;导入按 market_item_id + item_type 去重更新。 +3. **市场分享**:本地文件与 PR 内容一致;index.json 基于官方最新版本合并,不覆盖他人条目;Token 仅存本机浏览器(localStorage),不落库。 +4. **多租户**:市场条目平台级共享(TenantId=null),收藏租户级隔离;导入内容落到导入方租户。 + +--- + +## 四、关联文档 + +- [系统架构文档](./Architecture.md) +- [系统详细设计文档](./DesignDoc.md) +- [系统部署文档](./DEPLOY.md) +- [README(含更新日志)](./README.md) +- [数据库表结构](./docs/表结构/表列表.md) diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_api.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_api.md" new file mode 100644 index 0000000..2ac551a --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_api.md" @@ -0,0 +1,64 @@ +# t_api - API 接口表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| suite_code | TEXT | | 所属套件编码 | +| method_code | TEXT | | 接口方法编码 | +| method_name | TEXT | | 接口方法名称 | +| method_desc | TEXT | | 接口方法描述 | +| url | TEXT | | 请求地址 | +| request_type | TEXT | | 请求类型:GET / POST / PUT / DELETE | +| content_type | TEXT | | 内容类型:JSON / FORM | +| mock_json | TEXT | | Mock 数据 JSON | +| method_type | TEXT | DEFAULT 'HTTP' | 接口类型:HTTP / WEBSERVICE | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| suite_code | 关联所属套件 | +| method_code | 接口唯一编码 | +| url | 完整请求地址或相对路径 | +| request_type | HTTP方法类型 | +| mock_json | 启用Mock时的返回数据 | + +--- + +## 索引 + +| 索引名 | 字段 | 类型 | 说明 | +|--------|------|------|------| +| idx_method_code | method_code | UNIQUE | 方法编码唯一索引 | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "suite_code": "user_suite", + "method_code": "getUserInfo", + "method_name": "获取用户信息", + "method_desc": "根据用户ID获取用户详细信息", + "url": "https://api.example.com/user/info", + "request_type": "GET", + "content_type": "JSON", + "method_type": "HTTP", + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_audit_log.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_audit_log.md" new file mode 100644 index 0000000..7c512e8 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_audit_log.md" @@ -0,0 +1,65 @@ +# t_audit_log - 审计日志表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| module | TEXT | NOT NULL | 操作模块:tenant / role / user / flow 等 | +| action_type | TEXT | NOT NULL | 操作类型:add / update / delete | +| target_id | INTEGER | NOT NULL | 操作目标ID | +| change_content | TEXT | DEFAULT '{}' | 变更内容摘要(JSON格式) | +| operator_name | TEXT | | 操作人用户名 | +| operator_id | INTEGER | | 操作人用户ID | +| operator_tenant_id | INTEGER | | 操作人租户ID | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| module | 操作所属模块,便于分类查询和统计 | +| action_type | 操作类型枚举 | +| target_id | 被操作记录的主键ID | +| change_content | JSON格式记录变更前后对比,如 `{"before":{"name":"A"},"after":{"name":"B"}}` | + +--- + +## 操作类型枚举 + +| action_type | 说明 | +|-------------|------| +| add | 新增 | +| update | 修改 | +| delete | 删除 | +| enable | 启用 | +| disable | 禁用 | +| deploy | 部署 | +| trigger | 触发 | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "module": "user", + "action_type": "update", + "target_id": 5, + "change_content": "{\"before\":{\"role_id\":2},\"after\":{\"role_id\":1}}", + "operator_name": "admin", + "operator_id": 1, + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_base.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_base.md" new file mode 100644 index 0000000..c16dd84 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_base.md" @@ -0,0 +1,59 @@ +# t_base - 基础实体基类 + +> 所有业务实体表均包含以下公共字段 + +--- + +## 公共字段说明 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| id | INTEGER | 主键,自增 | +| deleted | INTEGER | 软删除标记:0=正常, 1=已删除 | +| tenant_id | INTEGER | 所属租户ID,null=全局数据(不隔离) | +| created_at | TEXT | 创建时间(ISO 8601 格式) | +| created_by | INTEGER | 创建人用户ID | +| updated_at | TEXT | 更新时间(ISO 8601 格式) | +| updated_by | INTEGER | 更新人用户ID | + +--- + +## 说明 + +`t_base` 不是独立的数据表,而是**所有业务表的公共基类字段**。 + +### 设计理念 + +1. **软删除**:使用 `deleted` 字段实现逻辑删除,数据不物理删除,方便数据恢复和审计 +2. **租户隔离**:`tenant_id` 字段支持多租户数据隔离,null 表示全局数据 +3. **审计字段**:`created_at/updated_at` 记录数据生命周期,`created_by/updated_by` 记录操作人 + +### 继承关系 + +``` +BaseEntity (抽象基类) + ├── UserEntity (用户) + ├── TenantEntity (租户) + ├── RoleEntity (角色) + ├── RoleMenuEntity (角色菜单) + ├── SuiteEntity (套件) + ├── ApiEntity (API接口) + ├── ObjectEntity (自定义对象) + ├── ParameterEntity (参数) + ├── FlowDefinitionEntity (流程定义) + ├── FlowInfoEntity (流程信息) + ├── FlowVersionEntity (流程版本) + ├── FlowLogEntity (流程日志) + ├── FlowNodeLogEntity (节点日志) + ├── FlowTestCaseEntity (测试用例) + ├── VariableInfoEntity (变量) + ├── StaticVariableEntity (静态变量) + ├── TokenEntity (Token) + ├── TokenPermissionEntity (Token权限) + ├── DataSourceEntity (数据源) + ├── SystemConfigEntity (系统配置) + ├── WebhookEntity (Webhook) + ├── ScheduleTaskEntity (定时任务) + ├── LoginLogEntity (登录日志) + └── AuditLogEntity (审计日志) +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_data_source.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_data_source.md" new file mode 100644 index 0000000..11628a5 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_data_source.md" @@ -0,0 +1,63 @@ +# t_data_source - 数据源配置表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| ds_name | TEXT | | 数据源名称 | +| ds_type | TEXT | | 数据源类型:mysql / postgres / sqlserver / oracle 等 | +| host | TEXT | | 主机地址 | +| port | INTEGER | | 端口号 | +| db_name | TEXT | | 数据库名称 | +| username | TEXT | | 用户名 | +| password | TEXT | | 密码(加密存储) | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| ds_name | 数据源显示名称 | +| ds_type | 支持多种数据库类型 | +| password | 敏感信息,应加密存储 | + +--- + +## 支持的数据库类型 + +| ds_type | 说明 | +|---------|------| +| mysql | MySQL 数据库 | +| postgres | PostgreSQL 数据库 | +| sqlserver | SQL Server 数据库 | +| oracle | Oracle 数据库 | +| dm | 达梦数据库 | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "ds_name": "业务数据库", + "ds_type": "mysql", + "host": "192.168.1.100", + "port": 3306, + "db_name": "business_db", + "username": "juggle", + "password": "encrypted_password", + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_definition.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_definition.md" new file mode 100644 index 0000000..df8a9a1 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_definition.md" @@ -0,0 +1,62 @@ +# t_flow_definition - 流程定义表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| flow_key | TEXT | NOT NULL | 流程唯一标识Key | +| flow_name | TEXT | | 流程名称 | +| flow_desc | TEXT | | 流程描述 | +| flow_content | TEXT | | 流程节点JSON配置 | +| flow_type | TEXT | | 流程类型:sync(同步)/ async(异步) | +| group_name | TEXT | | 分组名称(便于分类管理) | +| status | INTEGER | DEFAULT 0 | 状态:0=草稿, 1=已部署 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| flow_key | 全局唯一,用于API调用,如 `/open/flow/trigger/demo_flow` | +| flow_name | 流程显示名称 | +| flow_content | JSON格式的节点配置,部署时会复制到 t_flow_version | +| flow_type | sync=同步执行等待结果,async=异步执行立即返回实例ID | +| status | 草稿状态可编辑,部署后变为只读 | +| group_name | 支持流程分组,如"订单流程"、"用户流程" | + +--- + +## 索引 + +| 索引名 | 字段 | 类型 | 说明 | +|--------|------|------|------| +| idx_flow_key | flow_key | UNIQUE | 流程Key唯一索引 | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "flow_key": "order_process", + "flow_name": "订单处理流程", + "flow_desc": "处理订单创建、支付、发货完整流程", + "flow_content": "[{\"key\":\"start_1\",\"elementType\":\"START\",...}]", + "flow_type": "sync", + "group_name": "订单流程", + "status": 0, + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_info.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_info.md" new file mode 100644 index 0000000..1b41dd4 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_info.md" @@ -0,0 +1,54 @@ +# t_flow_info - 流程信息表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| flow_key | TEXT | NOT NULL | 流程唯一标识Key(关联定义) | +| flow_name | TEXT | | 流程名称 | +| flow_desc | TEXT | | 流程描述 | +| flow_type | TEXT | | 流程类型:sync / async | +| status | INTEGER | DEFAULT 1 | 状态:1=启用, 0=禁用 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| flow_key | 与 t_flow_definition.flow_key 一一对应 | +| status | 禁用后该流程无法被触发,但历史执行记录保留 | + +--- + +## 设计说明 + +- **部署流程**时,从 t_flow_definition 复制基本信息到 t_flow_info +- t_flow_info 作为**运行时引用表**,记录已发布流程 +- 多个版本共存时,flow_key 相同但 t_flow_version 不同 + +--- + +## 示例数据 + +```json +{ + "id": 1, + "flow_key": "order_process", + "flow_name": "订单处理流程", + "flow_desc": "处理订单创建、支付、发货完整流程", + "flow_type": "sync", + "status": 1, + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_log.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_log.md" new file mode 100644 index 0000000..62c5630 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_log.md" @@ -0,0 +1,71 @@ +# t_flow_log - 流程执行日志表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| flow_key | TEXT | | 流程Key | +| flow_name | TEXT | | 流程名称(冗余) | +| version | TEXT | | 版本号 | +| trigger_type | TEXT | | 触发方式:debug / open / schedule | +| status | TEXT | | 执行状态:SUCCESS / FAILED | +| start_time | TEXT | | 开始时间 | +| end_time | TEXT | | 结束时间 | +| cost_ms | INTEGER | | 耗时(毫秒) | +| error_message | TEXT | | 错误信息 | +| input_json | TEXT | | 输入参数 JSON | +| output_json | TEXT | | 输出结果 JSON | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| trigger_type | 区分触发来源,便于统计和分析 | +| status | 执行结果状态 | +| cost_ms | 性能监控指标 | +| input_json/output_json | 完整的输入输出数据,便于问题排查 | + +--- + +## 触发类型枚举 + +| trigger_type | 说明 | +|--------------|------| +| debug | 调试模式触发 | +| open | 开放接口触发(/open/flow/trigger) | +| schedule | 定时任务触发 | +| webhook | Webhook触发 | +| test_case | 测试用例执行 | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "flow_key": "order_process", + "flow_name": "订单处理流程", + "version": "v1", + "trigger_type": "open", + "status": "SUCCESS", + "start_time": "2026-03-24T10:00:00", + "end_time": "2026-03-24T10:00:05", + "cost_ms": 5000, + "input_json": "{\"orderId\": 12345}", + "output_json": "{\"code\": 200, \"message\": \"success\"}", + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_node_log.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_node_log.md" new file mode 100644 index 0000000..10a290c --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_node_log.md" @@ -0,0 +1,85 @@ +# t_flow_node_log - 流程节点执行明细日志表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| flow_log_id | INTEGER | NOT NULL | 关联流程日志ID | +| node_key | TEXT | | 节点Key | +| node_label | TEXT | | 节点标签/名称 | +| node_type | TEXT | | 节点类型 | +| seq_no | INTEGER | | 执行顺序(从1开始) | +| status | TEXT | | 执行状态:SUCCESS / FAILED / SKIPPED | +| start_time | TEXT | | 开始时间 | +| end_time | TEXT | | 结束时间 | +| cost_ms | INTEGER | | 耗时(毫秒) | +| input_snapshot | TEXT | | 节点输入(变量快照 JSON) | +| output_snapshot | TEXT | | 节点输出(变量快照 JSON) | +| detail | TEXT | | 日志详情(SQL/HTTP请求等) | +| error_message | TEXT | | 错误信息 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| flow_log_id | 关联 t_flow_log 表,标识属于哪次流程执行 | +| node_type | 节点类型:START/END/METHOD/CONDITION/ASSIGN/CODE/MYSQL等 | +| seq_no | 执行顺序,用于还原执行路径 | +| input_snapshot | 进入节点时的变量状态快照 | +| output_snapshot | 离开节点时的变量状态快照 | +| detail | 详细信息,如HTTP请求体、SQL语句等 | + +--- + +## 节点类型枚举 + +| node_type | 说明 | +|-----------|------| +| START | 开始节点 | +| END | 结束节点 | +| METHOD | HTTP API调用节点 | +| CONDITION | 条件分支节点 | +| ASSIGN | 变量赋值节点 | +| CODE | 代码执行节点 | +| MYSQL | 数据库操作节点 | +| MERGE | 聚合节点 | +| DELAY | 延时节点 | +| PARALLEL | 并行执行节点 | +| LOOP | 循环节点 | +| SUB_FLOW | 子流程调用节点 | +| NOTIFY | 通知节点 | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "flow_log_id": 1, + "node_key": "method_order", + "node_label": "查询订单", + "node_type": "METHOD", + "seq_no": 2, + "status": "SUCCESS", + "start_time": "2026-03-24T10:00:01", + "end_time": "2026-03-24T10:00:03", + "cost_ms": 2000, + "input_snapshot": "{\"orderId\": 12345}", + "output_snapshot": "{\"orderId\": 12345, \"orderStatus\": \"paid\"}", + "detail": "HTTP POST https://api.example.com/order/get", + "tenant_id": 1, + "created_at": "2026-03-24T10:00:01" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_test_case.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_test_case.md" new file mode 100644 index 0000000..1e4c9a9 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_test_case.md" @@ -0,0 +1,72 @@ +# t_flow_test_case - 流程测试用例表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| flow_key | TEXT | NOT NULL | 关联流程Key | +| case_name | TEXT | NOT NULL | 用例名称 | +| input_json | TEXT | | 入参 JSON | +| assert_json | TEXT | | 断言 JSON | +| last_run_status | TEXT | | 最近执行状态 | +| last_run_time | TEXT | | 最近执行时间 | +| last_run_result | TEXT | | 最近执行结果摘要 | +| remark | TEXT | | 备注说明 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| input_json | 测试入参,格式如 `{"userId": 123}` | +| assert_json | 断言配置,格式如 `{"result.code": 200, "data.token": "notNull"}` | +| last_run_status | SUCCESS / FAILED / PENDING | +| last_run_result | 最近一次执行的实际输出摘要 | + +--- + +## 断言配置示例 + +```json +{ + "result.code": 200, + "data.success": true, + "data.token": "notNull", + "data.userId": 12345 +} +``` + +断言类型: +- 精确匹配:`"field": "expectedValue"` +- 非空验证:`"field": "notNull"` +- 正则匹配:`"field": "/^\\d+$/"` +- 包含关系:`"field": "contains:value"` + +--- + +## 示例数据 + +```json +{ + "id": 1, + "flow_key": "user_login", + "case_name": "正常登录测试", + "input_json": "{\"username\": \"test\", \"password\": \"123456\"}", + "assert_json": "{\"code\": 200, \"data.token\": \"notNull\"}", + "last_run_status": "SUCCESS", + "last_run_time": "2026-03-24T10:00:00", + "last_run_result": "{\"code\": 200, \"data\": {\"token\": \"abc123\"}}", + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_version.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_version.md" new file mode 100644 index 0000000..ac8b5cc --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_flow_version.md" @@ -0,0 +1,56 @@ +# t_flow_version - 流程版本表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| flow_info_id | INTEGER | NOT NULL | 关联流程信息ID | +| flow_key | TEXT | NOT NULL | 流程唯一标识Key | +| version | TEXT | NOT NULL | 版本号,如 v1, v2 | +| flow_content | TEXT | | 部署时的流程JSON快照 | +| status | INTEGER | DEFAULT 1 | 状态:0=禁用, 1=启用 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| flow_info_id | 关联 t_flow_info 表,记录属于哪个流程 | +| version | 版本号,每次部署自增,支持回滚 | +| flow_content | 部署时的快照,修改流程定义不影响已部署版本 | +| status | 同一 flow_key 下只能有一个版本为启用状态 | + +--- + +## 设计说明 + +- **版本管理**:每次部署生成新版本,支持版本回滚 +- **快照机制**:flow_content 存储部署时的完整配置,与定义解耦 +- **灰度发布**:可同时部署多个版本,通过切换状态实现灰度 + +--- + +## 示例数据 + +```json +{ + "id": 1, + "flow_info_id": 1, + "flow_key": "order_process", + "version": "v1", + "flow_content": "[{\"key\":\"start_1\",\"elementType\":\"START\",...}]", + "status": 1, + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_login_log.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_login_log.md" new file mode 100644 index 0000000..18e30b2 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_login_log.md" @@ -0,0 +1,59 @@ +# t_login_log - 登录日志表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| user_id | INTEGER | | 登录用户ID | +| user_name | TEXT | | 登录用户名 | +| login_type | TEXT | DEFAULT 'login' | 登录类型:login / logout | +| result | TEXT | DEFAULT 'success' | 登录结果:success / fail | +| ip_address | TEXT | | 登录IP地址 | +| user_agent | TEXT | | 浏览器User-Agent | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| login_type | 区分登录和登出行为 | +| result | 记录登录成功/失败,便于安全审计 | +| ip_address | 记录登录来源IP,支持异常登录告警 | +| user_agent | 记录浏览器信息,支持设备识别 | + +--- + +## 使用场景 + +- 用户登录审计 +- 异常登录检测(如异地登录) +- 用户活跃度统计 +- 安全合规要求 + +--- + +## 示例数据 + +```json +{ + "id": 1, + "user_id": 1, + "user_name": "admin", + "login_type": "login", + "result": "success", + "ip_address": "192.168.1.100", + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...", + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_object.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_object.md" new file mode 100644 index 0000000..de43b3a --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_object.md" @@ -0,0 +1,68 @@ +# t_object - 自定义对象表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| object_code | TEXT | | 对象编码(唯一) | +| object_name | TEXT | | 对象名称 | +| object_desc | TEXT | | 对象描述 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| object_code | 对象唯一编码,用于参数引用 | +| object_name | 中文名称 | +| object_desc | 详细描述说明 | + +--- + +## 设计说明 + +- 自定义对象用于定义复杂的数据结构 +- 对象属性通过 t_parameter 表的 `param_type=3` 记录 +- 支持嵌套对象(param_type=object) + +--- + +## 索引 + +| 索引名 | 字段 | 类型 | 说明 | +|--------|------|------|------| +| idx_object_code | object_code | UNIQUE | 对象编码唯一索引 | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "object_code": "user_info", + "object_name": "用户信息", + "object_desc": "包含用户基本信息的数据结构", + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` + +关联的参数(t_parameter): +```json +[ + {"param_code": "userId", "param_name": "用户ID", "data_type": "int"}, + {"param_code": "userName", "param_name": "用户名", "data_type": "string"}, + {"param_code": "email", "param_name": "邮箱", "data_type": "string"} +] +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_parameter.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_parameter.md" new file mode 100644 index 0000000..059c515 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_parameter.md" @@ -0,0 +1,89 @@ +# t_parameter - 参数表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| owner_id | INTEGER | | 归属者ID(API ID / Object ID 等) | +| owner_code | TEXT | | 归属者编码 | +| param_type | INTEGER | NOT NULL | 参数类型 | +| param_code | TEXT | | 参数编码 | +| param_name | TEXT | | 参数名称 | +| data_type | TEXT | | 数据类型 | +| object_code | TEXT | | 引用对象编码(DataType=object时) | +| required | INTEGER | DEFAULT 0 | 是否必填:0=否, 1=是 | +| default_value | TEXT | | 默认值 | +| description | TEXT | | 参数描述 | +| sort_num | INTEGER | DEFAULT 0 | 排序号 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 参数类型枚举 + +| param_type | 说明 | 归属者 | +|------------|------|--------| +| 1 | API入参 | t_api | +| 2 | API出参 | t_api | +| 3 | 对象属性 | t_object | +| 4 | API Header | t_api | +| 5 | 流程入参 | t_flow_definition | +| 6 | 流程出参 | t_flow_definition | + +--- + +## 数据类型枚举 + +| data_type | 说明 | +|-----------|------| +| string | 字符串 | +| int | 整数 | +| double | 浮点数 | +| boolean | 布尔值 | +| date | 日期 | +| datetime | 日期时间 | +| array | 数组 | +| object | 对象(引用 t_object) | +| json | JSON字符串 | + +--- + +## 示例数据 + +API入参示例: +```json +{ + "id": 1, + "owner_id": 1, + "owner_code": "user_suite.getUserInfo", + "param_type": 1, + "param_code": "userId", + "param_name": "用户ID", + "data_type": "int", + "required": 1, + "description": "用户唯一标识", + "sort_num": 1 +} +``` + +流程入参示例: +```json +{ + "id": 10, + "owner_id": 1, + "owner_code": "order_process", + "param_type": 5, + "param_code": "orderId", + "param_name": "订单ID", + "data_type": "int", + "required": 1 +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_role.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_role.md" new file mode 100644 index 0000000..c73d406 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_role.md" @@ -0,0 +1,51 @@ +# t_role - 角色表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| role_name | TEXT | NOT NULL | 角色名称 | +| role_code | TEXT | | 角色编码(唯一) | +| remark | TEXT | | 备注说明 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID(null=全局角色,跨租户共享) | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| role_name | 角色显示名称,如"管理员"、"普通用户" | +| role_code | 角色唯一标识,如"admin"、"user" | +| tenant_id | null = 全局角色(所有租户共享);有值 = 租户私有角色 | + +--- + +## 设计说明 + +- **全局角色**:tenant_id 为 null,如系统内置的"超级管理员"角色 +- **租户角色**:tenant_id 有值,仅该租户可见和使用 +- 角色通过 t_role_menu 表关联菜单权限 + +--- + +## 示例数据 + +```json +{ + "id": 1, + "role_name": "超级管理员", + "role_code": "super_admin", + "tenant_id": null, + "created_at": "2026-03-24T10:00:00", + "deleted": 0 +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_role_menu.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_role_menu.md" new file mode 100644 index 0000000..7237ed5 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_role_menu.md" @@ -0,0 +1,58 @@ +# t_role_menu - 角色菜单权限表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| role_id | INTEGER | NOT NULL | 关联角色ID | +| menu_key | TEXT | NOT NULL | 菜单标识,如 "flow/define" | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| role_id | 关联 t_role 表的角色ID | +| menu_key | 菜单唯一标识,支持通配符如 "suite/*" 表示所有套件菜单 | + +--- + +## 设计说明 + +- 角色与菜单权限的**多对多中间表** +- 支持细粒度菜单级别权限控制 +- menu_key 使用通配符可批量授权,如: + - `flow/*` - 所有流程相关菜单 + - `suite/*` - 所有套件相关菜单 + - `system/*` - 所有系统管理菜单 + +--- + +## 示例数据 + +```json +[ + { + "id": 1, + "role_id": 1, + "menu_key": "flow/define", + "tenant_id": 1 + }, + { + "id": 2, + "role_id": 1, + "menu_key": "suite/*", + "tenant_id": 1 + } +] +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_schedule_task.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_schedule_task.md" new file mode 100644 index 0000000..3ca59e5 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_schedule_task.md" @@ -0,0 +1,81 @@ +# t_schedule_task - 定时任务调度表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| flow_key | TEXT | NOT NULL | 关联流程Key | +| flow_name | TEXT | | 流程名称(冗余) | +| cron_expression | TEXT | | Cron表达式 | +| input_json | TEXT | | 触发时的固定入参 JSON | +| status | INTEGER | DEFAULT 0 | 状态:0=暂停, 1=启用 | +| last_run_time | TEXT | | 上次执行时间 | +| last_run_status | TEXT | | 上次执行状态 | +| next_run_time | TEXT | | 下次执行时间(预计算) | +| run_count | INTEGER | DEFAULT 0 | 累计执行次数 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| flow_key | 关联 t_flow_definition | +| cron_expression | 标准6位Cron表达式 | +| input_json | 固定入参,触发时作为流程入参 | +| next_run_time | 后台预计算,用于前端展示下次执行时间 | + +--- + +## Cron 表达式说明 + +| 位置 | 含义 | 取值范围 | +|------|------|---------| +| 第1位 | 秒 | 0-59 | +| 第2位 | 分钟 | 0-59 | +| 第3位 | 小时 | 0-23 | +| 第4位 | 日期 | 1-31 | +| 第5位 | 月份 | 1-12 | +| 第6位 | 星期 | 0-6 (0=周日) | + +--- + +## 常用 Cron 表达式示例 + +| 表达式 | 含义 | +|--------|------| +| `0 */5 * * * *` | 每5分钟执行一次 | +| `0 0 * * * *` | 每小时整点执行 | +| `0 0 0 * * *` | 每天零点执行 | +| `0 0 9 * * 1-5` | 工作日9点执行 | +| `0 0 8 * * *` | 每天8点执行 | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "flow_key": "data_sync", + "flow_name": "数据同步流程", + "cron_expression": "0 */30 * * * *", + "input_json": "{\"syncType\": \"full\"}", + "status": 1, + "last_run_time": "2026-03-24T10:30:00", + "last_run_status": "SUCCESS", + "next_run_time": "2026-03-24T11:00:00", + "run_count": 128, + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_static_variable.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_static_variable.md" new file mode 100644 index 0000000..44324c2 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_static_variable.md" @@ -0,0 +1,61 @@ +# t_static_variable - 静态(全局)变量表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| var_code | TEXT | | 变量编码(唯一键) | +| var_name | TEXT | | 变量名称(中文描述) | +| data_type | TEXT | | 数据类型:string / integer / double / boolean / date / json | +| value | TEXT | | 当前值(字符串形式存储) | +| default_value | TEXT | | 默认值 | +| description | TEXT | | 描述说明 | +| group_name | TEXT | | 分组名称 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| var_code | 变量唯一编码,流程中用 `$static.xxx` 引用 | +| value | 当前值,存储为字符串,使用时转换类型 | +| group_name | 可按业务分组,便于管理 | + +--- + +## 使用方式 + +在流程中通过表达式引用: +``` +$static.redis_host // 获取静态变量值 +$static.max_retry_count +``` + +--- + +## 示例数据 + +```json +{ + "id": 1, + "var_code": "redis_host", + "var_name": "Redis服务器地址", + "data_type": "string", + "value": "192.168.1.100:6379", + "default_value": "localhost:6379", + "description": "缓存服务器地址", + "group_name": "缓存配置", + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_suite.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_suite.md" new file mode 100644 index 0000000..bc40e95 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_suite.md" @@ -0,0 +1,62 @@ +# t_suite - 套件表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| suite_code | TEXT | | 套件编码(唯一) | +| suite_name | TEXT | | 套件名称 | +| suite_classify_id | INTEGER | | 套件分类ID | +| suite_image | TEXT | | 套件图标/封面 | +| suite_version | TEXT | | 套件版本号 | +| suite_desc | TEXT | | 套件描述 | +| suite_help_doc_json | TEXT | | 帮助文档 JSON | +| suite_flag | INTEGER | DEFAULT 0 | 标识:0=自定义, 1=官方 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID(null=全局/官方) | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| suite_code | 套件唯一编码,用于API调用 | +| suite_classify_id | 关联套件分类,便于分类管理 | +| suite_image | 套件展示图标URL | +| suite_version | 遵循语义化版本,如 1.0.0 | +| suite_flag | 区分官方套件和用户自定义套件 | + +--- + +## 索引 + +| 索引名 | 字段 | 类型 | 说明 | +|--------|------|------|------| +| idx_suite_code | suite_code | UNIQUE | 套件编码唯一索引 | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "suite_code": "user_suite", + "suite_name": "用户管理套件", + "suite_classify_id": 1, + "suite_image": "https://example.com/user.png", + "suite_version": "1.0.0", + "suite_desc": "提供用户注册、登录、权限管理等功能", + "suite_flag": 1, + "tenant_id": null, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_system_config.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_system_config.md" new file mode 100644 index 0000000..3306efe --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_system_config.md" @@ -0,0 +1,71 @@ +# t_system_config - 系统配置表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| config_key | TEXT | NOT NULL | 配置键(唯一) | +| config_value | TEXT | | 配置值 | +| config_name | TEXT | | 配置名称 | +| config_group | TEXT | | 配置分组 | +| remark | TEXT | | 备注说明 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID(null=全局配置) | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| config_key | 全局唯一配置键 | +| config_value | 配置值,字符串形式存储 | +| config_group | 分组标识,便于分类管理 | + +--- + +## 配置分组示例 + +| config_group | 说明 | +|--------------|------| +| system | 系统配置 | +| email | 邮件配置 | +| alert | 告警配置 | +| sms | 短信配置 | + +--- + +## 示例数据 + +```json +[ + { + "id": 1, + "config_key": "system.name", + "config_value": "Juggle 接口编排平台", + "config_name": "系统名称", + "config_group": "system" + }, + { + "id": 2, + "config_key": "alert.email.enabled", + "config_value": "true", + "config_name": "邮件告警启用", + "config_group": "alert" + }, + { + "id": 3, + "config_key": "alert.email.smtp_host", + "config_value": "smtp.example.com", + "config_name": "SMTP服务器", + "config_group": "alert" + } +] +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_tenant.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_tenant.md" new file mode 100644 index 0000000..55c63ea --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_tenant.md" @@ -0,0 +1,57 @@ +# t_tenant - 租户表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| tenant_name | TEXT | NOT NULL | 租户名称 | +| tenant_code | TEXT | | 租户编码(唯一) | +| remark | TEXT | | 备注说明 | +| status | INTEGER | DEFAULT 1 | 状态:1=启用, 0=禁用 | +| expired_at | TEXT | | 过期时间,null=永不过期 | +| menu_keys | TEXT | DEFAULT '[]' | 租户菜单权限(JSON数组) | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID(null表示全局) | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| tenant_code | 租户唯一编码,用于系统标识 | +| status | 启用后可正常使用,禁用后该租户用户无法登录 | +| expired_at | 到期后自动禁用,支持订阅制商业模式 | +| menu_keys | JSON数组格式,如 `["flow/define","flow/log"]`,控制菜单可见性 | + +--- + +## 索引 + +| 索引名 | 字段 | 类型 | 说明 | +|--------|------|------|------| +| idx_tenant_code | tenant_code | UNIQUE | 租户编码唯一索引 | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "tenant_name": "演示租户", + "tenant_code": "demo", + "status": 1, + "expired_at": null, + "menu_keys": "[\"flow/define\",\"flow/list\",\"flow/version\",\"suite/*\",\"object/*\",\"system/*\"]", + "created_at": "2026-03-24T10:00:00", + "deleted": 0 +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_token.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_token.md" new file mode 100644 index 0000000..56c4151 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_token.md" @@ -0,0 +1,53 @@ +# t_token - 访问令牌表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| token_value | TEXT | | Token值(唯一) | +| token_name | TEXT | | Token名称 | +| expired_at | TEXT | | 过期时间,null=永不过期 | +| status | INTEGER | DEFAULT 1 | 状态:1=启用, 0=禁用 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| token_value | API访问凭证,用于 /open/* 接口认证 | +| token_name | Token显示名称,便于识别用途 | +| expired_at | 过期时间,到期自动失效 | + +--- + +## 使用场景 + +- 开放接口(/open/*)的身份认证 +- 第三方系统接入凭证 +- Webhook触发验证 + +--- + +## 示例数据 + +```json +{ + "id": 1, + "token_value": "sk-a1b2c3d4e5f6...", + "token_name": "第三方系统接入Token", + "expired_at": "2027-12-31T23:59:59", + "status": 1, + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_token_permission.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_token_permission.md" new file mode 100644 index 0000000..de16d4c --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_token_permission.md" @@ -0,0 +1,63 @@ +# t_token_permission - Token 权限配置表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| token_id | INTEGER | NOT NULL | 关联Token ID | +| permission_type | TEXT | NOT NULL | 权限类型:FLOW / API | +| resource_key | TEXT | NOT NULL | 资源Key(flowKey 或 methodCode) | +| resource_name | TEXT | | 资源名称(冗余存储) | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| token_id | 关联 t_token 表 | +| permission_type | FLOW=可调用流程,API=可调用套件接口 | +| resource_key | 具体资源标识 | + +--- + +## 权限类型说明 + +| permission_type | 说明 | resource_key 示例 | +|-----------------|------|-------------------| +| FLOW | 流程调用权限 | `order_process` | +| API | 套件接口权限 | `user_suite.getUserInfo` | + +--- + +## 示例数据 + +```json +[ + { + "id": 1, + "token_id": 1, + "permission_type": "FLOW", + "resource_key": "order_process", + "resource_name": "订单处理流程", + "tenant_id": 1 + }, + { + "id": 2, + "token_id": 1, + "permission_type": "API", + "resource_key": "user_suite.getUserInfo", + "resource_name": "获取用户信息", + "tenant_id": 1 + } +] +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_user.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_user.md" new file mode 100644 index 0000000..06f98ed --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_user.md" @@ -0,0 +1,52 @@ +# t_user - 用户表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| user_name | TEXT | NOT NULL | 用户名(登录账号) | +| password | TEXT | | 密码(加密存储) | +| role_id | INTEGER | | 关联角色ID | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| user_name | 用户登录账号,通常为唯一标识 | +| password | 密码经过加密存储(如 MD5/SHA256) | +| role_id | 关联 t_role 表,支持 RBAC 权限控制 | + +--- + +## 索引 + +| 索引名 | 字段 | 类型 | 说明 | +|--------|------|------|------| +| idx_user_name | user_name | UNIQUE | 用户名唯一索引 | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "user_name": "admin", + "password": "e10adc3949ba59abbe56e057f20f883e", + "role_id": 1, + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00", + "deleted": 0 +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_variable_info.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_variable_info.md" new file mode 100644 index 0000000..67add46 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_variable_info.md" @@ -0,0 +1,64 @@ +# t_variable_info - 变量信息表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| flow_definition_id | INTEGER | | 关联流程定义ID | +| flow_key | TEXT | | 流程Key | +| variable_code | TEXT | | 变量编码 | +| variable_name | TEXT | | 变量名称 | +| data_type | TEXT | | 数据类型:string / int / boolean / object / array | +| variable_type | TEXT | | 变量类型:input / output / env | +| default_value | TEXT | | 默认值 | +| description | TEXT | | 变量描述 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| variable_code | 变量唯一标识,流程中通过 `input_xxx` / `output_xxx` / `env_xxx` 引用 | +| variable_name | 中文名称,用于展示 | +| variable_type | input=入参, output=出参, env=内部环境变量 | +| data_type | 决定数据类型和校验规则 | + +--- + +## 变量类型说明 + +| variable_type | 说明 | 引用方式 | +|--------------|------|---------| +| input | 流程输入参数 | input_xxx | +| output | 流程输出结果 | output_xxx | +| env | 内部环境变量 | env_xxx | + +--- + +## 示例数据 + +```json +{ + "id": 1, + "flow_definition_id": 1, + "flow_key": "user_login", + "variable_code": "input_userName", + "variable_name": "用户名", + "data_type": "string", + "variable_type": "input", + "default_value": "", + "description": "登录用户名", + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_webhook.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_webhook.md" new file mode 100644 index 0000000..bb1b946 --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250/t_webhook.md" @@ -0,0 +1,82 @@ +# t_webhook - Webhook 触发配置表 + +--- + +## 表结构 + +| 字段名 | 类型 | 约束 | 说明 | +|--------|------|------|------| +| id | INTEGER | PK, AUTOINCREMENT | 主键 | +| webhook_key | TEXT | NOT NULL | Webhook唯一标识Key | +| webhook_name | TEXT | NOT NULL | Webhook名称 | +| flow_key | TEXT | NOT NULL | 关联流程Key | +| flow_name | TEXT | | 流程名称(冗余) | +| secret | TEXT | | 签名密钥(HMAC-SHA256) | +| allowed_method | TEXT | DEFAULT 'POST' | 允许的HTTP方法 | +| async_mode | INTEGER | DEFAULT 0 | 异步模式:0=同步, 1=异步 | +| status | INTEGER | DEFAULT 1 | 状态:1=启用, 0=禁用 | +| trigger_count | INTEGER | DEFAULT 0 | 触发次数统计 | +| last_trigger_time | TEXT | | 最后触发时间 | +| remark | TEXT | | 备注说明 | +| deleted | INTEGER | DEFAULT 0 | 软删除标记 | +| tenant_id | INTEGER | | 所属租户ID | +| created_at | TEXT | | 创建时间 | +| created_by | INTEGER | | 创建人ID | +| updated_at | TEXT | | 更新时间 | +| updated_by | INTEGER | | 更新人ID | + +--- + +## 字段说明 + +| 字段 | 说明 | +|------|------| +| webhook_key | 访问URL:`/open/webhook/{webhook_key}` | +| secret | 设置后请求需携带签名头 X-Webhook-Signature | +| async_mode | 同步模式等待执行完成,异步模式立即返回logId | + +--- + +## 触发方式 + +**同步触发**:`POST /open/webhook/{webhookKey}` +```json +{ + "data": { ... }, + "timestamp": 1711251200000, + "signature": "sha256=xxx" +} +``` + +**异步触发**:同上,设置 `async_mode=1` + +--- + +## 签名验证 + +如果配置了 secret,请求头需包含签名: +``` +X-Webhook-Signature: sha256={HMAC-SHA256(requestBody, secret)} +``` + +--- + +## 示例数据 + +```json +{ + "id": 1, + "webhook_key": "order_notify", + "webhook_name": "订单通知Webhook", + "flow_key": "order_process", + "flow_name": "订单处理流程", + "secret": "my-secret-key", + "allowed_method": "POST", + "async_mode": 0, + "status": 1, + "trigger_count": 156, + "last_trigger_time": "2026-03-24T10:00:00", + "tenant_id": 1, + "created_at": "2026-03-24T10:00:00" +} +``` diff --git "a/docs/\350\241\250\347\273\223\346\236\204/\350\241\250\345\210\227\350\241\250.md" "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250\345\210\227\350\241\250.md" new file mode 100644 index 0000000..27b605f --- /dev/null +++ "b/docs/\350\241\250\347\273\223\346\236\204/\350\241\250\345\210\227\350\241\250.md" @@ -0,0 +1,201 @@ +# Juggle 接口编排平台 - 数据库表结构 + +> 版本:v1.8 +> 日期:2026-09-12 +> 数据库:SQLite + +--- + +## 一、表列表总览 + +本系统共 **40** 张数据表,按功能模块分类如下: + +### 1. 基础模块 + +| 序号 | 表名 | 说明 | +|:---:|------|------| +| 1 | t_base | 基础实体基类(所有表包含) | +| 2 | t_user | 用户表 | +| 3 | t_tenant | 租户表 | +| 4 | t_role | 角色表 | +| 5 | t_role_menu | 角色菜单权限表 | +| 6 | t_login_log | 登录日志表 | +| 7 | t_audit_log | 审计日志表 | + +### 2. 流程编排模块 + +| 序号 | 表名 | 说明 | +|:---:|------|------| +| 8 | t_flow_definition | 流程定义表(草稿状态) | +| 9 | t_flow_info | 流程信息表(已部署) | +| 10 | t_flow_version | 流程版本表 | +| 11 | t_flow_log | 流程执行日志表 | +| 12 | t_flow_node_log | 流程节点执行明细日志表 | +| 13 | t_flow_test_case | 流程测试用例表 | +| 14 | t_variable_info | 变量信息表 | +| 15 | t_static_variable | 静态(全局)变量表 | + +### 3. 套件与接口模块 + +| 序号 | 表名 | 说明 | +|:---:|------|------| +| 16 | t_suite | 套件表 | +| 17 | t_api | API 接口表 | +| 18 | t_object | 自定义对象表 | +| 19 | t_parameter | 参数表(入参/出参/Header/属性) | + +### 4. 安全与集成模块 + +| 序号 | 表名 | 说明 | +|:---:|------|------| +| 20 | t_token | 访问令牌表 | +| 21 | t_token_permission | Token 权限配置表 | +| 22 | t_data_source | 数据源配置表 | +| 23 | t_system_config | 系统配置表 | + +### 5. 触发与调度模块 + +| 序号 | 表名 | 说明 | +|:---:|------|------| +| 24 | t_webhook | Webhook 触发配置表 | +| 25 | t_schedule_task | 定时任务调度表 | + +### 6. 报表与告警模块(v1.7) + +| 序号 | 表名 | 说明 | +|:---:|------|------| +| 26 | t_data_view | 数据视图表(报表数据集 SQL 视图) | +| 27 | t_report | 报表表(布局 JSON/查询参数配置) | +| 28 | t_alert_rule | 告警规则表 | +| 29 | t_alert_record | 告警记录表 | + +### 7. AI 与知识库模块(v1.8) + +| 序号 | 表名 | 说明 | +|:---:|------|------| +| 30 | t_ai_provider | AI 模型供应商表(baseUrl/apiKey/models/capabilities 能力绑定) | +| 31 | t_ai_assistant | AI 自定义助手表(系统提示词/入出参/快速提示词/图标) | +| 32 | t_ai_conversation | AI 对话会话表(多轮消息/输出 JSON/供应商模型切换) | +| 33 | t_skill | 技能表(分组/内容/启停/市场来源) | +| 34 | t_kb | 知识库表(切片大小/重叠/检索类型/向量模型) | +| 35 | t_kb_document | 知识库文档表 | +| 36 | t_kb_chunk | 知识库切片表(含 vector_json 向量) | +| 37 | t_kb_match_log | 知识库匹配记录表 | + +### 8. 集成与市场生态模块(v1.8) + +| 序号 | 表名 | 说明 | +|:---:|------|------| +| 38 | t_redis_config | Redis 多实例配置表 | +| 39 | t_market_item | 市场条目表(平台级共享,含官方 ID/图标/作者/版本) | +| 40 | t_market_favorite | 市场收藏表(租户级) | + +> 新增表(26-40)字段详情见 [系统详细设计文档](../../DesignDoc.md) 第十二章。 + +--- + +## 二、ER 关系图 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ t_tenant │ +│ (租户 - 多租户隔离) │ +└─────────────────────────────────────────────────────────────────────────┘ + │ │ │ + │ 1:N │ 1:N │ 1:N + ▼ ▼ ▼ +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ t_user │ │ t_role │ │ t_flow_* │ +│ (用户) │ │ (角色) │ │ (流程相关) │ +└────────┬────────┘ └────────┬────────┘ └────────┬────────┘ + │ │ + │ N:M │ N:M + ▼ ▼ +┌─────────────────┐ ┌─────────────────┐ +│ t_role_menu │ │ t_suite │ +│ (角色菜单权限) │ │ (套件) │ +└─────────────────┘ └────────┬────────┘ + │ + │ 1:N + ▼ + ┌─────────────────┐ + │ t_api │ + │ (API接口) │ + └────────┬────────┘ + │ 1:N + ▼ + ┌─────────────────┐ + │ t_parameter │ + │ (参数配置) │ + └─────────────────┘ +``` + +--- + +## 三、各表详情 + +| 文件 | 说明 | +|------|------| +| [t_base.md](./表/t_base.md) | 基础实体基类(公共字段说明) | +| [t_user.md](./表/t_user.md) | 用户表 | +| [t_tenant.md](./表/t_tenant.md) | 租户表 | +| [t_role.md](./表/t_role.md) | 角色表 | +| [t_role_menu.md](./表/t_role_menu.md) | 角色菜单权限表 | +| [t_login_log.md](./表/t_login_log.md) | 登录日志表 | +| [t_audit_log.md](./表/t_audit_log.md) | 审计日志表 | +| [t_flow_definition.md](./表/t_flow_definition.md) | 流程定义表 | +| [t_flow_info.md](./表/t_flow_info.md) | 流程信息表 | +| [t_flow_version.md](./表/t_flow_version.md) | 流程版本表 | +| [t_flow_log.md](./表/t_flow_log.md) | 流程执行日志表 | +| [t_flow_node_log.md](./表/t_flow_node_log.md) | 流程节点执行明细日志表 | +| [t_flow_test_case.md](./表/t_flow_test_case.md) | 流程测试用例表 | +| [t_variable_info.md](./表/t_variable_info.md) | 变量信息表 | +| [t_static_variable.md](./表/t_static_variable.md) | 静态变量表 | +| [t_suite.md](./表/t_suite.md) | 套件表 | +| [t_api.md](./表/t_api.md) | API 接口表 | +| [t_object.md](./表/t_object.md) | 自定义对象表 | +| [t_parameter.md](./表/t_parameter.md) | 参数表 | +| [t_token.md](./表/t_token.md) | 访问令牌表 | +| [t_token_permission.md](./表/t_token_permission.md) | Token 权限配置表 | +| [t_data_source.md](./表/t_data_source.md) | 数据源配置表 | +| [t_system_config.md](./表/t_system_config.md) | 系统配置表 | +| [t_webhook.md](./表/t_webhook.md) | Webhook 触发配置表 | +| [t_schedule_task.md](./表/t_schedule_task.md) | 定时任务调度表 | +| t_data_view / t_report | 数据视图 / 报表表(见 DesignDoc.md 十二) | +| t_alert_rule / t_alert_record | 告警规则 / 告警记录表(见 DesignDoc.md 十二) | +| t_ai_provider / t_ai_assistant / t_ai_conversation | AI 供应商 / 助手 / 对话表(见 DesignDoc.md 12.1) | +| t_skill | 技能表(见 DesignDoc.md 12.1) | +| t_kb / t_kb_document / t_kb_chunk / t_kb_match_log | 知识库 4 表(见 DesignDoc.md 12.1) | +| t_redis_config | Redis 多实例配置表(见 DesignDoc.md 12.1) | +| t_market_item / t_market_favorite | 市场条目 / 收藏表(见 DesignDoc.md 12.1) | + +--- + +## 四、字段命名规范 + +| 字段类型 | 前缀/后缀 | 示例 | +|---------|----------|------| +| 主键 | Id | UserId, FlowId | +| 外键 | xxxId | TenantId, FlowInfoId | +| 名称 | Name | FlowName, SuiteName | +| 编码 | Code | FlowKey, SuiteCode | +| 描述 | Desc | FlowDesc, ObjectDesc | +| 状态 | Status | Status, LoginStatus | +| 时间 | At/Time | CreatedAt, UpdatedAt, LastRunTime | +| 数量 | Count | TriggerCount, RunCount | +| JSON数据 | Json | FlowContent, InputJson | +| 布尔值 | Is/Flag | IsDeleted (用 Deleted 代替) | + +--- + +## 五、软删除与租户隔离 + +### 5.1 软删除 +- 所有业务表均包含 `deleted` 字段 +- `deleted = 0` 表示正常数据 +- `deleted = 1` 表示已删除(逻辑删除) + +### 5.2 租户隔离 +- 所有业务表均包含 `tenant_id` 字段(继承自 BaseEntity) +- `tenant_id = null` 表示全局数据(不隔离) +- `tenant_id` 有值时,查询自动按租户过滤 diff --git a/images/flowdesign.png b/images/flowdesign.png new file mode 100644 index 0000000..a8c0f94 Binary files /dev/null and b/images/flowdesign.png differ diff --git a/images/flowdesign01.png b/images/flowdesign01.png new file mode 100644 index 0000000..ffacdb0 Binary files /dev/null and b/images/flowdesign01.png differ diff --git a/market/api/1789186091.json b/market/api/1789186091.json new file mode 100644 index 0000000..b063942 --- /dev/null +++ b/market/api/1789186091.json @@ -0,0 +1,29 @@ +{ + "id": 1789186091, + "type": "api", + "name": "百度登录", + "description": "百度账号用户名密码登录相关接口", + "icon": "\uD83D\uDCE6", + "author": "pythonHuang", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "content": { + "suites": [ + { + "suiteCode": "baiduLogin", + "suiteName": "百度登录", + "suiteDesc": "百度账号用户名密码登录相关接口" + } + ], + "apis": [ + { + "suiteCode": "baiduLogin", + "methodCode": "baiduLoginByPwd", + "methodName": "百度用户名密码登录", + "methodDesc": "使用百度账号(用户名/手机号/邮箱)与密码进行登录,成功返回登录态令牌与用户基础信息", + "url": "/v2/api/?login", + "requestType": "POST" + } + ] + } +} \ No newline at end of file diff --git a/market/assistant/1789186181.json b/market/assistant/1789186181.json new file mode 100644 index 0000000..aed4ac6 --- /dev/null +++ b/market/assistant/1789186181.json @@ -0,0 +1,19 @@ +{ + "id": 1789186181, + "type": "assistant", + "name": "图表助手", + "description": "图表助手", + "icon": "\uD83D\uDCCA", + "author": "pythonHuang", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "content": { + "assistantName": "图表助手", + "description": "图表助手", + "systemPrompt": "根据用户给的数据,显示图表,图标要求美观大方。\n支持拆线图、柱状图、饼图、气泡图、国家份图、省份区域图等。", + "inputParams": "[{\u0022name\u0022:\u0022gtype\u0022,\u0022label\u0022:\u0022图表类型\u0022,\u0022type\u0022:\u0022select\u0022,\u0022default\u0022:\u0022\u0022,\u0022options\u0022:\u0022拆线图,柱状图,饼图,气泡图,国家份图,省份区域图\u0022}]", + "outputParams": "[{\u0022name\u0022:\u0022gimage\u0022,\u0022label\u0022:\u0022图表图片\u0022},{\u0022name\u0022:\u0022gdescription\u0022,\u0022label\u0022:\u0022图表说明\u0022}]", + "quickPrompts": "[\u0022拆线图\u0022,\u0022柱状图\u0022,\u0022饼图\u0022,\u0022气泡图\u0022,\u0022国家份图\u0022,\u0022省份区域图\u0022]", + "icon": "\uD83D\uDCCA" + } +} \ No newline at end of file diff --git a/market/flow/1789186031.json b/market/flow/1789186031.json new file mode 100644 index 0000000..85fb435 --- /dev/null +++ b/market/flow/1789186031.json @@ -0,0 +1,16 @@ +{ + "id": 1789186031, + "type": "flow", + "name": "登陆并获取订单信息", + "description": "登陆并获取订单信息", + "icon": "\uD83D\uDCE6", + "author": "pythonHuang", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "content": { + "flowName": "登陆并获取订单信息", + "flowDesc": "登陆并获取订单信息", + "groupName": "demo", + "flowContent": "[{\u0022key\u0022:\u0022n1\u0022,\u0022elementType\u0022:\u0022START\u0022,\u0022label\u0022:\u0022\\u5F00\\u59CB\u0022,\u0022x\u0022:100,\u0022y\u0022:160,\u0022outgoings\u0022:[\u0022n2\u0022]},{\u0022key\u0022:\u0022n2\u0022,\u0022elementType\u0022:\u0022METHOD\u0022,\u0022label\u0022:\u0022QQ\\u53F7\\u5BC6\\u7801\\u767B\\u5F55\u0022,\u0022x\u0022:320,\u0022y\u0022:160,\u0022method\u0022:{\u0022suiteCode\u0022:\u0022qqLogin\u0022,\u0022methodCode\u0022:\u0022qqAccountLogin\u0022,\u0022url\u0022:\u0022/api/qq/account/login\u0022,\u0022method\u0022:\u0022POST\u0022},\u0022inputFillRules\u0022:[{\u0022sourceType\u0022:\u0022INPUT\u0022,\u0022source\u0022:\u0022qq\u0022,\u0022target\u0022:\u0022qq\u0022},{\u0022sourceType\u0022:\u0022INPUT\u0022,\u0022source\u0022:\u0022password\u0022,\u0022target\u0022:\u0022password\u0022}],\u0022outputFillRules\u0022:[{\u0022source\u0022:\u0022data.token\u0022,\u0022targetType\u0022:\u0022VARIABLE\u0022,\u0022target\u0022:\u0022env_login_token\u0022},{\u0022source\u0022:\u0022data.cookie\u0022,\u0022targetType\u0022:\u0022VARIABLE\u0022,\u0022target\u0022:\u0022env_login_cookie\u0022}],\u0022outgoings\u0022:[\u0022n3\u0022]},{\u0022key\u0022:\u0022n3\u0022,\u0022elementType\u0022:\u0022CONDITION\u0022,\u0022label\u0022:\u0022\\u5224\\u65AD\\u662F\\u5426\\u767B\\u5F55\\u6210\\u529F\u0022,\u0022x\u0022:540,\u0022y\u0022:160,\u0022conditions\u0022:[{\u0022conditionName\u0022:\u0022\\u767B\\u5F55\\u6210\\u529F\u0022,\u0022conditionType\u0022:\u0022CUSTOM\u0022,\u0022expression\u0022:\u0022env_login_token != \\u0027\\u0027\u0022,\u0022outgoing\u0022:\u0022n4\u0022},{\u0022conditionName\u0022:\u0022\\u9ED8\\u8BA4\u0022,\u0022conditionType\u0022:\u0022DEFAULT\u0022,\u0022outgoing\u0022:\u0022n5\u0022}],\u0022outgoings\u0022:[]},{\u0022key\u0022:\u0022n4\u0022,\u0022elementType\u0022:\u0022METHOD\u0022,\u0022label\u0022:\u0022\\u83B7\\u53D6\\u8BA2\\u5355\\u4FE1\\u606F\u0022,\u0022x\u0022:760,\u0022y\u0022:40,\u0022method\u0022:{\u0022suiteCode\u0022:\u0022suite_816f52161afc4c3eb236dac6a6bcc0bd\u0022,\u0022methodCode\u0022:\u0022api_5d4404c10b0845bab5578ff0292bf05c\u0022,\u0022url\u0022:\u0022rr\u0022,\u0022method\u0022:\u0022GET\u0022},\u0022inputFillRules\u0022:[{\u0022sourceType\u0022:\u0022VARIABLE\u0022,\u0022source\u0022:\u0022env_login_token\u0022,\u0022target\u0022:\u0022token\u0022},{\u0022sourceType\u0022:\u0022VARIABLE\u0022,\u0022source\u0022:\u0022env_login_cookie\u0022,\u0022target\u0022:\u0022cookie\u0022}],\u0022outputFillRules\u0022:[{\u0022source\u0022:\u0022data\u0022,\u0022targetType\u0022:\u0022VARIABLE\u0022,\u0022target\u0022:\u0022env_order_list\u0022},{\u0022source\u0022:\u0022data\u0022,\u0022targetType\u0022:\u0022OUTPUT\u0022,\u0022target\u0022:\u0022orderList\u0022}],\u0022outgoings\u0022:[\u0022n5\u0022]},{\u0022key\u0022:\u0022n5\u0022,\u0022elementType\u0022:\u0022MERGE\u0022,\u0022label\u0022:\u0022\\u6C47\\u805A\u0022,\u0022x\u0022:980,\u0022y\u0022:160,\u0022outgoings\u0022:[\u0022n6\u0022]},{\u0022key\u0022:\u0022n6\u0022,\u0022elementType\u0022:\u0022END\u0022,\u0022label\u0022:\u0022\\u7ED3\\u675F\u0022,\u0022x\u0022:1200,\u0022y\u0022:160,\u0022outgoings\u0022:[]}]" + } +} \ No newline at end of file diff --git a/market/flow/1789186045.json b/market/flow/1789186045.json new file mode 100644 index 0000000..aa5c141 --- /dev/null +++ b/market/flow/1789186045.json @@ -0,0 +1,16 @@ +{ + "id": 1789186045, + "type": "flow", + "name": "登陆并获取订单", + "description": "登陆并获取订单", + "icon": "\uD83D\uDCE6", + "author": "pythonHuang", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "content": { + "flowName": "登陆并获取订单", + "flowDesc": "登陆并获取订单", + "groupName": "demo", + "flowContent": "[{\u0022key\u0022:\u0022n1\u0022,\u0022elementType\u0022:\u0022START\u0022,\u0022label\u0022:\u0022\\u5F00\\u59CB\u0022,\u0022x\u0022:100,\u0022y\u0022:100,\u0022outgoings\u0022:[\u0022n2\u0022]},{\u0022key\u0022:\u0022n2\u0022,\u0022elementType\u0022:\u0022METHOD\u0022,\u0022label\u0022:\u0022QQ\\u8D26\\u53F7\\u5BC6\\u7801\\u767B\\u5F55\u0022,\u0022x\u0022:320,\u0022y\u0022:100,\u0022method\u0022:{\u0022suiteCode\u0022:\u0022qqLogin\u0022,\u0022methodCode\u0022:\u0022loginByQqPassword\u0022,\u0022url\u0022:\u0022/api/qq/login\u0022,\u0022method\u0022:\u0022POST\u0022},\u0022inputFillRules\u0022:[{\u0022sourceType\u0022:\u0022INPUT\u0022,\u0022source\u0022:\u0022qq\u0022,\u0022target\u0022:\u0022qq\u0022},{\u0022sourceType\u0022:\u0022INPUT\u0022,\u0022source\u0022:\u0022password\u0022,\u0022target\u0022:\u0022password\u0022}],\u0022outputFillRules\u0022:[{\u0022source\u0022:\u0022data.token\u0022,\u0022targetType\u0022:\u0022VARIABLE\u0022,\u0022target\u0022:\u0022env_login_token\u0022},{\u0022source\u0022:\u0022data.cookie\u0022,\u0022targetType\u0022:\u0022VARIABLE\u0022,\u0022target\u0022:\u0022env_login_cookie\u0022},{\u0022source\u0022:\u0022code\u0022,\u0022targetType\u0022:\u0022VARIABLE\u0022,\u0022target\u0022:\u0022env_login_code\u0022}],\u0022outgoings\u0022:[\u0022n3\u0022]},{\u0022key\u0022:\u0022n3\u0022,\u0022elementType\u0022:\u0022CONDITION\u0022,\u0022label\u0022:\u0022\\u5224\\u65AD\\u767B\\u5F55\\u662F\\u5426\\u6210\\u529F\u0022,\u0022x\u0022:540,\u0022y\u0022:100,\u0022conditions\u0022:[{\u0022conditionName\u0022:\u0022\\u767B\\u5F55\\u6210\\u529F\u0022,\u0022conditionType\u0022:\u0022CUSTOM\u0022,\u0022expression\u0022:\u0022env_login_code == \\u0027200\\u0027\u0022,\u0022outgoing\u0022:\u0022n4\u0022},{\u0022conditionName\u0022:\u0022\\u9ED8\\u8BA4\u0022,\u0022conditionType\u0022:\u0022DEFAULT\u0022,\u0022outgoing\u0022:\u0022n4\u0022}],\u0022outgoings\u0022:[\u0022n4\u0022]},{\u0022key\u0022:\u0022n4\u0022,\u0022elementType\u0022:\u0022END\u0022,\u0022label\u0022:\u0022\\u7ED3\\u675F\u0022,\u0022x\u0022:760,\u0022y\u0022:100,\u0022outgoings\u0022:[]}]" + } +} \ No newline at end of file diff --git a/market/flow/1789191346.json b/market/flow/1789191346.json new file mode 100644 index 0000000..7e1454c --- /dev/null +++ b/market/flow/1789191346.json @@ -0,0 +1,16 @@ +{ + "id": 1789191346, + "type": "flow", + "name": "自动预约", + "description": "", + "icon": "\uD83D\uDCE6", + "author": "pythonHuang", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "content": { + "flowName": "自动预约", + "flowDesc": "", + "groupName": "测试", + "flowContent": "[]" + } +} diff --git a/market/index.json b/market/index.json new file mode 100644 index 0000000..3ef3b11 --- /dev/null +++ b/market/index.json @@ -0,0 +1,70 @@ +{ + "items": [ + { + "id": 1789186031, + "type": "flow", + "name": "登陆并获取订单信息", + "description": "登陆并获取订单信息", + "icon": "\uD83D\uDCE6", + "author": "pythonHuang", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "file": "flow/1789186031.json" + }, + { + "id": 1789186045, + "type": "flow", + "name": "登陆并获取订单", + "description": "登陆并获取订单", + "icon": "\uD83D\uDCE6", + "author": "pythonHuang", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "file": "flow/1789186045.json" + }, + { + "id": 1789186091, + "type": "api", + "name": "百度登录", + "description": "百度账号用户名密码登录相关接口", + "icon": "\uD83D\uDCE6", + "author": "pythonHuang", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "file": "api/1789186091.json" + }, + { + "id": 1789186136, + "type": "report", + "name": "智能生成患者结算信息", + "description": "demo", + "icon": "\uD83D\uDCE6", + "author": "pythonHuag", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "file": "report/1789186136.json" + }, + { + "id": 1789186181, + "type": "assistant", + "name": "图表助手", + "description": "图表助手", + "icon": "\uD83D\uDCCA", + "author": "pythonHuang", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "file": "assistant/1789186181.json" + }, + { + "id": 1789186345, + "type": "skill", + "name": "读取文件", + "description": "根据要求目录获取文件内容", + "icon": "\uD83D\uDCE6", + "author": "pythonHuange", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "file": "skill/1789186345.json" + } + ] +} \ No newline at end of file diff --git a/market/report/1789186136.json b/market/report/1789186136.json new file mode 100644 index 0000000..083f3c1 --- /dev/null +++ b/market/report/1789186136.json @@ -0,0 +1,16 @@ +{ + "id": 1789186136, + "type": "report", + "name": "智能生成患者结算信息", + "description": "demo", + "icon": "\uD83D\uDCE6", + "author": "pythonHuag", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "content": { + "name": "智能生成患者结算信息", + "groupName": "demo", + "paramsConfig": "[{\u0022name\u0022:\u0022beginDate\u0022,\u0022label\u0022:\u0022开始日期\u0022,\u0022type\u0022:\u0022date\u0022,\u0022options\u0022:\u0022\u0022,\u0022default\u0022:\u0022\u0022},{\u0022name\u0022:\u0022endDate\u0022,\u0022label\u0022:\u0022结束日期\u0022,\u0022type\u0022:\u0022date\u0022,\u0022options\u0022:\u0022\u0022,\u0022default\u0022:\u0022\u0022},{\u0022name\u0022:\u0022patientName\u0022,\u0022label\u0022:\u0022患者姓名\u0022,\u0022type\u0022:\u0022text\u0022,\u0022options\u0022:\u0022\u0022,\u0022default\u0022:\u0022\u0022},{\u0022name\u0022:\u0022settleType\u0022,\u0022label\u0022:\u0022结算类型\u0022,\u0022type\u0022:\u0022select\u0022,\u0022options\u0022:\u0022门诊,住院,急诊\u0022,\u0022default\u0022:\u0022\u0022},{\u0022name\u0022:\u0022settleWay\u0022,\u0022label\u0022:\u0022结算方式\u0022,\u0022type\u0022:\u0022select\u0022,\u0022options\u0022:\u0022医保,自费,商保\u0022,\u0022default\u0022:\u0022\u0022}]", + "layoutJson": "{\u0022page\u0022:{\u0022size\u0022:\u0022A4\u0022,\u0022orientation\u0022:\u0022landscape\u0022,\u0022margin\u0022:{\u0022top\u0022:20,\u0022bottom\u0022:20,\u0022left\u0022:15,\u0022right\u0022:15},\u0022header\u0022:\u0022\u0022,\u0022footer\u0022:\u0022\u0022,\u0022bgImage\u0022:\u0022\u0022},\u0022params\u0022:[{\u0022name\u0022:\u0022beginDate\u0022,\u0022label\u0022:\u0022\\u5F00\\u59CB\\u65E5\\u671F\u0022,\u0022type\u0022:\u0022date\u0022,\u0022options\u0022:\u0022\u0022,\u0022default\u0022:\u0022\u0022},{\u0022name\u0022:\u0022endDate\u0022,\u0022label\u0022:\u0022\\u7ED3\\u675F\\u65E5\\u671F\u0022,\u0022type\u0022:\u0022date\u0022,\u0022options\u0022:\u0022\u0022,\u0022default\u0022:\u0022\u0022},{\u0022name\u0022:\u0022patientName\u0022,\u0022label\u0022:\u0022\\u60A3\\u8005\\u59D3\\u540D\u0022,\u0022type\u0022:\u0022text\u0022,\u0022options\u0022:\u0022\u0022,\u0022default\u0022:\u0022\u0022},{\u0022name\u0022:\u0022settleType\u0022,\u0022label\u0022:\u0022\\u7ED3\\u7B97\\u7C7B\\u578B\u0022,\u0022type\u0022:\u0022select\u0022,\u0022options\u0022:\u0022\\u95E8\\u8BCA,\\u4F4F\\u9662,\\u6025\\u8BCA\u0022,\u0022default\u0022:\u0022\u0022},{\u0022name\u0022:\u0022settleWay\u0022,\u0022label\u0022:\u0022\\u7ED3\\u7B97\\u65B9\\u5F0F\u0022,\u0022type\u0022:\u0022select\u0022,\u0022options\u0022:\u0022\\u533B\\u4FDD,\\u81EA\\u8D39,\\u5546\\u4FDD\u0022,\u0022default\u0022:\u0022\u0022}],\u0022datasets\u0022:[{\u0022id\u0022:\u0022ds1\u0022,\u0022name\u0022:\u0022\\u60A3\\u8005\\u7ED3\\u7B97\\u6570\\u636E\u0022,\u0022sourceType\u0022:\u0022sql\u0022,\u0022sourceRef\u0022:\u0022\u0022,\u0022customSql\u0022:\u0022SELECT s.settle_no, s.patient_name, s.card_no, s.dept_name, s.settle_date, s.settle_type, s.settle_way, s.total_amount, s.insurance_amount, s.self_amount FROM his_settle_info s WHERE (@beginDate IS NULL OR s.settle_date \\u003E= @beginDate) AND (@endDate IS NULL OR s.settle_date \\u003C= @endDate) AND (@patientName IS NULL OR s.patient_name LIKE \\u0027%\\u0027 \\u002B @patientName \\u002B \\u0027%\\u0027) AND (@settleType IS NULL OR s.settle_type = @settleType) AND (@settleWay IS NULL OR s.settle_way = @settleWay) ORDER BY s.settle_date DESC, s.settle_no\u0022,\u0022dataSourceId\u0022:3,\u0022fields\u0022:[]}],\u0022rows\u0022:[{\u0022height\u0022:35,\u0022type\u0022:\u0022title\u0022,\u0022dataset\u0022:\u0022\u0022,\u0022expand\u0022:\u0022\u0022},{\u0022height\u0022:28,\u0022type\u0022:\u0022header\u0022,\u0022dataset\u0022:\u0022\u0022,\u0022expand\u0022:\u0022\u0022},{\u0022height\u0022:25,\u0022type\u0022:\u0022data\u0022,\u0022dataset\u0022:\u0022ds1\u0022,\u0022expand\u0022:\u0022auto\u0022,\u0022zebra\u0022:true},{\u0022height\u0022:25,\u0022type\u0022:\u0022footer\u0022,\u0022dataset\u0022:\u0022ds1\u0022,\u0022expand\u0022:\u0022\u0022}],\u0022cols\u0022:[{\u0022width\u0022:60},{\u0022width\u0022:160},{\u0022width\u0022:100},{\u0022width\u0022:120},{\u0022width\u0022:150},{\u0022width\u0022:110},{\u0022width\u0022:100},{\u0022width\u0022:100},{\u0022width\u0022:110},{\u0022width\u0022:110},{\u0022width\u0022:110}],\u0022cells\u0022:[{\u0022r\u0022:0,\u0022c\u0022:0,\u0022value\u0022:\u0022\\u60A3\\u8005\\u7ED3\\u7B97\\u4FE1\\u606F\\u62A5\\u8868\u0022,\u0022colspan\u0022:11,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022,\u0022fontSize\u0022:16}},{\u0022r\u0022:1,\u0022c\u0022:0,\u0022value\u0022:\u0022\\u5E8F\\u53F7\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:1,\u0022c\u0022:1,\u0022value\u0022:\u0022\\u7ED3\\u7B97\\u5355\\u53F7\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:1,\u0022c\u0022:2,\u0022value\u0022:\u0022\\u60A3\\u8005\\u59D3\\u540D\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:1,\u0022c\u0022:3,\u0022value\u0022:\u0022\\u75C5\\u5386\\u53F7\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:1,\u0022c\u0022:4,\u0022value\u0022:\u0022\\u7ED3\\u7B97\\u79D1\\u5BA4\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:1,\u0022c\u0022:5,\u0022value\u0022:\u0022\\u7ED3\\u7B97\\u65E5\\u671F\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:1,\u0022c\u0022:6,\u0022value\u0022:\u0022\\u7ED3\\u7B97\\u7C7B\\u578B\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:1,\u0022c\u0022:7,\u0022value\u0022:\u0022\\u7ED3\\u7B97\\u65B9\\u5F0F\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:1,\u0022c\u0022:8,\u0022value\u0022:\u0022\\u603B\\u91D1\\u989D(\\u5143)\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:1,\u0022c\u0022:9,\u0022value\u0022:\u0022\\u533B\\u4FDD\\u652F\\u4ED8(\\u5143)\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:1,\u0022c\u0022:10,\u0022value\u0022:\u0022\\u4E2A\\u4EBA\\u81EA\\u4ED8(\\u5143)\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:2,\u0022c\u0022:0,\u0022value\u0022:\u0022${rowIndex}\u0022,\u0022style\u0022:{\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:2,\u0022c\u0022:1,\u0022value\u0022:\u0022${ds1.settle_no}\u0022},{\u0022r\u0022:2,\u0022c\u0022:2,\u0022value\u0022:\u0022${ds1.patient_name}\u0022},{\u0022r\u0022:2,\u0022c\u0022:3,\u0022value\u0022:\u0022${ds1.card_no}\u0022},{\u0022r\u0022:2,\u0022c\u0022:4,\u0022value\u0022:\u0022${ds1.dept_name}\u0022},{\u0022r\u0022:2,\u0022c\u0022:5,\u0022value\u0022:\u0022${ds1.settle_date}\u0022,\u0022style\u0022:{\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:2,\u0022c\u0022:6,\u0022value\u0022:\u0022${ds1.settle_type}\u0022,\u0022style\u0022:{\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:2,\u0022c\u0022:7,\u0022value\u0022:\u0022${ds1.settle_way}\u0022,\u0022style\u0022:{\u0022align\u0022:\u0022center\u0022}},{\u0022r\u0022:2,\u0022c\u0022:8,\u0022value\u0022:\u0022${ds1.total_amount}\u0022,\u0022style\u0022:{\u0022align\u0022:\u0022right\u0022}},{\u0022r\u0022:2,\u0022c\u0022:9,\u0022value\u0022:\u0022${ds1.insurance_amount}\u0022,\u0022style\u0022:{\u0022align\u0022:\u0022right\u0022}},{\u0022r\u0022:2,\u0022c\u0022:10,\u0022value\u0022:\u0022=IF(${ds1.self_amount} \\u003E 5000, \\u0027\\u5927\\u989D\\u81EA\\u4ED8\\u0027, ${ds1.self_amount})\u0022,\u0022style\u0022:{\u0022align\u0022:\u0022right\u0022}},{\u0022r\u0022:3,\u0022c\u0022:0,\u0022value\u0022:\u0022\\u5408\\u8BA1\u0022,\u0022colspan\u0022:8,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022right\u0022}},{\u0022r\u0022:3,\u0022c\u0022:8,\u0022value\u0022:\u0022${ds1.total_amount:SUM}\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022right\u0022}},{\u0022r\u0022:3,\u0022c\u0022:9,\u0022value\u0022:\u0022${ds1.insurance_amount:SUM}\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022right\u0022}},{\u0022r\u0022:3,\u0022c\u0022:10,\u0022value\u0022:\u0022${ds1.self_amount:SUM}\u0022,\u0022style\u0022:{\u0022bold\u0022:true,\u0022align\u0022:\u0022right\u0022}}]}" + } +} \ No newline at end of file diff --git a/market/skill/1789186345.json b/market/skill/1789186345.json new file mode 100644 index 0000000..57233f6 --- /dev/null +++ b/market/skill/1789186345.json @@ -0,0 +1,16 @@ +{ + "id": 1789186345, + "type": "skill", + "name": "读取文件", + "description": "根据要求目录获取文件内容", + "icon": "\uD83D\uDCE6", + "author": "pythonHuange", + "version": "1.0.0", + "updatedAt": "2026-09-12", + "content": { + "skillName": "读取文件", + "groupName": "", + "description": "根据要求目录获取文件内容", + "content": "根据要求目录获取文件内容" + } +} \ No newline at end of file diff --git "a/\345\220\257\345\212\250Juggle.bat" "b/\345\220\257\345\212\250Juggle.bat" new file mode 100644 index 0000000..83cb25f --- /dev/null +++ "b/\345\220\257\345\212\250Juggle.bat" @@ -0,0 +1,228 @@ +@echo off +chcp 65001 >nul +:: ============================================================ +:: Juggle 接口编排平台 - Windows 一键启动脚本 +:: Version: 1.0 +:: ============================================================ + +echo. +echo ╔═══════════════════════════════════════════════════════╗ +echo ║ Juggle 接口编排平台 - 一键启动 (Windows) ║ +echo ╚═══════════════════════════════════════════════════════╝ +echo. + +:: 获取脚本所在目录 +set SCRIPT_DIR=%~dp0 +cd /d "%SCRIPT_DIR%" + +:menu +echo 请选择启动方式: +echo. +echo [1] Docker 启动 (推荐,需要 Docker Desktop) +echo [2] Api + Vue 前后端同时启动 (需要 .NET 8 SDK 和 Node.js) +echo [3] 仅构建 Docker 镜像 +echo [4] 清理 Docker 容器和镜像 +echo [5] 查看日志 (Docker模式) +echo [0] 退出 +echo. +set /p choice=请输入选项 [1-5, 0退出]: + +if "%choice%"=="1" goto docker_start +if "%choice%"=="2" goto dotnet_run +if "%choice%"=="3" goto docker_build +if "%choice%"=="4" goto docker_clean +if "%choice%"=="5" goto docker_logs +if "%choice%"=="0" goto end + +echo. +echo [错误] 无效选项,请重新选择! +echo. +goto menu + +:docker_start +echo. +echo [1/3] 检查 Docker 状态... +docker info >nul 2>&1 +if errorlevel 1 ( + echo [错误] Docker 未运行,请先启动 Docker Desktop + echo. + pause + goto menu +) +echo [OK] Docker 运行正常 + +echo. +echo [2/3] 检查 Docker 镜像是否存在... +docker images pythonhuang/juggle-net8:v1.0 -q >nul 2>&1 +if errorlevel 1 ( + echo [提示] 本地未找到镜像,正在尝试拉取... + docker pull pythonhuang/juggle-net8:v1.0 + if errorlevel 1 ( + echo [提示] 拉取失败,尝试本地构建... + goto docker_build + ) +) + +echo. +echo [3/3] 启动 Juggle 容器... +docker run -d ^ + --name juggle ^ + --restart unless-stopped ^ + -p 9127:9127 ^ + -v juggle_data:/data ^ + -e ASPNETCORE_ENVIRONMENT=Production ^ + -e ASPNETCORE_URLS=http://+:9127 ^ + -e DB_PATH=/data/juggle.db ^ + pythonhuang/juggle-net8:v1.0 + +if errorlevel 1 ( + echo. + echo [错误] 容器启动失败,可能端口已被占用 + echo. + goto menu +) + +echo. +echo ╔══════════════════════════════════════════════════════════╗ +echo ║ Juggle 启动成功! ║ +echo ╠══════════════════════════════════════════════════════════╣ +echo ║ 访问地址: http://localhost:9127 ║ +echo ║ 默认账号: juggle / juggle ║ +echo ╚══════════════════════════════════════════════════════════╝ +echo. +echo 提示: 使用选项 [5] 可查看运行日志 +echo. +pause +goto end + +:docker_build +echo. +echo [1/2] 停止并移除旧容器 (如果存在)... +docker stop juggle >nul 2>&1 +docker rm juggle >nul 2>&1 + +echo. +echo [2/2] 构建 Docker 镜像 (这可能需要几分钟)... +docker build -t pythonhuang/juggle-net8:v1.0 . +if errorlevel 1 ( + echo. + echo [错误] Docker 构建失败 + echo. + pause + goto menu +) + +echo. +echo [OK] 镜像构建完成! +echo. +set /p start_now=是否立即启动? [Y/N]: +if /i "%start_now%"=="Y" goto docker_start +goto menu + +:docker_clean +echo. +echo [警告] 即将清理 Docker 资源... +echo. +docker stop juggle >nul 2>&1 +docker rm juggle >nul 2>&1 +docker volume rm juggle_data >nul 2>&1 +echo [OK] 清理完成 +echo. +pause +goto menu + +:docker_logs +docker logs -f juggle +goto end + +:dotnet_run +echo. +echo [1/6] 检查 .NET SDK 版本... +dotnet --version >nul 2>&1 +if errorlevel 1 ( + echo [错误] 未安装 .NET 8 SDK,请先安装: + echo https://dotnet.microsoft.com/download/dotnet/8.0 + echo. + pause + goto menu +) +for /f "delims=" %%v in ('dotnet --version') do set DOTNET_VER=%%v +echo [OK] .NET 版本: %DOTNET_VER% + +echo. +echo [2/6] 检查 Node.js 版本... +node --version >nul 2>&1 +if errorlevel 1 ( + echo [错误] 未安装 Node.js,请先安装: + echo https://nodejs.org/ + echo. + pause + goto menu +) +for /f "delims=" %%v in ('node --version') do set NODE_VER=%%v +echo [OK] Node.js 版本: %NODE_VER% + +echo. +echo [3/6] 还原 NuGet 包... +dotnet restore Juggle.sln +if errorlevel 1 ( + echo [错误] 包还原失败 + echo. + pause + goto menu +) + +echo. +echo [4/6] 构建后端项目... +dotnet build Juggle.sln -c Release +if errorlevel 1 ( + echo [错误] 项目构建失败 + echo. + pause + goto menu +) + +echo. +echo [5/6] 安装前端依赖... +cd JuggleNet6.Frontend +call npm install +if errorlevel 1 ( + echo [错误] 前端依赖安装失败 + echo. + pause + goto menu +) +cd .. + +echo. +echo [6/6] 启动服务... +echo. + +:: 启动后端 API +start "Juggle.Api" cmd /c "dotnet run --project Juggle.Api/Juggle.Api.csproj --no-build" + +:: 等待后端启动 +timeout /t 3 /nobreak >nul + +:: 启动前端 Vue +start "Juggle.Vue" cmd /c "cd JuggleNet6.Frontend && npm run dev" + +echo. +echo ╔══════════════════════════════════════════════════════════╗ +echo ║ Juggle 前后端启动成功! ║ +echo ╠══════════════════════════════════════════════════════════╣ +echo ║ 后端 API: http://localhost:9127 ║ +echo ║ 前端界面: http://localhost:5173 ║ +echo ╠══════════════════════════════════════════════════════════╣ +echo ║ 默认账号: juggle / juggle ║ +echo ║ 关闭窗口即可停止服务 ║ +echo ╚══════════════════════════════════════════════════════════╝ +echo. +echo 提示: 两个窗口分别运行后端和前端,关闭任意窗口不会影响另一个 +echo. +pause +goto end + +:end +echo. +echo再见!