1703 lines
48 KiB
Vue
1703 lines
48 KiB
Vue
<template>
|
||
<div class="top-nav" @mouseleave="sildeOut">
|
||
<div class="top-nav-placeholder"></div>
|
||
<div id="topContainer" class="nav-container">
|
||
<div class="brand" @click="goHome">
|
||
<img
|
||
v-if="JSON.stringify(logoInfoNew) !== '{}'"
|
||
class="brand-logo"
|
||
:src="(logoInfoNew.home && logoInfoNew.home.logoImg) || ''"
|
||
alt=""
|
||
>
|
||
</div>
|
||
|
||
<nav class="site-nav">
|
||
<button type="button" class="nav-item" :class="{ active: isActiveHome }" @click.stop="goHome">首页</button>
|
||
<button
|
||
type="button"
|
||
class="nav-item nav-item--product"
|
||
:class="{ active: isShowPanel }"
|
||
@mouseenter="sildeIn(product_service)"
|
||
@click.stop="sildeIn(product_service)"
|
||
>
|
||
产品
|
||
<i class="iconfont" :class="isShowPanel ? 'icon-shang' : 'icon-xia'"></i>
|
||
</button>
|
||
<button type="button" class="nav-item" >案例</button>
|
||
<button type="button" class="nav-item">动态</button>
|
||
</nav>
|
||
|
||
<div class="user-actions">
|
||
<i v-if="loginState" class="iconfont icon-xiaoxi functions" @click="handleMessageClick"></i>
|
||
<button v-if="loginState" type="button" class="console-link" @click="goB">控制台</button>
|
||
|
||
<button
|
||
v-if="!loginState"
|
||
type="button"
|
||
class="login-btn"
|
||
@click="$router.push({ path: '/login', query: { fromPath: 'homePage' } })"
|
||
>
|
||
登录
|
||
</button>
|
||
<button
|
||
v-if="!loginState"
|
||
type="button"
|
||
class="register-btn"
|
||
@click="$router.push('/registrationPage')"
|
||
>
|
||
立即注册
|
||
</button>
|
||
|
||
<el-dropdown
|
||
v-if="loginState"
|
||
@visible-change="handleShow"
|
||
class="avatar-container right-menu-item hover-effect nick-name-style"
|
||
trigger="click"
|
||
>
|
||
<button type="button" class="login-pill login-pill--user">
|
||
{{ nick_name || '控制台' }}
|
||
<i id="resverIcon" class="el-icon-arrow-up el-icon--right resverIcon"></i>
|
||
</button>
|
||
<el-dropdown-menu slot="dropdown" style="width: 230px;font-size: 16px;" divided>
|
||
<div style="display: flex;flex-direction: column;padding:15px 15px;background-color: #f0f2f5">
|
||
<span style="font-weight: bold;font-size: 20px;margin-bottom: 5px;color: #333333">{{ nick_name }}</span>
|
||
<span style="font-size: 12px;color:#666;display: flex;justify-content:flex-start;align-items: center"> ID:
|
||
<span ref="contentToCopy">{{ userId }}</span>
|
||
<svg @click="copyBtn" class="copy-btn" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="12" height="12" style="fill: #1019ab;">
|
||
<path d="M394.666667 106.666667h448a74.666667 74.666667 0 0 1 74.666666 74.666666v448a74.666667 74.666667 0 0 1-74.666666 74.666667H394.666667a74.666667 74.666667 0 0 1-74.666667-74.666667V181.333333a74.666667 74.666667 0 0 1 74.666667-74.666666z m0 64a10.666667 10.666666 0 0 0-10.666667 10.666666v448a10.666667 10.666667 0 0 0 10.666667 10.666667h448a10.666667 10.666667 0 0 0 10.666666-10.666667V181.333333a10.666667 10.666667 0 0 0-10.666666-10.666666H394.666667z m245.333333 597.333333a32 32 0 0 1 64 0v74.666667a74.666667 74.666667 0 0 1-74.666667 74.666666H181.333333a74.666667 74.666667 0 0 1-74.666666-74.666666V394.666667a74.666667 74.666667 0 0 1 74.666666-74.666667h74.666667a32 32 0 0 1 0 64h-74.666667a10.666667 10.666667 0 0 0-10.666666 10.666667v448a10.666667 10.666667 0 0 0 10.666666 10.666666h448a10.666667 10.666667 0 0 0 10.666667-10.666666v-74.666667z"></path>
|
||
</svg>
|
||
</span>
|
||
</div>
|
||
<el-divider style="margin: 0!important;"></el-divider>
|
||
<div v-if="role.includes('客户')"
|
||
style="padding: 0 18px; width: 100%;height: 60px;display: flex;justify-content: space-between;align-items: center">
|
||
<span style="color:#666;display: block;font-size: 14px;" class="moneyNow"><span
|
||
style="display: block;margin-bottom: 5px">余额</span>{{
|
||
mybalance ? mybalance : initMybalance()
|
||
}} ¥</span>
|
||
<el-button v-if="!isShowKbossCharge" type="primary" @click="$router.push('/kbossCharge')" plain
|
||
style="padding: 8px; ">
|
||
充值
|
||
</el-button>
|
||
</div>
|
||
<el-dropdown-item v-if="role.includes('客户')" @click.native="$router.push('/customer/customerInformation')">
|
||
<span style="display: block">个人中心</span>
|
||
</el-dropdown-item>
|
||
<el-dropdown-item @click.native="logout">
|
||
<span style="display: block">退出登录</span>
|
||
</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</el-dropdown>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-show="isShowPanel" class="product-panel" @mouseenter="keepPanel" @mouseleave="sildeOut">
|
||
<aside class="product-panel__side">
|
||
<button type="button" class="product-side-item active">精选产品</button>
|
||
<button type="button" class="product-side-item" @click="navigateTo('/homePage/opc')">OPC</button>
|
||
<button type="button" class="product-side-item" @click="goComputeMarket">算力市场</button>
|
||
<button type="button" class="product-side-item" @click="handleModelSquareClick">Token市集</button>
|
||
<button type="button" class="product-side-item" @click="goTrainPlatform">训推平台</button>
|
||
<button type="button" class="product-side-item" @click="goAgentStore">智能体商店</button>
|
||
<button type="button" class="product-side-item" @click="goSupplySquare">供需广场</button>
|
||
</aside>
|
||
<div class="product-panel__content">
|
||
<div class="product-panel__head">
|
||
<div>
|
||
<h3 class="product-panel__title">精选产品</h3>
|
||
<p>覆盖模型服务、算力资源、智能体应用与供需协同</p>
|
||
</div>
|
||
<button type="button" class="product-panel__more" @click="navigateTo('/homePage/opc')">查看 OPC</button>
|
||
</div>
|
||
<div class="product-group">
|
||
<h4>核心服务</h4>
|
||
<div class="product-grid">
|
||
<button type="button" class="product-card product-card--blue" @click="handleModelSquareClick">
|
||
<span class="product-card__icon">T</span>
|
||
<span class="product-card__text">
|
||
<strong>Token市集</strong>
|
||
<em>一站式 AI 模型交易与服务平台</em>
|
||
</span>
|
||
</button>
|
||
<button type="button" class="product-card product-card--purple" @click="goYuanjing">
|
||
<span class="product-card__icon">AI</span>
|
||
<span class="product-card__text">
|
||
<strong>创镱工坊</strong>
|
||
<em>AI 驱动的创意影像创作平台</em>
|
||
</span>
|
||
</button>
|
||
<button type="button" class="product-card product-card--green" @click="navigateTo('/homePage/opc')">
|
||
<span class="product-card__icon">OPC</span>
|
||
<span class="product-card__text">
|
||
<strong>云枢基座</strong>
|
||
<em>企业级 AI 基础设施与算力底座</em>
|
||
</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="product-group product-group--compact">
|
||
<h4>应用入口</h4>
|
||
<div class="product-grid product-grid--compact">
|
||
<button type="button" class="product-card product-card--plain" @click="goComputeMarket">
|
||
<span class="product-card__text">
|
||
<strong>算力市场</strong>
|
||
<em>高性能算力资源灵活选购</em>
|
||
</span>
|
||
</button>
|
||
<button type="button" class="product-card product-card--plain" @click="goTrainPlatform">
|
||
<span class="product-card__text">
|
||
<strong>训推平台</strong>
|
||
<em>AI 模型全流程开发体验</em>
|
||
</span>
|
||
</button>
|
||
<button type="button" class="product-card product-card--plain" @click="goAgentStore">
|
||
<span class="product-card__text">
|
||
<strong>智能体商店</strong>
|
||
<em>即开即用的智能体服务</em>
|
||
</span>
|
||
</button>
|
||
<button type="button" class="product-card product-card--plain" @click="goSupplySquare">
|
||
<span class="product-card__text">
|
||
<strong>供需广场</strong>
|
||
<em>资源、算力、服务供需匹配</em>
|
||
</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div
|
||
v-show="aiDialogVisible"
|
||
ref="aiChatPanel"
|
||
class="ai-chat-panel"
|
||
:style="aiPanelStyle"
|
||
>
|
||
<div class="ai-chat-panel__header" @mousedown="startAIPanelDrag">
|
||
<div class="ai-chat-panel__title">
|
||
<span class="ai-chat-panel__logo">AI</span>
|
||
<span>有问题,找开元</span>
|
||
</div>
|
||
<i class="el-icon-close ai-chat-panel__close" @click="closeAIPanel"></i>
|
||
</div>
|
||
<div ref="aiChatMessages" class="ai-chat-panel__body">
|
||
<div v-if="!aiMessages.length" class="ai-chat-panel__welcome">
|
||
<h3>Hi!</h3>
|
||
<p>我是开元智能助手,可以为您解答算力服务器选型、采购、部署和资源配置等问题。</p>
|
||
<div class="ai-chat-panel__suggestions">
|
||
<span
|
||
v-for="item in aiQuickQuestions"
|
||
:key="item"
|
||
class="ai-chat-panel__tag"
|
||
@click="useAISuggestion(item)"
|
||
>
|
||
{{ item }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div
|
||
v-for="(item, index) in aiMessages"
|
||
:key="index"
|
||
:class="['ai-chat__message', `is-${item.role}`]"
|
||
>
|
||
<div class="ai-chat__avatar">
|
||
{{ item.role === 'assistant' ? 'AI' : '我' }}
|
||
</div>
|
||
<div class="ai-chat__bubble">
|
||
<div
|
||
v-if="item.role === 'assistant'"
|
||
class="ai-chat__rich-text"
|
||
v-html="formatAIContent(item.content)"
|
||
></div>
|
||
<span v-else>{{ item.content }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="ai-chat-panel__input-wrap">
|
||
<div class="ai-chat-panel__actions">
|
||
<span class="ai-chat-panel__new" @click="resetAIChat">新对话</span>
|
||
<span class="ai-chat__tip">Enter 发送</span>
|
||
</div>
|
||
<div class="ai-chat-panel__input">
|
||
<el-input
|
||
v-model="aiInput"
|
||
type="textarea"
|
||
:rows="2"
|
||
resize="none"
|
||
maxlength="500"
|
||
placeholder="请输入你的问题"
|
||
@keydown.native="handleAIKeydown"
|
||
/>
|
||
<el-button
|
||
class="ai-chat-panel__send"
|
||
type="text"
|
||
:loading="aiLoading"
|
||
@click="sendAIMessage"
|
||
>
|
||
<i class="iconfont icon-fasong"></i>
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<message-center
|
||
ref="messageCenter"
|
||
:visible.sync="messageCenterVisible"
|
||
:userId="userId"
|
||
@unread-count-update="handleUnreadCountUpdate"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import Vue from 'vue'
|
||
import { computingData, networkData, storageData, testData } from "@/views/homePage/components/topBox/testData";
|
||
import { reqNavList, reqNewHomeFestival, reqNewHomeSync } from "@/api/newHome";
|
||
import { mapGetters, mapState } from "vuex";
|
||
import { getLogoAPI, getUserInfoAPI } from "@/api/login";
|
||
import { reqApplyChannel } from "@/api/customer/channel";
|
||
import store from "@/store";
|
||
import { getHomePath } from '@/views/setting/tools'
|
||
import MessageCenter from '@/components/MessageCenter/MessageCenter.vue'
|
||
import { reqAIChat } from '@/api/AI/ai'
|
||
import { gotoYuanJingAPI } from '@/api/gotoYuanJing'
|
||
|
||
export default Vue.extend({
|
||
name: "TopBox",
|
||
components: {
|
||
MessageCenter
|
||
},
|
||
data() {
|
||
return {
|
||
aiDialogVisible: false,
|
||
aiInput: '',
|
||
aiLoading: false,
|
||
aiMessages: [],
|
||
aiPanelPosition: {
|
||
left: null,
|
||
top: null
|
||
},
|
||
aiPanelDragging: false,
|
||
aiPanelDragOffset: {
|
||
x: 0,
|
||
y: 0
|
||
},
|
||
aiQuickQuestions: [
|
||
'推荐适合训练大模型的 GPU 服务器',
|
||
'4090 和 A100 怎么选',
|
||
'有没有高性价比 8 卡方案',
|
||
'国产化算力服务器有哪些'
|
||
],
|
||
messageCenterVisible: false,
|
||
homePath: getHomePath(),
|
||
isShowKbossCharge: false,
|
||
role: sessionStorage.getItem("jueseNew") == "admin" ? "" : (sessionStorage.getItem("jueseNew") || ""),
|
||
userId: sessionStorage.getItem("userId"),
|
||
firId: "",
|
||
secId: "",
|
||
nick_name: "",
|
||
showTimer: null,
|
||
hideTimer: null,
|
||
showPanelData: [],
|
||
secMenuData: [],
|
||
showPanelRightData: [],
|
||
threeData: [],
|
||
fourData: [],
|
||
product_service: [],
|
||
messageCount: 0
|
||
}
|
||
},
|
||
created() {
|
||
this.homePath = getHomePath()
|
||
if (sessionStorage.getItem('userId')) {
|
||
this.$store.commit('setLoginState', true);
|
||
}
|
||
!this.showRegisterButton && this.getUserInfo();
|
||
this.init()
|
||
this.initData()
|
||
},
|
||
mounted() {
|
||
if (sessionStorage.getItem("username")) {
|
||
this.nick_name = sessionStorage.getItem("username");
|
||
}
|
||
|
||
// ===== 强制透明背景(导航栏 + 页面根元素) =====
|
||
this.$nextTick(() => {
|
||
// 1. 导航栏强制透明
|
||
const topContainer = document.getElementById('topContainer');
|
||
if (topContainer) {
|
||
topContainer.style.background = 'transparent';
|
||
topContainer.style.backgroundColor = 'transparent';
|
||
topContainer.style.backgroundImage = 'none';
|
||
topContainer.scrollIntoView({
|
||
behavior: 'smooth',
|
||
block: 'start'
|
||
});
|
||
}
|
||
// 父容器和占位符
|
||
const nav = document.querySelector('.top-nav');
|
||
if (nav) {
|
||
nav.style.background = 'transparent';
|
||
nav.style.backgroundColor = 'transparent';
|
||
nav.style.backgroundImage = 'none';
|
||
}
|
||
const placeholder = document.querySelector('.top-nav-placeholder');
|
||
if (placeholder) {
|
||
placeholder.style.background = 'transparent';
|
||
placeholder.style.backgroundColor = 'transparent';
|
||
placeholder.style.backgroundImage = 'none';
|
||
}
|
||
|
||
// 2. 页面背景强制透明(关键!解决根本问题)
|
||
document.body.style.background = 'transparent';
|
||
document.body.style.backgroundColor = 'transparent';
|
||
document.documentElement.style.background = 'transparent';
|
||
document.documentElement.style.backgroundColor = 'transparent';
|
||
});
|
||
window.addEventListener('kboss-open-ai-chat', this.handleExternalAIOpen);
|
||
},
|
||
beforeDestroy() {
|
||
window.removeEventListener('kboss-open-ai-chat', this.handleExternalAIOpen);
|
||
this.stopAIPanelDrag()
|
||
},
|
||
computed: {
|
||
...mapGetters(["sidebar", "avatar", "device"]),
|
||
...mapState({
|
||
isShowPanel: (state) => state.product.showHomeNav,
|
||
navIndex: (state) => state.product.navIndex,
|
||
gridObj: state => state.operationAnalysis.gridObj,
|
||
mybalance: state => state.user.mybalance,
|
||
logoutUrl: state => state.login.logoutUrl,
|
||
loginStateVuex: state => state.login.loginState,
|
||
logoInfoNew: state => state.product.logoInfoNew,
|
||
}),
|
||
loginState() {
|
||
const userId = sessionStorage.getItem('userId');
|
||
return this.loginStateVuex || (userId !== null && userId !== 'null' && userId !== '');
|
||
},
|
||
showRegisterButton() {
|
||
const orgType = window.sessionStorage.getItem('org_type');
|
||
const userId = window.sessionStorage.getItem('userId');
|
||
return orgType !== '2' && orgType !== '3' && userId === null;
|
||
},
|
||
username() {
|
||
return sessionStorage.getItem('username') || '';
|
||
},
|
||
isNcmatchDomain() {
|
||
return window.location.hostname.includes('ncmatch.cn');
|
||
},
|
||
isActiveHome() {
|
||
if (this.isNcmatchDomain) {
|
||
return this.$route.path.includes('/ncmatchHome/index');
|
||
} else {
|
||
return this.$route.path.includes('/homePage/index');
|
||
}
|
||
},
|
||
isActiveTokenMarket() {
|
||
const category = this.$route.query.category || this.$route.query.tab || ''
|
||
return this.$route.path === '/tokenMarket' ||
|
||
(this.$route.path === '/product' && ['TOKEN市集', 'Token市集', 'token市集'].includes(category))
|
||
},
|
||
aiPanelStyle() {
|
||
if (this.aiPanelPosition.left === null || this.aiPanelPosition.top === null) {
|
||
return {}
|
||
}
|
||
return {
|
||
left: `${this.aiPanelPosition.left}px`,
|
||
top: `${this.aiPanelPosition.top}px`,
|
||
right: 'auto',
|
||
bottom: 'auto'
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
navigateTo(path) {
|
||
this.$store.commit('setShowHomeNav', false)
|
||
if (this.$route.path === path) return
|
||
this.$router.push(path)
|
||
},
|
||
handleModelSquareClick() {
|
||
this.$store.commit('setShowHomeNav', false)
|
||
this.$router.push({
|
||
path: '/homePage/tokenMarket',
|
||
query: {
|
||
category: 'TOKEN市集',
|
||
single: '1'
|
||
}
|
||
})
|
||
},
|
||
goComputeMarket() {
|
||
this.navigateTo('/homePage/computeMarket')
|
||
},
|
||
goTrainPlatform() {
|
||
this.navigateTo('/homePage/trainPlatform')
|
||
},
|
||
goAgentStore() {
|
||
this.navigateTo('/homePage/agentStore')
|
||
},
|
||
goSupplySquare() {
|
||
this.navigateTo('/ncmatchHome/supplyAndDemandSquare')
|
||
},
|
||
goAbout() {
|
||
this.navigateTo('/homePage/about')
|
||
},
|
||
async goYuanjing() {
|
||
this.$store.commit('setShowHomeNav', false)
|
||
const yuanJingBaseUrl = window.location.origin === 'https://dev.opencomputing.cn'
|
||
? 'https://aidev.opencomputing.cn'
|
||
: 'https://ai.opencomputing.cn'
|
||
if (!this.loginState) {
|
||
window.open(`${yuanJingBaseUrl}/`, '_blank')
|
||
return
|
||
}
|
||
const yuanJingWindow = window.open('', '_blank')
|
||
try {
|
||
const res = await gotoYuanJingAPI({
|
||
user_id: sessionStorage.getItem('userId')
|
||
})
|
||
const deerer = this.getYuanJingAuthorization(res)
|
||
if (!deerer) {
|
||
if (yuanJingWindow) yuanJingWindow.close()
|
||
this.$message.error((res && res.msg) || '获取元境授权参数失败')
|
||
return
|
||
}
|
||
const loginUrl = `${yuanJingBaseUrl}/#/getCookie?deerer=${encodeURIComponent(deerer)}`
|
||
if (yuanJingWindow) {
|
||
yuanJingWindow.location.href = loginUrl
|
||
} else {
|
||
window.location.href = loginUrl
|
||
}
|
||
} catch (error) {
|
||
if (yuanJingWindow) yuanJingWindow.close()
|
||
this.$message.error('跳转元境失败,请稍后重试')
|
||
}
|
||
},
|
||
getYuanJingAuthorization(res) {
|
||
if (!res) return ''
|
||
if (typeof res === 'string') return res
|
||
const data = res.data || res
|
||
if (typeof data === 'string') return data
|
||
return data.Authorization || data.authorization || data.token || data.header || data.value || ''
|
||
},
|
||
isPanelFirClickable(item) {
|
||
const title = (item && item.firTitle) || ''
|
||
return title === '元境' || title === 'TOKEN市集' || title === 'token市集'
|
||
},
|
||
handlePanelFirClick(item) {
|
||
const title = (item && item.firTitle) || ''
|
||
if (title === '元境') {
|
||
this.$store.commit('setShowHomeNav', false)
|
||
this.goYuanjing()
|
||
return
|
||
}
|
||
if (title === 'TOKEN市集' || title === 'token市集') {
|
||
this.$store.commit('setShowHomeNav', false)
|
||
this.handleModelSquareClick()
|
||
}
|
||
},
|
||
handleAIClick() {
|
||
this.aiDialogVisible = true
|
||
this.$nextTick(() => {
|
||
this.initAIPanelPosition()
|
||
this.scrollAIChatToBottom()
|
||
})
|
||
},
|
||
handleExternalAIOpen() {
|
||
this.handleAIClick()
|
||
},
|
||
closeAIPanel() {
|
||
this.aiDialogVisible = false
|
||
this.stopAIPanelDrag()
|
||
},
|
||
resetAIChat() {
|
||
this.aiMessages = []
|
||
this.aiInput = ''
|
||
},
|
||
useAISuggestion(question) {
|
||
this.sendAIMessage(question)
|
||
},
|
||
initAIPanelPosition() {
|
||
if (this.aiPanelPosition.left !== null && this.aiPanelPosition.top !== null) return
|
||
const panel = this.$refs.aiChatPanel
|
||
if (!panel) return
|
||
const panelWidth = panel.offsetWidth || 380
|
||
const panelHeight = panel.offsetHeight || 620
|
||
this.aiPanelPosition = {
|
||
left: Math.max(window.innerWidth - panelWidth - 24, 16),
|
||
top: Math.max(window.innerHeight - panelHeight - 24, 16)
|
||
}
|
||
},
|
||
startAIPanelDrag(event) {
|
||
if (event.button !== 0) return
|
||
if (event.target && event.target.closest('.ai-chat-panel__close')) return
|
||
const panel = this.$refs.aiChatPanel
|
||
if (!panel) return
|
||
const rect = panel.getBoundingClientRect()
|
||
this.aiPanelDragging = true
|
||
this.aiPanelDragOffset = {
|
||
x: event.clientX - rect.left,
|
||
y: event.clientY - rect.top
|
||
}
|
||
window.addEventListener('mousemove', this.handleAIPanelDrag)
|
||
window.addEventListener('mouseup', this.stopAIPanelDrag)
|
||
document.body.style.userSelect = 'none'
|
||
},
|
||
handleAIPanelDrag(event) {
|
||
if (!this.aiPanelDragging) return
|
||
const panel = this.$refs.aiChatPanel
|
||
if (!panel) return
|
||
const panelWidth = panel.offsetWidth || 380
|
||
const panelHeight = panel.offsetHeight || 620
|
||
const minLeft = 0, minTop = 0
|
||
const maxLeft = Math.max(window.innerWidth - panelWidth, 0)
|
||
const maxTop = Math.max(window.innerHeight - panelHeight, 0)
|
||
const nextLeft = event.clientX - this.aiPanelDragOffset.x
|
||
const nextTop = event.clientY - this.aiPanelDragOffset.y
|
||
this.aiPanelPosition = {
|
||
left: Math.min(Math.max(nextLeft, minLeft), maxLeft),
|
||
top: Math.min(Math.max(nextTop, minTop), maxTop)
|
||
}
|
||
},
|
||
stopAIPanelDrag() {
|
||
this.aiPanelDragging = false
|
||
window.removeEventListener('mousemove', this.handleAIPanelDrag)
|
||
window.removeEventListener('mouseup', this.stopAIPanelDrag)
|
||
document.body.style.userSelect = ''
|
||
},
|
||
handleAIKeydown(event) {
|
||
if (event.key === 'Enter' && !event.shiftKey) {
|
||
event.preventDefault()
|
||
this.sendAIMessage()
|
||
}
|
||
},
|
||
async sendAIMessage(quickQuestion) {
|
||
const message = (quickQuestion || this.aiInput).trim()
|
||
if (!message || this.aiLoading) return
|
||
this.aiMessages.push({ role: 'user', content: message })
|
||
this.aiInput = ''
|
||
const loadingMessageIndex = this.aiMessages.push({
|
||
role: 'assistant',
|
||
content: '[正在检索并生成回答...]'
|
||
}) - 1
|
||
this.aiLoading = true
|
||
this.$nextTick(() => this.scrollAIChatToBottom())
|
||
try {
|
||
const response = await reqAIChat({ message }, (content) => {
|
||
if (!content) return
|
||
this.$set(this.aiMessages, loadingMessageIndex, { role: 'assistant', content })
|
||
this.$nextTick(() => this.scrollAIChatToBottom())
|
||
})
|
||
if (response && response.content) {
|
||
this.$set(this.aiMessages, loadingMessageIndex, { role: 'assistant', content: response.content })
|
||
} else {
|
||
this.$set(this.aiMessages, loadingMessageIndex, { role: 'assistant', content: '暂时没有获取到回复,请稍后再试。' })
|
||
}
|
||
} catch (error) {
|
||
this.$set(this.aiMessages, loadingMessageIndex, { role: 'assistant', content: '抱歉,当前服务繁忙,请稍后再试。' })
|
||
} finally {
|
||
this.aiLoading = false
|
||
this.$nextTick(() => this.scrollAIChatToBottom())
|
||
}
|
||
},
|
||
escapeAIHtml(content) {
|
||
return String(content || '')
|
||
.replace(/&/g, '&')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>')
|
||
},
|
||
formatAIInline(content) {
|
||
return this.escapeAIHtml(content).replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
||
},
|
||
formatAIContent(content) {
|
||
if (!content) return ''
|
||
const normalizedContent = String(content)
|
||
.replace(/\r\n/g, '\n')
|
||
.replace(/ {2,}/g, '\n')
|
||
.replace(/\n{3,}/g, '\n\n')
|
||
const lines = normalizedContent.split('\n')
|
||
return lines.map((line) => {
|
||
const trimmed = line.trim()
|
||
if (!trimmed) return '<div class="ai-chat__paragraph ai-chat__paragraph--space"></div>'
|
||
if (/^-\s+/.test(trimmed)) {
|
||
return `<div class="ai-chat__item"><span class="ai-chat__item-dot"></span><span>${this.formatAIInline(trimmed.replace(/^-\s+/, ''))}</span></div>`
|
||
}
|
||
if (/^\*\*(.+?)\*\*$/.test(trimmed)) {
|
||
return `<div class="ai-chat__section-title">${this.formatAIInline(trimmed)}</div>`
|
||
}
|
||
return `<div class="ai-chat__paragraph">${this.formatAIInline(trimmed)}</div>`
|
||
}).join('')
|
||
},
|
||
scrollAIChatToBottom() {
|
||
const messageBox = this.$refs.aiChatMessages
|
||
if (messageBox) messageBox.scrollTop = messageBox.scrollHeight
|
||
},
|
||
handleMessageClick() {
|
||
if (this.loginState) {
|
||
this.messageCenterVisible = true;
|
||
if (this.$refs.messageCenter) this.$refs.messageCenter.open();
|
||
} else {
|
||
this.handleGoLogin()
|
||
}
|
||
},
|
||
handleUnreadCountUpdate(count) {
|
||
this.messageCount = count;
|
||
},
|
||
goB() {
|
||
if (sessionStorage.getItem('jueseNew').includes('客户')) {
|
||
this.$router.push('/product/productHome')
|
||
} else if (sessionStorage.getItem('jueseNew').includes('运营')) {
|
||
this.$router.push('/operation/supplierManagement')
|
||
}else if(sessionStorage.getItem('jueseNew').includes('运维')){
|
||
this.$router.push('/operationAndMaintenance/workOrderProcessing')
|
||
}else if(sessionStorage.getItem('jueseNew').includes('销售')){
|
||
this.$router.push('/sales/distributorManagement')
|
||
}else if(sessionStorage.getItem('jueseNew').includes('财务')){
|
||
this.$router.push('/finance/supplierSettlementStatistics')
|
||
}else if(sessionStorage.getItem('jueseNew').includes('admin')){
|
||
this.$router.push('/superAdministrator/addAdmin')
|
||
}
|
||
},
|
||
init() {
|
||
let remoteUrl = ''
|
||
if (window.location.href.includes("dev")) {
|
||
remoteUrl = 'https://www.kaiyuancloud.cn/dev/reseller/get_ipc_logo.dspy'
|
||
} else if (window.location.href.includes("localhost")) {
|
||
remoteUrl = 'http://localhost:9527/'
|
||
} else {
|
||
remoteUrl = 'https://www.kaiyuancloud.cn/reseller/get_ipc_logo.dspy'
|
||
}
|
||
let params = { url_link: window.location.href.split("#")[0] }
|
||
getLogoAPI(params).then((res) => {
|
||
if (res.status == true && res.data && res.data.length) {
|
||
this.$store.commit('setLogoInfoNew', res.data[0].additional_msg);
|
||
this.isShow = true
|
||
if (res.data[0].orgname == '中关村数智人工智能产业联盟') {
|
||
this.logoUrlOut = 'https://www.ncmatch.cn'
|
||
}
|
||
this.photosUrl = res.data[0];
|
||
if (this.photosUrl.orgname != '业主机构') {
|
||
this.isLogo = true
|
||
this.logoImg = this.photosUrl.logo;
|
||
this.$store.commit('setLogo', this.photosUrl.logo)
|
||
this.logoText = this.photosUrl.orgname;
|
||
} else {
|
||
this.$store.commit('setLogo', "")
|
||
}
|
||
} else {
|
||
this.$message({ message: "获取ipc失败~", type: "error" });
|
||
}
|
||
});
|
||
},
|
||
async logout() {
|
||
let redirectPath = ''
|
||
if (this.$route && this.$route.fullPath && !this.$route.fullPath.includes('/login')) {
|
||
redirectPath = this.$route.fullPath
|
||
sessionStorage.setItem('loginRedirectPath', redirectPath)
|
||
}
|
||
this.$store.commit('setLoginState', false)
|
||
store.commit('tagsView/resetBreadcrumbState');
|
||
store.commit('permission/RESET_ROUTES');
|
||
sessionStorage.removeItem("auths");
|
||
sessionStorage.removeItem("routes");
|
||
sessionStorage.removeItem("user");
|
||
sessionStorage.removeItem("userId");
|
||
sessionStorage.removeItem("org_type")
|
||
sessionStorage.removeItem("userType");
|
||
sessionStorage.removeItem("orgType");
|
||
sessionStorage.removeItem("roles");
|
||
sessionStorage.removeItem("juese");
|
||
sessionStorage.removeItem("jueseNew");
|
||
localStorage.removeItem("auths");
|
||
localStorage.removeItem("routes");
|
||
localStorage.removeItem("user");
|
||
localStorage.removeItem("userId");
|
||
localStorage.removeItem("org_type")
|
||
localStorage.removeItem('userId')
|
||
await this.$router.push({
|
||
path: '/login',
|
||
query: redirectPath ? { redirect: redirectPath } : {}
|
||
});
|
||
},
|
||
edituserPassword() {
|
||
this.passwordDialog = true;
|
||
},
|
||
channelFirstBtn() {
|
||
reqApplyChannel({ user_id: this.userId }).then(res => {
|
||
if (res.code == "100" || res.code == "210") {
|
||
this.$message.success(res.msg)
|
||
} else if (res.code == "300") {
|
||
this.channelManagementShow = true
|
||
} else if (res.code == "200") {
|
||
this.$router.push('/customer/channelMangement')
|
||
}
|
||
})
|
||
},
|
||
initMybalance() {
|
||
return sessionStorage.getItem('mybalance')
|
||
},
|
||
copyBtn() {
|
||
const textToCopy = this.$refs.contentToCopy.innerText;
|
||
navigator.clipboard.writeText(textToCopy).then(() => {
|
||
this.$message.success('复制成功!')
|
||
}).catch((error) => {
|
||
console.error('复制失败', error);
|
||
});
|
||
},
|
||
async getUserInfo() {
|
||
if (!this.userId) return;
|
||
getUserInfoAPI({ id: this.userId }).then((res) => {
|
||
if (res.status) {
|
||
this.userInfoList = res.data;
|
||
sessionStorage.setItem("orgid", res.data[0].orgid);
|
||
} else {
|
||
this.$message({ message: res.msg, type: "error" });
|
||
}
|
||
});
|
||
},
|
||
handleShow(isShow) {
|
||
let resverNode = document.getElementById('resverIcon')
|
||
if (isShow) {
|
||
if (this.role.includes('客户')) {
|
||
this.$store.dispatch('user/getCustmoersMoney')
|
||
}
|
||
resverNode.style.transform = 'rotate(180deg)'
|
||
} else {
|
||
resverNode.style.transform = 'rotate(0)'
|
||
}
|
||
},
|
||
sildeThrMenu(item) {
|
||
let res = []
|
||
res.push(item)
|
||
this.showPanelRightData = res
|
||
},
|
||
clickGo(item) {
|
||
this.$store.commit('setShowHomeNav', false)
|
||
let userId = sessionStorage.getItem('userId')
|
||
const orgType = window.sessionStorage.getItem('org_type');
|
||
let isKehu = orgType === '2' || orgType === '3';
|
||
if (item.type === '百度云') {
|
||
if (this.loginState) {
|
||
this.$store.commit('setRedirectUrl', item.url)
|
||
localStorage.setItem('redirectUrl', item.url)
|
||
localStorage.setItem('userRescourseUrl', item.listUrl)
|
||
this.$router.push({
|
||
name: 'baiduProductShow',
|
||
params: { listUrl: item.listUrl, url: item.url }
|
||
})
|
||
} else {
|
||
this.$router.push({ path: "/login", query: { fromPath: 'homePage', type: 'bd', listUrl: item.listUrl, url: item.url } })
|
||
}
|
||
} else if (item.type === '阿里云') {
|
||
if (this.loginState) {
|
||
reqNewHomeSync().then(response => {
|
||
if (response.status) {
|
||
reqNewHomeFestival().then(res => {
|
||
if (res.status) window.open(res.data)
|
||
else this.$message.warning(res.msg)
|
||
})
|
||
} else {
|
||
this.$message.warning(response.msg)
|
||
}
|
||
})
|
||
} else {
|
||
this.$router.push({ path: "/login", query: { fromPath: 'homePage', type: 'ali' } })
|
||
}
|
||
} else if (item.type === '智算' || item.type === '算力网络') {
|
||
if (item.name === '容器云') {
|
||
if (this.loginState) {
|
||
this.$router.push('/product/productHome/k8s/createK8s')
|
||
} else {
|
||
this.$router.push({ path: "/login", query: { fromPath: 'homePage', type: 'rqy' } })
|
||
}
|
||
} else {
|
||
this.$router.push({ path: '/homePage/detail', query: { id: item.id } })
|
||
}
|
||
} else if (item.name === '灵医智能体') {
|
||
this.$router.push('/homePage/hospital')
|
||
} else if (item.name === '客悦·智能客服') {
|
||
this.$router.push('/homePage/customerService')
|
||
}
|
||
},
|
||
changeData(data) {
|
||
this.showPanelData = data || []
|
||
this.secMenuData = data?.[0]?.secMenu || []
|
||
if (this.secMenuData.length > 0) {
|
||
const firstSecMenu = this.secMenuData[0]
|
||
this.threeData = firstSecMenu.thrMenu || []
|
||
if (this.threeData.length > 0) {
|
||
this.showPanelRightData = this.threeData.map(item => ({
|
||
...item,
|
||
thrTitle: item.thrTitle || firstSecMenu.secTitle
|
||
}))
|
||
} else {
|
||
this.showPanelRightData = [{ thrTitle: firstSecMenu.secTitle, value: [] }]
|
||
}
|
||
} else {
|
||
this.threeData = []
|
||
this.showPanelRightData = []
|
||
}
|
||
},
|
||
initData() {
|
||
reqNavList({ url_link: window.location.href }).then(res => {
|
||
if (res.status) {
|
||
this.product_service = this.buildData(res.data.product_service)
|
||
this.changeData(this.product_service)
|
||
}
|
||
}).catch(error => {
|
||
console.error("获取导航数据失败:", error)
|
||
this.product_service = []
|
||
this.changeData([])
|
||
})
|
||
},
|
||
buildData(data) {
|
||
let res = [];
|
||
data.forEach(item => {
|
||
if (item.secMenu && Array.isArray(item.secMenu)) {
|
||
item.secMenu.forEach(secItem => {
|
||
if (secItem.thrMenu && Array.isArray(secItem.thrMenu)) {
|
||
secItem.thrMenu.forEach(thrItem => {
|
||
if (thrItem.value && Array.isArray(thrItem.value)) {
|
||
thrItem.value.forEach(valueItem => {
|
||
valueItem.type = secItem.secTitle;
|
||
});
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
});
|
||
return data;
|
||
},
|
||
sildeSecMenu(item) {
|
||
this.secId = item.id
|
||
if (!item.thrMenu || item.thrMenu.length === 0) {
|
||
this.threeData = []
|
||
this.showPanelRightData = [{ thrTitle: item.secTitle, value: [] }]
|
||
return
|
||
}
|
||
this.threeData = item.thrMenu.map(menu => ({
|
||
...menu,
|
||
thrTitle: menu.thrTitle || item.secTitle
|
||
}))
|
||
this.showPanelRightData = this.threeData
|
||
},
|
||
networkData() { return networkData },
|
||
storageData() { return storageData },
|
||
testData() { return testData },
|
||
sildeItemIn(item) {
|
||
this.firId = item.id
|
||
this.secId = item.secMenu[0].id
|
||
this.secMenuData = item.secMenu || []
|
||
this.showPanelRightData = this.secMenuData[0].thrMenu || []
|
||
},
|
||
computingData() { return computingData },
|
||
sildeIn(item) {
|
||
this.changeData(item)
|
||
if (this.hideTimer) clearTimeout(this.hideTimer)
|
||
this.showTimer = setTimeout(() => {
|
||
this.$store.commit('setShowHomeNav', true)
|
||
}, 100)
|
||
},
|
||
sildeOut() {
|
||
if (this.showTimer) clearTimeout(this.showTimer)
|
||
this.hideTimer = setTimeout(() => {
|
||
this.$store.commit('setShowHomeNav', false)
|
||
}, 200)
|
||
},
|
||
keepPanel() {
|
||
if (this.hideTimer) clearTimeout(this.hideTimer)
|
||
},
|
||
handleGoLogin() {
|
||
let token = this.$store.getters.token;
|
||
if (!token) {
|
||
this.$message.warning('请先登录哦~');
|
||
this.$router.push({ path: '/login' });
|
||
}
|
||
},
|
||
goHome() {
|
||
this.$store.commit('setShowHomeNav', false)
|
||
if (this.isNcmatchDomain) {
|
||
this.$router.push('/ncmatchHome/index');
|
||
} else {
|
||
this.$router.push('/homePage/index');
|
||
}
|
||
}
|
||
},
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
/* ===== 强制透明重置(最高优先级) ===== */
|
||
.top-nav,
|
||
.top-nav-placeholder,
|
||
.nav-container {
|
||
background: transparent !important;
|
||
background-color: transparent !important;
|
||
background-image: none !important;
|
||
backdrop-filter: none !important;
|
||
-webkit-backdrop-filter: none !important;
|
||
box-shadow: none !important;
|
||
}
|
||
|
||
.top-nav {
|
||
position: relative;
|
||
height: 0;
|
||
width: 100%;
|
||
min-width: 1200px;
|
||
color: #111827;
|
||
font-family: PingFang SC, Microsoft YaHei, Arial, sans-serif;
|
||
box-sizing: border-box;
|
||
|
||
}
|
||
|
||
.top-nav-placeholder {
|
||
display: block;
|
||
height: 0;
|
||
width: 100%;
|
||
flex-shrink: 0;
|
||
|
||
}
|
||
|
||
.nav-container {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 3000;
|
||
width: 100%;
|
||
height: 82px;
|
||
padding: 0 42px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.brand {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
min-width: 220px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.brand-logo {
|
||
width: 184px;
|
||
max-height: 52px;
|
||
object-fit: contain;
|
||
object-position: left center;
|
||
display: block;
|
||
}
|
||
|
||
.site-nav {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 38px;
|
||
margin-left: auto;
|
||
margin-right: 32px;
|
||
}
|
||
|
||
.nav-item {
|
||
padding: 0;
|
||
border: 0;
|
||
background: transparent;
|
||
color: #111827;
|
||
cursor: pointer;
|
||
font-size: 17px !important;
|
||
line-height: 82px;
|
||
font-weight: 600;
|
||
white-space: nowrap;
|
||
transition: color 0.2s ease;
|
||
|
||
&:hover,
|
||
&.active {
|
||
color: #1e6fff;
|
||
}
|
||
}
|
||
|
||
.nav-item--product {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
|
||
.iconfont {
|
||
font-size: 13px !important;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
|
||
.nav-lang {
|
||
color: #374151;
|
||
font-size: 15px !important;
|
||
}
|
||
|
||
.user-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
}
|
||
|
||
.functions {
|
||
color: #000;
|
||
cursor: pointer;
|
||
font-size: 20px !important;
|
||
line-height: 1;
|
||
transition: color 0.2s ease;
|
||
|
||
&:hover {
|
||
color: #1E6FFF;
|
||
}
|
||
}
|
||
|
||
.console-link {
|
||
height: 36px;
|
||
padding: 0;
|
||
border: 0;
|
||
background: transparent;
|
||
color: #333;
|
||
cursor: pointer;
|
||
font-size: 15px !important;
|
||
font-weight: 600;
|
||
line-height: 36px;
|
||
transition: color 0.2s ease;
|
||
|
||
&:hover {
|
||
color: #1E6FFF;
|
||
}
|
||
}
|
||
|
||
.login-btn {
|
||
height: 36px;
|
||
padding: 0;
|
||
border: 0;
|
||
background: transparent;
|
||
color: #333;
|
||
cursor: pointer;
|
||
font-size: 15px !important;
|
||
font-weight: 500;
|
||
line-height: 36px;
|
||
transition: color 0.2s ease;
|
||
|
||
&:hover {
|
||
color: #1E6FFF;
|
||
}
|
||
}
|
||
|
||
.register-btn {
|
||
height: 36px;
|
||
padding: 0 16px;
|
||
border: 0;
|
||
border-radius: 10px;
|
||
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
|
||
color: #fff;
|
||
cursor: pointer;
|
||
font-size: 15px !important;
|
||
font-weight: 600;
|
||
line-height: 36px;
|
||
transition: opacity 0.2s ease;
|
||
|
||
&:hover {
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
|
||
.login-pill {
|
||
min-width: 58px;
|
||
height: 36px;
|
||
padding: 0 20px;
|
||
border: 0;
|
||
border-radius: 999px;
|
||
background: #050505;
|
||
color: #fff;
|
||
cursor: pointer;
|
||
font-size: 15px !important;
|
||
font-weight: 600;
|
||
line-height: 36px;
|
||
transition: opacity 0.2s ease;
|
||
|
||
&:hover {
|
||
opacity: 0.84;
|
||
}
|
||
}
|
||
|
||
.login-pill--user {
|
||
max-width: 150px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.product-panel {
|
||
position: fixed;
|
||
top: 82px;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 2999;
|
||
min-height: 340px;
|
||
display: flex;
|
||
background: rgba(255, 255, 255, 0.98);
|
||
backdrop-filter: blur(14px);
|
||
box-shadow: 0 20px 46px rgba(15, 23, 42, 0.1);
|
||
border-top: 1px solid rgba(15, 23, 42, 0.04);
|
||
}
|
||
|
||
.product-panel__side {
|
||
width: 210px;
|
||
padding: 20px 16px;
|
||
background: linear-gradient(180deg, #f4f8ff 0%, #f8fafc 100%);
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.product-side-item {
|
||
width: 100%;
|
||
height: 42px;
|
||
padding: 0 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
border: 0;
|
||
border-radius: 12px;
|
||
background: transparent;
|
||
color: #374151;
|
||
cursor: pointer;
|
||
font-size: 14px !important;
|
||
text-align: left;
|
||
transition: all 0.2s ease;
|
||
|
||
&:hover,
|
||
&.active {
|
||
background: #e8f1ff;
|
||
color: #1e6fff;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
|
||
.product-panel__content {
|
||
flex: 1;
|
||
padding: 26px 46px 32px;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.product-panel__head {
|
||
margin-bottom: 24px;
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
|
||
p {
|
||
margin: 6px 0 0;
|
||
color: #667085;
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
}
|
||
}
|
||
|
||
.product-panel__title {
|
||
margin: 0;
|
||
color: #111827;
|
||
font-size: 22px !important;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.product-panel__more {
|
||
height: 34px;
|
||
padding: 0 16px;
|
||
border: 1px solid #dbeafe;
|
||
border-radius: 999px;
|
||
background: #f4f8ff;
|
||
color: #1e6fff;
|
||
cursor: pointer;
|
||
font-size: 14px !important;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.product-group {
|
||
margin-bottom: 24px;
|
||
|
||
h4 {
|
||
margin: 0 0 14px;
|
||
color: #111827;
|
||
font-size: 16px !important;
|
||
font-weight: 700;
|
||
}
|
||
}
|
||
|
||
.product-group--compact {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.product-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(180px, 1fr));
|
||
gap: 16px;
|
||
}
|
||
|
||
.product-grid--compact {
|
||
grid-template-columns: repeat(4, minmax(150px, 1fr));
|
||
}
|
||
|
||
.product-card {
|
||
min-height: 86px;
|
||
padding: 16px;
|
||
border: 1px solid #edf1f7;
|
||
border-radius: 16px;
|
||
background: #fff;
|
||
color: #111827;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14px;
|
||
text-align: left;
|
||
font-size: 15px !important;
|
||
font-weight: 600;
|
||
line-height: 1.5;
|
||
box-shadow: 0 8px 22px rgba(31, 45, 61, 0.04);
|
||
transition: all 0.2s ease;
|
||
|
||
&:hover {
|
||
transform: translateY(-2px);
|
||
border-color: #cfe0ff;
|
||
box-shadow: 0 14px 28px rgba(30, 111, 255, 0.1);
|
||
}
|
||
|
||
strong {
|
||
display: block;
|
||
margin-bottom: 6px;
|
||
color: #111827;
|
||
font-size: 16px !important;
|
||
font-weight: 700;
|
||
}
|
||
|
||
em {
|
||
display: block;
|
||
color: #6b7280;
|
||
font-size: 13px !important;
|
||
font-weight: 400;
|
||
font-style: normal;
|
||
}
|
||
|
||
&:hover,
|
||
&:hover strong {
|
||
color: #1e6fff;
|
||
}
|
||
}
|
||
|
||
.product-card__icon {
|
||
width: 42px;
|
||
height: 42px;
|
||
border-radius: 12px;
|
||
display: inline-flex !important;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
color: #fff !important;
|
||
font-size: 13px !important;
|
||
font-weight: 800 !important;
|
||
}
|
||
|
||
.product-card__text {
|
||
min-width: 0;
|
||
}
|
||
|
||
.product-card--blue .product-card__icon {
|
||
background: linear-gradient(135deg, #2563eb, #38bdf8);
|
||
}
|
||
|
||
.product-card--purple .product-card__icon {
|
||
background: linear-gradient(135deg, #7c3aed, #d946ef);
|
||
}
|
||
|
||
.product-card--green .product-card__icon {
|
||
background: linear-gradient(135deg, #059669, #22c55e);
|
||
}
|
||
|
||
.product-card--plain {
|
||
min-height: 74px;
|
||
padding: 14px 16px;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.activeFir {
|
||
background-image: linear-gradient(90deg, rgba(210, 228, 253, .6), hsla(0, 0%, 100%, .6));
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.twoMenuStyle {
|
||
cursor: pointer;
|
||
position: relative;
|
||
color: #091221;
|
||
font-size: 14px !important;
|
||
|
||
&::after {
|
||
transition: all .3s ease-in-out;
|
||
content: '';
|
||
width: 0;
|
||
position: absolute;
|
||
bottom: -5px;
|
||
left: 0;
|
||
height: 2px;
|
||
background: #091221;
|
||
border-radius: 1px;
|
||
}
|
||
}
|
||
|
||
.activeSec {
|
||
font-weight: 600;
|
||
|
||
&::after {
|
||
width: 100% !important;
|
||
}
|
||
}
|
||
|
||
.subTitle {
|
||
font-size: 16px;
|
||
color: #2468f2;
|
||
font-weight: 600;
|
||
margin: 5px 0;
|
||
display: inline-block;
|
||
}
|
||
|
||
.leastMenu {
|
||
overflow-y: auto;
|
||
|
||
.inBox {
|
||
li {
|
||
font-size: 14px !important;
|
||
margin: 6px 0;
|
||
display: flex;
|
||
justify-content: flex-start;
|
||
align-items: flex-end;
|
||
|
||
&:hover {
|
||
cursor: pointer;
|
||
color: #1E6FFF !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.ge {
|
||
background-image: url('https://bce.bdstatic.com/portal-cloud-server/images/nav/dropdown_bar_middle.png');
|
||
box-sizing: border-box;
|
||
display: block;
|
||
height: 100%;
|
||
width: 20px;
|
||
margin: 0 10px;
|
||
}
|
||
|
||
.zhe {
|
||
font-size: 12px !important;
|
||
border-radius: 4px;
|
||
padding: 1px 2px;
|
||
color: red;
|
||
display: inline-block;
|
||
margin-left: 3px;
|
||
}
|
||
|
||
.outUl {
|
||
.outLi {
|
||
padding: 10px;
|
||
|
||
.tilte {
|
||
width: 100%;
|
||
display: inline-block;
|
||
padding: 5px;
|
||
}
|
||
|
||
.inUl {
|
||
.inLi {
|
||
padding: 10px 10px 10px 5px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.logoImg {
|
||
width: 148px;
|
||
height: 48px;
|
||
}
|
||
|
||
.clickItem {
|
||
margin-bottom: 15px !important;
|
||
|
||
&:hover {
|
||
color: #1E6FFF !important;
|
||
}
|
||
}
|
||
|
||
.imgUser {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background-color: #eee;
|
||
width: 46px;
|
||
height: 46px;
|
||
border-radius: 50%;
|
||
color: white;
|
||
margin-right: 8px;
|
||
|
||
img {
|
||
// border-radius: 50%;
|
||
width: 26px;
|
||
height: 26px;
|
||
}
|
||
}
|
||
|
||
.company-name {
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
color: #222F60;
|
||
cursor: pointer;
|
||
transition: color 0.3s ease;
|
||
|
||
&:hover {
|
||
color: #1E6FFF;
|
||
}
|
||
}
|
||
::v-deep .v-model{
|
||
z-index: 1;
|
||
}
|
||
.ai-chat-panel {
|
||
position: fixed;
|
||
right: 24px;
|
||
bottom: 24px;
|
||
width: 380px;
|
||
height: 620px;
|
||
background: #fff;
|
||
border-radius: 20px;
|
||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12);
|
||
z-index: 3000;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
|
||
&__header {
|
||
height: 64px;
|
||
padding: 0 18px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
background: #fff;
|
||
cursor: move;
|
||
}
|
||
|
||
&__title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
font-size: 16px !important;
|
||
font-weight: 600;
|
||
color: #222;
|
||
}
|
||
|
||
&__logo {
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: 50%;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: linear-gradient(90deg, #d66bff 0%, #7d7cff 100%);
|
||
color: #fff;
|
||
font-size: 12px !important;
|
||
}
|
||
|
||
&__close {
|
||
cursor: pointer;
|
||
color: #666;
|
||
font-size: 18px !important;
|
||
}
|
||
|
||
&__body {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 18px 16px;
|
||
background: #fff;
|
||
}
|
||
|
||
&__welcome {
|
||
h3 {
|
||
margin: 0 0 12px;
|
||
color: #5f59ff;
|
||
font-size: 22px !important;
|
||
font-weight: 700;
|
||
}
|
||
|
||
p {
|
||
margin: 0 0 20px;
|
||
font-size: 14px !important;
|
||
line-height: 1.8;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
&__suggestions {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
}
|
||
|
||
&__tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
padding: 10px 14px;
|
||
border-radius: 10px;
|
||
background: #f7f7f8;
|
||
color: #333;
|
||
font-size: 14px !important;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
|
||
&:hover {
|
||
color: #1E6FFF;
|
||
background: #eef5ff;
|
||
}
|
||
}
|
||
|
||
&__input-wrap {
|
||
border-top: 1px solid #f0f0f0;
|
||
padding: 12px 14px 14px;
|
||
background: #fff;
|
||
}
|
||
|
||
&__actions {
|
||
margin-bottom: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
&__new {
|
||
font-size: 13px !important;
|
||
color: #666;
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
color: #1E6FFF;
|
||
}
|
||
}
|
||
|
||
&__input {
|
||
position: relative;
|
||
}
|
||
|
||
&__send {
|
||
position: absolute;
|
||
right: 8px;
|
||
bottom: 8px;
|
||
padding: 0;
|
||
color: #7d7cff;
|
||
}
|
||
}
|
||
|
||
::v-deep .ai-chat-panel__input {
|
||
.el-textarea__inner {
|
||
min-height: 84px !important;
|
||
padding: 12px 48px 12px 12px;
|
||
border-radius: 14px;
|
||
border: 1px solid #e5eaf3;
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
}
|
||
}
|
||
|
||
.ai-chat {
|
||
&__message {
|
||
display: flex;
|
||
gap: 12px;
|
||
margin-bottom: 16px;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
&.is-user {
|
||
flex-direction: row-reverse;
|
||
|
||
.ai-chat__bubble {
|
||
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
|
||
color: #fff;
|
||
}
|
||
}
|
||
}
|
||
|
||
&__avatar {
|
||
flex-shrink: 0;
|
||
width: 34px;
|
||
height: 34px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px !important;
|
||
color: #1E6FFF;
|
||
background: rgba(30, 111, 255, 0.12);
|
||
}
|
||
|
||
&__bubble {
|
||
max-width: calc(100% - 46px);
|
||
padding: 12px 14px;
|
||
border-radius: 12px;
|
||
background: #f7f9fc;
|
||
color: #333;
|
||
font-size: 14px !important;
|
||
line-height: 1.7;
|
||
white-space: pre-wrap;
|
||
word-break: break-word;
|
||
}
|
||
|
||
&__rich-text {
|
||
font-size: 14px !important;
|
||
line-height: 1.7;
|
||
}
|
||
|
||
&__paragraph {
|
||
margin-bottom: 8px;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
&--space {
|
||
height: 8px;
|
||
margin-bottom: 0;
|
||
}
|
||
}
|
||
|
||
&__section-title {
|
||
margin: 12px 0 8px;
|
||
font-weight: 700;
|
||
color: #222F60;
|
||
|
||
&:first-child {
|
||
margin-top: 0;
|
||
}
|
||
}
|
||
|
||
&__item {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 8px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
&__item-dot {
|
||
width: 6px;
|
||
height: 6px;
|
||
margin-top: 9px;
|
||
border-radius: 50%;
|
||
background: #7d7cff;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
&__tip {
|
||
color: #999;
|
||
font-size: 12px !important;
|
||
}
|
||
}
|
||
|
||
::v-deep .ai-chat__rich-text strong {
|
||
font-weight: 700;
|
||
color: #222F60;
|
||
}
|
||
</style> |