刷新自动回到底部

This commit is contained in:
14651
2025-08-14 09:51:55 +08:00
parent 5bc0354b6c
commit d3b5f50a2a
4 changed files with 1034 additions and 1017 deletions

View File

@@ -50,11 +50,11 @@
</template>
<script>
import {
import {
getHistory
} from '../../api/aiChat/ai_index.js';
} from '../../api/aiChat/ai_index.js';
export default {
export default {
name: 'HistoryDrawer',
props: {
visible: Boolean
@@ -215,32 +215,32 @@ export default {
this.closeDrawer();
}
}
};
};
</script>
<style scoped>
/* 抽屉容器样式 */
.drawer-container {
/* 抽屉容器样式 */
.drawer-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
}
}
/* 遮罩层样式 */
.drawer-mask {
/* 遮罩层样式 */
.drawer-mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
}
}
/* 抽屉内容区域样式 */
.drawer-content {
/* 抽屉内容区域样式 */
.drawer-content {
position: absolute;
top: 0;
left: 0;
@@ -250,10 +250,10 @@ export default {
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
}
}
/* 头部样式 */
.drawer-header {
/* 头部样式 */
.drawer-header {
padding: 15px 15px 10px;
display: flex;
justify-content: space-between;
@@ -261,139 +261,139 @@ export default {
border-bottom: 1px solid #eee;
height: 50px;
box-sizing: border-box;
}
}
.title {
.title {
font-size: 18px;
font-weight: 600;
color: #333;
}
}
.close-icon {
.close-icon {
width: 24px;
height: 24px;
}
}
/* 搜索栏样式 */
.search-bar {
/* 搜索栏样式 */
.search-bar {
display: flex;
align-items: center;
padding: 10px 15px;
background-color: #f5f5f5;
border-bottom: 1px solid #eee;
}
}
.search-icon {
.search-icon {
width: 18px;
height: 18px;
margin-right: 8px;
tint-color: #999;
}
}
.search-input {
.search-input {
flex: 1;
height: 36px;
background-color: #fff;
border-radius: 18px;
padding: 0 15px;
font-size: 14px;
}
}
.clear-icon {
.clear-icon {
width: 16px;
height: 16px;
margin-left: 8px;
tint-color: #999;
}
}
/* 历史列表样式 */
.history-list {
/* 历史列表样式 */
.history-list {
flex: 1;
overflow-y: auto;
padding: 10px 0;
box-sizing: border-box;
}
}
/* 分组标题样式 */
.group-title {
/* 分组标题样式 */
.group-title {
font-size: 14px;
color: #888;
padding: 12px 20px;
background-color: #f5f5f5;
}
}
/* 历史记录项样式 */
.history-item {
/* 历史记录项样式 */
.history-item {
padding: 15px 20px;
background-color: #fff;
border-bottom: 1px solid #f0f0f0;
}
}
/* 日期时间样式 */
.datetime {
/* 日期时间样式 */
.datetime {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
}
}
.date {
.date {
font-size: 13px;
color: #666;
}
}
.time {
.time {
font-size: 12px;
color: #999;
}
}
/* 消息内容样式 */
.record {
/* 消息内容样式 */
.record {
font-size: 14px;
line-height: 1.6;
}
}
.user-msg {
.user-msg {
display: block;
color: #333;
margin-bottom: 6px;
padding: 6px 10px;
background-color: #f9f9f9;
border-radius: 6px;
}
}
.ai-msg {
.ai-msg {
display: block;
color: #333;
padding: 6px 10px;
background-color: #eef7ff;
border-radius: 6px;
}
}
/* 关键词高亮样式 */
.highlight {
/* 关键词高亮样式 */
.highlight {
color: #ff4d4f;
font-weight: bold;
}
}
/* 分隔线样式 */
.divider {
/* 分隔线样式 */
.divider {
height: 8px;
background-color: #f9f9f9;
margin-top: 10px;
border-radius: 4px;
}
}
/* 空状态提示样式 */
.empty-tip {
/* 空状态提示样式 */
.empty-tip {
text-align: center;
color: #999;
font-size: 16px;
margin-top: 50px;
}
}
/* 修复输入框占位符样式 */
input::-webkit-input-placeholder {
/* 修复输入框占位符样式 */
input::-webkit-input-placeholder {
color: #ccc;
font-size: 14px;
}
}
</style>

View File

@@ -101,30 +101,30 @@
</template>
<script>
/* ========== 依赖 ========== */
import HistoryDrawer from '@/components/aiChat/HistoryDrawer.vue';
import {
/* ========== 依赖 ========== */
import HistoryDrawer from '@/components/aiChat/HistoryDrawer.vue';
import {
createChatStream
} from '@/utils/ai_stream.js';
import {
} from '@/utils/ai_stream.js';
import {
sendFeedback,
getHistory
} from '@/api/aiChat/ai_index.js';
import MarkdownIt from 'markdown-it';
import DOMPurify from 'dompurify';
} from '@/api/aiChat/ai_index.js';
import MarkdownIt from 'markdown-it';
import DOMPurify from 'dompurify';
/* DOMPurify 白名单加固 */
DOMPurify.addHook('afterSanitizeAttributes', node => {
/* DOMPurify 白名单加固 */
DOMPurify.addHook('afterSanitizeAttributes', node => {
if (node.tagName === 'A') node.setAttribute('rel', 'noopener noreferrer');
});
});
const md = new MarkdownIt({
const md = new MarkdownIt({
html: true,
linkify: true,
typographer: true
});
});
export default {
export default {
components: {
HistoryDrawer
},
@@ -162,38 +162,52 @@ export default {
return;
}
// 从本地存储获取conversation_id
this.conversation_id = uni.getStorageSync('conversation_id') || null;
// 初始化聊天并确保滚动到底部
// 初始化消息,再滚动到底部
this.initChat().then(() => {
// 多重延迟确保DOM完全渲染
// 使用三重确保策略处理不同设备的渲染差异
const scrollWithRetry = (attempt = 0) => {
this.$nextTick(() => {
setTimeout(() => {
this.forceScrollToBottom();
// 再次确保滚动(处理某些设备的渲染延迟)
setTimeout(() => {
this.forceScrollToBottom();
}, 500);
}, 300);
});
});
},
/**
* 页面显示时触发 - 确保每次进入页面都滚动到底部
*/
onShow() {
// 确保页面显示时滚动到底部
this.$nextTick(() => {
// 第二次尝试处理iOS等需要额外触发的设备
setTimeout(() => {
this.forceScrollToBottom();
// 额外延迟处理某些设备的渲染问题
this.forceScrollToBottom(30); // 使用稍小的偏移量
// 第三次确保(针对动态内容加载的情况)
if (attempt < 2) {
setTimeout(() => {
this.forceScrollToBottom();
const query = uni.createSelectorQuery()
.in(this);
query.select('.message-list')
.boundingClientRect(rect => {
if (rect && Math.abs(rect
.scrollHeight -
rect.height - this
.scrollTop) > 50) {
scrollWithRetry(
attempt + 1
); // 递归调用直到成功
}
}).exec();
}, attempt === 0 ? 500 : 800);
}
}, 200);
}, 100);
});
};
// 初始触发
scrollWithRetry();
}).catch(e => {
console.error('初始化失败:', e);
// 失败时仍尝试滚动
this.$nextTick(() => {
setTimeout(() => this.forceScrollToBottom(), 300);
});
});
},
/* ---------- 方法 ---------- */
@@ -208,15 +222,16 @@ export default {
},
/**
* 强制滚动到底部 - 优化版本
* 强制滚动到底部
* @param {number} offset - 额外的偏移量默认为50
*/
forceScrollToBottom() {
forceScrollToBottom(offset = 50) {
this.$nextTick(() => {
try {
const query = uni.createSelectorQuery().in(this);
query.select('.message-list').boundingClientRect(rect => {
if (rect && rect.scrollHeight > rect.height) {
// 计算需要滚动的距离
const targetScrollTop = rect.scrollHeight - rect.height + 50; // 额外50px确保完全显示
if (rect) {
const targetScrollTop = rect.scrollHeight - rect.height - offset;
this.scrollTop = targetScrollTop;
// 双重确保滚动生效
@@ -228,23 +243,25 @@ export default {
}, 100);
}
}).exec();
} catch (error) {
console.error('滚动到底部失败:', error);
}
});
},
forceScrollToTop() {
this.$nextTick(() => {
// 直接滚动到顶部
this.scrollTop = 999;
// forceScrollToTop() {
// this.$nextTick(() => {
// this.scrollTop = 0;
// 双重确保滚动生效
setTimeout(() => {
this.scrollTop = 1;
setTimeout(() => {
this.scrollTop = 0;
}, 50);
}, 100);
});
},
// // 双重确保滚动生效
// setTimeout(() => {
// this.scrollTop = 1;
// setTimeout(() => {
// this.scrollTop = 0;
// }, 50);
// }, 100);
// });
// },
/**
* 切换历史记录抽屉显示状态
@@ -866,10 +883,10 @@ export default {
});
}
}
};
};
</script>
<style scoped>
/* 引入全局样式 */
@import '@/static/scss/ai_index.css';
/* 引入全局样式 */
@import '@/static/scss/ai_index.css';
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 518 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB