feat: 代表团凭证
This commit is contained in:
@@ -105,7 +105,8 @@ public class SysConfController {
|
|||||||
if (conf == null || (!"AppHomeImg".equals(conf.getConfigKey())
|
if (conf == null || (!"AppHomeImg".equals(conf.getConfigKey())
|
||||||
&& !"H5AppHomeImg".equals(conf.getConfigKey())
|
&& !"H5AppHomeImg".equals(conf.getConfigKey())
|
||||||
&& !"AppFeaturedActivityImg".equals(conf.getConfigKey())
|
&& !"AppFeaturedActivityImg".equals(conf.getConfigKey())
|
||||||
&& !"AppFestivalBenefitImg".equals(conf.getConfigKey()))) {
|
&& !"AppFestivalBenefitImg".equals(conf.getConfigKey())
|
||||||
|
&& !"TeacherCongressCardBackImg".equals(conf.getConfigKey()))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String configValue = Strings.sNull(conf.getConfigValue());
|
String configValue = Strings.sNull(conf.getConfigValue());
|
||||||
@@ -145,6 +146,7 @@ public class SysConfController {
|
|||||||
ensureAppImageConfig("H5AppHomeImg", "移动端首页轮播图");
|
ensureAppImageConfig("H5AppHomeImg", "移动端首页轮播图");
|
||||||
ensureAppImageConfig("AppFeaturedActivityImg", "精彩活动页顶部图片");
|
ensureAppImageConfig("AppFeaturedActivityImg", "精彩活动页顶部图片");
|
||||||
ensureAppImageConfig("AppFestivalBenefitImg", "节日福利页顶部图片");
|
ensureAppImageConfig("AppFestivalBenefitImg", "节日福利页顶部图片");
|
||||||
|
ensureAppImageConfig("TeacherCongressCardBackImg", "教代会代表证背景图片");
|
||||||
Cnd cnd = Cnd.NEW();
|
Cnd cnd = Cnd.NEW();
|
||||||
if (Strings.isNotBlank(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
|
if (Strings.isNotBlank(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
|
||||||
cnd.orderBy(pageOrderName, PageUtil.getOrder(pageOrderBy));
|
cnd.orderBy(pageOrderName, PageUtil.getOrder(pageOrderBy));
|
||||||
|
|||||||
@@ -323,7 +323,7 @@ public class SysMenuController {
|
|||||||
public Object enable(String menuId, HttpServletRequest req) {
|
public Object enable(String menuId, HttpServletRequest req) {
|
||||||
try {
|
try {
|
||||||
req.setAttribute("name", sysMenuService.fetch(menuId).getName());
|
req.setAttribute("name", sysMenuService.fetch(menuId).getName());
|
||||||
sysMenuService.update(org.nutz.dao.Chain.make("disabled", false), Cnd.where("id", "=", menuId));
|
sysMenuService.update(Chain.make("disabled", false), Cnd.where("id", "=", menuId));
|
||||||
sysMenuService.clearCache();
|
sysMenuService.clearCache();
|
||||||
sysUserService.clearCache();
|
sysUserService.clearCache();
|
||||||
sysRoleService.clearCache();
|
sysRoleService.clearCache();
|
||||||
@@ -340,7 +340,7 @@ public class SysMenuController {
|
|||||||
public Object disable(String menuId, HttpServletRequest req) {
|
public Object disable(String menuId, HttpServletRequest req) {
|
||||||
try {
|
try {
|
||||||
req.setAttribute("name", sysMenuService.fetch(menuId).getName());
|
req.setAttribute("name", sysMenuService.fetch(menuId).getName());
|
||||||
sysMenuService.update(org.nutz.dao.Chain.make("disabled", true), Cnd.where("id", "=", menuId));
|
sysMenuService.update(Chain.make("disabled", true), Cnd.where("id", "=", menuId));
|
||||||
sysMenuService.clearCache();
|
sysMenuService.clearCache();
|
||||||
sysUserService.clearCache();
|
sysUserService.clearCache();
|
||||||
sysRoleService.clearCache();
|
sysRoleService.clearCache();
|
||||||
@@ -398,7 +398,7 @@ public class SysMenuController {
|
|||||||
sysMenuService.execute(Sqls.create("update sys_menu set location=0 where platform = '%s'".formatted(platform)));
|
sysMenuService.execute(Sqls.create("update sys_menu set location=0 where platform = '%s'".formatted(platform)));
|
||||||
for (String s : menuIds) {
|
for (String s : menuIds) {
|
||||||
if (!Strings.isBlank(s)) {
|
if (!Strings.isBlank(s)) {
|
||||||
sysMenuService.update(org.nutz.dao.Chain.make("location", i), Cnd.where("id", "=", s));
|
sysMenuService.update(Chain.make("location", i), Cnd.where("id", "=", s));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
|||||||
if (!FileUtil.exist(file)) {
|
if (!FileUtil.exist(file)) {
|
||||||
throw new IOException("找不到存储的文件");
|
throw new IOException("找不到存储的文件");
|
||||||
}
|
}
|
||||||
// CommonDownloadUtil.download(sys_file.getName(), IoUtil.readBytes(FileUtil.getInputStream(file)), response);
|
return IoUtil.readBytes(FileUtil.getInputStream(file));
|
||||||
} else if (sys_file.getEngine().equals(SysFileEngineTypeEnum.MINIO.getValue())) {
|
} else if (sys_file.getEngine().equals(SysFileEngineTypeEnum.MINIO.getValue())) {
|
||||||
return SysFileMinIoUtil.getFileBytes(sys_file.getBucket(), sys_file.getStoragePath());
|
return SysFileMinIoUtil.getFileBytes(sys_file.getBucket(), sys_file.getStoragePath());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
///*
|
package com.budwk.app.sys.utils; ///*
|
||||||
// * Copyright [2022] [https://www.xiaonuo.vip]
|
// * Copyright [2022] [https://www.xiaonuo.vip]
|
||||||
// *
|
// *
|
||||||
// * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
// * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||||
|
|||||||
+218
@@ -0,0 +1,218 @@
|
|||||||
|
package com.budwk.app.zhgh.democratic.teachercongress.delegate.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.budwk.app.base.constant.RoleConstant;
|
||||||
|
import com.budwk.app.base.result.Result;
|
||||||
|
import com.budwk.app.sys.models.Sys_config;
|
||||||
|
import com.budwk.app.sys.services.SysFileService;
|
||||||
|
import com.budwk.app.sys.services.SysRoleService;
|
||||||
|
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||||
|
import com.budwk.app.zhgh.democratic.teachercongress.delegate.models.Teacher_congress_delegate;
|
||||||
|
import com.budwk.app.zhgh.democratic.teachercongress.delegation.models.Teacher_congress_delegation;
|
||||||
|
import com.budwk.app.zhgh.democratic.teachercongress.prepare.models.Teacher_congress_session;
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.EncodeHintType;
|
||||||
|
import com.google.zxing.MultiFormatWriter;
|
||||||
|
import com.google.zxing.WriterException;
|
||||||
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||||
|
import org.nutz.dao.Cnd;
|
||||||
|
import org.nutz.dao.Dao;
|
||||||
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.json.Json;
|
||||||
|
import org.nutz.lang.Lang;
|
||||||
|
import org.nutz.lang.util.NutMap;
|
||||||
|
import org.nutz.mvc.annotation.At;
|
||||||
|
import org.nutz.mvc.annotation.Ok;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 教代会代表证
|
||||||
|
*/
|
||||||
|
@IocBean
|
||||||
|
@At("/platform/teacherCongress/delegate/card")
|
||||||
|
@Ok("json:full")
|
||||||
|
public class TeacherCongressDelegateCardController {
|
||||||
|
|
||||||
|
private static final String CARD_BACK_IMG_CONFIG = "TeacherCongressCardBackImg";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Dao dao;
|
||||||
|
@Inject
|
||||||
|
private SysFileService sysFileService;
|
||||||
|
@Inject
|
||||||
|
private SysRoleService sysRoleService;
|
||||||
|
|
||||||
|
@At("/h5")
|
||||||
|
@Ok("beetl:/platform/zhghh5/democratic/teachercongress/delegate/card/index.html")
|
||||||
|
@SaCheckLogin
|
||||||
|
public void h5Index() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@SaCheckLogin
|
||||||
|
public Object isDb() {
|
||||||
|
Teacher_congress_session session = getCurrentSession();
|
||||||
|
if (session == null) {
|
||||||
|
return Result.error("当前没有开启的教代会");
|
||||||
|
}
|
||||||
|
Teacher_congress_delegate delegate = getCurrentDelegate(session.getId());
|
||||||
|
if (delegate == null) {
|
||||||
|
return Result.error("抱歉," + getSessionTitle(session) + "您不是代表");
|
||||||
|
}
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@Ok("void")
|
||||||
|
@SaCheckLogin
|
||||||
|
public void showCard(HttpServletResponse response) throws IOException, WriterException {
|
||||||
|
NutMap cardInfo = getCardInfo();
|
||||||
|
BufferedImage backgroundImage = readBackgroundImage();
|
||||||
|
BufferedImage resultImage = new BufferedImage(backgroundImage.getWidth(), backgroundImage.getHeight(), BufferedImage.TYPE_INT_RGB);
|
||||||
|
Graphics2D graphics = resultImage.createGraphics();
|
||||||
|
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
graphics.drawImage(backgroundImage, 0, 0, null);
|
||||||
|
|
||||||
|
Map<EncodeHintType, ErrorCorrectionLevel> hintMap = new EnumMap<>(EncodeHintType.class);
|
||||||
|
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
|
||||||
|
NutMap qrData = new NutMap();
|
||||||
|
qrData.setv("userId", SecurityUtil.getUserId());
|
||||||
|
BitMatrix bitMatrix = new MultiFormatWriter().encode(Json.toJson(qrData), BarcodeFormat.QR_CODE, 200, 200, hintMap);
|
||||||
|
int qrCodeX = (resultImage.getWidth() - 200) / 2;
|
||||||
|
int qrCodeY = (resultImage.getHeight() - 200) / 2;
|
||||||
|
for (int x = 0; x < 200; x++) {
|
||||||
|
for (int y = 0; y < 200; y++) {
|
||||||
|
if (bitMatrix.get(x, y)) {
|
||||||
|
resultImage.setRGB(qrCodeX + x, qrCodeY + y, Color.BLACK.getRGB());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String title = StrUtil.blankToDefault(cardInfo.getString("title"), "");
|
||||||
|
int titleY = (resultImage.getHeight() / 2) - 130;
|
||||||
|
Font titleFont = new Font("微软雅黑", Font.PLAIN, 26).deriveFont(Font.BOLD);
|
||||||
|
commonFont(resultImage, graphics, title, titleY, titleFont, Color.decode("#d1b930"));
|
||||||
|
|
||||||
|
String nameText = StrUtil.blankToDefault(cardInfo.getString("nameText"), SecurityUtil.getUserUsername());
|
||||||
|
int nameTextY = (resultImage.getHeight() / 2) + 150;
|
||||||
|
Font nameFont = new Font("楷体", Font.BOLD, 40);
|
||||||
|
commonFont(resultImage, graphics, nameText, nameTextY, nameFont, Color.WHITE);
|
||||||
|
|
||||||
|
String dbtText = StrUtil.blankToDefault(cardInfo.getString("dbtText"), "");
|
||||||
|
int dbtTextY = (resultImage.getHeight() / 2) + 200;
|
||||||
|
Font dbtFont = new Font("cursive", Font.BOLD, 24);
|
||||||
|
commonFont(resultImage, graphics, dbtText, dbtTextY, dbtFont, Color.WHITE);
|
||||||
|
|
||||||
|
response.setContentType("image/png");
|
||||||
|
ImageIO.write(resultImage, "png", response.getOutputStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
private NutMap getCardInfo() throws IOException {
|
||||||
|
Teacher_congress_session session = getCurrentSession();
|
||||||
|
if (session == null) {
|
||||||
|
throw new IOException("当前没有开启的教代会");
|
||||||
|
}
|
||||||
|
Teacher_congress_delegate delegate = getCurrentDelegate(session.getId());
|
||||||
|
if (delegate == null) {
|
||||||
|
throw new IOException("抱歉," + getSessionTitle(session) + "您不是代表");
|
||||||
|
}
|
||||||
|
Teacher_congress_delegation delegation = null;
|
||||||
|
if (StrUtil.isNotBlank(delegate.getDelegationId())) {
|
||||||
|
delegation = dao.fetch(Teacher_congress_delegation.class, delegate.getDelegationId());
|
||||||
|
}
|
||||||
|
NutMap nutMap = NutMap.NEW();
|
||||||
|
nutMap.put("title", getSessionTitle(session));
|
||||||
|
nutMap.put("nameText", StrUtil.blankToDefault(delegate.getUserName(), SecurityUtil.getUserUsername()));
|
||||||
|
nutMap.put("dbtText", delegation == null ? "" : StrUtil.blankToDefault(delegation.getName(), ""));
|
||||||
|
return nutMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Teacher_congress_session getCurrentSession() {
|
||||||
|
List<Teacher_congress_session> sessions = dao.query(Teacher_congress_session.class, Cnd.where("enable", "=", true)
|
||||||
|
.desc("startDate"));
|
||||||
|
if (Lang.isEmpty(sessions)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return sessions.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Teacher_congress_delegate getCurrentDelegate(String sessionId) {
|
||||||
|
List<String> roleIds = sysRoleService.getRoleIdsByCode(List.of(
|
||||||
|
RoleConstant.TEACHER_CONGRESS_DELEGATE_FORMAL,
|
||||||
|
RoleConstant.TEACHER_CONGRESS_DELEGATE_ATTENDANCE,
|
||||||
|
RoleConstant.TEACHER_CONGRESS_DELEGATE_SPECIALLY_INVITE
|
||||||
|
));
|
||||||
|
return dao.fetch(Teacher_congress_delegate.class, Cnd.where("sessionId", "=", sessionId)
|
||||||
|
.and("userId", "=", SecurityUtil.getUserId())
|
||||||
|
.and("roleId", "in", roleIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSessionTitle(Teacher_congress_session session) {
|
||||||
|
String fullName = StrUtil.blankToDefault(session.getFullName(), "");
|
||||||
|
if (fullName.contains("教代会")) {
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
return fullName + "教代会";
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage readBackgroundImage() throws IOException {
|
||||||
|
String fileId = getCardBackImgFileId();
|
||||||
|
if (StrUtil.isBlank(fileId)) {
|
||||||
|
throw new IOException("请先配置教代会代表证背景图片");
|
||||||
|
}
|
||||||
|
byte[] bytes = sysFileService.download(fileId);
|
||||||
|
BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes));
|
||||||
|
if (image == null) {
|
||||||
|
throw new IOException("教代会代表证背景图片读取失败");
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getCardBackImgFileId() {
|
||||||
|
String configValue = getConfigValue(CARD_BACK_IMG_CONFIG);
|
||||||
|
if (StrUtil.isBlank(configValue)) {
|
||||||
|
configValue = getConfigValue("cardBackImg");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(configValue)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String firstValue = StrUtil.subBefore(configValue, ",", false);
|
||||||
|
if (firstValue.contains("id=")) {
|
||||||
|
firstValue = StrUtil.subAfter(firstValue, "id=", true);
|
||||||
|
firstValue = StrUtil.subBefore(firstValue, "&", false);
|
||||||
|
}
|
||||||
|
return URLDecoder.decode(firstValue, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getConfigValue(String configKey) {
|
||||||
|
Sys_config config = dao.fetch(Sys_config.class, configKey);
|
||||||
|
return config == null ? "" : StrUtil.blankToDefault(config.getConfigValue(), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void commonFont(BufferedImage resultImage, Graphics2D graphics, String text, int textY, Font font, Color color) {
|
||||||
|
graphics.setFont(font);
|
||||||
|
graphics.setColor(color);
|
||||||
|
FontMetrics fontMetrics = graphics.getFontMetrics();
|
||||||
|
int textWidth = fontMetrics.stringWidth(text);
|
||||||
|
int textX = (resultImage.getWidth() - textWidth) / 2;
|
||||||
|
graphics.drawString(text, textX, textY);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -147,6 +147,18 @@ layout("/layouts/platform.html"){
|
|||||||
></file-upload>
|
></file-upload>
|
||||||
<span>最佳分辨率:750 x 280,节日福利页顶部图片</span>
|
<span>最佳分辨率:750 x 280,节日福利页顶部图片</span>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="formData.configKey === 'TeacherCongressCardBackImg'">
|
||||||
|
<file-upload
|
||||||
|
key="TeacherCongressCardBackImg"
|
||||||
|
style="--upload-width: 214px;--upload-height:300px"
|
||||||
|
:value.sync="formData.configValue"
|
||||||
|
:upload_number="1"
|
||||||
|
upload_mode="image"
|
||||||
|
upload_result_category="interval"
|
||||||
|
upload_result_type="url"
|
||||||
|
></file-upload>
|
||||||
|
<span>教代会代表证背景图片,通过文件上传配置</span>
|
||||||
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div v-if="'true'===formData.configValue||'false'===formData.configValue">
|
<div v-if="'true'===formData.configValue||'false'===formData.configValue">
|
||||||
<el-radio-group v-model="formData.configValue">
|
<el-radio-group v-model="formData.configValue">
|
||||||
|
|||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform_h5.html"){
|
||||||
|
#-->
|
||||||
|
<style>
|
||||||
|
.card-page {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
height: calc(100vh - 46px);
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0 24px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-page .van-button {
|
||||||
|
width: 184px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 17px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #1867b0;
|
||||||
|
border-color: #1867b0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-page .card-tip {
|
||||||
|
margin-top: 16px;
|
||||||
|
color: #969799;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="app" v-cloak>
|
||||||
|
<van-nav-bar title="代表证" left-arrow placeholder fixed
|
||||||
|
@click-left="historyBack"></van-nav-bar>
|
||||||
|
|
||||||
|
<div class="card-page">
|
||||||
|
<van-button type="info" @click="showCard">教代会代表证</van-button>
|
||||||
|
<div class="card-tip" v-if="tipMsg">{{ tipMsg }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
tipMsg: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async showCard() {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/platform/teacherCongress/delegate/card/isDb", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const resp = await response.json()
|
||||||
|
if (resp.code !== 0) {
|
||||||
|
this.tipMsg = resp.msg || "暂无教代会代表证"
|
||||||
|
vant.Dialog.alert({
|
||||||
|
title: "温馨提示",
|
||||||
|
message: this.tipMsg
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.tipMsg = ""
|
||||||
|
vant.ImagePreview(["/platform/teacherCongress/delegate/card/showCard?t=" + Date.now()])
|
||||||
|
} catch (e) {
|
||||||
|
this.tipMsg = "代表证信息获取失败"
|
||||||
|
vant.Dialog.alert({
|
||||||
|
title: "温馨提示",
|
||||||
|
message: this.tipMsg
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
Reference in New Issue
Block a user