feat: 新增刷新缓存功能并优化系统初始化

refactor: 重构模型加载选项和CRUD预加载逻辑

fix: 修复日期范围查询格式问题

style: 优化前端组件样式和布局

perf: 提升字典数据更新性能

docs: 更新注释和文档说明

chore: 清理无用文件和代码

test: 更新测试用例

build: 添加vue-json-pretty依赖

ci: 优化初始化脚本和事务处理
This commit is contained in:
zhangtao
2025-10-27 02:33:50 +08:00
parent ab90f86623
commit 780e02b9de
89 changed files with 1549 additions and 914 deletions
@@ -37,7 +37,7 @@
<el-avatar size="small" :src="userStore.basicInfo.avatar" />
</template>
<template v-else>
<el-avatar icon="UserFilled" />
<el-avatar size="small" icon="UserFilled" />
</template>
<span class="user-profile__name">{{ userStore.basicInfo.username }}</span>
</div>
@@ -78,7 +78,7 @@
</div>
<!-- 引导 -->
<Guide v-if="guideVisible" v-model="guideVisible" />
<Guide v-if="guideVisible" v-model="guideVisible" @skip="handleGuideExit" />
<!-- 锁屏弹窗 -->
<LockDialog v-if="dialogVisible" v-model="dialogVisible" />
@@ -89,7 +89,7 @@
</teleport>
<!-- 配置中心抽屉 -->
<ConfigInfoDrawer v-if="drawerVisible" v-model="drawerVisible"/>
<ConfigInfoDrawer v-model="drawerVisible"/>
</template>
@@ -174,6 +174,18 @@ function handleTourClick() {
}
}
// 引导结束(点击跳过或最后一步完成关闭)后,自动关闭下次登录的自动展示
function handleGuideExit() {
// 关闭自动展示开关,确保下次登录不再自动开启
settingStore.updateSetting('showGuide', false);
}
// 监听引导关闭(从 true -> false),也同步关闭自动展示开关
watch(() => guideVisible.value, (val, oldVal) => {
if (oldVal && !val) {
settingStore.updateSetting('showGuide', false);
}
});
/**
* 锁屏
@@ -7,7 +7,6 @@
<!-- 标签导航容器 -->
<nav role="navigation" class="scroll-wrapper">
<el-scrollbar ref="scrollbarRef" class="scroll-container" @wheel="handleScroll">
<VueDraggable v-model="visitedViews" :animation="150">
<router-link
@@ -106,9 +105,11 @@
</el-icon>
<!-- 刷新按钮 -->
<el-icon class="btn" @click="refreshSelectedTag(selectedTag)">
<RefreshRight />
</el-icon>
<el-tooltip class="item" :content="t('navbar.refreshCache')" placement="top">
<el-icon class="btn" @click="handleAction('refreshCache')">
<RefreshRight />
</el-icon>
</el-tooltip>
<!-- 设置按钮 -->
<el-dropdown class="btn" trigger="click">
@@ -145,7 +146,7 @@
{{ t("navbar.closeRight") }}
</el-dropdown-item>
<el-dropdown-item :disabled="!selectedTag" @click="handleAction('closeOther')">
<el-dropdown-item :disabled="visitedViews.length <= 1" @click="handleAction('closeOther')">
<el-icon>
<Remove />
</el-icon>
@@ -168,7 +169,7 @@
import { useRoute, useRouter, type RouteRecordRaw } from "vue-router";
import { resolve } from "path-browserify";
import { translateRouteTitle } from "@/utils/i18n";
import { usePermissionStore, useTagsViewStore } from "@/store";
import { refreshAppCaches, usePermissionStore, useTagsViewStore } from "@/store";
import { VueDraggable } from "vue-draggable-plus";
import { quickStartManager } from "@/utils/quickStartManager";
import { ElMessage } from 'element-plus';
@@ -193,6 +194,11 @@ const displayedViews = computed(() => {
// 当前选中的标签
const selectedTag = ref<TagView | null>(null);
// 基于当前激活路由的回退标签(当未选中右键标签时)
const activeTag = computed(() => {
return selectedTag.value || routePathMap.value.get(route.path) || null;
});
// 滚动条引用
const scrollbarRef = ref();
@@ -210,17 +216,17 @@ const routePathMap = computed(() => {
// 判断是否为第一个标签
const isFirstView = computed(() => {
if (!selectedTag.value) return false;
if (!activeTag.value) return false;
return (
selectedTag.value.path === "/dashboard" ||
selectedTag.value.fullPath === visitedViews.value[1]?.fullPath
activeTag.value.path === "/dashboard" ||
activeTag.value.fullPath === visitedViews.value[1]?.fullPath
);
});
// 判断是否为最后一个标签
const isLastView = computed(() => {
if (!selectedTag.value) return false;
return selectedTag.value.fullPath === visitedViews.value[visitedViews.value.length - 1]?.fullPath;
if (!activeTag.value) return false;
return activeTag.value.fullPath === visitedViews.value[visitedViews.value.length - 1]?.fullPath;
});
/**
@@ -412,9 +418,10 @@ const closeSelectedTag = (tag: TagView | null) => {
* 关闭左侧标签
*/
const closeLeftTags = () => {
if (!selectedTag.value) return;
const targetTag = selectedTag.value || routePathMap.value.get(route.path);
if (!targetTag) return;
tagsViewStore.delLeftViews(selectedTag.value).then((result: any) => {
tagsViewStore.delLeftViews(targetTag).then((result: any) => {
const hasCurrentRoute = result.visitedViews.some((item: TagView) => item.path === route.path);
if (!hasCurrentRoute) {
@@ -431,9 +438,10 @@ const closeLeftTags = () => {
* 关闭右侧标签
*/
const closeRightTags = () => {
if (!selectedTag.value) return;
const targetTag = selectedTag.value || routePathMap.value.get(route.path);
if (!targetTag) return;
tagsViewStore.delRightViews(selectedTag.value).then((result: any) => {
tagsViewStore.delRightViews(targetTag).then((result: any) => {
const hasCurrentRoute = result.visitedViews.some((item: TagView) => item.path === route.path);
if (!hasCurrentRoute) {
@@ -450,10 +458,11 @@ const closeRightTags = () => {
* 关闭其他标签
*/
const closeOtherTags = () => {
if (!selectedTag.value) return;
const targetTag = selectedTag.value || routePathMap.value.get(route.path);
if (!targetTag) return;
router.push(selectedTag.value);
tagsViewStore.delOtherViews(selectedTag.value).then(() => {
router.push(targetTag);
tagsViewStore.delOtherViews(targetTag).then(() => {
updateCurrentTag();
// 关闭标签后重置滚动状态
nextTick(() => {
@@ -478,7 +487,7 @@ const closeAllTags = (tag: TagView | null) => {
/**
* 统一处理标签操作
*/
const handleAction = (action: string) => {
const handleAction = async (action: string) => {
// 总是使用当前路由对应的标签
const currentTag = routePathMap.value.get(route.path);
if (!currentTag) return;
@@ -502,6 +511,19 @@ const handleAction = (action: string) => {
case 'closeAll':
closeAllTags(currentTag);
break;
case 'refreshCache':
try {
// 1) 刷新服务端缓存(用户/权限/配置/公告/按需字典)并重建路由
await refreshAppCaches();
// 2) 软刷新当前页面,重新加载组件
refreshSelectedTag(currentTag);
// 3) 提示成功
ElMessage.success(t('navbar.refreshCache') + '完成');
} catch (error) {
console.error('刷新缓存失败:', error);
ElMessage.error('刷新失败');
}
break;
default:
console.warn(`Unknown action: ${action}`);
}