From 1305b2f13e256681c62203fa2b8b8870d4e4be28 Mon Sep 17 00:00:00 2001
From: huangdehua <2329023417@qq.com>
Date: Tue, 11 Aug 2026 18:07:00 +0800
Subject: [PATCH 1/6] =?UTF-8?q?=E4=BC=9A=E5=91=98=E5=8F=98=E6=9B=B4?=
=?UTF-8?q?=E4=BF=9D=E5=AD=98=E6=97=B6=E9=87=8D=E6=96=B0=E7=94=9F=E6=88=90?=
=?UTF-8?q?=E5=8D=95=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../association/plugin/member/UnitNameChangeFormInitPlugin.java | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangeFormInitPlugin.java b/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangeFormInitPlugin.java
index 2d9dd7c..e9781c8 100644
--- a/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangeFormInitPlugin.java
+++ b/common/common-association/src/main/java/apelet/association/plugin/member/UnitNameChangeFormInitPlugin.java
@@ -6,6 +6,7 @@ import apelet.common.generator.utils.OrmGenDataSourceUtil;
import apelet.common.online.abstractplugin.ExecutePluginParent;
import apelet.common.online.model.constant.AttributeEnum;
import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.List;
@@ -98,6 +99,7 @@ public class UnitNameChangeFormInitPlugin extends ExecutePluginParent {
// 获取源单据ID
String sourceBillId = getSourceBillId(objectValue);
String sourceBillNumber = getSourceBillNumber(objectValue);
+ this.setWidgetAttribute("history",AttributeEnum.VALUE_CHANGE, "0");
// 如果没有源单据ID,说明不是变更操作,正常返回
if (sourceBillId == null || sourceBillId.isEmpty()) {
@@ -147,6 +149,10 @@ public class UnitNameChangeFormInitPlugin extends ExecutePluginParent {
if (sourceBillId == null || sourceBillId.trim().isEmpty()) {
sourceBillId = objectValue.getString(PARAM_BILL_ID_ALT);
}
+ Object idObj = objectValue.get("id");
+ if (idObj != null && !Integer.valueOf(0).equals(idObj)) {
+ return false;
+ }
return sourceBillId != null && !sourceBillId.trim().isEmpty();
}
@@ -166,6 +172,7 @@ public class UnitNameChangeFormInitPlugin extends ExecutePluginParent {
}
newBill.put(getDbFieldKey(key), entry.getValue());
}
+ newBill.put("history", "0");
ObjectCollection detailEntry = copyEntryForManualSave(objectValue.getObjectCollection(CHILD_WIDGET_KEY));
if (detailEntry != null && !detailEntry.isEmpty()) {
From 37a31d6f4c68e06feb2fc875fe4dc3be761c6d3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=BD=8A?= <23>
Date: Thu, 13 Aug 2026 11:14:32 +0800
Subject: [PATCH 2/6] =?UTF-8?q?=E6=8F=90=E4=BA=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
application-tenant/tenant-admin/pom.xml | 4 +-
.../java/apelet/tenantadmin/config/CorsConfig.java | 16 +++
.../upms/controller/LoginController.java | 30 ++----
.../src/main/resources/application-config.yml | 2 +-
.../src/main/resources/tenant-admin-dev.yml | 8 +-
common/common-association/pom.xml | 6 +-
.../apelet/association/config/FrontendConfig.java | 16 +++
.../controller/DoPracticeProblemsController.java | 21 +++-
.../association/controller/HomeController.java | 71 +++++++++++++
.../apelet/association/dto/UserExerciseDto.java | 12 +--
.../plugin/active/ActivityInfoDetailsPlugin.java | 110 +++++++++++++++++++++
.../active/ActivityRegistrationSavePlugin.java | 15 +++
.../active/ActivityRegistrationUpdatePlugin.java | 98 ++++++++++++++++++
.../plugin/active/ActivitySignConfigPlugin.java | 16 +--
.../plugin/active/CompetitionDetailsPlugin.java | 7 +-
.../plugin/member/MembershipFeePayPlugin.java | 72 ++++++++++++++
.../plugin/member/MembershipPayPopupPlugin.java | 29 +++---
.../plugin/member/UnitNameChangePopupPlugin.java | 25 +++++
.../plugin/question/QuestionBankListPlugin.java | 6 +-
.../task/ContractPaymentReminderTask.java | 30 ++++++
.../association/task/UserRenewalReminderTask.java | 68 ++++++-------
common/common-qy/pom.xml | 4 +-
pom.xml | 2 +-
23 files changed, 559 insertions(+), 109 deletions(-)
create mode 100644 application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/CorsConfig.java
create mode 100644 common/common-association/src/main/java/apelet/association/config/FrontendConfig.java
create mode 100644 common/common-association/src/main/java/apelet/association/controller/HomeController.java
create mode 100644 common/common-association/src/main/java/apelet/association/plugin/active/ActivityInfoDetailsPlugin.java
create mode 100644 common/common-association/src/main/java/apelet/association/plugin/active/ActivityRegistrationSavePlugin.java
create mode 100644 common/common-association/src/main/java/apelet/association/plugin/active/ActivityRegistrationUpdatePlugin.java
create mode 100644 common/common-association/src/main/java/apelet/association/plugin/member/MembershipFeePayPlugin.java
create mode 100644 common/common-association/src/main/java/apelet/association/task/ContractPaymentReminderTask.java
diff --git a/application-tenant/tenant-admin/pom.xml b/application-tenant/tenant-admin/pom.xml
index eb54156..b2ab632 100644
--- a/application-tenant/tenant-admin/pom.xml
+++ b/application-tenant/tenant-admin/pom.xml
@@ -84,7 +84,7 @@
apelet
common-online
- 1.0.0
+ 1.0.3
apelet
@@ -140,7 +140,7 @@
apelet
common-orm
- 1.0.0
+ 1.0.2
apelet
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/CorsConfig.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/CorsConfig.java
new file mode 100644
index 0000000..0fc7bd5
--- /dev/null
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/CorsConfig.java
@@ -0,0 +1,16 @@
+package apelet.tenantadmin.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class CorsConfig implements WebMvcConfigurer {
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedOrigins("*") // 允许所有源
+ .allowedMethods("*") // 允许所有请求方法
+ .allowedHeaders("*"); // 允许所有请求头
+ }
+}
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java
index 9516e0e..970b03b 100644
--- a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java
@@ -1144,33 +1144,15 @@ public class LoginController {
String sessionId = user.getLoginName() + "_" + deviceType + "_" + MyCommonUtil.generateUuid();
JSONObject jsonData = this.createResponseData(user, sessionId);
TokenData tokenData = this.buildTokenData(user, sessionId, deviceType);
- String zwcjName = null;
- try {
- String result = (String)EasUtil.executeOsfServiceWs("com.kingdee.shr.custom.plat.osf.service.GetPersonalDataService"
- ,user.getLoginName(),new HashMap());
- JSONObject personData = JSONObject.parseObject(result);
- tokenData.setPersonId((String) personData.get("personId"));
- jsonData.put("personData", JSONObject.parseObject(result));
- zwcjName = (String)personData.get("zwcjName");
- }catch(Exception e) {
- e.printStackTrace();
- throw new RuntimeException(e);
- }
this.putTokenDataToSessionCache(tokenData);
// 这里手动将TokenData存入request,便于OperationLogAspect统一处理操作日志。
TokenData.addToRequest(tokenData);
List mobileEntryList;
- String roleId = getShrRole(zwcjName);
- if(!StringUtils.isEmpty(roleId)){
- mobileEntryList = mobileEntryService.getMobileEntryListByRoleIds(roleId);
- }else{
- if (isAdmin) {
- mobileEntryList = mobileEntryService.getAllListByOrder(SHOW_ORDER_FIELD);
- } else {
- mobileEntryList = mobileEntryService.getMobileEntryListByRoleIds(tokenData.getRoleIds());
- }
+ if (isAdmin) {
+ mobileEntryList = mobileEntryService.getAllListByOrder(SHOW_ORDER_FIELD);
+ } else {
+ mobileEntryList = mobileEntryService.getMobileEntryListByRoleIds(tokenData.getRoleIds());
}
-
jsonData.put("mobileEntryList", mobileEntryList);
Set permSet = new HashSet<>();
if (!isAdmin) {
@@ -1205,8 +1187,6 @@ public class LoginController {
sysPermService.putUserSysPermCache(sessionId, user.getUserId(), permSet);
sysDataPermService.putDataPermCache(sessionId, user.getUserId(), user.getDeptId());
}
-
-
return jsonData;
}
@@ -1552,4 +1532,6 @@ public class LoginController {
private List permCodeList;
private List permList;
}
+
+
}
diff --git a/application-tenant/tenant-admin/src/main/resources/application-config.yml b/application-tenant/tenant-admin/src/main/resources/application-config.yml
index f753b89..f0748e1 100644
--- a/application-tenant/tenant-admin/src/main/resources/application-config.yml
+++ b/application-tenant/tenant-admin/src/main/resources/application-config.yml
@@ -92,7 +92,7 @@ aliyun:
accessKey: LTAI5t5fEgzRRtdmBvczVS6r
secretKey: uESFiyyi6EwCkM5w4a4pbx6TmVhqgx
bucketName: yy-test12
-
+ nginxOssUrl:
minio:
enabled: false
diff --git a/application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml b/application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml
index d622b1e..0ff9796 100644
--- a/application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml
+++ b/application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml
@@ -218,9 +218,9 @@ spring:
password: X7&9p8L2@6z4K7!8
driverClassName: com.mysql.cj.jdbc.Driver
name: tenant-admin
- initialSize: 10
- minIdle: 10
- maxActive: 50
+ initialSize: 5
+ minIdle: 5
+ maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
@@ -229,7 +229,7 @@ spring:
maxOpenPreparedStatements: 20
validationQuery: SELECT 'x'
testWhileIdle: true
- testOnBorrow: false
+ testOnBorrow: true
testOnReturn: false
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
filters: stat,wall
diff --git a/common/common-association/pom.xml b/common/common-association/pom.xml
index 8740d9b..e97366e 100644
--- a/common/common-association/pom.xml
+++ b/common/common-association/pom.xml
@@ -42,17 +42,17 @@
apelet
common-generator
- 1.0.0
+ 1.0.2
apelet
common-online
- 1.0.0
+ 1.0.3
common-orm
apelet
- 1.0.0
+ 1.0.2
common-msg-notice
diff --git a/common/common-association/src/main/java/apelet/association/config/FrontendConfig.java b/common/common-association/src/main/java/apelet/association/config/FrontendConfig.java
new file mode 100644
index 0000000..74b3a6e
--- /dev/null
+++ b/common/common-association/src/main/java/apelet/association/config/FrontendConfig.java
@@ -0,0 +1,16 @@
+package apelet.association.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@Data
+public class FrontendConfig {
+
+// @Value("${frontend.address}")
+ public String address;
+
+
+}
+
diff --git a/common/common-association/src/main/java/apelet/association/controller/DoPracticeProblemsController.java b/common/common-association/src/main/java/apelet/association/controller/DoPracticeProblemsController.java
index 4b73ddd..03412dc 100644
--- a/common/common-association/src/main/java/apelet/association/controller/DoPracticeProblemsController.java
+++ b/common/common-association/src/main/java/apelet/association/controller/DoPracticeProblemsController.java
@@ -74,8 +74,10 @@ public class DoPracticeProblemsController {
long batchNumber = IdUtil.getSnowflakeNextId();
result.put("batchNumber", batchNumber);
- collection.forEach(f -> {
- ObjectValue examQuestions = f.getObjectValue("exam_questions_id");
+ for (int i = 0; i < collection.size(); i++) {
+ ObjectValue object = collection.getObject(i);
+
+ ObjectValue examQuestions = object.getObjectValue("exam_questions_id");
list.add(examQuestions.getString("id"));
ObjectValue userExercise = new ObjectValue("user_exercise");
@@ -92,7 +94,9 @@ public class DoPracticeProblemsController {
} catch (Exception e) {
throw new RuntimeException(e);
}
- });
+
+ }
+
List
+
+
cn.afterturn
easypoi-base
@@ -40,6 +42,20 @@
easypoi-annotation
4.4.0
+
+
+
+ org.apache.xmlbeans
+ xmlbeans
+ 3.1.0
+
+
+
+ cn.hutool
+ hutool-all
+ 5.8.26
+
+
org.jetbrains
annotations
@@ -57,7 +73,7 @@
org.quartz-scheduler
quartz
- 2.3.2
+ 2.3.2
org.mybatis
@@ -158,8 +174,6 @@
1.0.0
-
-
@@ -171,4 +185,4 @@
-
\ No newline at end of file
+
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java
index 970b03b..7387b36 100644
--- a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java
@@ -70,6 +70,7 @@ import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+
/**
* 登录接口控制器类。
*
@@ -138,6 +139,7 @@ public class LoginController {
private static final String SHOW_NAME_FIELD = "showName";
private static final String SHOW_ORDER_FIELD = "showOrder";
private static final String HEAD_IMAGE_URL_FIELD = "headImageUrl";
+ private static final String SIGNATURE_IMAGE = "signatureImage";
private static final String THIRD_PARTY_CONFIG = "third_party_config";
@@ -145,20 +147,18 @@ public class LoginController {
private OrmGenDataSourceUtil ormGenDataSourceUtil;
-
-
@PostMapping("/getEhrLtpa")
@NoAuthInterface
public ResponseResult getEhrLtap(
@MyRequestBody String username
- ){
+ ) {
EasConfig easConfig = ApplicationContextHolder.getBean("easConfig");
String path = easConfig.getLtpaToken();
// String path = "/ehrapp/yd/LtpaToken.properties"; // 测试环境地址
System.out.println("getEasSsoUrl path = " + path);
String password = LtpaTokenManager.generate(username, path).toString();
JSONObject jsonData = new JSONObject();
- jsonData.put("ltap",password);
+ jsonData.put("ltap", password);
return ResponseResult.success(jsonData);
}
@@ -220,7 +220,7 @@ public class LoginController {
if (entryValue.get(entryFiledKey) instanceof ObjectValue) {
ObjectValue entityValue = (ObjectValue) entryValue.get(entryFiledKey);
Long pk = entityValue.getPkValue();
- if (pk == null || pk == 0L) {
+ if (pk == 0L) {
continue;
}
entityValue = ormGenDataSourceUtil.queryOne(entityValue.getTableName(), pk);
@@ -610,7 +610,7 @@ public class LoginController {
return;
}
responseInfo.setDownloadUri("/tenantadmin/upms/login/downloadHeadImage");
- String newHeadImage = JSONArray.toJSONString(CollUtil.newArrayList(responseInfo));
+ String newHeadImage = JSON.toJSONString(CollUtil.newArrayList(responseInfo));
if (!sysUserService.changeHeadImage(TokenData.takeFromRequest().getUserId(), newHeadImage)) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST));
return;
@@ -657,7 +657,7 @@ public class LoginController {
log.info("Rest api login.");
try {
// Object tokenObj = redissonClient.getBucket(appid).get();
- String accessToken="";
+ String accessToken = "";
// if (tokenObj != null) {
// accessToken=tokenObj.toString();
// }else {
@@ -669,7 +669,7 @@ public class LoginController {
paramMap.put("scope", "app");
// 发送 POST 请求
String tokenData = HttpUtil.post(tokenUrl, paramMap);
- if (StringUtils.isBlank(tokenData)){
+ if (StringUtils.isBlank(tokenData)) {
return ResponseResult.error("500", "通过appId获取AccessToken失败,appId:" + appid);
}
JSONObject tokenJson = JSONObject.parseObject(tokenData);
@@ -679,10 +679,10 @@ public class LoginController {
accessToken = ((JSONObject) (tokenJson.get("data"))).get("accessToken").toString();
//accessToken的有效时间为6400秒,在该有效期内多次获取均返回同一token,
//连许多次请求会被拦截,因此需要本地缓存。为防止极端情况,设置过期时间为6200s
- redissonClient.getBucket(appid).set(accessToken,6200,TimeUnit.SECONDS);
+ redissonClient.getBucket(appid).set(accessToken, 6200, TimeUnit.SECONDS);
// }
String jsonInputString = String.format("{\"appid\":\"%s\", \"ticket\":\"%s\"}", appid, ticket);
- String infoUrl="https://www.yunzhijia.com/gateway/ticket/user/acquirecontext?accessToken="+accessToken;
+ String infoUrl = "https://www.yunzhijia.com/gateway/ticket/user/acquirecontext?accessToken=" + accessToken;
String userStr = HttpUtil.post(infoUrl, jsonInputString);
log.info("validateHubCloudLogin appid:{}, ticket:{} ", appid, ticket);
JSONObject userObj = JSONObject.parseObject(userStr);
@@ -729,11 +729,11 @@ public class LoginController {
log.info("Rest api mlogin.");
try {
// Object tokenObj = redissonClient.getBucket(appid).get();
- String accessToken="";
+ String accessToken = "";
// if (tokenObj != null) {
// accessToken=tokenObj.toString();
// }else {
- if(StringUtils.isEmpty(appid)){
+ if (StringUtils.isEmpty(appid)) {
appid = hubCloudAppId;
}
String tokenUrl = "https://www.yunzhijia.com/gateway/oauth2/token/getAccessToken";
@@ -744,7 +744,7 @@ public class LoginController {
paramMap.put("scope", "app");
// 发送 POST 请求
String tokenData = HttpUtil.post(tokenUrl, paramMap);
- if (StringUtils.isBlank(tokenData)){
+ if (StringUtils.isBlank(tokenData)) {
return ResponseResult.error("500", "通过appId获取AccessToken失败,appId:" + appid);
}
JSONObject tokenJson = JSONObject.parseObject(tokenData);
@@ -754,10 +754,10 @@ public class LoginController {
accessToken = ((JSONObject) (tokenJson.get("data"))).get("accessToken").toString();
//accessToken的有效时间为6400秒,在该有效期内多次获取均返回同一token,
//连许多次请求会被拦截,因此需要本地缓存。为防止极端情况,设置过期时间为6200s
- redissonClient.getBucket(appid).set(accessToken,6200,TimeUnit.SECONDS);
+ redissonClient.getBucket(appid).set(accessToken, 6200, TimeUnit.SECONDS);
// }
String jsonInputString = String.format("{\"appid\":\"%s\", \"ticket\":\"%s\"}", appid, ticket);
- String infoUrl="https://www.yunzhijia.com/gateway/ticket/user/acquirecontext?accessToken="+accessToken;
+ String infoUrl = "https://www.yunzhijia.com/gateway/ticket/user/acquirecontext?accessToken=" + accessToken;
String userStr = HttpUtil.post(infoUrl, jsonInputString);
log.info("validateHubCloudLogin appid:{}, ticket:{} ", appid, ticket);
JSONObject userObj = JSONObject.parseObject(userStr);
@@ -804,27 +804,27 @@ public class LoginController {
log.info("Rest api login.");
try {
Object tokenObj = redissonClient.getBucket(appKey).get();
- String accessToken="";
+ String accessToken = "";
if (tokenObj != null) {
- accessToken=tokenObj.toString();
- }else {
+ accessToken = tokenObj.toString();
+ } else {
String tokenUrl = "https://api.dingtalk.com/v1.0/oauth2/accessToken";
String jsonInputString = String.format(
"{\"appKey\":\"%s\", \"appSecret\":\"%s\"}",
appKey, dingTalkSecret);
// 发送 POST 请求
String tokenData = HttpUtil.post(tokenUrl, jsonInputString);
- if (StringUtils.isBlank(tokenData)){
+ if (StringUtils.isBlank(tokenData)) {
return ResponseResult.error("500", "通过appKey获取AccessToken失败,appKey:" + appKey);
}
JSONObject tokenJson = JSONObject.parseObject(tokenData);
accessToken = tokenJson.get("accessToken").toString();
//accessToken的有效时间为7200秒,在该有效期内多次获取均返回同一token,
//连许多次请求会被拦截,因此需要本地缓存。为防止极端情况,设置过期时间为6200s
- redissonClient.getBucket(appKey).set(accessToken,7000,TimeUnit.SECONDS);
+ redissonClient.getBucket(appKey).set(accessToken, 7000, TimeUnit.SECONDS);
}
- String jsonInputString = String.format("{\"code\":\"%s\"}",code);
- String infoUrl="https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token="+accessToken;
+ String jsonInputString = String.format("{\"code\":\"%s\"}", code);
+ String infoUrl = "https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token=" + accessToken;
String userStr = HttpUtil.post(infoUrl, jsonInputString);
log.info("validateHubCloudLogin appKey:{}, code:{} ", appKey, code);
JSONObject userObj = JSONObject.parseObject(userStr);
@@ -841,7 +841,7 @@ public class LoginController {
if (user.getUserStatus() == SysUserStatus.STATUS_LOCKED) {
return ResponseResult.error(ErrorCodeEnum.INVALID_USER_STATUS, "登录失败,用户账号被锁定!");
}
- JSONObject jsonData = this.buildLoginData(user,null,null);
+ JSONObject jsonData = this.buildLoginData(user, null, null);
return ResponseResult.success(jsonData);
} catch (Exception e) {
e.printStackTrace();
@@ -869,14 +869,14 @@ public class LoginController {
log.info("Rest api login.");
try {
- if(StringUtils.isBlank(ticket)){
- return ResponseResult.error("500","ticket不能为空");
+ if (StringUtils.isBlank(ticket)) {
+ return ResponseResult.error("500", "ticket不能为空");
}
- String jsonInputString = String.format("{\"ticket\":\"%s\",\"appId\":\"%s\",\"checkType\":1}",ticket,appId);
+ String jsonInputString = String.format("{\"ticket\":\"%s\",\"appId\":\"%s\",\"checkType\":1}", ticket, appId);
log.info("doLoginValidateDingTalkmJzt ", jsonInputString);
String userStr = HttpUtil.post(ticketUrl, jsonInputString);
- if(StringUtils.isBlank(userStr)){
- return ResponseResult.error("500","ticket异常:"+ticket);
+ if (StringUtils.isBlank(userStr)) {
+ return ResponseResult.error("500", "ticket异常:" + ticket);
}
log.info(" get user result:", userStr);
JSONObject userObj = JSONObject.parseObject(userStr);
@@ -896,7 +896,7 @@ public class LoginController {
return ResponseResult.success(jsonData);
} catch (Exception e) {
e.printStackTrace();
- return ResponseResult.error("500", "自动登录失败:"+e.getMessage());
+ return ResponseResult.error("500", "自动登录失败:" + e.getMessage());
}
}
@@ -1114,24 +1114,24 @@ public class LoginController {
}
- private String getShrRole(String zwcjName){
+ private String getShrRole(String zwcjName) {
String roleId = "";
- if(!StringUtils.isEmpty(zwcjName)){
+ if (!StringUtils.isEmpty(zwcjName)) {
SysRole role = new SysRole();
- if(!zwcjName.equals("员工")){//非员工
+ if (!zwcjName.equals("员工")) {//非员工
role.setRoleName("非员工");
- List roleList = sysRoleService.getSysRoleList(role,"");
- if(roleList.size() > 0){
+ List roleList = sysRoleService.getSysRoleList(role, "");
+ if (roleList.size() > 0) {
roleId = roleId + roleList.get(0).getRoleId();
}
}
role.setRoleName(zwcjName);
- List roleList = sysRoleService.getSysRoleList(role,"");
- if(roleList.size() > 0){
- if(StringUtils.isEmpty(roleId)){
- roleId = roleList.get(0).getRoleId()+"";
- }else{
- roleId = roleId +","+roleList.get(0).getRoleId();
+ List roleList = sysRoleService.getSysRoleList(role, "");
+ if (roleList.size() > 0) {
+ if (StringUtils.isEmpty(roleId)) {
+ roleId = roleList.get(0).getRoleId() + "";
+ } else {
+ roleId = roleId + "," + roleList.get(0).getRoleId();
}
}
}
@@ -1167,11 +1167,11 @@ public class LoginController {
if (mobileEntry.getPcurl() != null) {
mobileEntry.setPcurl(EasUtil.getEasSsoUrl(user.getLoginName(), mobileEntry.getPcurl()));
}
- if(mobileEntry.getExtraUrl() != null){
- if(mobileEntry.getExtraUrl().contains("?")){
- mobileEntry.setExtraUrl(mobileEntry.getExtraUrl()+"&userNumber="+user.getLoginName());
- }else{
- mobileEntry.setExtraUrl(mobileEntry.getExtraUrl()+"?userNumber="+user.getLoginName());
+ if (mobileEntry.getExtraUrl() != null) {
+ if (mobileEntry.getExtraUrl().contains("?")) {
+ mobileEntry.setExtraUrl(mobileEntry.getExtraUrl() + "&userNumber=" + user.getLoginName());
+ } else {
+ mobileEntry.setExtraUrl(mobileEntry.getExtraUrl() + "?userNumber=" + user.getLoginName());
}
}
}
@@ -1201,7 +1201,7 @@ public class LoginController {
jsonData.put(IS_ADMIN, user.getUserType() == SysUserType.TYPE_ADMIN);
if (user.getDeptId() != null) {
SysDept dept = sysDeptService.getById(user.getDeptId());
- if(dept != null){
+ if (dept != null) {
jsonData.put("deptName", dept.getDeptName());
}
@@ -1532,6 +1532,6 @@ public class LoginController {
private List permCodeList;
private List permList;
}
-
+
}
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/SysUserController.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/SysUserController.java
index a19d724..2d00389 100644
--- a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/SysUserController.java
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/SysUserController.java
@@ -20,6 +20,7 @@ import apelet.tenantadmin.upms.model.SysUser;
import apelet.tenantadmin.upms.service.SysUserService;
import apelet.tenantadmin.upms.vo.SysUserVo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ReflectUtil;
import com.alibaba.fastjson.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -225,7 +226,7 @@ public class SysUserController {
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/list")
- public ResponseResult> list(
+ public ResponseResult> list(
@MyRequestBody SysUserDto sysUserDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
@@ -235,7 +236,16 @@ public class SysUserController {
SysUser sysUserFilter = MyModelUtil.copyTo(sysUserDtoFilter, SysUser.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class);
List sysUserList = sysUserService.getSysUserListWithRelation(sysUserFilter, orderBy);
- return ResponseResult.success(MyPageUtil.makeResponseData(sysUserList, SysUser.INSTANCE));
+
+ MyPageData sysUserVoMyPageData = MyPageUtil.makeResponseData(sysUserList, SysUser.INSTANCE);
+ sysUserVoMyPageData.getDataList().forEach(f ->{
+ List collect = sysUserList.stream().filter(u -> f.getUserId().equals(u.getUserId())).collect(Collectors.toList());
+ SysUser sysUser = collect.get(0);
+ f.setSignatureImage(sysUser.getSignatureImage());
+ });
+ return ResponseResult.success(sysUserVoMyPageData);
+
+
}
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/dto/SysUserDto.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/dto/SysUserDto.java
index e096b69..86f1feb 100644
--- a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/dto/SysUserDto.java
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/dto/SysUserDto.java
@@ -1,5 +1,7 @@
package apelet.tenantadmin.upms.dto;
+import apelet.common.core.annotation.UploadFlagColumn;
+import apelet.common.core.upload.UploadStoreTypeEnum;
import apelet.common.core.validator.AddGroup;
import apelet.common.core.validator.ConstDictRef;
import apelet.common.core.validator.UpdateGroup;
@@ -70,6 +72,9 @@ public class SysUserDto {
@Schema(description = "用户头像的Url")
private String headImageUrl;
+ @Schema(description = "签名")
+ private String signatureImage;
+
/**
* 用户状态(0: 正常 1: 锁定)。
*/
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/model/SysUser.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/model/SysUser.java
index e1ed6fb..85dba06 100644
--- a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/model/SysUser.java
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/model/SysUser.java
@@ -63,6 +63,10 @@ public class SysUser {
@UploadFlagColumn(storeType = UploadStoreTypeEnum.LOCAL_SYSTEM)
private String headImageUrl;
+
+ @UploadFlagColumn(storeType = UploadStoreTypeEnum.LOCAL_SYSTEM)
+ private String signatureImage;
+
/**
* 用户状态(0: 正常 1: 锁定)。
*/
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/vo/SysUserVo.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/vo/SysUserVo.java
index 25c11ea..0125b29 100644
--- a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/vo/SysUserVo.java
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/vo/SysUserVo.java
@@ -53,6 +53,8 @@ public class SysUserVo {
@Schema(description = "用户头像的Url")
private String headImageUrl;
+ @Schema(description = "签名")
+ private String signatureImage;
/**
* 用户状态(0: 正常 1: 锁定)。
*/
diff --git a/application-tenant/tenant-admin/src/main/resources/application-config.yml b/application-tenant/tenant-admin/src/main/resources/application-config.yml
index f0748e1..b51ea11 100644
--- a/application-tenant/tenant-admin/src/main/resources/application-config.yml
+++ b/application-tenant/tenant-admin/src/main/resources/application-config.yml
@@ -88,7 +88,7 @@ aliyun:
oss:
enabled: true
expireSeconds: 1000
- endpoint: https://oss-cn-beijing.aliyuncs.com
+ endpoint: oss-cn-beijing.aliyuncs.com
accessKey: LTAI5t5fEgzRRtdmBvczVS6r
secretKey: uESFiyyi6EwCkM5w4a4pbx6TmVhqgx
bucketName: yy-test12
diff --git a/common/common-association/src/main/java/apelet/association/controller/HomeController.java b/common/common-association/src/main/java/apelet/association/controller/HomeController.java
index 794bb3b..370cee8 100644
--- a/common/common-association/src/main/java/apelet/association/controller/HomeController.java
+++ b/common/common-association/src/main/java/apelet/association/controller/HomeController.java
@@ -1,14 +1,21 @@
package apelet.association.controller;
-import apelet.common.core.object.ObjectCollection;
-import apelet.common.core.object.ResponseResult;
+import apelet.association.utils.WordDocUtil;
+import apelet.common.core.annotation.NoAuthInterface;
+import apelet.common.core.object.*;
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 com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@@ -68,4 +75,5 @@ public class HomeController {
}
+
}
diff --git a/common/common-association/src/main/java/apelet/association/plugin/active/ActivityInfoDetailsPlugin.java b/common/common-association/src/main/java/apelet/association/plugin/active/ActivityInfoDetailsPlugin.java
index e3736ec..018c538 100644
--- a/common/common-association/src/main/java/apelet/association/plugin/active/ActivityInfoDetailsPlugin.java
+++ b/common/common-association/src/main/java/apelet/association/plugin/active/ActivityInfoDetailsPlugin.java
@@ -3,6 +3,7 @@ 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.ObjectCollection;
import apelet.common.core.object.ObjectValue;
import apelet.common.core.upload.UploadResponseInfo;
import apelet.common.core.util.ApplicationContextHolder;
@@ -27,7 +28,9 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
/**
* 活动详情
@@ -59,14 +62,52 @@ public class ActivityInfoDetailsPlugin extends ListPlugin {
@Override
public void change(String widgetVariableName, ObjectValue objectValue) {
+ //添加 会员
+ if (widgetVariableName.equals("table1786587576012")) {
+ ObjectCollection memberInvitations = objectValue.getObjectCollection("member_invitation");
+ List collect = memberInvitations.stream().filter(f -> f.getString("rowkey").equals(objectValue.getString("rowkeysubset"))).collect(Collectors.toList());
+ if (!collect.isEmpty()) {
+ ObjectValue memberInvitation = collect.get(0);
+ ObjectValue membershipApplyId = memberInvitation.getObjectValue("membership_apply_id");
+ if (membershipApplyId == null) {
+ return;
+ }
+ ObjectValue membershipApply = ormGenDataSourceUtil.queryOne(membershipApplyId.getTableName(), membershipApplyId.getString("id"));
+ ObjectCollection applyEntry = membershipApply.getObjectCollection("membership_apply_entry");
+ if (applyEntry == null) {
+ return;
+ }
+ ObjectValue entryObject = applyEntry.getObject(0);
+ this.setWidgetAttributeByEntry("table1786587576012", "unit_name", AttributeEnum.VALUE_CHANGE, membershipApply.getString("unit_name"), objectValue.getString("rowkeysubset"));
+ this.setWidgetAttributeByEntry("table1786587576012", "person", AttributeEnum.VALUE_CHANGE, entryObject.getString("contact_name"), objectValue.getString("rowkeysubset"));
+ this.setWidgetAttributeByEntry("table1786587576012", "phone", AttributeEnum.VALUE_CHANGE, entryObject.getString("contact_phone"), objectValue.getString("rowkeysubset"));
+ }
+ }
+ //专家邀请
+ if(widgetVariableName.equals("table1786587648327")){
+ ObjectCollection expertInvitations = objectValue.getObjectCollection("expert_invitation");
+ List collect = expertInvitations.stream().filter(f -> f.getString("rowkey").equals(objectValue.getString("rowkeysubset"))).collect(Collectors.toList());
+ if (!collect.isEmpty()) {
+ ObjectValue expertInvitation = collect.get(0);
+ ObjectValue expert = expertInvitation.getObjectValue("expert_id");
+ expert = ormGenDataSourceUtil.queryOne(expert.getTableName(), expert.getString("id"));
+ this.setWidgetAttributeByEntry("table1786587648327", "person", AttributeEnum.VALUE_CHANGE, expert.getString("name"), objectValue.getString("rowkeysubset"));
+ this.setWidgetAttributeByEntry("table1786587648327", "phone", AttributeEnum.VALUE_CHANGE, expert.getString("phone"), objectValue.getString("rowkeysubset"));
+ }
+ }
+ //访客邀请
+ if(widgetVariableName.equals("table1786587726532")){
+
+ }
}
@Override
public void buttonTriggered(String widgetVariableName, ObjectValue objectValue) {
+ // 生成报名二维码
if (widgetVariableName.equals("button1786587153460")) {
String registrationQr = objectValue.getString("registration_qr");
- if(StringUtils.isNotEmpty(registrationQr)){
+ if (StringUtils.isNotEmpty(registrationQr)) {
this.showErrorMessage("当前已存在报名二维码, 请勿重复生成!!!");
return;
}
@@ -79,26 +120,31 @@ public class ActivityInfoDetailsPlugin extends ListPlugin {
// 生成 报名二维码
long id = objectValue.getLong("id");
- String url = "http://58.48.135.5:8069" + "/#/?" +
+ String url = "http://192.168.100.42:8099" + "/#/?" +
"loginName=" + "admin" +
"&password=" + "123456" +
- "&entryId=" + "2087413611113746432" +
+ "&entryId=" + "2087710350152568832" +
"&bindType=" + "1" +
- "&onlineFormId=" + "2087385700075835392" +
+ "&onlineFormId=" + "2048951917157027840" +
"&activeId=" + id;
byte[] checkInQr = qrCodeUtil.generateQrCode(url, 350, 350);
QRFile = MyFileUtil.writeToFile(checkInQr, savePath, "qrcode-" + System.currentTimeMillis() + ".png");
MultipartFile checkInMultipart = MyFileUtil.readFileAsMultipartFile(QRFile, "image/png");
- UploadResponseInfo registrationQR = myFileUtil.uploadMyFile(table, "registration_qr", true, checkInMultipart);
- this.setWidgetAttribute("registrationQr", AttributeEnum.VALUE_CHANGE, registrationQR);
+ UploadResponseInfo registrationQR = myFileUtil.uploadMyFile(table, "qr", true, checkInMultipart);
+
+ String s = "[" + new JSONObject(BeanUtil.beanToMap(registrationQR)).toJSONString() + "]";
+ this.setWidgetAttribute("registrationQr", AttributeEnum.VALUE_CHANGE, s);
+ this.setWidgetAttribute("qr", AttributeEnum.VALUE_CHANGE, s);
- objectValue.put("registration_qr", "["+new JSONObject(BeanUtil.beanToMap(registrationQR)).toJSONString()+"]");
+ objectValue.put("registration_qr", s);
+ objectValue.put("qr", s);
Selector selector = new Selector();
selector.getList().add(new SelectorItem("registration_qr"));
ormGenDataSourceUtil.update(objectValue.getTableName(), objectValue, selector);
} catch (Exception e) {
+ e.printStackTrace();
throw new MyRuntimeException(e.getMessage());
} finally {
QRFile.delete();
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
index 73d6f9a..4c40e69 100644
--- 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
@@ -102,16 +102,16 @@ public class ActivitySignConfigPlugin extends ListPlugin {
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;
- }
+// 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;
+ File checkOutFile = null;
+ File checkInFile = null;
try {
Object activityId = objectValue.get("id");
Object activityName = objectValue.get("name");
@@ -135,13 +135,6 @@ public class ActivitySignConfigPlugin extends ListPlugin {
} catch (Exception e) {
e.printStackTrace();
throw new MyRuntimeException("二维码生成失败, 请联系管理员!!!");
- } finally {
- try {
- FileUtils.cleanDirectory(new File(savePath));
- } catch (IOException e) {
- e.printStackTrace();
- System.err.println("文件刪除失敗!!!");
- }
}
}
}
diff --git a/common/common-association/src/main/java/apelet/association/plugin/clueManage/ClueSaveOpPlugin.java b/common/common-association/src/main/java/apelet/association/plugin/clueManage/ClueSaveOpPlugin.java
new file mode 100644
index 0000000..d5d6a7d
--- /dev/null
+++ b/common/common-association/src/main/java/apelet/association/plugin/clueManage/ClueSaveOpPlugin.java
@@ -0,0 +1,76 @@
+package apelet.association.plugin.clueManage;
+
+import apelet.common.core.exception.MyRuntimeException;
+import apelet.common.core.object.ObjectCollection;
+import apelet.common.core.object.ObjectValue;
+import apelet.common.core.object.TokenData;
+import apelet.common.core.util.ApplicationContextHolder;
+import apelet.common.generator.utils.OrmGenDataSourceUtil;
+import apelet.common.online.plugin.*;
+import apelet.common.orm.impl.Selector;
+import apelet.common.orm.impl.SelectorItem;
+import cn.hutool.core.date.DateUtil;
+import org.redisson.api.RBucket;
+import org.redisson.api.RedissonClient;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @ClassName: ClueActivateOpPlugin
+ * @Author: lihuangbin
+ * @Date: 2026/5/11
+ * @Description: 激活放弃的线索
+ */
+
+public class ClueSaveOpPlugin extends OperationServicePlugIn {
+
+ private final OrmGenDataSourceUtil ormGenDataSourceUtil;
+ private final RedissonClient redissonClient;
+
+ public ClueSaveOpPlugin() {
+ ormGenDataSourceUtil = ApplicationContextHolder.getBean(OrmGenDataSourceUtil.class);
+ redissonClient = ApplicationContextHolder.getBean(RedissonClient.class);
+ }
+
+
+ @Override
+ public void endOperationTransaction(EndOperationTransactionArgs e) {
+ ObjectValue objectValue = e.getModel();
+ String redisKey = "clue -- " + DateUtil.today();
+ RBucket>> bucket = redissonClient.getBucket(redisKey);
+ Map> map;
+ // 修复:key存在则读取,不存在新建空map
+ if (bucket.isExists()) {
+ map = bucket.get();
+ } else {
+ map = new HashMap<>();
+ }
+ Long userId = TokenData.takeFromRequest().getUserId();
+ Map userClueMap = map.get(userId);
+ if (userClueMap == null || userClueMap.isEmpty()) {
+ userClueMap = new HashMap<>();
+ }
+ String context = "完成线索, 名称: " +objectValue.getString("name")
+ + ", 咨询内容: " + objectValue.getString("seek_info");
+ userClueMap.put(objectValue.getLong("id"), context);
+ map.put(userId, userClueMap);
+
+ bucket.set(map);
+
+ // 判断:key不存在,写入同时设置过期;key已经存在,只更新value,**不修改TTL**
+ if (!bucket.isExists()) {
+ // 计算到次日0点毫秒
+ LocalDateTime tomorrowZero = LocalDate.now().plusDays(1).atStartOfDay();
+ long expireMs = ChronoUnit.MILLIS.between(LocalDateTime.now(), tomorrowZero);
+ // 原子:只有key不存在才写入并设置过期
+ bucket.expire(expireMs, TimeUnit.MILLISECONDS);
+ }
+ }
+
+
+}
diff --git a/common/common-association/src/main/java/apelet/association/plugin/quotation/ContractPlugin.java b/common/common-association/src/main/java/apelet/association/plugin/quotation/ContractPlugin.java
index d423550..6380ec7 100644
--- a/common/common-association/src/main/java/apelet/association/plugin/quotation/ContractPlugin.java
+++ b/common/common-association/src/main/java/apelet/association/plugin/quotation/ContractPlugin.java
@@ -1,9 +1,14 @@
package apelet.association.plugin.quotation;
+import apelet.association.utils.WordDocUtil;
+import apelet.common.core.object.ObjectValue;
import apelet.common.online.abstractplugin.ListPlugin;
import apelet.common.orm.impl.Filter;
import apelet.common.orm.impl.FilterItem;
+import java.time.LocalDate;
+import java.util.Map;
+
/*
合同列表界面设置过滤条件
@@ -15,4 +20,18 @@ public class ContractPlugin extends ListPlugin {
filter.add(new FilterItem("status", FilterItem.equals, "3"));
return filter;
}
+
+ @Override
+ public void buttonTriggered(String widgetVariableName, ObjectValue objectValue) {
+ if(widgetVariableName.equals("合同导出")){
+ try {
+ Map values = objectValue.getValues();
+ String template = System.getProperty("user.dir") + "\\zz-resource\\quotation_template.docx";
+ String outPath = System.getProperty("user.dir") + "\\zz-resource\\quotation_"+ System.currentTimeMillis()+".docx";
+ WordDocUtil.renderLocalDoc(template, outPath, values);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
}
diff --git a/common/common-association/src/main/java/apelet/association/utils/WordDocUtil.java b/common/common-association/src/main/java/apelet/association/utils/WordDocUtil.java
new file mode 100644
index 0000000..1ac88b2
--- /dev/null
+++ b/common/common-association/src/main/java/apelet/association/utils/WordDocUtil.java
@@ -0,0 +1,82 @@
+package apelet.association.utils;
+
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.data.PictureRenderData;
+import com.deepoove.poi.data.PictureType;
+import com.deepoove.poi.data.Pictures;
+
+import java.io.*;
+import java.util.Map;
+
+public class WordDocUtil {
+
+ /**
+ * 本地模板生成docx文件,输出到本地磁盘
+ *
+ * @param templateLocalPath 本地模板绝对路径
+ * @param outLocalPath 输出文件路径
+ * @param dataMap 填充数据
+ * @throws Exception IO异常
+ */
+ public static void renderLocalDoc(String templateLocalPath, String outLocalPath, Map dataMap) throws Exception {
+ // 自动创建输出文件夹
+ File outFile = new File(outLocalPath);
+ if (!outFile.getParentFile().exists()) {
+ outFile.getParentFile().mkdirs();
+ }
+ Configure config = Configure.builder()
+ .buildGramer("#{", "}")
+ .build();
+ try (InputStream templateIn = new FileInputStream(templateLocalPath);
+ OutputStream fileOut = new FileOutputStream(outLocalPath);
+ XWPFTemplate template = XWPFTemplate.compile(templateIn, config).render(dataMap)) {
+ template.write(fileOut);
+ }
+ }
+
+ /**
+ * ✅【新增】模板渲染直接输出到输出流(用于浏览器下载,不生成本地临时文件)
+ * @param templateLocalPath 模板文件路径
+ * @param outputStream response.getOutputStream()
+ * @param dataMap 填充数据
+ * @throws Exception ex
+ */
+ public static void renderToOutputStream(String templateLocalPath, OutputStream outputStream, Map dataMap) throws Exception {
+ Configure config = Configure.builder()
+ .buildGramer("#{", "}")
+ .build();
+ try (InputStream templateIn = new FileInputStream(templateLocalPath);
+ XWPFTemplate template = XWPFTemplate.compile(templateIn, config).render(dataMap)) {
+ template.write(outputStream);
+ }
+ }
+
+ /**
+ * OSS/网络URL图片构建(签字图片专用)
+ *
+ * @param ossUrl OSS完整图片地址 https://xxx.oss-cn-beijing.aliyuncs.com/sign/sign001.png
+ * @param widthCm 图片宽度 单位cm
+ * @param heightCm 图片高度 单位cm
+ * @return PictureRenderData
+ */
+ public static PictureRenderData getOssPic(String ossUrl, double widthCm, double heightCm) {
+ // poi‑tl size 参数单位是 像素,注意:不是厘米!!!
+ return Pictures.ofUrl(ossUrl)
+ .size((int) widthCm, (int) heightCm)
+ .create();
+ }
+
+ // 本地图片(备用)
+ public static PictureRenderData getLocalPic(String imgLocalPath, double width, double height) {
+ return Pictures.ofLocal(imgLocalPath).size((int) width, (int) height).create();
+ }
+
+ // base64图片(备用)
+ public static PictureRenderData getBase64Pic(String base64Str, double width, double height) {
+ return Pictures.ofBase64(base64Str, PictureType.PNG)
+ .size((int) width, (int) height)
+ .create();
+ }
+
+}
From b3b6c9df44221126255524bc89dc9cf7056e9f71 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=BD=8A?= <23>
Date: Fri, 14 Aug 2026 10:38:37 +0800
Subject: [PATCH 5/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../tenant/controller/DocxTemplateController.java | 141 +++++++++++++++++++++
1 file changed, 141 insertions(+)
create mode 100644 application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/tenant/controller/DocxTemplateController.java
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/tenant/controller/DocxTemplateController.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/tenant/controller/DocxTemplateController.java
new file mode 100644
index 0000000..1c3af35
--- /dev/null
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/tenant/controller/DocxTemplateController.java
@@ -0,0 +1,141 @@
+
+package apelet.tenantadmin.tenant.controller;
+
+import apelet.common.core.annotation.MyRequestBody;
+import apelet.common.core.exception.MyRuntimeException;
+import apelet.common.core.object.ObjectValue;
+import apelet.common.generator.utils.OrmGenDataSourceUtil;
+import cn.hutool.core.io.IoUtil;
+import org.apache.poi.xwpf.usermodel.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@RestController
+@RequestMapping("/api/template")
+public class DocxTemplateController {
+
+
+ @Autowired
+ private OrmGenDataSourceUtil ormGenDataSourceUtil;
+
+ private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{(.+?)\\}");
+
+ /**
+ * 替换字符串中 ${key},JDK8兼容
+ */
+ private String replaceContent(String text, Map dataMap) {
+ if (text == null) return "";
+ Matcher matcher = PLACEHOLDER_PATTERN.matcher(text);
+ StringBuffer sb = new StringBuffer();
+ while (matcher.find()) {
+ String key = matcher.group(1).trim();
+ Object val = dataMap.get(key);
+ String realVal = val == null ? "" : val.toString();
+ matcher.appendReplacement(sb, Matcher.quoteReplacement(realVal));
+ }
+ matcher.appendTail(sb);
+ return sb.toString();
+ }
+
+ @GetMapping("/downloadDocx")
+ public void downloadDocx(@RequestParam("id") String quotationId, HttpServletResponse response) {
+ XWPFDocument document = null;
+ InputStream templateIs = null;
+ OutputStream out = null;
+ try {
+ // 1. 查数据
+ ObjectValue objectValue = ormGenDataSourceUtil.queryOne("quotation", quotationId);
+ Map hashMap = new HashMap<>();
+ hashMap.put("name", objectValue.getString("name"));
+ hashMap.put("number", objectValue.getString("number"));
+ hashMap.put("create_time", objectValue.getString("create_time"));
+ hashMap.put("qty", objectValue.getObjectValue("qty"));
+ ObjectValue managerperson = objectValue.getObjectValue("managerperson");
+ if(managerperson != null){
+ managerperson = ormGenDataSourceUtil.queryOne(managerperson.getTableName(), managerperson.getString("id"));
+ hashMap.put("managerperson",1);
+ }
+ // 2. 读模板
+ File file = new File("D:\\work\\xykj-project\\xhgl\\zz-resource\\quotation_template.docx");
+ templateIs = new FileInputStream(file);
+ document = new XWPFDocument(templateIs);
+ // 3. 替换占位符
+ replaceParagraph(document, hashMap);
+ replaceTable(document, hashMap);
+ // 4. 设置响应头 —— 关键!
+ response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+ response.setCharacterEncoding("UTF-8");
+ String fileName = URLEncoder.encode("报价单.docx", StandardCharsets.UTF_8.name())
+ .replaceAll("\\+", "%20");
+ // 兼容各浏览器的文件名写法
+ response.setHeader("Content-Disposition",
+ "attachment; filename=\"" + fileName + "\"; filename*=UTF-8''" + fileName);
+ response.setHeader("Pragma", "no-cache");
+ response.setHeader("Cache-Control", "no-cache");
+ response.setDateHeader("Expires", 0);
+ // 5. 写出
+ out = response.getOutputStream();
+ document.write(out);
+ out.flush();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new MyRuntimeException("导出失败: " + e.getMessage());
+ } finally {
+ IoUtil.close(document);
+ IoUtil.close(templateIs);
+ IoUtil.close(out);
+ }
+ }
+
+
+
+
+ private void replaceParagraph(XWPFDocument document, Map dataMap) {
+ for (XWPFParagraph paragraph : document.getParagraphs()) {
+ String text = paragraph.getText();
+ Matcher matcher = PLACEHOLDER_PATTERN.matcher(text);
+ if (!matcher.find()) {
+ continue;
+ }
+ //清空原有run
+ for (XWPFRun run : paragraph.getRuns()) {
+ run.setText("", 0);
+ }
+ String newText = replaceContent(text, dataMap);
+ paragraph.createRun().setText(newText);
+ }
+ }
+
+ private void replaceTable(XWPFDocument document, Map dataMap) {
+ for (XWPFTable table : document.getTables()) {
+ for (XWPFTableRow row : table.getRows()) {
+ for (XWPFTableCell cell : row.getTableCells()) {
+ for (XWPFParagraph paragraph : cell.getParagraphs()) {
+ String text = paragraph.getText();
+ Matcher matcher = PLACEHOLDER_PATTERN.matcher(text);
+ if (!matcher.find()) {
+ continue;
+ }
+ for (XWPFRun run : paragraph.getRuns()) {
+ run.setText("", 0);
+ }
+ String newText = replaceContent(text, dataMap);
+ paragraph.createRun().setText(newText);
+ }
+ }
+ }
+ }
+ }
+
+
+}
From 4b8f8eefbff464b383dd9c3dab682008e8583529 Mon Sep 17 00:00:00 2001
From: myf
Date: Sat, 15 Aug 2026 15:43:12 +0800
Subject: [PATCH 6/6] =?UTF-8?q?=E4=BF=9D=E5=AD=98=E6=8F=92=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../plugin/member/MembershipSavePlugin.java | 360 +++++++++++++++++++++
1 file changed, 360 insertions(+)
create mode 100644 common/common-association/src/main/java/apelet/association/plugin/member/MembershipSavePlugin.java
diff --git a/common/common-association/src/main/java/apelet/association/plugin/member/MembershipSavePlugin.java b/common/common-association/src/main/java/apelet/association/plugin/member/MembershipSavePlugin.java
new file mode 100644
index 0000000..b36b002
--- /dev/null
+++ b/common/common-association/src/main/java/apelet/association/plugin/member/MembershipSavePlugin.java
@@ -0,0 +1,360 @@
+package apelet.association.plugin.member;
+
+import apelet.common.core.exception.MyRuntimeException;
+import apelet.common.core.object.ObjectCollection;
+import apelet.common.core.object.ObjectValue;
+import apelet.common.online.abstractplugin.ExecutePluginParent;
+import apelet.common.orm.impl.Filter;
+import apelet.common.orm.impl.FilterItem;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @ClassName: test
+ * @Date: 2026/8/14
+ * @Description: PC 与移动端共用的"保存"插件
+ * 场景:移动端小程序无法直连后端调试,将 PC 表单与移动端绑定同一个插件,
+ * 在 PC 上点击"保存"即可复现移动端小程序的保存逻辑,控制台/日志可看到保存报错。
+ *
+ * 保存逻辑:
+ * 1. 根据表单 id 区分"新增"与"修改":
+ * - 新增(id 为空/0):先按 unit_name 验重,已存在则拒绝新增;否则生成单据号(S + yyyyMMdd + 4 位流水)后 addNew
+ * - 修改(id 非空):按 id 直接 update,不验重
+ * 2. 无论新增还是修改,均写入默认值:flow_status / flow_approval_status / org / srcbillid / srcbillnumber / srcentryid = 0,history = 1
+ */
+public class MembershipSavePlugin extends ExecutePluginParent {
+
+ /** 保存的目标主表 */
+ private static final String TABLE_NAME = "membership_apply";
+
+ /** 单据号前缀 */
+ private static final String NUMBER_PREFIX = "S";
+
+ /** 单据号日期格式 */
+ private static final String DATE_PATTERN = "yyyyMMdd";
+
+ /** 流水号位数(不足补零,如 0001) */
+ private static final int SEQ_LENGTH = 4;
+
+ /** 唯一键:单位名称数据库字段 */
+ private static final String FIELD_UNIT_NAME = "unit_name";
+
+ /** 数据库字段 -> 表单控件 key 映射(与 UnitNameChangeFormInitPlugin 保持一致) */
+ private static final Map DB_FIELD_WIDGET_MAPPING = new HashMap<>();
+
+ static {
+ DB_FIELD_WIDGET_MAPPING.put("create_user_id", "createUserId");
+ DB_FIELD_WIDGET_MAPPING.put("create_time", "createTime");
+ DB_FIELD_WIDGET_MAPPING.put("update_user_id", "updateUserId");
+ DB_FIELD_WIDGET_MAPPING.put("update_time", "updateTime");
+ DB_FIELD_WIDGET_MAPPING.put("deleted_flag", "deletedFlag");
+ DB_FIELD_WIDGET_MAPPING.put("is_history", "history");
+ DB_FIELD_WIDGET_MAPPING.put("nature_unit", "natureUnit");
+ DB_FIELD_WIDGET_MAPPING.put("unit_name", "unitName");
+ DB_FIELD_WIDGET_MAPPING.put("membership_manger_id", "membershipMangerId");
+ DB_FIELD_WIDGET_MAPPING.put("membership_type", "membershipType");
+ DB_FIELD_WIDGET_MAPPING.put("menbership_attributes", "menbershipAttributes");
+ DB_FIELD_WIDGET_MAPPING.put("scope_business", "scopeBusiness");
+ DB_FIELD_WIDGET_MAPPING.put("business_regist_number", "businessRegistNumber");
+ DB_FIELD_WIDGET_MAPPING.put("regist_capital", "registCapital");
+ DB_FIELD_WIDGET_MAPPING.put("regist_time", "registTime");
+ DB_FIELD_WIDGET_MAPPING.put("company_address", "companyAddress");
+ DB_FIELD_WIDGET_MAPPING.put("version_number", "versionNumber");
+ DB_FIELD_WIDGET_MAPPING.put("change_reason", "changeReason");
+ }
+
+ /** 保存时需要跳过的非主表字段(objectValue 中的控件 key) */
+ private static final String[] SKIP_WIDGET_KEYS = {
+ "id", // 主键,由框架自动生成或单独处理
+ "eventparams", // 弹窗参数,非表字段
+ "sourcebillid", // 来源单据参数
+ "srcbillid",
+ "sourcebillnumber",
+ "srcbillnumber",
+ "membership_apply_entry", // 子表(本次保存不处理子表)
+ "table1777360622546",
+ "rowkeysubset" // 框架内部字段
+ };
+
+ /**
+ * 按钮点击事件:处理"保存"按钮
+ *
+ * @param widgetVariableName 按钮标识
+ * @param objectValue 当前表单数据对象
+ */
+ @Override
+ public void buttonTriggered(String widgetVariableName, ObjectValue objectValue) {
+ // 仅响应"保存"按钮
+ if (!"保存".equals(widgetVariableName)) {
+ return;
+ }
+
+ try {
+ // 根据表单 id 区分新增/修改
+ boolean isNew = isNewBill(objectValue);
+ if (isNew) {
+ // 新增:先按 unit_name 验重,再生成单据号入库
+ saveAsNew(objectValue);
+ this.showMessage("保存成功(新增)");
+ } else {
+ // 修改:按 id 直接更新,不验重
+ saveAsUpdate(objectValue);
+ this.showMessage("保存成功(修改)");
+ }
+ this.cancelOperate();
+ } catch (Exception e) {
+ // 保存失败:打印完整堆栈到控制台/日志,便于定位移动端小程序保存报错
+ e.printStackTrace();
+ // 抛出异常,让 PC 端弹窗显示具体错误
+ throw new MyRuntimeException("保存失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 判断当前表单是新增还是修改
+ * 表单 id 为空或 0 视为新增,否则视为修改
+ *
+ * @param objectValue 表单数据对象
+ * @return true 表示新增
+ */
+ private boolean isNewBill(ObjectValue objectValue) {
+ Object idObj = objectValue.get("id");
+ if (idObj == null) {
+ return true;
+ }
+ String idStr = idObj.toString().trim();
+ return idStr.isEmpty() || "0".equals(idStr);
+ }
+
+ /**
+ * 新增逻辑:按 unit_name 验重 -> 生成单据号 -> addNew
+ *
+ * @param objectValue 表单数据对象
+ */
+ private void saveAsNew(ObjectValue objectValue) throws Exception {
+ // 取唯一键单位名称(兼容 unit_name / unitName 两种控件 key)
+ String unitName = getUnitName(objectValue);
+
+ // 新增验重:unit_name 已存在则拒绝新增
+ ObjectValue existBill = findExistBillByUnitName(unitName);
+ if (existBill != null) {
+ throw new MyRuntimeException("单位【" + unitName + "】已存在,请勿重复新增");
+ }
+
+ // 自动生成单据号(S + yyyyMMdd + 4 位流水号)
+ String number = generateNumber();
+ // 组装数据库记录并新增
+ ObjectValue newBill = buildNewBill(objectValue, number);
+ ormGenDataSourceUtil().addNew(TABLE_NAME, newBill);
+ }
+
+ /**
+ * 修改逻辑:按 id 组装记录并 update(不验重)
+ * 先查出原记录的单据号 number 并填回,避免整体覆盖更新时把 number 置为 null
+ *
+ * @param objectValue 表单数据对象
+ */
+ private void saveAsUpdate(ObjectValue objectValue) throws Exception {
+ ObjectValue updateBill = buildUpdateBill(objectValue);
+
+ // 按主键查询原记录,把单据号 number 填回(update 为整体覆盖,缺失字段会被置空)
+ Object idObj = objectValue.get("id");
+ if (idObj != null) {
+ Filter filter = new Filter();
+ filter.add(new FilterItem("id", FilterItem.equals, idObj));
+ ObjectCollection collection = ormGenDataSourceUtil().query(TABLE_NAME, filter, null);
+ if (collection != null && !collection.isEmpty()) {
+ String existNumber = collection.getObject(0).getString("number");
+ if (existNumber != null && !existNumber.isEmpty()) {
+ updateBill.put("number", existNumber);
+ }
+ }
+ }
+
+ ormGenDataSourceUtil().update(TABLE_NAME, updateBill, null);
+ }
+
+ /**
+ * 根据单位名称查询已存在的单据(用于新增验重)
+ *
+ * @param unitName 单位名称
+ * @return 已存在的单据;不存在返回 null
+ */
+ private ObjectValue findExistBillByUnitName(String unitName) throws Exception {
+ if (unitName == null || unitName.trim().isEmpty()) {
+ return null;
+ }
+ Filter filter = new Filter();
+ filter.add(new FilterItem(FIELD_UNIT_NAME, FilterItem.equals, unitName));
+ ObjectCollection collection = ormGenDataSourceUtil().query(TABLE_NAME, filter, null);
+ if (collection != null && !collection.isEmpty()) {
+ return collection.getObject(0);
+ }
+ return null;
+ }
+
+ /**
+ * 组装新增记录:填充表单字段 + 单据号 + 默认值
+ *
+ * @param objectValue 表单数据对象
+ * @param number 自动生成的单据号
+ * @return 组装好的数据库记录
+ */
+ private ObjectValue buildNewBill(ObjectValue objectValue, String number) {
+ ObjectValue newBill = new ObjectValue(TABLE_NAME);
+ fillFields(newBill, objectValue);
+ // 设置自动生成的单据号
+ newBill.put("number", number);
+ // 设置默认值
+ setDefaultValues(newBill);
+ return newBill;
+ }
+
+ /**
+ * 组装修改记录:带主键 id,覆盖表单字段,单据号保留数据库原值
+ *
+ * @param objectValue 表单数据对象
+ * @return 组装好的数据库记录
+ */
+ private ObjectValue buildUpdateBill(ObjectValue objectValue) {
+ ObjectValue bill = new ObjectValue(TABLE_NAME);
+ // 主键 id 作为 update 条件
+ Object idObj = objectValue.get("id");
+ if (idObj != null) {
+ bill.put("id", idObj);
+ }
+ fillFields(bill, objectValue);
+ // 设置默认值
+ setDefaultValues(bill);
+ return bill;
+ }
+
+ /**
+ * 把表单字段复制到目标记录(跳过 id、number、非主表字段,控件 key 转数据库字段)
+ *
+ * @param target 目标数据库记录
+ * @param source 表单数据对象
+ */
+ private void fillFields(ObjectValue target, ObjectValue source) {
+ Map values = source.getValues();
+ if (values == null) {
+ return;
+ }
+ for (Object item : values.entrySet()) {
+ Map.Entry entry = (Map.Entry) item;
+ String widgetKey = entry.getKey().toString();
+
+ // 跳过主键、参数、子表等非主表字段
+ if (shouldSkipField(widgetKey)) {
+ continue;
+ }
+
+ // 控件 key 转成数据库字段名
+ String dbKey = getDbFieldKey(widgetKey);
+ // id 由单独逻辑处理,number 保留数据库原值(新增时才生成)
+ if ("id".equals(dbKey) || "number".equals(dbKey)) {
+ continue;
+ }
+ target.put(dbKey, entry.getValue());
+ }
+ }
+
+ /**
+ * 设置默认值:流程状态/来源单据等字段 = 0
+ *
+ * @param bill 数据库记录
+ */
+ private void setDefaultValues(ObjectValue bill) {
+ bill.put("flow_status", 0);
+ bill.put("flow_approval_status", 0);
+ bill.put("org", 0);
+ bill.put("srcbillid", 0);
+ bill.put("srcbillnumber", 0);
+ bill.put("srcentryid", 0);
+ bill.put("history", 0);
+ }
+
+ /**
+ * 自动生成单据号:S + yyyyMMdd + 当天最大流水号 + 1(补 4 位零)
+ * 例如当天已有 S202608140001,则生成 S202608140002
+ *
+ * @return 新单据号
+ */
+ private String generateNumber() throws Exception {
+ String prefix = NUMBER_PREFIX + LocalDate.now().format(DateTimeFormatter.ofPattern(DATE_PATTERN));
+
+ // 查询当天所有单据号,取最大流水号
+ Filter filter = new Filter();
+ filter.add(new FilterItem("number", FilterItem.like, prefix + "%"));
+ ObjectCollection collection = ormGenDataSourceUtil().query(TABLE_NAME, filter, null);
+
+ int maxSeq = 0;
+ if (collection != null) {
+ for (int i = 0; i < collection.size(); i++) {
+ String number = collection.getObject(i).getString("number");
+ if (number != null && number.length() > prefix.length()) {
+ try {
+ // 截取前缀后的流水号部分并比较
+ int seq = Integer.parseInt(number.substring(prefix.length()));
+ if (seq > maxSeq) {
+ maxSeq = seq;
+ }
+ } catch (NumberFormatException ignored) {
+ // 忽略非数字流水号
+ }
+ }
+ }
+ }
+
+ // 流水号 +1 并补零到指定位数
+ return prefix + String.format("%0" + SEQ_LENGTH + "d", maxSeq + 1);
+ }
+
+ /**
+ * 获取单位名称(唯一键),兼容 unit_name / unitName 两种控件 key
+ *
+ * @param objectValue 表单数据对象
+ * @return 单位名称
+ */
+ private String getUnitName(ObjectValue objectValue) {
+ String unitName = objectValue.getString(FIELD_UNIT_NAME);
+ if (unitName == null || unitName.isEmpty()) {
+ unitName = objectValue.getString("unitName");
+ }
+ return unitName;
+ }
+
+ /**
+ * 判断字段是否需要跳过(主键/弹窗参数/来源参数/子表等)
+ *
+ * @param widgetKey 控件 key
+ * @return true 表示跳过
+ */
+ private boolean shouldSkipField(String widgetKey) {
+ for (String skipKey : SKIP_WIDGET_KEYS) {
+ if (skipKey.equalsIgnoreCase(widgetKey)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 控件 key 转数据库字段名(通过 DB_FIELD_WIDGET_MAPPING 反向查找)
+ * 若未匹配则原样返回(可能是数据库字段名或无需转换的字段)
+ *
+ * @param widgetKey 控件 key
+ * @return 数据库字段名
+ */
+ private String getDbFieldKey(String widgetKey) {
+ for (Map.Entry entry : DB_FIELD_WIDGET_MAPPING.entrySet()) {
+ if (entry.getValue().equalsIgnoreCase(widgetKey)) {
+ return entry.getKey();
+ }
+ }
+ return widgetKey;
+ }
+}