完成清空聊天记录功能;接入群信息修改中的编辑群名称功能与相关交互,并调整群聊设置弹窗的样式;去除旧版群公告入口

This commit is contained in:
wangyifeng 2025-05-20 18:02:12 +08:00
parent 62f5b458a5
commit 8694921f25
9 changed files with 265 additions and 109 deletions

View File

@ -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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { reactive, computed, watch, ref } from 'vue'
import { NEmpty, NPopover, NPopconfirm, NSwitch, NIcon, NInput } 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, Down, Up } from '@icon-park/vue-next'
@ -10,14 +10,19 @@ import {
ServeGetGroupMembers,
ServeSecedeGroup,
ServeUpdateGroupCard,
ServeGetGroupNotices
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([
@ -44,9 +49,11 @@ const props = defineProps({
})
watch(props, () => {
loadDetail()
loadMembers()
getGroupNotices()
if (props.talkType === 2) {
loadDetail()
loadMembers()
getGroupNotices()
}
})
const editCardPopover = ref(false)
@ -88,7 +95,10 @@ const state = reactive({
updater_name: '',
updated_at: '',
content: ''
} //
}, //
editGroupName: false, //
editGroupNameValue: '', //
chatSettingOperateType: '' //
})
const members = ref<any[]>([])
@ -198,20 +208,41 @@ const onChangeRemark = () => {
})
}
loadDetail()
loadMembers()
//
const handleModalConfirm = (closeLoading) => {
setTimeout(() => {
closeLoading()
state.isShowModal = false
}, 2000)
if (state.chatSettingOperateType == 'clear') {
//
ServeEmptyMessage({
talk_type: props.talkType,
receiver_id: props.gid
})
.then((res) => {
closeLoading()
state.isShowModal = false
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 = '确定清空聊天记录'
@ -298,7 +329,55 @@ const getGroupNotices = () => {
}
})
}
getGroupNotices()
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">
@ -319,7 +398,7 @@ getGroupNotices()
<main class="el-main main me-scrollbar me-scrollbar-thumb">
<div class="info-box" v-if="talkType === 2">
<div class="b-box">
<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> -->
@ -336,54 +415,60 @@ getGroupNotices()
</div>
</div>
<!-- <div class="describe">群主已开启新成员入群可查看所有聊天记录</div> -->
<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 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>
<span>{{ memberItem.nickname }}</span>
</div>
</div>
</n-scrollbar>
<div
class="group-member-list-more"
v-if="!state.showAllMember && !state.openGroupMemberSearch"
v-if="
!state.showAllMember && !state.openGroupMemberSearch && groupMemberList.length > 18
"
@click="state.showAllMember = true"
>
<span>展开更多</span>
@ -391,20 +476,55 @@ getGroupNotices()
</div>
<div
class="group-member-list-more"
v-if="state.showAllMember && !state.openGroupMemberSearch"
v-if="
state.showAllMember && !state.openGroupMemberSearch && groupMemberList.length > 18
"
@click="state.showAllMember = false"
>
<span>收起更多</span>
<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">
<div class="b-box" :style="{ margin: state.editGroupName ? '-8px 0 -6px' : '16px 0 32px' }">
<div class="block">
<div class="title">群名称</div>
<div>
<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> -->
@ -413,7 +533,7 @@ getGroupNotices()
<div class="b-box">
<div class="block">
<div class="title">群类型</div>
<div>
<div class="group-name-box">
<span>{{ groupTypeText }}</span>
</div>
</div>
@ -457,7 +577,7 @@ getGroupNotices()
</div>
</div> -->
<div class="b-box b-box-bottomBorder" style="padding: 0 0 12px;">
<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"> -->
@ -470,21 +590,21 @@ getGroupNotices()
</div>
<div class="info-box">
<div class="b-box b-box-bottomBorder">
<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">
<div class="b-box" style="margin: 16px 0 32px;">
<div class="block">
<div class="title">置顶会话</div>
<n-switch />
</div>
</div>
<div class="b-box">
<div class="b-box" style="margin: 32px 0 20px;">
<div class="block">
<div class="title">消息免打扰</div>
<n-switch />
@ -662,8 +782,8 @@ getGroupNotices()
.b-box {
display: flex;
align-items: center;
min-height: 30px;
margin: 12px 0;
// min-height: 30px;
margin: 32px 0;
flex-direction: column;
&:first-child {
@ -690,6 +810,27 @@ getGroupNotices()
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;
@ -732,6 +873,7 @@ getGroupNotices()
font-size: 14px;
line-height: 20px;
color: #999999;
margin: 10px 0 0;
}
.group-member-list {
@ -741,10 +883,9 @@ getGroupNotices()
justify-content: flex-start;
flex-wrap: wrap;
gap: 16px 24px;
padding: 7px 0 16px;
padding: 7px 0 0;
width: 100%;
box-sizing: border-box;
border-bottom: 1px solid #f0f0f2;
.group-member-list-each {
display: flex;
@ -788,26 +929,27 @@ getGroupNotices()
.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;
span {
font-size: 14px;
line-height: 20px;
color: #747474;
font-weight: 400;
margin: 0 10px 0 0;
display: inline-block;
}
}
.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;
}
}
.group-member-list-more:hover {
span {
color: #46299d;
}
}
}

View File

@ -19,11 +19,11 @@ export const useDialogueStore = defineStore('dialogue', {
// 对话节点
talk: {
avatar:'',
avatar: '',
username: '',
talk_type: 0, // 对话来源[1:私聊;2:群聊]
receiver_id: 0,
group_type:0
group_type: 0
},
// 好友是否正在输入文字
@ -75,15 +75,14 @@ export const useDialogueStore = defineStore('dialogue', {
// 更新对话信息
setDialogue(data = {}) {
console.log('data',data)
console.log('data', data)
this.online = data.is_online == 1
this.talk = {
username: data.remark || data.name,
talk_type: data.talk_type,
receiver_id: data.receiver_id,
avatar:data.avatar,
group_type:data.group_type
avatar: data.avatar,
group_type: data.group_type
}
this.index_name = `${data.talk_type}_${data.receiver_id}`
@ -97,6 +96,16 @@ export const useDialogueStore = defineStore('dialogue', {
}
},
//按需更新对话节点部分信息
setTalkInfoPartially(data = {}) {
Object.assign(this.talk, data)
},
// 清空对话记录
clearDialogueRecord() {
this.records = []
},
// 更新提及列表
async updateGroupMembers() {
let { code, data } = await ServeGetGroupMembers({
@ -236,21 +245,21 @@ export const useDialogueStore = defineStore('dialogue', {
// 更新视频上传进度
updateUploadProgress(uploadId, percentage) {
const record = this.records.find(item =>
item.extra && item.extra.is_uploading && item.extra.upload_id === uploadId
const record = this.records.find(
(item) => item.extra && item.extra.is_uploading && item.extra.upload_id === uploadId
)
if (record) {
record.extra.percentage = percentage
}
},
// 视频上传完成后更新消息
completeUpload(uploadId, videoInfo) {
const record = this.records.find(item =>
item.extra && item.extra.is_uploading && item.extra.upload_id === uploadId
const record = this.records.find(
(item) => item.extra && item.extra.is_uploading && item.extra.upload_id === uploadId
)
if (record) {
record.extra.is_uploading = false
record.extra.url = videoInfo.url

View File

@ -18,7 +18,7 @@ export function isLoggedIn() {
*/
export function getAccessToken() {
// return storage.get(AccessToken) || ''
return JSON.parse(localStorage.getItem('token'))||'46d71a72d8d845ad7ed23eba9bdde260e635407190c2ce1bf7fd22088e41682ea07773ec65cae8946d2003f264d55961f96e0fc5da10eb96d3a348c1664e9644ce2108c311309f398ae8ea1b8200bfd490e5cb6e8c52c9e5d493cbabb163368f8351420451a631dbfa749829ee4cda49b77b5ed2d3dced5d0f2b7dd9ee76ba5465c84a17c23af040cd92b6b2a4ea48befbb5c729dcdad0a9c9668befe84074cc24f78899c1d947f8e7f94c7eda5325b8ed698df729e76febb98549ef3482ae942fb4f4a1c92d21836fa784728f0c5483aab2760a991b6b36e6b10c84f840a6433a6ecc31dee36e8f1c6158818bc89d22b9b32c043123b3db4f35a7a79e1bbe97875bfa18428a4f5ed561887bfbfcab3bd61f2f9348af8bdb89da8c35a7a681fe828af1502b58ebc4ffb99f28fe91d5ba4b0245d1eb24a5ccda9be0cd9bef4d01'
return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b89a542742bebcc3862e86adbcf9b360820a497764e7432d66963e70eb29f9eab5268ee8efa98eed3c981eea690d977b38b76b3a9a6b51bb685000752d9d26f98a91f4df6970ad165c5299f9eb77d0c40ed'
}
/**

View File

@ -271,7 +271,7 @@ const items = computed((): ISession[] => {
watch(
() => talkStore,
(newValue, oldValue) => {
console.log(newValue)
// console.log(newValue)
},
{ deep: true, immediate: true }
)

View File

@ -69,13 +69,13 @@ 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
:size="18"
class="icon"