醉梦人间三千年 6 hónapja
szülő
commit
3ed9090feb
33 módosított fájl, 1312 hozzáadás és 77 törlés
  1. 207 0
      app/Http/Common/Upload.php
  2. 16 3
      app/Http/Controllers/Frontend/Client/Auth/WechatAuthenticatedController.php
  3. 35 11
      app/Http/Controllers/Frontend/Client/Coach/UserController.php
  4. 89 0
      app/Http/Controllers/Frontend/Client/Member/AddressController.php
  5. 41 0
      app/Http/Controllers/Frontend/Client/Member/ToolController.php
  6. 23 8
      app/Http/Controllers/Frontend/Client/Member/UserController.php
  7. 7 2
      app/Http/Controllers/Frontend/Client/Service/OrderController.php
  8. 2 2
      app/Http/Requests/Backend/Server/System/UserRequest.php
  9. 71 0
      app/Http/Requests/Frontend/Client/Coach/UserRequest.php
  10. 48 0
      app/Http/Requests/Frontend/Client/Member/AddressRequest.php
  11. 57 0
      app/Http/Requests/Frontend/Client/Member/UserRequest.php
  12. 53 0
      app/Http/Requests/Frontend/Client/Service/OrderRequest.php
  13. 1 1
      app/Http/Requests/Request.php
  14. 115 2
      app/Http/Services/Frontend/Client/Auth/WechatAuthenticatedService.php
  15. 68 12
      app/Http/Services/Frontend/Client/Coach/UserService.php
  16. 101 0
      app/Http/Services/Frontend/Client/Member/AddressService.php
  17. 39 0
      app/Http/Services/Frontend/Client/Member/ToolService.php
  18. 9 0
      app/Http/Services/Frontend/Client/Member/UserService.php
  19. 25 18
      app/Http/Services/Frontend/Client/Service/OrderService.php
  20. 49 0
      app/Models/Coach/Site.php
  21. 6 1
      app/Models/Coach/User.php
  22. 44 0
      app/Models/Member/Address.php
  23. 1 1
      app/Models/Service/Order.php
  24. 43 0
      app/Models/System/Config.php
  25. 10 4
      bootstrap/app.php
  26. 1 1
      config/cors.php
  27. 2 1
      database/migrations/2024_09_10_090033_create_coach_users_table.php
  28. 1 1
      database/migrations/2024_09_23_025556_create_wechat_users_table.php
  29. 40 0
      database/migrations/2024_09_30_025556_create_coach_site_table.php
  30. 29 0
      database/migrations/2024_09_30_025556_create_system_config_table.php
  31. 39 0
      database/migrations/2024_10_01_025556_create_member_address_table.php
  32. 21 0
      database/seeders/SystemConfigTableSeeder.php
  33. 19 9
      routes/api.php

+ 207 - 0
app/Http/Common/Upload.php

@@ -0,0 +1,207 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/10/6 17:53
+ */
+
+namespace App\Http\Common;
+
+use Illuminate\Http\UploadedFile;
+use Illuminate\Support\Facades\File;
+use Illuminate\Support\Facades\Storage;
+use Illuminate\Support\Facades\Validator;
+
+class Upload
+{
+    protected $request;
+    protected $config;//配置
+    protected $uniacid;
+    protected $path_type;//图片  音频   视频
+    protected $attachment_model;
+    protected $is_weiqin = false;
+
+    /**
+     * 架构函数
+     * @access public
+     */
+    public function __construct()
+    {
+
+    }
+
+    //上传
+    public function upload($type, UploadedFile $file, $config = array(), string $is_check = '')
+    {
+        if (!empty($config)) $this->config = $config;
+
+        $base_path = '';
+        switch ($type) {
+            //图片
+            //音频
+            case 'audio':
+                $base_path .= 'audio/';
+                $type_data = 2;
+                break;
+            //视频
+            case 'video':
+                $base_path .= 'video/';
+                $type_data = 3;
+                break;
+            //证书
+            case 'cert':
+                $base_path .= 'cert/';
+                $type_data = 4;
+                break;
+            //证书
+//            case 'wxuploadkey':
+//                $base_path .= 'wxuploadkey/';
+//                $type_data = 4;
+//                break;
+            //证书
+            case 'file':
+                $base_path .= 'file/';
+                $type_data = 6;
+                break;
+            case 'picture':
+            default:
+                $base_path .= 'images/';
+                $type_data = 1;
+                break;
+        }
+        //根据时间生成路径
+        $base_path = $base_path . date("y/m/d") . '/';
+        $info = null;
+        $upload_status = false;
+
+        //数据检查
+        if ($this->checkFile($type, $file, $is_check)) {
+            $file_name = null;
+            //本地保存
+//            if (in_array($type, ['cert', 'wxuploadkey'])) {
+//                $file_name = $this->uniacid . '_' . $file->getOriginalName();
+//                $this->config['open_oss'] = 0;
+//            }
+
+            $file_name .= $is_check;
+
+            $info_path = $this->fileLoaclSave($base_path, $file, $file_name);
+            //获取数据
+            $info = $this->fileInfo($info_path, $file->getClientOriginalName() . $is_check, $type_data);
+            //云服务器上传
+            if (isset($this->config['open_oss'])) {
+                /* switch ($this->config['open_oss']) {
+                     //本地
+                     case 0:
+                         $upload_status = true;
+                         $info['longbing_driver'] = 'loacl';
+                         break;
+                     case 1:
+                         $oss_res = $this->aliyunUpload($info_path);
+
+                         if (isset($this->config['aliyun_base_dir']) && !empty($this->config['aliyun_base_dir'])) $info_path = $this->config['aliyun_base_dir'] . '/' . $info_path;
+                         if (in_array(substr($info_path, 0, 1), ['/', "/"])) {
+                             $info_path = substr($info_path, 1, (strlen($info_path) - 1));
+                         }
+                         $info['attachment'] = $info_path;
+                         $info['longbing_driver'] = 'aliyun';
+                         if (isset($oss_res['info']['url'])) $upload_status = true;
+                         break;
+                     case 2:
+                         $oss_res = $this->qiniuUpload($info_path);
+                         $info['longbing_driver'] = 'qiniuyun';
+                         if (!empty($oss_res) && empty($oss_res[1])) $upload_status = true;
+                         break;
+                     case 3:
+                         $oss_res = $this->tenxunUpoload($info_path);
+
+                         $info['longbing_driver'] = 'tengxunyun';
+                         if (isset($oss_res['ETag']) && isset($oss_res['ObjectURL'])) $upload_status = true;
+                         break;
+                     default:
+                         $info['longbing_driver'] = 'loacl';
+                         $upload_status = true;
+                         break;
+                 }*/
+            } else {
+                $upload_status = true;
+                $info['driver'] = 'local';
+            }
+        }
+        if (!$upload_status) $info = null;
+        return $info;
+    }
+
+
+    public function checkFile($type, $file, bool $is_check = false)
+    {
+        $validator = new Validator();
+        switch ($type) {
+            case 'picture':
+                $validator = Validator::make(['file' => $file], [
+                    'file' => 'required|file|mimes:jpg,jpeg,png,webp|max:2048',
+                    [
+                        '*' => '文件错误'
+                    ]
+                ]);
+//                $result = validate(['file' => ['fileSize' => 10 * 1024 * 1024, 'fileExt' => 'jpg,jpeg,bmp,png,image,gif']])->check(['file' => $file]);
+                break;
+            case 'audio':
+                $check = empty($is_check) ? 'mp3,wma,wav,m4a' : '';
+//                $result = validate(['file' => ['fileSize' => 50 * 1024 * 1024, 'fileExt' => $check]])->check(['file' => $file]);
+                break;
+            case 'video':
+//                $result = validate(['file' => ['fileSize' => 50 * 1024 * 1024, 'fileExt' => 'wmv,mp4,mp3,avi,mpg,rmvb,MPEG-4,MPEG,MOV,3GP,MPV,quicktime,Quicktime,mov']])->check(['file' => $file]);
+                break;
+            case 'cert':
+//                $result = validate(['file' => ['fileSize' => 50 * 1024 * 1024, 'fileExt' => 'cert,pem']])->check(['file' => $file]);
+                break;
+//            case 'wxuploadkey':
+//                $result = validate(['file' => ['fileSize' => 50 * 1024 * 1024, 'fileExt' => 'cert,pem']])->check(['file' => $file]);
+//                break;
+            case 'file':
+//                $result = validate(['file' => ['fileSize' => 50 * 1024 * 1024, 'fileExt' => 'doc,xls,docx,xlsx,ppt,pptx,pdf']])->check(['file' => $file]);
+                break;
+            default:
+                break;
+        }
+        if ($validator->fails()) {
+            return false;
+        }
+        return true;
+    }
+
+    //本地保存
+    public function fileLoaclSave($path, UploadedFile $file, $file_name = ''): string
+    {
+        if (!$file_name) $file_name = $file->hashName();
+
+//        $storagePath = Storage::disk('public')->path($path);
+
+        // 检查文件夹是否存在,如果不存在,则创建文件夹
+        if (!Storage::disk('public')->exists($path)) {
+            Storage::disk('public')->makeDirectory($path);
+        }
+
+//        if (!is_dir($storagePath)) {
+//            mkdir($storagePath, 0775, true);
+//        }
+
+        //保存
+        Storage::disk('public')->putFileAs($path, $file, $file_name);
+        return Storage::url($path . $file_name);
+    }
+
+    //生成返回数据
+    public function fileInfo($path, $file_name, $type_data)
+    {
+        $result = array(
+            'attachment' => ltrim($path, '/'),
+            'filename' => $file_name,
+            'createtime' => time(),
+            'type' => $type_data
+        );
+        return $result;
+    }
+}

+ 16 - 3
app/Http/Controllers/Frontend/Client/Auth/WechatAuthenticatedController.php

@@ -58,7 +58,7 @@ class WechatAuthenticatedController extends Controller
      */
     public function store(Request $request): JsonResponse
     {
-        $params = $request->only(['open_id']);
+        $params = $request->only(['open_id', 'auto_register']);
         $res = $this->wechatAuthenticatedService->store($params);
         return self::success($res);
     }
@@ -74,7 +74,7 @@ class WechatAuthenticatedController extends Controller
     }
 
     // 发送短信
-    public function send(Request $request): Response
+    public function send(Request $request): JsonResponse
     {
         $request->validate([
             'mobile' => ['required', 'regex:/^1[345789][0-9]{9}$/']
@@ -82,6 +82,19 @@ class WechatAuthenticatedController extends Controller
             'mobile.required' => '手机号不能为空!',
             'mobile.regex' => '手机号码格式不正确!'
         ]);
-        return (new WechatAuthenticatedService())->send($request->only(['mobile']));
+        $this->wechatAuthenticatedService->send($request->only(['mobile']));
+        return self::success(true);
+    }
+
+    /**
+     * Notes :
+     * Method : 公众号签名
+     * @throws ApiException
+     */
+    public function signature(Request $request): JsonResponse
+    {
+        $res = $this->wechatAuthenticatedService->getSignature($request->only(['url']));
+        return self::success($res);
     }
+
 }

+ 35 - 11
app/Http/Controllers/Frontend/Client/Coach/UserController.php

@@ -2,33 +2,57 @@
 
 namespace App\Http\Controllers\Frontend\Client\Coach;
 
+use App\Exceptions\ApiException;
 use App\Http\Controllers\Controller;
+use App\Http\Requests\Frontend\Client\Coach\UserRequest;
 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;
+    protected UserService $service;
 
-    public function __construct(UserService $userService)
+    public function __construct(UserService $service)
     {
-        $this->userService = $userService;
+        $this->service = $service;
     }
 
-    public function index(Request $request): JsonResponse
+    /**
+     * Notes :
+     * Method : 技师列表
+     * @param UserRequest $request
+     * @return JsonResponse
+     */
+    public function index(UserRequest $request): JsonResponse
     {
         // 处理首页逻辑
-        $params = $request->all();
-        $result = $this->userService->getUserPage($params);
+        $result = $this->service->getUserPage($request->safe()->toArray());
         return self::success($result);
     }
 
-    public function show(Request $request, int $id): JsonResponse
+    /**
+     * Notes :
+     * Method : 技师详情
+     * @param UserRequest $request
+     * @param int $id
+     * @return JsonResponse
+     */
+    public function show(UserRequest $request, int $id): JsonResponse
     {
-        $params = $request->all();
-        $result = $this->userService->getUser($params, $id);
+        $result = $this->service->getUser($request->safe()->toArray(), $id);
         return self::success($result);
     }
+
+    /**
+     * Notes :
+     * Method : 技师申请
+     * @param UserRequest $request
+     * @return JsonResponse
+     * @throws ApiException
+     */
+    public function apply(UserRequest $request): JsonResponse
+    {
+        $this->service->apply($request->safe()->toArray());
+        return self::success(true);
+    }
 }

+ 89 - 0
app/Http/Controllers/Frontend/Client/Member/AddressController.php

@@ -0,0 +1,89 @@
+<?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\Frontend\Client\Member\AddressRequest;
+use App\Http\Requests\Frontend\Client\Member\UserRequest;
+use App\Http\Requests\Request;
+use App\Http\Services\Frontend\Client\Auth\AuthenticatedService;
+use App\Http\Services\Frontend\Client\Member\AddressService;
+use App\Http\Services\Frontend\Client\Member\UserService;
+use Illuminate\Http\JsonResponse;
+
+class AddressController extends Controller
+{
+    protected AddressService $service;
+
+    public function __construct(AddressService $service)
+    {
+        $this->service = $service;
+    }
+
+    /**
+     * Notes :
+     * Method : 用户地址列表
+     * @return JsonResponse
+     */
+    public function index(): JsonResponse
+    {
+        return self::success($this->service->getAddressList());
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function store(AddressRequest $request): JsonResponse
+    {
+        return self::success($this->service->createAddress($request->safe()->toArray()));
+    }
+
+    /**
+     * Notes :
+     * Method : 用户地址详情
+     * @param $address_id
+     * @return JsonResponse
+     */
+    public function show($address_id): JsonResponse
+    {
+        return self::success($this->service->getAddress($address_id));
+    }
+
+    /**
+     * Notes :
+     * Method : 更新用户信息
+     * @param AddressRequest $request
+     * @param $address_id
+     * @return JsonResponse
+     * @throws ApiException
+     */
+    public function update(AddressRequest $request, $address_id): JsonResponse
+    {
+        $params = $request->safe()->toArray();
+        $this->service->updateAddress($params, $address_id);
+        return self::success(true);
+    }
+
+    /**
+     * Notes :
+     * Method : 注销用户
+     */
+    public function destroy(int $id): JsonResponse
+    {
+        $this->service->delAddress($id);
+        return self::success(true);
+    }
+
+    public function default(): JsonResponse
+    {
+        return self::success($this->service->getDefault());
+    }
+
+}

+ 41 - 0
app/Http/Controllers/Frontend/Client/Member/ToolController.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/26 11:58
+ */
+
+namespace App\Http\Controllers\Frontend\Client\Member;
+
+use App\Exceptions\ApiException;
+use App\Http\Common\Upload;
+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\ToolService;
+use App\Http\Services\Frontend\Client\Member\UserService;
+use Illuminate\Http\JsonResponse;
+
+class ToolController extends Controller
+{
+    protected ToolService $service;
+
+    public function __construct(ToolService $service)
+    {
+        $this->service = $service;
+    }
+
+    /**
+     */
+    public function upload(Request $request): JsonResponse
+    {
+        $params = $request->all();
+//        $path = $request->file('file')->store('public/images');
+//
+        $file = $request->file('file');
+
+        return self::success($this->service->uploadFile($params,$file));
+    }
+
+}

+ 23 - 8
app/Http/Controllers/Frontend/Client/Member/UserController.php

@@ -10,6 +10,7 @@ namespace App\Http\Controllers\Frontend\Client\Member;
 
 use App\Exceptions\ApiException;
 use App\Http\Controllers\Controller;
+use App\Http\Requests\Frontend\Client\Member\UserRequest;
 use App\Http\Requests\Request;
 use App\Http\Services\Frontend\Client\Auth\AuthenticatedService;
 use App\Http\Services\Frontend\Client\Member\UserService;
@@ -17,24 +18,33 @@ use Illuminate\Http\JsonResponse;
 
 class UserController extends Controller
 {
-    protected UserService $userService;
+    protected UserService $service;
 
-    public function __construct(UserService $userService)
+    public function __construct(UserService $service)
     {
-        $this->userService = $userService;
+        $this->service = $service;
     }
 
     /**
+     * Notes :
+     * Method : 用户信息
+     * @return JsonResponse
      */
-    public function show(Request $request): JsonResponse
+    public function show(): JsonResponse
     {
-        return self::success($this->userService->getUser());
+        return self::success($this->service->getUser());
     }
 
-    public function update(Request $request): JsonResponse
+    /**
+     * Notes :
+     * Method : 更新用户信息
+     * @param UserRequest $request
+     * @return JsonResponse
+     */
+    public function update(UserRequest $request): JsonResponse
     {
         $params = $request->all();
-        $this->userService->updateUser($params);
+        $this->service->updateUser($params);
         return self::success(true);
     }
 
@@ -44,8 +54,13 @@ class UserController extends Controller
      */
     public function destroy(Request $request): JsonResponse
     {
-        $this->userService->delUser($request);
+        $this->service->delUser($request);
         return self::success(true);
     }
 
+    public function address(): JsonResponse
+    {
+        return self::success($this->service->address());
+    }
+
 }

+ 7 - 2
app/Http/Controllers/Frontend/Client/Service/OrderController.php

@@ -8,8 +8,10 @@
 
 namespace App\Http\Controllers\Frontend\Client\Service;
 
+use App\Exceptions\ApiException;
 use App\Http\Controllers\Controller;
 use App\Http\Controllers\Frontend\Client\Order\Config;
+use App\Http\Requests\Frontend\Client\Service\OrderRequest;
 use App\Http\Requests\Request;
 use App\Http\Services\Frontend\Client\Service\OrderService;
 use App\Models\Coach\User;
@@ -33,9 +35,12 @@ class OrderController extends Controller
         return self::success($res);
     }
 
-    public function store(Request $request): JsonResponse
+    /**
+     * @throws ApiException
+     */
+    public function store(OrderRequest $request): JsonResponse
     {
-        $params = $request->all();
+        $params = $request->safe()->toArray();
         $res = $this->orderService->createOrder($params);
         return self::success($res);
     }

+ 2 - 2
app/Http/Requests/Backend/Server/System/UserRequest.php

@@ -34,8 +34,8 @@ class UserRequest extends Request
     public function messages(): array
     {
         return [
-            'name.required' => '请输入用户账号!',
-            'name.unique' => '用户账号已存在!',
+            'username.required' => '请输入用户账号!',
+            'username.unique' => '用户账号已存在!',
             'password.required' => '请输入用户密码!',
             'password.confirmed' => '两次输入密码不一致!',
             'password.min' => '密码最少8位字符'

+ 71 - 0
app/Http/Requests/Frontend/Client/Coach/UserRequest.php

@@ -0,0 +1,71 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/3/20 14:54
+ */
+
+namespace App\Http\Requests\Frontend\Client\Coach;
+
+use App\Http\Requests\Request;
+use Illuminate\Support\Facades\Route;
+use Illuminate\Validation\Rule;
+
+class UserRequest extends Request
+{
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array<string, array|string>
+     */
+    public function rules(): array
+    {
+        $rules = [
+            'categoryId' => ['bail', 'integer'],
+            'sort' => ['bail', 'string', Rule::in(['order', 'distance'])]
+        ];
+
+        $actionName = last(explode('@', Route::current()->getActionName()));
+        if ($actionName === 'index') {
+            $rules = [
+                'cityCode' => ['bail', 'required', 'string'],
+                'distance' => ['bail', 'integer', 'between:1,10'],
+                'lat' => ['bail', 'required', 'string'],
+                'lng' => ['bail', 'required', 'string'],
+            ];
+        }
+        if($actionName === 'show'){
+            $rules = [
+                'categoryId' => ['bail', 'integer'],
+                'lat' => ['bail', 'required', 'string'],
+                'lng' => ['bail', 'required', 'string'],
+            ];
+        }
+        if ($actionName === 'apply') {
+            $rules = [
+                'name' => ['bail', 'required', 'string', 'max:50'],
+                'sex' => ['bail', 'required', 'integer', Rule::in([0, 1])],
+                'birthday' => ['bail', 'nullable', 'string'],
+                'mobile' => ['bail', 'nullable', 'string'],
+                'city' => ['bail', 'nullable', 'string'],
+                'workImg' => ['bail', 'required', 'nullable', 'string'],
+            ];
+        }
+
+        return $rules;
+    }
+
+    public function messages(): array
+    {
+        return [
+            'name.required' => '姓名不能为空!',
+            'workImg.bail' => '工作照不能为空!',
+            'workImg.required' => '工作照不能为空!',
+            'workImg.nullable' => '工作照不能为空!1',
+            'sex.required' => '性别不能为空!',
+            'sex.in' => '性别取值范围错误!',
+            '*' => '参数或类型错误!'
+        ];
+    }
+}

+ 48 - 0
app/Http/Requests/Frontend/Client/Member/AddressRequest.php

@@ -0,0 +1,48 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/3/20 14:54
+ */
+
+namespace App\Http\Requests\Frontend\Client\Member;
+
+use App\Http\Requests\Request;
+use Illuminate\Support\Facades\Route;
+use Illuminate\Validation\Rule;
+
+class AddressRequest extends Request
+{
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array<string, array|string>
+     */
+    public function rules(): array
+    {
+        $rules = [
+
+            'userName' => ['bail', 'string'],
+            'mobile' => ['bail', 'required', 'string'],
+            'address' => ['bail', 'required', 'string'],
+            'addressInfo' => ['bail', 'required', 'string'],
+            'lat' => ['bail', 'required', 'string'],
+            'lng' => ['bail', 'required', 'string'],
+            'cityCode' => ['bail', 'required', 'string'],
+            'status' => ['bail', 'required', 'integer', Rule::in([0, 1])],
+            'sex' => ['bail', 'required', 'integer', Rule::in([0, 1])],
+        ];
+
+        $actionName = last(explode('@', Route::current()->getActionName()));
+
+        return $rules;
+    }
+
+    public function messages(): array
+    {
+        return [
+            '*' => '参数或类型错误!'
+        ];
+    }
+}

+ 57 - 0
app/Http/Requests/Frontend/Client/Member/UserRequest.php

@@ -0,0 +1,57 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/3/20 14:54
+ */
+
+namespace App\Http\Requests\Frontend\Client\Member;
+
+use App\Http\Requests\Request;
+use Illuminate\Support\Facades\Route;
+use Illuminate\Validation\Rule;
+
+class UserRequest extends Request
+{
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array<string, array|string>
+     */
+    public function rules(): array
+    {
+        $rules = [
+            'categoryId' => ['bail', 'required', 'integer'],
+            'sort' => ['bail', 'string', Rule::in(['order', ''])]
+        ];
+
+        $actionName = last(explode('@', Route::current()->getActionName()));
+
+        if ($actionName === 'update') {
+            $rules = [
+                'name' => ['bail', 'required', 'string', 'max:50'],
+                'sex' => ['bail', 'required', 'integer', Rule::in([0, 1])],
+                'birthday' => ['bail', 'nullable', 'string'],
+                'mobile' => ['bail', 'nullable', 'string'],
+                'city' => ['bail', 'nullable', 'string'],
+                'workImg' => ['bail', 'required', 'nullable', 'string'],
+            ];
+        }
+        return $rules;
+    }
+
+    public function messages(): array
+    {
+        return [
+            'categoryId.required' => '项目分类不能为空!',
+            'name.required' => '姓名不能为空!',
+            'workImg.bail' => '工作照不能为空!',
+            'workImg.required' => '工作照不能为空!',
+            'workImg.nullable' => '工作照不能为空!1',
+            'sex.required' => '性别不能为空!',
+            'sex.in' => '性别取值范围错误!',
+            '*' => '参数或类型错误!'
+        ];
+    }
+}

+ 53 - 0
app/Http/Requests/Frontend/Client/Service/OrderRequest.php

@@ -0,0 +1,53 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/3/20 14:54
+ */
+
+namespace App\Http\Requests\Frontend\Client\Service;
+
+use App\Http\Requests\Request;
+use Illuminate\Support\Facades\Route;
+use Illuminate\Validation\Rule;
+
+class OrderRequest extends Request
+{
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array<string, array|string>
+     */
+    public function rules(): array
+    {
+        $rules = [
+            'coachId' => ['bail', 'integer'],
+            'projectId' => ['bail', 'required', 'integer'],
+            'couponId' => ['bail', 'integer'],
+            'orderId' => ['bail', 'string'],
+            'payType' => ['bail', 'required', 'string'],
+            'addressId' => ['bail', 'required', 'integer'],
+        ];
+
+        $actionName = last(explode('@', Route::current()->getActionName()));
+        if ($actionName === 'index') {
+
+        }
+        if($actionName === 'show'){
+
+        }
+        if ($actionName === 'apply') {
+
+        }
+
+        return $rules;
+    }
+
+    public function messages(): array
+    {
+        return [
+            '*' => '参数或类型错误!'
+        ];
+    }
+}

+ 1 - 1
app/Http/Requests/Request.php

@@ -20,7 +20,7 @@ class Request  extends FormRequest
         $firstError = $validator->errors()->first();
         throw new ApiException([
             'message' => $firstError,
-            "status" => Response::HTTP_UNPROCESSABLE_ENTITY
+            "code" => Response::HTTP_UNPROCESSABLE_ENTITY
         ]);
     }
 }

+ 115 - 2
app/Http/Services/Frontend/Client/Auth/WechatAuthenticatedService.php

@@ -17,7 +17,9 @@ use App\Models\WechatUser;
 use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Response;
+use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Str;
 use Overtrue\LaravelWeChat\EasyWeChat;
 
 class WechatAuthenticatedService extends Service
@@ -115,7 +117,8 @@ class WechatAuthenticatedService extends Service
         $openID = $data['open_id'];
         $autoRegister = $data['auto_register'] ?? 0;
 
-        $user = User::query()->where('open_id', $openID)->first();
+        $user = User::query()->where('openid', $openID)->first();
+
         if (!$user && $autoRegister) {
             // 获取微信信息
             // 创建用户信息
@@ -138,7 +141,7 @@ class WechatAuthenticatedService extends Service
 
         // 绑定公众号
         $user = User::query()->where($where)->first();
-        $user->open_id = $data['open_id'];
+        $user->open_id = $data['openid'];
         $user->save();
         return (new AuthService)->store($user);
 
@@ -151,4 +154,114 @@ class WechatAuthenticatedService extends Service
         $sms = new SmsService();
         return $sms->send($mobile, 0, 2);
     }
+
+
+    /**
+     * 公众号签名
+     * @throws ApiException
+     */
+    public function getSignature(array $data): array
+    {
+        $wechat = EasyWeChat::officialAccount();
+        $ticket = $wechat->getTicket();
+        $jsapi_ticket = $ticket->getTicket();
+
+        // 当前URL
+        $url = request('url',request()->header('referer'));
+
+        // 生成签名
+        $nonceStr = 'xiaoding'.Str::random(20); // 请用随机算法生成
+        $timestamp = time(); // 当前时间戳
+
+        $signatureStr = "jsapi_ticket={$jsapi_ticket}&noncestr={$nonceStr}&timestamp={$timestamp}&url={$url}";
+
+        $signature = sha1($signatureStr);
+
+        $wechatConfig = $wechat->getConfig();
+
+        // 数据用于前端显示
+        $signPackage = [
+            "appId" => $wechatConfig['app_id'],
+            "nonceStr" => $nonceStr,
+            "timestamp" => $timestamp,
+            "url" => $url,
+            "signature" => $signature,
+            "rawString" => $signatureStr
+        ];
+
+
+//        $sign = $this->makeSha1Sign($signData); // 生成微信签名
+//
+//        $signData['signature'] = $sign;
+
+        return $signPackage;
+//
+//
+//        $access_token = $this->getAccessToken();
+//
+//        // 这里的$token就是你在微信公众平台设置的Token
+//        // 这里的$timestamp就是时间戳
+//        // 这里的$nonce就是随机数
+//        // 这里的$msg就是发送给微信服务器的数据
+//
+//        // 将token、timestamp、nonce三个参数按字典序排序
+//        $array = array($token, $timestamp, $nonce, $msg);
+//        sort($array, SORT_STRING);
+//
+//        // 将排序后的三个参数拼接成一个字符串
+//        $str = implode($array);
+//
+//        // 使用sha1算法计算出摘要
+//        $signature = sha1($str);
+//
+//        // 转换成小写
+//        $signature = strtolower($signature);
+//
+//        return $signature;
+    }
+
+    //生成 sha1 签名
+    private function makeSha1Sign($array): string
+    {
+        //升序数组的键
+        ksort($array);
+        $params = urldecode(http_build_query($array));
+
+        //字符串SHA1
+        return sha1($params);
+    }
+
+    //获取微信access_token
+
+    /**
+     * @throws ApiException
+     */
+    private function getAccessToken()
+    {
+        $tokeUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . config('easywechat.official_account.default.app_id') . "&secret=" . config('easywechat.official_account.default.secret');
+        $tokenResp = file_get_contents($tokeUrl);
+        !$tokenResp && self::error('token 服务器返回失败');
+        $tokenData = json_decode($tokenResp, true);
+        if (!isset($tokenData['access_token'])) self::error($tokenData['errmsg']);
+        return $tokenData['access_token'];
+    }
+
+    //获取微信ticket
+
+    /**
+     * @throws ApiException
+     */
+    private function getTicket($access_token)
+    {
+        $ticketUrl = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . $access_token . '&type=jsapi';
+        $ticketResp = file_get_contents($ticketUrl);
+        if (!$ticketResp) return self::error('ticket 获取失败');
+        $ticketData = json_decode($ticketResp, true);
+
+        if (!isset($ticketData['ticket'])) return self::error('ticket 解析错误');
+
+        $ticket = $ticketData['ticket'];
+        cache::set('wechart_share_ticket', $ticket, 7200);
+        return $ticket;
+    }
 }

+ 68 - 12
app/Http/Services/Frontend/Client/Coach/UserService.php

@@ -8,10 +8,13 @@
 
 namespace App\Http\Services\Frontend\Client\Coach;
 
+use App\Enums\Common\Status;
+use App\Exceptions\ApiException;
 use App\Http\Services\Service;
+use App\Models\Coach\Site;
 use App\Models\Coach\User;
-use App\Models\Service\Category;
 use App\Models\Service\Project;
+use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
 
 class UserService extends Service
@@ -22,29 +25,82 @@ class UserService extends Service
     public function getUserPage($params): array
     {
         $category_id = $params['categoryId'] ?? 1;
+        $sort = $params['sort'] ?? 'order';
 
+        // 给定的中心点坐标
+        $latitude = $params['lat'] ?? 0;
+        $longitude = $params['lng'] ?? 0;
+        // 城市区域
+        $cityCode = $params['cityCode'];
+        // 距离
+        $distance = $params['params'] ?? 10;
+
+
+        // 获取项目分类包含
         $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');
+        // 获取项目
+        $project_ids = Project::query()->whereIn('id', $project_ids)->where('status', Status::ENABLE)->pluck('id');
+        // 获取开通项目技师
         $coach_ids = DB::table('service_project_has_coach')->whereIn('project_id', $project_ids)->pluck('coach_id');
 
+        // 获取定位区域技师
+        $coach_ids = Site::query()->where('city_code', $cityCode)->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()];
+        $coachQuery = User::query()->whereIn('id', $coach_ids)->where($userWhere);
 
-//        $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()];
+        // 获取技师距离
+        $coachQuery->withWhereHas('site', function ($query) use ($latitude, $longitude, $sort, $distance) {
+            $r = 6370.996; // 地球半径
+            // 距离,单位为公里或英里,这里以公里为单位
+            $distanceRaw = "($r * acos(cos(radians($latitude)) * cos(radians(latitude)) * cos(radians(longitude) - radians($longitude)) + sin(radians($latitude)) * sin(radians(latitude))))";
+            $query->selectRaw("coach_id,round($distanceRaw,1) as distance");
+            $sort === 'distance' && $query->having('distance', '<=', $distance);
+        });
+        // 订单排序
+        $sort === 'order' && $coachQuery->orderByDesc('total_order_num');
+        $coachQuery->select($this->select_column);
+
+
+        $userPage = $coachQuery->paginate();
+        return ['list' => $userPage->items(), 'total' => $userPage->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);
+        $latitude = $params['lat'];
+        $longitude = $params['lng'];
+        $coachQuery = User::query()->select([...$this->select_column, ...$this->show_column]);
+
+        // 获取技师距离
+        $coachQuery->withWhereHas('site', function ($query) use ($latitude, $longitude) {
+            $r = 6370.996; // 地球半径
+            // 距离,单位为公里或英里,这里以公里为单位
+            $distanceRaw = "($r * acos(cos(radians($latitude)) * cos(radians(latitude)) * cos(radians(longitude) - radians($longitude)) + sin(radians($latitude)) * sin(radians(latitude))))";
+            $query->selectRaw("coach_id,round($distanceRaw,1) as distance");
+        });
+        $user = $coachQuery->find($id);
         $category_id && ($user['project'] = $user->getProject($category_id));
         return $user;
     }
+
+    /**
+     * Notes :
+     * Method : 申请技师
+     * @param array $params
+     * @param int $user_id
+     * @throws ApiException
+     */
+    public function apply(array $params)
+    {
+        $user_id = Auth::id();
+        // 判断技师资格是否已申请
+        $isExists = User::query()->where('user_id', $user_id)->exists();
+        if ($isExists) self::error('用户已经申请');
+
+        $params['user_id'] = $user_id;
+        // 判断邀请人$input['partner_id']
+        $user = self::toModel($params, User::class);
+        return User::query()->create($user->getAttributes())->id;
+    }
 }

+ 101 - 0
app/Http/Services/Frontend/Client/Member/AddressService.php

@@ -0,0 +1,101 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/27 12:05
+ */
+
+namespace App\Http\Services\Frontend\Client\Member;
+
+use App\Exceptions\ApiException;
+use App\Http\Requests\Request;
+use App\Http\Services\Frontend\Client\Common\AuthService;
+use App\Http\Services\Service;
+use App\Models\Member\Address;
+use App\Models\Member\User;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\DB;
+
+class AddressService extends Service
+{
+    protected array $select_column = ['id', 'user_name', 'mobile', 'address', 'lat', 'lng', 'status'];
+
+    public function getAddressList()
+    {
+        $id = Auth::id();
+        return Address::query()->where('user_id', $id)->select($this->select_column)->get();
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function createAddress(array $params)
+    {
+        $user_id = Auth::id();
+        $params['user_id'] = $user_id;
+        DB::beginTransaction();
+
+        try {
+            // 判断状态
+            if ($params['status']) {
+                // 更改所有地址状态为0
+                Address::query()->where('user_id', $user_id)->update(['status' => 0]);
+            }
+            $address = self::toModel($params, Address::class);
+            $admin_id = Address::query()->create($address->getAttributes())->id;
+            DB::commit();
+            return $admin_id;
+        } catch (\Exception) {
+            DB::rollBack();
+            self::error('操作失败');
+        }
+
+    }
+
+    public function getAddress(int $address_id)
+    {
+        $id = Auth::id();
+        return Address::query()->where('user_id', $id)->select($this->select_column)->find($address_id);
+    }
+
+    /**
+     * @throws ApiException
+     */
+    public function updateAddress(array $data, int $id): void
+    {
+        $user_id = Auth::id();
+        $data['user_id'] = $user_id;
+
+        DB::beginTransaction();
+        try {
+            // 判断状态
+            if ($data['status']) {
+                // 更改所有地址状态为0
+                Address::query()->where('user_id', $user_id)->update(['status' => 0]);
+            }
+
+            $user = self::toModel(['id' => $id, ...$data], Address::class);
+            $user->save();
+            DB::commit();
+        } catch (\Exception) {
+            DB::rollBack();
+            self::error('操作失败');
+        }
+
+    }
+
+    public function delAddress($id): void
+    {
+        $user_id = Auth::id();
+        $user = Address::query()->where('user_id', $user_id)->find($id);
+        $user->delete();
+    }
+
+    public function getDefault()
+    {
+        $user_id = Auth::id();
+        $where = ['user_id' => $user_id, 'status' => 1];
+        return Address::query()->where($where)->select($this->select_column)->first();
+    }
+}

+ 39 - 0
app/Http/Services/Frontend/Client/Member/ToolService.php

@@ -0,0 +1,39 @@
+<?php
+/**
+ * @Name
+ * @Description
+ * @Author 刘学玺
+ * @Date 2024/9/27 12:05
+ */
+
+namespace App\Http\Services\Frontend\Client\Member;
+
+use App\Http\Common\Upload;
+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\Http\UploadedFile;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\DB;
+
+class ToolService extends Service
+{
+    protected array $select_column = ['id', 'mobile', 'nickname', 'avatar', 'name', 'sex', 'birthday', 'mark', 'point'];
+
+    public function uploadFile(array $params, UploadedFile $file)
+    {
+        $info = (new Upload())->upload($params['type'], $file);
+        $result = null;
+
+        if ($info) {
+            //  $attachment_model = new CoreAttachment();
+            //  $result = $attachment_model->createAttach($info);
+            if ($info['driver'] === 'local') {
+                $result = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $info['attachment'];
+            }
+        }
+
+        return $result;
+    }
+}

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

@@ -11,6 +11,7 @@ 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\Address;
 use App\Models\Member\User;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
@@ -37,4 +38,12 @@ class UserService extends Service
         $user = User::query()->find(Auth::id());
         $user->delete();
     }
+
+    public function address()
+    {
+        $id = Auth::id();
+        $where = ['user_id' => $id, 'status' => 1];
+        $select = ['user_name', 'mobile', 'address', 'lat', 'lng', 'status'];
+        return Address::query()->where($where)->select($select)->first();
+    }
 }

+ 25 - 18
app/Http/Services/Frontend/Client/Service/OrderService.php

@@ -11,6 +11,7 @@ namespace App\Http\Services\Frontend\Client\Service;
 use App\Exceptions\ApiException;
 use App\Http\Services\Service;
 use App\Models\Coach\User;
+use App\Models\Member\Address;
 use App\Models\Service\Order;
 use Illuminate\Support\Facades\Auth;
 
@@ -29,12 +30,17 @@ class OrderService extends Service
      */
     public function createOrder(array $params)
     {
-        $params['user_id'] = Auth::id();
+        $data = ['user_id' => Auth::id()];
         // 用户地址
-        $params['address'] = '默认地址';
-//        $address_model       = new Address();
-        $address = ['lat' => 0, 'lng' => 0, 'area_id' => 0];
+        $address = Address::query()->where('user_id', $data['user_id'])->find($params['addressId']);
+        !$address && self::error('地址信息错误');
+        $data['address'] = $address['address'];
+        $data['real_address'] = $address['addressInfo'];
+        $data['address_lat'] = $address['lat'];
+        $data['address_lng'] = $address['lng'];
+
         // 优惠卷
+//        if ($params['couponId']) $data['coupon_id'] = $params['couponId'];
 //        $coupon_record_model = new CouponRecord();
 
 
@@ -45,26 +51,26 @@ class OrderService extends Service
 //        $input['channel_id'] = $channel_model->getChannelId($this->_user['id']);
 
         // 订单号
-        $order_id = !empty($params['order_id']) ? $params['order_id'] : 0;
+        $order_id = $params['orderId'] ?? null;
 
         // 使用余额
-        $use_balance = $params['use_balance'] ?? 0;
+        $use_balance = $params['useBalance'] ?? 0;
 
         // 出行方式
-        $car_type = $params['car_type'] ?? 0;
+        $car_type = $params['carType'] ?? 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('该技师已下架');
+        $coach_id = $params['coachId'] ?? null;
+        if ($coach_id) {
+            $coach_model = new User();
+            $coach_info = $coach_model->info($coach_id);
+            !$coach_info && self::error('技师不存在');
+            !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;
+        $coupon_id = $params['couponId'] ?? 0;
 
         // 加钟订单
         if ($order_id) {
@@ -78,7 +84,8 @@ class OrderService extends Service
         }
 
         $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);
+        $orderPayInfo = $orderModel->buildPayInfo($data['user_id'], $params['projectId'], $address['city_code'], $address['lat'], $address['lng'], $use_balance, $coach_id, $car_type, $coupon_id, $order_id);
+
 
         //默认微信
         $payType = $params['pay_type'] ?? 1;
@@ -86,8 +93,8 @@ class OrderService extends Service
 
         $orderData = [
             'order_sn' => $this->buildOrderSN(),
-            'user_id' => $params['user_id'],
             'pay_type' => $payType,
+            ...$data,
             ...$orderPayInfo,
             //备注
 //            'text' => $params['text'] ?: '',

+ 49 - 0
app/Models/Coach/Site.php

@@ -0,0 +1,49 @@
+<?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 Site extends Model
+{
+    use HasFactory, Notifiable;
+
+    protected $table = 'coach_site';
+
+    /**
+     * 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'
+        ];
+    }
+
+}

+ 6 - 1
app/Models/Coach/User.php

@@ -66,7 +66,7 @@ class User extends Model
         $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();
+        return Project::query()->whereIn('id', $project_ids)->where('status', 0)->where('is_add', $is_add)->select($select)->orderByDesc('sort')->get();
     }
 
     public function verify()
@@ -78,4 +78,9 @@ class User extends Model
     {
         return $this->hasOne(\App\Models\Member\User::class, 'id', 'user_id');
     }
+
+    public function site(): \Illuminate\Database\Eloquent\Relations\HasOne
+    {
+        return $this->hasOne(Site::class, 'coach_id', 'id');
+    }
 }

+ 44 - 0
app/Models/Member/Address.php

@@ -0,0 +1,44 @@
+<?php
+
+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;
+use Spatie\Permission\Traits\HasRoles;
+
+class Address extends Authenticatable
+{
+    use HasFactory, Notifiable;
+
+    protected $table = 'member_address';
+
+    /**
+     * 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 = ['password'];
+
+    /**
+     * Get the attributes that should be cast.
+     *
+     * @return array<string, string>
+     */
+    protected function casts(): array
+    {
+        return [];
+    }
+
+}

+ 1 - 1
app/Models/Service/Order.php

@@ -30,7 +30,6 @@ class Order extends Model
         // 获取代理项目
         $project = Project::query()->find($data['project_id']);
 
-
 //        $coupon_model= new Coupon();
 
         $coach_model = new User();
@@ -77,6 +76,7 @@ class Order extends Model
         $pay_price <= 0 && ($pay_price = 0);
         $data['pay_price'] = $pay_price;
         // 余额支付
+        $data['balance_price'] = 0;
         if ($use_balance) {
             // 用户余额
             $user['balance'] = 0;

+ 43 - 0
app/Models/System/Config.php

@@ -0,0 +1,43 @@
+<?php
+
+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;
+use Spatie\Permission\Traits\HasRoles;
+
+class Config extends Authenticatable
+{
+    use HasApiTokens, HasRoles, HasFactory, Notifiable, SoftDeletes;
+
+    protected $table = 'system_config';
+
+    /**
+     * 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 [];
+    }
+}

+ 10 - 4
bootstrap/app.php

@@ -12,20 +12,26 @@ use Illuminate\Foundation\Configuration\Middleware;
 // 官网? 客户端接口 技师端接口 后端管理接口 中台管理接口
 return Application::configure(basePath: dirname(__DIR__))
     ->withRouting(
-        web: __DIR__.'/../routes/web.php',
-        api: __DIR__.'/../routes/api.php',
-        commands: __DIR__.'/../routes/console.php',
+        web: __DIR__ . '/../routes/web.php',
+        api: __DIR__ . '/../routes/api.php',
+        commands: __DIR__ . '/../routes/console.php',
         health: '/up',
         apiPrefix: 'frontend'
     )
     ->withMiddleware(function (Middleware $middleware) {
+
         $middleware->use([
             \Illuminate\Http\Middleware\HandleCors::class,
             \App\Exceptions\Handler::class,
         ]);
 
         $middleware->api(prepend: [
-            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
+//            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
+//            \App\Http\Middleware\VerifyCsrfToken::class
+            \Illuminate\Cookie\Middleware\EncryptCookies::class,
+            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
+            \Illuminate\Session\Middleware\StartSession::class,
+            \Laravel\Sanctum\Http\Middleware\AuthenticateSession::class
         ]);
 
         $middleware->alias([

+ 1 - 1
config/cors.php

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

+ 2 - 1
database/migrations/2024_09_10_090033_create_coach_users_table.php

@@ -15,6 +15,7 @@ return new class extends Migration {
             $table->string('name')->nullable()->comment('技师姓名');
             $table->bigInteger('user_id');
             $table->string('mobile')->nullable()->comment('手机号');
+            $table->string('nickname')->nullable()->comment('昵称');
             $table->string('avatar')->nullable()->comment('头像');
             $table->tinyInteger('status')->default(0)->comment('状态 (0正常 1停用)');
             $table->tinyInteger('sex')->default(0)->nullable()->comment('用户性别');
@@ -30,7 +31,7 @@ return new class extends Migration {
             $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->string('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('是否推荐');

+ 1 - 1
database/migrations/2024_09_23_025556_create_wechat_users_table.php

@@ -25,6 +25,6 @@ return new class extends Migration {
      */
     public function down(): void
     {
-        Schema::dropIfExists('service_order');
+        Schema::dropIfExists('wechat_users');
     }
 };

+ 40 - 0
database/migrations/2024_09_30_025556_create_coach_site_table.php

@@ -0,0 +1,40 @@
+<?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_site', function (Blueprint $table) {
+            $table->id();
+            $table->bigInteger('coach_id')->comment('技师ID');
+            $table->string('longitude')->comment('经度');
+            $table->string('latitude')->comment('纬度');
+            $table->string('nation_code')->nullable()->comment('');
+            $table->string('city_code')->nullable()->comment('');
+            $table->string('province')->nullable()->comment('省');
+            $table->string('city')->nullable()->comment('省');
+            $table->string('district')->nullable()->comment('省');
+            $table->string('street')->nullable()->comment('街道');
+            $table->string('street_number')->nullable()->comment('街道号码');
+            $table->string('adcode')->nullable()->comment('城市编码');
+            $table->string('district_code')->nullable()->comment('地区编码');
+            $table->string('phone_area_code')->nullable()->comment('电话区号');
+            $table->string('address')->nullable()->comment('地址');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('coach_site');
+    }
+};

+ 29 - 0
database/migrations/2024_09_30_025556_create_system_config_table.php

@@ -0,0 +1,29 @@
+<?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('system_config', function (Blueprint $table) {
+            $table->string('name')->nullable()->comment('配置名称')->primary();
+            $table->string('model')->nullable()->comment('配置模块')->index();
+            $table->index('model', 'system_model_foreign_key_index');
+            $table->string('value')->nullable()->comment('配置值');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('system_config');
+    }
+};

+ 39 - 0
database/migrations/2024_10_01_025556_create_member_address_table.php

@@ -0,0 +1,39 @@
+<?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('member_address', function (Blueprint $table) {
+            $table->id();
+            $table->bigInteger('user_id')->comment('用户ID');
+            $table->string('user_name')->nullable()->comment('用户姓名');
+            $table->string('mobile')->nullable()->comment('手机号');
+            $table->tinyInteger('sex')->default(1)->nullable()->comment('性别');
+            $table->string('province')->nullable()->comment('省');
+            $table->string('city')->nullable()->comment('市');
+            $table->string('district')->nullable()->comment('区');
+            $table->string('address')->nullable()->comment('地址');
+            $table->string('address_info')->nullable()->comment('地址详情');
+            $table->string('city_code')->nullable();
+            $table->string('lng')->nullable()->comment('经度');
+            $table->string('lat')->nullable()->comment('纬度');
+            $table->tinyInteger('status')->default(0)->comment('状态 1:使用 ');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('system_config');
+    }
+};

+ 21 - 0
database/seeders/SystemConfigTableSeeder.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace Database\Seeders;
+
+use App\Models\System\User;
+use Illuminate\Database\Console\Seeds\WithoutModelEvents;
+use Illuminate\Database\Seeder;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Hash;
+
+class SystemConfigTableSeeder extends Seeder
+{
+    /**
+     * Run the database seeds.
+     */
+    public function run(): void
+    {
+        //
+        DB::table('system_config')->insert(['name' => 'upload_setting_way', 'model' => 'upload', 'value' => 'local']);
+    }
+}

+ 19 - 9
routes/api.php

@@ -11,6 +11,8 @@ use App\Http\Controllers\Frontend\Client\Auth\AuthenticatedController as ClientA
 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 App\Http\Controllers\Frontend\Client\Member\ToolController as ClientMemberToolController;
+use App\Http\Controllers\Frontend\Client\Member\AddressController as ClientMemberAddressController;
 
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Route;
@@ -31,15 +33,18 @@ Route::middleware(['auth:sanctum'])->get('/user', function (Request $request) {
 Route::prefix('client')->group(function () {
     # 登录
     Route::prefix('login')->group(function () {
-        Route::post('/',[ClientAccountAuthController::class,'store']);
-        Route::post('send',[ClientAccountAuthController::class,'send']);
+        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::get('/oauth', [ClientWechatAuthenticatedController::class, 'oauth']);
+        Route::get('/callback', [ClientWechatAuthenticatedController::class, 'callback']);
+        Route::get('/login', [ClientWechatAuthenticatedController::class, 'store']);
+        Route::get('/bind', [ClientWechatAuthenticatedController::class, 'bind']);
+
+        Route::get('/signature', [ClientWechatAuthenticatedController::class, 'signature']);
+
     });
 
     # 首页
@@ -49,7 +54,7 @@ Route::prefix('client')->group(function () {
         Route::get('project/{id}', [ClientProjectController::class, 'show']);
 
 
-        Route::middleware(['auth:sanctum'])->group(function (){
+        Route::middleware(['auth:sanctum'])->group(function () {
             # 订单
             Route::resource('order', ClientServiceOrderController::class);
         });
@@ -57,21 +62,26 @@ Route::prefix('client')->group(function () {
     });
 
 
-
     Route::prefix('coach')->group(function () {
         # 申请技师
-        Route::post('apply', [ClientCoachController::class, 'create']);
+        Route::post('apply', [ClientCoachUserController::class, 'apply'])->middleware('auth:sanctum');
         Route::get('/', [ClientCoachUserController::class, 'index']);
         Route::get('/{id}', [ClientCoachUserController::class, 'show']);
     });
 
     Route::prefix('member')->middleware(['auth:sanctum'])->group(function () {
+        Route::get('address/default', [ClientMemberAddressController::class,'default']);
+        Route::resource('address', ClientMemberAddressController::class);
+        Route::post('upload', [ClientMemberToolController::class, "upload"]);
         Route::get('/', [ClientMemberUserController::class, 'show']);
         Route::delete('/', [ClientMemberUserController::class, 'destroy']);
         Route::put('/', [ClientMemberUserController::class, 'update']);
     });
 
 
+
+
+
 });
 
 # 技师端