首页功能模块支持动态惨淡

This commit is contained in:
BBIT-Kai
2025-12-16 15:29:50 +08:00
parent dbdc222541
commit b6cc35d1ee
7 changed files with 209 additions and 151 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ export async function getMenuListForUser() {
/**
* 获取菜单数据列表
*/
export async function getMenuListForAll(plat_id:number) {
export async function getMenuListForAll(plat_id: number) {
return pyRequestClient.get<Array<SystemMenuApi.SystemMenu>>(
`/system/menu/list/all/${plat_id}`,
);
@@ -1,133 +1,109 @@
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import type {
WorkbenchProjectItem,
WorkbenchQuickNavItem,
} from '@vben/common-ui';
import { useRouter } from 'vue-router';
import { WorkbenchHeader, WorkbenchQuickNav } from '@vben/common-ui';
import { preferences } from '@vben/preferences';
import { useUserStore } from '@vben/stores';
import { openWindow } from '@vben/utils';
const userStore = useUserStore();
import * as api from '#/api';
// 同样,这里的 url 也可以使用以 http 开头的外部链接
const cv: WorkbenchQuickNavItem[] = [
{
color: '#3fb27f',
authority: ['iva'],
icon: 'mdi:video',
title: '工作视频分析',
url: '/cv/iva',
},
{
color: '#3fb27f',
authority: ['iva-sc'],
icon: 'mdi:video-image',
title: '蚕茧视频分析',
url: '/cv/iva-sc',
},
{
color: '#3fb27f',
authority: ['sca'],
icon: 'mdi:ice-cream',
title: '蚕茧仪评分析',
url: '/cv/sca',
},
{
color: '#3fb27f',
authority: ['sca2'],
icon: 'mdi:ice-pop',
title: '蚕茧仪评分析V2',
url: '/cv/sca2',
},
{
color: '#3fb27f',
authority: ['ysa'],
icon: 'mdi:waveform',
title: '催青阶段分析',
url: '/cv/ysa',
},
{
color: '#3fb27f',
authority: ['ticket'],
icon: 'mdi:ticket-confirmation',
title: '仪评指标联分析',
url: '/cv/ticket',
},
{
color: '#3fb27f',
authority: ['license'],
icon: 'mdi:certificate',
title: '证件照片分析',
url: '/cv/license',
},
{
color: '#3fb27f',
icon: 'ion:bar-chart-outline',
title: '数据标注入口',
authority: ['user'],
url: 'https://ai.ronsunny.cn:8094/',
},
];
const llm: WorkbenchQuickNavItem[] = [
{
color: '#1fdaca',
authority: ['bot'],
icon: 'mdi:face-agent',
title: '通用智能体',
url: '/llm/bot',
},
{
color: '#1fdaca',
authority: ['report'],
icon: 'mdi:set-center',
title: '智农观数阁',
url: '/llm/report/report-chat',
},
{
color: '#1fdaca',
authority: ['service'],
icon: 'mdi:android-head',
title: '灵思智服阁',
url: '/llm/service/service-chat',
},
];
const common: WorkbenchQuickNavItem[] = [
{
color: '#bf0c2c',
authority: ['remote'],
icon: 'carbon:workspace',
title: '设备远程控制',
url: '/remote',
},
{
color: '#bf0c2c',
icon: 'ion:grid-outline',
title: 'RAGFlow',
authority: ['user'],
url: '/out/rag',
},
];
/* -----------------------------
* 类型定义
* ----------------------------- */
interface MenuItem {
id: string;
name: string;
path: string;
type: 'catalog' | 'menu' | 'link';
meta?: {
title?: string;
icon?: string;
link?: string;
};
children?: MenuItem[];
}
/* -----------------------------
* 状态
* ----------------------------- */
const userStore = useUserStore();
const router = useRouter();
// 这是一个示例方法,实际项目中需要根据实际情况进行调整
const quickNavGroups = ref<
{
title: string;
items: WorkbenchQuickNavItem[];
}[]
>([]);
/* -----------------------------
* 工具函数
* ----------------------------- */
function resolveColorByPath(path: string) {
if (path.startsWith('/cv')) return '#3fb27f';
if (path.startsWith('/llm')) return '#1fdaca';
if (path.startsWith('/remote')) return '#bf0c2c';
if (path.startsWith('/out')) return '#bf0c2c';
return '#6366f1';
}
// 🌟 核心:拍平所有 menu / link
function flattenMenu(
nodes: MenuItem[] = [],
result: MenuItem[] = [],
) {
for (const node of nodes) {
if (node.type === 'menu' || node.type === 'link') {
result.push(node);
}
if (node.children?.length) {
flattenMenu(node.children, result);
}
}
return result;
}
function mapNodesToQuickNavItems(
nodes: MenuItem[],
color: string,
): WorkbenchQuickNavItem[] {
return nodes.map((item) => {
const isLink = item.type === 'link';
return {
title: item.meta?.title || item.name,
icon: item.meta?.icon,
color,
url: isLink ? item.meta?.link : item.path,
authority: item.path
? [item.path.split('/').filter(Boolean).pop() as string]
: ['user'],
};
});
}
function navTo(nav: WorkbenchProjectItem | WorkbenchQuickNavItem) {
if (nav.url?.startsWith('http')) {
openWindow(nav.url);
return;
}
if (nav.url?.startsWith('/')) {
router.push(nav.url).catch((error) => {
console.error('Navigation failed:', error);
});
} else {
console.warn(`Unknown URL for navigation item: ${nav.title} -> ${nav.url}`);
router.push(nav.url).catch(console.error);
}
}
/* -----------------------------
* 业务逻辑
* ----------------------------- */
function getGreeting() {
const hour = new Date().getHours();
if (hour < 6) return '凌晨好';
@@ -135,6 +111,28 @@ function getGreeting() {
if (hour < 18) return '下午好';
return '晚上好';
}
async function loadList() {
const res: MenuItem[] = await api.getMenuListForUser();
if (!res) return;
quickNavGroups.value = res
.filter((catalog) => catalog.type === 'catalog')
.map((catalog) => {
const color = resolveColorByPath(catalog.path);
const flatNodes = flattenMenu(catalog.children || []);
return {
title: catalog.meta?.title || catalog.name,
items: mapNodesToQuickNavItems(flatNodes, color),
};
})
.filter((group) => group.items.length > 0);
}
onMounted(() => {
loadList();
});
</script>
<template>
@@ -143,38 +141,23 @@ function getGreeting() {
:avatar="userStore.userInfo?.avatar || preferences.app.defaultAvatar"
>
<template #title>
{{ getGreeting() }}, {{ userStore.userInfo?.username }},
{{ getGreeting() }}, {{ userStore.userInfo?.username }}
开始您一天的工作吧
</template>
<template #description> 欢迎使用AI实验室</template>
<template #description>
欢迎使用 AI 实验室
</template>
</WorkbenchHeader>
<div class="mt-5 flex flex-col lg:flex-row">
<div
v-for="group in quickNavGroups"
:key="group.title"
class="mt-5 flex flex-col lg:flex-row"
>
<div class="w-full">
<WorkbenchQuickNav
:items="cv"
class="mt-5 lg:mt-0"
title="计算机视觉"
@click="navTo"
/>
</div>
</div>
<div class="mt-5 flex flex-col lg:flex-row">
<div class="w-full">
<WorkbenchQuickNav
:items="llm"
class="mt-5 lg:mt-0"
title="大语言模型"
@click="navTo"
/>
</div>
</div>
<div class="mt-5 flex flex-col lg:flex-row">
<div class="w-full">
<WorkbenchQuickNav
:items="common"
class="mt-5 lg:mt-0"
title="其他应用"
:title="group.title"
:items="group.items"
@click="navTo"
/>
</div>
@@ -65,7 +65,7 @@ const schema: VbenFormSchema[] = [
{
component: 'ApiTreeSelect',
componentProps: {
api: getMenuListForAll(0),
api: () => getMenuListForAll(0),
class: 'w-full',
filterTreeNode(input: string, node: Recordable<any>) {
if (!input || input.length === 0) {
@@ -65,7 +65,7 @@ const schema: VbenFormSchema[] = [
{
component: 'ApiTreeSelect',
componentProps: {
api: getMenuListForAll(1),
api: () => getMenuListForAll(1),
class: 'w-full',
filterTreeNode(input: string, node: Recordable<any>) {
if (!input || input.length === 0) {