commit db5ed78ea923e60b37ddbdf97c12d9ebb270acf4 Author: testadmin Date: Tue Apr 28 14:35:00 2026 +0800 feat: C2C商家交易系统后端 — API+后台管理 diff --git a/app/C2cMerchant.php b/app/C2cMerchant.php new file mode 100644 index 0000000..c5bcc62 --- /dev/null +++ b/app/C2cMerchant.php @@ -0,0 +1,13 @@ +belongsTo(C2cMerchant::class, 'merchant_id'); } + public function user() { return $this->belongsTo(Users::class, 'user_id'); } +} diff --git a/app/Http/Controllers/Api/C2cMerchantController.php b/app/Http/Controllers/Api/C2cMerchantController.php new file mode 100644 index 0000000..7d23f35 --- /dev/null +++ b/app/Http/Controllers/Api/C2cMerchantController.php @@ -0,0 +1,115 @@ +input('crypto_currency'); + if ($crypto) $query->where('crypto_currency', $crypto); + + $fiat = $request->input('fiat_currency'); + if ($fiat) $query->where('fiat_currency', $fiat); + + $list = $query->orderBy('sort', 'desc')->orderBy('id', 'desc')->get(); + return $this->success($list); + } + + public function createOrder(Request $request) + { + $user_id = Token::getUserIdByToken(Token::getToken()); + $user = \App\Users::find($user_id); + if (!$user) return $this->error('Please login'); + + $merchant_id = intval($request->input('merchant_id')); + $direction = $request->input('direction'); // buy / sell + $amount = floatval($request->input('amount')); + + if (!in_array($direction, ['buy', 'sell'])) return $this->error('Invalid direction'); + if ($amount <= 0) return $this->error('Invalid amount'); + + $merchant = C2cMerchant::find($merchant_id); + if (!$merchant || $merchant->status != 1) return $this->error('Merchant not available'); + + if ($amount < $merchant->min_amount) return $this->error('Min: ' . $merchant->min_amount); + if ($merchant->max_amount > 0 && $amount > $merchant->max_amount) return $this->error('Max: ' . $merchant->max_amount); + if ($merchant->available_qty > 0 && $amount > $merchant->available_qty) return $this->error('Insufficient merchant stock'); + + $unit_price = floatval($merchant->unit_price); + $total_price = round($amount * $unit_price, 6); + $fee_rate = 0.002; // 0.2% + $fee = round($total_price * $fee_rate, 6); + + $order_no = date('YmdHis') . rand(1000, 9999); + $expire_time = date('Y-m-d H:i:s', time() + 1800); + + $order = C2cMerchantOrder::create([ + 'order_no' => $order_no, + 'user_id' => $user->id, + 'merchant_id' => $merchant_id, + 'direction' => $direction, + 'crypto_currency' => $merchant->crypto_currency, + 'fiat_currency' => $merchant->fiat_currency, + 'amount' => $amount, + 'unit_price' => $unit_price, + 'total_price' => $total_price, + 'fee' => $fee, + 'fee_rate' => $fee_rate, + 'status' => 0, + 'contact_type' => $merchant->contact_type, + 'contact_link' => $merchant->contact_link, + 'expire_time' => $expire_time, + ]); + + $order->merchant_name = $merchant->name; + return $this->success($order); + } + + public function myOrders(Request $request) + { + $user_id = Token::getUserIdByToken(Token::getToken()); + $user = \App\Users::find($user_id); + if (!$user) return $this->error('Please login'); + + $query = C2cMerchantOrder::where('user_id', $user->id) + ->with('merchant:id,name,logo'); + + $status = $request->input('status'); + if ($status !== null && $status !== '' && $status !== 'all') { + $query->where('status', intval($status)); + } + + $data = $query->orderBy('id', 'desc')->paginate(intval($request->input('limit', 20))); + + $statusMap = [0 => 'Pending', 1 => 'Completed', 2 => 'Cancelled', 3 => 'Expired']; + foreach ($data as $item) { + $item->status_text = $statusMap[$item->status] ?? ''; + } + return $this->success($data); + } + + public function orderDetail(Request $request) + { + $user_id = Token::getUserIdByToken(Token::getToken()); + $user = \App\Users::find($user_id); + if (!$user) return $this->error('Please login'); + + $id = intval($request->input('id')); + $order = C2cMerchantOrder::with('merchant:id,name,logo,contact_type,contact_link') + ->where('id', $id)->where('user_id', $user->id)->first(); + if (!$order) return $this->error('Order not found'); + + $statusMap = [0 => 'Pending', 1 => 'Completed', 2 => 'Cancelled', 3 => 'Expired']; + $order->status_text = $statusMap[$order->status] ?? ''; + return $this->success($order); + } +} diff --git a/resources/views/manages/c2c_merchant/index.blade.php b/resources/views/manages/c2c_merchant/index.blade.php new file mode 100644 index 0000000..7bfe313 --- /dev/null +++ b/resources/views/manages/c2c_merchant/index.blade.php @@ -0,0 +1,104 @@ +@extends('admin._layoutNew') +@section('title', 'C2C商家管理') +@section('page-content') +
+
C2C商家管理
+
+ + +
+
+
+ + + + + +@endsection +@section('scripts') + +@endsection diff --git a/resources/views/manages/c2c_merchant/orders.blade.php b/resources/views/manages/c2c_merchant/orders.blade.php new file mode 100644 index 0000000..f22e546 --- /dev/null +++ b/resources/views/manages/c2c_merchant/orders.blade.php @@ -0,0 +1,64 @@ +@extends('admin._layoutNew') +@section('title', 'C2C商家订单') +@section('page-content') +
+
C2C商家订单管理
+
+
+ +
+
+
+
+ + + + +@endsection +@section('scripts') + +@endsection