/* vps-manager 前端应用入口(Vue 3 组件化 + Hash 路由) */
/* ================= 导航与 Hash 路由 ================= */
const NAVS = [
{ key: 'dashboard', label: '总览', icon: '📊' },
{ key: 'assets', label: '资产', icon: '📦' },
{ key: 'monitor', label: '监控中心', icon: '⏳' },
{ key: 'providers', label: '平台', icon: '🏢' },
{ key: 'settings', label: '设置', icon: '⚙️' },
];
const VIEW_MAP = {
dashboard: 'dashboard-view', assets: 'assets-view', monitor: 'monitor-view',
providers: 'providers-view', settings: 'settings-view',
// 服务器监控为隐藏路由(不进导航,从资产页 VPS「监控」进入)
servers: 'servers-view',
};
const VALID_VIEWS = new Set(Object.keys(VIEW_MAP));
function _viewFromHash() {
const h = (window.location.hash || '').replace(/^#\/?/, '').split('?')[0];
return VALID_VIEWS.has(h) ? h : 'dashboard';
}
function _applyView(key) {
store.view = key;
if (key !== 'servers') store.serverMetrics = {};
}
function navigate(key) {
if (!VALID_VIEWS.has(key)) key = 'dashboard';
if (window.location.hash !== '#' + key) {
window.location.hash = '#' + key;
} else {
_applyView(key);
}
}
function initRouter() {
_applyView(_viewFromHash());
window.addEventListener('hashchange', () => { _applyView(_viewFromHash()); });
}
/* ================= 根组件 ================= */
const AppRoot = {
template: `
`,
setup() {
const appName = Api.CFG.appName;
const appVersion = Api.CFG.version || 'dev';
const appCommit = Api.CFG.commit || 'unknown';
const navs = NAVS;
const currentNav = Vue.computed(() => navs.find(n => n.key === store.view) || navs[0]);
const viewComponent = Vue.computed(() => VIEW_MAP[store.view] || 'dashboard-view');
function go(key) { navigate(key); }
function quickAdd() {
if (store.view === 'providers') return openProviderCreate();
// 资产页:按当前 TAB 预设类型;监控中心/总览/设置:默认 VPS
let preset = 'vps';
if (store.view === 'assets') {
const t = store.assetTab;
if (t === 'ai_agent') return openAICreate('');
if (t === 'domain' || t === 'cloudflare' || t === 'subscription' || t === 'vps') preset = t === 'subscription' ? 'vps' : t;
}
openAssetCreate(preset);
}
function toggleDark() { store.dark = !store.dark; applyDark(); }
// 搜索防抖:300ms 内连续输入只触发一次请求
let searchTimer = null;
function debouncedReload() {
if (searchTimer) clearTimeout(searchTimer);
searchTimer = setTimeout(() => { loadAssets(); }, 300);
}
return { store, appName, appVersion, appCommit, navs, currentNav, viewComponent, go, quickAdd, toggleDark, reload: debouncedReload };
},
};
/* ================= 挂载 ================= */
const app = Vue.createApp(AppRoot);
app.component('dashboard-view', DashboardView);
app.component('assets-view', AssetsView);
app.component('monitor-view', MonitorView);
app.component('providers-view', ProvidersView);
app.component('servers-view', ServersView);
app.component('settings-view', SettingsView);
app.component('asset-modal', AssetModal);
app.component('provider-modal', ProviderModal);
app.component('account-modal', AccountModal);
applyDark();
initRouter();
loadAll();
app.mount('#app');