Commit 68fb0503 authored by 水玉婷's avatar 水玉婷
Browse files

feat:思考添加动画效果

parent 8c585125
...@@ -53,14 +53,21 @@ ...@@ -53,14 +53,21 @@
<div v-else v-html="item.content" class="message-inner-box"></div> <div v-else v-html="item.content" class="message-inner-box"></div>
<!-- 思考过程框 --> <!-- 思考过程框 -->
<div v-if="item.hasThinkBox" class="think-box-wrapper"> <div v-if="item.hasThinkBox" class="think-box-wrapper">
<div class="think-box-toggle" @click="toggleThinkBox(index, i)"> <div :class="['think-box-toggle', item.thinkBoxExpanded ? 'expanded' : 'collapsed']" @click="toggleThinkBox(index, i)">
<component <component
:is="item.thinkBoxExpanded ? UpOutlined : DownOutlined" :is="item.thinkBoxExpanded ? UpOutlined : DownOutlined"
class="toggle-icon" class="toggle-icon"
/> />
<span v-if="item.thinkingTimeText" class="thinking-text">{{ item.thinkingTimeText }}</span> <div v-if="item.thinkingTimeText" class="thinking-loading">
<span class="thinking-text">{{ item.thinkingTimeText }}</span>
<div v-if="item.thinkingTimeText === '正在思考中'" class="loading-dots">
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
</div>
</div> </div>
<div v-if="item.thinkBoxExpanded" class="think-box-content" <div :class="['think-box-content', item.thinkBoxExpanded ? 'expanded' : 'collapsed']"
v-html="templateService.generateThinkingTemplate(item.thinkContent || '')"></div> v-html="templateService.generateThinkingTemplate(item.thinkContent || '')"></div>
</div> </div>
</template> </template>
...@@ -326,17 +333,17 @@ const validateMessageParams = (type: MessageType, params: MessageParams): boolea ...@@ -326,17 +333,17 @@ const validateMessageParams = (type: MessageType, params: MessageParams): boolea
// 统一发送消息函数 // 统一发送消息函数
const sendMessage = async (type: MessageType = 'text', params: MessageParams = {}) => { const sendMessage = async (type: MessageType = 'text', params: MessageParams = {}) => {
// 如果消息文本为空且是文本类型,则延迟1秒后模拟折线图消息进行测试 // 如果消息文本为空且是文本类型,则延迟1秒后模拟折线图消息进行测试
if (type === 'text' && !messageText.value.trim() && !params.message) { // if (type === 'text' && !messageText.value.trim() && !params.message) {
loading.value = true; // loading.value = true;
console.log('📊 检测到空消息,1秒后发送折线图测试...'); // console.log('📊 检测到空消息,1秒后发送折线图测试...');
setTimeout(() => { // setTimeout(() => {
simulateLineChartMessage(); // simulateLineChartMessage();
loading.value = false; // loading.value = false;
}, 1000); // }, 1000);
return; // return;
} // }
loading.value = true; loading.value = true;
...@@ -589,63 +596,63 @@ onBeforeUnmount(() => { ...@@ -589,63 +596,63 @@ onBeforeUnmount(() => {
}); });
// 模拟折线图消息 // 模拟折线图消息
const simulateLineChartMessage = () => { // const simulateLineChartMessage = () => {
console.log('模拟折线图消息'); // console.log('模拟折线图消息');
// 使用真实医院数据创建折线图数据,包含多个维度和指标 // // 使用真实医院数据创建折线图数据,包含多个维度和指标
const lineChartData = { // const lineChartData = {
title:"2023年各医院月度运营数据汇总", // title:"2023年各医院月度运营数据汇总",
dimFields: ['月份', '地区', '医院类型', '科室'], // dimFields: ['月份', '地区', '医院类型', '科室'],
indexFields: ['用户总数', '费用汇总', '平均住院天数', '手术台数', '门诊量'], // indexFields: ['用户总数', '费用汇总', '平均住院天数', '手术台数', '门诊量'],
rows: [ // rows: [
{ '月份': '1月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 100, '费用汇总': 5000, '平均住院天数': 7.2, '手术台数': 15, '门诊量': 1200 }, // { '月份': '1月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 100, '费用汇总': 5000, '平均住院天数': 7.2, '手术台数': 15, '门诊量': 1200 },
{ '月份': '2月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 150, '费用汇总': 6000, '平均住院天数': 6.8, '手术台数': 18, '门诊量': 1400 }, // { '月份': '2月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 150, '费用汇总': 6000, '平均住院天数': 6.8, '手术台数': 18, '门诊量': 1400 },
{ '月份': '3月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 120, '费用汇总': 5500, '平均住院天数': 7.5, '手术台数': 16, '门诊量': 1300 }, // { '月份': '3月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 120, '费用汇总': 5500, '平均住院天数': 7.5, '手术台数': 16, '门诊量': 1300 },
{ '月份': '4月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 180, '费用汇总': 8000, '平均住院天数': 6.5, '手术台数': 22, '门诊量': 1600 }, // { '月份': '4月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 180, '费用汇总': 8000, '平均住院天数': 6.5, '手术台数': 22, '门诊量': 1600 },
{ '月份': '5月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 200, '费用汇总': 9000, '平均住院天数': 6.2, '手术台数': 25, '门诊量': 1800 }, // { '月份': '5月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 200, '费用汇总': 9000, '平均住院天数': 6.2, '手术台数': 25, '门诊量': 1800 },
{ '月份': '6月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 250, '费用汇总': 11000, '平均住院天数': 5.8, '手术台数': 30, '门诊量': 2000 }, // { '月份': '6月', '地区': '北京', '医院类型': '三甲医院', '科室': '内科', '用户总数': 250, '费用汇总': 11000, '平均住院天数': 5.8, '手术台数': 30, '门诊量': 2000 },
{ '月份': '1月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 80, '费用汇总': 8000, '平均住院天数': 8.5, '手术台数': 45, '门诊量': 800 }, // { '月份': '1月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 80, '费用汇总': 8000, '平均住院天数': 8.5, '手术台数': 45, '门诊量': 800 },
{ '月份': '2月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 120, '费用汇总': 9500, '平均住院天数': 8.2, '手术台数': 52, '门诊量': 900 }, // { '月份': '2月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 120, '费用汇总': 9500, '平均住院天数': 8.2, '手术台数': 52, '门诊量': 900 },
{ '月份': '3月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 100, '费用汇总': 8500, '平均住院天数': 8.8, '手术台数': 48, '门诊量': 850 }, // { '月份': '3月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 100, '费用汇总': 8500, '平均住院天数': 8.8, '手术台数': 48, '门诊量': 850 },
{ '月份': '4月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 150, '费用汇总': 12000, '平均住院天数': 7.8, '手术台数': 60, '门诊量': 1100 }, // { '月份': '4月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 150, '费用汇总': 12000, '平均住院天数': 7.8, '手术台数': 60, '门诊量': 1100 },
{ '月份': '5月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 180, '费用汇总': 14000, '平均住院天数': 7.5, '手术台数': 68, '门诊量': 1200 }, // { '月份': '5月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 180, '费用汇总': 14000, '平均住院天数': 7.5, '手术台数': 68, '门诊量': 1200 },
{ '月份': '6月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 220, '费用汇总': 16000, '平均住院天数': 7.2, '手术台数': 75, '门诊量': 1400 }, // { '月份': '6月', '地区': '北京', '医院类型': '三甲医院', '科室': '外科', '用户总数': 220, '费用汇总': 16000, '平均住院天数': 7.2, '手术台数': 75, '门诊量': 1400 },
{ '月份': '1月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 80, '费用汇总': 4000, '平均住院天数': 6.8, '手术台数': 12, '门诊量': 1000 }, // { '月份': '1月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 80, '费用汇总': 4000, '平均住院天数': 6.8, '手术台数': 12, '门诊量': 1000 },
{ '月份': '2月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 120, '费用汇总': 5000, '平均住院天数': 6.5, '手术台数': 15, '门诊量': 1200 }, // { '月份': '2月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 120, '费用汇总': 5000, '平均住院天数': 6.5, '手术台数': 15, '门诊量': 1200 },
{ '月份': '3月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 100, '费用汇总': 4500, '平均住院天数': 7.0, '手术台数': 13, '门诊量': 1100 }, // { '月份': '3月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 100, '费用汇总': 4500, '平均住院天数': 7.0, '手术台数': 13, '门诊量': 1100 },
{ '月份': '4月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 150, '费用汇总': 7000, '平均住院天数': 6.2, '手术台数': 18, '门诊量': 1400 }, // { '月份': '4月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 150, '费用汇总': 7000, '平均住院天数': 6.2, '手术台数': 18, '门诊量': 1400 },
{ '月份': '5月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 180, '费用汇总': 8000, '平均住院天数': 5.9, '手术台数': 22, '门诊量': 1600 }, // { '月份': '5月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 180, '费用汇总': 8000, '平均住院天数': 5.9, '手术台数': 22, '门诊量': 1600 },
{ '月份': '6月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 220, '费用汇总': 10000, '平均住院天数': 5.6, '手术台数': 28, '门诊量': 1800 }, // { '月份': '6月', '地区': '上海', '医院类型': '三甲医院', '科室': '内科', '用户总数': 220, '费用汇总': 10000, '平均住院天数': 5.6, '手术台数': 28, '门诊量': 1800 },
{ '月份': '1月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 60, '费用汇总': 2500, '平均住院天数': 5.5, '手术台数': 8, '门诊量': 600 }, // { '月份': '1月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 60, '费用汇总': 2500, '平均住院天数': 5.5, '手术台数': 8, '门诊量': 600 },
{ '月份': '2月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 90, '费用汇总': 3200, '平均住院天数': 5.2, '手术台数': 10, '门诊量': 700 }, // { '月份': '2月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 90, '费用汇总': 3200, '平均住院天数': 5.2, '手术台数': 10, '门诊量': 700 },
{ '月份': '3月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 80, '费用汇总': 2800, '平均住院天数': 5.8, '手术台数': 9, '门诊量': 650 }, // { '月份': '3月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 80, '费用汇总': 2800, '平均住院天数': 5.8, '手术台数': 9, '门诊量': 650 },
{ '月份': '4月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 120, '费用汇总': 4500, '平均住院天数': 5.0, '手术台数': 12, '门诊量': 800 }, // { '月份': '4月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 120, '费用汇总': 4500, '平均住院天数': 5.0, '手术台数': 12, '门诊量': 800 },
{ '月份': '5月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 150, '费用汇总': 5500, '平均住院天数': 4.8, '手术台数': 15, '门诊量': 900 }, // { '月份': '5月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 150, '费用汇总': 5500, '平均住院天数': 4.8, '手术台数': 15, '门诊量': 900 },
{ '月份': '6月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 180, '费用汇总': 6500, '平均住院天数': 4.5, '手术台数': 18, '门诊量': 1000 }, // { '月份': '6月', '地区': '上海', '医院类型': '二甲医院', '科室': '内科', '用户总数': 180, '费用汇总': 6500, '平均住院天数': 4.5, '手术台数': 18, '门诊量': 1000 },
{ '月份': '1月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 60, '费用汇总': 3000, '平均住院天数': 6.0, '手术台数': 10, '门诊量': 800 }, // { '月份': '1月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 60, '费用汇总': 3000, '平均住院天数': 6.0, '手术台数': 10, '门诊量': 800 },
{ '月份': '2月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 90, '费用汇总': 4000, '平均住院天数': 5.8, '手术台数': 12, '门诊量': 900 }, // { '月份': '2月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 90, '费用汇总': 4000, '平均住院天数': 5.8, '手术台数': 12, '门诊量': 900 },
{ '月份': '3月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 80, '费用汇总': 3500, '平均住院天数': 6.2, '手术台数': 11, '门诊量': 850 }, // { '月份': '3月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 80, '费用汇总': 3500, '平均住院天数': 6.2, '手术台数': 11, '门诊量': 850 },
{ '月份': '4月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 120, '费用汇总': 6000, '平均住院天数': 5.5, '手术台数': 15, '门诊量': 1100 }, // { '月份': '4月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 120, '费用汇总': 6000, '平均住院天数': 5.5, '手术台数': 15, '门诊量': 1100 },
{ '月份': '5月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 150, '费用汇总': 7000, '平均住院天数': 5.2, '手术台数': 18, '门诊量': 1200 }, // { '月份': '5月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 150, '费用汇总': 7000, '平均住院天数': 5.2, '手术台数': 18, '门诊量': 1200 },
{ '月份': '6月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 180, '费用汇总': 9000, '平均住院天数': 4.9, '手术台数': 22, '门诊量': 1400 } // { '月份': '6月', '地区': '广州', '医院类型': '三甲医院', '科室': '内科', '用户总数': 180, '费用汇总': 9000, '平均住院天数': 4.9, '手术台数': 22, '门诊量': 1400 }
], // ],
// chartType: 'line' // 设置默认图表类型为折线图 // // chartType: 'line' // 设置默认图表类型为折线图
}; // };
// 正确的SSE消息格式:status 3(图表数据),type 2(表格数据) // // 正确的SSE消息格式:status 3(图表数据),type 2(表格数据)
const simulatedMessage = { // const simulatedMessage = {
message: lineChartData, // message: lineChartData,
status: 3, // 图表数据 // status: 3, // 图表数据
type: 2 // 表格数据 // type: 2 // 表格数据
}; // };
// 调用handleSSEMessage处理模拟消息 // // 调用handleSSEMessage处理模拟消息
handleSSEMessage(simulatedMessage); // handleSSEMessage(simulatedMessage);
}; // };
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import './style.less'; @import './style.less';
......
...@@ -325,25 +325,113 @@ li { ...@@ -325,25 +325,113 @@ li {
cursor: pointer; cursor: pointer;
font-size: 14px; font-size: 14px;
text-decoration: none; text-decoration: none;
display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 8px;
padding: 4px 8px;
border-radius: 4px;
transition: all 0.2s ease; .toggle-icon {
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
transform: rotate(0deg);
}
// 展开状态下的图标旋转
&.expanded .toggle-icon {
transform: rotate(180deg);
}
.thinking-loading {
display: flex;
align-items: center;
gap: 8px;
}
.loading-dots {
display: flex;
gap: 4px;
.dot {
width: 6px;
height: 6px;
border-radius: 50%;
background-color: @primary-color;
animation: loading-dots 1.4s ease-in-out infinite both;
&:nth-child(1) {
animation-delay: -0.32s;
}
&:nth-child(2) {
animation-delay: -0.16s;
}
&:nth-child(3) {
animation-delay: 0s;
}
}
}
.thinking-text { .thinking-text {
margin-left: 6px;
color: @gray-7; color: @gray-7;
font-size: 13px; font-size: 13px;
transition: color 0.3s ease;
font-weight: 500;
}
}
// Loading dots动画
@keyframes loading-dots {
0%, 80%, 100% {
transform: scale(0.8);
opacity: 0.5;
}
40% {
transform: scale(1.2);
opacity: 1;
} }
} }
:deep(.think-box-content) { :deep(.think-box-content) {
margin-top: 8px; margin-top: 8px;
overflow: hidden;
max-height: 0;
opacity: 0;
transform: translateY(-10px);
transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.4s ease-in-out,
transform 0.4s ease-in-out,
margin-top 0.4s ease-in-out;
// 展开状态
&.expanded {
max-height: 20000px; // 设置足够大的高度
opacity: 1;
transform: translateY(0);
margin-top: 8px;
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94); // 平滑展开
}
// 折叠状态
&.collapsed {
max-height: 0;
opacity: 0;
transform: translateY(-10px);
margin-top: 0;
transition-timing-function: cubic-bezier(0.55, 0.085, 0.68, 0.53); // 平滑折叠
}
.think-content { .think-content {
font-size: 14px; font-size: 14px;
color: @gray-5; color: @gray-5;
padding: 12px 0;
opacity: 0;
transform: translateY(5px);
transition: opacity 0.3s ease-in-out 0.1s, transform 0.3s ease-in-out 0.1s;
}
&.expanded .think-content {
opacity: 1;
transform: translateY(0);
} }
} }
......
...@@ -425,7 +425,7 @@ export class ContentTemplateService { ...@@ -425,7 +425,7 @@ export class ContentTemplateService {
hasThinkBox: true, hasThinkBox: true,
thinkBoxExpanded: false, thinkBoxExpanded: false,
thinkingTime: 0, thinkingTime: 0,
thinkingTimeText: '正在思考中……', thinkingTimeText: '正在思考中',
}); });
} else { } else {
// 如果已有思考内容块,确保hasThinkBox为true // 如果已有思考内容块,确保hasThinkBox为true
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment