feat: chat css

This commit is contained in:
ulleo
2025-07-15 19:23:13 +08:00
parent f657721467
commit 59edf69edc
5 changed files with 131 additions and 116 deletions
+2 -1
View File
@@ -49,6 +49,7 @@
},
"qa": {
"new_chat": "New Chat",
"start_sqlbot": "Start SQLBot",
"title": "Smart Query",
"placeholder": "Enter your question",
"ask": "Ask",
@@ -57,7 +58,7 @@
"error": "An error occurred, please try again later",
"question_placeholder": "Press Enter to submit, or use Ctrl + Enter for new line",
"greeting": "Hi, I'm SQLBot, nice to serve you",
"description": "I can help query data, generate charts, detect data anomalies, predict data, etc. Please select a data source to start smart querying~",
"hint_description": "I can help query data, generate charts, detect data anomalies, predict data, etc. Please select a data source to start smart querying~",
"select_datasource": "Select Data Source",
"view_more": "View More",
"selected_datasource": "Selected Data Source",
+2 -1
View File
@@ -52,6 +52,7 @@
},
"qa": {
"new_chat": "新建对话",
"start_sqlbot": "开启问数",
"title": "智能问数",
"placeholder": "请输入您的问题",
"ask": "提问",
@@ -60,7 +61,7 @@
"error": "发生错误,请稍后再试",
"question_placeholder": "按下 Enter 提交问题, 或使用 Ctrl + Enter 换行",
"greeting": "你好,我是SQLBot,很高兴为你服务",
"description": "我可以帮忙查询数据、生成图表、检测数据异常、预测数据等,请选择一个数据源,开启智能问数吧~",
"hint_description": "我可以查询数据、生成图表、检测数据异常、预测数据等,请选择一个数据源,开启智能问数吧~",
"select_datasource": "选择数据源",
"view_more": "查看更多",
"selected_datasource": "已选择数据源",
+11 -26
View File
@@ -24,23 +24,9 @@ withDefaults(
<logo_fold v-if="!hideAvatar" />
</el-icon>
</el-avatar>
<!-- <el-avatar v-if="msg.role === 'user'" class="user-avatar" shape="square">-->
<!-- <el-icon>-->
<!-- <UserFilled v-if="!hideAvatar" />-->
<!-- </el-icon>-->
<!-- </el-avatar>-->
<slot></slot>
<!-- <ChatBlock v-if="!msg.first_chat" :msg="msg" :class="{ 'row-full': msg.role === 'assistant' }">-->
<!-- <slot></slot>-->
<!-- <template #footer>-->
<!-- <slot name="footer"></slot>-->
<!-- </template>-->
<!-- </ChatBlock>-->
<!-- <ChatRecordFirst v-else :current-chat="currentChat" :msg="msg">-->
<!-- <template #footer>-->
<!-- <slot name="footer"></slot>-->
<!-- </template>-->
<!-- </ChatRecordFirst>-->
<div :class="{ 'row-full': msg.role === 'assistant' }">
<slot></slot>
</div>
</div>
</template>
@@ -51,7 +37,9 @@ withDefaults(
align-items: flex-start;
gap: 8px;
padding: 20px 20px 0;
padding: 20px 0 0;
max-width: 800px;
width: 100%;
&.right-to-left {
flex-direction: row-reverse;
@@ -61,14 +49,11 @@ withDefaults(
flex: 1;
width: 0;
}
}
.ai-avatar {
font-size: 28px;
background: transparent;
}
.user-avatar {
font-size: 28px;
.ai-avatar {
font-size: 28px;
background: transparent;
width: 28px;
}
}
</style>
@@ -33,7 +33,7 @@ function clickPredict() {
flex-direction: row;
gap: 8px;
border-radius: 16px;
height: 48px;
min-height: 48px;
line-height: 24px;
font-size: 16px;
padding: 12px 16px;
+115 -87
View File
@@ -59,11 +59,15 @@
class="chat-record-list"
:class="{ 'hide-sidebar': !isAssistant && !chatListSideBarShow }"
>
<div v-if="computedMessages.length == 0" class="welcome-content-block">
<div v-if="computedMessages.length == 0 && !loading" class="welcome-content-block">
<div class="welcome-content">
<div class="logo">SQLBot</div>
<div>{{ t('qa.greeting') }}</div>
<div class="sub">{{ t('qa.description') }}</div>
<div class="greeting">
<el-icon size="32">
<logo_fold />
</el-icon>
{{ t('qa.greeting') }}
</div>
<div class="sub">{{ t('qa.hint_description') }}</div>
<el-button
v-if="currentChatId === undefined"
size="large"
@@ -71,91 +75,96 @@
@click="createNewChat"
>
<el-icon>
<Plus />
<icon_new_chat_outlined />
</el-icon>
{{ t('qa.new_chat') }}
{{ t('qa.start_sqlbot') }}
</el-button>
</div>
</div>
<div v-else-if="computedMessages.length == 0 && loading" class="welcome-content-block">
<logo />
</div>
<el-scrollbar v-if="computedMessages.length > 0" ref="chatListRef">
<template v-for="(message, _index) in computedMessages" :key="_index">
<ChatRow :current-chat="currentChat" :msg="message" :hide-avatar="message.first_chat">
<RecommendQuestion
v-if="message.role === 'assistant' && message.first_chat"
:questions="message.recommended_question"
:first-chat="message.first_chat"
@click-question="quickAsk"
/>
<UserChat v-if="message.role === 'user'" :message="message" />
<template v-if="message.role === 'assistant' && !message.first_chat">
<ChatAnswer
v-if="
message?.record?.analysis_record_id == undefined &&
message?.record?.predict_record_id == undefined
"
:message="message"
>
<template v-if="message.record?.chart">
<div style="padding: 0 22px; display: flex; justify-content: flex-end">
<el-button
text
type="primary"
:disabled="isTyping || isPredictTyping || isAnalysisTyping"
@click="clickAnalysis(message.record?.id)"
>
{{ t('chat.data_analysis') }}
</el-button>
<el-button
text
type="primary"
:disabled="isTyping || isPredictTyping || isAnalysisTyping"
@click="clickPredict(message.record?.id)"
>
{{ t('chat.data_predict') }}
</el-button>
</div>
</template>
</ChatAnswer>
<div
v-if="
message?.record?.analysis_record_id != undefined ||
message?.record?.predict_record_id != undefined
"
class="analysis-container"
>
<template v-if="message.record?.analysis || isAnalysisTyping">
<MdComponent :message="message.record?.analysis_thinking" />
<MdComponent :message="message.record?.analysis" />
</template>
<el-divider
v-if="
(message.record?.analysis || isAnalysisTyping) &&
(message.record?.predict || isPredictTyping)
"
/>
<template v-if="message.record?.predict || isPredictTyping">
<MdComponent :message="message.record?.predict" />
<MdComponent :message="message.record?.predict_content" />
<!-- <PredictChartBlock-->
<!-- :id="message.record?.id + '-predict'"-->
<!-- :data="message.record?.predict_data ?? '[]'"-->
<!-- :message="message"-->
<!-- :chart-type="data.chartType"-->
<!-- />-->
</template>
</div>
</template>
<template v-if="message.role === 'assistant'" #footer>
<div class="chat-scroll" :class="{ 'no-sidebar': !isAssistant && !chatListSideBarShow }">
<template v-for="(message, _index) in computedMessages" :key="_index">
<ChatRow :current-chat="currentChat" :msg="message" :hide-avatar="message.first_chat">
<RecommendQuestion
v-if="message.role === 'assistant' && message.first_chat"
:questions="message.recommended_question"
:first-chat="message.first_chat"
@click-question="quickAsk"
/>
</template>
</ChatRow>
</template>
<UserChat v-if="message.role === 'user'" :message="message" />
<template v-if="message.role === 'assistant' && !message.first_chat">
<ChatAnswer
v-if="
message?.record?.analysis_record_id == undefined &&
message?.record?.predict_record_id == undefined
"
:message="message"
>
<template v-if="message.record?.chart">
<div style="padding: 0 22px; display: flex; justify-content: flex-end">
<el-button
text
type="primary"
:disabled="isTyping || isPredictTyping || isAnalysisTyping"
@click="clickAnalysis(message.record?.id)"
>
{{ t('chat.data_analysis') }}
</el-button>
<el-button
text
type="primary"
:disabled="isTyping || isPredictTyping || isAnalysisTyping"
@click="clickPredict(message.record?.id)"
>
{{ t('chat.data_predict') }}
</el-button>
</div>
</template>
</ChatAnswer>
<div
v-if="
message?.record?.analysis_record_id != undefined ||
message?.record?.predict_record_id != undefined
"
class="analysis-container"
>
<template v-if="message.record?.analysis || isAnalysisTyping">
<MdComponent :message="message.record?.analysis_thinking" />
<MdComponent :message="message.record?.analysis" />
</template>
<el-divider
v-if="
(message.record?.analysis || isAnalysisTyping) &&
(message.record?.predict || isPredictTyping)
"
/>
<template v-if="message.record?.predict || isPredictTyping">
<MdComponent :message="message.record?.predict" />
<MdComponent :message="message.record?.predict_content" />
<!-- <PredictChartBlock-->
<!-- :id="message.record?.id + '-predict'"-->
<!-- :data="message.record?.predict_data ?? '[]'"-->
<!-- :message="message"-->
<!-- :chart-type="data.chartType"-->
<!-- />-->
</template>
</div>
</template>
<template v-if="message.role === 'assistant'" #footer>
<RecommendQuestion
:questions="message.recommended_question"
:first-chat="message.first_chat"
@click-question="quickAsk"
/>
</template>
</ChatRow>
</template>
</div>
</el-scrollbar>
</el-main>
<el-footer
@@ -200,7 +209,7 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, ref } from 'vue'
import { Plus, Position } from '@element-plus/icons-vue'
import { Position } from '@element-plus/icons-vue'
import { Chat, chatApi, ChatInfo, type ChatMessage, ChatRecord, questionApi } from '@/api/chat'
import ChatRow from './ChatRow.vue'
import ChatAnswer from './ChatAnswer.vue'
@@ -213,6 +222,8 @@ import { useI18n } from 'vue-i18n'
import { endsWith, find, startsWith } from 'lodash-es'
import icon_new_chat_outlined from '@/assets/svg/icon_new_chat_outlined.svg'
import icon_sidebar_outlined from '@/assets/svg/icon_sidebar_outlined.svg'
import logo_fold from '@/assets/LOGO-fold.svg'
import logo from '@/assets/LOGO.svg'
import { useAssistantStore } from '@/stores/assistant'
const assistantStore = useAssistantStore()
@@ -876,6 +887,19 @@ defineExpose({
}
}
.chat-scroll {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
padding-left: 56px;
padding-right: 56px;
&.no-sidebar {
padding-left: 96px;
}
}
.chat-footer {
--ed-footer-height: 120px;
@@ -929,22 +953,26 @@ defineExpose({
padding: 12px;
width: fit-content;
max-width: 800px;
display: flex;
gap: 16px;
align-items: center;
flex-direction: column;
.logo {
line-height: 60px;
font-size: 3em;
font-weight: bold;
color: var(--el-color-primary);
text-align: left;
.greeting {
display: flex;
align-items: center;
gap: 16px;
line-height: 32px;
font-size: 24px;
font-weight: 600;
color: rgba(31, 35, 41, 1);
}
.sub {
color: grey;
font-size: 0.8em;
font-size: 16px;
line-height: 24px;
}
}
}