Files
WeChatHookBot/utils/webui_static/app.js

166 lines
5.4 KiB
JavaScript

const { createApp, ref, provide, onMounted, onUnmounted } = Vue;
const app = createApp({
setup() {
const api = useApi();
const currentPage = ref('log');
const authReady = ref(false);
const authenticated = ref(false);
const authUser = ref('');
const loginLoading = ref(false);
const loginForm = ref({
username: '',
password: '',
});
provide('currentPage', currentPage);
async function refreshAuthState() {
const json = await api.getAuthStatus();
if (json) {
authenticated.value = !!json.authenticated;
authUser.value = json.username || '';
if (json.username && !loginForm.value.username) {
loginForm.value.username = json.username;
}
} else {
authenticated.value = false;
authUser.value = '';
}
authReady.value = true;
}
async function login() {
const username = (loginForm.value.username || '').trim();
const password = loginForm.value.password || '';
if (!username) {
ElementPlus.ElMessage.warning('请输入账号');
return;
}
if (!password) {
ElementPlus.ElMessage.warning('请输入密码');
return;
}
loginLoading.value = true;
const json = await api.login(username, password);
loginLoading.value = false;
if (!json) return;
authenticated.value = true;
authUser.value = json.username || username;
loginForm.value.password = '';
currentPage.value = 'log';
ElementPlus.ElMessage.success('登录成功');
}
async function logout() {
await api.logout();
authenticated.value = false;
loginForm.value.password = '';
currentPage.value = 'log';
}
function handleAuthExpired() {
const wasAuthenticated = authenticated.value;
authenticated.value = false;
loginForm.value.password = '';
currentPage.value = 'log';
if (wasAuthenticated) {
ElementPlus.ElMessage.warning('登录状态已失效,请重新登录');
}
}
function handleAuthUpdated(event) {
const username = event?.detail?.username;
if (username) {
authUser.value = username;
}
}
function handleLayoutAuthUpdated(username) {
if (username) {
authUser.value = username;
}
}
onMounted(() => {
window.addEventListener('webui-auth-required', handleAuthExpired);
window.addEventListener('webui-auth-updated', handleAuthUpdated);
refreshAuthState();
});
onUnmounted(() => {
window.removeEventListener('webui-auth-required', handleAuthExpired);
window.removeEventListener('webui-auth-updated', handleAuthUpdated);
});
return {
authReady,
authenticated,
authUser,
loginLoading,
loginForm,
login,
logout,
handleLayoutAuthUpdated,
};
},
template: `
<div v-if="authReady" class="app-root">
<div v-if="!authenticated"
class="login-page">
<el-card class="login-card">
<template #header>
<div class="login-title">WechatHookBot 控制台</div>
<div class="login-subtitle">Bright Tech UI · 安全登录</div>
</template>
<el-form label-position="top">
<el-form-item label="账号">
<el-input
v-model="loginForm.username"
autocomplete="username"
placeholder="请输入账号" />
</el-form-item>
<el-form-item label="密码">
<el-input
v-model="loginForm.password"
show-password
autocomplete="current-password"
placeholder="请输入密码"
@keyup.enter="login" />
</el-form-item>
<el-button type="primary" :loading="loginLoading" style="width:100%" @click="login">
登录
</el-button>
</el-form>
</el-card>
</div>
<AppLayout
v-else
:auth-user="authUser"
@logout="logout"
@auth-updated="handleLayoutAuthUpdated" />
</div>
`
});
app.use(ElementPlus, {
locale: ElementPlusLocaleZhCn,
});
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);
}
app.component('AppLayout', window.AppLayout);
app.component('LogViewer', window.LogViewer);
app.component('ConfigEditor', window.ConfigEditor);
app.component('ConfigSection', window.ConfigSection);
app.component('PluginList', window.PluginList);
app.component('PluginConfigDialog', window.PluginConfigDialog);
app.component('SecuritySettings', window.SecuritySettings);
app.mount('#app');