feat(declare): 同一申报项目进行中只允许一条申报
- 新增 DeclareGuardService:按已通过/未处理驳回/待审核数判重,申报项目行加锁防连点 - 9 张申报表补 declare_id / declare_status / declare_remark,提交时写入并随审核结果回写 - 新增撤回、作废(强制放行)接口;挑战杯团队成员按手机号判重 - 申报项目支持配置允许重复提交与最多同时条数 - 迁移脚本 sql/20261102_add_declare_uniqueness.sql(含存量回填与重复清单)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package com.gxwebsoft.gxmu.controller;
|
||||
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import com.gxwebsoft.gxmu.service.DeclareService;
|
||||
import com.gxwebsoft.gxmu.entity.Declare;
|
||||
import com.gxwebsoft.gxmu.param.DeclareParam;
|
||||
@@ -19,7 +20,9 @@ import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 申报管理控制器
|
||||
@@ -36,12 +39,16 @@ public class DeclareController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private DeclareService declareService;
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
|
||||
@ApiOperation("分页查询申报管理")
|
||||
@GetMapping("/page")
|
||||
public ApiResult<PageResult<Declare>> page(DeclareParam param) {
|
||||
// 使用关联查询
|
||||
return success(declareService.pageRel(param));
|
||||
PageResult<Declare> result = declareService.pageRel(param);
|
||||
fillUserDeclareStatus(result.getList());
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@ApiOperation("分页查询当前用户申报管理")
|
||||
@@ -49,21 +56,31 @@ public class DeclareController extends BaseController {
|
||||
public ApiResult<PageResult<Declare>> userPage(DeclareParam param) {
|
||||
Integer loginUserId = getLoginUserId();
|
||||
param.setUserId(loginUserId == null ? null : loginUserId.longValue());
|
||||
return success(declareService.pageRel(param));
|
||||
PageResult<Declare> result = declareService.pageRel(param);
|
||||
fillUserDeclareStatus(result.getList());
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@ApiOperation("查询全部申报管理")
|
||||
@GetMapping()
|
||||
public ApiResult<List<Declare>> list(DeclareParam param) {
|
||||
// 使用关联查询
|
||||
return success(declareService.listRel(param));
|
||||
List<Declare> list = declareService.listRel(param);
|
||||
fillUserDeclareStatus(list);
|
||||
return success(list);
|
||||
}
|
||||
|
||||
@ApiOperation("根据id查询申报管理")
|
||||
@GetMapping("/{id}")
|
||||
public ApiResult<Declare> get(@PathVariable("id") Integer id) {
|
||||
// 使用关联查询
|
||||
return success(declareService.getByIdRel(id));
|
||||
Declare declare = declareService.getByIdRel(id);
|
||||
if (declare != null) {
|
||||
List<Declare> single = new java.util.ArrayList<>();
|
||||
single.add(declare);
|
||||
fillUserDeclareStatus(single);
|
||||
}
|
||||
return success(declare);
|
||||
}
|
||||
|
||||
@ApiOperation("添加申报管理")
|
||||
@@ -78,6 +95,7 @@ public class DeclareController extends BaseController {
|
||||
if (validateMessage != null) {
|
||||
return fail(validateMessage);
|
||||
}
|
||||
normalizeRepeatConfig(declare, true);
|
||||
// 显式写北京时间,避免容器 JVM/库会话仍为 UTC 时 DEFAULT CURRENT_TIMESTAMP 偏 8 小时
|
||||
LocalDateTime now = LocalDateTime.now(BEIJING);
|
||||
declare.setCreateTime(now);
|
||||
@@ -95,6 +113,7 @@ public class DeclareController extends BaseController {
|
||||
if (validateMessage != null) {
|
||||
return fail(validateMessage);
|
||||
}
|
||||
normalizeRepeatConfig(declare, false);
|
||||
declare.setUpdateTime(LocalDateTime.now(BEIJING));
|
||||
if (declareService.updateById(declare)) {
|
||||
return success("修改成功");
|
||||
@@ -180,4 +199,68 @@ public class DeclareController extends BaseController {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** 是否允许重复提交 / 最多同时几条:默认不允许、上限 1 */
|
||||
private void normalizeRepeatConfig(Declare declare, boolean creating) {
|
||||
if (declare.getAllowRepeat() == null && creating) {
|
||||
declare.setAllowRepeat(0);
|
||||
}
|
||||
if (declare.getMaxPending() == null && creating) {
|
||||
declare.setMaxPending(1);
|
||||
}
|
||||
if (declare.getMaxPending() != null && declare.getMaxPending() < 1) {
|
||||
declare.setMaxPending(1);
|
||||
}
|
||||
}
|
||||
|
||||
/** 回填当前用户在各申报项目下的最新记录状态,供小程序列表展示与禁用 */
|
||||
private void fillUserDeclareStatus(List<Declare> list) {
|
||||
Integer userId = getLoginUserId();
|
||||
if (userId == null || list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Map<String, Map<Integer, Map<String, Object>>> cache = new HashMap<>();
|
||||
for (Declare declare : list) {
|
||||
String module = declare.getModule();
|
||||
if (declare.getId() == null || module == null || !declareGuardService.supports(module)) {
|
||||
continue;
|
||||
}
|
||||
Map<Integer, Map<String, Object>> mine = cache.get(module);
|
||||
if (mine == null) {
|
||||
mine = declareGuardService.myDeclareStatus(module, userId);
|
||||
cache.put(module, mine);
|
||||
}
|
||||
Map<String, Object> row = mine.get(declare.getId());
|
||||
if (row == null) {
|
||||
continue;
|
||||
}
|
||||
declare.setMyStatus(asInteger(row.get("declareStatus")));
|
||||
declare.setMyRecordId(asInteger(row.get("id")));
|
||||
declare.setMySubmitTime(formatSubmitTime(row.get("createTime")));
|
||||
declare.setMyStatusRemark(row.get("declareRemark") == null ? null : String.valueOf(row.get("declareRemark")));
|
||||
}
|
||||
}
|
||||
|
||||
private Integer asInteger(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).intValue();
|
||||
}
|
||||
try {
|
||||
return Integer.valueOf(String.valueOf(value));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String formatSubmitTime(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String text = String.valueOf(value);
|
||||
return text.length() >= 10 ? text.substring(0, 10) : text;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.gxwebsoft.gxmu.controller;
|
||||
|
||||
import com.gxwebsoft.common.core.annotation.OperationLog;
|
||||
import com.gxwebsoft.common.core.web.ApiResult;
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.gxmu.param.DeclareRecordActionParam;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 申报记录状态操作:撤回、作废(强制放行)。
|
||||
*
|
||||
* <p>规则见 docs/adr/0005-declare-uniqueness.md。</p>
|
||||
*/
|
||||
@Api(tags = "申报记录状态管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/gxmu/declare-record")
|
||||
public class DeclareRecordController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
|
||||
@OperationLog
|
||||
@ApiOperation("撤回申报:待审核 -> 草稿")
|
||||
@PostMapping("/withdraw")
|
||||
public ApiResult<?> withdraw(@RequestBody DeclareRecordActionParam param) {
|
||||
if (param == null || param.getModule() == null || param.getId() == null) {
|
||||
return fail("参数不正确");
|
||||
}
|
||||
boolean admin = !hasOnlyStudentRole();
|
||||
String error = declareGuardService.withdraw(param.getModule(), param.getId(), getLoginUserId(), admin);
|
||||
return error == null ? success("已撤回,可在草稿中继续修改后重新提交") : fail(error);
|
||||
}
|
||||
|
||||
@OperationLog
|
||||
@ApiOperation("作废申报(管理员,作废后本人可重新申报)")
|
||||
@PostMapping("/void")
|
||||
public ApiResult<?> voidRecord(@RequestBody DeclareRecordActionParam param) {
|
||||
if (param == null || param.getModule() == null || param.getId() == null) {
|
||||
return fail("参数不正确");
|
||||
}
|
||||
if (hasOnlyStudentRole()) {
|
||||
return fail("没有作废申报的权限");
|
||||
}
|
||||
String error = declareGuardService.voidRecord(param.getModule(), param.getId(), param.getReason());
|
||||
return error == null ? success("已作废,该申报人可重新申报") : fail(error);
|
||||
}
|
||||
|
||||
@ApiOperation("当前用户在某申报项目下的最新申报记录")
|
||||
@GetMapping("/mine")
|
||||
public ApiResult<?> mine(@RequestParam(value = "module", required = false) String module,
|
||||
@RequestParam(value = "declareId", required = false) Integer declareId) {
|
||||
Integer userId = getLoginUserId();
|
||||
if (module == null || declareId == null || userId == null) {
|
||||
Map<String, Object> empty = null;
|
||||
return success(empty);
|
||||
}
|
||||
Map<Integer, Map<String, Object>> all = declareGuardService.myDeclareStatus(module, userId);
|
||||
return success(all.get(declareId));
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,9 @@ import com.gxwebsoft.gxmu.entity.QmgcForm;
|
||||
import com.gxwebsoft.gxmu.param.QmgcFormParam;
|
||||
import com.gxwebsoft.gxmu.service.QmgcFormService;
|
||||
import com.gxwebsoft.gxmu.service.ReviewFlowStarterService;
|
||||
import com.gxwebsoft.gxmu.model.DeclareCheckResult;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.gxwebsoft.gxmu.util.GxmuQueryHelper;
|
||||
import com.gxwebsoft.gxmu.util.QmgcDocxExportUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
@@ -41,6 +44,8 @@ public class QmgcFormController extends BaseController {
|
||||
@Resource
|
||||
private ReviewFlowStarterService reviewFlowStarterService;
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
@Resource
|
||||
private FileRecordService fileRecordService;
|
||||
|
||||
@Value("${config.upload-path}")
|
||||
@@ -134,11 +139,21 @@ public class QmgcFormController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("添加青马工程培训班学员登记表")
|
||||
@PostMapping()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResult<?> save(@RequestBody QmgcForm qmgcForm) {
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
qmgcForm.setUserId(loginUser.getUserId());
|
||||
}
|
||||
DeclareCheckResult declareCheck = declareGuardService.checkBeforeCreate("gxmu_qmgc_form",
|
||||
qmgcForm.getDeclareId(), qmgcForm.getYear(), qmgcForm.getUserId());
|
||||
if (declareCheck.isRejected()) {
|
||||
return fail(declareCheck.getError());
|
||||
}
|
||||
if (declareCheck.getDeclareId() != null) {
|
||||
qmgcForm.setDeclareId(declareCheck.getDeclareId());
|
||||
}
|
||||
qmgcForm.setDeclareStatus(1);
|
||||
if (qmgcFormService.save(qmgcForm)) {
|
||||
reviewFlowStarterService.startReview("gxmu_qmgc_form", qmgcForm.getId());
|
||||
return success("添加成功");
|
||||
@@ -187,4 +202,4 @@ public class QmgcFormController extends BaseController {
|
||||
}
|
||||
return String.valueOf(java.time.LocalDate.now().getYear());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.gxwebsoft.gxmu.entity.ReviewFlow;
|
||||
import com.gxwebsoft.gxmu.entity.ReviewFlowConfig;
|
||||
import com.gxwebsoft.gxmu.service.ReviewFlowConfigService;
|
||||
import com.gxwebsoft.gxmu.service.ReviewFlowService;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import com.gxwebsoft.gxmu.service.ReviewListService;
|
||||
import com.gxwebsoft.gxmu.entity.ReviewList;
|
||||
import com.gxwebsoft.gxmu.param.ReviewListParam;
|
||||
@@ -38,6 +39,8 @@ public class ReviewListController extends BaseController {
|
||||
private ReviewFlowConfigService reviewFlowConfigService;
|
||||
@Resource
|
||||
private ReviewFlowService reviewFlowService;
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
|
||||
@ApiOperation("分页查询审核列表")
|
||||
@GetMapping("/page")
|
||||
@@ -125,6 +128,7 @@ public class ReviewListController extends BaseController {
|
||||
}
|
||||
}
|
||||
}
|
||||
declareGuardService.syncReviewStatus(reviewList.getModule(), reviewList.getPk());
|
||||
return success("修改成功");
|
||||
}
|
||||
return fail("修改失败");
|
||||
@@ -152,11 +156,25 @@ public class ReviewListController extends BaseController {
|
||||
@PutMapping("/batch")
|
||||
public ApiResult<?> updateBatch(@RequestBody BatchParam<ReviewList> batchParam) {
|
||||
if (batchParam.update(reviewListService, "id")) {
|
||||
syncBatchReviewStatus(batchParam);
|
||||
return success("修改成功");
|
||||
}
|
||||
return fail("修改失败");
|
||||
}
|
||||
|
||||
/** 批量审核后同样要回写申报记录状态,否则重复申报限制会读到旧状态 */
|
||||
private void syncBatchReviewStatus(BatchParam<ReviewList> batchParam) {
|
||||
if (batchParam == null || batchParam.getIds() == null) {
|
||||
return;
|
||||
}
|
||||
for (java.io.Serializable id : batchParam.getIds()) {
|
||||
ReviewList saved = reviewListService.getById(id);
|
||||
if (saved != null) {
|
||||
declareGuardService.syncReviewStatus(saved.getModule(), saved.getPk());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation("批量删除审核列表")
|
||||
@DeleteMapping("/batch")
|
||||
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
|
||||
@@ -196,4 +214,4 @@ public class ReviewListController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,9 @@ import com.gxwebsoft.common.system.service.OrganizationService;
|
||||
import com.gxwebsoft.gxmu.entity.SjqnForm;
|
||||
import com.gxwebsoft.gxmu.param.SjqnFormParam;
|
||||
import com.gxwebsoft.gxmu.service.ReviewFlowStarterService;
|
||||
import com.gxwebsoft.gxmu.model.DeclareCheckResult;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.gxwebsoft.gxmu.service.SjqnFormService;
|
||||
import com.gxwebsoft.gxmu.util.GxmuQueryHelper;
|
||||
import com.gxwebsoft.gxmu.util.SjqnDocxExportUtil;
|
||||
@@ -45,6 +48,8 @@ public class SjqnFormController extends BaseController {
|
||||
@Resource
|
||||
private ReviewFlowStarterService reviewFlowStarterService;
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
@Resource
|
||||
private FileRecordService fileRecordService;
|
||||
@Resource
|
||||
private OrganizationService organizationService;
|
||||
@@ -151,11 +156,21 @@ public class SjqnFormController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("添加十佳青年申报表")
|
||||
@PostMapping()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResult<?> save(@RequestBody SjqnForm sjqnForm) {
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
sjqnForm.setUserId(loginUser.getUserId());
|
||||
}
|
||||
DeclareCheckResult declareCheck = declareGuardService.checkBeforeCreate("gxmu_sjqn",
|
||||
sjqnForm.getDeclareId(), sjqnForm.getYear(), sjqnForm.getUserId());
|
||||
if (declareCheck.isRejected()) {
|
||||
return fail(declareCheck.getError());
|
||||
}
|
||||
if (declareCheck.getDeclareId() != null) {
|
||||
sjqnForm.setDeclareId(declareCheck.getDeclareId());
|
||||
}
|
||||
sjqnForm.setDeclareStatus(1);
|
||||
if (sjqnFormService.save(sjqnForm)) {
|
||||
reviewFlowStarterService.startReview("gxmu_sjqn", sjqnForm.getId());
|
||||
return success("添加成功");
|
||||
@@ -230,4 +245,4 @@ public class SjqnFormController extends BaseController {
|
||||
private String valueOf(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,9 @@ import com.gxwebsoft.common.system.service.OrganizationService;
|
||||
import com.gxwebsoft.gxmu.entity.SjtbzbsjForm;
|
||||
import com.gxwebsoft.gxmu.param.SjtbzbsjFormParam;
|
||||
import com.gxwebsoft.gxmu.service.ReviewFlowStarterService;
|
||||
import com.gxwebsoft.gxmu.model.DeclareCheckResult;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.gxwebsoft.gxmu.service.SjtbzbsjFormService;
|
||||
import com.gxwebsoft.gxmu.util.GxmuQueryHelper;
|
||||
import com.gxwebsoft.gxmu.util.SjtbzbsjDocxExportUtil;
|
||||
@@ -45,6 +48,8 @@ public class SjtbzbsjFormController extends BaseController {
|
||||
@Resource
|
||||
private ReviewFlowStarterService reviewFlowStarterService;
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
@Resource
|
||||
private FileRecordService fileRecordService;
|
||||
@Resource
|
||||
private OrganizationService organizationService;
|
||||
@@ -151,11 +156,21 @@ public class SjtbzbsjFormController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("添加十佳团支部书记申报表")
|
||||
@PostMapping()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResult<?> save(@RequestBody SjtbzbsjForm sjtbzbsjForm) {
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
sjtbzbsjForm.setUserId(loginUser.getUserId());
|
||||
}
|
||||
DeclareCheckResult declareCheck = declareGuardService.checkBeforeCreate("gxmu_sjtbzbsj",
|
||||
sjtbzbsjForm.getDeclareId(), sjtbzbsjForm.getYear(), sjtbzbsjForm.getUserId());
|
||||
if (declareCheck.isRejected()) {
|
||||
return fail(declareCheck.getError());
|
||||
}
|
||||
if (declareCheck.getDeclareId() != null) {
|
||||
sjtbzbsjForm.setDeclareId(declareCheck.getDeclareId());
|
||||
}
|
||||
sjtbzbsjForm.setDeclareStatus(1);
|
||||
if (sjtbzbsjFormService.save(sjtbzbsjForm)) {
|
||||
reviewFlowStarterService.startReview("gxmu_sjtbzbsj", sjtbzbsjForm.getId());
|
||||
return success("添加成功");
|
||||
@@ -230,4 +245,4 @@ public class SjtbzbsjFormController extends BaseController {
|
||||
private String valueOf(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,10 @@ import com.gxwebsoft.common.system.entity.User;
|
||||
import com.gxwebsoft.gxmu.entity.TzbcyForm;
|
||||
import com.gxwebsoft.gxmu.model.TzbcyStatisticsResult;
|
||||
import com.gxwebsoft.gxmu.param.TzbcyFormParam;
|
||||
import com.gxwebsoft.gxmu.model.DeclareCheckResult;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import com.gxwebsoft.gxmu.service.ReviewFlowStarterService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.gxwebsoft.gxmu.service.TzbcyFormService;
|
||||
import com.gxwebsoft.gxmu.util.GxmuQueryHelper;
|
||||
import com.gxwebsoft.gxmu.util.TzbcyFormItemNormalizer;
|
||||
@@ -36,6 +39,8 @@ public class TzbcyFormController extends BaseController {
|
||||
private TzbcyFormService tzbcyFormService;
|
||||
@Resource
|
||||
private ReviewFlowStarterService reviewFlowStarterService;
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
|
||||
@ApiOperation("分页查询挑战杯创业计划竞赛申报表")
|
||||
@GetMapping("/page")
|
||||
@@ -87,12 +92,26 @@ public class TzbcyFormController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("添加挑战杯创业计划竞赛申报表")
|
||||
@PostMapping()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResult<?> save(@RequestBody TzbcyForm tzbcyForm) {
|
||||
normalizeForm(tzbcyForm);
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
tzbcyForm.setUserId(loginUser.getUserId());
|
||||
}
|
||||
DeclareCheckResult declareCheck = declareGuardService.checkBeforeCreate("gxmu_tzbcy_form",
|
||||
tzbcyForm.getDeclareId(), tzbcyForm.getYear(), tzbcyForm.getUserId());
|
||||
if (declareCheck.isRejected()) {
|
||||
return fail(declareCheck.getError());
|
||||
}
|
||||
if (declareCheck.getDeclareId() != null) {
|
||||
tzbcyForm.setDeclareId(declareCheck.getDeclareId());
|
||||
}
|
||||
String teamError = checkTeamRepeat(tzbcyForm, null);
|
||||
if (teamError != null) {
|
||||
return fail(teamError);
|
||||
}
|
||||
tzbcyForm.setDeclareStatus(1);
|
||||
if (tzbcyFormService.save(tzbcyForm)) {
|
||||
reviewFlowStarterService.startReview("gxmu_tzbcy_form", tzbcyForm.getId());
|
||||
return success("添加成功");
|
||||
@@ -105,6 +124,16 @@ public class TzbcyFormController extends BaseController {
|
||||
@PutMapping()
|
||||
public ApiResult<?> update(@RequestBody TzbcyForm tzbcyForm) {
|
||||
normalizeForm(tzbcyForm);
|
||||
if (tzbcyForm.getDeclareId() == null && tzbcyForm.getId() != null) {
|
||||
TzbcyForm existing = tzbcyFormService.getById(tzbcyForm.getId());
|
||||
if (existing != null) {
|
||||
tzbcyForm.setDeclareId(existing.getDeclareId());
|
||||
}
|
||||
}
|
||||
String teamError = checkTeamRepeat(tzbcyForm, tzbcyForm.getId());
|
||||
if (teamError != null) {
|
||||
return fail(teamError);
|
||||
}
|
||||
if (tzbcyFormService.updateById(tzbcyForm)) {
|
||||
reviewFlowStarterService.restartReviewWhenLastRejected("gxmu_tzbcy_form", tzbcyForm.getId());
|
||||
return success("修改成功");
|
||||
@@ -170,4 +199,16 @@ public class TzbcyFormController extends BaseController {
|
||||
private boolean hasText(String value) {
|
||||
return value != null && !value.trim().isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/** 团队成员手机号在本项目内不得重复(见 ADR 0005) */
|
||||
private String checkTeamRepeat(TzbcyForm form, Integer excludeRecordId) {
|
||||
List<String> memberPhones = form.getTeamMembers() == null ? null
|
||||
: form.getTeamMembers().stream()
|
||||
.filter(java.util.Objects::nonNull)
|
||||
.map(TzbcyForm.TeamMember::getPhone)
|
||||
.collect(Collectors.toList());
|
||||
return declareGuardService.checkTeamPhones("gxmu_tzbcy_form", form.getDeclareId(),
|
||||
excludeRecordId, form.getPhone(), memberPhones);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,6 +15,9 @@ import com.gxwebsoft.common.system.service.OrganizationService;
|
||||
import com.gxwebsoft.gxmu.entity.WshqtwForm;
|
||||
import com.gxwebsoft.gxmu.param.WshqtwFormParam;
|
||||
import com.gxwebsoft.gxmu.service.ReviewFlowStarterService;
|
||||
import com.gxwebsoft.gxmu.model.DeclareCheckResult;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.gxwebsoft.gxmu.service.WshqtwFormService;
|
||||
import com.gxwebsoft.gxmu.util.GxmuQueryHelper;
|
||||
import com.gxwebsoft.gxmu.util.WshqtwDocxExportUtil;
|
||||
@@ -45,6 +48,8 @@ public class WshqtwFormController extends BaseController {
|
||||
@Resource
|
||||
private ReviewFlowStarterService reviewFlowStarterService;
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
@Resource
|
||||
private FileRecordService fileRecordService;
|
||||
@Resource
|
||||
private OrganizationService organizationService;
|
||||
@@ -146,11 +151,21 @@ public class WshqtwFormController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("添加五四红旗团委申报表")
|
||||
@PostMapping()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResult<?> save(@RequestBody WshqtwForm wshqtwForm) {
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
wshqtwForm.setUserId(loginUser.getUserId());
|
||||
}
|
||||
DeclareCheckResult declareCheck = declareGuardService.checkBeforeCreate("gxmu_wshqtw",
|
||||
wshqtwForm.getDeclareId(), wshqtwForm.getYear(), wshqtwForm.getUserId());
|
||||
if (declareCheck.isRejected()) {
|
||||
return fail(declareCheck.getError());
|
||||
}
|
||||
if (declareCheck.getDeclareId() != null) {
|
||||
wshqtwForm.setDeclareId(declareCheck.getDeclareId());
|
||||
}
|
||||
wshqtwForm.setDeclareStatus(1);
|
||||
if (wshqtwFormService.save(wshqtwForm)) {
|
||||
reviewFlowStarterService.startReview("gxmu_wshqtw", wshqtwForm.getId());
|
||||
return success("添加成功");
|
||||
@@ -225,4 +240,4 @@ public class WshqtwFormController extends BaseController {
|
||||
private String valueOf(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,9 @@ import com.gxwebsoft.common.system.service.OrganizationService;
|
||||
import com.gxwebsoft.gxmu.entity.WshqtzbForm;
|
||||
import com.gxwebsoft.gxmu.param.WshqtzbFormParam;
|
||||
import com.gxwebsoft.gxmu.service.ReviewFlowStarterService;
|
||||
import com.gxwebsoft.gxmu.model.DeclareCheckResult;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.gxwebsoft.gxmu.service.WshqtzbFormService;
|
||||
import com.gxwebsoft.gxmu.util.GxmuQueryHelper;
|
||||
import com.gxwebsoft.gxmu.util.WshqtzbDocxExportUtil;
|
||||
@@ -43,6 +46,8 @@ public class WshqtzbFormController extends BaseController {
|
||||
@Resource
|
||||
private ReviewFlowStarterService reviewFlowStarterService;
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
@Resource
|
||||
private FileRecordService fileRecordService;
|
||||
@Resource
|
||||
private OrganizationService organizationService;
|
||||
@@ -144,11 +149,21 @@ public class WshqtzbFormController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("添加五四红旗团支部申报表")
|
||||
@PostMapping()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResult<?> save(@RequestBody WshqtzbForm wshqtzbForm) {
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
wshqtzbForm.setUserId(loginUser.getUserId());
|
||||
}
|
||||
DeclareCheckResult declareCheck = declareGuardService.checkBeforeCreate("gxmu_wshqtzb",
|
||||
wshqtzbForm.getDeclareId(), wshqtzbForm.getYear(), wshqtzbForm.getUserId());
|
||||
if (declareCheck.isRejected()) {
|
||||
return fail(declareCheck.getError());
|
||||
}
|
||||
if (declareCheck.getDeclareId() != null) {
|
||||
wshqtzbForm.setDeclareId(declareCheck.getDeclareId());
|
||||
}
|
||||
wshqtzbForm.setDeclareStatus(1);
|
||||
if (wshqtzbFormService.save(wshqtzbForm)) {
|
||||
reviewFlowStarterService.startReview("gxmu_wshqtzb", wshqtzbForm.getId());
|
||||
return success("添加成功");
|
||||
@@ -223,4 +238,4 @@ public class WshqtzbFormController extends BaseController {
|
||||
private String valueOf(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,9 @@ import com.gxwebsoft.gxmu.param.WxxzxMaterialUpdateParam;
|
||||
import com.gxwebsoft.gxmu.param.WxxzxFormParam;
|
||||
import com.gxwebsoft.gxmu.service.QmgcFormService;
|
||||
import com.gxwebsoft.gxmu.service.ReviewFlowStarterService;
|
||||
import com.gxwebsoft.gxmu.model.DeclareCheckResult;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.gxwebsoft.gxmu.service.SjqnFormService;
|
||||
import com.gxwebsoft.gxmu.service.SjtbzbsjFormService;
|
||||
import com.gxwebsoft.gxmu.service.TzbcyFormService;
|
||||
@@ -115,6 +118,8 @@ public class WxxzxFormController extends BaseController {
|
||||
@Resource
|
||||
private ReviewFlowStarterService reviewFlowStarterService;
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
@Resource
|
||||
private FileRecordService fileRecordService;
|
||||
|
||||
@Value("${config.upload-path}")
|
||||
@@ -243,11 +248,21 @@ public class WxxzxFormController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("添加未来学术之星课题申报表")
|
||||
@PostMapping()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResult<?> save(@RequestBody WxxzxForm wxxzxForm) {
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
wxxzxForm.setUserId(loginUser.getUserId());
|
||||
}
|
||||
DeclareCheckResult declareCheck = declareGuardService.checkBeforeCreate("gxmu_wxxzx_project",
|
||||
wxxzxForm.getDeclareId(), wxxzxForm.getYear(), wxxzxForm.getUserId());
|
||||
if (declareCheck.isRejected()) {
|
||||
return fail(declareCheck.getError());
|
||||
}
|
||||
if (declareCheck.getDeclareId() != null) {
|
||||
wxxzxForm.setDeclareId(declareCheck.getDeclareId());
|
||||
}
|
||||
wxxzxForm.setDeclareStatus(1);
|
||||
if (wxxzxFormService.save(wxxzxForm)) {
|
||||
reviewFlowStarterService.startReview("gxmu_wxxzx_project", wxxzxForm.getId());
|
||||
return success("添加成功");
|
||||
@@ -889,4 +904,4 @@ public class WxxzxFormController extends BaseController {
|
||||
return suggestion;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,9 @@ import com.gxwebsoft.common.system.service.OrganizationService;
|
||||
import com.gxwebsoft.gxmu.entity.YxgqtdgbForm;
|
||||
import com.gxwebsoft.gxmu.param.YxgqtdgbFormParam;
|
||||
import com.gxwebsoft.gxmu.service.ReviewFlowStarterService;
|
||||
import com.gxwebsoft.gxmu.model.DeclareCheckResult;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.gxwebsoft.gxmu.service.YxgqtdgbFormService;
|
||||
import com.gxwebsoft.gxmu.util.GxmuQueryHelper;
|
||||
import com.gxwebsoft.gxmu.util.YxgqtdgbDocxExportUtil;
|
||||
@@ -43,6 +46,8 @@ public class YxgqtdgbFormController extends BaseController {
|
||||
@Resource
|
||||
private ReviewFlowStarterService reviewFlowStarterService;
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
@Resource
|
||||
private FileRecordService fileRecordService;
|
||||
@Resource
|
||||
private OrganizationService organizationService;
|
||||
@@ -144,11 +149,21 @@ public class YxgqtdgbFormController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("添加优秀共青团干部申报表")
|
||||
@PostMapping()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResult<?> save(@RequestBody YxgqtdgbForm yxgqtdgbForm) {
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
yxgqtdgbForm.setUserId(loginUser.getUserId());
|
||||
}
|
||||
DeclareCheckResult declareCheck = declareGuardService.checkBeforeCreate("gxmu_yxgqtdgb",
|
||||
yxgqtdgbForm.getDeclareId(), yxgqtdgbForm.getYear(), yxgqtdgbForm.getUserId());
|
||||
if (declareCheck.isRejected()) {
|
||||
return fail(declareCheck.getError());
|
||||
}
|
||||
if (declareCheck.getDeclareId() != null) {
|
||||
yxgqtdgbForm.setDeclareId(declareCheck.getDeclareId());
|
||||
}
|
||||
yxgqtdgbForm.setDeclareStatus(1);
|
||||
if (yxgqtdgbFormService.save(yxgqtdgbForm)) {
|
||||
reviewFlowStarterService.startReview("gxmu_yxgqtdgb", yxgqtdgbForm.getId());
|
||||
return success("添加成功");
|
||||
@@ -223,4 +238,4 @@ public class YxgqtdgbFormController extends BaseController {
|
||||
private String valueOf(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,9 @@ import com.gxwebsoft.common.system.service.OrganizationService;
|
||||
import com.gxwebsoft.gxmu.entity.YxgqtyForm;
|
||||
import com.gxwebsoft.gxmu.param.YxgqtyFormParam;
|
||||
import com.gxwebsoft.gxmu.service.ReviewFlowStarterService;
|
||||
import com.gxwebsoft.gxmu.model.DeclareCheckResult;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.gxwebsoft.gxmu.service.YxgqtyFormService;
|
||||
import com.gxwebsoft.gxmu.util.GxmuQueryHelper;
|
||||
import com.gxwebsoft.gxmu.util.YxgqtyDocxExportUtil;
|
||||
@@ -43,6 +46,8 @@ public class YxgqtyFormController extends BaseController {
|
||||
@Resource
|
||||
private ReviewFlowStarterService reviewFlowStarterService;
|
||||
@Resource
|
||||
private DeclareGuardService declareGuardService;
|
||||
@Resource
|
||||
private FileRecordService fileRecordService;
|
||||
@Resource
|
||||
private OrganizationService organizationService;
|
||||
@@ -144,11 +149,21 @@ public class YxgqtyFormController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("添加优秀共青团员申报表")
|
||||
@PostMapping()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResult<?> save(@RequestBody YxgqtyForm yxgqtyForm) {
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
yxgqtyForm.setUserId(loginUser.getUserId());
|
||||
}
|
||||
DeclareCheckResult declareCheck = declareGuardService.checkBeforeCreate("gxmu_yxgqty",
|
||||
yxgqtyForm.getDeclareId(), yxgqtyForm.getYear(), yxgqtyForm.getUserId());
|
||||
if (declareCheck.isRejected()) {
|
||||
return fail(declareCheck.getError());
|
||||
}
|
||||
if (declareCheck.getDeclareId() != null) {
|
||||
yxgqtyForm.setDeclareId(declareCheck.getDeclareId());
|
||||
}
|
||||
yxgqtyForm.setDeclareStatus(1);
|
||||
if (yxgqtyFormService.save(yxgqtyForm)) {
|
||||
reviewFlowStarterService.startReview("gxmu_yxgqty", yxgqtyForm.getId());
|
||||
return success("添加成功");
|
||||
@@ -223,4 +238,4 @@ public class YxgqtyFormController extends BaseController {
|
||||
private String valueOf(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import java.io.Serializable;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
@@ -55,6 +56,12 @@ public class Declare implements Serializable {
|
||||
|
||||
private String endTime;
|
||||
|
||||
@ApiModelProperty(value = "是否允许重复提交:0否 1是")
|
||||
private Integer allowRepeat;
|
||||
|
||||
@ApiModelProperty(value = "最多同时进行中的申报条数")
|
||||
private Integer maxPending;
|
||||
|
||||
@ApiModelProperty(value = "用户ID")
|
||||
private Integer userId;
|
||||
|
||||
@@ -71,4 +78,20 @@ public class Declare implements Serializable {
|
||||
@TableLogic
|
||||
private Integer deleted;
|
||||
|
||||
@ApiModelProperty(value = "当前用户在该项目下的最新申报状态:0草稿 1待审核 2通过 3驳回 4作废")
|
||||
@TableField(exist = false)
|
||||
private Integer myStatus;
|
||||
|
||||
@ApiModelProperty(value = "当前用户在该项目下的最新申报记录id")
|
||||
@TableField(exist = false)
|
||||
private Integer myRecordId;
|
||||
|
||||
@ApiModelProperty(value = "当前用户在该项目下的最新申报记录提交时间")
|
||||
@TableField(exist = false)
|
||||
private String mySubmitTime;
|
||||
|
||||
@ApiModelProperty(value = "当前用户在该项目下的最新申报记录状态备注")
|
||||
@TableField(exist = false)
|
||||
private String myStatusRemark;
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,15 @@ import java.util.List;
|
||||
public class QmgcForm implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("申报项目ID")
|
||||
private Integer declareId;
|
||||
|
||||
@ApiModelProperty("申报记录状态:0草稿 1待审核 2通过 3驳回 4作废")
|
||||
private Integer declareStatus;
|
||||
|
||||
@ApiModelProperty("状态备注(作废原因等)")
|
||||
private String declareRemark;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
|
||||
@@ -24,6 +24,15 @@ import java.util.List;
|
||||
public class SjqnForm implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("申报项目ID")
|
||||
private Integer declareId;
|
||||
|
||||
@ApiModelProperty("申报记录状态:0草稿 1待审核 2通过 3驳回 4作废")
|
||||
private Integer declareStatus;
|
||||
|
||||
@ApiModelProperty("状态备注(作废原因等)")
|
||||
private String declareRemark;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
|
||||
@@ -24,6 +24,15 @@ import java.util.List;
|
||||
public class SjtbzbsjForm implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("申报项目ID")
|
||||
private Integer declareId;
|
||||
|
||||
@ApiModelProperty("申报记录状态:0草稿 1待审核 2通过 3驳回 4作废")
|
||||
private Integer declareStatus;
|
||||
|
||||
@ApiModelProperty("状态备注(作废原因等)")
|
||||
private String declareRemark;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
|
||||
@@ -25,6 +25,15 @@ import java.util.List;
|
||||
public class TzbcyForm implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("申报项目ID")
|
||||
private Integer declareId;
|
||||
|
||||
@ApiModelProperty("申报记录状态:0草稿 1待审核 2通过 3驳回 4作废")
|
||||
private Integer declareStatus;
|
||||
|
||||
@ApiModelProperty("状态备注(作废原因等)")
|
||||
private String declareRemark;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
|
||||
@@ -24,6 +24,15 @@ import java.util.List;
|
||||
public class WshqtwForm implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("申报项目ID")
|
||||
private Integer declareId;
|
||||
|
||||
@ApiModelProperty("申报记录状态:0草稿 1待审核 2通过 3驳回 4作废")
|
||||
private Integer declareStatus;
|
||||
|
||||
@ApiModelProperty("状态备注(作废原因等)")
|
||||
private String declareRemark;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
|
||||
@@ -20,6 +20,15 @@ import java.util.List;
|
||||
public class WshqtzbForm implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("申报项目ID")
|
||||
private Integer declareId;
|
||||
|
||||
@ApiModelProperty("申报记录状态:0草稿 1待审核 2通过 3驳回 4作废")
|
||||
private Integer declareStatus;
|
||||
|
||||
@ApiModelProperty("状态备注(作废原因等)")
|
||||
private String declareRemark;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
|
||||
@@ -24,6 +24,15 @@ import java.util.List;
|
||||
public class WxxzxForm implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("申报项目ID")
|
||||
private Integer declareId;
|
||||
|
||||
@ApiModelProperty("申报记录状态:0草稿 1待审核 2通过 3驳回 4作废")
|
||||
private Integer declareStatus;
|
||||
|
||||
@ApiModelProperty("状态备注(作废原因等)")
|
||||
private String declareRemark;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
|
||||
@@ -24,6 +24,15 @@ import java.util.List;
|
||||
public class YxgqtdgbForm implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("申报项目ID")
|
||||
private Integer declareId;
|
||||
|
||||
@ApiModelProperty("申报记录状态:0草稿 1待审核 2通过 3驳回 4作废")
|
||||
private Integer declareStatus;
|
||||
|
||||
@ApiModelProperty("状态备注(作废原因等)")
|
||||
private String declareRemark;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
|
||||
@@ -24,6 +24,15 @@ import java.util.List;
|
||||
public class YxgqtyForm implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("申报项目ID")
|
||||
private Integer declareId;
|
||||
|
||||
@ApiModelProperty("申报记录状态:0草稿 1待审核 2通过 3驳回 4作废")
|
||||
private Integer declareStatus;
|
||||
|
||||
@ApiModelProperty("状态备注(作废原因等)")
|
||||
private String declareRemark;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.gxwebsoft.gxmu.mapper;
|
||||
|
||||
import com.gxwebsoft.gxmu.entity.Declare;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 申报记录跨模块查询(同一申报项目的重复申报限制)
|
||||
*
|
||||
* <p>table 只接受 {@link com.gxwebsoft.gxmu.service.DeclareGuardService} 白名单里的模块名,
|
||||
* 调用方不得把用户输入直接传进来。</p>
|
||||
*/
|
||||
@Mapper
|
||||
public interface DeclareRecordMapper {
|
||||
|
||||
/** 锁定申报项目行,串行化同一项目的并发提交 */
|
||||
@Select("SELECT * FROM gxmu_declare WHERE id = #{id} AND deleted = 0 FOR UPDATE")
|
||||
Declare lockDeclare(@Param("id") Integer id);
|
||||
|
||||
/** 某用户在某申报项目下、处于某状态的记录数 */
|
||||
@Select("SELECT COUNT(*) FROM ${table} WHERE declare_id = #{declareId} AND user_id = #{userId} "
|
||||
+ "AND declare_status = #{status} AND deleted = 0")
|
||||
int countByStatus(@Param("table") String table,
|
||||
@Param("declareId") Integer declareId,
|
||||
@Param("userId") Integer userId,
|
||||
@Param("status") Integer status);
|
||||
|
||||
/** 某用户在某申报项目下最近的一条记录 */
|
||||
@Select("SELECT id AS id, declare_status AS declareStatus, create_time AS createTime, declare_remark AS declareRemark "
|
||||
+ "FROM ${table} WHERE declare_id = #{declareId} AND user_id = #{userId} AND deleted = 0 "
|
||||
+ "ORDER BY id DESC LIMIT 1")
|
||||
Map<String, Object> selectLatestUserRecord(@Param("table") String table,
|
||||
@Param("declareId") Integer declareId,
|
||||
@Param("userId") Integer userId);
|
||||
|
||||
/** 某用户在某申报项目下的全部记录(申报项目列表回显本人状态用) */
|
||||
@Select("SELECT id AS id, declare_id AS declareId, declare_status AS declareStatus, create_time AS createTime, "
|
||||
+ "declare_remark AS declareRemark FROM ${table} WHERE user_id = #{userId} AND deleted = 0 ORDER BY id DESC")
|
||||
List<Map<String, Object>> selectUserRecords(@Param("table") String table, @Param("userId") Integer userId);
|
||||
|
||||
/** 单条记录(撤回 / 作废时校验归属) */
|
||||
@Select("SELECT id AS id, user_id AS userId, declare_id AS declareId, declare_status AS declareStatus "
|
||||
+ "FROM ${table} WHERE id = #{id} AND deleted = 0")
|
||||
Map<String, Object> selectRecord(@Param("table") String table, @Param("id") Integer id);
|
||||
|
||||
/** 同项目下其他有效申报的负责人手机号与团队成员,用于团队重复校验 */
|
||||
@Select("SELECT id AS id, phone AS phone, team_members AS teamMembers FROM gxmu_tzbcy_form "
|
||||
+ "WHERE declare_id = #{declareId} AND declare_status IN (1, 2, 3) AND deleted = 0 "
|
||||
+ "AND id <> #{excludeId}")
|
||||
List<Map<String, Object>> selectTzbcyTeamPhones(@Param("declareId") Integer declareId,
|
||||
@Param("excludeId") Integer excludeId);
|
||||
|
||||
/** 更新申报记录状态(草稿 / 待审核 / 通过 / 驳回 / 作废) */
|
||||
@Update("UPDATE ${table} SET declare_status = #{status}, declare_remark = #{remark}, update_time = NOW() "
|
||||
+ "WHERE id = #{id} AND deleted = 0")
|
||||
int updateStatus(@Param("table") String table,
|
||||
@Param("id") Integer id,
|
||||
@Param("status") Integer status,
|
||||
@Param("remark") String remark);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.gxwebsoft.gxmu.model;
|
||||
|
||||
/**
|
||||
* 申报提交前的校验结果。
|
||||
*
|
||||
* <p>三种形态:不适用(模块不在申报规则内)、被拒绝(带用户可读原因)、通过(带解析出的申报项目 id)。</p>
|
||||
*/
|
||||
public class DeclareCheckResult {
|
||||
private final boolean applicable;
|
||||
private final String error;
|
||||
private final Integer declareId;
|
||||
|
||||
private DeclareCheckResult(boolean applicable, String error, Integer declareId) {
|
||||
this.applicable = applicable;
|
||||
this.error = error;
|
||||
this.declareId = declareId;
|
||||
}
|
||||
|
||||
public static DeclareCheckResult skip() {
|
||||
return new DeclareCheckResult(false, null, null);
|
||||
}
|
||||
|
||||
public static DeclareCheckResult reject(String error) {
|
||||
return new DeclareCheckResult(true, error, null);
|
||||
}
|
||||
|
||||
public static DeclareCheckResult pass(Integer declareId) {
|
||||
return new DeclareCheckResult(true, null, declareId);
|
||||
}
|
||||
|
||||
public boolean isApplicable() {
|
||||
return applicable;
|
||||
}
|
||||
|
||||
public boolean isRejected() {
|
||||
return error != null;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public Integer getDeclareId() {
|
||||
return declareId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.gxwebsoft.gxmu.param;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 申报记录状态操作参数(撤回 / 作废)
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "DeclareRecordActionParam", description = "申报记录状态操作参数")
|
||||
public class DeclareRecordActionParam {
|
||||
|
||||
@ApiModelProperty("申报模块,同时也是表名")
|
||||
private String module;
|
||||
|
||||
@ApiModelProperty("申报记录id")
|
||||
private Integer id;
|
||||
|
||||
@ApiModelProperty("作废原因")
|
||||
private String reason;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.gxwebsoft.gxmu.service;
|
||||
|
||||
import com.gxwebsoft.gxmu.model.DeclareCheckResult;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 申报项目重复申报限制(见 docs/adr/0005-declare-uniqueness.md)。
|
||||
*
|
||||
* <p>规则:同一用户对同一申报项目,处于「待审核」的记录数不得超过项目配置的上限(默认 1);
|
||||
* 「通过」后该项目对本人关闭;「驳回」后必须修改原记录重新提交。</p>
|
||||
*/
|
||||
public interface DeclareGuardService {
|
||||
|
||||
/** 该模块是否走申报项目判重(9 张申报表) */
|
||||
boolean supports(String module);
|
||||
|
||||
/**
|
||||
* 提交前校验。
|
||||
*
|
||||
* @param module 申报模块(同时也是表名)
|
||||
* @param declareId 前端透传的申报项目 id,可为空
|
||||
* @param year 申报年度,declareId 为空时按「模块 + 年度」唯一解析
|
||||
* @param userId 提交人
|
||||
* @return 不适用 / 拒绝(带原因)/ 通过(带解析出的 declareId)
|
||||
*/
|
||||
DeclareCheckResult checkBeforeCreate(String module, Integer declareId, Integer year, Integer userId);
|
||||
|
||||
/**
|
||||
* 挑战杯团队成员重复校验:同一手机号不得出现在同一申报项目的两份申报里。
|
||||
*
|
||||
* @return 拒绝原因,null 表示通过
|
||||
*/
|
||||
String checkTeamPhones(String module, Integer declareId, Integer excludeRecordId,
|
||||
String leaderPhone, List<String> memberPhones);
|
||||
|
||||
/** 按审核节点的最新状态回写申报记录状态 */
|
||||
void syncReviewStatus(String module, Integer recordId);
|
||||
|
||||
/** 撤回:待审核 -> 草稿;任意一级审核通过后不再允许 */
|
||||
String withdraw(String module, Integer recordId, Integer userId, boolean admin);
|
||||
|
||||
/** 作废:置为终态,释放名额,记录仍对申报人可见 */
|
||||
String voidRecord(String module, Integer recordId, String reason);
|
||||
|
||||
/** 当前用户在各申报项目下的最新记录状态,key = declareId */
|
||||
Map<Integer, Map<String, Object>> myDeclareStatus(String module, Integer userId);
|
||||
|
||||
/** 记录当前状态值,找不到返回 null */
|
||||
Integer statusOf(String module, Integer recordId);
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
package com.gxwebsoft.gxmu.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.gxwebsoft.gxmu.entity.Declare;
|
||||
import com.gxwebsoft.gxmu.entity.ReviewList;
|
||||
import com.gxwebsoft.gxmu.mapper.DeclareRecordMapper;
|
||||
import com.gxwebsoft.gxmu.model.DeclareCheckResult;
|
||||
import com.gxwebsoft.gxmu.service.DeclareGuardService;
|
||||
import com.gxwebsoft.gxmu.service.DeclareService;
|
||||
import com.gxwebsoft.gxmu.service.ReviewListService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 申报项目重复申报限制实现,见 docs/adr/0005-declare-uniqueness.md
|
||||
*/
|
||||
@Service
|
||||
public class DeclareGuardServiceImpl implements DeclareGuardService {
|
||||
|
||||
/** 申报记录状态:0 草稿 / 1 待审核 / 2 通过 / 3 驳回 / 4 作废 */
|
||||
public static final int STATUS_DRAFT = 0;
|
||||
public static final int STATUS_PENDING = 1;
|
||||
public static final int STATUS_PASSED = 2;
|
||||
public static final int STATUS_REJECTED = 3;
|
||||
public static final int STATUS_VOID = 4;
|
||||
|
||||
/** 走申报项目判重的 9 个模块,模块名同时是表名 */
|
||||
private static final Set<String> MODULES = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(
|
||||
"gxmu_sjqn", "gxmu_sjtbzbsj", "gxmu_wshqtw", "gxmu_wshqtzb",
|
||||
"gxmu_yxgqtdgb", "gxmu_yxgqty", "gxmu_tzbcy_form", "gxmu_qmgc_form",
|
||||
"gxmu_wxxzx_project")));
|
||||
|
||||
private static final String TZBCY_MODULE = "gxmu_tzbcy_form";
|
||||
private static final DateTimeFormatter DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Resource
|
||||
private DeclareRecordMapper declareRecordMapper;
|
||||
@Resource
|
||||
private DeclareService declareService;
|
||||
@Resource
|
||||
private ReviewListService reviewListService;
|
||||
|
||||
@Override
|
||||
public boolean supports(String module) {
|
||||
return module != null && MODULES.contains(module);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public DeclareCheckResult checkBeforeCreate(String module, Integer declareId, Integer year, Integer userId) {
|
||||
if (!supports(module) || userId == null) {
|
||||
return DeclareCheckResult.skip();
|
||||
}
|
||||
Declare declare = null;
|
||||
if (declareId != null) {
|
||||
declare = declareRecordMapper.lockDeclare(declareId);
|
||||
if (declare == null) {
|
||||
return DeclareCheckResult.reject("申报项目不存在或已下架");
|
||||
}
|
||||
if (!module.equals(declare.getModule())) {
|
||||
return DeclareCheckResult.reject("申报项目与当前申报表不匹配");
|
||||
}
|
||||
} else if (year != null) {
|
||||
List<Declare> matched = declareService.list(new LambdaQueryWrapper<Declare>()
|
||||
.eq(Declare::getModule, module)
|
||||
.eq(Declare::getYear, year));
|
||||
if (matched.size() > 1) {
|
||||
return DeclareCheckResult.reject("存在多条同年度申报项目,请从申报项目列表进入");
|
||||
}
|
||||
if (matched.size() == 1) {
|
||||
declare = declareRecordMapper.lockDeclare(matched.get(0).getId());
|
||||
}
|
||||
}
|
||||
if (declare == null) {
|
||||
// 该模块还没配置对应的申报项目:不套用重复申报限制
|
||||
return DeclareCheckResult.skip();
|
||||
}
|
||||
Integer declareIdValue = declare.getId();
|
||||
if (declareRecordMapper.countByStatus(module, declareIdValue, userId, STATUS_PASSED) > 0) {
|
||||
return DeclareCheckResult.reject("该项目你已通过,不能重复申报");
|
||||
}
|
||||
if (declareRecordMapper.countByStatus(module, declareIdValue, userId, STATUS_REJECTED) > 0) {
|
||||
return DeclareCheckResult.reject("该项目有一份被驳回的申报,请修改原申报后重新提交");
|
||||
}
|
||||
int maxPending = effectiveMaxPending(declare);
|
||||
int pending = declareRecordMapper.countByStatus(module, declareIdValue, userId, STATUS_PENDING);
|
||||
if (pending >= maxPending) {
|
||||
Map<String, Object> latest =
|
||||
declareRecordMapper.selectLatestUserRecord(module, declareIdValue, userId);
|
||||
if (pending == 1) {
|
||||
return DeclareCheckResult.reject("该项目你已申报过,当前状态:审核中(提交于 "
|
||||
+ formatDate(latest == null ? null : latest.get("createTime")) + ")");
|
||||
}
|
||||
return DeclareCheckResult.reject("该项目已有 " + pending + " 条审核中的申报,最多允许 "
|
||||
+ maxPending + " 条");
|
||||
}
|
||||
return DeclareCheckResult.pass(declareIdValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String checkTeamPhones(String module, Integer declareId, Integer excludeRecordId,
|
||||
String leaderPhone, List<String> memberPhones) {
|
||||
if (!TZBCY_MODULE.equals(module) || declareId == null) {
|
||||
return null;
|
||||
}
|
||||
Set<String> incoming = new LinkedHashSet<>();
|
||||
addPhone(incoming, leaderPhone);
|
||||
if (memberPhones != null) {
|
||||
for (String phone : memberPhones) {
|
||||
addPhone(incoming, phone);
|
||||
}
|
||||
}
|
||||
if (incoming.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
List<Map<String, Object>> rows =
|
||||
declareRecordMapper.selectTzbcyTeamPhones(declareId, excludeRecordId == null ? 0 : excludeRecordId);
|
||||
for (Map<String, Object> row : rows) {
|
||||
Set<String> existing = new HashSet<>();
|
||||
addPhone(existing, asString(row.get("phone")));
|
||||
for (String phone : parseTeamPhones(asString(row.get("teamMembers")))) {
|
||||
addPhone(existing, phone);
|
||||
}
|
||||
for (String phone : incoming) {
|
||||
if (existing.contains(phone)) {
|
||||
return "手机号 " + phone + " 已出现在该项目的另一份申报中,团队成员不能重复申报";
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncReviewStatus(String module, Integer recordId) {
|
||||
if (!supports(module) || recordId == null) {
|
||||
return;
|
||||
}
|
||||
List<ReviewList> nodes = reviewListService.listByModuleNPK(module, recordId);
|
||||
if (nodes == null || nodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
boolean pending = nodes.stream()
|
||||
.anyMatch(node -> node.getStatus() != null && node.getStatus() == 0);
|
||||
if (pending) {
|
||||
declareRecordMapper.updateStatus(module, recordId, STATUS_PENDING, null);
|
||||
return;
|
||||
}
|
||||
ReviewList last = nodes.stream()
|
||||
.max((left, right) -> {
|
||||
int sortLeft = left.getSortNumber() == null ? 0 : left.getSortNumber();
|
||||
int sortRight = right.getSortNumber() == null ? 0 : right.getSortNumber();
|
||||
if (sortLeft != sortRight) {
|
||||
return Integer.compare(sortLeft, sortRight);
|
||||
}
|
||||
int idLeft = left.getId() == null ? 0 : left.getId();
|
||||
int idRight = right.getId() == null ? 0 : right.getId();
|
||||
return Integer.compare(idLeft, idRight);
|
||||
})
|
||||
.orElse(null);
|
||||
if (last == null || last.getStatus() == null) {
|
||||
return;
|
||||
}
|
||||
declareRecordMapper.updateStatus(module, recordId,
|
||||
last.getStatus() == 2 ? STATUS_REJECTED : STATUS_PASSED, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String withdraw(String module, Integer recordId, Integer userId, boolean admin) {
|
||||
if (!supports(module)) {
|
||||
return "当前模块不支持撤回";
|
||||
}
|
||||
Map<String, Object> record = declareRecordMapper.selectRecord(module, recordId);
|
||||
if (record == null) {
|
||||
return "申报记录不存在";
|
||||
}
|
||||
if (!admin && !Objects.equals(userId, asInteger(record.get("userId")))) {
|
||||
return "只能撤回自己的申报";
|
||||
}
|
||||
if (asInteger(record.get("declareStatus")) != STATUS_PENDING) {
|
||||
return "只有待审核的申报可以撤回";
|
||||
}
|
||||
boolean approved = reviewListService.listByModuleNPK(module, recordId).stream()
|
||||
.anyMatch(node -> node.getStatus() != null && node.getStatus() == 1);
|
||||
if (approved) {
|
||||
return "已有审核通过的记录不能撤回,请联系管理员处理";
|
||||
}
|
||||
removeReviewNodes(module, recordId);
|
||||
declareRecordMapper.updateStatus(module, recordId, STATUS_DRAFT, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String voidRecord(String module, Integer recordId, String reason) {
|
||||
if (!supports(module)) {
|
||||
return "当前模块不支持作废";
|
||||
}
|
||||
Map<String, Object> record = declareRecordMapper.selectRecord(module, recordId);
|
||||
if (record == null) {
|
||||
return "申报记录不存在";
|
||||
}
|
||||
if (asInteger(record.get("declareStatus")) == STATUS_VOID) {
|
||||
return "该申报已作废";
|
||||
}
|
||||
removeReviewNodes(module, recordId);
|
||||
declareRecordMapper.updateStatus(module, recordId, STATUS_VOID, reason);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, Map<String, Object>> myDeclareStatus(String module, Integer userId) {
|
||||
Map<Integer, Map<String, Object>> result = new LinkedHashMap<>();
|
||||
if (!supports(module) || userId == null) {
|
||||
return result;
|
||||
}
|
||||
for (Map<String, Object> row : declareRecordMapper.selectUserRecords(module, userId)) {
|
||||
Integer declareId = asInteger(row.get("declareId"));
|
||||
if (declareId == null || result.containsKey(declareId)) {
|
||||
continue;
|
||||
}
|
||||
result.put(declareId, row);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer statusOf(String module, Integer recordId) {
|
||||
if (!supports(module) || recordId == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> record = declareRecordMapper.selectRecord(module, recordId);
|
||||
return record == null ? null : asInteger(record.get("declareStatus"));
|
||||
}
|
||||
|
||||
private void removeReviewNodes(String module, Integer recordId) {
|
||||
reviewListService.remove(new LambdaQueryWrapper<ReviewList>()
|
||||
.eq(ReviewList::getModule, module)
|
||||
.eq(ReviewList::getPk, recordId));
|
||||
}
|
||||
|
||||
private int effectiveMaxPending(Declare declare) {
|
||||
if (declare.getAllowRepeat() != null && declare.getAllowRepeat() == 1) {
|
||||
Integer configured = declare.getMaxPending();
|
||||
if (configured != null && configured > 0) {
|
||||
return configured;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private List<String> parseTeamPhones(String json) {
|
||||
if (json == null || json.trim().isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
try {
|
||||
List<Map<String, Object>> members = objectMapper.readValue(json,
|
||||
objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class));
|
||||
List<String> phones = new ArrayList<>();
|
||||
for (Map<String, Object> member : members) {
|
||||
Object phone = member == null ? null : member.get("phone");
|
||||
if (phone != null) {
|
||||
phones.add(String.valueOf(phone));
|
||||
}
|
||||
}
|
||||
return phones;
|
||||
} catch (Exception ignored) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private void addPhone(Set<String> target, String raw) {
|
||||
String normalized = normalizePhone(raw);
|
||||
if (normalized != null) {
|
||||
target.add(normalized);
|
||||
}
|
||||
}
|
||||
|
||||
private String normalizePhone(String raw) {
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
String digits = raw.replaceAll("[^0-9]", "");
|
||||
return digits.length() >= 7 ? digits : null;
|
||||
}
|
||||
|
||||
private String asString(Object value) {
|
||||
return value == null ? null : String.valueOf(value);
|
||||
}
|
||||
|
||||
private Integer asInteger(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).intValue();
|
||||
}
|
||||
try {
|
||||
return Integer.valueOf(String.valueOf(value));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String formatDate(Object value) {
|
||||
if (value == null) {
|
||||
return "-";
|
||||
}
|
||||
if (value instanceof LocalDateTime) {
|
||||
return ((LocalDateTime) value).format(DATE);
|
||||
}
|
||||
if (value instanceof java.sql.Timestamp) {
|
||||
return ((java.sql.Timestamp) value).toLocalDateTime().format(DATE);
|
||||
}
|
||||
if (value instanceof java.sql.Date) {
|
||||
return ((java.sql.Date) value).toLocalDate().format(DATE);
|
||||
}
|
||||
if (value instanceof LocalDate) {
|
||||
return ((LocalDate) value).format(DATE);
|
||||
}
|
||||
String text = String.valueOf(value);
|
||||
return text.length() >= 10 ? text.substring(0, 10) : text;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user