<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FSE閾佽矾鐢靛瓙瀹㈢エ</title>
    <link rel="icon" type="image/png" href="/FSE-ticket.png">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <link rel="stylesheet" href="/style.css?v=12">
    <style>
        [v-cloak] {
            display: none;
        }

        body.jr-ticket-board-page {
            display: block !important;
            overflow-y: auto !important;
            min-height: 100vh !important;
            width: 100% !important;
            background: linear-gradient(180deg, #eef4ee 0, #eef4ee 146px, #f7f8f4 146px, #f7f8f4 100%) !important;
        }

        body.jr-ticket-board-page #app,
        body.jr-ticket-board-page .jr-public-shell,
        body.jr-ticket-board-page .jr-topbar,
        body.jr-ticket-board-page .jr-brandbar,
        body.jr-ticket-board-page .jr-public-main {
            display: block !important;
            width: 100% !important;
            min-width: 0 !important;
            margin-left: 0 !important;
            margin-right: 0 !important;
            float: none !important;
        }

        body.jr-ticket-board-page .jr-topbar-inner,
        body.jr-ticket-board-page .jr-brandbar-inner,
        body.jr-ticket-board-page .jr-public-main {
            width: min(1280px, calc(100% - 40px)) !important;
            margin: 0 auto !important;
        }
    </style>
</head>

<body class="public-search jr-public-page jr-ticket-board-page">
    <div id="app" v-cloak class="jr-public-shell">
        <header class="jr-topbar">
            <div class="jr-topbar-inner">
                <a href="javascript:void(0)" @click="goHome" class="jr-top-link">
                    <i class="fas fa-arrow-left"></i>
                    <span>杩斿洖鏌ヨ</span>
                </a>
                <div class="jr-top-status is-checking" data-server-status-root>
                    <span class="jr-top-status-label">鏈嶅姟鍣ㄧ姸鎬?/span>
                        <span class="jr-top-status-dot"></span>
                        <span class="jr-top-status-value" data-server-status-value>妫€娴嬩腑</span>
                </div>
            </div>
        </header>
        <div class="jr-brandbar">
            <div class="jr-brandbar-inner">
                <a href="javascript:void(0)" @click="goHome" class="jr-brand">
                    <img src="/FSE-ticket.png" alt="FSE Railway" class="jr-brand-logo" />
                    <div class="jr-brand-copy">
                        <strong>FSE閾佽矾绁ㄥ姟绯荤粺</strong>
                        <span>鐢靛瓙瀹㈢エ淇℃伅</span>
                    </div>
                </a>
                <nav class="jr-nav" aria-label="绔欑偣瀵艰埅">
                    <a href="https://ticket.fse-media.group/home.html" data-link="home">棣栭〉</a>
                    <a href="https://ticket.fse-media.group/order" data-link="order">绾夸笂棰勫畾</a>
                    <a href="https://ticket.fse-media.group/search" data-link="search" class="is-active">杞︾エ鏌ヨ</a>
                    <a href="https://ticket.fse-media.group/ic-card/search" data-link="card-search">IC 鍗℃煡璇?/a>
                        <a href="https://ticket.fse-media.group/ic-card/order" data-link="card-order">绾夸笂璐崱</a>
                </nav>
            </div>
        </div>
        <main class="jr-public-main">
            <section class="jr-page-intro">
                <span class="jr-kicker">ELECTRONIC TICKET</span>
                <h1>鏌ョ湅杞︾エ鐘舵€佷笌鏈€杩戞祦杞褰?/h1>
                    <p>鐢ㄤ簬鏌ョ湅鍗曞紶鐢靛瓙瀹㈢エ鐨勪箻杞︿俊鎭€佺姸鎬佷笌杩涘嚭绔欒褰曪紝渚夸簬鏃呭鍜屽伐浣滀汉鍛樺揩閫熺‘璁ょエ鎹姸鎬併€?/p>
            </section>
            <div v-if="loading" class="jr-panel-card">
                <div class="jr-center-empty">
                    <p>姝ｅ湪璇诲彇绁ㄦ嵁鏁版嵁...</p>
                </div>
            </div>
            <template v-if="!loading && hasTicket">
                <section class="jr-board-layout">
                    <article class="jr-board-card">
                        <div class="jr-panel-headline">
                            <h2 class="mono">{{ ticket.ticket_id }}</h2>
                            <span class="jr-status-pill" :class="statusInfo.class.replace('status-', 'jr-status-')">{{
                                statusInfo.text }}</span>
                        </div>
                        <div class="jr-route-board">
                            <div class="jr-station-block">
                                <div class="jr-station-line">
                                    <span class="jr-station-title">{{ ticket.overview.start_name }}</span>
                                    <span class="jr-station-code">{{ ticket.overview.start_code }}</span>
                                </div>
                                <div class="jr-station-en">{{ ticket.overview.start_en }}</div>
                            </div>
                            <div class="jr-route-track"><i class="fas fa-train"></i></div>
                            <div class="jr-station-block is-end">
                                <div class="jr-station-line">
                                    <span class="jr-station-title">{{ ticket.overview.terminal_name }}</span>
                                    <span class="jr-station-code">{{ ticket.overview.terminal_code }}</span>
                                </div>
                                <div class="jr-station-en">{{ ticket.overview.terminal_en }}</div>
                            </div>
                        </div>
                        <div class="jr-meta-grid">
                            <div class="jr-meta-item">
                                <span>杞﹀瀷</span>
                                <strong>{{ formatTrainType(ticket.overview.train_type) }}</strong>
                            </div>
                            <div class="jr-meta-item">
                                <span>绁ㄤ环</span>
                                <strong>楼 {{ ticket.overview.amount || 0 }}</strong>
                            </div>
                            <div class="jr-meta-item">
                                <span>涔樻</span>
                                <strong>{{ (ticket.overview.trips_remaining == null ? 1 :
                                    ticket.overview.trips_remaining) }} / {{ (ticket.overview.trips_total == null ? 1 :
                                    ticket.overview.trips_total) }}</strong>
                            </div>
                            <div class="jr-meta-item">
                                <span>鏇存柊鏃堕棿</span>
                                <strong>{{ formatTime(ticket.overview.last_update_ts) }}</strong>
                            </div>
                        </div>
                    </article>
                    <aside class="jr-board-card">
                        <div class="jr-panel-headline">
                            <h3>娴佽浆璁板綍</h3>
                            <span class="jr-panel-note">Recent Events</span>
                        </div>
                        <div class="jr-history-list" v-if="ticket.events && ticket.events.length > 0">
                            <div v-for="ev in ticket.events.slice().reverse().slice(0, 5)"
                                :key="ev.ts || ev.鏃堕棿鎴? class="jr-history-item">
                                <div class="jr-history-row">
                                    <span class="jr-history-title">{{ formatEvent(ev) }}</span>
                                    <span class="jr-history-time">{{ formatTime(ev.鏃堕棿鎴?|| ev.ts) }}</span>
                                </div>
                                <div class="jr-history-desc">
                                    <div>{{ formatEventLocation(ev) }}</div>
                                    <div v-if="formatEventMeta(ev)" style="margin-top:4px;">{{ formatEventMeta(ev) }}
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div v-else class="jr-center-empty">
                            <p>鏆傛棤娴佽浆璁板綍銆?/p>
                        </div>
                    </aside>
                </section>
            </template>

            <div v-if="!loading && !hasTicket" class="jr-panel-card">
                <div class="jr-center-empty">
                    <h2 style="margin:0 0 10px;">鏃犳晥杞︾エ</h2>
                    <p>鏈壘鍒拌杞︾エ鐨勮缁嗕俊鎭€?/p>
                    <div class="jr-action-row">
                        <button @click="goHome" class="btn primary jr-search-button">杩斿洖鏌ヨ</button>
                    </div>
                </div>
            </div>

            <footer class="site-footer jr-footer-space">
                <a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer">绮CP澶?025450093鍙?/a>
                    <span class="version">v1.0.12</span>
            </footer>
        </main>
    </div>

    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="/custom-dialog.js?v=11"></script>
    <script src="/public-status.js?v=13"></script>
    <script src="/ai-assistant.js?v=6"></script>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const isDomain = location.hostname.includes('fse-media.group');
            const links = {
                home: isDomain ? 'https://ticket.fse-media.group' : '/home.html',
                order: isDomain ? 'https://ticket.fse-media.group/order' : '/ticket-order.html',
                search: isDomain ? 'https://ticket.fse-media.group/search' : '/ticket-search.html',
                'card-search': isDomain ? 'https://ticket.fse-media.group/ic-card/search' : '/ic-card-search.html',
                'card-order': isDomain ? 'https://ticket.fse-media.group/ic-card/order' : '/ic-card-order.html'
            };

            document.querySelectorAll('[data-link]').forEach((el) => {
                const key = el.getAttribute('data-link');
                if (links[key]) el.href = links[key];
            });
        });
    </script>
    <script>
        const { createApp, ref, onMounted, computed } = Vue;

        createApp({
            setup() {
                const loading = ref(true);
                const ticket = ref(null);

                const sp = new URLSearchParams(window.location.search);
                const idFromQuery = sp.get('id') || '';
                const pathParts = window.location.pathname.split('/').filter(Boolean);
                const idFromPath = pathParts.length ? pathParts[pathParts.length - 1] : '';
                const ticketid = decodeURIComponent(idFromPath || idFromQuery || '');

                const hasTicket = computed(() => {
                    return ticket.value && (ticket.value.ticket_id || ticket.value.id) && ticket.value.overview != null;
                });

                const statusInfo = computed(() => {
                    if (!hasTicket.value) return {};
                    let raw = '';
                    if (ticket.value && ticket.value.overview) {
                        if (ticket.value.overview.status != null) raw = ticket.value.overview.status;
                    }
                    if (!raw && ticket.value) {
                        if (ticket.value.status != null) raw = ticket.value.status;
                    }
                    const status = String(raw).toLowerCase();

                    if (
                        status === '鏈夋晥' ||
                        status === 'valid' ||
                        status === 'unused' ||
                        status === 'active' ||
                        status.includes('鏈夋晥') ||
                        status.includes('鏈娇鐢?) ||
                        status.includes('unused')
                        ) {
                        return { text: '鏈夋晥', class: 'status-valid' };
                    }
                    if (status === '宸蹭娇鐢? || status === 'used' || status.includes('宸蹭娇鐢?) || status.includes('used')) {
                        return { text: '宸蹭娇鐢?, class: 'status-used' };
                    }
                    return { text: '澶辨晥', class: 'status-expired' };
                });

                const formatTime = (timestamp) => {
                    if (!timestamp) return '---';
                    let ts = Number(timestamp);
                    if (!Number.isFinite(ts)) return String(timestamp);
                    if (ts > 0 && ts < 1000000000000) ts = ts * 1000;
                    const date = new Date(ts);
                    return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit'});
                };

                const formatEvent = (event) => {
                    const type = String(event.type || event.绫诲瀷 || '').toLowerCase();
                    const action = String(event.action || event.鍔ㄤ綔 || '').toLowerCase();

                    if (type === '鐘舵€? || type === 'status') {
                        const actionMap = { 'entry': '杩涚珯鎴愬姛', 'exit': '鍑虹珯鎴愬姛' };
                        return actionMap[action] || '鐘舵€佸彉鏇?;
                    }

                    const typeMap = { 'sale': '鍞エ鎴愬姛', '鍞エ': '鍞エ鎴愬姛', 'entry': '杩涚珯鎴愬姛', 'exit': '鍑虹珯鎴愬姛' };
                    return typeMap[type] || event.type || event.绫诲瀷 || '鐘舵€佸彉鏇?;
                };

                const formatEventLocation = (event) => {
                    const type = String(event.type || event.绫诲瀷 || '').toLowerCase();
                    const stationName = event.station_name || event.鍞エ绔?|| event.鍙戠敓绔?|| '';
                    const stationCode = event.station_code || event.绔欑偣缂栧彿 || '';

                    if (type === 'sale' || type === '鍞エ') {
                        return stationName || '绾夸笂鍞エ';
                    }

                    if (!stationName && !stationCode) return '---';
                    return [stationName, stationName && stationCode ? stationCode : ''].filter(Boolean).join(' ');
                };

                const formatEventMeta = (event) => {
                    const type = String(event.type || event.绫诲瀷 || '').toLowerCase();
                    if (type === 'sale' || type === '鍞エ') {
                        const amount = event.amount ?? event.鍞エ棰?
                        if (amount != null && amount !== '') return `绁ㄤ环锛毬?${amount}`;
                    }

                    const stationEn = event.station_en || event.绔欑偣鑻辨枃 || '';
                    const deviceId = event.device_id || event.璁惧缂栧彿 || '';
                    if (stationEn && deviceId) return `${stationEn} (${deviceId})`;
                    if (deviceId) return `璁惧锛?{deviceId}`;
                    return stationEn;
                };

                const formatTrainType = (type) => {
                    if (!type) return '鏅€?;
                    const t = type.toLowerCase();
                    if (t === 'local') return '鏅€?;
                    if (t === 'ltd.exp' || t === 'express' || t === 'exp' || t === 'express_train') return '鐗规€?;
                    if (t.includes('鐗规€?)) return '鐗规€?;
                    return String(type);
                };

                const fetchData = async () => {
                    loading.value = true;
                    ticket.value = null; 

                    try {
                        const response = await fetch(`/api/public/tickets/${ticketid}`);
                        if (response.status === 404) {
                            ticket.value = null;
                        } else {
                            const data = await response.json();
                            const id = (data && (data.ticket_id || data.杞︾エ缂栧彿 || data.id)) || ticketid;
                            let overview = null;
                            if (data) {
                                if (data.overview != null) overview = data.overview;
                                else if (data.姒傝 != null) overview = data.姒傝;
                                else if (data.summary != null) overview = data.summary;
                            }
                            let events = [];
                            if (data) {
                                if (Array.isArray(data.events)) events = data.events;
                                else if (data.浜嬩欢 != null) events = data.浜嬩欢;
                            }
                            if (id && overview != null) {
                                const out = {};
                                if (data && typeof data === 'object') {
                                    for (const k in data) out[k] = data[k];
                                }
                                out.ticket_id = id;
                                out.overview = overview;
                                out.events = events;
                                ticket.value = out;
                            } else {
                                ticket.value = null;
                            }
                        }
                    } catch (e) {
                        console.error('鑾峰彇杞︾エ鏁版嵁澶辫触:', e);
                        ticket.value = null;
                    } finally {
                        loading.value = false;
                    }
                };

                const goHome = () => {
                    if (window.location.hostname.includes('fse-media.group')) {
                        window.location.href = 'https://ticket.fse-media.group/search';
                    } else {
                        window.location.href = '/ticket-search.html';
                    }
                };

                onMounted(() => {
                    fetchData();
                });

                return { 
                    loading, ticket, hasTicket, statusInfo, 
                    formatTime, formatEvent, formatEventLocation, formatEventMeta, formatTrainType, goHome 
                };
            }
        }).mount('#app');
    </script>



</body>

</html>

