mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/learning-system-portal.git
synced 2025-12-09 02:46:44 +08:00
fix:社招新员工项目学习页细节样式调整
This commit is contained in:
112
src/components/CustomInfoMessage.vue
Normal file
112
src/components/CustomInfoMessage.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<transition name="fade">
|
||||
<div v-if="visible" class="custom-info-message" @click="handleClose">
|
||||
<div class="message-content">
|
||||
<div class="icon-wrapper">
|
||||
<span class="icon-text">i</span>
|
||||
</div>
|
||||
<div class="message-text">{{ message }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "CustomInfoMessage",
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
message: "",
|
||||
timer: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
show(msg, duration = 3000) {
|
||||
this.message = msg;
|
||||
this.visible = true;
|
||||
|
||||
if (this.timer) {
|
||||
clearTimeout(this.timer);
|
||||
}
|
||||
|
||||
this.timer = setTimeout(() => {
|
||||
this.hide();
|
||||
}, duration);
|
||||
},
|
||||
hide() {
|
||||
this.visible = false;
|
||||
if (this.timer) {
|
||||
clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
},
|
||||
handleClose() {
|
||||
this.hide();
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.timer) {
|
||||
clearTimeout(this.timer);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.custom-info-message {
|
||||
position: fixed;
|
||||
top: 20%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 3000;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #ffffff;
|
||||
border-radius: 8px;
|
||||
padding: 8px 16px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.icon-wrapper {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background: rgba(22, 119, 255, 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.icon-wrapper .icon-text {
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -19,10 +19,16 @@
|
||||
type="primary"
|
||||
:loading="processing"
|
||||
@click="handleConfirmClick"
|
||||
v-if="showBtn"
|
||||
>
|
||||
立即学习
|
||||
</el-button>
|
||||
<el-button class="footer-btn" type="text" @click="handleCancelClick">
|
||||
<el-button
|
||||
v-if="showBtn"
|
||||
class="footer-btn"
|
||||
type="text"
|
||||
@click="handleCancelClick"
|
||||
>
|
||||
取消
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -46,6 +52,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showBtn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
onConfirm: {
|
||||
type: Function,
|
||||
default: null,
|
||||
|
||||
@@ -429,7 +429,7 @@ export default {
|
||||
two: urlPre + "/grow180/login",
|
||||
three: this.webBaseUrl + "/study/index?study=1",
|
||||
// four: 'https://m.qingxuetang.com/x/?appId=qxtcorp306130',
|
||||
five: urlPre + "/new-employee/welcome",
|
||||
five: this.webBaseUrl + "/new-employee/welcome",
|
||||
six: this.webBaseUrl + "/web/contributor/index",
|
||||
seven: this.webBaseUrl + "/grateful/index",
|
||||
};
|
||||
|
||||
65
src/main.js
65
src/main.js
@@ -20,8 +20,8 @@ import '@/assets/styles/uc.scss' // global css
|
||||
import Pagination from "@/components/Pagination";
|
||||
import Remark from "@/components/Remark";
|
||||
import './security'; //security control
|
||||
import VueAwesomeSwiper from 'vue-awesome-swiper';
|
||||
import 'swiper/dist/css/swiper.css';
|
||||
import VueAwesomeSwiper from 'vue-awesome-swiper';
|
||||
import 'swiper/dist/css/swiper.css';
|
||||
Vue.use(VueAwesomeSwiper)
|
||||
import watermark from './utils/warterMark.js'
|
||||
import Bus from './utils/bus.js'
|
||||
@@ -35,44 +35,44 @@ Vue.config.productionTip = false
|
||||
Vue.prototype.$xpage = xpage;
|
||||
|
||||
|
||||
Vue.prototype.msgSuccess = function(msg) {
|
||||
this.$message({ showClose: true, message: msg, type: "success", offset: 50 });
|
||||
Vue.prototype.msgSuccess = function (msg) {
|
||||
this.$message({ showClose: true, message: msg, type: "success", offset: 50 });
|
||||
}
|
||||
//用来筛选图标是否显示的方法,字符串和数组都支持,如果传入其他值或者不传值图标全显示
|
||||
Vue.prototype.$iconFilter = function(hideArray) {
|
||||
let iconOpinion = {
|
||||
isRemark: false,
|
||||
isShare: false,
|
||||
isCollect: false,
|
||||
isPraise: false,
|
||||
isBrowse: false
|
||||
}
|
||||
if (typeof hideArray == 'string') {
|
||||
iconOpinion[hideArray] = true
|
||||
}
|
||||
if (hideArray instanceof Array) {
|
||||
hideArray.forEach(item => {
|
||||
iconOpinion[item] = true;
|
||||
})
|
||||
}
|
||||
return iconOpinion
|
||||
Vue.prototype.$iconFilter = function (hideArray) {
|
||||
let iconOpinion = {
|
||||
isRemark: false,
|
||||
isShare: false,
|
||||
isCollect: false,
|
||||
isPraise: false,
|
||||
isBrowse: false
|
||||
}
|
||||
if (typeof hideArray == 'string') {
|
||||
iconOpinion[hideArray] = true
|
||||
}
|
||||
if (hideArray instanceof Array) {
|
||||
hideArray.forEach(item => {
|
||||
iconOpinion[item] = true;
|
||||
})
|
||||
}
|
||||
return iconOpinion
|
||||
}
|
||||
|
||||
Vue.prototype.msgError = function(msg) {
|
||||
this.$message({ showClose: true, message: msg, type: "error" });
|
||||
Vue.prototype.msgError = function (msg) {
|
||||
this.$message({ showClose: true, message: msg, type: "error" });
|
||||
}
|
||||
|
||||
Vue.prototype.msgInfo = function(msg) {
|
||||
this.$message.info(msg);
|
||||
Vue.prototype.msgInfo = function (msg) {
|
||||
this.$message.info(msg);
|
||||
}
|
||||
|
||||
//高亮显示
|
||||
Vue.prototype.$keywordActiveShow=function(str,keyword){
|
||||
Vue.prototype.$keywordActiveShow = function (str, keyword) {
|
||||
//color:#588afc暂时用老系统颜色,ui给的颜色是这个值
|
||||
if(!str||str.indexOf(keyword)===-1||keyword==''){
|
||||
if (!str || str.indexOf(keyword) === -1 || keyword == '') {
|
||||
return str
|
||||
}
|
||||
return str.replace(keyword,`<span style="color:#FF0000">${keyword}</span>`)
|
||||
return str.replace(keyword, `<span style="color:#FF0000">${keyword}</span>`)
|
||||
}
|
||||
|
||||
Vue.prototype.webBaseUrl = process.env.VUE_APP_PUBLIC_PATH;
|
||||
@@ -83,9 +83,10 @@ Vue.component('Remark', Remark)
|
||||
|
||||
|
||||
Vue.use(Element, {
|
||||
size: VueCookies.get('size') || 'medium' // set element-ui default size
|
||||
size: VueCookies.get('size') || 'medium' // set element-ui default size
|
||||
})
|
||||
|
||||
// VueCookies.set('token', "eyJ0eXBlIjoidG9rZW4iLCJhbGciOiJIUzI1NiJ9.eyJjb21wYW55Q29kZSI6IkMwMDEiLCJ1SWQiOiI5NjUzNDIwMjc0OTc2MDcxNjgiLCJjb21wYW55SWQiOiIxMDQxNjczOTc3Mzc5OTQ2NDk2IiwibG9naW5JZCI6IjE5MzgwNTQ2NDY2OTAxNzcwMjYiLCJpc3MiOiJodHRwOi8vdS5ib2UuY29tIiwiR2l2ZW5OYW1lIjoiYm9ldSIsImV4cCI6MTc1MDkxMDQwOTc0NiwidXNlck5hbWUiOiLmnY7njonlhrAiLCJ1c2VySWQiOiI2QjA0OUZBRi1DMzE0LTdDQ0YtMEQyOC0wRDIzRjRDNDI1MzEifQ==.7f03d1ce991253197f0e733ba554496e8de715595b169b505bed8831ede565a9", 1)
|
||||
// 加入百度统计
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.path) {
|
||||
@@ -97,7 +98,7 @@ router.beforeEach((to, from, next) => {
|
||||
})
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
|
||||
@@ -61,21 +61,23 @@
|
||||
<div class="title-box">
|
||||
<div class="item-title">{{ it.name }}</div>
|
||||
<!-- 右侧动作/成绩 -->
|
||||
<div
|
||||
class="item-right"
|
||||
:class="it.completed ? 'done' : 'link'"
|
||||
>
|
||||
<div class="item-right">
|
||||
<el-button
|
||||
v-if="!it.completed"
|
||||
v-if="it.status == 0"
|
||||
type="text"
|
||||
style="color: #999999"
|
||||
>未开始</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="it.status == 2"
|
||||
type="text"
|
||||
style="color: #ffb01e"
|
||||
>进行中</el-button
|
||||
>
|
||||
<el-button
|
||||
v-else
|
||||
v-if="it.status == 1"
|
||||
type="text"
|
||||
style="color: #27ce9a"
|
||||
disabled
|
||||
>已完成</el-button
|
||||
>
|
||||
</div>
|
||||
@@ -127,32 +129,37 @@
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<el-alert
|
||||
v-if="approvalResults == 2"
|
||||
title="报名申请正在审核中"
|
||||
type="primary"
|
||||
center
|
||||
show-icon
|
||||
:closable="false"
|
||||
/>
|
||||
|
||||
<el-alert
|
||||
v-if="approvalResults == 3"
|
||||
title="报名申请审核已通过"
|
||||
type="success"
|
||||
center
|
||||
show-icon
|
||||
:closable="false"
|
||||
/>
|
||||
<div style="cursor: pointer" @click="returnEnroll">
|
||||
<el-alert
|
||||
v-if="approvalResults == 4"
|
||||
title="报名申请审核不通过,请重新报名"
|
||||
type="error"
|
||||
center
|
||||
show-icon
|
||||
:closable="false"
|
||||
/>
|
||||
<div v-if="approvalResults == 2">
|
||||
<el-alert type="warning" center show-icon :closable="false">
|
||||
<template slot="title">
|
||||
<span style="color: rgba(0, 0, 0, 0.88)"
|
||||
>报名申请正在审核中</span
|
||||
>
|
||||
</template>
|
||||
</el-alert>
|
||||
</div>
|
||||
<div v-if="approvalResults == 3">
|
||||
<el-alert type="success" center show-icon :closable="false">
|
||||
<template slot="title">
|
||||
<span style="color: rgba(0, 0, 0, 0.88)"
|
||||
>报名申请审核已通过</span
|
||||
>
|
||||
</template>
|
||||
</el-alert>
|
||||
</div>
|
||||
<div
|
||||
v-if="approvalResults == 4"
|
||||
style="cursor: pointer"
|
||||
@click="returnEnroll"
|
||||
>
|
||||
<el-alert type="error" center show-icon :closable="false">
|
||||
<template slot="title">
|
||||
<span style="color: rgba(0, 0, 0, 0.88)"
|
||||
>报名申请审核不通过,请</span
|
||||
>
|
||||
<span style="color: #0078fc">重新报名</span>
|
||||
</template>
|
||||
</el-alert>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
@@ -162,8 +169,14 @@
|
||||
</div>
|
||||
<div class="label">成绩单</div>
|
||||
<div class="transcript">
|
||||
<el-button class="btn btn-long" type="success" @click="onDownload"
|
||||
>成 绩 下 载</el-button
|
||||
<el-button
|
||||
class="btn btn-long"
|
||||
:class="{ 'btn-disabled': isDownloadDisabled }"
|
||||
type="success"
|
||||
icon="el-icon-download"
|
||||
:disabled="isDownloadDisabled"
|
||||
@click="onDownload"
|
||||
>成绩下载</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="label">学习进度</div>
|
||||
@@ -205,10 +218,12 @@
|
||||
<NewEmployeeGuideDialog
|
||||
:visible.sync="guideDialogVisible"
|
||||
@close="guideDialogVisible = false"
|
||||
:showBtn="false"
|
||||
/>
|
||||
<!-- 转正流程图弹窗 -->
|
||||
<el-dialog
|
||||
:visible.sync="chartVisible"
|
||||
title="转正流程示意图"
|
||||
:close-on-click-modal="false"
|
||||
@close="chartVisible = false"
|
||||
>
|
||||
@@ -217,6 +232,8 @@
|
||||
<img width="100%" src="../../assets/images/flowchart.png" alt="" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 自定义信息提示 -->
|
||||
<CustomInfoMessage ref="customMessage" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -225,6 +242,7 @@ import portalHeader from "@/components/PortalHeader.vue";
|
||||
import portalFooter from "@/components/PortalFooter.vue";
|
||||
import portalFloatTools from "@/components/PortalFloatTools.vue";
|
||||
import NewEmployeeGuideDialog from "@/components/NewEmployeeGuideDialog.vue";
|
||||
import CustomInfoMessage from "@/components/CustomInfoMessage.vue";
|
||||
import { mapGetters } from "vuex";
|
||||
import {
|
||||
getWelcomeData,
|
||||
@@ -232,6 +250,7 @@ import {
|
||||
getStuProjectProcess,
|
||||
downloadSocialRecruitReport,
|
||||
getSzxygProjectInfo,
|
||||
enrollRequest,
|
||||
} from "@/api/new-employee/newEmployee";
|
||||
import { start } from "nprogress";
|
||||
|
||||
@@ -242,13 +261,14 @@ export default {
|
||||
portalFooter,
|
||||
portalFloatTools,
|
||||
NewEmployeeGuideDialog,
|
||||
CustomInfoMessage,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
flag: "all",
|
||||
status: "all",
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
loading: false,
|
||||
projectId: "",
|
||||
@@ -276,6 +296,12 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["userInfo"]),
|
||||
// 判断下载按钮是否应该禁用
|
||||
isDownloadDisabled() {
|
||||
// 只有在审核通过(3)且学习进度为100时才可下载
|
||||
// 其他情况(报名失败1、审核中2、审核失败4、进度未到100)都禁用
|
||||
return this.approvalResults != 3 || this.progressRing.total != 100;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async initIds() {
|
||||
@@ -343,24 +369,24 @@ export default {
|
||||
);
|
||||
},
|
||||
async onDownload() {
|
||||
if (!this.projectId || !this.studentId) {
|
||||
this.$message.warning("缺少项目信息或学员信息");
|
||||
return;
|
||||
}
|
||||
// if (!this.projectId || !this.studentId) {
|
||||
// this.$message.warning("缺少项目信息或学员信息");
|
||||
// return;
|
||||
// }
|
||||
if (this.approvalResults != 2) {
|
||||
this.$message.warning(
|
||||
"您的报名正在审核中,无法下载成绩单,请审核通过后下载"
|
||||
);
|
||||
// this.$refs.customMessage.show(
|
||||
// "您的报名正在审核中,无法下载成绩单,请审核通过后下载"
|
||||
// );
|
||||
return;
|
||||
}
|
||||
if (this.approvalResults != 4) {
|
||||
this.$message.warning(
|
||||
"请您重新报名,重新报名不影响当前学习进度,请在审核通过后下载成绩单"
|
||||
);
|
||||
// this.$refs.customMessage.show(
|
||||
// "请您重新报名,重新报名不影响当前学习进度,请在审核通过后下载成绩单"
|
||||
// );
|
||||
return;
|
||||
}
|
||||
if (this.progressRing.total != 100) {
|
||||
this.$message.warning("请您完成学习课程后下载成绩单");
|
||||
// this.$message.warning("请您完成学习课程后下载成绩单");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -375,15 +401,22 @@ export default {
|
||||
this.$message.error("下载失败");
|
||||
}
|
||||
},
|
||||
returnEnroll() {
|
||||
this.$router.push("/new-employee/welcome");
|
||||
async returnEnroll() {
|
||||
// this.$router.push("/new-employee/welcome");
|
||||
const res = await enrollRequest();
|
||||
if (res.data.sendToOaSuccess != 0) {
|
||||
this.$refs.customMessage.show("报名失败,请联系XXXX,联系方式:XXXXXX");
|
||||
} else {
|
||||
this.$refs.customMessage.show("您已重新报名成功");
|
||||
this.approvalResults = 2;
|
||||
}
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
const res = await getWelcomeData();
|
||||
// 社招新员工项目标识:0否,1是
|
||||
if (res.data.approvalResults == 1) {
|
||||
this.$message.error("未报名或报名失败,请前往报名页面进行报名");
|
||||
this.$refs.customMessage.show("未报名或报名失败,请前往报名页面进行报名");
|
||||
this.$router.push("/new-employee/welcome");
|
||||
}
|
||||
// 1报名失败、2审核中、3审核通过、4审核失败
|
||||
@@ -448,7 +481,7 @@ export default {
|
||||
|
||||
/* 筛选条 */
|
||||
.filters {
|
||||
padding: 8px 12px;
|
||||
padding: 0px 12px 8px;
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
align-items: center;
|
||||
@@ -600,12 +633,6 @@ export default {
|
||||
text-align: right;
|
||||
font-size: 14px;
|
||||
}
|
||||
.item-right.link {
|
||||
color: #0f80ff;
|
||||
}
|
||||
.item-right.done {
|
||||
color: #8a8f99;
|
||||
}
|
||||
.item-right.score {
|
||||
font-weight: 700;
|
||||
}
|
||||
@@ -665,7 +692,7 @@ export default {
|
||||
|
||||
/* 单选按钮组胶囊皮肤(替代 Tabs),保持外观一致 */
|
||||
.pill-radios {
|
||||
padding-top: 8px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
.pill-radios >>> .el-radio-button__inner {
|
||||
background: #f3f5f8;
|
||||
@@ -733,8 +760,8 @@ export default {
|
||||
font-weight: 600;
|
||||
}
|
||||
.btn-outline {
|
||||
background: #ffffff;
|
||||
color: rgba(0, 120, 252, 1);
|
||||
background: rgba(0, 120, 252, 1);
|
||||
color: #fff;
|
||||
border: 1px solid rgba(0, 120, 252, 1);
|
||||
width: 120px;
|
||||
}
|
||||
@@ -754,6 +781,18 @@ export default {
|
||||
color: #ffffff;
|
||||
box-shadow: 0 2px 8px rgba(26, 192, 127, 0.35);
|
||||
}
|
||||
.btn-long.btn-disabled,
|
||||
.btn-long:disabled {
|
||||
background: #cccccc !important;
|
||||
color: #ffffff !important;
|
||||
cursor: not-allowed !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.btn-long.btn-disabled:hover,
|
||||
.btn-long:disabled:hover {
|
||||
background: #cccccc !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.progress-circles {
|
||||
display: flex;
|
||||
|
||||
@@ -67,6 +67,8 @@
|
||||
:onCancel="() => (infoConfirmDialogVisible = false)"
|
||||
@close="handleDialogClose"
|
||||
/>
|
||||
<!-- 自定义信息提示 -->
|
||||
<CustomInfoMessage ref="customMessage" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -74,10 +76,11 @@
|
||||
import { mapGetters } from "vuex";
|
||||
import { getWelcomeData, enrollRequest } from "@/api/new-employee/newEmployee";
|
||||
import NewEmployeeGuideDialog from "@/components/NewEmployeeGuideDialog.vue";
|
||||
import CustomInfoMessage from "@/components/CustomInfoMessage.vue";
|
||||
|
||||
export default {
|
||||
name: "WelcomePage",
|
||||
components: { NewEmployeeGuideDialog },
|
||||
components: { NewEmployeeGuideDialog, CustomInfoMessage },
|
||||
data() {
|
||||
return {
|
||||
userName: "",
|
||||
@@ -115,19 +118,22 @@ export default {
|
||||
|
||||
// 报名按钮点击
|
||||
async handleEnrollClick() {
|
||||
this.infoConfirmDialogVisible = true;
|
||||
if (this.approvalResults == "1" || this.approvalResults == "4") {
|
||||
const res = await enrollRequest();
|
||||
if (res.data.sendToOaSuccess != 0) {
|
||||
this.$refs.customMessage.show(
|
||||
"报名失败,请联系XXXX,联系方式:XXXXXX"
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.infoConfirmDialogVisible = true;
|
||||
}
|
||||
},
|
||||
|
||||
// 确认按钮
|
||||
async handleConfirm() {
|
||||
try {
|
||||
if (this.approvalResults == "1" || this.approvalResults == "4") {
|
||||
const res = await enrollRequest();
|
||||
if (res.data.sendToOaSuccess != 0) {
|
||||
this.$message.error("报名失败,请联系XXXX,联系方式:XXXXXX");
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.$router.push("/new-employee/study");
|
||||
} catch (error) {
|
||||
console.error("提交失败:", error);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user