README.md 20 KB

技师端架构说明

用户与技师关系

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

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

  • MemberUser: 基础用户模型
  • CoachUser: 技师模型
  • 一对一关联: MemberUser hasOne CoachUser
  1. 技师相关验证:
  • 需要验证用户是否为技师(coach 关联是否存在)
  • 需要验证技师状态是否正常
  • 需要验证技师认证状态

技师认证与审核

1. 认证类型

  1. 基础信息认证:
  • 个人基本信息(姓名、手机号、身份证号等)
  • 居住地址信息
  • 联系人信息
  1. 实名认证:
  • 身份证正面照
  • 身份证背面 ��
  • 手持身份证照
  1. 资质认证:
  • 职业资格证书
  • 相关培训证书
  • 其他资质证明

2. 数据库设计

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

    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. 认证记录表:

    -- 基础信息认证记录表
    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. 提交限制:
  • 审核中状态不允许重新提交
  • 已通过状态不允许重新提交
  • 只有未提交或审核拒绝状态可以提交
  1. 提交校验:

    /**
    * 检查是否可以提交认证
    */
    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. 提交认证:

    /**
    * 提交基础信息认证
    */
    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. 审核操作:

    /**
    * 审核基础信息认证
    */
    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. 认证状态查询:

    /**
    * 获取认证状态
    */
    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. 认证历史记录:

    /**
    * 获取认证历史记录
    */
    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. 数据安全:
  • 敏感信息加密存储
  • 图片资源需要进行安全验证
  • 审核操作需要有操作日志
  1. 并发处理:
  • 使用数据库事务确保数据一致性
  • 状态变更时需要考虑并发情况
  • 关键操作需要加锁处理
  1. 通知机制:
  • 状态变更时需要通知相关人员
  • 审核结果需要实时推送给技师
  • 重要操作需要短信或其他方式通知
  1. 数据验证:
  • 提交时严格验证数据格式
  • 图片资源需要验证大小和格式
  • 身份证号等关键信息需要验证真实性
  1. 异常处理:
  • 所有操作需要有完善的异常处理
  • 异常发生时需要有友好的提示
  • 关键异常需要告警通知

7. 认证验证中间件

  1. 验证方法:

    /**
    * 技师认证状态验证
    *
    * @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 层基类中实现认证验证方法
  • 所有需要认证验证的方法必须调用验证方法
  • 可以使用中间件统一处理认证验证
  1. 验证规则:
  • 所有认证状态必须为 PASSED (已通过)
  • 未提交认证时提示"请先完成 XX 认证"
  • 认证审核中时提示"XX 认证审核中"
  • 认证被拒绝时提示"XX 认证未通过,请重新提交"
  1. 异常处理:
  • 认证验证失败时抛出 BusinessException
  • 异常信息需要明确指出具体未通过的认证项
  • 前端需要根据异常信息引导用户完成认证
  1. 注意事项:
  • 认证验证应该在业务逻辑执行前进行
  • 需要考虑多个认证未通过的情况
  • 验证提示信息要友好且明确
  • 记录认证验证失败的日志

目录结构

  1. 控制器位置:
  • app/Http/Controllers/Coach/*
  1. 服务类位置:
  • app/Services/Coach/*
  1. 请求验证类位置:
  • app/Http/Requests/Coach/*

核心服务类说明

  1. AccountService:
  • 处理技师账户相关操作
  • 包括基本信息、资质信息、实名认证的提交和查询
  • 处理技师位置信息和排班设置
  1. AuthService:
  • 处理技师认证相关操作
  • 包括基本信息认证、实名认证、资质认证
  • 提供认证状态查询
  1. OrderService:
  • 处理技师订单相关操作
  • 包括订单列表查询、抢单、接单、拒单
  • 处理订单状态流转(出发、到达、开始服务、撤离)
  1. ProjectService:
  • 处理技师项目相关操作
  • 包括可开通项目查询、项目开通
  • 处理项目设置(折扣、性别限制等)
  1. WalletService:
  • 处理技师钱包相关操作
  • 包括钱包信息查询、流水记录
  • 处理提现申请

注意事项

  1. 权限验证:
  • 所有技师端接口都需要验证用户是否为技师
  • 使用 abort_if(!$user->coach, 404, '技师信息不存在') 进行验证
  1. 数据获取:
  • 优先通过关联关系获取数据
  • 使用 with() 进行预加载以优化性能
  1. 错误处理:
  • 使用 abort_if 行前置条件验证
  • 在 Service 层进行详细的业务逻辑验证
  1. 事务处理:
  • 涉及多表操作时使用数据库事务
  • 在 Service 层实现事务逻辑
  1. 缓存策略:
  • 技师信息优先使用缓存
  • 更新操作时及时处理相关缓存
  1. 日志记录:
  • 重要操作需要记录日志
  • 包含用户 ID、技师 ID、操作内容等关键信息
  1. 敏感数据处理:
  • 手机号、身份证等敏感信息需要脱敏处理
  • 日志中不应该出现完整的敏感信息

常用枚举类型

  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)
  1. 订单相关:
  • 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)
  1. 项目相关:
  • ProjectStatus: 项目状态
    • OPEN: 开 (1)
    • CLOSE: 关闭 (2)
  1. 钱包相关:
  • WithdrawStatus: 提现状态
    • PROCESSING: 提现中 (1)
    • SUCCESS: 提现成功 (2)
    • FAILED: 提现失败 (3)

数据验证和安全

  1. 输入验证:
  • 使用专门的 Request 类进行请求验证
  • 在 Service 层进行业务规则验证
  • 所有外部输入都必须经过验证
  1. 数据安全:
  • 敏感数据传输需要加密
  • 关键操作需要验证用户身份
  • 定期清理临时数据和日志
  1. 并发处理:
  • 使用数据库事务确保数据一致性
  • 关键操作使用锁机制防止并发问题
  • 使用队列处理耗时操作

开发规范

  1. 代码风格:
  • 遵循 PSR-12 编码规范
  • 使用类型提示和返回值类型声明
  • 所有属性和方法都要有清晰的访问修饰符
  1. 注释规范:
  • 类和方法必须有 PHPDoc 注释
  • 复杂的业务逻辑需要添加行内注释
  • 关键参数和返回值要有说明
  1. 异常处理:
  • 使用自定义异常类区分不同类型的错误
  • 统一的异常处理机制
  • 详细的错误日志记录
  1. 测试要求:
  • 核心业务逻辑需要单元测试
  • 关键接口需要集成测试
  • 定期进行性能测试

API 接口规范

1. 路由规范

  1. 路由前缀:
  • 所有技师端 API 统一使用 /api/coach 前缀
  • 认证相关: /api/coach/auth/*
  • 订单相关: /api/coach/orders/*
  • 项目相关: /api/coach/projects/*
  • 钱包相关: /api/coach/wallet/*
  1. 路由命名规范:
  • 资源集合使用复数形式
  • 使用 kebab-case 命名方式
  • 遵循 RESTful 设计原则
  1. 标准 RESTful 路由:

    // 订单相关路由示例
    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: 删除资源
  1. 请求头要求:

    Accept: application/json
    Content-Type: application/json
    Authorization: Bearer {token}
    
  2. 分页查询参数:

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

3. 响应规范

  1. 响应格式:

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

    {
    "code": 422, // HTTP状态码
    "message": "验证失败", // 错误描述
    "errors": {
        // 详细错误信息
        "field": ["错误描述1", "错误描述2"]
    }
    }
    
  3. 分页查询参数:

    {
    "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: 服务器错误
  1. 业务状态码:
  • 0: 成功
  • 1000-1999: 用户相关错误
  • 2000-2999: 订单相关错误
  • 3000-3999: 支付相关错误
  • 4000-4999: ��� 统相关错误

5. 接口文档规范

  1. 文档注解要求:

    /**
    * 获取订单列表
    *
    * @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 有效期控制
  • 敏感接口需要二次验证
  1. 访问控制:
  • 接口访问频率限制
  • IP 白名单控制
  • 关键操作需要验证码
  1. 数据安全:
  • 敏感数据传输加密
  • 参数防注入处理
  • 上传文件类型限制

7. 开发规范

  1. 控制器命名:

    class OrderController extends Controller
    {
    // 获取订单列表
    public function index()
    
    // 获取订单详情
    public function show($id)
    
    // 接受订单
    public function accept($id)
    
    // 拒绝订单
    public function reject($id)
    }
    
  2. 请求验证:

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

    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')
        ];
    }
    }