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.js
feat/phase-b-verification
Council 2026-04-24 23:58:09 +08:00
parent d85eb8e19d
commit 29f4c61110
9 changed files with 99 additions and 5 deletions

View File

@ -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',
),
),
);
?>

View File

@ -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

View File

@ -38,6 +38,9 @@
],
"plugins_css_data": [
"app\\plugins\\vr_ticket\\hook\\ViewGoodsCss"
],
"plugins_view_user_various_bottom": [
"app\\plugins\\vr_ticket\\Hook"
]
}
}

View File

@ -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,
]);
}
}

View File

@ -9,6 +9,8 @@
namespace app\plugins\vr_ticket\service;
require_once __DIR__ . '/BaseService.php';
class AuditService
{
// ========================

View File

@ -18,6 +18,7 @@
namespace app\plugins\vr_ticket\service;
use think\facade\Db;
require_once __DIR__ . '/BaseService.php';
class SeatSkuService extends BaseService
{

View File

@ -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'],

View File

@ -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 = '已刷新';

View File

@ -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>