|
@@ -34,11 +34,32 @@
|
|
|
</div>
|
|
|
<!-- 使用 v-html 来渲染 Markdown 文本 -->
|
|
|
<div class="message-content">
|
|
|
- <div
|
|
|
- class="message-text"
|
|
|
- v-html="renderMarkdown(message.message)"
|
|
|
- @click="handleLinkClick"
|
|
|
- ></div>
|
|
|
+ <div class="message-text">
|
|
|
+ <!-- 如果有图片,先显示图片 -->
|
|
|
+ <div v-if="message.imageUrls && message.imageUrls.length" class="message-images">
|
|
|
+ <img
|
|
|
+ v-for="(url, index) in message.imageUrls"
|
|
|
+ :key="index"
|
|
|
+ :src="url"
|
|
|
+ class="uploaded-image"
|
|
|
+ alt="Uploaded content"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <!-- 如果有文档,显示文档预览 -->
|
|
|
+ <div v-if="message.documentUrls && message.documentUrls.length" class="message-documents">
|
|
|
+ <div
|
|
|
+ v-for="(doc, index) in message.documentUrls"
|
|
|
+ :key="index"
|
|
|
+ class="document-preview-item"
|
|
|
+ >
|
|
|
+ <i class="el-icon-document"></i>
|
|
|
+ <span class="document-name">{{ getDocumentName(doc) }}</span>
|
|
|
+ <a :href="doc" target="_blank" class="document-link">查看文档</a>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 显示文本内容 -->
|
|
|
+ <div v-html="renderMarkdown(message.message)" @click="handleLinkClick"></div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</li>
|
|
|
</ul>
|
|
@@ -61,7 +82,7 @@
|
|
|
<div
|
|
|
v-for="(file, index) in uploadFiles"
|
|
|
:key="'img-' + index"
|
|
|
- class="preview-item"
|
|
|
+ class="preview-item image-preview"
|
|
|
>
|
|
|
<div class="preview-content">
|
|
|
<img
|
|
@@ -70,10 +91,6 @@
|
|
|
class="preview-image"
|
|
|
alt="preview"
|
|
|
/>
|
|
|
- <div v-else class="file-info">
|
|
|
- <i class="el-icon-document"></i>
|
|
|
- <span>{{ file.name }}</span>
|
|
|
- </div>
|
|
|
</div>
|
|
|
<i class="el-icon-close remove-file" @click="removeFile(index)"></i>
|
|
|
</div>
|
|
@@ -81,13 +98,11 @@
|
|
|
<div
|
|
|
v-for="(doc, index) in documents"
|
|
|
:key="'doc-' + index"
|
|
|
- class="preview-item document-item"
|
|
|
+ class="preview-item document-preview"
|
|
|
>
|
|
|
<div class="preview-content">
|
|
|
- <div class="file-info">
|
|
|
- <i class="el-icon-document"></i>
|
|
|
- <span>{{ doc.name }}</span>
|
|
|
- </div>
|
|
|
+ <i class="el-icon-document"></i>
|
|
|
+ <span class="doc-name">{{ doc.name }}</span>
|
|
|
</div>
|
|
|
<i
|
|
|
class="el-icon-close remove-file"
|
|
@@ -382,7 +397,7 @@ export default {
|
|
|
console.log("WebSocket 连接已建立:", event);
|
|
|
};
|
|
|
this.websocket.onmessage = (event) => {
|
|
|
- // 解����收到的消息
|
|
|
+ // 解收到的消息
|
|
|
const result = JSON.parse(event.data);
|
|
|
|
|
|
// 检查消息是否完结
|
|
@@ -392,7 +407,7 @@ export default {
|
|
|
}
|
|
|
|
|
|
if (this.messages[this.messages.length - 1].done) {
|
|
|
- // 添加新的消息
|
|
|
+ // 添加的消息
|
|
|
this.messages.push({
|
|
|
time: Date.now(),
|
|
|
message: result.content,
|
|
@@ -434,6 +449,8 @@ export default {
|
|
|
message: message,
|
|
|
messageType: "TEXT",
|
|
|
user: "user",
|
|
|
+ imageUrls: imageUrls, // 添加图片URLs
|
|
|
+ documentUrls: documentUrls, // 添加文档URLs
|
|
|
done: true,
|
|
|
});
|
|
|
|
|
@@ -553,7 +570,7 @@ export default {
|
|
|
},
|
|
|
async simulateThinking(message, signal) {
|
|
|
this.isThinking = true;
|
|
|
- const dotInterval = 200; // 每 200ms 更新一次点
|
|
|
+ const dotInterval = 200; // 每 200ms 更新次点
|
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
const updateDots = () => {
|
|
@@ -639,7 +656,7 @@ export default {
|
|
|
linkify: true,
|
|
|
});
|
|
|
|
|
|
- // 自定义链接渲染规���
|
|
|
+ // 自定义链接渲染规则
|
|
|
md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
|
|
|
const token = tokens[idx];
|
|
|
const hrefIndex = token.attrIndex("href");
|
|
@@ -701,6 +718,13 @@ export default {
|
|
|
this.currentChat_id = res.data.id;
|
|
|
});
|
|
|
},
|
|
|
+ getDocumentName(url) {
|
|
|
+ // 从URL中提取文件名
|
|
|
+ const parts = url.split('/');
|
|
|
+ const fileName = parts[parts.length - 1];
|
|
|
+ // 解码URL编码的文件名
|
|
|
+ return decodeURIComponent(fileName);
|
|
|
+ }
|
|
|
},
|
|
|
updated() {
|
|
|
const messagesContainer = this.$el.querySelector(".messages");
|
|
@@ -876,7 +900,7 @@ export default {
|
|
|
width: 1180px; /* 设置消息列表宽度为屏幕宽度的 80% */
|
|
|
max-width: 90%; /* 限制最大宽度,避免超出视口 */
|
|
|
margin: 0 auto; /* 上下保持原有的 margin,左右自动调整以居中 */
|
|
|
- overflow-y: auto; /* 如果消息太多,允许滚动 */
|
|
|
+ overflow-y: auto; /* 如果消息太多允许滚动 */
|
|
|
height: calc(100vh - 230px); /* 高度需要根据输入框和其他元素的高度调整 */
|
|
|
padding: 10px; /* 或你希望的内边距大小 */
|
|
|
margin-bottom: 110px;
|
|
@@ -967,7 +991,7 @@ export default {
|
|
|
padding-left: 20px; /* 上下左右的内边距 */
|
|
|
padding-right: 20px; /* 上下左右的内边距 */
|
|
|
padding-top: 10px; /* 上下左右的内边距 */
|
|
|
- padding-bottom: 0px; /* 上下左右的内边距 */
|
|
|
+ padding-bottom: 0px; /* 上下左的内边距 */
|
|
|
max-width: calc(90% - 10px); /* 计算头像和间距 */
|
|
|
border-radius: 7px; /* 边框圆角 */
|
|
|
/* margin-bottom: 10px; 和下一条消息之间的间距 */
|
|
@@ -980,7 +1004,7 @@ export default {
|
|
|
.message-text {
|
|
|
margin: 0;
|
|
|
white-space: normal; /* 确保文本会换行 */
|
|
|
- word-wrap: break-word; /* 长单词或 URL 会被断开���适应容器宽度 */
|
|
|
+ word-wrap: break-word; /* 长单词或 URL 会被断开适应容器宽度 */
|
|
|
overflow: auto;
|
|
|
font-size: 14px;
|
|
|
}
|
|
@@ -1038,7 +1062,7 @@ textarea {
|
|
|
.input-container textarea {
|
|
|
width: 100%; /* 输入框占据所有可用空间 */
|
|
|
padding: 10px;
|
|
|
- margin-right: 10px; /* 与按钮的间�� */
|
|
|
+ margin-right: 10px; /* 与按��的间距 */
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|
|
@@ -1080,62 +1104,53 @@ textarea {
|
|
|
.upload-preview {
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
- gap: 10px;
|
|
|
- max-height: 100px;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 10px 0;
|
|
|
+ max-height: 120px;
|
|
|
overflow-y: auto;
|
|
|
}
|
|
|
|
|
|
.preview-item {
|
|
|
position: relative;
|
|
|
- width: 60px;
|
|
|
- height: 20px;
|
|
|
border-radius: 4px;
|
|
|
overflow: hidden;
|
|
|
- border: 1px solid #e0e0e0;
|
|
|
}
|
|
|
|
|
|
-.preview-content {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
+.image-preview {
|
|
|
+ width: 80px;
|
|
|
+ height: 40px;
|
|
|
}
|
|
|
-
|
|
|
-.preview-image {
|
|
|
+.image-preview img{
|
|
|
width: 100%;
|
|
|
- height: 100%;
|
|
|
- object-fit: cover;
|
|
|
}
|
|
|
-
|
|
|
-.file-info {
|
|
|
+.document-preview {
|
|
|
+ width: 120px;
|
|
|
+ height: 40px;
|
|
|
+ background: #f5f5f5;
|
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
align-items: center;
|
|
|
- justify-content: center;
|
|
|
- height: 100%;
|
|
|
- padding: 5px;
|
|
|
- text-align: center;
|
|
|
+ padding: 0 10px;
|
|
|
}
|
|
|
|
|
|
-.file-info span {
|
|
|
+.doc-name {
|
|
|
font-size: 12px;
|
|
|
- word-break: break-word;
|
|
|
overflow: hidden;
|
|
|
- display: -webkit-box;
|
|
|
- -webkit-line-clamp: 2;
|
|
|
- -webkit-box-orient: vertical;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ max-width: 90px;
|
|
|
}
|
|
|
+
|
|
|
.remove-file {
|
|
|
position: absolute;
|
|
|
- top: 2px;
|
|
|
- right: 2px;
|
|
|
+ top: 4px;
|
|
|
+ right: 4px;
|
|
|
background: rgba(0, 0, 0, 0.5);
|
|
|
color: white;
|
|
|
border-radius: 50%;
|
|
|
- padding: 2px;
|
|
|
+ padding: 4px;
|
|
|
cursor: pointer;
|
|
|
font-size: 12px;
|
|
|
+ z-index: 1;
|
|
|
}
|
|
|
|
|
|
.input-area {
|
|
@@ -1190,4 +1205,60 @@ textarea {
|
|
|
text-overflow: ellipsis;
|
|
|
white-space: nowrap;
|
|
|
}
|
|
|
+
|
|
|
+.message-images {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.uploaded-image {
|
|
|
+ max-width: 200px;
|
|
|
+ max-height: 200px;
|
|
|
+ border-radius: 4px;
|
|
|
+ object-fit: contain;
|
|
|
+}
|
|
|
+
|
|
|
+.message-documents {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.document-preview-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ background: #f5f5f5;
|
|
|
+ padding: 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.document-preview-item i {
|
|
|
+ font-size: 20px;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.document-name {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #333;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.document-link {
|
|
|
+ color: #3cbade;
|
|
|
+ text-decoration: none;
|
|
|
+ font-size: 14px;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.document-link:hover {
|
|
|
+ background: rgba(60, 186, 222, 0.1);
|
|
|
+}
|
|
|
</style>
|