2024-12-24 08:14:21 +00:00
|
|
|
<script lang="ts" setup>
|
2025-05-12 09:00:56 +00:00
|
|
|
import {
|
|
|
|
computed,
|
|
|
|
ref,
|
|
|
|
onMounted,
|
|
|
|
watch,
|
|
|
|
reactive,
|
|
|
|
onBeforeMount,
|
|
|
|
getCurrentInstance,
|
2025-05-16 09:00:28 +00:00
|
|
|
h,
|
|
|
|
nextTick
|
2025-05-12 09:00:56 +00:00
|
|
|
} from 'vue'
|
2024-12-24 08:14:21 +00:00
|
|
|
import { onBeforeRouteUpdate } from 'vue-router'
|
|
|
|
import { useDialogueStore, useTalkStore } from '@/store'
|
2025-05-12 09:00:56 +00:00
|
|
|
import {
|
|
|
|
NDropdown,
|
|
|
|
NIcon,
|
|
|
|
NInput,
|
|
|
|
NPopover,
|
|
|
|
NTabs,
|
|
|
|
NTab,
|
|
|
|
NCard,
|
|
|
|
NButton,
|
|
|
|
NPagination
|
|
|
|
} from 'naive-ui'
|
2025-05-21 03:41:03 +00:00
|
|
|
import { Search, Plus, Right } from '@icon-park/vue-next'
|
2024-12-24 08:14:21 +00:00
|
|
|
import TalkItem from './TalkItem.vue'
|
|
|
|
import Skeleton from './Skeleton.vue'
|
|
|
|
import { ServeClearTalkUnreadNum } from '@/api/chat'
|
|
|
|
import GroupLaunch from '@/components/group/GroupLaunch.vue'
|
|
|
|
import { getCacheIndexName } from '@/utils/talk'
|
|
|
|
import { ISession } from '@/types/chat'
|
|
|
|
import { useSessionMenu } from '@/hooks'
|
2025-05-12 05:55:14 +00:00
|
|
|
import customModal from '@/components/common/customModal.vue'
|
|
|
|
import xSearchForm from '@/components/x-naive-ui/x-search-form/index.vue'
|
2025-05-12 09:00:56 +00:00
|
|
|
import xNDataTable from '@/components/x-naive-ui/x-n-data-table/index.vue'
|
2025-05-12 05:55:14 +00:00
|
|
|
import flTree from '@/components/flnlayout/tree/flnindex.vue'
|
|
|
|
import { processError, processSuccess } from '@/utils/helper/message.js'
|
2025-05-13 11:05:42 +00:00
|
|
|
import chatAppSearchList from '@/components/search/searchList.vue'
|
2025-05-16 09:00:28 +00:00
|
|
|
import { ServeSeachQueryAll, ServeQueryTalkRecord, ServeUserGroupChatList } from '@/api/search'
|
|
|
|
import { getUserInfoByERPUserId } from '@/api/user'
|
2025-05-21 03:41:03 +00:00
|
|
|
import HighlightText from '@/components/search/highLightText.vue'
|
2025-05-16 09:00:28 +00:00
|
|
|
import { useRouter } from 'vue-router'
|
|
|
|
const router = useRouter()
|
2025-05-12 05:55:14 +00:00
|
|
|
|
|
|
|
const currentInstance = getCurrentInstance()
|
2025-05-12 09:00:56 +00:00
|
|
|
const $request = currentInstance?.appContext.config.globalProperties?.$request
|
2024-12-24 08:14:21 +00:00
|
|
|
|
|
|
|
const {
|
|
|
|
dropdown,
|
|
|
|
onContextMenuTalkHandle,
|
|
|
|
onContextMenu: onContextMenuTalk,
|
|
|
|
onCloseContextMenu,
|
|
|
|
onToTopTalk
|
|
|
|
} = useSessionMenu()
|
|
|
|
|
|
|
|
const dialogueStore = useDialogueStore()
|
|
|
|
const talkStore = useTalkStore()
|
|
|
|
const isShowGroup = ref(false)
|
|
|
|
const searchKeyword = ref('')
|
|
|
|
const topItems = computed((): ISession[] => talkStore.topItems)
|
|
|
|
const unreadNum = computed(() => talkStore.talkUnreadNum)
|
|
|
|
|
2025-05-13 11:05:42 +00:00
|
|
|
//自定义搜索
|
|
|
|
const renderChatAppSearch = () => {
|
|
|
|
return h(
|
|
|
|
chatAppSearchList,
|
|
|
|
{
|
|
|
|
searchResultPageSize: 3,
|
|
|
|
listLimit: true,
|
|
|
|
apiRequest: ServeSeachQueryAll,
|
2025-05-22 07:24:13 +00:00
|
|
|
searchText: searchKeyword.value,
|
2025-05-13 11:05:42 +00:00
|
|
|
onClickSearchItem: (searchText, searchResultKey, talk_type, receiver_id, res) => {
|
|
|
|
console.log(searchText, searchResultKey, talk_type, receiver_id)
|
|
|
|
const result = JSON.parse(decodeURIComponent(res))
|
|
|
|
console.log(result)
|
2025-05-29 10:04:16 +00:00
|
|
|
if (searchResultKey === 'general_infos') {
|
|
|
|
state.ServeQueryTalkRecordParams = encodeURIComponent(
|
|
|
|
JSON.stringify({
|
|
|
|
talk_type: 0, //1私聊2群聊
|
|
|
|
receiver_id: 0, //查详情的时候需传入
|
|
|
|
last_group_id: 0, //最后一条群id
|
|
|
|
last_member_id: 0, //最后一条用户id
|
|
|
|
last_receiver_user_name: '', //最后一条用户名
|
|
|
|
last_receiver_group_name: '' //最后一条群名
|
|
|
|
})
|
|
|
|
)
|
|
|
|
state.isShowSearchRecordModal = true
|
|
|
|
state.searchRecordText = searchText
|
|
|
|
state.selectItemInList = res
|
|
|
|
} else {
|
|
|
|
talkStore.toTalk(talk_type, receiver_id, router)
|
|
|
|
}
|
|
|
|
state.showSearchDropdown = false
|
2025-05-14 09:22:25 +00:00
|
|
|
},
|
|
|
|
onToMoreResultPage: (searchResultKey, searchText) => {
|
|
|
|
if (searchResultKey === 'general_infos') {
|
|
|
|
state.ServeQueryTalkRecordParams = encodeURIComponent(
|
|
|
|
JSON.stringify({
|
|
|
|
talk_type: 0, //1私聊2群聊
|
|
|
|
receiver_id: 0, //查详情的时候需传入
|
|
|
|
last_group_id: 0, //最后一条群id
|
|
|
|
last_member_id: 0, //最后一条用户id
|
|
|
|
last_receiver_user_name: '', //最后一条用户名
|
|
|
|
last_receiver_group_name: '' //最后一条群名
|
|
|
|
})
|
|
|
|
)
|
|
|
|
state.isShowSearchRecordModal = true
|
2025-05-29 10:51:27 +00:00
|
|
|
state.searchRecordText = searchText
|
2025-05-14 09:22:25 +00:00
|
|
|
}
|
|
|
|
console.log(searchResultKey, searchText)
|
2025-05-29 10:51:27 +00:00
|
|
|
state.showSearchDropdown = false
|
2025-05-13 11:05:42 +00:00
|
|
|
}
|
|
|
|
},
|
2025-05-21 03:41:03 +00:00
|
|
|
{
|
|
|
|
'result-title': ({ getResultKeysValue, searchResultKey, searchResultIndex }) => {
|
|
|
|
return h(
|
|
|
|
'div',
|
|
|
|
{
|
|
|
|
style: {
|
|
|
|
padding: searchResultIndex === 0 ? '6px 10px 5px' : '18px 10px 5px',
|
|
|
|
borderBottom: '1px solid #f8f8f8'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[
|
|
|
|
h(
|
|
|
|
'span',
|
|
|
|
{
|
|
|
|
class: 'text-[14px] font-regular',
|
|
|
|
style: 'line-height: 20px; color: #999999;'
|
|
|
|
},
|
|
|
|
getResultKeysValue(searchResultKey)
|
|
|
|
)
|
|
|
|
]
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2025-05-13 11:05:42 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2025-05-12 05:55:14 +00:00
|
|
|
const state = reactive({
|
|
|
|
isShowAddressBookModal: false, // 是否显示通讯录模态框
|
|
|
|
customModalStyle: {
|
|
|
|
width: '1288px',
|
|
|
|
height: '846px',
|
|
|
|
backgroundColor: '#F9F9FD'
|
|
|
|
}, //自定义模态框样式
|
2025-05-13 06:08:20 +00:00
|
|
|
addressBookSearchConfig: [
|
2025-05-12 05:55:14 +00:00
|
|
|
{
|
|
|
|
label: '姓名',
|
2025-05-13 06:08:20 +00:00
|
|
|
key: 'nickName',
|
2025-05-12 05:55:14 +00:00
|
|
|
type: 'input',
|
|
|
|
valueType: 'string'
|
|
|
|
}
|
2025-05-13 06:08:20 +00:00
|
|
|
], // 通讯录搜索配置
|
|
|
|
groupChatListSearchConfig: [
|
|
|
|
{
|
|
|
|
label: '群聊名称',
|
|
|
|
key: 'groupName',
|
|
|
|
type: 'input',
|
|
|
|
valueType: 'string'
|
|
|
|
}
|
|
|
|
], // 群聊列表搜索配置
|
2025-05-12 05:55:14 +00:00
|
|
|
treeData: [],
|
|
|
|
expandedKeys: [],
|
2025-05-12 09:00:56 +00:00
|
|
|
clickKey: 3,
|
2025-05-12 05:55:14 +00:00
|
|
|
treeRefreshCount: 0,
|
2025-05-12 09:00:56 +00:00
|
|
|
treeSelectData: {},
|
|
|
|
addressBookColumns: [
|
|
|
|
{
|
2025-05-13 06:08:20 +00:00
|
|
|
title: '姓名 【工号】',
|
|
|
|
field: 'nickName',
|
2025-05-12 09:00:56 +00:00
|
|
|
width: 200,
|
|
|
|
render(row, index) {
|
2025-05-13 06:08:20 +00:00
|
|
|
return row.nickName + '【' + row.jobNum + '】'
|
2025-05-12 09:00:56 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: '岗位名称',
|
|
|
|
field: 'positionName',
|
|
|
|
width: 400,
|
|
|
|
ellipsis: true,
|
|
|
|
render(row, index) {
|
2025-05-13 06:08:20 +00:00
|
|
|
let positionNames = Array.isArray(row.depPositions)
|
|
|
|
? row.depPositions.flatMap((dep) =>
|
|
|
|
Array.isArray(dep.positions) ? dep.positions.map((pos) => pos.name) : []
|
|
|
|
)
|
|
|
|
: []
|
|
|
|
return positionNames.join(' , ')
|
2025-05-12 09:00:56 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: '操作',
|
|
|
|
field: 'action',
|
|
|
|
width: 200,
|
|
|
|
align: 'center',
|
|
|
|
fixed: 'right',
|
|
|
|
render(row, index) {
|
|
|
|
return h(
|
|
|
|
NButton,
|
|
|
|
{
|
|
|
|
size: 'small',
|
|
|
|
text: true,
|
|
|
|
color: '#46299d',
|
|
|
|
onClick: () => handleEnterChat(row)
|
|
|
|
},
|
|
|
|
{ default: () => '进入聊天' }
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
], // 通讯录表格列
|
2025-05-13 06:08:20 +00:00
|
|
|
groupChatListColumns: [
|
|
|
|
{
|
|
|
|
title: '群聊名称',
|
|
|
|
field: 'groupName',
|
|
|
|
width: 200,
|
|
|
|
render(row, index) {
|
2025-05-16 09:00:28 +00:00
|
|
|
return row.group_name
|
2025-05-13 06:08:20 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: '群类型',
|
|
|
|
field: 'groupType',
|
|
|
|
width: 400,
|
|
|
|
ellipsis: true,
|
|
|
|
render(row, index) {
|
2025-05-16 09:00:28 +00:00
|
|
|
let groupType = row.group_type
|
|
|
|
if (groupType == 1) {
|
|
|
|
return '普通群'
|
|
|
|
} else if (groupType == 2) {
|
|
|
|
return '部门群'
|
|
|
|
} else if (groupType == 3) {
|
|
|
|
return '项目群'
|
|
|
|
} else if (groupType == 4) {
|
|
|
|
return '公司群'
|
|
|
|
}
|
2025-05-13 06:08:20 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: '操作',
|
|
|
|
field: 'action',
|
|
|
|
width: 200,
|
|
|
|
align: 'center',
|
|
|
|
fixed: 'right',
|
|
|
|
render(row, index) {
|
|
|
|
return h(
|
|
|
|
NButton,
|
|
|
|
{
|
|
|
|
size: 'small',
|
|
|
|
text: true,
|
|
|
|
color: '#46299d',
|
|
|
|
onClick: () => handleEnterChat(row)
|
|
|
|
},
|
|
|
|
{ default: () => '进入聊天' }
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
], // 群聊列表表格列
|
2025-05-12 09:00:56 +00:00
|
|
|
addressBookData: [], // 通讯录表格数据
|
2025-05-13 06:08:20 +00:00
|
|
|
groupChatListData: [], // 群聊列表表格数据
|
2025-05-12 09:00:56 +00:00
|
|
|
addressBookTableHeight: 524, // 通讯录表格高度
|
|
|
|
addressBookTableWidth: 800, // 通讯录表格宽度
|
|
|
|
addressBookPage: 1, // 通讯录表格页码
|
|
|
|
addressBookPageSize: 10, // 通讯录表格每页条数
|
2025-05-13 06:08:20 +00:00
|
|
|
addressBookTotal: 0, // 通讯录表格总条数
|
|
|
|
addressBookSearchNickName: '', // 通讯录搜索条件-姓名
|
|
|
|
addressBookCurrentTab: 'employeeAddressBook', // 通讯录当前tab
|
|
|
|
groupChatListPage: 1, // 群聊列表表格页码
|
|
|
|
groupChatListPageSize: 10, // 群聊列表表格每页条数
|
|
|
|
groupChatListTotal: 0, // 群聊列表表格总条数
|
|
|
|
groupChatListSearchGroupName: '', // 群聊列表搜索条件-群聊名称
|
2025-05-13 11:05:42 +00:00
|
|
|
chatSearchOptions: [
|
|
|
|
{
|
|
|
|
key: 'chatSearch',
|
|
|
|
type: 'render',
|
|
|
|
render: renderChatAppSearch
|
|
|
|
}
|
2025-05-14 09:22:25 +00:00
|
|
|
], // 聊天搜索选项
|
|
|
|
isShowSearchRecordModal: false, // 是否显示搜索聊天记录模态框
|
|
|
|
customSearchRecordModalStyle: {
|
|
|
|
width: '997px',
|
|
|
|
height: '740px',
|
|
|
|
backgroundColor: '#F9F9FD'
|
|
|
|
}, //自定义模态框样式
|
|
|
|
searchRecordText: '', // 搜索聊天记录文本
|
|
|
|
ServeQueryTalkRecordParams: '', // 搜索聊天记录参数
|
2025-05-15 10:56:41 +00:00
|
|
|
ServeQueryTalkRecordDetailParams: '', // 搜索聊天记录详情参数
|
2025-05-20 11:58:16 +00:00
|
|
|
isShowSearchRecordDetailInfo: false, // 是否显示搜索聊天记录详情
|
|
|
|
// 拆分 searchList 和 searchDetailList 独立状态
|
|
|
|
searchList: {
|
|
|
|
searchText: '',
|
|
|
|
apiParams: '',
|
|
|
|
lastId: undefined as any
|
|
|
|
},
|
|
|
|
searchDetailList: {
|
|
|
|
searchText: '',
|
|
|
|
apiParams: '',
|
2025-05-21 03:41:03 +00:00
|
|
|
lastId: undefined as any,
|
|
|
|
total: 0
|
2025-05-29 10:04:16 +00:00
|
|
|
},
|
|
|
|
showSearchDropdown: false, // 是否显示搜索下拉框
|
|
|
|
selectItemInList: '' // 在列表选中的聊天记录搜索项
|
2025-05-12 05:55:14 +00:00
|
|
|
})
|
|
|
|
|
2024-12-24 08:14:21 +00:00
|
|
|
const items = computed((): ISession[] => {
|
2025-05-21 11:57:07 +00:00
|
|
|
let filtered = talkStore.talkItems
|
|
|
|
|
|
|
|
if (searchKeyword.value.length > 0) {
|
|
|
|
filtered = filtered.filter((item: ISession) => {
|
|
|
|
let keyword = item.remark || item.name
|
|
|
|
return keyword.toLowerCase().indexOf(searchKeyword.value.toLowerCase()) != -1
|
|
|
|
})
|
2024-12-24 08:14:21 +00:00
|
|
|
}
|
|
|
|
|
2025-05-21 11:57:07 +00:00
|
|
|
// 置顶和非置顶分组
|
|
|
|
const topItems = filtered
|
2025-05-29 10:04:16 +00:00
|
|
|
.filter((item) => item.is_top === 1)
|
2025-05-21 11:57:07 +00:00
|
|
|
.sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime())
|
2025-05-29 10:04:16 +00:00
|
|
|
const normalItems = filtered.filter((item) => item.is_top !== 1)
|
2024-12-24 08:14:21 +00:00
|
|
|
|
2025-05-21 11:57:07 +00:00
|
|
|
return [...topItems, ...normalItems]
|
2024-12-24 08:14:21 +00:00
|
|
|
})
|
2025-05-13 06:08:20 +00:00
|
|
|
watch(
|
|
|
|
() => state.addressBookSearchNickName,
|
|
|
|
(newValue, oldValue) => {
|
|
|
|
// console.log(newValue, 'newValue')
|
|
|
|
if (newValue) {
|
|
|
|
state.addressBookTableWidth = 1142
|
|
|
|
state.addressBookPage = 1
|
|
|
|
} else {
|
|
|
|
state.addressBookTableWidth = 800
|
|
|
|
state.clickKey = 3
|
|
|
|
state.treeRefreshCount++
|
2025-05-16 09:00:28 +00:00
|
|
|
state.addressBookPage = 1
|
2025-05-13 06:08:20 +00:00
|
|
|
}
|
|
|
|
getDepPoisUser()
|
|
|
|
}
|
|
|
|
)
|
2025-05-16 09:00:28 +00:00
|
|
|
watch(
|
|
|
|
() => state.groupChatListSearchGroupName,
|
|
|
|
(newValue, oldValue) => {
|
|
|
|
if (newValue) {
|
|
|
|
state.groupChatListPage = 1
|
|
|
|
} else {
|
|
|
|
state.groupChatListPage = 1
|
|
|
|
}
|
|
|
|
getUserGroupChatList()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2025-05-20 11:58:16 +00:00
|
|
|
// 监听搜索关键字变化,重置所有相关状态
|
|
|
|
watch(
|
|
|
|
() => state.searchRecordText,
|
|
|
|
(newVal, oldVal) => {
|
|
|
|
// 重置左侧
|
|
|
|
state.searchList.searchText = newVal
|
2025-05-21 03:41:03 +00:00
|
|
|
state.searchList.apiParams = encodeURIComponent(
|
|
|
|
JSON.stringify({
|
|
|
|
talk_type: 0,
|
|
|
|
receiver_id: 0,
|
|
|
|
last_group_id: 0,
|
|
|
|
last_member_id: 0,
|
|
|
|
last_receiver_user_name: '',
|
|
|
|
last_receiver_group_name: ''
|
|
|
|
})
|
|
|
|
)
|
2025-05-20 11:58:16 +00:00
|
|
|
state.searchList.lastId = undefined
|
|
|
|
// 重置右侧
|
|
|
|
state.searchDetailList.searchText = newVal
|
|
|
|
state.searchDetailList.apiParams = ''
|
|
|
|
state.searchDetailList.lastId = undefined
|
|
|
|
// 关闭右侧详情
|
|
|
|
state.isShowSearchRecordDetailInfo = false
|
|
|
|
}
|
|
|
|
)
|
2024-12-24 08:14:21 +00:00
|
|
|
|
|
|
|
// 列表加载状态
|
|
|
|
const loadStatus = computed(() => talkStore.loadStatus)
|
|
|
|
|
|
|
|
// 当前会话索引
|
|
|
|
const indexName = computed(() => dialogueStore.index_name)
|
|
|
|
|
|
|
|
// 切换会话
|
|
|
|
const onTabTalk = (item: ISession, follow = false) => {
|
2025-05-21 03:41:03 +00:00
|
|
|
console.log('onTabTalk')
|
|
|
|
|
2024-12-24 08:14:21 +00:00
|
|
|
if (item.index_name === indexName.value) return
|
|
|
|
|
|
|
|
searchKeyword.value = ''
|
|
|
|
|
2025-05-22 07:24:13 +00:00
|
|
|
dialogueStore.isManualSwitch = true
|
|
|
|
|
2024-12-24 08:14:21 +00:00
|
|
|
// 更新编辑信息
|
|
|
|
dialogueStore.setDialogue(item)
|
|
|
|
|
|
|
|
// 清空消息未读数
|
|
|
|
if (item.unread_num > 0) {
|
|
|
|
ServeClearTalkUnreadNum({
|
|
|
|
talk_type: item.talk_type,
|
|
|
|
receiver_id: item.receiver_id
|
|
|
|
}).then(() => {
|
|
|
|
talkStore.updateItem({
|
|
|
|
index_name: item.index_name,
|
|
|
|
unread_num: 0
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// 设置滚动条跟随
|
|
|
|
if (follow) {
|
|
|
|
const el = document.getElementById('talk-session-list')
|
|
|
|
if (el) {
|
|
|
|
let index = talkStore.findTalkIndex(item.index_name)
|
|
|
|
|
|
|
|
el.scrollTo({
|
|
|
|
top: index * 66 + index * 5,
|
|
|
|
behavior: 'smooth'
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const onReload = () => {
|
|
|
|
talkStore.loadTalkList()
|
|
|
|
}
|
|
|
|
|
|
|
|
// 初始化加载
|
|
|
|
const onInitialize = () => {
|
|
|
|
let index_name = getCacheIndexName()
|
|
|
|
|
|
|
|
index_name && onTabTalk(talkStore.findItem(index_name), true)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 路由更新事件
|
|
|
|
onBeforeRouteUpdate(onInitialize)
|
|
|
|
|
2025-05-12 05:55:14 +00:00
|
|
|
onBeforeMount(() => {
|
|
|
|
getTreeData()
|
2025-05-16 09:00:28 +00:00
|
|
|
getUserGroupChatList()
|
2025-05-12 05:55:14 +00:00
|
|
|
})
|
|
|
|
|
2024-12-24 08:14:21 +00:00
|
|
|
onMounted(() => {
|
|
|
|
onInitialize()
|
|
|
|
})
|
2025-05-12 05:55:14 +00:00
|
|
|
|
|
|
|
// 点击显示通讯录模态框
|
|
|
|
const showAddressBookModal = () => {
|
|
|
|
state.isShowAddressBookModal = true
|
|
|
|
}
|
|
|
|
const handleTreeClick = ({ selectedKey, tree }) => {
|
2025-05-13 06:08:20 +00:00
|
|
|
// console.log(tree)
|
2025-05-12 05:55:14 +00:00
|
|
|
state.clickKey = tree.key
|
|
|
|
state.treeSelectData = tree
|
2025-05-13 06:08:20 +00:00
|
|
|
state.addressBookPage = 1
|
2025-05-12 09:00:56 +00:00
|
|
|
getDepPoisUser()
|
2025-05-12 05:55:14 +00:00
|
|
|
}
|
|
|
|
const calcTreeData = (data) => {
|
|
|
|
for (let item of data) {
|
|
|
|
item.key = item.ID
|
|
|
|
item.label = item.name
|
|
|
|
item.title = item.name
|
|
|
|
if (item.sons) {
|
|
|
|
item.children = item.sons
|
|
|
|
calcTreeData(item.children)
|
|
|
|
}
|
|
|
|
delete item.ID
|
|
|
|
delete item.name
|
|
|
|
delete item.sons
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 获取组织树数据
|
|
|
|
const getTreeData = () => {
|
|
|
|
let url = '/department/v2/tree/filter'
|
|
|
|
let params = {}
|
|
|
|
$request.HTTP.components.postDataByParams(url, params).then(
|
|
|
|
(res) => {
|
|
|
|
if (res.status === 0 && Array.isArray(res.data.nodes)) {
|
|
|
|
let data = res.data.nodes
|
|
|
|
calcTreeData(data)
|
|
|
|
state.treeData = data
|
|
|
|
state.treeRefreshCount++
|
2025-05-12 09:00:56 +00:00
|
|
|
getDepPoisUser()
|
2025-05-12 05:55:14 +00:00
|
|
|
} else {
|
|
|
|
processError(res.msg || '获取失败!')
|
|
|
|
}
|
|
|
|
},
|
|
|
|
() => {
|
|
|
|
processError('获取失败!')
|
|
|
|
},
|
|
|
|
() => {
|
|
|
|
processError('获取失败!')
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
2025-05-12 09:00:56 +00:00
|
|
|
// 获取部门下的人员
|
|
|
|
const getDepPoisUser = () => {
|
|
|
|
let url = '/user/v2/list'
|
|
|
|
let params = {
|
2025-05-13 06:08:20 +00:00
|
|
|
departmentId: state.addressBookSearchNickName ? undefined : state.clickKey,
|
2025-05-12 09:00:56 +00:00
|
|
|
page: state.addressBookPage,
|
|
|
|
pageSize: state.addressBookPageSize,
|
2025-05-13 06:08:20 +00:00
|
|
|
status: 'notactive',
|
|
|
|
nickName: state.addressBookSearchNickName
|
2025-05-12 09:00:56 +00:00
|
|
|
}
|
|
|
|
$request.HTTP.components.postDataByParams(url, params).then((res) => {
|
2025-05-13 06:08:20 +00:00
|
|
|
// console.log(res)
|
2025-05-12 09:00:56 +00:00
|
|
|
if (res.status === 0 && Array.isArray(res.data.data)) {
|
|
|
|
state.addressBookData = res.data.data || []
|
|
|
|
state.addressBookTotal = res.data.count
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
//点击进入对应的聊天
|
2025-05-16 09:00:28 +00:00
|
|
|
const handleEnterChat = async (row) => {
|
2025-05-12 09:00:56 +00:00
|
|
|
console.log(row)
|
2025-05-16 09:00:28 +00:00
|
|
|
if (state.addressBookCurrentTab === 'employeeAddressBook') {
|
|
|
|
//员工通讯录,聊天类型一定为单聊
|
|
|
|
await getUserInfoByERPUserId({ erp_user_id: row.ID }).then((res) => {
|
|
|
|
// console.log(res)
|
|
|
|
if (res.code === 200) {
|
|
|
|
let sysUserInfo = res.data
|
|
|
|
talkStore.toTalk(1, sysUserInfo.sys_id, router)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else if (state.addressBookCurrentTab === 'groupChatList') {
|
|
|
|
//群聊列表,聊天类型一定为群聊
|
|
|
|
talkStore.toTalk(2, row.id, router)
|
|
|
|
}
|
|
|
|
state.isShowAddressBookModal = false
|
|
|
|
resetAddressBookModal()
|
|
|
|
}
|
|
|
|
//恢复默认通讯录模态框
|
|
|
|
const resetAddressBookModal = () => {
|
|
|
|
nextTick(() => {
|
|
|
|
state.addressBookCurrentTab = 'employeeAddressBook'
|
|
|
|
state.addressBookSearchNickName = ''
|
|
|
|
state.groupChatListSearchGroupName = ''
|
|
|
|
state.addressBookTableWidth = 800
|
|
|
|
state.clickKey = 3
|
|
|
|
state.treeRefreshCount++
|
|
|
|
state.addressBookPage = 1
|
|
|
|
state.addressBookPageSize = 10
|
|
|
|
state.groupChatListPage = 1
|
|
|
|
state.groupChatListPageSize = 10
|
|
|
|
getDepPoisUser()
|
|
|
|
getUserGroupChatList()
|
|
|
|
})
|
2025-05-12 09:00:56 +00:00
|
|
|
}
|
|
|
|
//处理页数变化
|
|
|
|
const handleAddressBookPagination = (page) => {
|
|
|
|
state.addressBookPage = page
|
|
|
|
getDepPoisUser()
|
|
|
|
}
|
|
|
|
//处理每页条数变化
|
|
|
|
const handleAddressBookPaginationSize = (pageSize) => {
|
|
|
|
state.addressBookPageSize = pageSize
|
|
|
|
state.addressBookPage = 1
|
|
|
|
getDepPoisUser()
|
|
|
|
}
|
2025-05-13 06:08:20 +00:00
|
|
|
//处理通讯录搜索
|
|
|
|
const changeAddressBookSearch = (value) => {
|
|
|
|
if (!value.nickName?.trim()) {
|
|
|
|
state.addressBookSearchNickName = ''
|
|
|
|
} else {
|
|
|
|
state.addressBookSearchNickName = value.nickName
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//处理通讯录tab切换
|
|
|
|
const handleAddressBookTabChange = (value) => {
|
|
|
|
console.log(value, 'value')
|
|
|
|
state.addressBookCurrentTab = value
|
|
|
|
}
|
|
|
|
//处理群聊列表搜索
|
|
|
|
const changeGroupChatListSearch = (value) => {
|
|
|
|
console.log(value, 'value')
|
2025-05-16 09:00:28 +00:00
|
|
|
if (!value.groupName?.trim()) {
|
|
|
|
state.groupChatListSearchGroupName = ''
|
|
|
|
} else {
|
|
|
|
state.groupChatListSearchGroupName = value.groupName
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//获取用户所在群聊列表
|
|
|
|
const getUserGroupChatList = () => {
|
|
|
|
let params = {
|
|
|
|
page: state.groupChatListPage,
|
|
|
|
page_size: state.groupChatListPageSize,
|
|
|
|
group_name: state.groupChatListSearchGroupName
|
|
|
|
}
|
|
|
|
ServeUserGroupChatList(params).then((res) => {
|
|
|
|
// console.log(res)
|
|
|
|
if (res.code === 200) {
|
|
|
|
state.groupChatListData = res?.data?.items || []
|
|
|
|
state.groupChatListTotal = res?.data?.total || 0
|
|
|
|
}
|
|
|
|
})
|
2025-05-13 06:08:20 +00:00
|
|
|
}
|
2025-05-16 09:00:28 +00:00
|
|
|
|
2025-05-13 06:08:20 +00:00
|
|
|
//处理群聊列表页数变化
|
|
|
|
const handleGroupChatListPagination = (value) => {
|
|
|
|
console.log(value, 'value')
|
|
|
|
state.groupChatListPage = value
|
2025-05-16 09:00:28 +00:00
|
|
|
getUserGroupChatList()
|
2025-05-13 06:08:20 +00:00
|
|
|
}
|
|
|
|
//处理群聊列表每页条数变化
|
|
|
|
const handleGroupChatListPaginationSize = (value) => {
|
|
|
|
console.log(value, 'value')
|
|
|
|
state.groupChatListPageSize = value
|
2025-05-16 09:00:28 +00:00
|
|
|
state.groupChatListPage = 1
|
|
|
|
getUserGroupChatList()
|
2025-05-13 06:08:20 +00:00
|
|
|
}
|
2025-05-15 10:56:41 +00:00
|
|
|
//处理搜索聊天记录点击
|
|
|
|
const handleClickSearchItem = (searchText, searchResultKey, talk_type, receiver_id, res) => {
|
|
|
|
console.log(searchText, searchResultKey, talk_type, receiver_id)
|
2025-05-29 10:04:16 +00:00
|
|
|
// const result = JSON.parse(decodeURIComponent(res))
|
|
|
|
// console.log(result)
|
2025-05-15 10:56:41 +00:00
|
|
|
if (searchResultKey === 'general_infos') {
|
2025-05-20 11:58:16 +00:00
|
|
|
// 先清空右侧
|
|
|
|
state.isShowSearchRecordDetailInfo = false
|
2025-05-21 03:41:03 +00:00
|
|
|
state.searchDetailList.apiParams = encodeURIComponent(
|
2025-05-15 10:56:41 +00:00
|
|
|
JSON.stringify({
|
2025-05-21 03:41:03 +00:00
|
|
|
last_group_id: 0,
|
|
|
|
last_member_id: 0,
|
|
|
|
receiver_id: receiver_id,
|
|
|
|
talk_type: talk_type
|
2025-05-15 10:56:41 +00:00
|
|
|
})
|
|
|
|
)
|
2025-05-20 11:58:16 +00:00
|
|
|
state.searchDetailList.searchText = state.searchRecordText
|
|
|
|
state.searchDetailList.lastId = undefined
|
|
|
|
// 再显示
|
2025-05-16 09:00:28 +00:00
|
|
|
nextTick(() => {
|
2025-05-20 11:58:16 +00:00
|
|
|
state.isShowSearchRecordDetailInfo = true
|
2025-05-16 09:00:28 +00:00
|
|
|
})
|
2025-05-15 10:56:41 +00:00
|
|
|
}
|
|
|
|
}
|
2025-05-22 07:24:13 +00:00
|
|
|
//处理点击搜索结果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)
|
2025-05-29 10:51:27 +00:00
|
|
|
state.isShowSearchRecordModal = false
|
|
|
|
state.searchRecordText = ''
|
|
|
|
searchKeyword.value = ''
|
2025-05-22 07:24:13 +00:00
|
|
|
}
|
2025-05-15 10:56:41 +00:00
|
|
|
//处理点击停留item变化
|
|
|
|
const handleClickStayItemChange = (item) => {
|
|
|
|
if (item) {
|
|
|
|
state.isShowSearchRecordDetailInfo = true
|
|
|
|
} else {
|
|
|
|
state.isShowSearchRecordDetailInfo = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 定义搜索列表组件的ref
|
|
|
|
const searchListRef = ref()
|
|
|
|
|
|
|
|
// 定义搜索详情列表组件的ref
|
|
|
|
const searchDetailListRef = ref()
|
|
|
|
|
2025-05-20 11:58:16 +00:00
|
|
|
// lastIdChange 事件区分来源
|
2025-05-21 03:41:03 +00:00
|
|
|
const handleSearchListLastIdChange = (
|
2025-05-15 10:56:41 +00:00
|
|
|
last_id,
|
|
|
|
last_group_id,
|
|
|
|
last_member_id,
|
|
|
|
last_receiver_user_name,
|
|
|
|
last_receiver_group_name
|
|
|
|
) => {
|
2025-05-21 03:41:03 +00:00
|
|
|
state.searchList.lastId = {
|
2025-05-15 10:56:41 +00:00
|
|
|
last_id,
|
|
|
|
last_group_id,
|
|
|
|
last_member_id,
|
|
|
|
last_receiver_user_name,
|
|
|
|
last_receiver_group_name
|
|
|
|
}
|
2025-05-21 03:41:03 +00:00
|
|
|
state.searchList.apiParams = encodeURIComponent(
|
|
|
|
JSON.stringify({
|
|
|
|
...JSON.parse(decodeURIComponent(state.searchList.apiParams)),
|
|
|
|
last_id,
|
|
|
|
last_group_id,
|
|
|
|
last_member_id,
|
|
|
|
last_receiver_user_name,
|
|
|
|
last_receiver_group_name
|
|
|
|
})
|
2025-05-15 10:56:41 +00:00
|
|
|
)
|
|
|
|
}
|
2025-05-20 11:58:16 +00:00
|
|
|
const handleSearchDetailListLastIdChange = (last_id, last_group_id, last_member_id) => {
|
|
|
|
state.searchDetailList.lastId = { last_id, last_group_id, last_member_id }
|
2025-05-21 03:41:03 +00:00
|
|
|
state.searchDetailList.apiParams = encodeURIComponent(
|
|
|
|
JSON.stringify({
|
|
|
|
...JSON.parse(decodeURIComponent(state.searchDetailList.apiParams)),
|
|
|
|
last_id,
|
|
|
|
last_group_id,
|
|
|
|
last_member_id
|
|
|
|
})
|
2025-05-15 10:56:41 +00:00
|
|
|
)
|
2025-05-13 06:08:20 +00:00
|
|
|
}
|
2025-05-21 03:41:03 +00:00
|
|
|
|
|
|
|
// 关闭搜索聊天记录模态框
|
|
|
|
const handleCloseSearchRecordModal = () => {
|
|
|
|
state.isShowSearchRecordModal = false
|
|
|
|
state.searchRecordText = ''
|
|
|
|
}
|
|
|
|
|
|
|
|
// 获取搜索结果总数
|
|
|
|
const getResultTotalCount = (total) => {
|
|
|
|
state.searchDetailList.total = total
|
2025-05-13 06:08:20 +00:00
|
|
|
}
|
2025-05-22 07:24:13 +00:00
|
|
|
|
|
|
|
// 进入搜索结果聊天
|
|
|
|
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 = ''
|
|
|
|
}
|
2024-12-24 08:14:21 +00:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<!-- 右键菜单 -->
|
|
|
|
<n-dropdown
|
|
|
|
class="dropdown-menus"
|
|
|
|
:show="dropdown.show"
|
|
|
|
:x="dropdown.x"
|
|
|
|
:y="dropdown.y"
|
|
|
|
:options="dropdown.options"
|
|
|
|
@select="onContextMenuTalkHandle"
|
|
|
|
@clickoutside="onCloseContextMenu"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<section class="el-container is-vertical height100">
|
|
|
|
<!-- 工具栏目 -->
|
|
|
|
<header class="el-header header-tools">
|
2025-05-13 11:05:42 +00:00
|
|
|
<n-dropdown
|
|
|
|
trigger="click"
|
|
|
|
:options="state.chatSearchOptions"
|
2025-05-20 11:58:16 +00:00
|
|
|
style="width: 248px; height: 677px;"
|
2025-05-29 10:04:16 +00:00
|
|
|
:show="state.showSearchDropdown"
|
|
|
|
@clickoutside="state.showSearchDropdown = false"
|
2024-12-24 08:14:21 +00:00
|
|
|
>
|
2025-05-13 11:05:42 +00:00
|
|
|
<n-input
|
|
|
|
placeholder="搜索好友 / 群聊"
|
|
|
|
v-model:value.trim="searchKeyword"
|
|
|
|
clearable
|
|
|
|
style="width: 78%;"
|
2025-05-29 10:04:16 +00:00
|
|
|
@click="state.showSearchDropdown = true"
|
2025-05-13 11:05:42 +00:00
|
|
|
>
|
2025-05-29 10:51:27 +00:00
|
|
|
<!-- <template #prefix>
|
2025-05-13 11:05:42 +00:00
|
|
|
<n-icon :component="Search" />
|
2025-05-29 10:51:27 +00:00
|
|
|
</template> -->
|
2025-05-13 11:05:42 +00:00
|
|
|
</n-input>
|
|
|
|
</n-dropdown>
|
2025-05-29 10:51:27 +00:00
|
|
|
<!-- <n-button circle @click="isShowGroup = true">
|
2024-12-24 08:14:21 +00:00
|
|
|
<template #icon>
|
|
|
|
<n-icon :component="Plus" />
|
|
|
|
</template>
|
2025-05-29 10:51:27 +00:00
|
|
|
</n-button> -->
|
2025-05-12 05:55:14 +00:00
|
|
|
<img
|
2025-05-13 11:05:42 +00:00
|
|
|
style="width: 19px; height: 20px; cursor: pointer;"
|
2025-05-12 05:55:14 +00:00
|
|
|
src="@/assets/image/chatList/addressBook.png"
|
|
|
|
alt=""
|
|
|
|
@click="showAddressBookModal"
|
|
|
|
/>
|
2024-12-24 08:14:21 +00:00
|
|
|
</header>
|
|
|
|
|
|
|
|
<!-- 置顶栏目 -->
|
2025-05-16 11:49:57 +00:00
|
|
|
<!-- <header class="el-header header-top" v-show="loadStatus == 3 && topItems.length > 0">
|
2024-12-24 08:14:21 +00:00
|
|
|
<n-popover v-for="item in topItems" :key="item.index_name" placement="bottom" trigger="hover">
|
|
|
|
<template #trigger>
|
|
|
|
<div
|
|
|
|
class="top-item pointer"
|
|
|
|
@click="onTabTalk(item, true)"
|
|
|
|
:class="{
|
|
|
|
active: item.index_name == indexName
|
|
|
|
}"
|
|
|
|
>
|
|
|
|
<im-avatar :src="item.avatar" :size="34" :username="item.name" />
|
|
|
|
|
|
|
|
<span class="icon-mark robot" v-show="item.is_robot == 1"> 助 </span>
|
|
|
|
|
|
|
|
<span class="icon-mark group" v-show="item.talk_type == 2 && item.is_robot == 0">
|
|
|
|
群
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<span class="text">{{ item.remark || item.name }}</span>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<span> {{ item.remark || item.name }} </span>
|
|
|
|
</n-popover>
|
2025-05-16 11:49:57 +00:00
|
|
|
</header> -->
|
2024-12-24 08:14:21 +00:00
|
|
|
|
|
|
|
<!-- 标题栏目 -->
|
2025-05-19 03:39:20 +00:00
|
|
|
<!-- <header
|
2024-12-24 08:14:21 +00:00
|
|
|
v-show="loadStatus == 3 && talkStore.talkItems.length > 0"
|
|
|
|
class="el-header header-badge"
|
|
|
|
:class="{ shadow: false }"
|
|
|
|
>
|
|
|
|
<p>会话记录({{ talkStore.talkItems.length }})</p>
|
|
|
|
<p>
|
|
|
|
<span class="badge unread" v-show="unreadNum">{{ unreadNum }}未读</span>
|
|
|
|
</p>
|
2025-05-19 03:39:20 +00:00
|
|
|
</header> -->
|
2024-12-24 08:14:21 +00:00
|
|
|
|
|
|
|
<main id="talk-session-list" class="el-main me-scrollbar me-scrollbar-thumb">
|
|
|
|
<template v-if="loadStatus == 2"><Skeleton /></template>
|
|
|
|
<template v-else>
|
|
|
|
<TalkItem
|
|
|
|
v-for="item in items"
|
|
|
|
:key="item.index_name"
|
|
|
|
:data="item"
|
|
|
|
:avatar="item.avatar"
|
|
|
|
:username="item.remark || item.name"
|
|
|
|
:active="item.index_name == indexName"
|
|
|
|
@tab-talk="onTabTalk"
|
|
|
|
@top-talk="onToTopTalk"
|
|
|
|
@contextmenu.prevent="onContextMenuTalk($event, item)"
|
|
|
|
/>
|
|
|
|
</template>
|
|
|
|
</main>
|
|
|
|
</section>
|
|
|
|
|
|
|
|
<GroupLaunch v-if="isShowGroup" @close="isShowGroup = false" @on-submit="onReload" />
|
2025-05-12 05:55:14 +00:00
|
|
|
|
|
|
|
<customModal
|
|
|
|
v-model:show="state.isShowAddressBookModal"
|
|
|
|
title="通讯录"
|
|
|
|
:style="state.customModalStyle"
|
|
|
|
:customCloseBtn="true"
|
|
|
|
:closable="false"
|
|
|
|
>
|
|
|
|
<template #content>
|
|
|
|
<div class="custom-modal-content">
|
2025-05-12 09:00:56 +00:00
|
|
|
<n-card style="padding: 0 12px;">
|
2025-05-13 11:05:42 +00:00
|
|
|
<n-tabs
|
|
|
|
type="line"
|
|
|
|
@update:value="handleAddressBookTabChange"
|
|
|
|
tab-style="font-size: 16px; font-weight: 600;color: #8B8B8B;"
|
|
|
|
>
|
2025-05-12 05:55:14 +00:00
|
|
|
<n-tab name="employeeAddressBook">员工通讯录</n-tab>
|
|
|
|
<n-tab name="groupChatList">群聊列表</n-tab>
|
|
|
|
</n-tabs>
|
2025-05-13 06:08:20 +00:00
|
|
|
<xSearchForm
|
|
|
|
v-if="state.addressBookCurrentTab == 'employeeAddressBook'"
|
|
|
|
:search-config="state.addressBookSearchConfig"
|
|
|
|
customInputPlaceholder="请输入姓名"
|
|
|
|
@change="changeAddressBookSearch"
|
|
|
|
:cols="3"
|
|
|
|
></xSearchForm>
|
|
|
|
<xSearchForm
|
|
|
|
v-if="state.addressBookCurrentTab == 'groupChatList'"
|
|
|
|
:search-config="state.groupChatListSearchConfig"
|
|
|
|
customInputPlaceholder="请输入群聊名称"
|
|
|
|
@change="changeGroupChatListSearch"
|
|
|
|
:cols="3"
|
|
|
|
></xSearchForm>
|
|
|
|
<div
|
|
|
|
class="addressBook-content"
|
|
|
|
v-if="state.addressBookCurrentTab == 'employeeAddressBook'"
|
|
|
|
>
|
|
|
|
<div class="addressBook-tree" v-if="!state.addressBookSearchNickName">
|
2025-05-12 05:55:14 +00:00
|
|
|
<fl-tree
|
|
|
|
:data="state.treeData"
|
|
|
|
:expandedKeys="state.expandedKeys"
|
|
|
|
:refreshCount="state.treeRefreshCount"
|
|
|
|
:clickKey="state.clickKey"
|
|
|
|
@triggerTreeClick="handleTreeClick"
|
|
|
|
></fl-tree>
|
|
|
|
</div>
|
2025-05-12 09:00:56 +00:00
|
|
|
<div class="addressBook-table">
|
|
|
|
<xNDataTable
|
|
|
|
:columns="state.addressBookColumns"
|
|
|
|
:data="state.addressBookData"
|
|
|
|
:style="{
|
|
|
|
height: `${state.addressBookTableHeight}px`,
|
|
|
|
width: `${state.addressBookTableWidth}px`
|
|
|
|
}"
|
|
|
|
flex-height
|
|
|
|
></xNDataTable>
|
|
|
|
<div class="addressBook-pagination">
|
|
|
|
<n-pagination
|
|
|
|
v-model:page="state.addressBookPage"
|
|
|
|
v-model:page-size="state.addressBookPageSize"
|
|
|
|
:item-count="state.addressBookTotal"
|
|
|
|
show-quick-jumper
|
|
|
|
show-size-picker
|
|
|
|
:page-sizes="[10, 20, 50]"
|
|
|
|
:on-update:page="handleAddressBookPagination"
|
|
|
|
:on-update:page-size="handleAddressBookPaginationSize"
|
|
|
|
>
|
|
|
|
<template #prefix="{ itemCount }"> 共 {{ itemCount }} 条记录 </template>
|
|
|
|
</n-pagination>
|
|
|
|
</div>
|
|
|
|
</div>
|
2025-05-12 05:55:14 +00:00
|
|
|
</div>
|
2025-05-13 06:08:20 +00:00
|
|
|
<div class="groupChatList-content" v-if="state.addressBookCurrentTab == 'groupChatList'">
|
|
|
|
<div class="groupChatList-table">
|
|
|
|
<xNDataTable
|
|
|
|
:columns="state.groupChatListColumns"
|
|
|
|
:data="state.groupChatListData"
|
|
|
|
:style="{
|
|
|
|
height: '523px',
|
|
|
|
width: '1148px'
|
|
|
|
}"
|
|
|
|
flex-height
|
|
|
|
></xNDataTable>
|
|
|
|
<div class="groupChatList-pagination">
|
|
|
|
<n-pagination
|
|
|
|
v-model:page="state.groupChatListPage"
|
|
|
|
v-model:page-size="state.groupChatListPageSize"
|
|
|
|
:item-count="state.groupChatListTotal"
|
|
|
|
show-quick-jumper
|
|
|
|
show-size-picker
|
|
|
|
:page-sizes="[10, 20, 50]"
|
|
|
|
:on-update:page="handleGroupChatListPagination"
|
|
|
|
:on-update:page-size="handleGroupChatListPaginationSize"
|
|
|
|
>
|
|
|
|
<template #prefix="{ itemCount }"> 共 {{ itemCount }} 条记录 </template>
|
|
|
|
</n-pagination>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2025-05-12 05:55:14 +00:00
|
|
|
</n-card>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</customModal>
|
2025-05-14 09:22:25 +00:00
|
|
|
|
|
|
|
<customModal
|
|
|
|
v-model:show="state.isShowSearchRecordModal"
|
|
|
|
title="搜索聊天记录"
|
|
|
|
:style="state.customSearchRecordModalStyle"
|
|
|
|
:customCloseBtn="true"
|
|
|
|
:closable="false"
|
2025-05-21 03:41:03 +00:00
|
|
|
:customCloseEvent="true"
|
|
|
|
@customCloseModal="handleCloseSearchRecordModal"
|
2025-05-14 09:22:25 +00:00
|
|
|
>
|
|
|
|
<template #content>
|
|
|
|
<div class="search-record-modal-content">
|
|
|
|
<n-card style="padding: 0 12px;">
|
|
|
|
<div class="search-record-input">
|
|
|
|
<span class="search-record-input-title">搜索</span>
|
|
|
|
<n-input
|
|
|
|
type="text"
|
|
|
|
v-model:value="state.searchRecordText"
|
|
|
|
placeholder="请输入"
|
|
|
|
clearable
|
|
|
|
>
|
|
|
|
<template #clear-icon>
|
|
|
|
<img src="@/assets/image/icon/close-btn-grey-line.png" alt="close" />
|
|
|
|
</template>
|
|
|
|
</n-input>
|
|
|
|
</div>
|
|
|
|
<div class="search-record-card" v-if="state.searchRecordText">
|
2025-05-20 11:58:16 +00:00
|
|
|
<div class="search-record-list">
|
2025-05-14 09:22:25 +00:00
|
|
|
<chatAppSearchList
|
2025-05-15 10:56:41 +00:00
|
|
|
ref="searchListRef"
|
2025-05-14 09:22:25 +00:00
|
|
|
:searchResultPageSize="10"
|
|
|
|
:listLimit="false"
|
|
|
|
:apiRequest="ServeQueryTalkRecord"
|
2025-05-20 11:58:16 +00:00
|
|
|
:apiParams="state.searchList.apiParams"
|
|
|
|
:searchText="state.searchList.searchText"
|
2025-05-14 09:22:25 +00:00
|
|
|
:isPagination="true"
|
|
|
|
searchResultKey="general_infos"
|
2025-05-15 10:56:41 +00:00
|
|
|
@clickSearchItem="handleClickSearchItem"
|
|
|
|
:useClickStay="true"
|
|
|
|
@clickStayItemChange="handleClickStayItemChange"
|
2025-05-20 11:58:16 +00:00
|
|
|
@lastIdChange="handleSearchListLastIdChange"
|
|
|
|
:searchResultMaxHeight="'517px'"
|
2025-05-29 10:04:16 +00:00
|
|
|
:selectItemInList="state.selectItemInList"
|
2025-05-14 09:22:25 +00:00
|
|
|
></chatAppSearchList>
|
|
|
|
</div>
|
2025-05-20 11:58:16 +00:00
|
|
|
<div class="search-record-detail">
|
2025-05-21 03:41:03 +00:00
|
|
|
<div class="search-record-detail-header" v-if="state.isShowSearchRecordDetailInfo">
|
|
|
|
<HighlightText
|
|
|
|
class="text-[14px] text-[#B0B0B0] leading-[20px]"
|
|
|
|
:text="
|
|
|
|
state.searchDetailList.total +
|
|
|
|
'条与“' +
|
|
|
|
state.searchRecordText +
|
|
|
|
'”相关的搜索结果'
|
|
|
|
"
|
|
|
|
:searchText="state.searchRecordText"
|
|
|
|
/>
|
2025-05-22 07:24:13 +00:00
|
|
|
<div class="search-record-detail-header-btn" @click="handleEnterSearchResultChat">
|
2025-05-21 03:41:03 +00:00
|
|
|
<span>进入聊天</span>
|
|
|
|
<n-icon :component="Right" color="#46299D" size="14px" />
|
|
|
|
</div>
|
|
|
|
</div>
|
2025-05-14 09:22:25 +00:00
|
|
|
<chatAppSearchList
|
2025-05-15 10:56:41 +00:00
|
|
|
ref="searchDetailListRef"
|
|
|
|
v-if="state.isShowSearchRecordDetailInfo"
|
2025-05-14 09:22:25 +00:00
|
|
|
:searchResultPageSize="10"
|
|
|
|
:listLimit="false"
|
|
|
|
:apiRequest="ServeQueryTalkRecord"
|
2025-05-20 11:58:16 +00:00
|
|
|
:apiParams="state.searchDetailList.apiParams"
|
|
|
|
:searchText="state.searchDetailList.searchText"
|
2025-05-14 09:22:25 +00:00
|
|
|
:isPagination="true"
|
|
|
|
:searchRecordDetail="true"
|
2025-05-20 11:58:16 +00:00
|
|
|
@lastIdChange="handleSearchDetailListLastIdChange"
|
2025-05-21 03:41:03 +00:00
|
|
|
:searchResultMaxHeight="'469px'"
|
|
|
|
@resultTotalCount="getResultTotalCount"
|
2025-05-22 07:24:13 +00:00
|
|
|
@clickSearchItem="handleClickSearchResultItem"
|
2025-05-14 09:22:25 +00:00
|
|
|
></chatAppSearchList>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="search-record-empty" v-if="!state.searchRecordText">
|
|
|
|
<img src="@/assets/image/chatList/search-empty.png" alt="" />
|
|
|
|
<span>暂无搜索内容</span>
|
|
|
|
</div>
|
|
|
|
</n-card>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</customModal>
|
2024-12-24 08:14:21 +00:00
|
|
|
</template>
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
.header-tools {
|
|
|
|
height: 60px;
|
|
|
|
flex-shrink: 0;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: row;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: space-around;
|
|
|
|
padding: 0 8px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.header-badge {
|
|
|
|
height: 38px;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: space-between;
|
|
|
|
padding-left: 10px;
|
|
|
|
|
|
|
|
&.shadow {
|
|
|
|
box-shadow: 0 2px 6px 0 rgb(31 35 41 / 5%);
|
|
|
|
}
|
|
|
|
|
|
|
|
.unread {
|
|
|
|
background-color: #ff4d4f;
|
|
|
|
color: white;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.header-top {
|
|
|
|
padding: 5px 8px;
|
|
|
|
padding-right: 0;
|
|
|
|
padding-right: 8px;
|
|
|
|
-webkit-justify-content: space-between;
|
|
|
|
-ms-flex-pack: justify;
|
|
|
|
justify-content: space-between;
|
|
|
|
grid-gap: 0 14px;
|
|
|
|
grid-template-columns: repeat(auto-fill, 32px);
|
|
|
|
display: grid;
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
|
|
.top-item {
|
|
|
|
flex-basis: 46px;
|
|
|
|
flex-shrink: 0;
|
|
|
|
height: 56px;
|
|
|
|
margin: 3px 2px 3px 2px;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
justify-content: space-between;
|
|
|
|
align-items: center;
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
.icon-mark {
|
|
|
|
position: absolute;
|
|
|
|
height: 25px;
|
|
|
|
width: 25px;
|
|
|
|
font-size: 14px;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
right: -12px;
|
|
|
|
bottom: 15px;
|
|
|
|
transform: scale(0.6);
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
|
|
&.group {
|
|
|
|
color: #3370ff;
|
|
|
|
background-color: #e1eaff;
|
|
|
|
}
|
|
|
|
|
|
|
|
&.robot {
|
|
|
|
color: #dc9b04 !important;
|
|
|
|
background-color: #faf1d1 !important;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
&.active {
|
|
|
|
.text {
|
|
|
|
color: rgb(80 138 254);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.text {
|
|
|
|
display: inline-block;
|
|
|
|
height: 20px;
|
|
|
|
font-size: 12px;
|
|
|
|
transform: scale(0.9);
|
|
|
|
text-align: center;
|
|
|
|
line-height: 20px;
|
|
|
|
word-break: break-all;
|
|
|
|
overflow: hidden;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
html[theme-mode='dark'] {
|
|
|
|
.header-badge {
|
|
|
|
&.shadow {
|
|
|
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2025-05-12 05:55:14 +00:00
|
|
|
|
|
|
|
.custom-modal-content {
|
|
|
|
box-sizing: border-box;
|
|
|
|
width: 100%;
|
|
|
|
padding: 0 12px;
|
2025-05-13 06:08:20 +00:00
|
|
|
:deep(.n-tabs-tab--active) {
|
2025-05-13 11:05:42 +00:00
|
|
|
color: #46299d !important;
|
2025-05-13 06:08:20 +00:00
|
|
|
}
|
2025-05-12 05:55:14 +00:00
|
|
|
.addressBook-content {
|
2025-05-12 09:00:56 +00:00
|
|
|
display: flex;
|
|
|
|
flex-direction: row;
|
|
|
|
gap: 20px;
|
2025-05-12 05:55:14 +00:00
|
|
|
.addressBook-tree {
|
|
|
|
width: 328px;
|
|
|
|
height: 524px;
|
|
|
|
overflow: auto;
|
|
|
|
border: 1px solid #efeff5;
|
|
|
|
border-radius: 4px;
|
|
|
|
padding: 12px 20px;
|
|
|
|
box-sizing: border-box;
|
|
|
|
}
|
2025-05-12 09:00:56 +00:00
|
|
|
.addressBook-table {
|
|
|
|
:deep(.n-data-table-th) {
|
|
|
|
background-color: #46299d;
|
|
|
|
color: #fff;
|
|
|
|
}
|
|
|
|
.addressBook-pagination {
|
|
|
|
display: flex;
|
|
|
|
justify-content: flex-end;
|
|
|
|
align-items: center;
|
|
|
|
padding: 22px 0 0;
|
|
|
|
box-sizing: border-box;
|
|
|
|
}
|
|
|
|
}
|
2025-05-12 05:55:14 +00:00
|
|
|
}
|
2025-05-13 06:08:20 +00:00
|
|
|
.groupChatList-content {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: row;
|
|
|
|
gap: 20px;
|
|
|
|
.groupChatList-table {
|
|
|
|
:deep(.n-data-table-th) {
|
|
|
|
background-color: #46299d;
|
|
|
|
color: #fff;
|
|
|
|
}
|
|
|
|
.groupChatList-pagination {
|
|
|
|
display: flex;
|
|
|
|
justify-content: flex-end;
|
|
|
|
align-items: center;
|
|
|
|
padding: 22px 0 0;
|
|
|
|
box-sizing: border-box;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2025-05-12 05:55:14 +00:00
|
|
|
}
|
2025-05-14 09:22:25 +00:00
|
|
|
|
|
|
|
.search-record-modal-content {
|
|
|
|
box-sizing: border-box;
|
|
|
|
width: 100%;
|
|
|
|
padding: 0 12px;
|
|
|
|
:deep(.n-card) {
|
|
|
|
border: 0;
|
|
|
|
box-shadow: 0 3px 6px 1px rgba(188, 188, 188, 0.18);
|
|
|
|
}
|
|
|
|
.search-record-input {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
.search-record-input-title {
|
|
|
|
width: 78px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.search-record-card {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: row;
|
|
|
|
gap: 20px;
|
|
|
|
padding: 28px 0 0;
|
|
|
|
.search-record-list {
|
|
|
|
width: 260px;
|
|
|
|
height: 517px;
|
|
|
|
border: 1px solid #efeff5;
|
|
|
|
}
|
|
|
|
.search-record-detail {
|
|
|
|
width: 578px;
|
|
|
|
height: 517px;
|
|
|
|
border: 1px solid #efeff5;
|
2025-05-21 03:41:03 +00:00
|
|
|
.search-record-detail-header {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: space-between;
|
|
|
|
padding: 14px 4px 14px 10px;
|
|
|
|
box-sizing: border-box;
|
|
|
|
.search-record-detail-header-btn {
|
|
|
|
line-height: 20px;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: row;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: flex-end;
|
|
|
|
gap: 8px;
|
|
|
|
cursor: pointer;
|
|
|
|
span {
|
|
|
|
line-height: 20px;
|
|
|
|
color: #46299d;
|
|
|
|
font-size: 14px;
|
|
|
|
font-weight: 400;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2025-05-14 09:22:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
.search-record-empty {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
padding: 28px 0 0;
|
|
|
|
height: 519px;
|
|
|
|
img {
|
|
|
|
width: 160px;
|
|
|
|
height: 104px;
|
|
|
|
}
|
|
|
|
span {
|
|
|
|
font-size: 14px;
|
|
|
|
color: #999;
|
|
|
|
font-weight: 400;
|
|
|
|
margin: 13px 0 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-12-24 08:14:21 +00:00
|
|
|
</style>
|