Release: merge develop into master - 重组文档结构

This commit is contained in:
root
2026-02-28 11:43:00 +08:00
16 changed files with 741 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
# X-Server Mobile 文档中心
## 📚 文档导航
### 快速开始
| 文档 | 说明 |
|------|------|
| [项目总览](PROJECT.md) | 项目介绍和技术栈 |
| [环境配置](guides/environment.md) | 开发/生产环境配置 |
| [Git 工作流程](guides/git-workflow.md) | 分支管理和协作流程 |
### 模块文档
| 模块 | 说明 | 负责人 |
|------|------|--------|
| [认证模块](modules/auth/README.md) | 登录、登出、Token 管理 | mzl |
| [审批流程](modules/approval/README.md) | 审批流程引擎 | - |
| [出差申请](modules/business-trip/README.md) | 出差申请业务 | - |
| [用户管理](modules/user/README.md) | 用户、公司、权限 | - |
### 部署指南
| 文档 | 说明 |
|------|------|
| [部署指南](guides/deployment.md) | 完整部署流程 |
| [部署检查清单](guides/DEPLOYMENT_CHECKLIST.md) | 上线前检查项 |
| [快速部署](guides/QUICK_DEPLOY.md) | 快速部署步骤 |
| [线上部署指南](guides/DEPLOY_ONLINE_GUIDE.md) | 生产环境部署 |
### 开发指南
| 文档 | 说明 |
|------|------|
| [反向代理配置](guides/REVERSE_PROXY_SETUP.md) | OpenResty 配置 |
| [开发环境代理](guides/DEV_REVERSE_PROXY_SETUP.md) | 本地开发代理 |
### 参考
| 文档 | 说明 |
|------|------|
| [历史问题汇总](PROJECT_ISSUES.md) | 开发中遇到的问题 |
| [实现计划](IMPLEMENTATION_PLAN.md) | 功能实现计划 |
| [数据库分析](database-analysis.md) | 数据库设计说明 |
---
## 🚀 快速链接
### 开发环境
```bash
# 启动前端
cd /www/x-server-mobile/frontend && npm run dev
# 启动后端
docker logs x-server-backend -f
```
### 常用命令
```bash
# 查看日志
docker logs x-server-backend -f --tail 50
# 重启后端
docker compose restart backend
# 数据库操作
docker exec -it 1Panel-mysql-409s mysql -uroot -pmysql_xEsdPa xserver
```
---
## 📋 文档规范
### 模块文档结构
```
docs/modules/{module-name}/
├── README.md # 模块概述(必需)
├── api.md # API 接口说明(可选)
├── database.md # 数据库设计(可选)
└── guide.md # 使用指南(可选)
```
### 文档编写规范
1. **README.md** 必须包含:概述、核心功能、API接口、关键文件
2. 使用表格列出关键信息
3. 代码块注明语言类型
4. 保持与代码同步更新
---
**最后更新**: 2026-02-28
+181
View File
@@ -0,0 +1,181 @@
# 审批流程模块 (Approval Module)
## 概述
审批流程模块是系统的核心功能,支持多种审批节点类型和灵活的流程配置。
---
## 节点类型
| 类型 | 代码 | 说明 |
|------|------|------|
| 单人审批 | `single_approve` | 需要一个审批人通过 |
| 会签 | `and_sign` | 所有人都需要通过 |
| 或签 | `or_sign` | 任一人通过即可 |
| 通知 | `notify` | 仅通知,无需审批 |
---
## 订单状态
| 状态 | 代码 | 说明 |
|------|------|------|
| 待审批 | `pending` | 等待当前节点审批 |
| 已通过 | `approved` | 流程完成,已通过 |
| 已拒绝 | `rejected` | 流程完成,已拒绝 |
| 已撤销 | `cancelled` | 申请人主动撤销 |
---
## 列表过滤逻辑
### 我发起的
```sql
applicant_id = current_user_id
```
### 待我审批
```sql
status = 'pending'
AND current_user_id IN 当前节点审批人列表
AND NOT EXISTS (已审批记录)
```
### 我已审批
```sql
EXISTS (用户有审批记录)
AND status IN ('approved', 'rejected', 'cancelled')
```
---
## API 接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/v1/approval/list` | GET | 获取审批列表 |
| `/api/v1/approval/detail/:id` | GET | 获取审批详情 |
| `/api/v1/approval/approve/:id` | POST | 审批通过 |
| `/api/v1/approval/reject/:id` | POST | 审批拒绝 |
| `/api/v1/approval/cancel/:id` | POST | 撤销申请 |
---
## 前端关键文件
```
frontend/src/
├── pages/approval/
│ ├── list.tsx # 审批列表页
│ └── detail.tsx # 审批详情页
└── modules/approval/
└── components/ # 审批相关组件
```
---
## 后端关键文件
```
backend/app/
├── Controller/
│ └── ApprovalController.php # 审批控制器
├── Service/
│ └── ApprovalService.php # 审批服务
└── Model/
├── ApprovalOrder.php # 审批订单
├── ApprovalFlow.php # 审批流程
├── ApprovalNode.php # 审批节点
└── ApprovalRecord.php # 审批记录
```
---
## 数据库表结构
### approval_order (审批订单)
```sql
id -- 主键
company_id -- 公司ID
applicant_id -- 申请人ID
title -- 标题
content -- 内容
type -- 类型 (business_trip, expense, etc.)
status -- 状态 (pending, approved, rejected, cancelled)
current_node_id -- 当前节点ID
created_at
updated_at
```
### approval_node (审批节点)
```sql
id -- 主键
flow_id -- 流程ID
node_type -- 节点类型 (single_approve, and_sign, or_sign, notify)
node_order -- 节点顺序
approvers -- 审批人列表 (JSON)
```
### approval_record (审批记录)
```sql
id -- 主键
order_id -- 订单ID
node_id -- 节点ID
approver_id -- 审批人ID
action -- 操作 (approve, reject, cancel)
comment -- 意见
created_at
```
---
## 流程图
```
┌─────────────┐
│ 申请人提交 │
└──────┬──────┘
│
▼
┌─────────────┐ 通过 ┌─────────────┐
│ 节点1审批 │ ────────────▶│ 节点2审批 │
└──────┬──────┘ └──────┬──────┘
│ 拒绝 │ 拒绝
▼ ▼
┌─────────────┐ ┌─────────────┐
│ 已拒绝 │ │ 已拒绝 │
└─────────────┘ └─────────────┘
│ 通过到最后节点
▼
┌─────────────┐
│ 已通过 │
└─────────────┘
```
---
## 测试数据
运行测试数据脚本:
```bash
docker exec x-server-backend php test_data.php
```
该脚本会创建:
- 2 个待审批的订单(其他用户提交,用户1审批)
- 1 个已通过的订单(用户1已审批)
- 1 个已拒绝的订单(用户1已拒绝)
---
## 相关文档
- [PROJECT_ISSUES.md](../../PROJECT_ISSUES.md) - 历史问题汇总
- [IMPLEMENTATION_PLAN.md](../../IMPLEMENTATION_PLAN.md) - 实现计划
---
**负责人**: 待分配
**最后更新**: 2026-02-28
+137
View File
@@ -0,0 +1,137 @@
# 认证模块 (Auth Module)
## 概述
认证模块负责用户登录、登出、token 管理等功能。支持多种登录方式:
| 登录方式 | 说明 | 文档 |
|---------|------|------|
| 飞书内免登 | 在飞书客户端内自动登录 | [feishu-login.md](./feishu-login.md) |
| 飞书外扫码登录 | 普通浏览器扫码登录 | [feishu-qrcode.md](./feishu-qrcode.md) |
| 邮箱密码登录 | 传统账号密码登录 | - |
| 飞书消息通知 | 飞书卡片消息通知 | [feishu-notification.md](./feishu-notification.md) |
---
## 核心功能
### 1. 飞书免登
用户在飞书客户端内打开应用时,自动完成登录,无需输入密码。
**关键点:**
- 使用 H5 JSSDK (`h5-js-sdk-1.5.19.js`)
- 调用 `tt.requestAuthCode()` 获取授权码
- 支持多租户(通过 `company` 参数)
### 2. Token 自动刷新
当 API 返回 401 时,在飞书环境中自动刷新 token,用户无感知。
**流程:**
```
API 返回 401
↓
检测飞书环境
↓
调用 tt.requestAuthCode 获取新授权码
↓
用新授权码登录获取新 token
↓
用新 token 重试原始请求
```
### 3. 扫码登录
用户在普通浏览器中使用飞书 APP 扫码登录。
---
## API 接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/v1/auth/feishu-login` | POST | 飞书免登/扫码登录 |
| `/api/v1/auth/feishu-config` | GET | 获取公司飞书应用配置 |
| `/api/v1/auth/qrcode-login` | POST | 生成扫码登录二维码 |
| `/api/v1/auth/qrcode-login/status` | GET | 轮询扫码状态 |
| `/login/callback` | GET | 飞书授权回调 |
| `/api/v1/auth/login` | POST | 邮箱密码登录 |
---
## 前端关键文件
```
frontend/src/
├── pages/login/
│ ├── index.tsx # 登录页主逻辑
│ └── QRCodeLogin.tsx # 扫码登录组件
├── services/
│ └── api.ts # API 封装(含 401 token 刷新)
└── stores/
└── user.ts # 用户状态管理
```
---
## 后端关键文件
```
backend/app/
├── Controller/
│ └── AuthController.php # 认证控制器
├── Service/
│ └── FeishuService.php # 飞书服务
└── Model/
├── User.php # 用户模型
└── CompanyFeishuApp.php # 飞书应用配置
```
---
## 环境变量
```env
# 飞书应用配置(多租户时在数据库中配置)
FEISHU_APP_ID=cli_xxxxxxxxxxxxx
FEISHU_APP_SECRET=xxxxxxxxxxxxxxxxxxxx
FEISHU_ENCRYPT_KEY=xxxxxxxxxxxxxxxxxxxx
FEISHU_VERIFICATION_TOKEN=xxxxxxxxxxxxxxxxxxxx
```
---
## URL 参数
| 参数 | 说明 | 示例 |
|------|------|------|
| `company` | 公司ID(必需) | `?company=2` |
| `app_id` | 飞书应用ID(可选) | `?app_id=cli_xxx` |
| `redirect` | 登录成功后跳转地址 | `?redirect=/dashboard` |
---
## 常见问题
### Q1: 飞书免登失败 "invalid appId"
**A:** 确保 URL 中有 `company` 参数,或直接传 `app_id` 参数。
### Q2: 扫码后没反应
**A:** 检查飞书开放平台是否配置了正确的重定向 URL 白名单。
### Q3: Token 过期后需要重新登录
**A:** 已实现自动刷新,在飞书环境中会自动获取新 token。
---
## 相关文档
- [飞书登录完整经验](./feishu-login.md)
- [飞书扫码登录详解](./feishu-qrcode.md)
- [环境配置说明](../guides/environment.md)
---
**负责人**: mzl
**最后更新**: 2026-02-28
+148
View File
@@ -0,0 +1,148 @@
# 出差申请模块 (Business Trip Module)
## 概述
出差申请模块是审批流程的具体业务实现,支持出差行程管理、审批人选择、抄送人选择、草稿自动保存等功能。
---
## 核心功能
| 功能 | 说明 |
|------|------|
| 行程管理 | 支持添加多个出差行程(城市、日期、住宿) |
| 审批人选择 | 单选审批人,支持搜索 |
| 抄送人选择 | 多选抄送人,支持搜索 |
| 草稿保存 | 自动保存到 localStorage,刷新后恢复 |
| 默认审批人 | 自动加载历史审批人 |
---
## API 接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/v1/business-trip/list` | GET | 获取出差列表 |
| `/api/v1/business-trip/detail/:id` | GET | 获取出差详情 |
| `/api/v1/business-trip/create` | POST | 创建出差申请 |
| `/api/v1/business-trip/update/:id` | POST | 更新出差申请 |
| `/api/v1/business-trip/submit/:id` | POST | 提交审批 |
| `/api/v1/business-trip/cancel/:id` | POST | 撤销申请 |
| `/api/v1/business-trip/delete/:id` | DELETE | 删除草稿 |
| `/api/v1/business-trip/default-approvers` | GET | 获取默认审批人 |
---
## 前端关键文件
```
frontend/src/pages/business-trip/
├── list.tsx # 出差列表页
├── apply.tsx # 出差申请页
├── detail.tsx # 出差详情页
├── select-approver.tsx # 选择审批人
└── select-cc.tsx # 选择抄送人
```
---
## 草稿自动保存
### 保存时机
- 表单字段变化时
- 添加/删除行程时
- 选择审批人/抄送人时
### 保存内容
```typescript
{
trips: [...], // 出差行程
approvers: [...], // 审批人列表
ccUsers: [...], // 抄送人列表
reason: string, // 出差事由
savedAt: timestamp // 保存时间
}
```
### 恢复逻辑
- 进入申请页时检查 localStorage
- 如果存在草稿且未超过24小时,提示恢复
- 用户可选择恢复或放弃
---
## 表单验证
### 必填字段
- 出差行程(至少一条)
- 每条行程:出发城市、目的城市、出发日期、返回日期
- 审批人(至少一人)
- 出差事由
### 日期验证
- 出发日期不能早于今天
- 返回日期不能早于出发日期
- 多条行程日期不能重叠
---
## 数据库表结构
### business_trip (出差申请)
```sql
id -- 主键
company_id -- 公司ID
applicant_id -- 申请人ID
title -- 标题
reason -- 出差事由
status -- 状态 (draft, pending, approved, rejected, cancelled)
current_node_id -- 当前节点ID
created_at
updated_at
```
### business_trip_trip (出差行程)
```sql
id -- 主键
business_trip_id -- 出差申请ID
from_city -- 出发城市
to_city -- 目的城市
start_date -- 出发日期
end_date -- 返回日期
hotel_required -- 是否需要住宿
hotel_name -- 酒店名称(可选)
```
### business_trip_approver (审批人)
```sql
id -- 主键
business_trip_id -- 出差申请ID
approver_id -- 审批人ID
is_default -- 是否默认审批人
```
---
## 状态流转
```
draft (草稿)
│ 提交
▼
pending (待审批)
│ 通过 │ 拒绝 │ 撤销
▼ ▼ ▼
approved rejected cancelled
```
---
## 相关文档
- [审批流程模块](../approval/README.md)
- [PROJECT_ISSUES.md](../../PROJECT_ISSUES.md)
---
**负责人**: 待分配
**最后更新**: 2026-02-28
+183
View File
@@ -0,0 +1,183 @@
# 用户管理模块 (User Module)
## 概述
用户管理模块负责用户信息、多租户公司管理、权限控制等功能。
---
## 核心功能
| 功能 | 说明 | 状态 |
|------|------|------|
| 用户信息 | 获取、更新用户信息 | ✅ |
| 多租户支持 | 用户可关联多个公司 | ✅ |
| 公司切换 | 切换当前公司 | ⏳ 待实现 |
| 权限控制 | 基于角色的权限管理 | ⏳ 待实现 |
| 密码修改 | 修改登录密码 | ✅ |
---
## API 接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/v1/user/info` | GET | 获取用户信息 |
| `/api/v1/user/menu` | GET | 获取用户菜单 |
| `/api/v1/user/companies` | GET | 获取用户公司列表 |
| `/api/v1/user/switch-company` | POST | 切换公司 |
| `/api/v1/user/change-password` | POST | 修改密码 |
| `/api/v1/user/list` | GET | 获取用户列表(管理员) |
---
## 前端关键文件
```
frontend/src/
├── pages/
│ ├── profile/ # 个人中心
│ └── change-password/ # 修改密码
├── stores/
│ └── user.ts # 用户状态管理
└── components/
└── CompanySelector/ # 公司选择器(待实现)
```
---
## 后端关键文件
```
backend/app/
├── Controller/
│ └── UserController.php # 用户控制器
├── Model/
│ ├── User.php # 用户模型
│ └── Company.php # 公司模型
└── Middleware/
└── AuthMiddleware.php # 认证中间件
```
---
## 多租户设计
### 用户-公司关系
```
user (用户)
├── user_company (用户公司关联)
│ ├── company_id
│ ├── is_default -- 是否默认公司
│ └── role -- 在该公司的角色
└── ...
```
### 切换公司流程
```
1. 用户选择公司
↓
2. 前端调用 /api/v1/user/switch-company
↓
3. 后端验证用户权限
↓
4. 更新 token 中的 company_id
↓
5. 返回新的 token
↓
6. 前端更新本地存储和状态
```
---
## 用户状态管理 (Zustand)
```typescript
interface UserStore {
user: User | null
token: string | null
login: (user: User, token: string) => void
logout: () => void
updateUser: (user: User) => void
}
// 使用
const { user, login, logout } = useUserStore()
```
---
## Token 结构
```json
{
"user_id": 1,
"company_id": 2,
"feishu_user_id": "ou_xxx",
"union_id": "on_xxx",
"exp": 1234567890
}
```
---
## 数据库表结构
### user (用户)
```sql
id -- 主键
username -- 用户名(登录用)
email -- 邮箱
phone -- 手机号
name -- 姓名
avatar -- 头像
password -- 密码(加密)
feishu_user_id -- 飞书用户ID
feishu_union_id -- 飞书union_id
created_at
updated_at
```
### company (公司)
```sql
id -- 主键
name -- 公司名称
logo -- 公司logo
status -- 状态
```
### user_company (用户公司关联)
```sql
id -- 主键
user_id -- 用户ID
company_id -- 公司ID
role -- 角色
is_default -- 是否默认公司
created_at
```
---
## 权限设计(待实现)
### 角色类型
| 角色 | 代码 | 说明 |
|------|------|------|
| 超级管理员 | `super_admin` | 全部权限 |
| 公司管理员 | `company_admin` | 公司内全部权限 |
| 普通用户 | `user` | 基础权限 |
---
## 相关文档
- [认证模块](../auth/README.md)
- [数据库分析](../../database-analysis.md)
---
**负责人**: 待分配
**最后更新**: 2026-02-28