chat-pc/src/views/message/inner/IndexContent.vue

890 lines
26 KiB
Vue
Raw Normal View History

2024-12-24 08:14:21 +00:00
<script lang="ts" setup>
import { reactive, computed, watch } from 'vue'
import { NDrawer, NCard, NTag, NInput } from 'naive-ui'
2024-12-24 08:14:21 +00:00
import { useUserStore, useDialogueStore, useUploadsStore } from '@/store'
import PanelHeader from './panel/PanelHeader.vue'
import PanelContent from './panel/PanelContent.vue'
import PanelFooter from './panel/PanelFooter.vue'
import GroupPanel from '@/components/group/GroupPanel.vue'
import GroupNotice from '@/components/group/GroupNotice.vue'
import UploadsModal from '@/components/base/UploadsModal.vue'
import customModal from '@/components/common/customModal.vue'
import historyRecord from '@/components/search/searchByCondition.vue'
import { ServeEditGroupNotice, ServeGetGroupNotices, ServeDeleteGroupNotice } from '@/api/group'
import avatarModule from '@/components/avatar-module/index.vue'
2024-12-24 08:14:21 +00:00
const userStore = useUserStore()
const dialogueStore = useDialogueStore()
const uploadsStore = useUploadsStore()
console.log('dialogueStore', dialogueStore)
2024-12-24 08:14:21 +00:00
const members = computed(() => dialogueStore.members)
const membersByAlphabet = computed(() => {
if (state.searchMemberByAlphabet) {
// 过滤分组,并且只保留匹配成员
return (
(dialogueStore.membersByAlphabet as any)
.map((group: any) => {
// 只保留匹配的成员
const filteredMembers = group.members.filter(
(member) => member.nickname && member.nickname.includes(state.searchMemberByAlphabet)
)
return {
...group,
members: filteredMembers
}
})
// 只保留有成员的分组
.filter((group) => group.members.length > 0)
)
}
return dialogueStore.membersByAlphabet
})
2024-12-24 08:14:21 +00:00
const isShowEditor = computed(() => dialogueStore.isShowEditor)
// 当前对话参数
const talkParams = reactive({
uid: computed(() => userStore.uid),
index_name: computed(() => dialogueStore.index_name),
type: computed(() => dialogueStore.talk.talk_type),
receiver_id: computed(() => dialogueStore.talk.receiver_id),
username: computed(() => dialogueStore.talk.username),
online: computed(() => dialogueStore.online),
keyboard: computed(() => dialogueStore.keyboard),
num: computed(() => dialogueStore.members.length),
avatar: computed(() => dialogueStore.talk.avatar),
specifiedMsg: computed(() => dialogueStore.specifiedMsg)
2024-12-24 08:14:21 +00:00
})
const state = reactive({
// 是否显示群面板
isShowGroupAside: false,
isShowGroupNotice: false,
isShowSearchRecordByConditionModal: false, //是否显示按条件搜索记录弹窗
customSearchRecordByConditionModalStyle: {
width: '997px',
height: '740px',
backgroundColor: '#F9F9FD'
}, //按条件搜索记录弹窗样式
searchRecordByConditionText: '', //按条件搜索记录文本
conditionTag: 'all', //当前条件标签
conditionType: 'all', //当前条件类型
isShowGroupNoticeModal: false, //是否显示群公告模态框
customGroupNoticeModalStyle: {
width: '997px',
height: '740px'
}, //群公告模态框样式
groupNoticeModalActionBtns: {
confirmBtn: {
text: '编辑',
doLoading: false,
disabled: false
},
cancelBtn: false
}, //群公告模态框操作按钮
groupNoticeModalActionBtnsStyle: 'padding: 20px 0;', //群公告模态框操作按钮样式
groupNoticeInEdit: '', //编辑中的公告
groupNoticeEditMode: 3, //群公告编辑模式2=编辑3=查看
groupNoticeModalConfirmBtnEvent: 'edit', //群公告模态框确认按钮事件edit=编辑fillIn=输入
isShowNoticeHintModal: false, //是否显示群公告提示模态框
customNoticeHintModalStyle: {
width: '724px',
height: '314px'
}, //群公告提示模态框样式
noticeHintModalActionBtns: {}, //群公告提示模态框操作按钮
noticeHintModalContent: '', //群公告提示模态框内容
noticeHintMode: 'publish', //群公告提示模式publish=发布cancel=取消
groupNoticeInfo: {
id: 0,
avatar: '',
updater_name: '',
updated_at: '',
content: ''
}, //群公告信息
isAdmin: false, //当前登录用户是否是该群管理员
groupNoticeContentChange: '', //群公告内容变化
searchMemberByAlphabet: '', //群成员搜索文本
searchMemberItem: '', //群成员搜索item
showMemberListByAlphabetPopover: false // 控制群成员弹窗显示
2024-12-24 08:14:21 +00:00
})
const events = {
notice: () => {
state.isShowGroupNotice = !state.isShowGroupNotice
},
group: () => {
state.isShowGroupAside = !state.isShowGroupAside
}
}
watch(
() => talkParams,
(newValue, oldValue) => {
console.log(newValue)
},
{ deep: true, immediate: true }
)
2024-12-24 08:14:21 +00:00
// Header 工具栏事件
const onPanelHeaderEvent = (eventType: string) => {
events[eventType] && events[eventType]()
}
//点击切换搜索条件/分类
const changeConditionTag = (tag) => {
console.log(tag)
state.conditionType = tag
if (tag === 'file') {
state.conditionTag = '文件'
} else if (tag === 'imgAndVideo') {
state.conditionTag = '图片与视频'
} else if (tag === 'date') {
state.conditionTag = '日期'
} else if (tag === 'member') {
state.conditionTag = '群成员'
} else {
state.conditionTag = 'all'
}
}
//取消群公告编辑并返回查看
const cancelEditGroupNotice = () => {
//切换群公告编辑模式为查看
state.groupNoticeEditMode = 3
state.groupNoticeModalActionBtns = {
confirmBtn: {
text: '编辑',
doLoading: false,
disabled: false
},
cancelBtn: false
}
//切换确定按钮事件为编辑
state.groupNoticeModalConfirmBtnEvent = 'edit'
}
// 群公告模态框确定按钮事件
const handleGroupNoticeModalConfirm = () => {
if (state.groupNoticeModalConfirmBtnEvent === 'edit') {
//点击切换群公告编辑模式为编辑
state.groupNoticeEditMode = 2
state.groupNoticeModalActionBtns = {
confirmBtn: {
text: '完成',
doLoading: false,
disabled: true
},
cancelBtn: true
}
//切换确定按钮事件为输入
state.groupNoticeModalConfirmBtnEvent = 'fillIn'
if (state.groupNoticeInfo?.id) {
state.groupNoticeInEdit = state.groupNoticeInfo.content
state.groupNoticeModalActionBtns.confirmBtn.disabled = false
}
} else if (state.groupNoticeModalConfirmBtnEvent === 'fillIn') {
//点击显示发布提示
state.isShowNoticeHintModal = true
if (state?.groupNoticeInfo?.id && !state.groupNoticeInEdit) {
//如果是在编辑中,但是没有输入内容,此时点击完成即为删除群公告
state.noticeHintModalContent = '确定清空群公告吗?'
state.noticeHintModalActionBtns = {
confirmBtn: {
text: '清空',
doLoading: true
},
cancelBtn: true
}
//切换公告提示模式为清空
state.noticeHintMode = 'clear'
} else {
state.noticeHintModalContent = '发布该公告会通知全部群成员'
state.noticeHintModalActionBtns = {
confirmBtn: {
text: '发布',
doLoading: true
},
cancelBtn: true
}
//切换公告提示模式为发布
state.noticeHintMode = 'publish'
}
}
}
// 群公告模态框取消按钮事件
const handleGroupNoticeModalCancel = () => {
if (state.groupNoticeModalConfirmBtnEvent === 'fillIn') {
if (state.groupNoticeInEdit || (state.groupNoticeInfo?.id && !state.groupNoticeInEdit)) {
//如果有正在编辑中的公告或者编辑已发布的公告内容为空,显示确认取消编辑弹窗
state.isShowNoticeHintModal = true
state.noticeHintModalContent = '退出本次编辑'
state.noticeHintModalActionBtns = {
confirmBtn: {
text: '继续编辑',
doLoading: false
},
cancelBtn: {
text: '退出'
}
}
//切换公告提示模式为取消
state.noticeHintMode = 'cancel'
} else {
//没有正在编辑中的公告,退出编辑
cancelEditGroupNotice()
}
}
}
// 群公告模态框关闭事件
const handleGroupNoticeModalClose = () => {
//关闭应与取消事件一致
handleGroupNoticeModalCancel()
}
// 群公告提示模态框确认按钮事件
const handleNoticeHintModalConfirm = (closeLoading) => {
console.log('handleNoticeHintModalConfirm')
if (state.noticeHintMode === 'cancel') {
//不退出,回到编辑
state.isShowNoticeHintModal = false
} else if (state.noticeHintMode === 'publish') {
//发布
doPublishGroupNotice(closeLoading)
} else if (state.noticeHintMode === 'clear') {
//清空
doClearGroupNotice(closeLoading)
}
}
// 群公告提示模态框取消按钮事件
const handleNoticeHintModalCancel = () => {
console.log('handleNoticeHintModalCancel')
if (state.noticeHintMode === 'publish') {
//取消发布,回到编辑
state.isShowNoticeHintModal = false
} else if (state.noticeHintMode === 'cancel') {
//清除正在编辑中的公告并退出编辑
state.groupNoticeInEdit = ''
state.isShowNoticeHintModal = false
cancelEditGroupNotice()
} else if (state.noticeHintMode === 'clear') {
//不清空,继续编辑
state.isShowNoticeHintModal = false
}
}
// 群公告模态框输入事件
const handleGroupNoticeModalInput = (value) => {
console.log(value)
if (value.trim()) {
state.groupNoticeModalActionBtns.confirmBtn.disabled = false
} else {
if (!state.groupNoticeInfo?.id) {
state.groupNoticeModalActionBtns.confirmBtn.disabled = true
} else {
state.groupNoticeModalActionBtns.confirmBtn.disabled = false
}
}
}
// 发布群公告
const doPublishGroupNotice = (closeLoading) => {
let params = {
notice_id: state?.groupNoticeInfo?.id || 0,
group_id: talkParams.receiver_id,
title: '',
content: state.groupNoticeInEdit,
is_top: 0,
is_confirm: 0
}
console.log(params)
const resp = ServeEditGroupNotice(params)
resp
.then((res) => {
closeLoading()
if (res.code == 200) {
// 发布成功,关闭群公告模态框
state.isShowGroupNoticeModal = false
state.isShowNoticeHintModal = false
state.groupNoticeContentChange = state.groupNoticeInEdit
state.groupNoticeInEdit = ''
cancelEditGroupNotice()
window['$message'].success(res.msg)
} else {
window['$message'].warning(res.msg)
}
})
.catch((err) => {
closeLoading()
window['$message'].warning(err.msg)
})
}
//获取群公告列表
const getGroupNotices = () => {
ServeGetGroupNotices({
group_id: talkParams.receiver_id
}).then((res) => {
console.log(res)
if (res.code == 200) {
if (res?.data?.items[0]?.id) {
state.groupNoticeInfo = res.data.items[0]
} else {
state.groupNoticeInfo = {
id: 0,
avatar: '',
updater_name: '',
updated_at: '',
content: ''
}
}
} else {
window['$message'].warning(res.msg)
}
})
}
// 清空群公告
const doClearGroupNotice = (closeLoading) => {
ServeDeleteGroupNotice({
notice_id: state.groupNoticeInfo.id,
group_id: talkParams.receiver_id
})
.then((res) => {
closeLoading()
if (res.code == 200) {
// 清空成功,关闭群公告模态框并恢复群公告模态框初始状态
state.groupNoticeInfo = {
id: 0,
avatar: '',
updater_name: '',
updated_at: '',
content: ''
}
state.isShowGroupNoticeModal = false
state.isShowNoticeHintModal = false
state.groupNoticeContentChange = ''
cancelEditGroupNotice()
window['$message'].success(res.msg)
} else {
window['$message'].warning(res.msg)
}
})
.catch((err) => {
closeLoading()
window['$message'].warning(err.msg)
})
}
// 群公告模态框显示事件
const handleGroupNoticeModalShow = (isAdmin) => {
state.isAdmin = isAdmin
if (isAdmin) {
state.groupNoticeModalActionBtns = {
confirmBtn: {
text: '编辑',
doLoading: false,
disabled: false
},
cancelBtn: false
}
} else {
;(state.groupNoticeModalActionBtns.confirmBtn as any) = false
}
state.isShowGroupNoticeModal = true
getGroupNotices()
}
//点击群成员类型搜索聊天记录下的群成员item
const handleMemberItemClick = (memberItem) => {
state.searchMemberItem = encodeURIComponent(JSON.stringify(memberItem))
state.showMemberListByAlphabetPopover = false // 关闭弹窗
state.searchMemberByAlphabet = ''
}
//清空按A-Z排序下搜索群成员关键字
const clearSearchMemberByAlphabet = () => {
state.searchMemberByAlphabet = ''
}
// 搜索记录模态框关闭事件
const handleSearchRecordByConditionModalClose = () => {
state.isShowSearchRecordByConditionModal = false
resetSearchRecordByCondition()
}
// 重置搜索记录模态框
const resetSearchRecordByCondition = () => {
state.searchRecordByConditionText = ''
state.conditionType = 'all'
state.conditionTag = 'all'
state.searchMemberItem = ''
state.showMemberListByAlphabetPopover = false
state.searchMemberByAlphabet = ''
}
2024-12-24 08:14:21 +00:00
</script>
<template>
<section id="drawer-container" class="el-container is-vertical">
<!-- 头部区域 -->
<header class="el-header bdr-b">
<PanelHeader
:type="talkParams.type"
:username="talkParams.username"
:online="talkParams.online"
:keyboard="talkParams.keyboard"
:num="talkParams.num"
:avatar="talkParams.avatar"
2024-12-24 08:14:21 +00:00
@evnet="onPanelHeaderEvent"
/>
</header>
<!-- 聊天区域 -->
<main class="el-main">
<PanelContent
:uid="talkParams.uid"
:talk_type="talkParams.type"
:receiver_id="talkParams.receiver_id"
:index_name="talkParams.index_name"
:specifiedMsg="talkParams.specifiedMsg"
2024-12-24 08:14:21 +00:00
/>
</main>
<!-- 编辑器区域 -->
<footer
v-show="isShowEditor"
class="el-footer"
:style="{ height: 200 + 'px' }"
v-dropsize="{ min: 200, max: 600, direction: 'top', key: 'editor' }"
>
<PanelFooter
:uid="talkParams.uid"
:index_name="talkParams.index_name"
:talk_type="talkParams.type"
:receiver_id="talkParams.receiver_id"
:online="talkParams.online"
:members="members"
/>
</footer>
</section>
<n-drawer
v-model:show="uploadsStore.isShow"
:width="400"
placement="right"
:trap-focus="false"
:block-scroll="false"
show-mask="transparent"
to="#drawer-container"
>
<UploadsModal />
</n-drawer>
<n-drawer
v-model:show="state.isShowGroupNotice"
:width="400"
placement="right"
:trap-focus="false"
:block-scroll="false"
show-mask="transparent"
to="#drawer-container"
>
<GroupNotice :group-id="talkParams.receiver_id" @close="state.isShowGroupNotice = false" />
</n-drawer>
<n-drawer
v-model:show="state.isShowGroupAside"
:width="453"
2024-12-24 08:14:21 +00:00
placement="right"
:trap-focus="false"
:block-scroll="false"
:show-mask="true || 'transparent'"
2024-12-24 08:14:21 +00:00
to="#drawer-container"
>
<GroupPanel
:gid="talkParams.receiver_id"
@close="state.isShowGroupAside = false"
:talkType="talkParams.type"
@handleSearchRecordByConditionModalShow="state.isShowSearchRecordByConditionModal = true"
@handleGroupNoticeModalShow="handleGroupNoticeModalShow"
:groupNoticeContentChange="state.groupNoticeContentChange"
/>
2024-12-24 08:14:21 +00:00
</n-drawer>
<customModal
v-model:show="state.isShowSearchRecordByConditionModal"
:title="`${talkParams.type === 1 ? '与' : ''}&nbsp;&quot;${
talkParams.username
}&quot;&nbsp;的聊天记录`"
:style="state.customSearchRecordByConditionModalStyle"
:customCloseBtn="true"
:closable="false"
:customCloseEvent="true"
@customCloseModal="handleSearchRecordByConditionModalClose"
>
<template #content>
<div class="search-record-modal-searchArea">
<n-card style="padding: 0 12px;">
<div class="search-record-input">
<span class="search-record-input-title">搜索</span>
<n-input
type="text"
v-model:value="state.searchRecordByConditionText"
placeholder="请输入"
clearable
>
<template #clear-icon>
<img src="@/assets/image/icon/close-btn-grey-line.png" alt="close" />
</template>
<template #prefix>
<n-tag
closable
v-if="state.conditionTag && state.conditionTag !== 'all'"
@close="changeConditionTag('all')"
>
{{ state.conditionTag }}
</n-tag>
</template>
</n-input>
</div>
<div class="search-area-condition">
<span @click="changeConditionTag('file')">文件</span>
<span @click="changeConditionTag('imgAndVideo')">图片与视频</span>
<n-popover trigger="click" placement="bottom-start" style="height: 312px; padding: 0;">
<template #trigger>
<span id="date-condition" @click="changeConditionTag('date')">日期</span>
</template>
<historyRecord conditionType="dateTimePicker" v-if="state.conditionType === 'date'" />
</n-popover>
<n-popover
v-model:show="state.showMemberListByAlphabetPopover"
trigger="click"
placement="bottom-start"
style="width: 290px; height: 505px; padding: 0;"
v-if="talkParams.type === 2"
>
<template #trigger>
<span @click="changeConditionTag('member')">群成员</span>
</template>
<div class="member-list-by-alphabet-container">
<n-input
placeholder="请输入群成员"
style="margin: 0 0 17px;"
v-model:value="state.searchMemberByAlphabet"
/>
<n-scrollbar style="height: 430px;">
<div
class="member-list-by-alphabet"
v-for="(alphabetMembersItem, alphabetMembersIndex) in membersByAlphabet"
:key="alphabetMembersIndex"
>
<div class="member-list-each-alphabet-header">
<span>{{ (alphabetMembersItem as any).alphabet }}</span>
</div>
<div class="member-list-each-alphabet">
<div
class="member-item-each-alphabet"
v-for="(memberItem, memberItemIndex) in (alphabetMembersItem as any).members"
:key="memberItemIndex"
@click="handleMemberItemClick(memberItem)"
>
<avatarModule
:mode="1"
:avatar="memberItem.avatar"
:userName="memberItem.nickname"
:groupType="0"
:customStyle="{
width: '38px',
height: '38px'
}"
:customTextStyle="{
fontSize: '12px',
fontWeight: 'bold',
color: '#fff',
lineHeight: '17px'
}"
></avatarModule>
<span>{{ memberItem.nickname }}</span>
</div>
</div>
</div>
</n-scrollbar>
</div>
</n-popover>
</div>
</n-card>
</div>
<div class="search-record-modal-content">
<n-card>
<div class="search-record-card">
<historyRecord
:conditionType="state.conditionType"
:searchMemberItem="state.searchMemberItem"
@clearSearchMemberByAlphabet="clearSearchMemberByAlphabet"
:searchRecordByConditionText="state.searchRecordByConditionText"
/>
</div>
</n-card>
</div>
</template>
</customModal>
<customModal
v-model:show="state.isShowGroupNoticeModal"
:title="`&quot;${talkParams.username}&quot;&nbsp;的群公告`"
:style="state.customGroupNoticeModalStyle"
:customCloseBtn="true"
:closable="false"
:actionBtns="state.groupNoticeModalActionBtns"
:customModalBtnsStyle="state.groupNoticeModalActionBtnsStyle"
@confirm="handleGroupNoticeModalConfirm"
@cancel="handleGroupNoticeModalCancel"
:customCloseEvent="state.groupNoticeEditMode === 2 ? true : false"
@customCloseModal="handleGroupNoticeModalClose"
>
<template #content>
<div class="group-notice-modal-content">
<div class="group-notice-text-area" v-if="state.groupNoticeEditMode === 2">
<n-input
v-model:value="state.groupNoticeInEdit"
type="textarea"
:autosize="{
minRows: 22,
maxRows: 22
}"
placeholder="请输入"
:maxlength="500"
:show-count="true"
@input="handleGroupNoticeModalInput"
/>
</div>
<div
class="group-notice-info"
v-if="state.groupNoticeEditMode === 3 && state.groupNoticeInfo?.id"
>
<div class="group-notice-header">
<avatarModule
:mode="1"
:avatar="state.groupNoticeInfo.avatar"
:userName="state.groupNoticeInfo.updater_name"
:groupType="0"
:customStyle="{
width: '42px',
height: '42px'
}"
:customTextStyle="{
fontSize: '14px',
fontWeight: 'bold',
color: '#fff',
lineHeight: '20px'
}"
></avatarModule>
<div class="group-notice-header-userInfo">
<span style="color: #1b1b1b; font-weight: 600; line-height: 20px;">{{
state.groupNoticeInfo.updater_name
}}</span>
<span>{{ state.groupNoticeInfo.updated_at }}</span>
</div>
</div>
<div class="group-notice-content">
<span>{{ state.groupNoticeInfo.content }}</span>
</div>
</div>
<div
class="group-notice-empty"
v-if="state.groupNoticeEditMode === 3 && !state.groupNoticeInfo?.id"
>
<img src="@/assets/image/chatList/search-empty.png" alt="" />
<span>暂无公告</span>
</div>
</div>
</template>
</customModal>
<customModal
v-model:show="state.isShowNoticeHintModal"
title="提示"
:style="state.customNoticeHintModalStyle"
:closable="false"
:actionBtns="state.noticeHintModalActionBtns"
customModalBtnsStyle="padding: 0 0 30px;"
@confirm="handleNoticeHintModalConfirm"
@cancel="handleNoticeHintModalCancel"
>
<template #content>
<div class="notice-hint-modal-content">
<text>{{ state.noticeHintModalContent }}</text>
</div>
</template>
</customModal>
2024-12-24 08:14:21 +00:00
</template>
<style lang="less" scoped>
.drawer-target {
overflow: hidden;
}
.search-record-modal-searchArea {
box-sizing: border-box;
width: 100%;
padding: 0 12px;
:deep(.n-card) {
border: 0;
box-shadow: 0 3px 6px 1px rgba(188, 188, 188, 0.18);
}
:deep(.n-card__content) {
padding: 27px 12px 0;
}
.search-record-input {
display: flex;
align-items: center;
justify-content: center;
.search-record-input-title {
width: 78px;
}
}
.search-area-condition {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 22px 0 11px;
span {
font-size: 14px;
color: #46299d;
font-weight: 400;
line-height: 20px;
margin: 0 62px 0 0;
cursor: pointer;
}
}
}
.search-record-modal-content {
box-sizing: border-box;
width: 100%;
padding: 0 12px;
margin: 18px 0 0;
:deep(.n-card__content) {
padding: 0;
}
:deep(.n-card) {
border: 0;
box-shadow: 0 3px 6px 1px rgba(188, 188, 188, 0.18);
}
.search-record-card {
}
}
.group-notice-modal-content {
.group-notice-text-area {
:deep(.n-input-wrapper) {
padding: 20px 23px 15px;
}
:deep(.n-input-word-count) {
right: 23px;
bottom: 15px;
}
}
.group-notice-info {
.group-notice-header {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 20px 0;
margin: 0 12px;
border-bottom: 1px solid #e5e5e5;
.group-notice-header-userInfo {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
margin: 0 0 0 10px;
span {
font-size: 14px;
color: #adadad;
font-weight: 400;
line-height: 17px;
}
}
}
.group-notice-content {
padding: 20px 0;
margin: 0 12px;
span {
font-size: 14px;
font-weight: 400;
line-height: 20px;
}
}
}
.group-notice-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 552px;
box-sizing: border-box;
img {
width: 160px;
height: 104px;
}
span {
font-size: 14px;
color: #999;
font-weight: 400;
margin: 14px 0 0;
}
}
}
.notice-hint-modal-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
text {
font-size: 20px;
line-height: 28px;
font-weight: 400;
color: #1f2225;
}
}
.member-list-by-alphabet-container {
padding: 12px;
width: 290px;
.member-list-by-alphabet {
.member-list-each-alphabet-header {
border-bottom: 1px solid #e5e5e5;
span {
font-size: 14px;
color: #999;
font-weight: 400;
line-height: 20px;
}
}
.member-list-each-alphabet {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
gap: 10px;
padding: 12px 0;
.member-item-each-alphabet {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
gap: 10px;
width: 100%;
cursor: pointer;
span {
font-size: 12px;
color: #000;
font-weight: 400;
line-height: 17px;
}
}
}
}
}
2024-12-24 08:14:21 +00:00
</style>