醉梦人间三千年 6 月之前
父节点
当前提交
b0c7ac71bc
共有 52 个文件被更改,包括 3245 次插入77 次删除
  1. 1 0
      .env
  2. 1 1
      app/Exceptions/ApiException.php
  3. 22 0
      app/Http/Controllers/Backend/Server/Coach/ApplyController.php
  4. 74 0
      app/Http/Controllers/Backend/Server/Coach/UserController.php
  5. 5 5
      app/Http/Controllers/Backend/Server/Service/CategoryController.php
  6. 56 0
      app/Http/Controllers/Frontend/Client/Auth/AuthenticatedController.php
  7. 87 0
      app/Http/Controllers/Frontend/Client/Auth/WechatAuthenticatedController.php
  8. 34 0
      app/Http/Controllers/Frontend/Client/Coach/UserController.php
  9. 71 0
      app/Http/Controllers/Frontend/Client/CoachController.php
  10. 51 0
      app/Http/Controllers/Frontend/Client/Member/UserController.php
  11. 26 0
      app/Http/Controllers/Frontend/Client/Service/CategoryController.php
  12. 65 0
      app/Http/Controllers/Frontend/Client/Service/OrderController.php
  13. 34 0
      app/Http/Controllers/Frontend/Client/Service/ProjectController.php
  14. 47 0
      app/Http/Controllers/Frontend/Server/Coach/UserController.php
  15. 37 0
      app/Http/Controllers/Frontend/Server/Service/ProjectController.php
  16. 105 0
      app/Http/Services/Backend/Server/Coach/UserService.php
  17. 7 1
      app/Http/Services/Backend/Server/Service/CategoryService.php
  18. 65 13
      app/Http/Services/Backend/Server/Service/ProjectService.php
  19. 55 0
      app/Http/Services/Frontend/Client/Auth/AuthenticatedService.php
  20. 154 0
      app/Http/Services/Frontend/Client/Auth/WechatAuthenticatedService.php
  21. 50 0
      app/Http/Services/Frontend/Client/Coach/UserService.php
  22. 48 0
      app/Http/Services/Frontend/Client/Common/AuthService.php
  23. 35 0
      app/Http/Services/Frontend/Client/Common/DistanceService.php
  24. 66 0
      app/Http/Services/Frontend/Client/Common/SmsService.php
  25. 40 0
      app/Http/Services/Frontend/Client/Member/UserService.php
  26. 27 0
      app/Http/Services/Frontend/Client/Service/CategoryService.php
  27. 160 0
      app/Http/Services/Frontend/Client/Service/OrderService.php
  28. 36 0
      app/Http/Services/Frontend/Client/Service/ProjectService.php
  29. 52 0
      app/Http/Services/Frontend/Server/Coach/UserService.php
  30. 41 0
      app/Http/Services/Frontend/Server/Service/ProjectService.php
  31. 2 1
      app/Http/Services/Service.php
  32. 81 0
      app/Models/Coach/User.php
  33. 47 0
      app/Models/Coach/Verify.php
  34. 7 1
      app/Models/Member/User.php
  35. 7 0
      app/Models/Service/Category.php
  36. 102 0
      app/Models/Service/Order.php
  37. 46 0
      app/Models/Service/Project.php
  38. 2 1
      app/Models/System/User.php
  39. 47 0
      app/Models/Wechat/User.php
  40. 1 0
      composer.json
  41. 812 49
      composer.lock
  42. 10 0
      config/auth.php
  43. 1 1
      config/cors.php
  44. 168 0
      config/easywechat.php
  45. 3 1
      database/migrations/2024_09_04_022856_create_member_users_table.php
  46. 56 0
      database/migrations/2024_09_10_090033_create_coach_users_table.php
  47. 45 0
      database/migrations/2024_09_10_090034_create_coach_verify_table.php
  48. 30 0
      database/migrations/2024_09_20_052430_create_service_project_has_coach_table.php
  49. 104 0
      database/migrations/2024_09_23_025555_create_service_order_table.php
  50. 30 0
      database/migrations/2024_09_23_025556_create_wechat_users_table.php
  51. 77 3
      routes/api.php
  52. 15 0
      routes/web.php

+ 1 - 0
.env

@@ -5,6 +5,7 @@ APP_DEBUG=true
 APP_TIMEZONE=UTC
 APP_URL=http://localhost:8000
 FRONTEND_URL=http://127.0.0.1:8080
+BACKEND_URL=http://127.0.0.1:8080
 
 APP_LOCALE=en
 APP_FALLBACK_LOCALE=en

+ 1 - 1
app/Exceptions/ApiException.php

@@ -13,6 +13,6 @@ class ApiException extends Exception
 {
     public function __construct(array $apiErrorConst, \Throwable $previous = null)
     {
-        parent::__construct($apiErrorConst['message'], $apiErrorConst['status'], $previous);
+        parent::__construct($apiErrorConst['message'], $apiErrorConst['code'], $previous);
     }
 }

+ 22 - 0
app/Http/Controllers/Backend/Server/Coach/ApplyController.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/18 12:09
+ */
+
+namespace App\Http\Controllers\Backend\Server\Coach;
+
+use App\Http\Controllers\Controller;
+use App\Http\Requests\Request;
+use App\Models\Member\User as MemberUser;
+
+class ApplyController extends Controller
+{
+    public function show(Request $request, int $id)
+    {
+        $user = MemberUser::query()->with('coach')->find($id);
+        return self::success($user);
+    }
+}

+ 74 - 0
app/Http/Controllers/Backend/Server/Coach/UserController.php

@@ -0,0 +1,74 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/18 12:09
+ */
+
+namespace App\Http\Controllers\Backend\Server\Coach;
+
+use App\Exceptions\ApiException;
+use App\Http\Controllers\Controller;
+use App\Http\Requests\Request;
+use App\Http\Services\Backend\Server\Coach\UserService;
+use App\Http\Services\Backend\Server\Member\ConfigService;
+use App\Models\Coach\User;
+use Illuminate\Http\JsonResponse;
+
+class UserController extends Controller
+{
+    protected UserService $userService;
+
+    public function __construct(UserService $userService)
+    {
+        $this->userService = $userService;
+    }
+
+    public function index(Request $request)
+    {
+        // 处理首页逻辑
+        $params = $request->all();
+        $result = $this->userService->getUserList($params);
+        return self::success($result);
+    }
+
+    public function apply(Request $request, int $id)
+    {
+        $res = $this->userService->apply($id);
+        return self::success($res);
+    }
+
+    public function doApply(Request $request, int $id): JsonResponse
+    {
+        $params = $request->all();
+        $this->userService->updateApply($params, $id);
+        return self::success(true);
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function doReApply(Request $request, int $id): JsonResponse
+    {
+        $params = $request->all();
+        $this->userService->updateReApply($params, $id);
+        return self::success(true);
+    }
+
+    public function auth(int $id): JsonResponse
+    {
+        $res = $this->userService->auth($id);
+        return self::success($res);
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function doAuth(Request $request, int $id): JsonResponse
+    {
+        $authData = $request->only(['name', 'idCode', 'idCard', 'authStatus', 'authText']);
+        $this->userService->updateAuth($authData, $id);
+        return self::success(true);
+    }
+}

+ 5 - 5
app/Http/Controllers/Backend/Server/Service/CategoryController.php

@@ -63,9 +63,9 @@ class CategoryController extends Controller
 //        return self::success($res);
     }
 
-//    public function simple(): JsonResponse
-//    {
-//        $result = $this->categoryService->getDeptSimpleList();
-//        return self::success($result);
-//    }
+    public function simple(): JsonResponse
+    {
+        $result = $this->categoryService->getCategorySimpleList();
+        return self::success($result);
+    }
 }

+ 56 - 0
app/Http/Controllers/Frontend/Client/Auth/AuthenticatedController.php

@@ -0,0 +1,56 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/26 11:58
+ */
+
+namespace App\Http\Controllers\Frontend\Client\Auth;
+
+use App\Exceptions\ApiException;
+use App\Http\Controllers\Controller;
+use App\Http\Requests\Request;
+use App\Http\Services\Frontend\Client\Auth\AuthenticatedService;
+use Illuminate\Http\JsonResponse;
+
+class AuthenticatedController extends Controller
+{
+    protected AuthenticatedService $authService;
+
+    public function __construct(AuthenticatedService $authService)
+    {
+        $this->authService = $authService;
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function store(Request $request): JsonResponse
+    {
+        $request->validate([
+            'mobile' => ['required', 'regex:/^1[345789][0-9]{9}$/'],
+            'code' => ['required'],
+        ], [
+            'mobile.required' => '手机号不能为空!',
+            'mobile.regex' => '手机号码格式不正确!',
+            'code.required' => '手机验证码不能为空!',
+        ]);
+        $params = $request->only(['mobile','code']);
+        return self::success($this->authService->login($params));
+    }
+
+    /**
+     * Method : 发送验证码
+     * @param Request $request
+     * @return JsonResponse
+     * @throws ApiException
+     */
+    public function send(Request $request): JsonResponse
+    {
+        $params = $request->only(['mobile']);
+        $this->authService->send($params);
+        return self::success(true);
+    }
+
+}

+ 87 - 0
app/Http/Controllers/Frontend/Client/Auth/WechatAuthenticatedController.php

@@ -0,0 +1,87 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/3/25 16:47
+ */
+
+namespace App\Http\Controllers\Frontend\Client\Auth;
+
+use App\Exceptions\ApiException;
+use App\Http\Controllers\Controller;
+use App\Http\Services\Frontend\Client\Auth\WechatAuthenticatedService;
+use App\Models\Member\User;
+use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Illuminate\Http\Response;
+
+class WechatAuthenticatedController extends Controller
+{
+    protected WechatAuthenticatedService $wechatAuthenticatedService;
+
+    public function __construct(WechatAuthenticatedService $wechatAuthenticatedService)
+    {
+        $this->wechatAuthenticatedService = $wechatAuthenticatedService;
+    }
+
+    /**
+     * Notes :
+     * Method : 公众号授权
+     * @param Request $request
+     * @return JsonResponse
+     * @throws InvalidArgumentException
+     */
+    public function oauth(Request $request): JsonResponse
+    {
+        $params = $request->only(['redirect_url', 'scopes']);
+        return self::success($this->wechatAuthenticatedService->oauth($params));
+    }
+
+    /**
+     * Notes :
+     * Method : 公众号授权回调
+     * @param Request $request
+     * @return JsonResponse
+     * @throws InvalidArgumentException
+     */
+    public function callback(Request $request): JsonResponse
+    {
+        $params = $request->only(['code']);
+        $res = $this->wechatAuthenticatedService->callback($params);
+        return self::success($res);
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function store(Request $request): JsonResponse
+    {
+        $params = $request->only(['open_id']);
+        $res = $this->wechatAuthenticatedService->store($params);
+        return self::success($res);
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function bind(Request $request): JsonResponse
+    {
+        $params = $request->only(['mobile', 'code', 'open_id']);
+        $this->wechatAuthenticatedService->bind($params);
+        return self::success(true);
+    }
+
+    // 发送短信
+    public function send(Request $request): Response
+    {
+        $request->validate([
+            'mobile' => ['required', 'regex:/^1[345789][0-9]{9}$/']
+        ], [
+            'mobile.required' => '手机号不能为空!',
+            'mobile.regex' => '手机号码格式不正确!'
+        ]);
+        return (new WechatAuthenticatedService())->send($request->only(['mobile']));
+    }
+}

+ 34 - 0
app/Http/Controllers/Frontend/Client/Coach/UserController.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Http\Controllers\Frontend\Client\Coach;
+
+use App\Http\Controllers\Controller;
+use App\Http\Services\Frontend\Client\Coach\UserService;
+use App\Http\Services\Frontend\Client\Service\ProjectService;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+
+class UserController extends Controller
+{
+    protected UserService $userService;
+
+    public function __construct(UserService $userService)
+    {
+        $this->userService = $userService;
+    }
+
+    public function index(Request $request): JsonResponse
+    {
+        // 处理首页逻辑
+        $params = $request->all();
+        $result = $this->userService->getUserPage($params);
+        return self::success($result);
+    }
+
+    public function show(Request $request, int $id): JsonResponse
+    {
+        $params = $request->all();
+        $result = $this->userService->getUser($params, $id);
+        return self::success($result);
+    }
+}

+ 71 - 0
app/Http/Controllers/Frontend/Client/CoachController.php

@@ -0,0 +1,71 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/13 17:20
+ */
+
+namespace App\Http\Controllers\Frontend\Client;
+
+use App\Http\Controllers\Controller;
+use App\Http\Requests\Request;
+use App\Http\Services\Frontend\Client\Coach\UserService;
+use App\Models\Coach\User;
+use Illuminate\Http\JsonResponse;
+
+class CoachController extends Controller
+{
+    protected UserService $userService;
+
+    public function __construct(UserService $userService)
+    {
+        $this->userService = $userService;
+    }
+    public function index(): JsonResponse
+    {
+//        $this->userService->getUserPage();
+        $where = ['status' => 1];
+        $userPage = User::query()->where($where)->paginate();
+        return self::success(['list' => $userPage->items(), 'total' => $userPage->total()]);
+    }
+
+    public function show()
+    {
+
+    }
+
+    /**
+     * Method : 申请技师
+     */
+    public function create(Request $request): JsonResponse
+    {
+        $params = $request->only(['name', 'sex', 'birthday', 'mobile', 'city', 'work_img']);
+        // 验证码验证手机号
+        $user_id = 1;
+        if (isset($user_id) && filled($user_id)) {
+            // 判断技师资格是否已申请
+            $isExists = User::query()->where('user_id', $user_id)->exists();
+            if ($isExists) return ['code' => 500, 'msg' => '用户已经申请'];
+        }
+
+        $params['user_id'] = $user_id;
+        // 判断邀请人$input['partner_id']
+
+        $id = User::query()->create($params)->id;
+        return self::success($id);
+    }
+
+    public function update()
+    {
+
+    }
+
+
+    public function reapply()
+    {
+
+    }
+
+
+}

+ 51 - 0
app/Http/Controllers/Frontend/Client/Member/UserController.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/26 11:58
+ */
+
+namespace App\Http\Controllers\Frontend\Client\Member;
+
+use App\Exceptions\ApiException;
+use App\Http\Controllers\Controller;
+use App\Http\Requests\Request;
+use App\Http\Services\Frontend\Client\Auth\AuthenticatedService;
+use App\Http\Services\Frontend\Client\Member\UserService;
+use Illuminate\Http\JsonResponse;
+
+class UserController extends Controller
+{
+    protected UserService $userService;
+
+    public function __construct(UserService $userService)
+    {
+        $this->userService = $userService;
+    }
+
+    /**
+     */
+    public function show(Request $request): JsonResponse
+    {
+        return self::success($this->userService->getUser());
+    }
+
+    public function update(Request $request): JsonResponse
+    {
+        $params = $request->all();
+        $this->userService->updateUser($params);
+        return self::success(true);
+    }
+
+    /**
+     * Notes :
+     * Method : 注销用户
+     */
+    public function destroy(Request $request): JsonResponse
+    {
+        $this->userService->delUser($request);
+        return self::success(true);
+    }
+
+}

+ 26 - 0
app/Http/Controllers/Frontend/Client/Service/CategoryController.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace App\Http\Controllers\Frontend\Client\Service;
+
+use App\Http\Controllers\Controller;
+use App\Http\Services\Backend\Server\Member\UserService;
+use App\Http\Services\Frontend\Client\Service\CategoryService;
+use App\Http\Services\Frontend\Client\Service\ProjectService;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+
+class CategoryController extends Controller
+{
+    protected CategoryService $categoryService;
+
+    public function __construct(CategoryService $categoryService)
+    {
+        $this->categoryService = $categoryService;
+    }
+
+    public function index(): JsonResponse
+    {
+        $result = $this->categoryService->getSimpleCategories();
+        return self::success($result);
+    }
+}

+ 65 - 0
app/Http/Controllers/Frontend/Client/Service/OrderController.php

@@ -0,0 +1,65 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/23 10:06
+ */
+
+namespace App\Http\Controllers\Frontend\Client\Service;
+
+use App\Http\Controllers\Controller;
+use App\Http\Controllers\Frontend\Client\Order\Config;
+use App\Http\Requests\Request;
+use App\Http\Services\Frontend\Client\Service\OrderService;
+use App\Models\Coach\User;
+use App\Models\Service\Order;
+use Illuminate\Http\JsonResponse;
+
+class OrderController extends Controller
+{
+
+    protected OrderService $orderService;
+
+    public function __construct(OrderService $orderService)
+    {
+        $this->orderService = $orderService;
+    }
+
+    public function index(Request $request): JsonResponse
+    {
+        $params = $request->all();
+        $res = $this->orderService->getOrderPage($params);
+        return self::success($res);
+    }
+
+    public function store(Request $request): JsonResponse
+    {
+        $params = $request->all();
+        $res = $this->orderService->createOrder($params);
+        return self::success($res);
+    }
+
+    public function show(Request $request, int $id): JsonResponse
+    {
+        return self::success($this->orderService->getOrder($id));
+    }
+
+    public function update(Request $request, int $id): JsonResponse
+    {
+        $params = $request->all();
+        $this->orderService->updateOrder($params, $id);
+        return self::success(true);
+    }
+
+    public function destroy(int $id): JsonResponse
+    {
+        $this->orderService->delOrder($id);
+        return self::success(true);
+    }
+
+}
+
+
+
+

+ 34 - 0
app/Http/Controllers/Frontend/Client/Service/ProjectController.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Http\Controllers\Frontend\Client\Service;
+
+use App\Http\Controllers\Controller;
+use App\Http\Services\Backend\Server\Member\UserService;
+use App\Http\Services\Frontend\Client\Service\ProjectService;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+
+class ProjectController extends Controller
+{
+    protected ProjectService $projectService;
+
+    public function __construct(ProjectService $projectService)
+    {
+        $this->projectService = $projectService;
+    }
+
+    public function index(Request $request): JsonResponse
+    {
+        // 处理首页逻辑
+        $params = $request->all();
+        $result = $this->projectService->getProjectPage($params);
+        return self::success($result);
+    }
+
+    public function show(Request $request, int $id)
+    {
+        $params = $request->all();
+        $result = $this->projectService->getProject($params, $id);
+        return self::success($result);
+    }
+}

+ 47 - 0
app/Http/Controllers/Frontend/Server/Coach/UserController.php

@@ -0,0 +1,47 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/13 17:20
+ */
+
+namespace App\Http\Controllers\Frontend\Server\Coach;
+
+use App\Exceptions\ApiException;
+use App\Http\Controllers\Controller;
+use App\Http\Requests\Request;
+use App\Http\Services\Frontend\Server\Coach\UserService;
+use Illuminate\Http\JsonResponse;
+
+class UserController extends Controller
+{
+    protected UserService $userService;
+
+    public function __construct(UserService $userService)
+    {
+        $this->userService = $userService;
+    }
+    public function show(): JsonResponse
+    {
+        $res = $this->userService->getUser();
+        return self::success($res);
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function update(Request $request): JsonResponse
+    {
+        $data = $request->all();
+        $this->userService->updateUser($data);
+        return self::success(true);
+    }
+
+    public function reapply()
+    {
+
+    }
+
+
+}

+ 37 - 0
app/Http/Controllers/Frontend/Server/Service/ProjectController.php

@@ -0,0 +1,37 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/20 11:26
+ */
+
+namespace App\Http\Controllers\Frontend\Server\Service;
+
+use App\Http\Controllers\Controller;
+use App\Http\Requests\Request;
+use App\Http\Services\Frontend\Server\Service\ProjectService;
+use Illuminate\Http\JsonResponse;
+
+class ProjectController extends Controller
+{
+    protected ProjectService $projectService;
+
+    public function __construct(ProjectService $projectService)
+    {
+        $this->projectService = $projectService;
+    }
+    public function index(Request $request): JsonResponse
+    {
+        $params = $request->all();
+        $res = $this->projectService->getProjectPage($params);
+        return self::success($res);
+    }
+
+    public function update(Request $request): JsonResponse
+    {
+        $params = $request->all();
+        $this->projectService->updateProject($params);
+        return self::success(true);
+    }
+}

+ 105 - 0
app/Http/Services/Backend/Server/Coach/UserService.php

@@ -0,0 +1,105 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/18 13:59
+ */
+
+namespace App\Http\Services\Backend\Server\Coach;
+
+use App\Exceptions\ApiException;
+use App\Http\Services\Service;
+use App\Models\Coach\User;
+use App\Models\Coach\Verify;
+use Illuminate\Support\Facades\DB;
+
+class UserService extends Service
+{
+
+    protected array $selectColumn = ['id', 'name', 'user_id', 'nickname', 'sex', 'mobile', 'avatar', 'id_code as idCode', 'id_card as idCard', 'status', 'auth_status as authStatus'];
+    protected array $appendColumn = ['created_at as createTime'];
+
+    protected array $authColumn = ['auth_time as authTime', 'auth_text as authText'];
+
+    public function getUserList($params)
+    {
+
+//        isset($params['nickname']) && filled($params['nickname']) && $user->whereLike('nickname', "%{$params['nickname']}%");
+//        isset($params['mobile']) && filled($params['mobile']) && $user->whereLike('mobile', "%{$params['mobile']}%");
+//        isset($params['status']) && filled($params['status']) && $user->where('status', $params['status']);
+//        !empty($params['loginDate']) && $user->whereBetween('login_date', $params['loginDate']);
+//        !empty($params['createTime']) && $user->whereBetween('created_at', $params['createTime']);
+        $user = User::query();
+        $rolePage = $user->with('verify', function ($query) {
+            $query->select(['coach_id', 'status']);
+        })->paginate($params['pageSize'], [...$this->selectColumn, ...$this->appendColumn], 'page', $params['pageNo']);
+        return ['list' => $rolePage->items(), 'total' => $rolePage->total()];
+    }
+
+    public function apply(int $id)
+    {
+        // 查询审核信息
+        $verify = Verify::query()->where('coach_id', $id)->first();
+        $coach = User::query()->find($id);
+        $verify = $verify? $verify->toArray():[];
+        return array_merge($coach->toArray(), $verify);
+    }
+
+    public function updateApply(array $data, int $id)
+    {
+        $coach = User::query()->find($id);
+        unset($data['id']);
+        if (isset($data['status']) && in_array($data['status'], [1, 3]) && $coach->status === 0) {
+            $data['verifyTime'] = time();
+        }
+        $coach = self::toModel([...$data], User::class);
+        $coach->where('id', $id)->update($coach->getAttributes());
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function updateReApply(array $data, int $id): void
+    {
+
+        $verify_id = Verify::query()->where('coach_id', $id)->value('id');
+        empty($verify_id) && self::error();
+
+        $data['id'] = $verify_id;
+
+        $verify = self::toModel($data, Verify::class);
+        DB::beginTransaction();
+        try {
+            $verify->save();
+            if ($data['status'] === 1) {
+                $coachData = $verify->only(['name', 'mobile', 'status', 'verify_text', 'verify_time', 'sex', 'work_img']);
+                $coachData['id'] = $id;
+                $coach = self::toModel($coachData, User::class);
+                $coach->save();
+            }
+            DB::commit();
+        } catch (\Exception) {
+            DB::rollBack();
+            self::error();
+        }
+
+    }
+
+    public function auth(int $id)
+    {
+        return User::query()->select([...$this->selectColumn, ...$this->authColumn])->find($id);
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function updateAuth(array $data, int $id): void
+    {
+        $isExistsCoach = User::query()->where('id', $id)->exists();
+        !$isExistsCoach && self::error('数据错误');
+        $data['authTime'] = time();
+        $data['id'] = $id;
+        self::toModel($data, User::class)->save();
+    }
+}

+ 7 - 1
app/Http/Services/Backend/Server/Service/CategoryService.php

@@ -8,6 +8,7 @@
 
 namespace App\Http\Services\Backend\Server\Service;
 
+use App\Enums\Common\Status;
 use App\Http\Services\Service;
 use App\Models\Service\Category;
 use App\Models\System\Dept;
@@ -44,7 +45,7 @@ class CategoryService extends Service
     public function updateCategory(array $data, int $id): void
     {
         $category = self::toModel($data, Category::class);
-        $category->where('id',$id)->update($category->getAttributes());
+        $category->where('id', $id)->update($category->getAttributes());
     }
 
     public function deleteCategory(int $id)
@@ -52,4 +53,9 @@ class CategoryService extends Service
         $category = self::toModel(['id' => $id], Category::class);
         return $category->delete();
     }
+
+    public function getCategorySimpleList()
+    {
+        return Category::query()->where('status', Status::ENABLE)->select($this->simpleColumn)->get();
+    }
 }

+ 65 - 13
app/Http/Services/Backend/Server/Service/ProjectService.php

@@ -8,18 +8,18 @@
 
 namespace App\Http\Services\Backend\Server\Service;
 
+use App\Exceptions\ApiException;
 use App\Http\Services\Service;
-use App\Models\Service\Category;
 use App\Models\Service\Project;
-use App\Models\System\Dept;
-use App\Models\System\DictData;
-use App\Models\System\DictType;
-use Symfony\Component\HttpFoundation\Response;
+use Exception;
+use Illuminate\Support\Facades\DB;
 
 class ProjectService extends Service
 {
     protected array $simpleColumn = ['id', 'title', 'cover'];
-    protected array $selectColumn = ['price', 'init_price as initPrice', 'material_price as materialPrice', 'time_long as timeLong', 'sort', 'status'];
+    protected array $selectColumn = ['sub_title as subTitle', 'time_long as timeLong', 'sort', 'status'];
+    protected array $selectDetailColumn = ['sale', 'material_price as materialPrice', 'com_balance as comBalance', 'is_add as isAdd', 'is_store as isStore', 'is_door as isDoor', 'introduce', 'explain', 'notice'];
+    protected string $selectRawColumn = "FORMAT(price/100,2) as price,FORMAT(init_price/100,2) as initPrice,FORMAT(material_price/100,2) as materialPrice";
     protected array $appendColumn = ['created_at as createTime'];
 
     public function getProjectList($params)
@@ -28,32 +28,84 @@ class ProjectService extends Service
         isset($params['title']) && filled($params['title']) && $project->whereLike('title', "%{$params['title']}%");
         isset($params['status']) && filled($params['status']) && $project->where('status', $params['status']);
         !empty($params['createTime']) && $project->whereIn('created_at', $params['createTime']);
-        $projectPage = $project->paginate($params['pageSize'], [...$this->simpleColumn, ...$this->selectColumn, ...$this->appendColumn], 'page', $params['pageNo']);
+        $projectPage = $project->select([...$this->simpleColumn, ...$this->selectColumn, ...$this->appendColumn])->selectRaw($this->selectRawColumn)->paginate($params['pageSize'], ['*'], 'page', $params['pageNo']);
         return ['list' => $projectPage->items(), 'total' => $projectPage->total()];
     }
 
+    /**
+     * @throws ApiException
+     */
     public function createProject(array $data)
     {
         $collection = collect($data);
-        $category = $collection->forget('category');
-        $project = self::toModel($collection, Project::class);
-        return $project->create($project->getAttributes())->id;
+        $collection->forget('category');
+        DB::beginTransaction();
+
+        try {
+
+            // 保存服务项目
+            $project = self::toModel($collection, Project::class);
+            self::initProperty($project);
+            $project = $project->create($project->getAttributes());
+
+            // 关联服务项目所属分类
+            !empty($data['category']) && $project->saveCategory($data['category']);
+            DB::commit();
+            return $project->id;
+        } catch (Exception) {
+            DB::rollBack();
+            self::error('操作失败');
+        }
+
     }
 
     public function getProject(int $id)
     {
-        return Project::query()->select([...$this->simpleColumn, ...$this->selectColumn])->find($id);
+        $project = Project::query()->select([...$this->simpleColumn, ...$this->selectColumn, ...$this->selectDetailColumn])->selectRaw($this->selectRawColumn)->find($id);
+        $project->category = $project->getCategory();
+        return $project;
     }
 
     public function updateProject(array $data, int $id): void
     {
-        $project = self::toModel($data, Project::class);
-        $project->where('id', $id)->update($project->getAttributes());
+        $collection = collect($data);
+        $collection->forget('category');
+        DB::beginTransaction();
+
+        try {
+            // 保存服务项目
+            $project = self::toModel([...$collection, 'id' => $id], Project::class);
+            self::initProperty($project);
+            $project->update($project->getAttributes());
+
+            // 清空服务项目所属分类
+            $project->deleteCategory();
+            // 关联服务项目所属分类
+            !empty($data['category']) && $project->saveCategory($data['category']);
+            DB::commit();
+        } catch (Exception) {
+            DB::rollBack();
+            self::error('操作失败');
+        }
     }
 
     public function deleteProject(int $id)
     {
+
         $project = self::toModel(['id' => $id], Project::class);
+        // 清空服务项目所属分类
+        $project->deleteCategory();
         return $project->delete();
     }
+
+    protected static function initProperty(Project &$project): void
+    {
+        $project['price'] *= 100;
+        $project['init_price'] *= 100;
+        $project['material_price'] *= 100;
+        $project['total_sale'] = (int)($project['sale'] ?? 0 + $project['true_sale'] ?? 0);
+        $project['introduce'] = $project['introduce'] ?? '';
+        $project['explain'] = $project['explain'] ?? '';
+        $project['notice'] = $project['notice'] ?? '';
+    }
 }

+ 55 - 0
app/Http/Services/Frontend/Client/Auth/AuthenticatedService.php

@@ -0,0 +1,55 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/26 12:11
+ */
+
+namespace App\Http\Services\Frontend\Client\Auth;
+
+use App\Exceptions\ApiException;
+use App\Http\Services\Frontend\Client\Common\AuthService;
+use App\Http\Services\Frontend\Client\Common\SmsService;
+
+use App\Http\Services\Service;
+use App\Models\Member\User;
+
+class AuthenticatedService extends Service
+{
+
+    /**
+     * @throws ApiException
+     */
+    public function login(array $data)
+    {
+        // 手机号
+        $mobile = $data['mobile'];
+        // 手机验证码
+        $code = $data['code'];
+
+        // 判断验证码
+        $verifyCodeResult = (new SmsService())->verifyCode($mobile, $code);
+        !$verifyCodeResult && self::error('验证码错误!', 400);
+
+        // 判断手机号
+        $where = ['mobile' => $data['mobile']];
+        $userQuery = User::query();
+        $user = $userQuery->where($where)->first();
+        !$user && self::error('账户不存在!', 400);
+        $token = (new AuthService())->store($user);
+        return ['token' => $token];
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function send($data): void
+    {
+        // 手机号
+        $mobile = $data['mobile'];
+        $category = $data['category'] ?? 1;
+        $sms = new SmsService();
+        $sms->send($mobile, $category);
+    }
+}

+ 154 - 0
app/Http/Services/Frontend/Client/Auth/WechatAuthenticatedService.php

@@ -0,0 +1,154 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/3/25 17:00
+ */
+
+namespace App\Http\Services\Frontend\Client\Auth;
+
+use App\Exceptions\ApiException;
+use App\Http\Services\Frontend\Client\Common\AuthService;
+use App\Http\Services\Frontend\Client\Common\SmsService;
+use App\Http\Services\Service;
+use App\Models\Member\User;
+use App\Models\WechatUser;
+use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Response;
+use Illuminate\Support\Facades\DB;
+use Overtrue\LaravelWeChat\EasyWeChat;
+
+class WechatAuthenticatedService extends Service
+{
+    /**
+     * @throws InvalidArgumentException
+     */
+    public function oauth($data): array
+    {
+        $wechat = EasyWeChat::officialAccount();
+        $oauth = $wechat->getOAuth();
+        $scopes = $data['scopes'] ?: 'snsapi_base';
+        //callback_url 是授权回调的URL
+        //生成完整的授权URL
+        $redirectUrl = $oauth->scopes([$scopes])->redirect($data['redirect_url']);
+        return ['redirectUrl' => $redirectUrl];
+    }
+
+    /**
+     * @throws InvalidArgumentException
+     */
+    public function callback(array $params): array
+    {
+        $wechat = EasyWeChat::officialAccount();
+        $oauth = $wechat->getOAuth();
+
+        // 获取 OAuth 授权用户信息
+        $wechat_user = $oauth->userFromCode($params['code']);
+        //$wechat_user = $user->toArray();
+
+        $data = [
+            'openid' => $wechat_user->getId() ?? $wechat_user->getTokenResponse()['openid'],
+            'bindUser' => true
+        ];
+        $avatar = $wechat_user->getAvatar();
+        $avatar && ($data['avatar'] = $avatar);
+        $nickname = $wechat_user->getNickname();
+        $nickname && ($data['nickname'] = $nickname);
+
+        $userIsExists = User::query()->where('openid', $data['openid'])->exists();
+        if (!$userIsExists) {
+//            $user_id = User::query()->create($data)->id;
+//            $user = User::query()->find($user_id);
+            $data['bindUser'] = false;
+        }
+//        $isExits = $this->hasOpenID($data['openid']);
+        // 是否已存在
+//        !$isExits && $this->create($data);
+
+//        $wechatUser = WechatUser::query()->with('user.info')->where('openid', $data['openid'])->first();
+
+//        return $this->success('', ['wechatUser' => $wechatUser->toArray()]);
+        return $data;
+    }
+
+    private function hasOpenID($openId): bool
+    {
+        return false;
+//        return WechatUser::query()->where('openid', $openId)->exists();
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function bind(array $params): void
+    {
+        $mobile = $params['mobile'];
+        $code = $params['code'];
+        $openid = $params['open_id'];
+        // 验证验证码
+        $verifyCodeResult = (new SmsService())->verifyCode($mobile, $code);
+        !$verifyCodeResult && self::error('验证码错误!', 400);
+
+        // 获取微信信息
+//        $data = [
+//            'openid' => $params['openid'],
+//            'avatar' => $params['avatar'],
+//            'nickname' => $params['nickname'],
+//        ];
+
+        $register_ip = request()->getClientIp();
+
+        // 获取绑定用户
+        User::query()->updateOrCreate(['openid' => $openid], ['openid' => $openid, 'mobile' => $mobile, 'register_ip' => $register_ip]);
+
+    }
+
+
+    /**
+     * @throws ApiException
+     */
+    public function store($data): array
+    {
+        // 公众号OpenID
+        $openID = $data['open_id'];
+        $autoRegister = $data['auto_register'] ?? 0;
+
+        $user = User::query()->where('open_id', $openID)->first();
+        if (!$user && $autoRegister) {
+            // 获取微信信息
+            // 创建用户信息
+            $user_id = User::query()->create(['openid' => $openID])->id;
+            $user = User::query()->find($user_id);
+        }
+        $token = (new AuthService)->store($user);
+        return ['token' => $token];
+    }
+
+    public function create1($data): Response
+    {
+        // 判断验证码
+        (new SmsService())->verify($data['mobile'], $data['code']);
+
+        $where = ['mobile' => $data['mobile'], 'type' => 0];
+        $exists = User::query()->where($where)->exists();
+
+        if (!$exists) User::query()->create($where);
+
+        // 绑定公众号
+        $user = User::query()->where($where)->first();
+        $user->open_id = $data['open_id'];
+        $user->save();
+        return (new AuthService)->store($user);
+
+    }
+
+    // 发送短信
+    public function send($data): Response
+    {
+        $mobile = $data['mobile'];
+        $sms = new SmsService();
+        return $sms->send($mobile, 0, 2);
+    }
+}

+ 50 - 0
app/Http/Services/Frontend/Client/Coach/UserService.php

@@ -0,0 +1,50 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/10 16:07
+ */
+
+namespace App\Http\Services\Frontend\Client\Coach;
+
+use App\Http\Services\Service;
+use App\Models\Coach\User;
+use App\Models\Service\Category;
+use App\Models\Service\Project;
+use Illuminate\Support\Facades\DB;
+
+class UserService extends Service
+{
+    protected $select_column = ['id', 'name', 'avatar', 'sex', 'brief', 'total_order_num as totalOrderNum'];
+    protected $show_column = ['license', 'work_img as workImg', 'self_img as selfImg'];
+
+    public function getUserPage($params): array
+    {
+        $category_id = $params['categoryId'] ?? 1;
+
+        $project_ids = DB::table('service_project_has_category')->where('category_id', $category_id)->pluck('project_id');
+        $project_ids = Project::query()->whereIn('id', $project_ids)->where('status', 0)->pluck('id');
+        $coach_ids = DB::table('service_project_has_coach')->whereIn('project_id', $project_ids)->pluck('coach_id');
+
+        $userWhere = ['status' => 1, 'auth_status' => 2];
+        $userPage = User::query()->whereIn('id', $coach_ids)->where($userWhere)->select($this->select_column)->paginate();
+        return ['list' => $userPage->items(), 'total' => $userPage->total()];
+
+//        $project = Project::query();
+//        $category_id = $params['categoryId'] ?? 1;
+//        $project_ids = DB::table('service_project_has_category')->where('category_id', $category_id)->pluck('project_id');
+//        !$project_ids->isEmpty() && $project->whereIn('id', $project_ids);
+//        $where['status'] = 0;
+//        $projectPage = $project->where($where)->paginate();
+//        return ['list' => $projectPage->items(), 'total' => $projectPage->total()];
+    }
+
+    public function getUser(array $params, int $id)
+    {
+        $category_id = $params['categoryId'] ?? 0;
+        $user = User::query()->select([...$this->select_column, ...$this->show_column])->find($id);
+        $category_id && ($user['project'] = $user->getProject($category_id));
+        return $user;
+    }
+}

+ 48 - 0
app/Http/Services/Frontend/Client/Common/AuthService.php

@@ -0,0 +1,48 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/3/25 17:11
+ */
+
+namespace App\Http\Services\Frontend\Client\Common;
+
+use App\Enums\Common\Status;
+use App\Exceptions\ApiException;
+use App\Http\Requests\Request;
+use App\Http\Services\Service;
+use App\Models\Member\User;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Response;
+use Illuminate\Support\Facades\Auth;
+
+class AuthService extends Service
+{
+    /**
+     * @throws ApiException
+     */
+    public static function store($user, $guardName = 'web')
+    {
+        if (!$user) return self::error('用户不存在!', 404);
+        // 清理token历史
+        $user->tokens()->where('name', $guardName)->delete();
+
+        $user->status === Status::DISABLE && self::error('账号已停用!', 403);
+
+        $token = $user->createToken($guardName, ['mobile' => $user->mobile]);
+        $result = $token->plainTextToken;
+        !$result && self::error('登录失败!', 401);
+//        $user->last_activity_at = time();
+//        $user->ip_address = request()->getClientIp();
+//        $user->save();
+        return $result;
+    }
+
+    public static function destroy(Request $request): void
+    {
+        Auth::guard('web')->logout();
+        $request->session()->invalidate();
+        $request->session()->regenerateToken();
+    }
+}

+ 35 - 0
app/Http/Services/Frontend/Client/Common/DistanceService.php

@@ -0,0 +1,35 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/4/1 18:38
+ */
+
+namespace App\Http\Services\Frontend\Common;
+
+class DistanceService
+{
+    /**
+     * 根据起点坐标和终点坐标测距离
+     * @param array $from [起点坐标(经纬度),例如:array(118.012951,36.810024)]
+     * @param array $to [终点坐标(经纬度)]
+     * @param bool $km 是否以公里为单位 false:米 true:公里(千米)
+     * @param int $decimal 精度 保留小数位数
+     * @return float 距离数值
+     */
+    function get_distance(array $from, array $to, bool $km = true, int $decimal = 2): float
+    {
+        sort($from);
+        sort($to);
+        $EARTH_RADIUS = 6370.996; // 地球半径系数
+
+        $distance = $EARTH_RADIUS * 2 * asin(sqrt(pow(sin(($from[0] * pi() / 180 - $to[0] * pi() / 180) / 2), 2) + cos($from[0] * pi() / 180) * cos($to[0] * pi() / 180) * pow(sin(($from[1] * pi() / 180 - $to[1] * pi() / 180) / 2), 2))) * 1000;
+
+        if ($km) {
+            $distance = $distance / 1000;
+        }
+
+        return round($distance, $decimal);
+    }
+}

+ 66 - 0
app/Http/Services/Frontend/Client/Common/SmsService.php

@@ -0,0 +1,66 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/3/25 11:38
+ */
+
+namespace App\Http\Services\Frontend\Client\Common;
+
+use App\Exceptions\ApiException;
+use App\Http\Services\Service;
+use App\Models\Member\User;
+
+class SmsService extends Service
+{
+    /**
+     * Notes :
+     * Method : Interface send
+     * @param $mobile
+     * @param int $category 0-注册 1-登录 2-忽略类型
+     * @throws ApiException
+     */
+    public function send($mobile, int $category = 0): void
+    {
+        $where = ['mobile' => $mobile];
+        $exists = User::query()->where($where)->exists();
+        $category === 1 && !$exists && self::error('用户不存在!',404);
+        $category === 0 && $exists && self::error('用户已存在!', 409);
+        // 检测短信发送间隔
+        // 生成验证码
+        $code = 123456;
+        // 发送短信
+        // 判断发送结果
+        // 缓存验证码
+        $this->save($mobile, $code);
+    }
+
+    /**
+     * Notes :
+     * Method : 验证手机验证码并清除缓存
+     * @param $mobile
+     * @param $code
+     * @return bool
+     */
+    public function verifyCode($mobile, $code): bool
+    {
+        $correctCode = cache('mobile_verification_code_' . $mobile);
+        $isValid = $correctCode === $code;
+        $isValid && cache(['mobile_verification_code_' . $mobile => 0], 0);
+        return $isValid;
+    }
+
+    /**
+     * Notes :
+     * Method : 使用缓存保存手机验证码
+     * @param $mobile
+     * @param $code
+     */
+    protected function save($mobile, $code): void
+    {
+        $sms_expires_time = env('SMS_EXPIRES_TIME', 10);
+        $expiresAt = now()->addMinutes(floatval($sms_expires_time)); // 设置验证码有效期为10分钟
+        cache(['mobile_verification_code_' . $mobile => $code], $expiresAt);
+    }
+}

+ 40 - 0
app/Http/Services/Frontend/Client/Member/UserService.php

@@ -0,0 +1,40 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/27 12:05
+ */
+
+namespace App\Http\Services\Frontend\Client\Member;
+
+use App\Http\Requests\Request;
+use App\Http\Services\Frontend\Client\Common\AuthService;
+use App\Http\Services\Service;
+use App\Models\Member\User;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\DB;
+
+class UserService extends Service
+{
+    protected array $select_column = ['id', 'mobile', 'nickname', 'avatar', 'name', 'sex', 'birthday', 'mark', 'point'];
+
+    public function getUser()
+    {
+        $id = Auth::id();
+        return User::query()->select($this->select_column)->find($id);
+    }
+
+    public function updateUser(array $data): void
+    {
+        $id = Auth::id();
+        $user = self::toModel(['id' => $id, ...$data], User::class);
+        $user->save();
+    }
+
+    public function delUser(Request $request): void
+    {
+        $user = User::query()->find(Auth::id());
+        $user->delete();
+    }
+}

+ 27 - 0
app/Http/Services/Frontend/Client/Service/CategoryService.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/10 16:07
+ */
+
+namespace App\Http\Services\Frontend\Client\Service;
+
+use App\Enums\Common\Status;
+use App\Http\Services\Service;
+use App\Models\Service\Category;
+use App\Models\Service\Project;
+use Illuminate\Support\Facades\DB;
+
+class CategoryService extends Service
+{
+    protected array $select_column = ['id','title','cover'];
+    public function getSimpleCategories()
+    {
+        $categoryQuery = Category::query();
+        $where['status'] = Status::ENABLE;
+        return $categoryQuery->where($where)->select($this->select_column)->get();
+    }
+
+}

+ 160 - 0
app/Http/Services/Frontend/Client/Service/OrderService.php

@@ -0,0 +1,160 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/26 11:11
+ */
+
+namespace App\Http\Services\Frontend\Client\Service;
+
+use App\Exceptions\ApiException;
+use App\Http\Services\Service;
+use App\Models\Coach\User;
+use App\Models\Service\Order;
+use Illuminate\Support\Facades\Auth;
+
+class OrderService extends Service
+{
+    protected array $baseColumn = ['id', 'project_name', 'project_icon', 'time_long', 'pay_type', 'pay_price', 'real_address', 'status', 'created_at'];
+
+    function buildOrderSN(): string
+    {
+        $random = rand(1, 999999);
+        return date('YmdHis') . str_repeat('0', 6 - strlen($random)) . $random;
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function createOrder(array $params)
+    {
+        $params['user_id'] = Auth::id();
+        // 用户地址
+        $params['address'] = '默认地址';
+//        $address_model       = new Address();
+        $address = ['lat' => 0, 'lng' => 0, 'area_id' => 0];
+        // 优惠卷
+//        $coupon_record_model = new CouponRecord();
+
+
+        // 渠道
+//        $channel_model       = new UserChannel();
+
+        // 用户渠道
+//        $input['channel_id'] = $channel_model->getChannelId($this->_user['id']);
+
+        // 订单号
+        $order_id = !empty($params['order_id']) ? $params['order_id'] : 0;
+
+        // 使用余额
+        $use_balance = $params['use_balance'] ?? 0;
+
+        // 出行方式
+        $car_type = $params['car_type'] ?? 0;
+
+        // 技师
+        $coach_id = $params['coach_id'] ?? 0;
+        $coach_model = new User();
+        $coach_info = $coach_model->info($coach_id);
+
+        !empty($coach_info) && $coach_info['is_work'] == 0 && self::error('该技师未上班');
+
+
+        !empty($coach_info) && ($coach_info['auth_status'] !== 2 || $coach_info['status'] !== 1) && self::error('该技师已下架');
+
+        // 优惠卷ID
+        $coupon_id = !empty($params['coupon_id']) ? $params['coupon_id'] : 0;
+
+        // 加钟订单
+        if ($order_id) {
+
+        } else {
+
+//            $address = $address_model->info($params['address_id']);
+//            if(empty($address)){
+//                $this->errorMsg('请添加地址');
+//            }
+        }
+
+        $orderModel = new Order();
+        $orderPayInfo = $orderModel->buildPayInfo($params['user_id'], $params['project_id'], $address['area_id'], $address['lat'], $address['lng'], $use_balance, $coach_id, $car_type, $coupon_id, $order_id);
+
+        //默认微信
+        $payType = $params['pay_type'] ?? 1;
+        $use_balance && !$orderPayInfo['pay_price'] && ($payType = 0);
+
+        $orderData = [
+            'order_sn' => $this->buildOrderSN(),
+            'user_id' => $params['user_id'],
+            'pay_type' => $payType,
+            ...$orderPayInfo,
+            //备注
+//            'text' => $params['text'] ?: '',
+//            'car_type' => $car_type,
+//            'channel_id' => $params['channel_id'] ?: 0,
+
+            //目的地地址
+            //加钟
+//            'add_pid' => $order_id,
+//            'is_add' => $order_id ? 1 : 0,
+        ];
+        // 创建订单
+        return $orderModel->newQuery()->create($orderData)->id;
+    }
+
+    public function getOrderPage(array $data)
+    {
+        $user_id = Auth::id();
+        $status = intval($data['status'] ?? 0);
+        $where = ['user_id' => $user_id, 'user_del' => 0];
+        $statusRange = match ($status) {
+            1 => [0, 1, 2, 3],
+            2 => [4, 5],
+            3 => [5],
+            4 => [6, 7],
+            default => [0, 1, 2, 3, 4, 5, 6, 7]
+        };
+//        $select = ['id', 'project_name', 'project_icon', 'duration', 'paid_type', 'price', 'real_address', 'status', 'created_at', 'refunded_at'];
+        $select = ['id', 'project_name', 'project_icon', 'time_long', 'pay_type', 'pay_price', 'real_address', 'status', 'created_at'];
+        $orderPage = Order::query()->where($where)->whereIn('status', $statusRange)->select($select)->latest()->paginate();
+        return ['list' => $orderPage->items(), 'total' => $orderPage->total()];
+    }
+
+    public function getOrder(int $order_id)
+    {
+        $user_id = Auth::id();
+        return Order::query()->where('user_id', $user_id)->select($this->baseColumn)->find($order_id);
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function updateOrder(array $data, int $order_id): void
+    {
+        $order = Order::query()->find($order_id);
+        $status = $data['status'];
+        switch ($status) {
+            // 结束订单
+            case 6:
+                $order->status !== 5 && self::error('订单状态有误');
+                // 查询是否存在加钟订单
+                // 判断加钟服务是否完成
+                $order->user_end = 1;
+                $order->end_time = time();
+                break;
+            case 9:
+                !in_array($order->status, [0, 1, 2, 3]) && self::error('订单状态有误');
+                break;
+        }
+        $order->status = $status;
+        $order->save();
+    }
+
+    public function delOrder(int $order_id): void
+    {
+        $order = Order::query()->find($order_id);
+        $order->user_del = 1;
+        $order->save();
+    }
+}

+ 36 - 0
app/Http/Services/Frontend/Client/Service/ProjectService.php

@@ -0,0 +1,36 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/10 16:07
+ */
+
+namespace App\Http\Services\Frontend\Client\Service;
+
+use App\Enums\Common\Status;
+use App\Http\Services\Service;
+use App\Models\Service\Category;
+use App\Models\Service\Project;
+use Illuminate\Support\Facades\DB;
+
+class ProjectService extends Service
+{
+    protected $select_column = ['id','title','sub_title as subTitle','cover','price','init_price as InitPrice','total_sale as totalSale','time_long as timeLong','introduce','explain','notice','is_store as isStore','is_door as isDoor'];
+    public function getProjectPage($params): array
+    {
+        $project = Project::query();
+        $category_id = $params['categoryId'] ?? 1;
+        $project_ids = DB::table('service_project_has_category')->where('category_id', $category_id)->pluck('project_id');
+        // !$project_ids->isEmpty() &&
+        $project->whereIn('id', $project_ids);
+        $where['status'] = Status::ENABLE;
+        $projectPage = $project->where($where)->select($this->select_column)->paginate();
+        return ['list' => $projectPage->items(), 'total' => $projectPage->total()];
+    }
+
+    public function getProject(array $params, int $id)
+    {
+        return Project::query()->select($this->select_column)->find($id);
+    }
+}

+ 52 - 0
app/Http/Services/Frontend/Server/Coach/UserService.php

@@ -0,0 +1,52 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/10 16:07
+ */
+
+namespace App\Http\Services\Frontend\Server\Coach;
+
+use App\Exceptions\ApiException;
+use App\Http\Services\Service;
+use App\Models\Coach\User;
+use App\Models\Coach\Verify;
+
+class UserService extends Service
+{
+    protected array $selectColumn = ['name', 'mobile', 'sex', 'birthday', 'work_img as workImg', 'city_id as cityId', 'status', 'verify_text as verifyText'];
+
+    public function getUser()
+    {
+        // 获取用户ID
+        $user_id = 1; // member_user_id
+
+        // 获取认证信息
+        $coach = Verify::query()->where('user_id', $user_id)->select($this->selectColumn)->first();
+
+        // 判断认证信息
+        return $coach ?: User::query()->where('user_id', $user_id)->select($this->selectColumn)->first();
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function updateUser(array $data): void
+    {
+        // 获取用户ID
+        $user_id = 1; // member_user_id
+        // 获取技师ID
+        $coach_id = User::query()->where('user_id', $user_id)->value('id');
+
+        // 验证技师ID
+        !$coach_id && self::error('数据错误');
+
+        // 填充数据
+        $data['user_id'] = $user_id;
+        $data['coach_id'] = $coach_id;
+        $data['status'] = 0;
+        $data['id'] = Verify::query()->where('coach_id', $user_id)->value('id');
+        self::toModel($data, Verify::class)->save();
+    }
+}

+ 41 - 0
app/Http/Services/Frontend/Server/Service/ProjectService.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/20 11:29
+ */
+
+namespace App\Http\Services\Frontend\Server\Service;
+
+use App\Enums\Common\Status;
+use App\Http\Services\Service;
+use App\Models\Coach\User;
+use App\Models\Service\Category;
+use App\Models\Service\Project;
+
+class ProjectService extends Service
+{
+    public function getProjectPage(array $params): array
+    {
+        $category = Category::query()->find($params['category_id']);
+        (empty($category) || $category->status === Status::DISABLE) && self::error();
+
+        $user_id = 1;
+        // 获取技师ID
+        $coach_id = User::query()->where('user_id', $user_id)->value('id');
+        $project_ids = $category->getProjectIds();
+        $projectPage = Project::query()->whereIn('id', $project_ids)->where('status', Status::ENABLE)->orderByDesc('sort')->paginate($params['pageSize'], ['*'], 'page', $params['pageNo']);
+        collect($projectPage->items())->each(fn($project) => $project->setAttribute('coachProjectStatus', $project->getCoachProjectStatus($coach_id)));
+        return ['list' => $projectPage->items(), 'total' => $projectPage->total()];
+    }
+
+    public function updateProject(array $data): void
+    {
+        $user_id = 1;
+        // 获取技师ID
+        $coach_id = User::query()->where('user_id', $user_id)->value('id');
+        $project = Project::query()->find($data['project_id']);
+        $project->updateCoachProjectStatus($coach_id, $data['status']);
+    }
+}

+ 2 - 1
app/Http/Services/Service.php

@@ -17,10 +17,11 @@ use Spatie\Permission\Guard;
 class Service
 {
     protected string $guard_name = 'web';
+
     protected static function toModel($attributes, $class)
     {
         $classInstance = app($class);
-        isset($attributes['id']) && ($classInstance = $classInstance->find($attributes['id']));
+        isset($attributes['id']) && filled($attributes['id']) && ($classInstance = $classInstance->find($attributes['id']));
 //        $oldAttributes = $classInstance->getAttributes();
 //        $newAttributes = array_merge($oldAttributes, $attributes);
 //        $classInstance->setRawAttributes($newAttributes);

+ 81 - 0
app/Models/Coach/User.php

@@ -0,0 +1,81 @@
+<?php
+
+namespace App\Models\Coach;
+
+use App\Models\Service\Project;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Notifications\Notifiable;
+use Illuminate\Support\Facades\DB;
+
+class User extends Model
+{
+    use HasFactory, Notifiable;
+
+    protected $table = 'coach_users';
+
+    /**
+     * The attributes that are mass assignable.
+     *
+     * @var array<int, string>
+     */
+    protected $fillable = [];
+
+    protected $guarded = [];
+
+    protected $appends = [];
+
+    /**
+     * The attributes that should be hidden for serialization.
+     *
+     * @var array<int, string>
+     */
+    protected $hidden = [];
+
+    /**
+     * Get the attributes that should be cast.
+     *
+     * @return array<string, string>
+     */
+    protected function casts(): array
+    {
+        return [
+//            'password' => 'hashed',
+            'verify_time' => 'datetime',
+            'auth_time' => 'datetime'
+        ];
+    }
+
+    public function getVerifyStatusAttribute()
+    {
+        return '1232';
+    }
+
+    public function info($attribute, $file = ['*']): array
+    {
+        gettype($attribute) === "string" && ($attribute = ['id' => $attribute]);
+        if (gettype($attribute) === "NULL") return [];
+        $data = $this::query()->where($attribute)->first($file);
+        return !empty($data) ? $data->toArray() : [];
+    }
+
+    public function getProject($category_id, $is_add = 0)
+    {
+        $project_ids = DB::table('service_project_has_category')->where('category_id', $category_id)->pluck('project_id');
+
+        $project_ids = DB::table('service_project_has_coach')->whereIn('project_id', $project_ids)->where('coach_id', $this->attributes['id'])->where('status', 1)->pluck('project_id');
+
+        $select = ['id', 'title', 'sub_title as subTitle', 'cover', 'price', 'init_price as initPrice', 'total_sale as totalSale', 'time_long as timeLong'];
+        return Project::query()->whereIn('id', $project_ids)->where('status', 0)->where('is_add', $is_add)->select($select)->get();
+    }
+
+    public function verify()
+    {
+        return $this->hasOne(Verify::class, 'coach_id');
+    }
+
+    public function member(): \Illuminate\Database\Eloquent\Relations\HasOne
+    {
+        return $this->hasOne(\App\Models\Member\User::class, 'id', 'user_id');
+    }
+}

+ 47 - 0
app/Models/Coach/Verify.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Models\Coach;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Foundation\Auth\User as Authenticatable;
+use Illuminate\Notifications\Notifiable;
+use Laravel\Sanctum\HasApiTokens;
+use Spatie\Permission\Traits\HasRoles;
+
+class Verify extends Model
+{
+    use HasFactory, Notifiable;
+
+    protected $table = 'coach_verify';
+
+    /**
+     * The attributes that are mass assignable.
+     *
+     * @var array<int, string>
+     */
+    protected $fillable = [];
+
+    protected $guarded = [];
+
+    /**
+     * The attributes that should be hidden for serialization.
+     *
+     * @var array<int, string>
+     */
+    protected $hidden = [];
+
+    /**
+     * Get the attributes that should be cast.
+     *
+     * @return array<string, string>
+     */
+    protected function casts(): array
+    {
+        return [
+//            'password' => 'hashed',
+            'verify_time' => 'datetime'
+        ];
+    }
+
+}

+ 7 - 1
app/Models/Member/User.php

@@ -3,6 +3,7 @@
 namespace App\Models\Member;
 
 use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\SoftDeletes;
 use Illuminate\Foundation\Auth\User as Authenticatable;
 use Illuminate\Notifications\Notifiable;
 use Laravel\Sanctum\HasApiTokens;
@@ -10,7 +11,7 @@ use Spatie\Permission\Traits\HasRoles;
 
 class User extends Authenticatable
 {
-    use HasApiTokens, HasFactory, Notifiable;
+    use HasApiTokens, HasFactory, Notifiable, SoftDeletes;
 
     protected $table = 'member_users';
 
@@ -44,4 +45,9 @@ class User extends Authenticatable
             'login_date' => 'datetime'
         ];
     }
+
+    public function coach(): \Illuminate\Database\Eloquent\Relations\HasOne
+    {
+        return $this->hasOne(\App\Models\Coach\User::class, 'user_id');
+    }
 }

+ 7 - 0
app/Models/Service/Category.php

@@ -4,6 +4,7 @@ namespace App\Models\Service;
 
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
 
 class Category extends Model
 {
@@ -12,4 +13,10 @@ class Category extends Model
     protected $table = 'service_category';
 
     protected $guarded = [];
+
+    // 获取服务项目ID集合
+    public function getProjectIds()
+    {
+        return DB::table('service_project_has_category')->where('category_id', $this->attributes['id'])->pluck('project_id');
+    }
 }

+ 102 - 0
app/Models/Service/Order.php

@@ -0,0 +1,102 @@
+<?php
+
+namespace App\Models\Service;
+
+use App\Models\Coach\User;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
+
+class Order extends Model
+{
+    use HasFactory;
+
+    protected $table = 'service_order';
+
+    protected $guarded = [];
+
+    protected $appends = [];
+
+    protected $casts = [
+        'end_time' => 'datetime'
+    ];
+
+    public function buildPayInfo($user_id, $project_id, $area_id, $lat, $lng,$use_balance = 0, $coach_id = null, $car_type = 0, $coupon_id = 0, $order_id = 0): array
+    {
+
+        $data['project_id'] = $project_id;
+
+        // 通过定位获取代理
+        // 获取代理项目
+        $project = Project::query()->find($data['project_id']);
+
+
+//        $coupon_model= new Coupon();
+
+        $coach_model = new User();
+//        $car_config_model = new CarPrice();
+        $coach = $coach_model->info($coach_id);
+
+        // 优惠卷
+        $data['coupon_id'] = $coupon_id ?: 0;
+        // 优惠金额
+        $data['coupon_price'] = 0;
+
+        // 折扣金额
+        $data['discount_price'] = 0;
+
+        // 物料费
+        $data['material_price'] = $project['material_price'] ?? 0;
+
+        // 车费默认值
+        $data['car_price'] = 0;
+
+        // 选择技师
+        if ($coach) {
+            $data['coach_id'] = $coach_id;
+
+            if ($lat && $lng) {
+                // 订单距离
+//        $data['distance'] = getDriveDistance($coach['lng'], $coach['lat'], $lng, $lat, $coach['uniacid']);
+
+//        $data['distance'] += $data['car_config']['invented_distance'] * $data['distance'] / 100;
+                //车费
+                $data['car_price'] = 0;
+//        $data['car_price'] = $this->getCarPrice($data['distance'], $data['car_config'], $car_type);
+
+            }
+        }
+        // 订单支付价
+        // 订单总价格
+        $pay_total_price = $project['price'] + $data['car_price'] + $data['material_price'];
+        // 订单总优惠
+        $coupon_total_price = $data['coupon_price'] + $data['discount_price'];
+
+        // 支付金额
+        $pay_price = $pay_total_price - $coupon_total_price;
+        $pay_price <= 0 && ($pay_price = 0);
+        $data['pay_price'] = $pay_price;
+        // 余额支付
+        if ($use_balance) {
+            // 用户余额
+            $user['balance'] = 0;
+            // 余额抵扣金额
+            $balance_price = $user['balance'] - $pay_price;
+            if ($balance_price >= 0) {
+                $data['balance_price'] = $pay_price;
+                $data['pay_price'] = 0;
+            } else {
+                $data['balance_price'] = $user['balance'];
+                $data['pay_price'] = abs($balance_price);
+            }
+        }
+
+        // 店铺
+//        $data['store_id'] = $coach['store_id'];
+
+        // 服务时长
+        $data['time_long'] = $project['time_long'];
+
+        return $data;
+    }
+}

+ 46 - 0
app/Models/Service/Project.php

@@ -4,6 +4,7 @@ namespace App\Models\Service;
 
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
 
 class Project extends Model
 {
@@ -13,9 +14,54 @@ class Project extends Model
 
     protected $guarded = [];
 
+    protected $appends = [];
+
     protected $casts = [
         'isAdd' => 'bool',
         'isStore' => 'bool',
         'isDoor' => 'bool'
     ];
+
+    public function getCoachProjectStatus($coach_id)
+    {
+        $status = DB::table('service_project_has_coach')->where('project_id', $this->attributes['id'])
+            ->where('coach_id', $coach_id)->value('status');
+        return $status ?: 0;
+    }
+
+    public function updateCoachProjectStatus(int $coach_id, int $status): void
+    {
+        $model = DB::table('service_project_has_coach');
+        $project_id = $model->where('project_id', $this->attributes['id'])
+            ->where('coach_id', $coach_id)->value('id');
+        if($project_id)
+            $model->where('id',$project_id)->update(['status' => $status]);
+        else
+            $model->insert(['project_id' => $this->attributes['id'], 'coach_id' => $coach_id, 'status' => $status]);
+    }
+
+    // 关联服务项目所属分类
+    public function saveCategory(array $category_ids)
+    {
+        $data = collect($category_ids)->map(fn($category_id) => ['project_id' => $this->attributes['id'], 'category_id' => $category_id]);
+        DB::table('service_project_has_category')->insert($data->all());
+    }
+
+    // 获取服务项目所属分类
+    public function getCategory()
+    {
+        return DB::table('service_project_has_category')->where('project_id', $this->attributes['id'])->pluck('category_id');
+    }
+
+    public function deleteCategory()
+    {
+        return DB::table('service_project_has_category')->where('project_id', $this->attributes['id'])->delete();
+    }
+
+//    public function hasCoach()
+//    {
+//        return $this->hasOne(\App\Models\Coach\User::class,'user_id');
+//
+//    }
+
 }

+ 2 - 1
app/Models/System/User.php

@@ -3,6 +3,7 @@
 namespace App\Models\System;
 
 use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\SoftDeletes;
 use Illuminate\Foundation\Auth\User as Authenticatable;
 use Illuminate\Notifications\Notifiable;
 use Laravel\Sanctum\HasApiTokens;
@@ -10,7 +11,7 @@ use Spatie\Permission\Traits\HasRoles;
 
 class User extends Authenticatable
 {
-    use HasApiTokens, HasRoles, HasFactory, Notifiable;
+    use HasApiTokens, HasRoles, HasFactory, Notifiable, SoftDeletes;
 
     protected $table = 'system_users';
 

+ 47 - 0
app/Models/Wechat/User.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Models\Wechat;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\SoftDeletes;
+use Illuminate\Foundation\Auth\User as Authenticatable;
+use Illuminate\Notifications\Notifiable;
+use Laravel\Sanctum\HasApiTokens;
+use Spatie\Permission\Traits\HasRoles;
+
+class User extends Authenticatable
+{
+    use HasFactory, Notifiable;
+
+    protected $table = 'wechat_users';
+
+    /**
+     * The attributes that are mass assignable.
+     *
+     * @var array<int, string>
+     */
+    protected $fillable = [];
+
+    protected $guarded = [];
+
+    /**
+     * The attributes that should be hidden for serialization.
+     *
+     * @var array<int, string>
+     */
+    protected $hidden = [];
+
+    /**
+     * Get the attributes that should be cast.
+     *
+     * @return array<string, string>
+     */
+    protected function casts(): array
+    {
+        return [
+            'password' => 'hashed',
+            'login_date' => 'datetime'
+        ];
+    }
+
+}

+ 1 - 0
composer.json

@@ -10,6 +10,7 @@
         "laravel/framework": "^11.9",
         "laravel/sanctum": "^4.0",
         "laravel/tinker": "^2.9",
+        "overtrue/laravel-wechat": "^7.3",
         "spatie/laravel-permission": "^6.9"
     },
     "require-dev": {

文件差异内容过多而无法显示
+ 812 - 49
composer.lock


+ 10 - 0
config/auth.php

@@ -40,6 +40,11 @@ return [
             'driver' => 'session',
             'provider' => 'system_users',
         ],
+        'api' => [
+            'driver' => 'sanctum',
+            'provider' => 'member_users',
+            'hash' => false,
+        ]
     ],
 
     /*
@@ -65,6 +70,11 @@ return [
             'model' => env('AUTH_MODEL', App\Models\System\User::class),
         ],
 
+        'member_users' => [
+            'driver' => 'eloquent',
+            'model' => App\Models\Member\User::class,
+        ],
+
         // 'users' => [
         //     'driver' => 'database',
         //     'table' => 'users',

+ 1 - 1
config/cors.php

@@ -19,7 +19,7 @@ return [
 
     'allowed_methods' => ['*'],
 
-    'allowed_origins' => [env('FRONTEND_URL', 'http://localhost:3000')],
+    'allowed_origins' => [env('FRONTEND_URL', 'http://localhost:3000'),env('BACKEND_URL', 'http://localhost:3000')],
 
     'allowed_origins_patterns' => [],
 

+ 168 - 0
config/easywechat.php

@@ -0,0 +1,168 @@
+<?php
+
+return [
+    /*
+     * 默认配置,将会合并到各模块中
+     */
+    'defaults' => [
+        'http' => [
+            'timeout' => 5.0,
+        ],
+    ],
+
+    /*
+     * 公众号
+     */
+    'official_account' => [
+        'default' => [
+            'app_id' => env('WECHAT_OFFICIAL_ACCOUNT_APPID', 'wxd9f14d5e42a56563'),     // AppID
+            'secret' => env('WECHAT_OFFICIAL_ACCOUNT_SECRET', '43addf850a9a3582ffc48ba1f7cc99f1'),    // AppSecret
+            'token' => env('WECHAT_OFFICIAL_ACCOUNT_TOKEN', 'didongdiandao'),     // Token
+            'aes_key' => env('WECHAT_OFFICIAL_ACCOUNT_AES_KEY', 'x42tErK0vXtXZX7uQdgRVhqxYaABrsH3FQmbi1fBPzN'),   // EncodingAESKey
+
+            /*
+             * OAuth 配置
+             *
+             * scopes:公众平台(snsapi_userinfo / snsapi_base),开放平台:snsapi_login
+             * callback:OAuth授权完成后的回调页地址(如果使用中间件,则随便填写。。。)
+             * enforce_https:是否强制使用 HTTPS 跳转
+             */
+            // 'oauth'   => [
+            //     'scopes'        => array_map('trim', explode(',', env('WECHAT_OFFICIAL_ACCOUNT_OAUTH_SCOPES', 'snsapi_userinfo'))),
+            //     'callback'      => env('WECHAT_OFFICIAL_ACCOUNT_OAUTH_CALLBACK', '/examples/oauth_callback.php'),
+            //     'enforce_https' => true,
+            // ],
+
+        /**
+         * 接口请求相关配置,超时时间等,具体可用参数请参考:
+         * https://github.com/symfony/symfony/blob/6.0/src/Symfony/Contracts/HttpClient/HttpClientInterface.php#L26
+         */
+            //'http' => [
+            //  'timeout' => 5.0,
+            //   // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
+            //  'base_uri' => 'https://api.weixin.qq.com/',
+            //],
+        ],
+    ],
+
+    /*
+     * 开放平台第三方平台
+     */
+    // 'open_platform' => [
+    //     'default' => [
+    //         'app_id'     => env('WECHAT_OPEN_PLATFORM_APPID', ''),
+    //         'secret'     => env('WECHAT_OPEN_PLATFORM_SECRET', ''),
+    //         'token'      => env('WECHAT_OPEN_PLATFORM_TOKEN', ''),
+    //         'aes_key'    => env('WECHAT_OPEN_PLATFORM_AES_KEY', ''),
+
+/**
+ * 接口请求相关配置,超时时间等,具体可用参数请参考:
+ * https://github.com/symfony/symfony/blob/6.0/src/Symfony/Contracts/HttpClient/HttpClientInterface.php#L26
+ */
+    //          'http' => [
+    //            'timeout' => 5.0,
+    //             // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
+    //            'base_uri' => 'https://api.weixin.qq.com/',
+    //          ],
+    //     ],
+    // ],
+
+    /*
+     * 小程序
+     */
+    // 'mini_app' => [
+    //     'default' => [
+    //         'app_id'     => env('WECHAT_MINI_APP_APPID', ''),
+    //         'secret'     => env('WECHAT_MINI_APP_SECRET', ''),
+    //         'token'      => env('WECHAT_MINI_APP_TOKEN', ''),
+    //         'aes_key'    => env('WECHAT_MINI_APP_AES_KEY', ''),
+
+/**
+ * 接口请求相关配置,超时时间等,具体可用参数请参考:
+ * https://github.com/symfony/symfony/blob/6.0/src/Symfony/Contracts/HttpClient/HttpClientInterface.php#L26
+ */
+    //          'http' => [
+    //            'timeout' => 5.0,
+    //             // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
+    //            'base_uri' => 'https://api.weixin.qq.com/',
+    //          ],
+    //     ],
+    // ],
+
+    /*
+     * 微信支付
+     */
+    // 'pay' => [
+    //     'default' => [
+    //         'app_id'             => env('WECHAT_PAY_APPID', ''),
+    //         'mch_id'             => env('WECHAT_PAY_MCH_ID', 'your-mch-id'),
+    //         'private_key'        => '/data/private/certs/apiclient_key.pem',
+    //         'certificate'        => '/data/private/certs/apiclient_cert.pem',
+    //         'notify_url'         => 'http://example.com/payments/wechat-notify',                           // 默认支付结果通知地址
+    //          /**
+    //           * 证书序列号,可通过命令从证书获取:
+    //           * `openssl x509 -in application_cert.pem -noout -serial`
+    //           */
+    //          'certificate_serial_no' => '6F2BADBE1738B07EE45C6A85C5F86EE343CAABC3',
+    //
+    //          'http' => [
+    //              'base_uri' => 'https://api.mch.weixin.qq.com/',
+    //          ],
+    //
+    //          // v2 API 秘钥
+    //          //'v2_secret_key' => '26db3e15cfedb44abfbb5fe94fxxxxx',
+    //
+    //          // v3 API 秘钥
+    //          //'secret_key' => '43A03299A3C3FED3D8CE7B820Fxxxxx',
+    //
+    //          // 注意 此处为微信支付平台证书 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/wechatpay5_1.shtml
+    //          'platform_certs' => [
+    //              '/data/private/certs/platform_key.pem',
+    //          ],
+    //     ],
+    // ],
+
+    /*
+     * 企业微信
+     */
+    // 'work' => [
+    //     'default' => [
+    //         'corp_id'    => env('WECHAT_WORK_CORP_ID', ''),
+    //         'secret'     => env('WECHAT_WORK_SECRET', ''),
+    //         'token'      => env('WECHAT_WORK_TOKEN', ''),
+    //         'aes_key'    => env('WECHAT_WORK_AES_KEY', ''),
+
+/**
+ * 接口请求相关配置,超时时间等,具体可用参数请参考:
+ * https://github.com/symfony/symfony/blob/6.0/src/Symfony/Contracts/HttpClient/HttpClientInterface.php#L26
+ */
+    //          'http' => [
+    //            'timeout' => 5.0,
+    //             // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
+    //            'base_uri' => 'https://api.weixin.qq.com/',
+    //          ],
+    //      ],
+    // ],
+
+    /*
+     * 企业微信开放平台
+     */
+    // 'open_work' => [
+    //     'default' => [
+    //         'corp_id'            => env('WECHAT_OPEN_WORK_CORP_ID', ''),
+    //         'provider_secret'    => env('WECHAT_OPEN_WORK_SECRET', ''),
+    //         'token'              => env('WECHAT_OPEN_WORK_TOKEN', ''),
+    //         'aes_key'            => env('WECHAT_OPEN_WORK_AES_KEY', ''),
+
+/**
+ * 接口请求相关配置,超时时间等,具体可用参数请参考:
+ * https://github.com/symfony/symfony/blob/6.0/src/Symfony/Contracts/HttpClient/HttpClientInterface.php#L26
+ */
+    //          'http' => [
+    //            'timeout' => 5.0,
+    //             // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
+    //            'base_uri' => 'https://api.weixin.qq.com/',
+    //          ],
+    //      ],
+    // ],
+];

+ 3 - 1
database/migrations/2024_09_04_022856_create_member_users_table.php

@@ -15,10 +15,12 @@ return new class extends Migration {
             $table->string('mobile')->nullable()->comment('手机号');
             $table->string('password')->default('')->comment('密码');
             $table->tinyInteger('status')->default(0)->comment('状态 (0正常 1停用)');
-            $table->string('register_ip')->comment('注册IP');
+            $table->string('register_ip')->nullable()->comment('注册IP');
             $table->tinyInteger('register_terminal')->nullable()->comment('注册终端');
             $table->string('login_ip', 50)->nullable()->comment('最后登录IP');
             $table->timestamp('login_date')->nullable()->comment('最后登录时间');
+            $table->string('openid')->nullable();
+            $table->integer('balance')->default(0)->comment('余额');
             $table->string('nickname')->nullable()->comment('用户昵称');
             $table->string('avatar')->nullable()->comment('用户头像');
             $table->string('name')->nullable()->comment('用户姓名');

+ 56 - 0
database/migrations/2024_09_10_090033_create_coach_users_table.php

@@ -0,0 +1,56 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration {
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('coach_users', function (Blueprint $table) {
+            $table->id();
+            $table->string('name')->nullable()->comment('技师姓名');
+            $table->bigInteger('user_id');
+            $table->string('mobile')->nullable()->comment('手机号');
+            $table->string('avatar')->nullable()->comment('头像');
+            $table->tinyInteger('status')->default(0)->comment('状态 (0正常 1停用)');
+            $table->tinyInteger('sex')->default(0)->nullable()->comment('用户性别');
+            $table->bigInteger('work_time')->nullable()->comment('从业年份');
+            $table->string('city')->nullable()->comment('城市');
+            $table->string('lng')->nullable();
+            $table->string('lat')->nullable();
+            $table->string('address')->nullable()->comment('详细地址');
+            $table->string('brief')->nullable()->comment('简介');
+            $table->string('id_code')->nullable()->comment('证件号');
+            $table->string('id_card')->nullable()->comment('证件照片');
+            $table->text('license')->nullable()->comment('执照');
+            $table->string('work_img')->nullable()->comment('工作照');
+            $table->string('self_img')->nullable()->comment('个人照');
+            $table->tinyInteger('is_work')->default(1)->comment('是否工作');
+            $table->integer('birthday')->nullable()->comment('出生日期');
+            $table->integer('order_num')->default(0)->comment('虚拟订单量');
+            $table->integer('total_order_num')->default(0)->comment('总订单量');
+            $table->tinyInteger('is_recommend')->default(0)->comment('是否推荐');
+            $table->integer('sort')->default(0)->comment('排序');
+            $table->tinyInteger('auth_status')->default(0)->comment('认证状态');
+            $table->string('alipay_number')->nullable()->comment('支付宝账号');
+            $table->text('verify_text')->nullable()->comment('审核意见');
+            $table->timestamp('verify_time')->nullable()->comment('审核时间');
+            $table->text('auth_text')->nullable()->comment('认证意见');
+            $table->timestamp('auth_time')->nullable()->comment('认证时间');
+            $table->timestamps();
+            $table->softDeletes();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('coach_users');
+    }
+};

+ 45 - 0
database/migrations/2024_09_10_090034_create_coach_verify_table.php

@@ -0,0 +1,45 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration {
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('coach_verify', function (Blueprint $table) {
+            $table->id();
+            $table->string('name')->nullable()->comment('技师姓名');
+            $table->bigInteger('user_id');
+            $table->bigInteger('coach_id');
+            $table->string('mobile')->nullable()->comment('手机号');
+            $table->string('avatar')->nullable()->comment('头像');
+            $table->tinyInteger('status')->default(0)->comment('状态');
+            $table->tinyInteger('sex')->default(0)->nullable()->comment('用户性别');
+            $table->bigInteger('work_time')->nullable()->comment('从业年份');
+            $table->string('city_id')->nullable()->comment('城市');
+            $table->string('lng')->nullable();
+            $table->string('lat')->nullable();
+            $table->string('address')->nullable()->comment('详细地址');
+            $table->string('brief')->nullable()->comment('简介');
+            $table->text('license')->nullable()->comment('执照');
+            $table->string('work_img')->nullable()->comment('工作照');
+            $table->string('self_img')->nullable()->comment('个人照');
+            $table->integer('birthday')->nullable()->comment('出生日期');
+            $table->text('verify_text')->nullable()->comment('审核意见');
+            $table->timestamp('verify_time')->nullable()->comment('审核时间');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('coach_verify');
+    }
+};

+ 30 - 0
database/migrations/2024_09_20_052430_create_service_project_has_coach_table.php

@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('service_project_has_coach', function (Blueprint $table) {
+            $table->id();
+            $table->bigInteger('project_id');
+            $table->bigInteger('coach_id');
+            $table->tinyInteger('status')->default(0)->comment('状态 0开启 1关闭');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('service_project_has_coach');
+    }
+};

+ 104 - 0
database/migrations/2024_09_23_025555_create_service_order_table.php

@@ -0,0 +1,104 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration {
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('service_order', function (Blueprint $table) {
+            $table->id();
+            $table->bigInteger('user_id')->comment('用户ID');
+            $table->string('order_sn')->comment('订单编号');
+            $table->tinyInteger('pay_type')->comment('支付类型');
+            $table->string('transaction_id')->comment('商户订单号');
+            $table->bigInteger('project_id')->comment('项目ID');
+            $table->bigInteger('area_id')->comment('区域ID');
+
+            $table->string('project_name')->comment('项目名称');
+            $table->string('project_icon')->comment('项目图标');
+
+            $table->integer('pay_price')->default('0.00')->nullable()->comment('支付金额');
+            $table->integer('balance_price')->default('0.00')->nullable()->comment('余额金额');
+            $table->integer('discount_price')->default('0.00')->nullable()->comment('折扣金额');
+            $table->integer('coupon_price')->default('0.00')->nullable()->comment('优惠金额');
+            $table->integer('car_price')->default('0.00')->nullable()->comment('车费金额');
+            $table->integer('material_price')->default('0.00')->nullable()->comment('物料金额');
+            $table->integer('service_price')->default('0.00')->nullable()->comment('服务金额');
+
+            $table->bigInteger('coach_id')->nullable()->comment('技师ID');
+            $table->timestamp('start_time')->nullable()->comment('开始时间');
+            $table->timestamp('end_time')->nullable()->comment('结束时间');
+            $table->integer('time_long')->nullable()->comment('服务时长');
+            $table->integer('true_time_long')->nullable()->comment('真实服务时长');
+            $table->integer('payment_time')->nullable()->comment('入账时间');
+
+            $table->text('remark')->nullable()->comment('备注');
+            $table->timestamp('pay_time')->nullable()->comment('支付时间');
+            $table->timestamp('receiving_time')->nullable()->comment('接单时间');
+            $table->timestamp('depart_time')->nullable()->comment('出发时间');
+            $table->timestamp('arrive_time')->nullable()->comment('到达时间');
+            $table->timestamp('over_time')->nullable()->comment('撤离时间');
+            $table->timestamp('refund_time')->nullable()->comment('退款时间');
+            $table->text('refund_text')->nullable()->comment('退款原因');
+
+            $table->decimal('distance', 10, 2)->nullable()->comment('相隔距离');
+            $table->tinyInteger('is_show')->default('1')->comment('展示订单');
+
+            $table->string('depart_lng')->nullable()->comment('出发经度');
+            $table->string('depart_lat')->nullable()->comment('出发纬度');
+
+            $table->string('depart_address')->nullable()->comment('出发地址');
+
+            $table->string('arrive_img')->nullable()->comment('到达图片');
+            $table->integer('arrive_lng')->nullable()->comment('到达经度');
+            $table->integer('arrive_lat')->nullable()->comment('到达纬度');
+            $table->string('arrive_address')->nullable()->comment('到达地址');
+
+            $table->string('address')->nullable()->comment('目的地地址');
+            $table->string('real_address')->nullable()->comment('目的地真实地址');
+            $table->integer('address_lng')->nullable()->comment('目的地经度');
+            $table->integer('address_lat')->nullable()->comment('目的地纬度');
+
+            $table->string('over_img')->nullable()->comment('撤离图片');
+            $table->integer('over_lng')->nullable()->comment('撤离经度');
+            $table->integer('over_lat')->nullable()->comment('撤离纬度');
+            $table->string('over_address')->nullable()->comment('撤离地址');
+
+            $table->integer('agent_commission_ratio')->nullable()->comment('代理佣金比例');
+            $table->decimal('agent_commission_price', 10, 2)->nullable()->comment('代理佣金金额');
+
+            $table->integer('coach_commission_ratio')->nullable()->comment('技师佣金比例');
+            $table->decimal('coach_commission_price', 10, 2)->nullable()->comment('技师佣金金额');
+            $table->decimal('company_price', 10, 2)->nullable()->comment('平台金额');
+            $table->decimal('retail_price', 10, 2)->nullable()->comment('分销金额');
+
+            $table->bigInteger('coupon_id')->nullable()->comment('优惠卷ID');
+            $table->bigInteger('channel_id')->nullable()->comment('渠道ID');
+            $table->bigInteger('channel_cate_id')->nullable()->comment('渠道ID');
+
+
+            $table->tinyInteger('extend_order')->default(0)->comment('加钟订单');
+            $table->tinyInteger('extend_order_id')->default(0)->comment('加钟订单ID');
+            $table->bigInteger('store_id')->nullable()->comment('店铺ID');
+            $table->tinyInteger('type')->default(0)->comment('订单类型');
+            $table->tinyInteger('status')->default(0)->comment('订单状态 0:未支付 1:已支付(待接单) 2:已接单 3:已出发 4:已到达 5:开始服务(服务中) 6:服务结束 7:已撤离 8:已评价 9:取消订单(退款中) 10:已退款');
+            $table->tinyInteger('user_del')->default(0)->comment('用户删除');
+            $table->tinyInteger('user_end')->default(0)->comment('用户结束订单');
+
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('service_order');
+    }
+};

+ 30 - 0
database/migrations/2024_09_23_025556_create_wechat_users_table.php

@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration {
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('wechat_users', function (Blueprint $table) {
+            $table->id();
+            $table->string('nickname')->nullable()->comment('昵称');
+            $table->string('mobile')->nullable()->comment('手机号');
+            $table->string('avatar')->nullable()->comment('头像');
+            $table->string('openid')->nullable();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('service_order');
+    }
+};

+ 77 - 3
routes/api.php

@@ -1,6 +1,17 @@
 <?php
 
 use App\Http\Controllers\Backend\Server\System\UserController;
+use App\Http\Controllers\Frontend\Client\CoachController as ClientCoachController;
+use App\Http\Controllers\Frontend\Client\Coach\UserController as ClientCoachUserController;
+use App\Http\Controllers\Frontend\Server\Coach\UserController as ServerCoachUserController;
+use App\Http\Controllers\Frontend\Client\Service\ProjectController as ClientProjectController;
+use App\Http\Controllers\Frontend\Server\Service\ProjectController as ServerProjectController;
+use App\Http\Controllers\Frontend\Client\Service\OrderController as ClientServiceOrderController;
+use App\Http\Controllers\Frontend\Client\Auth\AuthenticatedController as ClientAccountAuthController;
+use App\Http\Controllers\Frontend\Client\Service\CategoryController as ClientServiceCategory;
+use App\Http\Controllers\Frontend\Client\Member\UserController as ClientMemberUserController;
+use App\Http\Controllers\Frontend\Client\Auth\WechatAuthenticatedController as ClientWechatAuthenticatedController;
+
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Route;
 
@@ -8,14 +19,77 @@ Route::prefix('client')->group(function () {
     Route::get('/', function () {
         return ['Laravel' => 'frontend client'];
     });
+
 });
 
+
+Route::middleware(['auth:sanctum'])->get('/user', function (Request $request) {
+    return $request->user();
+});
+
+# 客户
+Route::prefix('client')->group(function () {
+    # 登录
+    Route::prefix('login')->group(function () {
+        Route::post('/',[ClientAccountAuthController::class,'store']);
+        Route::post('send',[ClientAccountAuthController::class,'send']);
+    });
+    # 微信
+    Route::prefix('wechat')->group(function () {
+        Route::get('/signature',[ClientWechatAuthenticatedController::class,'oauth']);
+        Route::post('/callback',[ClientWechatAuthenticatedController::class,'callback']);
+        Route::post('/login',[ClientWechatAuthenticatedController::class,'store']);
+        Route::post('/bind',[ClientWechatAuthenticatedController::class,'bind']);
+    });
+
+    # 首页
+    Route::prefix('service')->group(function () {
+        Route::get('category', [ClientServiceCategory::class, 'index']);
+        Route::get('project', [ClientProjectController::class, 'index']);
+        Route::get('project/{id}', [ClientProjectController::class, 'show']);
+
+
+        Route::middleware(['auth:sanctum'])->group(function (){
+            # 订单
+            Route::resource('order', ClientServiceOrderController::class);
+        });
+
+    });
+
+
+
+    Route::prefix('coach')->group(function () {
+        # 申请技师
+        Route::post('apply', [ClientCoachController::class, 'create']);
+        Route::get('/', [ClientCoachUserController::class, 'index']);
+        Route::get('/{id}', [ClientCoachUserController::class, 'show']);
+    });
+
+    Route::prefix('member')->middleware(['auth:sanctum'])->group(function () {
+        Route::get('/', [ClientMemberUserController::class, 'show']);
+        Route::delete('/', [ClientMemberUserController::class, 'destroy']);
+        Route::put('/', [ClientMemberUserController::class, 'update']);
+    });
+
+
+});
+
+# 技师端
 Route::prefix('server')->group(function () {
     Route::get('/', function () {
         return ['Laravel' => 'frontend server'];
     });
-});
 
-Route::middleware(['auth:sanctum'])->get('/user', function (Request $request) {
-    return $request->user();
+
+    Route::prefix('coach')->group(function () {
+        # 获取技师详情
+        Route::get('user', [ServerCoachUserController::class, 'show']);
+        Route::put('user', [ServerCoachUserController::class, 'update']);
+
+    });
+
+    Route::prefix('service')->group(function () {
+        Route::get('project', [ServerProjectController::class, 'index']);
+        Route::post('project', [ServerProjectController::class, 'update']);
+    });
 });

+ 15 - 0
routes/web.php

@@ -15,6 +15,8 @@ use App\Http\Controllers\Backend\Server\Member\UserController as MemberUserContr
 use App\Http\Controllers\Backend\Server\Member\ConfigController as MemberConfigController;
 use App\Http\Controllers\Backend\Server\Service\CategoryController as ServiceCategoryController;
 use App\Http\Controllers\Backend\Server\Service\ProjectController as ServiceProjectController;
+use App\Http\Controllers\Backend\Server\Coach\UserController as CoachUserController;
+use App\Http\Controllers\Backend\Server\Coach\ApplyController as CoachApplyController;
 
 use Illuminate\Support\Facades\Route;
 
@@ -38,6 +40,7 @@ Route::prefix('client')->group(function () {
 # 服务中心
 Route::prefix('service')->group(function () {
     # 服务分类
+    Route::get('category/simple', [ServiceCategoryController::class, 'simple']);
     Route::resource('category', ServiceCategoryController::class);
     # 服务项目
     Route::resource('project', ServiceProjectController::class);
@@ -53,6 +56,18 @@ Route::prefix('member')->group(function () {
 
 });
 
+# 技工中心
+Route::prefix('coach')->group(function () {
+    Route::get('user/apply/{id}', [CoachUserController::class, 'apply']);
+    Route::put('user/apply/{id}', [CoachUserController::class, 'doApply']);
+    Route::put('user/reapply/{id}', [CoachUserController::class, 'doReApply']);
+
+    Route::get('user/auth/{id}', [CoachUserController::class, 'auth']);
+    Route::put('user/auth/{id}', [CoachUserController::class, 'doAuth']);
+
+    Route::resource('user', CoachUserController::class);
+});
+
 Route::prefix('system')->group(function () {
     Route::post('auth/login', [AuthController::class, 'login']);
     Route::get('auth/get-permission-info', [AuthController::class, 'getPermissionInfo']);

部分文件因为文件数量过多而无法显示