重构部分聊天详情页面;重构部分管理员选择页面

This commit is contained in:
wangyifeng 2025-02-11 11:45:19 +08:00
parent 5c55411aa3
commit 2c063f3d4f
6 changed files with 372 additions and 361 deletions

View File

@ -9,6 +9,9 @@
<template #left>
<slot name="left"></slot>
</template>
<template #subTitle>
<slot name="subTitle"></slot>
</template>
<template #right>
<slot name="right"></slot>
</template>

View File

@ -210,16 +210,11 @@ const removeGroupAdmin = (adminItem) => {
) {
let positionInfos = []
if (state?.groupAdminList?.length > 0) {
state?.groupAdminList.forEach((item) => {
if (
positionInfos = state?.groupAdminList.filter((item) => {
return (
item.dept_id != adminItem.dept_id ||
item.position_id != adminItem.position_id
) {
positionInfos.push({
position_id: item.position_id,
position_name: item.deptPos,
})
}
)
})
let params = {
source: 'app',

View File

@ -364,7 +364,8 @@ const handleClickItem = (item) => {
if (
state.manageType === 'admin' &&
(groupParams.groupInfo.group_type == 2 ||
groupParams.groupInfo.group_type == 4)
groupParams.groupInfo.group_type == 4 ||
state.isCreateDepGroup === 1)
) {
itemList = state.resultMemberList[0].memberList
}
@ -388,7 +389,8 @@ const confirmSelectMembers = () => {
if (
state.manageType === 'admin' &&
(groupParams.groupInfo.group_type == 2 ||
groupParams.groupInfo.group_type == 4)
groupParams.groupInfo.group_type == 4 ||
state.isCreateDepGroup === 1)
) {
itemList = state.resultMemberList[0].memberList
}
@ -404,7 +406,15 @@ const confirmSelectMembers = () => {
ele.checkArr?.length > 0 ||
(ele.leader && (ele.leader == 1 || ele.leader == 2))
) {
positionInfos.push(ele.positionInfo)
if (state.isCreateDepGroup === 1) {
let posInfo = Object.assign({}, ele.positionInfo, {
name: ele.nickname,
id: ele.id,
})
positionInfos.push(posInfo)
} else {
positionInfos.push(ele.positionInfo)
}
}
})
console.log(selectedUserIds)
@ -426,45 +436,53 @@ const confirmSelectMembers = () => {
})
resp.catch(() => {})
} else if (state.manageType === 'admin') {
if (
groupParams.groupInfo.group_type == 1 ||
groupParams.groupInfo.group_type == 3
) {
let params = {
mode: 1, //12
group_id: dialogueParams.receiverId, //id
user_ids: selectedUserIds,
}
console.log(params)
const resp = ServeGroupAssignAdmin(params)
resp.then(({ code, data }) => {
console.log(data)
if (code == 200) {
useDialogueStore().updateGroupMembers()
} else {
}
if (state.isCreateDepGroup === 1) {
// console.log(positionInfos)
groupTypeStore.groupAdmins.value = positionInfos
uni.navigateBack({
delta: 1,
})
resp.catch(() => {})
} else if (
groupParams.groupInfo.group_type == 2 ||
groupParams.groupInfo.group_type == 4
) {
let params = {
source: 'app',
id: dialogueParams.receiverId,
deptInfos: groupParams.groupInfo.deptInfos,
positionInfos: positionInfos,
}
console.log(params)
const resp = ServeEditGroupAdmin(params)
resp.then(({ code, data }) => {
console.log(data)
if (code == 200) {
groupStore.ServeGroupDetail()
} else {
} else {
if (
groupParams.groupInfo.group_type == 1 ||
groupParams.groupInfo.group_type == 3
) {
let params = {
mode: 1, //12
group_id: dialogueParams.receiverId, //id
user_ids: selectedUserIds,
}
})
resp.catch(() => {})
console.log(params)
const resp = ServeGroupAssignAdmin(params)
resp.then(({ code, data }) => {
console.log(data)
if (code == 200) {
useDialogueStore().updateGroupMembers()
} else {
}
})
resp.catch(() => {})
} else if (
groupParams.groupInfo.group_type == 2 ||
groupParams.groupInfo.group_type == 4
) {
let params = {
source: 'app',
id: dialogueParams.receiverId,
deptInfos: groupParams.groupInfo.deptInfos,
positionInfos: positionInfos,
}
console.log(params)
const resp = ServeEditGroupAdmin(params)
resp.then(({ code, data }) => {
console.log(data)
if (code == 200) {
groupStore.ServeGroupDetail()
} else {
}
})
resp.catch(() => {})
}
}
} else if (state.manageType === 'removeMembers') {
let params = {
@ -523,10 +541,9 @@ const assembleAlphabetMemberList = async (newMemberList) => {
}
getPosiByDep(departmentIdsArr)
} else if (state.isCreateDepGroup === 1) {
console.log(groupTypeStore.depCheckedKeys)
let departmentIdsArr = []
if (groupTypeStore?.depCheckedKeys?.length > 0) {
groupTypeStore.depCheckedKeys.forEach((item) => {
if (groupTypeStore?.depCheckedKeys?.value?.length > 0) {
groupTypeStore.depCheckedKeys.value.forEach((item) => {
departmentIdsArr.push(item.ID)
})
}
@ -571,7 +588,18 @@ const getPosiByDep = async (departmentIdsArr) => {
})
})
}
// console.log(departmentAllPositions)
if (
state.isCreateDepGroup === 1 &&
groupTypeStore?.groupAdmins?.value?.length > 0
) {
departmentAllPositions.forEach((allPos) => {
groupTypeStore.groupAdmins.value.forEach((admin) => {
if (allPos.id === admin.id) {
allPos.checkArr = [allPos.id]
}
})
})
}
state.resultMemberList = [
{
key: '',

View File

@ -1,44 +1,42 @@
<template>
<div class="outer-layer">
<div>
<tm-navbar :hideBack="false" hideHome title="" :leftWidth="220">
<div class="flex flex-col items-center justify-center">
<div class="text-[34rpx] font-bold">{{ talkParams.username }}</div>
<div v-if="true" class="text-[24rpx] text-[#999999]">公司群</div>
</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>
</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"
>
<!-- <template #top>
<div class="dialog-page">
<ZPaging
use-chat-record-mode
: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>
<customNavbar :title="talkParams.username">
<template
#subTitle
v-if="talkStore?.findItem(talkParams.index_name)?.group_type === 4"
>
<div class="text-[24rpx] text-[#999999]">公司群</div>
</template>
<template #right>
<div class="mr-[36rpx] toChatSetting_btn">
<tm-icon
color="rgb(51, 51, 51)"
:font-size="36"
name="tmicon-gengduo"
@click="toChatSettingsPage"
></tm-icon>
</div>
</template>
</customNavbar>
</template>
<!-- <template #top>
<div class="load-toolbar pointer">
<span v-if="loadConfig.status == 0"> 正在加载数据中 ... </span>
<span v-else-if="loadConfig.status == 1" @click="onRefreshLoad"> 查看更多消息 ... </span>
@ -46,106 +44,105 @@
</div>
</template> -->
<!-- 数据加载状态栏 -->
<!-- 数据加载状态栏 -->
<div class="dialog-list">
<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"
/>
</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"
/>
</div>
<div
class="message-item"
v-for="item in virtualList"
:id="`zp-id-${item.zp_index}`"
:key="item.zp_index"
style="transform: scaleY(-1);"
v-else
class="message-box record-box"
:class="{
'direction-rt': item.float == 'right',
'multi-select': dialogueStore.isOpenMultiSelect,
'multi-select-check': item.isCheck,
}"
>
<!-- 系统消息 -->
<div v-if="item.msg_type >= 1000" class="message-box">
<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"
/>
</div>
<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>
</aside>
<!-- <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>
</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)"
/>
</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)"
/>
</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>
<span>
{{ parseTime(item.created_at, '{m}/{d} {h}:{i}') }}
</span>
</div>
<div
class="talk-content"
:class="{ pointer: dialogueStore.isOpenMultiSelect }"
<!-- 主体信息 -->
<main class="main-column">
<div class="talk-title">
<span
class="nickname pointer"
v-show="talkParams.type == 2 && item.float == 'left'"
@click="onClickNickname(item)"
>
<deepBubble
@clickMenu="(menuType) => onContextMenu(menuType, item)"
:isShowCopy="isShowCopy(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'"
/>
</deepBubble>
<!-- <div class="talk-tools">
<span class="at">@</span>
{{ item.nickname }}
</span>
<span>
{{ parseTime(item.created_at, '{m}/{d} {h}:{i}') }}
</span>
</div>
<div
class="talk-content"
:class="{ pointer: dialogueStore.isOpenMultiSelect }"
>
<deepBubble
@clickMenu="(menuType) => onContextMenu(menuType, item)"
:isShowCopy="isShowCopy(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'"
/>
</deepBubble>
<!-- <div class="talk-tools">
<template v-if="talkParams.type == 1 && item.float == 'right'">
<loading theme="outline" size="19" fill="#000" :sxtrokeWidth="1" class="icon-rotate"
v-show="item.send_status == 1" />
@ -155,155 +152,159 @@
</template>
</div> -->
</div>
</div>
<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 }}:
{{ item.extra?.reply?.content }}
</span>
</div>
</main>
<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 }}:
{{ item.extra?.reply?.content }}
</span>
</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>
</div>
</div>
<template #bottom>
<div class="footBox">
<div v-if="!dialogueStore.isOpenMultiSelect">
<div
class="pt-[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;"
/>
<!-- <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>
</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 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>
<div v-else class="h-[232rpx]">
<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"
>
<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"
>
<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"
>
<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"
>
<tm-image :width="68" :height="68" :src="zu6053"></tm-image>
<div class="mt-[6rpx]">删除</div>
</div>
</div>
</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="flex-1 quillBox">
<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>
</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="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"
>
<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"
>
<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"
>
<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"
>
<tm-image :width="68" :height="68" :src="zu6053"></tm-image>
<div class="mt-[6rpx]">删除</div>
</div>
</div>
</div>
<!--底部安全区-->
<div class="content-placeholder"></div>
<tm-drawer
placement="bottom"
v-model:show="state.showWin"
:hideHeader="true"
: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="content-placeholder"></div>
<tm-drawer
placement="bottom"
v-model:show="state.showWin"
:hideHeader="true"
:height="416"
:round="6"
>
撤回该条消息
</div>
<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>
<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>
<div class="divider"></div>
<div
@click="state.showWin = false"
class="mt-[32rpx] mb-[32rpx] text-[32rpx] text-[#000000] leading-[48rpx]"
>
取消
</div>
</div>
</tm-drawer>
</div>
</tm-drawer>
</div>
</template>
</ZPaging>
</div>
</template>
<script setup>
@ -854,24 +855,23 @@ onUnmounted(() => {
})
</script>
<style scoped lang="less">
uni-page-body,
page {
height: 100%;
}
.outer-layer {
.dialog-page {
flex: 1;
background-image: url('@/static/image/clockIn/z3280@3x.png');
background-size: cover;
display: flex;
flex-direction: column;
overflow: hidden;
}
background-position: bottom center;
background-attachment: fixed;
width: 100%;
.root {
flex: 1;
padding: 20rpx 32rpx;
min-height: 0;
.dialog-list {
padding: 20rpx 32rpx;
}
.toChatSetting_btn {
::v-deep .tmicon-gengduo {
line-height: unset !important;
}
}
}
.searchRoot {
@ -889,22 +889,6 @@ page {
background-color: #fff;
}
.dialogBox {
height: 100%;
min-height: 0;
overflow: auto;
//
&::-webkit-scrollbar {
display: none;
}
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
.load-toolbar {
height: 50rpx;
color: #409eff;

View File

@ -78,8 +78,8 @@ export const useGroupTypeStore = createGlobalState(() => {
}),
positionInfos: groupAdmins.value.map((v) => {
return {
position_id: v.ID,
position_name: v.name,
position_id: v.position_id,
position_name: v.position_name,
}
}),
})

View File

@ -54,7 +54,7 @@
<!-- #endif -->
<slot name="left"></slot>
</view>
<view class="flex flex-row-center-center" :style="{ width: contentwidth + 'px' }">
<view class="flex flex-row-center-center flex-col" :style="{ width: contentwidth + 'px' }">
<slot>
<tm-text
:unit="props.unit"
@ -63,6 +63,7 @@
:font-size="props.fontSize"
:label="_title"
></tm-text>
<slot name="subTitle"></slot>
</slot>
</view>
<view class="flex-row flex flex-row-center-end" :style="{ width: _rightWidth + 'rpx' }">