Browse Source

feat:后端-技师管理

刘学玺 4 months ago
parent
commit
39d67b9aa0
3 changed files with 162 additions and 2 deletions
  1. 55 0
      app/Admin/Controllers/CoachUserController.php
  2. 105 2
      app/Services/CoachUserService.php
  3. 2 0
      routes/web.php

+ 55 - 0
app/Admin/Controllers/CoachUserController.php

@@ -3,6 +3,7 @@
 namespace App\Admin\Controllers;
 
 use App\Services\CoachUserService;
+use Illuminate\Http\Request;
 use Slowlyo\OwlAdmin\Controllers\AdminController;
 
 /**
@@ -79,4 +80,58 @@ class CoachUserController extends AdminController
             amis()->TextControl('updated_at', admin_trans('admin.updated_at'))->static(),
         ]);
     }
+
+    /**
+     * [技师管理]拉黑技师
+     *
+     * @description 将技师加入黑名单
+     *
+     * @header x-xsrf-token required CSRF令牌 Example: your_csrf_token
+     *
+     * @bodyParam coach_id integer required 技师ID Example: 1
+     * @bodyParam reason string required 拉黑原因 Example: 服务态度恶劣
+     *
+     * @response {
+     *   "code": 200,
+     *   "message": "拉黑成功",
+     *   "data": null
+     * }
+     */
+    public function blockCoach(Request $request)
+    {
+        $validated = $request->validate([
+            'coach_id' => 'required|integer|exists:coach_users,id',
+            'reason' => 'required|string|max:255',
+        ]);
+
+        return $this->service->blockCoach($validated);
+    }
+
+    /**
+     * [技师管理]冻结技师余额
+     *
+     * @description 冻结技师钱包余额
+     *
+     * @header x-xsrf-token required CSRF令牌 Example: your_csrf_token
+     *
+     * @bodyParam coach_id integer required 技师ID Example: 1
+     * @bodyParam amount numeric required 冻结金额 Example: 100.00
+     * @bodyParam reason string required 冻结原因 Example: 涉嫌违规操作
+     *
+     * @response {
+     *   "code": 200,
+     *   "message": "冻结成功",
+     *   "data": null
+     * }
+     */
+    public function freezeBalance(Request $request)
+    {
+        $validated = $request->validate([
+            'coach_id' => 'required|integer|exists:coach_users,id',
+            'amount' => 'required|numeric|min:0.01',
+            'reason' => 'required|string|max:255',
+        ]);
+
+        return $this->service->freezeCoachBalance($validated);
+    }
 }

+ 105 - 2
app/Services/CoachUserService.php

@@ -2,7 +2,11 @@
 
 namespace App\Services;
 
+use App\Enums\TechnicianStatus;
 use App\Models\CoachUser;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
 use Slowlyo\OwlAdmin\Services\AdminService;
 
 /**
@@ -13,5 +17,104 @@ use Slowlyo\OwlAdmin\Services\AdminService;
  */
 class CoachUserService extends AdminService
 {
-	protected string $modelName = CoachUser::class;
-}
+    protected string $modelName = CoachUser::class;
+
+    /**
+     * 拉黑技师
+     *
+     * @param  array  $data  包含 coach_id 和 reason
+     */
+    public function blockCoach(array $data): array
+    {
+        try {
+            DB::beginTransaction();
+
+            // 获取技师信息
+            $coach = CoachUser::findOrFail($data['coach_id']);
+
+            // 验证技师当前状态
+            abort_if($coach->state === TechnicianStatus::BLACKLIST->value, 422, '技师已经被拉黑');
+
+            // 更新技师状态为拉黑
+            $coach->state = TechnicianStatus::BLACKLIST->value;
+            $coach->block_reason = $data['reason'];
+            $coach->block_time = now();
+            $coach->block_operator_id = Auth::user()->id;
+            $coach->save();
+
+            DB::commit();
+
+            return [
+                'code' => 200,
+                'message' => '拉黑成功',
+                'data' => null,
+            ];
+
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('拉黑技师失败', [
+                'coach_id' => $data['coach_id'],
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString(),
+            ]);
+
+            throw $e;
+        }
+    }
+
+    /**
+     * 冻结技师余额
+     *
+     * @param  array  $data  包含 coach_id, amount 和 reason
+     */
+    public function freezeCoachBalance(array $data): array
+    {
+        try {
+            DB::beginTransaction();
+
+            // 获取技师及其钱包信息
+            $coach = CoachUser::findOrFail($data['coach_id']);
+            $wallet = $coach->wallet()->lockForUpdate()->firstOrFail();
+
+            // 验证可用余额是否足够
+            abort_if($wallet->available_amount < $data['amount'], 422, '技师可用余额不足');
+
+            // 更新钱包余额
+            $wallet->available_amount -= $data['amount'];
+            $wallet->frozen_amount += $data['amount'];
+            $wallet->save();
+
+            // 记录冻结流水
+            WalletTransRecord::create([
+                'user_id' => $data['coach_id'],
+                'type' => TransactionType::FREEZE->value,
+                'amount' => $data['amount'],
+                'before_amount' => $wallet->available_amount + $data['amount'],
+                'after_amount' => $wallet->available_amount,
+                'operator_id' => Auth::user()->id,
+                'operator_type' => 'admin',
+                'remark' => $data['reason'],
+                'state' => TransactionStatus::SUCCESS->value,
+            ]);
+
+            DB::commit();
+
+            return [
+                'code' => 200,
+                'message' => '冻结成功',
+                'data' => null,
+            ];
+
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('冻结技师余额失败', [
+                'coach_id' => $data['coach_id'],
+                'amount' => $data['amount'],
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString(),
+            ]);
+
+            throw $e;
+        }
+    }
+}

+ 2 - 0
routes/web.php

@@ -170,5 +170,7 @@ Route::group([
         Route::post('user/block', [MemberUserController::class, 'blockUser']);
         Route::post('user/freeze-balance', [MemberUserController::class, 'freezeBalance']);
         Route::post('user/bad-behavior', [MemberUserController::class, 'recordBadBehavior']);
+        Route::post('coach/block', [CoachUserController::class, 'blockCoach']);
+        Route::post('coach/freeze-balance', [CoachUserController::class, 'freezeBalance']);
     });
 });