feat: 代表团凭证
This commit is contained in:
@@ -105,7 +105,8 @@ public class SysConfController {
|
||||
if (conf == null || (!"AppHomeImg".equals(conf.getConfigKey())
|
||||
&& !"H5AppHomeImg".equals(conf.getConfigKey())
|
||||
&& !"AppFeaturedActivityImg".equals(conf.getConfigKey())
|
||||
&& !"AppFestivalBenefitImg".equals(conf.getConfigKey()))) {
|
||||
&& !"AppFestivalBenefitImg".equals(conf.getConfigKey())
|
||||
&& !"TeacherCongressCardBackImg".equals(conf.getConfigKey()))) {
|
||||
return;
|
||||
}
|
||||
String configValue = Strings.sNull(conf.getConfigValue());
|
||||
@@ -145,6 +146,7 @@ public class SysConfController {
|
||||
ensureAppImageConfig("H5AppHomeImg", "移动端首页轮播图");
|
||||
ensureAppImageConfig("AppFeaturedActivityImg", "精彩活动页顶部图片");
|
||||
ensureAppImageConfig("AppFestivalBenefitImg", "节日福利页顶部图片");
|
||||
ensureAppImageConfig("TeacherCongressCardBackImg", "教代会代表证背景图片");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (Strings.isNotBlank(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
|
||||
cnd.orderBy(pageOrderName, PageUtil.getOrder(pageOrderBy));
|
||||
|
||||
@@ -323,7 +323,7 @@ public class SysMenuController {
|
||||
public Object enable(String menuId, HttpServletRequest req) {
|
||||
try {
|
||||
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();
|
||||
sysUserService.clearCache();
|
||||
sysRoleService.clearCache();
|
||||
@@ -340,7 +340,7 @@ public class SysMenuController {
|
||||
public Object disable(String menuId, HttpServletRequest req) {
|
||||
try {
|
||||
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();
|
||||
sysUserService.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)));
|
||||
for (String s : menuIds) {
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
||||
if (!FileUtil.exist(file)) {
|
||||
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())) {
|
||||
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]
|
||||
// *
|
||||
// * 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>
|
||||
<span>最佳分辨率:750 x 280,节日福利页顶部图片</span>
|
||||
</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>
|
||||
<div v-if="'true'===formData.configValue||'false'===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