diff --git a/src/components/search/searchByCondition.vue b/src/components/search/searchByCondition.vue
index f8e7f39..09b0824 100644
--- a/src/components/search/searchByCondition.vue
+++ b/src/components/search/searchByCondition.vue
@@ -200,10 +200,10 @@
>
diff --git a/src/hooks/useTalkRecord.ts b/src/hooks/useTalkRecord.ts
index aee0272..880ada2 100644
--- a/src/hooks/useTalkRecord.ts
+++ b/src/hooks/useTalkRecord.ts
@@ -11,6 +11,17 @@ interface Params {
limit: number
}
+interface SpecialParams extends Params {
+ msg_id?: string
+ cursor?: number
+ direction?: 'up' | 'down'
+}
+
+interface LoadOptions {
+ specifiedMsg?: SpecialParams
+ middleMsgCreatedAt?: string
+}
+
export const useTalkRecord = (uid: number) => {
const dialogueStore = useDialogueStore()
@@ -25,9 +36,19 @@ export const useTalkRecord = (uid: number) => {
receiver_id: 0,
talk_type: 0,
status: 0,
- cursor: 0
+ cursor: 0,
+ specialParams: undefined as SpecialParams | undefined
})
+ // 重置 loadConfig
+ const resetLoadConfig = () => {
+ loadConfig.receiver_id = 0
+ loadConfig.talk_type = 0
+ loadConfig.status = 0
+ loadConfig.cursor = 0
+ loadConfig.specialParams = undefined
+ }
+
const onJumpMessage = (msgid: string) => {
const element = document.getElementById(msgid)
if (!element) {
@@ -131,8 +152,160 @@ export const useTalkRecord = (uid: number) => {
})
}
+ // 获取当前消息的最小 sequence
+ const getMinSequence = () => {
+ console.error('records.value', records.value)
+ if (!records.value.length) return 0
+ console.error(Math.min(...records.value.map(item => item.sequence)))
+ return Math.min(...records.value.map(item => item.sequence))
+ }
+ // 获取当前消息的最大 sequence
+ const getMaxSequence = () => {
+ if (!records.value.length) return 0
+ return Math.max(...records.value.map(item => item.sequence))
+ }
+
+ /**
+ * 加载数据主入口,支持指定消息定位模式
+ * @param params 原有参数
+ * @param options 可选,{ specifiedMsg } 指定消息对象
+ */
+ const onLoad = (params: Params, options?: LoadOptions) => {
+ // 如果会话切换,重置所有状态
+ if (params.talk_type !== loadConfig.talk_type || params.receiver_id !== loadConfig.receiver_id) {
+ resetLoadConfig()
+ }
+
+ loadConfig.cursor = 0
+ loadConfig.receiver_id = params.receiver_id
+ loadConfig.talk_type = params.talk_type
+
+ console.error('onLoad', params, options)
+
+ // 新增:支持指定消息定位模式,参数以传入为准合并
+ if (options?.specifiedMsg?.cursor !== undefined) {
+ loadConfig.specialParams = { ...options.specifiedMsg } // 记录特殊参数,供分页加载用
+ console.error('options', options)
+ loadConfig.status = 0 // 复用主流程 loading 状态
+ // 以 params 为基础,合并 specifiedMsg 的所有字段(只要有就覆盖)
+ const contextParams = {
+ ...params,
+ ...options.specifiedMsg
+ }
+ ServeTalkRecords(contextParams).then(({ data, code }) => {
+ if (code !== 200) {
+ loadConfig.status = 2
+ return
+ }
+ dialogueStore.clearDialogueRecord()
+ const items = (data.items || []).map((item: ITalkRecord) => formatTalkRecord(uid, item))
+ dialogueStore.unshiftDialogueRecord(items.reverse())
+ loadConfig.status = items.length >= contextParams.limit ? 1 : 2
+ loadConfig.cursor = data.cursor
+ nextTick(() => {
+ setTimeout(() => {
+ const el = document.getElementById('imChatPanel')
+ const target = document.getElementById(options.specifiedMsg?.msg_id || '')
+ if (el && target) {
+ const containerRect = el.getBoundingClientRect()
+ const targetRect = target.getBoundingClientRect()
+ const offset = targetRect.top - containerRect.top
+ // 居中
+ const scrollTo = el.scrollTop + offset - el.clientHeight / 2 + target.clientHeight / 2
+ el.scrollTo({ top: scrollTo, behavior: 'smooth' })
+
+ addClass(target, 'border')
+ setTimeout(() => removeClass(target, 'border'), 3000)
+ } else if (el) {
+ el.scrollTop = el.scrollHeight
+ }
+ }, 50)
+ })
+ })
+ return
+ }
+
+ loadConfig.specialParams = undefined // 普通模式清空
+ // 原有逻辑
+ load(params)
+ }
+
+ // 向上加载更多(兼容特殊参数模式)
const onRefreshLoad = () => {
+ console.error('loadConfig.status', loadConfig.status)
if (loadConfig.status == 1) {
+ console.log('specialParams', loadConfig.specialParams)
+ // 判断是否是特殊参数模式
+ if (loadConfig.specialParams && typeof loadConfig.specialParams === 'object') {
+ // 检查特殊参数是否与当前会话匹配
+ if (loadConfig.specialParams.talk_type === loadConfig.talk_type &&
+ loadConfig.specialParams.receiver_id === loadConfig.receiver_id) {
+ // 特殊参数模式下,direction: 'up',cursor: 当前最小 sequence
+ onLoad(
+ {
+ receiver_id: loadConfig.receiver_id,
+ talk_type: loadConfig.talk_type,
+ limit: 30
+ },
+ {
+ specifiedMsg: {
+ ...loadConfig.specialParams,
+ direction: 'up',
+ cursor: getMinSequence()
+ }
+ }
+ )
+ } else {
+ // 如果不匹配,重置为普通模式
+ resetLoadConfig()
+ load({
+ receiver_id: loadConfig.receiver_id,
+ talk_type: loadConfig.talk_type,
+ limit: 30
+ })
+ }
+ } else {
+ // 原有逻辑
+ load({
+ receiver_id: loadConfig.receiver_id,
+ talk_type: loadConfig.talk_type,
+ limit: 30
+ })
+ }
+ }
+ }
+
+ // 向下加载更多(兼容特殊参数模式)
+ const onLoadMoreDown = () => {
+ // 判断是否是特殊参数模式
+ if (loadConfig.specialParams && typeof loadConfig.specialParams === 'object') {
+ // 检查特殊参数是否与当前会话匹配
+ if (loadConfig.specialParams.talk_type === loadConfig.talk_type &&
+ loadConfig.specialParams.receiver_id === loadConfig.receiver_id) {
+ onLoad(
+ {
+ receiver_id: loadConfig.receiver_id,
+ talk_type: loadConfig.talk_type,
+ limit: 30
+ },
+ {
+ specifiedMsg: {
+ ...loadConfig.specialParams,
+ direction: 'down',
+ cursor: getMaxSequence()
+ }
+ }
+ )
+ } else {
+ // 如果不匹配,重置为普通模式
+ resetLoadConfig()
+ load({
+ receiver_id: loadConfig.receiver_id,
+ talk_type: loadConfig.talk_type,
+ limit: 30
+ })
+ }
+ } else {
load({
receiver_id: loadConfig.receiver_id,
talk_type: loadConfig.talk_type,
@@ -141,13 +314,5 @@ export const useTalkRecord = (uid: number) => {
}
}
- const onLoad = (params: Params) => {
- loadConfig.cursor = 0
- loadConfig.receiver_id = params.receiver_id
- loadConfig.talk_type = params.talk_type
-
- load(params)
- }
-
- return { loadConfig, records, onLoad, onRefreshLoad, onJumpMessage }
+ return { loadConfig, records, onLoad, onRefreshLoad, onLoadMoreDown, onJumpMessage, resetLoadConfig }
}
diff --git a/src/store/modules/dialogue.js b/src/store/modules/dialogue.js
index 509400b..7f13422 100644
--- a/src/store/modules/dialogue.js
+++ b/src/store/modules/dialogue.js
@@ -35,6 +35,12 @@ export const useDialogueStore = defineStore('dialogue', {
// 聊天记录
records: [],
+ // 查询指定消息上下文的消息信息
+ specifiedMsg: '',
+
+ // 是否是手动切换会话
+ isManualSwitch: false,
+
// 新消息提示
unreadBubble: 0,
@@ -76,6 +82,7 @@ export const useDialogueStore = defineStore('dialogue', {
// 更新对话信息
setDialogue(data = {}) {
console.log('data', data)
+
this.online = data.is_online == 1
this.talk = {
username: data.remark || data.name,
@@ -89,6 +96,12 @@ export const useDialogueStore = defineStore('dialogue', {
this.records = []
this.unreadBubble = 0
this.isShowEditor = data?.is_robot === 0
+
+ // 只在手动切换会话时清空 specifiedMsg
+ // if (this.isManualSwitch) {
+ // this.specifiedMsg = ''
+ // this.isManualSwitch = false
+ // }
this.members = []
if (data.talk_type == 2) {
diff --git a/src/utils/auth.js b/src/utils/auth.js
index 605aea5..10ed3a0 100644
--- a/src/utils/auth.js
+++ b/src/utils/auth.js
@@ -18,7 +18,7 @@ export function isLoggedIn() {
*/
export function getAccessToken() {
// return storage.get(AccessToken) || ''
- return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b89855de0ffae3adff28137845adce8c6b2c8160f779573f4e6553e86ac85dc8e689aa8970c6a4de122173f4db7bf7cdfa3ca7796d181a43b3fdf8ec549a8f33c82fbab7f0175efce75aca5cf6188ccf2a8'
+ return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b89a6a1266874decb435c4ea86321f35d90bdc30204aed39f91f4d34d074462099ce788933c4b4c4c10e31272d7bb0f3b1d8086a4695de3f9cb4cd702f79b98dc4efd5f2b753acec3bad2d1d3a4b6c85972'
}
/**
diff --git a/src/views/message/inner/IndexContent.vue b/src/views/message/inner/IndexContent.vue
index 46b8fb9..03fd8a5 100644
--- a/src/views/message/inner/IndexContent.vue
+++ b/src/views/message/inner/IndexContent.vue
@@ -31,7 +31,8 @@ const talkParams = reactive({
online: computed(() => dialogueStore.online),
keyboard: computed(() => dialogueStore.keyboard),
num: computed(() => dialogueStore.members.length),
- avatar:computed(() => dialogueStore.talk.avatar)
+ avatar:computed(() => dialogueStore.talk.avatar),
+ specifiedMsg: computed(() => dialogueStore.specifiedMsg)
})
const state = reactive({
@@ -394,6 +395,7 @@ const handleGroupNoticeModalShow = (isAdmin) => {
:talk_type="talkParams.type"
:receiver_id="talkParams.receiver_id"
:index_name="talkParams.index_name"
+ :specifiedMsg="talkParams.specifiedMsg"
/>
diff --git a/src/views/message/inner/IndexSider.vue b/src/views/message/inner/IndexSider.vue
index 385e608..32097e8 100644
--- a/src/views/message/inner/IndexSider.vue
+++ b/src/views/message/inner/IndexSider.vue
@@ -66,21 +66,10 @@ const renderChatAppSearch = () => {
return h(
chatAppSearchList,
{
- // searchResultKey: 'user_infos',
- // searchItem: {
- // avatar:
- // 'https://e-cdn.fontree.cn/fonchain-main/prod/image/18248/avatar/a0b2bee7-947f-465a-986e-10a1b2b87032.png',
- // created_at: '2025-03-27 14:44:23',
- // erp_user_id: 18248,
- // id: 44,
- // mobile: '18994430450',
- // nickname: '周俊耀'
- // },
- // searchText: '周'
searchResultPageSize: 3,
listLimit: true,
apiRequest: ServeSeachQueryAll,
- searchText: '王',
+ searchText: searchKeyword.value,
onClickSearchItem: (searchText, searchResultKey, talk_type, receiver_id, res) => {
console.log(searchText, searchResultKey, talk_type, receiver_id)
const result = JSON.parse(decodeURIComponent(res))
@@ -377,6 +366,8 @@ const onTabTalk = (item: ISession, follow = false) => {
searchKeyword.value = ''
+ dialogueStore.isManualSwitch = true
+
// 更新编辑信息
dialogueStore.setDialogue(item)
@@ -619,6 +610,25 @@ const handleClickSearchItem = (searchText, searchResultKey, talk_type, receiver_
})
}
}
+//处理点击搜索结果item
+const handleClickSearchResultItem = (searchText, searchResultKey, talk_type, receiver_id, res) => {
+ const result = JSON.parse(decodeURIComponent(res))
+ console.error(result, 'result')
+ // 根据搜索结果, 指定用于查询指定消息上下文的sequence
+ dialogueStore.specifiedMsg = encodeURIComponent(
+ JSON.stringify({
+ talk_type,
+ receiver_id,
+ msg_id: result.msg_id,
+ cursor: result.sequence - 15 > 0 ? result.sequence - 15 : 0,
+ direction: 'down',
+ sort_sequence: 'asc',
+ create_time: result.created_at
+ })
+ )
+ console.error(dialogueStore.specifiedMsg, 'dialogueStore.specifiedMsg')
+ talkStore.toTalk(talk_type, receiver_id, router)
+}
//处理点击停留item变化
const handleClickStayItemChange = (item) => {
if (item) {
@@ -682,6 +692,15 @@ const handleCloseSearchRecordModal = () => {
const getResultTotalCount = (total) => {
state.searchDetailList.total = total
}
+
+// 进入搜索结果聊天
+const handleEnterSearchResultChat = () => {
+ const searchResult = JSON.parse(decodeURIComponent(state.searchDetailList.apiParams))
+ talkStore.toTalk(searchResult.talk_type, searchResult.receiver_id, router)
+ state.isShowSearchRecordModal = false
+ state.searchRecordText = ''
+ searchKeyword.value = ''
+}
@@ -945,7 +964,7 @@ const getResultTotalCount = (total) => {
"
:searchText="state.searchRecordText"
/>
-
diff --git a/src/views/message/inner/panel/PanelContent.vue b/src/views/message/inner/panel/PanelContent.vue
index fc37085..53b606f 100644
--- a/src/views/message/inner/panel/PanelContent.vue
+++ b/src/views/message/inner/panel/PanelContent.vue
@@ -1,5 +1,5 @@