Files
zhxg_pc/src/layout/index.vue
2025-08-26 10:01:22 +08:00

251 lines
5.7 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.

<!--E:\桌面\AI辅导员\学工系统\zhxg_pc\src\layout\index.vue-->
<template>
<div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
<el-scrollbar>
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
<div :class="{ 'fixed-header': fixedHeader }">
<navbar />
<tags-view v-if="needTagsView" />
</div>
<app-main />
<right-panel>
<settings />
</right-panel>
</div>
</el-scrollbar>
<!-- ai悬停 -->
<div>
<!-- 其他页面内容 -->
<!-- 触发按钮控制弹窗显示隐藏 -->
<div class="ai-hover" @click="toggleAI">
<span v-if="!showAI" style="font-size: 30px; font-weight: bold;">AI</span>
<i v-else class="el-icon-close" style="font-size: 20px;"></i>
</div>
<!-- 聊天弹窗通过 v-if 控制显隐 -->
<transition name="chat-popup">
<ChatPopup v-if="showAI" @close="showAI = false" />
</transition>
</div>
</div>
</template>
<script>
import RightPanel from '@/components/RightPanel'
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'
import variables from '@/assets/styles/variables.scss'
import ChatPopup from '../layout/components/Aichat/ChatPopup.vue'
import {
initCoze
} from '@/utils/ai.js'
import {
getAccessToken
} from '@/api/aiJWT/aiJWT.js'
export default {
name: 'Layout',
components: {
AppMain,
Navbar,
RightPanel,
Settings,
Sidebar,
TagsView,
ChatPopup // 注册ChatPopup组件
},
mixins: [ResizeMixin],
data() {
return {
showAI: false // 控制AI弹窗显示/隐藏的变量
}
},
computed: {
...mapState({
theme: state => state.settings.theme,
sideTheme: state => state.settings.sideTheme,
sidebar: state => state.app.sidebar,
device: state => state.app.device,
needTagsView: state => state.settings.tagsView,
fixedHeader: state => state.settings.fixedHeader,
avatar: state => state.user.avatar,
userInfo: state => state.user.userInfo,
token: state => state.user.token
}),
classObj() {
return {
hideSidebar: !this.sidebar.opened,
openSidebar: this.sidebar.opened,
withoutAnimation: this.sidebar.withoutAnimation,
mobile: this.device === 'mobile'
}
},
variables() {
return variables
}
},
methods: {
handleClickOutside() {
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
},
// 切换AI弹窗显示状态
toggleAI() {
// 使用明确的状态切换避免与close事件冲突
if (this.showAI) {
this.showAI = false
} else {
this.showAI = true
}
},
// 原有AI初始化逻辑保持注释状态
async initializeAI() {
// let userInfo = {
// roleGroup: this.userInfo.roles[0].roleName || "student",
// nickName: this.userInfo.nickName,
// username: this.userInfo.userName,
// avater: this.avatar,
// user_token: this.token
// }
// console.log("请求AI的信息", userInfo)
//
// //1.获取token
// userInfo.accessToken = (await this.getAccessToken()).access_token;
// userInfo.onRefreshToken = async () => (await this.getAccessToken()).accessToken;
// const sdk = await initCoze(userInfo);
// sdk.showChatBot();
},
async getAccessToken() {
const res = await getAccessToken() // 调用请求函数
const data = JSON.parse(res.data) // 解析数据
return data // ✅ 返回 data
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/assets/styles/mixin.scss";
@import "~@/assets/styles/variables.scss";
//~@/assets/styles/variables.scss
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
.el-scrollbar {
height: 100%;
}
::v-deep .el-scrollbar__bar.is-vertical {
z-index: 10;
}
::v-deep .el-scrollbar__wrap {
overflow-x: hidden;
}
&.mobile.openSidebar {
position: fixed;
top: 0;
}
}
.drawer-bg {
background: #000;
opacity: 0.3;
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
}
.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$base-sidebar-width});
transition: width 0.28s;
}
.hideSidebar .fixed-header {
width: calc(100% - 54px);
}
.sidebarHide .fixed-header {
width: 100%;
}
.mobile .fixed-header {
width: 100%;
}
//AI
.ai-hover {
position: fixed;
right: 20px;
bottom: 20px;
/* 和弹窗拉开距离 */
width: 5vw;
height: 7vh;
background-color: #409eff;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
cursor: pointer;
z-index: 9999;
transition: all 0.2s ease;
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
}
.ai-hover:hover {
transform: scale(1.05);
box-shadow: 0 6px 16px rgba(64, 158, 255, 0.4);
}
/* 聊天弹窗动画 - 优化版本,避免闪烁 */
.chat-popup-enter-active {
transition: all 0.25s ease-out;
}
.chat-popup-leave-active {
transition: all 0.15s ease-in;
}
.chat-popup-enter-from {
opacity: 0;
transform: translateY(15px) scale(0.95);
}
.chat-popup-enter-to {
opacity: 1;
transform: translateY(0) scale(1);
}
.chat-popup-leave-from {
opacity: 1;
transform: translateY(0) scale(1);
}
.chat-popup-leave-to {
opacity: 0;
transform: translateY(15px) scale(0.95);
}
</style>