From c285d224e4eb5fb6ea3002ac1bae5a1807e9da78 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Mon, 10 Nov 2025 17:11:09 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=89=8D=E7=AB=AF=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/.windsurfrules | 23 -- backend/frontend.rules | 291 ------------------ .../components/DeployFlowGraphModal.tsx | 161 ++++++---- 3 files changed, 94 insertions(+), 381 deletions(-) delete mode 100644 backend/.windsurfrules delete mode 100644 backend/frontend.rules diff --git a/backend/.windsurfrules b/backend/.windsurfrules deleted file mode 100644 index 5544dbb3..00000000 --- a/backend/.windsurfrules +++ /dev/null @@ -1,23 +0,0 @@ -你是一名java高级开发工程师,对你有以下要求 -1. 缺陷修正: -- 在提出修复建议前,应充分分析问题 -- 提供精准、有针对性的解决方案 -- 解释bug的根本原因 - -2. 保持简单: -- 优先考虑可读性和可维护性 -- 避免过度工程化的解决方案 -- 尽可能使用标准库和模式 -- 遵循正确、最佳实践、DRY原则、无错误、功能齐全的代码编写原则 - -3. 代码更改: -- 在做出改变之前提出一个清晰的计划 -- 一次将所有修改应用于单个文件 -- 请勿修改不相关的文件 - -4. 新增或者修改初始化数据 -- 新增或者修改数据库表需在V1.0.0__init_schema.sql、V1.0.1__init_data.sql中补充表结构和初始化数据,不要随意删除 - - - -记住要始终考虑每个项目的背景和特定需求。 \ No newline at end of file diff --git a/backend/frontend.rules b/backend/frontend.rules deleted file mode 100644 index 0b5435da..00000000 --- a/backend/frontend.rules +++ /dev/null @@ -1,291 +0,0 @@ -# 前端接口对接文档 - -## 通用说明 - -### 1. 接口响应格式 - -所有接口统一返回以下格式: -```typescript -interface Response { - success: boolean; // 请求是否成功 - code: number; // 状态码,200表示成功,其他表示失败 - message: string; // 提示信息 - data?: T; // 响应数据,可选 -} -``` - -### 2. 分页请求参数 -```typescript -interface PageQuery { - pageNum: number; // 页码,从1开始 - pageSize: number; // 每页大小 - sortField?: string; // 排序字段,可选 - sortOrder?: 'asc' | 'desc'; // 排序方式,可选 -} -``` - -### 3. 分页响应格式 -```typescript -interface PageResponse { - content: T[]; // 数据列表 - totalElements: number;// 总记录数 - totalPages: number; // 总页数 - size: number; // 每页大小 - number: number; // 当前页码(从0开始) - first: boolean; // 是否第一页 - last: boolean; // 是否最后一页 - empty: boolean; // 是否为空 -} -``` - -## 通用接口 - -### 1. 基础CRUD接口 -所有实体都支持以下基础操作接口: - -#### 1.1 分页查询 -```typescript -GET /api/v1/{module}/page - -请求参数:PageQuery & { - // 其他查询条件,根据具体模块定义 -} - -响应结果:Response> -``` - -#### 1.2 列表查询 -```typescript -GET /api/v1/{module}/list - -请求参数:{ - // 查询条件,根据具体模块定义 -} - -响应结果:Response -``` - -#### 1.3 获取详情 -```typescript -GET /api/v1/{module}/{id} - -响应结果:Response -``` - -#### 1.4 创建 -```typescript -POST /api/v1/{module} - -请求参数:{ - // 创建参数,根据具体模块定义 -} - -响应结果:Response -``` - -#### 1.5 更新 -```typescript -PUT /api/v1/{module}/{id} - -请求参数:{ - // 更新参数,根据具体模块定义 -} - -响应结果:Response -``` - -#### 1.6 删除 -```typescript -DELETE /api/v1/{module}/{id} - -响应结果:Response -``` - -#### 1.7 批量删除 -```typescript -DELETE /api/v1/{module}/batch - -请求参数:{ - ids: number[]; // ID列表 -} - -响应结果:Response -``` - -#### 1.8 导出数据 -```typescript -GET /api/v1/{module}/export - -请求参数:{ - // 查询条件,根据具体模块定义 -} - -响应结果:二进制文件流 -``` - -### 2. 树形结构接口 -对于树形结构的数据(如部门、菜单等),还支持以下接口: - -#### 2.1 获取树形数据 -```typescript -GET /api/v1/{module}/tree - -响应结果:Response - -interface TreeNode { - id: number; - parentId: number | null; - children: TreeNode[]; - // 其他字段根据具体模块定义 -} -``` - -### 3. 状态管理接口 -对于需要状态管理的数据(如租户、用户等),还支持以下接口: - -#### 3.1 获取状态 -```typescript -GET /api/v1/{module}/{id}/enabled - -响应结果:Response -``` - -#### 3.2 更新状态 -```typescript -PUT /api/v1/{module}/{id}/enabled - -请求参数: -enabled=true // 是否启用 - -响应结果:Response -``` - -## 错误处理 - -### 1. 错误码说明 -- 200:成功 -- 400:请求参数错误 -- 401:未认证 -- 403:无权限 -- 404:资源不存在 -- 500:服务器内部错误 - -### 2. 错误响应示例 -```json -{ - "success": false, - "code": 400, - "message": "请求参数错误", - "data": { - "field": "name", - "message": "名称不能为空" - } -} -``` - -## 接口调用示例 - -### TypeScript 示例 -```typescript -// 定义接口返回类型 -interface User { - id: number; - username: string; - enabled: boolean; -} - -// 分页查询 -async function getUserList(query: PageQuery & { username?: string }) { - const response = await axios.get>>('/api/v1/user/page', { - params: query - }); - return response.data; -} - -// 创建用户 -async function createUser(user: Omit) { - const response = await axios.post>('/api/v1/user', user); - return response.data; -} - -// 更新状态 -async function updateUserStatus(id: number, enabled: boolean) { - const response = await axios.put>(`/api/v1/user/${id}/enabled`, null, { - params: { enabled } - }); - return response.data; -} -``` - -### Vue3 + TypeScript 示例 -```typescript -// 在组件中使用 -import { ref, onMounted } from 'vue'; - -export default defineComponent({ - setup() { - const userList = ref([]); - const total = ref(0); - const loading = ref(false); - - const queryList = async (query: PageQuery) => { - try { - loading.value = true; - const response = await getUserList(query); - if (response.success) { - userList.value = response.data.content; - total.value = response.data.totalElements; - } - } finally { - loading.value = false; - } - }; - - onMounted(() => { - queryList({ - pageNum: 1, - pageSize: 10 - }); - }); - - return { - userList, - total, - loading, - queryList - }; - } -}); -``` - -## 注意事项 - -1. 请求头要求 -```typescript -{ - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ${token}' // JWT认证token -} -``` - -2. 日期时间格式 -- 请求参数:使用ISO 8601格式(YYYY-MM-DDTHH:mm:ss.sssZ) -- 响应数据:统一返回ISO 8601格式 - -3. 文件上传 -- 使用multipart/form-data格式 -- 文件大小限制:10MB - -4. 接口版本 -- 所有接口统一使用v1版本 -- URL格式:/api/v1/{module}/{resource} - -5. 安全性 -- 所有接口都需要JWT认证 -- Token过期时间:2小时 -- 需要定期刷新Token - -6. 错误处理 -- 统一使用axios拦截器处理错误 -- 401错误跳转到登录页 -- 其他错误统一提示 \ No newline at end of file diff --git a/frontend/src/pages/Dashboard/components/DeployFlowGraphModal.tsx b/frontend/src/pages/Dashboard/components/DeployFlowGraphModal.tsx index 2ee79f6e..ad1239da 100644 --- a/frontend/src/pages/Dashboard/components/DeployFlowGraphModal.tsx +++ b/frontend/src/pages/Dashboard/components/DeployFlowGraphModal.tsx @@ -71,16 +71,17 @@ const getLayoutedElements = ( const dagreGraph = new dagre.graphlib.Graph(); dagreGraph.setDefaultEdgeLabel(() => ({})); - const nodeWidth = 180; - const nodeHeight = 120; + const nodeWidth = 200; + const nodeHeight = 150; const isHorizontal = direction === 'LR'; dagreGraph.setGraph({ rankdir: direction, - nodesep: 50, - ranksep: 80, - marginx: 20, - marginy: 20, + nodesep: isHorizontal ? 80 : 100, // 同一层节点间距:横向80,纵向100 + ranksep: isHorizontal ? 150 : 120, // 层级间距:横向150,纵向120 + marginx: 40, + marginy: 40, + align: 'UL', // 对齐方式 }); nodes.forEach((node) => { @@ -137,57 +138,73 @@ const CustomFlowNode: React.FC = ({ data }) => { const nodeContent = (
+ {/* 顶部状态指示条 */} + {!isNotStarted && ( +
+ )} + {/* 节点名称 */} -
-
{nodeName}
+
+
{nodeName}
{canViewLog && ( - + )}
- {/* 节点状态 */} + {/* 节点状态 - 使用徽章样式 */}
{getNodeStatusText(status)}
- {/* 时间信息 */} - {!isNotStarted && ( -
- {displayDuration && ( -
- {isRunning ? '运行: ' : '时长: '} - {displayDuration} -
- )} + {/* 时间信息 - 更紧凑的显示 */} + {!isNotStarted && displayDuration && ( +
+
+ ⏱️ {displayDuration} +
)} - {/* 错误提示 */} + {/* 弹性空间,让底部提示始终在底部 */} +
+ + {/* 错误提示 - 增强样式 */} {hasFailed && errorMessage && ( -
- - 有错误 +
+ + 查看错误
)} - {/* 查看日志提示 */} - {canViewLog && ( -
- 点击查看日志 + {/* 查看日志提示 - 增强样式 */} + {canViewLog && !hasFailed && ( +
+ + 点击查看日志
)}
@@ -298,35 +315,39 @@ const ProgressCard: React.FC<{ flowData: DeployRecordFlowGraph }> = ({ flowData
-
- 已执行 - - {executedNodeCount} / {totalNodeCount} 节点 +
+ 已执行 + + {executedNodeCount} / {totalNodeCount}
- -
- {Math.round(progress)}% +
+ +
+ + {Math.round(progress)}% + +
-
-
- - 成功 - {successNodeCount} +
+
+ + 成功 + {successNodeCount}
-
- - 失败 - {failedNodeCount} +
+ + 失败 + {failedNodeCount}
-
- - 运行中 - {runningNodeCount} +
+ 0 && "animate-spin")} /> + 运行中 + {runningNodeCount}
@@ -433,7 +454,7 @@ const MonitoringAlert: React.FC<{ flowData: DeployRecordFlowGraph }> = ({ flowDa */ const DeployInfoPanel: React.FC<{ flowData: DeployRecordFlowGraph }> = ({ flowData }) => { return ( -
+
@@ -581,7 +602,7 @@ export const DeployFlowGraphModal: React.FC = ({ return { id: node.id, type: 'custom', - position: node.position || { x: 0, y: 0 }, // 使用设计器中保存的坐标 + position: { x: 0, y: 0 }, // 忽略设计器坐标,使用dagre自动布局 data: { nodeName: node.nodeName, nodeType: instance?.nodeType || node.nodeType, // 优先使用运行时的 nodeType @@ -617,32 +638,37 @@ export const DeployFlowGraphModal: React.FC = ({ const targetStatus = targetInstance?.status || 'NOT_STARTED'; // 根据节点状态确定边的样式 - let strokeColor = '#d1d5db'; // 默认灰色 - let strokeWidth = 2; + let strokeColor = '#cbd5e1'; // 默认浅灰色 + let strokeWidth = 3; // 增加连线粗细 let animated = false; let strokeDasharray: string | undefined = undefined; // 源节点已完成 + 目标节点也已完成/运行中 = 绿色实线 if (sourceStatus === 'COMPLETED' && (targetStatus === 'COMPLETED' || targetStatus === 'RUNNING')) { strokeColor = '#10b981'; // 绿色 + strokeWidth = 3.5; } // 源节点 TERMINATED = 橙色实线 else if (sourceStatus === 'TERMINATED') { strokeColor = '#f59e0b'; // 橙色 + strokeWidth = 3.5; } // 源节点失败 = 红色实线 else if (sourceStatus === 'FAILED') { strokeColor = '#ef4444'; // 红色 + strokeWidth = 3.5; } // 源节点运行中 = 蓝色动画 else if (sourceStatus === 'RUNNING') { strokeColor = '#3b82f6'; // 蓝色 + strokeWidth = 4; // 运行中的线更粗 animated = true; } // 源节点完成 + 目标节点未开始 = 虚线(即将执行的路径) else if ((sourceStatus === 'COMPLETED' || sourceStatus === 'TERMINATED') && targetStatus === 'NOT_STARTED') { - strokeColor = '#9ca3af'; // 浅灰色 - strokeDasharray = '5,5'; + strokeColor = '#94a3b8'; // 稍深的灰色 + strokeDasharray = '8,4'; + strokeWidth = 2.5; } return { @@ -659,8 +685,8 @@ export const DeployFlowGraphModal: React.FC = ({ markerEnd: { type: 'arrowclosed', color: strokeColor, - width: 20, - height: 20, + width: 24, + height: 24, }, }; }); @@ -773,16 +799,17 @@ export const DeployFlowGraphModal: React.FC = ({ >