Files
1/static/js/app.js
T

109 lines
3.7 KiB
JavaScript
Raw Normal View History

2026-09-14 10:23:36 +08:00
/* 应用外壳:左侧菜单 + 顶栏 + 内容区,最后加载并挂载
(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');