save code

This commit is contained in:
xsl
2026-01-25 12:47:29 +08:00
parent f33a902c95
commit 688adc32d3
13 changed files with 1014 additions and 1122 deletions
+81
View File
@@ -0,0 +1,81 @@
# 海洋项目管理系统 - 权限控制
## 目录权限说明
本项目采用严格的工作目录分离策略,各角色只能在指定目录中工作。
## 权限配置
### 后端程序员
**允许访问:**
- backend/
**禁止访问:**
- frontend/
- testing/
### 前端程序员
**允许访问:**
- frontend/
**禁止访问:**
- backend/
- testing/
### 测试工程师
**允许访问:**
- testing/
**禁止访问:**
- backend/
- frontend/
## 实施方法
### Git Hooks (建议)
使用pre-commit hook检查跨目录提交:
```bash
#!/bin/bash
# .git/hooks/pre-commit
USER_ROLE=${USER_ROLE:-unknown}
if [ "$USER_ROLE" = "backend" ]; then
if git diff --cached --name-only | grep -E "^frontend/|^testing/"; then
echo "❌ 错误: 后端程序员不能提交frontend/或testing/目录的文件"
exit 1
fi
fi
if [ "$USER_ROLE" = "frontend" ]; then
if git diff --cached --name-only | grep -E "^backend/|^testing/"; then
echo "❌ 错误: 前端程序员不能提交backend/或testing/目录的文件"
exit 1
fi
fi
if [ "$USER_ROLE" = "testing" ]; then
if git diff --cached --name-only | grep -E "^backend/|^frontend/"; then
echo "❌ 错误: 测试工程师不能提交backend/或frontend/目录的文件"
exit 1
fi
fi
```
### 使用方法
```bash
export USER_ROLE=backend # 设置你的角色
git commit -m "提交信息"
```
## 违规处理
如发现跨目录提交:
1. 技术总监将拒绝合并
2. 要求重新在正确目录中工作
3. 记录违规情况
## 例外情况
只有在获得技术总监明确批准的情况下,才可以跨目录工作。
+94
View File
@@ -0,0 +1,94 @@
# 海洋项目管理系统
## 项目概述
海洋项目管理系统是一个全栈项目管理系统,采用前后端分离架构。
## 项目结构
```
ocean_project_manager/
├── backend/ # 后端开发(后端程序员工作区)
├── frontend/ # 前端开发(前端程序员工作区)
├── testing/ # 测试工作(测试工程师工作区)
└── docs/ # 项目文档
```
## 团队角色
### 技术总监
- 审查设计和代码
- 协调团队协作
- 批准重大变更
### 后端程序员
- 工作目录: `backend/`
- 负责API开发和维护
- 编写API文档
- 编写单元测试
### 前端程序员
- 工作目录: `frontend/`
- 负责UI开发和维护
- 编写组件文档
- 集成后端API
### 测试工程师
- 工作目录: `testing/`
- 编写测试计划和用例
- 执行功能测试和自动化测试
- 生成测试报告
## 工作规范
各角色的详细工作规范请查看:
- [后端程序员工作规范](backend/WORKSTANDARDS.md)
- [前端程序员工作规范](frontend/WORKSTANDARDS.md)
- [测试工程师工作规范](testing/WORKSTANDARDS.md)
- [团队协作规范](docs/TEAM-COLLABORATION.md)
## 工作流程
1. **需求分析**: 技术总监编写设计方案
2. **开发**: 后端和前端程序员在各自目录中开发
3. **测试**: 测试工程师执行测试并生成报告
4. **审查**: 技术总监审查代码和文档
5. **发布**: 合并代码并部署
## 重要提醒
⚠️ **各角色只能在各自的工作目录中工作**
- 后端程序员只能在 `backend/` 目录中工作
- 前端程序员只能在 `frontend/` 目录中工作
- 测试工程师只能在 `testing/` 目录中工作
## 快速开始
### 后端程序员
```bash
cd backend
# 查看工作规范
cat WORKSTANDARDS.md
```
### 前端程序员
```bash
cd frontend
# 查看工作规范
cat WORKSTANDARDS.md
```
### 测试工程师
```bash
cd testing
# 查看工作规范
cat WORKSTANDARDS.md
```
## 文档资源
- [UI设计规范](docs/ui-design-spec.md)
- [设计方案](docs/plans/)
- [团队协作规范](docs/TEAM-COLLABORATION.md)
+37
View File
@@ -0,0 +1,37 @@
# 后端开发目录
## 目录说明
### src/
源代码目录,包含所有后端业务逻辑代码。
#### controllers/
控制器层,处理HTTP请求和响应。
#### services/
服务层,实现业务逻辑。
#### models/
数据模型,定义数据库表结构。
#### routes/
路由定义,配置API端点。
#### middleware/
中间件,处理认证、日志等横切关注点。
#### utils/
工具函数,提供通用功能。
### tests/
测试目录,包含单元测试和集成测试。
### docs/
文档目录,包含API文档和技术文档。
### config/
配置目录,包含数据库配置、环境变量等。
## 工作规范
详见 [WORKSTANDARDS.md](WORKSTANDARDS.md)
+57
View File
@@ -0,0 +1,57 @@
# 后端程序员工作规范
## 工作目录
- **主目录**: `backend/`
- **代码目录**: `backend/src/`
- **测试目录**: `backend/tests/`
- **文档目录**: `backend/docs/`
- **配置目录**: `backend/config/`
## 开发规范
### 代码结构
```
backend/
├── src/ # 源代码
│ ├── controllers/ # 控制器
│ ├── services/ # 业务逻辑
│ ├── models/ # 数据模型
│ ├── routes/ # 路由定义
│ ├── middleware/ # 中间件
│ └── utils/ # 工具函数
├── tests/ # 单元测试和集成测试
├── docs/ # API文档和技术文档
├── config/ # 配置文件
└── requirements.txt # Python依赖(如使用Python
```
### 开发流程
1.`backend/src/` 中编写业务代码
2.`backend/tests/` 中编写单元测试
3.`backend/docs/` 中编写API文档
4. 提交前必须运行测试
### 代码提交规范
- 提交信息格式: `[backend] <类型>: <描述>`
- 类型: feat, fix, docs, style, refactor, test, chore
- 示例: `[backend] feat: 添加用户认证API`
### 禁止事项
- ❌ 不得在 `frontend/``testing/` 目录中工作
- ❌ 不得修改公共配置文件(需提交技术总监审批)
- ❌ 不得提交包含敏感信息的代码
## API文档要求
- 所有API必须在 `backend/docs/api.md` 中文档化
- 文档包含: 接口路径、请求方法、参数、返回值、错误码
- 使用OpenAPI/Swagger格式
## 测试要求
- 单元测试覆盖率 > 80%
- 所有新增功能必须有对应测试
- 测试文件命名: `test_<模块名>.py``<模块名>.test.js`
## 技术栈
- 语言: Python/Node.js/Go
- 框架: 根据项目需求选择
- 数据库: PostgreSQL/MySQL/MongoDB
+157
View File
@@ -0,0 +1,157 @@
# 海洋项目管理系统 - 团队协作规范
## 项目结构
```
ocean_project_manager/
├── backend/ # 后端程序员工作区
│ ├── src/ # 后端源代码
│ ├── tests/ # 后端测试
│ ├── docs/ # API文档
│ └── WORKSTANDARDS.md
├── frontend/ # 前端程序员工作区
│ ├── src/ # 前端源代码
│ ├── tests/ # 前端测试
│ ├── docs/ # 组件文档
│ └── WORKSTANDARDS.md
├── testing/ # 测试工程师工作区
│ ├── testcases/ # 测试用例
│ ├── reports/ # 测试报告
│ ├── scripts/ # 自动化测试脚本
│ └── WORKSTANDARDS.md
└── docs/ # 项目文档
├── plans/ # 设计方案
└── ui-design-spec.md
```
## 角色职责
### 技术总监
- 审查设计和文档
- Review代码质量
- 协调团队协作
- 批准重大变更
### 后端程序员
- 负责后端API开发和维护
- 编写API文档
- 确保代码质量和测试覆盖率
- 工作目录: `backend/`
### 前端程序员
- 负责前端UI开发和维护
- 编写组件文档
- 集成后端API
- 工作目录: `frontend/`
### 测试工程师
- 编写测试计划和测试用例
- 执行功能测试、UI测试、自动化测试
- 生成测试报告和Bug报告
- 工作目录: `testing/`
## 协作流程
### 1. 需求分析阶段
- 技术总监编写设计方案
- 后端程序员和前端程序员查看设计方案
- 测试工程师编写测试计划
### 2. 开发阶段
**后端开发流程:**
1. 后端程序员开发API
2. 编写单元测试
3. 更新API文档 (`backend/docs/api.md`)
4. 提交代码审查
**前端开发流程:**
1. 前端程序员查看API文档
2. 开发UI组件
3. 集成API
4. 编写组件测试
5. 提交代码审查
### 3. 测试阶段
1. 测试工程师执行测试用例
2. 记录Bug和问题
3. 生成测试报告
4. 后端程序员和前端程序员修复Bug
### 4. 发布阶段
1. 技术总监审查代码和测试报告
2. 合并代码到主分支
3. 部署上线
## 代码审查流程
### 提交PR要求
1. 代码必须通过所有测试
2. 必须有对应文档更新
3. 提交信息符合规范
4. Pull Request描述清晰
### 审查检查项
- [ ] 代码符合规范
- [ ] 测试覆盖率达标
- [ ] 文档完整
- [ ] 无安全漏洞
- [ ] 性能可接受
## 文档要求
### 设计文档
- 存储位置: `docs/plans/`
- 包含: 需求分析、架构设计、数据库设计
### API文档
- 存储位置: `backend/docs/api.md`
- 使用OpenAPI/Swagger格式
### 测试文档
- 存储位置: `testing/docs/`
- 包含: 测试计划、测试用例、Bug报告
## 沟通机制
### 每日站会
- 各角色汇报工作进展
- 讨论遇到的问题
### 周会
- 代码审查
- 设计方案讨论
- 进度同步
### 紧急沟通
- 重大Bug立即通知技术总监
- 设计变更需要技术总监批准
## 版本管理
### 分支策略
- `main`: 生产环境
- `develop`: 开发环境
- `feature/<功能名>`: 功能分支
- `bugfix/<bug编号>`: Bug修复分支
### 提交规范
- 后端: `[backend] <类型>: <描述>`
- 前端: `[frontend] <类型>: <描述>`
- 测试: `[testing] <类型>: <描述>`
## 质量保证
### 代码质量
- 后端测试覆盖率 > 80%
- 前端关键组件必须有测试
- 代码必须通过Linter检查
### 测试质量
- 功能测试覆盖率 100%
- 关键流程必须有自动化测试
- Bug修复必须经过验证
### 文档质量
- API文档与代码同步
- 组件文档包含使用示例
- 测试用例清晰可执行
+93
View File
@@ -0,0 +1,93 @@
# docs/pid.md 文档更新说明
## 更新时间
2026-01-25
## 更新内容
### 1. 更新了第3.2节 - 项目目录结构
**更新前**: 使用传统的Flask项目结构(app目录)
**更新后**: 采用新的团队协作目录结构
**变更说明**:
- 后端结构从 `backend/app/` 更新为 `backend/src/`,包含更清晰的分层架构(controllers, services, models, routes, middleware, utils
- 前端结构从基本的React项目结构更新为包含types、hooks、styles等子目录的现代React项目结构
- 新增了 `testing/` 目录,包含testcases、reports、data、scripts、docs等子目录
- 为每个工作区添加了WORKSTANDARDS.md和README.md
### 2. 新增第3.3节 - 工作目录说明
**新增内容**:
- 后端程序员工作区职责和主要工作
- 前端程序员工作区职责和主要工作
- 测试工程师工作区职责和主要工作
### 3. 新增第3.4节 - 权限限制
**新增内容**:
- 明确规定各角色只能在指定目录中工作
- 添加权限控制文档链接
- 强调跨目录工作需要技术总监批准
### 4. 新增第4章 - 团队协作
**新增内容**:
- 4.1 角色职责: 详细说明各角色的工作职责
- 4.2 工作流程: 包含需求分析、后端开发、前端开发、测试、代码审查五个阶段的详细流程
- 4.3 代码提交规范: 明确各角色的提交信息格式和类型说明
- 4.4 文档规范: 说明后端、前端、测试的文档规范
- 4.5 沟通机制: 说明日常沟通、文档沟通、技术总监审查的方式
### 5. 更新章节编号
由于新增了第4章"团队协作",后续章节编号全部+1:
- 原第4章"数据库设计" → 现第5章
- 原第5章"API设计" → 现第6章
- 原第6章"前端设计" → 现第7章
- 原第7章"安全设计" → 现第8章
- 原第8章"部署方案" → 现第9章
- 原第9章"后续优化建议" → 现第10章
- 原第10章"开发计划" → 现第11章
### 6. 新增第12章 - 相关文档
**新增内容**:
- 12.1 团队协作文档链接
- 12.2 角色工作规范链接
- 12.3 技术文档链接
- 12.4 项目文档链接
### 7. 更新所有子章节编号
所有子章节编号根据父章节编号进行了相应更新:
- 数据库设计: 4.1-4.2 → 5.1-5.2
- API设计: 5.1-5.4 → 6.1-6.4
- 前端设计: 6.1-6.4 → 7.1-7.4
- 安全设计: 7.1-7.3 → 8.1-8.3
- 部署方案: 8.1-8.2 → 9.1-9.2
- 后续优化建议: 9.1-9.3 → 10.1-10.3
- 开发计划: 10.1-10.3 → 11.1-11.3
## 影响范围
1. **文档结构**: 文档从10章扩展到12章,新增了团队协作和相关文档两章
2. **项目架构**: 完全按照当前的项目目录结构更新,与实际的backend/、frontend/、testing/目录保持一致
3. **角色分工**: 明确了后端程序员、前端程序员、测试工程师的具体职责和工作范围
4. **协作流程**: 提供了详细的团队协作流程,从前端到后端再到测试的完整工作链
## 后续维护
- 后端程序员需要在 `backend/docs/api.md` 中维护API文档
- 前端程序员需要在 `frontend/docs/components.md` 中维护组件文档
- 测试工程师需要在 `testing/docs/` 中维护测试文档
- 技术总监负责维护本设计文档 (`docs/pid.md`)
## 文档状态
✅ 已完成更新,文档与当前项目架构保持一致
---
**更新人**: 技术总监
**审核**: 待审核
@@ -123,74 +123,264 @@
``` ```
ocean_project_manager/ ocean_project_manager/
├── backend/ # 后端代码 ├── backend/ # 后端程序员工作区
│ ├── app/ │ ├── src/ # 源代码
│ │ ├── __init__.py # Flask应用初始化 │ │ ├── controllers/ # 控制器层
│ │ ├── config.py # 配置文件
│ │ ├── models/ # 数据库模型
│ │ │ ├── __init__.py
│ │ │ ├── user.py
│ │ │ └── project.py
│ │ ├── routes/ # API路由
│ │ │ ├── __init__.py
│ │ │ ├── auth.py # 认证相关 │ │ │ ├── auth.py # 认证相关
│ │ │ ├── users.py # 用户管理 │ │ │ ├── users.py # 用户管理
│ │ │ └── projects.py # 项目管理 │ │ │ └── projects.py # 项目管理
│ │ ├── services/ # 业务逻辑 │ │ ├── services/ # 业务逻辑
│ │ │ ├── __init__.py
│ │ │ ├── auth_service.py │ │ │ ├── auth_service.py
│ │ │ ├── user_service.py │ │ │ ├── user_service.py
│ │ │ └── project_service.py │ │ │ └── project_service.py
│ │ ├── models/ # 数据模型层
│ │ │ ├── user.py
│ │ │ └── project.py
│ │ ├── routes/ # 路由定义
│ │ │ ├── auth.py
│ │ │ ├── users.py
│ │ │ └── projects.py
│ │ ├── middleware/ # 中间件
│ │ │ ├── jwt_middleware.py
│ │ │ └── auth_middleware.py
│ │ └── utils/ # 工具函数 │ │ └── utils/ # 工具函数
│ │ ├── __init__.py
│ │ ├── jwt_utils.py │ │ ├── jwt_utils.py
│ │ └── decorators.py │ │ └── password_utils.py
│ ├── tests/ # 单元测试和集成测试
│ ├── docs/ # API文档和技术文档
│ │ └── api.md # API文档
│ ├── config/ # 配置文件
│ ├── requirements.txt # Python依赖 │ ├── requirements.txt # Python依赖
│ ├── run.py # 启动文件 │ ├── run.py # 启动文件
── .env # 环境变量 ── WORKSTANDARDS.md # 后端程序员工作规范
│ └── README.md # 后端开发说明
├── frontend/ # 前端代码 ├── frontend/ # 前端程序员工作区
│ ├── public/ │ ├── src/ # 源代码
│ │ ── index.html │ │ ── components/ # 可复用组件
├── src/ │ │ ├── Layout.jsx
│ │ ├── components/ # 公共组件 │ │ │ ├── Header.jsx
│ │ │ ── Layout.js │ │ │ ── Sidebar.jsx
│ │ │ ├── Header.js
│ │ │ └── Sidebar.js
│ │ ├── pages/ # 页面组件 │ │ ├── pages/ # 页面组件
│ │ │ ├── Login.js │ │ │ ├── Login.jsx
│ │ │ ├── Dashboard.js │ │ │ ├── Dashboard.jsx
│ │ │ ├── UserList.js │ │ │ ├── UserList.jsx
│ │ │ ├── UserForm.js │ │ │ ├── UserForm.jsx
│ │ │ ├── ProjectList.js │ │ │ ├── ProjectList.jsx
│ │ │ ├── ProjectForm.js │ │ │ ├── ProjectForm.jsx
│ │ │ └── ProjectDetail.js │ │ │ └── ProjectDetail.jsx
│ │ ├── hooks/ # 自定义Hooks
│ │ │ └── useAuth.js
│ │ ├── services/ # API服务 │ │ ├── services/ # API服务
│ │ │ ├── api.js # Axios配置 │ │ │ ├── api.js # Axios配置
│ │ │ ├── auth.js │ │ │ ├── auth.js
│ │ │ ├── user.js │ │ │ ├── user.js
│ │ │ └── project.js │ │ │ └── project.js
│ │ ├── contexts/ # Context
│ │ │ └── AuthContext.js
│ │ ├── utils/ # 工具函数 │ │ ├── utils/ # 工具函数
│ │ │ └── auth.js │ │ │ └── auth.js
│ │ ├── App.js # 根组 │ │ ├── styles/ # 样式文
│ │ ├── index.js # 入口文件 │ │ │ └── global.css
│ │ ── App.css │ │ ── types/ # TypeScript类型定义
│ │ │ ├── user.ts
│ │ │ └── project.ts
│ │ ├── App.jsx # 根组件
│ │ └── index.js # 入口文件
│ ├── tests/ # 组件测试
│ ├── docs/ # 组件文档和开发文档
│ │ └── components.md # 组件文档
│ ├── package.json │ ├── package.json
── .env # 环境变量 ── WORKSTANDARDS.md # 前端程序员工作规范
│ └── README.md # 前端开发说明
├── docs/ # 文档 ├── testing/ # 测试工程师工作区
│ ├── testcases/ # 测试用例
│ │ ├── api/ # API测试用例
│ │ │ ├── auth_test.json
│ │ │ ├── user_test.json
│ │ │ └── project_test.json
│ │ ├── ui/ # UI测试用例
│ │ │ ├── login_test.json
│ │ │ ├── user_list_test.json
│ │ │ └── project_list_test.json
│ │ └── integration/ # 集成测试用例
│ │ └── workflow_test.json
│ ├── reports/ # 测试报告
│ ├── data/ # 测试数据
│ ├── scripts/ # 自动化测试脚本
│ │ ├── api_test.py # API自动化测试
│ │ └── ui_test.js # UI自动化测试
│ ├── docs/ # 测试文档
│ │ ├── test_plan.md # 测试计划
│ │ └── test_strategy.md # 测试策略
│ ├── WORKSTANDARDS.md # 测试工程师工作规范
│ └── README.md # 测试工作说明
├── docs/ # 项目文档
│ ├── plans/ # 设计文档 │ ├── plans/ # 设计文档
│ │ └── 2026-01-24-project-management-system-design.md │ │ └── 2026-01-24-project-management-system-design.md
── api/ # API文档 ── ui-design-spec.md # UI设计规范
│ ├── pid.md # 项目信息文档(本文档)
│ └── TEAM-COLLABORATION.md # 团队协作规范
── README.md ── ACCESS-CONTROL.md # 权限控制文档
├── README.md # 项目说明
└── .git/ # Git仓库
``` ```
## 4. 数据库设计 ### 3.3 工作目录说明
### 4.1 数据库表结构 #### 后端程序员工作区 (`backend/`)
- **负责**: 后端API开发、数据库设计、单元测试编写
- **主要工作**: 在 `backend/src/` 中编写业务代码
- **输出文档**: `backend/docs/api.md` - API文档
- **测试**: `backend/tests/` - 单元测试和集成测试
#### 前端程序员工作区 (`frontend/`)
- **负责**: 前端UI开发、组件封装、API集成
- **主要工作**: 在 `frontend/src/` 中编写UI组件
- **输出文档**: `frontend/docs/components.md` - 组件文档
- **测试**: `frontend/tests/` - 组件测试
#### 测试工程师工作区 (`testing/`)
- **负责**: 测试计划编写、测试用例设计、自动化测试
- **主要工作**: 在 `testing/testcases/` 中编写测试用例
- **输出文档**: `testing/reports/` - 测试报告
- **自动化**: `testing/scripts/` - 自动化测试脚本
### 3.4 权限限制
⚠️ **严格遵守工作目录限制**
- 后端程序员只能在 `backend/` 目录中工作
- 前端程序员只能在 `frontend/` 目录中工作
- 测试工程师只能在 `testing/` 目录中工作
跨目录工作需要技术总监批准,详见 [ACCESS-CONTROL.md](../ACCESS-CONTROL.md)
## 4. 团队协作
### 4.1 角色职责
#### 技术总监
- 审查设计方案和技术文档
- Review代码质量和架构设计
- 协调团队协作,解决技术分歧
- 批准重大变更和跨目录访问请求
#### 后端程序员
- **工作目录**: `backend/`
- **主要职责**:
- 设计和实现后端API接口
- 编写API文档 (`backend/docs/api.md`)
- 编写单元测试,确保测试覆盖率 > 80%
- 参与技术方案讨论和代码审查
#### 前端程序员
- **工作目录**: `frontend/`
- **主要职责**:
- 实现前端UI组件和页面
- 编写组件文档 (`frontend/docs/components.md`)
- 集成后端API,确保前后端对接
- 遵循UI设计规范 (`docs/ui-design-spec.md`)
#### 测试工程师
- **工作目录**: `testing/`
- **主要职责**:
- 编写测试计划和测试用例
- 执行功能测试、UI测试、自动化测试
- 生成测试报告和Bug报告
- 验证Bug修复效果
### 4.2 工作流程
#### 4.2.1 需求分析阶段
1. 技术总监编写设计方案 (`docs/plans/`)
2. 后端程序员和前端程序员查看设计方案
3. 测试工程师编写测试计划 (`testing/docs/`)
#### 4.2.2 后端开发流程
1. 后端程序员在 `backend/src/` 中开发API
2. 编写单元测试 (`backend/tests/`)
3. 更新API文档 (`backend/docs/api.md`)
4. 提交代码进行审查
#### 4.2.3 前端开发流程
1. 前端程序员查看API文档 (`backend/docs/api.md`)
2. 在 `frontend/src/` 中开发UI组件
3. 集成后端API
4. 编写组件测试 (`frontend/tests/`)
5. 提交代码进行审查
#### 4.2.4 测试流程
1. 测试工程师执行测试用例 (`testing/testcases/`)
2. 记录Bug和问题
3. 生成测试报告 (`testing/reports/`)
4. 后端程序员和前端程序员根据Bug报告修复问题
5. 测试工程师验证修复效果
#### 4.2.5 代码审查流程
1. 开发人员提交Pull Request
2. 技术总监审查代码质量、文档完整性、测试覆盖率
3. 如有问题,退回修改;如通过,合并到主分支
### 4.3 代码提交规范
#### 提交信息格式
- 后端程序员: `[backend] <类型>: <描述>`
- 前端程序员: `[frontend] <类型>: <描述>`
- 测试工程师: `[testing] <类型>: <描述>`
#### 类型说明
- `feat`: 新功能
- `fix`: Bug修复
- `docs`: 文档更新
- `style`: 代码格式调整
- `refactor`: 代码重构
- `test`: 测试相关
- `chore`: 构建或工具相关
#### 示例
```
[backend] feat: 添加用户认证API
[frontend] fix: 修复项目列表分页问题
[testing] test: 添加用户登录API测试用例
```
### 4.4 文档规范
#### 后端文档
- **API文档**: `backend/docs/api.md`
- 使用OpenAPI/Swagger格式
- 包含: 接口路径、请求方法、参数、返回值、错误码
#### 前端文档
- **组件文档**: `frontend/docs/components.md`
- 包含: 组件名称、Props、使用示例、截图
#### 测试文档
- **测试计划**: `testing/docs/test_plan.md`
- **测试报告**: `testing/reports/` 目录
- **Bug报告**: 包含标题、重现步骤、预期结果、实际结果、截图/日志
### 4.5 沟通机制
#### 日常沟通
- 各角色在各自目录中独立工作
- 需要协作时通过技术总监协调
#### 文档沟通
- 后端API文档作为前后端对接的桥梁
- 测试报告作为Bug修复的依据
- 所有重要决策记录在项目文档中
#### 技术总监审查
- 所有设计方案需要技术总监批准
- 所有代码合并需要技术总监审查
- 重大变更需要技术总监批准
## 5. 数据库设计
### 5.1 数据库表结构
#### 4.1.1 用户表 (users) #### 4.1.1 用户表 (users)
@@ -275,7 +465,7 @@ CREATE INDEX idx_projects_department ON projects(department);
CREATE INDEX idx_projects_created_by ON projects(created_by); CREATE INDEX idx_projects_created_by ON projects(created_by);
``` ```
### 4.2 角色权限矩阵 ### 5.2 角色权限矩阵
| 功能 | admin | market | other | | 功能 | admin | market | other |
|------|-------|--------|-------| |------|-------|--------|-------|
@@ -290,9 +480,9 @@ CREATE INDEX idx_projects_created_by ON projects(created_by);
| 查看所有项目 | ✓ | ✓ | ✓ | | 查看所有项目 | ✓ | ✓ | ✓ |
| 查看项目详情 | ✓ | ✓ | ✓ | | 查看项目详情 | ✓ | ✓ | ✓ |
## 5. API设计 ## 6. API设计
### 5.1 API规范 ### 6.1 API规范
- **Base URL**: `/api/v1` - **Base URL**: `/api/v1`
- **Content-Type**: `application/json` - **Content-Type**: `application/json`
@@ -306,7 +496,7 @@ CREATE INDEX idx_projects_created_by ON projects(created_by);
} }
``` ```
### 5.2 认证相关API ### 6.2 认证相关API
#### 5.2.1 用户登录 #### 5.2.1 用户登录
- **URL**: `POST /api/v1/auth/login` - **URL**: `POST /api/v1/auth/login`
@@ -363,7 +553,7 @@ CREATE INDEX idx_projects_created_by ON projects(created_by);
} }
``` ```
### 5.3 用户管理API ### 6.3 用户管理API
#### 5.3.1 获取用户列表 #### 5.3.1 获取用户列表
- **URL**: `GET /api/v1/users` - **URL**: `GET /api/v1/users`
@@ -458,7 +648,7 @@ CREATE INDEX idx_projects_created_by ON projects(created_by);
} }
``` ```
### 5.4 项目管理API ### 6.4 项目管理API
#### 5.4.1 获取项目列表 #### 5.4.1 获取项目列表
- **URL**: `GET /api/v1/projects` - **URL**: `GET /api/v1/projects`
@@ -542,9 +732,9 @@ CREATE INDEX idx_projects_created_by ON projects(created_by);
- **Header**: `Authorization: Bearer <token>` - **Header**: `Authorization: Bearer <token>`
- **权限**: admin, market(只能删除自己创建的) - **权限**: admin, market(只能删除自己创建的)
## 6. 前端设计 ## 7. 前端设计
### 6.1 页面结构 ### 7.1 页面结构
``` ```
登录页 (Login) 登录页 (Login)
@@ -566,7 +756,7 @@ CREATE INDEX idx_projects_created_by ON projects(created_by);
└─ 项目详情 └─ 项目详情
``` ```
### 6.2 核心组件 ### 7.2 核心组件
#### 6.2.1 AuthContext #### 6.2.1 AuthContext
全局认证状态管理: 全局认证状态管理:
@@ -590,7 +780,7 @@ const AuthContext = createContext({
- 请求拦截器 - 请求拦截器
- 响应拦截器 - 响应拦截器
### 6.3 页面设计 ### 7.3 页面设计
#### 6.3.1 登录页 #### 6.3.1 登录页
- 简洁的登录表单 - 简洁的登录表单
@@ -625,31 +815,31 @@ const AuthContext = createContext({
- 编辑功能 - 编辑功能
- 操作日志(可选) - 操作日志(可选)
### 6.4 UI风格 ### 7.4 UI风格
- 使用Ant Design默认主题 - 使用Ant Design默认主题
- 响应式布局 - 响应式布局
- 简洁、专业的企业级UI - 简洁、专业的企业级UI
## 7. 安全设计 ## 8. 安全设计
### 7.1 认证安全 ### 8.1 认证安全
- 密码使用bcrypt加密存储 - 密码使用bcrypt加密存储
- JWT Token有效期设置(如24小时) - JWT Token有效期设置(如24小时)
- Token过期自动刷新机制 - Token过期自动刷新机制
### 7.2 权限控制 ### 8.2 权限控制
- 后端基于装饰器的权限验证 - 后端基于装饰器的权限验证
- 前端路由级别的权限控制 - 前端路由级别的权限控制
- 前端组件级别的权限控制 - 前端组件级别的权限控制
### 7.3 数据安全 ### 8.3 数据安全
- SQL注入防护(使用SQLAlchemy ORM - SQL注入防护(使用SQLAlchemy ORM
- XSS防护(React自动转义) - XSS防护(React自动转义)
- 输入验证(前后端双重验证) - 输入验证(前后端双重验证)
## 8. 部署方案 ## 9. 部署方案
### 8.1 开发环境 ### 9.1 开发环境
**后端** **后端**
```bash ```bash
@@ -673,7 +863,7 @@ npm start
- 数据库名:`project_manager` - 数据库名:`project_manager`
- 配置文件:`.env` - 配置文件:`.env`
### 8.2 生产环境(推荐方案) ### 9.2 生产环境(推荐方案)
**使用Docker Compose** **使用Docker Compose**
@@ -712,37 +902,62 @@ volumes:
mysql_data: mysql_data:
``` ```
## 9. 后续优化建议 ## 10. 后续优化建议
### 9.1 功能扩展 ### 10.1 功能扩展
- 项目附件上传 - 项目附件上传
- 操作日志记录 - 操作日志记录
- 数据导出功能 - 数据导出功能
- 报表统计功能 - 报表统计功能
### 9.2 性能优化 ### 10.2 性能优化
- 数据库索引优化 - 数据库索引优化
- API响应缓存(如需要) - API响应缓存(如需要)
- 前端代码分割 - 前端代码分割
### 9.3 用户体验 ### 10.3 用户体验
- 表单自动保存 - 表单自动保存
- 批量操作功能 - 批量操作功能
- 消息通知功能 - 消息通知功能
## 10. 开发计划 ## 11. 开发计划
### 10.1 第一阶段(MVP ### 11.1 第一阶段(MVP
- 用户登录/登出 - 用户登录/登出
- 项目CRUD基础功能 - 项目CRUD基础功能
- 简单的用户管理(仅管理员) - 简单的用户管理(仅管理员)
### 10.2 第二阶段 ### 11.2 第二阶段
- 权限控制完善 - 权限控制完善
- 项目列表筛选和搜索 - 项目列表筛选和搜索
- 表单验证优化 - 表单验证优化
### 10.3 第三阶段(可选) ### 11.3 第三阶段(可选)
- 高级功能扩展 - 高级功能扩展
- 性能优化 - 性能优化
- 用户体验优化 - 用户体验优化
## 12. 相关文档
### 12.1 团队协作文档
- [团队协作规范](../TEAM-COLLABORATION.md) - 详细的团队协作流程和规范
- [权限控制文档](../ACCESS-CONTROL.md) - 各角色访问权限说明
### 12.2 角色工作规范
- [后端程序员工作规范](../backend/WORKSTANDARDS.md) - 后端开发详细规范
- [前端程序员工作规范](../frontend/WORKSTANDARDS.md) - 前端开发详细规范
- [测试工程师工作规范](../testing/WORKSTANDARDS.md) - 测试工作详细规范
### 12.3 技术文档
- [UI设计规范](../docs/ui-design-spec.md) - 前端UI设计规范
- [后端API文档](../backend/docs/api.md) - API接口文档(由后端程序员维护)
- [前端组件文档](../frontend/docs/components.md) - 前端组件文档(由前端程序员维护)
- [测试文档](../testing/docs/) - 测试计划和测试策略(由测试工程师维护)
### 12.4 项目文档
- [README.md](../README.md) - 项目说明文档
- [设计方案](../docs/plans/) - 项目设计方案和技术设计文档
---
**文档维护**: 本文档由技术总监维护,如有疑问请联系技术总监。
-293
View File
@@ -1,293 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>项目信息管理系统 - UI预览</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/antd/5.12.2/reset.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.10/dayjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.10/locale/zh-cn.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/antd/5.12.2/antd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/@ant-design/icons/5.2.6/index.min.js"></script>
<style>
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: #f0f2f5;
}
#root {
min-height: 100vh;
}
.ant-layout {
min-height: 100vh;
}
.ant-layout-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
background: #001529;
}
.ant-layout-sider {
box-shadow: 2px 0 8px rgba(0,0,0,0.15);
}
.ant-layout-content {
margin: 24px 16px;
padding: 24px;
min-height: 280px;
}
.logo {
color: white;
font-size: 18px;
font-weight: 600;
display: flex;
align-items: center;
gap: 8px;
}
.user-info {
display: flex;
align-items: center;
gap: 12px;
}
.dashboard-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 24px;
margin-bottom: 24px;
}
.dashboard-card {
background: white;
padding: 24px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.dashboard-card h3 {
margin: 0 0 8px 0;
font-size: 14px;
color: #666;
}
.dashboard-card .number {
margin: 0;
font-size: 32px;
font-weight: 600;
color: #1890ff;
}
.preview-section {
margin-bottom: 48px;
}
.preview-section h2 {
border-bottom: 2px solid #1890ff;
padding-bottom: 12px;
margin-bottom: 24px;
}
.mockup {
background: white;
padding: 24px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-bottom: 24px;
}
</style>
</head>
<body>
<div id="root"></div>
<script>
const { useState } = React;
const { Layout, Menu, Card, Table, Button, Form, Input, Select, DatePicker, Space, Dropdown, Avatar, Tag, Modal, message, Statistic } = antd;
const { Header, Sider, Content } = Layout;
const { ProjectOutlined, UserOutlined, DashboardOutlined, LogoutOutlined, SettingOutlined, FileTextOutlined, TeamOutlined, PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined } = icons;
dayjs.locale('zh-cn');
const { Option } = Select;
const { RangePicker } = DatePicker;
const menuItems = [
{ key: 'dashboard', icon: React.createElement(DashboardOutlined), label: '仪表盘' },
{ key: 'projects', icon: React.createElement(FileTextOutlined), label: '项目管理' },
{ key: 'users', icon: React.createElement(TeamOutlined), label: '用户管理' },
];
const projectColumns = [
{ title: '项目编号', dataIndex: 'project_no', key: 'project_no' },
{ title: '合同编号', dataIndex: 'contract_no', key: 'contract_no' },
{ title: '项目名称', dataIndex: 'name', key: 'name' },
{ title: '预算', dataIndex: 'budget', key: 'budget', render: (val) => `¥${val.toLocaleString()}` },
{ title: '已付款', dataIndex: 'payment_amount', key: 'payment_amount', render: (val) => `¥${val.toLocaleString()}` },
{ title: '状态', dataIndex: 'status', key: 'status', render: (status) => {
const colorMap = { '新建': 'blue', '进行中': 'green', '已完成': 'default', '已暂停': 'orange', '已取消': 'red' };
return React.createElement(Tag, { color: colorMap[status] || 'default' }, status);
}},
{ title: '所属部门', dataIndex: 'department', key: 'department' },
{ title: '创建人', dataIndex: 'created_by_name', key: 'created_by_name' },
{ title: '创建时间', dataIndex: 'created_at', key: 'created_at', render: (val) => dayjs(val).format('YYYY-MM-DD') },
{
title: '操作',
key: 'action',
render: () => React.createElement(Space, null,
React.createElement(Button, { type: 'link', size: 'small', icon: React.createElement(EyeOutlined) }, '查看'),
React.createElement(Button, { type: 'link', size: 'small', icon: React.createElement(EditOutlined) }, '编辑'),
React.createElement(Button, { type: 'link', size: 'small', danger: true, icon: React.createElement(DeleteOutlined) }, '删除')
)
}
];
const userColumns = [
{ title: '用户名', dataIndex: 'username', key: 'username' },
{ title: '真实姓名', dataIndex: 'real_name', key: 'real_name' },
{ title: '部门', dataIndex: 'department', key: 'department' },
{ title: '角色', dataIndex: 'role', key: 'role', render: (role) => {
const roleMap = { 'admin': '管理员', 'market': '市场部', 'other': '其他部门' };
return React.createElement(Tag, { color: role === 'admin' ? 'red' : 'blue' }, roleMap[role] || role);
}},
{ title: '邮箱', dataIndex: 'email', key: 'email' },
{ title: '状态', dataIndex: 'is_active', key: 'is_active', render: (active) => React.createElement(Tag, { color: active ? 'green' : 'default' }, active ? '正常' : '禁用') },
{ title: '创建时间', dataIndex: 'created_at', key: 'created_at', render: (val) => dayjs(val).format('YYYY-MM-DD') },
{
title: '操作',
key: 'action',
render: () => React.createElement(Space, null,
React.createElement(Button, { type: 'link', size: 'small', icon: React.createElement(EditOutlined) }, '编辑'),
React.createElement(Button, { type: 'link', size: 'small', icon: React.createElement(SettingOutlined) }, '重置密码'),
React.createElement(Button, { type: 'link', size: 'small', danger: true, icon: React.createElement(DeleteOutlined) }, '删除')
)
}
];
const projectData = [
{ key: 1, project_no: 'PRJ2026001', contract_no: 'CT2026001', name: '某公司官网开发', budget: 50000, payment_amount: 25000, status: '进行中', department: '市场部', created_by_name: '张三', created_at: '2026-01-24' },
{ key: 2, project_no: 'PRJ2026002', contract_no: 'CT2026002', name: '电商平台开发', budget: 100000, payment_amount: 50000, status: '新建', department: '市场部', created_by_name: '李四', created_at: '2026-01-23' },
{ key: 3, project_no: 'PRJ2026003', contract_no: 'CT2026003', name: '移动APP开发', budget: 150000, payment_amount: 150000, status: '已完成', department: '技术部', created_by_name: '王五', created_at: '2026-01-20' },
{ key: 4, project_no: 'PRJ2026004', contract_no: 'CT2026004', name: '数据分析系统', budget: 80000, payment_amount: 30000, status: '进行中', department: '市场部', created_by_name: '张三', created_at: '2026-01-18' },
{ key: 5, project_no: 'PRJ2026005', contract_no: 'CT2026005', name: '企业OA系统', budget: 200000, payment_amount: 0, status: '已暂停', department: '技术部', created_by_name: '赵六', created_at: '2026-01-15' },
];
const userData = [
{ key: 1, username: 'admin', real_name: '管理员', department: '管理部', role: 'admin', email: 'admin@example.com', is_active: true, created_at: '2026-01-10' },
{ key: 2, username: 'zhangsan', real_name: '张三', department: '市场部', role: 'market', email: 'zhangsan@example.com', is_active: true, created_at: '2026-01-15' },
{ key: 3, username: 'lisi', real_name: '李四', department: '市场部', role: 'market', email: 'lisi@example.com', is_active: true, created_at: '2026-01-16' },
{ key: 4, username: 'wangwu', real_name: '王五', department: '技术部', role: 'other', email: 'wangwu@example.com', is_active: true, created_at: '2026-01-17' },
{ key: 5, username: 'zhaoliu', real_name: '赵六', department: '技术部', role: 'other', email: 'zhaoliu@example.com', is_active: false, created_at: '2026-01-18' },
];
function App() {
const [currentView, setCurrentView] = useState('dashboard');
const [selectedMenu, setSelectedMenu] = useState('dashboard');
const [userModalVisible, setUserModalVisible] = useState(false);
const [projectModalVisible, setProjectModalVisible] = useState(false);
const handleMenuClick = ({ key }) => {
setSelectedMenu(key);
setCurrentView(key);
};
const Dashboard = () => React.createElement('div', null,
React.createElement('div', { className: 'dashboard-cards' },
React.createElement(Card, null,
React.createElement(Statistic, { title: '总项目数', value: 15, prefix: React.createElement(ProjectOutlined) })
),
React.createElement(Card, null,
React.createElement(Statistic, { title: '进行中', value: 8, valueStyle: { color: '#3f8600' }, prefix: React.createElement(FileTextOutlined) })
),
React.createElement(Card, null,
React.createElement(Statistic, { title: '已完成', value: 5, prefix: React.createElement(FileTextOutlined) })
),
React.createElement(Card, null,
React.createElement(Statistic, { title: '本月预算', value: 500000, prefix: '¥' })
)
),
React.createElement(Card, { title: '最近项目' },
React.createElement(Table, {
columns: projectColumns,
dataSource: projectData.slice(0, 3),
pagination: false
})
)
);
const ProjectList = () => React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 16, display: 'flex', justifyContent: 'space-between' } },
React.createElement(Space, null,
React.createElement(Input, { placeholder: '搜索项目...', style: { width: 200 } }),
React.createElement(Select, { placeholder: '状态', style: { width: 120 } },
React.createElement(Option, { value: '新建' }, '新建'),
React.createElement(Option, { value: '进行中' }, '进行中'),
React.createElement(Option, { value: '已完成' }, '已完成')
),
React.createElement(Select, { placeholder: '部门', style: { width: 120 } },
React.createElement(Option, { value: '市场部' }, '市场部'),
React.createElement(Option, { value: '技术部' }, '技术部')
)
),
React.createElement(Button, { type: 'primary', icon: React.createElement(PlusOutlined) }, '新建项目')
),
React.createElement(Card, null,
React.createElement(Table, {
columns: projectColumns,
dataSource: projectData,
pagination: { pageSize: 10 }
})
)
);
const UserList = () => React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 16, display: 'flex', justifyContent: 'space-between' } },
React.createElement(Space, null,
React.createElement(Input, { placeholder: '搜索用户...', style: { width: 200 } }),
React.createElement(Select, { placeholder: '角色', style: { width: 120 } },
React.createElement(Option, { value: 'admin' }, '管理员'),
React.createElement(Option, { value: 'market' }, '市场部'),
React.createElement(Option, { value: 'other' }, '其他部门')
)
),
React.createElement(Button, { type: 'primary', icon: React.createElement(PlusOutlined) }, '新建用户')
),
React.createElement(Card, null,
React.createElement(Table, {
columns: userColumns,
dataSource: userData,
pagination: { pageSize: 10 }
})
)
);
const content = {
dashboard: Dashboard,
projects: ProjectList,
users: UserList
}[currentView] || Dashboard;
return React.createElement(Layout, null,
React.createElement(Header, null,
React.createElement('div', { className: 'logo' },
React.createElement(ProjectOutlined),
' 项目信息管理系统'
),
React.createElement('div', { className: 'user-info' },
React.createElement(Avatar, { icon: React.createElement(UserOutlined) }),
React.createElement('span', { style: { color: 'white' } }, '管理员'),
React.createElement(Button, { type: 'text', icon: React.createElement(LogoutOutlined), style: { color: 'white' } }, '退出')
)
),
React.createElement(Layout, null,
React.createElement(Sider, { width: 256, style: { background: '#fff' } },
React.createElement(Menu, {
mode: 'inline',
selectedKeys: [selectedMenu],
items: menuItems,
onClick: handleMenuClick
})
),
React.createElement(Content, { style: { background: '#fff' } }, content())
)
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(React.createElement(App));
</script>
</body>
</html>
+41
View File
@@ -0,0 +1,41 @@
# 前端开发目录
## 目录说明
### src/
源代码目录,包含所有前端UI代码。
#### components/
可复用组件,如按钮、表单、卡片等。
#### pages/
页面组件,如登录页、首页、设置页等。
#### hooks/
自定义React Hooks,封装可复用的状态逻辑。
#### services/
API服务,封装与后端的HTTP请求。
#### utils/
工具函数,提供通用功能。
#### styles/
样式文件,包含全局样式和主题。
#### types/
TypeScript类型定义。
### tests/
测试目录,包含组件测试和集成测试。
### docs/
文档目录,包含组件文档和开发文档。
## 工作规范
详见 [WORKSTANDARDS.md](WORKSTANDARDS.md)
## UI设计规范
详见 [../docs/ui-design-spec.md](../docs/ui-design-spec.md)
+60
View File
@@ -0,0 +1,60 @@
# 前端程序员工作规范
## 工作目录
- **主目录**: `frontend/`
- **源代码目录**: `frontend/src/`
- **组件目录**: `frontend/src/components/`
- **页面目录**: `frontend/src/pages/`
- **样式目录**: `frontend/src/styles/`
- **测试目录**: `frontend/tests/`
- **文档目录**: `frontend/docs/`
## 开发规范
### 代码结构
```
frontend/
├── src/ # 源代码
│ ├── components/ # 可复用组件
│ ├── pages/ # 页面组件
│ ├── hooks/ # 自定义Hooks
│ ├── services/ # API服务
│ ├── utils/ # 工具函数
│ ├── styles/ # 样式文件
│ └── types/ # TypeScript类型定义
├── tests/ # 组件测试
├── docs/ # 组件文档和开发文档
└── package.json # 依赖管理
```
### 开发流程
1.`frontend/src/` 中编写UI组件和页面
2.`frontend/tests/` 中编写组件测试
3.`frontend/docs/` 中编写组件文档
4. 开发前需在 `docs/ui-design-spec.md` 中查看UI设计规范
### 代码提交规范
- 提交信息格式: `[frontend] <类型>: <描述>`
- 类型: feat, fix, style, refactor, test, chore
- 示例: `[frontend] feat: 添加项目列表组件`
### 禁止事项
- ❌ 不得在 `backend/``testing/` 目录中工作
- ❌ 不得修改后端API(需协调后端程序员)
- ❌ 不得提交未经过测试的代码
## UI组件要求
- 所有组件必须在 `frontend/docs/components.md` 中文档化
- 文档包含: 组件名称、Props、使用示例、截图
- 遵循设计规范 `docs/ui-design-spec.md`
## 测试要求
- 关键组件必须有单元测试
- 测试文件命名: `<组件名>.test.tsx``<组件名>.spec.tsx`
- 使用Jest或Vitest测试框架
## 技术栈
- 框架: React/Vue/Angular
- 状态管理: Redux/Vuex/Zustand
- 样式: Tailwind CSS/CSS Modules
- 构建工具: Vite/Webpack
+39
View File
@@ -0,0 +1,39 @@
# 测试工作目录
## 目录说明
### testcases/
测试用例目录。
#### api/
API测试用例,测试后端接口功能。
#### ui/
UI测试用例,测试前端用户界面。
#### integration/
集成测试用例,测试系统整体功能。
### reports/
测试报告目录,存储每次测试的结果报告。
### data/
测试数据目录,存储测试用的数据。
### scripts/
自动化测试脚本目录,存储自动化测试代码。
### docs/
测试文档目录,包含测试计划、测试策略等。
## 工作规范
详见 [WORKSTANDARDS.md](WORKSTANDARDS.md)
## 测试流程
1. 编写测试计划
2. 编写测试用例
3. 执行测试
4. 记录Bug
5. 生成测试报告
+73
View File
@@ -0,0 +1,73 @@
# 测试工程师工作规范
## 工作目录
- **主目录**: `testing/`
- **测试用例目录**: `testing/testcases/`
- **测试报告目录**: `testing/reports/`
- **测试数据目录**: `testing/data/`
- **测试脚本目录**: `testing/scripts/`
- **文档目录**: `testing/docs/`
## 工作规范
### 目录结构
```
testing/
├── testcases/ # 测试用例
│ ├── api/ # API测试用例
│ ├── ui/ # UI测试用例
│ └── integration/ # 集成测试用例
├── reports/ # 测试报告
├── data/ # 测试数据
├── scripts/ # 自动化测试脚本
└── docs/ # 测试计划和文档
```
### 测试流程
1.`testing/docs/` 中编写测试计划
2.`testing/testcases/` 中编写测试用例
3.`testing/scripts/` 中编写自动化测试脚本
4.`testing/reports/` 中记录测试结果
### 代码提交规范
- 提交信息格式: `[testing] <类型>: <描述>`
- 类型: test, bug, docs, automation
- 示例: `[testing] test: 添加用户登录API测试用例`
### 禁止事项
- ❌ 不得在 `backend/``frontend/` 目录中修改代码
- ❌ 不得跳过测试步骤直接提交报告
- ❌ 不得遗漏Bug记录
## 测试要求
### 功能测试
- 遵循后端API文档 `backend/docs/api.md`
- 覆盖所有正常和异常场景
- 记录所有发现的Bug
### UI测试
- 遵循前端设计规范 `docs/ui-design-spec.md`
- 测试所有用户交互流程
- 记录UI问题和兼容性问题
### 自动化测试
- 编写自动化测试脚本
- 定期执行回归测试
- 维护测试数据
## Bug报告要求
- Bug报告必须包含: 标题、重现步骤、预期结果、实际结果、截图/日志
- Bug等级分类: 致命、严重、一般、轻微
- 提交给技术总监进行审核
## 测试报告
- 每次测试后必须生成报告
- 报告包含: 测试范围、测试结果、Bug列表、风险评估
- 存储在 `testing/reports/` 目录
## 技术栈
- 自动化测试: Selenium/Playwright/Cypress
- API测试: Postman/Insomnia/REST Assured
- 性能测试: JMeter/Locust
- 测试管理: TestRail/Jira
-762
View File
@@ -1,762 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>项目信息管理系统 - UI设计图</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: #f0f2f5;
padding: 20px;
}
.design-container {
max-width: 1400px;
margin: 0 auto;
}
.design-title {
text-align: center;
margin-bottom: 40px;
color: #333;
}
.section-title {
font-size: 24px;
color: #1890ff;
border-bottom: 3px solid #1890ff;
padding-bottom: 10px;
margin: 40px 0 20px 0;
}
.mockup {
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
margin-bottom: 30px;
overflow: hidden;
}
.mockup-header {
background: #001529;
color: white;
padding: 16px 24px;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
display: flex;
align-items: center;
gap: 10px;
font-size: 18px;
font-weight: 600;
}
.logo-icon {
width: 24px;
height: 24px;
background: #1890ff;
border-radius: 4px;
}
.user-nav {
display: flex;
align-items: center;
gap: 15px;
}
.avatar {
width: 32px;
height: 32px;
background: #1890ff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
.layout-grid {
display: grid;
grid-template-columns: 256px 1fr;
min-height: 600px;
}
.sidebar {
background: #fff;
border-right: 1px solid #e8e8e8;
padding: 20px 0;
}
.menu-item {
padding: 12px 24px;
display: flex;
align-items: center;
gap: 10px;
color: #666;
cursor: pointer;
border-left: 3px solid transparent;
}
.menu-item:hover {
background: #e6f7ff;
color: #1890ff;
}
.menu-item.active {
background: #e6f7ff;
color: #1890ff;
border-left-color: #1890ff;
}
.content {
padding: 24px;
background: #f0f2f5;
}
.card {
background: white;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
margin-bottom: 24px;
}
.card-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 20px;
color: #333;
}
.stat-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
margin-bottom: 24px;
}
.stat-card {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.stat-label {
font-size: 14px;
color: #666;
margin-bottom: 8px;
}
.stat-value {
font-size: 32px;
font-weight: 600;
color: #1890ff;
}
.stat-icon {
float: right;
font-size: 24px;
color: #1890ff;
opacity: 0.3;
}
table {
width: 100%;
border-collapse: collapse;
}
th {
background: #fafafa;
padding: 12px 16px;
text-align: left;
font-weight: 600;
color: #333;
border-bottom: 1px solid #e8e8e8;
}
td {
padding: 12px 16px;
border-bottom: 1px solid #e8e8e8;
color: #666;
}
.tag {
display: inline-block;
padding: 2px 8px;
border-radius: 2px;
font-size: 12px;
}
.tag-blue { background: #e6f7ff; color: #1890ff; }
.tag-green { background: #f6ffed; color: #52c41a; }
.tag-orange { background: #fff7e6; color: #fa8c16; }
.tag-red { background: #fff1f0; color: #f5222d; }
.tag-gray { background: #f5f5f5; color: #999; }
.btn {
padding: 6px 16px;
border-radius: 4px;
border: none;
cursor: pointer;
font-size: 14px;
}
.btn-primary {
background: #1890ff;
color: white;
}
.btn-default {
background: white;
border: 1px solid #d9d9d9;
color: #666;
}
.btn-link {
background: none;
color: #1890ff;
padding: 0 8px;
}
.btn-danger {
background: none;
color: #ff4d4f;
padding: 0 8px;
}
.toolbar {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.toolbar-left {
display: flex;
gap: 12px;
}
.input {
padding: 6px 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
width: 200px;
}
.select {
padding: 6px 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
width: 120px;
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
margin-bottom: 8px;
color: #333;
font-weight: 500;
}
.form-input {
width: 100%;
padding: 8px 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.login-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 600px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.login-box {
background: white;
padding: 40px;
border-radius: 8px;
width: 400px;
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
}
.login-title {
text-align: center;
font-size: 24px;
margin-bottom: 30px;
color: #333;
}
.login-btn {
width: 100%;
padding: 12px;
background: #1890ff;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
margin-top: 20px;
cursor: pointer;
}
.design-note {
background: #fffbe6;
border-left: 4px solid #faad14;
padding: 16px;
margin: 20px 0;
color: #666;
}
</style>
</head>
<body>
<div class="design-container">
<h1 class="design-title">📐 项目信息管理系统 - UI设计图</h1>
<!-- 登录页 -->
<h2 class="section-title">1. 登录页面</h2>
<div class="mockup">
<div class="login-container">
<div class="login-box">
<div class="login-title">项目信息管理系统</div>
<div class="form-group">
<label class="form-label">用户名</label>
<input type="text" class="form-input" placeholder="请输入用户名">
</div>
<div class="form-group">
<label class="form-label">密码</label>
<input type="password" class="form-input" placeholder="请输入密码">
</div>
<button class="login-btn">登录</button>
<div style="text-align: center; margin-top: 20px; color: #999; font-size: 12px;">
© 2026 项目信息管理系统
</div>
</div>
</div>
</div>
<!-- 仪表盘 -->
<h2 class="section-title">2. 仪表盘页面</h2>
<div class="mockup">
<div class="mockup-header">
<div class="logo">
<div class="logo-icon"></div>
<span>项目信息管理系统</span>
</div>
<div class="user-nav">
<span>管理员</span>
<div class="avatar"></div>
<button class="btn btn-link" style="color: white;">退出</button>
</div>
</div>
<div class="layout-grid">
<div class="sidebar">
<div class="menu-item active">
<span>📊</span> 仪表盘
</div>
<div class="menu-item">
<span>📄</span> 项目管理
</div>
<div class="menu-item">
<span>👥</span> 用户管理
</div>
</div>
<div class="content">
<div class="stat-grid">
<div class="stat-card">
<div class="stat-icon">📊</div>
<div class="stat-label">总项目数</div>
<div class="stat-value">15</div>
</div>
<div class="stat-card">
<div class="stat-icon">🔄</div>
<div class="stat-label">进行中</div>
<div class="stat-value" style="color: #52c41a;">8</div>
</div>
<div class="stat-card">
<div class="stat-icon"></div>
<div class="stat-label">已完成</div>
<div class="stat-value" style="color: #1890ff;">5</div>
</div>
<div class="stat-card">
<div class="stat-icon">💰</div>
<div class="stat-label">本月预算</div>
<div class="stat-value">¥50万</div>
</div>
</div>
<div class="card">
<div class="card-title">最近项目</div>
<table>
<thead>
<tr>
<th>项目编号</th>
<th>项目名称</th>
<th>预算</th>
<th>状态</th>
<th>创建人</th>
</tr>
</thead>
<tbody>
<tr>
<td>PRJ2026001</td>
<td>某公司官网开发</td>
<td>¥50,000</td>
<td><span class="tag tag-green">进行中</span></td>
<td>张三</td>
</tr>
<tr>
<td>PRJ2026002</td>
<td>电商平台开发</td>
<td>¥100,000</td>
<td><span class="tag tag-blue">新建</span></td>
<td>李四</td>
</tr>
<tr>
<td>PRJ2026003</td>
<td>移动APP开发</td>
<td>¥150,000</td>
<td><span class="tag tag-gray">已完成</span></td>
<td>王五</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 项目管理 -->
<h2 class="section-title">3. 项目管理页面</h2>
<div class="mockup">
<div class="mockup-header">
<div class="logo">
<div class="logo-icon"></div>
<span>项目信息管理系统</span>
</div>
<div class="user-nav">
<span>管理员</span>
<div class="avatar"></div>
<button class="btn btn-link" style="color: white;">退出</button>
</div>
</div>
<div class="layout-grid">
<div class="sidebar">
<div class="menu-item">
<span>📊</span> 仪表盘
</div>
<div class="menu-item active">
<span>📄</span> 项目管理
</div>
<div class="menu-item">
<span>👥</span> 用户管理
</div>
</div>
<div class="content">
<div class="card">
<div class="card-title">项目管理</div>
<div class="toolbar">
<div class="toolbar-left">
<input type="text" class="input" placeholder="搜索项目...">
<select class="select">
<option>所有状态</option>
<option>新建</option>
<option>进行中</option>
<option>已完成</option>
</select>
<select class="select">
<option>所有部门</option>
<option>市场部</option>
<option>技术部</option>
</select>
</div>
<button class="btn btn-primary">+ 新建项目</button>
</div>
<table>
<thead>
<tr>
<th>项目编号</th>
<th>合同编号</th>
<th>项目名称</th>
<th>预算</th>
<th>已付款</th>
<th>状态</th>
<th>部门</th>
<th>创建人</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>PRJ2026001</td>
<td>CT2026001</td>
<td>某公司官网开发</td>
<td>¥50,000</td>
<td>¥25,000</td>
<td><span class="tag tag-green">进行中</span></td>
<td>市场部</td>
<td>张三</td>
<td>
<button class="btn btn-link">查看</button>
<button class="btn btn-link">编辑</button>
<button class="btn btn-danger">删除</button>
</td>
</tr>
<tr>
<td>PRJ2026002</td>
<td>CT2026002</td>
<td>电商平台开发</td>
<td>¥100,000</td>
<td>¥50,000</td>
<td><span class="tag tag-blue">新建</span></td>
<td>市场部</td>
<td>李四</td>
<td>
<button class="btn btn-link">查看</button>
<button class="btn btn-link">编辑</button>
<button class="btn btn-danger">删除</button>
</td>
</tr>
<tr>
<td>PRJ2026003</td>
<td>CT2026003</td>
<td>移动APP开发</td>
<td>¥150,000</td>
<td>¥150,000</td>
<td><span class="tag tag-gray">已完成</span></td>
<td>技术部</td>
<td>王五</td>
<td>
<button class="btn btn-link">查看</button>
<button class="btn btn-link">编辑</button>
<button class="btn btn-danger">删除</button>
</td>
</tr>
<tr>
<td>PRJ2026004</td>
<td>CT2026004</td>
<td>数据分析系统</td>
<td>¥80,000</td>
<td>¥30,000</td>
<td><span class="tag tag-green">进行中</span></td>
<td>市场部</td>
<td>张三</td>
<td>
<button class="btn btn-link">查看</button>
<button class="btn btn-link">编辑</button>
<button class="btn btn-danger">删除</button>
</td>
</tr>
<tr>
<td>PRJ2026005</td>
<td>CT2026005</td>
<td>企业OA系统</td>
<td>¥200,000</td>
<td>¥0</td>
<td><span class="tag tag-orange">已暂停</span></td>
<td>技术部</td>
<td>赵六</td>
<td>
<button class="btn btn-link">查看</button>
<button class="btn btn-link">编辑</button>
<button class="btn btn-danger">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 用户管理 -->
<h2 class="section-title">4. 用户管理页面(仅管理员可见)</h2>
<div class="mockup">
<div class="mockup-header">
<div class="logo">
<div class="logo-icon"></div>
<span>项目信息管理系统</span>
</div>
<div class="user-nav">
<span>管理员</span>
<div class="avatar"></div>
<button class="btn btn-link" style="color: white;">退出</button>
</div>
</div>
<div class="layout-grid">
<div class="sidebar">
<div class="menu-item">
<span>📊</span> 仪表盘
</div>
<div class="menu-item">
<span>📄</span> 项目管理
</div>
<div class="menu-item active">
<span>👥</span> 用户管理
</div>
</div>
<div class="content">
<div class="card">
<div class="card-title">用户管理</div>
<div class="toolbar">
<div class="toolbar-left">
<input type="text" class="input" placeholder="搜索用户...">
<select class="select">
<option>所有角色</option>
<option>管理员</option>
<option>市场部</option>
<option>其他部门</option>
</select>
</div>
<button class="btn btn-primary">+ 新建用户</button>
</div>
<table>
<thead>
<tr>
<th>用户名</th>
<th>真实姓名</th>
<th>部门</th>
<th>角色</th>
<th>邮箱</th>
<th>状态</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>admin</td>
<td>管理员</td>
<td>管理部</td>
<td><span class="tag tag-red">管理员</span></td>
<td>admin@example.com</td>
<td><span class="tag tag-green">正常</span></td>
<td>2026-01-10</td>
<td>
<button class="btn btn-link">编辑</button>
<button class="btn btn-link">重置密码</button>
<button class="btn btn-link">删除</button>
</td>
</tr>
<tr>
<td>zhangsan</td>
<td>张三</td>
<td>市场部</td>
<td><span class="tag tag-blue">市场部</span></td>
<td>zhangsan@example.com</td>
<td><span class="tag tag-green">正常</span></td>
<td>2026-01-15</td>
<td>
<button class="btn btn-link">编辑</button>
<button class="btn btn-link">重置密码</button>
<button class="btn btn-danger">删除</button>
</td>
</tr>
<tr>
<td>lisi</td>
<td>李四</td>
<td>市场部</td>
<td><span class="tag tag-blue">市场部</span></td>
<td>lisi@example.com</td>
<td><span class="tag tag-green">正常</span></td>
<td>2026-01-16</td>
<td>
<button class="btn btn-link">编辑</button>
<button class="btn btn-link">重置密码</button>
<button class="btn btn-danger">删除</button>
</td>
</tr>
<tr>
<td>wangwu</td>
<td>王五</td>
<td>技术部</td>
<td><span class="tag tag-blue">其他部门</span></td>
<td>wangwu@example.com</td>
<td><span class="tag tag-green">正常</span></td>
<td>2026-01-17</td>
<td>
<button class="btn btn-link">编辑</button>
<button class="btn btn-link">重置密码</button>
<button class="btn btn-danger">删除</button>
</td>
</tr>
<tr>
<td>zhaoliu</td>
<td>赵六</td>
<td>技术部</td>
<td><span class="tag tag-blue">其他部门</span></td>
<td>zhaoliu@example.com</td>
<td><span class="tag tag-gray">禁用</span></td>
<td>2026-01-18</td>
<td>
<button class="btn btn-link">编辑</button>
<button class="btn btn-link">重置密码</button>
<button class="btn btn-danger">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 新建/编辑项目表单 -->
<h2 class="section-title">5. 新建/编辑项目表单</h2>
<div class="mockup">
<div class="content">
<div class="card">
<div class="card-title">新建项目</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">项目编号 *</label>
<input type="text" class="form-input" placeholder="如:PRJ2026001">
</div>
<div class="form-group">
<label class="form-label">合同编号 *</label>
<input type="text" class="form-input" placeholder="如:CT2026001">
</div>
</div>
<div class="form-group">
<label class="form-label">项目名称 *</label>
<input type="text" class="form-input" placeholder="请输入项目名称">
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">预算金额 *</label>
<input type="text" class="form-input" placeholder="请输入预算金额">
</div>
<div class="form-group">
<label class="form-label">已付款金额</label>
<input type="text" class="form-input" placeholder="请输入已付款金额">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">所属部门 *</label>
<select class="form-input">
<option>市场部</option>
<option>技术部</option>
<option>财务部</option>
</select>
</div>
<div class="form-group">
<label class="form-label">项目状态 *</label>
<select class="form-input">
<option>新建</option>
<option>进行中</option>
<option>已完成</option>
<option>已暂停</option>
<option>已取消</option>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">开始日期</label>
<input type="date" class="form-input">
</div>
<div class="form-group">
<label class="form-label">结束日期</label>
<input type="date" class="form-input">
</div>
</div>
<div class="form-group">
<label class="form-label">项目描述</label>
<textarea class="form-input" rows="4" placeholder="请输入项目描述"></textarea>
</div>
<div style="display: flex; gap: 12px; justify-content: flex-end;">
<button class="btn btn-default">取消</button>
<button class="btn btn-primary">保存</button>
</div>
</div>
</div>
</div>
<div class="design-note">
<strong>💡 设计说明:</strong>
<ul style="margin-top: 10px; padding-left: 20px;">
<li>整体采用Ant Design风格,简洁专业</li>
<li>深色顶部导航栏(#001529),浅色侧边栏(白色),内容区使用浅灰背景(#f0f2f5)</li>
<li>状态标签使用不同颜色区分:新建-蓝色、进行中-绿色、已完成-灰色、已暂停-橙色、已取消-红色</li>
<li>按钮样式:主操作用蓝色(#1890ff),删除操作用红色</li>
<li>表格支持搜索和筛选功能</li>
<li>所有页面共用相同的布局结构(Header + Sidebar + Content</li>
</ul>
</div>
</div>
</body>
</html>