feat(ui): 全局弹窗替代原生 alert/confirm,添加防重复提交与搜索功能
- 新增 ConfirmModal / ResultModal 全局组件,替代原生 alert/confirm/prompt - 资产/平台/账号保存添加防重复提交锁(assetSaving / providerSaving) - 添加 Esc 键盘快捷键关闭模态框 - 平台/监控视图添加搜索过滤功能 - 修复监控中心 SSL TAB 下新增按钮的显示逻辑 - 调整 toast 位置避免遮挡底部导航 - 统一各弹窗 z-index 层级
This commit is contained in:
+35
-3
@@ -61,9 +61,13 @@ const AppRoot = {
|
||||
<div class="flex-1 flex flex-col min-w-0">
|
||||
<header class="sticky top-0 z-30 bg-white/80 dark:bg-slate-900/80 backdrop-blur border-b border-slate-200 dark:border-slate-800 px-4 py-3 flex items-center gap-3">
|
||||
<h1 class="font-semibold text-slate-900 dark:text-white md:text-lg">{{ currentNav.label }}</h1>
|
||||
<div v-if="store.loading" class="flex items-center gap-1.5 text-xs text-slate-400">
|
||||
<span class="inline-block w-3 h-3 border-2 border-blue-500 border-t-transparent rounded-full animate-spin"></span>
|
||||
<span class="hidden sm:inline">加载中…</span>
|
||||
</div>
|
||||
<div class="ml-auto flex items-center gap-2">
|
||||
<input v-if="store.view==='assets'" v-model="store.search" @input="reload" placeholder="搜索…" class="text-sm px-3 py-1.5 rounded-lg border border-slate-300 dark:border-slate-700 bg-white dark:bg-slate-900 w-32 md:w-48">
|
||||
<button @click="quickAdd" class="text-sm px-3 py-1.5 rounded-lg bg-blue-600 text-white hover:bg-blue-700 whitespace-nowrap">+ 新增</button>
|
||||
<button v-if="store.view!=='monitor' || store.monitorTab==='ssl'" @click="quickAdd" class="text-sm px-3 py-1.5 rounded-lg bg-blue-600 text-white hover:bg-blue-700 whitespace-nowrap">+ 新增</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -89,9 +93,11 @@ const AppRoot = {
|
||||
<credential-modal></credential-modal>
|
||||
<action-modal></action-modal>
|
||||
<dns-modal></dns-modal>
|
||||
<confirm-modal></confirm-modal>
|
||||
<result-modal></result-modal>
|
||||
|
||||
<!-- 复制等操作的轻提示(底部导航上方,不遮内容) -->
|
||||
<div v-if="toast.show" class="fixed bottom-20 md:bottom-6 left-1/2 -translate-x-1/2 z-[80] px-4 py-2 rounded-full bg-slate-900/90 dark:bg-slate-100/90 text-white dark:text-slate-900 text-xs shadow-lg pointer-events-none whitespace-nowrap">{{ toast.text }}</div>
|
||||
<div v-if="toast.show" class="fixed bottom-24 md:bottom-6 left-1/2 -translate-x-1/2 z-[80] px-4 py-2 rounded-full bg-slate-900/90 dark:bg-slate-100/90 text-white dark:text-slate-900 text-xs shadow-lg pointer-events-none whitespace-nowrap">{{ toast.text }}</div>
|
||||
</div>`,
|
||||
setup() {
|
||||
const appName = Api.CFG.appName;
|
||||
@@ -104,7 +110,12 @@ const AppRoot = {
|
||||
function quickAdd() {
|
||||
if (store.view === 'providers') return openProviderCreate();
|
||||
if (store.view === 'vault') return openCredentialCreate();
|
||||
// 资产页:按当前 TAB 预设类型;监控中心/总览/设置:默认 VPS
|
||||
// 监控中心:SSL TAB 下添加证书监控,其他情况隐藏新增按钮(模板已控制)
|
||||
if (store.view === 'monitor') {
|
||||
if (store.monitorTab === 'ssl') return showResult('提示', '请在「资产 → 域名」的子域名面板点「探测SSL」添加证书监控');
|
||||
return; // 非 SSL TAB 不响应(模板已隐藏按钮)
|
||||
}
|
||||
// 总览/设置:默认创建 VPS
|
||||
let preset = 'vps';
|
||||
if (store.view === 'assets') {
|
||||
const t = store.assetTab;
|
||||
@@ -124,6 +135,24 @@ const AppRoot = {
|
||||
},
|
||||
};
|
||||
|
||||
/* ================= 键盘快捷键 ================= */
|
||||
function initKeyboard() {
|
||||
document.addEventListener('keydown', (e) => {
|
||||
// Esc 关闭最上层模态框(按 z-index 从高到低检查)
|
||||
if (e.key === 'Escape') {
|
||||
if (store.resultModal.show) { closeResult(); return; }
|
||||
if (store.confirmModal.show) { closeConfirm(false); return; }
|
||||
if (store.credentialModal.show) { store.credentialModal.show = false; return; }
|
||||
if (store.accountModal.show) { store.accountModal.show = false; return; }
|
||||
if (store.assetModal.show) { store.assetModal.show = false; return; }
|
||||
if (store.providerModal.show) { store.providerModal.show = false; return; }
|
||||
if (store.accountsModal.show) { store.accountsModal.show = false; return; }
|
||||
if (actionModal.show) { closeActions(); return; }
|
||||
if (dnsModal.show) { closeDns(); return; }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* ================= 挂载 ================= */
|
||||
const app = Vue.createApp(AppRoot);
|
||||
app.component('dashboard-view', DashboardView);
|
||||
@@ -140,7 +169,10 @@ app.component('accounts-view-modal', AccountsViewModal);
|
||||
app.component('credential-modal', CredentialModal);
|
||||
app.component('action-modal', ActionModal);
|
||||
app.component('dns-modal', DnsModal);
|
||||
app.component('confirm-modal', ConfirmModal);
|
||||
app.component('result-modal', ResultModal);
|
||||
applyDark();
|
||||
initRouter();
|
||||
initKeyboard();
|
||||
loadAll();
|
||||
app.mount('#app');
|
||||
|
||||
Reference in New Issue
Block a user