order_no = self::generateOrderNo(); $order->patient_id = $params['patient_id']; $order->creator_id = $params['creator_id']; $order->order_type = $params['order_type']; $order->amount = $params['amount']; $order->status = 1; // 待支付 $order->remark = $params['remark'] ?? ''; $order->save(); return $order; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * @notes 编辑订单 * @param int $id * @param array $params * @return bool */ public static function edit(int $id, array $params): bool { try { $order = Order::find($id); if (!$order) { self::setError('订单不存在'); return false; } if (isset($params['remark'])) { $order->remark = $params['remark']; } $order->save(); return true; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * @notes 支付订单 * @param int $id * @param string $paymentMethod * @return bool */ public static function pay(int $id, string $paymentMethod): bool { try { $order = Order::find($id); if (!$order) { self::setError('订单不存在'); return false; } if ($order->status != 1) { self::setError('订单状态不允许支付'); return false; } $order->status = 2; // 已支付 $order->payment_method = $paymentMethod; $order->payment_time = date('Y-m-d H:i:s'); $order->save(); return true; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * @notes 取消订单 * @param int $id * @return bool */ public static function cancel(int $id): bool { try { $order = Order::find($id); if (!$order) { self::setError('订单不存在'); return false; } if ($order->status != 1) { self::setError('只有待支付的订单才能取消'); return false; } $order->status = 3; // 已取消 $order->save(); return true; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * @notes 退款订单 * @param int $id * @return bool */ public static function refund(int $id): bool { try { $order = Order::find($id); if (!$order) { self::setError('订单不存在'); return false; } if ($order->status != 2) { self::setError('只有已支付的订单才能退款'); return false; } $order->status = 4; // 已退款 $order->save(); return true; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * @notes 删除订单 * @param int $id * @return bool */ public static function delete(int $id): bool { try { $order = Order::find($id); if (!$order) { self::setError('订单不存在'); return false; } // 删除订单 $order->delete(); return true; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * @notes 获取订单详情 * @param int $id * @return array|null */ public static function detail(int $id): ?array { $order = Order::with(['patient', 'creator']) ->find($id); if (!$order) { return null; } return $order->toArray(); } private static $error = ''; public static function setError(string $error): void { self::$error = $error; } public static function getError(): string { return self::$error; } /** * @notes 生成支付宝签名 * @param array $params * @param string $privateKey * @return string */ private static function generateAlipaySign(array $params, string $privateKey): string { // 移除sign字段 unset($params['sign']); // 按键排序 ksort($params); // 构建签名字符串 $signStr = ''; foreach ($params as $key => $value) { if ($value !== '' && $value !== null) { $signStr .= $key . '=' . $value . '&'; } } $signStr = rtrim($signStr, '&'); // 使用私钥签名 $privateKeyResource = openssl_pkey_get_private($privateKey); openssl_sign($signStr, $sign, $privateKeyResource, OPENSSL_ALGO_SHA256); openssl_free_key($privateKeyResource); return base64_encode($sign); } /** * @notes 生成微信签名 * @param array $params * @param string $apiKey * @return string */ private static function generateWechatSign(array $params, string $apiKey): string { // 移除sign字段 unset($params['sign']); // 按键排序 ksort($params); // 构建签名字符串 $signStr = ''; foreach ($params as $key => $value) { if ($value !== '' && $value !== null) { $signStr .= $key . '=' . $value . '&'; } } $signStr .= 'key=' . $apiKey; // MD5签名 return strtoupper(md5($signStr)); } /** * @notes 生成随机字符串 * @param int $length * @return string */ private static function generateNonceStr(int $length = 32): string { $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $str = ''; for ($i = 0; $i < $length; $i++) { $str .= $chars[mt_rand(0, strlen($chars) - 1)]; } return $str; } /** * @notes 支付宝支付 * @param $order * @return string|false */ public static function alipayPay($order) { try { // 这里调用支付宝SDK生成支付链接 // 示例:生成支付宝支付URL $payUrl = self::generateAlipayUrl($order); return $payUrl; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * @notes 微信支付 * @param $order * @return array|false */ public static function wechatPay($order) { try { // 这里调用微信SDK生成支付二维码或链接 // 示例:生成微信支付数据 $payData = self::generateWechatPayData($order); return $payData; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * @notes 生成支付宝支付URL * @param $order * @return string */ private static function generateAlipayUrl($order): string { try { // 获取订单号 $orderNo = is_array($order) ? $order['order_no'] : $order->order_no; $amount = is_array($order) ? ($order['amount'] ?? 0) : $order->amount; // 获取支付宝配置 $alipayConfig = config('pay.alipay'); if (empty($alipayConfig['app_id']) || empty($alipayConfig['merchant_private_key'])) { throw new \Exception('支付宝配置不完整'); } // 使用支付宝SDK生成支付URL $params = [ 'app_id' => $alipayConfig['app_id'], 'method' => 'alipay.trade.page.pay', 'charset' => 'UTF-8', 'sign_type' => 'RSA2', 'timestamp' => date('Y-m-d H:i:s'), 'version' => '1.0', 'notify_url' => $alipayConfig['notify_url'] ?: config('app.url') . '/api/order/alipay-notify', 'return_url' => $alipayConfig['return_url'] ?: config('app.url') . '/order', 'biz_content' => json_encode([ 'out_trade_no' => $orderNo, 'product_code' => 'FAST_INSTANT_TRADE_PAY', 'total_amount' => $amount, 'subject' => '订单支付', 'body' => '订单号:' . $orderNo, ], JSON_UNESCAPED_UNICODE), ]; // 生成签名 $sign = self::generateAlipaySign($params, $alipayConfig['merchant_private_key']); $params['sign'] = $sign; // 生成支付URL $payUrl = $alipayConfig['gateway_url'] . '?' . http_build_query($params); return $payUrl; } catch (\Exception $e) { self::setError($e->getMessage()); return ''; } } /** * @notes 生成微信支付数据 * @param $order * @return array */ private static function generateWechatPayData($order): array { try { // 获取订单号 $orderNo = is_array($order) ? $order['order_no'] : $order->order_no; $amount = is_array($order) ? ($order['amount'] ?? 0) : $order->amount; // 获取微信配置 $wechatConfig = config('pay.wechat'); if (empty($wechatConfig['app_id']) || empty($wechatConfig['mch_id']) || empty($wechatConfig['api_key'])) { throw new \Exception('微信支付配置不完整'); } // 生成微信支付数据 $payData = [ 'appid' => $wechatConfig['app_id'], 'mch_id' => $wechatConfig['mch_id'], 'nonce_str' => self::generateNonceStr(), 'body' => '订单支付', 'out_trade_no' => $orderNo, 'total_fee' => (int)($amount * 100), // 转换为分 'spbill_create_ip' => request()->ip() ?: '127.0.0.1', 'notify_url' => $wechatConfig['notify_url'] ?: config('app.url') . '/api/order/wechat-notify', 'trade_type' => 'NATIVE', // 二维码支付 ]; // 生成签名 $sign = self::generateWechatSign($payData, $wechatConfig['api_key']); $payData['sign'] = $sign; // 返回支付数据 return [ 'pay_url' => $wechatConfig['gateway_url'] . '/pay/unifiedorder', 'pay_data' => $payData, 'order_no' => $orderNo, ]; } catch (\Exception $e) { self::setError($e->getMessage()); return []; } } private static $orderTypeNames = [ 0 => '退款统计', 1 => '挂号费', 2 => '问诊费', 3 => '药品费用', 4 => '首付费用', 5 => '尾款费用', 6 => '其他费用', ]; /** * @notes 订单统计(按订单类型或退款) * @param array $params order_type(0退款,1挂号费,2问诊费,3药品费用,4首付,5尾款,6其他), days(0今天,7,30) * @return array */ public static function orderStats(array $params = []) { $orderType = isset($params['order_type']) ? (int)$params['order_type'] : 1; if (!array_key_exists($orderType, self::$orderTypeNames)) { $orderType = 1; } $days = isset($params['days']) ? (int)$params['days'] : 7; $endTime = !empty($params['end_time']) ? strtotime($params['end_time']) : time(); if ($days === 0) { $startTime = strtotime(date('Y-m-d')); } else { $days = $days > 0 ? min($days, 90) : 7; $startTime = strtotime("-{$days} days", $endTime); } $startStr = date('Y-m-d H:i:s', $startTime); $endStr = date('Y-m-d H:i:s', $endTime); $depts = \app\common\model\dept\Dept::where('status', 1) ->whereNull('delete_time') ->order('sort desc, id asc') ->column('name', 'id'); $query = Order::where('create_time', 'between', [$startStr, $endStr]) ->whereNull('delete_time'); if ($orderType === 0) { $query->where('status', 4); } else { $query->where('order_type', $orderType)->where('status', 2); } $orderRows = $query ->field('creator_id, count(*) as cnt, sum(amount) as total_amount') ->group('creator_id') ->select() ->toArray(); $creatorIds = array_unique(array_column($orderRows, 'creator_id')); $creatorIds = array_filter($creatorIds); if (empty($creatorIds)) { return [ 'order_type' => $orderType, 'order_type_name' => self::$orderTypeNames[$orderType], 'date_range' => [date('Y-m-d', $startTime), date('Y-m-d', $endTime)], 'today_total' => 0, 'today_amount' => '0.00', 'today_ranking' => [], 'departments' => [], 'ranking' => [], 'chart' => ['xAxis' => [], 'series' => []], ]; } $counts = []; $amounts = []; foreach ($orderRows as $row) { $counts[$row['creator_id']] = (int)$row['cnt']; $amounts[$row['creator_id']] = round((float)$row['total_amount'], 2); } $adminDepts = \app\common\model\auth\AdminDept::whereIn('admin_id', $creatorIds) ->select() ->toArray(); $adminToDepts = []; foreach ($adminDepts as $ad) { $adminId = $ad['admin_id']; if (!isset($adminToDepts[$adminId])) { $adminToDepts[$adminId] = []; } $adminToDepts[$adminId][] = (int)$ad['dept_id']; } $admins = \app\common\model\auth\Admin::whereIn('id', $creatorIds) ->whereNull('delete_time') ->column('name', 'id'); $todayStart = strtotime(date('Y-m-d')); $todayEnd = time(); $todayStr = date('Y-m-d H:i:s', $todayStart); $todayEndStr = date('Y-m-d H:i:s', $todayEnd); $todayQuery = Order::where('create_time', 'between', [$todayStr, $todayEndStr]) ->whereNull('delete_time'); if ($orderType === 0) { $todayQuery->where('status', 4); } else { $todayQuery->where('order_type', $orderType)->where('status', 2); } $todayRows = $todayQuery ->field('creator_id, count(*) as cnt, sum(amount) as total_amount') ->group('creator_id') ->select() ->toArray(); $todayCounts = []; $todayAmounts = []; foreach ($todayRows as $row) { $todayCounts[$row['creator_id']] = (int)$row['cnt']; $todayAmounts[$row['creator_id']] = round((float)$row['total_amount'], 2); } $todayTotal = array_sum($todayCounts); $todayAmount = array_sum($todayAmounts); $todayRanking = []; foreach ($creatorIds as $cid) { $cnt = (int)($todayCounts[$cid] ?? 0); $amt = (float)($todayAmounts[$cid] ?? 0); if ($cnt > 0 || $amt > 0) { $todayRanking[] = [ 'id' => (int)$cid, 'name' => $admins[$cid] ?? '未知', 'count' => $cnt, 'amount' => number_format($amt, 2, '.', ''), ]; } } usort($todayRanking, fn($a, $b) => $b['count'] <=> $a['count']); $deptData = []; $assignedIds = []; foreach ($depts as $deptId => $deptName) { $members = []; foreach ($adminToDepts as $adminId => $deptIdsArr) { if (!in_array((int)$deptId, $deptIdsArr)) { continue; } $assignedIds[] = $adminId; $members[] = [ 'id' => (int)$adminId, 'name' => $admins[$adminId] ?? '未知', 'count' => (int)($counts[$adminId] ?? 0), 'amount' => number_format((float)($amounts[$adminId] ?? 0), 2, '.', ''), ]; } $deptTotal = array_sum(array_column($members, 'count')); $deptAmount = array_sum(array_map(fn($m) => (float)$m['amount'], $members)); $deptData[] = [ 'dept_id' => (int)$deptId, 'dept_name' => $deptName, 'members' => $members, 'total' => $deptTotal, 'amount' => number_format($deptAmount, 2, '.', ''), ]; } $unassignedIds = array_diff($creatorIds, array_unique($assignedIds)); if (!empty($unassignedIds)) { $members = []; foreach ($unassignedIds as $adminId) { $members[] = [ 'id' => (int)$adminId, 'name' => $admins[$adminId] ?? '未知', 'count' => (int)($counts[$adminId] ?? 0), 'amount' => number_format((float)($amounts[$adminId] ?? 0), 2, '.', ''), ]; } $deptData[] = [ 'dept_id' => 0, 'dept_name' => '未分配部门', 'members' => $members, 'total' => array_sum(array_column($members, 'count')), 'amount' => number_format(array_sum(array_map(fn($m) => (float)$m['amount'], $members)), 2, '.', ''), ]; } $ranking = []; foreach ($creatorIds as $adminId) { $ranking[] = [ 'id' => (int)$adminId, 'name' => $admins[$adminId] ?? '未知', 'count' => (int)($counts[$adminId] ?? 0), 'amount' => number_format((float)($amounts[$adminId] ?? 0), 2, '.', ''), ]; } usort($ranking, fn($a, $b) => $b['count'] <=> $a['count']); $chartNames = []; $chartData = []; foreach ($ranking as $i => $r) { $chartNames[] = ($i + 1) . '.' . $r['name']; $chartData[] = $r['count']; } return [ 'order_type' => $orderType, 'order_type_name' => self::$orderTypeNames[$orderType], 'date_range' => [date('Y-m-d', $startTime), date('Y-m-d', $endTime)], 'today_total' => $todayTotal, 'today_amount' => number_format($todayAmount, 2, '.', ''), 'today_ranking' => $todayRanking, 'departments' => $deptData, 'ranking' => $ranking, 'chart' => [ 'xAxis' => $chartNames, 'series' => [['name' => '单数', 'data' => $chartData]], ], ]; } }