where('slug', $slug); if (!$product) { \Core\App::notFound(); return ''; } $err = isset($_GET['err']) ? '请填写姓名与手机号' : ''; return $this->view('order/checkout', ['p' => $product, 'slug' => $slug, 'err' => $err]); } public function store() { if ($_SERVER['REQUEST_METHOD'] !== 'POST') { $this->redirect('products'); } if (!csrf_check()) { $this->redirect('products'); } $slug = $this->post('slug', ''); $product = (new Product())->where('slug', $slug); if (!$product) { $this->redirect('products'); } $name = trim($this->post('name', '')); $phone = trim($this->post('phone', '')); $email = trim($this->post('email', '')); $qty = max(1, (int) $this->post('qty', 1)); if ($name === '' || $phone === '') { $this->redirect('order/checkout/' . $slug . '?err=1'); } $amount = round((float) $product['price'] * $qty, 2); $orderNo = $this->genNo(); $oid = (new Order())->insert([ 'order_no' => $orderNo, 'product_id' => $product['id'], 'product_name' => $product['name'], 'customer_name' => $name, 'phone' => $phone, 'email' => $email, 'qty' => $qty, 'amount' => $amount, 'channel' => '', 'status' => 'pending', 'created_at' => date('Y-m-d H:i:s'), ]); Notify::newCustomerOrder($orderNo, $name, $phone, $oid); $this->redirect('order/pay/' . $orderNo); } public function pay($orderNo) { $order = (new Order())->where('order_no', $orderNo); if (!$order) { \Core\App::notFound(); return ''; } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $channel = $this->post('channel', ''); if ($channel === 'alipay' || $channel === 'wechat') { if ($order['channel'] !== $channel) { (new Order())->update($order['id'], ['channel' => $channel]); $order['channel'] = $channel; } } } if ($order['status'] === 'paid') { return $this->view('order/pay', ['order' => $order, 'paid' => true]); } if (empty($order['channel'])) { return $this->view('order/pay', ['order' => $order, 'choose' => true]); } $gw = GatewayFactory::make($order['channel']); $res = $gw->pay($order); return $this->view('order/pay', ['order' => $order, 'gw' => $res]); } /** 演示支付:模拟支付成功(默认模式可用,便于走通全流程) */ public function demo($orderNo) { $o = (new Order())->where('order_no', $orderNo); $channel = ($o && $o['channel'] === 'wechat') ? 'wechat' : 'alipay'; OrderService::markPaid($orderNo, 'DEMO' . time(), $channel); $this->redirect('order/success/' . $orderNo); } public function success($orderNo) { $order = (new Order())->where('order_no', $orderNo); if (!$order) { \Core\App::notFound(); return ''; } $payments = (new Payment())->whereAll('order_no', $orderNo); return $this->view('order/result', ['order' => $order, 'payments' => $payments]); } /** * 客户查询订单:客户名 + 手机号 双重校验 * - 必填:客户名(下单时填写的姓名/单位)+ 手机号 * - 选填:订单号(精确查单笔) */ public function query() { $orders = []; $no = ''; $name = ''; $phone = ''; $err = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST' && csrf_check()) { $no = trim($this->post('order_no', '')); $name = trim($this->post('name', '')); $phone = trim($this->post('phone', '')); if ($name === '' || $phone === '') { $err = '请输入客户名与手机号以核验身份'; } else { $om = new Order(); $pm = new Payment(); $nameKey = mb_strtolower($name, 'UTF-8'); // 客户名 + 手机号 同时匹配 $matched = array_filter($om->all(), function ($o) use ($nameKey, $phone) { $oName = mb_strtolower(trim($o['customer_name'] ?? ''), 'UTF-8'); $oPhone = trim($o['phone'] ?? ''); return $oName === $nameKey && $oPhone === $phone; }); if ($no !== '') { $matched = array_values(array_filter($matched, fn($o) => ($o['order_no'] ?? '') === $no)); } if (empty($matched)) { $err = $no !== '' ? '未找到该订单号对应的订单,请核对客户名与手机号' : '未找到匹配的客户名与手机号对应的订单'; } else { $orders = array_map(function ($o) use ($pm) { return ['order' => $o, 'payments' => $pm->whereAll('order_no', $o['order_no'])]; }, $matched); } } } return $this->view('order/query', [ 'orders' => $orders, 'no' => $no, 'name' => $name, 'phone' => $phone, 'err' => $err, ]); } private function genNo(): string { return 'SQY' . date('YmdHis') . str_pad((int) ((microtime(true) * 1000) % 1000), 3, '0', STR_PAD_LEFT); } }