All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 1m18s
1. 重構機台在線狀態判定機制:移除資料庫 status 欄位,改由 Model 根據心跳時間動態計算。 2. 修正儀表板 (Dashboard) 與機台管理頁面的多語系顯示問題,解決換行導致翻譯失效的 Bug。 3. 修正個人檔案頁面的麵包屑 (Breadcrumbs) 導航,補齊「個人設定」層級。 4. 更新 IoT API (B010, B600) 的認證機制與日誌處理邏輯。 5. 同步更新繁中、英文、日文語言檔,確保 UI 標籤一致性。
241 lines
11 KiB
PHP
241 lines
11 KiB
PHP
@props(['links' => null])
|
|
|
|
@php
|
|
if (is_null($links)) {
|
|
$routeName = Route::currentRouteName();
|
|
$links = [];
|
|
|
|
// 預設首頁 (Dashboard)
|
|
$links[] = [
|
|
'label' => __('Dashboard'),
|
|
'url' => route('admin.dashboard'),
|
|
'active' => $routeName === 'admin.dashboard'
|
|
];
|
|
|
|
if ($routeName && $routeName !== 'admin.dashboard') {
|
|
// 定義大模組映射表 (路由前綴 => 大模組名稱)
|
|
$moduleMap = [
|
|
'profile' => __('Profile Settings'),
|
|
'admin.members' => __('Member Management'),
|
|
'admin.membership-tiers' => __('Member Management'),
|
|
'admin.deposit-bonus-rules' => __('Member Management'),
|
|
'admin.point-rules' => __('Member Management'),
|
|
'admin.gift-definitions' => __('Member Management'),
|
|
'admin.machines' => __('Machine Management'),
|
|
'admin.app' => __('APP Management'),
|
|
'admin.warehouses' => __('Warehouse Management'),
|
|
'admin.sales' => __('Sales Management'),
|
|
'admin.analysis' => __('Analysis Management'),
|
|
'admin.audit' => __('Audit Management'),
|
|
'admin.data-config' => __('Data Configuration'),
|
|
'admin.remote' => __('Remote Management'),
|
|
'admin.line' => __('Line Management'),
|
|
'admin.reservation' => __('Reservation System'),
|
|
'admin.special-permission' => __('Special Permission'),
|
|
'admin.permission' => __('Permission Settings'),
|
|
'admin.basic-settings' => __('Basic Settings'),
|
|
'admin.maintenance' => __('Machine Management'),
|
|
];
|
|
|
|
// 1. 找出所屬大模組
|
|
$foundModule = null;
|
|
foreach ($moduleMap as $prefix => $label) {
|
|
if (str_starts_with($routeName, $prefix)) {
|
|
$foundModule = [
|
|
'label' => $label,
|
|
'url' => '#',
|
|
'active' => false
|
|
];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($foundModule) {
|
|
$links[] = $foundModule;
|
|
}
|
|
|
|
// 2. 處理中間層級與具體頁面
|
|
$segments = explode('.', $routeName);
|
|
$lastSegment = end($segments);
|
|
|
|
// 如果路由有四段以上 (如 admin.permission.companies.index),則處理中間一段
|
|
if (count($segments) >= 4) {
|
|
$midSegment = $segments[2];
|
|
$midLabel = match($midSegment) {
|
|
'companies' => __('Customer Management'),
|
|
'members' => __('Member List'),
|
|
'machines' => __('Machine Settings'),
|
|
'products' => __('Product Management'),
|
|
'machine-models' => __('Machine Model Settings'),
|
|
'accounts' => __('Account Management'),
|
|
'sub-accounts' => __('Account Management'),
|
|
'roles' => __('Roles'),
|
|
'sub-account-roles' => __('Sub Account Roles'),
|
|
'payment-configs' => __('Customer Payment Config'),
|
|
'warehouses' => __('Warehouse List'),
|
|
'sales' => __('Sales Records'),
|
|
'maintenance' => __('Maintenance Records'),
|
|
default => null,
|
|
};
|
|
|
|
if ($midLabel) {
|
|
$links[] = [
|
|
'label' => $midLabel,
|
|
'url' => match($midSegment) {
|
|
'maintenance' => route('admin.maintenance.index'),
|
|
'machines' => str_contains($routeName, 'basic-settings') ? route('admin.basic-settings.machines.index') : '#',
|
|
'products' => route('admin.data-config.products.index'),
|
|
'accounts' => route('admin.permission.accounts'),
|
|
'sub-accounts' => route('admin.data-config.sub-accounts'),
|
|
'sub-account-roles' => route('admin.data-config.sub-account-roles'),
|
|
default => '#',
|
|
},
|
|
'active' => $lastSegment === 'index'
|
|
];
|
|
}
|
|
}
|
|
|
|
// 特殊處理:當只有三段且第二段是 maintenance 時,增加中間層級
|
|
if (count($segments) === 3 && $segments[1] === 'maintenance' && $lastSegment !== 'index') {
|
|
$links[] = [
|
|
'label' => __('Maintenance Records'),
|
|
'url' => route('admin.maintenance.index'),
|
|
'active' => false
|
|
];
|
|
}
|
|
|
|
// 3. 處理最後一個動作/頁面
|
|
$pageLabel = match($lastSegment) {
|
|
'index' => match($segments[1] ?? '') {
|
|
'members' => __('Member List'),
|
|
'machines' => __('Machine List'),
|
|
'warehouses' => __('Warehouse List (All)'),
|
|
'sales' => __('Sales Records'),
|
|
'analysis' => __('Analysis Management'),
|
|
'audit' => __('Audit Management'),
|
|
'maintenance' => __('Maintenance Records'),
|
|
'data-config' => match($segments[2] ?? '') {
|
|
'products' => __('Product Management'),
|
|
'advertisements' => __('Advertisement Management'),
|
|
default => null,
|
|
},
|
|
'remote' => __('Command Center'),
|
|
'stock' => __('Stock & Expiry'),
|
|
default => null,
|
|
},
|
|
'edit' => str_starts_with($routeName, 'profile') ? __('Profile') : __('Edit'),
|
|
'create' => __('Create'),
|
|
'show' => __('Detail'),
|
|
'logs' => __('Machine Logs'),
|
|
'permissions' => __('Machine Permissions'),
|
|
'utilization' => __('Utilization Rate'),
|
|
'expiry' => __('Expiry Management'),
|
|
'maintenance' => __('Maintenance Records'),
|
|
'ui-elements' => __('UI Elements'),
|
|
'helper' => __('Helper'),
|
|
'questionnaire' => __('Questionnaire'),
|
|
'games' => __('Games'),
|
|
'timer' => __('Timer'),
|
|
'personal' => __('Warehouse List (Individual)'),
|
|
'stock-management' => __('Stock Management'),
|
|
'transfers' => __('Transfers'),
|
|
'purchases' => __('Purchases'),
|
|
'replenishments' => __('Replenishments'),
|
|
'replenishment-records' => __('Replenishment Records'),
|
|
'machine-stock' => __('Stock & Expiry'),
|
|
'staff-stock' => __('Staff Stock'),
|
|
'returns' => __('Returns'),
|
|
'pickup-codes' => __('Pickup Codes'),
|
|
'orders' => __('Orders'),
|
|
'promotions' => __('Promotions'),
|
|
'pass-codes' => __('Pass Codes'),
|
|
'store-gifts' => __('Store Gifts'),
|
|
'change-stock' => __('Change Stock'),
|
|
'machine-reports' => __('Machine Reports'),
|
|
'product-reports' => __('Product Reports'),
|
|
'survey-analysis' => __('Survey Analysis'),
|
|
'products' => __('Product Management'),
|
|
'advertisements' => __('Advertisement Management'),
|
|
'accounts' => __('Account Management'),
|
|
'sub-accounts' => __('Sub Accounts'),
|
|
'sub-account-roles' => __('Sub Account Roles'),
|
|
'points' => __('Point Settings'),
|
|
'badges' => __('Badge Settings'),
|
|
'restart' => __('Machine Restart'),
|
|
'restart-card-reader' => __('Card Reader Restart'),
|
|
'checkout' => __('Remote Checkout'),
|
|
'lock' => __('Remote Lock'),
|
|
'change' => __('Remote Change'),
|
|
'dispense' => __('Remote Dispense'),
|
|
'official-account' => __('Line Official Account'),
|
|
'coupons' => __('Line Coupons'),
|
|
'stores' => __('Store Management'),
|
|
'time-slots' => __('Time Slots'),
|
|
'venues' => __('Venue Management'),
|
|
'reservations' => __('Reservations'),
|
|
'clear-stock' => __('Clear Stock'),
|
|
'apk-versions' => __('APK Versions'),
|
|
'discord-notifications' => __('Discord Notifications'),
|
|
'app-features' => __('APP Features'),
|
|
'roles' => __('Roles'),
|
|
'others' => __('Others'),
|
|
'ai-prediction' => __('AI Prediction'),
|
|
'data-config' => __('Data Configuration Permissions'),
|
|
'sales' => __('Sales Permissions'),
|
|
'machines' => __('Machine Management Permissions'),
|
|
'warehouses' => __('Warehouse Permissions'),
|
|
'analysis' => __('Analysis Permissions'),
|
|
'audit' => __('Audit Permissions'),
|
|
'remote' => __('Command Center'),
|
|
'line' => __('Line Permissions'),
|
|
'stock' => __('Stock & Expiry'),
|
|
default => null,
|
|
};
|
|
|
|
if ($pageLabel) {
|
|
$links[] = [
|
|
'label' => $pageLabel,
|
|
'active' => true
|
|
];
|
|
}
|
|
|
|
// 確保最後一個 link 是 active 的
|
|
if (!empty($links)) {
|
|
$links[count($links) - 1]['active'] = true;
|
|
// 檢查是否有相鄰重複的 Label (例如 Dashboard > Dashboard)
|
|
if (count($links) > 1 && $links[count($links)-1]['label'] === $links[count($links)-2]['label']) {
|
|
array_pop($links);
|
|
$links[count($links)-1]['active'] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
@endphp
|
|
|
|
<nav {{ $attributes->merge(['class' => 'flex', 'aria-label' => 'Breadcrumb']) }}>
|
|
<ol class="flex items-center whitespace-nowrap min-w-0 w-full">
|
|
@foreach($links as $link)
|
|
@php
|
|
$isActive = $link['active'] ?? false;
|
|
$url = $link['url'] ?? '#';
|
|
@endphp
|
|
<li class="flex items-center text-sm {{ $isActive ? 'font-semibold text-slate-800 dark:text-slate-200' : 'text-slate-500 dark:text-slate-400' }} {{ !$loop->last ? 'shrink-0' : 'truncate' }}">
|
|
@if(!$isActive && $url !== '#')
|
|
<a class="hover:text-cyan-600 transition-colors" href="{{ $url }}">
|
|
{{ $link['label'] }}
|
|
</a>
|
|
@else
|
|
{{ $link['label'] }}
|
|
@endif
|
|
|
|
@if(!$loop->last)
|
|
<svg class="flex-shrink-0 mx-3 overflow-visible h-2.5 w-2.5 text-slate-500 dark:text-slate-400" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
</svg>
|
|
@endif
|
|
</li>
|
|
@endforeach
|
|
</ol>
|
|
</nav>
|