|
@@ -0,0 +1,846 @@
|
|
|
+# 技师端架构说明
|
|
|
+
|
|
|
+## 用户与技师关系
|
|
|
+
|
|
|
+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')
|
|
|
+ ];
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|