!DOCTYPE html
html lang=zh-HK
head
meta charset=UTF-8
meta name=viewport content=width=device-width, initial-scale=1.0, viewport-fit=cover
title西鐵紅van通title
style
root {
--primary-color #7A1F1F; 招牌深邃棗紅
--accent-color #FFD700; 高對比亮黃
--bg-color #121212; 暗黑背景
--text-light #FFFFFF;
--success-color #2ecc71; 綠色
--danger-color #e74c3c; 亮紅色
--panel-bg #1e1e1e;
--warning-bar #f39c12;
}
{ margin 0; padding 0; box-sizing border-box; font-family sans-serif; }
body {
background-color var(--bg-color); color var(--text-light);
padding-top 75px; padding-bottom 100px; min-height 100vh;
display flex; flex-direction column;
}
頂部導航欄 (強制雙行置中)
.top-bar {
position fixed; top 0; left 0; width 100%;
background-color var(--primary-color); padding 10px 0;
text-align center; box-shadow 0 2px 10px rgba(0,0,0,0.5); z-index 1000;
}
.top-bar .company-name { color var(--accent-color); font-size 1.1rem; font-weight bold; }
.top-bar .developer-name { color var(--accent-color); font-size 0.8rem; opacity 0.9; }
網絡斷線動態提示條
.status-toast {
background-color var(--warning-bar); color #000; text-align center;
padding 6px; font-size 0.85rem; font-weight bold; position fixed;
top 65px; left 0; width 100%; z-index 999; display none;
}
.main-container { flex 1; padding 15px; max-width 600px; margin 0 auto; width 100%; }
.app-header { text-align center; margin 15px 0; }
.app-header h1 { color var(--accent-color); font-size 2.2rem; }
☕ 轉數快打賞
.coffee-box {
background linear-gradient(135deg, #2c1f1f, #1f1414);
border 2px dashed var(--accent-color); border-radius 12px;
padding 15px; text-align center; margin-bottom 20px;
}
.fps-code {
display inline-block; background-color var(--primary-color); color var(--accent-color);
padding 6px 12px; font-size 1.2rem; font-weight bold; border-radius 6px; cursor pointer;
}
角色登入區
.login-section {
background-color var(--panel-bg); border 1px solid #333; border-radius 12px; padding 20px; margin-bottom 20px;
}
.login-section h2 { color var(--accent-color); margin-bottom 15px; font-size 1.3rem; text-align center; }
.phone-input {
width 100%; padding 12px; background-color #000; border 1px solid #444;
color #fff; font-size 1.1rem; border-radius 8px; margin-bottom 15px; text-align center;
}
.btn-login-group { display flex; flex-direction column; gap 12px; }
.btn-universal {
background-color var(--primary-color); color var(--accent-color);
padding 14px; border 1px solid var(--accent-color); border-radius 8px;
font-size 1.05rem; font-weight bold; cursor pointer; transition background-color 0.1s;
}
.btn-universalactive { background-color #551313; }
🔒 司機未授權攔截
.approval-waiting-panel {
background-color #2c1a1a; border 2px solid var(--danger-color); border-radius 12px;
padding 25px; text-align center; margin-bottom 20px; display none;
}
.approval-waiting-panel h3 { color var(--danger-color); margin-bottom 15px; }
工作台主區
.core-workspace { display none; }
.matrix-title { color var(--accent-color); font-size 1.2rem; margin-bottom 12px; border-left 5px solid var(--primary-color); padding-left 10px; font-weight bold; }
路線配置操作區
.route-config-panel {
background-color var(--panel-bg); border 1px solid #333; border-radius 12px; padding 15px; margin-bottom 20px;
}
.route-select-box {
width 100%; padding 12px; background-color #000; border 2px solid var(--primary-color);
color #fff; font-size 1.1rem; border-radius 8px; margin-bottom 12px; font-weight bold;
}
.custom-route-input {
width 100%; padding 10px; background-color #000; border 1px solid #555; color #fff; border-radius 6px; margin-bottom 12px; display none;
}
大輝哥超級指揮總台
.super-admin-panel {
background linear-gradient(135deg, #3a0d0d, #1e1e1e); border 2px solid var(--accent-color);
border-radius 12px; padding 20px; margin-bottom 25px; display none;
}
.super-grid { display grid; grid-template-columns repeat(2, 1fr); gap 12px; margin-top 15px; }
.btn-super-power {
background-color #000; color var(--accent-color); border 1px solid var(--accent-color);
padding 12px 10px; font-size 0.9rem; font-weight bold; border-radius 6px; cursor pointer; text-align center;
}
🚖 司機端工作台
.driver-seats-panel {
background-color #1a252f; border 1px solid #34495e; border-radius 12px; padding 15px; margin-bottom 25px; display none;
}
.seat-config-row { display flex; gap 10px; margin-bottom 15px; }
.btn-seat-choice { flex 1; padding 10px; background-color #2c3e50; color #fff; border 1px solid #7f8c8d; border-radius 6px; font-weight bold; cursor pointer; }
.btn-seat-choice.active { background-color var(--accent-color); color #000; border-color var(--accent-color); }
.counter-row { display flex; justify-content space-between; align-items center; background-color #000; padding 15px; border-radius 8px; margin-bottom 15px; }
.counter-display { font-size 1.8rem; font-weight bold; color var(--accent-color); line-height 1.3; }
.counter-btn-group { display flex; gap 10px; }
.btn-counter { width 55px; height 55px; border-radius 8px; border none; font-size 1.8rem; font-weight bold; cursor pointer; background-color var(--primary-color); color var(--accent-color); }
.btn-full-trigger {
background-color var(--success-color); color #fff; width 100%; padding 14px;
border none; border-radius 8px; font-size 1.1rem; font-weight bold; cursor pointer;
transition all 0.2s ease;
}
.btn-full-trigger.is-full { background-color var(--danger-color) !important; }
👤 乘客端看板
.passenger-view-panel { display none; }
.live-status-card { background-color var(--panel-bg); border 1px solid #333; border-radius 12px; padding 20px; text-align center; box-shadow 0 4px 6px rgba(0,0,0,0.3); margin-bottom 20px; }
.live-route-display { font-size 1.2rem; font-weight bold; color var(--accent-color); margin-bottom 15px; }
.live-seats-display { font-size 2.2rem; font-weight bold; margin-bottom 15px; }
@keyframes pulse-gps {
0% { transform scale(1); box-shadow 0 0 0 0 rgba(46, 204, 113, 0.7); }
70% { transform scale(1.02); box-shadow 0 0 0 10px rgba(46, 204, 113, 0); }
100% { transform scale(1); box-shadow 0 0 0 0 rgba(46, 204, 113, 0); }
}
.btn-gps-active {
background-color var(--success-color) !important; color #fff !important;
animation pulse-gps 1.5s infinite;
}
西鐵群組真實通訊攻略
.comm-guide-grid { display grid; grid-template-columns repeat(2, 1fr); gap 12px; margin-bottom 25px; }
.comm-card { background-color #1e1e1e; border 1px solid #444; border-radius 10px; padding 15px; text-align center; }
.comm-card h4 { color var(--accent-color); margin-bottom 8px; font-size 1.1rem; }
.comm-card p { font-size 0.8rem; color #aaa; margin-bottom 10px; }
.debug-console { background-color #000; border 1px solid #222; border-radius 8px; padding 12px; font-family monospace; font-size 0.8rem; color #39ff14; height 110px; overflow-y auto; margin-top 15px; }
底部導航
.bottom-nav {
position fixed; bottom 0; left 0; width 100%; background-color #1a1a1a; border-top 1px solid #333;
display flex; justify-content space-around; padding-top 12px; padding-bottom calc(12px + env(safe-area-inset-bottom)); z-index 1000;
}
.nav-item { background none; border none; color #888; font-size 0.95rem; font-weight bold; cursor pointer; }
.nav-item.active { color var(--accent-color); }
.logout-box { text-align right; margin-bottom 10px; }
.btn-logout { background none; border none; color #aaa; font-size 0.85rem; text-decoration underline; cursor pointer; }
style
head
body
div class=top-bar
div class=company-name浚鍵管理有限公司div
div class=developer-name開發者-大輝div
div
div class=status-toast id=statusToast📡 正在連接西鐵紅van通實時中樞...div
div class=main-container
div class=app-header
h1西鐵紅van通h1
div
div class=coffee-box
p☕ 如果覺得 App 好用,請大輝飲杯咖啡啦!p
div class=fps-code onclick=copyFPS()轉數快碼 122891914div
div
div class=login-section id=loginSection
h2系統角色登入驗證h2
input type=number class=phone-input id=phoneInput placeholder=請輸入香港手機號碼
div class=btn-login-group
button class=btn-universal onclick=doLogin('Passenger')👤 乘客安全登入button
button class=btn-universal onclick=doLogin('Driver')🚖 司機審批登入button
button class=btn-universal onclick=doLogin('SuperAdmin')⚡ 超級版主大輝入口button
div
div
div class=approval-waiting-panel id=approvalWaitingPanel
h3🚖 浚鍵管理安全系統提示h3
p style=line-height 1.6; margin-bottom 15px;您的帳號正在審核中,目前【未獲授權】。br請耐心等待版主大輝批准後方可開工使用。p
button class=btn-universal style=width 100%; padding 10px; font-size 0.9rem; onclick=doLogout(true)返回登入主頁button
div
div class=core-workspace id=coreWorkspace
div class=logout-box
button class=btn-logout onclick=doLogout()[ 🔄 登出 切換角色 ]button
div
div class=super-admin-panel id=superAdminPanel
div style=display flex; justify-content space-between; align-items center; margin-bottom 10px;
span style=font-weight bold; color var(--accent-color); font-size 1.2rem;⚡ 大輝超級指揮總台span
div
div style=background-color#000; padding10px; border-radius6px; font-size0.9rem; margin-bottom10px;
📋 申請開工司機:span id=pendingDriverDisplay style=colorvar(--accent-color); font-weightbold;暫無新申請span
button id=btnApproveDriver class=btn-universal style=padding4px 10px; font-size0.8rem; floatright; margin-top-3px; displaynone; onclick=approveDriverAction()親自批准開工button
div
div class=super-grid
button class=btn-super-power onclick=superAction('RESET_ALL')🔄 全線數據強制歸零button
button class=btn-super-power onclick=superAction('BLOCK_USER')🚫 強制永久封鎖用家button
button class=btn-super-power onclick=superAction('CALC_PAYROLL')💰 計算司機當班薪酬button
button class=btn-super-power onclick=superAction('BROADCAST')📢 全港車隊緊急廣播button
div
div
div class=workspace-role-header id=workspaceTitle style=font-weight bold; color var(--accent-color); margin-bottom 15px; font-size 1.1rem; text-align center;實時智慧工作台div
div class=route-config-panel
div style=font-weight bold; margin-bottom 8px; color var(--accent-color);🗺️ 當班營運路線配置div
select class=route-select-box id=routeSelect onchange=handleRouteSelectChange()
option value=ROUTE_01大棠黃泥墩 ⇄ 元朗西鐵站option
option value=ROUTE_02錦田水流田 ⇄ 元朗西鐵站option
option value=ROUTE_CUSTOM➕ [自由路線輸入]option
select
input type=text class=custom-route-input id=customRouteInput placeholder=請手動輸入自訂起點及終點 (如 屯門 ⇄ 旺角) oninput=syncLiveDisplay()
button class=btn-universal style=width100%; padding 10px; font-size 0.95rem; id=btnReverseRoute onclick=reverseRoute()🔄 起點與終點對調按鈕button
div
div class=driver-seats-panel id=driverSeatsPanel
div style=font-weight bold; margin-bottom 8px; color var(--accent-color);🚖 司機座位實時申報系統div
div class=seat-config-row
button class=btn-seat-choice active id=btnSeat16 onclick=setTotalSeats(16)16 座舊款車button
button class=btn-seat-choice id=btnSeat19 onclick=setTotalSeats(19)19 座新款車button
div
div class=counter-row
div
div style=font-size0.85rem; color#aaa;已上車乘客 (從0開始)div
div class=counter-display id=passengerCountDisplay style=color #fff;0 人div
div
div
div style=font-size0.85rem; color#aaa;實時賸餘空位div
div class=counter-display id=emptySeatsDisplay16 個位div
div
div class=counter-btn-group
button class=btn-counter onclick=adjustPassengers(-1)-button
button class=btn-counter onclick=adjustPassengers(1)+button
div
div
button class=btn-full-trigger id=btnFullHouse onclick=triggerFullHouse()申報滿座button
div
div class=passenger-view-panel id=passengerViewPanel
div style=font-weight bold; margin-bottom 8px; color var(--accent-color);👤 實時紅VAN當班狀態看板div
div class=live-status-card
div class=live-route-display id=liveRouteName大棠黃泥墩 ⇄ 元朗西鐵站div
div class=live-seats-display id=liveSeatsText🚺 剩餘空位 16div
button class=btn-universal style=width100%; transition all 0.3s; id=btnReservePassenger onclick=triggerPassengerGpsRadar(this)📡 我在此上車button
div
div
div class=matrix-title💬 西鐵紅van通群組通訊攻略div
div class=comm-guide-grid
div class=comm-card
h4西鐵 A 群組h4
p車務調度留位中心p
button class=btn-universal style=padding 8px 12px; font-size 0.9rem; width 100%; onclick=joinTrueGroup('httpschat.whatsapp.comBAK4sPyQjDP61OXfTXxxdT')進入 A 群button
div
div class=comm-card
h4西鐵 B 群組h4
p車務調度留位中心p
button class=btn-universal style=padding 8px 12px; font-size 0.9rem; width 100%; onclick=joinTrueGroup('httpschat.whatsapp.comDP7vMUnUEQtC63BB4Xel4S')進入 B 群button
div
div class=comm-card
h4西鐵 C 群組h4
p車務調度留位中心p
button class=btn-universal style=padding 8px 12px; font-size 0.9rem; width 100%; onclick=joinTrueGroup('httpschat.whatsapp.comFGWXQ7MbxlpK9zxLp2Cxk4')進入 C 群button
div
div class=comm-card
h4西鐵 D 群組h4
p車務調度留位中心p
button class=btn-universal style=padding 8px 12px; font-size 0.9rem; width 100%; onclick=joinTrueGroup('httpschat.whatsapp.comGJQxt5dxf2qJugAODTDB1M')進入 D 群button
div
div
div class=matrix-title系統實時日誌div
div class=debug-console id=debugConsole[系統提示] 請先完成角色登入。div
div
div
nav class=bottom-nav
button class=nav-item activespan[ 主頁 ]spanbutton
button class=nav-item onclick=window.open('httpswww.google.commaps@22.3954,113.9749,16z', '_blank')span[ 地圖 ]spanbutton
button class=nav-item onclick=window.open('httpsapi.whatsapp.comsendphone=&text=你好,大輝哥!我想查詢西鐵紅van通群組調度事宜。', '_blank')span[ 通訊 ]spanbutton
nav
script
let state = {
role '',
phone '',
currentRouteTitle '大棠黃泥墩 ⇄ 元朗西鐵站',
totalSeats 16,
passengers 0,
isReversed false
};
const NetworkHub = {
socket null,
💡 大輝哥!放上 Cloudflare 後,將下面呢行換成你專屬嘅真 Workers wss 網址即可!
wsUrl 'wssyour-van-worker.dahui.workers.dev',
init function() {
if(state.role === '') return;
logToConsole(`🌐 正在建立全港實時數據連動 (WebSocket)...`);
document.getElementById('statusToast').style.display = 'block';
document.getElementById('statusToast').innerText = 📡 正在同步雲端車務數據中...;
try {
this.socket = new WebSocket(this.wsUrl);
this.socket.onopen = () = {
logToConsole(⚡ [網絡對接] 成功連通雲端總台!實時零延遲同步解鎖。);
document.getElementById('statusToast').style.display = 'none';
this.broadcastToServer({
type 'auth',
userId state.phone,
role state.role
});
};
this.socket.onmessage = (event) = {
try {
const data = JSON.parse(event.data);
this.handleIncomingBroadcast(data);
} catch (e) {}
};
this.socket.onclose = () = {
document.getElementById('statusToast').style.display = 'block';
document.getElementById('statusToast').innerText = ⚠️ 訊號微弱!正在發動 Tunnel-Proof 全自動重連保護...;
logToConsole(⚠️ 網絡連線斷開,5秒後全自動重新對接後端...);
setTimeout(() = this.init(), 5000);
};
} catch (err) {
console.log(WS 異常,切換至沙盒沙箱環境。);
}
},
broadcastToServer function(msgObj) {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(JSON.stringify(msgObj));
}
},
handleIncomingBroadcast function(data) {
if (data.type === SEAT_SYNC && state.role === Passenger) {
state.totalSeats = data.totalSeats;
state.passengers = data.passengers;
state.currentRouteTitle = data.routeTitle;
logToConsole(`🔔 [即時更新] 司機已動態更新座位!剩餘空位:${data.totalSeats - data.passengers}`);
syncUI(false);
}
if (data.type === SYSTEM_SHUTDOWN) {
alert(data.message);
doLogout(true);
}
if (data.type === EMERGENCY_ALERT) {
alert(`【大輝哥全線緊急公告】nn${data.message}`);
logToConsole(`📢 收到全體公告 ${data.message}`);
}
}
};
let passengerGpsWatchId = null;
if(localStorage.getItem('van_realtime_state')) {
state = JSON.parse(localStorage.getItem('van_realtime_state'));
}
let approvedDriversList = JSON.parse(localStorage.getItem('van_approved_drivers')) [];
let pendingDriverPhone = localStorage.getItem('van_pending_driver') '';
function saveState(triggerNetworkBroadcast = true) {
localStorage.setItem('van_realtime_state', JSON.stringify(state));
syncUI();
if (triggerNetworkBroadcast && (state.role === 'Driver' state.role === 'SuperAdmin')) {
NetworkHub.broadcastToServer({
type 'SEAT_SYNC',
totalSeats state.totalSeats,
passengers state.passengers,
routeTitle state.currentRouteTitle
});
}
}
function logToConsole(message) {
const consoleEl = document.getElementById('debugConsole');
const time = new Date().toLocaleTimeString();
consoleEl.innerHTML += `br[${time}] ${message}`;
consoleEl.scrollTop = consoleEl.scrollHeight;
}
async function copyFPS() {
await navigator.clipboard.writeText('122891914');
alert('轉數快碼 122891914 已複製!多謝大輝哥!☕');
}
門戶登入
function doLogin(role, bypassPasswordCheck = false) {
let phone = '';
if (bypassPasswordCheck) {
phone = state.phone;
} else {
phone = document.getElementById('phoneInput').value.trim();
if (phone.length 8) { alert('請輸入有效的香港手機號碼!'); return; }
state.phone = phone;
state.role = role;
}
if (role === 'Driver') {
if (!approvedDriversList.includes(phone)) {
pendingDriverPhone = phone;
localStorage.setItem('van_pending_driver', phone);
document.getElementById('loginSection').style.display = 'none';
document.getElementById('approvalWaitingPanel').style.display = 'block';
logToConsole(`⚠️ 司機 ${phone} 企圖登入,已被攔截!狀態:等待大輝哥審批。`);
return;
}
}
if (role === 'SuperAdmin' && !bypassPasswordCheck) {
let pwd = prompt(請輸入超級版主大輝的最高權力密碼:);
if (pwd !== Fai64989786) { alert(超級權力校驗失敗!); return; }
}
localStorage.setItem('van_logged_user', JSON.stringify({ role role, phone phone }));
document.getElementById('loginSection').style.display = 'none';
document.getElementById('approvalWaitingPanel').style.display = 'none';
document.getElementById('coreWorkspace').style.display = 'block';
if (role === 'SuperAdmin') {
document.getElementById('superAdminPanel').style.display = 'block';
refreshSuperAdminApprovalSection();
}
const titleMap = {
'Passenger' `👤 乘客看板 (手機 ${state.phone})`,
'Driver' `🚖 司機控制台 (手機 ${state.phone})`,
'SuperAdmin' `⚡ 大輝超級控制台 (最高絕對權限)`
};
document.getElementById('workspaceTitle').innerText = titleMap[role];
NetworkHub.init();
if (bypassPasswordCheck) {
logToConsole(`⚡ [免驗證自動登入] 歡迎回來!已回復上一次操作狀態。`);
} else {
logToConsole(`👤 身份儲存成功!下次打開此 App 將自動秒進工作台。`);
}
saveState(false);
}
function doLogout(silent = false) {
if(silent confirm(確定要登出並清除自動登入紀錄嗎?)) {
if(passengerGpsWatchId) { navigator.geolocation.clearWatch(passengerGpsWatchId); }
localStorage.removeItem('van_logged_user');
localStorage.removeItem('van_realtime_state');
if(!silent) alert(已成功登出。);
window.location.reload();
}
}
function refreshSuperAdminApprovalSection() {
const displayEl = document.getElementById('pendingDriverDisplay');
const btnEl = document.getElementById('btnApproveDriver');
if (pendingDriverPhone) {
displayEl.innerText = `${pendingDriverPhone} (等待您批准)`;
displayEl.style.color = 'var(--danger-color)';
btnEl.style.display = 'inline-block';
} else {
displayEl.innerText = 暫無新司機申請開工;
displayEl.style.color = 'var(--success-color)';
btnEl.style.display = 'none';
}
}
function approveDriverAction() {
if (pendingDriverPhone && !approvedDriversList.includes(pendingDriverPhone)) {
approvedDriversList.push(pendingDriverPhone);
localStorage.setItem('van_approved_drivers', JSON.stringify(approvedDriversList));
logToConsole(`解鎖成功:大輝哥已批准司機 ${pendingDriverPhone} 的開工授權!`);
alert(`成功批准司機 ${pendingDriverPhone} 開工!`);
pendingDriverPhone = '';
localStorage.removeItem('van_pending_driver');
refreshSuperAdminApprovalSection();
}
}
🗺️ 路線配置
function handleRouteSelectChange() {
const select = document.getElementById('routeSelect');
const customInput = document.getElementById('customRouteInput');
if(select.value === 'ROUTE_CUSTOM') {
customInput.style.display = 'block';
state.currentRouteTitle = customInput.value '自訂自由路線';
} else {
customInput.style.display = 'none';
state.currentRouteTitle = select.options[select.selectedIndex].text;
}
state.passengers = 0;
state.isReversed = false;
logToConsole(`切換營運路線:${state.currentRouteTitle},乘客數重置。`);
saveState();
}
function syncLiveDisplay() {
state.currentRouteTitle = document.getElementById('customRouteInput').value '自訂自由路線';
saveState();
}
🔄 起點與終點對調
function reverseRoute() {
let title = state.currentRouteTitle;
if (title.includes('⇄')) {
let parts = title.split('⇄');
state.currentRouteTitle = `${parts[1].trim()} ⇄ ${parts[0].trim()}`;
state.isReversed = !state.isReversed;
logToConsole(`🔄 起點與終點對調完美跳轉為 [${state.currentRouteTitle}]`);
saveState();
} else {
alert('自訂自由路線請使用 ⇄ 符號分隔起訖點。');
}
}
🚖 1619座切換
function setTotalSeats(num) {
state.totalSeats = num;
if(state.passengers num) { state.passengers = num; }
logToConsole(`車型更換:新款 ${num} 座規格車。`);
saveState();
}
🚖 手動上客計數
function adjustPassengers(delta) {
let targetPassengers = state.passengers + delta;
if(targetPassengers 0) { alert('人數不能小於 0!'); return; }
if(targetPassengers state.totalSeats) { alert('全車已爆棚滿座!'); return; }
state.passengers = targetPassengers;
logToConsole(`司機點擊上客:當前車上 ${state.passengers} 人。`);
saveState();
}
🚖 宣告滿座快捷按鈕
function triggerFullHouse() {
let emptySeats = state.totalSeats - state.passengers;
if (emptySeats 0) {
state.passengers = state.totalSeats;
logToConsole(`🚨 宣告全車爆棚滿座!`);
} else {
state.passengers = 0;
logToConsole(`🔄 清空乘客,重頭數起。`);
}
saveState();
}
📡 我在此上車 (高精準 GPS 雷達晶片喚醒)
function triggerPassengerGpsRadar(btn) {
if(!state.phone) { alert('請先登入!'); return; }
if (passengerGpsWatchId === null) {
if (!navigator.geolocation) { alert(手機不支援 GPS 硬件!); return; }
btn.classList.add('btn-gps-active');
btn.innerText = 🛑 取消上車申報;
logToConsole(`📡 [雷達啟動] 強行喚醒手機最高精準度 GPS 硬件...`);
passengerGpsWatchId = navigator.geolocation.watchPosition(
(pos) = {
const lat = pos.coords.latitude;
const lng = pos.coords.longitude;
const accuracy = pos.coords.accuracy;
logToConsole(`🛰️ [雷達鎖定成功] 座標:緯度 ${lat.toFixed(5)}, 經度 ${lng.toFixed(5)} (精準度 ${accuracy.toFixed(1)} 米內)`);
將乘客高精準坐標實時上傳廣播池
NetworkHub.broadcastToServer({
type 'LOCATION_UPDATE',
userId state.phone,
lat lat,
lng lng,
accuracy accuracy
});
},
(err) = { logToConsole(`❌ GPS 硬件搜尋衛星失敗:${err.message}`); },
{ enableHighAccuracy true, timeout 10000, maximumAge 0 }
);
alert(`【位置已鎖定】n高精準雷達已成功連線!等車位置已即時同步發送。`);
} else {
navigator.geolocation.clearWatch(passengerGpsWatchId);
passengerGpsWatchId = null;
btn.classList.remove('btn-gps-active');
btn.innerText = 📡 我在此上車;
logToConsole(🛑 GPS 追蹤雷達已關閉,背景零電量消耗。);
alert(已取消上車位置申報。);
}
}
function joinTrueGroup(url) {
logToConsole(`💬 安全跳轉至真實西鐵群組:${url}`);
setTimeout(() = { window.open(url, '_blank'); }, 300);
}
👁️ 數據連動中樞
function syncUI(triggerBroadcast = true) {
if(!document.getElementById('btnSeat16')) return;
if(state.totalSeats === 16) {
document.getElementById('btnSeat16').classList.add('active');
document.getElementById('btnSeat19').classList.remove('active');
} else {
document.getElementById('btnSeat19').classList.add('active');
document.getElementById('btnSeat16').classList.remove('active');
}
let emptySeats = state.totalSeats - state.passengers;
document.getElementById('passengerCountDisplay').innerText = `${state.passengers} 人`;
document.getElementById('emptySeatsDisplay').innerText = `${emptySeats} 個位`;
document.getElementById('liveRouteName').innerText = state.currentRouteTitle;
const btnFullHouse = document.getElementById('btnFullHouse');
const btnReservePassenger = document.getElementById('btnReservePassenger');
if (emptySeats === 0) {
btnFullHouse.classList.add('is-full');
btnFullHouse.innerText = 滿座;
btnFullHouse.style.backgroundColor = var(--danger-color);
document.getElementById('liveSeatsText').innerHTML = `span style=colorvar(--danger-color); font-weightbold;🚨 全車滿座 (爆棚)span`;
btnReservePassenger.disabled = true;
btnReservePassenger.style.backgroundColor = '#444';
btnReservePassenger.style.color = '#aaa';
btnReservePassenger.innerText = '已滿座無法申報';
if(passengerGpsWatchId) {
navigator.geolocation.clearWatch(passengerGpsWatchId);
passengerGpsWatchId = null;
btnReservePassenger.classList.remove('btn-gps-active');
}
} else {
btnFullHouse.classList.remove('is-full');
btnFullHouse.innerText = 申報滿座;
btnFullHouse.style.backgroundColor = var(--success-color);
document.getElementById('liveSeatsText').innerHTML = `🚺 當前剩餘空位 span style=colorvar(--accent-color); font-weightbold;${emptySeats}span ${state.totalSeats}`;
btnReservePassenger.disabled = false;
if(passengerGpsWatchId === null) {
btnReservePassenger.style.backgroundColor = 'var(--primary-color)';
btnReservePassenger.style.color = 'var(--accent-color)';
btnReservePassenger.innerText = '📡 我在此上車';
}
}
}
大輝哥最高絕對特權
function superAction(type) {
logToConsole(`⚡ [超級特權發動]:${type}`);
if(type === 'RESET_ALL') {
NetworkHub.broadcastToServer({
type 'SUPER_ADMIN_COMMAND',
authKey 'Fai64989786',
action 'REVOKE'
});
state.totalSeats = 16; state.passengers = 0;
localStorage.clear();
alert(全港所有車隊數據、審批紀錄、自動登入已強行完全歸零清空!);
window.location.reload();
}
if(type === 'CALC_PAYROLL') {
2026 最新對帳規則:星期六固定 $450,平日正常時薪 $75 港幣
let isSaturday = new Date().getDay() === 6;
let pay = isSaturday 450 8 75;
alert(`💰 【浚鍵管理有限公司 - 財務動態對帳】n-----------------------------n今日工作型態:${isSaturday '星期六週末定額班' '平日正常時薪計'}n當班司機核算報酬:$${pay} 港幣n-----------------------------n(財務部核實發放 • 浚鍵管理授權)`);
}
if(type === 'BLOCK_USER') {
let num = prompt(請輸入要永久封鎖的乘客電話:);
if(num) alert(`號碼 ${num} 已打入全港黑名單!`);
}
if(type === 'BROADCAST') {
let msg = prompt(請輸入全港紅VAN緊急廣播公告:);
if(msg) {
NetworkHub.broadcastToServer({
type 'SUPER_ADMIN_COMMAND',
authKey 'Fai64989786',
action 'BROADCAST_MSG',
msg msg
});
alert(廣播已全自動秒傳推送!);
}
}
}
window.onload = function() {
syncUI(false);
const savedUser = localStorage.getItem('van_logged_user');
if (savedUser) {
try {
const userData = JSON.parse(savedUser);
doLogin(userData.role, true);
} catch (e) {
console.error(e);
}
}
};
script
body
html