Compare commits
15 Commits
db599dadb9
...
9487ae526b
Author | SHA1 | Date | |
---|---|---|---|
|
9487ae526b | ||
|
e3d61107cb | ||
8694921f25 | |||
62f5b458a5 | |||
2439562838 | |||
|
df80cd031e | ||
cecca6df9c | |||
19e4954484 | |||
115a3f1f10 | |||
|
c93023effa | ||
3eaac91ba8 | |||
9360ecaaf9 | |||
c39d5aea88 | |||
814eb44358 | |||
ed0737b5e3 |
1
components.d.ts
vendored
@ -61,6 +61,7 @@ declare module 'vue' {
|
||||
NoticeEditor: typeof import('./src/components/group/manage/NoticeEditor.vue')['default']
|
||||
NoticeTab: typeof import('./src/components/group/manage/NoticeTab.vue')['default']
|
||||
NotificationApi: typeof import('./src/components/common/NotificationApi.vue')['default']
|
||||
NPopover: typeof import('naive-ui')['NPopover']
|
||||
NRadio: typeof import('naive-ui')['NRadio']
|
||||
NSpin: typeof import('naive-ui')['NSpin']
|
||||
NTag: typeof import('naive-ui')['NTag']
|
||||
|
@ -89,3 +89,8 @@ export const ServeSendVote = (data = {}) => {
|
||||
export const ServeConfirmVoteHandle = (data = {}) => {
|
||||
return post('/api/v1/talk/message/vote/handle', data)
|
||||
}
|
||||
|
||||
//清空聊天记录
|
||||
export const ServeEmptyMessage = (data) => {
|
||||
return post('/api/v1/talk/message/empty', data)
|
||||
}
|
||||
|
@ -77,6 +77,11 @@ export const ServeEditGroupNotice = (data) => {
|
||||
return post('/api/v1/group/notice/edit', data)
|
||||
}
|
||||
|
||||
// 删除群公告
|
||||
export const ServeDeleteGroupNotice = (data) => {
|
||||
return post('/api/v1/group/notice/delete', data)
|
||||
}
|
||||
|
||||
export const ServeGetGroupApplyList = (data) => {
|
||||
return get('/api/v1/group/apply/list', data)
|
||||
}
|
||||
|
26
src/api/search.js
Normal file
@ -0,0 +1,26 @@
|
||||
import { post, get, upload } from '@/utils/request'
|
||||
|
||||
//ES搜索-主页搜索什么都有、指定用户、指定群、群与用户概览
|
||||
export const ServeSeachQueryAll = (data = {}) => {
|
||||
return post('/api/v1/elasticsearch/query-all', data)
|
||||
}
|
||||
|
||||
//ES搜索聊天记录-主页搜索什么都有、聊天记录
|
||||
export const ServeQueryTalkRecord = (data = {}) => {
|
||||
return post('/api/v1/elasticsearch/query-talk-record', data)
|
||||
}
|
||||
|
||||
//查看存在聊天记录的天数
|
||||
export const ServeTalkDate = (data) => {
|
||||
return post('/api/v1/talk/date', data)
|
||||
}
|
||||
|
||||
//获取会话Id
|
||||
export const ServeGetSessionId = (data) => {
|
||||
return post('/api/v1/talk/session/getId', data)
|
||||
}
|
||||
|
||||
//获取用户所在群聊列表
|
||||
export const ServeUserGroupChatList = (data) => {
|
||||
return post('/api/v1/group/user/list', data)
|
||||
}
|
@ -29,3 +29,8 @@ export const ServeGetUserDetail = () => {
|
||||
export const ServeGetUserSetting = () => {
|
||||
return get('/api/v1/users/setting')
|
||||
}
|
||||
|
||||
//根据erpUserId查询聊天系统用户详情
|
||||
export const getUserInfoByERPUserId = (data) => {
|
||||
return post('/api/v1/users/info', data)
|
||||
}
|
||||
|
BIN
src/assets/image/chatList/chat-settings.png
Normal file
After Width: | Height: | Size: 657 B |
BIN
src/assets/image/chatList/search-empty.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
src/assets/image/chatSettings/edit-btn.png
Normal file
After Width: | Height: | Size: 337 B |
BIN
src/assets/image/chatSettings/edit-cancel.png
Normal file
After Width: | Height: | Size: 486 B |
BIN
src/assets/image/chatSettings/edit-confirm.png
Normal file
After Width: | Height: | Size: 473 B |
BIN
src/assets/image/icon/close-btn-grey-line.png
Normal file
After Width: | Height: | Size: 286 B |
BIN
src/assets/image/icon/search-grey.png
Normal file
After Width: | Height: | Size: 436 B |
@ -16,22 +16,26 @@
|
||||
</div>
|
||||
</template>
|
||||
<slot name="content"></slot>
|
||||
<template #footer v-if="actionBtns.cancelBtn || actionBtns.confirmBtn">
|
||||
<div class="custom-modal-btns">
|
||||
<template #footer v-if="actionBtns?.cancelBtn || actionBtns?.confirmBtn">
|
||||
<div
|
||||
class="custom-modal-btns"
|
||||
:style="props?.customModalBtnsStyle ? props.customModalBtnsStyle : ''"
|
||||
>
|
||||
<customBtn
|
||||
color="#C7C7C9"
|
||||
style="width: 161px; height: 34px;"
|
||||
@click="handleCancel"
|
||||
v-if="actionBtns.cancelBtn"
|
||||
>取消</customBtn
|
||||
v-if="actionBtns?.cancelBtn"
|
||||
>{{ actionBtns?.cancelBtn?.text || '取消' }}</customBtn
|
||||
>
|
||||
<customBtn
|
||||
color="#46299D"
|
||||
style="width: 161px; height: 34px;"
|
||||
@click="handleConfirm"
|
||||
:loading="state.confirmBtnLoading"
|
||||
v-if="actionBtns.confirmBtn"
|
||||
>确定</customBtn
|
||||
:disabled="actionBtns?.confirmBtn?.disabled"
|
||||
:loading="state.confirmBtnLoading && actionBtns?.confirmBtn?.doLoading"
|
||||
v-if="actionBtns?.confirmBtn"
|
||||
>{{ actionBtns?.confirmBtn?.text || '确定' }}</customBtn
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
@ -63,6 +67,16 @@ const props = defineProps({
|
||||
// 是否显示自定义关闭按钮
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
customModalBtnsStyle: {
|
||||
// 自定义按钮样式
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
customCloseEvent: {
|
||||
// 是否自定义关闭事件
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
@ -74,12 +88,16 @@ const show = computed({
|
||||
})
|
||||
|
||||
const handleCancel = () => {
|
||||
if (props.actionBtns?.cancelBtn?.hideModal) {
|
||||
show.value = false
|
||||
}
|
||||
emit('cancel')
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
if (props.actionBtns?.confirmBtn?.doLoading) {
|
||||
state.confirmBtnLoading = true
|
||||
}
|
||||
emit('confirm', closeLoading)
|
||||
}
|
||||
|
||||
@ -92,8 +110,12 @@ const state = reactive({
|
||||
})
|
||||
|
||||
const handleCloseModal = () => {
|
||||
if (props.customCloseEvent) {
|
||||
emit('closeModal')
|
||||
} else {
|
||||
show.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
@ -1,33 +1,59 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive, computed, watch, ref } from 'vue'
|
||||
import { NEmpty, NPopover, NPopconfirm } from 'naive-ui'
|
||||
import { useUserStore } from '@/store'
|
||||
import { NEmpty, NPopover, NPopconfirm, NSwitch, NIcon, NInput, NScrollbar } from 'naive-ui'
|
||||
import { useUserStore, useTalkStore, useDialogueStore } from '@/store'
|
||||
import GroupLaunch from './GroupLaunch.vue'
|
||||
import GroupManage from './manage/index.vue'
|
||||
import { Comment, Search, Close, Plus } from '@icon-park/vue-next'
|
||||
import { Comment, Search, Close, Plus, Down, Up } from '@icon-park/vue-next'
|
||||
import {
|
||||
ServeGroupDetail,
|
||||
ServeGetGroupMembers,
|
||||
ServeSecedeGroup,
|
||||
ServeUpdateGroupCard
|
||||
ServeUpdateGroupCard,
|
||||
ServeGetGroupNotices,
|
||||
ServeEditGroup
|
||||
} from '@/api/group'
|
||||
import { useInject } from '@/hooks'
|
||||
import customModal from '@/components/common/customModal.vue'
|
||||
import avatarModule from '@/components/avatar-module/index.vue'
|
||||
import UserCardModal from '@/components/user/UserCardModal.vue'
|
||||
import { ServeEmptyMessage } from '@/api/chat'
|
||||
import { parseTime } from '@/utils/datetime'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const talkStore = useTalkStore()
|
||||
const dialogueStore = useDialogueStore()
|
||||
const { showUserInfoModal } = useInject()
|
||||
|
||||
const emit = defineEmits(['close', 'to-talk'])
|
||||
const emit = defineEmits([
|
||||
'close',
|
||||
'to-talk',
|
||||
'handleSearchRecordByConditionModalShow',
|
||||
'handleGroupNoticeModalShow'
|
||||
])
|
||||
const props = defineProps({
|
||||
gid: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
talkType: {
|
||||
// 1: 单聊, 2: 群聊
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
groupNoticeContentChange: {
|
||||
// 群公告内容变化
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
watch(props, () => {
|
||||
if (props.talkType === 2) {
|
||||
loadDetail()
|
||||
loadMembers()
|
||||
getGroupNotices()
|
||||
}
|
||||
})
|
||||
|
||||
const editCardPopover = ref(false)
|
||||
@ -40,7 +66,8 @@ const state = reactive({
|
||||
name: '',
|
||||
profile: '',
|
||||
visit_card: '',
|
||||
notice: ''
|
||||
notice: '',
|
||||
group_type: 0
|
||||
},
|
||||
remark: '',
|
||||
isShowModal: false, //是否显示提示模态框
|
||||
@ -51,14 +78,32 @@ const state = reactive({
|
||||
chatSettingOperateHint: '', // 提示信息
|
||||
chatSettingOperateSubHint: '', // 次要提示信息
|
||||
actionBtns: {
|
||||
confirmBtn: true,
|
||||
cancelBtn: true
|
||||
confirmBtn: {
|
||||
doLoading: true
|
||||
},
|
||||
cancelBtn: {
|
||||
hideModal: true
|
||||
}
|
||||
}, // 操作按钮
|
||||
showAllMember: false, // 是否显示全部成员
|
||||
openGroupMemberSearch: false, //是否开启群成员搜索
|
||||
isShowUserCardModal: false, //是否显示成员信息模态框
|
||||
userInfo: {}, //当前打开的成员信息卡信息
|
||||
groupNoticeInfo: {
|
||||
id: 0,
|
||||
avatar: '',
|
||||
updater_name: '',
|
||||
updated_at: '',
|
||||
content: ''
|
||||
}, //群公告信息
|
||||
editGroupName: false, //是否编辑群名称
|
||||
editGroupNameValue: '', //编辑中的群名称
|
||||
chatSettingOperateType: '' //聊天设置操作类型
|
||||
})
|
||||
|
||||
const members = ref<any[]>([])
|
||||
|
||||
const search = computed<any[]>(() => {
|
||||
const groupMemberList = computed<any[]>(() => {
|
||||
if (state.keywords) {
|
||||
return members.value.filter((item: any) => {
|
||||
return (
|
||||
@ -105,6 +150,7 @@ function loadDetail() {
|
||||
state.detail.name = result.group_name
|
||||
state.detail.profile = result.profile
|
||||
state.detail.visit_card = result.visit_card
|
||||
state.detail.group_type = result.group_type
|
||||
state.remark = result.visit_card
|
||||
|
||||
if (result.notice) {
|
||||
@ -122,7 +168,7 @@ function loadMembers() {
|
||||
group_id: props.gid
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
members.value = res.data.items || []
|
||||
members.value = res.data.sortItems || []
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -162,30 +208,53 @@ const onChangeRemark = () => {
|
||||
})
|
||||
}
|
||||
|
||||
loadDetail()
|
||||
loadMembers()
|
||||
|
||||
// 处理模态框的确认
|
||||
const handleModalConfirm = (closeLoading) => {
|
||||
setTimeout(() => {
|
||||
if (state.chatSettingOperateType == 'clear') {
|
||||
//清空聊天记录
|
||||
ServeEmptyMessage({
|
||||
talk_type: props.talkType,
|
||||
receiver_id: props.gid
|
||||
})
|
||||
.then((res) => {
|
||||
closeLoading()
|
||||
state.isShowModal = false
|
||||
}, 2000)
|
||||
if (res.code == 200) {
|
||||
window['$message'].success('聊天记录清空成功')
|
||||
//热更新清除会话记录及会话列表中的最近消息展示
|
||||
dialogueStore.clearDialogueRecord()
|
||||
useTalkStore().updateItem({
|
||||
index_name: props.talkType + '_' + props.gid,
|
||||
msg_text: '...',
|
||||
updated_at: parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}')
|
||||
})
|
||||
} else {
|
||||
window['$message'].error(res.message)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
closeLoading()
|
||||
window['$message'].error(err.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//显示聊天设置操作提示模态框
|
||||
const showChatSettingOperateModal = (type: string) => {
|
||||
state.isShowModal = true
|
||||
state.chatSettingOperateType = type
|
||||
switch (type) {
|
||||
case 'clear':
|
||||
state.chatSettingOperateHint = '确定清空聊天记录'
|
||||
state.chatSettingOperateSubHint = ''
|
||||
break
|
||||
case 'dismiss':
|
||||
state.chatSettingOperateHint = '确定解散本群'
|
||||
state.chatSettingOperateSubHint = ''
|
||||
break
|
||||
case 'quit':
|
||||
state.chatSettingOperateHint = '确定退出群聊'
|
||||
const findAdmin = search.value.find((item) => item.leader === 2 || item.leader === 1)
|
||||
const findAdmin = groupMemberList.value.find((item) => item.leader === 2 || item.leader === 1)
|
||||
const isLastAdmin = findAdmin && findAdmin.user_id === userStore.uid
|
||||
if (isLastAdmin) {
|
||||
state.chatSettingOperateSubHint = '退出后,本群将被解散'
|
||||
@ -195,12 +264,127 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
//点击显示查找聊天记录模态框
|
||||
const showSearchRecordByConditionModal = () => {
|
||||
emit('handleSearchRecordByConditionModalShow', true)
|
||||
}
|
||||
|
||||
//根据群类型返回群类型文本
|
||||
const groupTypeText = computed(() => {
|
||||
let groupTypeText_ = ''
|
||||
switch (state.detail.group_type) {
|
||||
case 1:
|
||||
groupTypeText_ = '普通群'
|
||||
break
|
||||
case 2:
|
||||
groupTypeText_ = '部门群'
|
||||
break
|
||||
case 3:
|
||||
groupTypeText_ = '项目群'
|
||||
break
|
||||
case 4:
|
||||
groupTypeText_ = '公司群'
|
||||
}
|
||||
return groupTypeText_
|
||||
})
|
||||
|
||||
//取消搜索群成员
|
||||
const cancelSearch = () => {
|
||||
state.openGroupMemberSearch = false
|
||||
state.keywords = ''
|
||||
}
|
||||
|
||||
//点击显示成员信息
|
||||
const showMemberInfo = (memberItem: any) => {
|
||||
state.userInfo = memberItem
|
||||
state.isShowUserCardModal = true
|
||||
}
|
||||
|
||||
//点击显示群公告模态框
|
||||
const showGroupNoticeModal = () => {
|
||||
emit('handleGroupNoticeModalShow', isAdmin.value || isLeader.value)
|
||||
}
|
||||
|
||||
//获取群公告列表
|
||||
const getGroupNotices = () => {
|
||||
ServeGetGroupNotices({
|
||||
group_id: props.gid
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.code == 200) {
|
||||
if (res?.data?.items[0]?.id) {
|
||||
state.groupNoticeInfo = res.data.items[0]
|
||||
} else {
|
||||
state.groupNoticeInfo = {
|
||||
id: 0,
|
||||
avatar: '',
|
||||
updater_name: '',
|
||||
updated_at: '',
|
||||
content: ''
|
||||
}
|
||||
}
|
||||
} else {
|
||||
window['$message'].warning(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (props.talkType === 2) {
|
||||
loadDetail()
|
||||
loadMembers()
|
||||
getGroupNotices()
|
||||
}
|
||||
|
||||
//点击编辑群名称
|
||||
const handleEditGroupName = () => {
|
||||
state.editGroupName = true
|
||||
state.editGroupNameValue = state.detail.name
|
||||
}
|
||||
|
||||
//取消编辑群名称
|
||||
const handleEditGroupNameCancel = () => {
|
||||
state.editGroupName = false
|
||||
state.editGroupNameValue = ''
|
||||
}
|
||||
|
||||
//确认修改群名称
|
||||
const handleEditGroupNameConfirm = () => {
|
||||
if (!state.editGroupNameValue.trim()) {
|
||||
window['$message'].warning('群名称不能为空')
|
||||
return
|
||||
}
|
||||
ServeEditGroup({
|
||||
group_id: props.gid,
|
||||
group_name: state.editGroupNameValue,
|
||||
avatar: state.detail.avatar,
|
||||
profile: state.detail.profile
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
window['$message'].success('群名称修改成功')
|
||||
state.detail.name = state.editGroupNameValue
|
||||
state.editGroupName = false
|
||||
//热更新会话列表中的群名
|
||||
talkStore.updateItem({
|
||||
index_name: props.talkType + '_' + props.gid,
|
||||
name: state.editGroupNameValue
|
||||
})
|
||||
//热更新会话详情中的群名
|
||||
dialogueStore.setTalkInfoPartially({
|
||||
username: state.editGroupNameValue
|
||||
})
|
||||
} else {
|
||||
window['$message'].error(res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<section class="el-container is-vertical section">
|
||||
<header class="el-header header bdr-b">
|
||||
<div class="left-icon" @click="emit('to-talk')">
|
||||
<n-icon size="21" :component="Comment" />
|
||||
<header class="el-header header">
|
||||
<!-- <div class="left-icon" @click="emit('to-talk')"> -->
|
||||
<div class="left-icon" style="cursor: unset;">
|
||||
<!-- <n-icon size="21" :component="Comment" /> -->
|
||||
</div>
|
||||
<div class="center-text">
|
||||
<!-- <span>群信息</span> -->
|
||||
@ -213,20 +397,149 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
</header>
|
||||
|
||||
<main class="el-main main me-scrollbar me-scrollbar-thumb">
|
||||
<div class="info-box">
|
||||
<div class="b-box">
|
||||
<div class="block">
|
||||
<div class="info-box" v-if="talkType === 2">
|
||||
<div class="b-box" style="margin: 0 0 16px;">
|
||||
<div class="block" style="height: 34px;">
|
||||
<div class="title">群成员</div>
|
||||
<div class="text">{{ members.length }}人</div>
|
||||
<!-- <div class="text">{{ members.length }}人</div> -->
|
||||
<img
|
||||
v-if="!state.openGroupMemberSearch"
|
||||
src="@/assets/image/icon/search-grey.png"
|
||||
alt=""
|
||||
style="width: 16px; height: 16px; cursor: pointer;"
|
||||
@click="state.openGroupMemberSearch = true"
|
||||
/>
|
||||
<div class="group-member-search" v-if="state.openGroupMemberSearch">
|
||||
<n-input v-model:value="state.keywords" placeholder="请输入" style="width: 170px;" />
|
||||
<span @click="cancelSearch">取消</span>
|
||||
</div>
|
||||
<div class="describe">群主已开启“新成员入群可查看所有聊天记录</div>
|
||||
</div>
|
||||
<!-- <div class="describe">群主已开启“新成员入群可查看所有聊天记录</div> -->
|
||||
<div style="width: 100%;" :style="{ height: state.openGroupMemberSearch ? '656px' : '' }">
|
||||
<n-scrollbar :style="{ maxHeight: state.openGroupMemberSearch ? '656px' : '621px' }">
|
||||
<div class="group-member-list">
|
||||
<div
|
||||
v-for="(memberItem, memberIndex) in groupMemberList"
|
||||
:key="memberIndex"
|
||||
:class="
|
||||
!state.showAllMember && memberIndex >= 18 && !state.openGroupMemberSearch
|
||||
? 'group-member-list-each-box'
|
||||
: ''
|
||||
"
|
||||
>
|
||||
<div
|
||||
class="group-member-list-each"
|
||||
v-if="
|
||||
state.showAllMember ||
|
||||
(!state.showAllMember && memberIndex < 18 && !state.openGroupMemberSearch) ||
|
||||
state.openGroupMemberSearch
|
||||
"
|
||||
@click="showMemberInfo(memberItem)"
|
||||
>
|
||||
<div class="group-member-list-each-avatar">
|
||||
<avatarModule
|
||||
:mode="1"
|
||||
:avatar="memberItem.avatar"
|
||||
:userName="memberItem.nickname"
|
||||
:groupType="0"
|
||||
:customStyle="{
|
||||
width: '36px',
|
||||
height: '36px'
|
||||
}"
|
||||
:customTextStyle="{
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
color: '#fff',
|
||||
lineHeight: '17px'
|
||||
}"
|
||||
></avatarModule>
|
||||
<span
|
||||
class="group-member-list-each-admin-tag"
|
||||
v-if="memberItem.leader == 2 || memberItem.leader == 1"
|
||||
>管理员</span
|
||||
>
|
||||
</div>
|
||||
<span>{{ memberItem.nickname }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</n-scrollbar>
|
||||
<div
|
||||
class="group-member-list-more"
|
||||
v-if="
|
||||
!state.showAllMember && !state.openGroupMemberSearch && groupMemberList.length > 18
|
||||
"
|
||||
@click="state.showAllMember = true"
|
||||
>
|
||||
<span>展开更多</span>
|
||||
<n-icon :component="Down" />
|
||||
</div>
|
||||
<div
|
||||
class="group-member-list-more"
|
||||
v-if="
|
||||
state.showAllMember && !state.openGroupMemberSearch && groupMemberList.length > 18
|
||||
"
|
||||
@click="state.showAllMember = false"
|
||||
>
|
||||
<span>收起</span>
|
||||
<n-icon :component="Up" />
|
||||
</div>
|
||||
<div
|
||||
style="cursor: unset;"
|
||||
class="group-member-list-more"
|
||||
v-if="groupMemberList.length <= 18 && !state.openGroupMemberSearch"
|
||||
>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="b-box" :style="{ margin: state.editGroupName ? '-8px 0 -6px' : '16px 0 32px' }">
|
||||
<div class="block">
|
||||
<div class="title" :style="{ margin: state.editGroupName ? '2px 0 0' : '' }">
|
||||
群名称
|
||||
</div>
|
||||
<div class="group-name-box" v-if="!state.editGroupName">
|
||||
<span>{{ state.detail.name }}</span>
|
||||
<img
|
||||
src="@/assets/image/chatSettings/edit-btn.png"
|
||||
alt=""
|
||||
v-if="isAdmin || isLeader"
|
||||
@click="handleEditGroupName"
|
||||
/>
|
||||
</div>
|
||||
<div class="group-name-box" v-if="state.editGroupName">
|
||||
<n-input
|
||||
v-model:value="state.editGroupNameValue"
|
||||
placeholder="请输入"
|
||||
style="width: 302px;"
|
||||
clearable
|
||||
/>
|
||||
<img
|
||||
src="@/assets/image/chatSettings/edit-cancel.png"
|
||||
alt=""
|
||||
@click="handleEditGroupNameCancel"
|
||||
/>
|
||||
<img
|
||||
src="@/assets/image/chatSettings/edit-confirm.png"
|
||||
alt=""
|
||||
@click="handleEditGroupNameConfirm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="describe">{{ state.detail.name }}</div> -->
|
||||
</div>
|
||||
|
||||
<div class="b-box">
|
||||
<div class="block">
|
||||
<div class="title">群名称</div>
|
||||
<div class="title">群类型</div>
|
||||
<div class="group-name-box">
|
||||
<span>{{ groupTypeText }}</span>
|
||||
</div>
|
||||
<div class="describe">{{ state.detail.name }}</div>
|
||||
</div>
|
||||
<!-- <div class="describe">
|
||||
{{ '暂无群类型' }}
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- <div class="b-box">
|
||||
@ -263,28 +576,43 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
{{ state.detail.profile ? state.detail.profile : '暂无群简介' }}
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="b-box">
|
||||
<div class="block">
|
||||
<div class="title">群类型</div>
|
||||
</div>
|
||||
<div class="describe">
|
||||
{{ '暂无群类型' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="b-box">
|
||||
<div class="block">
|
||||
<div class="b-box b-box-bottomBorder" style="padding: 0 0 16px; margin: 32px 0 16px;">
|
||||
<div class="block" @click="showGroupNoticeModal" style="cursor: pointer;">
|
||||
<div class="title">群公告</div>
|
||||
<!-- <div class="text"> -->
|
||||
<!-- <n-button type="primary" text> 更多 </n-button> -->
|
||||
<img class="icon-right" src="@/assets/image/icon/arrow-right-grey.png" alt="" />
|
||||
<!-- </div> -->
|
||||
</div>
|
||||
<div class="describe">管理员未设置</div>
|
||||
<div class="describe">{{ state.groupNoticeInfo?.content || '管理员未设置' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="member-box">
|
||||
<div class="info-box">
|
||||
<div class="b-box b-box-bottomBorder" style="margin: 16px 0 0; padding: 0 0 16px;">
|
||||
<div class="block" @click="showSearchRecordByConditionModal" style="cursor: pointer;">
|
||||
<div class="title">查找聊天记录</div>
|
||||
<img class="icon-right" src="@/assets/image/icon/arrow-right-grey.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="b-box" style="margin: 16px 0 32px;">
|
||||
<div class="block">
|
||||
<div class="title">置顶会话</div>
|
||||
<n-switch />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="b-box" style="margin: 32px 0 20px;">
|
||||
<div class="block">
|
||||
<div class="title">消息免打扰</div>
|
||||
<n-switch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="member-box" v-if="talkType === 2">
|
||||
<div class="flex">
|
||||
<n-input placeholder="搜索" v-model:value="state.keywords" :clearable="true" round>
|
||||
<template #prefix>
|
||||
@ -306,7 +634,7 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
<div class="card">群名片</div>
|
||||
</div>
|
||||
|
||||
<div class="row pointer" v-for="item in search" :key="item.id" @click="onToInfo(item)">
|
||||
<div class="row pointer" v-for="item in groupMemberList" :key="item.id" @click="onToInfo(item)">
|
||||
<div class="avatar">
|
||||
<im-avatar :size="20" :src="item.avatar" :username="item.nickname" />
|
||||
</div>
|
||||
@ -320,7 +648,7 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-t20 pd-t20" v-if="search.length == 0">
|
||||
<div class="mt-t20 pd-t20" v-if="groupMemberList.length == 0">
|
||||
<n-empty size="200" description="暂无相关数据">
|
||||
<template #icon>
|
||||
<img src="@/assets/image/no-data.svg" alt="" />
|
||||
@ -328,9 +656,9 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
</n-empty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="chat-settings-btns">
|
||||
<div class="chat-settings-btns" v-if="talkType === 2">
|
||||
<n-button class="btn" type="error" ghost @click="showChatSettingOperateModal('clear')">
|
||||
清空聊天记录
|
||||
</n-button>
|
||||
@ -349,7 +677,10 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- <footer class="el-footer footer bdr-t"> -->
|
||||
<footer class="el-footer footer" v-if="talkType === 1">
|
||||
<n-button class="btn" type="error" ghost @click="showChatSettingOperateModal('clear')">
|
||||
清空聊天记录
|
||||
</n-button>
|
||||
<!-- <template v-if="!isAdmin">
|
||||
<n-popconfirm negative-text="取消" positive-text="确定" @positive-click="onSignOut">
|
||||
<template #trigger>
|
||||
@ -368,7 +699,7 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
>
|
||||
群聊管理
|
||||
</n-button> -->
|
||||
<!-- </footer> -->
|
||||
</footer>
|
||||
</section>
|
||||
|
||||
<GroupLaunch
|
||||
@ -397,6 +728,11 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
</div>
|
||||
</template>
|
||||
</customModal>
|
||||
|
||||
<UserCardModal
|
||||
v-model:show="state.isShowUserCardModal"
|
||||
v-model:uid="(state.userInfo as any).erp_user_id"
|
||||
/>
|
||||
</template>
|
||||
<style lang="less" scoped>
|
||||
.section {
|
||||
@ -404,8 +740,11 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
height: 100%;
|
||||
|
||||
.header {
|
||||
width: 100%;
|
||||
width: calc(100% - 40px);
|
||||
height: 60px;
|
||||
margin: 0 20px;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 2px solid #efeff2;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -419,13 +758,13 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
|
||||
.center-text {
|
||||
flex: auto;
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.left-icon,
|
||||
.right-icon {
|
||||
width: 50px;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
@ -437,14 +776,14 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 15px;
|
||||
padding: 7px 20px 15px;
|
||||
|
||||
.info-box {
|
||||
.b-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 30px;
|
||||
margin: 12px 0;
|
||||
// min-height: 30px;
|
||||
margin: 32px 0;
|
||||
flex-direction: column;
|
||||
|
||||
&:first-child {
|
||||
@ -471,6 +810,27 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.group-name-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 0 10px;
|
||||
|
||||
span {
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
color: #999999;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
// height: 100%;
|
||||
// line-height: 30px;
|
||||
@ -482,6 +842,23 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
width: 5px;
|
||||
height: 9px;
|
||||
}
|
||||
|
||||
.group-member-search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
width: 28px;
|
||||
display: inline-block;
|
||||
line-height: 20px;
|
||||
color: #46299d;
|
||||
font-weight: 400;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.describe {
|
||||
@ -496,7 +873,88 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #999999;
|
||||
margin: 10px 0 0;
|
||||
}
|
||||
|
||||
.group-member-list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px 24px;
|
||||
padding: 7px 0 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
.group-member-list-each {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
.group-member-list-each-avatar {
|
||||
position: relative;
|
||||
.group-member-list-each-admin-tag {
|
||||
font-size: 8px;
|
||||
font-weight: 400;
|
||||
line-height: 11px;
|
||||
color: #fff;
|
||||
background-color: #cf3050;
|
||||
border-radius: 8px;
|
||||
padding: 0px 6px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 36px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 17px;
|
||||
color: #999999;
|
||||
width: 48px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.group-member-list-each-box:nth-child(n + 19) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.group-member-list-more {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #f0f0f2;
|
||||
padding: 16px 0;
|
||||
span {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #747474;
|
||||
font-weight: 400;
|
||||
margin: 0 10px 0 0;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.group-member-list-more:hover {
|
||||
span {
|
||||
color: #46299d;
|
||||
}
|
||||
}
|
||||
}
|
||||
.b-box-bottomBorder {
|
||||
border-bottom: 1px solid #f0f0f2;
|
||||
}
|
||||
}
|
||||
|
||||
@ -568,11 +1026,13 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
gap: 30px;
|
||||
gap: 15px;
|
||||
.btn {
|
||||
width: calc(100% - 50px);
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
color: #CF3050;
|
||||
color: #cf3050;
|
||||
height: 46px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -580,10 +1040,17 @@ const showChatSettingOperateModal = (type: string) => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
height: 60px;
|
||||
padding: 15px;
|
||||
height: 86px;
|
||||
padding: 20px;
|
||||
.btn {
|
||||
width: 48%;
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
border-radius: 4px;
|
||||
:deep(.n-button__content) {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
993
src/components/search/searchByCondition.vue
Normal file
@ -0,0 +1,993 @@
|
||||
<template>
|
||||
<div class="outer-layer search-by-condition-page">
|
||||
<n-infinite-scroll style="height: 455px;" :distance="10">
|
||||
<div class="root">
|
||||
<div v-if="state.condition === 'dateTimePicker'" class="search-by-date">
|
||||
<n-date-picker
|
||||
:panel="true"
|
||||
type="datetime"
|
||||
:clearable="true"
|
||||
:first-day-of-week="6"
|
||||
:is-date-disabled="dateDisabled"
|
||||
:actions="['clear', 'confirm']"
|
||||
/>
|
||||
<!-- <tm-time-picker
|
||||
:show="state.showMonthPicker"
|
||||
:showDetail="{
|
||||
year: true,
|
||||
month: true,
|
||||
day: false,
|
||||
hour: false,
|
||||
minute: false,
|
||||
second: false,
|
||||
am_pm: false
|
||||
}"
|
||||
:showSuffix="{
|
||||
year: '',
|
||||
month: ''
|
||||
}"
|
||||
:defaultValue="state.nowDate"
|
||||
format="YYYY年MM月"
|
||||
start=""
|
||||
:end="state.maxDate"
|
||||
@confirm="confirmSelectedMonth"
|
||||
:round="0"
|
||||
:title="'请选择聊天日期'"
|
||||
>
|
||||
<div class="search-date-picker">
|
||||
<span class="text-[14px] font-regular">
|
||||
{{ state.selectedMonth }}
|
||||
</span>
|
||||
<img src="@/static/image/search/down-pointer.png" />
|
||||
</div>
|
||||
</tm-time-picker> -->
|
||||
<!-- <tm-calendar-view
|
||||
:show="true"
|
||||
:hideTool="true"
|
||||
:hideButton="true"
|
||||
:dateStyle="state.dateStyle"
|
||||
:defaultValue="state.selectedDateArray"
|
||||
v-model="state.selectedDateArray"
|
||||
:disabledDate="state.disabledDateArray"
|
||||
@click="selectDate"
|
||||
model="day"
|
||||
:end="state.maxDate"
|
||||
@getDArray="getDArray"
|
||||
:showDefault="false"
|
||||
></tm-calendar-view> -->
|
||||
</div>
|
||||
<div
|
||||
class="search-by-condition-input-list"
|
||||
v-if="
|
||||
state.condition === 'imgAndVideo' ||
|
||||
state.condition === 'file' ||
|
||||
state.condition === 'link' ||
|
||||
state.condition === 'member'
|
||||
"
|
||||
:style="{
|
||||
padding: state.condition === 'imgAndVideo' ? '20px 38px' : ''
|
||||
}"
|
||||
>
|
||||
<!-- <div
|
||||
class="search-by-condition-input"
|
||||
v-if="state.condition === 'file' || state.condition === 'link'"
|
||||
>
|
||||
<customInput
|
||||
:searchText="state.searchText"
|
||||
:first_talk_record_infos="state.first_talk_record_infos"
|
||||
@inputSearchText="inputSearchText"
|
||||
></customInput>
|
||||
<span
|
||||
@click="cancelSearch"
|
||||
class="search-by-condition-input-text text-[16px] font-medium"
|
||||
>
|
||||
取消
|
||||
</span>
|
||||
</div> -->
|
||||
<div class="search-by-condition-list">
|
||||
<div class="condition-dimensionality">
|
||||
<div
|
||||
class="condition-dimensionality-each"
|
||||
v-for="(conditionItem, conditionIndex) in state.searchResultList"
|
||||
:key="conditionIndex"
|
||||
>
|
||||
<div
|
||||
class="condition-dimensionality-each-month"
|
||||
v-if="state.condition === 'imgAndVideo'"
|
||||
>
|
||||
<span class="text-[14px] font-regular">
|
||||
{{ conditionItem.dateMonth }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="condition-each-resultList"
|
||||
:class="[
|
||||
state.condition === 'imgAndVideo' ? 'condition-type-imgAndVideo-result' : ''
|
||||
]"
|
||||
>
|
||||
<div
|
||||
class="condition-each-resultList-each"
|
||||
v-for="(item, index) in conditionItem.monthResultList"
|
||||
:key="index"
|
||||
:style="{
|
||||
border:
|
||||
state.condition === 'imgAndVideo' || state.condition === 'member'
|
||||
? '0'
|
||||
: '',
|
||||
padding: state.condition === 'imgAndVideo' ? '' : ''
|
||||
}"
|
||||
>
|
||||
<div class="condition-result-member" v-if="state.condition === 'member'">
|
||||
<searchItem
|
||||
@click="toDialogueByMember(item)"
|
||||
:searchResultKey="'search_by_member_condition'"
|
||||
:searchItem="item"
|
||||
:searchText="state.searchText"
|
||||
:searchRecordDetail="true"
|
||||
></searchItem>
|
||||
</div>
|
||||
<div
|
||||
class="condition-result-imgAndVideo"
|
||||
v-if="state.condition === 'imgAndVideo'"
|
||||
>
|
||||
<div
|
||||
class="condition-result-imgAndVideo-area condition-result-imgAndVideo-area-imgText"
|
||||
v-if="item?.extra?.items?.length > 0"
|
||||
>
|
||||
<n-scrollbar style="height: 131px;">
|
||||
<div
|
||||
class="condition-result-imgAndVideo-each"
|
||||
v-for="(imgItem, imgIndex) in item?.extra?.items"
|
||||
:key="imgIndex"
|
||||
>
|
||||
<n-image
|
||||
:src="imgItem?.content"
|
||||
v-if="imgItem?.type == 3"
|
||||
:lazy="true"
|
||||
:preview-src="imgItem?.content"
|
||||
:width="131"
|
||||
:height="131"
|
||||
object-fit="cover"
|
||||
></n-image>
|
||||
</div>
|
||||
</n-scrollbar>
|
||||
</div>
|
||||
<div class="condition-result-imgAndVideo-area" v-if="item?.extra?.url">
|
||||
<template v-if="item?.msg_type === 3">
|
||||
<n-image
|
||||
:src="item?.extra?.url"
|
||||
:lazy="true"
|
||||
:preview-src="item?.extra?.url"
|
||||
:width="131"
|
||||
:height="131"
|
||||
object-fit="cover"
|
||||
></n-image>
|
||||
</template>
|
||||
<template v-else-if="item?.msg_type === 5">
|
||||
<div class="video-preview" @click="onPlay(item?.extra?.url)">
|
||||
<video :src="item?.extra?.url" :controls="false"></video>
|
||||
<!-- <n-image
|
||||
:src="
|
||||
item?.extra?.url
|
||||
? item?.extra?.url + '#t=0.001'
|
||||
: item?.extra?.cover
|
||||
"
|
||||
:width="131"
|
||||
:height="131"
|
||||
object-fit="cover"
|
||||
></n-image> -->
|
||||
<div class="btn-video">
|
||||
<!-- <img :src="playCircle" /> -->
|
||||
<n-icon :component="Play" size="40" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div
|
||||
class="condition-each-result-main"
|
||||
v-if="state.condition === 'file' || state.condition === 'link'"
|
||||
>
|
||||
<searchItem :searchItem="item" :conditionType="state.msg_type"></searchItem>
|
||||
<span class="text-[12px] font-medium condition-each-result-main-date">
|
||||
{{ item.dateTime }}
|
||||
</span>
|
||||
</div> -->
|
||||
<div
|
||||
class="condition-each-result-attachments"
|
||||
@click="previewPDF(item)"
|
||||
v-if="state.condition === 'file' || state.condition === 'link'"
|
||||
>
|
||||
<div class="attachment-avatar">
|
||||
<img :src="item?.extra?.file_avatar" v-if="state.condition === 'file'" />
|
||||
<img
|
||||
src="@/static/image/search/result-link-icon.png"
|
||||
v-if="state.condition === 'link'"
|
||||
/>
|
||||
</div>
|
||||
<div class="attachment-info">
|
||||
<div class="attachment-info-title">
|
||||
<span class="text-[14px] font-regular" v-if="state.condition === 'file'">
|
||||
{{ item?.extra?.name }}
|
||||
</span>
|
||||
<span class="text-[14px] font-regular" v-if="state.condition === 'link'">
|
||||
分享链接
|
||||
</span>
|
||||
<span
|
||||
class="text-[14px] font-regular"
|
||||
v-if="state.condition === 'file'"
|
||||
style="color: #999999;"
|
||||
>
|
||||
{{ item.dateTime }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="attachment-sub-info"
|
||||
:style="{
|
||||
margin: state.condition === 'file' ? '10px 0 0' : ''
|
||||
}"
|
||||
>
|
||||
<!-- <span class="text-[12px] font-regular" v-if="state.condition === 'file'">
|
||||
{{ item?.extra?.typeText }}
|
||||
</span>
|
||||
<span class="text-[12px] font-regular" v-if="state.condition === 'link'">
|
||||
{{ item?.extra?.content }}
|
||||
</span> -->
|
||||
<span class="text-[12px] font-regular" v-if="state.condition === 'file'">
|
||||
{{ item?.nickname }}
|
||||
</span>
|
||||
<span class="text-[12px] font-regular" v-if="state.condition === 'file'">
|
||||
{{ item?.extra?.fileSize }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <ZPaging
|
||||
ref="zPaging"
|
||||
:show-scrollbar="false"
|
||||
@query="queryAllSearch"
|
||||
:refresher-enabled="false"
|
||||
:auto="false"
|
||||
:loading-more-default-as-loading="true"
|
||||
:inside-more="true"
|
||||
v-model="state.flatList"
|
||||
>
|
||||
<template #top v-if="state.showPageTitle">
|
||||
<customNavbar :title="state.pageTitle"></customNavbar>
|
||||
</template>
|
||||
|
||||
</ZPaging> -->
|
||||
<teleport to="body">
|
||||
<div v-show="open" class="video-container">
|
||||
<video
|
||||
:src="currentVideoUrl"
|
||||
controls
|
||||
@fullscreenchange="fullscreenchange"
|
||||
:id="currentVideoUrl"
|
||||
playsinline
|
||||
webkit-playsinline
|
||||
x5-playsinline
|
||||
class="fullscreen-video"
|
||||
></video>
|
||||
</div>
|
||||
</teleport>
|
||||
</div>
|
||||
</n-infinite-scroll>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
// import playCircle from '@/assets/image/icon/play-circle.png'
|
||||
// import customInput from '@/components/custom-input/custom-input.vue'
|
||||
// import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||
// import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
|
||||
// const zPaging = ref()
|
||||
// useZPaging(zPaging)
|
||||
|
||||
import { Play } from '@icon-park/vue-next'
|
||||
import fileType_PPT from '@/assets/image/ppt-text.png'
|
||||
import fileType_EXCEL from '@/assets/image/excel-text.png'
|
||||
import fileType_WORD from '@/assets/image/word-text.png'
|
||||
import fileType_PDF from '@/assets/image/pdf-text.png'
|
||||
import fileType_Files from '@/assets/image/file-text.png'
|
||||
import { useDialogueStore } from '@/store'
|
||||
import { onMounted, reactive, computed, ref, nextTick, watch } from 'vue'
|
||||
import searchItem from './searchItem.vue'
|
||||
import { ServeFindTalkRecords } from '@/api/chat.js'
|
||||
import { ServeTalkDate, ServeGetSessionId } from '@/api/search.js'
|
||||
import { parseTime } from '@/utils/datetime'
|
||||
import { fileFormatSize, fileSuffix } from '@/utils/strings'
|
||||
import { NImage, NInfiniteScroll, NScrollbar, NIcon, NDatePicker } from 'naive-ui'
|
||||
|
||||
const dialogueStore = useDialogueStore()
|
||||
// 当前对话参数
|
||||
const dialogueParams = reactive({
|
||||
talk_type: computed(() => dialogueStore.talk.talk_type),
|
||||
receiver_id: computed(() => dialogueStore.talk.receiver_id)
|
||||
})
|
||||
|
||||
let nowDay = new Date().setHours(0, 0, 0, 0)
|
||||
|
||||
const props = defineProps({
|
||||
conditionType: {
|
||||
//搜索条件
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const state = reactive({
|
||||
pageTitle: '', //页面标题
|
||||
dateStyle: [], //日期样式
|
||||
nowDate: new Date(nowDay), //当前时间
|
||||
maxDate: new Date(nowDay), //可选择最大时间
|
||||
selectedDateArray: Array(new Date(nowDay)), //选择的月份数组
|
||||
showMonthPicker: false, //是否显示月份选择
|
||||
selectedMonth: new Date(nowDay), //当前选择的月份
|
||||
disabledDateArray: [], //被禁用的日期数组
|
||||
dArray: [], //日历日期数组
|
||||
showPageTitle: false, //是否显示页面标题
|
||||
searchText: '', //搜索内容
|
||||
first_talk_record_infos: Object,
|
||||
searchResultList: [], //搜索结果列表
|
||||
cursor: 0, //上次查询的游标
|
||||
msg_type: 0, //查询的消息类型
|
||||
group_member_id: 0, //群成员id
|
||||
flatList: [] // 用于存储扁平化的数据
|
||||
})
|
||||
|
||||
const videoContext = ref()
|
||||
const open = ref(false)
|
||||
const currentVideoUrl = ref('')
|
||||
|
||||
const fullscreenchange = (e) => {
|
||||
if (!e.detail.fullScreen) {
|
||||
videoContext.value.stop()
|
||||
videoContext.value.seek(0)
|
||||
open.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function onPlay(url) {
|
||||
currentVideoUrl.value = url
|
||||
open.value = true
|
||||
|
||||
// 等待 DOM 更新
|
||||
await nextTick()
|
||||
|
||||
// 创建新的视频上下文
|
||||
videoContext.value = uni.createVideoContext(url, getCurrentInstance())
|
||||
|
||||
setTimeout(() => {
|
||||
// 先请求全屏
|
||||
videoContext.value.requestFullScreen({ direction: 2 })
|
||||
|
||||
// 延迟一下再播放,确保全屏已经完成
|
||||
setTimeout(() => {
|
||||
videoContext.value.play()
|
||||
}, 100)
|
||||
}, 200)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
state.selectedMonth = parseTime(state.selectedMonth, '{y}年{m}月')
|
||||
state.dateStyle = [
|
||||
{
|
||||
date: state.nowDate, //日期
|
||||
text: false, //浅色背景。
|
||||
color: '#46299D', //主题色.
|
||||
extra: '今天' //额外的内容,在日期下方显示的文本。
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
//查看存在聊天记录的天数
|
||||
const ServeQueryTalkDate = (month) => {
|
||||
let params = {
|
||||
month: month,
|
||||
talk_type: dialogueParams.talk_type, //1私聊2群聊
|
||||
receiver_id: dialogueParams.receiver_id //目标人id
|
||||
}
|
||||
const resp = ServeTalkDate(params)
|
||||
console.log(resp)
|
||||
resp.then(({ code, data }) => {
|
||||
console.log(data)
|
||||
if (code == 200) {
|
||||
if (data && data.length > 0) {
|
||||
const formattedData = data.map(
|
||||
(item) => item.substring(0, 4) + '/' + item.substring(4, 6) + '/' + item.substring(6, 8)
|
||||
)
|
||||
let disabledDateArray = state.dArray.filter((dIt) => !formattedData.includes(dIt))
|
||||
disabledDateArray = disabledDateArray.map((item) => item.replace(/\//g, '/'))
|
||||
console.log(disabledDateArray)
|
||||
state.disabledDateArray = disabledDateArray
|
||||
} else {
|
||||
state.disabledDateArray = state.dArray
|
||||
}
|
||||
} else {
|
||||
}
|
||||
})
|
||||
|
||||
resp.catch(() => {})
|
||||
}
|
||||
|
||||
//禁用的日期
|
||||
const dateDisabled = (e) => {
|
||||
const date = new Date(e)
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
const formattedDate = `${year}/${month}/${day}`
|
||||
return state.disabledDateArray.includes(formattedDate)
|
||||
}
|
||||
|
||||
//点击选择日期
|
||||
const selectDate = async (e) => {
|
||||
if (e == parseTime(state.nowDate, '{y}/{m}/{d}')) {
|
||||
console.log('==今日')
|
||||
state.dateStyle = [
|
||||
{
|
||||
date: state.nowDate, //日期
|
||||
text: false, //浅色背景。
|
||||
color: '#46299D', //主题色.
|
||||
extra: '今天' //额外的内容,在日期下方显示的文本。
|
||||
}
|
||||
]
|
||||
} else {
|
||||
state.dateStyle = [
|
||||
{
|
||||
date: state.nowDate, //日期
|
||||
text: false, //浅色背景。
|
||||
color: '', //主题色.
|
||||
extra: '今天' //额外的内容,在日期下方显示的文本。
|
||||
},
|
||||
{
|
||||
date: new Date(e), //日期
|
||||
text: false, //浅色背景。
|
||||
color: '#46299D' //主题色.
|
||||
}
|
||||
]
|
||||
}
|
||||
const sessionId = await getSessionId(dialogueParams.talk_type, dialogueParams.receiver_id)
|
||||
uni.navigateTo({
|
||||
url:
|
||||
'/pages/dialog/index?sessionId=' +
|
||||
sessionId +
|
||||
'&keepDialogInfo=1' +
|
||||
'&recordDate=' +
|
||||
parseTime(e, '{y}-{m}-{d}')
|
||||
})
|
||||
}
|
||||
|
||||
//获取会话Id
|
||||
const getSessionId = (talk_type, receiver_id) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let params = {
|
||||
talkType: talk_type,
|
||||
receiverId: receiver_id
|
||||
}
|
||||
const resp = ServeGetSessionId(params)
|
||||
console.log(resp)
|
||||
resp.then(({ code, data }) => {
|
||||
console.log(data)
|
||||
if (code == 200) {
|
||||
resolve(data?.sessionId)
|
||||
} else {
|
||||
}
|
||||
})
|
||||
resp.catch(() => {})
|
||||
})
|
||||
}
|
||||
|
||||
//点击确认选择月份
|
||||
const confirmSelectedMonth = (e) => {
|
||||
console.log(e)
|
||||
state.selectedMonth = parseTime(e, '{y}年{m}月')
|
||||
// console.log()
|
||||
let newDate = new Date(e)
|
||||
newDate.setHours(0, 0, 0, 0)
|
||||
newDate.setDate(1)
|
||||
state.selectedDateArray = Array(new Date(newDate))
|
||||
state.dateStyle = [
|
||||
{
|
||||
date: state.nowDate, //日期
|
||||
text: false, //浅色背景。
|
||||
color: '', //主题色.
|
||||
extra: '今天' //额外的内容,在日期下方显示的文本。
|
||||
}
|
||||
]
|
||||
ServeQueryTalkDate(parseTime(e, '{y}{m}'))
|
||||
}
|
||||
|
||||
//获取日历日期数组
|
||||
const getDArray = (selectedMonth) => {
|
||||
const [year, month] = selectedMonth.split('-').map(Number)
|
||||
const daysInMonth = new Date(year, month, 0).getDate()
|
||||
const dArray = Array.from({ length: daysInMonth }, (_, i) => {
|
||||
const day = i + 1
|
||||
return `${year}/${String(month).padStart(2, '0')}/${String(day).padStart(2, '0')}`
|
||||
})
|
||||
state.dArray = dArray
|
||||
}
|
||||
|
||||
//输入搜索内容
|
||||
const inputSearchText = (e) => {
|
||||
state.searchText = e
|
||||
state.cursor = 0
|
||||
queryAllSearch()
|
||||
}
|
||||
|
||||
//点击取消搜索
|
||||
const cancelSearch = () => {
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 1) {
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
})
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//查询数据
|
||||
const queryAllSearch = () => {
|
||||
let params = {
|
||||
talk_type: dialogueParams.talk_type, //1私聊;2群聊
|
||||
receiver_id: dialogueParams.receiver_id, //目标用户id或群聊id
|
||||
msg_type: state.msg_type, //消息类型:0:全部;2:代码;3:图片;4:音频;5:视频;6:文件;7:位置;9:会话;11群投票;12图文混合
|
||||
cursor: state.cursor, //上次查询的游标
|
||||
limit: 10, //数据行数
|
||||
no_limit: '', //1不限制
|
||||
direction: 'up', //down向下查最新,up向上查老数据
|
||||
start_time: '',
|
||||
end_time: '',
|
||||
group_member_user_id: state.group_member_id, //群成员id,当查询群历史消息的时候,需要指定群成员的时候送
|
||||
file_name: state.msg_type === 6 ? state.searchText : ''
|
||||
}
|
||||
console.log(params)
|
||||
const resp = ServeFindTalkRecords(params)
|
||||
console.log(resp)
|
||||
resp.then(({ code, data }) => {
|
||||
console.log(data)
|
||||
if (code == 200) {
|
||||
// 当cursor为0时,清空searchResultList
|
||||
let dateList = state.cursor === 0 ? [] : state.searchResultList
|
||||
let noMore = false
|
||||
if (data?.items?.length > 0) {
|
||||
data.items.forEach((item) => {
|
||||
item.dateTime = parseTime(item?.created_at, '{m}/{d}')
|
||||
if (item?.extra) {
|
||||
item.extra.fileSize = fileFormatSize(item?.extra?.size)
|
||||
item.extra.typeText = item?.extra?.name ? fileSuffix(item?.extra?.name) : ''
|
||||
item.extra.file_avatar = fileTypeAvatar(item?.extra?.typeText)
|
||||
console.log(item.extra.type)
|
||||
}
|
||||
let year = new Date(item.created_at).getFullYear()
|
||||
let month = new Date(item.created_at).getMonth() + 1
|
||||
let dateMonth =
|
||||
year == state.nowDate.getFullYear() && month == state.nowDate.getMonth() + 1
|
||||
? '这个月'
|
||||
: year + '年' + month + '月'
|
||||
if (dateList.length > 0) {
|
||||
let hasAdd = false
|
||||
dateList.forEach((dateItem) => {
|
||||
if (dateItem.dateMonth === dateMonth) {
|
||||
dateItem.monthResultList.push(item)
|
||||
hasAdd = true
|
||||
}
|
||||
})
|
||||
if (!hasAdd) {
|
||||
console.log(dateList)
|
||||
dateList.push({
|
||||
dateMonth: dateMonth,
|
||||
monthResultList: [item]
|
||||
})
|
||||
}
|
||||
} else {
|
||||
dateList.push({
|
||||
dateMonth: dateMonth,
|
||||
monthResultList: [item]
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
noMore = true
|
||||
}
|
||||
|
||||
// 保存分组数据用于显示
|
||||
state.searchResultList = dateList
|
||||
|
||||
// 将分组数据扁平化,用于z-paging分页
|
||||
state.flatList = dateList.reduce((acc, group) => {
|
||||
return acc.concat(group.monthResultList)
|
||||
}, [])
|
||||
|
||||
if (state.cursor === 0) {
|
||||
// zPaging.value?.complete(state.flatList)
|
||||
} else {
|
||||
// zPaging.value?.completeByNoMore(state.flatList, noMore)
|
||||
}
|
||||
state.cursor = data?.cursor
|
||||
} else {
|
||||
if (state.cursor === 0) {
|
||||
state.searchResultList = []
|
||||
state.flatList = []
|
||||
}
|
||||
// zPaging.value?.complete([])
|
||||
}
|
||||
})
|
||||
|
||||
resp.catch(() => {
|
||||
if (state.cursor === 0) {
|
||||
state.searchResultList = []
|
||||
state.flatList = []
|
||||
}
|
||||
// zPaging.value?.complete([])
|
||||
})
|
||||
}
|
||||
|
||||
//文件类型图标
|
||||
const fileTypeAvatar = (fileType) => {
|
||||
let file_type_avatar = fileType_Files
|
||||
if (fileType) {
|
||||
if (fileType === 'ppt' || fileType === 'pptx') {
|
||||
file_type_avatar = fileType_PPT
|
||||
} else if (fileType === 'pdf') {
|
||||
file_type_avatar = fileType_PDF
|
||||
} else if (fileType === 'doc' || fileType === 'docx') {
|
||||
file_type_avatar = fileType_WORD
|
||||
} else if (fileType === 'xls' || fileType === 'xlsx') {
|
||||
file_type_avatar = fileType_EXCEL
|
||||
} else {
|
||||
file_type_avatar = fileType_Files
|
||||
}
|
||||
}
|
||||
return file_type_avatar
|
||||
}
|
||||
|
||||
const previewPDF = (item) => {
|
||||
console.log(item)
|
||||
if (typeof plus !== 'undefined') {
|
||||
downloadAndOpenFile(item)
|
||||
} else {
|
||||
document.addEventListener('plusready', () => {
|
||||
downloadAndOpenFile(item)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const downloadAndOpenFile = (item) => {
|
||||
uni.showLoading({ title: '加载中...', mask: true })
|
||||
const downloadUrl = item?.extra?.path
|
||||
const options = {
|
||||
filename: '_doc/downloads/' // 保存路径
|
||||
}
|
||||
const dtask = plus.downloader.createDownload(downloadUrl, options, function (d, status) {
|
||||
if (status === 200) {
|
||||
uni.hideLoading()
|
||||
const filePath = d.filename
|
||||
plus.runtime.openFile(
|
||||
filePath,
|
||||
{},
|
||||
function () {},
|
||||
function (error) {}
|
||||
)
|
||||
} else {
|
||||
uni.hideLoading()
|
||||
}
|
||||
})
|
||||
dtask.start()
|
||||
}
|
||||
|
||||
//跳转到对应的记录位置
|
||||
const toDialogueByMember = async (msgInfo) => {
|
||||
const sessionId = await getSessionId(dialogueParams.talk_type, dialogueParams.receiver_id)
|
||||
uni.navigateTo({
|
||||
url:
|
||||
'/pages/dialog/index?sessionId=' +
|
||||
sessionId +
|
||||
'&keepDialogInfo=1' +
|
||||
'&msgInfo=' +
|
||||
encodeURIComponent(JSON.stringify(msgInfo))
|
||||
})
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props?.conditionType,
|
||||
(newVal, oldVal) => {
|
||||
console.log(newVal, oldVal)
|
||||
state.condition = newVal
|
||||
if (newVal) {
|
||||
if (newVal === 'member') {
|
||||
state.showPageTitle = true
|
||||
state.pageTitle = '按群成员查找'
|
||||
// state.group_member_id = options.groupMemberId
|
||||
queryAllSearch()
|
||||
} else if (newVal === 'dateTimePicker') {
|
||||
state.showPageTitle = true
|
||||
state.pageTitle = '按日期查找'
|
||||
ServeQueryTalkDate(parseTime(state.nowDate, '{y}{m}'))
|
||||
getDArray(parseTime(state.nowDate, '{y}-{m}'))
|
||||
} else if (newVal === 'imgAndVideo') {
|
||||
state.showPageTitle = true
|
||||
state.pageTitle = '图片与视频'
|
||||
state.msg_type = '3,5'
|
||||
queryAllSearch()
|
||||
} else if (newVal === 'file') {
|
||||
console.log(dialogueParams)
|
||||
let first_talk_record_infos = {
|
||||
receiver_name: '文件'
|
||||
}
|
||||
state.first_talk_record_infos = Object.assign(
|
||||
{},
|
||||
state.first_talk_record_infos,
|
||||
first_talk_record_infos
|
||||
)
|
||||
state.msg_type = 6
|
||||
queryAllSearch()
|
||||
} else if (newVal === 'link') {
|
||||
console.log(dialogueParams)
|
||||
let first_talk_record_infos = {
|
||||
receiver_name: '链接'
|
||||
}
|
||||
state.first_talk_record_infos = Object.assign(
|
||||
{},
|
||||
state.first_talk_record_infos,
|
||||
first_talk_record_infos
|
||||
)
|
||||
state.msg_type = 14
|
||||
queryAllSearch()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
)
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.search-by-date {
|
||||
:deep(.n-date-panel-header) {
|
||||
display: none;
|
||||
}
|
||||
.search-date-picker {
|
||||
padding: 10px 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
span {
|
||||
line-height: 20px;
|
||||
color: #999999;
|
||||
}
|
||||
img {
|
||||
width: 9px;
|
||||
height: 6px;
|
||||
margin: 0 0 0 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body:deep(.text-overflow-1) {
|
||||
color: #666666 !important;
|
||||
line-height: 22px !important;
|
||||
font-size: 16px !important;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
body:deep(.tmicon-times-circle-fill) {
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
}
|
||||
body:deep(.round-3) {
|
||||
background: linear-gradient(to right, #674bbc, #46299d);
|
||||
}
|
||||
|
||||
.search-by-condition-input-list {
|
||||
// padding: 10px 24px 0 21px;
|
||||
padding: 20px 40px;
|
||||
.search-by-condition-input {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.search-by-condition-input-text {
|
||||
flex-shrink: 0;
|
||||
margin: 0 0 0 10px;
|
||||
color: #46299d;
|
||||
}
|
||||
}
|
||||
|
||||
.search-by-condition-list {
|
||||
.condition-dimensionality {
|
||||
.condition-dimensionality-each {
|
||||
.condition-dimensionality-each-month {
|
||||
padding: 0 0 18px;
|
||||
span {
|
||||
line-height: 20px;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
.condition-each-resultList {
|
||||
.condition-each-resultList-each {
|
||||
border-bottom: 1px solid #f8f8f8;
|
||||
.condition-each-result-main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.condition-each-result-main-date {
|
||||
line-height: 17px;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
.condition-each-result-attachments {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 14px 0;
|
||||
// background-color: #f3f3f3;
|
||||
border-radius: 4px;
|
||||
.attachment-avatar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
.attachment-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
margin: 0 0 0 11px;
|
||||
width: 100%;
|
||||
.attachment-info-title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
span {
|
||||
line-height: 20px;
|
||||
color: #191919;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
.attachment-sub-info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
span {
|
||||
line-height: 17px;
|
||||
color: #999999;
|
||||
word-break: break-all;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.condition-type-imgAndVideo-result {
|
||||
border-bottom: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
.condition-each-resultList-each {
|
||||
.condition-result-imgAndVideo {
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
:deep(.overflow) {
|
||||
width: 131px !important;
|
||||
height: 131px !important;
|
||||
}
|
||||
.condition-result-imgAndVideo-area {
|
||||
:deep(.overflow) {
|
||||
width: 131px !important;
|
||||
height: 131px !important;
|
||||
}
|
||||
:deep(.round-0) {
|
||||
width: 131px !important;
|
||||
height: 131px !important;
|
||||
}
|
||||
.video-preview {
|
||||
// position: relative;
|
||||
// .play-icon {
|
||||
// position: absolute;
|
||||
// top: 50%;
|
||||
// left: 50%;
|
||||
// transform: translate(-50%, -50%);
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
|
||||
// img {
|
||||
// width: 40px !important;
|
||||
// height: 40px !important;
|
||||
// }
|
||||
// }
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
width: 131px;
|
||||
height: 131px;
|
||||
|
||||
video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
background-color: #333; /* 添加背景色,避免默认显示为灰色 */
|
||||
}
|
||||
|
||||
.btn-video {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.btn-video {
|
||||
color: #46299d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.condition-dimensionality-each:nth-child(1) {
|
||||
.condition-each-result-attachments {
|
||||
padding: 0 0 14px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.video-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: #000;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.fullscreen-video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
</style>
|
@ -3,7 +3,10 @@
|
||||
class="search-item"
|
||||
:class="props?.conditionType ? 'search-item-condition' : ''"
|
||||
v-if="resultName"
|
||||
:style="props.searchResultKey === 'talk_record_infos_receiver' ? 'margin: 12px 0 0' : ''"
|
||||
:style="{
|
||||
'margin': props.searchResultKey === 'talk_record_infos_receiver' ? '12px 0 0' : '',
|
||||
'background-color': props.isClickStay ? '#EEE9F8' : ''
|
||||
}"
|
||||
>
|
||||
<div class="search-item-avatar">
|
||||
<avatarModule
|
||||
@ -101,7 +104,11 @@ const props = defineProps({
|
||||
conditionType: {
|
||||
type: Number,
|
||||
default: 0
|
||||
} //搜索类型
|
||||
}, //搜索类型
|
||||
isClickStay: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
} //是否点击停留
|
||||
})
|
||||
// 映射表-查找对应结构下的属性名
|
||||
const keyMapping = {
|
||||
@ -259,8 +266,9 @@ const resultDetail = computed(() => {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 11px 0 12px;
|
||||
border-bottom: 1px solid #f8f8f8;
|
||||
padding: 11px 10px 12px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
.search-item-avatar{
|
||||
position: relative;
|
||||
@ -331,7 +339,21 @@ const resultDetail = computed(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-item::after{
|
||||
content: '';
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 10px;
|
||||
width: calc(100% - 20px);
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
.search-item-condition {
|
||||
border: 0;
|
||||
}
|
||||
.search-item:hover {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
</style>
|
||||
|
@ -34,6 +34,11 @@
|
||||
:searchItem="item"
|
||||
:searchText="state.searchText"
|
||||
:searchRecordDetail="props.searchRecordDetail"
|
||||
:isClickStay="
|
||||
props.useClickStay &&
|
||||
typeof state.clickStayItem === 'string' &&
|
||||
state.clickStayItem === `${item.talk_type}_${item.receiver_id}`
|
||||
"
|
||||
></searchItem>
|
||||
</div>
|
||||
</div>
|
||||
@ -127,16 +132,23 @@
|
||||
// useZPaging(zPaging)
|
||||
|
||||
import searchItem from './searchItem.vue'
|
||||
import { ref, reactive, defineEmits, defineProps, onMounted } from 'vue'
|
||||
import { ref, reactive, defineEmits, defineProps, onMounted, watch } from 'vue'
|
||||
|
||||
const emits = defineEmits(['toMoreResultPage', 'lastIdChange', 'clickSearchItem'])
|
||||
const emits = defineEmits([
|
||||
'toMoreResultPage',
|
||||
'lastIdChange',
|
||||
'clickSearchItem',
|
||||
'clickStayItemChange',
|
||||
'doLoadMore'
|
||||
])
|
||||
|
||||
const state = reactive({
|
||||
searchText: '', //搜索内容
|
||||
searchResultList: [], //搜素结果列表
|
||||
searchResult: null, //搜索结果
|
||||
pageNum: 1, //当前请求数据页数
|
||||
uid: 1496 //当前用户id
|
||||
uid: 12303, //当前用户id
|
||||
clickStayItem: '' //点击停留的item
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
@ -174,144 +186,72 @@ const props = defineProps({
|
||||
hideFirstRecord: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
} //是否隐藏前缀及搜索群/用户主体信息
|
||||
}, //是否隐藏前缀及搜索群/用户主体信息
|
||||
useClickStay: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
} //是否使用点击停留样式
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (props.searchText) {
|
||||
state.searchText = props.searchText
|
||||
queryAllSearch(1, 10)
|
||||
queryAllSearch()
|
||||
}
|
||||
})
|
||||
|
||||
// 监听每页数量变化
|
||||
watch(
|
||||
() => props.searchResultPageSize,
|
||||
(newVal, oldVal) => {
|
||||
queryAllSearch()
|
||||
}
|
||||
)
|
||||
|
||||
// 监听搜索文本变化
|
||||
watch(
|
||||
() => props.searchText,
|
||||
(newVal, oldVal) => {
|
||||
queryAllSearch()
|
||||
state.clickStayItem = ''
|
||||
emits('clickStayItemChange', state.clickStayItem)
|
||||
}
|
||||
)
|
||||
|
||||
//输入搜索文本
|
||||
const inputSearchText = (e) => {
|
||||
if (e.trim() != state.searchText.trim()) {
|
||||
state.pageNum = 1
|
||||
state.searchResult = null // 清空搜索结果
|
||||
emits('lastIdChange', 0, 0, 0)
|
||||
emits('lastIdChange', 0, 0, 0, '', '')
|
||||
}
|
||||
state.searchText = e.trim()
|
||||
if (!e.trim()) {
|
||||
state.searchResult = null // 清空搜索结果
|
||||
emits('lastIdChange', 0, 0, 0)
|
||||
emits('lastIdChange', 0, 0, 0, '', '')
|
||||
}
|
||||
// zPaging.value?.reload()
|
||||
queryAllSearch()
|
||||
}
|
||||
|
||||
// ES搜索聊天记录-主页搜索什么都有、指定用户、指定群、群与用户概览
|
||||
const queryAllSearch = (pageNum, searchResultPageSize) => {
|
||||
const queryAllSearch = (doClearSearchResult) => {
|
||||
if (doClearSearchResult) {
|
||||
state.searchResult = null
|
||||
}
|
||||
let params = {
|
||||
key: state.searchText, //关键字
|
||||
size: searchResultPageSize
|
||||
size: props.searchResultPageSize
|
||||
}
|
||||
if (props.apiParams) {
|
||||
let apiParams = JSON.parse(decodeURIComponent(props.apiParams))
|
||||
params = Object.assign({}, params, apiParams)
|
||||
}
|
||||
const data = {
|
||||
user_infos: [
|
||||
{
|
||||
id: 127,
|
||||
mobile: '17706200252',
|
||||
nickname: '测试-王溢韬',
|
||||
avatar:
|
||||
'https://dci-file-new.bj.bcebos.com/fonchain-main/test/runtime/image/avatar/40/b8ed6fea-6662-416d-8bb3-1fd8a8197061.jpg',
|
||||
created_at: '2025-03-28 11:33:13',
|
||||
erp_user_id: 18282
|
||||
},
|
||||
{
|
||||
id: 103,
|
||||
mobile: '13814969538',
|
||||
nickname: '王静测试',
|
||||
avatar: '',
|
||||
created_at: '2025-03-27 14:44:23',
|
||||
erp_user_id: 2639
|
||||
},
|
||||
{
|
||||
id: 57,
|
||||
mobile: '13862027511',
|
||||
nickname: '王西',
|
||||
avatar:
|
||||
'https://dci-file-new.bj.bcebos.com/fonchain-main/test/runtime/image/avatar/40/b8ed6fea-6662-416d-8bb3-1fd8a8197061.jpg',
|
||||
created_at: '2025-03-27 14:44:23',
|
||||
erp_user_id: 18229
|
||||
}
|
||||
],
|
||||
user_count: 9,
|
||||
group_infos: null,
|
||||
group_member_infos: [
|
||||
{
|
||||
id: 79,
|
||||
group_id: 1,
|
||||
group_name: '泰丰国际',
|
||||
group_type: 4,
|
||||
group_avatar: '',
|
||||
group_num: 103,
|
||||
user_id: 103,
|
||||
user_name: '王静',
|
||||
user_card: '',
|
||||
created_at: '2025-03-27 14:44:24'
|
||||
},
|
||||
{
|
||||
id: 55,
|
||||
group_id: 1,
|
||||
group_name: '泰丰国际',
|
||||
group_type: 4,
|
||||
group_avatar: '',
|
||||
group_num: 103,
|
||||
user_id: 57,
|
||||
user_name: '王西',
|
||||
user_card: '',
|
||||
created_at: '2025-03-27 14:44:24'
|
||||
},
|
||||
{
|
||||
id: 35,
|
||||
group_id: 1,
|
||||
group_name: '泰丰国际',
|
||||
group_type: 4,
|
||||
group_avatar: '',
|
||||
group_num: 103,
|
||||
user_id: 37,
|
||||
user_name: '王雯婷',
|
||||
user_card: '',
|
||||
created_at: '2025-03-27 14:44:24'
|
||||
}
|
||||
],
|
||||
group_count: 9,
|
||||
general_infos: [
|
||||
{
|
||||
receiver_id: 40,
|
||||
receiver_name: '孙志远',
|
||||
receiver_avatar:
|
||||
'https://dci-file-new.bj.bcebos.com/fonchain-main/test/runtime/image/avatar/40/b8ed6fea-6662-416d-8bb3-1fd8a8197061.jpg',
|
||||
group_num: 0,
|
||||
talk_type: 1,
|
||||
count: 3,
|
||||
group_type: 0
|
||||
},
|
||||
{
|
||||
receiver_id: 2,
|
||||
receiver_name: '吹牛个人群',
|
||||
receiver_avatar: '',
|
||||
group_num: 4,
|
||||
talk_type: 2,
|
||||
count: 2,
|
||||
group_type: 3
|
||||
},
|
||||
{
|
||||
receiver_id: 3,
|
||||
receiver_name: '丰链30自己人',
|
||||
receiver_avatar:
|
||||
'https://e-cdn.fontree.cn/fonchain-main/prod/image/default/fonchain-chat/3d273326-d2a5-4ad4-a974-32d020c6b3f9.jpg?width=1080&height=2412',
|
||||
group_num: 8,
|
||||
talk_type: 2,
|
||||
count: 2,
|
||||
group_type: 3
|
||||
}
|
||||
],
|
||||
record_count: 3
|
||||
}
|
||||
|
||||
const resp = props.apiRequest(params)
|
||||
resp.then(({ code, data }) => {
|
||||
console.log(data)
|
||||
if (code == 200) {
|
||||
if ((data.user_infos || []).length > 0) {
|
||||
;(data.user_infos || []).forEach((item) => {
|
||||
item.group_type = 0
|
||||
@ -348,7 +288,11 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
|
||||
receiverInfo.user_avatar = temp_avatar
|
||||
}
|
||||
}
|
||||
state.first_talk_record_infos = Object.assign({}, state.first_talk_record_infos, receiverInfo)
|
||||
state.first_talk_record_infos = Object.assign(
|
||||
{},
|
||||
state.first_talk_record_infos,
|
||||
receiverInfo
|
||||
)
|
||||
;(data.talk_record_infos || []).forEach((item) => {
|
||||
item.group_type = 0
|
||||
})
|
||||
@ -373,7 +317,7 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
|
||||
})
|
||||
|
||||
if (isEmpty) {
|
||||
if (pageNum === 1) {
|
||||
if (state.pageNum === 1) {
|
||||
// 第一页请求且为空,清空结果
|
||||
state.searchResult = null
|
||||
// zPaging.value?.complete([])
|
||||
@ -383,17 +327,14 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
|
||||
}
|
||||
} else {
|
||||
if (props.isPagination) {
|
||||
if (pageNum === 1) {
|
||||
if (state.pageNum === 1) {
|
||||
// 第一页请求,直接设置新数据
|
||||
state.searchResult = data
|
||||
} else {
|
||||
// 加载更多,合并数据
|
||||
if (
|
||||
paginationKey &&
|
||||
Array.isArray((state?.searchResult && state?.searchResult[paginationKey]) || [])
|
||||
) {
|
||||
data[paginationKey] = state.searchResult[paginationKey].concat(data[paginationKey])
|
||||
}
|
||||
data[paginationKey] = (state.searchResult?.[paginationKey] || []).concat(
|
||||
data[paginationKey]
|
||||
)
|
||||
state.searchResult = data
|
||||
}
|
||||
|
||||
@ -419,149 +360,29 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
|
||||
// zPaging.value?.complete([data])
|
||||
}
|
||||
}
|
||||
// const resp = props.apiRequest(params)
|
||||
// resp.then(({ code, data }) => {
|
||||
// console.log(data)
|
||||
// if (code == 200) {
|
||||
// if ((data.user_infos || []).length > 0) {
|
||||
// ;(data.user_infos || []).forEach((item) => {
|
||||
// item.group_type = 0
|
||||
// })
|
||||
// }
|
||||
// if ((data.group_infos || []).length > 0) {
|
||||
// ;(data.group_infos || []).forEach((item) => {
|
||||
// item.group_type = item.type
|
||||
// item.groupTempType = 'group_infos'
|
||||
// })
|
||||
// }
|
||||
// if ((data.group_member_infos || []).length > 0) {
|
||||
// ;(data.group_member_infos || []).forEach((item) => {
|
||||
// item.groupTempType = 'group_member_infos'
|
||||
// })
|
||||
// }
|
||||
// if ((data.talk_record_infos || []).length > 0) {
|
||||
// let receiverInfo = JSON.parse(JSON.stringify(data.talk_record_infos[0]))
|
||||
// if (receiverInfo.talk_type === 1) {
|
||||
// //单聊才需此判断
|
||||
// if (receiverInfo.user_id === state.uid) {
|
||||
// //发送人是自己,接收人不需要变
|
||||
// }
|
||||
// if (receiverInfo.receiver_id === state.uid) {
|
||||
// //接收人是自己,这里需要变成对方
|
||||
// let temp_id = receiverInfo.receiver_id
|
||||
// let temp_name = receiverInfo.receiver_name
|
||||
// let temp_avatar = receiverInfo.receiver_avatar
|
||||
// receiverInfo.receiver_id = receiverInfo.user_id
|
||||
// receiverInfo.receiver_name = receiverInfo.user_name
|
||||
// receiverInfo.receiver_avatar = receiverInfo.user_avatar
|
||||
// receiverInfo.user_id = temp_id
|
||||
// receiverInfo.user_name = temp_name
|
||||
// receiverInfo.user_avatar = temp_avatar
|
||||
// }
|
||||
// }
|
||||
// state.first_talk_record_infos = Object.assign(
|
||||
// {},
|
||||
// state.first_talk_record_infos,
|
||||
// receiverInfo,
|
||||
// )
|
||||
// ;(data.talk_record_infos || []).forEach((item) => {
|
||||
// item.group_type = 0
|
||||
// })
|
||||
// }
|
||||
|
||||
// let tempGeneral_infos = Array.isArray(data.general_infos)
|
||||
// ? [...data.general_infos]
|
||||
// : data.general_infos
|
||||
// delete data.general_infos
|
||||
// data.combinedGroup = (data.group_infos || []).concat(
|
||||
// data.group_member_infos || [],
|
||||
// )
|
||||
// data.general_infos = tempGeneral_infos
|
||||
|
||||
// // 检查数据是否为空
|
||||
// let isEmpty = true
|
||||
// let dataKeys = Object.keys(data)
|
||||
// let paginationKey = ''
|
||||
// dataKeys.forEach((item) => {
|
||||
// if (Array.isArray(data[item]) && data[item].length > 0) {
|
||||
// paginationKey = item
|
||||
// isEmpty = false
|
||||
// }
|
||||
// })
|
||||
|
||||
// if (isEmpty) {
|
||||
// if (pageNum === 1) {
|
||||
// // 第一页请求且为空,清空结果
|
||||
// state.searchResult = null
|
||||
state.pageNum = state.pageNum + 1
|
||||
} else {
|
||||
if (state.pageNum === 1) {
|
||||
// 第一页请求失败,清空结果
|
||||
state.searchResult = null
|
||||
// zPaging.value?.complete([])
|
||||
// } else {
|
||||
// // 加载更多且为空,保持原列表不变
|
||||
} else {
|
||||
// 加载更多失败,保持原列表不变
|
||||
// zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
|
||||
// }
|
||||
// } else {
|
||||
// if (props.isPagination) {
|
||||
// if (pageNum === 1) {
|
||||
// // 第一页请求,直接设置新数据
|
||||
// state.searchResult = data
|
||||
// } else {
|
||||
// // 加载更多,合并数据
|
||||
// if (
|
||||
// paginationKey &&
|
||||
// Array.isArray(
|
||||
// (state?.searchResult && state?.searchResult[paginationKey]) || [],
|
||||
// )
|
||||
// ) {
|
||||
// data[paginationKey] = state.searchResult[paginationKey].concat(
|
||||
// data[paginationKey],
|
||||
// )
|
||||
// }
|
||||
// state.searchResult = data
|
||||
// }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// emits(
|
||||
// 'lastIdChange',
|
||||
// data.last_id,
|
||||
// data.last_group_id,
|
||||
// data.last_member_id,
|
||||
// data.last_receiver_user_name,
|
||||
// data.last_receiver_group_name,
|
||||
// )
|
||||
// let total = data.count
|
||||
// if (props.searchRecordDetail) {
|
||||
// if (state?.first_talk_record_infos?.talk_type === 1) {
|
||||
// total = data.user_record_count
|
||||
// } else if (state?.first_talk_record_infos?.talk_type === 2) {
|
||||
// total = data.group_record_count
|
||||
// }
|
||||
// }
|
||||
// zPaging.value?.completeByTotal([data], total)
|
||||
// } else {
|
||||
// state.searchResult = data
|
||||
// zPaging.value?.complete([data])
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// if (pageNum === 1) {
|
||||
// // 第一页请求失败,清空结果
|
||||
// state.searchResult = null
|
||||
resp.catch(() => {
|
||||
if (state.pageNum === 1) {
|
||||
// 第一页请求异常,清空结果
|
||||
state.searchResult = null
|
||||
// zPaging.value?.complete([])
|
||||
// } else {
|
||||
// // 加载更多失败,保持原列表不变
|
||||
} else {
|
||||
// 加载更多异常,保持原列表不变
|
||||
// zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
|
||||
// resp.catch(() => {
|
||||
// if (pageNum === 1) {
|
||||
// // 第一页请求异常,清空结果
|
||||
// state.searchResult = null
|
||||
// zPaging.value?.complete([])
|
||||
// } else {
|
||||
// // 加载更多异常,保持原列表不变
|
||||
// zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
|
||||
// }
|
||||
// })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//点击取消搜索
|
||||
@ -648,6 +469,12 @@ const toMoreResultPage = (searchResultKey) => {
|
||||
//点击了搜索结果项
|
||||
const clickSearchItem = (searchResultKey, searchItem) => {
|
||||
console.log(searchResultKey, searchItem)
|
||||
if (props.useClickStay) {
|
||||
state.clickStayItem = searchItem.talk_type + '_' + searchItem.receiver_id
|
||||
} else {
|
||||
state.clickStayItem = ''
|
||||
}
|
||||
emits('clickStayItemChange', state.clickStayItem)
|
||||
let talk_type = searchItem.talk_type
|
||||
let receiver_id = searchItem.receiver_id
|
||||
if (searchResultKey === 'user_infos') {
|
||||
@ -684,6 +511,16 @@ const clickSearchItem = (searchResultKey, searchItem) => {
|
||||
encodeURIComponent(JSON.stringify(searchItem))
|
||||
)
|
||||
}
|
||||
|
||||
//加载更多数据
|
||||
const doLoadMore = (doClearSearchResult) => {
|
||||
queryAllSearch(doClearSearchResult)
|
||||
}
|
||||
|
||||
// 暴露doLoadMore方法给父组件
|
||||
defineExpose({
|
||||
doLoadMore
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.search-list {
|
||||
@ -706,7 +543,7 @@ const clickSearchItem = (searchResultKey, searchItem) => {
|
||||
}
|
||||
.search-result {
|
||||
width: 100%;
|
||||
padding: 0 10px;
|
||||
// padding: 0 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
@ -715,13 +552,13 @@ const clickSearchItem = (searchResultKey, searchItem) => {
|
||||
|
||||
.search-result-list {
|
||||
width: 100%;
|
||||
// padding: 0 9px;
|
||||
// padding: 0 10px;
|
||||
|
||||
.search-result-part {
|
||||
margin: 18px 0 0;
|
||||
|
||||
.result-title {
|
||||
padding: 0 0 5px;
|
||||
padding: 0 10px 5px;
|
||||
border-bottom: 1px solid #f8f8f8;
|
||||
span {
|
||||
line-height: 20px;
|
||||
@ -729,13 +566,17 @@ const clickSearchItem = (searchResultKey, searchItem) => {
|
||||
}
|
||||
}
|
||||
.result-has-more {
|
||||
padding: 10px 0;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #f8f8f8;
|
||||
cursor: pointer;
|
||||
span {
|
||||
color: #191919;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
.result-has-more:hover {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import dropsize from './dropsize'
|
||||
import focus from './focus'
|
||||
import loading from './loading'
|
||||
import dropsize from './dropsize.js'
|
||||
import focus from './focus.js'
|
||||
import loading from './loading.js'
|
||||
|
||||
const directives = {
|
||||
dropsize,
|
||||
|
118
src/plugins/directive/index.js
Normal file
@ -0,0 +1,118 @@
|
||||
import { Local } from "@/utils/erpStorage.js";
|
||||
import {debounce} from 'lodash-es'
|
||||
import { setupDirective as setupCustomDirectives } from '@/directive/index.ts'
|
||||
// 缓存按钮权限列表的key
|
||||
const BTN_PERMISSION_KEY = 'ruleBtn';
|
||||
|
||||
// 工具函数: 获取权限列表
|
||||
const getPermissionList = () => Local.get(BTN_PERMISSION_KEY) || [];
|
||||
|
||||
// 工具函数: 安全地移除DOM元素
|
||||
const safeRemoveElement = (el) => {
|
||||
el.style.display = 'none';
|
||||
requestAnimationFrame(() => el.parentNode?.removeChild(el));
|
||||
};
|
||||
|
||||
export default (app) => {
|
||||
// 防抖函数
|
||||
const directives = {
|
||||
// 禁止输入空格
|
||||
'no-space': {
|
||||
mounted(el) {
|
||||
const input = el.tagName === 'INPUT' ? el : el.querySelector('input');
|
||||
if (!input) return;
|
||||
const handleInput = debounce((e) => {
|
||||
const value = e.target.value;
|
||||
const trimmedValue = value.replace(/\s/g, '');
|
||||
if (value !== trimmedValue) {
|
||||
e.target.value = trimmedValue;
|
||||
// 创建一次性的input事件
|
||||
const inputEvent = new InputEvent('input', { bubbles: true });
|
||||
e.target.dispatchEvent(inputEvent);
|
||||
}
|
||||
}, 100);
|
||||
|
||||
input.addEventListener('input', handleInput);
|
||||
|
||||
// 存储清理函数
|
||||
el._cleanup = () => input.removeEventListener('input', handleInput);
|
||||
},
|
||||
unmounted(el) {
|
||||
// 清理事件监听
|
||||
el._cleanup?.();
|
||||
}
|
||||
},
|
||||
|
||||
// 上拉加载更多
|
||||
'loadmore': {
|
||||
mounted(el, binding) {
|
||||
const handleScroll = debounce(() => {
|
||||
const { scrollHeight, scrollTop, clientHeight } = el;
|
||||
const threshold = 50; // 提前触发的距离
|
||||
const isNearBottom = scrollHeight - scrollTop - clientHeight <= threshold;
|
||||
|
||||
if (isNearBottom && typeof binding.value === 'function') {
|
||||
binding.value();
|
||||
}
|
||||
}, 200);
|
||||
|
||||
el.addEventListener('scroll', handleScroll, { passive: true });
|
||||
|
||||
el._cleanup = () => el.removeEventListener('scroll', handleScroll);
|
||||
},
|
||||
unmounted(el) {
|
||||
el._cleanup?.();
|
||||
}
|
||||
},
|
||||
|
||||
// 按钮权限控制
|
||||
'permission': {
|
||||
mounted(el, binding) {
|
||||
if (!binding.value) return;
|
||||
const btnList = getPermissionList();
|
||||
const hasPermission = btnList.includes(binding.value);
|
||||
|
||||
if (!hasPermission) {
|
||||
safeRemoveElement(el);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 注册指令
|
||||
Object.entries(directives).forEach(([name, directive]) => {
|
||||
app.directive(name, directive);
|
||||
});
|
||||
|
||||
// 权限检查函数
|
||||
const hasPermission = (permissions) => {
|
||||
const permissionList = getPermissionList();
|
||||
if (!permissionList.length) return false;
|
||||
|
||||
const requiredPermissions = Array.isArray(permissions) ? permissions : [permissions];
|
||||
return requiredPermissions.some(permission => permissionList.includes(permission));
|
||||
};
|
||||
// 缓存代理以提高性能
|
||||
// 注册全局权限检查方法
|
||||
app.config.globalProperties.$hadRule = new Proxy(hasPermission, {
|
||||
// 创建缓存Map
|
||||
cache: new Map(),
|
||||
// 代理函数调用
|
||||
apply(target, thisArg, args) {
|
||||
// 将参数序列化作为缓存key
|
||||
const key = JSON.stringify(args);
|
||||
// 如果缓存中存在,直接返回缓存结果
|
||||
if (this.cache.has(key)) {
|
||||
return this.cache.get(key);
|
||||
}
|
||||
|
||||
// 如果缓存中不存在,执行原函数并缓存结果
|
||||
const result = target.apply(thisArg, args);
|
||||
this.cache.set(key, result);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
// 注册 src/directive 里的 loading、dropsize、focus 等指令
|
||||
setupCustomDirectives(app)
|
||||
};
|
@ -5,3 +5,8 @@ export * from './naive-ui'
|
||||
export * from './sms-lock'
|
||||
export * from './ws-socket'
|
||||
export * from './pinia'
|
||||
import directive from './directive'
|
||||
|
||||
export function setupDirective(app) {
|
||||
directive(app)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive, computed, watch } from 'vue'
|
||||
import { NDrawer } from 'naive-ui'
|
||||
import { NDrawer, NCard, NTag } from 'naive-ui'
|
||||
import { useUserStore, useDialogueStore, useUploadsStore } from '@/store'
|
||||
import PanelHeader from './panel/PanelHeader.vue'
|
||||
import PanelContent from './panel/PanelContent.vue'
|
||||
@ -8,6 +8,10 @@ import PanelFooter from './panel/PanelFooter.vue'
|
||||
import GroupPanel from '@/components/group/GroupPanel.vue'
|
||||
import GroupNotice from '@/components/group/GroupNotice.vue'
|
||||
import UploadsModal from '@/components/base/UploadsModal.vue'
|
||||
import customModal from '@/components/common/customModal.vue'
|
||||
import historyRecord from '@/components/search/searchByCondition.vue'
|
||||
import { ServeEditGroupNotice, ServeGetGroupNotices, ServeDeleteGroupNotice } from '@/api/group'
|
||||
import avatarModule from '@/components/avatar-module/index.vue'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const dialogueStore = useDialogueStore()
|
||||
@ -33,8 +37,50 @@ const talkParams = reactive({
|
||||
const state = reactive({
|
||||
// 是否显示群面板
|
||||
isShowGroupAside: false,
|
||||
|
||||
isShowGroupNotice: false
|
||||
isShowGroupNotice: false,
|
||||
isShowSearchRecordByConditionModal: false, //是否显示按条件搜索记录弹窗
|
||||
customSearchRecordByConditionModalStyle: {
|
||||
width: '997px',
|
||||
height: '740px',
|
||||
backgroundColor: '#F9F9FD'
|
||||
}, //按条件搜索记录弹窗样式
|
||||
searchRecordByConditionText: '', //按条件搜索记录文本
|
||||
conditionTag: '', //当前条件标签
|
||||
conditionType: '', //当前条件类型
|
||||
isShowGroupNoticeModal: false, //是否显示群公告模态框
|
||||
customGroupNoticeModalStyle: {
|
||||
width: '997px',
|
||||
height: '740px'
|
||||
}, //群公告模态框样式
|
||||
groupNoticeModalActionBtns: {
|
||||
confirmBtn: {
|
||||
text: '编辑',
|
||||
doLoading: false,
|
||||
disabled: false
|
||||
},
|
||||
cancelBtn: false
|
||||
}, //群公告模态框操作按钮
|
||||
groupNoticeModalActionBtnsStyle: 'padding: 20px 0;', //群公告模态框操作按钮样式
|
||||
groupNoticeInEdit: '', //编辑中的公告
|
||||
groupNoticeEditMode: 3, //群公告编辑模式:2=编辑;3=查看
|
||||
groupNoticeModalConfirmBtnEvent: 'edit', //群公告模态框确认按钮事件:edit=编辑;fillIn=输入
|
||||
isShowNoticeHintModal: false, //是否显示群公告提示模态框
|
||||
customNoticeHintModalStyle: {
|
||||
width: '724px',
|
||||
height: '314px'
|
||||
}, //群公告提示模态框样式
|
||||
noticeHintModalActionBtns: {}, //群公告提示模态框操作按钮
|
||||
noticeHintModalContent: '', //群公告提示模态框内容
|
||||
noticeHintMode: 'publish', //群公告提示模式:publish=发布;cancel=取消
|
||||
groupNoticeInfo: {
|
||||
id: 0,
|
||||
avatar: '',
|
||||
updater_name: '',
|
||||
updated_at: '',
|
||||
content: ''
|
||||
}, //群公告信息
|
||||
isAdmin: false, //当前登录用户是否是该群管理员
|
||||
groupNoticeContentChange: '' //群公告内容变化
|
||||
})
|
||||
|
||||
const events = {
|
||||
@ -46,15 +92,283 @@ const events = {
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => talkParams, (newValue, oldValue) => {
|
||||
console.log(newValue);
|
||||
|
||||
},{deep:true,immediate:true})
|
||||
watch(
|
||||
() => talkParams,
|
||||
(newValue, oldValue) => {
|
||||
console.log(newValue)
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
|
||||
// Header 工具栏事件
|
||||
const onPanelHeaderEvent = (eventType: string) => {
|
||||
events[eventType] && events[eventType]()
|
||||
}
|
||||
//点击切换搜索条件/分类
|
||||
const changeConditionTag = (tag) => {
|
||||
console.log(tag)
|
||||
state.conditionType = tag
|
||||
if (tag === 'file') {
|
||||
state.conditionTag = '文件'
|
||||
} else if (tag === 'imgAndVideo') {
|
||||
state.conditionTag = '图片与视频'
|
||||
} else if (tag === 'date') {
|
||||
state.conditionTag = '日期'
|
||||
} else if (tag === 'member') {
|
||||
state.conditionTag = '群成员'
|
||||
} else {
|
||||
state.conditionTag = ''
|
||||
}
|
||||
}
|
||||
|
||||
//取消群公告编辑并返回查看
|
||||
const cancelEditGroupNotice = () => {
|
||||
//切换群公告编辑模式为查看
|
||||
state.groupNoticeEditMode = 3
|
||||
state.groupNoticeModalActionBtns = {
|
||||
confirmBtn: {
|
||||
text: '编辑',
|
||||
doLoading: false,
|
||||
disabled: false
|
||||
},
|
||||
cancelBtn: false
|
||||
}
|
||||
//切换确定按钮事件为编辑
|
||||
state.groupNoticeModalConfirmBtnEvent = 'edit'
|
||||
}
|
||||
|
||||
// 群公告模态框确定按钮事件
|
||||
const handleGroupNoticeModalConfirm = () => {
|
||||
if (state.groupNoticeModalConfirmBtnEvent === 'edit') {
|
||||
//点击切换群公告编辑模式为编辑
|
||||
state.groupNoticeEditMode = 2
|
||||
state.groupNoticeModalActionBtns = {
|
||||
confirmBtn: {
|
||||
text: '完成',
|
||||
doLoading: false,
|
||||
disabled: true
|
||||
},
|
||||
cancelBtn: true
|
||||
}
|
||||
//切换确定按钮事件为输入
|
||||
state.groupNoticeModalConfirmBtnEvent = 'fillIn'
|
||||
if (state.groupNoticeInfo?.id) {
|
||||
state.groupNoticeInEdit = state.groupNoticeInfo.content
|
||||
state.groupNoticeModalActionBtns.confirmBtn.disabled = false
|
||||
}
|
||||
} else if (state.groupNoticeModalConfirmBtnEvent === 'fillIn') {
|
||||
//点击显示发布提示
|
||||
state.isShowNoticeHintModal = true
|
||||
if (state?.groupNoticeInfo?.id && !state.groupNoticeInEdit) {
|
||||
//如果是在编辑中,但是没有输入内容,此时点击完成即为删除群公告
|
||||
state.noticeHintModalContent = '确定清空群公告吗?'
|
||||
state.noticeHintModalActionBtns = {
|
||||
confirmBtn: {
|
||||
text: '清空',
|
||||
doLoading: true
|
||||
},
|
||||
cancelBtn: true
|
||||
}
|
||||
//切换公告提示模式为清空
|
||||
state.noticeHintMode = 'clear'
|
||||
} else {
|
||||
state.noticeHintModalContent = '发布该公告会通知全部群成员'
|
||||
state.noticeHintModalActionBtns = {
|
||||
confirmBtn: {
|
||||
text: '发布',
|
||||
doLoading: true
|
||||
},
|
||||
cancelBtn: true
|
||||
}
|
||||
//切换公告提示模式为发布
|
||||
state.noticeHintMode = 'publish'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 群公告模态框取消按钮事件
|
||||
const handleGroupNoticeModalCancel = () => {
|
||||
if (state.groupNoticeModalConfirmBtnEvent === 'fillIn') {
|
||||
if (state.groupNoticeInEdit || (state.groupNoticeInfo?.id && !state.groupNoticeInEdit)) {
|
||||
//如果有正在编辑中的公告或者编辑已发布的公告内容为空,显示确认取消编辑弹窗
|
||||
state.isShowNoticeHintModal = true
|
||||
state.noticeHintModalContent = '退出本次编辑'
|
||||
state.noticeHintModalActionBtns = {
|
||||
confirmBtn: {
|
||||
text: '继续编辑',
|
||||
doLoading: false
|
||||
},
|
||||
cancelBtn: {
|
||||
text: '退出'
|
||||
}
|
||||
}
|
||||
//切换公告提示模式为取消
|
||||
state.noticeHintMode = 'cancel'
|
||||
} else {
|
||||
//没有正在编辑中的公告,退出编辑
|
||||
cancelEditGroupNotice()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 群公告模态框关闭事件
|
||||
const handleGroupNoticeModalClose = () => {
|
||||
//关闭应与取消事件一致
|
||||
handleGroupNoticeModalCancel()
|
||||
}
|
||||
|
||||
// 群公告提示模态框确认按钮事件
|
||||
const handleNoticeHintModalConfirm = (closeLoading) => {
|
||||
console.log('handleNoticeHintModalConfirm')
|
||||
if (state.noticeHintMode === 'cancel') {
|
||||
//不退出,回到编辑
|
||||
state.isShowNoticeHintModal = false
|
||||
} else if (state.noticeHintMode === 'publish') {
|
||||
//发布
|
||||
doPublishGroupNotice(closeLoading)
|
||||
} else if (state.noticeHintMode === 'clear') {
|
||||
//清空
|
||||
doClearGroupNotice(closeLoading)
|
||||
}
|
||||
}
|
||||
|
||||
// 群公告提示模态框取消按钮事件
|
||||
const handleNoticeHintModalCancel = () => {
|
||||
console.log('handleNoticeHintModalCancel')
|
||||
if (state.noticeHintMode === 'publish') {
|
||||
//取消发布,回到编辑
|
||||
state.isShowNoticeHintModal = false
|
||||
} else if (state.noticeHintMode === 'cancel') {
|
||||
//清除正在编辑中的公告并退出编辑
|
||||
state.groupNoticeInEdit = ''
|
||||
state.isShowNoticeHintModal = false
|
||||
cancelEditGroupNotice()
|
||||
} else if (state.noticeHintMode === 'clear') {
|
||||
//不清空,继续编辑
|
||||
state.isShowNoticeHintModal = false
|
||||
}
|
||||
}
|
||||
|
||||
// 群公告模态框输入事件
|
||||
const handleGroupNoticeModalInput = (value) => {
|
||||
console.log(value)
|
||||
if (value.trim()) {
|
||||
state.groupNoticeModalActionBtns.confirmBtn.disabled = false
|
||||
} else {
|
||||
if (!state.groupNoticeInfo?.id) {
|
||||
state.groupNoticeModalActionBtns.confirmBtn.disabled = true
|
||||
} else {
|
||||
state.groupNoticeModalActionBtns.confirmBtn.disabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 发布群公告
|
||||
const doPublishGroupNotice = (closeLoading) => {
|
||||
let params = {
|
||||
notice_id: state?.groupNoticeInfo?.id || 0,
|
||||
group_id: talkParams.receiver_id,
|
||||
title: '',
|
||||
content: state.groupNoticeInEdit,
|
||||
is_top: 0,
|
||||
is_confirm: 0
|
||||
}
|
||||
console.log(params)
|
||||
const resp = ServeEditGroupNotice(params)
|
||||
resp
|
||||
.then((res) => {
|
||||
closeLoading()
|
||||
if (res.code == 200) {
|
||||
// 发布成功,关闭群公告模态框
|
||||
state.isShowGroupNoticeModal = false
|
||||
state.isShowNoticeHintModal = false
|
||||
state.groupNoticeContentChange = state.groupNoticeInEdit
|
||||
state.groupNoticeInEdit = ''
|
||||
cancelEditGroupNotice()
|
||||
window['$message'].success(res.msg)
|
||||
} else {
|
||||
window['$message'].warning(res.msg)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
closeLoading()
|
||||
window['$message'].warning(err.msg)
|
||||
})
|
||||
}
|
||||
|
||||
//获取群公告列表
|
||||
const getGroupNotices = () => {
|
||||
ServeGetGroupNotices({
|
||||
group_id: talkParams.receiver_id
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.code == 200) {
|
||||
if (res?.data?.items[0]?.id) {
|
||||
state.groupNoticeInfo = res.data.items[0]
|
||||
} else {
|
||||
state.groupNoticeInfo = {
|
||||
id: 0,
|
||||
avatar: '',
|
||||
updater_name: '',
|
||||
updated_at: '',
|
||||
content: ''
|
||||
}
|
||||
}
|
||||
} else {
|
||||
window['$message'].warning(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 清空群公告
|
||||
const doClearGroupNotice = (closeLoading) => {
|
||||
ServeDeleteGroupNotice({
|
||||
notice_id: state.groupNoticeInfo.id,
|
||||
group_id: talkParams.receiver_id
|
||||
})
|
||||
.then((res) => {
|
||||
closeLoading()
|
||||
if (res.code == 200) {
|
||||
// 清空成功,关闭群公告模态框并恢复群公告模态框初始状态
|
||||
state.groupNoticeInfo = {
|
||||
id: 0,
|
||||
avatar: '',
|
||||
updater_name: '',
|
||||
updated_at: '',
|
||||
content: ''
|
||||
}
|
||||
state.isShowGroupNoticeModal = false
|
||||
state.isShowNoticeHintModal = false
|
||||
state.groupNoticeContentChange = ''
|
||||
cancelEditGroupNotice()
|
||||
window['$message'].success(res.msg)
|
||||
} else {
|
||||
window['$message'].warning(res.msg)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
closeLoading()
|
||||
window['$message'].warning(err.msg)
|
||||
})
|
||||
}
|
||||
// 群公告模态框显示事件
|
||||
const handleGroupNoticeModalShow = (isAdmin) => {
|
||||
state.isAdmin = isAdmin
|
||||
if (isAdmin) {
|
||||
state.groupNoticeModalActionBtns = {
|
||||
confirmBtn: {
|
||||
text: '编辑',
|
||||
doLoading: false,
|
||||
disabled: false
|
||||
},
|
||||
cancelBtn: false
|
||||
}
|
||||
} else {
|
||||
;(state.groupNoticeModalActionBtns.confirmBtn as any) = false
|
||||
}
|
||||
state.isShowGroupNoticeModal = true
|
||||
getGroupNotices()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -127,19 +441,333 @@ const onPanelHeaderEvent = (eventType: string) => {
|
||||
|
||||
<n-drawer
|
||||
v-model:show="state.isShowGroupAside"
|
||||
:width="400"
|
||||
:width="453"
|
||||
placement="right"
|
||||
:trap-focus="false"
|
||||
:block-scroll="false"
|
||||
show-mask="transparent"
|
||||
:show-mask="true || 'transparent'"
|
||||
to="#drawer-container"
|
||||
>
|
||||
<GroupPanel :gid="talkParams.receiver_id" @close="state.isShowGroupAside = false" />
|
||||
<GroupPanel
|
||||
:gid="talkParams.receiver_id"
|
||||
@close="state.isShowGroupAside = false"
|
||||
:talkType="talkParams.type"
|
||||
@handleSearchRecordByConditionModalShow="state.isShowSearchRecordByConditionModal = true"
|
||||
@handleGroupNoticeModalShow="handleGroupNoticeModalShow"
|
||||
:groupNoticeContentChange="state.groupNoticeContentChange"
|
||||
/>
|
||||
</n-drawer>
|
||||
|
||||
<customModal
|
||||
v-model:show="state.isShowSearchRecordByConditionModal"
|
||||
:title="`${talkParams.type === 1 ? '与' : ''} "${
|
||||
talkParams.username
|
||||
}" 的聊天记录`"
|
||||
:style="state.customSearchRecordByConditionModalStyle"
|
||||
:customCloseBtn="true"
|
||||
:closable="false"
|
||||
>
|
||||
<template #content>
|
||||
<div class="search-record-modal-searchArea">
|
||||
<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.searchRecordByConditionText"
|
||||
placeholder="请输入"
|
||||
clearable
|
||||
>
|
||||
<template #clear-icon>
|
||||
<img src="@/assets/image/icon/close-btn-grey-line.png" alt="close" />
|
||||
</template>
|
||||
<template #prefix>
|
||||
<n-tag closable v-if="state.conditionTag" @close="changeConditionTag('')">
|
||||
{{ state.conditionTag }}
|
||||
</n-tag>
|
||||
</template>
|
||||
</n-input>
|
||||
</div>
|
||||
<div class="search-area-condition">
|
||||
<span @click="changeConditionTag('file')">文件</span>
|
||||
<span @click="changeConditionTag('imgAndVideo')">图片与视频</span>
|
||||
<n-popover trigger="click" placement="bottom-start" style="height: 312px; padding: 0;">
|
||||
<template #trigger>
|
||||
<span id="date-condition" @click="changeConditionTag('date')">日期</span>
|
||||
</template>
|
||||
<historyRecord conditionType="dateTimePicker" v-if="state.conditionType === 'date'" />
|
||||
</n-popover>
|
||||
<n-popover
|
||||
trigger="click"
|
||||
placement="bottom-start"
|
||||
style="height: 505px; padding: 0;"
|
||||
v-if="talkParams.type === 2"
|
||||
>
|
||||
<template #trigger>
|
||||
<span @click="changeConditionTag('member')">群成员</span>
|
||||
</template>
|
||||
<div>
|
||||
<text>这里是memberList</text>
|
||||
</div>
|
||||
</n-popover>
|
||||
</div>
|
||||
</n-card>
|
||||
</div>
|
||||
<div class="search-record-modal-content">
|
||||
<n-card>
|
||||
<div
|
||||
class="search-record-card"
|
||||
v-if="state.searchRecordByConditionText || state.conditionType"
|
||||
>
|
||||
<historyRecord :conditionType="state.conditionType" />
|
||||
</div>
|
||||
<div
|
||||
class="search-record-empty"
|
||||
v-if="!state.searchRecordByConditionText && !state.conditionType"
|
||||
>
|
||||
<img src="@/assets/image/chatList/search-empty.png" alt="" />
|
||||
<span>无内容</span>
|
||||
</div>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
</customModal>
|
||||
|
||||
<customModal
|
||||
v-model:show="state.isShowGroupNoticeModal"
|
||||
:title="`"${talkParams.username}" 的群公告`"
|
||||
:style="state.customGroupNoticeModalStyle"
|
||||
:customCloseBtn="true"
|
||||
:closable="false"
|
||||
:actionBtns="state.groupNoticeModalActionBtns"
|
||||
:customModalBtnsStyle="state.groupNoticeModalActionBtnsStyle"
|
||||
@confirm="handleGroupNoticeModalConfirm"
|
||||
@cancel="handleGroupNoticeModalCancel"
|
||||
:customCloseEvent="state.groupNoticeEditMode === 2 ? true : false"
|
||||
@closeModal="handleGroupNoticeModalClose"
|
||||
>
|
||||
<template #content>
|
||||
<div class="group-notice-modal-content">
|
||||
<div class="group-notice-text-area" v-if="state.groupNoticeEditMode === 2">
|
||||
<n-input
|
||||
v-model:value="state.groupNoticeInEdit"
|
||||
type="textarea"
|
||||
:autosize="{
|
||||
minRows: 22,
|
||||
maxRows: 22
|
||||
}"
|
||||
placeholder="请输入"
|
||||
:maxlength="500"
|
||||
:show-count="true"
|
||||
@input="handleGroupNoticeModalInput"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="group-notice-info"
|
||||
v-if="state.groupNoticeEditMode === 3 && state.groupNoticeInfo?.id"
|
||||
>
|
||||
<div class="group-notice-header">
|
||||
<avatarModule
|
||||
:mode="1"
|
||||
:avatar="state.groupNoticeInfo.avatar"
|
||||
:userName="state.groupNoticeInfo.updater_name"
|
||||
:groupType="0"
|
||||
:customStyle="{
|
||||
width: '42px',
|
||||
height: '42px'
|
||||
}"
|
||||
:customTextStyle="{
|
||||
fontSize: '14px',
|
||||
fontWeight: 'bold',
|
||||
color: '#fff',
|
||||
lineHeight: '20px'
|
||||
}"
|
||||
></avatarModule>
|
||||
<div class="group-notice-header-userInfo">
|
||||
<span style="color: #1b1b1b; font-weight: 600; line-height: 20px;">{{
|
||||
state.groupNoticeInfo.updater_name
|
||||
}}</span>
|
||||
<span>{{ state.groupNoticeInfo.updated_at }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group-notice-content">
|
||||
<span>{{ state.groupNoticeInfo.content }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="group-notice-empty"
|
||||
v-if="state.groupNoticeEditMode === 3 && !state.groupNoticeInfo?.id"
|
||||
>
|
||||
<img src="@/assets/image/chatList/search-empty.png" alt="" />
|
||||
<span>暂无公告</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</customModal>
|
||||
|
||||
<customModal
|
||||
v-model:show="state.isShowNoticeHintModal"
|
||||
title="提示"
|
||||
:style="state.customNoticeHintModalStyle"
|
||||
:closable="false"
|
||||
:actionBtns="state.noticeHintModalActionBtns"
|
||||
customModalBtnsStyle="padding: 0 0 30px;"
|
||||
@confirm="handleNoticeHintModalConfirm"
|
||||
@cancel="handleNoticeHintModalCancel"
|
||||
>
|
||||
<template #content>
|
||||
<div class="notice-hint-modal-content">
|
||||
<text>{{ state.noticeHintModalContent }}</text>
|
||||
</div>
|
||||
</template>
|
||||
</customModal>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.drawer-target {
|
||||
overflow: hidden;
|
||||
}
|
||||
.search-record-modal-searchArea {
|
||||
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);
|
||||
}
|
||||
:deep(.n-card__content) {
|
||||
padding: 27px 12px 0;
|
||||
}
|
||||
.search-record-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.search-record-input-title {
|
||||
width: 78px;
|
||||
}
|
||||
}
|
||||
.search-area-condition {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 22px 0 11px;
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #46299d;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
margin: 0 62px 0 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-record-modal-content {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 0 12px;
|
||||
margin: 18px 0 0;
|
||||
:deep(.n-card__content) {
|
||||
padding: 0;
|
||||
}
|
||||
:deep(.n-card) {
|
||||
border: 0;
|
||||
box-shadow: 0 3px 6px 1px rgba(188, 188, 188, 0.18);
|
||||
}
|
||||
.search-record-card {
|
||||
}
|
||||
.search-record-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 455px;
|
||||
box-sizing: border-box;
|
||||
img {
|
||||
width: 160px;
|
||||
height: 104px;
|
||||
}
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
font-weight: 400;
|
||||
margin: 13px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.group-notice-modal-content {
|
||||
.group-notice-text-area {
|
||||
:deep(.n-input-wrapper) {
|
||||
padding: 20px 23px 15px;
|
||||
}
|
||||
:deep(.n-input-word-count) {
|
||||
right: 23px;
|
||||
bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.group-notice-info {
|
||||
.group-notice-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 20px 0;
|
||||
margin: 0 12px;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
.group-notice-header-userInfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
margin: 0 0 0 10px;
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #adadad;
|
||||
font-weight: 400;
|
||||
line-height: 17px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.group-notice-content {
|
||||
padding: 20px 0;
|
||||
margin: 0 12px;
|
||||
span {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.group-notice-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 552px;
|
||||
box-sizing: border-box;
|
||||
img {
|
||||
width: 160px;
|
||||
height: 104px;
|
||||
}
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
font-weight: 400;
|
||||
margin: 14px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.notice-hint-modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
text {
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
font-weight: 400;
|
||||
color: #1f2225;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -7,7 +7,8 @@ import {
|
||||
reactive,
|
||||
onBeforeMount,
|
||||
getCurrentInstance,
|
||||
h
|
||||
h,
|
||||
nextTick
|
||||
} from 'vue'
|
||||
import { onBeforeRouteUpdate } from 'vue-router'
|
||||
import { useDialogueStore, useTalkStore } from '@/store'
|
||||
@ -36,6 +37,11 @@ import xNDataTable from '@/components/x-naive-ui/x-n-data-table/index.vue'
|
||||
import flTree from '@/components/flnlayout/tree/flnindex.vue'
|
||||
import { processError, processSuccess } from '@/utils/helper/message.js'
|
||||
import chatAppSearchList from '@/components/search/searchList.vue'
|
||||
import { ServeSeachQueryAll, ServeQueryTalkRecord, ServeUserGroupChatList } from '@/api/search'
|
||||
import { getUserInfoByERPUserId } from '@/api/user'
|
||||
|
||||
import { useRouter } from 'vue-router'
|
||||
const router = useRouter()
|
||||
|
||||
const currentInstance = getCurrentInstance()
|
||||
const $request = currentInstance?.appContext.config.globalProperties?.$request
|
||||
@ -79,24 +85,28 @@ const renderChatAppSearch = () => {
|
||||
console.log(searchText, searchResultKey, talk_type, receiver_id)
|
||||
const result = JSON.parse(decodeURIComponent(res))
|
||||
console.log(result)
|
||||
},
|
||||
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
|
||||
}
|
||||
console.log(searchResultKey, searchText)
|
||||
}
|
||||
},
|
||||
{}
|
||||
)
|
||||
}
|
||||
|
||||
//ES搜索聊天记录-主页搜索什么都有、指定用户、指定群、群与用户概览
|
||||
const ServeSeachQueryAll = () => {
|
||||
let url = '/api/v1/elasticsearch/query-all'
|
||||
let params = {}
|
||||
let config = {
|
||||
baseURL: import.meta.env.VITE_BASE_API
|
||||
}
|
||||
return $request.HTTP.components.postDataByParams(url, params, config).then((res) => {
|
||||
console.log(res)
|
||||
})
|
||||
}
|
||||
|
||||
const state = reactive({
|
||||
isShowAddressBookModal: false, // 是否显示通讯录模态框
|
||||
customModalStyle: {
|
||||
@ -174,7 +184,7 @@ const state = reactive({
|
||||
field: 'groupName',
|
||||
width: 200,
|
||||
render(row, index) {
|
||||
return row.groupName
|
||||
return row.group_name
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -183,7 +193,16 @@ const state = reactive({
|
||||
width: 400,
|
||||
ellipsis: true,
|
||||
render(row, index) {
|
||||
return row.groupType
|
||||
let groupType = row.group_type
|
||||
if (groupType == 1) {
|
||||
return '普通群'
|
||||
} else if (groupType == 2) {
|
||||
return '部门群'
|
||||
} else if (groupType == 3) {
|
||||
return '项目群'
|
||||
} else if (groupType == 4) {
|
||||
return '公司群'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -225,7 +244,17 @@ const state = reactive({
|
||||
type: 'render',
|
||||
render: renderChatAppSearch
|
||||
}
|
||||
] // 聊天搜索选项
|
||||
], // 聊天搜索选项
|
||||
isShowSearchRecordModal: false, // 是否显示搜索聊天记录模态框
|
||||
customSearchRecordModalStyle: {
|
||||
width: '997px',
|
||||
height: '740px',
|
||||
backgroundColor: '#F9F9FD'
|
||||
}, //自定义模态框样式
|
||||
searchRecordText: '', // 搜索聊天记录文本
|
||||
ServeQueryTalkRecordParams: '', // 搜索聊天记录参数
|
||||
ServeQueryTalkRecordDetailParams: '', // 搜索聊天记录详情参数
|
||||
isShowSearchRecordDetailInfo: false // 是否显示搜索聊天记录详情
|
||||
})
|
||||
|
||||
const items = computed((): ISession[] => {
|
||||
@ -249,7 +278,7 @@ const items = computed((): ISession[] => {
|
||||
watch(
|
||||
() => talkStore,
|
||||
(newValue, oldValue) => {
|
||||
console.log(newValue)
|
||||
// console.log(newValue)
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
@ -264,10 +293,39 @@ watch(
|
||||
state.addressBookTableWidth = 800
|
||||
state.clickKey = 3
|
||||
state.treeRefreshCount++
|
||||
state.addressBookPage = 1
|
||||
}
|
||||
getDepPoisUser()
|
||||
}
|
||||
)
|
||||
watch(
|
||||
() => state.groupChatListSearchGroupName,
|
||||
(newValue, oldValue) => {
|
||||
if (newValue) {
|
||||
state.groupChatListPage = 1
|
||||
} else {
|
||||
state.groupChatListPage = 1
|
||||
}
|
||||
getUserGroupChatList()
|
||||
}
|
||||
)
|
||||
|
||||
// watch(
|
||||
// () => state.searchRecordText,
|
||||
// (newValue, oldValue) => {
|
||||
// console.log(newValue, 'newValue')
|
||||
// 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: '' //最后一条群名
|
||||
// })
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
|
||||
// 列表加载状态
|
||||
const loadStatus = computed(() => talkStore.loadStatus)
|
||||
@ -329,6 +387,7 @@ onBeforeRouteUpdate(onInitialize)
|
||||
|
||||
onBeforeMount(() => {
|
||||
getTreeData()
|
||||
getUserGroupChatList()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
@ -403,8 +462,40 @@ const getDepPoisUser = () => {
|
||||
})
|
||||
}
|
||||
//点击进入对应的聊天
|
||||
const handleEnterChat = (row) => {
|
||||
const handleEnterChat = async (row) => {
|
||||
console.log(row)
|
||||
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()
|
||||
})
|
||||
}
|
||||
//处理页数变化
|
||||
const handleAddressBookPagination = (page) => {
|
||||
@ -433,16 +524,121 @@ const handleAddressBookTabChange = (value) => {
|
||||
//处理群聊列表搜索
|
||||
const changeGroupChatListSearch = (value) => {
|
||||
console.log(value, 'value')
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//处理群聊列表页数变化
|
||||
const handleGroupChatListPagination = (value) => {
|
||||
console.log(value, 'value')
|
||||
state.groupChatListPage = value
|
||||
getUserGroupChatList()
|
||||
}
|
||||
//处理群聊列表每页条数变化
|
||||
const handleGroupChatListPaginationSize = (value) => {
|
||||
console.log(value, 'value')
|
||||
state.groupChatListPageSize = value
|
||||
state.groupChatListPage = 1
|
||||
getUserGroupChatList()
|
||||
}
|
||||
//处理搜索聊天记录点击
|
||||
const handleClickSearchItem = (searchText, searchResultKey, talk_type, receiver_id, res) => {
|
||||
console.log(searchText, searchResultKey, talk_type, receiver_id)
|
||||
const result = JSON.parse(decodeURIComponent(res))
|
||||
console.log(result)
|
||||
if (searchResultKey === 'general_infos') {
|
||||
state.ServeQueryTalkRecordDetailParams = encodeURIComponent(
|
||||
JSON.stringify({
|
||||
last_group_id: 0, //最后一条群id
|
||||
last_member_id: 0, //最后一条用户id
|
||||
receiver_id: receiver_id, //查详情的时候需传入
|
||||
talk_type: talk_type //1私聊2群聊
|
||||
})
|
||||
)
|
||||
nextTick(() => {
|
||||
searchDetailListRef.value?.doLoadMore(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
//处理点击停留item变化
|
||||
const handleClickStayItemChange = (item) => {
|
||||
if (item) {
|
||||
state.isShowSearchRecordDetailInfo = true
|
||||
} else {
|
||||
state.isShowSearchRecordDetailInfo = false
|
||||
}
|
||||
}
|
||||
|
||||
// 定义搜索列表组件的ref
|
||||
const searchListRef = ref()
|
||||
|
||||
// 定义搜索详情列表组件的ref
|
||||
const searchDetailListRef = ref()
|
||||
|
||||
//搜索聊天记录列表加载更多
|
||||
const loadMoreRecordList = () => {
|
||||
searchListRef.value?.doLoadMore()
|
||||
}
|
||||
|
||||
// 搜索聊天记录详情列表加载更多
|
||||
const loadMoreRecordDetail = () => {
|
||||
searchDetailListRef.value?.doLoadMore()
|
||||
}
|
||||
|
||||
const handleMoreRecordLastIdChange = (
|
||||
last_id,
|
||||
last_group_id,
|
||||
last_member_id,
|
||||
last_receiver_user_name,
|
||||
last_receiver_group_name
|
||||
) => {
|
||||
let idChanges = {
|
||||
last_id,
|
||||
last_group_id,
|
||||
last_member_id,
|
||||
last_receiver_user_name,
|
||||
last_receiver_group_name
|
||||
}
|
||||
state.ServeQueryTalkRecordParams = encodeURIComponent(
|
||||
JSON.stringify(
|
||||
Object.assign({}, JSON.parse(decodeURIComponent(state.ServeQueryTalkRecordParams)), idChanges)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
const handleRecordDetailLastIdChange = (last_id, last_group_id, last_member_id) => {
|
||||
let idChanges = {
|
||||
last_id,
|
||||
last_group_id,
|
||||
last_member_id
|
||||
}
|
||||
state.ServeQueryTalkRecordDetailParams = encodeURIComponent(
|
||||
JSON.stringify(
|
||||
Object.assign(
|
||||
{},
|
||||
JSON.parse(decodeURIComponent(state.ServeQueryTalkRecordDetailParams)),
|
||||
idChanges
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -651,6 +847,70 @@ const handleGroupChatListPaginationSize = (value) => {
|
||||
</div>
|
||||
</template>
|
||||
</customModal>
|
||||
|
||||
<customModal
|
||||
v-model:show="state.isShowSearchRecordModal"
|
||||
title="搜索聊天记录"
|
||||
:style="state.customSearchRecordModalStyle"
|
||||
:customCloseBtn="true"
|
||||
:closable="false"
|
||||
>
|
||||
<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">
|
||||
<div class="search-record-list" v-loadmore="loadMoreRecordList">
|
||||
<chatAppSearchList
|
||||
ref="searchListRef"
|
||||
:searchResultPageSize="10"
|
||||
:listLimit="false"
|
||||
:apiRequest="ServeQueryTalkRecord"
|
||||
:apiParams="state.ServeQueryTalkRecordParams"
|
||||
:searchText="state.searchRecordText"
|
||||
:isPagination="true"
|
||||
searchResultKey="general_infos"
|
||||
@clickSearchItem="handleClickSearchItem"
|
||||
:useClickStay="true"
|
||||
@clickStayItemChange="handleClickStayItemChange"
|
||||
@lastIdChange="handleMoreRecordLastIdChange"
|
||||
></chatAppSearchList>
|
||||
</div>
|
||||
<div class="search-record-detail" v-loadmore="loadMoreRecordDetail">
|
||||
<chatAppSearchList
|
||||
ref="searchDetailListRef"
|
||||
v-if="state.isShowSearchRecordDetailInfo"
|
||||
:searchResultPageSize="10"
|
||||
:listLimit="false"
|
||||
:apiRequest="ServeQueryTalkRecord"
|
||||
:apiParams="state.ServeQueryTalkRecordDetailParams"
|
||||
:searchText="state.searchRecordText"
|
||||
:isPagination="true"
|
||||
:searchRecordDetail="true"
|
||||
@lastIdChange="handleRecordDetailLastIdChange"
|
||||
></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>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@ -808,4 +1068,58 @@ html[theme-mode='dark'] {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.search-record-detail {
|
||||
width: 578px;
|
||||
height: 517px;
|
||||
border: 1px solid #efeff5;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -69,20 +69,20 @@ const onSetMenu = () => {
|
||||
</div>
|
||||
|
||||
<div class="module right-module">
|
||||
<n-icon
|
||||
<!-- <n-icon
|
||||
v-show="type == 2"
|
||||
:component="Announcement"
|
||||
:size="18"
|
||||
class="icon"
|
||||
@click="emit('evnet', 'notice')"
|
||||
/>
|
||||
/> -->
|
||||
<n-icon
|
||||
v-show="type == 2"
|
||||
:component="Peoples"
|
||||
:size="18"
|
||||
class="icon"
|
||||
@click="emit('evnet', 'group')"
|
||||
/>
|
||||
>
|
||||
<img style="width: 20px; height: 20px;" src="@/assets/image/chatList/chat-settings.png" alt="" />
|
||||
</n-icon>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|