|
|
@ -98,32 +98,42 @@ |
|
|
<view class="message-content"> |
|
|
<view class="message-content"> |
|
|
<!-- <text class="message-text">{{ message.content }}</text> --> |
|
|
<!-- <text class="message-text">{{ message.content }}</text> --> |
|
|
<!-- loading --> |
|
|
<!-- loading --> |
|
|
<view class="loading-dots" v-if="message.isThinking || message.isTyping"> |
|
|
|
|
|
<div class="thinking-process"> |
|
|
|
|
|
<div class="thinking-header"> |
|
|
|
|
|
<div class="thinking-icon">∞</div> |
|
|
|
|
|
<div class="thinking-title">深度思考 正在思考</div> |
|
|
|
|
|
<div class="thinking-count">25 个结果</div> |
|
|
|
|
|
<div class="thinking-toggle" @click="toggleThinking"> |
|
|
|
|
|
<span v-if="showThinking">↑</span> |
|
|
|
|
|
|
|
|
<view |
|
|
|
|
|
class="loading-dots" |
|
|
|
|
|
v-if="message.isThinking || !message.isUser" |
|
|
|
|
|
> |
|
|
|
|
|
<view class="thinking-process"> |
|
|
|
|
|
<view class="thinking-header"> |
|
|
|
|
|
<view class="thinking-icon">∞</view> |
|
|
|
|
|
<view class="thinking-title">{{ |
|
|
|
|
|
message.isTyping ? "正在思考" : "思考完成" |
|
|
|
|
|
}}</view> |
|
|
|
|
|
<view class="thinking-count"> |
|
|
|
|
|
|
|
|
|
|
|
</view> |
|
|
|
|
|
<view |
|
|
|
|
|
class="thinking-toggle" |
|
|
|
|
|
@click="message.isThinking = !message.isThinking" |
|
|
|
|
|
> |
|
|
|
|
|
<span v-if="message.isThinking">↑</span> |
|
|
<span v-else>↓</span> |
|
|
<span v-else>↓</span> |
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div v-show="showThinking" class="thinking-content"> |
|
|
|
|
|
<div class="thinking-item"> |
|
|
|
|
|
<div class="item-status"> |
|
|
|
|
|
|
|
|
</view> |
|
|
|
|
|
</view> |
|
|
|
|
|
<view v-show="message.isThinking" class="thinking-content"> |
|
|
|
|
|
<view class="thinking-item"> |
|
|
|
|
|
<view class="item-status"> |
|
|
<span class="checkmark">✓</span> |
|
|
<span class="checkmark">✓</span> |
|
|
</div> |
|
|
|
|
|
<div class="item-text">问题分析完成</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div class="thinking-item"> |
|
|
|
|
|
<div class="item-status"> |
|
|
|
|
|
|
|
|
</view> |
|
|
|
|
|
<view class="item-text">问题分析完成</view> |
|
|
|
|
|
</view> |
|
|
|
|
|
<view class="thinking-item"> |
|
|
|
|
|
<view class="item-status"> |
|
|
<span class="checkmark">✓</span> |
|
|
<span class="checkmark">✓</span> |
|
|
</div> |
|
|
|
|
|
<div class="item-text">收集相关信息</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
</view> |
|
|
|
|
|
<view class="item-text">收集相关信息</view> |
|
|
|
|
|
</view> |
|
|
|
|
|
</view> |
|
|
|
|
|
</view> |
|
|
</view> |
|
|
</view> |
|
|
<!-- 使用 rich-text 渲染 Markdown 内容 --> |
|
|
<!-- 使用 rich-text 渲染 Markdown 内容 --> |
|
|
<rich-text v-if="!message.isUser" class="message-text" |
|
|
<rich-text v-if="!message.isUser" class="message-text" |
|
|
@ -252,7 +262,7 @@ onMounted(() => { |
|
|
|
|
|
|
|
|
initUUID(); |
|
|
initUUID(); |
|
|
if (messages.value.length === 0) { |
|
|
if (messages.value.length === 0) { |
|
|
nextTick(startTabsMarquee); |
|
|
|
|
|
|
|
|
// nextTick(startTabsMarquee); |
|
|
} |
|
|
} |
|
|
if (messages.value.length > 0) { |
|
|
if (messages.value.length > 0) { |
|
|
nextTick(() => { measureChatContainer(); scrollToBottom(); }); |
|
|
nextTick(() => { measureChatContainer(); scrollToBottom(); }); |
|
|
@ -342,14 +352,14 @@ const sendMessage = () => { |
|
|
|
|
|
|
|
|
// 发送后强制恢复并滚到底部 |
|
|
// 发送后强制恢复并滚到底部 |
|
|
shouldAutoScroll.value = true; |
|
|
shouldAutoScroll.value = true; |
|
|
nextTick(() => { forceScrollToBottom(); }); |
|
|
|
|
|
|
|
|
nextTick(() => { scrollToBottom(); }); |
|
|
|
|
|
|
|
|
// 模拟机器人回复 |
|
|
// 模拟机器人回复 |
|
|
simulateBotResponse(userMessage.content); |
|
|
simulateBotResponse(userMessage.content); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// 模拟机器人回复 |
|
|
// 模拟机器人回复 |
|
|
const simulateBotResponse = (userMessage) => { |
|
|
|
|
|
|
|
|
const simulateBotResponse = async(userMessage) => { |
|
|
isSending.value = true; |
|
|
isSending.value = true; |
|
|
|
|
|
|
|
|
// 添加机器人加载消息 |
|
|
// 添加机器人加载消息 |
|
|
@ -357,57 +367,32 @@ const simulateBotResponse = (userMessage) => { |
|
|
content: "", |
|
|
content: "", |
|
|
isUser: false, |
|
|
isUser: false, |
|
|
isTyping: true, |
|
|
isTyping: true, |
|
|
isThinking: false, |
|
|
|
|
|
|
|
|
isThinking: true, |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
messages.value.push(botMsg); |
|
|
messages.value.push(botMsg); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 添加请求延迟 |
|
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 2000)); |
|
|
|
|
|
const toDataInfo = await getDataInfo(); |
|
|
|
|
|
console.log(toDataInfo); |
|
|
|
|
|
// dataInfo.value = toDataInfo.data; |
|
|
|
|
|
// console.log(dataInfo.value); |
|
|
|
|
|
messages.value[messages.value.length - 1].isThinking = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 滚动到底部 |
|
|
// 滚动到底部 |
|
|
nextTick(() => { |
|
|
nextTick(() => { |
|
|
scrollToBottom(); |
|
|
scrollToBottom(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
// 模拟流式响应 |
|
|
// 模拟流式响应 |
|
|
let responseText = `我已经收到您的消息: "${userMessage}"。 ## 股票分析报告 |
|
|
|
|
|
|
|
|
|
|
|
### 股票名称: Tesla Inc. (TSLA) |
|
|
|
|
|
|
|
|
|
|
|
- **当前价格**: 448.980 |
|
|
|
|
|
- **更新时间**: 23/10/2025 |
|
|
|
|
|
- **今日无变盘点** |
|
|
|
|
|
|
|
|
|
|
|
### 技术分析 |
|
|
|
|
|
- **CFTL**: 当前牵牛绳为红色,处于龙线区域,最近出现“牛刀小试”,度牛线目前处于青绿色区域。 |
|
|
|
|
|
- **空间预测**: |
|
|
|
|
|
- 预测低一值: 413.364 |
|
|
|
|
|
- 预测高一值: 426.636 |
|
|
|
|
|
- 预测低二值: 421.670 |
|
|
|
|
|
- 预测高二值: 448.314 |
|
|
|
|
|
- **能量分析**: AI智能均线多头排列,当前卖盘小于买盘 |
|
|
|
|
|
|
|
|
|
|
|
### 资金与主力 |
|
|
|
|
|
- **主力分析**: |
|
|
|
|
|
1. 该股庄家中长期筹码成本价格为 356.036,短期资金成本价格为 406.429。该股筹码分散,当日筹码成本价格为 439.322。 |
|
|
|
|
|
2. 近日没有出现主力集中吸筹。 |
|
|
|
|
|
3. 近期主力持仓比例大于散户持仓比例。当日主力持仓增加。当日散户持仓减少。 |
|
|
|
|
|
|
|
|
|
|
|
### 综合评价 |
|
|
|
|
|
- **个股走势评价**: |
|
|
|
|
|
- 该股整体趋势向好,出现暴涨的可能性较大,当前如果已经持有该股票,可以继续持股观察,如果尚未持有该股票,可持续进行观察,目前处于机会的初期,处于反弹阶段,可以分步建仓! |
|
|
|
|
|
|
|
|
|
|
|
- **核心证据链**: |
|
|
|
|
|
- 资金共识:当日多方资金流入。 |
|
|
|
|
|
- 趋势动能:该股中长期处于上升趋势,短期处于弱势状态。 |
|
|
|
|
|
|
|
|
|
|
|
- **牛股评级**: ★★★☆☆ |
|
|
|
|
|
- **暴涨概率**: 60% |
|
|
|
|
|
- **风险评估**: 非常安全 |
|
|
|
|
|
- **安全边际**: 432.671~458.057 |
|
|
|
|
|
- **黄金价域**: 427.995~440.835`; |
|
|
|
|
|
|
|
|
let responseText = `我已经收到您的消息: "${userMessage}"。+"${toDataInfo.data}" `; |
|
|
let index = 0; |
|
|
let index = 0; |
|
|
|
|
|
|
|
|
const botIndex = messages.value.length - 1; |
|
|
const botIndex = messages.value.length - 1; |
|
|
const baseDelay = 165; // 普通字符基础延迟(毫秒) |
|
|
|
|
|
|
|
|
const baseDelay = 5; // 普通字符基础延迟(毫秒) |
|
|
const slowPunct = /[。!?!?;;]/; // 句号、感叹号、分号等较长停顿 |
|
|
const slowPunct = /[。!?!?;;]/; // 句号、感叹号、分号等较长停顿 |
|
|
const midPunct = /[,、,::]/; // 逗号、顿号、冒号等中等停顿 |
|
|
const midPunct = /[,、,::]/; // 逗号、顿号、冒号等中等停顿 |
|
|
|
|
|
|
|
|
@ -472,7 +457,7 @@ const shouldAutoScroll = ref(true); |
|
|
const latestContentHeight = ref(0); |
|
|
const latestContentHeight = ref(0); |
|
|
const lastScrollTop = ref(0); |
|
|
const lastScrollTop = ref(0); |
|
|
const windowHeight = uni.getSystemInfoSync().windowHeight; |
|
|
const windowHeight = uni.getSystemInfoSync().windowHeight; |
|
|
const AUTO_SCROLL_REENABLE_THRESHOLD = 400; // px,接近底部时恢复自动滚动 |
|
|
|
|
|
|
|
|
const AUTO_SCROLL_REENABLE_THRESHOLD = 40000; // px,接近底部时恢复自动滚动 |
|
|
|
|
|
|
|
|
const onChatScroll = (e) => { |
|
|
const onChatScroll = (e) => { |
|
|
const st = e.detail?.scrollTop || 0; |
|
|
const st = e.detail?.scrollTop || 0; |
|
|
@ -562,6 +547,30 @@ const onBackTopClick = () => { |
|
|
scrollToTop(); |
|
|
scrollToTop(); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getDataInfo() { |
|
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
|
uni.request({ |
|
|
|
|
|
url: "http://localhost:8888/ka", |
|
|
|
|
|
data: {}, |
|
|
|
|
|
header: { |
|
|
|
|
|
Accept: "application/json", |
|
|
|
|
|
"Content-Type": "application/json", |
|
|
|
|
|
"X-Requested-With": "XMLHttpRequest", |
|
|
|
|
|
}, |
|
|
|
|
|
method: "GET", |
|
|
|
|
|
sslVerify: true, |
|
|
|
|
|
success: (res) => { |
|
|
|
|
|
resolve(res.data); |
|
|
|
|
|
}, |
|
|
|
|
|
fail: (error) => { |
|
|
|
|
|
reject(error); |
|
|
|
|
|
}, |
|
|
|
|
|
}); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
</script> |
|
|
</script> |
|
|
|
|
|
|
|
|
<style scoped> |
|
|
<style scoped> |
|
|
@ -1144,7 +1153,7 @@ const onBackTopClick = () => { |
|
|
padding: 20rpx 30rpx; |
|
|
padding: 20rpx 30rpx; |
|
|
cursor: pointer; |
|
|
cursor: pointer; |
|
|
background-color: #fff; |
|
|
background-color: #fff; |
|
|
border-bottom: 2px solid #e5e5e5; |
|
|
|
|
|
|
|
|
border-bottom: 2rpx solid #e5e5e5; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.thinking-icon { |
|
|
.thinking-icon { |
|
|
|