diff --git a/liics b/liics
new file mode 160000
index 0000000..e9d7f5b
--- /dev/null
+++ b/liics
@@ -0,0 +1 @@
+Subproject commit e9d7f5bf799bf2d3d3df068f35290eba414237ad
diff --git a/src/components/chat-new.vue b/src/components/chat-new.vue
index df0452c..ffedc39 100644
--- a/src/components/chat-new.vue
+++ b/src/components/chat-new.vue
@@ -2,11 +2,15 @@
import { ref, computed, inject, watch, nextTick, onMounted } from 'vue'
import { showToast } from 'vant'
import _ from 'lodash'
+import { showImagePreview } from 'vant'
+import xss from 'xss'
import footerBarInput from '@/components/footer-bar-input.vue'
import hotQuestionNew from '@/components/hot-question-new.vue'
import welcomes from '@/components/welcomes.vue'
import abstract from '@/components/abstract.vue'
import chatContent from '@/components/chat-content.vue'
+import DynamicImage from '@/components/common/DynamicImage.vue'
+import imageService from '@/utils/imageService'
import { messageSend } from '@/utils/api'
import { Post } from '@/utils/https'
import { SJHLCmdList } from '@/utils/constant'
@@ -28,9 +32,85 @@ const pageNum = ref(1)
const pageSize = ref(10)
const nolist = ref(false)
const nolistTxt = ref('没有更多数据了')
+function getMessageOptions(item) {
+ return item?.message?.[0]?.options || {}
+}
+
+function isImageMessage(item) {
+ const raw = item?.raw || item || {}
+ const options = getMessageOptions(item)
+ const reqAndResType = String(raw.reqAndResType || '')
+ const msgType = String(raw.msgType || '')
+ const fromFlag = String(raw.fromFlag || '')
+ const isProtocolImage =
+ (reqAndResType === '2' && fromFlag === '1' && msgType !== '01') ||
+ (reqAndResType === '08' && msgType === '02')
+ const isTextAnswer = Boolean(raw.msgText) && (msgType === '01' || fromFlag !== '1') && !isProtocolImage
+
+ return !isTextAnswer && (
+ item?.message?.[0]?.type === 'image' ||
+ isProtocolImage ||
+ Boolean((item?.imageUrl || item?.imageKey || options.imageUrl || options.imageKey || raw.imgUrl || raw.imgKey || raw.fileKey) && !raw.msgText)
+ )
+}
+
+function getItemImage(item) {
+ const raw = item?.raw || item || {}
+ const options = getMessageOptions(item)
+ const reqAndResType = String(raw.reqAndResType || '')
+ const msgType = String(raw.msgType || '')
+ const fromFlag = String(raw.fromFlag || '')
+ const imageMessage =
+ (reqAndResType === '2' && fromFlag === '1' && msgType !== '01') ||
+ (reqAndResType === '08' && msgType === '02')
+ const directImage = [item?.imageUrl, options.imageUrl, raw.imgUrl]
+ .map((value) => String(value || ''))
+ .find((value) => /^(data:|blob:|https?:\/\/)/i.test(value))
+
+ return String(
+ directImage ||
+ item?.imageKey ||
+ options.imageKey ||
+ raw.imgKey ||
+ raw.fileKey ||
+ item?.imageUrl ||
+ options.imageUrl ||
+ raw.imgUrl ||
+ (imageMessage ? raw.msgText : '') ||
+ '',
+ )
+}
function getItemText(item) {
- return item?.message?.[0]?.options?.label || ''
+ if (isImageMessage(item)) return ''
+ return String(getMessageOptions(item).label || '').replace(/\\n/g, '\n')
+}
+
+function isImageUploading(item) {
+ return isImageMessage(item) && item?.uploadStatus === 'uploading'
+}
+
+function isImageFailed(item) {
+ return isImageMessage(item) && item?.uploadStatus === 'failed'
+}
+
+function getItemHtml(item) {
+ const content = getItemText(item)
+ if (!content) return ''
+
+ // liics renders msgText as sanitized HTML and converts escaped newlines to
+ // line breaks. Keep the same behavior for msgType=01 and rich msgType=02.
+ return xss(content.replace(/\\"/g, '"').replace(/\n/g, '
'))
+}
+
+async function previewImage(item) {
+ if (isImageUploading(item) || isImageFailed(item)) return
+
+ const imageKey = getItemImage(item)
+ if (!imageKey) return
+
+ const imageUrl = await imageService.getImageByKey(imageKey)
+ if (typeof imageUrl === 'string' && imageUrl) showImagePreview([imageUrl])
}
const showTyping = computed(
@@ -208,6 +288,16 @@ onMounted(async () => {
getHeaderUrl()
getChatHistory()
})
+watch(
+ chatArr,
+ () => {
+ nextTick(() => {
+ const container = mainContainerRef.value
+ if (container) container.scrollTop = container.scrollHeight
+ })
+ },
+ { deep: true },
+)
@@ -219,7 +309,25 @@ onMounted(async () => {
@@ -115,7 +155,9 @@ onMounted(() => { processedEmoji() })
@@ -163,6 +205,17 @@ onMounted(() => { processedEmoji() })
max-width: 75%;
}
+.history-message-image {
+ display: block;
+ width: 130px;
+ min-width: 30px;
+ height: 130px;
+ min-height: 30px;
+ border-radius: 16px 16px 4px 16px;
+ overflow: hidden;
+ cursor: pointer;
+}
+
.chat-room-cont {
display: flex;
margin-bottom: 12px;
@@ -202,4 +255,8 @@ onMounted(() => { processedEmoji() })
border-radius: 4px 16px 16px 16px;
padding: 14px;
}
-
\ No newline at end of file
+
+.history-message-image-left {
+ border-radius: 4px 16px 16px 16px;
+}
+
diff --git a/src/components/history-main.vue b/src/components/history-main.vue
index 32b0da8..b5ecd05 100644
--- a/src/components/history-main.vue
+++ b/src/components/history-main.vue
@@ -50,7 +50,7 @@