|
@@ -28,6 +28,10 @@
|
|
|
</view>
|
|
|
</block>
|
|
|
</scroll-view>
|
|
|
+ <!-- 添加新建对话按钮 -->
|
|
|
+ <view class="new-chat-btn">
|
|
|
+ <button @tap="startNewChat" class="btn-new">新建对话</button>
|
|
|
+ </view>
|
|
|
<view class="input-container">
|
|
|
<textarea v-model="userInput" @keydown="handleKeydown" placeholder="有问题可以咨询我..." maxlength="100"></textarea>
|
|
|
<button @tap="sendMessage" class="btn">发送</button>
|
|
@@ -49,11 +53,10 @@
|
|
|
time: "",
|
|
|
done: true,
|
|
|
}, ],
|
|
|
- generating: false,
|
|
|
userInput: "",
|
|
|
websocket: null,
|
|
|
AiUrl: '',
|
|
|
- apiUrl: 'http://192.168.66.208:8082',
|
|
|
+ apiUrl: 'https://ylaiapi.raycos.com.cn',
|
|
|
scrollTop: 0,
|
|
|
tweaks: {},
|
|
|
userAvatar: '/static/用户.png',
|
|
@@ -61,15 +64,28 @@
|
|
|
level: 1,
|
|
|
idArray: [],
|
|
|
minioUrls: [], // 新增:用于存储 Minio URL
|
|
|
+ generating: false, // 是否正在生成回复
|
|
|
+ typewriterTimer: null,
|
|
|
+ currentIndex: 0,
|
|
|
+ fullMessage: '',
|
|
|
+ session_id: "",
|
|
|
+ platform: {
|
|
|
+ type: '', // 平台类型
|
|
|
+ name: '', // 平台名称
|
|
|
+ isWeixin: false
|
|
|
+ }
|
|
|
};
|
|
|
},
|
|
|
created() {
|
|
|
|
|
|
-
|
|
|
},
|
|
|
onLoad() {
|
|
|
- this.getKbmUrl()
|
|
|
+ // this.getKbmUrl()
|
|
|
this.loadUserInfo()
|
|
|
+ this.getPlatformInfo();
|
|
|
+ },
|
|
|
+ onShow() {
|
|
|
+ this.getKbmUrl()
|
|
|
},
|
|
|
watch: {
|
|
|
messages: {
|
|
@@ -82,6 +98,112 @@
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
+ // 添加新建对话方法
|
|
|
+ startNewChat() {
|
|
|
+ uni.showModal({
|
|
|
+ title: '确认新建对话',
|
|
|
+ content: '是否清空当前对话内容开始新的对话?',
|
|
|
+ success: (res) => {
|
|
|
+ if (res.confirm) {
|
|
|
+ // 重置消息列表,只保留欢迎消息
|
|
|
+ this.messages = [{
|
|
|
+ user: "bot",
|
|
|
+ messageType: "TEXT",
|
|
|
+ message: "欢迎使用智能AI助理",
|
|
|
+ html: "",
|
|
|
+ time: "",
|
|
|
+ done: true,
|
|
|
+ }];
|
|
|
+
|
|
|
+ // 清空session_id
|
|
|
+ this.session_id = "";
|
|
|
+
|
|
|
+ // 清空MinioUrls
|
|
|
+ this.minioUrls = [];
|
|
|
+
|
|
|
+ // 重置其他相关状态
|
|
|
+ this.generating = false;
|
|
|
+ this.currentIndex = 0;
|
|
|
+ this.fullMessage = '';
|
|
|
+
|
|
|
+ // 显示提示
|
|
|
+ uni.showToast({
|
|
|
+ title: '已开始新对话',
|
|
|
+ icon: 'success',
|
|
|
+ duration: 1500
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 获取平台信息
|
|
|
+ getPlatformInfo() {
|
|
|
+ try {
|
|
|
+ const systemInfo = uni.getSystemInfoSync();
|
|
|
+ // console.log('系统信息:', systemInfo);
|
|
|
+
|
|
|
+ // 判断平台类型
|
|
|
+ // #ifdef MP-WEIXIN
|
|
|
+ this.platform.type = 'mp-weixin';
|
|
|
+ this.platform.name = '微信小程序';
|
|
|
+ this.platform.isWeixin = true;
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // #ifdef MP-ALIPAY
|
|
|
+ this.platform.type = 'mp-alipay';
|
|
|
+ this.platform.name = '支付宝小程序';
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // #ifdef MP-BAIDU
|
|
|
+ this.platform.type = 'mp-baidu';
|
|
|
+ this.platform.name = '百度小程序';
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // #ifdef MP-TOUTIAO
|
|
|
+ this.platform.type = 'mp-toutiao';
|
|
|
+ this.platform.name = '头条小程序';
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // #ifdef H5
|
|
|
+ this.platform.type = 'h5';
|
|
|
+ this.platform.name = 'H5';
|
|
|
+ // 在H5中判断是否在微信浏览器中
|
|
|
+ if (navigator.userAgent.toLowerCase().indexOf('micromessenger') !== -1) {
|
|
|
+ this.platform.isWeixin = true;
|
|
|
+ this.platform.name = 'H5微信浏览器';
|
|
|
+ }
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // #ifdef APP-PLUS
|
|
|
+ this.platform.type = 'app';
|
|
|
+ this.platform.name = 'App';
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // console.log('当前平台:', this.platform);
|
|
|
+
|
|
|
+ // 获取更详细的平台信息
|
|
|
+ const platformInfo = {
|
|
|
+ brand: systemInfo.brand, // 手机品牌
|
|
|
+ model: systemInfo.model, // 手机型号
|
|
|
+ system: systemInfo.system, // 操作系统版本
|
|
|
+ platform: systemInfo.platform, // 客户端平台
|
|
|
+ SDKVersion: systemInfo.SDKVersion, // 小程序基础库版本
|
|
|
+ version: systemInfo.version, // 微信版本号
|
|
|
+ };
|
|
|
+
|
|
|
+ // console.log('平台详细信息:', platformInfo);
|
|
|
+
|
|
|
+ return this.platform;
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取平台信息失败:', error);
|
|
|
+ return {
|
|
|
+ type: 'unknown',
|
|
|
+ name: '未知平台',
|
|
|
+ isWeixin: false
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
getMainContent(message) {
|
|
|
const parts = message.split('相关资料来源');
|
|
|
return parts[0].trim();
|
|
@@ -138,7 +260,7 @@
|
|
|
},
|
|
|
scrollToBottom() {
|
|
|
// 使用一个很大的值来确保滚动到底部
|
|
|
- this.scrollTop += 1000;
|
|
|
+ this.scrollTop += 9999;
|
|
|
// 重置 scrollTop 以便下次滚动生效
|
|
|
// this.$nextTick(() => {
|
|
|
// this.scrollTop = 0;
|
|
@@ -282,10 +404,12 @@
|
|
|
async sendMessage() {
|
|
|
const wsUrl = this.AiUrl;
|
|
|
let message = this.userInput.trim();
|
|
|
- if (message) {
|
|
|
+ if (!message || this.typewriterTimer) return; // 防止重复发送
|
|
|
+
|
|
|
+ try {
|
|
|
// 添加用户消息
|
|
|
const userMessage = {
|
|
|
- id: this.getUuid(), // 为每条消息添加唯一ID
|
|
|
+ id: this.getUuid(),
|
|
|
user: "user",
|
|
|
messageType: "TEXT",
|
|
|
message: message,
|
|
@@ -294,7 +418,7 @@
|
|
|
};
|
|
|
this.messages.push(userMessage);
|
|
|
|
|
|
- // 清空输入框并滚动
|
|
|
+ // 清空输入框
|
|
|
this.userInput = "";
|
|
|
this.scrollToBottom();
|
|
|
|
|
@@ -303,44 +427,53 @@
|
|
|
id: this.getUuid(),
|
|
|
user: "bot",
|
|
|
messageType: "TEXT",
|
|
|
- message: "",
|
|
|
+ message: "正在思考中...",
|
|
|
time: Date.now(),
|
|
|
done: false,
|
|
|
};
|
|
|
this.messages.push(botMessage);
|
|
|
|
|
|
- try {
|
|
|
- const response = await uni.request({
|
|
|
- url: wsUrl,
|
|
|
- method: 'POST',
|
|
|
- header: {
|
|
|
- 'Content-Type': 'application/json'
|
|
|
- },
|
|
|
- data: {
|
|
|
- message: message,
|
|
|
- chat_config_id: '17',
|
|
|
- user_id: this.userInfo.phoneNumber,
|
|
|
- session_id: this.session_id || "",
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- if (response.statusCode === 200 && response.data) {
|
|
|
- if (this.level === '0' && response.data.data?.milvus_ids) {
|
|
|
- await this.getMinioUrls({
|
|
|
- ids: response.data.data.milvus_ids
|
|
|
- });
|
|
|
- }
|
|
|
- await this.handleResponse(response.data, botMessage);
|
|
|
+ const response = await uni.request({
|
|
|
+ url: wsUrl,
|
|
|
+ method: 'POST',
|
|
|
+ header: {
|
|
|
+ 'Content-Type': 'application/json'
|
|
|
+ },
|
|
|
+ data: {
|
|
|
+ message: message,
|
|
|
+ chat_config_id: '17',
|
|
|
+ user_id: this.userInfo.phoneNumber,
|
|
|
+ session_id: this.session_id || "",
|
|
|
+ source: this.platform.type //uni.getAccountInfoSync().miniProgram.appName,
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error("Error sending message:", error);
|
|
|
- botMessage.message = "抱歉,发送消息失败,请重试。";
|
|
|
- botMessage.done = true;
|
|
|
- uni.showToast({
|
|
|
- title: '发送消息失败,请重试',
|
|
|
- icon: 'none'
|
|
|
+ });
|
|
|
+
|
|
|
+ // 检查响应状态和数据
|
|
|
+ if (response.statusCode !== 200 || !response.data || !response.data.data?.answer) {
|
|
|
+ throw new Error('Invalid response from server');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.level === '0' && response.data.data?.milvus_ids) {
|
|
|
+ await this.getMinioUrls({
|
|
|
+ ids: response.data.data.milvus_ids
|
|
|
});
|
|
|
}
|
|
|
+ this.session_id = response.data.data.session_id;
|
|
|
+ await this.handleResponse(response.data, botMessage);
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error("Error sending message:", error);
|
|
|
+ // 找到最后一条消息(应该是机器人的消息)并更新它
|
|
|
+ const lastMessage = this.messages[this.messages.length - 1];
|
|
|
+ if (lastMessage && lastMessage.user === 'bot') {
|
|
|
+ lastMessage.message = "抱歉,处理消息时出现错误,请重试。";
|
|
|
+ lastMessage.done = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ uni.showToast({
|
|
|
+ title: '发送消息失败,请重试',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
}
|
|
|
},
|
|
|
|
|
@@ -381,23 +514,13 @@
|
|
|
}
|
|
|
|
|
|
const data = value.data.answer;
|
|
|
- let mainText = data;
|
|
|
+ this.fullMessage = data;
|
|
|
+ this.currentIndex = 0;
|
|
|
+ existingMessage.message = '';
|
|
|
|
|
|
- // 直接设置主要回答内容
|
|
|
- existingMessage.message = mainText;
|
|
|
+ // 开始打字效果
|
|
|
+ this.startTypewriter(existingMessage);
|
|
|
|
|
|
- // 如果有 MinioUrls,添加资料来源标记
|
|
|
- if (this.minioUrls && this.minioUrls.length > 0) {
|
|
|
- existingMessage.message += '\n\n相关资料来源';
|
|
|
- }
|
|
|
-
|
|
|
- // 标记消息完成
|
|
|
- existingMessage.done = true;
|
|
|
-
|
|
|
- // 确保滚动到底部
|
|
|
- this.$nextTick(() => {
|
|
|
- this.scrollToBottom();
|
|
|
- });
|
|
|
} catch (error) {
|
|
|
console.error("Error handling response:", error);
|
|
|
existingMessage.message = "抱歉,处理响应时出现错误。";
|
|
@@ -405,6 +528,42 @@
|
|
|
}
|
|
|
},
|
|
|
|
|
|
+ // 新的打字效果实现
|
|
|
+ startTypewriter(existingMessage) {
|
|
|
+ // 清除可能存在的旧计时器
|
|
|
+ if (this.typewriterTimer) {
|
|
|
+ clearInterval(this.typewriterTimer);
|
|
|
+ this.typewriterTimer = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ const doTypewriter = () => {
|
|
|
+ if (this.currentIndex < this.fullMessage.length) {
|
|
|
+ existingMessage.message = this.fullMessage.slice(0, this.currentIndex + 1);
|
|
|
+ this.currentIndex++;
|
|
|
+
|
|
|
+ // 使用 nextTick 确保视图更新
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.scrollToBottom();
|
|
|
+ });
|
|
|
+
|
|
|
+ // 使用 setTimeout 代替 setInterval
|
|
|
+ this.typewriterTimer = setTimeout(() => {
|
|
|
+ doTypewriter();
|
|
|
+ }, 30);
|
|
|
+ } else {
|
|
|
+ // 打字效果完成
|
|
|
+ if (this.minioUrls && this.minioUrls.length > 0) {
|
|
|
+ existingMessage.message += '\n\n相关资料来源';
|
|
|
+ }
|
|
|
+ existingMessage.done = true;
|
|
|
+ this.typewriterTimer = null;
|
|
|
+ this.scrollToBottom();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 立即开始打字效果
|
|
|
+ doTypewriter();
|
|
|
+ },
|
|
|
// 修改 renderMarkdown 方法以保留 HTML 标签
|
|
|
/* renderMarkdown(rawMarkdown) {
|
|
|
if (typeof rawMarkdown !== 'string') {
|
|
@@ -440,7 +599,7 @@
|
|
|
}, */
|
|
|
|
|
|
// 修改 sendMessage 方法
|
|
|
- async sendMessage() {
|
|
|
+ /* async sendMessage() {
|
|
|
const wsUrl = this.AiUrl;
|
|
|
let message = this.userInput.trim();
|
|
|
if (message) {
|
|
@@ -505,7 +664,7 @@
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
- },
|
|
|
+ }, */
|
|
|
// 修改 renderMarkdown 方法
|
|
|
/* renderMarkdown(rawMarkdown) {
|
|
|
if (typeof rawMarkdown !== 'string') {
|
|
@@ -655,15 +814,15 @@
|
|
|
/* 上下保持原有的 margin,左右自动调整以居中 */
|
|
|
overflow-y: auto;
|
|
|
/* 如果消息太多,允许滚动 */
|
|
|
- height: calc(100vh - 160px);
|
|
|
+ height: calc(100vh - 190px);
|
|
|
/* 高度需要根据输入框和其他元素的高度调整 */
|
|
|
- padding: 10px;
|
|
|
+ padding: 10px 10px 0;
|
|
|
/* 或你希望的内边距大小 */
|
|
|
}
|
|
|
|
|
|
.message {
|
|
|
display: flex;
|
|
|
- padding:10px;
|
|
|
+ padding: 10px;
|
|
|
align-items: flex-start;
|
|
|
}
|
|
|
|
|
@@ -812,7 +971,7 @@
|
|
|
/* 例如,按钮的最小宽度为 100px */
|
|
|
width: 40px;
|
|
|
height: 30px;
|
|
|
- line-height: 14px;
|
|
|
+ line-height: 20px;
|
|
|
font-size: 12px;
|
|
|
white-space: nowrap;
|
|
|
/* 防止文字折行 */
|
|
@@ -838,59 +997,76 @@
|
|
|
}
|
|
|
|
|
|
.message-content :deep(p) {
|
|
|
- font-size: 12px !important;
|
|
|
- margin: 5px 0 10px;
|
|
|
- padding: 0;
|
|
|
- line-height: 22px;
|
|
|
- font-weight: inherit;
|
|
|
+ font-size: 12px !important;
|
|
|
+ margin: 5px 0 10px;
|
|
|
+ padding: 0;
|
|
|
+ line-height: 22px;
|
|
|
+ font-weight: inherit;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
.message-content :deep(ol) {
|
|
|
- padding-bottom: 10px;
|
|
|
+ padding-bottom: 10px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
.message-content :deep(.source-section) {
|
|
|
- margin: 20px 0 3px;
|
|
|
- color: #333;
|
|
|
- font-size: 16px;
|
|
|
+ margin: 20px 0 3px;
|
|
|
+ color: #333;
|
|
|
+ font-size: 16px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
.message-content :deep(ol li) {
|
|
|
- padding-top: 3px;
|
|
|
+ padding-top: 3px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
.message-content :deep(ol li a) {
|
|
|
- font-size: 14px;
|
|
|
- color: #1296db;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #1296db;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/* 添加资料来源相关的新样式 */
|
|
|
.source-section {
|
|
|
- border-top: 1px solid #e5e5e5;
|
|
|
- padding-top: 10px;
|
|
|
- margin-top: 10px;
|
|
|
+ border-top: 1px solid #e5e5e5;
|
|
|
+ padding-top: 10px;
|
|
|
+ margin-top: 10px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
.source-title {
|
|
|
- font-size: 14px;
|
|
|
- color: #666;
|
|
|
- margin-bottom: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #666;
|
|
|
+ margin-bottom: 8px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
.source-links {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 5px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 5px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
.source-link {
|
|
|
- color: #1296db;
|
|
|
- font-size: 12px;
|
|
|
- cursor: pointer;
|
|
|
- /* text-decoration: underline; */
|
|
|
+ color: #1296db;
|
|
|
+ font-size: 12px;
|
|
|
+ cursor: pointer;
|
|
|
+ /* text-decoration: underline; */
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
.source-link:hover {
|
|
|
- opacity: 0.8;
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+ /* 添加新建对话按钮样式 */
|
|
|
+ .new-chat-btn {
|
|
|
+ padding: 0px 20px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-start;
|
|
|
+ background-color: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-new {
|
|
|
+ background-color: #1296db;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 14px;
|
|
|
+ border-radius: 5px;
|
|
|
+ border: none;
|
|
|
+ height: 35px;
|
|
|
+ margin: 0;
|
|
|
}
|
|
|
</style>
|