个人详情界面日期显示优化,完善了编辑信息和修改密码功能
This commit is contained in:
@@ -51,6 +51,15 @@ export const getUserProfile = (id: number) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 更新用户信息
|
||||||
|
export const updateUserProfile = (data: Partial<UserInfo>) => {
|
||||||
|
return http({
|
||||||
|
url: "/user/update",
|
||||||
|
method: "put",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 获取用户地址列表
|
// 获取用户地址列表
|
||||||
export const getAddressList = (userId: number) => {
|
export const getAddressList = (userId: number) => {
|
||||||
return http<UserAddress[]>({
|
return http<UserAddress[]>({
|
||||||
|
|||||||
@@ -8,17 +8,28 @@ import {
|
|||||||
ElTag,
|
ElTag,
|
||||||
ElButton,
|
ElButton,
|
||||||
ElMessage,
|
ElMessage,
|
||||||
|
ElDialog,
|
||||||
|
ElForm,
|
||||||
|
ElFormItem,
|
||||||
|
ElInput,
|
||||||
|
ElSelect,
|
||||||
|
ElOption,
|
||||||
|
ElAvatar,
|
||||||
} from "element-plus";
|
} from "element-plus";
|
||||||
|
import type { FormRules } from "element-plus";
|
||||||
import {
|
import {
|
||||||
Iphone,
|
Iphone,
|
||||||
Message,
|
Message,
|
||||||
Male,
|
Male,
|
||||||
Female,
|
Female,
|
||||||
UserFilled,
|
UserFilled,
|
||||||
|
Edit,
|
||||||
|
Lock,
|
||||||
} from "@element-plus/icons-vue";
|
} from "@element-plus/icons-vue";
|
||||||
import { getUserProfile } from "@/apis/user";
|
import { getUserProfile, updateUserProfile } from "@/apis/user";
|
||||||
import { useUserStore } from "@/stores/UserStore";
|
import { useUserStore } from "@/stores/UserStore";
|
||||||
import type { UserInfo } from "@/types/user";
|
import type { UserInfo } from "@/types/user";
|
||||||
|
import MainLayout from "@/layouts/MainLayout.vue";
|
||||||
|
|
||||||
// 用户信息
|
// 用户信息
|
||||||
const userInfo = ref<UserInfo | null>(null);
|
const userInfo = ref<UserInfo | null>(null);
|
||||||
@@ -26,6 +37,65 @@ const loading = ref(true);
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
// 编辑信息相关
|
||||||
|
const showEditDialog = ref(false);
|
||||||
|
const editForm = ref({
|
||||||
|
nickname: "",
|
||||||
|
phone: "",
|
||||||
|
email: "",
|
||||||
|
gender: 0,
|
||||||
|
avatar: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
// 修改密码相关
|
||||||
|
const showPasswordDialog = ref(false);
|
||||||
|
const passwordForm = ref({
|
||||||
|
oldPassword: "",
|
||||||
|
newPassword: "",
|
||||||
|
confirmPassword: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const editRules: FormRules = {
|
||||||
|
nickname: [
|
||||||
|
{ required: true, message: "请输入昵称", trigger: "blur" },
|
||||||
|
{ min: 2, max: 20, message: "昵称长度在2-20个字符之间", trigger: "blur" },
|
||||||
|
],
|
||||||
|
phone: [
|
||||||
|
{
|
||||||
|
pattern: /^1[3-9]\d{9}$/,
|
||||||
|
message: "请输入正确的手机号",
|
||||||
|
trigger: "blur",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: "blur" }],
|
||||||
|
};
|
||||||
|
|
||||||
|
const passwordRules: FormRules = {
|
||||||
|
oldPassword: [{ required: true, message: "请输入原密码", trigger: "blur" }],
|
||||||
|
newPassword: [
|
||||||
|
{ required: true, message: "请输入新密码", trigger: "blur" },
|
||||||
|
{ min: 6, message: "密码长度至少6位", trigger: "blur" },
|
||||||
|
],
|
||||||
|
confirmPassword: [
|
||||||
|
{ required: true, message: "请再次输入新密码", trigger: "blur" },
|
||||||
|
{
|
||||||
|
validator: (
|
||||||
|
_rule: unknown,
|
||||||
|
value: string,
|
||||||
|
callback: (arg0?: Error) => void,
|
||||||
|
) => {
|
||||||
|
if (value !== passwordForm.value.newPassword) {
|
||||||
|
callback(new Error("两次输入的密码不一致"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: "blur",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
// 性别映射
|
// 性别映射
|
||||||
const genderMap: { [key: number]: string } = {
|
const genderMap: { [key: number]: string } = {
|
||||||
0: "未知",
|
0: "未知",
|
||||||
@@ -42,11 +112,19 @@ const statusMap: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 格式化时间显示
|
// 格式化时间显示
|
||||||
const formatDateTime = (dateTime: string | undefined | null): string => {
|
const formatDateTime = (
|
||||||
|
dateTime: string | undefined | null | Array<number>,
|
||||||
|
): string => {
|
||||||
if (!dateTime) return "-";
|
if (!dateTime) return "-";
|
||||||
|
|
||||||
|
// 如果是数组格式的日期时间 [2025, 12, 17, 15, 13, 19]
|
||||||
|
if (Array.isArray(dateTime)) {
|
||||||
|
const [year, month, day, hour, minute, second] = dateTime;
|
||||||
|
return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")} ${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}:${String(second).padStart(2, "0")}`;
|
||||||
|
}
|
||||||
|
|
||||||
// 如果是完整的日期时间字符串,可以直接返回
|
// 如果是完整的日期时间字符串,可以直接返回
|
||||||
// 如果需要特定格式,可以使用 date-fns 或 dayjs 等库进行格式化
|
return dateTime.toString();
|
||||||
return dateTime;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
@@ -74,12 +152,72 @@ const fetchUserProfile = async () => {
|
|||||||
|
|
||||||
// 编辑个人信息
|
// 编辑个人信息
|
||||||
const handleEditProfile = () => {
|
const handleEditProfile = () => {
|
||||||
ElMessage.info("编辑功能开发中");
|
if (userInfo.value) {
|
||||||
|
editForm.value = {
|
||||||
|
nickname: userInfo.value.nickname || "",
|
||||||
|
phone: userInfo.value.phone || "",
|
||||||
|
email: userInfo.value.email || "",
|
||||||
|
gender: userInfo.value.gender || 0,
|
||||||
|
avatar: userInfo.value.avatar || "",
|
||||||
|
};
|
||||||
|
showEditDialog.value = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存编辑的个人信息
|
||||||
|
const saveEditProfile = async () => {
|
||||||
|
try {
|
||||||
|
// 添加用户ID到编辑表单数据中
|
||||||
|
const updateData = {
|
||||||
|
...editForm.value,
|
||||||
|
id: userStore.userInfo?.id, // 添加用户ID
|
||||||
|
};
|
||||||
|
const response = await updateUserProfile(updateData);
|
||||||
|
if (response.code === 200) {
|
||||||
|
ElMessage.success("更新成功");
|
||||||
|
showEditDialog.value = false;
|
||||||
|
fetchUserProfile(); // 重新获取用户信息
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response.message || "更新失败");
|
||||||
|
}
|
||||||
|
} catch (err: unknown) {
|
||||||
|
console.error(err);
|
||||||
|
ElMessage.error("更新失败");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 修改密码
|
// 修改密码
|
||||||
const handleChangePassword = () => {
|
const handleChangePassword = () => {
|
||||||
ElMessage.info("修改密码功能开发中");
|
passwordForm.value = {
|
||||||
|
oldPassword: "",
|
||||||
|
newPassword: "",
|
||||||
|
confirmPassword: "",
|
||||||
|
};
|
||||||
|
showPasswordDialog.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存新密码
|
||||||
|
const saveNewPassword = async () => {
|
||||||
|
try {
|
||||||
|
// 通过更新用户信息接口来修改密码
|
||||||
|
const response = await updateUserProfile({
|
||||||
|
id: userStore.userInfo?.id, // 确保ID已传递
|
||||||
|
password: passwordForm.value.newPassword,
|
||||||
|
oldPassword: passwordForm.value.oldPassword,
|
||||||
|
});
|
||||||
|
if (response.code === 200) {
|
||||||
|
ElMessage.success("密码修改成功");
|
||||||
|
showPasswordDialog.value = false;
|
||||||
|
// 退出登录并跳转到登录页
|
||||||
|
userStore.clearUserInfo();
|
||||||
|
router.push("/user/login");
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response.message || "密码修改失败");
|
||||||
|
}
|
||||||
|
} catch (err: unknown) {
|
||||||
|
console.error(err);
|
||||||
|
ElMessage.error("密码修改失败");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 退出登录
|
// 退出登录
|
||||||
@@ -109,108 +247,195 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="profile-page">
|
<MainLayout>
|
||||||
<div class="container mx-auto px-4 py-8">
|
<div class="profile-page">
|
||||||
<el-card class="profile-card">
|
<div class="container mx-auto px-4 py-8">
|
||||||
<template #header>
|
<el-card class="profile-card">
|
||||||
<div
|
<template #header>
|
||||||
class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4"
|
<div
|
||||||
>
|
class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4"
|
||||||
<span class="text-xl font-bold">个人中心</span>
|
>
|
||||||
<div class="flex flex-wrap gap-2">
|
<span class="text-xl font-bold">个人中心</span>
|
||||||
<el-button @click="handleEditProfile" size="small">
|
<div class="flex flex-wrap gap-2">
|
||||||
编辑信息
|
<el-button @click="handleEditProfile" size="small">
|
||||||
</el-button>
|
<el-icon :size="14" class="mr-1"><edit /></el-icon>
|
||||||
<el-button
|
编辑信息
|
||||||
type="primary"
|
</el-button>
|
||||||
@click="handleChangePassword"
|
<el-button
|
||||||
size="small"
|
type="primary"
|
||||||
>
|
@click="handleChangePassword"
|
||||||
修改密码
|
size="small"
|
||||||
</el-button>
|
>
|
||||||
<el-button type="danger" @click="handleLogout" size="small">
|
<el-icon :size="14" class="mr-1"><lock /></el-icon>
|
||||||
退出登录
|
修改密码
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button type="danger" @click="handleLogout" size="small">
|
||||||
|
退出登录
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
</template>
|
|
||||||
|
|
||||||
<div v-if="loading" class="text-center py-10">
|
<div v-if="loading" class="text-center py-10">
|
||||||
<i class="el-icon-loading text-2xl"></i>
|
<i class="el-icon-loading text-2xl"></i>
|
||||||
<p class="mt-2">加载中...</p>
|
<p class="mt-2">加载中...</p>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else-if="userInfo" class="profile-content">
|
|
||||||
<div
|
|
||||||
class="flex flex-col md:flex-row items-center mb-8 pb-6 border-b"
|
|
||||||
>
|
|
||||||
<el-avatar :size="80" class="mb-4 md:mb-0 md:mr-6">
|
|
||||||
<img v-if="userInfo.avatar" :src="userInfo.avatar" alt="头像" />
|
|
||||||
<user-filled v-else />
|
|
||||||
</el-avatar>
|
|
||||||
<div class="text-center md:text-left">
|
|
||||||
<h2 class="text-2xl font-bold mb-2">
|
|
||||||
{{ userInfo.nickname || userInfo.username }}
|
|
||||||
</h2>
|
|
||||||
<p class="text-gray-600 mb-2 text-sm">@{{ userInfo.username }}</p>
|
|
||||||
<el-tag :type="getStatusInfo(userInfo.status).type" size="small">
|
|
||||||
{{ getStatusInfo(userInfo.status).label }}
|
|
||||||
</el-tag>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-descriptions title="基本信息" :column="1" border>
|
<div v-else-if="userInfo" class="profile-content">
|
||||||
<el-descriptions-item label="用户ID">
|
<div
|
||||||
{{ userInfo.id }}
|
class="flex flex-col md:flex-row items-center mb-8 pb-6 border-b"
|
||||||
</el-descriptions-item>
|
>
|
||||||
<el-descriptions-item label="用户名">
|
<el-avatar :size="80" class="mb-4 md:mb-0 md:mr-6">
|
||||||
{{ userInfo.username }}
|
<img v-if="userInfo.avatar" :src="userInfo.avatar" alt="头像" />
|
||||||
</el-descriptions-item>
|
<user-filled v-else />
|
||||||
<el-descriptions-item label="昵称">
|
</el-avatar>
|
||||||
{{ userInfo.nickname || "-" }}
|
<div class="text-center md:text-left">
|
||||||
</el-descriptions-item>
|
<h2 class="text-2xl font-bold mb-2">
|
||||||
<el-descriptions-item label="性别">
|
{{ userInfo.nickname || userInfo.username }}
|
||||||
<div class="flex items-center">
|
</h2>
|
||||||
<male
|
<p class="text-gray-600 mb-2 text-sm">
|
||||||
v-if="userInfo.gender === 1"
|
@{{ userInfo.username }}
|
||||||
class="text-blue-500 mr-1"
|
</p>
|
||||||
:size="14"
|
<el-tag
|
||||||
/>
|
:type="getStatusInfo(userInfo.status).type"
|
||||||
<female
|
size="small"
|
||||||
v-else-if="userInfo.gender === 2"
|
>
|
||||||
class="text-pink-500 mr-1"
|
{{ getStatusInfo(userInfo.status).label }}
|
||||||
:size="14"
|
</el-tag>
|
||||||
/>
|
|
||||||
<span>{{ getGenderText(userInfo.gender) }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</el-descriptions-item>
|
</div>
|
||||||
<el-descriptions-item label="手机号">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<iphone class="mr-2 text-gray-500" :size="14" />
|
|
||||||
<span>{{ userInfo.phone || "-" }}</span>
|
|
||||||
</div>
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="邮箱">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<message class="mr-2 text-gray-500" :size="14" />
|
|
||||||
<span>{{ userInfo.email || "-" }}</span>
|
|
||||||
</div>
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="创建时间">
|
|
||||||
{{ formatDateTime(userInfo.createTime) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="更新时间">
|
|
||||||
{{ formatDateTime(userInfo.updateTime) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else class="text-center py-10">
|
<el-descriptions title="基本信息" :column="1" border>
|
||||||
<p>无法加载用户信息</p>
|
<el-descriptions-item label="用户ID">
|
||||||
</div>
|
{{ userInfo.id }}
|
||||||
</el-card>
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="用户名">
|
||||||
|
{{ userInfo.username }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="昵称">
|
||||||
|
{{ userInfo.nickname || "-" }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="性别">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<male
|
||||||
|
v-if="userInfo.gender === 1"
|
||||||
|
class="text-blue-500 mr-1"
|
||||||
|
:size="14"
|
||||||
|
/>
|
||||||
|
<female
|
||||||
|
v-else-if="userInfo.gender === 2"
|
||||||
|
class="text-pink-500 mr-1"
|
||||||
|
:size="14"
|
||||||
|
/>
|
||||||
|
<span>{{ getGenderText(userInfo.gender) }}</span>
|
||||||
|
</div>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="手机号">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<iphone class="mr-2 text-gray-500" :size="14" />
|
||||||
|
<span>{{ userInfo.phone || "-" }}</span>
|
||||||
|
</div>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="邮箱">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<message class="mr-2 text-gray-500" :size="14" />
|
||||||
|
<span>{{ userInfo.email || "-" }}</span>
|
||||||
|
</div>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="创建时间">
|
||||||
|
{{ formatDateTime(userInfo.createTime) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="更新时间">
|
||||||
|
{{ formatDateTime(userInfo.updateTime) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="text-center py-10">
|
||||||
|
<p>无法加载用户信息</p>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<!-- 编辑信息对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="showEditDialog"
|
||||||
|
title="编辑个人信息"
|
||||||
|
width="500px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-form :model="editForm" :rules="editRules" label-width="80px">
|
||||||
|
<el-form-item label="昵称" prop="nickname">
|
||||||
|
<el-input v-model="editForm.nickname" placeholder="请输入昵称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号" prop="phone">
|
||||||
|
<el-input v-model="editForm.phone" placeholder="请输入手机号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="邮箱" prop="email">
|
||||||
|
<el-input v-model="editForm.email" placeholder="请输入邮箱" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="性别" prop="gender">
|
||||||
|
<el-select
|
||||||
|
v-model="editForm.gender"
|
||||||
|
placeholder="请选择性别"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<el-option :value="0" label="未知" />
|
||||||
|
<el-option :value="1" label="男" />
|
||||||
|
<el-option :value="2" label="女" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="头像" prop="avatar">
|
||||||
|
<el-input v-model="editForm.avatar" placeholder="请输入头像URL" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="showEditDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="saveEditProfile">保存</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 修改密码对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="showPasswordDialog"
|
||||||
|
title="修改密码"
|
||||||
|
width="500px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-form :model="passwordForm" :rules="passwordRules" label-width="100px">
|
||||||
|
<el-form-item label="原密码" prop="oldPassword">
|
||||||
|
<el-input
|
||||||
|
v-model="passwordForm.oldPassword"
|
||||||
|
type="password"
|
||||||
|
placeholder="请输入原密码"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="新密码" prop="newPassword">
|
||||||
|
<el-input
|
||||||
|
v-model="passwordForm.newPassword"
|
||||||
|
type="password"
|
||||||
|
placeholder="请输入新密码"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="确认新密码" prop="confirmPassword">
|
||||||
|
<el-input
|
||||||
|
v-model="passwordForm.confirmPassword"
|
||||||
|
type="password"
|
||||||
|
placeholder="请再次输入新密码"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="showPasswordDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="saveNewPassword">保存</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</MainLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -230,6 +455,12 @@ onMounted(() => {
|
|||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.el-descriptions__label) {
|
:deep(.el-descriptions__label) {
|
||||||
width: 100px !important;
|
width: 100px !important;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ export interface UserInfo {
|
|||||||
avatar?: string;
|
avatar?: string;
|
||||||
gender?: number;
|
gender?: number;
|
||||||
status?: number;
|
status?: number;
|
||||||
|
password?: string;
|
||||||
|
oldPassword?: string;
|
||||||
createTime?: string;
|
createTime?: string;
|
||||||
updateTime?: string;
|
updateTime?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user