Files
yunhai-agent-front/src/App.vue
T
2026-10-12 14:45:00 +08:00

104 lines
3.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
/**
* 应用外壳:左侧导航栏 + 右侧内容区。
*
* 职责划分:
* - 这里统一拉取「当前用户」和「能力目录」(两者都是全局信息,侧栏和对话页都要用),
* 再往下传,避免各组件各拉一次。
* - 会话状态留在对话页内部,侧栏的「新建对话」通过组件 ref 调用它的方法触发。
*/
import { computed, onMounted, ref } from "vue";
import { Message } from "view-ui-plus";
import { agentApi, baseApi } from "@/api/module/agent";
import AppSidebar from "@/components/AppSidebar.vue";
import type { AgentToolCatalog, UserInfoVo } from "@/types/agent";
const user = ref<UserInfoVo | null>(null);
const catalog = ref<AgentToolCatalog | null>(null);
const loading = ref(true);
const online = ref(false);
/** 对话页组件实例(用于从侧栏触发"新建对话") */
const chatRef = ref<any>(null);
const statusText = computed(() => (loading.value ? "正在连接" : online.value ? "服务已连接" : "服务未连接"));
const toolCount = computed(() => catalog.value?.total ?? 0);
const writeCount = computed(() => {
const mods = catalog.value?.modules || {};
let n = 0;
Object.keys(mods).forEach(k => mods[k].forEach(t => t.write && n++));
return n;
});
/**
* 拉取当前登录用户(平台 CAS 会话)。
*
* 未登录时后端 CasSsoApiRedirectFilter 返回 code=302 + urlToRedirectTo,
* alova 的 errorHandle 收到 302 会直接整页跳转登录页,并返回一个**永不 resolve** 的 Promise,
* 所以跳转链路根本不会落到下面的 catch —— 这里只需处理「服务没起来 / 接口报错」。
*/
async function loadUser() {
try {
const info = await baseApi.getUserInfo().send();
user.value = (info || null) as UserInfoVo;
online.value = true;
} catch (e: any) {
console.warn("载入用户信息失败", e);
Message.error("载入用户信息失败,请检查智能体服务是否已启动");
} finally {
loading.value = false;
}
}
/** 能力目录:拉取失败不阻塞对话(只是侧栏模块列表为空) */
async function loadCatalog() {
try {
catalog.value = (await agentApi.tools().send()) as AgentToolCatalog;
online.value = true;
} catch (e) {
console.warn("能力目录拉取失败", e);
}
}
onMounted(() => {
loadUser();
loadCatalog();
});
function onNewSession() {
chatRef.value?.newSession?.();
}
</script>
<template>
<div class="agent-shell">
<AppSidebar :catalog="catalog" :user="user" @pick="t => chatRef?.pickSample?.(t)" @new-session="onNewSession" />
<section class="agent-main">
<header class="agent-topbar">
<div class="agent-topbar__titles">
<h1>智能对话</h1>
<p>说出需求,我直接调用系统接口帮你办</p>
</div>
<div class="agent-topbar__right">
<span class="agent-status" :class="{ 'agent-status--off': !loading && !online }">
<i class="agent-status__dot" />
{{ statusText }}
</span>
<span v-if="toolCount" class="agent-capsule">
可用能力 <strong class="agent-num">{{ toolCount }}</strong> 项
<i class="agent-capsule__sep" />
可直接提交 <strong class="agent-num">{{ writeCount }}</strong> 项
</span>
</div>
</header>
<main class="agent-body">
<router-view v-slot="{ Component }">
<component :is="Component" ref="chatRef" :user="user" :catalog="catalog" />
</router-view>
</main>
</section>
</div>
</template>