2026-05-22 11:07:13 +08:00

547 lines
11 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.

<template>
<div class="experience-page">
<aside class="chat-sidebar">
<button class="back-btn" title="返回上一页" @click="goBack">
<i class="el-icon-arrow-left"></i>
<span>返回</span>
</button>
<div class="brand-card">
<img class="brand-logo" :src="siteLogo" alt="logo">
<div class="brand-info">
<strong>模型体验</strong>
<span>Model Playground</span>
</div>
</div>
<el-button class="new-chat-btn" type="primary" icon="el-icon-plus" @click="startNewChat">
开启新对话
</el-button>
<div class="history-panel">
<div class="panel-title">最近对话</div>
<div
v-for="item in historyList"
:key="item.id"
class="history-item"
:class="{ active: activeHistoryId === item.id }"
@click="activeHistoryId = item.id"
>
<i class="el-icon-chat-dot-round"></i>
<span>{{ item.title }}</span>
</div>
</div>
</aside>
<main class="chat-main">
<header class="chat-header">
<div>
<h2>K-Boss AI 模型助手</h2>
<p>选择模型后可在这里进行问答推理方案生成和能力验证</p>
</div>
</header>
<section ref="messageBody" class="message-body">
<div v-if="messages.length === 0" class="welcome-card">
<img class="welcome-logo" :src="siteLogo" alt="logo">
<h1>你好我是模型体验助手</h1>
<p>可以输入问题体验模型效果也可以点击下方示例快速开始</p>
<div class="prompt-list">
<button
v-for="prompt in promptList"
:key="prompt"
class="prompt-card"
@click="usePrompt(prompt)"
>
{{ prompt }}
</button>
</div>
</div>
<div
v-for="message in messages"
:key="message.id"
class="message-row"
:class="message.role"
>
<div class="avatar">
<img v-if="message.role === 'assistant'" :src="siteLogo" alt="logo">
<i v-else class="el-icon-user"></i>
</div>
<div class="message-bubble">
<div class="message-name">{{ message.role === 'assistant' ? '模型助手' : '我' }}</div>
<div class="message-text">{{ message.content }}</div>
</div>
</div>
</section>
<footer class="chat-input-area">
<div class="billing-tip">
<i class="el-icon-info"></i>
<span>体验模型将会消耗 Tokens费用以实际发生为主</span>
<button type="button">计费说明</button>
</div>
<div class="input-shell">
<el-input
v-model="inputValue"
type="textarea"
:rows="3"
resize="none"
placeholder="请输入你想体验的问题,例如:帮我生成一个模型上架介绍"
@keydown.native.ctrl.enter="sendMessage"
></el-input>
<div class="input-actions">
<span>Ctrl + Enter 发送</span>
<el-button
type="primary"
icon="el-icon-position"
:disabled="!inputValue.trim()"
@click="sendMessage"
>
发送
</el-button>
</div>
</div>
</footer>
</main>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'ModelExperience',
data() {
return {
inputValue: '',
activeHistoryId: 1,
messages: [],
historyList: [
{ id: 1, title: '模型能力咨询' },
{ id: 2, title: '产品介绍生成' },
{ id: 3, title: '部署方案建议' }
],
promptList: [
'帮我介绍一下这个模型适合哪些业务场景',
'生成一段模型上架介绍文案',
'给我一份模型部署前的检查清单',
'对比大语言模型和图像识别模型的使用差异'
]
}
},
computed: {
...mapState({
logoInfoNew: state => state.product.logoInfoNew
}),
siteLogo() {
return this.logoInfoNew?.home?.logoImg || require('@/assets/kyy/LOGO.png')
}
},
methods: {
goBack() {
this.$router.back()
},
startNewChat() {
this.messages = []
this.inputValue = ''
},
usePrompt(prompt) {
this.inputValue = prompt
this.sendMessage()
},
sendMessage() {
const content = this.inputValue.trim()
if (!content) return
this.messages.push({
id: Date.now(),
role: 'user',
content
})
this.inputValue = ''
this.mockAssistantReply(content)
},
mockAssistantReply(question) {
setTimeout(() => {
this.messages.push({
id: Date.now() + 1,
role: 'assistant',
content: `已收到你的问题:“${question}”。这里后续可以接入真实模型接口,目前先展示模型对话页面效果。`
})
this.$nextTick(this.scrollToBottom)
}, 300)
},
scrollToBottom() {
const body = this.$refs.messageBody
if (body) {
body.scrollTop = body.scrollHeight
}
}
}
}
</script>
<style lang="less" scoped>
.experience-page {
display: flex;
width: 100vw;
height: 100vh;
padding: 0;
background: #f5f7fb;
overflow: hidden;
}
.chat-sidebar {
display: flex;
flex-direction: column;
width: 280px;
height: 100vh;
padding: 18px;
margin-right: 0;
background: #ffffff;
border: 1px solid #edf1f7;
border-top: none;
border-bottom: none;
border-left: none;
border-radius: 0;
box-shadow: 0 14px 36px rgba(31, 45, 61, 0.06);
}
.back-btn {
display: inline-flex;
align-items: center;
align-self: flex-start;
height: 34px;
padding: 0 12px;
margin-bottom: 14px;
color: #5d6678;
font-size: 13px;
cursor: pointer;
background: #f7f9fc;
border: 1px solid #edf1f7;
border-radius: 999px;
transition: all 0.2s ease;
i {
margin-right: 4px;
}
&:hover {
color: #1e6fff;
background: #eef5ff;
border-color: #bdd7ff;
}
}
.brand-card {
display: flex;
align-items: center;
padding: 12px;
margin-bottom: 18px;
background: linear-gradient(135deg, #f4f8ff 0%, #eef5ff 100%);
border-radius: 16px;
}
.brand-logo {
width: 48px;
height: 40px;
margin-right: 12px;
object-fit: contain;
}
.brand-info {
strong {
display: block;
color: #1f2d3d;
font-size: 16px;
}
span {
color: #8a94a6;
font-size: 12px;
}
}
.new-chat-btn {
width: 100%;
margin-bottom: 18px;
border-radius: 12px;
}
.history-panel {
flex: 1;
overflow-y: auto;
}
.panel-title {
margin-bottom: 10px;
color: #98a2b3;
font-size: 13px;
}
.history-item {
display: flex;
align-items: center;
height: 42px;
padding: 0 12px;
margin-bottom: 8px;
color: #4d5969;
cursor: pointer;
border-radius: 12px;
transition: all 0.2s ease;
i {
margin-right: 8px;
}
&:hover,
&.active {
color: #1e6fff;
background: #f4f8ff;
}
}
.chat-main {
display: flex;
flex: 1;
min-width: 0;
height: 100vh;
flex-direction: column;
background: #ffffff;
border: none;
border-radius: 0;
box-shadow: none;
overflow: hidden;
}
.chat-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 24px;
border-bottom: 1px solid #edf1f7;
h2 {
margin: 0 0 6px;
color: #1f2d3d;
font-size: 20px;
}
p {
margin: 0;
color: #8a94a6;
font-size: 13px;
}
}
.message-body {
flex: 1;
padding: 28px;
overflow-y: auto;
background:
radial-gradient(circle at 50% 0%, rgba(30, 111, 255, 0.08), transparent 30%),
#fbfcff;
}
.welcome-card {
max-width: 760px;
margin: 80px auto 0;
text-align: center;
.welcome-logo {
width: 72px;
height: 56px;
object-fit: contain;
}
h1 {
margin: 18px 0 10px;
color: #1f2d3d;
font-size: 28px;
}
p {
margin: 0 0 24px;
color: #8a94a6;
}
}
.prompt-list {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
}
.prompt-card {
min-height: 62px;
padding: 14px 16px;
color: #475467;
text-align: left;
cursor: pointer;
background: #ffffff;
border: 1px solid #edf1f7;
border-radius: 16px;
transition: all 0.2s ease;
&:hover {
color: #1e6fff;
border-color: #bdd7ff;
box-shadow: 0 10px 24px rgba(30, 111, 255, 0.1);
}
}
.message-row {
display: flex;
max-width: 860px;
margin: 0 auto 18px;
&.user {
flex-direction: row-reverse;
.avatar {
margin: 0 0 0 12px;
color: #ffffff;
background: #1e6fff;
}
.message-bubble {
color: #ffffff;
background: linear-gradient(135deg, #1e6fff, #5d8dff);
}
.message-name {
color: rgba(255, 255, 255, 0.78);
}
}
}
.avatar {
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 38px;
width: 38px;
height: 38px;
margin-right: 12px;
background: #eef5ff;
border-radius: 50%;
img {
width: 28px;
height: 24px;
object-fit: contain;
}
}
.message-bubble {
max-width: 70%;
padding: 13px 16px;
color: #344054;
background: #ffffff;
border: 1px solid #edf1f7;
border-radius: 16px;
box-shadow: 0 8px 22px rgba(31, 45, 61, 0.05);
}
.message-name {
margin-bottom: 6px;
color: #98a2b3;
font-size: 12px;
}
.message-text {
white-space: pre-wrap;
line-height: 1.7;
}
.chat-input-area {
padding: 18px 24px 22px;
background: #ffffff;
border-top: 1px solid #edf1f7;
}
.billing-tip {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
margin: 0 auto 10px;
color: #8a94a6;
font-size: 12px;
i {
color: #98a2b3;
font-size: 14px;
}
button {
padding: 0;
color: #1e6fff;
font-size: 12px;
cursor: pointer;
background: transparent;
border: none;
&:hover {
text-decoration: underline;
}
}
}
.input-shell {
max-width: 920px;
margin: 0 auto;
padding: 12px;
background: #f8fbff;
border: 1px solid #e5ecf6;
border-radius: 18px;
/deep/ .el-textarea__inner {
border: none;
background: transparent;
box-shadow: none;
}
}
.input-actions {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 2px 0;
span {
color: #98a2b3;
font-size: 12px;
}
/deep/ .el-button {
border-radius: 999px;
}
}
@media (max-width: 900px) {
.experience-page {
flex-direction: column;
height: 100vh;
}
.chat-sidebar {
width: auto;
height: auto;
max-height: 240px;
margin: 0;
}
.prompt-list {
grid-template-columns: 1fr;
}
}
</style>