vr-shopxo-plugin/shopxo/app/plugins/vr_ticket/Hook.php

241 lines
12 KiB
PHP
Raw Normal View History

<?php
namespace app\plugins\vr_ticket;
use app\plugins\vr_ticket\service\TicketService;
class Hook
{
public function handle($params = [])
{
if(!empty($params['hook_name']))
{
$ret = '';
switch($params['hook_name'])
{
// 后台左侧菜单钩子
case 'plugins_service_admin_menu_data':
$this->AdminSidebarInit($params['admin_left_menu']);
break;
// 订单支付成功处理
case 'plugins_service_order_pay_success_handle_end':
$ret = TicketService::onOrderPaid($params);
break;
case 'plugins_service_order_detail_page_info':
// C端订单详情页注入票夹入口
$ret = $this->InjectTicketCard($params);
break;
case 'plugins_service_order_delete_success':
// 如果有删除拦截等
break;
}
return $ret;
}
}
public function AdminSidebarInit(&$params)
{
$params[] = [
'id' => 'plugins-vr_ticket',
'name' => 'VR票务',
'title' => 'VR票务',
'icon' => 'am-icon-ticket',
'control' => 'admin',
'action' => 'index',
'is_show' => 1,
'power' => 'vr_ticket-admin',
'url' => PluginsAdminUrl('vr_ticket', 'admin', 'index'),
'item' => [
[
'id' => 'plugins-vr_ticket-venue',
'name' => '场馆配置',
'title' => '场馆配置',
'is_show' => 1,
'control' => 'admin',
'action' => 'VenueList',
'url' => PluginsAdminUrl('vr_ticket', 'admin', 'VenueList'),
'power' => 'vr_ticket-venueList',
],
[
'id' => 'plugins-vr_ticket-seat',
'name' => '座位模板',
'title' => '座位模板',
'is_show' => 1,
'control' => 'admin',
'action' => 'SeatTemplateList',
'url' => PluginsAdminUrl('vr_ticket', 'admin', 'SeatTemplateList'),
'power' => 'vr_ticket-seatTemplateList',
],
[
'id' => 'plugins-vr_ticket-ticket',
'name' => '电子票',
'title' => '电子票',
'is_show' => 1,
'control' => 'admin',
'action' => 'TicketList',
'url' => PluginsAdminUrl('vr_ticket', 'admin', 'TicketList'),
'power' => 'vr_ticket-ticketList',
],
[
'id' => 'plugins-vr_ticket-verifier',
'name' => '核销员',
'title' => '核销员',
'is_show' => 1,
'control' => 'admin',
'action' => 'VerifierList',
'url' => PluginsAdminUrl('vr_ticket', 'admin', 'VerifierList'),
'power' => 'vr_ticket-verifierList',
],
[
'id' => 'plugins-vr_ticket-varification',
'name' => '核销记录',
'title' => '核销记录',
'is_show' => 1,
'control' => 'admin',
'action' => 'VerificationList',
'url' => PluginsAdminUrl('vr_ticket', 'admin', 'VerificationList'),
'power' => 'vr_ticket-verificationList',
],
[
'id' => 'plugins-vr_ticket-setup',
'name' => '插件设置',
'title' => '插件设置',
'is_show' => 1,
'control' => 'admin',
'action' => 'Setup',
'url' => PluginsAdminUrl('vr_ticket', 'admin', 'Setup'),
'power' => 'vr_ticket-setup',
]
]
];
}
/**
* C端订单详情页注入票卡片
*/
public function InjectTicketCard(&$params)
{
$order = $params['order'] ?? [];
if (empty($order) || ($order['pay_status'] ?? 0) != 1) {
return;
}
$userId = session('user_id');
if (empty($userId)) {
return;
}
$tickets = \think\facade\Db::name('vr_tickets')
->where('order_id', $order['id'])
->select()
->toArray();
if (empty($tickets)) {
return;
}
$token = session('user_token') ?: '';
$hostUrl = \think\facade\Config::get('shopxo.host_url');
$ticketCardsHtml = '';
foreach ($tickets as $ticket) {
$shortCode = \app\plugins\vr_ticket\service\BaseService::shortCodeEncode($ticket['goods_id'], $ticket['id']);
$statusMap = [0 => ['text' => '未核销', 'class' => 'unverified'], 1 => ['text' => '已核销', 'class' => 'verified'], 2 => ['text' => '已退款', 'class' => 'refunded']];
$status = $statusMap[$ticket['verify_status']] ?? $statusMap[0];
$ticketCardsHtml .= '<div class="vr-ticket-card" data-ticket-id="' . $ticket['id'] . '">' .
'<div class="vr-ticket-card-header">' .
'<div class="vr-ticket-goods-title">电子票</div>' .
'<div class="vr-ticket-status ' . $status['class'] . '">' . $status['text'] . '</div>' .
'</div>' .
'<div class="vr-ticket-info">' .
'<div class="vr-ticket-info-row"><span class="vr-ticket-info-icon">💺</span><span>' . htmlspecialchars($ticket['seat_info'] ?? '') . '</span></div>' .
'<div class="vr-ticket-info-row"><span class="vr-ticket-info-icon">👤</span><span>' . htmlspecialchars($ticket['real_name'] ?? '') . '</span></div>' .
'</div>' .
'<div class="vr-ticket-footer">' .
'<div class="vr-ticket-short-code">短码: ' . htmlspecialchars($shortCode) . '</div>' .
'<a href="javascript:;" class="vr-ticket-view-btn" onclick="VrTicketWallet.viewTicket(' . $ticket['id'] . ')">查看票码 →</a>' .
'</div>' .
'</div>';
}
$style = '<style>
.vr-ticket-card { background: #fff; border-radius: 12px; padding: 16px; margin: 12px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.06); cursor: pointer; }
.vr-ticket-card:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.12); }
.vr-ticket-card-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; }
.vr-ticket-goods-title { font-size: 16px; font-weight: 600; color: #333; }
.vr-ticket-status { font-size: 12px; padding: 2px 8px; border-radius: 4px; font-weight: 500; }
.vr-ticket-status.unverified { background: #e6f7ff; color: #1890ff; }
.vr-ticket-status.verified { background: #f6ffed; color: #52c41a; }
.vr-ticket-status.refunded { background: #fff1f0; color: #ff4d4f; }
.vr-ticket-info { font-size: 13px; color: #666; line-height: 1.6; }
.vr-ticket-info-row { display: flex; align-items: center; margin-bottom: 4px; }
.vr-ticket-info-icon { width: 16px; color: #999; margin-right: 6px; }
.vr-ticket-footer { display: flex; justify-content: space-between; align-items: center; margin-top: 12px; padding-top: 12px; border-top: 1px solid #f0f0f0; }
.vr-ticket-short-code { font-size: 14px; font-family: "Courier New", monospace; color: #333; font-weight: 600; letter-spacing: 1px; }
.vr-ticket-view-btn { font-size: 13px; color: #1890ff; text-decoration: none; }
.vr-ticket-view-btn:hover { text-decoration: underline; }
</style>';
$ticketHtml = '<div class="vr-order-ticket-section">' .
'<div style="font-size:16px;font-weight:600;margin-bottom:12px;">📋 我的电子票</div>' .
$ticketCardsHtml .
'</div>';
$params['page_data']['ticket_section'] = $ticketHtml;
$params['page_data']['ticket_css'] = $style;
// JS
$js = '<script>
(function() {
var apiBase = "' . $hostUrl . '?s=api/plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=";
var token = "' . htmlspecialchars($token) . '";
window.VrTicketWallet = {
viewTicket: function(ticketId) {
var modal = document.getElementById("vrTicketModal") || createModal();
modal.classList.add("active");
var body = document.getElementById("vrTicketModalBody");
body.innerHTML = \'<div style="text-align:center;padding:40px;">加载中...</div>\';
$.ajax({
url: apiBase + "detail&id=" + ticketId,
headers: token ? {"X-Token": token} : {},
success: function(res) {
if (res.code === 0 && res.data.ticket) {
var t = res.data.ticket;
var statusMap = {0:{text:"未核销",class:"unverified"},1:{text:"已核销",class:"verified"},2:{text:"已退款",class:"refunded"}};
var status = statusMap[t.verify_status] || statusMap[0];
body.innerHTML = \'<div style="text-align:center;padding:20px;background:#fafafa;border-radius:12px;"><div id="vrQrcodeBox"></div></div>\' +
\'<div style="text-align:center;margin:16px 0;padding:12px;background:#f5f5f5;border-radius:8px;">\' +
\'<div style="font-size:12px;color:#999;margin-bottom:4px;">短码(人工核销)</div>\' +
\'<div style="font-size:20px;font-family:monospace;font-weight:700;letter-spacing:2px;">\' + t.short_code + \'</div></div>\' +
\'<div style="text-align:center;"><span class="vr-ticket-status \' + status.class + \'">\' + status.text + \'</span></div>\';
if (t.qr_payload) {
$("#vrQrcodeBox").qrcode({text: atob(t.qr_payload), width: 180, height: 180});
}
}
}
});
},
closeModal: function() {
var modal = document.getElementById("vrTicketModal");
if (modal) modal.classList.remove("active");
}
};
function createModal() {
var html = \'<div id="vrTicketModal" style="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:9999;display:none;align-items:center;justify-content:center;">\' +
\'<div style="background:#fff;border-radius:16px;width:90%;max-width:400px;padding:24px;"><div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;">\' +
\'<div style="font-size:18px;font-weight:600;">电子票</div><button onclick="VrTicketWallet.closeModal()" style="width:28px;height:28px;border-radius:50%;background:#f0f0f0;border:none;cursor:pointer;">×</button></div>\' +
\'<div id="vrTicketModalBody"></div></div></div>\';
document.body.insertAdjacentHTML("beforeend", html);
var modal = document.getElementById("vrTicketModal");
modal.addEventListener("click", function(e) { if (e.target === modal) VrTicketWallet.closeModal(); });
return modal;
}
})();
</script>';
$params['page_data']['ticket_js'] = $js;
}
}
?>