feat(Task1): seat_number display + CODE128 barcode rendering
- WalletService: add seat_number field (parseSeatNumber helper) - ticket_card.html: seat_info → seat_number in all 3 locations (card template + viewTicket modal + showTicketDetail modal) - ticket_card.html: add barcode canvas in both modals - ticket_card.html: JsBarcode() calls after renderQrCode (3 locations) - ticket_wallet.html: load JsBarcode.all.min.js before ticket_card.jsfeat/phase-b-verification
parent
d85eb8e19d
commit
29f4c61110
|
|
@ -41,6 +41,10 @@ return array (
|
|||
array (
|
||||
0 => 'app\\plugins\\vr_ticket\\hook\\ViewGoodsCss',
|
||||
),
|
||||
'plugins_view_user_various_bottom' =>
|
||||
array (
|
||||
0 => 'app\\plugins\\vr_ticket\\Hook',
|
||||
),
|
||||
),
|
||||
);
|
||||
?>
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
<?php
|
||||
namespace app\plugins\vr_ticket;
|
||||
|
||||
require_once __DIR__ . '/service/BaseService.php';
|
||||
|
||||
use app\plugins\vr_ticket\service\BaseService;
|
||||
use app\plugins\vr_ticket\service\TicketService;
|
||||
|
||||
class Hook
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@
|
|||
],
|
||||
"plugins_css_data": [
|
||||
"app\\plugins\\vr_ticket\\hook\\ViewGoodsCss"
|
||||
],
|
||||
"plugins_view_user_various_bottom": [
|
||||
"app\\plugins\\vr_ticket\\Hook"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
/**
|
||||
* VR票务插件 - C端首页/票夹控制器
|
||||
*
|
||||
* 路由机制(PluginsService::PluginsControlCall):
|
||||
* URL: ?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=index&pluginsaction=wallet
|
||||
* → pluginsname=vr_ticket, pluginscontrol=index, pluginsaction=wallet
|
||||
* → class = \app\plugins\vr_ticket\index\Index (ucfirst('index') = 'Index')
|
||||
* → method = ucfirst('wallet') = 'Wallet'
|
||||
* → app/plugins/vr_ticket/index/Index.php::Wallet() ✓
|
||||
*
|
||||
* @package vr_ticket\index
|
||||
*/
|
||||
|
||||
namespace app\plugins\vr_ticket\index;
|
||||
|
||||
use app\service\UserService;
|
||||
|
||||
class Index
|
||||
{
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// 初始化检查
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认首页(重定向到用户中心或票夹)
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return $this->wallet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 票夹页面
|
||||
*
|
||||
* URL: ?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=index&pluginsaction=wallet
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function wallet()
|
||||
{
|
||||
// 用 ShopXO 标准方式获取登录用户(session key = 'user_login_info')
|
||||
$user = UserService::LoginUserInfo();
|
||||
if (empty($user)) {
|
||||
// 未登录,重定向到登录页
|
||||
return redirect(MyUrl('index/user/logininfo'));
|
||||
}
|
||||
|
||||
// 渲染票夹页面
|
||||
return MyView('../../../plugins/vr_ticket/view/goods/ticket_wallet', [
|
||||
'user' => $user,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
namespace app\plugins\vr_ticket\service;
|
||||
|
||||
require_once __DIR__ . '/BaseService.php';
|
||||
|
||||
class AuditService
|
||||
{
|
||||
// ========================
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
namespace app\plugins\vr_ticket\service;
|
||||
|
||||
use think\facade\Db;
|
||||
require_once __DIR__ . '/BaseService.php';
|
||||
|
||||
class SeatSkuService extends BaseService
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
namespace app\plugins\vr_ticket\service;
|
||||
|
||||
require_once __DIR__ . '/BaseService.php';
|
||||
|
||||
class WalletService extends BaseService
|
||||
{
|
||||
/**
|
||||
|
|
@ -85,7 +87,8 @@ class WalletService extends BaseService
|
|||
'id' => $ticket['id'],
|
||||
'goods_id' => $ticket['goods_id'],
|
||||
'goods_title' => $goodsMap[$ticket['goods_id']] ?? '已下架商品',
|
||||
'seat_info' => $ticket['seat_info'] ?? '',
|
||||
'seat_info' => $ticket['seat_info'] ?? '', // 完整 5 维(保留)
|
||||
'seat_number' => self::parseSeatNumber($ticket['seat_info'] ?? ''), // 仅座位号
|
||||
'session_time' => $seatInfo['session'] ?? '',
|
||||
'venue_name' => $seatInfo['venue'] ?? '',
|
||||
'real_name' => $ticket['real_name'] ?? '',
|
||||
|
|
@ -93,12 +96,25 @@ class WalletService extends BaseService
|
|||
'verify_status' => $ticket['verify_status'],
|
||||
'issued_at' => $ticket['issued_at'],
|
||||
'short_code' => $shortCode,
|
||||
'seat_number' => self::parseSeatNumber($ticket['seat_info'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取座位号(seat_info 最后一个 | 分段)
|
||||
* @param string $seatInfo 完整 5 维坐席信息
|
||||
* @return string 仅座位号
|
||||
*/
|
||||
public static function parseSeatNumber(string $seatInfo): string
|
||||
{
|
||||
if (empty($seatInfo)) return '';
|
||||
$parts = explode('|', $seatInfo);
|
||||
return end($parts) ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取票详情
|
||||
*
|
||||
|
|
@ -160,6 +176,7 @@ class WalletService extends BaseService
|
|||
'verify_time' => $ticket['verify_time'] ?? 0,
|
||||
'issued_at' => $ticket['issued_at'],
|
||||
'short_code' => $shortCode,
|
||||
'seat_number' => self::parseSeatNumber($ticket['seat_info'] ?? ''),
|
||||
'qr_payload' => $qrData['payload'],
|
||||
'qr_expires_at' => $qrData['expires_at'],
|
||||
'qr_expires_in' => $qrData['expires_in'],
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@
|
|||
</div>
|
||||
<div class="vr-ticket-info-row">
|
||||
<span class="vr-ticket-info-icon">💺</span>
|
||||
<span>{{seat_info}}</span>
|
||||
<span>{{seat_number}}</span>
|
||||
</div>
|
||||
<div class="vr-ticket-info-row">
|
||||
<span class="vr-ticket-info-icon">👤</span>
|
||||
|
|
@ -273,7 +273,7 @@
|
|||
* 3. 调用 VrTicketWallet.loadTickets() 加载票列表
|
||||
*/
|
||||
var VrTicketWallet = (function() {
|
||||
var apiBase = '<?php echo Config("shopxo.host_url"); ?>?s=api/plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=';
|
||||
var apiBase = '<?php echo Config("shopxo.host_url"); ?>/api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=';
|
||||
var token = '';
|
||||
var tickets = [];
|
||||
var currentTicket = null;
|
||||
|
|
@ -436,6 +436,7 @@ var VrTicketWallet = (function() {
|
|||
'<div class="vr-ticket-short-code-display">' +
|
||||
'<div class="vr-ticket-short-code-label">短码(人工核销)</div>' +
|
||||
'<div class="vr-ticket-short-code-value">' + escapeHtml(ticket.short_code) + '</div>' +
|
||||
'<canvas id="vrBarcodeCanvas" style="margin-top:8px;max-width:100%;display:block;"></canvas>' +
|
||||
'</div>' +
|
||||
'<div class="vr-ticket-detail-row">' +
|
||||
'<div class="vr-ticket-detail-label">状态</div>' +
|
||||
|
|
@ -451,7 +452,7 @@ var VrTicketWallet = (function() {
|
|||
'</div>' +
|
||||
'<div class="vr-ticket-detail-row">' +
|
||||
'<div class="vr-ticket-detail-label">座位</div>' +
|
||||
'<div class="vr-ticket-detail-value">' + escapeHtml(ticket.seat_info) + '</div>' +
|
||||
'<div class="vr-ticket-detail-value">' + escapeHtml(ticket.seat_number) + '</div>' +
|
||||
'</div>' +
|
||||
'<div class="vr-ticket-detail-row">' +
|
||||
'<div class="vr-ticket-detail-label">观演人</div>' +
|
||||
|
|
@ -485,6 +486,7 @@ var VrTicketWallet = (function() {
|
|||
'<div class="vr-ticket-short-code-display">' +
|
||||
'<div class="vr-ticket-short-code-label">短码(人工核销)</div>' +
|
||||
'<div class="vr-ticket-short-code-value">' + escapeHtml(ticket.short_code) + '</div>' +
|
||||
'<canvas id="vrBarcodeCanvas" style="margin-top:8px;max-width:100%;display:block;"></canvas>' +
|
||||
'</div>' +
|
||||
verifiedBadge +
|
||||
'<div class="vr-ticket-detail-row">' +
|
||||
|
|
@ -497,7 +499,7 @@ var VrTicketWallet = (function() {
|
|||
'</div>' +
|
||||
'<div class="vr-ticket-detail-row">' +
|
||||
'<div class="vr-ticket-detail-label">座位</div>' +
|
||||
'<div class="vr-ticket-detail-value">' + escapeHtml(ticket.seat_info) + '</div>' +
|
||||
'<div class="vr-ticket-detail-value">' + escapeHtml(ticket.seat_number) + '</div>' +
|
||||
'</div>' +
|
||||
'<div class="vr-ticket-detail-row">' +
|
||||
'<div class="vr-ticket-detail-label">观演人</div>' +
|
||||
|
|
@ -508,6 +510,7 @@ var VrTicketWallet = (function() {
|
|||
// 渲染 QR 码
|
||||
if (ticket.qr_payload) {
|
||||
renderQrCode(ticket.qr_payload, ticket.qr_expires_in);
|
||||
try { var bc = document.getElementById('vrBarcodeCanvas'); if (bc && ticket.short_code) { JsBarcode(bc, ticket.short_code, {format:'CODE128', width:2, height:60, displayValue:true, fontSize:14, margin:5}); } } catch(e){}
|
||||
} else {
|
||||
document.getElementById('vrQrcodeBox').innerHTML = '<div style="color:#999;">QR加载中...</div>';
|
||||
}
|
||||
|
|
@ -555,6 +558,7 @@ var VrTicketWallet = (function() {
|
|||
}));
|
||||
|
||||
renderQrCode(ticket.qr_payload, expiresIn);
|
||||
try { var bc = document.getElementById('vrBarcodeCanvas'); if (bc && ticket.short_code) { JsBarcode(bc, ticket.short_code, {format:'CODE128', width:2, height:60, displayValue:true, fontSize:14, margin:5}); } } catch(e){}
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
|
|
@ -622,6 +626,7 @@ var VrTicketWallet = (function() {
|
|||
|
||||
// 重新渲染 QR
|
||||
renderQrCode(ticket.qr_payload, ticket.qr_expires_in);
|
||||
try { var bc = document.getElementById('vrBarcodeCanvas'); if (bc && ticket.short_code) { JsBarcode(bc, ticket.short_code, {format:'CODE128', width:2, height:60, displayValue:true, fontSize:14, margin:5}); } } catch(e){}
|
||||
|
||||
if (btn) {
|
||||
btn.textContent = '已刷新';
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
<!-- 引入票卡片组件样式和JS -->
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="<?php echo Config('shopxo.host_url'); ?>plugins/vr_ticket/static/css/ticket_card.css?v=<?php echo time(); ?>" />
|
||||
<script src="<?php echo Config('shopxo.host_url'); ?>public/static/common/lib/hiprint/plugins/JsBarcode.all.min.js"></script>
|
||||
<script src="<?php echo Config('shopxo.host_url'); ?>plugins/vr_ticket/static/js/ticket_card.js?v=<?php echo time(); ?>"></script>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
Loading…
Reference in New Issue