mirror of
https://github.com/cedar2025/Xboard.git
synced 2025-02-08 18:08:13 -05:00
feat: add user deletion functionality and fix known issues
This commit is contained in:
parent
1ae8deca99
commit
b2e7ed44f3
@ -4,6 +4,7 @@ namespace App\Http\Controllers\V1\User;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\CouponResource;
|
||||
use App\Services\CouponService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@ -11,19 +12,14 @@ class CouponController extends Controller
|
||||
{
|
||||
public function check(Request $request)
|
||||
{
|
||||
// $request->validate([
|
||||
// 'code' => 'required|string',
|
||||
// 'plan_id' => 'required|integer',
|
||||
// 'period' => 'nullable|string',
|
||||
// ]);
|
||||
if (empty($request->input('code'))) {
|
||||
return $this->fail([422,__('Coupon cannot be empty')]);
|
||||
return $this->fail([422, __('Coupon cannot be empty')]);
|
||||
}
|
||||
$couponService = new CouponService($request->input('code'));
|
||||
$couponService->setPlanId($request->input('plan_id'));
|
||||
$couponService->setUserId($request->user()->id);
|
||||
$couponService->setPeriod($request->input('period'));
|
||||
$couponService->check();
|
||||
return $this->success($couponService->getCoupon());
|
||||
return $this->success(CouponResource::make($couponService->getCoupon()));
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ use App\Services\AuthService;
|
||||
use App\Utils\Helper;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class UserController extends Controller
|
||||
@ -86,11 +87,11 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
[$operator, $filterValue] = explode(':', $value, 2);
|
||||
|
||||
|
||||
// Convert numeric strings to appropriate type
|
||||
if (is_numeric($filterValue)) {
|
||||
$filterValue = strpos($filterValue, '.') !== false
|
||||
? (float) $filterValue
|
||||
$filterValue = strpos($filterValue, '.') !== false
|
||||
? (float) $filterValue
|
||||
: (int) $filterValue;
|
||||
}
|
||||
|
||||
@ -149,12 +150,12 @@ class UserController extends Controller
|
||||
{
|
||||
$current = $request->input('current', 1);
|
||||
$pageSize = $request->input('pageSize', 10);
|
||||
|
||||
|
||||
$userModel = User::with(['plan:id,name', 'invite_user:id,email', 'group:id,name'])
|
||||
->select(DB::raw('*, (u+d) as total_used'));
|
||||
|
||||
$this->applyFiltersAndSorts($request, $userModel);
|
||||
|
||||
|
||||
$users = $userModel->orderBy('id', 'desc')
|
||||
->paginate($pageSize, ['*'], 'page', $current);
|
||||
|
||||
@ -397,4 +398,35 @@ class UserController extends Controller
|
||||
|
||||
return $this->success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户及其关联数据
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'id' => 'required|exists:App\Models\User,id'
|
||||
], [
|
||||
'id.required' => '用户ID不能为空',
|
||||
'id.exists' => '用户不存在'
|
||||
]);
|
||||
$user = User::find($request->input('id'));
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$user->orders()->delete();
|
||||
$user->codes()->delete();
|
||||
$user->stat()->delete();
|
||||
$user->tickets()->delete();
|
||||
$user->delete();
|
||||
DB::commit();
|
||||
return $this->success(true);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
\Log::error($e);
|
||||
return $this->fail([500, '删除失败']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
34
app/Http/Resources/CouponResource.php
Normal file
34
app/Http/Resources/CouponResource.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
* 优惠券资源类
|
||||
*
|
||||
* @property array|null $limit_plan_ids 限制可用的套餐ID列表
|
||||
*/
|
||||
class CouponResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* 将资源转换为数组
|
||||
*
|
||||
* @param Request $request 请求实例
|
||||
* @return array<string, mixed> 转换后的数组
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
...$this->resource->toArray(),
|
||||
'limit_plan_ids' => $this->when(
|
||||
!empty($this->limit_plan_ids),
|
||||
fn() => collect($this->limit_plan_ids)
|
||||
->map(fn(mixed $id): string => (string) $id)
|
||||
->values()
|
||||
->all()
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
@ -108,6 +108,7 @@ class AdminRoute
|
||||
$router->post('/ban', [UserController::class, 'ban']);
|
||||
$router->post('/resetSecret', [UserController::class, 'resetSecret']);
|
||||
$router->post('/setInviteUser', [UserController::class, 'setInviteUser']);
|
||||
$router->post('/destroy', [UserController::class, 'destroy']);
|
||||
});
|
||||
|
||||
// Stat
|
||||
|
@ -24,17 +24,4 @@ class Coupon extends Model
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
public function getLimitPlanIdsAttribute($value)
|
||||
{
|
||||
$planIds = json_decode($value, true);
|
||||
|
||||
if (blank($planIds)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return collect($planIds)
|
||||
->map(fn($id) => (string) $id)
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,16 @@ class User extends Authenticatable
|
||||
return $this->hasMany(InviteCode::class, 'user_id', 'id');
|
||||
}
|
||||
|
||||
public function orders()
|
||||
{
|
||||
return $this->hasMany(Order::class, 'user_id', 'id');
|
||||
}
|
||||
|
||||
public function stat()
|
||||
{
|
||||
return $this->hasMany(StatUser::class, 'user_id', 'id');
|
||||
}
|
||||
|
||||
// 关联工单列表
|
||||
public function tickets()
|
||||
{
|
||||
|
14
public/assets/admin/assets/index.js
vendored
14
public/assets/admin/assets/index.js
vendored
File diff suppressed because one or more lines are too long
12
public/assets/admin/locales/en-US.js
vendored
12
public/assets/admin/locales/en-US.js
vendored
@ -815,7 +815,11 @@ window.XBOARD_TRANSLATIONS['en-US'] = {
|
||||
"success": "Success",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete",
|
||||
"confirm": "Confirm",
|
||||
"delete": {
|
||||
"success": "Deleted successfully",
|
||||
"failed": "Failed to delete"
|
||||
},
|
||||
"edit": "Edit",
|
||||
"view": "View",
|
||||
"toggleNavigation": "Toggle Navigation",
|
||||
@ -832,6 +836,7 @@ window.XBOARD_TRANSLATIONS['en-US'] = {
|
||||
"logout": "Logout",
|
||||
"copy": {
|
||||
"success": "Copied successfully",
|
||||
"failed": "Failed to copy",
|
||||
"error": "Copy failed",
|
||||
"errorLog": "Error copying to clipboard"
|
||||
},
|
||||
@ -1740,7 +1745,10 @@ window.XBOARD_TRANSLATIONS['en-US'] = {
|
||||
"reset_secret": "Reset UUID & URL",
|
||||
"orders": "Orders",
|
||||
"invites": "Invites",
|
||||
"traffic_records": "Traffic Records"
|
||||
"traffic_records": "Traffic Records",
|
||||
"delete": "Delete",
|
||||
"delete_confirm_title": "Confirm Delete User",
|
||||
"delete_confirm_description": "This action will permanently delete user {{email}} and all associated data, including orders, coupons, traffic records, and support tickets. This action cannot be undone. Do you want to continue?"
|
||||
}
|
||||
},
|
||||
"filter": {
|
||||
|
20
public/assets/admin/locales/ko-KR.js
vendored
20
public/assets/admin/locales/ko-KR.js
vendored
@ -815,7 +815,11 @@ window.XBOARD_TRANSLATIONS['ko-KR'] = {
|
||||
"success": "성공",
|
||||
"save": "저장",
|
||||
"cancel": "취소",
|
||||
"delete": "삭제",
|
||||
"confirm": "확인",
|
||||
"delete": {
|
||||
"success": "삭제되었습니다",
|
||||
"failed": "삭제에 실패했습니다"
|
||||
},
|
||||
"edit": "편집",
|
||||
"view": "보기",
|
||||
"toggleNavigation": "네비게이션 전환",
|
||||
@ -831,9 +835,8 @@ window.XBOARD_TRANSLATIONS['ko-KR'] = {
|
||||
"settings": "설정",
|
||||
"logout": "로그아웃",
|
||||
"copy": {
|
||||
"success": "복사 성공",
|
||||
"error": "복사 실패",
|
||||
"errorLog": "클립보드에 복사하는 중 오류 발생"
|
||||
"success": "복사되었습니다",
|
||||
"failed": "복사에 실패했습니다"
|
||||
},
|
||||
"table": {
|
||||
"noData": "데이터가 없습니다",
|
||||
@ -1692,9 +1695,12 @@ window.XBOARD_TRANSLATIONS['ko-KR'] = {
|
||||
"assign_order": "주문 할당",
|
||||
"copy_url": "구독 URL 복사",
|
||||
"reset_secret": "UUID 및 URL 재설정",
|
||||
"orders": "주문",
|
||||
"invites": "초대",
|
||||
"traffic_records": "트래픽 기록"
|
||||
"orders": "주문 내역",
|
||||
"invites": "초대 내역",
|
||||
"traffic_records": "트래픽 기록",
|
||||
"delete": "삭제",
|
||||
"delete_confirm_title": "사용자 삭제 확인",
|
||||
"delete_confirm_description": "이 작업은 사용자 {{email}}와 관련된 모든 데이터(주문, 쿠폰, 트래픽 기록, 지원 티켓 등)를 영구적으로 삭제합니다. 이 작업은 취소할 수 없습니다. 계속하시겠습니까?"
|
||||
}
|
||||
},
|
||||
"filter": {
|
||||
|
12
public/assets/admin/locales/zh-CN.js
vendored
12
public/assets/admin/locales/zh-CN.js
vendored
@ -820,7 +820,11 @@ window.XBOARD_TRANSLATIONS['zh-CN'] = {
|
||||
"success": "成功",
|
||||
"save": "保存",
|
||||
"cancel": "取消",
|
||||
"delete": "删除",
|
||||
"confirm": "确认",
|
||||
"delete": {
|
||||
"success": "删除成功",
|
||||
"failed": "删除失败"
|
||||
},
|
||||
"edit": "编辑",
|
||||
"view": "查看",
|
||||
"toggleNavigation": "切换导航",
|
||||
@ -837,6 +841,7 @@ window.XBOARD_TRANSLATIONS['zh-CN'] = {
|
||||
"logout": "退出登录",
|
||||
"copy": {
|
||||
"success": "复制成功",
|
||||
"failed": "复制失败",
|
||||
"error": "复制失败",
|
||||
"errorLog": "复制到剪贴板时出错"
|
||||
},
|
||||
@ -1707,7 +1712,10 @@ window.XBOARD_TRANSLATIONS['zh-CN'] = {
|
||||
"reset_secret": "重置UUID及订阅URL",
|
||||
"orders": "TA的订单",
|
||||
"invites": "TA的邀请",
|
||||
"traffic_records": "TA的流量记录"
|
||||
"traffic_records": "TA的流量记录",
|
||||
"delete": "删除",
|
||||
"delete_confirm_title": "确认删除用户",
|
||||
"delete_confirm_description": "此操作将永久删除用户 {{email}} 及其所有相关数据,包括订单、优惠码、流量记录、工单记录等信息。删除后无法恢复,是否继续?"
|
||||
}
|
||||
},
|
||||
"filter": {
|
||||
|
Loading…
Reference in New Issue
Block a user