diff --git a/frontend/.cursorrules b/frontend/.cursorrules deleted file mode 100644 index 209e4803..00000000 --- a/frontend/.cursorrules +++ /dev/null @@ -1,159 +0,0 @@ -你是一名高级前端开发人员,是ReactJS, NextJS, JavaScript, TypeScript, HTML, CSS和现代UI/UX框架(例如,TailwindCSS, Shadcn, Radix)的专家。你深思熟虑,给出细致入微的答案,并且善于推理。你细心地提供准确、真实、深思熟虑的答案,是推理的天才。 -# 严格遵循的要求 -- 不要随意删除代码,请先详细浏览下现在所有的代码,再进行询问修改,得到确认再修改。重点切记 -- 首先,一步一步地思考——详细描述你在伪代码中构建什么的计划。 -- 确认,然后写代码! -- 始终编写正确、最佳实践、DRY原则(不要重复自己)、无错误、功能齐全且可工作的代码,还应与下面代码实施指南中列出的规则保持一致。 -- 专注于简单易读的代码,而不是高性能。 -- 完全实现所有要求的功能。 -- 不要留下待办事项、占位符或缺失的部分。 -- 确保代码完整!彻底确认。 -- 包括所有必需的导入的包,并确保关键组件的正确命名。 -- 如果你认为可能没有正确答案,你就说出来。 -- 如果你不知道答案,就说出来,而不是猜测。 -- 可以提出合理化的建议,但是需要等待是否可以。 -- 对于新设计的实体类、字段、方法都要写注释,对于实际的逻辑要有逻辑注释。 -- 不要随意修改现在的接口调用路径,如果不知道接口是什么,可以问。 -#代码实现指南 -在编写代码时遵循以下规则: -- 尽可能使用早期返回,使代码更具可读性。 -- 总是使用顺风类样式HTML元素;避免使用CSS或标签。 -- 尽可能在类标记中使用“ class: ”而不是第三操作符。 -- 使用描述性变量名和函数/const名。此外,事件函数应该以“handle”前缀命名,就像onClick的“handleClick”和onKeyDown的“handleKeyDown”。 -- 在元素上实现可访问性特性。例如,一个标签应该有tabindex= " 0 "、aria-label、on:click和on:keydown以及类似的属性。 -— 使用const代替函数,例如:const toggle =() =>。另外,如果可能的话,定义一个类型。 - -# Deploy Ease Platform 前端开发规范 - -## 1. 项目结构规范 - -``` -src/ -├── components/ # 公共组件 -├── pages/ # 页面组件 -│ └── System/ # 系统管理模块 -├── layouts/ # 布局组件 -├── router/index.ts # 路由配置 -├── store/ # 状态管理 -├── services/ # API 服务 -├── utils/ # 工具函数 -├── hooks/ # 自定义 Hooks -└── types/ # TS 类型定义 -│ └── pages.ts # 分页基础类 - -ModuleName/ # 模块结构 -├── components/ # 模块私有组件 -├── type.ts # 类型定义 -├── service.ts # API 服务 -└── index.tsx # 模块入口 -``` - -## 2. 命名与类型规范 - -1. 文件命名: - - 组件:PascalCase(`UserProfile.tsx`) - - 工具函数:camelCase(`formatDate.ts`) - - 样式:组件同名(`UserProfile.module.css`) - - Redux:`xxxSlice.ts` - - 类型:`types.ts` - - 服务:`service.ts` - -2. 变量命名: - - 常量:UPPER_SNAKE_CASE - - 变量:camelCase - - 接口:以 `I` 开头,PascalCase - - 类型:以 `T` 开头,PascalCase - - 事件处理:`handle` 前缀 - - 异步函数:动词开头(`fetchData`) - -3. 已定义了基础类型src\types\base下直接继承即可,把Response query request 的定义都模块的types.ts文件中: - -## 3. 服务层规范 - -1. 方法定义: - ```typescript - // 推荐写法 - 使用 request 工具 - export const resetPassword = (id: number, password: string) => - request.post(`/api/v1/users/${id}/reset-password`, { password }); - - // 标准 CRUD 接口 - export const getList = (params?: Query) => - request.get>('/api/v1/xxx/page', { params }); // 列表接口统一使用 /page 后缀 - - export const create = (data: Request) => - request.post('/api/v1/xxx', data); - - export const update = (id: number, data: Request) => - request.put(`/api/v1/xxx/${id}`, data); - - export const remove = (id: number) => - request.delete(`/api/v1/xxx/${id}`); - - export const batchRemove = (ids: number[]) => - request.post('/api/v1/xxx/batch-delete', { ids }); - - export const exportData = (params?: Query) => - request.download('/api/v1/xxx/export', undefined, { params }); - ``` - -2. 规范要点: - - 统一使用 src\utils\request.ts - - 使用泛型指定响应数据类型 - - 错误处理在拦截器中统一处理 - - 使用模板字符串拼接路径 - - API 路径使用 `/api/v1/` 前缀 - - 资源使用复数形式(users, roles) - - 特殊操作使用动词(export, import) - -3. 列表数据获取规范: - - API 路径必须以 `/page` 结尾,例如:`/api/v1/workflow-definitions/page` - - 服务层方法定义示例: - ```typescript - export const getDefinitions = (params?: WorkflowDefinitionQuery) => - request.get>(`${DEFINITION_URL}/page`, { params }); - ``` - - 组件中获取列表数据: - ```typescript - const response = await getDefinitions(); - if (response) { - setList(response.content); // 使用 response.content 获取列表数据 - } - ``` - - 分页数据结构统一使用 `Page` 类型 - - 列表数据必须位于返回结果的 `content` 字段中 - -## 4. 类型处理规则: - - request 工具的泛型参数 T 表示业务数据类型 - - 响应拦截器负责从 Response 中提取 data - - 服务方法直接使用业务数据类型作为泛型参数 - - 组件中可以直接使用返回的业务数据 - - TypeScript 类型系统能正确推断类型 - -## 5. React 开发规范 - -1. 组件开发: - - 使用函数组件和箭头函数 - - Props 类型必须定义 - - 必须提供默认值 - - 使用 memo 优化 - - 复杂组件需拆分 - -2. Hooks 使用: - - 自定义 hooks 以 `use` 开头 - - 使用 TypeScript 泛型 - - 使用 useCallback 和 useMemo - - 使用 Promise.all 处理并行请求 - -3. 状态管理: - - 使用 Redux Toolkit - - 持久化数据存储在 localStorage - - Token、用户信息、菜单统一管理 - -## 6. 样式与布局规范 - -1. CSS 规范: - - 使用 CSS Modules - - 类名使用 kebab-case - - 避免内联样式 - - 响应式适配 - - 支持暗色主题 \ No newline at end of file diff --git a/frontend/.windsurfrules b/frontend/.windsurfrules deleted file mode 100644 index 3b6c2946..00000000 --- a/frontend/.windsurfrules +++ /dev/null @@ -1,159 +0,0 @@ -你是一名高级前端开发人员,是ReactJS, NextJS, JavaScript, TypeScript, HTML, CSS和现代UI/UX框架(例如,TailwindCSS, Shadcn, Radix)的专家。你深思熟虑,给出细致入微的答案,并且善于推理。你细心地提供准确、真实、深思熟虑的答案,是推理的天才。 -# 严格遵循的要求 -- 不要随意删除代码,请先详细浏览下现在所有的代码,再进行询问修改,得到确认再修改。重点切记 -- 首先,一步一步地思考——详细描述你在伪代码中构建什么的计划。 -- 确认,然后写代码! -- 始终编写正确、最佳实践、DRY原则(不要重复自己)、无错误、功能齐全且可工作的代码,还应与下面代码实施指南中列出的规则保持一致。 -- 专注于简单易读的代码,而不是高性能。 -- 完全实现所有要求的功能。 -- 不要留下待办事项、占位符或缺失的部分。 -- 确保代码完整!彻底确认。 -- 包括所有必需的导入的包,并确保关键组件的正确命名。 -- 如果你认为可能没有正确答案,你就说出来。 -- 如果你不知道答案,就说出来,而不是猜测。 -- 可以提出合理化的建议,但是需要等待是否可以。 -- 对于新设计的实体类、字段、方法都要写注释,对于实际的逻辑要有逻辑注释。 -- 不要随意修改现在的接口调用路径,如果不知道接口是什么,可以问。 -#代码实现指南 -在编写代码时遵循以下规则: -- 尽可能使用早期返回,使代码更具可读性。 -- 总是使用顺风类样式HTML元素;避免使用CSS或标签。 -- 尽可能在类标记中使用“ class: ”而不是第三操作符。 -- 使用描述性变量名和函数/const名。此外,事件函数应该以“handle”前缀命名,就像onClick的“handleClick”和onKeyDown的“handleKeyDown”。 -- 在元素上实现可访问性特性。例如,一个标签应该有tabindex= " 0 "、aria-label、on:click和on:keydown以及类似的属性。 -— 使用const代替函数,例如:const toggle =() =>。另外,如果可能的话,定义一个类型。 - -# Deploy Ease Platform 前端开发规范 - -## 1. 项目结构规范 - -``` -src/ -├── components/ # 公共组件 -├── pages/ # 页面组件 -│ └── System/ # 系统管理模块 -├── layouts/ # 布局组件 -├── router/index.ts # 路由配置 -├── store/ # 状态管理 -├── services/ # API 服务 -├── utils/ # 工具函数 -├── hooks/ # 自定义 Hooks -└── types/ # TS 类型定义 -│ └── pages.ts # 分页基础类 - -ModuleName/ # 模块结构 -├── components/ # 模块私有组件 -├── type.ts # 类型定义 -├── service.ts # API 服务 -└── index.tsx # 模块入口 -``` - -## 2. 命名与类型规范 - -1. 文件命名: - - 组件:PascalCase(`UserProfile.tsx`) - - 工具函数:camelCase(`formatDate.ts`) - - 样式:组件同名(`UserProfile.module.css`) - - Redux:`xxxSlice.ts` - - 类型:`types.ts` - - 服务:`service.ts` - -2. 变量命名: - - 常量:UPPER_SNAKE_CASE - - 变量:camelCase - - 接口:以 `I` 开头,PascalCase - - 类型:以 `T` 开头,PascalCase - - 事件处理:`handle` 前缀 - - 异步函数:动词开头(`fetchData`) - -3. 要使用和继承定义了基础类型src\types\base.ts - -## 3. 服务层规范 - -1. 方法定义: - ```typescript - // 推荐写法 - 使用 request 工具 - export const resetPassword = (id: number, password: string) => - request.post(`/api/v1/users/${id}/reset-password`, { password }); - - // 标准 CRUD 接口 - export const getList = (params?: Query) => - request.get>('/api/v1/xxx/page', { params }); // 列表接口统一使用 /page 后缀 - - export const create = (data: Request) => - request.post('/api/v1/xxx', data); - - export const update = (id: number, data: Request) => - request.put(`/api/v1/xxx/${id}`, data); - - export const remove = (id: number) => - request.delete(`/api/v1/xxx/${id}`); - - export const batchRemove = (ids: number[]) => - request.post('/api/v1/xxx/batch-delete', { ids }); - - export const exportData = (params?: Query) => - request.download('/api/v1/xxx/export', undefined, { params }); - ``` - -2. 规范要点: - - 统一使用 src\utils\request.ts - - 使用泛型指定响应数据类型 - - 错误处理在拦截器中统一处理 - - 使用模板字符串拼接路径 - - API 路径使用 `/api/v1/` 前缀 - - 资源使用复数形式(users, roles) - - 特殊操作使用动词(export, import) - -3. 列表数据获取规范: - - API 路径必须以 `/page` 结尾,例如:`/api/v1/workflow-definitions/page` - - 服务层方法定义示例: - ```typescript - export const getDefinitions = (params?: WorkflowDefinitionQuery) => - request.get>(`${DEFINITION_URL}/page`, { params }); - ``` - - 组件中获取列表数据: - ```typescript - const response = await getDefinitions(); - if (response) { - setList(response.content); // 使用 response.content 获取列表数据 - } - ``` - - 分页数据结构统一使用 `Page` 类型 - - 列表数据必须位于返回结果的 `content` 字段中 - -## 4. 类型处理规则: - - request 工具的泛型参数 T 表示业务数据类型 - - 响应拦截器负责从 Response 中提取 data - - 服务方法直接使用业务数据类型作为泛型参数 - - 组件中可以直接使用返回的业务数据 - - TypeScript 类型系统能正确推断类型 - -## 5. React 开发规范 - -1. 组件开发: - - 使用函数组件和箭头函数 - - Props 类型必须定义 - - 必须提供默认值 - - 使用 memo 优化 - - 复杂组件需拆分 - -2. Hooks 使用: - - 自定义 hooks 以 `use` 开头 - - 使用 TypeScript 泛型 - - 使用 useCallback 和 useMemo - - 使用 Promise.all 处理并行请求 - -3. 状态管理: - - 使用 Redux Toolkit - - 持久化数据存储在 localStorage - - Token、用户信息、菜单统一管理 - -## 6. 样式与布局规范 - -1. CSS 规范: - - 使用 CSS Modules - - 类名使用 kebab-case - - 避免内联样式 - - 响应式适配 - - 支持暗色主题 \ No newline at end of file diff --git a/frontend/api.md b/frontend/api.md deleted file mode 100644 index 9e674001..00000000 --- a/frontend/api.md +++ /dev/null @@ -1,659 +0,0 @@ -# API 接口文档 - -## 1. 通用说明 - -### 1.1 接口规范 - -- 基础路径: `/api/v1` -- 请求方式: REST风格 -- 数据格式: JSON -- 字符编码: UTF-8 -- 时间格式: ISO8601 (YYYY-MM-DDTHH:mm:ss.SSSZ) - -### 1.2 通用响应格式 - -```json -{ - "code": 0, // 响应码,0表示成功,非0表示失败 - "message": "成功", // 响应消息 - "data": { // 响应数据 - // 具体数据结构 - } -} -``` - -### 1.3 通用查询参数 - -分页查询参数: -```json -{ - "page": 1, // 页码,从1开始 - "size": 10, // 每页大小 - "sort": ["id,desc"], // 排序字段,可选 - "keyword": "", // 关键字搜索,可选 -} -``` - -### 1.4 通用错误码 - -| 错误码 | 说明 | 处理建议 | -|--------|------|----------| -| 0 | 成功 | - | -| 1000 | 系统内部错误 | 联系管理员 | -| 1001 | 数据库操作失败 | 重试或联系管理员 | -| 1002 | 并发操作冲突 | 刷新后重试 | -| 2000 | 参数验证失败 | 检查参数 | -| 2001 | 数据不存在 | 检查参数 | -| 2002 | 数据已存在 | 检查参数 | - -## 2. 工作流定义��口 - -### 2.1 创建工作流定义 - -**接口说明**:创建新的工作流定义 - -**请求路径**:POST /workflow-definitions - -**请求参数**: -```json -{ - "code": "string", // 工作流编码,必填,唯一 - "name": "string", // 工作流名称,必填 - "description": "string", // 描述,可选 - "nodeConfig": { // 节点配置,必填 - "nodes": [{ - "id": "string", // 节点ID - "type": "string", // 节点类型 - "name": "string", // 节点名称 - "config": { // 节点配置 - // 具体配置项根据节点类型定义 - } - }] - }, - "transitionConfig": { // 流转配置,必填 - "transitions": [{ - "from": "string", // 来源节点ID - "to": "string", // 目标节点ID - "condition": "string" // 流转条件 - }] - }, - "formDefinition": { // 表单定义,必填 - // 表单配置项 - }, - "graphDefinition": { // 图形定义,必填 - // 图形布局配置 - } -} -``` - -**响应数据**: -```json -{ - "code": 0, - "message": "成功", - "data": { - "id": "long", // 工作流定义ID - "code": "string", // 工作流编码 - "name": "string", // 工作流名称 - "description": "string", // 描述 - "version": 1, // 版本号 - "status": "DRAFT", // 状态:DRAFT-草稿、PUBLISHED-已发布、DISABLED-已禁用 - "enabled": true, // 是否启用 - "nodeConfig": {}, // 节点配置 - "transitionConfig": {}, // 流转配置 - "formDefinition": {}, // 表单定义 - "graphDefinition": {}, // 图形定义 - "createTime": "string", // 创建时间 - "updateTime": "string" // 更新时间 - } -} -``` - -### 2.2 更新工作流定义 - -**接口说明**:更新工作流定义,仅草稿状态可更新 - -**请求路径**:PUT /workflow-definitions/{id} - -**路径参数**: -- id: 工作流定义ID - -**请求参数**:同创建接口 - -**响应数据**:同创建接口 - -### 2.3 发布工作流定义 - -**接口说明**:发布工作流定义,使其可被使用 - -**请求路径**:POST /workflow-definitions/{id}/publish - -**路径参数**: -- id: 工作流定义ID - -**响应数据**:同创建接口 - -### 2.4 禁用工作流定义 - -**接口说明**:禁用工作流定义,禁止新建实例 - -**请求路径**:POST /workflow-definitions/{id}/disable - -**路径参数**: -- id: 工作流定义ID - -**响应数据**:同创建接口 - -### 2.5 启用工作流定义 - -**接口说明**:启用已��用的工作流定义 - -**请求路径**:POST /workflow-definitions/{id}/enable - -**路径参数**: -- id: 工作流定义ID - -**响应数据**:同创建接口 - -### 2.6 创建新版本 - -**接口说明**:基于现有工作流定义创建新版本 - -**请求路径**:POST /workflow-definitions/{id}/versions - -**路径参数**: -- id: 工作流定义ID - -**响应数据**:同创建接口 - -### 2.7 查询工作流定义列表 - -**接口说明**:分页查询工作流定义列表 - -**请求路径**:GET /workflow-definitions - -**请求参数**: -```json -{ - "page": 1, // 页码,从1开始 - "size": 10, // 每页大小 - "sort": ["id,desc"], // 排序字段 - "keyword": "", // 关键字搜索 - "status": "DRAFT", // 状态过滤 - "enabled": true // 是否启用 -} -``` - -**响应数据**: -```json -{ - "code": 0, - "message": "成功", - "data": { - "content": [{ // 列表数据 - // 工作流定义数据,同创建接口 - }], - "totalElements": 100, // 总记录数 - "totalPages": 10, // 总页数 - "size": 10, // 每页大小 - "number": 1 // 当前页码 - } -} -``` - -## 3. 工作流实例接口 - -### 3.1 创建工作流实例 - -**接口说明**:创建工作流实例 - -**请求路径**:POST /workflow-instances - -**请求参数**: -```json -{ - "definitionId": "long", // 工作流定义ID,必填 - "businessKey": "string", // 业务标识,可选 - "variables": { // 初始变量,可选 - "key": "value" - } -} -``` - -**响应数据**: -```json -{ - "code": 0, - "message": "成功", - "data": { - "id": "long", // 实例ID - "definitionId": "long", // 定义ID - "businessKey": "string",// 业务标识 - "status": "CREATED", // 状态:CREATED-已创建、RUNNING-运行中、SUSPENDED-已暂停、COMPLETED-已完成、TERMINATED-已终止 - "startTime": "string", // 开始时间 - "endTime": "string", // 结束时间 - "variables": {}, // 变量 - "createTime": "string", // 创建时间 - "updateTime": "string" // 更新时间 - } -} -``` - -### 3.2 启动工作流实例 - -**接口说明**:启动工作流实例 - -**请求路径**:POST /workflow-instances/{id}/start - -**路径参数**: -- id: 实例ID - -**响应数据**:同创建接口 - -### 3.3 暂停工作流实例 - -**接口说明**:暂停运行中的工作流实例 - -**请求路径**:POST /workflow-instances/{id}/suspend - -**路径参数**: -- id: 实例ID - -**响应数据**:同创建接口 - -### 3.4 恢复工作流实例 - -**接口说明**:恢复已暂停的工作流实例 - -**请求路径**:POST /workflow-instances/{id}/resume - -**路径参数**: -- id: 实例ID - -**响应数据**:同创建接口 - -### 3.5 终止工作流实例 - -**接口说明**:强制终止工作流实例 - -**请求路径**:POST /workflow-instances/{id}/terminate - -**路径参数**: -- id: 实例ID - -**响应数据**:同创建接口 - -### 3.6 查询工作流实例列表 - -**接口说明**:分页查询工作流实例列表 - -**请求路径**:GET /workflow-instances - -**请求参数**: -```json -{ - "page": 1, // 页码,从1开始 - "size": 10, // 每页大小 - "sort": ["id,desc"], // 排序字段 - "keyword": "", // 关键字搜索 - "status": "RUNNING", // 状态过滤 - "definitionId": "long", // 定义ID过滤 - "businessKey": "string" // 业务标识过滤 -} -``` - -**响应数据**: -```json -{ - "code": 0, - "message": "成功", - "data": { - "content": [{ // 列表数据 - // 工作流实例数据,同创建接口 - }], - "totalElements": 100, // 总记录数 - "totalPages": 10, // 总页数 - "size": 10, // 每页大小 - "number": 1 // 当前页码 - } -} -``` - -## 4. 节点实例接口 - -### 4.1 查询节点实例列表 - -**接口说明**:查询工作流实例的节点列表 - -**请求路径**:GET /workflow-instances/{instanceId}/nodes - -**路径参数**: -- instanceId: 工作流实例ID - -**请求参数**: -```json -{ - "status": "RUNNING" // 状态过滤,可选 -} -``` - -**响应数据**: -```json -{ - "code": 0, - "message": "成功", - "data": [{ - "id": "long", // 节点实例ID - "workflowInstanceId": "long", // 工作流实例ID - "nodeId": "string", // 节点定义ID - "nodeName": "string", // 节点名称 - "nodeType": "string", // 节点类型 - "status": "string", // 状态:CREATED、RUNNING、COMPLETED、FAILED - "startTime": "string", // 开始时间 - "endTime": "string", // 结束时间 - "output": "string", // 输出结果 - "error": "string", // 错误信息 - "createTime": "string", // 创建时间 - "updateTime": "string" // 更新时间 - }] -} -``` - -## 5. 工作流变量接口 - -### 5.1 设置变量 - -**接口说明**:设置工作流实例变量 - -**请求路径**:POST /workflow-instances/{instanceId}/variables - -**路径参数**: -- instanceId: 工作流实例ID - -**请求参数**: -```json -{ - "name": "string", // 变量名,必填 - "value": "object", // 变量值,必�� - "scope": "GLOBAL" // 作用域:GLOBAL-全局、NODE-节点,可选,默认GLOBAL -} -``` - -**响应数据**: -```json -{ - "code": 0, - "message": "成功" -} -``` - -### 5.2 获取变量 - -**接口说明**:获取工作流实例变量 - -**请求路径**:GET /workflow-instances/{instanceId}/variables - -**路径参数**: -- instanceId: 工作流实例ID - -**请求参数**: -```json -{ - "scope": "GLOBAL" // 作用域过滤,可选 -} -``` - -**响应数据**: -```json -{ - "code": 0, - "message": "成功", - "data": { - "variableName": "variableValue" - } -} -``` - -## 6. 工作流日志接口 - -### 6.1 查询日志列表 - -**接口说明**:查询工作流实例日志 - -**请求路径**:GET /workflow-instances/{instanceId}/logs - -**路径参数**: -- instanceId: 工作流实例ID - -**请求参数**: -```json -{ - "nodeId": "string", // 节点ID过滤,可选 - "level": "INFO", // 日志级别过滤:DEBUG、INFO、WARN、ERROR,可选 - "startTime": "string", // 开始时间过滤,可选 - "endTime": "string" // 结束时间过滤,可选 -} -``` - -**响应数据**: -```json -{ - "code": 0, - "message": "成功", - "data": [{ - "id": "long", // 日志ID - "workflowInstanceId": "long", // 工作流实例ID - "nodeId": "string", // 节点ID - "level": "string", // 日志级别 - "content": "string", // 日志内容 - "detail": "string", // 详细信息 - "createTime": "string" // 创建时间 - }] -} -``` - -## 7. 节点类型接口 - -### 7.1 查询节点类型列表 - -**接口说明**:查询可用的节点类型列表 - -**请求路径**:GET /node-types - -**请求参数**: -```json -{ - "enabled": true, // 是否启用过滤,可选 - "category": "TASK" // 类型分类过滤:TASK、EVENT、GATEWAY,可选 -} -``` - -**响应数据**: -```json -{ - "code": 0, - "message": "成功", - "data": [{ - "id": "long", // 节点类型ID - "code": "string", // 节点类型编码 - "name": "string", // 节点类型名称 - "category": "string", // 分类 - "description": "string", // 描述 - "enabled": true, // 是否启用 - "icon": "string", // 图标 - "color": "string", // 颜色 - "executors": [{ // 执行器列表(仅TASK类型) - "code": "string", // 执行器编码 - "name": "string", // 执行器名称 - "description": "string", // 描述 - "configSchema": {} // 配置模式 - }], - "createTime": "string", // 创建时间 - "updateTime": "string" // 更新时间 - }] -} -``` - -### 7.2 获取节点执行器列表 - -**接口说明**:获取指定节点类型支持的执行器列表 - -**请求路径**:GET /node-types/{code}/executors - -**路径参数**: -- code: 节点类型编码 - -**响应数据**: -```json -{ - "code": 0, - "message": "成功", - "data": [{ - "code": "string", // 执行器编码 - "name": "string", // 执行器名称 - "description": "string", // 描述 - "configSchema": { // 配置模式 - "type": "object", - "properties": { - // 具体配置项定义 - }, - "required": [] // 必填项 - } - }] -} -``` - -## 8. 错误码说明 - -### 8.1 系统错误 (1xxx) -- 1000: 系统内部错误 -- 1001: 数据库操作失败 -- 1002: 并发操作冲突 - -### 8.2 通用业务错误 (2xxx) -- 2000: 参数验证失败 -- 2001: 数据不存在 -- 2002: 数据已存在 - -### 8.3 工作流定义错误 (3xxx) -- 3000: 工作流定义不存在 -- 3001: 工作流编码已存在 -- 3002: 工作流定义非草稿状态 -- 3003: 工作流定义未发布 -- 3004: 工作流定义已禁用 -- 3005: 节点配置无效 -- 3006: 流转配置无效 -- 3007: 表单配置无效 - -### 8.4 工作流实例错误 (4xxx) -- 4000: 工作流实例不存在 -- 4001: 工作流实例状态无效 -- 4002: 工作流实例已终止 -- 4003: 节点实例不存在 -- 4004: 变量类型无效 - -## 9. 数据结构说明 - -### 9.1 工作流状态 - -```typescript -enum WorkflowStatus { - DRAFT = "DRAFT", // 草稿 - PUBLISHED = "PUBLISHED", // 已发布 - DISABLED = "DISABLED" // 已禁用 -} -``` - -### 9.2 实例状态 - -```typescript -enum InstanceStatus { - CREATED = "CREATED", // 已创建 - RUNNING = "RUNNING", // 运行中 - SUSPENDED = "SUSPENDED", // 已暂停 - COMPLETED = "COMPLETED", // 已完成 - TERMINATED = "TERMINATED"// 已终止 -} -``` - -### 9.3 节点状态 - -```typescript -enum NodeStatus { - CREATED = "CREATED", // 已创建 - RUNNING = "RUNNING", // 运行中 - COMPLETED = "COMPLETED", // 已完成 - FAILED = "FAILED" // 失败 -} -``` - -### 9.4 日志级别 - -```typescript -enum LogLevel { - DEBUG = "DEBUG", - INFO = "INFO", - WARN = "WARN", - ERROR = "ERROR" -} -``` - -### 9.5 变量作用域 - -```typescript -enum VariableScope { - GLOBAL = "GLOBAL", // 全局变量 - NODE = "NODE" // 节点变量 -} -``` - -## 10. 最佳实践 - -### 10.1 工作流设计 - -1. 工作流定义创建流程: - - 创建草稿 - - 配置节点和流转 - - 验证配置 - - 发布使用 - -2. 节点类型选择: - - 根据业务场景选择合适的节点类型 - - 配置合适的执行器 - - 设置必要的变量 - -### 10.2 实例管理 - -1. 实例生命周期管理: - - 创建 -> 启动 -> 运行 -> 完成 - - 必要时可暂停或终止 - - 记录关键节点日志 - -2. 变量使用: - - 合理使用变量作用域 - - 及时清理无用变量 - - 注意变量类型匹配 - -### 10.3 错误处理 - -1. 异常处理: - - 捕获所有可能的错误码 - - 提供友好的错误提示 - - 记录详细的错误日志 - -2. 重试机制: - - 对非致命错误进行重试 - - 设置合理的重试间隔 - - 限制最大重试次数 - -### 10.4 性能优化 - -1. 查询优化: - - 合理使用分页 - - 避免大量数据查询 - - 使用合适的查询条件 - -2. 缓存使用: - - 缓存常用数据 - - 及时更新缓存 - - 避免缓存穿透 \ No newline at end of file diff --git a/frontend/src/layouts/BasicLayout.tsx b/frontend/src/layouts/BasicLayout.tsx index 3903df68..edd5f42b 100644 --- a/frontend/src/layouts/BasicLayout.tsx +++ b/frontend/src/layouts/BasicLayout.tsx @@ -196,8 +196,8 @@ const BasicLayout: React.FC = () => { - - {userInfo?.nickname || userInfo?.username} + + {userInfo?.nickname || userInfo?.username} diff --git a/frontend/src/pages/System/Department/List/components/DeleteDialog.tsx b/frontend/src/pages/System/Department/List/components/DeleteDialog.tsx index 299847ee..047e8409 100644 --- a/frontend/src/pages/System/Department/List/components/DeleteDialog.tsx +++ b/frontend/src/pages/System/Department/List/components/DeleteDialog.tsx @@ -34,7 +34,7 @@ const DeleteDialog: React.FC = ({ return ( - + 确认删除部门? @@ -48,7 +48,7 @@ const DeleteDialog: React.FC = ({ )} -
+

部门编码: {record.code}

diff --git a/frontend/src/pages/System/Department/List/components/EditDialog.tsx b/frontend/src/pages/System/Department/List/components/EditDialog.tsx index 71047e45..d1b80fd0 100644 --- a/frontend/src/pages/System/Department/List/components/EditDialog.tsx +++ b/frontend/src/pages/System/Department/List/components/EditDialog.tsx @@ -181,7 +181,7 @@ const EditDialog: React.FC = ({ {record ? '编辑部门' : '新增部门'} -
+
= ({ const [submitting, setSubmitting] = useState(false); const [menuTree, setMenuTree] = useState([]); const [checkedPermissionIds, setCheckedPermissionIds] = useState([]); + const [searchText, setSearchText] = useState(''); useEffect(() => { const loadPermissionTree = async () => { @@ -135,6 +136,45 @@ const PermissionDialog: React.FC = ({ } }; + // 筛选菜单树(根据搜索文本) + const filteredMenuTree = useMemo(() => { + if (!searchText.trim()) return menuTree; + + const filterMenu = (menu: MenuItem): MenuItem | null => { + const matchesName = menu.name.toLowerCase().includes(searchText.toLowerCase()); + const matchingPermissions = menu.permissions?.filter(p => + p.name.toLowerCase().includes(searchText.toLowerCase()) + ) || []; + const matchingChildren = menu.permissionChildren + ?.map(child => filterMenu(child)) + .filter(Boolean) as MenuItem[] || []; + + if (matchesName || matchingPermissions.length > 0 || matchingChildren.length > 0) { + return { + ...menu, + permissions: matchingPermissions, + permissionChildren: matchingChildren + }; + } + return null; + }; + + return menuTree.map(menu => filterMenu(menu)).filter(Boolean) as MenuItem[]; + }, [menuTree, searchText]); + + // 统计信息 + const statistics = useMemo(() => { + const countPermissions = (menus: MenuItem[]): number => { + return menus.reduce((sum, menu) => { + return sum + (menu.permissions?.length || 0) + countPermissions(menu.permissionChildren || []); + }, 0); + }; + const total = countPermissions(menuTree); + const selected = checkedPermissionIds.length; + const percentage = total > 0 ? Math.round((selected / total) * 100) : 0; + return { total, selected, percentage }; + }, [menuTree, checkedPermissionIds]); + // 渲染菜单项 const renderMenuItem = (menu: MenuItem, level: number = 0): React.ReactNode => { const hasChildren = menu.permissionChildren && menu.permissionChildren.length > 0; @@ -147,7 +187,7 @@ const PermissionDialog: React.FC = ({ } return ( -
0 ? 'ml-4' : ''}> +
0 ? 'ml-4' : 'mb-2'}> {hasChildren ? ( @@ -163,16 +203,16 @@ const PermissionDialog: React.FC = ({ onCheckedChange={() => handleToggleMenu(menu)} onClick={(e) => e.stopPropagation()} /> - + {menu.name}
{/* 渲染当前菜单的权限 */} {hasPermissions && ( -
+
{menu.permissions.map(permission => ( -
+
= ({ />
))} @@ -209,13 +249,13 @@ const PermissionDialog: React.FC = ({ }} onCheckedChange={() => handleToggleMenu(menu)} /> - + {menu.name}
{hasPermissions && ( -
+
{menu.permissions.map(permission => ( -
+
= ({ />
))} @@ -252,43 +292,75 @@ const PermissionDialog: React.FC = ({ return ( - - - - 分配权限 + + + + 分配权限 + {!loading && ( + + 已选择 {statistics.selected} / {statistics.total} 项权限 + + )} -
- {loading ? ( -
- - 加载中... + + {/* 搜索框 */} + {!loading && menuTree.length > 0 && ( +
+
+ + setSearchText(e.target.value)} + className="pl-10" + />
- ) : menuTree.length > 0 ? ( +
+ )} + + {/* 权限树 */} +
+ {loading ? ( +
+ + 正在加载权限数据... +
+ ) : filteredMenuTree.length > 0 ? ( - {menuTree.map(menu => renderMenuItem(menu))} + {filteredMenuTree.map(menu => renderMenuItem(menu))} + ) : searchText ? ( +
+ +

未找到匹配的权限

+

请尝试其他关键词

+
) : ( -
- 暂无权限数据 +
+ +

暂无权限数据

)}
- -
- - 已选择 {checkedPermissionIds.length} 个权限 - -
- - -
-
-
+ +
+ + +
); diff --git a/frontend/src/pages/System/Role/List/components/TagDialog.tsx b/frontend/src/pages/System/Role/List/components/TagDialog.tsx index bd0df939..38aa8510 100644 --- a/frontend/src/pages/System/Role/List/components/TagDialog.tsx +++ b/frontend/src/pages/System/Role/List/components/TagDialog.tsx @@ -153,7 +153,7 @@ const TagDialog: React.FC = ({ 标签管理 -
+