新增通讯录页面;新增发起单聊功能;新增聊天会话左滑删除并同时删除localStorage中的记录

This commit is contained in:
wangyifeng 2025-02-05 16:22:32 +08:00
parent 2e3b0b994b
commit 78ca543946
17 changed files with 607 additions and 348 deletions

View File

@ -135,6 +135,15 @@ export const ServeRemoveRecords = (data) => {
})
}
//清空聊天记录
export const ServeEmptyMessage = (data) => {
return request({
url: '/api/v1/talk/message/empty',
method: 'POST',
data,
})
}
// 收藏表情包服务接口
export const ServeCollectEmoticon = (data) => {
return request({

View File

@ -12,7 +12,7 @@ import { reactive, nextTick, computed, h, inject } from 'vue'
// IdCard
// } from '@icon-park/vue-next'
import { ServeTopTalkList, ServeDeleteTalkList, ServeSetNotDisturb } from '@/api/chat'
import { useDialogueStore, useTalkStore } from '@/store'
import { useDialogueStore, useTalkStore, useDialogueListStore } from '@/store'
import { ServeSecedeGroup } from '@/api/group'
// import { ServeDeleteContact, ServeEditContactRemark } from '@/api/contact'
// import { NInput } from 'naive-ui'
@ -28,6 +28,7 @@ export function useSessionMenu() {
const dialogueStore = useDialogueStore()
const talkStore = useTalkStore()
const dialogueListStore = useDialogueListStore()
const user = inject('$user')
@ -105,6 +106,7 @@ export function useSessionMenu() {
const onDeleteTalk = (index_name = '') => {
talkStore.delItem(index_name)
dialogueListStore.delDialogueStorage(index_name)
index_name === indexName.value && dialogueStore.$reset()
}
@ -264,5 +266,5 @@ export function useSessionMenu() {
evnets[key] && evnets[key](dropdown.item)
}
return { dropdown, onCloseContextMenu, onContextMenuTalkHandle, onToTopTalk }
return { dropdown, onCloseContextMenu, onContextMenuTalkHandle, onToTopTalk, onRemoveTalk }
}

View File

@ -51,7 +51,7 @@
"type": "page",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh":false
"enablePullDownRefresh": false
}
},
{
@ -186,6 +186,14 @@
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/addressBook/index",
"type": "page",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {

View File

@ -0,0 +1,30 @@
<template>
<div class="address-book-page">
<zPaging ref="zPaging" :show-scrollbar="false">
<template #top>
<customNavbar
:title="$t('index.mine.addressBook')"
:shadowNum="0"
></customNavbar>
</template>
<div class="address-book">
</div>
</zPaging>
</div>
</template>
<script setup>
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
</script>
<style scoped lang="scss">
::v-deep .zp-paging-container-content {
height: 100%;
display: flex;
}
.address-book-page {
background-image: url('@/static/image/clockIn/z3280@3x.png');
background-size: cover;
background-position: center bottom;
width: 100%;
}
</style>

View File

@ -19,12 +19,12 @@
"
>
<div class="group-member-avatar">
<img v-if="memberItem.avatar" :src="memberItem.avatar" />
<span v-if="!memberItem.avatar" class="text-[24rpx] font-bold">
<img v-if="memberItem?.avatar" :src="memberItem?.avatar" />
<span v-if="!memberItem?.avatar" class="text-[24rpx] font-bold">
{{
(memberItem.nickname || memberItem.nickName).length >= 2
? (memberItem.nickname || memberItem.nickName).slice(-2)
: memberItem.nickname || memberItem.nickName
(memberItem?.nickname || memberItem?.nickName)?.length >= 2
? (memberItem?.nickname || memberItem?.nickName).slice(-2)
: memberItem?.nickname || memberItem?.nickName
}}
</span>
</div>
@ -90,7 +90,9 @@ const toUserDetailPage = (userItem) => {
uni.navigateTo({
url:
'/pages/dialog/dialogDetail/userDetail?erpUserId=' +
(userItem.erp_user_id || userItem.ID),
(userItem.erp_user_id || userItem.ID) +
'&user_id=' +
(userItem.user_id || userItem.id),
})
}

View File

@ -7,7 +7,16 @@
</template>
<div class="edit-group-info">
<div class="group-avatar">
<img :src="state.groupAvatar" />
<avatarModule
:mode="2"
:avatar="groupParams?.groupInfo?.avatar"
:groupType="groupParams?.groupInfo?.group_type"
:customStyle="{
width: '460rpx',
height: '460rpx',
borderRadius: '0',
}"
></avatarModule>
</div>
</div>
<customBtn
@ -19,6 +28,7 @@
</div>
</template>
<script setup>
import avatarModule from '@/components/avatar-module/index.vue'
import customBtn from '@/components/custom-btn/custom-btn.vue'
import { ServeEditGroup } from '@/api/group/index.js'
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
@ -39,18 +49,6 @@ const dialogueParams = reactive({
receiver_id: computed(() => dialogueStore.talk.receiver_id),
})
const state = reactive({
groupAvatar: '', //
})
watch(
() => groupParams.groupInfo,
(newGroupInfo) => {
state.groupAvatar = newGroupInfo.avatar
},
{ deep: true },
)
const onProgressFn = (progress, id) => {
console.log((progress.loaded / progress.total) * 100, 'progress')
@ -62,9 +60,6 @@ const onProgressFn = (progress, id) => {
onLoad((options) => {
console.log(options)
if (options.groupAvatar) {
state.groupAvatar = options.groupAvatar
}
})
//
@ -138,10 +133,6 @@ const editAvatar = () => {
flex-direction: row;
align-items: center;
justify-content: center;
img {
width: 460rpx;
height: 460rpx;
}
}
}
</style>

View File

@ -9,7 +9,15 @@
</template>
<div class="edit-group-info">
<div class="group-avatar">
<img :src="state.groupAvatar" />
<avatarModule
:mode="2"
:avatar="groupParams?.groupInfo?.avatar"
:groupType="groupParams?.groupInfo?.group_type"
:customStyle="{
width: '192rpx',
height: '192rpx',
}"
></avatarModule>
</div>
<div class="group-name">
<span class="text-[28rpx] font-medium">
@ -42,6 +50,7 @@
</div>
</template>
<script setup>
import avatarModule from '@/components/avatar-module/index.vue'
import customBtn from '@/components/custom-btn/custom-btn.vue'
import { ServeEditGroup } from '@/api/group/index.js'
import { useGroupStore, useDialogueStore } from '@/store'
@ -61,15 +70,11 @@ const dialogueParams = reactive({
const state = reactive({
pageTitle: '', //
groupAvatar: '', //
groupName: '', //
})
onLoad((options) => {
console.log(options)
if (options.groupAvatar) {
state.groupAvatar = options.groupAvatar
}
state.groupName = groupParams.groupInfo.group_name
})
@ -126,11 +131,6 @@ const confirmEdit = () => {
flex-direction: row;
align-items: center;
justify-content: center;
img {
width: 192rpx;
height: 192rpx;
border-radius: 50%;
}
}
.group-name {
padding: 0 32rpx;

View File

@ -8,7 +8,12 @@
<div class="chat-settings">
<div class="chat-group-base-infos chat-settings-card">
<div class="base-info-avatar" @click="toEditAvatarPage">
<img :src="groupAvatar" />
<avatarModule
:mode="2"
:avatar="groupParams?.groupInfo?.avatar"
:groupType="groupParams?.groupInfo?.group_type"
:customStyle="{ width: '96rpx', height: '96rpx' }"
></avatarModule>
</div>
<div class="base-info">
<div class="base-info-name">
@ -161,11 +166,8 @@
</div>
</template>
<script setup>
import avatarModule from '@/components/avatar-module/index.vue'
import useConfirm from '@/components/x-confirm/useConfirm.js'
import groupDepartment from '@/static/image/chatList/groupDepartment.png'
import groupProject from '@/static/image/chatList/groupProject.png'
import groupNormal from '@/static/image/chatList/groupNormal.png'
import groupCompany from '@/static/image/chatList/groupCompany.png'
import recordSearchTypeIcon_groupMember from '@/static/image/chatSettings/recordSearchTypeGroupMembers.png'
import recordSearchTypeIcon_date from '@/static/image/chatSettings/recordSearchTypeDate.png'
import recordSearchTypeIcon_imgAndVideo from '@/static/image/chatSettings/recordSearchTypeImgAndVideo.png'
@ -183,7 +185,7 @@ import {
useGroupTypeStore,
} from '@/store'
import { onLoad } from '@dcloudio/uni-app'
import { ServeInviteGroup } from '@/api/group/index'
import { ServeInviteGroup, ServeDismissGroup } from '@/api/group/index'
import { ServeTopTalkList, ServeSetNotDisturb } from '@/api/chat/index'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
@ -306,14 +308,6 @@ onMounted(() => {
]
})
//
const groupAvatar = computed(() => {
return (
groupParams?.groupInfo?.avatar ||
groupTypeMapping[groupParams?.groupInfo?.group_type]?.defaultImg
)
})
//
const groupName = computed(() => {
return groupParams?.groupInfo?.group_name
@ -326,27 +320,21 @@ const groupNum = computed(() => {
// -groupType
const groupTypeMapping = {
0: {
defaultImg: 'textImg',
},
0: {},
1: {
result_type: t('index.mine.normal'),
defaultImg: groupNormal,
},
2: {
result_type: t('index.mine.department'),
result_type_color: '#377EC6',
defaultImg: groupDepartment,
},
3: {
result_type: t('index.mine.project'),
result_type_color: '#C1681C',
defaultImg: groupProject,
},
4: {
result_type: t('index.type.company'),
result_type_color: '#7A58DE',
defaultImg: groupCompany,
},
}
@ -420,9 +408,7 @@ const updateGroupInfos = () => {
//
const toEditGroupInfoPage = () => {
uni.navigateTo({
url:
'/pages/chatSettings/groupManage/editGroupName?groupAvatar=' +
groupAvatar.value,
url: '/pages/chatSettings/groupManage/editGroupName',
})
}
@ -432,9 +418,7 @@ const toEditAvatarPage = () => {
return
}
uni.navigateTo({
url:
'/pages/chatSettings/groupManage/editAvatar?groupAvatar=' +
groupAvatar.value,
url: '/pages/chatSettings/groupManage/editAvatar',
})
}
@ -447,9 +431,7 @@ const toManagePage = (label) => {
return
}
uni.navigateTo({
url:
'/pages/chatSettings/groupManage/editGroupName?groupAvatar=' +
groupAvatar.value,
url: '/pages/chatSettings/groupManage/editGroupName',
})
} else if (label === t('chat.settings.groupNotice')) {
uni.navigateTo({
@ -547,12 +529,15 @@ const showConfirmPrompt = (flag) => {
let subContent = ''
let subContentColor = ''
if (flag === 1) {
//
confirmContent = t('ok') + t('chat.settings.clearChatRecord')
} else if (flag === 2) {
//
confirmContent = t('ok') + t('group.quit.btn')
subContent = t('groupManage.disband.hint')
subContentColor = '#CF3050'
} else if (flag === 3) {
//退
confirmContent = t('ok') + t('group.quit.btn')
subContent = t('groupManage.quit.hint')
subContentColor = '#B4B4B4'
@ -565,7 +550,24 @@ const showConfirmPrompt = (flag) => {
contentText: t('ok'),
confirmText: t('ok'),
cancelText: t('cancel'),
onConfirm: () => {},
onConfirm: async () => {
if (flag === 1) {
useDialogueStore().apiClearRecord()
} else if (flag === 2) {
let params = {
group_id: dialogueParams.receiver_id, //id
}
console.log(params)
const res = await ServeDismissGroup(params)
if (res.code === 200) {
useDialogueStore().updateGroupMembers()
groupStore.ServeGroupDetail()
uni.navigateBack({
delta: 2,
})
}
}
},
onCancel: () => {},
})
}
@ -630,16 +632,7 @@ const inviteMembersInGroup = async (memberList) => {
padding: 32rpx 40rpx 32rpx 20rpx;
.base-info-avatar {
width: 96rpx;
height: 96rpx;
flex-shrink: 0;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
.base-info {
width: 100%;

View File

@ -146,7 +146,7 @@
<div class="userAvatar flex items-center justify-center">
{{ item.nickName.slice(-2) }}
</div>
<div class="ml-[20rpx] flex flex-col items-center">
<div class="ml-[20rpx] flex flex-col justify-center">
<div class="text-[28rpx] font-bold">{{ item.nickName }}</div>
<div class="text-[20rpx] text-[#747474]">
{{ item.jobNum }}
@ -154,11 +154,11 @@
</div>
<tm-popover position="tc">
<div
class="ml-[20rpx] flex h-[68rpx] flex-wrap line-clamp-2 max-w-[342rpx]"
class="ml-[6rpx] flex h-[68rpx] flex-wrap line-clamp-2 max-w-[342rpx]"
>
<div
v-for="post in item.positions"
class="postTag truncate mb-[4rpx] mr-[14rpx] max-w-[164rpx]"
class="postTag truncate mb-[4rpx] ml-[14rpx] max-w-[164rpx]"
>
{{ post.name }}
</div>

View File

@ -259,7 +259,7 @@ const handleConfirm = async () => {
if (allChooseMembers?.value?.length > 0) {
allChooseMembers?.value?.forEach((ele) => {
if (!erp_ids) {
erp_ids = ele.ID
erp_ids = String(ele.ID)
} else {
erp_ids += ',' + ele.ID
}

View File

@ -60,6 +60,7 @@
:isBottom="true"
:btnText="$t('user.detail.sendMsg')"
:subBtnText="$t('user.detail.ringBell')"
@clickBtn="toTalkUser"
></customBtn>
</template>
</ZPaging>
@ -72,6 +73,9 @@ import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
import { onLoad } from '@dcloudio/uni-app'
import { reactive } from 'vue'
import { useTalkStore } from '@/store'
const talkStore = useTalkStore()
import { getUserInfoByClickAvatar } from '@/api/user/index'
import { useI18n } from 'vue-i18n'
@ -79,6 +83,7 @@ const { t } = useI18n()
const state = reactive({
erpUserId: '', //erpid
userId: '', //Id
userInfo: null, //
userBasicInfos: [], //
})
@ -86,15 +91,18 @@ const state = reactive({
onLoad((options) => {
console.log(options)
if (options.erpUserId) {
state.erpUserId = options.erpUserId
state.erpUserId = Number(options.erpUserId)
getUserInfo()
}
if(options.user_id){
state.userId = Number(options.user_id)
}
})
//
const getUserInfo = () => {
let params = {
erp_user_id: Number(state.erpUserId),
erp_user_id: state.erpUserId,
}
console.log(params)
const resp = getUserInfoByClickAvatar(params)
@ -166,6 +174,11 @@ const getUserInfo = () => {
resp.catch(() => {})
}
//
const toTalkUser = () => {
talkStore.toTalk(1, state.userId, state.erpUserId)
}
</script>
<style scoped lang="scss">
.outer-layer {

View File

@ -8,18 +8,36 @@
</div>
<template v-slot:right>
<div class="mr-[36rpx]">
<tm-icon color="rgb(51, 51, 51)" :font-size="36" name="tmicon-gengduo" @click="toChatSettingsPage"></tm-icon>
<tm-icon
color="rgb(51, 51, 51)"
:font-size="36"
name="tmicon-gengduo"
@click="toChatSettingsPage"
></tm-icon>
</div>
</template>
</tm-navbar>
</div>
<div class="root">
<div class="dialogBox">
<ZPaging :fixed="false" use-chat-record-mode :use-page-scroll="false" :refresher-enabled="false"
:show-scrollbar="false" :loading-more-enabled="false" :hide-empty-view="true" height="100%" ref="zpagingRef"
:use-virtual-list="true" :preload-page="1" cell-height-mode="dynamic" virtual-scroll-fps="80"
:loading-more-custom-style="{ display: 'none', height: '0' }" @virtualListChange="virtualListChange"
@scrolltolower="onRefreshLoad">
<ZPaging
:fixed="false"
use-chat-record-mode
:use-page-scroll="false"
:refresher-enabled="false"
:show-scrollbar="false"
:loading-more-enabled="false"
:hide-empty-view="true"
height="100%"
ref="zpagingRef"
:use-virtual-list="true"
:preload-page="1"
cell-height-mode="dynamic"
virtual-scroll-fps="80"
:loading-more-custom-style="{ display: 'none', height: '0' }"
@virtualListChange="virtualListChange"
@scrolltolower="onRefreshLoad"
>
<!-- <template #top>
<div class="load-toolbar pointer">
<span v-if="loadConfig.status == 0"> 正在加载数据中 ... </span>
@ -29,55 +47,103 @@
</template> -->
<!-- 数据加载状态栏 -->
<div class="message-item" v-for="item in virtualList" :id="`zp-id-${item.zp_index}`" :key="item.zp_index"
style="transform: scaleY(-1);">
<div
class="message-item"
v-for="item in virtualList"
:id="`zp-id-${item.zp_index}`"
:key="item.zp_index"
style="transform: scaleY(-1);"
>
<!-- 系统消息 -->
<div v-if="item.msg_type >= 1000" class="message-box">
<component :is="MessageComponents[item.msg_type] || 'unknown-message'" :extra="item.extra" :data="item" />
<component
:is="MessageComponents[item.msg_type] || 'unknown-message'"
:extra="item.extra"
:data="item"
/>
</div>
<!-- 撤回消息 -->
<div v-else-if="item.is_revoke == 1" class="message-box">
<revoke-message :login_uid="userStore.uid" :user_id="item.user_id" :nickname="item.nickname"
:talk_type="item.talk_type" :datetime="item.created_at" />
<revoke-message
:login_uid="userStore.uid"
:user_id="item.user_id"
:nickname="item.nickname"
:talk_type="item.talk_type"
:datetime="item.created_at"
/>
</div>
<div v-else class="message-box record-box" :class="{
'direction-rt': item.float == 'right',
'multi-select': dialogueStore.isOpenMultiSelect,
'multi-select-check': item.isCheck
}">
<div
v-else
class="message-box record-box"
:class="{
'direction-rt': item.float == 'right',
'multi-select': dialogueStore.isOpenMultiSelect,
'multi-select-check': item.isCheck,
}"
>
<!-- 多选按钮 -->
<aside v-if="dialogueStore.isOpenMultiSelect" class="checkbox-column">
<aside
v-if="dialogueStore.isOpenMultiSelect"
class="checkbox-column"
>
<!-- <n-checkbox size="small" :checked="item.isCheck" @update:checked="item.isCheck = !item.isCheck" /> -->
<tm-checkbox :round="10" :defaultChecked="item.isCheck"
@update:modelValue="item.isCheck = !item.isCheck" :size="42" color="#46299D"></tm-checkbox>
<tm-checkbox
:round="10"
:defaultChecked="item.isCheck"
@update:modelValue="item.isCheck = !item.isCheck"
:size="42"
color="#46299D"
></tm-checkbox>
</aside>
<!-- 头像信息 -->
<aside class="avatar-column" @click="toUserDetailPage(item)">
<im-avatar class="pointer" :src="item.avatar" :size="80" :username="item.nickname"
@click="showUserInfoModal(item.user_id)" />
<im-avatar
class="pointer"
:src="item.avatar"
:size="80"
:username="item.nickname"
@click="showUserInfoModal(item.user_id)"
/>
</aside>
<!-- 主体信息 -->
<main class="main-column">
<div class="talk-title">
<span class="nickname pointer" v-show="talkParams.type == 2 && item.float == 'left'"
@click="onClickNickname(item)">
<span class="at">@</span>{{ item.nickname }}
<span
class="nickname pointer"
v-show="talkParams.type == 2 && item.float == 'left'"
@click="onClickNickname(item)"
>
<span class="at">@</span>
{{ item.nickname }}
</span>
<span>
{{ parseTime(item.created_at, '{m}/{d} {h}:{i}') }}
</span>
<span>{{ parseTime(item.created_at, '{m}/{d} {h}:{i}') }}</span>
</div>
<div class="talk-content" :class="{ pointer: dialogueStore.isOpenMultiSelect }">
<div
class="talk-content"
:class="{ pointer: dialogueStore.isOpenMultiSelect }"
>
<deepBubble
@clickMenu="(menuType) => onContextMenu(menuType, item)"
:isShowCopy="isShowCopy(item)"
:isShowWithdraw="isRevoke(talkParams.uid,item)"
:isShowWithdraw="isRevoke(talkParams.uid, item)"
>
<component class="component-content" :key="item.zp_index"
:is="MessageComponents[item.msg_type] || 'unknown-message'" :extra="item.extra" :data="item"
:max-width="true" :source="'panel'" />
<component
class="component-content"
:key="item.zp_index"
:is="
MessageComponents[item.msg_type] || 'unknown-message'
"
:extra="item.extra"
:data="item"
:max-width="true"
:source="'panel'"
/>
</deepBubble>
<!-- <div class="talk-tools">
<template v-if="talkParams.type == 1 && item.float == 'right'">
@ -91,8 +157,11 @@
</div> -->
</div>
<div v-if="item.extra.reply" class="talk-reply pointer"
@click="onJumpMessage(item.extra?.reply?.msg_id)">
<div
v-if="item.extra.reply"
class="talk-reply pointer"
@click="onJumpMessage(item.extra?.reply?.msg_id)"
>
<!-- <n-icon :component="ToTop" size="14" class="icon-top" /> -->
<span class="ellipsis">
回复 {{ item.extra?.reply?.nickname }}:
@ -101,60 +170,102 @@
</div>
</main>
</div>
</div>
<div class="load-toolbar pointer" style="transform: scaleY(-1);">
<span v-if="loadConfig.status == 0"> 正在加载数据中 ... </span>
<span v-else-if="loadConfig.status == 1" @click="onRefreshLoad"> 查看更多消息 ... </span>
<span v-else class="no-more"> 没有更多消息了 </span>
<span v-if="loadConfig.status == 0">正在加载数据中 ...</span>
<span v-else-if="loadConfig.status == 1" @click="onRefreshLoad">
查看更多消息 ...
</span>
<span v-else class="no-more">没有更多消息了</span>
</div>
</ZPaging>
</div>
</div>
<div class="footBox">
<div v-if="!dialogueStore.isOpenMultiSelect">
<div class="mt-[16rpx] ml-[32rpx] mr-[32rpx] flex items-center justify-between">
<div
class="mt-[16rpx] ml-[32rpx] mr-[32rpx] flex items-center justify-between"
>
<div class="flex-1 quillBox">
<QuillEditor ref="editor" id="editor" :options="editorOption" @editorChange="onEditorChange"
style="height: 100%; border: none" />
<QuillEditor
ref="editor"
id="editor"
:options="editorOption"
@editorChange="onEditorChange"
style="height: 100%; border: none;"
/>
<!-- <tm-input type=textarea autoHeight focusColor="#F9F9F9" color="#F9F9F9" :inputPadding="[12]"
placeholder=""></tm-input> -->
</div>
<tm-image :margin="[10, 0]" @click="handleEmojiPanel" :width="52" :height="52" :round="12"
:src="state.isOpenEmojiPanel ? keyboard : smile"></tm-image>
<tm-image @click="handleFilePanel" :margin="[10, 0]" :width="52" :height="52" :round="12"
:src="addCircleGray"></tm-image>
<tm-button @click="onSendMessageClick" :margin="[0, 0]" :padding="[0, 30]" color="#46299D" :fontSize="28"
size="mini" :shadow="0" label="发送"></tm-button>
<tm-image
:margin="[10, 0]"
@click="handleEmojiPanel"
:width="52"
:height="52"
:round="12"
:src="state.isOpenEmojiPanel ? keyboard : smile"
></tm-image>
<tm-image
@click="handleFilePanel"
:margin="[10, 0]"
:width="52"
:height="52"
:round="12"
:src="addCircleGray"
></tm-image>
<tm-button
@click="onSendMessageClick"
:margin="[0, 0]"
:padding="[0, 30]"
color="#46299D"
:fontSize="28"
size="mini"
:shadow="0"
label="发送"
></tm-button>
</div>
<div v-if="state.isOpenEmojiPanel" class="mt-[50rpx]">
<emojiPanel @on-select="onEmoticonEvent" />
</div>
<div v-if="state.isOpenFilePanel" class="mt-[16rpx]">
<filePanel @selectImg="handleSelectImg" :talkParams="talkParams" />
</div>
</div>
<div v-else class="h-[232rpx]">
<div class="flex items-center justify-center mt-[12rpx] text-[24rpx] text-[#747474] leading-[44rpx]">
<div
class="flex items-center justify-center mt-[12rpx] text-[24rpx] text-[#747474] leading-[44rpx]"
>
<div class="mr-[8rpx]">已选中:</div>
<div>{{ selectedMessage.length }}条消息</div>
</div>
<div class="flex items-center justify-around pl-[128rpx] pr-[128rpx] mt-[18rpx] text-[20rpx] text-[#737373] ">
<div @click="handleMergeForward" class="flex flex-col items-center justify-center">
<div
class="flex items-center justify-around pl-[128rpx] pr-[128rpx] mt-[18rpx] text-[20rpx] text-[#737373]"
>
<div
@click="handleMergeForward"
class="flex flex-col items-center justify-center"
>
<tm-image :width="68" :height="68" :src="zu6050"></tm-image>
<div class="mt-[6rpx]">合并转发</div>
</div>
<div @click="handleSingleForward" class="flex flex-col items-center justify-center">
<div
@click="handleSingleForward"
class="flex flex-col items-center justify-center"
>
<tm-image :width="68" :height="68" :src="zu6051"></tm-image>
<div class="mt-[6rpx]">逐条转发</div>
</div>
<div @click="handleWechatForward" class="flex flex-col items-center justify-center">
<div
@click="handleWechatForward"
class="flex flex-col items-center justify-center"
>
<tm-image :width="68" :height="68" :src="zu6052"></tm-image>
<div class="mt-[6rpx]">微信</div>
</div>
<div @click="handleDelete" class="flex flex-col items-center justify-center">
<div
@click="handleDelete"
class="flex flex-col items-center justify-center"
>
<tm-image :width="68" :height="68" :src="zu6053"></tm-image>
<div class="mt-[6rpx]">删除</div>
</div>
@ -170,16 +281,24 @@
:height="416"
:round="6"
>
<div class="w-full h-full flex flex-col items-center" >
<div class="mt-[46rpx] mb-[44rpx] leading-[48rpx] text-[#747474] text-[24rpx]" >
<div class="w-full h-full flex flex-col items-center">
<div
class="mt-[46rpx] mb-[44rpx] leading-[48rpx] text-[#747474] text-[24rpx]"
>
撤回该条消息
</div>
<div class="divider" ></div>
<div @click="withdrawerConfirm" class="mt-[32rpx] mb-[32rpx] text-[32rpx] text-[#CF3050] leading-[48rpx]">
<div class="divider"></div>
<div
@click="withdrawerConfirm"
class="mt-[32rpx] mb-[32rpx] text-[32rpx] text-[#CF3050] leading-[48rpx]"
>
撤回
</div>
<div class="divider" ></div>
<div @click="state.showWin = false" class="mt-[32rpx] mb-[32rpx] text-[32rpx] text-[#000000] leading-[48rpx]">
<div class="divider"></div>
<div
@click="state.showWin = false"
class="mt-[32rpx] mb-[32rpx] text-[32rpx] text-[#000000] leading-[48rpx]"
>
取消
</div>
</div>
@ -188,11 +307,19 @@
</div>
</template>
<script setup>
import { ref, reactive, watch, computed, onMounted, onUnmounted, nextTick } from 'vue';
import {
ref,
reactive,
watch,
computed,
onMounted,
onUnmounted,
nextTick,
} from 'vue'
import { QuillEditor, Quill } from '@vueup/vue-quill'
import EmojiBlot from './formats/emoji'
import { useChatList } from "@/store/chatList/index.js";
import { useAuth } from "@/store/auth";
import { useChatList } from '@/store/chatList/index.js'
import { useAuth } from '@/store/auth'
import {
useUserStore,
useDialogueStore,
@ -200,41 +327,45 @@ import {
useEditorDraftStore,
useTalkStore,
useSettingsStore,
useDialogueListStore
useDialogueListStore,
} from '@/store'
import addCircleGray from "@/static/image/chatList/addCircleGray.png";
import addCircleGray from '@/static/image/chatList/addCircleGray.png'
import { MessageComponents, ForwardableMessageType } from '@/constant/message'
import { formatTime, parseTime } from '@/utils/datetime'
import { deltaToMessage, deltaToString, isEmptyDelta } from './util'
import smile from "@/static/image/chatList/smile@2x.png";
import keyboard from "@/static/image/chatList/keyboard@2x.png";
import smile from '@/static/image/chatList/smile@2x.png'
import keyboard from '@/static/image/chatList/keyboard@2x.png'
import { useInject, useTalkRecord } from '@/hooks'
import { emitCall } from '@/utils/common'
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";
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'
import emojiPanel from './components/emojiPanel.vue'
import filePanel from './components/filePanel.vue'
import lodash from "lodash";
import lodash from 'lodash'
import { ServePublishMessage } from '@/api/chat'
import copy07 from "@/static/image/chatList/copy07@2x.png"
import multipleChoices from "@/static/image/chatList/multipleChoices@2x.png"
import cite from "@/static/image/chatList/cite@2x.png"
import withdraw from "@/static/image/chatList/withdraw@2x.png"
import delete07 from "@/static/image/chatList/delete@2x.png"
import zu6050 from "@/static/image/chatList/zu6050@2x.png"
import zu6051 from "@/static/image/chatList/zu6051@2x.png"
import zu6052 from "@/static/image/chatList/zu6052@2x.png"
import zu6053 from "@/static/image/chatList/zu6053@2x.png"
import deepBubble from "@/components/deep-bubble/deep-bubble.vue"
import {isRevoke } from './menu'
import copy07 from '@/static/image/chatList/copy07@2x.png'
import multipleChoices from '@/static/image/chatList/multipleChoices@2x.png'
import cite from '@/static/image/chatList/cite@2x.png'
import withdraw from '@/static/image/chatList/withdraw@2x.png'
import delete07 from '@/static/image/chatList/delete@2x.png'
import zu6050 from '@/static/image/chatList/zu6050@2x.png'
import zu6051 from '@/static/image/chatList/zu6051@2x.png'
import zu6052 from '@/static/image/chatList/zu6052@2x.png'
import zu6053 from '@/static/image/chatList/zu6053@2x.png'
import deepBubble from '@/components/deep-bubble/deep-bubble.vue'
import { isRevoke } from './menu'
import useConfirm from '@/components/x-confirm/useConfirm.js'
import { onLoad as uniOnload } from '@dcloudio/uni-app'
Quill.register('formats/emoji', EmojiBlot)
const { getDialogueList, updateZpagingRef, virtualList } = useDialogueListStore()
const {
getDialogueList,
updateZpagingRef,
virtualList,
} = useDialogueListStore()
const talkStore = useTalkStore()
const { showConfirm } = useConfirm();
const { showConfirm } = useConfirm()
const settingsStore = useSettingsStore()
const userStore = useUserStore()
const dialogueStore = useDialogueStore()
@ -251,7 +382,7 @@ const talkParams = reactive({
username: computed(() => dialogueStore.talk.username),
online: computed(() => dialogueStore.online),
keyboard: computed(() => dialogueStore.keyboard),
num: computed(() => dialogueStore.members.length)
num: computed(() => dialogueStore.members.length),
})
const state = ref({
@ -259,7 +390,7 @@ const state = ref({
isOpenFilePanel: false,
showWin: false,
onfocusItem: null,
sessionId: ''
sessionId: '',
})
uniOnload((options) => {
@ -269,11 +400,11 @@ uniOnload((options) => {
})
const handleEmojiPanel = () => {
state.value.isOpenFilePanel = false;
state.value.isOpenFilePanel = false
state.value.isOpenEmojiPanel = !state.value.isOpenEmojiPanel
}
const handleFilePanel = () => {
state.value.isOpenEmojiPanel = false;
state.value.isOpenEmojiPanel = false
state.value.isOpenFilePanel = !state.value.isOpenFilePanel
}
@ -282,8 +413,8 @@ const onSendMessage = (data = {}) => {
...data,
receiver: {
receiver_id: talkParams.receiver_id,
talk_type: talkParams.type
}
talk_type: talkParams.type,
},
}
ServePublishMessage(message)
@ -313,10 +444,11 @@ const onSendMessageClick = () => {
return message.info('发送内容超长,请分条发送')
}
onSendTextEvent({
data, callBack: (ok) => {
data,
callBack: (ok) => {
if (!ok) return
getQuill().setContents([], Quill.sources.USER)
}
},
})
break
}
@ -330,7 +462,7 @@ const onSendTextEvent = lodash.throttle((value) => {
type: 'text',
content: data.items[0].content,
quote_id: data.quoteId,
mentions: data.mentionUids
mentions: data.mentionUids,
}
onSendMessage(message)
@ -340,7 +472,7 @@ const onSendTextEvent = lodash.throttle((value) => {
const onInputEvent = ({ data }) => {
talkStore.updateItem({
index_name: indexName.value,
draft_text: data
draft_text: data,
})
// 线
@ -365,7 +497,13 @@ const evnets = {
},
}
const { loadConfig, records, onLoad, onRefreshLoad, onJumpMessage } = useTalkRecord(talkParams.uid)
const {
loadConfig,
records,
onLoad,
onRefreshLoad,
onJumpMessage,
} = useTalkRecord(talkParams.uid)
const getQuill = () => {
return editor.value?.getQuill()
@ -384,11 +522,10 @@ const isShowCopy = (item) => {
default:
return false
}
}
const selectedMessage = computed(() => {
return virtualList.value.filter(item => item.isCheck)
return virtualList.value.filter((item) => item.isCheck)
})
//
@ -421,7 +558,7 @@ const onEmoticonEvent = (data) => {
quill.setSelection(index + 1, 0, 'user')
} else {
let fn = emitCall('emoticon_event', data.value, () => { })
let fn = emitCall('emoticon_event', data.value, () => {})
emit('editor-event', fn)
}
}
@ -434,7 +571,7 @@ const onEditorChange = () => {
if (!isEmptyDelta(delta)) {
editorDraftStore.items[indexName.value || ''] = JSON.stringify({
text: text,
ops: delta.ops
ops: delta.ops,
})
} else {
// editorDraftStore.items
@ -452,7 +589,7 @@ const onClipboardMatcher = (node, Delta) => {
if (op.insert && typeof op.insert === 'string') {
ops.push({
insert: op.insert, //
attributes: {} //
attributes: {}, //
})
} else {
ops.push(op)
@ -469,16 +606,16 @@ const editorOption = {
toolbar: false,
clipboard: {
//
matchers: [[Node.ELEMENT_NODE, onClipboardMatcher]]
matchers: [[Node.ELEMENT_NODE, onClipboardMatcher]],
},
keyboard: {
bindings: {
enter: {
key: 13,
handler: onSendMessageClick
}
}
handler: onSendMessageClick,
},
},
},
// imageUploader: {
@ -527,49 +664,49 @@ const virtualListChange = (vList) => {
}
const onContextMenu = (menuType, item) => {
console.log(menuType, item, 'item');
console.log(menuType, item, 'item')
switch (menuType) {
case 'actionCopy':
actionCopy(item)
break;
break
case 'multipleChoose':
multipleChoose(item)
break;
break
case 'actionCite':
actionCite(item)
break;
break
case 'actionWithdraw':
actionWithdraw(item)
break;
break
case 'actionDelete':
actionDelete(item)
break;
break
default:
break;
break
}
}
const actionCopy = (item) => {
console.log('复制');
console.log('复制')
let content = ''
switch (item.msg_type) {
case 1:
content = item.extra.content
break;
break
case 3:
content = item.extra.url
break;
break
case 5:
content = item.extra.url
break;
break
default:
break;
break
}
uni.setClipboardData({
data: content,
});
})
}
const multipleChoose = (item) => {
@ -578,23 +715,23 @@ const multipleChoose = (item) => {
}
const actionCite = (item) => {
console.log('引用');
console.log('引用')
}
const actionWithdraw = (item) => {
console.log('撤回');
console.log('撤回')
state.value.onfocusItem = item
state.value.showWin = true;
state.value.showWin = true
}
const withdrawerConfirm = () => {
dialogueStore.ApiRevokeRecord(state.value.onfocusItem.msg_id)
state.value.onfocusItem = null
state.value.showWin = false;
state.value.showWin = false
}
const actionDelete = (item) => {
console.log('删除');
console.log('删除')
item.isCheck = true
handleDelete()
}
@ -603,14 +740,14 @@ const handleMergeForward = () => {
if (selectedMessage.value.length == 0) {
return message.warning('未选择消息')
}
console.log('合并转发');
console.log('合并转发')
dialogueStore.setForwardType(2)
dialogueStore.setForwardMessages(selectedMessage.value)
uni.navigateTo({
url: '/pages/chooseChat/index',
success: function (res) {
clearMultiSelect()
}
},
})
}
@ -618,14 +755,14 @@ const handleSingleForward = () => {
if (selectedMessage.value.length == 0) {
return message.warning('未选择消息')
}
console.log('逐条转发');
console.log('逐条转发')
dialogueStore.setForwardType(1)
dialogueStore.setForwardMessages(selectedMessage.value)
uni.navigateTo({
url: '/pages/chooseChat/index',
success: function (res) {
clearMultiSelect()
}
},
})
}
@ -633,40 +770,42 @@ const handleWechatForward = () => {
if (selectedMessage.value.length == 0) {
return message.warning('未选择消息')
}
console.log('微信转发');
console.log('微信转发')
}
const handleDelete = () => {
if (selectedMessage.value.length == 0) {
return message.warning('未选择消息')
}
console.log('删除');
console.log('删除')
showConfirm({
content: '确定删除聊天记录',
confirmText:'删除',
confirmColor:'#CF3050',
confirmText: '删除',
confirmColor: '#CF3050',
onConfirm: async () => {
const msgIds = selectedMessage.value.map(item => item.msg_id)
virtualList.value = virtualList.value.filter(item => !msgIds.includes(item.msg_id))
const msgIds = selectedMessage.value.map((item) => item.msg_id)
virtualList.value = virtualList.value.filter(
(item) => !msgIds.includes(item.msg_id),
)
dialogueStore.ApiDeleteRecord(msgIds)
clearMultiSelect()
},
onCancel: () => {
}
onCancel: () => {},
})
}
watch(() => zpagingRef.value, (newValue, oldValue) => {
if (newValue) {
updateZpagingRef(newValue)
}
})
watch(
() => zpagingRef.value,
(newValue, oldValue) => {
if (newValue) {
updateZpagingRef(newValue)
}
},
)
const clearMultiSelect = () => {
dialogueStore.setMultiSelect(false)
virtualList.value.forEach(item => {
virtualList.value.forEach((item) => {
item.isCheck = false
})
}
@ -689,14 +828,22 @@ const initData = async () => {
//
const toChatSettingsPage = () => {
uni.navigateTo({
url: '/pages/chatSettings/index?groupId=' + talkParams?.receiver_id + '&sessionId=' + state.sessionId
url:
'/pages/chatSettings/index?groupId=' +
talkParams?.receiver_id +
'&sessionId=' +
state.sessionId,
})
}
//
const toUserDetailPage = (userItem) => {
uni.navigateTo({
url: '/pages/dialog/dialogDetail/userDetail?erpUserId=' + userItem.erp_user_id,
url:
'/pages/dialog/dialogDetail/userDetail?erpUserId=' +
userItem.erp_user_id +
'&user_id=' +
userItem.user_id,
})
}
@ -717,7 +864,7 @@ page {
.outer-layer {
flex: 1;
background-image: url("@/static/image/clockIn/z3280@3x.png");
background-image: url('@/static/image/clockIn/z3280@3x.png');
background-size: cover;
display: flex;
flex-direction: column;
@ -825,7 +972,7 @@ page {
margin-bottom: 6rpx;
font-size: 24rpx;
user-select: none;
color: #BABABA;
color: #bababa;
opacity: 1;
&.show {
@ -970,7 +1117,7 @@ page {
:deep(.ql-editor) {
padding: 14rpx 22rpx;
background-color: #F9F9F9;
background-color: #f9f9f9;
border-radius: 8rpx;
outline: none !important;
max-height: 294rpx;
@ -1011,6 +1158,6 @@ page {
.divider {
width: 100%;
height: 1rpx;
background-color: #E7E7E7;
background-color: #e7e7e7;
}
</style>

View File

@ -11,12 +11,22 @@
:maxCount="99"
color="#D03050"
>
<tm-image
:width="96"
:height="96"
:round="12"
:src="avatarCpt"
></tm-image>
<avatarModule
:mode="props?.data?.group_type === 0 ? 1 : 2"
:avatar="props?.data?.avatar"
:groupType="props?.data?.group_type"
:userName="props?.data?.name"
:customStyle="{
width: '96rpx',
height: '96rpx',
}"
:customTextStyle="{
fontSize: '32rpx',
fontWeight: 'bold',
color: '#fff',
lineHeight: '44rpx',
}"
></avatarModule>
</tm-badge>
</div>
<div class="chatInfo">
@ -54,9 +64,10 @@
@click="handleTop"
class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#F09F1F] flex items-center justify-center"
>
{{ props.data.is_top === 1 ? "取消置顶" : "置顶" }}
{{ props.data.is_top === 1 ? '取消置顶' : '置顶' }}
</div>
<div
@click="handleDelete"
class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#CF3050] flex items-center justify-center"
>
删除
@ -71,20 +82,17 @@
</div>
</template>
<script setup>
import { ref, reactive, defineProps,computed } from "vue";
import dayjs from "dayjs";
import { beautifyTime } from "@/utils/datetime";
import { ServeClearTalkUnreadNum } from "@/api/chat";
import { useTalkStore, useDialogueStore } from "@/store";
import { useSessionMenu } from "@/hooks";
import groupDepartment from "@/static/image/chatList/groupDepartment.png";
import groupProject from "@/static/image/chatList/groupProject.png";
import groupNormal from "@/static/image/chatList/groupNormal.png";
import groupCompany from "@/static/image/chatList/groupCompany.png";
import avatarModule from '@/components/avatar-module/index.vue'
import { ref, reactive, defineProps, computed } from 'vue'
import dayjs from 'dayjs'
import { beautifyTime } from '@/utils/datetime'
import { ServeClearTalkUnreadNum } from '@/api/chat'
import { useTalkStore, useDialogueStore } from '@/store'
import { useSessionMenu } from '@/hooks'
const talkStore = useTalkStore();
const { onToTopTalk } = useSessionMenu();
const dialogueStore = useDialogueStore();
const talkStore = useTalkStore()
const { onToTopTalk, onRemoveTalk } = useSessionMenu()
const dialogueStore = useDialogueStore()
const props = defineProps({
data: {
type: Object,
@ -96,35 +104,12 @@ const props = defineProps({
default: -1,
required: true,
},
});
const avatarCpt = computed(() => {
let avatar = null;
if (props.data.avatar !== "") {
avatar = props.data.avatar;
} else {
switch (props.data.group_type) {
case 1:
avatar = groupNormal;
break;
case 2:
avatar = groupDepartment;
break;
case 3:
avatar = groupProject;
break;
case 4:
avatar = groupCompany;
break;
}
}
return avatar;
});
})
const cellClick = () => {
console.log(props.data);
console.log(props.data)
//
dialogueStore.setDialogue(props.data);
dialogueStore.setDialogue(props.data)
//
if (props.data.unread_num > 0) {
@ -135,18 +120,24 @@ const cellClick = () => {
talkStore.updateItem({
index_name: props.data.index_name,
unread_num: 0,
});
});
})
})
}
uni.navigateTo({
url: '/pages/dialog/index?sessionId=' + props.data.id,
});
};
})
}
const handleTop = () => {
console.log(props.data, 1);
onToTopTalk(props.data);
};
console.log(props.data, 1)
onToTopTalk(props.data)
}
//
const handleDelete = () => {
console.log(props.data)
onRemoveTalk(props.data)
}
</script>
<style lang="scss" scoped>
.chatItem {
@ -161,11 +152,6 @@ const handleTop = () => {
}
}
.avatarImg {
height: 96rpx;
width: 96rpx;
}
.chatInfo {
flex: 1;
margin-left: 20rpx;

View File

@ -25,8 +25,13 @@
:src="addCircle"
></tm-image>
<template v-slot:label>
<div class="w-full h-[208rpx] pt-[22rpx] pb-[22rpx] pl-[34rpx] pr-[32rpx]" >
<div @click="creatGroupChat" class="flex items-center mb-[30rpx]" >
<div
class="w-full h-[208rpx] pt-[22rpx] pb-[22rpx] pl-[34rpx] pr-[32rpx]"
>
<div
@click="creatGroupChat"
class="flex items-center mb-[30rpx]"
>
<div class="mr-[26rpx] flex items-center">
<tm-image
:width="40"
@ -34,10 +39,17 @@
:src="cahtPopover"
></tm-image>
</div>
<div class="leading-[54rpx] text-[32rpx] text-[#FFFFFF] font-bold" >发起群聊</div>
<div
class="leading-[54rpx] text-[32rpx] text-[#FFFFFF] font-bold"
>
发起群聊
</div>
</div>
<div class="divider" ></div>
<div class="flex items-center mt-[28rpx]" >
<div class="divider"></div>
<div
@click="toAddressBookPage"
class="flex items-center mt-[28rpx]"
>
<div class="mr-[26rpx] flex items-center">
<tm-image
:width="40"
@ -45,7 +57,9 @@
:src="zu3289"
></tm-image>
</div>
<div class="leading-[54rpx] text-[32rpx] text-[#FFFFFF] font-bold" >
<div
class="leading-[54rpx] text-[32rpx] text-[#FFFFFF] font-bold"
>
通讯录
</div>
</div>
@ -78,24 +92,25 @@
</div>
</template>
<script setup>
import { ref, watch, computed } from "vue";
import { onShow, onLoad } from "@dcloudio/uni-app";
import { useChatList } from "@/store/chatList/index.js";
import { useAuth } from "@/store/auth";
import { useTalkStore, useUserStore } from "@/store";
import chatItem from "./components/chatItem.vue";
import addCircle from "@/static/image/chatList/addCircle.png";
import cahtPopover from "@/static/image/chatList/cahtPopover.png";
import zu3289 from "@/static/image/chatList/zu3289@2x.png";
import { ref, watch, computed } from 'vue'
import { onShow, onLoad } from '@dcloudio/uni-app'
import { useChatList } from '@/store/chatList/index.js'
import { useAuth } from '@/store/auth'
import { useTalkStore, useUserStore, useDialogueStore } from '@/store'
import chatItem from './components/chatItem.vue'
import addCircle from '@/static/image/chatList/addCircle.png'
import cahtPopover from '@/static/image/chatList/cahtPopover.png'
import zu3289 from '@/static/image/chatList/zu3289@2x.png'
const talkStore = useTalkStore();
const userStore = useUserStore();
const { userInfo } = useAuth();
const talkStore = useTalkStore()
const userStore = useUserStore()
const dialogueStore = useDialogueStore()
const { userInfo } = useAuth()
const topItems = computed(() => talkStore.topItems);
const topItems = computed(() => talkStore.topItems)
const items = computed(() => {
// if (searchKeyword.value.length === 0) {
return talkStore.talkItems;
return talkStore.talkItems
// }
// return talkStore.talkItems.filter((item) => {
@ -103,31 +118,64 @@ const items = computed(() => {
// return keyword.toLowerCase().indexOf(searchKeyword.value.toLowerCase()) != -1
// })
});
})
const creatGroupChat = () => {
uni.navigateTo({
url: "/pages/creatGroupChat/index",
});
};
url: '/pages/creatGroupChat/index',
})
}
const toSearchPage = () => {
uni.navigateTo({
url: "/pages/search/index",
});
};
url: '/pages/search/index',
})
}
//
const toAddressBookPage = () => {
uni.navigateTo({
url: '/pages/addressBook/index',
})
}
watch(
() => talkStore,
(newValue, oldValue) => {
console.log(talkStore);
// console.log(talkStore)
},
{ deep: true, immediate: true }
);
{ deep: true, immediate: true },
)
onShow(() => {
talkStore.loadTalkList();
});
talkStore.loadTalkList()
})
onLoad((options) => {
if (options?.openSessionIndex || options?.openSessionIndex === 0) {
if (items?.value?.length > 0) {
items.value.forEach((openSession,index) => {
if (index === Number(options?.openSessionIndex)) {
dialogueStore.setDialogue(openSession)
if (openSession.unread_num > 0) {
ServeClearTalkUnreadNum({
talk_type: openSession.talk_type,
receiver_id: openSession.receiver_id,
}).then(() => {
talkStore.updateItem({
index_name: openSession.index_name,
unread_num: 0,
})
})
}
uni.navigateTo({
url: '/pages/dialog/index?sessionId=' + openSession.id,
})
}
})
}
}
})
</script>
<style scoped lang="scss">
uni-page-body,
@ -137,7 +185,7 @@ page {
.outer-layer {
overflow-y: auto;
flex: 1;
background-image: url("@/static/image/clockIn/z3280@3x.png");
background-image: url('@/static/image/clockIn/z3280@3x.png');
background-size: cover;
padding: 0 32rpx 20rpx 32rpx;
display: flex;
@ -155,14 +203,14 @@ page {
margin-top: 20rpx;
background-color: #fff;
}
.divider{
.divider {
height: 1rpx;
background-color: #7C7C7C;
background-color: #7c7c7c;
opacity: 0.6;
}
.popoverBox {
:deep(.popover-bcc){
transform:translateX(20rpx) translateY(40rpx);
:deep(.popover-bcc) {
transform: translateX(20rpx) translateY(40rpx);
}
}
</style>

View File

@ -4,6 +4,7 @@ import {
ServeRevokeRecords,
ServePublishMessage,
ServeCollectEmoticon,
ServeEmptyMessage,
} from '@/api/chat/index'
import { ServeGetGroupMembers } from '@/api/group/index'
import { useEditorStore } from './editor'
@ -123,7 +124,8 @@ export const useDialogueStore = defineStore('dialogue', {
key: o.key,
erp_user_id: o.erp_user_id,
is_mute: o.is_mute,
is_mine: useAuth()?.userInfo?.value?.ID === o?.erp_user_id ? true : false,
is_mine:
useAuth()?.userInfo?.value?.ID === o?.erp_user_id ? true : false,
}))
},
@ -213,6 +215,18 @@ export const useDialogueStore = defineStore('dialogue', {
})
},
//清空聊天记录
apiClearRecord() {
ServeEmptyMessage({
talk_type: this.talk.talk_type,
receiver_id: this.talk.receiver_id,
}).then((res) => {
if (res.code == 200) {
} else {
}
})
},
// 撤销聊天记录
ApiRevokeRecord(msg_id = '') {
ServeRevokeRecords({ msg_id }).then((res) => {

View File

@ -109,6 +109,18 @@ export const useDialogueListStore = createGlobalState(() => {
item.records = item.records.filter(item=>!msgIds.includes(item.msg_id))
}
//删除会话时同时刪除storage中存儲的會話
const delDialogueStorage = (indexName) =>{
if(dialogueList?.value?.length > 0){
dialogueList.value.forEach((item, index) => {
if (item?.index_name === indexName) {
dialogueList.value.splice(index, 1)
}
})
}
}
return {
dialogueList,
zpagingRef,
@ -122,5 +134,6 @@ export const useDialogueListStore = createGlobalState(() => {
addChatRecord,
virtualList,
batchDelDialogueRecord,
delDialogueStorage
}
})

View File

@ -10,7 +10,7 @@ export const useTalkStore = defineStore('talk', {
// 加载状态[1:未加载;2:加载中;3:加载完成;4:加载失败;]
loadStatus: 2,
// 会话列表
items: []
items: [],
}
},
getters: {
@ -26,14 +26,14 @@ export const useTalkStore = defineStore('talk', {
// 对话列表
talkItems: (state) => {
let topList = state.items.filter((item) => item.is_top == 1)
let listT = state.items.filter(v=>v.is_top !== 1)
let listT = state.items.filter((v) => v.is_top !== 1)
let listP = topList.sort((a, b) => {
return ttime(b.updated_at) - ttime(a.updated_at)
})
listT = listT.sort((a, b) => {
return ttime(b.updated_at) - ttime(a.updated_at)
})
return [...listP,...listT]
return [...listP, ...listT]
},
// 消息未读数总计
@ -41,7 +41,7 @@ export const useTalkStore = defineStore('talk', {
return state.items.reduce((total, item) => {
return total + item.unread_num
}, 0)
}
},
},
actions: {
findItem(index_name) {
@ -50,7 +50,9 @@ export const useTalkStore = defineStore('talk', {
// 更新对话节点
updateItem(params) {
const item = this.items.find((item) => item.index_name === params.index_name)
const item = this.items.find(
(item) => item.index_name === params.index_name,
)
item && Object.assign(item, params)
},
@ -73,7 +75,9 @@ export const useTalkStore = defineStore('talk', {
// 更新对话消息
updateMessage(params) {
const item = this.items.find((item) => item.index_name === params.index_name)
const item = this.items.find(
(item) => item.index_name === params.index_name,
)
if (item) {
item.unread_num++
item.msg_text = params.msg_text
@ -83,7 +87,9 @@ export const useTalkStore = defineStore('talk', {
// 更新联系人备注
setRemark(params) {
const item = this.items.find((item) => item.index_name === `1_${params.user_id}`)
const item = this.items.find(
(item) => item.index_name === `1_${params.user_id}`,
)
item && (item.remark = params.remark)
},
@ -126,34 +132,31 @@ export const useTalkStore = defineStore('talk', {
return this.items.findIndex((item) => item.index_name === index_name)
},
toTalk(talk_type, receiver_id, router) {
const route = {
path: '/message',
query: {
v: new Date().getTime()
}
}
toTalk(talk_type, receiver_id, erp_user_id) {
if (this.findTalkIndex(`${talk_type}_${receiver_id}`) >= 0) {
sessionStorage.setItem(KEY_INDEX_NAME, `${talk_type}_${receiver_id}`)
return router.push(route)
uni.reLaunch({
url: '/pages/index/index?openSessionIndex=' + this.findTalkIndex(`${talk_type}_${receiver_id}`),
})
return
}
ServeCreateTalkList({
talk_type,
receiver_id
erp_user_id,
}).then(({ code, data, message }) => {
if (code == 200) {
if (this.findTalkIndex(`${talk_type}_${receiver_id}`) === -1) {
this.addItem(formatTalkItem(data))
}
sessionStorage.setItem(KEY_INDEX_NAME, `${talk_type}_${receiver_id}`)
return router.push(route)
uni.reLaunch({
url: '/pages/index/index?openSessionIndex=' + this.findTalkIndex(`${talk_type}_${receiver_id}`),
})
} else {
message.warning(message)
}
})
}
}
},
},
})