Browse Source

feat:技师端-投流创建订单

刘学玺 4 months ago
parent
commit
5deba84e8c

+ 73 - 0
app/Admin/Controllers/CoachFlowOrderController.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Services\CoachFlowOrderService;
+use Slowlyo\OwlAdmin\Controllers\AdminController;
+
+/**
+ * 技师投流订单
+ *
+ * @property CoachFlowOrderService $service
+ */
+class CoachFlowOrderController extends AdminController
+{
+	protected string $serviceName = CoachFlowOrderService::class;
+
+	public function list()
+	{
+		$crud = $this->baseCRUD()
+			->filterTogglable(false)
+			->headerToolbar([
+				$this->createButton('dialog'),
+				...$this->baseHeaderToolBar()
+			])
+			->columns([
+				amis()->TableColumn('id', 'ID')->sortable(),
+				amis()->TableColumn('coach_id', '技师ID'),
+				amis()->TableColumn('position_type', '投放位置 1:轮播图 2:弹屏 3:推荐和附近'),
+				amis()->TableColumn('time_slot', '时间段 1:上午 2:下午 3:晚上'),
+				amis()->TableColumn('days', '投放天数')->sortable(),
+				amis()->TableColumn('amount', '支付金额'),
+				amis()->TableColumn('start_time', '开始时间'),
+				amis()->TableColumn('end_time', '结束时间'),
+				amis()->TableColumn('state', '状态 0:待支付 1:投放中 2:已结束'),
+				amis()->TableColumn('created_at', admin_trans('admin.created_at'))->type('datetime')->sortable(),
+				amis()->TableColumn('updated_at', admin_trans('admin.updated_at'))->type('datetime')->sortable(),
+				$this->rowActions('dialog')
+			]);
+
+		return $this->baseList($crud);
+	}
+
+	public function form($isEdit = false)
+	{
+		return $this->baseForm()->body([
+			amis()->TextControl('coach_id', '技师ID'),
+			amis()->TextControl('position_type', '投放位置 1:轮播图 2:弹屏 3:推荐和附近'),
+			amis()->TextControl('time_slot', '时间段 1:上午 2:下午 3:晚上'),
+			amis()->TextControl('days', '投放天数'),
+			amis()->TextControl('amount', '支付金额'),
+			amis()->TextControl('start_time', '开始时间'),
+			amis()->TextControl('end_time', '结束时间'),
+			amis()->TextControl('state', '状态 0:待支付 1:投放中 2:已结束'),
+		]);
+	}
+
+	public function detail()
+	{
+		return $this->baseDetail()->body([
+			amis()->TextControl('id', 'ID')->static(),
+			amis()->TextControl('coach_id', '技师ID')->static(),
+			amis()->TextControl('position_type', '投放位置 1:轮播图 2:弹屏 3:推荐和附近')->static(),
+			amis()->TextControl('time_slot', '时间段 1:上午 2:下午 3:晚上')->static(),
+			amis()->TextControl('days', '投放天数')->static(),
+			amis()->TextControl('amount', '支付金额')->static(),
+			amis()->TextControl('start_time', '开始时间')->static(),
+			amis()->TextControl('end_time', '结束时间')->static(),
+			amis()->TextControl('state', '状态 0:待支付 1:投放中 2:已结束')->static(),
+			amis()->TextControl('created_at', admin_trans('admin.created_at'))->static(),
+			amis()->TextControl('updated_at', admin_trans('admin.updated_at'))->static(),
+		]);
+	}
+}

+ 0 - 36
app/Http/Controllers/Coach/CoachController.php

@@ -1,36 +0,0 @@
-<?php
-
-namespace App\Http\Controllers\Coach;
-
-use App\Http\Controllers\Controller;
-use App\Services\Coach\AccountService;
-use Illuminate\Support\Facades\Auth;
-
-class CoachController extends Controller
-{
-    protected AccountService $service;
-
-    public function __construct(AccountService $service)
-    {
-        $this->service = $service;
-    }
-
-    /**
-     * [技师]获取工作状态
-     *
-     * @description 获取技师当前工作状态
-     *
-     * @authenticated
-     *
-     * @response {
-     *   "work_status": 2,
-     *   "work_status_text": "空闲中",
-     *   "has_active_order": false,
-     *   "updated_at": "2024-03-22 10:00:00"
-     * }
-     */
-    public function getWorkStatus()
-    {
-        return $this->service->getWorkStatus(Auth::user()->coach->id);
-    }
-}

+ 89 - 0
app/Http/Controllers/Coach/CoachFlowController.php

@@ -0,0 +1,89 @@
+<?php
+
+namespace App\Http\Controllers\Coach;
+
+use App\Http\Controllers\Controller;
+use App\Services\Coach\CoachFlowService;
+use App\Traits\ResponseTrait;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+
+/**
+ * @group 技师端
+ *
+ * 技师投流相关的API接口
+ */
+class CoachFlowController extends Controller
+{
+    use ResponseTrait;
+
+    protected $flowService;
+
+    public function __construct(CoachFlowService $flowService)
+    {
+        $this->flowService = $flowService;
+    }
+
+    /**
+     * [投流]创建订单
+     *
+     * @description 创建教练投流订单
+     *
+     * @bodyParam position_type integer required 位置类型(1:首页 2:列表页) Example: 1
+     * @bodyParam time_slot integer required 时间段(1:上午 2:下午 3:晚上) Example: 1
+     * @bodyParam days integer required 投放天数(可选值:1,7,15,30,90,180,365) Example: 7
+     *
+     * @response {
+     *  "code": 0,
+     *  "message": "success",
+     *  "data": {
+     *    "order_id": 1,
+     *    "order_no": "FL202403201445201234",
+     *    "amount": "53.00"
+     *  }
+     * }
+     */
+    public function createOrder(Request $request)
+    {
+        $params = $request->validate([
+            'position_type' => 'required|integer|in:1,2',
+            'time_slot' => 'required|integer|in:1,2,3',
+            'days' => 'required|integer|in:1,7,15,30,90,180,365',
+        ]);
+
+        $result = $this->flowService->createOrder(Auth::user()->id, $params);
+
+        return $this->success($result);
+    }
+
+    /**
+     * 技师投流-获取价格配置
+     *
+     * @description 获取投流价格配置信息
+     *
+     * @response {
+     *  "code": 200,
+     *  "message": "success",
+     *  "data": {
+     *    "time_slots": [
+     *      {"type": 1, "name": "上午", "time": "6:00~12:00", "price": 4},
+     *      {"type": 2, "name": "下午", "time": "12:00~18:00", "price": 6},
+     *      {"type": 3, "name": "晚上", "time": "18:00~6:00", "price": 8}
+     *    ],
+     *    "days": [
+     *      {"days": 1, "price": 12},
+     *      {"days": 7, "price": 53},
+     *      {"days": 15, "price": 99},
+     *      {"days": 30, "price": 160},
+     *      {"days": 90, "price": 430},
+     *      {"days": 180, "price": 760},
+     *      {"days": 365, "price": 1360}
+     *    ]
+     *  }
+     * }
+     */
+    public function getPriceConfig()
+    {
+        return $this->flowService->getPriceConfig();
+    }
+}

+ 18 - 0
app/Models/CoachFlowOrder.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\SoftDeletes;
+use Slowlyo\OwlAdmin\Models\BaseModel as Model;
+
+/**
+ * 技师投流订单
+ */
+class CoachFlowOrder extends Model
+{
+    use SoftDeletes;
+
+    protected $table = 'coach_flow_orders';
+
+    protected $guarded = [];
+}

+ 158 - 0
app/Services/Coach/CoachFlowService.php

@@ -0,0 +1,158 @@
+<?php
+
+namespace App\Services\Coach;
+
+use App\Models\MemberUser;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+
+class CoachFlowService
+{
+    /**
+     * 创建投流订单
+     *
+     * @param  int  $userId  用户ID
+     * @param  array  $params  订单参数
+     * @return array
+     */
+    public function createOrder(int $userId, array $params)
+    {
+        try {
+            return DB::transaction(function () use ($params, $userId) {
+                // 查询用户信息
+                $user = MemberUser::findOrFail($userId);
+
+                // 验证用户是否为教练
+                abort_if(! $user->coach, 403, '非教练用户无法创建投流订单');
+
+                // 验证时间段参数
+                abort_if(! in_array($params['time_slot'], [1, 2, 3]), 422, '无效的时间段');
+
+                // 验证天数参数
+                $validDays = [1, 7, 15, 30, 90, 180, 365];
+                abort_if(! in_array($params['days'], $validDays), 422, '无效的天数');
+
+                // 验证位置类型
+                abort_if(! in_array($params['position_type'], [1, 2]), 422, '无效的位置类型');
+
+                // 计算订单金额
+                $amount = $this->calculateAmount($params['time_slot'], $params['days']);
+
+                // 生成订单号
+                $orderNo = $this->generateOrderNo();
+
+                // 创建订单
+                $order = $user->coach->flowOrders()->create([
+                    'order_no' => $orderNo,
+                    'coach_id' => $user->id,
+                    'position_type' => $params['position_type'],
+                    'time_slot' => $params['time_slot'],
+                    'days' => $params['days'],
+                    'amount' => $amount,
+                    'state' => 0,
+                    'start_time' => null,
+                    'end_time' => null,
+                ]);
+
+                Log::info('创建投流订单成功', [
+                    'order_id' => $order->id,
+                    'order_no' => $orderNo,
+                    'user_id' => $userId,
+                    'amount' => $amount,
+                    'params' => $params,
+                ]);
+
+                return [
+                    'order_id' => $order->id,
+                    'order_no' => $orderNo,
+                    'amount' => number_format($amount, 2),
+                ];
+            });
+        } catch (\Exception $e) {
+            Log::error('创建投流订单失败', [
+                'message' => $e->getMessage(),
+                'user_id' => $userId,
+                'params' => $params,
+                'trace' => $e->getTraceAsString(),
+            ]);
+            throw new \Exception('创建订单失败:'.$e->getMessage());
+        }
+    }
+
+    /**
+     * 生成订单号
+     */
+    private function generateOrderNo(): string
+    {
+        return 'FL'.date('YmdHis').mt_rand(1000, 9999);
+    }
+
+    /**
+     * 获取价格配置
+     */
+    public function getPriceConfig()
+    {
+        return [
+            'time_slots' => [
+                ['type' => 1, 'name' => '上午', 'time' => '6:00~12:00', 'price' => 4],
+                ['type' => 2, 'name' => '下午', 'time' => '12:00~18:00', 'price' => 6],
+                ['type' => 3, 'name' => '晚上', 'time' => '18:00~6:00', 'price' => 8],
+            ],
+            'days' => [
+                ['days' => 1, 'price' => 12],
+                ['days' => 7, 'price' => 53],
+                ['days' => 15, 'price' => 99],
+                ['days' => 30, 'price' => 160],
+                ['days' => 90, 'price' => 430],
+                ['days' => 180, 'price' => 760],
+                ['days' => 365, 'price' => 1360],
+            ],
+        ];
+    }
+
+    /**
+     * 计算订单金额
+     */
+    private function calculateAmount($timeSlot, $days)
+    {
+        $dayPrice = 0;
+        switch ($timeSlot) {
+            case 1:
+                $dayPrice = 4;
+                break;
+            case 2:
+                $dayPrice = 6;
+                break;
+            case 3:
+                $dayPrice = 8;
+                break;
+        }
+
+        $totalPrice = 0;
+        switch ($days) {
+            case 1:
+                $totalPrice = 12;
+                break;
+            case 7:
+                $totalPrice = 53;
+                break;
+            case 15:
+                $totalPrice = 99;
+                break;
+            case 30:
+                $totalPrice = 160;
+                break;
+            case 90:
+                $totalPrice = 430;
+                break;
+            case 180:
+                $totalPrice = 760;
+                break;
+            case 365:
+                $totalPrice = 1360;
+                break;
+        }
+
+        return $totalPrice;
+    }
+}

+ 17 - 0
app/Services/CoachFlowOrderService.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\CoachFlowOrder;
+use Slowlyo\OwlAdmin\Services\AdminService;
+
+/**
+ * 技师投流订单
+ *
+ * @method CoachFlowOrder getModel()
+ * @method CoachFlowOrder|\Illuminate\Database\Query\Builder query()
+ */
+class CoachFlowOrderService extends AdminService
+{
+	protected string $modelName = CoachFlowOrder::class;
+}

+ 2 - 0
routes/admin.php

@@ -97,5 +97,7 @@ Route::group([
     $router->resource('setting_values', \App\Admin\Controllers\SettingValueController::class);
     // 技师排班
     $router->resource('coach_schedules', \App\Admin\Controllers\CoachScheduleController::class);
+    // 技师投流订单
+    $router->resource('coach_flow_orders', \App\Admin\Controllers\CoachFlowOrderController::class);
 
 });

+ 3 - 0
routes/api.php

@@ -199,6 +199,9 @@ Route::middleware(['auth:sanctum'])->prefix('coach')->group(function () {
 
     // 获取技师工作状态
     Route::get('/work-status', [CoachController::class, 'getWorkStatus']);
+
+    // 投流订单
+    Route::post('flow/create-order', [\App\Http\Controllers\Coach\CoachFlowController::class, 'createOrder']);
 });
 
 // 大观支付回调