feat(web): 升级至 v3.0 并重构组件与引导流程

- 提取应用引导逻辑至 useAppBootstrap 组合式函数
- 增强日期选择器组件,支持全类型与格式自动推导
- 修复资源泄漏:清理 RAF、定时器、事件与 mitt 监听
- 修复退出登录逻辑与异步导出流程
- 迁移 ::v-deep 至 Vue 3 标准 :deep 语法
- 移除调试日志并改进类型定义与注释文档
This commit is contained in:
zhangtao
2026-05-11 23:37:11 +08:00
parent 7e7a5c97cb
commit 9a231aa58c
120 changed files with 2282 additions and 1931 deletions
+145 -113
View File
@@ -1,3 +1,4 @@
<!-- 缓存监控 -->
<template>
<div class="fa-full-height">
<el-tabs>
@@ -143,44 +144,46 @@
</div>
</div>
</template>
<ElTable :loading="loading" :data="cacheNames" row-key="cache_name">
<template #empty>
<ElEmpty :image-size="80" description="暂无数据" />
</template>
<ElTableColumn prop="cache_name" label="缓存名称" show-overflow-tooltip>
<template #default="{ row }">
<ElButton
v-hasPerm="['module_monitor:cache:query']"
type="primary"
link
@click="getCacheKeyList(row)"
>
{{ row.cache_name }}
</ElButton>
<div class="cache-table-wrap">
<ElTable :loading="loading" :data="cacheNames" row-key="cache_name" height="100%">
<template #empty>
<ElEmpty :image-size="80" description="暂无数据" />
</template>
</ElTableColumn>
<ElTableColumn prop="remark" label="备注" show-overflow-tooltip />
<ElTableColumn label="操作" width="60" align="center">
<template #default="{ row }">
<ElPopconfirm
class="box-item"
:title="`确认删除缓存 ${row.cache_name} 吗?`"
placement="top"
@confirm="handleClearCacheName(row)"
>
<template #reference>
<ElButton
v-hasPerm="['module_monitor:cache:delete']"
type="danger"
size="small"
link
icon="delete"
/>
</template>
</ElPopconfirm>
</template>
</ElTableColumn>
</ElTable>
<ElTableColumn prop="cache_name" label="缓存名称" show-overflow-tooltip>
<template #default="{ row }">
<ElButton
v-hasPerm="['module_monitor:cache:query']"
type="primary"
link
@click="getCacheKeyList(row)"
>
{{ row.cache_name }}
</ElButton>
</template>
</ElTableColumn>
<ElTableColumn prop="remark" label="备注" show-overflow-tooltip />
<ElTableColumn label="操作" width="60" align="center">
<template #default="{ row }">
<ElPopconfirm
class="box-item"
:title="`确认删除缓存 ${row.cache_name} 吗?`"
placement="top"
@confirm="handleClearCacheName(row)"
>
<template #reference>
<ElButton
v-hasPerm="['module_monitor:cache:delete']"
type="danger"
size="small"
link
icon="delete"
/>
</template>
</ElPopconfirm>
</template>
</ElTableColumn>
</ElTable>
</div>
</ElCard>
</ElCol>
@@ -211,53 +214,56 @@
</div>
</div>
</template>
<ElTable
:loading="subLoading"
:data="cacheKeys.map((key) => ({ cacheKey: key }))"
row-key="cacheKey"
>
<template #empty>
<ElEmpty :image-size="80" description="暂无数据" />
</template>
<ElTableColumn prop="cacheKey" label="缓存键名" show-overflow-tooltip>
<template #default="{ row }">
<ElButton
v-hasPerm="['module_monitor:cache:detail']"
type="primary"
link
@click="handleCacheValue(row.cacheKey)"
>
{{ row.cacheKey }}
</ElButton>
<div class="cache-table-wrap">
<ElTable
:loading="subLoading"
:data="cacheKeys.map((key) => ({ cacheKey: key }))"
row-key="cacheKey"
height="100%"
>
<template #empty>
<ElEmpty :image-size="80" description="暂无数据" />
</template>
</ElTableColumn>
<ElTableColumn label="操作" width="60" align="center">
<template #default="{ row }">
<ElPopconfirm
class="box-item"
:title="`确认删除键 ${row.cacheKey} 吗?`"
placement="top"
@confirm="handleClearCacheKey(row.cacheKey)"
>
<template #reference>
<ElButton
v-hasPerm="['module_monitor:cache:delete']"
type="danger"
size="small"
link
icon="delete"
/>
</template>
</ElPopconfirm>
</template>
</ElTableColumn>
</ElTable>
<ElTableColumn prop="cacheKey" label="缓存键名" show-overflow-tooltip>
<template #default="{ row }">
<ElButton
v-hasPerm="['module_monitor:cache:detail']"
type="primary"
link
@click="handleCacheValue(row.cacheKey)"
>
{{ row.cacheKey }}
</ElButton>
</template>
</ElTableColumn>
<ElTableColumn label="操作" width="60" align="center">
<template #default="{ row }">
<ElPopconfirm
class="box-item"
:title="`确认删除键 ${row.cacheKey} 吗?`"
placement="top"
@confirm="handleClearCacheKey(row.cacheKey)"
>
<template #reference>
<ElButton
v-hasPerm="['module_monitor:cache:delete']"
type="danger"
size="small"
link
icon="delete"
/>
</template>
</ElPopconfirm>
</template>
</ElTableColumn>
</ElTable>
</div>
</ElCard>
</ElCol>
<!-- 缓存内容 -->
<ElCol :span="8">
<ElCard :loading="loading" shadow="hover">
<ElCol :span="8" class="cache-mgmt-col">
<ElCard :loading="loading" shadow="hover" class="cache-mgmt-card">
<template #header>
<div class="flex justify-between items-center">
<div class="flex items-center gap-2">
@@ -284,23 +290,29 @@
</div>
</div>
</template>
<ElForm :model="cacheForm" label-suffix=":" label-width="auto" label-position="top">
<ElFormItem label="缓存名称">
<ElInput v-model="cacheForm.cache_name" readonly placeholder="缓存名称" />
</ElFormItem>
<ElFormItem label="缓存键名">
<ElInput v-model="cacheForm.cache_key" readonly placeholder="缓存键名" />
</ElFormItem>
<ElFormItem label="缓存内容">
<ElInput
v-model="cacheForm.cache_value"
type="textarea"
:rows="20"
readonly
placeholder="缓存内容"
/>
</ElFormItem>
</ElForm>
<div class="cache-form-wrap">
<ElForm
:model="cacheForm"
label-suffix=":"
label-width="auto"
label-position="top"
>
<ElFormItem label="缓存名称">
<ElInput v-model="cacheForm.cache_name" readonly placeholder="缓存名称" />
</ElFormItem>
<ElFormItem label="缓存键名">
<ElInput v-model="cacheForm.cache_key" readonly placeholder="缓存键名" />
</ElFormItem>
<ElFormItem label="缓存内容" class="cache-value-item">
<ElInput
v-model="cacheForm.cache_value"
type="textarea"
readonly
placeholder="缓存内容"
/>
</ElFormItem>
</ElForm>
</div>
</ElCard>
</ElCol>
</ElRow>
@@ -432,22 +444,19 @@ async function handleCacheValue(cacheKey: string) {
// 清理全部缓存
const handleClearCacheAll = async () => {
ElMessageBox.confirm("确定要清理全部缓存吗?", "危险!", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(async () => {
return await CacheAPI.deleteCacheAll();
})
.then(() => {
getCacheNameList();
})
.catch((error: unknown) => {
if (error !== "cancel") {
console.error("清理全部缓存失败:", error);
}
try {
await ElMessageBox.confirm("确定要清理全部缓存吗?", "危险!", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
});
await CacheAPI.deleteCacheAll();
getCacheNameList();
} catch (error: unknown) {
if (error !== "cancel") {
console.error("清理全部缓存失败:", error);
}
}
};
// 监控数据获取
@@ -567,7 +576,7 @@ onUnmounted(() => {
flex-direction: column;
min-height: 0;
::v-deep(.el-card__body) {
:deep(.el-card__body) {
display: flex;
flex: 1;
flex-direction: column;
@@ -607,7 +616,30 @@ onUnmounted(() => {
flex-direction: column;
min-height: 0;
::v-deep(.el-card__body) {
:deep(.el-card__body) {
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
> .cache-table-wrap,
> .cache-form-wrap {
flex: 1;
min-height: 0;
}
}
}
.cache-table-wrap {
overflow: hidden;
}
.cache-form-wrap {
display: flex;
flex-direction: column;
overflow: hidden;
.el-form {
display: flex;
flex: 1;
flex-direction: column;
@@ -125,21 +125,20 @@ const onlineSearchItems = computed<SearchFormItem[]>(() => [
const clearAllLoading = ref(false);
function kickSession(sessionId: string) {
ElMessageBox.confirm(`确认强制退出会话 ${sessionId}?`, "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(async () => {
try {
await OnlineAPI.deleteOnline(sessionId);
ElMessage.success("操作成功");
await refreshData();
} catch (error: unknown) {
console.error(error);
}
})
.catch(() => {});
(async () => {
try {
await ElMessageBox.confirm(`确认强制退出会话 ${sessionId}?`, "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
});
await OnlineAPI.deleteOnline(sessionId);
ElMessage.success("操作成功");
await refreshData();
} catch {
// 用户取消或操作失败
}
})();
}
const {
@@ -259,24 +258,23 @@ async function onResetSearch() {
}
function handleClearAll() {
ElMessageBox.confirm("确认强制退出所有用户?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(async () => {
try {
clearAllLoading.value = true;
await OnlineAPI.clearOnline();
ElMessage.success("操作成功");
await refreshData();
} catch (error: unknown) {
console.error(error);
} finally {
clearAllLoading.value = false;
}
})
.catch(() => {});
(async () => {
try {
await ElMessageBox.confirm("确认强制退出所有用户?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
});
clearAllLoading.value = true;
await OnlineAPI.clearOnline();
ElMessage.success("操作成功");
await refreshData();
} catch {
// 用户取消
} finally {
clearAllLoading.value = false;
}
})();
}
</script>
@@ -92,7 +92,7 @@
</FaTableHeader>
<!-- 面包屑与表头已占用高度:表格高度须在独立 flex 子项内计算,否则分页会被挤出卡片 -->
<div class="resource-table-region min-h-0 flex flex-1 flex-col overflow-hidden pb-3">
<div class="resource-table-region min-h-0 flex flex-1 flex-col overflow-hidden">
<FaTable
row-key="file_url"
:show-table-header="false"
@@ -633,14 +633,14 @@ async function handleBatchDelete() {
</script>
<style lang="scss" scoped>
.resource-monitor-page ::v-deep(.resource-monitor-card.el-card > .el-card__body) {
.resource-monitor-page :deep(.resource-monitor-card.el-card > .el-card__body) {
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
}
::v-deep(.el-breadcrumb__item) {
:deep(.el-breadcrumb__item) {
&.is-link {
color: var(--el-color-primary);
cursor: pointer;