feat:完善快速开始功能

This commit is contained in:
张凯博
2025-08-19 20:58:37 +08:00
committed by zhangtao
parent 21c8e928d5
commit 0050f3fcd1
8 changed files with 230 additions and 54 deletions
@@ -23,13 +23,12 @@
<template #dropdown>
<el-dropdown-menu>
<!-- 收藏到快速开始 -->
<el-dropdown-item
@click="addToQuickStart(tag)"
:disabled="isQuickLinkExists(tag)">
<el-dropdown-item @click="toggleQuickStart(tag)">
<el-icon>
<Star />
<Star v-if="!isQuickLinkExists(tag)" />
<StarFilled v-else />
</el-icon>
{{ isQuickLinkExists(tag) ? '收藏' : '收藏到快速开始' }}
{{ isQuickLinkExists(tag) ? '取消收藏' : '收藏到快速开始' }}
</el-dropdown-item>
<el-dropdown-item divided @click="refreshSelectedTag(tag)">
@@ -169,7 +168,7 @@ import { translateRouteTitle } from "@/utils/i18n";
import { usePermissionStore, useTagsViewStore } from "@/store";
import { VueDraggable } from "vue-draggable-plus";
import { quickStartManager } from "@/utils/quickStartManager";
import { Star } from "@element-plus/icons-vue";
import { Star, StarFilled } from "@element-plus/icons-vue";
import { ElMessage } from 'element-plus';
const { t } = useI18n();
@@ -459,15 +458,30 @@ const onContextMenuVisibleChange = (visible: boolean, tag?: TagView) => {
};
/**
* 添加到快速开始
* 切换快速开始收藏状态
*/
const addToQuickStart = (tag: TagView) => {
const toggleQuickStart = (tag: TagView) => {
try {
const quickLink = quickStartManager.createQuickLinkFromRoute(tag);
quickStartManager.addQuickLink(quickLink);
const href = tag.fullPath || tag.path;
const isExists = quickStartManager.isLinkExists(href);
if (isExists) {
// 取消收藏:找到对应的链接并删除
const links = quickStartManager.getQuickLinks();
const targetLink = links.find(link => link.href === href);
if (targetLink?.id) {
quickStartManager.removeQuickLink(targetLink.id);
ElMessage.success(`已取消收藏:${tag.title}`);
}
} else {
// 添加收藏
const quickLink = quickStartManager.createQuickLinkFromRoute(tag);
quickStartManager.addQuickLink(quickLink);
ElMessage.success(`已收藏:${tag.title}`);
}
} catch (error) {
console.error('Failed to add to quick start:', error);
ElMessage.error('添加到快速开始失败');
console.error('Failed to toggle quick start:', error);
ElMessage.error('操作失败');
}
};
+1
View File
@@ -325,6 +325,7 @@ declare module 'vue' {
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']>
readonly ElNotification: UnwrapRef<typeof import('element-plus/es')['ElNotification']>
readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
+59 -21
View File
@@ -115,34 +115,72 @@ class QuickStartManager {
// 从路由信息创建快速链接
createQuickLinkFromRoute(route: any, customTitle?: string, customDescription?: string): QuickLink {
// 根据路径推断图标和颜色
const iconMap: Record<string, { icon: string; color: string }> = {
'/dashboard': { icon: 'House', color: '#409EFF' },
'/system': { icon: 'Setting', color: '#67C23A' },
'/user': { icon: 'User', color: '#409EFF' },
'/role': { icon: 'UserFilled', color: '#E6A23C' },
'/menu': { icon: 'Menu', color: '#F56C6C' },
'/dept': { icon: 'OfficeBuilding', color: '#909399' },
'/monitor': { icon: 'Monitor', color: '#606266' },
'/log': { icon: 'Document', color: '#FF6B6B' },
'/codegen': { icon: 'Code', color: '#4ECDC4' },
'/demo': { icon: 'DataAnalysis', color: '#3385FF' },
};
// 优先使用路由配置的图标
let routeIcon = route.meta?.icon;
let routeColor = '#409EFF'; // 默认颜色
// 查找匹配的图标配置
let iconConfig = { icon: 'Link', color: '#909399' }; // 默认配置
for (const [path, config] of Object.entries(iconMap)) {
if (route.path.includes(path)) {
iconConfig = config;
break;
// 如果路由没有配置图标,根据路径推断
if (!routeIcon) {
const iconMap: Record<string, { icon: string; color: string }> = {
'/dashboard/workplace': { icon: 'House', color: '#409EFF' },
'/dashboard/analysis': { icon: 'TrendCharts', color: '#67C23A' },
'/dashboard': { icon: 'House', color: '#409EFF' },
'/system/user': { icon: 'User', color: '#409EFF' },
'/system/role': { icon: 'UserFilled', color: '#E6A23C' },
'/system/menu': { icon: 'Menu', color: '#F56C6C' },
'/system/dept': { icon: 'OfficeBuilding', color: '#909399' },
'/system/position': { icon: 'Briefcase', color: '#606266' },
'/system/dict': { icon: 'Collection', color: '#FF6B6B' },
'/system/config': { icon: 'Setting', color: '#67C23A' },
'/system/notice': { icon: 'Bell', color: '#E6A23C' },
'/system/log': { icon: 'Document', color: '#FF6B6B' },
'/system': { icon: 'Setting', color: '#67C23A' },
'/monitor/server': { icon: 'Monitor', color: '#606266' },
'/monitor/cache': { icon: 'Coin', color: '#F56C6C' },
'/monitor/job': { icon: 'Timer', color: '#909399' },
'/monitor/online': { icon: 'Connection', color: '#67C23A' },
'/monitor': { icon: 'Monitor', color: '#606266' },
'/codegen': { icon: 'Code', color: '#4ECDC4' },
'/demo': { icon: 'DataAnalysis', color: '#3385FF' },
'/profile': { icon: 'User', color: '#409EFF' },
};
// 查找最匹配的路径配置
let bestMatch = { icon: 'Link', color: '#909399' }; // 默认配置
let maxMatchLength = 0;
for (const [path, config] of Object.entries(iconMap)) {
if (route.path.startsWith(path) && path.length > maxMatchLength) {
bestMatch = config;
maxMatchLength = path.length;
}
}
routeIcon = bestMatch.icon;
routeColor = bestMatch.color;
} else {
// 如果有路由图标,尝试获取对应的颜色
const colorMap: Record<string, string> = {
'house': '#409EFF',
'user': '#409EFF',
'setting': '#67C23A',
'monitor': '#606266',
'document': '#FF6B6B',
'bell': '#E6A23C',
'menu': '#F56C6C',
'office-building': '#909399',
'data-analysis': '#3385FF',
'trend-charts': '#67C23A',
};
routeColor = colorMap[routeIcon.toLowerCase()] || '#409EFF';
}
return {
title: customTitle || route.meta?.title || route.name || '未命名页面',
description: customDescription || `快速访问 ${route.meta?.title || route.name || '页面'}`,
icon: iconConfig.icon,
color: iconConfig.color,
icon: routeIcon,
color: routeColor,
href: route.fullPath || route.path,
action: 'navigate',
id: `route-${route.path.replace(/\//g, '-')}-${Date.now()}`
@@ -14,9 +14,10 @@
### 2. 标签栏右键收藏
- ✅ 在任意标签页右击可收藏到快速开始
- ✅ 已收藏的页面显示"已收藏"状态
- ✅ 自动生成合适的图标和颜色
- ✅ 防止重复收藏
- ✅ 支持切换收藏状态(收藏/取消收藏)
- ✅ 自动获取路由配置的图标
- ✅ 智能图标匹配和颜色配置
- ✅ 实时状态显示和图标切换
### 3. 手动添加链接
- ✅ 通过对话框手动添加自定义链接
@@ -33,17 +34,28 @@
### 4. 数据持久化
- ✅ 使用 localStorage 保存用户配置
- ✅ 页面刷新后数据不丢失
- ✅ 支持导入/导出配置(可扩展)
- ✅ 支持导入/导出配置(后续可扩展)
## 使用方法
### 从标签栏收藏页面
#### 收藏页面
1. 在任意页面的标签上右击
2. 选择"收藏到快速开始"
3. 系统会自动添加到快速开始列表
3. 系统会自动获取路由图标和颜色
4. 前往工作台查看新添加的链接
#### 取消收藏
1. 在已收藏页面的标签上右击
2. 选择"取消收藏"(图标会显示为实心星星)
3. 链接立即从快速开始列表中移除
#### 自动图标获取
- **优先级1**:使用路由 `meta.icon` 配置
- **优先级2**:根据路径智能匹配预设图标
- **优先级3**:使用默认链接图标
### 手动添加链接
1. 在快速开始组件中点击"添加"按钮
@@ -63,12 +75,14 @@
1. **编辑链接**
- 在快速开始组件中右击任意链接
- 选择"编辑链接"
- 修改链接信息后保存
- 对话框会自动填充现有的链接信息
- 修改需要更改的字段
- 点击"确定"保存修改
2. **删除链接**
- 在快速开始组件中右击任意链接
- 选择"删除链接"
- 确认删除操作
- 确认对话框中点击"确定"
### 使用快速链接
@@ -276,9 +276,32 @@ const handleConfirm = async () => {
}
};
// 监听编辑数据变化,填充表单
// 监听对话框显示状态,处理表单数据
watch(() => props.visible, (visible) => {
if (visible) {
if (props.editData) {
// 编辑模式:填充现有数据
console.log('编辑模式 - 填充数据:', props.editData);
Object.assign(form, {
title: props.editData.title,
description: props.editData.description,
icon: props.editData.icon,
color: props.editData.color,
href: props.editData.href,
action: props.editData.action
});
console.log('表单数据已填充:', form);
} else {
// 新增模式:重置表单
console.log('新增模式 - 重置表单');
resetForm();
}
}
});
// 监听编辑数据变化(当对话框已经打开时)
watch(() => props.editData, (editData) => {
if (editData && props.visible) {
if (props.visible && editData) {
// 编辑模式:填充现有数据
Object.assign(form, {
title: editData.title,
@@ -289,15 +312,7 @@ watch(() => props.editData, (editData) => {
action: editData.action
});
}
}, { immediate: true });
// 监听对话框显示状态
watch(() => props.visible, (visible) => {
if (visible && !props.editData) {
// 新增模式:重置表单
resetForm();
}
});
}, { immediate: false });
// 监听链接类型变化,自动调整链接地址格式
watch(() => form.action, (newAction) => {
@@ -137,7 +137,10 @@ const onContextMenuChange = (visible: boolean, item?: QuickLink) => {
// 处理编辑链接
const handleEditLink = (item: QuickLink) => {
selectedLink.value = item;
// 深拷贝链接数据,避免直接修改原数据
console.log('开始编辑链接:', item);
selectedLink.value = { ...item };
console.log('设置选中链接:', selectedLink.value);
addDialogVisible.value = true;
};
@@ -22,6 +22,8 @@
<h3>测试步骤</h3>
<ol class="test-steps">
<li><strong>收藏功能</strong>在当前页面的标签上右击选择"收藏到快速开始"</li>
<li><strong>取消收藏</strong>在已收藏页面的标签上右击选择"取消收藏"</li>
<li><strong>自动图标</strong>收藏时会自动获取路由配置的图标</li>
<li><strong>查看收藏</strong>前往工作台页面查看快速开始组件</li>
<li><strong>编辑链接</strong>在快速开始组件中右击任意链接选择"编辑链接"</li>
<li><strong>删除链接</strong>在快速开始组件中右击任意链接选择"删除链接"</li>
@@ -41,6 +43,14 @@
<ElDescriptionsItem label="完整路径">
{{ $route.fullPath }}
</ElDescriptionsItem>
<ElDescriptionsItem label="路由图标">
<div class="flex items-center">
<el-icon v-if="$route.meta?.icon" :size="20" class="mr-2">
<component :is="$route.meta.icon" />
</el-icon>
<span>{{ $route.meta?.icon || '无图标配置' }}</span>
</div>
</ElDescriptionsItem>
<ElDescriptionsItem label="收藏状态">
<ElTag :type="isBookmarked ? 'success' : 'info'">
{{ isBookmarked ? '已收藏' : '未收藏' }}
@@ -74,6 +84,22 @@
>
删除收藏
</ElButton>
<ElButton
type="info"
@click="previewQuickLink"
class="ml-2"
>
预览收藏信息
</ElButton>
<ElButton
type="warning"
@click="testEditFunction"
class="ml-2"
>
测试编辑功能
</ElButton>
</div>
<div class="mt-4">
@@ -100,6 +126,7 @@
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router';
import { quickStartManager, type QuickLink } from '@/utils/quickStartManager';
import { ElMessageBox } from 'element-plus';
defineOptions({
name: "QuickStartTest",
@@ -141,6 +168,70 @@ const removeBookmark = () => {
}
};
// 预览收藏信息
const previewQuickLink = () => {
const quickLink = quickStartManager.createQuickLinkFromRoute(
route,
'快速开始测试页面',
'用于测试快速开始收藏功能的演示页面'
);
ElMessageBox.alert(
`<div style="text-align: left;">
<p><strong>标题:</strong>${quickLink.title}</p>
<p><strong>描述:</strong>${quickLink.description}</p>
<p><strong>图标:</strong>${quickLink.icon}</p>
<p><strong>颜色:</strong><span style="color: ${quickLink.color};">${quickLink.color}</span></p>
<p><strong>链接:</strong>${quickLink.href}</p>
<p><strong>类型:</strong>${quickLink.action}</p>
</div>`,
'收藏信息预览',
{
dangerouslyUseHTMLString: true,
confirmButtonText: '确定'
}
);
};
// 测试编辑功能
const testEditFunction = () => {
const links = quickStartManager.getQuickLinks();
if (links.length === 0) {
ElMessage.warning('没有可编辑的快速链接,请先添加一些链接');
return;
}
ElMessageBox.alert(
`<div style="text-align: left;">
<p><strong>测试说明:</strong></p>
<ol>
<li>前往工作台页面</li>
<li>在快速开始组件中右击任意链接</li>
<li>选择"编辑链接"</li>
<li>验证表单是否预填充了现有数据</li>
<li>修改任意字段后保存</li>
<li>确认修改是否生效</li>
</ol>
<p><strong>当前可编辑的链接:</strong></p>
<ul>
${links.slice(0, 3).map(link => `<li>${link.title} (${link.href})</li>`).join('')}
${links.length > 3 ? `<li>... 还有 ${links.length - 3} 个链接</li>` : ''}
</ul>
</div>`,
'编辑功能测试指南',
{
dangerouslyUseHTMLString: true,
confirmButtonText: '前往工作台测试',
cancelButtonText: '取消',
showCancelButton: true
}
).then(() => {
goToWorkplace();
}).catch(() => {
// 用户取消
});
};
// 前往工作台
const goToWorkplace = () => {
router.push('/dashboard/workplace');