diff --git a/package-lock.json b/package-lock.json
index 188963d..a9eb9f7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2,5 +2,81 @@
"name": "deepChartVueApp",
"lockfileVersion": 3,
"requires": true,
- "packages": {}
+ "packages": {
+ "": {
+ "dependencies": {
+ "markdown-it": "^14.1.0",
+ "marked": "^2.0.1"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/linkify-it": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+ "dependencies": {
+ "uc.micro": "^2.0.0"
+ }
+ },
+ "node_modules/markdown-it": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-14.1.0.tgz",
+ "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
+ "dependencies": {
+ "argparse": "^2.0.1",
+ "entities": "^4.4.0",
+ "linkify-it": "^5.0.0",
+ "mdurl": "^2.0.0",
+ "punycode.js": "^2.3.1",
+ "uc.micro": "^2.1.0"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.mjs"
+ }
+ },
+ "node_modules/marked": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/marked/-/marked-2.0.1.tgz",
+ "integrity": "sha512-5+/fKgMv2hARmMW7DOpykr2iLhl0NgjyELk5yn92iE7z8Se1IS9n3UsFm86hFXIkvMBmVxki8+ckcpjBeyo/hw==",
+ "bin": {
+ "marked": "bin/marked"
+ },
+ "engines": {
+ "node": ">= 8.16.2"
+ }
+ },
+ "node_modules/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="
+ },
+ "node_modules/punycode.js": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmmirror.com/punycode.js/-/punycode.js-2.3.1.tgz",
+ "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/uc.micro": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-2.1.0.tgz",
+ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="
+ }
+ }
}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..c0827ed
--- /dev/null
+++ b/package.json
@@ -0,0 +1,6 @@
+{
+ "dependencies": {
+ "markdown-it": "^14.1.0",
+ "marked": "^2.0.1"
+ }
+}
diff --git a/pages/deepMate/deepMate.vue b/pages/deepMate/deepMate.vue
index aea697c..77ff2d9 100644
--- a/pages/deepMate/deepMate.vue
+++ b/pages/deepMate/deepMate.vue
@@ -82,7 +82,7 @@
Hi, 我是您的股市随身顾问~ 个股诊断、市场情绪解读,都可以找我。
-
+
- {{ message.content }}
+
-
-
-
+
+
+
+ {{ message.content }}
-
+
@@ -158,12 +187,32 @@ const { safeAreaInsets } = uni.getSystemInfoSync();
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from "vue";
import footerBar from '../../components/footerBar-cn'
+import marked from "marked"; // 引入 marked 库
import { onPageScroll } from '@dcloudio/uni-app'
-
-
+// 设置 marked 选项
+marked.setOptions({
+ renderer: new marked.Renderer(),
+ highlight: null, // 如果需要代码高亮,可以设置适当的函数
+ langPrefix: "language-",
+ pedantic: false,
+ gfm: true,
+ breaks: false,
+ sanitize: false,
+ smartLists: true,
+ smartypants: false,
+ xhtml: false,
+});
+// 创建一个用于渲染 Markdown 的函数
+const renderMarkdown = (content) => {
+ if (!content) return "";
+ return marked.parse(content);
+};
const type = ref('member')
const inputMessage = ref("");
+const showThinking = ref(true);
const isSending = ref(false);
+const chatScrollTop = ref(0);
+const chatContainerHeight = ref(0);
const uuid = ref("");
const messages = ref([]);
const hotTopics = ref([
@@ -210,7 +259,7 @@ onMounted(() => {
nextTick(startTabsMarquee);
}
if (messages.value.length > 0) {
- nextTick(() => { scrollToBottom(); });
+ nextTick(() => { measureChatContainer(); scrollToBottom(); });
}
});
@@ -233,6 +282,15 @@ const generateUUID = () => {
});
};
+// 计算聊天容器可视高度
+const measureChatContainer = () => {
+ const q = uni.createSelectorQuery();
+ q.select('.chat-container').boundingClientRect();
+ q.exec((res) => {
+ chatContainerHeight.value = res[0]?.height || 0;
+ });
+};
+
// 新会话
const newChat = () => {
messages.value = [];
@@ -289,7 +347,42 @@ const simulateBotResponse = (userMessage) => {
});
// 模拟流式响应
- let responseText = `我已经收到您的消息: "${userMessage}"。作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?`;
+ 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 index = 0;
const botIndex = messages.value.length - 1;
@@ -328,31 +421,40 @@ const simulateBotResponse = (userMessage) => {
setTimeout(typeWriter, 500);
};
-// 滚动到底部
+// 当消息出现或变化时,测量容器并滚到底部
+watch(messages, (arr) => {
+ if (arr.length > 0) {
+ nextTick(() => {
+ measureChatContainer();
+ scrollToBottom();
+ });
+ }
+});
+
+// 滚动到底部(仅聊天区域滚动)
const scrollToBottom = () => {
- if (!shouldAutoScroll.value) return; // 暂停自动滚动
+ if (!shouldAutoScroll.value) return;
const query = uni.createSelectorQuery();
- query.select("#messageList").boundingClientRect();
- query.selectViewport().scrollOffset();
+ query.select('#messageList').boundingClientRect();
query.exec((res) => {
- if (res[0] && res[1]) {
+ if (res[0]) {
latestContentHeight.value = res[0].height;
- uni.pageScrollTo({ scrollTop: res[0].height, duration: 100 });
+ chatScrollTop.value = res[0].height; // scroll-view 会自动夹紧到最大位置
}
});
};
const scrollToTop = () => {
- uni.pageScrollTo({ scrollTop: 0, duration: 200 });
+ chatScrollTop.value = 0;
};
// 自动滚动控制:用户向上滚动时暂停自动滚到底部
const shouldAutoScroll = ref(true);
const latestContentHeight = ref(0);
const lastScrollTop = ref(0);
const windowHeight = uni.getSystemInfoSync().windowHeight;
-const AUTO_SCROLL_REENABLE_THRESHOLD = 1; // px,接近底部时恢复自动滚动
+const AUTO_SCROLL_REENABLE_THRESHOLD = 400; // px,接近底部时恢复自动滚动
-onPageScroll((e) => {
- const st = e.scrollTop;
+const onChatScroll = (e) => {
+ const st = e.detail?.scrollTop || 0;
const delta = st - lastScrollTop.value;
lastScrollTop.value = st;
@@ -361,11 +463,11 @@ onPageScroll((e) => {
return;
}
- const distanceToBottom = latestContentHeight.value - st - windowHeight;
+ const distanceToBottom = latestContentHeight.value - st - chatContainerHeight.value;
if (distanceToBottom <= AUTO_SCROLL_REENABLE_THRESHOLD) {
shouldAutoScroll.value = true;
}
-});
+};
// 回到顶部图标拖拽状态
const backTopX = ref(0);
@@ -445,10 +547,12 @@ const onBackTopClick = () => {
.deepMate-page {
display: flex;
flex-direction: column;
+ position: fixed; /* 充满视口,彻底禁用页面滚动 */
+ top: 0; left: 0; right: 0; bottom: 0;
height: 100vh;
+ overflow: hidden; /* 锁定页面滚动 */
background-color: #ffffff;
padding: 20rpx 0rpx;
-
}
.header {
@@ -457,7 +561,7 @@ const onBackTopClick = () => {
align-items: center;
padding: 20rpx 30rpx;
background-color: #ffffff;
-
+ box-shadow: 0 2rpx rgba(0, 0, 0, 0.1);
}
.header-left,
@@ -494,9 +598,11 @@ const onBackTopClick = () => {
.main-content {
background-color: #fff;
flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden; /* 内部滚动交给聊天容器 */
padding: 20rpx;
- /* overflow-y: auto; 取消独立滚动,使用页面滚动以便自动到达底部 */
- margin-top: 20rpx;
+ margin-top: 1rpx;
margin-bottom: 120rpx;
}
@@ -680,8 +786,9 @@ const onBackTopClick = () => {
.chat-container {
margin-top: 30rpx;
border-radius: 10rpx;
- height: fit-content;
- /* overflow-y: auto; */
+ height: 65%; /* 缩短滚动区域,避免被输入框覆盖 */
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
}
.message-list {
@@ -843,7 +950,9 @@ const onBackTopClick = () => {
color: #ffffff !important;
opacity: 1;
}
-
+/* .uni-scroll-view{
+ height: 92%;
+} */
.send-button {
background: url("https://d31zlh4on95l9h.cloudfront.net/images/95f1ea2262e9157db13c93c0dc1c5d96.svg");
background-repeat: no-repeat;
@@ -914,4 +1023,75 @@ const onBackTopClick = () => {
position: fixed;
bottom: 0;
}
+.thinking-process {
+ margin: 20rpx 0;
+ border: 2rpx solid #e5e5e5;
+ border-radius: 2rpx;
+ background-color: #f9f9f9;
+}
+
+.thinking-header {
+ display: flex;
+ align-items: center;
+ padding: 20rpx 30rpx;
+ cursor: pointer;
+ background-color: #fff;
+ border-bottom: 2px solid #e5e5e5;
+}
+
+.thinking-icon {
+ font-size: 32rpx;
+ margin-right: 16rpx;
+ color: #d47c45;
+}
+
+.thinking-title {
+ font-size: 28rpx;
+ font-weight: 500;
+ color: #d47c45;
+ margin-right: 16rpx;
+}
+
+.thinking-count {
+ font-size: 24rpx;
+ color: #666;
+ margin-right: 16rpx;
+}
+
+.thinking-toggle {
+ font-size: 24rpx;
+ color: #999;
+}
+
+.thinking-content {
+ padding: 20rpx 30rpx;
+}
+
+.thinking-item {
+ display: flex;
+ align-items: center;
+ margin-bottom: 16rpx;
+ padding: 8rpx 0;
+}
+
+.item-status {
+ width: 32rpx;
+ height: 32rpx;
+ border-radius: 50%;
+ background-color: #f0f0f0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-right: 16rpx;
+}
+
+.checkmark {
+ font-size: 20rpx;
+ color: #ff0000;
+}
+
+.item-text {
+ font-size: 24rpx;
+ color: #333;
+}
\ No newline at end of file