feat: 添加文件上传进度对话框
- 在 codes、data/import 和 data/maintain 模块中添加上传进度对话框 - 对话框包含上传步骤、提示信息和加载动画 - 优化了上传逻辑,增加了步骤状态更新 - 修改了上传相关提示信息,统一为英文 - 调整了下载模板文件名,使用 "UploadTemplate" 前缀
This commit is contained in:
parent
de4463cc24
commit
b9b64ceb5a
@ -101,6 +101,40 @@
|
|||||||
</el-popconfirm>
|
</el-popconfirm>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
title="Upload Status"
|
||||||
|
width="50%"
|
||||||
|
draggable
|
||||||
|
center
|
||||||
|
:show-close="false"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-steps :active="activeStep" align-center>
|
||||||
|
<el-step
|
||||||
|
title="Step 1"
|
||||||
|
description="Upload File"
|
||||||
|
finish-status="success"
|
||||||
|
/>
|
||||||
|
<el-step
|
||||||
|
title="Step 2"
|
||||||
|
description="Parsing Data"
|
||||||
|
finish-status="success"
|
||||||
|
/>
|
||||||
|
<el-step
|
||||||
|
title="Step 3"
|
||||||
|
description="Parse Complete"
|
||||||
|
finish-status="success"
|
||||||
|
/>
|
||||||
|
</el-steps>
|
||||||
|
<el-divider />
|
||||||
|
<el-alert
|
||||||
|
title="Data is being parsed, please be patient~"
|
||||||
|
type="warning"
|
||||||
|
center
|
||||||
|
show-icon
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 查询结果 -->
|
<!-- 查询结果 -->
|
||||||
<el-card v-if="queryResult" shadow="never" class="mt-2">
|
<el-card v-if="queryResult" shadow="never" class="mt-2">
|
||||||
@ -351,6 +385,8 @@ const {
|
|||||||
queryResult,
|
queryResult,
|
||||||
selectedNum,
|
selectedNum,
|
||||||
showUploadArea,
|
showUploadArea,
|
||||||
|
dialogVisible,
|
||||||
|
activeStep,
|
||||||
fileIds,
|
fileIds,
|
||||||
fileList,
|
fileList,
|
||||||
uploadStatus,
|
uploadStatus,
|
||||||
|
@ -58,6 +58,10 @@ export const useIndex = (tableRef: Ref) => {
|
|||||||
const fileId = ref<string>("");
|
const fileId = ref<string>("");
|
||||||
/**上传按钮状态 */
|
/**上传按钮状态 */
|
||||||
const uploadStatus = ref<boolean>(false);
|
const uploadStatus = ref<boolean>(false);
|
||||||
|
/**上传对话框 */
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
/**当前上传步骤 */
|
||||||
|
const activeStep = ref<number>(1);
|
||||||
/**
|
/**
|
||||||
* 查询结果
|
* 查询结果
|
||||||
*/
|
*/
|
||||||
@ -201,7 +205,7 @@ export const useIndex = (tableRef: Ref) => {
|
|||||||
// 创建 <a> 元素并触发下载
|
// 创建 <a> 元素并触发下载
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.href = url;
|
link.href = url;
|
||||||
link.download = `上传模版.${type}`; // 设置下载文件名,确保后缀名正确
|
link.download = `UploadTemplate.${type}`; // 设置下载文件名,确保后缀名正确
|
||||||
document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中
|
document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中
|
||||||
link.click(); // 模拟点击下载
|
link.click(); // 模拟点击下载
|
||||||
|
|
||||||
@ -227,7 +231,7 @@ export const useIndex = (tableRef: Ref) => {
|
|||||||
// const maxSize = 20 * 1024 * 1024; // 20MB 限制
|
// const maxSize = 20 * 1024 * 1024; // 20MB 限制
|
||||||
|
|
||||||
if (!isExcel) {
|
if (!isExcel) {
|
||||||
message("只能上传 xlsx 或 xls 文件!", { type: "error" });
|
message("Only xlsx or xls files can be uploaded!", { type: "error" });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -242,8 +246,14 @@ export const useIndex = (tableRef: Ref) => {
|
|||||||
|
|
||||||
/**处理文件上传 */
|
/**处理文件上传 */
|
||||||
const handleUpload = async () => {
|
const handleUpload = async () => {
|
||||||
|
activeStep.value = 1;
|
||||||
|
dialogVisible.value = true;
|
||||||
if (fileList.value.length === 0) {
|
if (fileList.value.length === 0) {
|
||||||
message("请先上传文件!", { type: "error", duration: 5000 });
|
message("Please select the file first!", {
|
||||||
|
type: "error",
|
||||||
|
duration: 5000
|
||||||
|
});
|
||||||
|
dialogVisible.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uploadStatus.value = true;
|
uploadStatus.value = true;
|
||||||
@ -252,7 +262,7 @@ export const useIndex = (tableRef: Ref) => {
|
|||||||
if (file.status === "success") {
|
if (file.status === "success") {
|
||||||
const data = await getQueryCodeAPI(fileId.value);
|
const data = await getQueryCodeAPI(fileId.value);
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
message("查询成功!", { type: "success" });
|
message(data.msg, { type: "success" });
|
||||||
queryResult.value = data.data;
|
queryResult.value = data.data;
|
||||||
dataList.value = data.data.response_result;
|
dataList.value = data.data.response_result;
|
||||||
pagination.total = data.data.result_count;
|
pagination.total = data.data.result_count;
|
||||||
@ -266,7 +276,10 @@ export const useIndex = (tableRef: Ref) => {
|
|||||||
if (res.success) {
|
if (res.success) {
|
||||||
file.status = "success";
|
file.status = "success";
|
||||||
fileId.value = res.data.id;
|
fileId.value = res.data.id;
|
||||||
message(`${res.data.name}上传成功!`, { type: "success" });
|
message(`${res.data.name} Uploaded successfully!`, {
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
|
activeStep.value = 2;
|
||||||
fileIds.value.push(res.data);
|
fileIds.value.push(res.data);
|
||||||
const data = await getQueryCodeAPI(fileId.value);
|
const data = await getQueryCodeAPI(fileId.value);
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
@ -295,6 +308,9 @@ export const useIndex = (tableRef: Ref) => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
activeStep.value = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uploadStatus.value = false;
|
uploadStatus.value = false;
|
||||||
@ -536,6 +552,8 @@ export const useIndex = (tableRef: Ref) => {
|
|||||||
queryResult,
|
queryResult,
|
||||||
selectedNum,
|
selectedNum,
|
||||||
showUploadArea,
|
showUploadArea,
|
||||||
|
dialogVisible,
|
||||||
|
activeStep,
|
||||||
fileIds,
|
fileIds,
|
||||||
fileList,
|
fileList,
|
||||||
uploadStatus,
|
uploadStatus,
|
||||||
|
@ -192,6 +192,40 @@
|
|||||||
</el-popconfirm>
|
</el-popconfirm>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
title="Upload Status"
|
||||||
|
width="50%"
|
||||||
|
draggable
|
||||||
|
center
|
||||||
|
:show-close="false"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-steps :active="activeStep" align-center>
|
||||||
|
<el-step
|
||||||
|
title="Step 1"
|
||||||
|
description="Upload File"
|
||||||
|
finish-status="success"
|
||||||
|
/>
|
||||||
|
<el-step
|
||||||
|
title="Step 2"
|
||||||
|
description="Parsing Data"
|
||||||
|
finish-status="success"
|
||||||
|
/>
|
||||||
|
<el-step
|
||||||
|
title="Step 3"
|
||||||
|
description="Parse Complete"
|
||||||
|
finish-status="success"
|
||||||
|
/>
|
||||||
|
</el-steps>
|
||||||
|
<el-divider />
|
||||||
|
<el-alert
|
||||||
|
title="Data is being parsed, please be patient~"
|
||||||
|
type="warning"
|
||||||
|
center
|
||||||
|
show-icon
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
</el-card>
|
</el-card>
|
||||||
<div
|
<div
|
||||||
v-if="selectedNum > 0"
|
v-if="selectedNum > 0"
|
||||||
@ -385,6 +419,8 @@ const {
|
|||||||
selectedNum,
|
selectedNum,
|
||||||
showUploadArea,
|
showUploadArea,
|
||||||
departments,
|
departments,
|
||||||
|
dialogVisible,
|
||||||
|
activeStep,
|
||||||
fileList,
|
fileList,
|
||||||
uploadStatus,
|
uploadStatus,
|
||||||
beforeUpload,
|
beforeUpload,
|
||||||
|
@ -69,6 +69,10 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
const fileIds = ref([]);
|
const fileIds = ref([]);
|
||||||
/**上传按钮状态 */
|
/**上传按钮状态 */
|
||||||
const uploadStatus = ref<boolean>(false);
|
const uploadStatus = ref<boolean>(false);
|
||||||
|
/**上传对话框 */
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
/**当前上传步骤 */
|
||||||
|
const activeStep = ref<number>(1);
|
||||||
|
|
||||||
const getStatusTag = (status: number) => {
|
const getStatusTag = (status: number) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -366,7 +370,7 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
// 创建 <a> 元素并触发下载
|
// 创建 <a> 元素并触发下载
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.href = url;
|
link.href = url;
|
||||||
link.download = `上传模版.${type}`; // 设置下载文件名,确保后缀名正确
|
link.download = `UploadTemplate.${type}`; // 设置下载文件名,确保后缀名正确
|
||||||
document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中
|
document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中
|
||||||
link.click(); // 模拟点击下载
|
link.click(); // 模拟点击下载
|
||||||
|
|
||||||
@ -391,7 +395,7 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
// const maxSize = 20 * 1024 * 1024; // 20MB 限制
|
// const maxSize = 20 * 1024 * 1024; // 20MB 限制
|
||||||
|
|
||||||
if (!isExcel) {
|
if (!isExcel) {
|
||||||
message("只能上传 xlsx 或 xls 文件!", { type: "error" });
|
message("Only xlsx or xls files can be uploaded!", { type: "error" });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -406,8 +410,14 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
|
|
||||||
/** 处理文件上传 */
|
/** 处理文件上传 */
|
||||||
const handleUpload = async () => {
|
const handleUpload = async () => {
|
||||||
|
activeStep.value = 1;
|
||||||
|
dialogVisible.value = true;
|
||||||
if (fileList.value.length === 0) {
|
if (fileList.value.length === 0) {
|
||||||
message("请先选择文件!", { type: "error", duration: 5000 });
|
message("Please select the file first!", {
|
||||||
|
type: "error",
|
||||||
|
duration: 5000
|
||||||
|
});
|
||||||
|
dialogVisible.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,14 +432,18 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
if (res.success) {
|
if (res.success) {
|
||||||
file.status = "success";
|
file.status = "success";
|
||||||
fileIds.value.push(res.data); // 记录成功上传的文件ID
|
fileIds.value.push(res.data); // 记录成功上传的文件ID
|
||||||
message(`${res.data.name} 上传成功!`, { type: "success" });
|
message(`${res.data.name} Uploaded successfully!`, {
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
file.status = "fail";
|
file.status = "fail";
|
||||||
message(`${file.name} 上传失败!`, { type: "error" });
|
message(`${file.name} Upload failed!`, { type: "error" });
|
||||||
|
dialogVisible.value = false;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
file.status = "fail";
|
file.status = "fail";
|
||||||
|
dialogVisible.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,12 +456,16 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
getKeyList(fileIds.value, "id")
|
getKeyList(fileIds.value, "id")
|
||||||
);
|
);
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
|
activeStep.value = 3;
|
||||||
message("批量导入成功!", { type: "success" });
|
message("批量导入成功!", { type: "success" });
|
||||||
await onSearch();
|
await onSearch();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
message("批量导入失败!", { type: "error" });
|
message("批量导入失败!", { type: "error" });
|
||||||
|
} finally {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
activeStep.value = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -657,6 +675,8 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
selectedNum,
|
selectedNum,
|
||||||
showUploadArea,
|
showUploadArea,
|
||||||
departments,
|
departments,
|
||||||
|
dialogVisible,
|
||||||
|
activeStep,
|
||||||
fileIds,
|
fileIds,
|
||||||
fileList,
|
fileList,
|
||||||
uploadStatus,
|
uploadStatus,
|
||||||
|
@ -184,6 +184,40 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
title="Upload Status"
|
||||||
|
width="50%"
|
||||||
|
draggable
|
||||||
|
center
|
||||||
|
:show-close="false"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-steps :active="activeStep" align-center>
|
||||||
|
<el-step
|
||||||
|
title="Step 1"
|
||||||
|
description="Upload File"
|
||||||
|
finish-status="success"
|
||||||
|
/>
|
||||||
|
<el-step
|
||||||
|
title="Step 2"
|
||||||
|
description="Parsing Data"
|
||||||
|
finish-status="success"
|
||||||
|
/>
|
||||||
|
<el-step
|
||||||
|
title="Step 3"
|
||||||
|
description="Parse Complete"
|
||||||
|
finish-status="success"
|
||||||
|
/>
|
||||||
|
</el-steps>
|
||||||
|
<el-divider />
|
||||||
|
<el-alert
|
||||||
|
title="Data is being parsed, please be patient~"
|
||||||
|
type="warning"
|
||||||
|
center
|
||||||
|
show-icon
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
<div
|
<div
|
||||||
v-if="selectedNum > 0"
|
v-if="selectedNum > 0"
|
||||||
v-motion-fade
|
v-motion-fade
|
||||||
@ -299,6 +333,7 @@ const { t } = useI18n();
|
|||||||
*/
|
*/
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
form,
|
form,
|
||||||
dataList,
|
dataList,
|
||||||
@ -310,6 +345,8 @@ const {
|
|||||||
showUploadArea,
|
showUploadArea,
|
||||||
fileList,
|
fileList,
|
||||||
uploadStatus,
|
uploadStatus,
|
||||||
|
dialogVisible,
|
||||||
|
activeStep,
|
||||||
beforeUpload,
|
beforeUpload,
|
||||||
handleUpload,
|
handleUpload,
|
||||||
beforeRemove,
|
beforeRemove,
|
||||||
|
@ -66,6 +66,10 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
const fileIds = ref([]);
|
const fileIds = ref([]);
|
||||||
/**上传按钮状态 */
|
/**上传按钮状态 */
|
||||||
const uploadStatus = ref<boolean>(false);
|
const uploadStatus = ref<boolean>(false);
|
||||||
|
/**上传对话框 */
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
/**当前上传步骤 */
|
||||||
|
const activeStep = ref<number>(1);
|
||||||
/**
|
/**
|
||||||
* 表格列设置
|
* 表格列设置
|
||||||
*/
|
*/
|
||||||
@ -305,7 +309,7 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
// 创建 <a> 元素并触发下载
|
// 创建 <a> 元素并触发下载
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.href = url;
|
link.href = url;
|
||||||
link.download = "上传模版.xlsx"; // 设置下载文件名,确保后缀名正确
|
link.download = "UploadTemplate.xlsx"; // 设置下载文件名,确保后缀名正确
|
||||||
document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中
|
document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中
|
||||||
link.click(); // 模拟点击下载
|
link.click(); // 模拟点击下载
|
||||||
|
|
||||||
@ -330,7 +334,7 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
// const maxSize = 20 * 1024 * 1024; // 20MB 限制
|
// const maxSize = 20 * 1024 * 1024; // 20MB 限制
|
||||||
|
|
||||||
if (!isExcel) {
|
if (!isExcel) {
|
||||||
message("只能上传 xlsx 或 xls 文件!", { type: "error" });
|
message("Only xlsx or xls files can be uploaded!", { type: "error" });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -345,30 +349,43 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
|
|
||||||
/** 处理文件上传 */
|
/** 处理文件上传 */
|
||||||
const handleUpload = async () => {
|
const handleUpload = async () => {
|
||||||
|
activeStep.value = 1;
|
||||||
|
dialogVisible.value = true;
|
||||||
if (fileList.value.length === 0) {
|
if (fileList.value.length === 0) {
|
||||||
message("请先选择文件!", { type: "error", duration: 5000 });
|
message("Please select the file first!", {
|
||||||
|
type: "error",
|
||||||
|
duration: 5000
|
||||||
|
});
|
||||||
|
dialogVisible.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadStatus.value = true;
|
uploadStatus.value = true;
|
||||||
|
|
||||||
for (const file of fileList.value) {
|
for (const file of fileList.value) {
|
||||||
if (file.status === "success") continue; // 已上传成功的跳过
|
if (file.status === "success") {
|
||||||
|
activeStep.value = 2;
|
||||||
|
continue;
|
||||||
|
} // 已上传成功的跳过
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await postUploadFileAPI({ file: file.raw });
|
const res = await postUploadFileAPI({ file: file.raw });
|
||||||
|
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
file.status = "success";
|
file.status = "success";
|
||||||
fileIds.value.push(res.data); // 记录成功上传的文件ID
|
fileIds.value.push(res.data); // 记录成功上传的文件ID
|
||||||
message(`${res.data.name} 上传成功!`, { type: "success" });
|
activeStep.value = 2;
|
||||||
|
message(`${res.data.name} Uploaded successfully!`, {
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
file.status = "fail";
|
file.status = "fail";
|
||||||
message(`${file.name} 上传失败!`, { type: "error" });
|
message(`${file.name} Upload failed!`, { type: "error" });
|
||||||
|
dialogVisible.value = false;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
file.status = "fail";
|
file.status = "fail";
|
||||||
|
dialogVisible.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,12 +398,16 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
getKeyList(fileIds.value, "id")
|
getKeyList(fileIds.value, "id")
|
||||||
);
|
);
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
|
activeStep.value = 3;
|
||||||
message("批量导入成功!", { type: "success" });
|
message("批量导入成功!", { type: "success" });
|
||||||
await onSearch();
|
await onSearch();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
message("批量导入失败!", { type: "error" });
|
message("批量导入失败!", { type: "error" });
|
||||||
|
} finally {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
activeStep.value = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -457,6 +478,8 @@ export const useCode = (tableRef: Ref) => {
|
|||||||
selectedNum,
|
selectedNum,
|
||||||
departments,
|
departments,
|
||||||
showUploadArea,
|
showUploadArea,
|
||||||
|
dialogVisible,
|
||||||
|
activeStep,
|
||||||
fileIds,
|
fileIds,
|
||||||
fileList,
|
fileList,
|
||||||
uploadStatus,
|
uploadStatus,
|
||||||
|
@ -27,7 +27,7 @@ export default ({ mode }: ConfigEnv): UserConfigExport => {
|
|||||||
proxy: {
|
proxy: {
|
||||||
"/api": {
|
"/api": {
|
||||||
// 这里填写后端地址
|
// 这里填写后端地址
|
||||||
target: "http://localhost:8082",
|
target: "http://127.0.0.1:8082",
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: path => path.replace(/^\/api/, "")
|
rewrite: path => path.replace(/^\/api/, "")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user