Ver Fonte

feat:用户地址->添加地址

刘学玺 há 4 meses atrás
pai
commit
8c4d42f017

+ 122 - 0
app/Http/Controllers/Client/UserAddressController.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace App\Http\Controllers\Client;
+
+use App\Http\Controllers\Controller;
+use App\Services\Client\UserAddressService;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+
+class UserAddressController extends Controller
+{
+    protected $userAddressService;
+
+    public function __construct(UserAddressService $userAddressService)
+    {
+        $this->userAddressService = $userAddressService;
+    }
+
+    /**
+     * [用户地址] 获取默认地址
+     *
+     * @description 根据用户编号查询用户数据,用户状态为正常,查询用户地址列表,返回用户默认地址
+     *
+     * @response {
+     *  "code": 200,
+     *  "message": "success",
+     *  "data": {
+     *    "id": 1,
+     *    "user_id": 1,
+     *    "name": "张三",
+     *    "phone": "13800138000",
+     *    "province": "广东省",
+     *    "city": "深圳市",
+     *    "district": "南山区",
+     *    "address": "科技园",
+     *    "is_default": 1,
+     *    "created_at": "2024-01-01 00:00:00",
+     *    "updated_at": "2024-01-01 00:00:00"
+     *  }
+     * }
+     */
+    public function getDefault()
+    {
+        return $this->userAddressService->getDefault(Auth::user()->id);
+    }
+
+    /**
+     * [用户地址] 添加地址
+     *
+     * @description 根据用户编号查询用户数据,用户状态为正常,保存用户地址,如果用户只有一个地址则设置为默认地址
+     *
+     * @bodyParam phone string required 手机号 Example: 13800138000
+     * @bodyParam province string required 省份 Example: 广东省
+     * @bodyParam city string required 城市 Example: 深圳市
+     * @bodyParam district string required 区县 Example: 南山区
+     * @bodyParam longitude string required 经度 Example: 113.93041
+     * @bodyParam latitude string required 纬度 Example: 22.53332
+     * @bodyParam area_code string required 区划代码 Example: 440305
+     * @bodyParam is_default boolean required 是否默认地址 Example: true
+     * @bodyParam location string required 定位地址 Example: 科技园
+     * @bodyParam detail string required 详细地址 Example: 科技园南区
+     *
+     * @response {"code": 200,"message": "添加成功"}
+     */
+    public function store(Request $request)
+    {
+        $data = $request->only(['phone', 'province', 'city', 'district', 'longitude', 'latitude', 'area_code', 'is_default', 'location', 'detail']);
+
+        return $this->userAddressService->store(Auth::user()->id, $data);
+    }
+
+    /**
+     * [用户地址] 修改地址
+     *
+     * @description 根据用户编号查询用户数据,用户状态为正常,根据地址编号查询地址数据,修改地址信息
+     *
+     * @urlParam id integer required 地址ID Example: 1
+     *
+     * @bodyParam name string required 收货人姓名 Example: 张三
+     * @bodyParam phone string required 收货人手机号 Example: 13800138000
+     * @bodyParam province string required 省份 Example: 广东省
+     * @bodyParam city string required 城市 Example: 深圳市
+     * @bodyParam district string required 区县 Example: 南山区
+     * @bodyParam address string required 详细地址 Example: 科技园南区
+     *
+     * @response {"code": 200,"message": "修改成功"}
+     */
+    public function update(Request $request, $id)
+    {
+        $data = $request->only(['name', 'phone', 'province', 'city', 'district', 'address']);
+
+        return $this->userAddressService->update(Auth::user()->id, $id, $data);
+    }
+
+    /**
+     * [用户地址] 删除地址
+     *
+     * @description 根据用户编号查询用户数据,用户状态为正常,根据地址编号查询地址数据,删除地址
+     *
+     * @urlParam id integer required 地址ID 默认值: 1
+     *
+     * @response {"code": 200,"message": "删除成功"}
+     */
+    public function destroy($id)
+    {
+        return $this->userAddressService->destroy(Auth::id(), $id);
+    }
+
+    /**
+     * [用户地址] 设置默认地址
+     *
+     * @description 根据用户编号查询用户数据,用户状态为正常,根据地址编号查询地址数据,设置为默认地址
+     *
+     * @urlParam id integer required 地址ID 默认值: 1
+     *
+     * @response {"code": 200,"message": "设置成功"}
+     */
+    public function setDefault($id)
+    {
+        return $this->userAddressService->setDefault(Auth::id(), $id);
+    }
+}

+ 33 - 33
app/Logging/CustomizeFormatter.php

@@ -22,39 +22,39 @@ class CustomizeFormatter
             ));
 
             // 添加更严格的过滤器
-            $handler->pushProcessor(function (LogRecord $record): LogRecord {
-                // 1. 允许SQL日志
-                if (str_contains($record->message, 'sql:')) {
-                    return $record;
-                }
-
-                // 2. 过滤所有来自vendor目录的日志
-                if (isset($record->extra['file']) && str_contains($record->extra['file'], '/vendor/')) {
-                    $record->extra['filtered'] = true;
-                    return $record;
-                }
-
-                // 3. 过滤框架的默认日志通道
-                if (in_array($record->channel, [
-                    'laravel',
-                    'framework',
-                    'security',
-                    'request',
-                    'schedule',
-                    'queue',
-                ])) {
-                    $record->extra['filtered'] = true;
-                    return $record;
-                }
-
-                // 4. 只允许来自app目录的日志
-                if (isset($record->extra['file']) && str_contains($record->extra['file'], '/app/')) {
-                    return $record;
-                }
-
-                $record->extra['filtered'] = true;
-                return $record;
-            });
+            // $handler->pushProcessor(function (LogRecord $record): LogRecord {
+            //     // 1. 允许SQL日志
+            //     if (str_contains($record->message, 'sql:')) {
+            //         return $record;
+            //     }
+
+            //     // 2. 过滤所有来自vendor目录的日志
+            //     if (isset($record->extra['file']) && str_contains($record->extra['file'], '/vendor/')) {
+            //         $record->extra['filtered'] = true;
+            //         return $record;
+            //     }
+
+            //     // 3. 过滤框架的默认日志通道
+            //     if (in_array($record->channel, [
+            //         'laravel',
+            //         'framework',
+            //         'security',
+            //         'request',
+            //         'schedule',
+            //         'queue',
+            //     ])) {
+            //         $record->extra['filtered'] = true;
+            //         return $record;
+            //     }
+
+            //     // 4. 只允许来自app目录的日志
+            //     if (isset($record->extra['file']) && str_contains($record->extra['file'], '/app/')) {
+            //         return $record;
+            //     }
+
+            //     $record->extra['filtered'] = true;
+            //     return $record;
+            // });
         }
     }
 }

+ 6 - 3
app/Models/MemberAddress.php

@@ -10,16 +10,19 @@ use Slowlyo\OwlAdmin\Models\BaseModel as Model;
  */
 class MemberAddress extends Model
 {
-	use SoftDeletes;
+    use SoftDeletes;
 
-	protected $table = 'member_address';
+    protected $table = 'member_address';
+
+    protected $guarded = [];
 
     /**
      * @Author FelixYin
+     *
      * @description 地址所属会员
      */
     public function member()
     {
         return $this->belongsTo('App\Models\MemberUser', 'user_id');
     }
-}
+}

+ 7 - 96
app/Models/MemberUser.php

@@ -2,109 +2,20 @@
 
 namespace App\Models;
 
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\HasMany;
 use Illuminate\Database\Eloquent\SoftDeletes;
-use Slowlyo\OwlAdmin\Models\BaseModel as Model;
-use \Laravel\Sanctum\HasApiTokens;
+use Laravel\Sanctum\HasApiTokens;
 
-/**
- * 用户
- */
 class MemberUser extends Model
 {
-	use HasApiTokens, SoftDeletes;
-
-	protected $table = 'member_users';
-	protected $hidden = ['password'];
-	protected $fillable = ['mobile', 'state', 'register_area'];
-
-	protected static function booted()
-	{
-		static::created(function ($user) {
-			$user->wallet()->create([
-				'owner_type' => MemberUser::class,
-				'owner_id' => $user->id
-			]);
-		});
-	}
-
-    /**
-     * @Author FelixYin
-     * @description 用户关联社交账户
-     */
-    public function socialAccounts()
-    {
-        return $this->hasMany('App\Models\MemberSocialAccount', 'user_id', 'id');
-    }
-
-    /**
-     * @Author FelixYin
-     * @description 用户关联地址
-     */
-    public function addresses()
-    {
-        return $this->hasMany('App\Models\MemberAddress', 'user_id', 'id');
-    }
-
-    /**
-     * @Author FelixYin
-     * @description 用户关联技师身份
-     */
-    public function coach()
-    {
-        return $this->hasOne('App\Models\CoachUser', 'user_id', 'id');
-    }
-
-    /**
-     * @Author FelixYin
-     * @description 用户关联订单
-     */
-    public function orders()
-    {
-        return $this->hasMany('App\Models\OrderInfo', 'user_id', 'id');
-    }
-
-    /**
-     * @Author FelixYin
-     * @description 用户关联评论
-     */
-    public function comments()
-    {
-        return $this->hasMany('App\Models\OrderComment', 'user_id', 'id');
-    }
-
-    /**
-     * @Author FelixYin
-     * @description 用户关联钱包
-     */
-    public function wallet()
-    {
-        return $this->MORPH_ONE('App\Models\Wallet', 'undefined', 'id');
-    }
-
-    /**
-     * @Author FelixYin
-     * @description 用户关联店铺身份
-     */
-    public function shop()
-    {
-        return $this->hasOne('App\Models\ShopInfo', 'user_id', 'id');
-    }
-
-    /**
-     * @Author FelixYin
-     * @description 用户关联代理商身份
-     */
-    public function agent()
-    {
-        return $this->hasOne('App\Models\AgentInfo', 'user_id', 'id');
-    }
+    use HasApiTokens, SoftDeletes;
 
     /**
-     * @Author FelixYin
-     * @description 会员所属行政区划
+     * 获取用户的所有地址
      */
-    public function region()
+    public function addresses(): HasMany
     {
-        return $this->belongsTo('App\Models\SysRegion', 'register_area');
+        return $this->hasMany(MemberAddress::class, 'user_id', 'id');
     }
 }

+ 22 - 49
app/Services/Client/CoachService.php

@@ -4,8 +4,8 @@ namespace App\Services\Client;
 
 use App\Models\CoachUser;
 use Illuminate\Support\Facades\Auth;
-use Illuminate\Support\Facades\Redis;
 use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Redis;
 
 class CoachService
 {
@@ -26,7 +26,7 @@ class CoachService
         ]);
 
         // 检查用户状态
-        if (!$user) {
+        if (! $user) {
             throw new \Exception('用户未登录');
         }
 
@@ -85,7 +85,7 @@ class CoachService
             Log::info('Redis connection test:', ['ping_result' => $pingResult]);
         } catch (\Exception $e) {
             Log::error('Redis connection error:', ['error' => $e->getMessage()]);
-            throw new \Exception('Redis连接失败:' . $e->getMessage());
+            throw new \Exception('Redis连接失败:'.$e->getMessage());
         }
 
         // 检查Redis中的所有位置数据
@@ -99,11 +99,11 @@ class CoachService
             'user' => $user ? $user->id : null,
             'latitude' => $latitude,
             'longitude' => $longitude,
-            'coach_id' => $coachId
+            'coach_id' => $coachId,
         ]);
 
         // 检查用户状态
-        if (!$user) {
+        if (! $user) {
             throw new \Exception('用户未登录');
         }
 
@@ -132,68 +132,40 @@ class CoachService
         $homeLocation = Redis::geopos('coach_locations', $coachId.'_home');
         $workLocation = Redis::geopos('coach_locations', $coachId.'_work');
 
-        Log::info('Coach locations from Redis:', [
-            'coach_id' => $coachId,
-            'home_location' => $homeLocation,
-            'work_location' => $workLocation,
-            'home_key' => $coachId.'_home',
-            'work_key' => $coachId.'_work'
-        ]);
-
         // 检查输入的经纬度是否有效
-        if (!is_numeric($latitude) || !is_numeric($longitude)) {
+        if (! is_numeric($latitude) || ! is_numeric($longitude)) {
             Log::error('Invalid coordinates:', ['latitude' => $latitude, 'longitude' => $longitude]);
             throw new \Exception('无效的经纬度坐标');
         }
 
         // 临时存储用户当前位置用于计算距离
         $tempKey = 'user_temp_'.$user->id;
-        $addResult = Redis::geoadd('coach_locations', $longitude, $latitude, $tempKey);
-
-        Log::info('User location added to Redis:', [
-            'temp_key' => $tempKey,
-            'latitude' => $latitude,
-            'longitude' => $longitude,
-            'add_result' => $addResult
-        ]);
+        Redis::geoadd('coach_locations', $longitude, $latitude, $tempKey);
 
         // 计算距离(单位:km)
         $distanceHome = null;
         $distanceWork = null;
 
-        if ($homeLocation && !empty($homeLocation[0])) {
+        if ($homeLocation && ! empty($homeLocation[0])) {
             $distanceHome = Redis::geodist('coach_locations', $tempKey, $coachId.'_home', 'km');
             Log::info('Home distance calculation:', [
                 'from' => $tempKey,
                 'to' => $coachId.'_home',
                 'distance' => $distanceHome,
-                'home_location' => $homeLocation[0]
+                'home_location' => $homeLocation[0],
             ]);
         }
 
-        if ($workLocation && !empty($workLocation[0])) {
+        if ($workLocation && ! empty($workLocation[0])) {
             $distanceWork = Redis::geodist('coach_locations', $tempKey, $coachId.'_work', 'km');
-            Log::info('Work distance calculation:', [
-                'from' => $tempKey,
-                'to' => $coachId.'_work',
-                'distance' => $distanceWork,
-                'work_location' => $workLocation[0]
-            ]);
         }
 
-        Log::info('Distance calculation results:', [
-            'distance_home' => $distanceHome,
-            'distance_work' => $distanceWork,
-            'temp_key' => $tempKey,
-            'coach_id' => $coachId
-        ]);
-
         // 删除临时位置点
         Redis::zrem('coach_locations', $tempKey);
 
         // 选择最近的距离
         $distances = array_filter([$distanceHome, $distanceWork]);
-        $coach->distance = !empty($distances) ? round(min($distances), 2) : null;
+        $coach->distance = ! empty($distances) ? round(min($distances), 2) : null;
 
         return $coach;
     }
@@ -201,29 +173,30 @@ class CoachService
     /**
      * 设置技师位置信息
      *
-     * @param int $coachId 技师ID
-     * @param float $latitude 纬度
-     * @param float $longitude 经度
-     * @param string $type 位置类型 (home|work)
+     * @param  int  $coachId  技师ID
+     * @param  float  $latitude  纬度
+     * @param  float  $longitude  经度
+     * @param  string  $type  位置类型 (home|work)
      * @return bool
+     *
      * @throws \Exception
      */
     public function setCoachLocation($coachId, $latitude, $longitude, $type = 'home')
     {
-        if (!is_numeric($latitude) || !is_numeric($longitude)) {
+        if (! is_numeric($latitude) || ! is_numeric($longitude)) {
             Log::error('Invalid coordinates in setCoachLocation:', [
                 'coach_id' => $coachId,
                 'latitude' => $latitude,
-                'longitude' => $longitude
+                'longitude' => $longitude,
             ]);
             throw new \Exception('无效的经纬度坐标');
         }
 
-        if (!in_array($type, ['home', 'work'])) {
+        if (! in_array($type, ['home', 'work'])) {
             throw new \Exception('无效的位置类型,必须是 home 或 work');
         }
 
-        $key = $coachId . '_' . $type;
+        $key = $coachId.'_'.$type;
         $result = Redis::geoadd('coach_locations', $longitude, $latitude, $key);
 
         Log::info('Coach location set:', [
@@ -232,14 +205,14 @@ class CoachService
             'key' => $key,
             'latitude' => $latitude,
             'longitude' => $longitude,
-            'result' => $result
+            'result' => $result,
         ]);
 
         // 验证数据是否成功写入
         $location = Redis::geopos('coach_locations', $key);
         Log::info('Verify location after set:', [
             'key' => $key,
-            'location' => $location
+            'location' => $location,
         ]);
 
         return $result;

+ 189 - 0
app/Services/Client/UserAddressService.php

@@ -0,0 +1,189 @@
+<?php
+
+namespace App\Services\Client;
+
+use App\Models\MemberUser;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+
+class UserAddressService
+{
+    /**
+     * 获取默认地址
+     */
+    public function getDefault($userId)
+    {
+        try {
+            // 根据用户编号查询用户数据
+            $user = MemberUser::findOrFail($userId);
+            if ($user->state != 'enable') {
+                return ['code' => 400, 'message' => '用户状态异常'];
+            }
+
+            // 查询用户地址列表,返回用户默认地址
+            $address = $user->addresses()
+                ->where('is_default', 1)
+                ->first();
+
+            return ['code' => 200, 'message' => 'success', 'data' => $address];
+        } catch (\Exception $e) {
+            Log::error('获取默认地址失败', [
+                'user_id' => $userId,
+                'error' => $e->getMessage(),
+            ]);
+
+            return ['code' => 500, 'message' => '获取默认地址失败'];
+        }
+    }
+
+    /**
+     * 添加地址
+     */
+    public function store($userId, array $data)
+    {
+        DB::beginTransaction();
+        try {
+            // 根据用户编号查询用户数据
+            $user = MemberUser::findOrFail($userId);
+            if ($user->state != 'enable') {
+                return ['code' => 400, 'message' => '用户状态异常'];
+            }
+
+            // 如果用户只有一个地址,或者传入的is_default为true,则设置为默认地址
+            $isFirst = $user->addresses()->count() == 0 || ($data['is_default'] ?? false);
+            if ($isFirst) {
+                $data['is_default'] = 1;
+                // 将用户其他地址设为非默认
+                $user->addresses()->update(['is_default' => 0]);
+            }
+
+            // 保存用户地址
+            $user->addresses()->create($data);
+
+            DB::commit();
+
+            return ['code' => 200, 'message' => '添加成功'];
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('添加地址失败', [
+                'user_id' => $userId,
+                'data' => $data,
+                'error' => $e->getMessage(),
+            ]);
+
+            return ['code' => 500, 'message' => '添加地址失败'];
+        }
+    }
+
+    /**
+     * 修改地址
+     */
+    public function update($userId, $id, array $data)
+    {
+        DB::beginTransaction();
+        try {
+            // 根据用户编号查询用户数据
+            $user = MemberUser::findOrFail($userId);
+            if ($user->state != 'enable') {
+                return ['code' => 400, 'message' => '用户状态异常'];
+            }
+
+            // 根据地址编号查询地址数据
+            $address = $user->addresses()
+                ->where('id', $id)
+                ->firstOrFail();
+
+            // 修改地址信息
+            $address->update($data);
+
+            DB::commit();
+
+            return ['code' => 200, 'message' => '修改成功'];
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('修改地址失败', [
+                'user_id' => $userId,
+                'id' => $id,
+                'data' => $data,
+                'error' => $e->getMessage(),
+            ]);
+
+            return ['code' => 500, 'message' => '修改地址失败'];
+        }
+    }
+
+    /**
+     * 删除地址
+     */
+    public function destroy($userId, $id)
+    {
+        DB::beginTransaction();
+        try {
+            // 根据用户编号查询用户数据
+            $user = MemberUser::findOrFail($userId);
+            if ($user->state != 'enable') {
+                return ['code' => 400, 'message' => '用户状态异常'];
+            }
+
+            // 根据地址编号查询地址数据
+            $address = $user->addresses()
+                ->where('id', $id)
+                ->firstOrFail();
+
+            // 删除地址
+            $address->delete();
+
+            DB::commit();
+
+            return ['code' => 200, 'message' => '删除成功'];
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('删除地址失败', [
+                'user_id' => $userId,
+                'id' => $id,
+                'error' => $e->getMessage(),
+            ]);
+
+            return ['code' => 500, 'message' => '删除地址失败'];
+        }
+    }
+
+    /**
+     * 设置默认地址
+     */
+    public function setDefault($userId, $id)
+    {
+        DB::beginTransaction();
+        try {
+            // 根据用户编号查询用户数据
+            $user = MemberUser::findOrFail($userId);
+            if ($user->state != 'enable') {
+                return ['code' => 400, 'message' => '用户状态异常'];
+            }
+
+            // 根据地址编号查询地址数据
+            $address = $user->addresses()
+                ->where('id', $id)
+                ->firstOrFail();
+
+            // 将所有地址设为非默认
+            $user->addresses()->update(['is_default' => 0]);
+
+            // 设置为默认地址
+            $address->update(['is_default' => 1]);
+
+            DB::commit();
+
+            return ['code' => 200, 'message' => '设置成功'];
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('设置默认地址失败', [
+                'user_id' => $userId,
+                'id' => $id,
+                'error' => $e->getMessage(),
+            ]);
+
+            return ['code' => 500, 'message' => '设置默认地址失败'];
+        }
+    }
+}

+ 10 - 0
routes/api.php

@@ -4,6 +4,7 @@ use App\Http\Controllers\Client\AccountController;
 use App\Http\Controllers\Client\CoachController;
 use App\Http\Controllers\Client\CoachLocationController;
 use App\Http\Controllers\Client\ProjectController;
+use App\Http\Controllers\Client\UserAddressController;
 use App\Http\Controllers\Client\UserController;
 use App\Http\Controllers\ScribeController;
 use Illuminate\Support\Facades\Route;
@@ -66,4 +67,13 @@ Route::middleware('auth:sanctum')->group(function () {
 
     });
 
+    // 用户地址相关
+    Route::prefix('address')->group(function () {
+        Route::get('default', [UserAddressController::class, 'getDefault']);
+        Route::post('/', [UserAddressController::class, 'store']);
+        Route::put('/{id}', [UserAddressController::class, 'update']);
+        Route::delete('/{id}', [UserAddressController::class, 'destroy']);
+        Route::put('/{id}/default', [UserAddressController::class, 'setDefault']);
+    });
+
 });