# 技师端架构说明

## 用户与技师关系

1. 技师端的用户模型:

-   基础用户模型为 MemberUser
-   技师信息通过 coach 关联获取
-   Auth::user() 获取的是当前登录的 MemberUser 实例
-   技师信息通过 Auth::user()->coach 获取

2. 关键代码示例:

```php
/** @var MemberUser $user */
// 获取当前登录用户
$user = Auth::user(); // 返回 MemberUser 实例
// 获取用户关联的技师信息
$coach = $user->coach; // 返回 CoachUser 实例
// 常见的验证模式
abort_if(!$user->coach, 404, '技师信息不存在');
```

3. 主要模型关系:

-   MemberUser: 基础用户模型
-   CoachUser: 技师模型
-   一对一关联: MemberUser hasOne CoachUser

4. 技师相关验证:

-   需要验证用户是否为技师(coach 关联是否存在)
-   需要验证技师状态是否正常
-   需要验证技师认证状态

## 技师认证与审核

### 1. 认证类型

1. 基础信息认证:

-   个人基本信息(姓名、手机号、身份证号等)
-   居住地址信息
-   联系人信息

2. 实名认证:

-   身份证正面照
-   身份证背面 ��
-   手持身份证照

3. 资质认证:

-   职业资格证书
-   相关培训证书
-   其他资质证明

### 2. 数据库设计

1. 技师表认证状态字段:

```sql
ALTER TABLE coach_users
ADD COLUMN base_auth_status tinyint(1) COMMENT '基础信息认证状态 1:审核中 2:已通过 3:已拒绝',
ADD COLUMN real_name_auth_status tinyint(1) COMMENT '实名认证状态 1:审核中 2:已通过 3:已拒绝',
ADD COLUMN qualification_auth_status tinyint(1) COMMENT '资质认证状态 1:审核中 2:已通过 3:已拒绝',
ADD COLUMN base_auth_at timestamp NULL COMMENT '基础信息认证时间',
ADD COLUMN real_name_auth_at timestamp NULL COMMENT '实名认证时间',
ADD COLUMN qualification_auth_at timestamp NULL COMMENT '资质认证时间',
ADD COLUMN base_auth_remark varchar(255) NULL COMMENT '基础信息认证备注',
ADD COLUMN real_name_auth_remark varchar(255) NULL COMMENT '实名认证备注',
ADD COLUMN qualification_auth_remark varchar(255) NULL COMMENT '资质认证备注';
```

2. 认证记录表:

```sql
-- 基础信息认证记录表
CREATE TABLE coach_base_auth_records (
    id bigint unsigned NOT NULL AUTO_INCREMENT,
    coach_id bigint unsigned NOT NULL COMMENT '技师ID',
    name varchar(50) NOT NULL COMMENT '姓名',
    mobile varchar(20) NOT NULL COMMENT '手机号',
    id_card varchar(20) NOT NULL COMMENT '身份证号',
    gender tinyint(1) NOT NULL COMMENT '性别 1:男 2:女',
    birthday date NOT NULL COMMENT '出生日期',
    address varchar(255) NOT NULL COMMENT '居住地址',
    status tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态 1:审核中 2:已通过 3:已拒绝',
    remark varchar(255) NULL COMMENT '审核备注',
    created_at timestamp NULL,
    updated_at timestamp NULL,
    PRIMARY KEY (id)
) COMMENT='技师基础信息认证记录表';

-- 实名认证记录表
CREATE TABLE coach_real_name_auth_records (
    id bigint unsigned NOT NULL AUTO_INCREMENT,
    coach_id bigint unsigned NOT NULL COMMENT '技师ID',
    id_card_front varchar(255) NOT NULL COMMENT '身份证正面照',
    id_card_back varchar(255) NOT NULL COMMENT '身份证背面照',
    id_card_hand varchar(255) NOT NULL COMMENT '手持身份证照',
    status tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态 1:审核中 2:已通过 3:已拒绝',
    remark varchar(255) NULL COMMENT '审核备注',
    created_at timestamp NULL,
    updated_at timestamp NULL,
    PRIMARY KEY (id)
) COMMENT='技师实名认证记录表';

-- 资质认证记录表
CREATE TABLE coach_qualification_auth_records (
    id bigint unsigned NOT NULL AUTO_INCREMENT,
    coach_id bigint unsigned NOT NULL COMMENT '技师ID',
    certificate_type tinyint(1) NOT NULL COMMENT '证书类型',
    certificate_no varchar(50) NOT NULL COMMENT '证书编号',
    certificate_image varchar(255) NOT NULL COMMENT '证书照片',
    status tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态 1:审核中 2:已通过 3:已拒绝',
    remark varchar(255) NULL COMMENT '审核备注',
    created_at timestamp NULL,
    updated_at timestamp NULL,
    PRIMARY KEY (id)
) COMMENT='技师资质认证记录表';
```

### 3. 认证提交规则

1. 提交限制:

-   审核中状态不允许重新提交
-   已通过状态不允许重新提交
-   只有未提交或审核拒绝状态可以提交

2. 提交校验:

```php
/**
 * 检查是否可以提交认证
 */
public function canSubmitAuth(int $coachId, string $type): bool
{
    $coach = CoachUser::find($coachId);

    $status = match($type) {
        'base' => $coach->base_auth_status,
        'real_name' => $coach->real_name_auth_status,
        'qualification' => $coach->qualification_auth_status,
    };

    // 审核中或已通过的状态下不允许重新提交
    return !in_array($status, [
        TechnicianAuthStatus::AUDITING,  // 审核中
        TechnicianAuthStatus::PASSED     // 已通过
    ]);
}
```

### 4. 审核流程

1. 提交认证:

```php
/**
 * 提交基础信息认证
 */
public function submitBaseAuth(int $coachId, array $data): void
{
    // 检查是否可以提交
    if (!$this->canSubmitAuth($coachId, 'base')) {
        throw new BusinessException('当前状态不允许提交认证');
    }

    DB::transaction(function () use ($coachId, $data) {
        // 1. 创建认证记录
        $record = CoachBaseAuthRecord::create([
            'coach_id' => $coachId,
            'name' => $data['name'],
            'mobile' => $data['mobile'],
            // ... 其他字段
        ]);

        // 2. 更新技师认证状态
        CoachUser::where('id', $coachId)->update([
            'base_auth_status' => TechnicianAuthStatus::AUDITING,
            'base_auth_record_id' => $record->id
        ]);

        // 3. 发送提交通知
        event(new CoachAuthSubmitted($coachId, 'base'));
    });
}
```

2. 审核操作:

```php
/**
 * 审核基础信息认证
 */
public function auditBaseAuth(int $recordId, bool $passed, ?string $remark = null): void
{
    DB::transaction(function () use ($recordId, $passed, $remark) {
        // 1. 获取认证记录
        $record = CoachBaseAuthRecord::findOrFail($recordId);

        // 2. 更新认证记录状态
        $status = $passed ? TechnicianAuthStatus::PASSED : TechnicianAuthStatus::REJECTED;
        $record->update([
            'status' => $status,
            'remark' => $remark
        ]);

        // 3. 更新技师认证状态
        CoachUser::where('id', $record->coach_id)->update([
            'base_auth_status' => $status,
            'base_auth_remark' => $remark,
            'base_auth_at' => $passed ? now() : null
        ]);

        // 4. 如果通过,更新技师基本信息
        if ($passed) {
            CoachUser::where('id', $record->coach_id)->update([
                'name' => $record->name,
                'mobile' => $record->mobile,
                // ... 其他字段
            ]);
        }

        // 5. 发送审核结果通知
        event(new CoachAuthAudited($record->coach_id, 'base', $passed, $remark));
    });
}
```

### 5. 状态查询

1. 认证状态查询:

```php
/**
 * 获取认证状态
 */
public function getAuthStatus(int $coachId): array
{
    $coach = CoachUser::find($coachId);

    return [
        'base' => [
            'status' => $coach->base_auth_status,
            'remark' => $coach->base_auth_remark,
            'updated_at' => $coach->base_auth_at,
        ],
        'real_name' => [
            'status' => $coach->real_name_auth_status,
            'remark' => $coach->real_name_auth_remark,
            'updated_at' => $coach->real_name_auth_at,
        ],
        'qualification' => [
            'status' => $coach->qualification_auth_status,
            'remark' => $coach->qualification_auth_remark,
            'updated_at' => $coach->qualification_auth_at,
        ],
    ];
}
```

2. 认证历史记录:

```php
/**
 * 获取认证历史记录
 */
public function getAuthHistory(int $coachId, string $type): Collection
{
    $model = match($type) {
        'base' => CoachBaseAuthRecord::class,
        'real_name' => CoachRealNameAuthRecord::class,
        'qualification' => CoachQualificationAuthRecord::class,
    };

    return $model::where('coach_id', $coachId)
        ->orderBy('id', 'desc')
        ->get();
}
```

### 6. 注意事项

1. 数据安全:

-   敏感信息加密存储
-   图片资源需要进行安全验证
-   审核操作需要有操作日志

2. 并发处理:

-   使用数据库事务确保数据一致性
-   状态变更时需要考虑并发情况
-   关键操作需要加锁处理

3. 通知机制:

-   状态变更时需要通知相关人员
-   审核结果需要实时推送给技师
-   重要操作需要短信或其他方式通知

4. 数据验证:

-   提交时严格验证数据格式
-   图片资源需要验证大小和格式
-   身份证号等关键信息需要验证真实性

5. 异常处理:

-   所有操作需要有完善的异常处理
-   异常发生时需要有友好的提示
-   关键异常需要告警通知

### 7. 认证验证中间件

1. 验证方法:

```php
/**
 * 技师认证状态验证
 *
 * @param MemberUser $user 当前登录用户
 * @throws BusinessException 认证未通过时抛出异常
 */
private function validateTechnicianAuth(MemberUser $user): void
{
    // 验证技师是否存在
    abort_if(!$user->coach, 404, '技师信息不存在');

    $coach = $user->coach;

    // 基础信息认证验证
    if (!$coach->isBaseInfoVerified()) {
        throw new BusinessException('请先完成基础信息认证');
    }

    // 实名认证验证
    if (!$coach->isRealNameVerified()) {
        throw new BusinessException('请先完成实名认证');
    }

    // 资质认证验证
    if (!$coach->isQualificationVerified()) {
        throw new BusinessException('请先完成资质认证');
    }
}
```

2. 使用说明:

-   除认证相关接口外,所有技师端接口都需要进行完整的认证验证
-   在 Service 层基类中实现认证验证方法
-   所有需要认证验证的方法必须调用验证方法
-   可以使用中间件统一处理认证验证

3. 验证规则:

-   所有认证状态必须为 PASSED (已通过)
-   未提交认证时提示"请先完成 XX 认证"
-   认证审核中时提示"XX 认证审核中"
-   认证被拒绝时提示"XX 认证未通过,请重新提交"

4. 异常处理:

-   认证验证失败时抛出 BusinessException
-   异常信息需要明确指出具体未通过的认证项
-   前端需要根据异常信息引导用户完成认证

5. 注意事项:

-   认证验证应该在业务逻辑执行前进行
-   需要考虑多个认证未通过的情况
-   验证提示信息要友好且明确
-   记录认证验证失败的日志

## 目录结构

1. 控制器位置:

-   app/Http/Controllers/Coach/\*

2. 服务类位置:

-   app/Services/Coach/\*

3. 请求验证类位置:

-   app/Http/Requests/Coach/\*

## 核心服务类说明

1. AccountService:

-   处理技师账户相关操作
-   包括基本信息、资质信息、实名认证的提交和查询
-   处理技师位置信息和排班设置

2. AuthService:

-   处理技师认证相关操作
-   包括基本信息认证、实名认证、资质认证
-   提供认证状态查询

3. OrderService:

-   处理技师订单相关操作
-   包括订单列表查询、抢单、接单、拒单
-   处理订单状态流转(出发、到达、开始服务、撤离)

4. ProjectService:

-   处理技师项目相关操作
-   包括可开通项目查询、项目开通
-   处理项目设置(折扣、性别限制等)

5. WalletService:

-   处理技师钱包相关操作
-   包括钱包信息查询、流水记录
-   处理提现申请

## 注意事项

1. 权限验证:

-   所有技师端接口都需要验证用户是否为技师
-   使用 abort_if(!$user->coach, 404, '技师信息不存在') 进行验证

2. 数据获取:

-   优先通过关联关系获取数据
-   使用 with() 进行预加载以优化性能

3. 错误处理:

-   使用 abort_if 行前置条件验证
-   在 Service 层进行详细的业务逻辑验证

4. 事务处理:

-   涉及多表操作时使用数据库事务
-   在 Service 层实现事务逻辑

5. 缓存策略:

-   技师信息优先使用缓存
-   更新操作时及时处理相关缓存

6. 日志记录:

-   重要操作需要记录日志
-   包含用户 ID、技师 ID、操作内容等关键信息

7. 敏感数据处理:

-   手机号、身份证等敏感信息需要脱敏处理
-   日志中不应该出现完整的敏感信息

## 常用枚举类型

1. 技师状态相关:

-   TechnicianStatus: 技师状态

    -   PENDING: 待认证 (1)
    -   ACTIVE: 正常服务 (2)
    -   SUSPENDED: 暂停服务 (3)
    -   BLACKLIST: 黑名单 (4)
    -   TERMINATED: 已终止 (5)

-   TechnicianAuthStatus: 认证状态

    -   AUDITING: 审核中 (1)
    -   PASSED: 审核通过 (2)
    -   REJECTED: 审核拒绝 (3)

-   TechnicianWorkStatus: 工 �� 状态

    -   REST: 休息 (1)
    -   FREE: 空闲 (2)
    -   BUSY: 忙碌 (3)

-   TechnicianLocationType: 位置类型
    -   CURRENT: 当前定位 (1)
    -   COMMON: 常用定位 (2)

2. 订单相关:

-   OrderStatus: 订单状态

    -   CREATED: 下单 (1)
    -   ASSIGNED: 指定 (2)
    -   PAID: 支付 (3)
    -   CANCELLED: 取消 (4)
    -   REFUNDING: 退款中 (5)
    -   REFUNDED: 退款成功 (6)
    -   REFUND_FAILED: 退款失败 (7)
    -   ACCEPTED: 接单 (8)
    -   DEPARTED: 出发 (9)
    -   ARRIVED: 到达 (10)
    -   STARTED: 开始服务 (11)
    -   SERVING: 服务中 (12)
    -   FINISHED: 服务结束 (13)
    -   LEFT: 撤离 (14)
    -   COMMENTED: 已评价 (15)
    -   REJECTED: 已拒单 (16)
    -   ALARM: 报警 (17)
    -   COMPLETED: 服务完成 (18)

-   OrderType: 订单类型

    -   VISIT: 上门 (1)
    -   GRAB: 抢单 (2)
    -   OVERTIME: 加钟 (3)
    -   SHOP: 到店 (4)
    -   EMERGENCY: 应急 (5)

-   OrderRecordStatus: 订单记录状态
    -   CREATED: 创建订单 (1)
    -   PAID: 支付完成 (2)
    -   ASSIGNED: 已分配技师 (3)
    -   ARRIVED: 技师到达 (4)
    -   STARTED: 开始服务 (5)
    -   COMPLETED: 服务完成 (6)
    -   EVALUATED: 已评价 (7)
    -   CANCELLED: 已取消 (8)
    -   REJECTED: 已拒单 (9)
    -   DEPARTED: 技师出发 (10)
    -   LEFT: 技师撤离 (11)
    -   REFUNDING: 退款中 (12)
    -   REFUNDED: 退款完成 (13)
    -   CHANGE_COACH: 更换技师 (14)
    -   RESET_COACH: 重置技师 (15)
    -   TEMPORARY_ACCEPTED: 临时接单 (16)
    -   ALARM_HANDLED: 报警已处理 (17)

3. 项目相关:

-   ProjectStatus: 项目状态
    -   OPEN: 开 (1)
    -   CLOSE: 关闭 (2)

4. 钱包相关:

-   WithdrawStatus: 提现状态
    -   PROCESSING: 提现中 (1)
    -   SUCCESS: 提现成功 (2)
    -   FAILED: 提现失败 (3)

## 数据验证和安全

1. 输入验证:

-   使用专门的 Request 类进行请求验证
-   在 Service 层进行业务规则验证
-   所有外部输入都必须经过验证

2. 数据安全:

-   敏感数据传输需要加密
-   关键操作需要验证用户身份
-   定期清理临时数据和日志

3. 并发处理:

-   使用数据库事务确保数据一致性
-   关键操作使用锁机制防止并发问题
-   使用队列处理耗时操作

## 开发规范

1. 代码风格:

-   遵循 PSR-12 编码规范
-   使用类型提示和返回值类型声明
-   所有属性和方法都要有清晰的访问修饰符

2. 注释规范:

-   类和方法必须有 PHPDoc 注释
-   复杂的业务逻辑需要添加行内注释
-   关键参数和返回值要有说明

3. 异常处理:

-   使用自定义异常类区分不同类型的错误
-   统一的异常处理机制
-   详细的错误日志记录

4. 测试要求:

-   核心业务逻辑需要单元测试
-   关键接口需要集成测试
-   定期进行性能测试

## API 接口规范

### 1. 路由规范

1. 路由前缀:

-   所有技师端 API 统一使用 `/api/coach` 前缀
-   认证相关: `/api/coach/auth/*`
-   订单相关: `/api/coach/orders/*`
-   项目相关: `/api/coach/projects/*`
-   钱包相关: `/api/coach/wallet/*`

2. 路由命名规范:

-   资源集合使用复数形式
-   使用 kebab-case 命名方式
-   遵循 RESTful 设计原则

3. 标准 RESTful 路由:

```php
// 订单相关路由示例
Route::prefix('api/coach')->group(function () {
    // 订单列表
    Route::get('orders', 'OrderController@index');
    // 订单详情
    Route::get('orders/{id}', 'OrderController@show');
    // 接受订单
    Route::post('orders/{id}/accept', 'OrderController@accept');
    // 拒绝订单
    Route::post('orders/{id}/reject', 'OrderController@reject');
    // 开始服务
    Route::post('orders/{id}/start', 'OrderController@start');
    // 完成服务
    Route::post('orders/{id}/finish', 'OrderController@finish');
});
```

### 2. 请求规范

1. 请求方法:

-   GET: 获取资源
-   POST: 创建资源
-   PUT: 更新资源(完整更新)
-   PATCH: 更新资源(部分更新)
-   DELETE: 删除资源

2. 请求头要求:

```http
Accept: application/json
Content-Type: application/json
Authorization: Bearer {token}
```

3. 分页查询参数:

```json
{
    "page": 1, // 当前页码
    "per_page": 15, // 每页数量
    "order_by": "created_at", // 排序字段
    "order_type": "desc" // 排序方式
}
```

### 3. 响应规范

1. 响应格式:

```json
{
    "code": 0, // 业务状态码
    "message": "success", // 状态描述
    "data": {
        // 响应数据
        "items": [
            // 列表数据
            {
                "id": 1,
                "order_no": "O202401010001",
                "status": 1,
                "created_at": "2024-01-01 00:00:00"
            }
        ],
        "total": 100 // 总记录数
    }
}
```

2. 错误响应格式:

```json
{
    "code": 422, // HTTP状态码
    "message": "验证失败", // 错误描述
    "errors": {
        // 详细错误信息
        "field": ["错误描述1", "错误描述2"]
    }
}
```

3. 分页查询参数:

```json
{
    "page": 1, // 当前页码
    "per_page": 15, // 每页数量
    "order_by": "created_at", // 排序字段
    "order_type": "desc" // 排序方式
}
```

### 4. 状态码规范

1. HTTP 状态码:

-   200: 请求成功
-   201: 创建成功
-   204: 删除成功
-   400: 请求参数错误
-   401: 未授权
-   403: 禁止访问
-   404: 资源不存在
-   422: 参数验证失败
-   429: 请求过于频繁
-   500: 服务器错误

2. 业务状态码:

-   0: 成功
-   1000-1999: 用户相关错误
-   2000-2999: 订单相关错误
-   3000-3999: 支付相关错误
-   4000-4999: ��� 统相关错误

### 5. 接口文档规范

1. 文档注解要求:

```php
/**
 * 获取订单列表
 *
 * @group 订单管理
 *
 * @queryParam page int 页码 Example: 1
 * @queryParam per_page int 每页数量 Example: 15
 * @queryParam status int 订单状态 Example: 1
 *
 * @response {
 *  "code": 0,
 *  "message": "success",
 *  "data": {
 *      "items": [
 *          {
 *              "id": 1,
 *              "order_no": "O202401010001",
 *              "status": 1,
 *              "created_at": "2024-01-01 00:00:00"
 *          }
 *      ],
 *      "total": 100
 *  }
 * }
 */
```

2. 版本控制:

-   URI 版本控制: /api/v1/coach/\*
-   在请求头中指定版本: Accept: application/vnd.app.v1+json

### 6. 安全规范

1. 认证要求:

-   使用 Bearer Token 认证
-   Token 有效期控制
-   敏感接口需要二次验证

2. 访问控制:

-   接口访问频率限制
-   IP 白名单控制
-   关键操作需要验证码

3. 数据安全:

-   敏感数据传输加密
-   参数防注入处理
-   上传文件类型限制

### 7. 开发规范

1. 控制器命名:

```php
class OrderController extends Controller
{
    // 获取订单列表
    public function index()

    // 获取订单详情
    public function show($id)

    // 接受订单
    public function accept($id)

    // 拒绝订单
    public function reject($id)
}
```

2. 请求验证:

```php
class AcceptOrderRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'id' => 'required|integer|exists:orders,id',
            'remark' => 'nullable|string|max:255'
        ];
    }
}
```

3. 响应封装:

```php
class OrderResource extends JsonResource
{
    public function toArray($request): array
    {
        return [
            'id' => $this->id,
            'order_no' => $this->order_no,
            'status' => $this->status,
            'status_text' => $this->status_text,
            'created_at' => $this->created_at->format('Y-m-d H:i:s')
        ];
    }
}
```