From 6a05f066176779a9676a8bb6101dd1daaed2fb5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BD=8A?= <23> Date: Tue, 23 Jun 2026 14:10:29 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B4=BB=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/common-association/pom.xml | 56 ++++-- .../AssociationActivitiesController.java | 109 +++++++++++ .../controller/ProjectListController.java | 38 +++- .../plugin/active/ActivitySchedulePlugin.java | 49 +++++ .../plugin/active/ActivitySignConfigPlugin.java | 153 +++++++++++++++ .../plugin/clueManage/ClueAuditOpPlugin.java | 1 - .../plugin/member/UnitNameChangeFormPlugin.java | 1 - .../plugin/member/UnitNameChangePopupPlugin.java | 109 +++++++---- .../plugin/quotation/ConfirmPlugin.java | 5 +- .../plugin/quotation/PopupGetIdPlugin.java | 1 + .../association/task/UserRenewalReminderTask.java | 73 +++++++ .../association/utils/DataTransformationUtil.java | 27 +++ .../java/apelet/association/utils/MyFileUtil.java | 211 +++++++++++++++++++++ .../java/apelet/association/utils/QRCodeUtil.java | 78 ++++++++ 14 files changed, 840 insertions(+), 71 deletions(-) create mode 100644 common/common-association/src/main/java/apelet/association/controller/AssociationActivitiesController.java create mode 100644 common/common-association/src/main/java/apelet/association/plugin/active/ActivitySchedulePlugin.java create mode 100644 common/common-association/src/main/java/apelet/association/plugin/active/ActivitySignConfigPlugin.java create mode 100644 common/common-association/src/main/java/apelet/association/task/UserRenewalReminderTask.java create mode 100644 common/common-association/src/main/java/apelet/association/utils/DataTransformationUtil.java create mode 100644 common/common-association/src/main/java/apelet/association/utils/MyFileUtil.java create mode 100644 common/common-association/src/main/java/apelet/association/utils/QRCodeUtil.java diff --git a/common/common-association/pom.xml b/common/common-association/pom.xml index d5df353..1b9cc10 100644 --- a/common/common-association/pom.xml +++ b/common/common-association/pom.xml @@ -29,26 +29,44 @@ - apelet - common-core - 1.0.0 - + apelet + common-core + 1.0.0 + - - apelet - common-generator - 1.0.0 - - - apelet - common-online - 1.0.0 - - - common-orm - apelet - 1.0.0 - + + apelet + common-generator + 1.0.0 + + + apelet + common-online + 1.0.0 + + + common-orm + apelet + 1.0.0 + + + + common-msg-notice + apelet + 1.0.0 + + + + + com.google.zxing + core + 3.5.1 + + + com.google.zxing + javase + 3.5.1 + apelet common-core diff --git a/common/common-association/src/main/java/apelet/association/controller/AssociationActivitiesController.java b/common/common-association/src/main/java/apelet/association/controller/AssociationActivitiesController.java new file mode 100644 index 0000000..4f635ad --- /dev/null +++ b/common/common-association/src/main/java/apelet/association/controller/AssociationActivitiesController.java @@ -0,0 +1,109 @@ +package apelet.association.controller; + +import apelet.association.utils.DataTransformationUtil; +import apelet.common.core.object.ObjectCollection; +import apelet.common.core.object.ObjectValue; +import apelet.common.core.object.ResponseResult; +import apelet.common.generator.utils.OrmGenDataSourceUtil; +import apelet.common.orm.impl.Filter; +import apelet.common.orm.impl.FilterItem; +import apelet.common.orm.impl.Selector; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/tenantadmin/activity") +public class AssociationActivitiesController { + + @Autowired + private OrmGenDataSourceUtil ormGenDataSourceUtil; + + /** + * 签到/签退 + * + * @param jsonObject + * @return + */ + @PostMapping("/checkInOut") + public ResponseResult activityCheckIn(@RequestBody JSONObject jsonObject) throws Exception { + String activityId = jsonObject.getString("activityId"); + String activityName = jsonObject.getString("activityName"); + if (StringUtils.isEmpty(activityId) || StringUtils.isEmpty(activityName)) { + return ResponseResult.error("500", "活动信息为空!!!"); + } + String signInPerson = jsonObject.getString("signInPerson"); + if (StringUtils.isEmpty(signInPerson)) { + return ResponseResult.error("500", "签到人为空!!!"); + } + String phoneNumber = jsonObject.getString("phoneNumber"); + if (StringUtils.isEmpty(phoneNumber)) { + return ResponseResult.error("500", "用户手机号为空!!!"); + } + + String signInUnit = jsonObject.getString("signInUnit"); + if (StringUtils.isEmpty(signInUnit)) { + return ResponseResult.error("500", "签到单位为空!!!"); + } + Integer type = jsonObject.getInteger("type"); + + Filter filter = new Filter(); + filter.add(new FilterItem("unit_name", FilterItem.equals, signInUnit)); + ObjectCollection collection = ormGenDataSourceUtil.query("membership_apply", filter, new Selector()); + + if (collection == null || collection.isEmpty()) { + return ResponseResult.error("500", "签到单位不存在, 请检查签到单位!!!"); + } + + ObjectCollection managerCollection = ormGenDataSourceUtil.query("membership_manager", new Filter(), new Selector()); + List> managerList = DataTransformationUtil.objectCollectionToList(managerCollection); + Map> mapMap = managerList.stream().collect(Collectors.toMap(map -> String.valueOf(map.get("id")), map -> map, (oldValue, newValue) -> oldValue)); + + ObjectValue member = null; + for (int i = 0; i < collection.size(); i++) { + ObjectValue object = collection.getObject(i); + ObjectValue manger = object.getObjectValue("membership_manger_id"); + Map map = mapMap.get(manger != null && manger.get("id") != null ? manger.get("id") : ""); + Object phone = map.get("phone"); + if (ObjectUtil.equal(phone, phoneNumber)) { + member = object; + } + } + if (member == null) { + return ResponseResult.error("500", signInUnit + " 签到单位下签到人不存在!!!"); + } + if (type == 1) { + //签到 + ObjectValue value = new ObjectValue("check_in_out"); + value.put("name", signInPerson); + value.put("phone", phoneNumber); + value.put("membership_id", member); + value.put("create_time", new Date()); + value.put("create_time", new Date()); + value.put("parent_id", activityId); + value.put("check_in", 1); + ormGenDataSourceUtil.addNew(value.getTableName(), value); + } + if (type == 2) { + //签退 + filter = new Filter(); + filter.add(new FilterItem("membership_id", FilterItem.equals, member.get("id"))); + filter.add(new FilterItem("parent_id", FilterItem.equals, activityId)); + filter.add(new FilterItem("check_in", FilterItem.equals, 1)); + collection = ormGenDataSourceUtil.query("check_in_out", filter, new Selector()); + if (collection != null && !collection.isEmpty()) { + ObjectValue object = collection.getObject(0); + object.put("check_out", 1); + ormGenDataSourceUtil.update("check_in_out", object, new Selector()); + } + } + return ResponseResult.success("签到成功!!!"); + } + + +} diff --git a/common/common-association/src/main/java/apelet/association/controller/ProjectListController.java b/common/common-association/src/main/java/apelet/association/controller/ProjectListController.java index 68dfbd2..47713f9 100644 --- a/common/common-association/src/main/java/apelet/association/controller/ProjectListController.java +++ b/common/common-association/src/main/java/apelet/association/controller/ProjectListController.java @@ -1,12 +1,16 @@ package apelet.association.controller; +import apelet.association.utils.QRCodeUtil; import apelet.common.core.annotation.MyRequestBody; -import apelet.common.core.object.MyPageParam; +import apelet.common.core.annotation.NoAuthInterface; import apelet.common.core.object.ResponseResult; -import apelet.common.core.object.TokenData; -import com.github.pagehelper.page.PageMethod; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.Map; @@ -15,18 +19,42 @@ import java.util.Map; @RequestMapping("/tenantadmin/project") public class ProjectListController { + @Autowired + private QRCodeUtil qrCodeUtil; + + @GetMapping(value = "/list") public ResponseResult list() { - Map pammap= new HashMap<>(); + Map pammap = new HashMap<>(); return ResponseResult.success(pammap); } @PostMapping("/update") public ResponseResult update( - @MyRequestBody String entryId){ + @MyRequestBody String entryId) { return ResponseResult.success(null); } + /** + * 生成二维码接口 + */ + @GetMapping("/qrcode") + @NoAuthInterface + public ResponseEntity getQRCode(@RequestParam String content, HttpServletResponse response) { + try { + byte[] bytes = qrCodeUtil.generateQrCode(content, 300, 300); + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "image/png"); + return new ResponseEntity<>(bytes, headers, HttpStatus.OK); + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.internalServerError().build(); + } + + + } + + } diff --git a/common/common-association/src/main/java/apelet/association/plugin/active/ActivitySchedulePlugin.java b/common/common-association/src/main/java/apelet/association/plugin/active/ActivitySchedulePlugin.java new file mode 100644 index 0000000..b17e969 --- /dev/null +++ b/common/common-association/src/main/java/apelet/association/plugin/active/ActivitySchedulePlugin.java @@ -0,0 +1,49 @@ +package apelet.association.plugin.active; + +import apelet.common.core.exception.MyRuntimeException; +import apelet.common.core.object.ObjectValue; +import apelet.common.core.util.ApplicationContextHolder; +import apelet.common.generator.utils.OrmGenDataSourceUtil; +import apelet.common.online.abstractplugin.ListPlugin; +import apelet.common.online.dto.OnlineEventPluginExecuteDto; +import apelet.common.online.model.constant.AttributeEnum; +import apelet.common.orm.impl.Selector; + +/** + * 活动日程插件 + */ +public class ActivitySchedulePlugin extends ListPlugin { + + private OrmGenDataSourceUtil ormGenDataSourceUtil; + + public ActivitySchedulePlugin() { + ormGenDataSourceUtil = ApplicationContextHolder.getBean(OrmGenDataSourceUtil.class); + } + + + @Override + public void formCreated(String widgetVariableName, ObjectValue objectValue) { + OnlineEventPluginExecuteDto dto = getDto(); + this.setWidgetAttribute("id", AttributeEnum.SHOW, false); + + } + + @Override + public void change(String widgetVariableName, ObjectValue objectValue) { + + } + + @Override + public void buttonTriggered(String widgetVariableName, ObjectValue objectValue) { + if ("保存".equals(widgetVariableName)) { + try { + ObjectValue value = ormGenDataSourceUtil.queryOne("association_activity", objectValue.get("id")); + value.put("activity_schedule", objectValue.getObjectCollection("activity_schedule")); + ormGenDataSourceUtil.update("association_activity", value, new Selector()); + } catch (Exception e) { + throw new MyRuntimeException(e.getMessage()); + } + this.cancelOperate(); + } + } +} diff --git a/common/common-association/src/main/java/apelet/association/plugin/active/ActivitySignConfigPlugin.java b/common/common-association/src/main/java/apelet/association/plugin/active/ActivitySignConfigPlugin.java new file mode 100644 index 0000000..31ed774 --- /dev/null +++ b/common/common-association/src/main/java/apelet/association/plugin/active/ActivitySignConfigPlugin.java @@ -0,0 +1,153 @@ +package apelet.association.plugin.active; + +import apelet.association.utils.MyFileUtil; +import apelet.association.utils.QRCodeUtil; +import apelet.common.core.exception.MyRuntimeException; +import apelet.common.core.object.*; +import apelet.common.core.upload.*; +import apelet.common.core.util.ApplicationContextHolder; +import apelet.common.generator.utils.OrmGenDataSourceUtil; +import apelet.common.online.abstractplugin.ListPlugin; +import apelet.common.online.dto.OnlineEventPluginExecuteDto; +import apelet.common.online.model.OnlineDatasource; +import apelet.common.online.model.OnlineTable; +import apelet.common.online.model.constant.AttributeEnum; +import apelet.common.online.service.OnlineColumnService; +import apelet.common.online.service.OnlineDatasourceService; +import apelet.common.online.service.OnlineTableService; +import apelet.common.orm.impl.*; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; + +/** + * 活动签到配置插件 + */ + +@Slf4j +public class ActivitySignConfigPlugin extends ListPlugin { + + private MyFileUtil myFileUtil; + private QRCodeUtil qrCodeUtil; + + private OnlineTableService onlineTableService; + private OnlineColumnService onlineColumnService; + private OrmGenDataSourceUtil ormGenDataSourceUtil; + + + private OnlineDatasourceService onlineDatasourceService; + + + public ActivitySignConfigPlugin() { + myFileUtil = ApplicationContextHolder.getBean(MyFileUtil.class); + qrCodeUtil = ApplicationContextHolder.getBean(QRCodeUtil.class); + onlineTableService = ApplicationContextHolder.getBean(OnlineTableService.class); + onlineColumnService = ApplicationContextHolder.getBean(OnlineColumnService.class); + ormGenDataSourceUtil = ApplicationContextHolder.getBean(OrmGenDataSourceUtil.class); + onlineDatasourceService = ApplicationContextHolder.getBean(OnlineDatasourceService.class); + } + + + @Override + public void formCreated(String widgetVariableName, ObjectValue objectValue) { + OnlineEventPluginExecuteDto dto = getDto(); + Map parentParams = dto.getParentParams(); + Object activityId = parentParams.get("id"); + this.setWidgetAttribute("activityId", AttributeEnum.VALUE_CHANGE, parentParams); + Filter filter = new Filter(); + filter.add(new FilterItem("activity_id", FilterItem.equals, activityId)); + Object data = ormGenDataSourceUtil.queryData("orm", "activity_sign_config", filter, new Selector(), new Sorter(), new HashMap<>()); + if (data instanceof ObjectCollection) { + ObjectCollection collection = (ObjectCollection) data; + ObjectValue object = collection.getObject(0); + this.setWidgetAttribute("id", AttributeEnum.VALUE_CHANGE, object.get("id")); + + this.setWidgetAttribute("checkAction", AttributeEnum.VALUE_CHANGE, object.get("check_action")); + + this.setWidgetAttribute("scanCheck", AttributeEnum.VALUE_CHANGE, object.getInt("scan_check")); + this.setWidgetAttribute("positionLimit", AttributeEnum.VALUE_CHANGE, object.getInt("position_limit")); + this.setWidgetAttribute("duplicateCheck", AttributeEnum.VALUE_CHANGE, object.getInt("duplicate_check")); + this.setWidgetAttribute("scanCodeReview", AttributeEnum.VALUE_CHANGE, object.getInt("scan_code_review")); + this.setWidgetAttribute("checkCertificate", AttributeEnum.VALUE_CHANGE, object.getInt("id")); + + try { + JSONObject signInCode = JSON.parseObject(object.getString("sign_in_code")); + this.setWidgetAttribute("signInCode", AttributeEnum.VALUE_CHANGE, signInCode); + + JSONObject signOutCode = JSON.parseObject(object.getString("sign_out_code")); + this.setWidgetAttribute("signOutCode", AttributeEnum.VALUE_CHANGE, signOutCode); + } catch (Exception ee) { + log.error("二维码数据转换失败!!!"); + ee.printStackTrace(); + } + + } + this.setWidgetAttribute("id", AttributeEnum.SHOW, false); + this.setWidgetAttribute("activityId", AttributeEnum.SHOW, false); + } + + + @Override + public void buttonTriggered(String widgetVariableName, ObjectValue objectValue) { + OnlineEventPluginExecuteDto dto = getDto(); + Model model = dto.getModel(); + if ("button1778742711763".equals(widgetVariableName)) { + + if (StringUtils.isNotBlank(objectValue.getString("sign_in_code")) && + StringUtils.isNotBlank(objectValue.getString("sign_out_code"))) { + showWarningMessage("当前已存在二维码, 请勿重复生产!!!"); + return; + } + // 生成二维码 + String savePath = System.getProperty("user.dir") + "\\zz-resource\\qrcode"; + + File checkOutFile; + File checkInFile; + try { + Object activityId = objectValue.get("id"); + Object activityName = objectValue.get("name"); + + OnlineDatasource onlineDatasource = onlineDatasourceService.getById(model.getDatasourceId()); + OnlineTable table = onlineTableService.getOnlineTableFromCache(onlineDatasource.getMasterTableId()); + + String checkIn = "https://localhost:8080/#/pages/login/routerHdView?activityId=" + activityId + "&activityName=" + activityName + "&type=" + 1; + byte[] checkInQr = qrCodeUtil.generateQrCode(checkIn, 350, 350); + checkInFile = MyFileUtil.writeToFile(checkInQr, savePath, "qrcode-" + System.currentTimeMillis() + ".png"); + MultipartFile checkInMultipart = MyFileUtil.readFileAsMultipartFile(checkInFile, "image/png"); + UploadResponseInfo checkInUpload = myFileUtil.uploadMyFile(table, "sign_in_code", true, checkInMultipart); + this.setWidgetAttribute("signInCode", AttributeEnum.VALUE_CHANGE, checkInUpload); + + String checkOut = "https://localhost:8080/#/pages/login/routerHdView?activityId=" + activityId + "&activityName=" + activityName + "&type=" + 2; + byte[] checkOutQr = qrCodeUtil.generateQrCode(checkOut, 300, 300); + checkOutFile = MyFileUtil.writeToFile(checkOutQr, savePath, "qrcode-" + System.currentTimeMillis() + ".png"); + MultipartFile checkOutMultipart = MyFileUtil.readFileAsMultipartFile(checkOutFile, "image/png"); + UploadResponseInfo checkOutUpload = myFileUtil.uploadMyFile(table, "sign_out_code", true, checkOutMultipart); + this.setWidgetAttribute("signOutCode", AttributeEnum.VALUE_CHANGE, checkOutUpload); + } catch (Exception e) { + e.printStackTrace(); + throw new MyRuntimeException("二维码生成失败, 请联系管理员!!!"); + } finally { + try { + FileUtils.cleanDirectory(new File(savePath)); + } catch (IOException e) { + e.printStackTrace(); + System.err.println("文件刪除失敗!!!"); + } + } + } + } + + @Override + public void change(String widgetVariableName, ObjectValue objectValue) { + super.formCreated(widgetVariableName, objectValue); + } + + +} diff --git a/common/common-association/src/main/java/apelet/association/plugin/clueManage/ClueAuditOpPlugin.java b/common/common-association/src/main/java/apelet/association/plugin/clueManage/ClueAuditOpPlugin.java index 983df77..044d2e9 100644 --- a/common/common-association/src/main/java/apelet/association/plugin/clueManage/ClueAuditOpPlugin.java +++ b/common/common-association/src/main/java/apelet/association/plugin/clueManage/ClueAuditOpPlugin.java @@ -5,7 +5,6 @@ import apelet.common.core.object.ObjectValue; import apelet.common.core.util.ApplicationContextHolder; import apelet.common.generator.utils.OrmGenDataSourceUtil; import apelet.common.online.plugin.BeginOperationTransactionArgs; -import apelet.common.online.plugin.OperationResult; import apelet.common.online.plugin.OperationServicePlugIn; import apelet.common.online.plugin.OperationServicePlugInArgs; import apelet.common.online.service.impl.OnlineFormServiceImpl; diff --git a/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangeFormPlugin.java b/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangeFormPlugin.java index fe7fa12..9a91672 100644 --- a/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangeFormPlugin.java +++ b/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangeFormPlugin.java @@ -2,7 +2,6 @@ package apelet.association.plugin.member; import apelet.common.core.object.ObjectValue; import apelet.common.online.abstractplugin.ExecutePluginParent; -import apelet.common.online.model.constant.AttributeEnum; /** * @ClassName: UnitNameChangeFormPlugin diff --git a/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangePopupPlugin.java b/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangePopupPlugin.java index 9f9af31..abb56d7 100644 --- a/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangePopupPlugin.java +++ b/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangePopupPlugin.java @@ -1,12 +1,20 @@ package apelet.association.plugin.member; +import apelet.common.core.exception.MyRuntimeException; import apelet.common.core.object.ObjectValue; -import apelet.common.online.abstractplugin.ExecutePluginParent; +import apelet.common.core.util.ApplicationContextHolder; +import apelet.common.generator.utils.OrmGenDataSourceUtil; +import apelet.common.online.abstractplugin.ListPlugin; +import apelet.common.online.dto.OnlineEventPluginExecuteDto; import apelet.common.online.model.ShowParameter; import apelet.common.online.model.constant.ShowTypeEnum; import apelet.common.online.model.constant.ViewStatus; +import apelet.common.orm.impl.Filter; +import apelet.common.orm.impl.FilterItem; +import apelet.common.orm.impl.Selector; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -16,22 +24,19 @@ import java.util.Map; * @Description: 入会申请与审核 - 变更单位名称弹窗插件 * 点击"变更"按钮时,弹出入会申请表单,并将列表中选中行数据带入弹窗中 */ -public class UnitNameChangePopupPlugin extends ExecutePluginParent { +public class UnitNameChangePopupPlugin extends ListPlugin { + + private OrmGenDataSourceUtil ormGenDataSourceUtil; + + public UnitNameChangePopupPlugin() { + ormGenDataSourceUtil = ApplicationContextHolder.getBean(OrmGenDataSourceUtil.class); + } /** * 目标表单ID - membership_apply 表单在平台中的表单ID */ private static final String TARGET_FORM_ID = "2048951917157027840"; - /** - * 触发按钮的标识 - 对应表单上按钮的 key/标识 - */ - private static final String BUTTON_KEY = "变更"; - - /** - * 列表页面中表格控件的变量名/key - */ - private static final String TABLE_WIDGET_KEY = "table1777354992881"; /** * 传递到弹窗的参数key - 单据ID @@ -43,53 +48,75 @@ public class UnitNameChangePopupPlugin extends ExecutePluginParent { */ private static final String PARAM_BILL_NUMBER = "sourceBillNumber"; + + @Override + protected Filter getFilter() { + Filter filter = new Filter(); + filter.add(new FilterItem("deleted_flag", FilterItem.equals, "1")); + return filter; + } + /** * 按钮点击事件(列表按钮) * 点击"变更"按钮时,通过 getSelectData 获取列表中选中行的单据数据, * 以弹窗方式打开入会申请表单,并将选中行数据带入 * - * @param buttonKey 按钮标识 + * @param buttonKey 按钮标识 * @param objectValue 列表按钮事件数据对象(非表单数据) */ @Override public void buttonTriggered(String buttonKey, ObjectValue objectValue) { - // 仅响应"变更"按钮的点击事件 - if (!BUTTON_KEY.equals(buttonKey)) { - return; - } - - // 【列表场景】通过框架提供的 getSelectData 方法获取选中/点击行的数据 - // objectValue 中的 rowdata 包含列表所有行,getSelectData 会找到 - // 标记了 isClick=true(点击行)或 isSelect=true(勾选行)的那一行 - Map selectedRow = getSelectData(objectValue, TABLE_WIDGET_KEY); - - if (selectedRow == null) { + OnlineEventPluginExecuteDto dto = getDto(); + List rowDatas = dto.getModel().getRowDatas(); + if (rowDatas == null || rowDatas.size() != 1) { showWarningMessage("请先在列表中选中一条单据"); + this.cancelOperate(); return; } + Map data = rowDatas.get(0); + if ("变更".equals(buttonKey)) { + // 调用 showForm 打开入会申请表单(新建空表单,不加载任何已有记录) + ShowParameter showParameter = new ShowParameter(); + showParameter.setFormId(TARGET_FORM_ID); + showParameter.setHowType(ShowTypeEnum.OPEN_ONLINE_MODAL); + showParameter.setStatus(ViewStatus.EDIT); + showParameter.setPkId(null); // 明确指定为空,表示新建表单而非打开已有单据 + // 设置自定义参数,用于在目标表单中获取源单据数据 + Map customParam = new HashMap<>(); + customParam.put(PARAM_BILL_ID, data.get("id")); + customParam.put(PARAM_BILL_NUMBER, data.get("number")); + showParameter.setCustomParam(customParam); + super.showForm(showParameter); + } - // 从选中行中获取单据ID和编号 - String billId = selectedRow.get("id") != null ? selectedRow.get("id").toString() : ""; - String billNumber = selectedRow.get("number") != null ? selectedRow.get("number").toString() : ""; - - if (billId.isEmpty()) { - showWarningMessage("选中的单据缺少ID信息,请重新选择"); + if ("退会".equals(buttonKey)) { + this.showConfirm("withdrawal", "确定是否退出协会?"); + this.cancelOperate(); return; } - // 调用 showForm 打开入会申请表单(新建空表单,不加载任何已有记录) - ShowParameter showParameter = new ShowParameter(); - showParameter.setFormId(TARGET_FORM_ID); - showParameter.setHowType(ShowTypeEnum.OPEN_ONLINE_MODAL); - showParameter.setStatus(ViewStatus.EDIT); - showParameter.setPkId(null); // 明确指定为空,表示新建表单而非打开已有单据 + } + - // 设置自定义参数,用于在目标表单中获取源单据数据 - Map customParam = new HashMap<>(); - customParam.put(PARAM_BILL_ID, billId); - customParam.put(PARAM_BILL_NUMBER, billNumber); - showParameter.setCustomParam(customParam); + @Override + public void confirmCallBack(String widgetVariableName, ObjectValue objectValue) { + if (widgetVariableName.equals("withdrawal")) {//confirmid + Map clickResult = (Map) this.getDto().getEventObject(); + if ((Integer) clickResult.get("result") == 1) {//confirm + Map data = getDto().getModel().getRowDatas().get(0); + Object id = data.get("id"); + ObjectValue value = ormGenDataSourceUtil.queryOne("membership_apply", id); + value.put("deleted_flag", "0"); + value.put("billstatus", "0"); + try { + ormGenDataSourceUtil.update("membership_apply", value, new Selector()); + } catch (Exception e) { + throw new MyRuntimeException(e.getMessage()); + } + } else {//取消 + this.cancelOperate();//取消操作 + } + } - super.showForm(showParameter); } } diff --git a/common/common-association/src/main/java/apelet/association/plugin/quotation/ConfirmPlugin.java b/common/common-association/src/main/java/apelet/association/plugin/quotation/ConfirmPlugin.java index d186eb5..287f611 100644 --- a/common/common-association/src/main/java/apelet/association/plugin/quotation/ConfirmPlugin.java +++ b/common/common-association/src/main/java/apelet/association/plugin/quotation/ConfirmPlugin.java @@ -8,10 +8,7 @@ import apelet.common.online.plugin.BeginOperationTransactionArgs; import apelet.common.online.plugin.OperationServicePlugIn; import apelet.common.online.plugin.OperationServicePlugInArgs; import apelet.common.online.service.impl.OnlineFormServiceImpl; -import apelet.common.orm.impl.Filter; -import apelet.common.orm.impl.FilterItem; -import apelet.common.orm.impl.Selector; -import apelet.common.orm.impl.SelectorItem; +import apelet.common.orm.impl.*; /* 弹窗确认后,保存数据库 diff --git a/common/common-association/src/main/java/apelet/association/plugin/quotation/PopupGetIdPlugin.java b/common/common-association/src/main/java/apelet/association/plugin/quotation/PopupGetIdPlugin.java index 97f0f1c..a222136 100644 --- a/common/common-association/src/main/java/apelet/association/plugin/quotation/PopupGetIdPlugin.java +++ b/common/common-association/src/main/java/apelet/association/plugin/quotation/PopupGetIdPlugin.java @@ -6,6 +6,7 @@ import apelet.common.online.dto.OnlineEventPluginExecuteDto; import apelet.common.online.model.constant.AttributeEnum; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; + import java.util.Collection; import java.util.Map; diff --git a/common/common-association/src/main/java/apelet/association/task/UserRenewalReminderTask.java b/common/common-association/src/main/java/apelet/association/task/UserRenewalReminderTask.java new file mode 100644 index 0000000..31fe821 --- /dev/null +++ b/common/common-association/src/main/java/apelet/association/task/UserRenewalReminderTask.java @@ -0,0 +1,73 @@ +package apelet.association.task; + + +import apelet.common.core.object.ObjectCollection; +import apelet.common.core.object.ObjectValue; +import apelet.common.generator.utils.OrmGenDataSourceUtil; +import apelet.common.orm.impl.Filter; +import apelet.common.orm.impl.Selector; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.Date; + +@Component +public class UserRenewalReminderTask { + + @Autowired + OrmGenDataSourceUtil ormGenDataSourceUtil; + + // 提前 30 天提醒 + private static final int REMIND_BEFORE_DAYS = 30; + // 会员年度天数(固定 365) + private static final int YEAR_DAYS = 365; + + @Scheduled(cron = "0 0 1 * * ?") + public void sendRemind(){ + ObjectCollection collection = ormGenDataSourceUtil.query("membership_apply", new Filter(), new Selector()); + if(collection == null){ + return; + } + for (int i = 0; i < collection.size(); i++) { + ObjectValue objectValue = collection.getObject(i); + Date registTime = objectValue.getDate("regist_time"); + if (needRemind(registTime)) { + // TODO 发送消息提示续费 + + } + + } + + + } + + + public boolean needRemind(Date date) { + LocalDate today = LocalDate.now(); + LocalDate join = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + + if (today.isBefore(join)) { + return false; + } + // 入会到今天总天数 + long totalDays = ChronoUnit.DAYS.between(join, today); + + // 第几个年度(从 1 开始) + int yearIndex = (int) (totalDays / YEAR_DAYS) + 1; + + // 该年度到期日 + LocalDate expireDate = join.plusDays((long) YEAR_DAYS * yearIndex); + + // 提醒开始日:到期前 30 天 + LocalDate remindStart = expireDate.minusDays(REMIND_BEFORE_DAYS); + + // 今天在 [remindStart, expireDate] 区间内,则提醒 + return !today.isBefore(remindStart) && !today.isAfter(expireDate); + } + + +} diff --git a/common/common-association/src/main/java/apelet/association/utils/DataTransformationUtil.java b/common/common-association/src/main/java/apelet/association/utils/DataTransformationUtil.java new file mode 100644 index 0000000..ccb8544 --- /dev/null +++ b/common/common-association/src/main/java/apelet/association/utils/DataTransformationUtil.java @@ -0,0 +1,27 @@ +package apelet.association.utils; + +import apelet.common.core.object.ObjectCollection; +import apelet.common.core.object.ObjectValue; +import com.alibaba.fastjson.JSONObject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class DataTransformationUtil { + + public static List> objectCollectionToList(ObjectCollection oc) { + + List> list = new ArrayList<>(); + if(oc == null || oc.isEmpty()){ + return list; + } + for (int i = 0; i < oc.size(); i++) { + ObjectValue object = oc.getObject(i); + JSONObject jsonObject = new JSONObject(object.getValues()); + list.add(jsonObject); + } + return list; + } + +} diff --git a/common/common-association/src/main/java/apelet/association/utils/MyFileUtil.java b/common/common-association/src/main/java/apelet/association/utils/MyFileUtil.java new file mode 100644 index 0000000..db6f8a1 --- /dev/null +++ b/common/common-association/src/main/java/apelet/association/utils/MyFileUtil.java @@ -0,0 +1,211 @@ +package apelet.association.utils; + +import apelet.common.core.constant.ErrorCodeEnum; +import apelet.common.core.object.ResponseResult; +import apelet.common.core.upload.*; +import apelet.common.online.config.OnlineProperties; +import apelet.common.online.model.OnlineColumn; +import apelet.common.online.model.OnlineTable; +import apelet.common.online.model.constant.FieldKind; + +import liquibase.util.BooleanUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.nio.file.*; + +@Component +public class MyFileUtil { + + @Autowired + private UpDownloaderFactory upDownloaderFactory; + + @Autowired + private OnlineProperties onlineProperties; + + + public UploadResponseInfo uploadMyFile(OnlineTable table, String fieldName, Boolean asImg, MultipartFile multipartFile) throws IOException { + ResponseResult verifyResult = this.doVerifyUpDownloadFileColumn(table, fieldName, asImg); + OnlineColumn uploadColumn = verifyResult.getData(); + UploadStoreTypeEnum uploadStoreType = UploadStoreTypeEnum.values()[uploadColumn.getUploadFileSystemType()]; + BaseUpDownloader upDownloader = upDownloaderFactory.get(uploadStoreType); + return upDownloader.doUpload(null, onlineProperties.getUploadFileBaseDir(), table.getModelName(), fieldName, asImg, multipartFile); + } + + + public static MultipartFile createMultipartFile(String filePath, String fileName) { + Path path = Paths.get(filePath); + return new MultipartFile() { + @Override + public String getName() { + return fileName; + } + + @Override + public String getOriginalFilename() { + return fileName; + } + + @Override + public String getContentType() { + try { + return Files.probeContentType(path); + } catch (IOException e) { + return MediaType.APPLICATION_OCTET_STREAM_VALUE; + } + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public long getSize() { + try { + return Files.size(path); + } catch (IOException e) { + return 0; + } + } + + @Override + public byte[] getBytes() throws IOException { + return Files.readAllBytes(path); + } + + @Override + public InputStream getInputStream() throws IOException { + return Files.newInputStream(path); + } + + @Override + public void transferTo(File dest) throws IOException { + Files.copy(path, dest.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + }; + } + + + public static void saveFileToLocal(byte[] qrCodeByte, String savePath, String fileName) throws IOException { + // 1. 创建文件夹 + File folder = new File(savePath); + if (!folder.exists()) { + folder.mkdirs(); + } + // 2. 最终文件 + File file = new File(folder, fileName); + // 3. 写入文件(try-with-resources 会自动关闭流,最安全) + try (FileOutputStream fos = new FileOutputStream(file); + ByteArrayInputStream bais = new ByteArrayInputStream(qrCodeByte)) { + byte[] buffer = new byte[1024]; + int len; + while ((len = bais.read(buffer)) != -1) { + fos.write(buffer, 0, len); + } + fos.flush(); + } + } + + private ResponseResult doVerifyUpDownloadFileColumn( + OnlineTable table, String fieldName, Boolean asImage) { + OnlineColumn column = null; + for (OnlineColumn c : table.getColumnMap().values()) { + if (c.getColumnName().equals(fieldName)) { + column = c; + break; + } + } + if (column == null) { + return ResponseResult.error(ErrorCodeEnum.INVALID_DATA_FIELD); + } + if (BooleanUtil.isTrue(asImage)) { + if (column.getFieldKind() != FieldKind.UPLOAD_IMAGE) { + return ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD); + } + } else { + if (column.getFieldKind() != FieldKind.UPLOAD) { + return ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD); + } + } + return ResponseResult.success(column); + } + + + public static File writeToFile(byte[] qrBytes, String dirPath, String fileName) throws IOException { + Path dir = Paths.get(dirPath); + if (!Files.exists(dir)) { + Files.createDirectories(dir); + } + Path filePath = dir.resolve(fileName); + try (FileOutputStream fos = new FileOutputStream(filePath.toFile())) { + fos.write(qrBytes); + } + return filePath.toFile(); + } + + + public static MultipartFile readFileAsMultipartFile(File file, String contentType) throws IOException { + return new CustomMultipartFile(file, contentType); + } + + // ==================== 步骤3:获取 InputStream ==================== + public static InputStream getInputStream(MultipartFile multipartFile) throws IOException { + return multipartFile.getInputStream(); + } + + // ==================== 自定义 MultipartFile 实现 ==================== + public static class CustomMultipartFile implements MultipartFile { + + private final File file; + private final String contentType; + + public CustomMultipartFile(File file, String contentType) { + this.file = file; + this.contentType = contentType; + } + + @Override + public String getName() { + return file.getName(); + } + + @Override + public String getOriginalFilename() { + return file.getName(); + } + + @Override + public String getContentType() { + return contentType; + } + + @Override + public boolean isEmpty() { + return file.length() == 0; + } + + @Override + public long getSize() { + return file.length(); + } + + @Override + public byte[] getBytes() throws IOException { + return Files.readAllBytes(file.toPath()); + } + + @Override + public InputStream getInputStream() throws IOException { + return new FileInputStream(file); + } + + @Override + public void transferTo(File dest) throws IOException { + Files.copy(file.toPath(), dest.toPath()); + } + } +} diff --git a/common/common-association/src/main/java/apelet/association/utils/QRCodeUtil.java b/common/common-association/src/main/java/apelet/association/utils/QRCodeUtil.java new file mode 100644 index 0000000..c1dd83c --- /dev/null +++ b/common/common-association/src/main/java/apelet/association/utils/QRCodeUtil.java @@ -0,0 +1,78 @@ +package apelet.association.utils; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import lombok.var; +import org.springframework.stereotype.Component; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; + +@Component +public class QRCodeUtil { + + + /** + * 生成二维码并直接输出到响应流中 + * + * @param url 扫码后要跳转的网址 + * @param response HTTP响应 + */ + public void generateQRCode(String url, HttpServletResponse response) { + try { + // 设置响应类型为图片 + response.setContentType("image/png"); + OutputStream os = response.getOutputStream(); + + // 二维码参数配置 + Map hints = new HashMap<>(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 防止中文乱码 + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 高容错率(30%) + hints.put(EncodeHintType.MARGIN, 1); // 白边宽度 + + // 生成二维码矩阵 (宽350,高350) + BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 350, 350, hints); + + // 将矩阵转换成图片并输出 + MatrixToImageWriter.writeToStream(bitMatrix, "PNG", os); + + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("生成二维码失败"); + } + } + + + + /** + * 生成二维码字节流(可直接返回给前端) + * @param content 二维码内容:即你的网页 URL + * @param width 宽度 + * @param height 高度 + * @return 图片字节数组 + */ + public byte[] generateQrCode(String content, int width, int height) throws Exception { + Map hints = new HashMap<>(); + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + // 缩小白边(可选) + hints.put(EncodeHintType.MARGIN, 1); + QRCodeWriter writer = new QRCodeWriter(); + var bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints); + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "PNG", baos); + return baos.toByteArray(); + } +} \ No newline at end of file