Files
x-server-mobile/CLAUDE.md
T
root d37d82bc13 docs: 更新 CLAUDE.md 添加 Git 分支模型说明
- 更新环境对比表,增加测试环境
- 添加 Git 分支模型说明
- 更新文档引用链接
2026-02-28 11:35:43 +08:00

387 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# X-Server Mobile 项目文档
## 项目概述
这是一个基于飞书的企业内部H5移动工具平台,采用多租户架构,支持审批流程引擎。
**关键特性:**
- 支持5种语言:中文、英文、俄语、西语、法语
- 多租户架构(用户全局唯一,关联多个公司)
- 审批流程引擎(单人审批、会签、或签、通知)
- 飞书免登集成
**技术栈:**
- 前端:React 18.3.1 + TypeScript + Vite + Ant Design Mobile
- 后端:PHP 8.5 + Webman 2.x + MySQL + Redis
- 部署:Docker
## 国际化 (i18n) - 重要!
### 前端
- 配置:`frontend/src/i18n/`
- 翻译文件:`frontend/src/i18n/locales/{zh,en,ru,es,fr}.json`
- 语言切换:
- 首页右上角国旗按钮
- 个人中心 -> 语言设置
- 存储位置:localStorage `i18nextLng`
使用方式:
```tsx
import { useTranslation } from 'react-i18next'
const { t } = useTranslation()
<div>{t('common.confirm')}</div>
```
### 后端
- 翻译文件:`backend/lang/{zh,en,ru,es,fr}.php`
- 工具类:`backend/app/Util/Lang.php`
使用方式:
```php
use App\Util\Lang;
$message = Lang::get('common.confirm');
Lang::setLocale('en');
```
## 目录结构
```
/www/x-server-mobile/
├── frontend/ # React 前端 (运行在 5173)
│ ├── src/
│ │ ├── i18n/ # 国际化配置
│ │ ├── components/ # 组件
│ │ ├── pages/ # 页面
│ │ ├── modules/ # 业务模块 (approval等)
│ │ └── router/ # 路由
│ └── package.json
├── backend/ # PHP 后端 (运行在 8787)
│ ├── app/
│ │ ├── Controller/ # 控制器 (PascalCase命名)
│ │ ├── Model/ # 模型 (PascalCase命名)
│ │ ├── Service/ # 服务层
│ │ ├── Util/ # 工具类
│ │ └── Middleware/ # 中间件
│ ├── config/ # 配置
│ ├── lang/ # 语言文件
│ └── composer.json
├── docker-compose.yml # Docker 编排
├── nginx/ # OpenResty 配置
├── frpc/ # frpc 配置
├── docs/ # 项目文档
│ ├── PROJECT.md # 项目详细文档
│ ├── ENVIRONMENT.md # 环境配置说明(开发/生产对比)
│ ├── FEISHU_LOGIN_EXPERIENCE.md # 飞书登录实现经验(重要)
│ ├── feishu-qrcode-login.md # 飞书扫码登录原始文档
│ ├── PROJECT_ISSUES.md # 历史问题汇总
│ ├── GIT_WORKFLOW.md # Git 工作流程
│ └── IMPLEMENTATION_PLAN.md # 实现计划
```
## 环境配置
### 端口
- Frontend (Vite): 5173
- Backend (Webman): 8787
- OpenResty: 8080
- MySQL: 3306
- Redis: 6379
### 数据库
- 数据库名:xserver
- 密码:mysql_xEsdPa
- 容器名:1Panel-mysql-409s
- 网络:1panel-network
### Docker 容器
- 后端容器:x-server-backend
- 使用 Dockerfile:`backend/Dockerfile`
- PHP 版本:8.5
## 关键文件路径
### 前端关键文件
- 入口:`frontend/src/main.tsx`
- SDK 引入:`frontend/index.html`(飞书 H5 JSSDK + QR SDK)
- 路由:`frontend/src/router/index.tsx`
- 布局:`frontend/src/components/layout/`
- 状态管理:`frontend/src/stores/`
- API 封装:`frontend/src/services/api.ts`(含 401 token 刷新)
- 登录页:`frontend/src/pages/login/index.tsx`
- 扫码登录:`frontend/src/pages/login/QRCodeLogin.tsx`
- 环境检测:`frontend/src/pages/feishu-env-test.tsx`
- rem 适配:`frontend/src/utils/rem.ts`
### 后端关键文件
- 入口:`backend/start.php`
- 路由:`backend/config/route.php`
- 数据库配置:`backend/config/database.php`
- Redis 配置:`backend/config/redis.php`
- 容器配置:`backend/config/container.php`
### 重要配置文件
- Docker 编排:`docker-compose.yml`
- OpenResty 配置:`nginx/x-server-api.conf`
- frpc 配置:`frpc/frpc-dev.ini`
## 审批流程引擎
### 节点类型
- `single_approve` - 单人审批
- `and_sign` - 会签(所有人通过)
- `or_sign` - 或签(任一人通过)
- `notify` - 通知节点
### 状态
- pending: 待审批
- approved: 已通过
- rejected: 已拒绝
- cancelled: 已撤销
### 关键文件
- 服务:`backend/app/Service/ApprovalService.php`
- 控制器:`backend/app/Controller/ApprovalController.php`
- 模型:`backend/app/Model/ApprovalOrder.php`, `ApprovalFlow.php`, `ApprovalNode.php`, `ApprovalRecord.php`
- 前端列表页:`frontend/src/pages/approval/list.tsx`
- 前端详情页:`frontend/src/pages/approval/detail.tsx`
### 列表过滤逻辑
- **我发起的 (my)**: `applicant_id = current_user_id`
- **待我审批 (pending)**: 订单状态为 pending + 当前用户在当前节点的审批人列表中 + 未审批
- **我已审批 (approved)**: 用户有审批记录(approve/reject)+ 订单状态为已完成(approved/rejected/cancelled)
### 测试数据
运行测试数据脚本:
```bash
docker exec x-server-backend php test_data.php
```
该脚本会创建:
- 2 个待审批的订单(其他用户提交,用户1审批)
- 1 个已通过的订单(用户1已审批)
- 1 个已拒绝的订单(用户1已拒绝)
## 飞书集成
### 登录方式
支持两种飞书登录方式:
| 方式 | 使用场景 | SDK |
|------|----------|-----|
| **飞书内免登** | 用户在飞书客户端内打开应用,自动登录 | H5 JSSDK (`h5-js-sdk-1.5.19.js`) |
| **飞书外扫码登录** | 用户在普通浏览器中打开,用飞书扫码登录 | QR SDK (`LarkSSOSDKWebQRCode-1.0.3.js`) |
### 核心接口
- `POST /api/v1/auth/feishu-login` - 飞书免登/扫码登录
- `GET /api/v1/auth/feishu-config?company=2` - 获取公司飞书应用配置
- `POST /api/v1/auth/qrcode-login` - 生成扫码登录二维码
- `GET /api/v1/auth/qrcode-login/status?session_id=xxx` - 轮询扫码状态
- `GET /login/callback` - 飞书授权回调
### URL 参数
| 参数 | 说明 | 示例 |
|------|------|------|
| `company` | 公司ID(必需) | `?company=2` |
| `app_id` | 飞书应用ID(可选) | `?app_id=cli_xxx` |
| `redirect` | 登录成功后跳转地址 | `?redirect=/dashboard` |
### Token 自动刷新
- API 返回 401 时,在飞书环境中自动调用免登刷新 token
- 刷新成功后自动重试原始请求,用户无感知
- 使用 `_retry` 标记防止死循环
### 详细文档
飞书登录完整实现经验:`docs/FEISHU_LOGIN_EXPERIENCE.md`
### 环境变量
```env
FEISHU_APP_ID=cli_xxxxxxxxxxxxx
FEISHU_APP_SECRET=xxxxxxxxxxxxxxxxxxxx
FEISHU_ENCRYPT_KEY=xxxxxxxxxxxxxxxxxxxx
FEISHU_VERIFICATION_TOKEN=xxxxxxxxxxxxxxxxxxxx
```
## 常用命令
### 前端
```bash
cd /www/x-server-mobile/frontend
npm install
npm run dev
npm run build
```
### 后端
```bash
cd /www/x-server-mobile/backend
composer install
php start.php start
php start.php stop
```
### Docker
```bash
cd /www/x-server-mobile
docker compose up -d
docker compose restart backend
docker logs x-server-backend -f
```
## 反向代理配置(开发环境)
用户已有 frpc 和 OpenResty,配置用于调试飞书登录。
1. OpenResty 监听 8080,代理到 8787
2. frpc 将 8080 暴露到公网
3. 飞书回调地址配置为公网域名
### 环境对比
| 项目 | 开发环境 | 测试环境 | 生产环境 |
|------|----------|----------|----------|
| **分支** | `feature/*` | `develop` | `master` |
| **域名** | `xsm.dev.hnxinyouhe.com` | 待配置 | `uniservice-mobile.hnxinyouhe.com` |
| **服务器** | 本地 WSL2 | 待配置 | 45.153.130.80 |
| **调试模式** | `APP_DEBUG=true` | `APP_DEBUG=true` | `APP_DEBUG=false` |
**详细说明**: `docs/ENVIRONMENT.md`
**Git 工作流程**: `docs/GIT_WORKFLOW.md`
### Webman 框架要点
**PSR-4 自动加载**
- 目录名必须是 PascalCase(Controller、Model、Service、Util)
**数据库连接**
- 使用 Webman 官方 `webman/database` 包
- 使用 `support\Db` facade 进行数据库操作
- 使用 `Db::connection()` 获取数据库连接进行事务处理
**Bootstrap 接口**
- 方法签名:`public static function start(?\Workerman\Worker $worker): void`
**官方依赖包**
```bash
composer require workerman/webman:^2.0
composer require webman/database:^2.0
composer require webman/redis:^2.0
composer require illuminate/pagination:^11.0
composer require illuminate/events:^11.0
composer require symfony/var-dumper:^7.0
```
### 前端框架要点
**React 版本**
- 必须使用 React 18.3.1(不能用19)
- @types/react 和 @types/react-dom 也要用 v18
**Ant Design Mobile**
- 必须导入全局样式:`import 'antd-mobile/es/global'`
- DatePicker 使用 `visible` 属性控制弹框显示
**Zustand 状态管理**
- 登录时必须调用 `login(user, token)` 方法设置状态
- Token 存储在 localStorage,key 为 `token`
**类型定义**
- `User.id` 是 `number` 类型(后端返回整型)
- `User.company_id` 是 `number` 类型(数据库字段名)
## 语言切换位置
1. **首页** - 右上角显示当前语言国旗,点击切换
2. **个人中心** -> 语言设置
## 当前开发状态
- ✅ 前端基础框架搭建完成
- ✅ 后端 API 框架搭建完成
- ✅ 5语言国际化支持完成
- ✅ Docker 开发环境配置完成
- ✅ 飞书登录完成
- ✅ 飞书内免登(静默授权)
- ✅ 飞书外扫码登录
- ✅ Token 过期自动刷新(飞书环境)
- ✅ 多租户支持(company 参数)
- ✅ 审批流程引擎完成
- ✅ 通用审批列表页(我发起的/待我审批/我已审批)
- ✅ 通用审批详情页(支持审批通过/拒绝/撤销操作)
- ✅ 出差申请功能完成
- ✅ 出差申请页(含行程管理、审批人选择、抄送人选择)
- ✅ 草稿自动保存/恢复功能
- ✅ 默认审批人自动加载
## 下一步工作
1. 完善审批流程的会签、或签逻辑测试
2. 实现公司切换功能
3. 完善权限控制
4. 添加更多业务类型(费用报销、请假申请、采购申请)
---
## Git 分支模型
项目采用三分支模型:
```
master (生产)
↑
发布合并
↑
develop (开发集成)
↑
功能合并
↑
┌─┴─┬─┴─┬─┴─┐
feature/* (个人功能分支)
```
**工作流程:**
1. 从 `develop` 创建 `feature/xxx` 分支开发
2. 完成后合并到 `develop` 进行团队测试
3. 测试通过后合并到 `master` 发布
**详细说明**: `docs/GIT_WORKFLOW.md`
---
## 快速参考
### 查看问题汇总
所有历史问题已整理在 `docs/PROJECT_ISSUES.md` 文件中。
### 飞书登录文档
飞书登录完整实现经验和调试技巧:`docs/FEISHU_LOGIN_EXPERIENCE.md`
### 让 CLAUDE 加载问题文档
```
请参考 docs/PROJECT_ISSUES.md 中的问题汇总
请参考 docs/FEISHU_LOGIN_EXPERIENCE.md 中的飞书登录经验
```
### 调试后端
```bash
# 查看日志
docker logs x-server-backend -f --tail 50
# 重启后端
docker compose restart backend
# 复制文件到容器
docker cp host_file x-server-backend:/app/app/service/xxx.php
# 重载 workers(不重启整个服务)
docker exec x-server-backend php /app/webman reload
```
### 数据库操作
```bash
# 进入 MySQL 容器
docker exec -it 1Panel-mysql-409s mysql -uroot -pmysql_xEsdPa xserver
# 运行测试数据脚本
docker exec x-server-backend php /app/test_data.php
```