Merge remote-tracking branch 'origin/master'
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 50 KiB |
@@ -24,19 +24,16 @@
|
|||||||
|
|
||||||
<!-- 头部导航 -->
|
<!-- 头部导航 -->
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<router-link
|
<div
|
||||||
v-for="(item, index) in headerItems"
|
v-for="(item, index) in headerItems"
|
||||||
:key="index"
|
:key="index"
|
||||||
:to="item.path"
|
|
||||||
class="header-item"
|
class="header-item"
|
||||||
custom
|
|
||||||
v-slot="{ navigate }"
|
|
||||||
>
|
>
|
||||||
<div @click="navigate" class="header-item-content">
|
<div @click="item.text === '系统公告' ? handleSystemAnnouncementClick() : $router.push(item.path)" class="header-item-content">
|
||||||
<img :src="item.image" :alt="item.text" class="header-image" />
|
<img :src="item.image" :alt="item.text" class="header-image" />
|
||||||
<div class="header-text">{{ item.text }}</div>
|
<div class="header-text">{{ item.text }}</div>
|
||||||
</div>
|
</div>
|
||||||
</router-link>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 修改后的操作区域 - 三个图片并排 -->
|
<!-- 修改后的操作区域 - 三个图片并排 -->
|
||||||
@@ -75,7 +72,7 @@
|
|||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="showWelcomeDialog"
|
v-model="showWelcomeDialog"
|
||||||
width="90%"
|
width="90%"
|
||||||
:style="{ height: '425px' }"
|
:style="{ height: isSystemAnnouncementClick ? '525px' : '425px' }"
|
||||||
:show-close="true"
|
:show-close="true"
|
||||||
:close-on-click-modal="true"
|
:close-on-click-modal="true"
|
||||||
:close-on-press-escape="true"
|
:close-on-press-escape="true"
|
||||||
@@ -87,10 +84,10 @@
|
|||||||
<div class="welcome-icon">🎉</div>
|
<div class="welcome-icon">🎉</div>
|
||||||
<h3>融汇通更新</h3>
|
<h3>融汇通更新</h3>
|
||||||
<div class="welcome-features">
|
<div class="welcome-features">
|
||||||
<div class="announcements-container" v-if="unreadAnnouncements.length > 0">
|
<div class="announcements-container" v-if="displayAnnouncements.length > 0">
|
||||||
<div
|
<div
|
||||||
class="announcement-item"
|
class="announcement-item"
|
||||||
v-for="announcement in unreadAnnouncements"
|
v-for="announcement in displayAnnouncements"
|
||||||
:key="announcement.id"
|
:key="announcement.id"
|
||||||
>
|
>
|
||||||
<div class="announcement-header">
|
<div class="announcement-header">
|
||||||
@@ -105,7 +102,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="no-announcements">
|
<div v-else class="no-announcements">
|
||||||
<span>暂无未读更新信息</span>
|
<span>{{ isSystemAnnouncementClick ? '暂无公告信息' : '暂无未读更新信息' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -203,6 +200,20 @@ export default {
|
|||||||
return announcements.value.filter(announcement => !announcement.is_read);
|
return announcements.value.filter(announcement => !announcement.is_read);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 标记是否通过系统公告按钮打开对话框
|
||||||
|
const isSystemAnnouncementClick = ref(false);
|
||||||
|
|
||||||
|
// 计算要显示的公告列表
|
||||||
|
const displayAnnouncements = computed(() => {
|
||||||
|
if (isSystemAnnouncementClick.value) {
|
||||||
|
// 如果是通过系统公告按钮打开,显示所有公告并按创建时间倒序排列(最新的在前)
|
||||||
|
return [...announcements.value].sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
|
||||||
|
} else {
|
||||||
|
// 否则只显示未读公告
|
||||||
|
return unreadAnnouncements.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 计算是否应该显示弹窗
|
// 计算是否应该显示弹窗
|
||||||
const shouldShowDialog = computed(() => {
|
const shouldShowDialog = computed(() => {
|
||||||
return unreadAnnouncements.value.length > 0;
|
return unreadAnnouncements.value.length > 0;
|
||||||
@@ -290,8 +301,12 @@ export default {
|
|||||||
|
|
||||||
// 关闭欢迎弹窗并标记所有未读公告为已读
|
// 关闭欢迎弹窗并标记所有未读公告为已读
|
||||||
const closeWelcomeDialog = async () => {
|
const closeWelcomeDialog = async () => {
|
||||||
|
// 只有在非系统公告点击时才标记为已读
|
||||||
|
if (!isSystemAnnouncementClick.value) {
|
||||||
await markAllAnnouncementsAsRead();
|
await markAllAnnouncementsAsRead();
|
||||||
|
}
|
||||||
showWelcomeDialog.value = false;
|
showWelcomeDialog.value = false;
|
||||||
|
isSystemAnnouncementClick.value = false; // 重置标志
|
||||||
};
|
};
|
||||||
|
|
||||||
// 点击已读按钮
|
// 点击已读按钮
|
||||||
@@ -299,6 +314,13 @@ export default {
|
|||||||
showWelcomeDialog.value = false;
|
showWelcomeDialog.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理系统公告点击事件
|
||||||
|
const handleSystemAnnouncementClick = () => {
|
||||||
|
console.log('触发')
|
||||||
|
isSystemAnnouncementClick.value = true;
|
||||||
|
showWelcomeDialog.value = true; // 无条件显示对话框
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
modules: [Autoplay, Pagination],
|
modules: [Autoplay, Pagination],
|
||||||
userPoints,
|
userPoints,
|
||||||
@@ -315,6 +337,9 @@ export default {
|
|||||||
getUserPoints, // 如果需要外部调用可以暴露
|
getUserPoints, // 如果需要外部调用可以暴露
|
||||||
closeWelcomeDialog,
|
closeWelcomeDialog,
|
||||||
handleReadClick,
|
handleReadClick,
|
||||||
|
handleSystemAnnouncementClick,
|
||||||
|
displayAnnouncements,
|
||||||
|
isSystemAnnouncementClick,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,10 +7,6 @@
|
|||||||
<p>欢迎来到炬融圈</p>
|
<p>欢迎来到炬融圈</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="image">
|
|
||||||
<img src="/imgs/login.png" alt="炬融圈">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-form
|
<el-form
|
||||||
ref="loginFormRef"
|
ref="loginFormRef"
|
||||||
:model="loginForm"
|
:model="loginForm"
|
||||||
@@ -346,33 +342,6 @@ const handleRememberMe = () => {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 图片容器样式 */
|
|
||||||
.image {
|
|
||||||
width: 375px; /* 固定宽度 */
|
|
||||||
height: 287px; /* 固定高度 */
|
|
||||||
margin: 0 auto 20px; /* 水平居中,底部留出间距 */
|
|
||||||
overflow: hidden; /* 隐藏超出容器的部分 */
|
|
||||||
border-radius: 8px; /* 可选:添加圆角增强视觉效果 */
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); /* 可选:添加轻微阴影 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 图片填充样式 */
|
|
||||||
.image img {
|
|
||||||
width: 100%; /* 宽度充满容器 */
|
|
||||||
height: 100%; /* 高度充满容器 */
|
|
||||||
object-fit: contain;
|
|
||||||
display: block; /* 去除图片底部默认空白 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 响应式适配(小屏设备自动缩放) */
|
|
||||||
@media (max-width: 375px) {
|
|
||||||
.image {
|
|
||||||
width: 100%; /* 在小于375px的屏幕上宽度自适应 */
|
|
||||||
height: auto; /* 高度按比例自动计算 */
|
|
||||||
aspect-ratio: 375 / 287; /* 保持原比例 */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-form {
|
.login-form {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,28 +114,16 @@
|
|||||||
<el-form-item prop="agreement">
|
<el-form-item prop="agreement">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-model="registerForm.agreement"
|
v-model="registerForm.agreement"
|
||||||
@change="handleAgreementChange"
|
@click.prevent="showAgreementDialog"
|
||||||
|
:disabled="true"
|
||||||
>
|
>
|
||||||
我已阅读并同意
|
<span @click="showAgreementDialog" class="agreement-text">
|
||||||
<el-link
|
我已阅读并同意《用户协议》和《隐私政策》
|
||||||
type="primary"
|
</span>
|
||||||
@click="showAgreement"
|
|
||||||
:class="{ viewed: agreementViewed }"
|
|
||||||
>
|
|
||||||
《用户协议》
|
|
||||||
</el-link>
|
|
||||||
和
|
|
||||||
<el-link
|
|
||||||
type="primary"
|
|
||||||
@click="showPrivacy"
|
|
||||||
:class="{ viewed: privacyViewed }"
|
|
||||||
>
|
|
||||||
《隐私政策》
|
|
||||||
</el-link>
|
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
<div v-if="!canCheckAgreement" class="agreement-hint">
|
<div class="agreement-hint">
|
||||||
<el-icon><InfoFilled /></el-icon>
|
<el-icon><InfoFilled /></el-icon>
|
||||||
<span>请先点击查看用户协议和隐私政策</span>
|
<span>请点击查看用户协议和隐私政策</span>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@@ -170,6 +158,64 @@
|
|||||||
<div class="decoration-shape shape-3"></div>
|
<div class="decoration-shape shape-3"></div>
|
||||||
<div class="decoration-shape shape-4"></div>
|
<div class="decoration-shape shape-4"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 协议弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="showAgreementDialogVisible"
|
||||||
|
title="用户协议和隐私政策"
|
||||||
|
width="90%"
|
||||||
|
:style="{ maxWidth: '600px' }"
|
||||||
|
:show-close="true"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
center
|
||||||
|
class="agreement-dialog"
|
||||||
|
position="bottom"
|
||||||
|
>
|
||||||
|
<div class="agreement-content">
|
||||||
|
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
|
||||||
|
<el-tab-pane name="agreement">
|
||||||
|
<template #label>
|
||||||
|
<span class="tab-label">用户协议</span>
|
||||||
|
<el-icon v-if="agreementViewed" class="check-icon"><Check /></el-icon>
|
||||||
|
</template>
|
||||||
|
<div class="agreement-text-content" ref="agreementContent">
|
||||||
|
<h3>用户协议</h3>
|
||||||
|
<p>1. 用户应当遵守法律法规,不得发布违法违规内容。</p>
|
||||||
|
<p>2. 用户对自己发布的内容承担全部责任。</p>
|
||||||
|
<p>3. 平台有权对违规内容进行删除或限制。</p>
|
||||||
|
<p>4. 用户应当保护好自己的账号安全。</p>
|
||||||
|
<p>5. 平台保留修改本协议的权利。</p>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="privacy">
|
||||||
|
<template #label>
|
||||||
|
<span class="tab-label">隐私政策</span>
|
||||||
|
<el-icon v-if="privacyViewed" class="check-icon"><Check /></el-icon>
|
||||||
|
</template>
|
||||||
|
<div class="privacy-text-content" ref="privacyContent">
|
||||||
|
<h3>隐私政策</h3>
|
||||||
|
<p>1. 我们重视用户隐私保护。</p>
|
||||||
|
<p>2. 我们只收集必要的用户信息。</p>
|
||||||
|
<p>3. 用户信息仅用于提供服务。</p>
|
||||||
|
<p>4. 我们不会向第三方泄露用户信息。</p>
|
||||||
|
<p>5. 用户有权查看、修改或删除个人信息。</p>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<div class="read-status">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="dialog-buttons">
|
||||||
|
<el-button @click="closeAgreementDialog">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmAgreement" :disabled="!(agreementViewed && privacyViewed)">确认已阅读</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -187,6 +233,7 @@ import {
|
|||||||
CreditCard,
|
CreditCard,
|
||||||
Location,
|
Location,
|
||||||
InfoFilled,
|
InfoFilled,
|
||||||
|
Check,
|
||||||
} from '@element-plus/icons-vue';
|
} from '@element-plus/icons-vue';
|
||||||
import Captcha from '@/components/Captcha.vue';
|
import Captcha from '@/components/Captcha.vue';
|
||||||
import api from '@/utils/api'
|
import api from '@/utils/api'
|
||||||
@@ -218,9 +265,12 @@ const registerForm = reactive({
|
|||||||
// 协议查看状态
|
// 协议查看状态
|
||||||
const agreementViewed = ref(false);
|
const agreementViewed = ref(false);
|
||||||
const privacyViewed = ref(false);
|
const privacyViewed = ref(false);
|
||||||
const canCheckAgreement = computed(
|
|
||||||
() => agreementViewed.value && privacyViewed.value
|
// 协议弹窗相关状态
|
||||||
);
|
const showAgreementDialogVisible = ref(false);
|
||||||
|
const activeTab = ref('agreement');
|
||||||
|
const agreementContent = ref();
|
||||||
|
const privacyContent = ref();
|
||||||
|
|
||||||
// 短信验证码相关状态
|
// 短信验证码相关状态
|
||||||
const sendingSMS = ref(false);
|
const sendingSMS = ref(false);
|
||||||
@@ -477,61 +527,44 @@ const handleRegister = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 显示用户协议
|
// 显示协议弹窗
|
||||||
const showAgreement = () => {
|
const showAgreementDialog = () => {
|
||||||
ElMessageBox.alert(
|
showAgreementDialogVisible.value = true;
|
||||||
`<div style="text-align: left; line-height: 1.6;">
|
activeTab.value = 'agreement';
|
||||||
<h3>用户协议</h3>
|
// 弹窗打开时默认用户协议已读
|
||||||
<p>1. 用户应当遵守法律法规,不得发布违法违规内容。</p>
|
|
||||||
<p>2. 用户对自己发布的内容承担全部责任。</p>
|
|
||||||
<p>3. 平台有权对违规内容进行删除或限制。</p>
|
|
||||||
<p>4. 用户应当保护好自己的账号安全。</p>
|
|
||||||
<p>5. 平台保留修改本协议的权利。</p>
|
|
||||||
</div>`,
|
|
||||||
'用户协议',
|
|
||||||
{
|
|
||||||
confirmButtonText: '我已了解',
|
|
||||||
dangerouslyUseHTMLString: true,
|
|
||||||
customClass: 'agreement-dialog',
|
|
||||||
}
|
|
||||||
).then(() => {
|
|
||||||
agreementViewed.value = true;
|
agreementViewed.value = true;
|
||||||
ElMessage.success('已查看用户协议');
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 显示隐私政策
|
// 关闭协议弹窗
|
||||||
const showPrivacy = () => {
|
const closeAgreementDialog = () => {
|
||||||
ElMessageBox.alert(
|
showAgreementDialogVisible.value = false;
|
||||||
`<div style="text-align: left; line-height: 1.6;">
|
};
|
||||||
<h3>隐私政策</h3>
|
|
||||||
<p>1. 我们重视用户隐私保护。</p>
|
// 确认已阅读协议
|
||||||
<p>2. 我们只收集必要的用户信息。</p>
|
const confirmAgreement = () => {
|
||||||
<p>3. 用户信息仅用于提供服务。</p>
|
if (agreementViewed.value && privacyViewed.value) {
|
||||||
<p>4. 我们不会向第三方泄露用户信息。</p>
|
registerForm.agreement = true;
|
||||||
<p>5. 用户有权查看、修改或删除个人信息。</p>
|
showAgreementDialogVisible.value = false;
|
||||||
</div>`,
|
ElMessage.success('已确认阅读用户协议和隐私政策');
|
||||||
'隐私政策',
|
} else {
|
||||||
{
|
ElMessage.warning('请先查看用户协议和隐私政策');
|
||||||
confirmButtonText: '我已了解',
|
|
||||||
dangerouslyUseHTMLString: true,
|
|
||||||
customClass: 'privacy-dialog',
|
|
||||||
}
|
}
|
||||||
).then(() => {
|
};
|
||||||
|
|
||||||
|
// 处理选项卡切换
|
||||||
|
const handleTabChange = (tabName) => {
|
||||||
|
if (tabName === 'agreement') {
|
||||||
|
// 切换到用户协议时,标记为已读
|
||||||
|
agreementViewed.value = true;
|
||||||
|
} else if (tabName === 'privacy') {
|
||||||
|
// 切换到隐私政策时,标记为已读
|
||||||
privacyViewed.value = true;
|
privacyViewed.value = true;
|
||||||
ElMessage.success('已查看隐私政策');
|
}
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理协议勾选
|
|
||||||
const handleAgreementChange = (value) => {
|
|
||||||
if (value && !canCheckAgreement.value) {
|
|
||||||
registerForm.agreement = false;
|
|
||||||
ElMessage.warning('请先查看用户协议和隐私政策后再勾选');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 图片上传成功处理
|
// 图片上传成功处理
|
||||||
const handleUploadSuccess = (response, field) => {
|
const handleUploadSuccess = (response, field) => {
|
||||||
@@ -888,9 +921,111 @@ onMounted(() => {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-link.viewed) {
|
.agreement-text {
|
||||||
color: #67c23a !important;
|
color: #409eff;
|
||||||
font-weight: 500;
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-text:hover {
|
||||||
|
color: #66b1ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 协议弹窗样式 */
|
||||||
|
:deep(.agreement-dialog) {
|
||||||
|
.el-dialog__body {
|
||||||
|
padding: 20px;
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-content {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.agreement-dialog .el-tabs__nav) {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.agreement-dialog .el-tabs__item) {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-label {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-text-content,
|
||||||
|
.privacy-text-content {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 20px;
|
||||||
|
line-height: 1.6;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-text-content h3,
|
||||||
|
.privacy-text-content h3 {
|
||||||
|
color: #303133;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-text-content p,
|
||||||
|
.privacy-text-content p {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-text-content strong,
|
||||||
|
.privacy-text-content strong {
|
||||||
|
color: #409eff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-icon {
|
||||||
|
color: #67c23a;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条样式 */
|
||||||
|
.agreement-text-content::-webkit-scrollbar,
|
||||||
|
.privacy-text-content::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-text-content::-webkit-scrollbar-track,
|
||||||
|
.privacy-text-content::-webkit-scrollbar-track {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-text-content::-webkit-scrollbar-thumb,
|
||||||
|
.privacy-text-content::-webkit-scrollbar-thumb {
|
||||||
|
background: #c1c1c1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-text-content::-webkit-scrollbar-thumb:hover,
|
||||||
|
.privacy-text-content::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #a8a8a8;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-link.viewed:hover) {
|
:deep(.el-link.viewed:hover) {
|
||||||
|
|||||||
Reference in New Issue
Block a user