feat: 对接ai对答,纯文本,折线,柱状,饼图,主题切换,问答体验优化

main
许宏杰 1 month ago
parent e78a248c69
commit b01f61b773

@ -69,7 +69,9 @@
align-items: flex-start;
}
.ai-hint {
margin-top: 6px;
font-size: 12px;
color: #c3cad9;
}
}
.message-content {
@ -138,6 +140,10 @@
box-sizing: border-box;
padding: 2px 10px;
}
.activeTheme{
color: #3F7BF8;
background: rgba(63,123,248,0.1);
}
}
}
}

@ -43,7 +43,7 @@ export class BarChart {
}
},
grid: {
top: '18%',
top: '25%',
left: '3%',
right: '3%',
bottom: '3%',

@ -36,7 +36,7 @@ export class LineChart {
const option = {
backgroundColor: this.styleColor.backgroundColor,
title: {
text: '图表标题',
text:this.chartData.title ,
left: 'center',
top: '3%',
textStyle: {
@ -45,7 +45,7 @@ export class LineChart {
}
},
grid: {
top: '18%',
top: '25%',
left: '3%',
right: '3%',
bottom: '3%',
@ -65,7 +65,7 @@ export class LineChart {
},
yAxis: {
type: 'value',
name:'个',
name:this.chartData.unit,
nameTextStyle:{
color:this.styleColor.axisLabelColor
},

@ -58,7 +58,7 @@ export class PieChart {
formatter:`{b0}: {c0}${this.chartData.unit}`
},
grid: {
top: '18%',
top: '20%',
left: '3%',
right: '3%',
bottom: '3%',

@ -26,9 +26,10 @@
<div class="message-content">
<div class="message-time">{{ item.time }}</div>
<div class="message-text">
<!-- 纯文本 -->
<div class="text-ros">
<span>{{ item.text }}</span>
<div v-show="item.from === 'user'">
<div v-show="item.add">
<n-tooltip placement="bottom" trigger="hover">
<template #trigger>
<n-icon size="14" style="cursor: pointer">
@ -50,11 +51,33 @@
</n-tooltip>
</div>
</div>
<!-- 图表 -->
<section v-if="item.chartType">
<div class="echarts-box" :id="item.chartType + index"></div>
<div class="echatrs-theme">
<div class="theme-title">风格切换</div>
<div class="theme-list">
<div
class="theme-item"
@click="handlerTheme(item, themeIndex)"
v-for="(themeItem, themeIndex) in echartsTheme"
:key="themeIndex"
:class="item.chartInstanceActiveIndex == themeIndex ? 'activeTheme' : ''"
>
{{ themeItem }}
</div>
</div>
</div>
</section>
<!-- 思考 -->
<div v-show="item.from === 'ai' && item.loading" class="ai-loading">
<span>思考中</span> <n-spin size="small" />
<span>思考中</span> <n-spin size="small" content-class="spin-class" />
</div>
<!-- 免责 -->
<div class="ai-hint" v-show="item.from === 'ai' && (item.text || item.chartType)">
本回答由AI生成内容仅供参考
</div>
<div class="ai-hint" v-show="item.from === 'ai'">AI</div>
</div>
</div>
</div>
@ -93,12 +116,13 @@ let loading = ref(false)
let keyWord = ref('')
//list
let messageList = reactive([])
//
const scrollContainer = ref(null)
//
let lastIndex = ref(0)
//
const echartsTheme = ['简约风', '商务风', '科技风']
// let bar = null
let stopWatch = null
/**
* 页面初始完成
@ -128,36 +152,81 @@ const handleSend = async () => {
setMessageItem({
from: 'user',
text: keyWord.value,
time: moment().format('YYYY/MM/DD HH:mm:ss')
time: moment().format('YYYY/MM/DD HH:mm:ss'),
add: true
})
// //AI
// setMessageItem({
// from: 'ai',
// text: '',
// time: moment().format('YYYY/MM/DD HH:mm:ss'),
// loading: true //ai
// })
// try {
// const res = await getAiMsg({ prompt: keyWord.value })
// if (res.type) {
// console.log('')
// } else {
// //
// updataMessageItem({
// from: 'ai',
// text: res,
// time: moment().format('YYYY/MM/DD HH:mm:ss'),
// loading: false
// })
// }
// } catch {
// updataMessageItem({
// from: 'ai',
// text: '',
// time: moment().format('YYYY/MM/DD HH:mm:ss'),
// loading: false
// })
// }
//AI
setMessageItem({
from: 'ai',
text: '',
time: moment().format('YYYY/MM/DD HH:mm:ss'),
loading: true, //ai
chartInstanceItem: null,
chartInstanceActiveIndex: 0,
chartType: null,
xData: [],
yData: []
})
try {
const res = await getAiMsg({ prompt: keyWord.value })
if (res.type) {
//
updataMessageItem({
from: 'ai',
text: '',
time: moment().format('YYYY/MM/DD HH:mm:ss'),
loading: false, //ai
chartInstanceItem: null,
chartInstanceActiveIndex: 0,
chartType: res.chartType,
xData: res.xData,
yData: res.yData,
title: res.title,
unit: res.unit
})
nextTick(() => {
const itemData = messageList[lastIndex.value]
//
if (res.chartType === 'pie') {
itemData.chartInstanceItem = new PieChart(`${res.chartType}${lastIndex.value}`, {
title: res.title,
unit: res.unit,
xData: res.xData,
data: res.yData
})
} else if (res.chartType === 'bar') {
itemData.chartInstanceItem = new BarChart(`${res.chartType}${lastIndex.value}`, {
title: res.title,
unit: res.unit,
xData: res.xData,
data: res.yData
})
} else if (res.chartType === 'line') {
itemData.chartInstanceItem = new LineChart(`${res.chartType}${lastIndex.value}`, {
title: res.title,
unit: res.unit,
xData: res.xData,
data: res.yData
})
}
})
} else {
//
updataMessageItem({
from: 'ai',
text: res,
time: moment().format('YYYY/MM/DD HH:mm:ss'),
loading: false
})
}
} catch {
updataMessageItem({
from: 'ai',
text: '服务器繁忙,请稍后再试。',
time: moment().format('YYYY/MM/DD HH:mm:ss'),
loading: false
})
}
}
/**
* 存储聊天室数据
@ -183,9 +252,42 @@ const updataMessageItem = data => {
* 图表切换主题
* @param index
*/
const handlerTheme = index => {
bar.changeColorStyle(index)
const handlerTheme = (item, index) => {
pauseWatching()
item.chartInstanceActiveIndex = index
item.chartInstanceItem.changeColorStyle(index)
setTimeout(()=>{
startWatching()
},1000)
}
//
const startWatching = () => {
stopWatch = watch(messageList, newVal => {
nextTick(() => {
if (scrollContainer.value) {
scrollContainer.value.scrollTop = scrollContainer.value.scrollHeight
}
})
})
}
const pauseWatching = () => {
if (stopWatch) {
stopWatch() //
stopWatch = null
}
}
onMounted(() => {
startWatching()
})
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
/* 设置滚动条整体样式 */
::-webkit-scrollbar {
width: 0px;
}
</style>

@ -85,7 +85,7 @@ let list = reactive([
}
}
.issue-list{
margin-top: 15px;
margin-top: 10px;
display: flex;
flex-direction: column;
gap: 10px;

@ -56,7 +56,7 @@ export default ({ mode }) => defineConfig({
},
'/ai': {
target: 'http://5179zv4ns298.vicp.fun/',
target: 'http://baijiahu.mynatapp.cc',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/ai/, '')
},

Loading…
Cancel
Save