change
This commit is contained in:
@@ -391,4 +391,12 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
@Comment("openId")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String openId;
|
||||
|
||||
@Column
|
||||
@Comment("编制信息")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 64)
|
||||
@DataCenterColumn(name = "编制信息", key = "bzxx")
|
||||
private String compilationInformation;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.budwk.app.sys.services.SysDataUnitPullService;
|
||||
import com.budwk.app.sys.services.SysDataUserPullService;
|
||||
import com.budwk.app.sys.services.SysDictService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.nutz.aop.interceptor.async.Async;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
@@ -228,6 +229,8 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
// 插入到数据库
|
||||
dao().insert(latestSourceList);
|
||||
|
||||
updateDictCompilationInformation(latestSourceList);
|
||||
|
||||
// 人员的单位数据和数据库的单位数据比较,如果人员里面有单位不存在,去更新单位数据
|
||||
List<String> sourceUnitIds = latestSourceList.stream().map(Sys_user_source::getUnitId).distinct().toList();
|
||||
Sql sql = Sqls.create("select id from sys_unit group by id");
|
||||
@@ -245,6 +248,36 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新编制信息
|
||||
* @param userSources
|
||||
*/
|
||||
private void updateDictCompilationInformation(List<Sys_user_source> userSources){
|
||||
if(CollUtil.isNotEmpty(userSources)){
|
||||
List<String> compilationInformationList = userSources.stream()
|
||||
.map(Sys_user_source::getCompilationInformation)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
//系统在职状态字典
|
||||
List<Sys_dict> sysUserStates = sysDictService.getSubListByCode("USER_COMPILATION_INFORMATION");
|
||||
//系统中不存在的就插入
|
||||
List<Sys_dict> insertUserStates = compilationInformationList.stream()
|
||||
.filter(compilationInformation -> sysUserStates.stream().noneMatch(dict -> dict.getCode().equals(compilationInformation)))
|
||||
.map(compilationInformation -> {
|
||||
Sys_dict dict = new Sys_dict();
|
||||
dict.setCode(compilationInformation);
|
||||
dict.setName(compilationInformation);
|
||||
return dict;
|
||||
}).toList();
|
||||
if(CollUtil.isNotEmpty(insertUserStates)){
|
||||
for (Sys_dict dict : insertUserStates) {
|
||||
sysDictService.saveByParentCode(dict, "USER_COMPILATION_INFORMATION");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Async
|
||||
private void updateDict(List<Sys_user_source> userSources) {
|
||||
//判断是否要更新在职状态字典
|
||||
|
||||
@@ -96,6 +96,9 @@ public class View_user {
|
||||
@Column
|
||||
private String preparedBy;
|
||||
|
||||
@Column
|
||||
private String compilationInformation;
|
||||
|
||||
@Column
|
||||
private String identityType;
|
||||
|
||||
|
||||
+30
@@ -1,17 +1,24 @@
|
||||
package com.budwk.app.zhgh.staffmanage.member.controller.change;
|
||||
|
||||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.zhgh.staffmanage.member.param.pageform.MemberManagePageForm;
|
||||
import com.budwk.app.zhgh.staffmanage.member.service.MemberCommonService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
@@ -44,6 +51,29 @@ public class MemberChangeRecordController {
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出变更记录列表,导出的字段和数据范围与当前页面查询结果保持一致。
|
||||
*
|
||||
* @param pageForm 当前页面查询条件和显示字段
|
||||
* @param response 文件下载响应
|
||||
*/
|
||||
@At
|
||||
@Ok("void")
|
||||
@SaCheckPermission("member.change.record")
|
||||
public void doExport(MemberManagePageForm pageForm, HttpServletResponse response) {
|
||||
try {
|
||||
// 导出列由前端当前表格列配置决定,额外补充页面固定展示的异动信息列。
|
||||
List<ExcelExportEntity> exportEntities = memberCommonService.buildMemberHistoryRecordExportEntities(pageForm.getColumns());
|
||||
List<NutMap> list = memberCommonService.memberHistoryRecordExportData(pageForm);
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list);
|
||||
CommonDownloadUtil.download("会员变更记录.xlsx", workbook, response);
|
||||
} catch (Exception e) {
|
||||
log.error("导出会员变更记录失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckPermission("member.change.record")
|
||||
|
||||
+6
@@ -14,6 +14,7 @@ import org.nutz.dao.util.cri.Static;
|
||||
import org.nutz.lang.Lang;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
@@ -59,6 +60,11 @@ public class MemberManagePageForm extends PageForm {
|
||||
//变更来源
|
||||
private List<Integer> changeOrigins;
|
||||
|
||||
/**
|
||||
* 页面当前显示的列表字段,导出时按照该字段顺序动态生成表头。
|
||||
*/
|
||||
private List<Map<String, String>> columns;
|
||||
|
||||
public static void buildSearch(Cnd cnd, MemberManagePageForm pageForm) {
|
||||
if (cnd == null) {
|
||||
cnd = Cnd.NEW();
|
||||
|
||||
+3
@@ -44,6 +44,9 @@ public class MemberStatisticsPageForm extends PageForm {
|
||||
|
||||
private List<String> preparedBys;
|
||||
|
||||
@ApiModelProperty("编制信息")
|
||||
private List<String> compilationInformations;
|
||||
|
||||
private List<String> userStates;
|
||||
|
||||
private List<String> memberStatus;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.budwk.app.zhgh.staffmanage.member.service;
|
||||
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
@@ -43,6 +44,22 @@ public interface MemberCommonService extends BaseService<Sys_user> {
|
||||
*/
|
||||
Pagination memberHistoryRecords(MemberManagePageForm pageForm);
|
||||
|
||||
/**
|
||||
* 根据变更记录页面查询条件获取全部导出数据,导出数据与列表查询口径保持一致。
|
||||
*
|
||||
* @param pageForm 变更记录查询参数
|
||||
* @return 变更记录导出数据
|
||||
*/
|
||||
List<NutMap> memberHistoryRecordExportData(MemberManagePageForm pageForm);
|
||||
|
||||
/**
|
||||
* 根据前端当前列表列配置生成导出列,确保页面展示什么字段就导出什么字段。
|
||||
*
|
||||
* @param columns 页面列配置
|
||||
* @return Excel 导出列配置
|
||||
*/
|
||||
List<ExcelExportEntity> buildMemberHistoryRecordExportEntities(List<Map<String, String>> columns);
|
||||
|
||||
|
||||
/**
|
||||
* 获取可变更字段
|
||||
|
||||
+75
-1
@@ -1,11 +1,13 @@
|
||||
package com.budwk.app.zhgh.staffmanage.member.service.impl;
|
||||
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HtmlUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
@@ -139,6 +141,54 @@ public class MemberManageServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
|
||||
@Override
|
||||
public Pagination memberHistoryRecords(MemberManagePageForm pageForm) {
|
||||
Sql sql = getMemberHistoryRecordSql(pageForm);
|
||||
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据变更记录查询条件获取全部数据,用于页面导出,保证导出数据与列表查询口径一致。
|
||||
*
|
||||
* @param pageForm 变更记录查询参数
|
||||
* @return 已转换异动类型显示文本的导出数据
|
||||
*/
|
||||
@Override
|
||||
public List<NutMap> memberHistoryRecordExportData(MemberManagePageForm pageForm) {
|
||||
List<NutMap> list = listMap(getMemberHistoryRecordSql(pageForm));
|
||||
Map<String, String> changeTypeNameMap = Arrays.stream(MemberChangeType.values())
|
||||
.collect(Collectors.toMap(MemberChangeType::getCode, MemberChangeType::getChangeTypeName));
|
||||
int[] no = {1};
|
||||
list.forEach(row -> {
|
||||
row.put("no", no[0]++);
|
||||
row.put("changeTypesText", getChangeTypesText(row.get("changeTypes"), changeTypeNameMap));
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据页面表格列生成导出列,并补充页面分组展示的更新时间、异动类型两列。
|
||||
*
|
||||
* @param columns 页面当前显示的基础列
|
||||
* @return Excel 导出列配置
|
||||
*/
|
||||
@Override
|
||||
public List<ExcelExportEntity> buildMemberHistoryRecordExportEntities(List<Map<String, String>> columns) {
|
||||
List<ExcelExportEntity> exportEntities = new ArrayList<>();
|
||||
exportEntities.add(new ExcelExportEntity("序号", "no", 10));
|
||||
if (Lang.isNotEmpty(columns)) {
|
||||
columns.forEach(column -> exportEntities.add(new ExcelExportEntity(column.get("label"), column.get("prop"), 20)));
|
||||
}
|
||||
exportEntities.add(new ExcelExportEntity("更新时间", "changeTime", 25));
|
||||
exportEntities.add(new ExcelExportEntity("异动类型", "changeTypesText", 30));
|
||||
return exportEntities;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建变更记录列表 SQL,分页查询和导出查询共用该方法,避免筛选条件不一致。
|
||||
*
|
||||
* @param pageForm 变更记录查询参数
|
||||
* @return 变更记录查询 SQL
|
||||
*/
|
||||
private Sql getMemberHistoryRecordSql(MemberManagePageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
his.id,
|
||||
@@ -206,7 +256,31 @@ public class MemberManageServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
cnd.andEX("his.unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据库保存的异动类型 JSON 数组转换为页面展示的中文名称,供导出 Excel 使用。
|
||||
*
|
||||
* @param changeTypes 数据库中的异动类型值
|
||||
* @param changeTypeNameMap 异动类型枚举名称映射
|
||||
* @return 逗号分隔的异动类型名称
|
||||
*/
|
||||
private String getChangeTypesText(Object changeTypes, Map<String, String> changeTypeNameMap) {
|
||||
if (changeTypes == null) {
|
||||
return null;
|
||||
}
|
||||
List<String> changeTypeList;
|
||||
if (changeTypes instanceof Collection<?> collection) {
|
||||
changeTypeList = collection.stream().map(String::valueOf).toList();
|
||||
} else if (StrUtil.isNotBlank(String.valueOf(changeTypes))) {
|
||||
changeTypeList = JSONUtil.parseArray(String.valueOf(changeTypes)).toList(String.class);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return changeTypeList.stream()
|
||||
.map(type -> changeTypeNameMap.getOrDefault(type, type))
|
||||
.collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
@@ -90,6 +90,8 @@ public class MemberStatisticsServiceImpl extends BaseServiceImpl<Sys_user> imple
|
||||
handleField("unitId", pageForm.getUnitId(), reverseSelection, IN_OR_NIN_OP, cnd);
|
||||
handleField("personType", pageForm.getPersonTypes(), reverseSelection, IN_OR_NIN_OP, cnd);
|
||||
handleField("preparedBy", pageForm.getPreparedBys(), reverseSelection, IN_OR_NIN_OP, cnd);
|
||||
// 编制信息前端使用独立字典传值,实际对应用户表/视图中的 compilationInformation 字段。
|
||||
handleField("compilationInformation", pageForm.getCompilationInformations(), reverseSelection, IN_OR_NIN_OP, cnd);
|
||||
handleField("userState", pageForm.getUserStates(), reverseSelection, IN_OR_NIN_OP, cnd);
|
||||
handleField("sex", pageForm.getSexTypes(), reverseSelection, IN_OR_NIN_OP, cnd);
|
||||
cnd.andEX("sur.roleId", IN_OR_NIN_OP, pageForm.getRoleIds());
|
||||
@@ -145,6 +147,7 @@ public class MemberStatisticsServiceImpl extends BaseServiceImpl<Sys_user> imple
|
||||
u.arrivalAtSchoolDate,
|
||||
u.personType,
|
||||
u.preparedBy,
|
||||
u.compilationInformation,
|
||||
u.identityType,
|
||||
u.userState,
|
||||
u.unionName,
|
||||
|
||||
@@ -41,7 +41,6 @@ const basicForm = {
|
||||
<el-col :span="12">
|
||||
<el-form-item :rules="{required:true,message: '请选择活动时间', trigger: 'blur'}" label="活动时间" prop="activityTime">
|
||||
<el-date-picker
|
||||
:picker-options="pickerOptions"
|
||||
end-placeholder="请选择活动结束日期"
|
||||
range-separator="至"
|
||||
start-placeholder="请选择活动开始日期"
|
||||
|
||||
@@ -41,7 +41,6 @@ const basicForm = {
|
||||
<el-col :span="12">
|
||||
<el-form-item :rules="{required:true,message: '请选择活动时间', trigger: 'blur'}" label="活动时间" prop="activityTime">
|
||||
<el-date-picker
|
||||
:picker-options="pickerOptions"
|
||||
end-placeholder="请选择活动结束日期"
|
||||
range-separator="至"
|
||||
start-placeholder="请选择活动开始日期"
|
||||
|
||||
@@ -39,7 +39,9 @@ layout("/layouts/platform.html"){
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt10">
|
||||
<table-tool label="变更列表" :app="this"></table-tool>
|
||||
<table-tool label="变更列表" :app="this">
|
||||
<el-button icon="el-icon-printer" type="primary" size="small" @click="doExport">导出</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" style="width: 100%" row-key="id"
|
||||
@sort-change="pageOrder"
|
||||
resizable
|
||||
@@ -189,6 +191,19 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
},
|
||||
|
||||
doExport() {
|
||||
const pageForm = clone(this.pageForm)
|
||||
pageForm.userStates = JSON.stringify(pageForm.userStates)
|
||||
pageForm.personTypes = JSON.stringify(pageForm.personTypes)
|
||||
pageForm.changeTypes = JSON.stringify(pageForm.changeTypes)
|
||||
pageForm.changeOrigins = JSON.stringify(pageForm.changeOrigins)
|
||||
// 导出字段取当前页面列表列,并补充后端固定处理的异动信息列。
|
||||
pageForm.columns = JSON.stringify(this.tableColumns.map((item) => {
|
||||
return {prop: item.prop, label: item.label}
|
||||
}))
|
||||
this.$downLoad(loc() + "/doExport", pageForm)
|
||||
},
|
||||
|
||||
},
|
||||
async created() {
|
||||
|
||||
|
||||
+4
@@ -160,6 +160,7 @@ layout("/layouts/platform.html"){
|
||||
{ prop: "userState", label: "在职状态", width: 120, sortable: true },
|
||||
{ prop: "personType", label: "教职工类别", width: 120, sortable: true },
|
||||
{ prop: "preparedBy", label: "编制类别", width: 120, sortable: true },
|
||||
{ prop: "compilationInformation", label: "编制信息", width: 120, sortable: true },
|
||||
{ prop: "postDoctoralJoinDate", label: "进站时间", sortable: true, checked: 0 },
|
||||
{ prop: "unionName", label: "所属工会", width: 120, sortable: true },
|
||||
{ prop: "unitName", label: "所属单位", width: 120, sortable: true },
|
||||
@@ -201,6 +202,8 @@ layout("/layouts/platform.html"){
|
||||
pageForm.sexTypes = JSON.stringify(this.pageForm.sexTypes)
|
||||
pageForm.memberTypes = JSON.stringify(this.pageForm.memberTypes)
|
||||
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
||||
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
|
||||
pageForm.compilationInformations = JSON.stringify(this.pageForm.compilationInformations)
|
||||
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
||||
const data = this.tableColumns.filter(item => this.checkedFields.includes(item.prop)).map(item => {
|
||||
return {prop: item.prop, label: item.label}
|
||||
@@ -225,6 +228,7 @@ layout("/layouts/platform.html"){
|
||||
pageForm.memberTypes = JSON.stringify(this.pageForm.memberTypes)
|
||||
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
||||
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
|
||||
pageForm.compilationInformations = JSON.stringify(this.pageForm.compilationInformations)
|
||||
pageForm.memberStatus = JSON.stringify(this.pageForm.memberStatus)
|
||||
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
||||
if (pageForm.birthdayRange && pageForm.birthdayRange.length > 0) {
|
||||
|
||||
+32
@@ -111,6 +111,31 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
|
||||
</el-link>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row type="flex" align="middle" class="query-row query-row-tag">
|
||||
<el-col class="query-row-title">编制信息:</el-col>
|
||||
<el-col class="query-row-content query-row-content-tag">
|
||||
<el-tag
|
||||
style="margin-right: 10px;cursor: pointer"
|
||||
v-for="item in compilationInformationOptions"
|
||||
:key="item.code"
|
||||
:type="item.name"
|
||||
:effect="pageForm.compilationInformations.includes(item.name)?'dark':'plain'"
|
||||
@click="tagClick('compilationInformations',item.name)">
|
||||
{{ item.name }}
|
||||
</el-tag>
|
||||
|
||||
<el-link type="danger"
|
||||
v-if="compilationInformationOptions.length&&pageForm.compilationInformations.length"
|
||||
:underline="false"
|
||||
@click="pageForm.compilationInformations=[];doSearch()">清空
|
||||
</el-link>
|
||||
<el-link :underline="false"
|
||||
@click="pageForm.compilationInformations=compilationInformationOptions.map(p=>p.code);doSearch()"
|
||||
type="success">全部
|
||||
</el-link>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row type="flex" align="middle" class="query-row">
|
||||
<el-col class="query-row-content">
|
||||
@@ -208,6 +233,7 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
|
||||
searchName: "username",
|
||||
personTypes: [],
|
||||
preparedBys: [],
|
||||
compilationInformations: [],
|
||||
userStates: [],
|
||||
memberStatus: [],
|
||||
year: moment().format("YYYY"),
|
||||
@@ -224,6 +250,7 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
|
||||
},
|
||||
personTypeOptions: [],
|
||||
preparedByOptions: [],
|
||||
compilationInformationOptions: [],
|
||||
userStateOptions: [],
|
||||
memberStatusOptions: [],
|
||||
unions: [],
|
||||
@@ -315,6 +342,7 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
|
||||
this.pageForm.sexTypes = []
|
||||
this.pageForm.personTypes = []
|
||||
this.pageForm.preparedBys = []
|
||||
this.pageForm.compilationInformations = []
|
||||
this.pageForm.memberStatus = []
|
||||
this.pageForm.userStates = []
|
||||
this.pageForm.unionId = []
|
||||
@@ -352,6 +380,10 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
|
||||
this.$businessTool.getDictOptions("USER_PREPARED_BY_TYPE").then((data) => {
|
||||
this.preparedByOptions = data
|
||||
})
|
||||
// 编制信息使用独立字典,后端按 sys_user.compilationInformation 字段进行筛选。
|
||||
this.$businessTool.getDictOptions("USER_COMPILATION_INFORMATION").then((data) => {
|
||||
this.compilationInformationOptions = data
|
||||
})
|
||||
this.$businessTool.getDictOptions("USER_STATE").then((data) => {
|
||||
this.userStateOptions = data
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user