vr-shopxo-plugin/shopxo/app/plugins/vr_ticket/api/Ticket.php

388 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
/**
* VR票务插件 - C端票夹API控制器
*
* 路由机制PluginsService::PluginsApiCall:
* URL: /api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=list
* → pluginsname=vr_ticket, pluginscontrol=ticket, pluginsaction=list
* → class = \app\plugins\vr_ticket\api\Ticket (ucfirst('ticket') = 'Ticket')
* → method = ucfirst('list') = 'list'
* → app/plugins/vr_ticket/api/Ticket.php::list() ✓
*
* @package vr_ticket\api
*/
namespace app\plugins\vr_ticket\api;
use app\plugins\vr_ticket\service\WalletService;
/**
* C端票夹 API
*/
class Ticket
{
private static function getUserId()
{
// 方式1X-Token / Authorization headerJS 发送方式)
$token = request()->header('X-Token') ?: request()->header('Authorization', '');
if (!empty($token)) {
$token = trim(str_replace('Bearer ', '', $token));
}
// 方式1.5UniApp 以 query 参数传入 token&token=xxx
if (empty($token)) {
$token = input('token', '', null);
}
if (!empty($token)) {
// 优先用 vrt_user_platform.token 查 DBApp 登录场景)
$user = \app\service\UserService::UserTokenData($token);
if (!empty($user) && !empty($user['id'])) {
return intval($user['id']);
}
// 如果没查到,说明是 web 登录 token存在 user_info cookie 里,不在 vrt_user_platform
// 尝试从 user_info cookie 直接解码cookie 内容 = 用户 JSON
$userInfoCookie = request()->cookie('user_info');
if (!empty($userInfoCookie)) {
$decoded = urldecode($userInfoCookie);
$userData = json_decode($decoded, true);
if (!empty($userData) && !empty($userData['id'])) {
return intval($userData['id']);
}
}
}
// 方式2ShopXO 标准方式session / cookie适用于页面直接访问场景
$user = \app\service\UserService::LoginUserInfo();
if (!empty($user) && !empty($user['id'])) {
return intval($user['id']);
}
return null;
}
/**
* 返回未登录错误
*
* @return Json
*/
private static function unauthorized(string $msg = '请先登录')
{
return [
'code' => 401,
'msg' => $msg,
'data' => [],
];
}
/**
* 返回成功响应
*
* @param mixed $data
* @param string $msg
* @return Json
*/
private static function success($data = [], string $msg = 'success')
{
return [
'code' => 0,
'msg' => $msg,
'data' => $data,
];
}
/**
* 返回错误响应
*
* @param string $msg
* @param int $code
* @return Json
*/
private static function error(string $msg = '请求失败', int $code = -1)
{
return [
'code' => $code,
'msg' => $msg,
'data' => [],
];
}
/**
* 获取用户票列表
*
* GET /api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=list
*
* @return Json
*/
public function list()
{
$userId = self::getUserId();
if (empty($userId)) {
return self::unauthorized();
}
try {
$tickets = WalletService::getUserTickets($userId);
return self::success([
'tickets' => $tickets,
'count' => count($tickets),
]);
} catch (\Exception $e) {
return self::error('获取票列表失败: ' . $e->getMessage());
}
}
/**
* 获取用户票列表tickets 别名,兼容文档格式)
*
* GET /api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=tickets
*
* @return Json
*/
public function tickets()
{
$userId = self::getUserId();
if (empty($userId)) {
return self::unauthorized();
}
try {
$tickets = WalletService::getUserTickets($userId);
return self::success([
'tickets' => $tickets,
'count' => count($tickets),
]);
} catch (\Exception $e) {
return self::error('获取票列表失败: ' . $e->getMessage());
}
}
/**
* 获取票详情(含 QR payload
*
* GET /api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=detail&id=X
*
* @return Json
*/
public function detail()
{
$userId = self::getUserId();
if (empty($userId)) {
return self::unauthorized();
}
$ticketId = input('id', 0, 'intval');
if ($ticketId <= 0) {
return self::error('参数错误票ID无效');
}
try {
$ticket = WalletService::getTicketDetail($ticketId, $userId);
if (empty($ticket)) {
return self::error('票不存在或无权访问', -404);
}
return self::success([
'ticket' => $ticket,
]);
} catch (\Exception $e) {
return self::error('获取票详情失败: ' . $e->getMessage());
}
}
/**
* 强制刷新 QR payload
*
* GET /api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=refreshQr&id=X
*
* @return Json
*/
public function refreshQr()
{
$userId = self::getUserId();
if (empty($userId)) {
return self::unauthorized();
}
$ticketId = input('id', 0, 'intval');
if ($ticketId <= 0) {
return self::error('参数错误票ID无效');
}
try {
$ticket = WalletService::refreshQrPayload($ticketId, $userId);
if (empty($ticket)) {
return self::error('票不存在或无权访问', -404);
}
return self::success([
'ticket' => $ticket,
]);
} catch (\Exception $e) {
return self::error('刷新QR失败: ' . $e->getMessage());
}
}
/**
* 扫码核销票
*
* POST /api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=verify
* Body: { ticket_code: "AB12..." }
*
* 鉴权:用户必须是 vr_verifiers 表中 status=1 的记录
* @return Json
*/
public function verify()
{
$userId = self::getUserId();
if (empty($userId)) {
return self::unauthorized();
}
// 鉴权:检查该 C 端用户是否是授权核销员
$verifier = \think\facade\Db::name('vr_verifiers')
->where('user_id', $userId)
->where('status', 1)
->find();
if (empty($verifier)) {
return self::error('你不是授权核销员,无权核销', -403);
}
$verifier_id = $verifier['id'];
$ticket_code = input('ticket_code', '', null, 'trim');
if (empty($ticket_code)) {
return self::error('票码不能为空');
}
// 自动识别短码 vs UUID短码长度 < 20 且不含连字符
$is_short_code = (strlen($ticket_code) < 20 && strpos($ticket_code, '-') === false);
if ($is_short_code) {
$result = \app\plugins\vr_ticket\service\TicketService::verifyByShortCode($ticket_code, $verifier_id);
} else {
$result = \app\plugins\vr_ticket\service\TicketService::verifyTicket($ticket_code, $verifier_id);
}
return [
'code' => $result['code'],
'msg' => $result['msg'],
'data' => $result['data'] ?? [],
];
}
/**
* 我的核销记录
*
* GET /api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=myVerifications
*
* @return Json
*/
public function myVerifications()
{
$userId = self::getUserId();
if (empty($userId)) {
return self::unauthorized();
}
// 鉴权:检查该 C 端用户是否是授权核销员
$verifier = \think\facade\Db::name('vr_verifiers')
->where('user_id', $userId)
->where('status', 1)
->find();
if (empty($verifier)) {
return self::error('你不是授权核销员', -403);
}
$verifier_id = $verifier['id'];
// 分页参数
$page = max(1, intval(input('page', 1)));
$page_size = min(100, max(10, intval(input('page_size', 20))));
$where = ['verifier_id' => $verifier_id];
$list = \think\facade\Db::name('vr_verifications')
->where($where)
->order('id', 'desc')
->page($page, $page_size)
->select();
$total = \think\facade\Db::name('vr_verifications')
->where($where)
->count();
// 关联票和商品信息
$ticket_ids = array_filter(array_column($list, 'ticket_id'));
$tickets_map = [];
if (!empty($ticket_ids)) {
$tickets_raw = \think\facade\Db::name('vr_tickets')
->where('id', 'in', $ticket_ids)
->select();
foreach ($tickets_raw as $t) {
$tickets_map[$t['id']] = $t;
}
}
$goods_ids = array_filter(array_unique(array_column($list, 'goods_id')));
$goods_map = [];
if (!empty($goods_ids)) {
$goods_list = \think\facade\Db::name('Goods')
->where('id', 'in', $goods_ids)
->column('title', 'id');
$goods_map = $goods_list;
}
$result = [];
foreach ($list as $v) {
$ticket = $tickets_map[$v['ticket_id']] ?? [];
$result[] = [
'id' => $v['id'],
'ticket_id' => $v['ticket_id'],
'ticket_code' => $v['ticket_code'],
'seat_info' => $ticket['seat_info'] ?? '',
'real_name' => $ticket['real_name'] ?? '',
'goods_title' => $goods_map[$v['goods_id']] ?? '已下架商品',
'created_at' => $v['created_at'],
];
}
return self::success([
'list' => $result,
'total' => $total,
'page' => $page,
'page_size' => $page_size,
'pages' => ceil($total / $page_size),
]);
}
/**
* 检测当前登录用户是否为授权核销员
*
* GET /api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=checkVerifier
*
* 轻量接口,用于前端快速判断是否展示核销员入口
* @return Json
*/
public function checkVerifier()
{
$userId = self::getUserId();
if (empty($userId)) {
return self::unauthorized();
}
$verifier = \think\facade\Db::name('vr_verifiers')
->where('user_id', $userId)
->where('status', 1)
->find();
return self::success([
'is_verifier' => !empty($verifier),
'verifier_id' => $verifier['id'] ?? 0,
'verifier_name' => $verifier['name'] ?? '',
]);
}
}