This commit is contained in:
Phoenix 2025-06-11 14:48:09 +08:00
commit a506b4dcc1
11 changed files with 334 additions and 38 deletions

View File

@ -686,13 +686,18 @@ const fileTypeAvatar = (fileType) => {
const previewPDF = (item) => {
console.log(item)
if (typeof plus !== 'undefined') {
downloadAndOpenFile(item)
} else {
document.addEventListener('plusready', () => {
downloadAndOpenFile(item)
})
}
// if (typeof plus !== 'undefined') {
// downloadAndOpenFile(item)
// } else {
// document.addEventListener('plusready', () => {
// downloadAndOpenFile(item)
// })
// }
window.open(
`${import.meta.env.VITE_PAGE_URL}/office?url=${item.extra.path}`,
'_blank',
'width=1200,height=900,left=200,top=200,toolbar=no,menubar=no,scrollbars=yes,resizable=yes,location=no,status=no'
)
}
const downloadAndOpenFile = (item) => {
@ -926,7 +931,6 @@ body:deep(.round-3) {
}
.condition-each-resultList {
.condition-each-resultList-each {
border-bottom: 1px solid #f8f8f8;
.condition-each-result-main {
display: flex;
flex-direction: row;
@ -942,9 +946,16 @@ body:deep(.round-3) {
flex-direction: row;
align-items: center;
justify-content: flex-start;
padding: 14px 0;
padding: 14px 20px;
// background-color: #f3f3f3;
border-radius: 4px;
cursor: pointer;
border-bottom: 1px solid #f8f8f8;
&:hover {
background-color: rgba(70, 41, 157, 0.1)
}
.attachment-avatar {
display: flex;
flex-direction: row;
@ -1126,6 +1137,10 @@ body:deep(.round-3) {
.image-container {
width: 100% !important;
height: 100% !important;
&:hover {
cursor: pointer;
border: 1px solid #46299d;
}
}
:deep(.n-image) {

View File

@ -69,7 +69,43 @@
class="text-[12px] font-regular"
:text="resultDetail"
:searchText="props.searchText"
v-if="props.searchItem?.msg_type !== 3 && props.searchItem?.msg_type !== 6"
/>
<div class="message-component-wrapper" v-if="props.searchItem?.msg_type === 3" @click.stop>
<component
:is="MessageComponents[props.searchItem?.msg_type] || 'unknown-message'"
:extra="resultDetail"
:data="props?.searchItem"
/>
</div>
<div class="file-message-wrapper" v-if="props.searchItem?.msg_type === 6" @click.stop>
<div class="condition-each-result-attachments" @click="previewPDF(resultDetail.path)">
<div class="attachment-avatar">
<img :src="resultDetail?.file_avatar" />
</div>
<div class="attachment-info">
<div class="attachment-info-title">
<span class="text-[14px] font-regular">
{{ resultDetail?.name }}
</span>
<span
class="text-[14px] font-regular"
style="color: #999999; flex-shrink: 0; margin: 0 0 0 20px;"
>
{{ resultDetail?.dateTime }}
</span>
</div>
<div class="attachment-sub-info">
<span class="text-[12px] font-regular">
{{ resultDetail?.typeText }}
</span>
<span class="text-[12px] font-regular" style="flex-shrink: 0; margin: 0 0 0 20px;">
{{ resultDetail?.fileSize }}
</span>
</div>
</div>
</div>
</div>
<div class="searchRecordDetail-fastLocal" v-if="searchRecordDetail">
<span>定位到聊天位置</span>
</div>
@ -85,7 +121,7 @@ import avatarModule from '@/components/avatar-module/index.vue'
import { ref, watch, computed, onMounted, onUnmounted, reactive, defineProps } from 'vue'
import HighlightText from './highLightText.vue'
import { beautifyTime } from '@/utils/datetime'
import { ChatMsgTypeMapping } from '@/constant/message'
import { ChatMsgTypeMapping, MessageComponents } from '@/constant/message'
const props = defineProps({
searchItem: Object | Number,
searchResultKey: {
@ -255,6 +291,8 @@ const resultDetail = computed(() => {
result_detail =
props.searchItem?.msg_type === 1
? props.searchItem?.extra?.content
: props.searchItem?.msg_type === 3 || props.searchItem?.msg_type === 6
? props.searchItem?.extra
: ChatMsgTypeMapping[props.searchItem?.msg_type]
break
default:
@ -262,6 +300,22 @@ const resultDetail = computed(() => {
}
return result_detail
})
const previewPDF = (item) => {
console.log(item)
// if (typeof plus !== 'undefined') {
// downloadAndOpenFile(item)
// } else {
// document.addEventListener('plusready', () => {
// downloadAndOpenFile(item)
// })
// }
window.open(
`${import.meta.env.VITE_PAGE_URL}/office?url=${item}`,
'_blank',
'width=1200,height=900,left=200,top=200,toolbar=no,menubar=no,scrollbars=yes,resizable=yes,location=no,status=no'
)
}
</script>
<style lang="scss" scoped>
.search-item {
@ -321,6 +375,69 @@ const resultDetail = computed(() => {
color: #999999;
line-height: 20px;
}
.file-message-wrapper {
.condition-each-result-attachments {
width: 289px;
height: 62px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
padding: 12px 15px;
background-color: #f3f3f3;
border-radius: 4px;
border-bottom: 1px solid #f8f8f8;
box-sizing: border-box;
.attachment-avatar {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
flex-shrink: 0;
img {
width: 38px;
height: 38px;
}
}
.attachment-info {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
margin: 0 0 0 11px;
width: calc(100% - 38px - 11px);
.attachment-info-title {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
width: 100%;
span {
line-height: 20px;
color: #191919;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.attachment-sub-info {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
width: 100%;
span {
line-height: 17px;
color: #999999;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
}
}
.info-detail-searchRecordDetail {
display: flex;
@ -380,4 +497,31 @@ const resultDetail = computed(() => {
}
}
}
.message-component-wrapper {
width: 154px;
height: 100px;
display: inline-block;
overflow: hidden;
position: relative;
.im-message-video,
.im-message-image,
.image-container {
width: 100% !important;
height: 100% !important;
}
:deep(.n-image) {
width: 100% !important;
height: 100% !important;
}
:deep(img),
:deep(video) {
width: 100% !important;
height: 100% !important;
object-fit: cover !important;
}
}
</style>

View File

@ -16,12 +16,16 @@ const props = defineProps({
createdAt: {
type: String,
required: false
}
},
modalTitle: {
type: String,
required: true
},
})
const isShow=defineModel<boolean>('show')
const { showUserInfoModal } = useInject()
const items = ref<ITalkRecord[]>([])
const title = ref('会话记录')
const title = ref(props?.modalTitle || '会话记录')
const onMaskClick = () => {
isShow.value=false
@ -30,7 +34,7 @@ const onMaskClick = () => {
const onLoadData = () => {
ServeGetForwardRecords({
msg_id: props.msgId,
biz_date: parseTime(new Date(props.createdAt), '{y}{m}')
biz_date: parseTime(new Date(props.createdAt || ''), '{y}{m}')
}).then((res) => {
if (res.code == 200) {
items.value = res.data.items || []

View File

@ -12,7 +12,13 @@ const props = defineProps<{
const isShowRecord = ref(false)
const title = computed(() => {
return [...new Set(props.extra.records.map((v) => v.nickname))].join('、')
const uniqueNames = [...new Set(props.extra.records.map(v => v.nickname))];
if (uniqueNames.length <= 2) {
return uniqueNames.join('和');
} else {
return uniqueNames.slice(0, 2).join('和') + '等';
}
// return [...new Set(props.extra.records.map((v) => v.nickname))].join('')
})
const onClick = () => {
@ -21,7 +27,7 @@ const onClick = () => {
</script>
<template>
<section class="im-message-forward pointer" @click="onClick">
<div class="title">{{ title }} 的会话记录</div>
<div class="title">{{ extra.forward_name || title}}的会话记录</div>
<div class="list" v-for="(record, index) in extra.records" :key="index">
<p>
<span>{{ record.nickname }}: </span>
@ -33,7 +39,7 @@ const onClick = () => {
<span>转发聊天会话记录 ({{ extra.msg_ids.length }})</span>
</div>
<ForwardRecord v-model:show="isShowRecord" :msg-id="data.msg_id" @close="isShowRecord = false" :created-at="data.created_at"/>
<ForwardRecord v-model:show="isShowRecord" :msg-id="data.msg_id" @close="isShowRecord = false" :created-at="data.created_at" :modalTitle="(extra.forward_name || title) + '的会话记录'"/>
</section>
</template>
@ -41,19 +47,21 @@ const onClick = () => {
.im-message-forward {
width: 250px;
min-height: 95px;
max-height: 150px;
max-height: 190px;
border-radius: 10px;
padding: 8px 10px;
border: 1px solid var(--im-message-border-color);
user-select: none;
.title {
height: 30px;
max-height: 60px;
line-height: 30px;
font-size: 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-weight: 400;
margin-bottom: 5px;
}

View File

@ -11,12 +11,20 @@ defineProps<{
let show = ref(false)
</script>
<template>
<section class="im-message-group-notice pointer" @click="show = !show">
<section
class="im-message-group-notice pointer"
@click="show = !show"
:class="{
left: data.float === 'left',
right: data.float === 'right'
}"
>
<div class="title">
<n-tag :bordered="false" size="small" type="primary"> 群公告 </n-tag>
{{ extra.title }}
<!-- <n-tag :bordered="false" size="small" type="primary"> 群公告 </n-tag>
{{ extra.title }} -->
<text>群公告</text>
</div>
<div class="content" :class="{ ellipsis: !show }">
<div class="title" :class="{ ellipsis: !show }">
{{ extra.content }}
</div>
</section>
@ -30,14 +38,14 @@ let show = ref(false)
padding: 8px 10px;
border: 1px solid var(--im-message-border-color);
user-select: none;
background-color: #fff;
.title {
height: 30px;
line-height: 30px;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 44rpx;
font-size: 32rpx;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
font-weight: 400;
margin-bottom: 5px;
position: relative;
@ -56,5 +64,18 @@ let show = ref(false)
white-space: nowrap;
}
}
&.left {
background-color: #fff;
border-radius: 0 16rpx 16rpx 16rpx;
}
&.right {
background-color: #46299d;
border-radius: 16rpx 0 16rpx 16rpx;
.title {
color: #fff;
}
}
}
</style>

View File

@ -27,6 +27,16 @@ const props = defineProps({
data: {
type: Object,
default: () => {}
},
revokeInfo: {
type: Object,
default() {
return {}
}
},
extra: {
type: String,
default: ''
}
})
@ -42,16 +52,92 @@ const onRevoke = () => {
</script>
<template>
<div class="im-message-revoke">
<div class="content">
<div v-if="login_uid === user_id">
<span> 你撤回了一条消息 | {{ formatTime(datetime) }} </span>
<n-button @click="onRevoke" v-if="data.msg_type === 1&&data.extra?.content&&data.is_self_action" text class="text-#46299D text-11px">重新编辑</n-button>
</div>
<span v-else-if="talk_type == 1"> 对方撤回了一条消息 | {{ formatTime(datetime) }} </span>
<span v-else>
"{{ nickname }}" 撤回了一条消息 |
<div class="content" v-if="JSON.stringify(revokeInfo) !== '{}'">
<span v-if="talk_type === 1 && login_uid === revokeInfo.withdraw_id">
你撤回了一条消息 | {{ formatTime(datetime) }}
</span>
<span v-if="talk_type === 1 && login_uid !== revokeInfo.withdraw_id">
{{ revokeInfo.withdraw_name }}撤回了一条消息 | {{ formatTime(datetime) }}
</span>
<span
v-if="
talk_type === 2 &&
login_uid === revokeInfo.withdraw_id &&
login_uid === revokeInfo.retracted_id
"
>
你撤回了一条消息 |
{{ formatTime(datetime) }}
<slot></slot>
</span>
<span
v-if="
talk_type === 2 &&
login_uid === revokeInfo.withdraw_id &&
login_uid !== revokeInfo.retracted_id
"
>
你撤回了{{ revokeInfo.retracted_name }}一条消息 |
{{ formatTime(datetime) }}
</span>
<span
v-if="
talk_type === 2 &&
login_uid !== revokeInfo.withdraw_id &&
revokeInfo.withdraw_id === revokeInfo.retracted_id
"
>
{{ revokeInfo.withdraw_name }}撤回了一条消息 |
{{ formatTime(datetime) }}
</span>
<span
v-if="
talk_type === 2 &&
login_uid !== revokeInfo.withdraw_id &&
login_uid === revokeInfo.retracted_id &&
revokeInfo.withdraw_id !== revokeInfo.retracted_id
"
>
{{ revokeInfo.withdraw_name }}撤回了你一条消息 |
{{ formatTime(datetime) }}
</span>
<span
v-if="
talk_type === 2 &&
login_uid !== revokeInfo.withdraw_id &&
login_uid !== revokeInfo.retracted_id &&
revokeInfo.withdraw_id !== revokeInfo.retracted_id
"
>
{{ revokeInfo.withdraw_name }}撤回了{{ revokeInfo.retracted_name }}一条消息 |
{{ formatTime(datetime) }}
</span>
<div style="display: inline-block;" v-if="login_uid === user_id">
<n-button @click="onRevoke" v-if="data.msg_type === 1&&data.extra?.content&&data.is_self_action" text class="text-#46299D text-11px">重新编辑</n-button>
</div>
<!-- <span v-if="login_uid == user_idA"> 你撤回B了一条消息 | {{ formatTime(datetime) }} </span>
<span v-else-if="login_uid == user_idB"> A撤回你了一条消息 | {{ formatTime(datetime) }} </span>
<span v-else> A撤回B了一条消息 | {{ formatTime(datetime) }} </span> -->
</div>
<div class="content" v-if="JSON.stringify(revokeInfo) === '{}'">
<span v-if="talk_type === 1 && login_uid === user_id">
你撤回了一条消息 | {{ formatTime(datetime) }}
</span>
<span v-if="talk_type === 1 && login_uid !== user_id">
{{ nickname }}撤回了一条消息 | {{ formatTime(datetime) }}
</span>
<span v-if="talk_type === 2 && !extra && login_uid === user_id">
你撤回了一条消息 | {{ formatTime(datetime) }}
</span>
<span v-if="talk_type === 2 && !extra && login_uid !== user_id">
{{ nickname }}撤回了一条消息 | {{ formatTime(datetime) }}
</span>
<span v-if="talk_type === 2 && extra"> {{ extra }} | {{ formatTime(datetime) }} </span>
<div style="display: inline-block;" v-if="login_uid === user_id">
<n-button @click="onRevoke" v-if="data.msg_type === 1&&data.extra?.content&&data.is_self_action" text class="text-#46299D text-11px">重新编辑</n-button>
</div>
</div>
</div>
</template>

View File

@ -70,6 +70,12 @@ class Revoke extends Base {
useTalkStore().updateItem({
index_name: this.getIndexName(),
msg_text: this.resource.text,
revokeInfo: {
retracted_id: this.resource.retracted_id,
retracted_name: this.resource.retracted_name,
withdraw_id: this.resource.withdraw_id,
withdraw_name: this.resource.withdraw_name,
},
updated_at: parseTime(new Date())
})
@ -80,6 +86,12 @@ class Revoke extends Base {
useDialogueStore().updateDialogueRecord({
msg_id: this.msg_id,
revokeInfo: {
retracted_id: this.resource.retracted_id,
retracted_name: this.resource.retracted_name,
withdraw_id: this.resource.withdraw_id,
withdraw_name: this.resource.withdraw_name,
},
is_revoke: 1
})
}

View File

@ -51,7 +51,8 @@ export interface ITalkRecord {
float: string,
is_convert_text?:number//语音记录的 是否是在展示转文本状态 1是 0否,
erp_user_id:number,
read_total_num:number
read_total_num:number,
revokeInfo?: any
}
export interface ITalkRecordExtraText {
@ -81,6 +82,7 @@ export interface ITalkRecordExtraForward {
}[]
talk_type: number
user_id: number
forward_name?: any
}
export interface ITalkRecordExtraGroupNotice {

View File

@ -37,6 +37,7 @@ const labelColor=[
<div class="header">
<div class="title">
<span class="nickname">{{ username }}</span>
<span v-if="data.talk_type == 2">({{data.group_member_num}})</span>
<!-- <span class="badge top" v-show="data.is_top"></span>
<span class="badge roboot" v-show="data.is_robot"></span>
<span class="badge group" v-show="data.talk_type == 2"></span> -->

View File

@ -767,6 +767,8 @@ const onCustomSkipBottomEvent = () => {
:nickname="item.nickname"
:talk_type="item.talk_type"
:datetime="item.created_at"
:revokeInfo="item.revokeInfo"
:extra="item.extra"
/>
</div>

View File

@ -147,6 +147,7 @@ const onSetMenu = () => {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin: 0 5px 0 0;
}
}