Files
zyt/server/app/adminapi/controller/order/OrderController.php
T
2026-04-22 12:14:39 +08:00

526 lines
18 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace app\adminapi\controller\order;
use app\adminapi\controller\BaseAdminController;
use app\adminapi\lists\order\OrderLists;
use app\adminapi\logic\order\OrderActionLogLogic;
use app\adminapi\logic\order\OrderLogic;
use app\adminapi\validate\order\OrderValidate;
/**
* 订单管理控制器
* Class OrderController
* @package app\adminapi\controller\order
*/
class OrderController extends BaseAdminController
{
/**
* @notes 订单列表
* @return \think\response\Json
*/
public function lists()
{
return $this->dataLists(new OrderLists());
}
/**
* @notes 指定诊单下已支付支付单列表(创建/编辑处方业务订单时多选关联)
* @return \think\response\Json
*/
public function paidOrdersForDiagnosis()
{
$diagnosisId = (int) $this->request->get('diagnosis_id', 0);
if ($diagnosisId <= 0) {
return $this->fail('诊单ID必填');
}
$exceptPo = (int) $this->request->get('prescription_order_id', 0);
$lists = OrderLogic::listPaidOrdersForDiagnosis(
$diagnosisId,
$this->adminId,
$this->adminInfo,
$exceptPo > 0 ? $exceptPo : null
);
return $this->success('', ['lists' => $lists]);
}
/**
* @notes 同步企业微信对外收款账单到订单
* 员工直接在企业微信发起收款(未经过后台创建)时,通过此接口拉取并创建订单
* @return \think\response\Json
*/
public function syncWechatWorkBills()
{
$beginStr = $this->request->get('begin_time', date('Y-m-d', strtotime('-7 days')));
$endStr = $this->request->get('end_time', date('Y-m-d'));
$beginTime = strtotime($beginStr . ' 00:00:00');
$endTime = strtotime($endStr . ' 23:59:59');
if ($beginTime >= $endTime) {
return $this->fail('开始时间必须早于结束时间');
}
if ($endTime - $beginTime > 31 * 86400) {
return $this->fail('企业微信接口限制:时间范围不能超过31天');
}
$result = OrderLogic::syncFromWechatWorkBills($beginTime, $endTime);
if (!empty($result['errors']) && $result['created'] === 0 && $result['updated'] === 0) {
return $this->fail(implode('', $result['errors']));
}
return $this->success('同步完成', $result);
}
/**
* @notes 调试:测试企业微信对外收款 API 连接(返回原始响应,用于排查同步为0的问题)
* @return \think\response\Json
*/
public function syncWechatWorkBillsDebug()
{
$beginStr = $this->request->get('begin_time', date('Y-m-d'));
$endStr = $this->request->get('end_time', date('Y-m-d'));
$payeeUserid = trim((string)$this->request->get('payee_userid', ''));
$beginTime = strtotime($beginStr . ' 00:00:00');
$endTime = strtotime($endStr . ' 23:59:59');
$service = new \app\common\service\wechat\WechatWorkExternalPayService();
$config = config('pay.wechat_work', []);
$debug = [
'config_ok' => !empty($config['corp_id']) && !empty($config['external_pay_secret']),
'corp_id' => $config['corp_id'] ? substr($config['corp_id'], 0, 8) . '***' : '(空)',
'time_range' => [$beginStr, $endStr],
'payee_userid' => $payeeUserid ?: '(未指定,查全部)',
'access_token' => $service->getAccessToken() ? '已获取' : '获取失败',
];
$resp = $service->getBillList($beginTime, $endTime, $payeeUserid, '', 100);
$debug['api_errcode'] = $resp['errcode'] ?? -999;
$debug['api_errmsg'] = $resp['errmsg'] ?? '';
$debug['bill_count'] = count($resp['bill_list'] ?? []);
$debug['next_cursor'] = !empty($resp['next_cursor']) ? '有' : '无';
$debug['page1'] = $resp;
if (!empty($resp['next_cursor']) && $debug['bill_count'] === 0) {
$resp2 = $service->getBillList($beginTime, $endTime, $payeeUserid, $resp['next_cursor'], 100);
$debug['page2_errcode'] = $resp2['errcode'] ?? -999;
$debug['page2_bill_count'] = count($resp2['bill_list'] ?? []);
$debug['page2_sample'] = isset($resp2['bill_list'][0]) ? $resp2['bill_list'][0] : null;
}
if ($debug['bill_count'] === 0 && empty($payeeUserid)) {
$admins = \app\common\model\auth\Admin::where('work_wechat_userid', '<>', '')
->whereNull('delete_time')->column('work_wechat_userid', 'id');
$debug['try_payee_userids'] = array_values(array_filter(array_unique($admins)));
$debug['tip'] = '若 try_payee_userids 有值,可传 payee_userid=xxx 重试(如 ?payee_userid=GaoXingLiang';
}
return $this->success('调试信息', $debug);
}
/**
* @notes 今日收益(按角色权限)
* @return \think\response\Json
*/
public function todayRevenue()
{
$result = OrderLogic::todayRevenue($this->adminId, $this->adminInfo);
return $this->data($result);
}
/**
* @notes 订单统计(挂号费/药品费用)
* @return \think\response\Json
*/
public function orderStats()
{
$params = $this->request->get();
$result = OrderLogic::orderStats($params);
return $this->data($result);
}
/**
* @notes 订单详情
* @return \think\response\Json
*/
public function detail()
{
$params = (new OrderValidate())->post()->goCheck('detail');
$orderId = (int)$params['id'];
$detail = OrderLogic::detail($orderId);
if (!$detail) {
return $this->fail('订单不存在');
}
$this->logOrderAction($orderId, 'view_detail', '查看订单详情');
return $this->data($detail);
}
/**
* @notes 支付单操作日志(单条订单,分页)
*/
public function actionLogs()
{
$orderId = (int)$this->request->get('order_id', 0);
if ($orderId <= 0) {
return $this->fail('order_id 必填');
}
$pageNo = (int)$this->request->get('page_no', 1);
$pageSize = (int)$this->request->get('page_size', 20);
$data = OrderActionLogLogic::listByOrderId($orderId, $pageNo, $pageSize);
return $this->success('', $data);
}
/**
* @notes 按人统计操作次数(时间范围内)
* @return \think\response\Json
*/
public function actionLogStats()
{
$start = trim((string)$this->request->get('start_time', ''));
$end = trim((string)$this->request->get('end_time', ''));
if ($start === '' || $end === '') {
$endTime = time();
$startTime = $endTime - 7 * 86400;
} else {
$startTime = strtotime($start . ' 00:00:00') ?: 0;
$endTime = strtotime($end . ' 23:59:59') ?: 0;
}
if ($startTime <= 0 || $endTime < $startTime) {
return $this->fail('时间范围无效');
}
$limit = (int)$this->request->get('limit', 50);
$rows = OrderActionLogLogic::statsByAdmin($startTime, $endTime, $limit);
return $this->success('', [
'list' => $rows,
'start_time' => date('Y-m-d H:i:s', $startTime),
'end_time' => date('Y-m-d H:i:s', $endTime),
]);
}
/**
* @notes 创建订单
* @return \think\response\Json
*/
public function create()
{
$params = (new OrderValidate())->post()->goCheck('create');
$params['creator_id'] = $this->adminId;
$params['payment_channel'] = (string)$this->request->post('payment_channel', 'normal');
$params['require_payment_slip_audit'] = (int)$this->request->post('require_payment_slip_audit', 0);
$result = OrderLogic::create($params);
if (!$result) {
return $this->fail(OrderLogic::getError());
}
$this->logOrderAction((int)$result->id, 'create', '创建支付单(普通/付呗等)');
return $this->success('创建成功', $result->toArray());
}
/**
* @notes 创建企业微信对外收款订单
* 返回 order_no,供员工在企业微信发起收款时作为商户订单号(out_trade_no)使用
* 收款成功后,微信支付回调会自动更新订单为已支付
* @return \think\response\Json
*/
public function createForWechatWork()
{
$params = (new OrderValidate())->post()->goCheck('create');
$params['creator_id'] = $this->adminId;
$result = OrderLogic::createForWechatWork($params);
if (!$result) {
return $this->fail(OrderLogic::getError());
}
$ord = $result['order'] ?? null;
if (is_array($ord) && !empty($ord['id'])) {
$this->logOrderAction((int)$ord['id'], 'create_wechat_work', '创建支付单(企业微信对外收款)');
}
return $this->success('创建成功,请在企业微信收款时使用以下订单号', [
'order_no' => $result['order_no'],
'order' => $result['order'],
'tip' => '在企业微信发起对外收款时,将上述订单号填写为「商户订单号」',
]);
}
/**
* @notes 批量指派医助(写入 order.assistant_id,并记操作日志)
*/
public function assignAssistant()
{
$params = (new OrderValidate())->post()->goCheck('assign_assistant');
$rawIds = $params['order_ids'] ?? [];
if (!\is_array($rawIds) || $rawIds === []) {
return $this->fail('请选择订单');
}
$orderIds = array_map('intval', $rawIds);
$orderIds = array_values(array_unique(array_filter($orderIds, static fn (int $id) => $id > 0)));
if ($orderIds === []) {
return $this->fail('请选择有效订单');
}
$allowed = [];
foreach ($orderIds as $id) {
$order = \app\common\model\Order::find($id);
if (!$order) {
continue;
}
if (!$this->canEditOrder($order)) {
return $this->fail('无权限操作订单:' . (string) ($order->order_no ?? $id));
}
$allowed[] = $id;
}
if ($allowed === []) {
return $this->fail('没有可指派的订单');
}
$assistantId = (int) $params['assistant_id'];
$result = OrderLogic::batchAssignAssistant($allowed, $assistantId);
if ($result === false) {
return $this->fail(OrderLogic::getError());
}
foreach ($result['per_log'] as $row) {
$this->logOrderAction((int) $row['order_id'], 'assign_assistant', (string) ($row['summary'] ?? ''));
}
$msg = '已变更「创建人」' . (int) $result['success'] . ' 单';
if (!empty($result['errors'])) {
$msg .= ',说明:' . implode('', $result['errors']);
}
return $this->success($msg, $result);
}
/**
* @notes 编辑订单(关联患者、订单类型)
* 权限:超管或指定角色组可修改任意订单;其他用户只能修改自己创建的订单
* @return \think\response\Json
*/
public function edit()
{
$params = (new OrderValidate())->post()->goCheck('edit');
$orderId = (int)$params['id'];
$order = \app\common\model\Order::find($orderId);
if (!$order) {
return $this->fail('订单不存在');
}
if (!$this->canEditOrder($order)) {
return $this->fail('无权限修改此订单');
}
$result = OrderLogic::edit($orderId, $params);
if (!$result) {
return $this->fail(OrderLogic::getError());
}
$this->logOrderAction($orderId, 'edit', '编辑患者/订单类型等');
return $this->success('编辑成功');
}
/**
* @notes 是否可编辑指定订单(超管或指定角色可编辑任意,否则只能编辑自己创建的)
*/
private function canEditOrder($order): bool
{
if (!empty($this->adminInfo['root']) && $this->adminInfo['root'] == 1) {
return true;
}
$editAllRoles = config('project.order_edit_all_roles', [0, 3]);
$roleIds = \app\common\model\auth\AdminRole::where('admin_id', $this->adminId)->column('role_id');
if (count(array_intersect($roleIds, $editAllRoles)) > 0) {
return true;
}
return (int)$order->creator_id === $this->adminId;
}
/**
* @notes 支付订单
* @return \think\response\Json
*/
public function pay()
{
$params = (new OrderValidate())->post()->goCheck('pay');
// 判断是否是补单支付
if (!empty($params['is_supplement']) && $params['is_supplement'] == 1) {
// 补单支付:通过订单号查找订单
if (empty($params['order_no'])) {
return $this->fail('补单支付需要提供订单号');
}
$order = \app\common\model\Order::where('order_no', $params['order_no'])->find();
if (!$order) {
return $this->fail('订单不存在');
}
$orderId = $order->id;
} else {
// 正常支付:通过订单ID
if (empty($params['id'])) {
return $this->fail('订单ID不能为空');
}
$orderId = (int)$params['id'];
}
$result = OrderLogic::pay($orderId, $params['payment_method']);
if (!$result) {
return $this->fail(OrderLogic::getError());
}
$this->logOrderAction($orderId, 'pay', '确认支付/标记已付,方式:' . (string)($params['payment_method'] ?? ''));
return $this->success('支付成功');
}
/**
* @notes 取消订单
* @return \think\response\Json
*/
public function cancel()
{
$params = (new OrderValidate())->post()->goCheck('cancel');
$oid = (int)$params['id'];
$result = OrderLogic::cancel($oid);
if (!$result) {
return $this->fail(OrderLogic::getError());
}
$this->logOrderAction($oid, 'cancel', '取消订单');
return $this->success('取消成功');
}
/**
* @notes 退款订单
* @return \think\response\Json
*/
public function refund()
{
$params = (new OrderValidate())->post()->goCheck('refund');
$oid = (int)$params['id'];
$result = OrderLogic::refund($oid);
if (!$result) {
return $this->fail(OrderLogic::getError());
}
$this->logOrderAction($oid, 'refund', '退款');
return $this->success('退款成功');
}
/**
* @notes 删除订单
* @return \think\response\Json
*/
public function delete()
{
$params = (new OrderValidate())->post()->goCheck('delete');
$oid = (int)$params['id'];
$result = OrderLogic::delete($oid);
if (!$result) {
return $this->fail(OrderLogic::getError());
}
$this->logOrderAction($oid, 'delete', '删除订单(软删)');
return $this->success('删除成功');
}
/**
* @notes 导出订单
* @return \think\response\Json
*/
public function export()
{
return $this->dataLists(new OrderLists());
}
/**
* @notes 支付宝支付
* @return \think\response\Json
*/
public function alipay()
{
$params = (new OrderValidate())->post()->goCheck('pay');
// 补单支付不需要校验订单是否存在
if (!empty($params['is_supplement']) && $params['is_supplement'] == 1) {
// 补单支付:直接返回支付URL,不校验订单
$payUrl = OrderLogic::alipayPay(['order_no' => $params['order_no']]);
if (!$payUrl) {
return $this->fail(OrderLogic::getError());
}
return $this->data(['pay_url' => $payUrl]);
}
// 正常支付需要校验订单
$order = $this->getOrderByParams($params);
if (!$order) {
return $this->fail('订单不存在');
}
// 调用支付宝支付接口
$payUrl = OrderLogic::alipayPay($order);
if (!$payUrl) {
return $this->fail(OrderLogic::getError());
}
return $this->data(['pay_url' => $payUrl]);
}
/**
* @notes 微信支付
* @return \think\response\Json
*/
public function wechat()
{
$params = (new OrderValidate())->post()->goCheck('pay');
// 补单支付不需要校验订单是否存在
if (!empty($params['is_supplement']) && $params['is_supplement'] == 1) {
// 补单支付:直接返回支付数据,不校验订单
$payData = OrderLogic::wechatPay(['order_no' => $params['order_no']]);
if (!$payData) {
return $this->fail(OrderLogic::getError());
}
return $this->data($payData);
}
// 正常支付需要校验订单
$order = $this->getOrderByParams($params);
if (!$order) {
return $this->fail('订单不存在');
}
// 调用微信支付接口
$payData = OrderLogic::wechatPay($order);
if (!$payData) {
return $this->fail(OrderLogic::getError());
}
return $this->data($payData);
}
/**
* @notes 根据参数获取订单
* @param array $params
* @return mixed
*/
private function getOrderByParams(array $params)
{
if (!empty($params['is_supplement']) && $params['is_supplement'] == 1) {
// 补单支付:通过订单号查找
if (empty($params['order_no'])) {
return null;
}
return \app\common\model\Order::where('order_no', $params['order_no'])->find();
} else {
// 正常支付:通过订单ID
if (empty($params['id'])) {
return null;
}
return \app\common\model\Order::find((int)$params['id']);
}
}
private function logOrderAction(int $orderId, string $action, string $summary = ''): void
{
OrderActionLogLogic::record($orderId, (int) $this->adminId, $this->adminInfo, $action, $summary);
}
}