|
@ -1,15 +1,141 @@ |
|
|
|
|
|
|
|
|
import { chat_groupList, chat_userList } from "@/api/chat" |
|
|
|
|
|
|
|
|
import { chat_cancelMuteGroup, chat_changeGroup, chat_createGroup, chat_dismissGroup, chat_groupList, chat_muteGroup, chat_userList } from "@/api/chat" |
|
|
import BuzzFaceURL from "@/components/buzzup/BuzzFaceURL"; |
|
|
import BuzzFaceURL from "@/components/buzzup/BuzzFaceURL"; |
|
|
import MyTable from "@/components/MyTable" |
|
|
import MyTable from "@/components/MyTable" |
|
|
import { getTime, isGender, isPlatformId } from "@/utils"; |
|
|
import { getTime, isGender, isPlatformId } from "@/utils"; |
|
|
import React from "react" |
|
|
|
|
|
|
|
|
import { LoadingOutlined, PlusOutlined } from "@ant-design/icons"; |
|
|
|
|
|
import { Button, Drawer, Form, Input, Modal, notification, Popconfirm, Select, Upload } from "antd"; |
|
|
|
|
|
import TextArea from "antd/lib/input/TextArea"; |
|
|
|
|
|
import React, { useRef, useState } from "react" |
|
|
import { useLocation, useHistory } from "react-router-dom"; |
|
|
import { useLocation, useHistory } from "react-router-dom"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ChatGroupList = () => { |
|
|
const ChatGroupList = () => { |
|
|
|
|
|
|
|
|
const history = useHistory() |
|
|
const history = useHistory() |
|
|
|
|
|
const tableRef = useRef(null) |
|
|
|
|
|
const tableOwnerRef = useRef(null) |
|
|
|
|
|
const tableAdminRef = useRef(null) |
|
|
|
|
|
const tableMemberRef = useRef(null) |
|
|
|
|
|
|
|
|
|
|
|
const [visible, setVisible] = useState(false) |
|
|
|
|
|
const [visibleModal, setVisibleModal] = useState(false) |
|
|
|
|
|
const [visibleModal1, setVisibleModal1] = useState(false) |
|
|
|
|
|
const [visibleModal2, setVisibleModal2] = useState(false) |
|
|
|
|
|
const [loading, setLoading] = useState(false) |
|
|
|
|
|
|
|
|
|
|
|
const groupOperate = useRef('' as 'c' | 'u') |
|
|
|
|
|
|
|
|
|
|
|
const [form] = Form.useForm() |
|
|
|
|
|
|
|
|
|
|
|
const muteGroup = async (item) => { |
|
|
|
|
|
try { |
|
|
|
|
|
const res: any = await chat_muteGroup({ |
|
|
|
|
|
groupID: item.groupInfo.groupID |
|
|
|
|
|
}) |
|
|
|
|
|
if (res.code === 0) { |
|
|
|
|
|
notification.success({ |
|
|
|
|
|
message: '全体禁言成功' |
|
|
|
|
|
}); |
|
|
|
|
|
tableRef.current.update() |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const cancelMuteGroup = async (item) => { |
|
|
|
|
|
try { |
|
|
|
|
|
const res: any = await chat_cancelMuteGroup({ |
|
|
|
|
|
groupID: item.groupInfo.groupID |
|
|
|
|
|
}) |
|
|
|
|
|
if (res.code === 0) { |
|
|
|
|
|
notification.success({ |
|
|
|
|
|
message: '解除禁言成功' |
|
|
|
|
|
}); |
|
|
|
|
|
tableRef.current.update() |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const dismissGroup = async (item) => { |
|
|
|
|
|
try { |
|
|
|
|
|
const res: any = await chat_dismissGroup({ |
|
|
|
|
|
groupID: item.groupInfo.groupID |
|
|
|
|
|
}) |
|
|
|
|
|
if (res.code === 0) { |
|
|
|
|
|
notification.success({ |
|
|
|
|
|
message: '解散群组成功' |
|
|
|
|
|
}); |
|
|
|
|
|
tableRef.current.update() |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const createGroup = async (values) => { |
|
|
|
|
|
try { |
|
|
|
|
|
const params = { |
|
|
|
|
|
"adminUserIDs": values.adminUserIDs ? values.adminUserIDs.map(v => v.userID) : [], |
|
|
|
|
|
"groupInfo": { |
|
|
|
|
|
applyMemberFriend: values.applyMemberFriend, |
|
|
|
|
|
groupName: values.groupName, |
|
|
|
|
|
groupType: 2, |
|
|
|
|
|
lookMemberInfo: values.lookMemberInfo, |
|
|
|
|
|
needVerification: values.needVerification, |
|
|
|
|
|
introduction: values.introduction || '', |
|
|
|
|
|
notification: values.notification || '' |
|
|
|
|
|
}, |
|
|
|
|
|
"memberUserIDs": values.memberUserIDs.map(v => v.userID), |
|
|
|
|
|
"ownerUserID": values.ownerUserID[0].userID |
|
|
|
|
|
} |
|
|
|
|
|
setVisible(false) |
|
|
|
|
|
form.resetFields() |
|
|
|
|
|
const res: any = await chat_createGroup(params) |
|
|
|
|
|
if (res.code === 0) { |
|
|
|
|
|
notification.success({ |
|
|
|
|
|
message: '创建成功' |
|
|
|
|
|
}) |
|
|
|
|
|
tableRef.current.update() |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const changeGroup = async (values) => { |
|
|
|
|
|
const { applyMemberFriend, groupID, groupName, introduction, lookMemberInfo, needVerification } = values |
|
|
|
|
|
const params = { applyMemberFriend, groupID, groupName, introduction, lookMemberInfo, needVerification, notification: values.notification } |
|
|
|
|
|
setVisible(false) |
|
|
|
|
|
form.resetFields() |
|
|
|
|
|
const res: any = await chat_changeGroup({ groupInfoForSet: params }) |
|
|
|
|
|
if (res.code === 0) { |
|
|
|
|
|
notification.success({ |
|
|
|
|
|
message: '修改成功' |
|
|
|
|
|
}); |
|
|
|
|
|
tableRef.current.update() |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const onFinish = async (values) => { |
|
|
|
|
|
if (groupOperate.current === 'c') { |
|
|
|
|
|
createGroup(values) |
|
|
|
|
|
} else { |
|
|
|
|
|
changeGroup(values) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const openVisible = async (item) => { |
|
|
|
|
|
setVisible(true); |
|
|
|
|
|
groupOperate.current = 'u'; |
|
|
|
|
|
console.log(item); |
|
|
|
|
|
form.setFieldsValue({ |
|
|
|
|
|
...item.groupInfo |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
const columns = [ |
|
|
const columns = [ |
|
|
{ |
|
|
{ |
|
@ -74,24 +200,246 @@ const ChatGroupList = () => { |
|
|
{ |
|
|
{ |
|
|
title: 'options', |
|
|
title: 'options', |
|
|
fixed: 'right', |
|
|
fixed: 'right', |
|
|
width: 250, |
|
|
|
|
|
|
|
|
width: 280, |
|
|
render: (item) => ( |
|
|
render: (item) => ( |
|
|
<div className="" style={{ display: 'flex' }}> |
|
|
<div className="" style={{ display: 'flex' }}> |
|
|
<div style={{ fontSize: 12, color: '#1890ff', textWrap: 'nowrap', cursor: 'pointer' }} onClick={() => history.push(`/group-member?id=${item.groupInfo.groupID}`)}>群成员</div> |
|
|
<div style={{ fontSize: 12, color: '#1890ff', textWrap: 'nowrap', cursor: 'pointer' }} onClick={() => history.push(`/group-member?id=${item.groupInfo.groupID}`)}>群成员</div> |
|
|
<div style={{ fontSize: 12, color: '#1890ff', marginLeft: 15, textWrap: 'nowrap', cursor: 'pointer' }}>群聊设置</div> |
|
|
|
|
|
|
|
|
<div style={{ fontSize: 12, color: '#1890ff', marginLeft: 15, textWrap: 'nowrap', cursor: 'pointer' }} onClick={() => openVisible(item)}>群聊设置</div> |
|
|
|
|
|
{item.groupInfo.status === 3 ? ( |
|
|
|
|
|
<Popconfirm title="确认全体解除禁言?" onConfirm={() => cancelMuteGroup(item)}> |
|
|
|
|
|
<div style={{ fontSize: 12, color: '#1890ff', marginLeft: 15, textWrap: 'nowrap', cursor: 'pointer' }}>解除禁言</div> |
|
|
|
|
|
</Popconfirm> |
|
|
|
|
|
) : <Popconfirm title="确认全体禁言?" onConfirm={() => muteGroup(item)}> |
|
|
<div style={{ fontSize: 12, color: '#1890ff', marginLeft: 15, textWrap: 'nowrap', cursor: 'pointer' }}>全体禁言</div> |
|
|
<div style={{ fontSize: 12, color: '#1890ff', marginLeft: 15, textWrap: 'nowrap', cursor: 'pointer' }}>全体禁言</div> |
|
|
|
|
|
</Popconfirm>} |
|
|
|
|
|
<Popconfirm title="确认解散吗?" onConfirm={() => dismissGroup(item)}> |
|
|
<div style={{ fontSize: 12, color: '#1890ff', marginLeft: 15, textWrap: 'nowrap', cursor: 'pointer' }}>解散群组</div> |
|
|
<div style={{ fontSize: 12, color: '#1890ff', marginLeft: 15, textWrap: 'nowrap', cursor: 'pointer' }}>解散群组</div> |
|
|
|
|
|
</Popconfirm> |
|
|
</div> |
|
|
</div> |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
const searchConfig = [ |
|
|
|
|
|
{ |
|
|
|
|
|
key: 'groupID', |
|
|
|
|
|
label: '群组ID', |
|
|
|
|
|
slot: <Input placeholder="请输入" /> |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
key: 'groupName', |
|
|
|
|
|
label: '群组名称', |
|
|
|
|
|
slot: <Input placeholder="请输入" /> |
|
|
|
|
|
}, |
|
|
] |
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
const userColumnData = [ |
|
|
|
|
|
{ |
|
|
|
|
|
title: '头像', |
|
|
|
|
|
dataIndex: "", |
|
|
|
|
|
width: 100, |
|
|
|
|
|
render: (row) => ( |
|
|
|
|
|
<div> |
|
|
|
|
|
<BuzzFaceURL size={30} faceUrl={row.faceURL} name={row.nickname} /> |
|
|
|
|
|
</div> |
|
|
|
|
|
) |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
title: '用户昵称', |
|
|
|
|
|
dataIndex: "nickname", |
|
|
|
|
|
width: 200 |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
title: '用户ID', |
|
|
|
|
|
dataIndex: "userID", |
|
|
|
|
|
}, |
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
const handleDisableKeys = (type: 'adminUserIDs' | 'ownerUserID' | 'memberUserIDs') => { |
|
|
|
|
|
let list = [] |
|
|
|
|
|
if (form.getFieldValue('adminUserIDs') && type !== 'adminUserIDs') { |
|
|
|
|
|
list = list.concat(form.getFieldValue('adminUserIDs')) |
|
|
|
|
|
} |
|
|
|
|
|
if (form.getFieldValue('ownerUserID') && type !== 'ownerUserID') { |
|
|
|
|
|
list = list.concat(form.getFieldValue('ownerUserID')) |
|
|
|
|
|
} |
|
|
|
|
|
if (form.getFieldValue('memberUserIDs') && type !== 'memberUserIDs') { |
|
|
|
|
|
list = list.concat(form.getFieldValue('memberUserIDs')) |
|
|
|
|
|
} |
|
|
|
|
|
return list.map(v => v.userID) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const uploadButton = ( |
|
|
|
|
|
<div> |
|
|
|
|
|
{loading ? <LoadingOutlined /> : <PlusOutlined />} |
|
|
|
|
|
<div style={{ marginTop: 8 }}>Upload</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
// 用户头像 用户昵称 用户ID 性别 手机号 在线状态
|
|
|
// 用户头像 用户昵称 用户ID 性别 手机号 在线状态
|
|
|
return ( |
|
|
return ( |
|
|
|
|
|
<> |
|
|
<MyTable |
|
|
<MyTable |
|
|
|
|
|
header={ |
|
|
|
|
|
<Button type="primary" onClick={() => { |
|
|
|
|
|
setVisible(true) |
|
|
|
|
|
groupOperate.current = 'c' |
|
|
|
|
|
}}>新建群组</Button> |
|
|
|
|
|
} |
|
|
|
|
|
searchConfigList={searchConfig} |
|
|
|
|
|
ref={tableRef} |
|
|
apiFun={chat_groupList} |
|
|
apiFun={chat_groupList} |
|
|
columns={columns} |
|
|
columns={columns} |
|
|
/> |
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
{visibleModal && < Modal visible={visibleModal} onCancel={() => setVisibleModal(false)} title="选择群主" width={700} onOk={() => { |
|
|
|
|
|
setVisibleModal(false) |
|
|
|
|
|
}}> |
|
|
|
|
|
<MyTable |
|
|
|
|
|
ref={tableOwnerRef} |
|
|
|
|
|
rowKey="userID" |
|
|
|
|
|
onSelectRow={(_, row) => { |
|
|
|
|
|
form.setFieldsValue({ |
|
|
|
|
|
ownerUserID: row |
|
|
|
|
|
}) |
|
|
|
|
|
}} |
|
|
|
|
|
apiFun={chat_userList} |
|
|
|
|
|
columns={userColumnData} |
|
|
|
|
|
selectionType="radio" |
|
|
|
|
|
disableKeys={handleDisableKeys('ownerUserID')} |
|
|
|
|
|
selectKeys={form.getFieldValue('ownerUserID') ? form.getFieldValue('ownerUserID').map(v => v.userID) : []} |
|
|
|
|
|
/> |
|
|
|
|
|
</Modal >} |
|
|
|
|
|
|
|
|
|
|
|
{visibleModal1 && < Modal visible={visibleModal1} onCancel={() => setVisibleModal1(false)} title="选择管理员" width={700} onOk={() => { |
|
|
|
|
|
setVisibleModal1(false) |
|
|
|
|
|
}}> |
|
|
|
|
|
<MyTable |
|
|
|
|
|
ref={tableAdminRef} |
|
|
|
|
|
rowKey="userID" |
|
|
|
|
|
onSelectRow={(_, row) => { |
|
|
|
|
|
form.setFieldsValue({ |
|
|
|
|
|
adminUserIDs: row |
|
|
|
|
|
}) |
|
|
|
|
|
}} |
|
|
|
|
|
apiFun={chat_userList} |
|
|
|
|
|
columns={userColumnData} |
|
|
|
|
|
selectionType="checkbox" |
|
|
|
|
|
disableKeys={handleDisableKeys('adminUserIDs')} |
|
|
|
|
|
selectKeys={form.getFieldValue('adminUserIDs') ? form.getFieldValue('adminUserIDs').map(v => v.userID) : []} |
|
|
|
|
|
/> |
|
|
|
|
|
</Modal >} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{visibleModal2 && < Modal visible={visibleModal2} onCancel={() => setVisibleModal2(false)} title="选择群员" width={700} onOk={() => { |
|
|
|
|
|
setVisibleModal2(false) |
|
|
|
|
|
}}> |
|
|
|
|
|
<MyTable |
|
|
|
|
|
ref={tableMemberRef} |
|
|
|
|
|
rowKey="userID" |
|
|
|
|
|
onSelectRow={(_, row) => { |
|
|
|
|
|
form.setFieldsValue({ |
|
|
|
|
|
memberUserIDs: row |
|
|
|
|
|
}) |
|
|
|
|
|
}} |
|
|
|
|
|
apiFun={chat_userList} |
|
|
|
|
|
columns={userColumnData} |
|
|
|
|
|
selectionType="checkbox" |
|
|
|
|
|
disableKeys={handleDisableKeys('memberUserIDs')} |
|
|
|
|
|
selectKeys={form.getFieldValue('memberUserIDs') ? form.getFieldValue('memberUserIDs').map(v => v.userID) : []} |
|
|
|
|
|
/> |
|
|
|
|
|
</Modal >} |
|
|
|
|
|
|
|
|
|
|
|
<Drawer title="新建群组" width={450} visible={visible} onClose={() => { |
|
|
|
|
|
setVisible(false) |
|
|
|
|
|
form.resetFields() |
|
|
|
|
|
}}> |
|
|
|
|
|
<Form form={form} onFinish={onFinish}> |
|
|
|
|
|
<Form.Item name="faceURL"> |
|
|
|
|
|
<div style={{ display: 'flex', justifyContent: 'center' }}> |
|
|
|
|
|
<Upload |
|
|
|
|
|
name="avatar" |
|
|
|
|
|
listType="picture-card" |
|
|
|
|
|
className="avatar-uploader" |
|
|
|
|
|
showUploadList={false} |
|
|
|
|
|
action="https://www.mocky.io/v2/5cc8019d300000980a055e76" |
|
|
|
|
|
> |
|
|
|
|
|
{form.getFieldValue('faceURL') ? <img src={form.getFieldValue('faceURL')} alt="avatar" style={{ width: '100%' }} /> : uploadButton} |
|
|
|
|
|
</Upload> |
|
|
|
|
|
</div> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
<Form.Item label="群组名称" rules={[{ required: true, message: '请输入' }]} name="groupName"> |
|
|
|
|
|
<Input placeholder="请输入" /> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
{groupOperate.current === 'c' && <> |
|
|
|
|
|
<Form.Item label="群主" rules={[{ required: true, message: '请选择' }]} name="ownerUserID"> |
|
|
|
|
|
<div style={{ width: '100%', height: 30, border: '1px solid #434343', cursor: 'pointer', display: 'flex', alignItems: 'center' }} onClick={() => setVisibleModal(true)}> |
|
|
|
|
|
{ |
|
|
|
|
|
form.getFieldValue('ownerUserID') && form.getFieldValue('ownerUserID').length > 0 && ( |
|
|
|
|
|
<div style={{ fontSize: 10, backgroundColor: '#434343', borderRadius: 2, marginLeft: 10, padding: 1 }}>{form.getFieldValue('ownerUserID')[0].nickname}</div> |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
</div> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
<Form.Item label="管理员" name="adminUserIDs"> |
|
|
|
|
|
<div style={{ width: '290px', height: 30, border: '1px solid #434343', cursor: 'pointer', overflow: 'hidden', display: 'flex', alignItems: 'center' }} onClick={() => setVisibleModal1(true)}> |
|
|
|
|
|
{ |
|
|
|
|
|
form.getFieldValue('adminUserIDs') && form.getFieldValue('adminUserIDs').length > 0 && form.getFieldValue('adminUserIDs').map(item => ( |
|
|
|
|
|
<div key={item.userID} style={{ fontSize: 10, backgroundColor: '#434343', borderRadius: 2, marginLeft: 10, padding: 1 }}>{item.nickname}</div> |
|
|
|
|
|
)) |
|
|
|
|
|
} |
|
|
|
|
|
</div> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
<Form.Item label="群成员" rules={[{ required: true, message: '请选择' }]} name="memberUserIDs"> |
|
|
|
|
|
<div style={{ width: '280px', height: 30, border: '1px solid #434343', cursor: 'pointer', overflow: 'hidden', display: 'flex', alignItems: 'center' }} onClick={() => setVisibleModal2(true)}> |
|
|
|
|
|
{ |
|
|
|
|
|
form.getFieldValue('memberUserIDs') && form.getFieldValue('memberUserIDs').length > 0 && form.getFieldValue('memberUserIDs').map(item => ( |
|
|
|
|
|
<div key={item.userID} style={{ fontSize: 10, backgroundColor: '#434343', borderRadius: 2, marginLeft: 10, padding: 1 }}>{item.nickname}</div> |
|
|
|
|
|
)) |
|
|
|
|
|
} |
|
|
|
|
|
</div> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
</>} |
|
|
|
|
|
{ |
|
|
|
|
|
groupOperate.current === 'u' && ( |
|
|
|
|
|
<Form.Item label='群组ID' name="groupID"> |
|
|
|
|
|
<Input disabled /> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
<Form.Item label="群验证" name="needVerification" initialValue={2}> |
|
|
|
|
|
<Select options={[ |
|
|
|
|
|
{ label: '群成员邀请无需验证', value: 0 }, |
|
|
|
|
|
{ label: '需要发送验证消息', value: 1 }, |
|
|
|
|
|
{ label: '允许所有人加群', value: 2 }, |
|
|
|
|
|
]} /> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
<Form.Item label="添加好友" name="applyMemberFriend" initialValue={1}> |
|
|
|
|
|
<Select options={[ |
|
|
|
|
|
{ label: '允许群内添加好友', value: 0 }, |
|
|
|
|
|
{ label: '不允许群内添加好友', value: 1 }, |
|
|
|
|
|
]} /> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
<Form.Item label="查看资料" name="lookMemberInfo" initialValue={1}> |
|
|
|
|
|
<Select options={[ |
|
|
|
|
|
{ label: '允许查看群员资料', value: 0 }, |
|
|
|
|
|
{ label: '不允许查看群员资料', value: 1 }, |
|
|
|
|
|
]} /> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
<Form.Item label="群公告" name="notification"> |
|
|
|
|
|
<TextArea /> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
<Form.Item label="群简介" name="introduction"> |
|
|
|
|
|
<TextArea /> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
<Form.Item > |
|
|
|
|
|
<div style={{ display: 'flex', justifyContent: 'flex-end' }}> |
|
|
|
|
|
<Button type="primary" htmlType="submit">确认</Button> |
|
|
|
|
|
</div> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
</Form> |
|
|
|
|
|
</Drawer> |
|
|
|
|
|
</> |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
|