547 lines
11 KiB
Vue
547 lines
11 KiB
Vue
<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>
|