Files
2026-09-14 10:23:36 +08:00

109 lines
3.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 应用外壳:左侧菜单 + 顶栏 + 内容区,最后加载并挂载
(ref / computed / createApp 等已在 util.js 里解构到全局) */
const App = {
template: `
<div class="layout">
<aside class="sidebar">
<div class="brand">
<div class="brand-mark">沃</div>
<div class="brand-text">
<div class="brand-title">沃林学生管理系统</div>
<div class="brand-sub">Student Manager</div>
</div>
</div>
<nav class="nav">
<template v-for="g in groups" :key="g.name">
<div class="nav-group">{{ g.name }}</div>
<div v-for="p in g.items" :key="p.key"
class="nav-item" :class="{ active: p.key === currentKey }"
@click="go(p.key)">
<span v-html="icon(p.icon)"></span>
<span>{{ p.title }}</span>
</div>
</template>
</nav>
<div class="sidebar-foot">
接口文档:<a :href="docsUrl" target="_blank" style="color:#4F46E5">/docs</a><br>
后端 127.0.0.1:8001
</div>
</aside>
<div class="main">
<header class="topbar">
<div>
<div class="topbar-title">{{ current.title }}</div>
<div class="topbar-sub">{{ current.sub }}</div>
</div>
<div class="topbar-actions">
<el-button @click="reload">
<span style="margin-right:4px">↻</span>刷新本页
</el-button>
</div>
</header>
<section class="content">
<component :is="current.component" :key="currentKey + '#' + reloadTick" />
</section>
</div>
</div>
`,
setup() {
const pages = window.PAGES;
// 分组:按注册顺序把页面归到各自的分组里(总览 / 数据管理 / 统计分析)
const groups = [];
pages.forEach(p => {
const name = p.group || '其他';
let g = groups.find(x => x.name === name);
if (!g) { g = { name, items: [] }; groups.push(g); }
g.items.push(p);
});
const fallback = (pages[0] && pages[0].key) || '';
const currentKey = ref(location.hash.replace(/^#\/?/, '') || fallback);
// 刷新本页:改 key 让组件重新挂载,页面自己会重新拉数据
const reloadTick = ref(0);
const reload = () => { reloadTick.value++; };
const current = computed(() =>
pages.find(p => p.key === currentKey.value) || pages[0] || { title: '', sub: '', component: null });
const go = (key) => {
if (key === currentKey.value) { reload(); return; }
location.hash = '#/' + key;
};
// 地址栏直接改 hash / 浏览器前进后退也能切页
const onHash = () => {
const k = location.hash.replace(/^#\/?/, '');
if (k && k !== currentKey.value) currentKey.value = k;
};
onMounted(() => window.addEventListener('hashchange', onHash));
onUnmounted(() => window.removeEventListener('hashchange', onHash));
// 把地址栏补齐,刷新页面能停在当前页
if (!location.hash) location.hash = '#/' + currentKey.value;
// 前后端不同源了,/docs 这种站内相对路径会指到前端服务器上,必须用后端地址
const docsUrl = API_BASE + '/docs';
return { groups, currentKey, current, go, reload, reloadTick, icon, docsUrl };
},
};
const app = createApp(App);
// 模板里写错组件名之类的错误,直接在界面上弹出来,比只看控制台快
app.config.errorHandler = (err) => {
console.error(err);
toastErr(err && err.message ? err.message : '页面出错了,请按 F12 看控制台');
};
app.use(ElementPlus, { locale: ElementPlusLocaleZhCn });
app.mount('#app');