From df51d733d55bfde1a4ba72cbe1308a13bad95477 Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Wed, 20 Nov 2024 10:48:22 +0800 Subject: [PATCH 01/13] =?UTF-8?q?ureport-core=E5=8C=85=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=EF=BC=88=E4=BF=AE=E5=A4=8D=E9=A1=B5=E7=9C=89=E9=A1=B5=E8=84=9A?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E3=80=81=E5=BC=80=E6=BA=90=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?bug=E4=BF=AE=E5=A4=8D=E5=90=8C=E6=AD=A5=EF=BC=89=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/ureport-core-2.3.0-SNAPSHOT.jar | Bin 925690 -> 929339 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cf-module-report/cf-module-report-biz/src/main/resources/lib/ureport-core-2.3.0-SNAPSHOT.jar b/cf-module-report/cf-module-report-biz/src/main/resources/lib/ureport-core-2.3.0-SNAPSHOT.jar index fa2621d2e73525449c43184e7096af0ae31e1483..8e8acf0b4032b5a4c89a12aadb8a934e6b13e247 100644 GIT binary patch delta 53386 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 mmbJi{3VhZG5*WApl7s Date: Wed, 20 Nov 2024 10:42:53 +0800 Subject: [PATCH 02/13] =?UTF-8?q?1=E3=80=81=E6=A8=A1=E6=9D=BF=E5=92=8C?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=BA=90=E6=9F=A5=E8=AF=A2=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=8C=E8=B6=85=E7=AE=A1=E5=8F=AF=E7=9C=8B?= =?UTF-8?q?=E7=9A=84=E5=86=85=E5=AE=B9=E5=92=8C=E6=99=AE=E9=80=9A=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=9B=B8=E5=90=8C=EF=BC=8C=E4=BD=86=E6=98=AF=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E9=80=9A=E8=BF=87=E7=BB=84=E7=BB=87=E6=A0=91=E7=9C=8B?= =?UTF-8?q?=E5=85=B6=E4=BB=96=E7=BB=84=E7=BB=87=EF=BC=9B2=E3=80=81?= =?UTF-8?q?=E6=89=93=E5=8D=B0=E5=92=8C=E6=96=87=E4=BB=B6=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E7=A7=9F=E6=88=B7=E4=BC=98=E5=8C=96=EF=BC=9B?= =?UTF-8?q?3=E3=80=81ureport-core=E5=8C=85=E5=90=8C=E6=AD=A5=EF=BC=88?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A1=B5=E7=9C=89=E9=A1=B5=E8=84=9A=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E3=80=81=E5=BC=80=E6=BA=90=E9=A1=B9=E7=9B=AEbug?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=90=8C=E6=AD=A5=EF=BC=89=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../report/enums/ErrorCodeConstants.java | 1 + .../ReportDatasourceController.java | 4 +- .../template/ReportTemplateController.java | 6 +- .../template/vo/ReportTemplateReqVO.java | 3 + .../datasource/ReportDatasourceService.java | 4 +- .../ReportDatasourceServiceImpl.java | 20 +++--- .../template/ReportTemplateServiceImpl.java | 65 ++++++++++++++----- .../ReportDatasourceServiceImplTest.java | 2 +- 8 files changed, 75 insertions(+), 30 deletions(-) diff --git a/cf-module-report/cf-module-report-api/src/main/java/com/cf/imes/module/report/enums/ErrorCodeConstants.java b/cf-module-report/cf-module-report-api/src/main/java/com/cf/imes/module/report/enums/ErrorCodeConstants.java index a594ec997..a2425150b 100644 --- a/cf-module-report/cf-module-report-api/src/main/java/com/cf/imes/module/report/enums/ErrorCodeConstants.java +++ b/cf-module-report/cf-module-report-api/src/main/java/com/cf/imes/module/report/enums/ErrorCodeConstants.java @@ -14,6 +14,7 @@ public final class ErrorCodeConstants { public static final ErrorCode TEMPLATE_NOT_EXISTS = new ErrorCode(1_003_001_001, "报表模板信息不存在"); public static final ErrorCode TEMPLATE_BUILDIN_OPERATION_PERMISSION_ERROR = new ErrorCode(1_003_001_002, "内置模板操作权限不足"); public static final ErrorCode TEMPLATE_NAME_UNIQE_ERROR = new ErrorCode(1_003_001_003, "模板名【{}】已存在,请编辑模板名后重试"); + public static final ErrorCode TEMPLATE_PREIVEW_QUERYPARAM_EMPTY = new ErrorCode(1_003_001_004, "查询参数不能为空:{}"); // ========== UREPORT datasource模块 1-003-002-000 ========== diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/ReportDatasourceController.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/ReportDatasourceController.java index 30a62b9b4..e5272def7 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/ReportDatasourceController.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/ReportDatasourceController.java @@ -87,8 +87,8 @@ public class ReportDatasourceController { @GetMapping("/datasources") @Operation(summary = "获取报表数据源列表") @PreAuthorize("@ss.hasPermission('report:design')") - public CommonResult> getDatasourcePage() { - return success(BeanUtils.toBean(datasourceService.getDatasourceList(), ReportDatasourceRespVO.class)); + public CommonResult> getDatasourcePage(@RequestParam(value = "organId", required = false) Long organId) { + return success(BeanUtils.toBean(datasourceService.getDatasourceList(organId), ReportDatasourceRespVO.class)); } @GetMapping("/datasource/beans") diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/ReportTemplateController.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/ReportTemplateController.java index 4903eaf50..4a7b1d32a 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/ReportTemplateController.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/ReportTemplateController.java @@ -101,8 +101,10 @@ public class ReportTemplateController { @GetMapping("/templates") @Operation(summary = "获取报表模板信息列表") @PreAuthorize("@ss.hasPermission('report:design')") - public CommonResult> getTemplatePage(@RequestParam(value = "name", required = false) @Size(max = 64, message = "模板名称长度不能超过64个字符") String name) { - ReportTemplateReqVO reqVO = new ReportTemplateReqVO(name, null); + public CommonResult> getTemplatePage( + @RequestParam(value = "name", required = false) @Size(max = 64, message = "模板名称长度不能超过64个字符") String name, + @RequestParam(value = "organId", required = false) Long organId) { + ReportTemplateReqVO reqVO = new ReportTemplateReqVO(name, null, organId); return success(BeanUtils.toBean(templateService.getReportTemplateList(reqVO), ReportTemplateRespVO.class)); } diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/vo/ReportTemplateReqVO.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/vo/ReportTemplateReqVO.java index 397a40189..727350d73 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/vo/ReportTemplateReqVO.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/vo/ReportTemplateReqVO.java @@ -21,4 +21,7 @@ public class ReportTemplateReqVO { @Schema(description = "模板类型,0内置、1自定义", example = "1") private Integer type; + + @Schema(description = "组织id") + private Long organId; } diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceService.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceService.java index b602e7e75..ac7c93b0d 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceService.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceService.java @@ -49,10 +49,10 @@ public interface ReportDatasourceService { /** * 获取模板下的数据源列表 * - * @param reqVO 查询参数 + * @param organId 组织id * @return 报表数据源分页 */ - List getDatasourceList(); + List getDatasourceList(Long organId); /** * 获取springbean数据源列表 diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceServiceImpl.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceServiceImpl.java index fabd876f3..9dfd34eb1 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceServiceImpl.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceServiceImpl.java @@ -133,16 +133,21 @@ public class ReportDatasourceServiceImpl implements ReportDatasourceService { @Override @OrganIgnore - public List getDatasourceList() { + public List getDatasourceList(Long organId) { LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapperX().orderByDesc(ReportDatasourceDO::getCreateTime); - if (ObjectUtil.isNotNull(loginUser) && Boolean.FALSE.equals(loginUser.getIsSupAdmin())) { - // 普通用户查看机构下的和system数据源 - queryWrapper.or(wrapper -> wrapper - .eq(ReportDatasourceDO::getOrganId, loginUser.getOrganId()) - .eq(ReportDatasourceDO::getBuildinType, ReportTemplateTypeEnum.CUSTOM)) - .or(wrapper -> wrapper.eq(ReportDatasourceDO::getBuildinType, ReportTemplateTypeEnum.SYSTEM)); + // 当前登录人机构id + Long currentOrganId = loginUser.getOrganId(); + // 超管查看不同组织数据源 + if (ObjectUtil.isNotNull(loginUser) && Boolean.TRUE.equals(loginUser.getIsSupAdmin()) && ObjectUtil.isNotNull(organId)) { + currentOrganId = organId; } + Long finalCurrentOrganId = currentOrganId; + queryWrapper.or(wrapper -> wrapper + .eq(ReportDatasourceDO::getOrganId, finalCurrentOrganId) + .eq(ReportDatasourceDO::getBuildinType, ReportTemplateTypeEnum.CUSTOM)) + .or(wrapper -> wrapper.eq(ReportDatasourceDO::getBuildinType, ReportTemplateTypeEnum.SYSTEM)); + List reportDatasourceDOS = datasourceMapper.selectList(queryWrapper); // 查询数据集 if (CollUtil.isNotEmpty(reportDatasourceDOS)) { @@ -150,7 +155,6 @@ public class ReportDatasourceServiceImpl implements ReportDatasourceService { queryDatasetInSource(reportDatasourceDO); }); } - // 超管查看全部 return reportDatasourceDOS; } diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java index f5fb34878..e9e3baee0 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java @@ -30,6 +30,7 @@ import com.bstek.ureport.parser.ReportParser; import com.bstek.ureport.utils.ToolUtils; import com.cf.imes.framework.common.exception.ServiceException; import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants; +import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil; import com.cf.imes.framework.common.util.object.BeanUtils; import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; import com.cf.imes.framework.security.core.LoginUser; @@ -49,6 +50,7 @@ import com.cf.imes.module.report.enums.template.ReportTemplateTypeEnum; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; @@ -70,6 +72,7 @@ import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.e import static com.cf.imes.module.report.enums.ErrorCodeConstants.TEMPLATE_BUILDIN_OPERATION_PERMISSION_ERROR; import static com.cf.imes.module.report.enums.ErrorCodeConstants.TEMPLATE_NAME_UNIQE_ERROR; import static com.cf.imes.module.report.enums.ErrorCodeConstants.TEMPLATE_NOT_EXISTS; +import static com.cf.imes.module.report.enums.ErrorCodeConstants.TEMPLATE_PREIVEW_QUERYPARAM_EMPTY; /** * 报表模板信息 Service 实现类 @@ -340,28 +343,56 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { @Override public List getReportTemplateList(ReportTemplateReqVO reqVO) { LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapperX().likeIfPresent(ReportTemplateDO::getName, reqVO.getName()) - .orderByDesc(ReportTemplateDO::getCreateTime) - // 不返回content xml,点击具体的模板中返回xml - .select(ReportTemplateDO::getId, ReportTemplateDO::getName, ReportTemplateDO::getCreateTime, ReportTemplateDO::getRemark, ReportTemplateDO::getType); - if (ObjectUtil.isNotNull(loginUser) && Boolean.FALSE.equals(loginUser.getIsSupAdmin())) { - return templateMapper.selectNormalTemplateList(reqVO.getName(), loginUser.getOrganId()); - } else { - // 超管查看全部 - return templateMapper.selectList(queryWrapper); + // 当前登录人机构id + Long organId = loginUser.getOrganId(); + // 超管查看不同组织模板 + if (ObjectUtil.isNotNull(loginUser) && Boolean.TRUE.equals(loginUser.getIsSupAdmin()) && ObjectUtil.isNotNull(reqVO.getOrganId())) { + organId = reqVO.getOrganId(); + } + return templateMapper.selectNormalTemplateList(reqVO.getName(), organId); + } + + /** + * 检查查询参数不为空 + * + * @param queryMap + */ + private void checkQueryNotEmpty(Map queryMap) { + if (ObjectUtil.isNotNull(queryMap)) { + for (Map.Entry entry : queryMap.entrySet()) { + String key = entry.getKey(); + if (ObjectUtils.isEmpty(entry.getValue()) && (ObjectUtil.notEqual(key, "datasetIds") || ObjectUtil.notEqual(key, "datasourceIds "))) { + throw ServiceExceptionUtil.exception(TEMPLATE_PREIVEW_QUERYPARAM_EMPTY, key); + } + } } } @Override public HtmlReport preview(ReportTemplatePreviewReqVO reqVO) { + // 检查查询参数中的空值 + checkQueryNotEmpty(reqVO.getQuery()); // 自定义请求vo转ureport对象 PreviewParameters params = BeanUtils.toBean(reqVO, PreviewParameters.class); - Long userOrganId = SecurityFrameworkUtils.getUserOrganId(); HtmlProducer htmlProducer = new HtmlProducer(); ReportRender reportRender = new ReportRender(); ReportDefinition reportDefinition = getReportDefinition(reportRender, params); Map parameters = params.getQuery(); + // 增加多租户参数 + prepareTenantParam(parameters); + Report report = reportRender.render(reportDefinition, parameters); + return htmlProducer.produce(reportDefinition, report); + } + + + /** + * 往parameters中增加租户相关参数 + * + * @param parameters + */ + private void prepareTenantParam(Map parameters) { + Long userOrganId = SecurityFrameworkUtils.getUserOrganId(); if (Boolean.FALSE.equals(SecurityFrameworkUtils.isSuperAdmin())) { // 根据前端传递的数据集id,判断是不是内置数据源下的,是就把name传给ureport List datasetIds = (List) parameters.get("datasetIds"); @@ -375,7 +406,7 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { // 查询数据源,如果是内置数据源则把数据集的name传给ureport // 机构下 + 内置数据源查询 ReportDatasourceDO datasourceDO = datasourceMapper.selectNormalDatasourceById(datasourceId, userOrganId); - if (ObjectUtil.equal(datasourceDO.getBuildinType(), ReportTemplateTypeEnum.SYSTEM)) { + if (ObjectUtil.isNotNull(datasourceDO) && ObjectUtil.equal(datasourceDO.getBuildinType(), ReportTemplateTypeEnum.SYSTEM)) { buildinDsNames.add(datasetDO.getName()); } } @@ -388,8 +419,6 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { // 用户组织id parameters.put("organId", userOrganId); } - Report report = reportRender.render(reportDefinition, parameters); - return htmlProducer.produce(reportDefinition, report); } @Override @@ -400,7 +429,10 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { long start = System.currentTimeMillis(); ReportRender reportRender = new ReportRender(); ReportDefinition reportDefinition = getReportDefinition(reportRender, params); - Report report = reportRender.render(reportDefinition, params.getQuery()); + Map query = params.getQuery(); + // 增加多租户参数 + prepareTenantParam(query); + Report report = reportRender.render(reportDefinition, query); Map chartImages = params.getChartImages(); report.setChartImages(chartImages); try { @@ -427,7 +459,10 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { ReportRender reportRender = new ReportRender(); ReportDefinition reportDefinition = getReportDefinition(reportRender, params); - Report report = reportRender.render(reportDefinition, params.getQuery()); + Map query = params.getQuery(); + // 增加多租户参数 + prepareTenantParam(query); + Report report = reportRender.render(reportDefinition, query); Map chartImages = params.getChartImages(); report.setChartImages(chartImages); try { diff --git a/cf-module-report/cf-module-report-biz/src/test/java/com/cf/imes/module/report/service/template/ReportDatasourceServiceImplTest.java b/cf-module-report/cf-module-report-biz/src/test/java/com/cf/imes/module/report/service/template/ReportDatasourceServiceImplTest.java index 63670c962..4cc9aaed1 100644 --- a/cf-module-report/cf-module-report-biz/src/test/java/com/cf/imes/module/report/service/template/ReportDatasourceServiceImplTest.java +++ b/cf-module-report/cf-module-report-biz/src/test/java/com/cf/imes/module/report/service/template/ReportDatasourceServiceImplTest.java @@ -72,7 +72,7 @@ public class ReportDatasourceServiceImplTest extends ReportCommonServiceImplTest reqVO.setTemplateId(templateId); reqVO.setType(ReportDatasourceTypeEnum.JDBC.getCode()); reqVO.setName(updateReqVO.getName()); - List templateDatasourceList = reportDatasourceService.getDatasourceList(); + List templateDatasourceList = reportDatasourceService.getDatasourceList(null); assertNotNull(templateDatasourceList); assertNotEquals(0, templateDatasourceList.size()); From b6a81f2151c05d01e7423b897eceaa7c8519a79a Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Mon, 25 Nov 2024 09:20:13 +0800 Subject: [PATCH 03/13] =?UTF-8?q?1=E3=80=81=E7=A6=85=E9=81=93#582=E3=80=81?= =?UTF-8?q?#583=E3=80=81#584=E3=80=81#587=E9=97=AE=E9=A2=98=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=EF=BC=9B2=E3=80=81=E6=97=A0=E7=94=A8=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E7=A7=BB=E9=99=A4=EF=BC=9AneedSetPwd=E3=80=81password?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/order/OrderController.java | 2 -- .../controller/admin/auth/vo/AuthLoginReqVO.java | 10 +++++----- .../admin/auth/vo/AuthPermissionInfoRespVO.java | 3 --- .../controller/admin/notice/NoticeController.java | 2 -- .../controller/admin/user/vo/user/UserSaveReqVO.java | 5 ----- .../imes/module/system/convert/auth/AuthConvert.java | 2 +- .../system/service/user/AdminUserServiceImpl.java | 2 -- .../system/service/user/AdminUserServiceImplTest.java | 2 -- 8 files changed, 6 insertions(+), 22 deletions(-) diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/OrderController.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/OrderController.java index 7671b65ae..1b32e61fe 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/OrderController.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/OrderController.java @@ -505,7 +505,6 @@ public class OrderController { // 生产单超期(工作台) @GetMapping("/getOrderOverdue") @Operation(summary = "生产单超期 (工作台)") - @PreAuthorize("@ss.hasPermission('productManager:List')") public CommonResult> getOrderOverdue(@Valid PageParam pageParam) { return success(orderService.getOrderOverdue(pageParam)); } @@ -513,7 +512,6 @@ public class OrderController { // 生产单到期告警 (工作台) @GetMapping("/getOrderWarn") @Operation(summary = "生产单到期告警 (工作台)") - @PreAuthorize("@ss.hasPermission('productManager:List')") public CommonResult> getOrderNear(@Valid PageParam pageParam) { return success(orderService.getOrderNear(pageParam)); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthLoginReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthLoginReqVO.java index 5c17b3c3b..f6a038b74 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthLoginReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthLoginReqVO.java @@ -22,14 +22,14 @@ import javax.validation.constraints.Pattern; public class AuthLoginReqVO { @Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "chenfengyuanma") - @NotEmpty(message = "登录账号不能为空") - @Length(min = 4, max = 16, message = "账号长度为 4-16 位") - @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") + @NotEmpty(message = "登录失败,账号密码不正确") + @Length(max = 11, message = "登录失败,账号密码不正确") + @Pattern(regexp = "^[A-Za-z0-9]+$", message = "登录失败,账号密码不正确") private String username; @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao") - @Length(min = 4, max = 16, message = "密码长度为 4-16 位") - @NotEmpty(message = "密码不能为空") + @Length(min = 8, max = 16, message = "登录失败,账号密码不正确") + @NotEmpty(message = "登录失败,账号密码不正确") private String password; // ========== 图片验证码相关 ========== diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java index f643ce620..464e0cabe 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java @@ -48,9 +48,6 @@ public class AuthPermissionInfoRespVO { @Schema(description = "组织id") private Long organId; - @Schema(description = "是否需要设置密码") - private boolean needSetPwd; - @Schema(description = "ip地址") private String ip; diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/NoticeController.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/NoticeController.java index 69cdbed4c..c04ed748b 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/NoticeController.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/NoticeController.java @@ -62,7 +62,6 @@ public class NoticeController { @GetMapping("/page") @Operation(summary = "获取通知公告列表") - @PreAuthorize("@ss.hasPermission('system:notice:query')") public CommonResult> getNoticePage(@Validated NoticePageReqVO pageReqVO) { PageResult pageResult = noticeService.getNoticePage(pageReqVO); return success(BeanUtils.toBean(pageResult, NoticeRespVO.class)); @@ -71,7 +70,6 @@ public class NoticeController { @GetMapping("/get") @Operation(summary = "获得通知公告") @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('system:notice:query')") public CommonResult getNotice(@RequestParam("id") Long id) { NoticeDO notice = noticeService.getNotice(id); return success(BeanUtils.toBean(notice, NoticeRespVO.class)); diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserSaveReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserSaveReqVO.java index 26d159330..f71485d9d 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserSaveReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserSaveReqVO.java @@ -36,7 +36,6 @@ public class UserSaveReqVO { @Schema(description = "用户邮箱", example = "chenfeng@cf.com") @Email(message = "邮箱格式不正确") @Size(max = 50, message = "邮箱长度不能超过 50 个字符") - @NotBlank(message = "邮箱不能为空") private String email; @Schema(description = "手机号码", example = "15601691300") @@ -54,10 +53,6 @@ public class UserSaveReqVO { // ========== 仅【创建】时,需要传递的字段 ========== - @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") - @Size(min = 4, max = 16, message = "密码长度为 4-16 位") - private String password; - @Schema(description = "帐号状态(0正常 1停用)") @NotNull(message = "账号状态不能空") @CommonStatus diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/convert/auth/AuthConvert.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/convert/auth/AuthConvert.java index 43d91c398..97c6f471d 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/convert/auth/AuthConvert.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/convert/auth/AuthConvert.java @@ -49,7 +49,7 @@ public interface AuthConvert { return AuthPermissionInfoRespVO.builder() .user(AuthPermissionInfoRespVO.UserVO.builder() - .id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).organId(user.getOrganId()).needSetPwd(StringUtils.isEmpty(user.getPassword())) + .id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).organId(user.getOrganId()) .expireTime(organizationDO.getExpireTime()).ip(ipQuerySuccess ? ipQueryDataRespDTO.getIp() : "") .region(region) .build()) diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java index 444e4cd0d..c98433458 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java @@ -490,8 +490,6 @@ public class AdminUserServiceImpl implements AdminUserService { validateUserExists(id); // 校验用户名唯一 validateUsernameUnique(id, username, organId); - // 校验邮箱唯一 - validateEmailUnique(id, email, organId); // 校验部门处于开启状态 deptService.validateDeptList(CollectionUtils.singleton(deptId)); // 校验岗位处于开启状态 diff --git a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/user/AdminUserServiceImplTest.java b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/user/AdminUserServiceImplTest.java index 4326b9441..4fba52f93 100644 --- a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/user/AdminUserServiceImplTest.java +++ b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/user/AdminUserServiceImplTest.java @@ -106,8 +106,6 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { o.setStatus(CommonStatusEnum.ENABLE.getStatus()); })); //when(postService.getPostList(eq(reqVO.getPostIds()), isNull())).thenReturn(posts); - // mock passwordEncoder 的方法 - when(passwordEncoder.encode(eq(reqVO.getPassword()))).thenReturn("chenfengyuanma"); // 调用 Long userId = userService.createUser(reqVO); From 185d6ce34b563a83b86890007df1a4a02f5dab0c Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Mon, 25 Nov 2024 11:24:46 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E7=A6=85=E9=81=93#601=E3=80=81#636?= =?UTF-8?q?=E3=80=81#659=E3=80=81#662=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/enums/DictTypeConstants.java | 1 + .../admin/permission/vo/role/RoleRespVO.java | 7 +- .../admin/sms/vo/log/SmsLogRespVO.java | 96 ++++--------------- .../service/notice/NoticeServiceImpl.java | 7 ++ .../service/permission/RoleServiceImpl.java | 49 +++++++++- 5 files changed, 75 insertions(+), 85 deletions(-) diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/DictTypeConstants.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/DictTypeConstants.java index 0d97370cc..47c79a9f2 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/DictTypeConstants.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/DictTypeConstants.java @@ -9,6 +9,7 @@ public class DictTypeConstants { public static final String USER_TYPE = "user_type"; // 用户类型 public static final String COMMON_STATUS = "common_status"; // 系统状态 + public static final String ROLE_TYPE = "system_role_type"; // 系统角色类型 // ========== SYSTEM 模块 ========== diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/vo/role/RoleRespVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/vo/role/RoleRespVO.java index be9d8f9a4..6212e2aac 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/vo/role/RoleRespVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/vo/role/RoleRespVO.java @@ -1,5 +1,6 @@ package com.cf.imes.module.system.controller.admin.permission.vo.role; +import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.cf.imes.framework.excel.core.annotations.DictFormat; import com.cf.imes.framework.excel.core.convert.DictConvert; import com.cf.imes.module.system.enums.DictTypeConstants; @@ -39,19 +40,23 @@ public class RoleRespVO { private Integer status; @Schema(description = "角色类型,参见 RoleTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "角色类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.ROLE_TYPE) private Integer type; @Schema(description = "备注", example = "我是一个角色") + @ExcelProperty("备注") private String remark; @Schema(description = "数据范围,参见 DataScopeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("数据范围") private Integer dataScope; @Schema(description = "数据范围(指定部门数组)", example = "1") private Set dataScopeDeptIds; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + @ExcelProperty("创建时间") + @ColumnWidth(20) private LocalDateTime createTime; @Schema(description = "组织id", example = "1") diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/sms/vo/log/SmsLogRespVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/sms/vo/log/SmsLogRespVO.java index ce927b1f5..42675b425 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/sms/vo/log/SmsLogRespVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/sms/vo/log/SmsLogRespVO.java @@ -1,8 +1,8 @@ package com.cf.imes.module.system.controller.admin.sms.vo.log; +import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.cf.imes.framework.excel.core.annotations.DictFormat; import com.cf.imes.framework.excel.core.convert.DictConvert; -import com.cf.imes.framework.excel.core.convert.JsonConvert; import com.cf.imes.module.system.enums.DictTypeConstants; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; @@ -21,13 +21,23 @@ public class SmsLogRespVO { @ExcelProperty("编号") private Long id; - @Schema(description = "短信渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - @ExcelProperty("短信渠道编号") - private Long channelId; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + @ColumnWidth(20) + private LocalDateTime createTime; - @Schema(description = "短信渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "ALIYUN") - @ExcelProperty("短信渠道编码") - private String channelCode; + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @ExcelProperty("手机号") + private String mobile; + + @Schema(description = "短信内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你的验证码是 1024") + @ExcelProperty("短信内容") + private String templateContent; + + @Schema(description = "发送状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "发送状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.SMS_SEND_STATUS) + private Integer sendStatus; @Schema(description = "模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") @ExcelProperty("模板编号") @@ -41,76 +51,4 @@ public class SmsLogRespVO { @ExcelProperty(value = "短信类型", converter = DictConvert.class) @DictFormat(DictTypeConstants.SMS_TEMPLATE_TYPE) private Integer templateType; - - @Schema(description = "短信内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你的验证码是 1024") - @ExcelProperty("短信内容") - private String templateContent; - - @Schema(description = "短信参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "name,code") - @ExcelProperty(value = "短信参数", converter = JsonConvert.class) - private Map templateParams; - - @Schema(description = "短信 API 的模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "SMS_207945135") - @ExcelProperty("短信 API 的模板编号") - private String apiTemplateId; - - @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") - @ExcelProperty("手机号") - private String mobile; - - @Schema(description = "用户编号", example = "10") - @ExcelProperty("用户编号") - private Long userId; - - @Schema(description = "用户类型", example = "1") - @ExcelProperty(value = "用户类型", converter = DictConvert.class) - @DictFormat(DictTypeConstants.USER_TYPE) - private Integer userType; - - @Schema(description = "发送状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty(value = "发送状态", converter = DictConvert.class) - @DictFormat(DictTypeConstants.SMS_SEND_STATUS) - private Integer sendStatus; - - @Schema(description = "发送时间") - @ExcelProperty("发送时间") - private LocalDateTime sendTime; - - @Schema(description = "短信 API 发送结果的编码", example = "SUCCESS") - @ExcelProperty("短信 API 发送结果的编码") - private String apiSendCode; - - @Schema(description = "短信 API 发送失败的提示", example = "成功") - @ExcelProperty("短信 API 发送失败的提示") - private String apiSendMsg; - - @Schema(description = "短信 API 发送返回的唯一请求 ID", example = "3837C6D3-B96F-428C-BBB2-86135D4B5B99") - @ExcelProperty("短信 API 发送返回的唯一请求 ID") - private String apiRequestId; - - @Schema(description = "短信 API 发送返回的序号", example = "62923244790") - @ExcelProperty("短信 API 发送返回的序号") - private String apiSerialNo; - - @Schema(description = "接收状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") - @ExcelProperty(value = "接收状态", converter = DictConvert.class) - @DictFormat(DictTypeConstants.SMS_RECEIVE_STATUS) - private Integer receiveStatus; - - @Schema(description = "接收时间") - @ExcelProperty("接收时间") - private LocalDateTime receiveTime; - - @Schema(description = "API 接收结果的编码", example = "DELIVRD") - @ExcelProperty("API 接收结果的编码") - private String apiReceiveCode; - - @Schema(description = "API 接收结果的说明", example = "用户接收成功") - @ExcelProperty("API 接收结果的说明") - private String apiReceiveMsg; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java index eaa3728eb..0828dbe4d 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java @@ -1,5 +1,7 @@ package com.cf.imes.module.system.service.notice; +import cn.hutool.core.util.ObjectUtil; +import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil; import com.cf.imes.framework.common.pojo.PageResult; import com.cf.imes.framework.common.util.object.BeanUtils; @@ -52,6 +54,11 @@ public class NoticeServiceImpl implements NoticeService { @Override public PageResult getNoticePage(NoticePageReqVO reqVO) { + // 没有显示传入状态默认查有效的 + Integer status = reqVO.getStatus(); + if (ObjectUtil.isNull(status)) { + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + } return noticeMapper.selectPage(reqVO); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/RoleServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/RoleServiceImpl.java index dc0553aee..6a5a02a27 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/RoleServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/RoleServiceImpl.java @@ -17,6 +17,7 @@ import com.cf.imes.module.system.controller.admin.permission.vo.role.RoleSaveReq import com.cf.imes.module.system.dal.dataobject.permission.RoleDO; import com.cf.imes.module.system.dal.mysql.permission.RoleMapper; import com.cf.imes.module.system.dal.redis.RedisKeyConstants; +import com.cf.imes.module.system.dal.redis.RedisRefreshChannelTopicConstants; import com.cf.imes.module.system.enums.permission.DataScopeEnum; import com.cf.imes.module.system.enums.permission.RoleCodeEnum; import com.cf.imes.module.system.enums.permission.RoleTypeEnum; @@ -24,6 +25,9 @@ import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; @@ -53,6 +57,12 @@ public class RoleServiceImpl implements RoleService { @Resource private RoleService roleService; + @Resource + private StringRedisTemplate stringRedisTemplate; + + // 模糊匹配redisKey:role:{organId}:{roleId} + public static final String REDIS_ROLE_KEY_PATTERN = RedisKeyConstants.ROLE + ":*:%d"; + @Override @Transactional(rollbackFor = Exception.class) public Long createRole(RoleSaveReqVO createReqVO, Integer type) { @@ -80,6 +90,8 @@ public class RoleServiceImpl implements RoleService { // 更新到数据库 RoleDO updateObj = BeanUtils.toBean(updateReqVO, RoleDO.class); roleMapper.updateById(updateObj); + // 移除角色缓存 + scanAndDelKeys(String.format(REDIS_ROLE_KEY_PATTERN, updateObj.getId())); } @Override @@ -91,6 +103,8 @@ public class RoleServiceImpl implements RoleService { // 更新状态 RoleDO updateObj = new RoleDO().setId(id).setStatus(status); roleMapper.updateById(updateObj); + // 移除角色缓存 + scanAndDelKeys(String.format(REDIS_ROLE_KEY_PATTERN, updateObj.getId())); } @Override @@ -117,6 +131,31 @@ public class RoleServiceImpl implements RoleService { roleMapper.deleteById(id); // 删除相关数据 permissionService.processRoleDeleted(id); + // 删除角色移除角色缓存 + scanAndDelKeys(String.format(REDIS_ROLE_KEY_PATTERN, id)); + } + + /** + * scan匹配keyPattern下缓存并删除缓存 + * + * @param keyPattern + */ + private void scanAndDelKeys(String keyPattern) { + // 根据keyPattern scan匹配的redis key + List matchKeys = new ArrayList<>(); + Cursor cursor = stringRedisTemplate.scan(ScanOptions.scanOptions().match(keyPattern).count(200).build()); + while (cursor.hasNext()) { + matchKeys.add(cursor.next()); + } + cursor.close(); + if (CollUtil.isNotEmpty(matchKeys)) { + for (String key : matchKeys) { + // 移除缓存 + stringRedisTemplate.delete(key); + } + } + // 通知刷新本地缓存 + stringRedisTemplate.convertAndSend(RedisRefreshChannelTopicConstants.PERMISSION_REFRESH, ""); } /** @@ -127,7 +166,7 @@ public class RoleServiceImpl implements RoleService { * * @param name 角色名字 * @param code 角色额编码 - * @param id 角色编号 + * @param id 角色编号 */ @VisibleForTesting void validateRoleDuplicate(String name, String code, Long id, Long organId) { @@ -156,7 +195,7 @@ public class RoleServiceImpl implements RoleService { * * @param id 角色编号 */ - // @VisibleForTesting + // @VisibleForTesting @OrganIgnore @Override public void validateRoleForUpdate(Long id) { @@ -199,7 +238,7 @@ public class RoleServiceImpl implements RoleService { public List getRoleListByStatus(Collection statuses, Long organId) { LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); assert loginUser != null; - if(!loginUser.getIsSupAdmin()) { + if (!loginUser.getIsSupAdmin()) { return roleMapper.selectList(new LambdaQueryWrapperX() .in(RoleDO::getStatus, statuses) .in(RoleDO::getOrganId, loginUser.getOrganId(), 0L) @@ -226,7 +265,7 @@ public class RoleServiceImpl implements RoleService { if (CollUtil.isEmpty(ids)) { return Collections.emptyList(); } - return roleMapper.selectBatchIds(ids); + return roleMapper.selectBatchIds(ids); } @Override @@ -293,7 +332,7 @@ public class RoleServiceImpl implements RoleService { if (CollUtil.isEmpty(roleIds)) { return Collections.emptyList(); } - return roleMapper.selectBatchIds(roleIds); + return roleMapper.selectBatchIds(roleIds); } } From cb5a02c7c98518f6b5b2694efa4f1fbeb9314c74 Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Mon, 25 Nov 2024 14:45:44 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E7=A6=85=E9=81=93#655=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/cf/imes/module/system/enums/ErrorCodeConstants.java | 6 +++--- .../imes/module/system/service/organ/OrganServiceImpl.java | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java index 92200f4b4..733635506 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java @@ -123,8 +123,8 @@ public class ErrorCodeConstants { // ========== 组织信息 1-002-015-000 ========== public static final ErrorCode ORGAN_NOT_EXISTS = new ErrorCode(1_002_015_000, "组织不存在"); - public static final ErrorCode ORGAN_DISABLE = new ErrorCode(1_002_015_001, "名字为【{}】的组织已被禁用"); - public static final ErrorCode ORGAN_EXPIRE = new ErrorCode(1_002_015_002, "名字为【{}】的组织已过期"); + public static final ErrorCode ORGAN_DISABLE = new ErrorCode(1_002_015_001, "【{}】组织已被禁用"); + public static final ErrorCode ORGAN_EXPIRE = new ErrorCode(1_002_015_002, "【{}】组织已过期"); public static final ErrorCode ORGAN_CAN_NOT_UPDATE_SYSTEM = new ErrorCode(1_002_015_003, "系统组织不能进行修改、删除等操作!"); public static final ErrorCode ORGAN_NAME_DUPLICATE = new ErrorCode(1_002_015_004, "名字为【{}】的组织已存在"); public static final ErrorCode ORGAN_WEBSITE_DUPLICATE = new ErrorCode(1_002_015_005, "域名为【{}】的组织已存在"); @@ -135,7 +135,7 @@ public class ErrorCodeConstants { // ========== 组织套餐 1-002-016-000 ========== public static final ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "组织套餐不存在"); public static final ErrorCode TENANT_PACKAGE_USED = new ErrorCode(1_002_016_001, "组织正在使用该套餐,请给组织重新设置套餐后再尝试删除"); - public static final ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "名字为【{}】的组织套餐已被禁用"); + public static final ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "【{}】组织套餐已被禁用"); public static final ErrorCode TENANT_PACKAGE_DEPT_EXIT = new ErrorCode(1_002_016_003, "无法修改内置组织权限套餐"); public static final ErrorCode TENANT_PACKAGE_DELETED_EXIT = new ErrorCode(1_002_016_004, "无法删除内置组织权限套餐"); public static final ErrorCode TENANT_PACKAGE_NAME_UNIQE_ERROR = new ErrorCode(1_002_016_005, "套餐名已存在,请编辑套餐名后重试"); diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganServiceImpl.java index ce62f758b..c5d3c3068 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganServiceImpl.java @@ -115,6 +115,12 @@ public class OrganServiceImpl implements OrganService { if (ObjectUtil.isNull(organizationDO.getPackageId())) { throw exception(TENANT_PACKAGE_NOT_EXISTS); } + // 组织套餐相关校验 + Long packageId = organizationDO.getPackageId(); + if (ObjectUtil.isNull(packageId)) { + throw exception(TENANT_PACKAGE_NOT_EXISTS); + } + tenantPackageService.validTenantPackage(packageId); return organizationDO; } From 5931c21034d6e35f8a333fa982765eabaae3ca85 Mon Sep 17 00:00:00 2001 From: liuzhaotian Date: Mon, 25 Nov 2024 14:56:52 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E7=94=9F=E4=BA=A7=E5=8D=95=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=AE=8C=E6=88=90=E6=97=B6=E9=97=B4=EF=BC=8C=E9=85=8D?= =?UTF-8?q?=E4=BB=B6=E8=BF=87=E6=BB=A4"=20=E5=B0=81=E8=BE=B9=E6=9D=A1=20"?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/plan/bo/OrderIds.java | 1 - .../optimizeplan/OptimizePlanServiceImpl.java | 26 ++++++++----- .../admin/pack/vo/OrderPartsRespVO.java | 21 +++++++++++ .../admin/pack/vo/OtherPackReqVO.java | 8 +++- .../query/vo/pack/PackageDetailsRespVO.java | 19 ++++++++++ .../dal/mysql/pack/OrderPackageMapper.java | 3 -- .../dal/mysql/query/OrderItemMapper.java | 19 ++++------ .../manage/service/pack/PackServiceImpl.java | 16 +++++--- .../dal/mysql/pack/OrderPackageMapper.xml | 15 -------- .../dal/mysql/query/OrderItemMapper.xml | 28 ++++++++++++++ .../dal/mysql/query/OrderPartsMapper.xml | 37 ++++++++++++++++++- .../system/enums/ErrorCodeConstants.java | 2 +- .../impl/IntellectBranchingService.java | 12 +++--- 13 files changed, 154 insertions(+), 53 deletions(-) diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/plan/bo/OrderIds.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/plan/bo/OrderIds.java index d7f710275..1deffa1f3 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/plan/bo/OrderIds.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/plan/bo/OrderIds.java @@ -7,7 +7,6 @@ import lombok.Data; @Data - public class OrderIds { diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/optimizeplan/OptimizePlanServiceImpl.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/optimizeplan/OptimizePlanServiceImpl.java index a547e2c04..f9d99404d 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/optimizeplan/OptimizePlanServiceImpl.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/optimizeplan/OptimizePlanServiceImpl.java @@ -266,8 +266,11 @@ public class OptimizePlanServiceImpl implements OptimizePlanService { List orderDOS = orderMapper.selectOrderPackList(orderIds, getUserOrganId()); if (ObjectUtil.isNotEmpty(orderDOS)) { - List orderDOList = orderDOS.stream().map(m -> m.setStatus(OrderStatusEnum.FINISH_PRODUCTION.getStatus())).toList(); - orderMapper.updateBatch(orderDOList); + orderDOS.forEach(f -> { + f.setStatus(OrderStatusEnum.FINISH_PRODUCTION.getStatus()); + f.setFinishTime(LocalDateTime.now()); + }); + orderMapper.updateBatch(orderDOS); } } @@ -304,9 +307,7 @@ public class OptimizePlanServiceImpl implements OptimizePlanService { Boolean isOptimized = optimizeBoardModelDO.getIsOptimized(); if(Boolean.FALSE.equals(isOptimized)){ - throw exception(ORDER_PLAN_NO_OPTIMIZE_UPDATE_ERROR); - } @@ -355,9 +356,12 @@ public class OptimizePlanServiceImpl implements OptimizePlanService { if(!orderIdList.isEmpty()) { List orderDOList = orderMapper.selectBatchIds(orderIdList); - orderMapper.updateBatch(orderDOList.stream() - .map(m -> m.setStatus(OrderStatusEnum.SORTED.getStatus())) - .toList()); + orderDOList.forEach(f -> { + f.setStatus(OrderStatusEnum.SORTED.getStatus()); + f.setFinishTime(null); + }); + orderMapper.updateBatch(orderDOList); + } return; @@ -382,8 +386,11 @@ public class OptimizePlanServiceImpl implements OptimizePlanService { List orderDOS = orderMapper.selectOrderList(orderIds, getUserOrganId()); if(!orderDOS.isEmpty()){ - List orderDOList = orderDOS.stream().map(m -> m.setStatus(OrderStatusEnum.IN_PRODUCTION.getStatus())).toList(); - orderMapper.updateBatch(orderDOList); + orderDOS.forEach(f -> { + f.setStatus(OrderStatusEnum.IN_PRODUCTION.getStatus()); + f.setFinishTime(null); + }); + orderMapper.updateBatch(orderDOS); } } @@ -916,6 +923,7 @@ public class OptimizePlanServiceImpl implements OptimizePlanService { + // ES 文档数据刷新 public void refresh( String index) { try { diff --git a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/pack/vo/OrderPartsRespVO.java b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/pack/vo/OrderPartsRespVO.java index acaf61fae..98b7fb5ec 100644 --- a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/pack/vo/OrderPartsRespVO.java +++ b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/pack/vo/OrderPartsRespVO.java @@ -45,4 +45,25 @@ public class OrderPartsRespVO { @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED) private String remark; + + @Schema(description = "配件颜色", requiredMode = Schema.RequiredMode.REQUIRED) + private String partsColor; + + @Schema(description = "配件宽度", requiredMode = Schema.RequiredMode.REQUIRED) + private Double partsWidth; + + @Schema(description = "配件长度", requiredMode = Schema.RequiredMode.REQUIRED) + private Double partsLength; + + @Schema(description = "配件厚度", requiredMode = Schema.RequiredMode.REQUIRED) + private Double partsThickness; + + @Schema(description = "配件主类:1封边2五金3组件", requiredMode = Schema.RequiredMode.REQUIRED) + private String category; + + @Schema(description = "子配件ID列表,复合部件时记录子配件ID,半角逗号分隔", requiredMode = Schema.RequiredMode.REQUIRED) + private String subparts; + + + } diff --git a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/pack/vo/OtherPackReqVO.java b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/pack/vo/OtherPackReqVO.java index c62f1b8d8..b637737bc 100644 --- a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/pack/vo/OtherPackReqVO.java +++ b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/pack/vo/OtherPackReqVO.java @@ -23,7 +23,7 @@ public class OtherPackReqVO { @Schema(description = "配件名称", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "配件名称不能为空") - @Size(max = 30, message = "配件名称长度不能超过 64 个字符") + @Size(max = 64, message = "配件名称长度不能超过 64 个字符") private String name; @@ -31,6 +31,12 @@ public class OtherPackReqVO { @NumberValid(name = "配件数量") private Double num; + + @Schema(description = "配件单位", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "配件单位不能为空") + @Size(max = 32, message = "配件单位长度不能超过 32 个字符") + private String unit; + @Schema(description = "包裹编号", requiredMode = Schema.RequiredMode.REQUIRED) private String packNo; diff --git a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/query/vo/pack/PackageDetailsRespVO.java b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/query/vo/pack/PackageDetailsRespVO.java index 1faa5b3fc..d62bf6436 100644 --- a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/query/vo/pack/PackageDetailsRespVO.java +++ b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/controller/admin/query/vo/pack/PackageDetailsRespVO.java @@ -105,4 +105,23 @@ public class PackageDetailsRespVO { private String factory; + @Schema(description = "配件颜色", requiredMode = Schema.RequiredMode.REQUIRED) + private String partsColor; + + @Schema(description = "配件宽度", requiredMode = Schema.RequiredMode.REQUIRED) + private Double partsWidth; + + @Schema(description = "配件长度", requiredMode = Schema.RequiredMode.REQUIRED) + private Double partsLength; + + @Schema(description = "配件厚度", requiredMode = Schema.RequiredMode.REQUIRED) + private Double partsThickness; + + @Schema(description = "配件主类:1封边2五金3组件", requiredMode = Schema.RequiredMode.REQUIRED) + private String category; + + @Schema(description = "子配件ID列表,复合部件时记录子配件ID,半角逗号分隔", requiredMode = Schema.RequiredMode.REQUIRED) + private String subparts; + + } diff --git a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/dal/mysql/pack/OrderPackageMapper.java b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/dal/mysql/pack/OrderPackageMapper.java index 1189ac1e8..688174273 100644 --- a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/dal/mysql/pack/OrderPackageMapper.java +++ b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/dal/mysql/pack/OrderPackageMapper.java @@ -10,7 +10,6 @@ import com.cf.imes.framework.common.enums.OrderPackageTypeEnum; import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX; import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; import com.cf.imes.module.manage.controller.admin.pack.vo.PackRespVO; -import com.cf.imes.module.manage.controller.admin.pack.vo.PlateAndPartIdList; import com.cf.imes.module.manage.controller.admin.query.vo.pack.OrderPackageVO; import com.cf.imes.module.manage.dal.dataobject.query.OrderPackageDO; import org.apache.ibatis.annotations.Mapper; @@ -73,8 +72,6 @@ public interface OrderPackageMapper extends BaseMapperX { List selectPackPieceCount(@Param("orderIds") List orderIds, @Param("organId") Long organId); - List selectOrderPack(@Param("orderId") Long orderId,@Param("organId") Long organId); - // 删除当前生产单下所有的包裹 default void updateDelete(Long orderId,Long organId) { diff --git a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/dal/mysql/query/OrderItemMapper.java b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/dal/mysql/query/OrderItemMapper.java index 0d6ddea53..87384bb37 100644 --- a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/dal/mysql/query/OrderItemMapper.java +++ b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/dal/mysql/query/OrderItemMapper.java @@ -3,6 +3,7 @@ package com.cf.imes.module.manage.dal.mysql.query; import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX; import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.cf.imes.module.manage.controller.admin.pack.vo.PlateAndPartIdList; import com.cf.imes.module.manage.controller.admin.pack.vo.PlateDetailsRespVO; import com.cf.imes.module.manage.controller.admin.process.vo.PlateDetails; import com.cf.imes.module.manage.controller.admin.process.vo.ProcessPlateReqVO; @@ -80,17 +81,6 @@ public interface OrderItemMapper extends BaseMapperX { } - - - default List selectPartsList(Long orderId, Long organId) { - return selectList(new LambdaQueryWrapperX() - .eq(OrderItemDO::getOrganId, organId) - .eqIfPresent(OrderItemDO::getOrderId, orderId) - .eq(OrderItemDO::getPackageId,0) - .select(OrderItemDO::getPartsId)); - } - - default List selectPackByPlateId(List plateId,Long orderId ,Long organId) { return selectList(new LambdaQueryWrapperX() .eq(OrderItemDO::getOrganId, organId) @@ -98,4 +88,11 @@ public interface OrderItemMapper extends BaseMapperX { .inIfPresent(OrderItemDO::getPlateId, plateId) .select(OrderItemDO::getPackageId)); } + + + List selectOrderPackPartsIds(@Param("orderId") Long orderId, @Param("organId") Long organId); + + List selectOrderPackPlateIds(@Param("orderId") Long orderId,@Param("organId") Long organId); + + } diff --git a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/service/pack/PackServiceImpl.java b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/service/pack/PackServiceImpl.java index 0fe435075..c23967ed1 100644 --- a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/service/pack/PackServiceImpl.java +++ b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/java/com/cf/imes/module/manage/service/pack/PackServiceImpl.java @@ -44,6 +44,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -268,7 +269,6 @@ public class PackServiceImpl implements PackService { @Override public List getPartsList(OrderPartsReqVO reqVO) { - return orderPartsMapper.selectPartsList(reqVO.getOrderId(), getUserOrganId()); } @@ -381,6 +381,7 @@ public class PackServiceImpl implements PackService { if(orderDO.getStatus().equals(OrderStatusEnum.FINISH_PRODUCTION.getStatus())){ orderDO.setStatus(OrderStatusEnum.IN_PRODUCTION.getStatus()); + orderDO.setFinishTime(null); } ordersMapper.updateById(orderDO); @@ -491,10 +492,11 @@ public class PackServiceImpl implements PackService { return false; } - List plateAndPartIdLists = orderPackageMapper.selectOrderPack(orderId, getUserOrganId()); + List partsIds = orderItemMapper.selectOrderPackPartsIds(orderId, getUserOrganId()); + List plateIds = orderItemMapper.selectOrderPackPlateIds(orderId, getUserOrganId()); - return plateAndPartIdLists.isEmpty(); + return partsIds.isEmpty() && plateIds.isEmpty(); } @@ -512,6 +514,7 @@ public class PackServiceImpl implements PackService { if(orderPlanApi.getOrder(orderId).getData()){ orderDO.setStatus(OrderStatusEnum.FINISH_PRODUCTION.getStatus()); + orderDO.setFinishTime(LocalDateTime.now()); } @@ -618,6 +621,7 @@ public class PackServiceImpl implements PackService { OrderPartsNDO orderParts = BeanUtils.toBean(reqVO, OrderPartsNDO.class); // 因为是外部配件,所以配件类型的名称固定为 “ 外部配件” orderParts.setType("外部配件"); + orderParts.setUnit(reqVO.getUnit()); orderPartsMapper.insert(orderParts); @@ -665,6 +669,7 @@ public class PackServiceImpl implements PackService { OrderPartsNDO orderParts = BeanUtils.toBean(reqVO, OrderPartsNDO.class); // 因为是外部配件,所以配件类型的名称固定为 “ 外部配件” orderParts.setType("外部配件"); + orderParts.setUnit(reqVO.getUnit()); orderPartsMapper.insert(orderParts); // 在生产单明细表中添加数据(生产单号,配件ID,包裹ID,部件数量) @@ -825,13 +830,14 @@ public class PackServiceImpl implements PackService { orderItemMapper.updateBatch(orderItemDOS); // 查询配件是否为空,为空,修改生产单的状态为已打包 - List orderItemDoPartsList = orderItemMapper.selectPartsList(reqVO.getOrderId(), getUserOrganId()); + List partsIds = orderItemMapper.selectOrderPackPartsIds(reqVO.getOrderId(), getUserOrganId()); - if (orderItemDoPartsList.isEmpty()) { + if (partsIds.isEmpty()) { OrderDO orderDO = ordersMapper.selectById(reqVO.getOrderId()); orderDO.setPackaged(OrderPackageStatusEnum.PACKAGED.getStatus()); if(Boolean.TRUE.equals(orderPlanApi.getOrder(reqVO.getOrderId()).getData())){ orderDO.setStatus(OrderStatusEnum.FINISH_PRODUCTION.getStatus()); + orderDO.setFinishTime(LocalDateTime.now()); } ordersMapper.updateById(orderDO); } diff --git a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/com/cf/imes/module/manage/dal/mysql/pack/OrderPackageMapper.xml b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/com/cf/imes/module/manage/dal/mysql/pack/OrderPackageMapper.xml index ccab1614e..0e8651dc5 100644 --- a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/com/cf/imes/module/manage/dal/mysql/pack/OrderPackageMapper.xml +++ b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/com/cf/imes/module/manage/dal/mysql/pack/OrderPackageMapper.xml @@ -110,21 +110,6 @@ - - - + + + + \ No newline at end of file diff --git a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/com/cf/imes/module/manage/dal/mysql/query/OrderPartsMapper.xml b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/com/cf/imes/module/manage/dal/mysql/query/OrderPartsMapper.xml index d59e9704b..1ded583dd 100644 --- a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/com/cf/imes/module/manage/dal/mysql/query/OrderPartsMapper.xml +++ b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/com/cf/imes/module/manage/dal/mysql/query/OrderPartsMapper.xml @@ -17,6 +17,12 @@ + + + + + + diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java index 92200f4b4..95c05718d 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java @@ -343,7 +343,7 @@ public class ErrorCodeConstants { public static final ErrorCode CURRENTLY_NO_CONFIGURATION_AVAILABLE = new ErrorCode(1_002_039_001, "当前没有{}配置信息,请前往设置配置"); public static final ErrorCode BRANCHING_SETTING_NAME_REPEAT = new ErrorCode(1_002_039_002, "分线配置名称重复,请重新设置"); public static final ErrorCode BRANCHING_SETTING_RULE_SAVE_CHECK_ERROR = new ErrorCode(1_002_039_003, "智能分线配置保存解析失败,数据有误,请检查配置规则或联系客服"); - public static final ErrorCode BRANCHING_SETTING_SAVE_ERROR = new ErrorCode(1_002_039_004, "智能分线配置为空,请添加配置"); + public static final ErrorCode BRANCHING_SETTING_SAVE_ERROR = new ErrorCode(1_002_039_004, "机台:{} 的配置为空,请添加配置"); public static final ErrorCode BRANCHING_SETTING_COUNT_ERROR = new ErrorCode(1_002_039_005, "智能分线配置机台数量必须大于2才能保存"); //=========== 系统配置 1-002-040-000 ============ diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/IntellectBranchingService.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/IntellectBranchingService.java index a1d2c7f1e..50f0ae731 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/IntellectBranchingService.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/IntellectBranchingService.java @@ -22,6 +22,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; +import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.cf.imes.module.system.enums.ErrorCodeConstants.*; @@ -57,11 +58,12 @@ public class IntellectBranchingService extends AbstractSystemConfigServiceHandle JSONObject jsonObject = jsonArray.getJSONObject(i); checkMachineId(jsonObject.getString("machineId")); - checkMachineName(jsonObject.getString("machineName")); - checkMachineConfig(jsonObject.get("machineConfig")); + String machineName = jsonObject.getString("machineName"); + checkMachineName(machineName); + checkMachineConfig(jsonObject.get("machineConfig"),machineName); } - if(jsonArray.size() < 2){ + if(jsonArray.size() <= 2){ throw new ServiceException(BRANCHING_SETTING_COUNT_ERROR); } @@ -136,9 +138,9 @@ public class IntellectBranchingService extends AbstractSystemConfigServiceHandle * 校验 机台分流条件 * */ - private void checkMachineConfig(Object machineConfig) { + private void checkMachineConfig(Object machineConfig,String machineName) { if (ObjectUtil.isEmpty(machineConfig)) { - throw new ServiceException(BRANCHING_SETTING_SAVE_ERROR); + throw exception(BRANCHING_SETTING_SAVE_ERROR,machineName); } } From dfb2a0cccffe9fdb078265608d2cc8fb43ae2157 Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Mon, 25 Nov 2024 16:08:40 +0800 Subject: [PATCH 07/13] =?UTF-8?q?=E7=A6=85=E9=81=93#636=E3=80=81#670?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/notice/NoticeController.java | 11 +++++++++++ .../system/dal/mysql/permission/RoleMapper.java | 2 +- .../system/service/notice/NoticeServiceImpl.java | 5 ----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/NoticeController.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/NoticeController.java index c04ed748b..bee49431a 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/NoticeController.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/NoticeController.java @@ -1,6 +1,7 @@ package com.cf.imes.module.system.controller.admin.notice; import cn.hutool.core.lang.Assert; +import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.framework.common.enums.UserTypeEnum; import com.cf.imes.framework.common.pojo.CommonResult; import com.cf.imes.framework.common.pojo.PageResult; @@ -62,11 +63,21 @@ public class NoticeController { @GetMapping("/page") @Operation(summary = "获取通知公告列表") + @PreAuthorize("@ss.hasPermission('system:notice:query')") public CommonResult> getNoticePage(@Validated NoticePageReqVO pageReqVO) { PageResult pageResult = noticeService.getNoticePage(pageReqVO); return success(BeanUtils.toBean(pageResult, NoticeRespVO.class)); } + @GetMapping("/homepage") + @Operation(summary = "获取首页通知公告列表") + public CommonResult> getHomePageNoticePage(@Validated NoticePageReqVO pageReqVO) { + // 首页只看生效的公告 + pageReqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + PageResult pageResult = noticeService.getNoticePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, NoticeRespVO.class)); + } + @GetMapping("/get") @Operation(summary = "获得通知公告") @Parameter(name = "id", description = "编号", required = true, example = "1024") diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/permission/RoleMapper.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/permission/RoleMapper.java index 3e7a757c4..05f467a8b 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/permission/RoleMapper.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/permission/RoleMapper.java @@ -36,7 +36,7 @@ public interface RoleMapper extends BaseMapperX { .eqIfPresent(RoleDO::getStatus, reqVO.getStatus()) .betweenIfPresent(RoleDO::getCreateTime, reqVO.getCreateTime()) .ne(RoleDO::getId, 1) - .orderByAsc(RoleDO::getId); + .orderByAsc(RoleDO::getSort).orderByAsc(RoleDO::getId); return selectPage(reqVO, lambdaQueryWrapperX); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java index 0828dbe4d..c8c249efb 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java @@ -54,11 +54,6 @@ public class NoticeServiceImpl implements NoticeService { @Override public PageResult getNoticePage(NoticePageReqVO reqVO) { - // 没有显示传入状态默认查有效的 - Integer status = reqVO.getStatus(); - if (ObjectUtil.isNull(status)) { - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - } return noticeMapper.selectPage(reqVO); } From abcae73678118591fbaa1d220aa0b8ae962f6f3f Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Mon, 25 Nov 2024 17:54:43 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E7=A6=85=E9=81=93#676=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../report/service/template/ReportTemplateServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java index e9e3baee0..991221db0 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java @@ -361,7 +361,7 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { if (ObjectUtil.isNotNull(queryMap)) { for (Map.Entry entry : queryMap.entrySet()) { String key = entry.getKey(); - if (ObjectUtils.isEmpty(entry.getValue()) && (ObjectUtil.notEqual(key, "datasetIds") || ObjectUtil.notEqual(key, "datasourceIds "))) { + if (ObjectUtils.isEmpty(entry.getValue()) && ObjectUtil.notEqual(key, "datasetIds") && ObjectUtil.notEqual(key, "datasourceIds")) { throw ServiceExceptionUtil.exception(TEMPLATE_PREIVEW_QUERYPARAM_EMPTY, key); } } From 6168360e457948f57caeffbb865b02881b1603cf Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Tue, 26 Nov 2024 18:48:15 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=E7=A6=85=E9=81=93#585=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/cf/imes/module/system/enums/ErrorCodeConstants.java | 2 +- .../admin/user/vo/profile/UserProfileUpdatePasswordReqVO.java | 4 ++-- .../controller/admin/user/vo/user/UserResetPasswordReqVO.java | 2 +- .../admin/user/vo/user/UserUpdatePasswordReqVO.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java index ce7188167..e4b1ae094 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java @@ -50,7 +50,7 @@ public class ErrorCodeConstants { public static final ErrorCode USER_IS_DISABLE = new ErrorCode(1_002_003_006, "名字为【{}】的用户已被禁用"); public static final ErrorCode USER_COUNT_MAX = new ErrorCode(1_002_003_008, "创建用户失败,原因:超过组织最大组织配额({})!"); public static final ErrorCode USER_ME_ERROR = new ErrorCode(1_002_003_009, "不允许操作用户自身"); - public static final ErrorCode THE_PASSWORD_LENGTH_MUST_BE_AT_LEAST_8_CHARACTERS = new ErrorCode(1_002_003_010, "密码长度必须至少为8个字符"); + public static final ErrorCode THE_PASSWORD_LENGTH_MUST_BE_AT_LEAST_8_CHARACTERS = new ErrorCode(1_002_003_010, "密码长度不少于8位,且包含大小写字母、数字和特殊字符"); public static final ErrorCode THE_PASSWORD_MUST_CONTAIN_AT_LEAST_ONE_LOWER_LETTER = new ErrorCode(1_002_003_011, "密码必须包含至少一个小写字母"); public static final ErrorCode THE_PASSWORD_MUST_CONTAIN_AT_LEAST_ONE_NUMBER = new ErrorCode(1_002_003_012, "密码必须包含至少一个数字"); diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/profile/UserProfileUpdatePasswordReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/profile/UserProfileUpdatePasswordReqVO.java index 52f8be672..f8d5cff90 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/profile/UserProfileUpdatePasswordReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/profile/UserProfileUpdatePasswordReqVO.java @@ -12,12 +12,12 @@ public class UserProfileUpdatePasswordReqVO { @Schema(description = "旧密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") @NotEmpty(message = "旧密码不能为空") - @Length(min = 8, max = 16, message = "密码长度为 4-16 位") + @Length(min = 8, max = 16, message = "密码长度不少于8位,且包含大小写字母、数字和特殊字符") private String oldPassword; @Schema(description = "新密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "654321") @NotEmpty(message = "新密码不能为空") - @Length(min = 8, max = 16, message = "密码长度为 4-16 位") + @Length(min = 8, max = 16, message = "密码长度不少于8位,且包含大小写字母、数字和特殊字符") private String newPassword; } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserResetPasswordReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserResetPasswordReqVO.java index d8447f844..4c2a15779 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserResetPasswordReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserResetPasswordReqVO.java @@ -13,7 +13,7 @@ public class UserResetPasswordReqVO { @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") @NotEmpty(message = "密码不能为空") - @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + @Length(min = 4, max = 16, message = "密码长度不少于8位,且包含大小写字母、数字和特殊字符") private String password; @Schema(description = "短信验证码", example = "123456") diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserUpdatePasswordReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserUpdatePasswordReqVO.java index 3a24d07cb..253e50018 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserUpdatePasswordReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserUpdatePasswordReqVO.java @@ -17,7 +17,7 @@ public class UserUpdatePasswordReqVO { @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") @NotEmpty(message = "密码不能为空") - @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + @Length(min = 4, max = 16, message = "密码长度不少于8位,且包含大小写字母、数字和特殊字符") private String password; } From b636c85c87191cb50a44d2d7d64b74b0bb83317d Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Wed, 27 Nov 2024 10:48:09 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E6=8A=A5=E8=A1=A8=E4=BC=98=E5=8C=96?= =?UTF-8?q?=EF=BC=9A1=E3=80=81=E6=95=B0=E6=8D=AE=E9=9B=86=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E5=AD=97=E6=AE=B5=E5=88=97=E8=A1=A8=E6=95=B0=E9=87=8F?= =?UTF-8?q?=E9=99=90=E5=88=B630=E6=94=B9=E4=B8=BA100=EF=BC=9B2=E3=80=81ure?= =?UTF-8?q?port=E6=9F=A5=E8=AF=A2=E7=A7=9F=E6=88=B7=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E9=99=90=E5=88=B6=E9=9D=9E=E8=B6=85=E7=AE=A1=EF=BC=8C=E8=B6=85?= =?UTF-8?q?=E7=AE=A1=E4=B9=9F=E6=94=AF=E6=8C=81=E7=A7=9F=E6=88=B7=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=EF=BC=9B3=E3=80=81=E6=95=B0=E6=8D=AE=E9=9B=86?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E8=A1=A8=E4=BC=98=E5=8C=96=E3=80=81=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E4=BF=9D=E5=AD=98=E5=92=8C=E9=A2=84=E8=A7=88=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=A7=9F=E6=88=B7=E5=AD=97=E6=AE=B5=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dataset/vo/ReportDatasetSaveReqVO.java | 2 +- .../ReportDatasourceController.java | 9 +- .../vo/ReportDatasourcePreviewReqVO.java | 6 +- .../ReportDatasourceServiceImpl.java | 3 +- .../template/ReportTemplateServiceImpl.java | 47 +------- .../report/utils/TenantParamsUtils.java | 102 ++++++++++++++++++ .../lib/ureport-core-2.3.0-SNAPSHOT.jar | Bin 929339 -> 929328 bytes 7 files changed, 120 insertions(+), 49 deletions(-) create mode 100644 cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/utils/TenantParamsUtils.java diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/dataset/vo/ReportDatasetSaveReqVO.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/dataset/vo/ReportDatasetSaveReqVO.java index c36eba371..bb15f22fe 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/dataset/vo/ReportDatasetSaveReqVO.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/dataset/vo/ReportDatasetSaveReqVO.java @@ -56,7 +56,7 @@ public class ReportDatasetSaveReqVO implements Serializable { private List parameters = new ArrayList<>(); @Schema(description = "字段列表") - @Size(max = 30, message = "字段列表数量不能超过30个") + @Size(max = 100, message = "字段列表数量不能超过100个") @Valid private List fields = new ArrayList<>(); } diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/ReportDatasourceController.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/ReportDatasourceController.java index e5272def7..e2800af05 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/ReportDatasourceController.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/ReportDatasourceController.java @@ -2,7 +2,6 @@ package com.cf.imes.module.report.controller.admin.datasource; import com.bstek.common.utils.MultipleJdbcTemplate; import com.bstek.datasource.bean.DataSourceInfo; -import com.bstek.datasource.bean.PreviewParams; import com.bstek.datasource.service.DataSourceService; import com.bstek.ureport.definition.dataset.Field; import com.cf.imes.framework.common.pojo.CommonResult; @@ -14,6 +13,7 @@ import com.cf.imes.module.report.controller.admin.datasource.vo.ReportDatasource import com.cf.imes.module.report.controller.admin.datasource.vo.ReportDatasourceTestConnReqVO; import com.cf.imes.module.report.dal.dataobject.datasource.ReportDatasourceDO; import com.cf.imes.module.report.service.datasource.ReportDatasourceService; +import com.cf.imes.module.report.utils.TenantParamsUtils; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -51,6 +51,9 @@ public class ReportDatasourceController { @Resource private DataSourceService ureportDataSourceService; + @Resource + private TenantParamsUtils tenantParamsUtils; + @PutMapping("/datasource") @Operation(summary = "创建报表数据源") @PreAuthorize("@ss.hasPermission('report:design')") @@ -134,13 +137,13 @@ public class ReportDatasourceController { @Operation(summary = "获取数据源表字段") @PreAuthorize("@ss.hasPermission('report:design')") public CommonResult> getDatasourceTableFields(@RequestBody @Valid ReportDatasourcePreviewReqVO reqVO) { - return success(datasourceService.getTableFields(BeanUtils.toBean(reqVO, PreviewParams.class))); + return success(datasourceService.getTableFields(tenantParamsUtils.prepareTenantParam(reqVO))); } @PostMapping("/datasource/preview") @Operation(summary = "数据源预览") @PreAuthorize("@ss.hasPermission('report:design')") public CommonResult> previewData(@RequestBody @Valid ReportDatasourcePreviewReqVO reqVO) { - return success(ureportDataSourceService.previewData(BeanUtils.toBean(reqVO, PreviewParams.class))); + return success(ureportDataSourceService.previewData(tenantParamsUtils.prepareTenantParam(reqVO))); } } diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/vo/ReportDatasourcePreviewReqVO.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/vo/ReportDatasourcePreviewReqVO.java index a90a1a37c..9ff4a8a3c 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/vo/ReportDatasourcePreviewReqVO.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/datasource/vo/ReportDatasourcePreviewReqVO.java @@ -24,7 +24,7 @@ import java.util.List; @NoArgsConstructor public class ReportDatasourcePreviewReqVO { @Schema(description = "数据源连接信息") - @NotNull + @NotNull(message = "数据源连接信息不能为空") @Valid private ReportDatasourceTestConnReqVO info; @@ -37,4 +37,8 @@ public class ReportDatasourcePreviewReqVO { @Size(max = 30, message = "查询参数列表数量不能超过30个") @Valid private List parameters; + + @Schema(description = "数据源编号") + @NotNull(message = "数据源编号不能为空") + private Long datasourceId; } diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceServiceImpl.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceServiceImpl.java index 9dfd34eb1..d25e1bb2a 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceServiceImpl.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/datasource/ReportDatasourceServiceImpl.java @@ -13,7 +13,6 @@ import com.bstek.datasource.bean.PreviewParams; import com.bstek.ureport.definition.dataset.Field; import com.bstek.ureport.definition.dataset.Parameter; import com.bstek.ureport.definition.dataset.SqlDatasetDefinition; -import com.bstek.ureport.definition.dataset.TenantParams; import com.bstek.ureport.utils.ProcedureUtils; import com.cf.imes.framework.common.exception.ServiceException; import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil; @@ -237,7 +236,7 @@ public class ReportDatasourceServiceImpl implements ReportDatasourceService { Map params = new HashMap<>(); Map pmap = sqlDatasetDefinition.buildParameters(params); - String sqlForUse = sqlDatasetDefinition.parseSql(pmap, new TenantParams()); + String sqlForUse = sqlDatasetDefinition.parseSql(pmap, previewParams.getTenantParams()); if (ProcedureUtils.isProcedure(sqlForUse)) { return ProcedureUtils.procedureColumnsQuery(sqlForUse, pmap, conn); } diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java index 991221db0..bb4201bb5 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java @@ -35,7 +35,6 @@ import com.cf.imes.framework.common.util.object.BeanUtils; import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; import com.cf.imes.framework.security.core.LoginUser; import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils; -import com.cf.imes.module.report.config.CfReportProperties; import com.cf.imes.module.report.controller.admin.template.vo.ReportTemplatePreviewReqVO; import com.cf.imes.module.report.controller.admin.template.vo.ReportTemplateReqVO; import com.cf.imes.module.report.controller.admin.template.vo.ReportTemplateRespVO; @@ -47,6 +46,7 @@ import com.cf.imes.module.report.dal.mysql.dataset.ReportDatasetMapper; import com.cf.imes.module.report.dal.mysql.datasource.ReportDatasourceMapper; import com.cf.imes.module.report.dal.mysql.template.ReportTemplateMapper; import com.cf.imes.module.report.enums.template.ReportTemplateTypeEnum; +import com.cf.imes.module.report.utils.TenantParamsUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -66,7 +66,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.cf.imes.module.report.enums.ErrorCodeConstants.TEMPLATE_BUILDIN_OPERATION_PERMISSION_ERROR; @@ -95,7 +94,7 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { private static final String UTF8_CHARSET = CharsetUtil.UTF_8; @Resource - private CfReportProperties cfReportProperties; + private TenantParamsUtils tenantParamsUtils; @Override @Transactional(rollbackFor = Exception.class) @@ -380,47 +379,11 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { ReportDefinition reportDefinition = getReportDefinition(reportRender, params); Map parameters = params.getQuery(); // 增加多租户参数 - prepareTenantParam(parameters); + tenantParamsUtils.prepareTenantParam(parameters); Report report = reportRender.render(reportDefinition, parameters); return htmlProducer.produce(reportDefinition, report); } - - /** - * 往parameters中增加租户相关参数 - * - * @param parameters - */ - private void prepareTenantParam(Map parameters) { - Long userOrganId = SecurityFrameworkUtils.getUserOrganId(); - if (Boolean.FALSE.equals(SecurityFrameworkUtils.isSuperAdmin())) { - // 根据前端传递的数据集id,判断是不是内置数据源下的,是就把name传给ureport - List datasetIds = (List) parameters.get("datasetIds"); - if (CollUtil.isNotEmpty(datasetIds)) { - // 内置数据集名称列表 - List buildinDsNames = new ArrayList<>(); - // 遍历获取所有上级数据源 - List reportDatasetDOS = datasetMapper.selectNormalDatasetList(datasetIds.stream().collect(Collectors.toSet())); - for (ReportDatasetDO datasetDO : reportDatasetDOS) { - Long datasourceId = datasetDO.getDatasourceId(); - // 查询数据源,如果是内置数据源则把数据集的name传给ureport - // 机构下 + 内置数据源查询 - ReportDatasourceDO datasourceDO = datasourceMapper.selectNormalDatasourceById(datasourceId, userOrganId); - if (ObjectUtil.isNotNull(datasourceDO) && ObjectUtil.equal(datasourceDO.getBuildinType(), ReportTemplateTypeEnum.SYSTEM)) { - buildinDsNames.add(datasetDO.getName()); - } - } - if (CollUtil.isNotEmpty(buildinDsNames)) { - parameters.put("buildinDsNames", buildinDsNames); - } - } - // imes多租户业务表表名列表 - parameters.put("tenantTableNames", cfReportProperties.getTenantTableNames()); - // 用户组织id - parameters.put("organId", userOrganId); - } - } - @Override public void print(ReportTemplatePreviewReqVO reqVO, HttpServletResponse response) { // 自定义请求vo转ureport对象 @@ -431,7 +394,7 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { ReportDefinition reportDefinition = getReportDefinition(reportRender, params); Map query = params.getQuery(); // 增加多租户参数 - prepareTenantParam(query); + tenantParamsUtils.prepareTenantParam(query); Report report = reportRender.render(reportDefinition, query); Map chartImages = params.getChartImages(); report.setChartImages(chartImages); @@ -461,7 +424,7 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { ReportDefinition reportDefinition = getReportDefinition(reportRender, params); Map query = params.getQuery(); // 增加多租户参数 - prepareTenantParam(query); + tenantParamsUtils.prepareTenantParam(query); Report report = reportRender.render(reportDefinition, query); Map chartImages = params.getChartImages(); report.setChartImages(chartImages); diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/utils/TenantParamsUtils.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/utils/TenantParamsUtils.java new file mode 100644 index 000000000..8493278ac --- /dev/null +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/utils/TenantParamsUtils.java @@ -0,0 +1,102 @@ +package com.cf.imes.module.report.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.bstek.datasource.bean.PreviewParams; +import com.bstek.ureport.definition.dataset.TenantParams; +import com.cf.imes.framework.common.util.object.BeanUtils; +import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils; +import com.cf.imes.module.report.config.CfReportProperties; +import com.cf.imes.module.report.controller.admin.datasource.vo.ReportDatasourcePreviewReqVO; +import com.cf.imes.module.report.dal.dataobject.dataset.ReportDatasetDO; +import com.cf.imes.module.report.dal.dataobject.datasource.ReportDatasourceDO; +import com.cf.imes.module.report.dal.mysql.dataset.ReportDatasetMapper; +import com.cf.imes.module.report.dal.mysql.datasource.ReportDatasourceMapper; +import com.cf.imes.module.report.enums.template.ReportTemplateTypeEnum; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 租户参数工具类 + * + * @author Gqr + * @since 2024/11/27 10:32 + */ +@Component +public class TenantParamsUtils { + + @Resource + private ReportDatasourceMapper datasourceMapper; + + @Resource + private ReportDatasetMapper datasetMapper; + + @Resource + private CfReportProperties cfReportProperties; + + /** + * 根据数据源id构造租户对象 + * + * @param reqVO + */ + public PreviewParams prepareTenantParam(ReportDatasourcePreviewReqVO reqVO) { + PreviewParams previewParams = BeanUtils.toBean(reqVO, PreviewParams.class); + Long datasourceId = reqVO.getDatasourceId(); + TenantParams tenantParams = new TenantParams(); + Long userOrganId = SecurityFrameworkUtils.getUserOrganId(); + // 根据前端传递的数据源id,判断是不是内置数据源,是就把所有其下的datasetname传给ureport + ReportDatasourceDO datasourceDO = datasourceMapper.selectNormalDatasourceById(datasourceId, userOrganId); + if (ObjectUtil.isNotNull(datasourceDO) && ObjectUtil.equal(datasourceDO.getBuildinType(), ReportTemplateTypeEnum.SYSTEM)) { + List datasetDOList = datasetMapper.selectList(new LambdaQueryWrapperX().in(ReportDatasetDO::getDatasourceId, datasourceId)); + if (CollUtil.isNotEmpty(datasetDOList)) { + tenantParams.setBuildinDsNames(datasetDOList.stream().map(ReportDatasetDO::getName).collect(Collectors.toList())); + } + } + // 用户组织id + tenantParams.setOrganId(userOrganId); + // imes多租户业务表表名列表 + tenantParams.setTenantTableNames(cfReportProperties.getTenantTableNames()); + previewParams.setTenantParams(tenantParams); + return previewParams; + } + + /** + * 往parameters中增加租户相关参数 + * + * @param parameters + */ + public void prepareTenantParam(Map parameters) { + Long userOrganId = SecurityFrameworkUtils.getUserOrganId(); + // 根据前端传递的数据集id,判断是不是内置数据源下的,是就把name传给ureport + List datasetIds = (List) parameters.get("datasetIds"); + if (CollUtil.isNotEmpty(datasetIds)) { + // 内置数据集名称列表 + List buildinDsNames = new ArrayList<>(); + // 遍历获取所有上级数据源 + List reportDatasetDOS = datasetMapper.selectNormalDatasetList(datasetIds.stream().collect(Collectors.toSet())); + for (ReportDatasetDO datasetDO : reportDatasetDOS) { + Long datasourceId = datasetDO.getDatasourceId(); + // 查询数据源,如果是内置数据源则把数据集的name传给ureport + // 机构下 + 内置数据源查询 + ReportDatasourceDO datasourceDO = datasourceMapper.selectNormalDatasourceById(datasourceId, userOrganId); + if (ObjectUtil.isNotNull(datasourceDO) && ObjectUtil.equal(datasourceDO.getBuildinType(), ReportTemplateTypeEnum.SYSTEM)) { + buildinDsNames.add(datasetDO.getName()); + } + } + if (CollUtil.isNotEmpty(buildinDsNames)) { + parameters.put("buildinDsNames", buildinDsNames); + } + } + // imes多租户业务表表名列表 + parameters.put("tenantTableNames", cfReportProperties.getTenantTableNames()); + // 用户组织id + parameters.put("organId", userOrganId); + } + +} diff --git a/cf-module-report/cf-module-report-biz/src/main/resources/lib/ureport-core-2.3.0-SNAPSHOT.jar b/cf-module-report/cf-module-report-biz/src/main/resources/lib/ureport-core-2.3.0-SNAPSHOT.jar index 8e8acf0b4032b5a4c89a12aadb8a934e6b13e247..6121e521afb135d42066020fef3de6aa4c1ef9b3 100644 GIT binary patch delta 38477 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 z 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

-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 delta 38763 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 From 1ea586b316ffcd0b986eaa8694f28e5355fb4185 Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Wed, 27 Nov 2024 14:34:38 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=E7=A6=85=E9=81=93#585=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/auth/vo/AuthLoginSmsCheckReqVO.java | 2 +- .../user/vo/profile/UserMobileUpdateReqVO.java | 2 +- .../user/vo/user/UserResetPasswordReqVO.java | 2 +- .../service/user/AdminUserServiceImpl.java | 17 +++++++++++------ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthLoginSmsCheckReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthLoginSmsCheckReqVO.java index 79f8853a1..85e54955f 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthLoginSmsCheckReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/vo/AuthLoginSmsCheckReqVO.java @@ -24,7 +24,7 @@ public class AuthLoginSmsCheckReqVO { private String mobile; @Schema(description = "验证码", example = "123456") - @Length(min = 6, max = 6, message = "验证码长度必须 6 位") + @Length(min = 6, max = 6, message = "短信验证码不正确") @NotEmpty(message = "短信验证码不能为空") private String smsCaptchaVerification; } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/profile/UserMobileUpdateReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/profile/UserMobileUpdateReqVO.java index 8d25db462..79dd7a358 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/profile/UserMobileUpdateReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/profile/UserMobileUpdateReqVO.java @@ -20,7 +20,7 @@ public class UserMobileUpdateReqVO { private String mobile; @Schema(description = "验证码", example = "123456") - @Length(min = 6, max = 6, message = "验证码长度必须 6 位") + @Length(min = 6, max = 6, message = "短信验证码不正确") @NotEmpty(message = "短信验证码不能为空") private String smsCaptchaVerification; } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserResetPasswordReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserResetPasswordReqVO.java index 4c2a15779..3e89a7d7e 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserResetPasswordReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/user/vo/user/UserResetPasswordReqVO.java @@ -17,7 +17,7 @@ public class UserResetPasswordReqVO { private String password; @Schema(description = "短信验证码", example = "123456") - @Length(min = 6, max = 6, message = "短信验证码长度为 6 位") + @Length(min = 6, max = 6, message = "短信验证码不正确") @NotEmpty(message = "短信验证码不能为空") private String smsCaptchaVerification; diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java index c98433458..03e21d157 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java @@ -119,7 +119,8 @@ public class AdminUserServiceImpl implements AdminUserService { private static final String UPPER_LETTER_PATTERN = ".*[A-Z].*"; private static final String LOWER_LETTER_PATTERN = ".*[a-z].*"; private static final String DIGIT_PATTERN = ".*\\d.*"; - private static final String VALID_CHAR_PATTERN = "^[A-Za-z\\d]+$"; + private static final String SPECIAL_CHARACTER_PATTERN = ".*[~!@#$%^&*()_+\\-=].*"; + private static final String VALID_CHAR_PATTERN = "^[A-Za-z\\d~!@#$%^&*()_+\\-=]+$"; @Override @Transactional(rollbackFor = Exception.class) @@ -506,19 +507,23 @@ public class AdminUserServiceImpl implements AdminUserService { } // 检查是否包含大写字母 if (!Pattern.matches(UPPER_LETTER_PATTERN, password)) { - throw ServiceExceptionUtil.exception(ErrorCodeConstants.THE_PASSWORD_MUST_CONTAIN_AT_LEAST_ONE_UPPER_LETTER); + throw ServiceExceptionUtil.exception(ErrorCodeConstants.THE_PASSWORD_LENGTH_MUST_BE_AT_LEAST_8_CHARACTERS); } // 检查是否包含小写字母 if (!Pattern.matches(LOWER_LETTER_PATTERN, password)) { - throw ServiceExceptionUtil.exception(ErrorCodeConstants.THE_PASSWORD_MUST_CONTAIN_AT_LEAST_ONE_LOWER_LETTER); + throw ServiceExceptionUtil.exception(ErrorCodeConstants.THE_PASSWORD_LENGTH_MUST_BE_AT_LEAST_8_CHARACTERS); } // 检查是否包含数字 if (!Pattern.matches(DIGIT_PATTERN, password)) { - throw ServiceExceptionUtil.exception(ErrorCodeConstants.THE_PASSWORD_MUST_CONTAIN_AT_LEAST_ONE_NUMBER); + throw ServiceExceptionUtil.exception(ErrorCodeConstants.THE_PASSWORD_LENGTH_MUST_BE_AT_LEAST_8_CHARACTERS); } - // 检查是否只包含字母和数字 + // 检查是否包含特殊字符 + if (!Pattern.matches(SPECIAL_CHARACTER_PATTERN, password)) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.THE_PASSWORD_LENGTH_MUST_BE_AT_LEAST_8_CHARACTERS); + } + // 检查是否只包含字母、数字和特殊字符 if (!Pattern.matches(VALID_CHAR_PATTERN, password)) { - throw ServiceExceptionUtil.exception(ErrorCodeConstants.PASSWORDS_CAN_ONLY_CONTAIN_LETTERS_AND_NUMBERS); + throw ServiceExceptionUtil.exception(ErrorCodeConstants.THE_PASSWORD_LENGTH_MUST_BE_AT_LEAST_8_CHARACTERS); } } From 137c1a0485da25197e5b1cff4c9ea2e9eb6d58a1 Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Wed, 27 Nov 2024 17:31:42 +0800 Subject: [PATCH 12/13] =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E6=9D=BF?= =?UTF-8?q?=E7=BC=96=E5=8F=B7=E7=94=9F=E6=88=90=E5=8A=9F=E8=83=BD=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../executor/enums/ErrorCodeConstants.java | 7 + .../dal/dataobject/plate/PlateDO.java | 8 +- .../CustomPlateNoGenerateService.java | 4 +- .../CustomPlateNoGenerateServiceImpl.java | 143 +++++++- .../vo/CustomPlateNoGenerateConfigVO.java | 4 +- .../customplateno/vo/CustomPlateNoRuleVO.java | 6 + .../vo/OrderCustomPlateNoSeqBodyVO.java | 26 ++ .../OrderCustomPlateNoSeqProcessGroupVO.java | 26 ++ .../vo/OrderCustomPlateNoSeqRoomVO.java | 37 +++ .../vo/OrderCustomPlateNoSeqVO.java | 89 ++--- .../BodyNoGenerateRuleServiceImpl.java | 223 +++++++++++++ .../CustomGenerateRuleServiceImpl.java | 33 ++ .../CustomPlateNoGenerateRuleService.java | 47 +++ .../DateGenerateRuleServiceImpl.java | 33 ++ .../OrderNoGenerateRuleServiceImpl.java | 185 +++++++++++ .../PlateNoGenerateRuleServiceImpl.java | 311 ++++++++++++++++++ ...ProcessGroupNoGenerateRuleServiceImpl.java | 240 ++++++++++++++ .../RoomNoGenerateRuleServiceImpl.java | 107 ++++++ .../customplateno/CustomPlateNoSeqApi.java | 10 +- ...qRespDTO.java => CustomPlateNoSeqDTO.java} | 8 +- .../system/enums/ErrorCodeConstants.java | 2 +- .../CustomPlateNoRuleCodeEnum.java} | 18 +- .../enums/customplateno/ResetModeEnum.java | 70 ++++ .../CustomPlateNoSeqApiImpl.java | 12 +- .../impl/CustomPlateNoServiceHandler.java | 121 ++++--- .../DefaultSystemConfigServiceHandler.java | 18 +- .../CustomPlateNoSeqService.java | 7 + .../CustomPlateNoSeqServiceImpl.java | 9 +- 28 files changed, 1646 insertions(+), 158 deletions(-) create mode 100644 cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqBodyVO.java create mode 100644 cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqProcessGroupVO.java create mode 100644 cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqRoomVO.java create mode 100644 cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/BodyNoGenerateRuleServiceImpl.java create mode 100644 cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/CustomGenerateRuleServiceImpl.java create mode 100644 cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/CustomPlateNoGenerateRuleService.java create mode 100644 cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/DateGenerateRuleServiceImpl.java create mode 100644 cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/OrderNoGenerateRuleServiceImpl.java create mode 100644 cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/PlateNoGenerateRuleServiceImpl.java create mode 100644 cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/ProcessGroupNoGenerateRuleServiceImpl.java create mode 100644 cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/RoomNoGenerateRuleServiceImpl.java rename cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/api/customplateno/dto/{CustomPlateNoSeqRespDTO.java => CustomPlateNoSeqDTO.java} (86%) rename cf-module-system/{cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/config/CustBoardRuleCodeEnum.java => cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/customplateno/CustomPlateNoRuleCodeEnum.java} (68%) create mode 100644 cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/customplateno/ResetModeEnum.java diff --git a/cf-module-prod-executor/cf-module-prod-executor-api/src/main/java/com/cf/imes/module/executor/enums/ErrorCodeConstants.java b/cf-module-prod-executor/cf-module-prod-executor-api/src/main/java/com/cf/imes/module/executor/enums/ErrorCodeConstants.java index 37c8fde9a..31f75df7e 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-api/src/main/java/com/cf/imes/module/executor/enums/ErrorCodeConstants.java +++ b/cf-module-prod-executor/cf-module-prod-executor-api/src/main/java/com/cf/imes/module/executor/enums/ErrorCodeConstants.java @@ -59,4 +59,11 @@ public class ErrorCodeConstants { public static final ErrorCode SOURCE_NOT_EXITS_ERROR = new ErrorCode(1_002_029_013, "源数据查询失败"); public static final ErrorCode ORDER_DELETED_ERR = new ErrorCode(1_002_029_006, "生产单删除失败"); public static final ErrorCode ORDER_RESTORE_ERR = new ErrorCode(1_002_029_006, "生产单还原失败"); + + // ========== 自定义板编号生成 ========== + public static final ErrorCode CUSTOM_PLATENO_GENERATE_ORDERNO_RULE_NOT_SUPPORT_RESETMODE = new ErrorCode(1_002_030_001, "自定义版编号生产单序号规则中存在不支持的复位类型:{}"); + public static final ErrorCode CUSTOM_PLATENO_GENERATE_BODY_RULE_NOT_SUPPORT_RESETMODE = new ErrorCode(1_002_030_002, "自定义版编号柜体序号规则中存在不支持的复位类型:{}"); + public static final ErrorCode CUSTOM_PLATENO_GENERATE_PROCESSGROUP_RULE_NOT_SUPPORT_RESETMODE = new ErrorCode(1_002_030_003, "自定义版编号加工组序号规则中存在不支持的复位类型:{}"); + public static final ErrorCode CUSTOM_PLATENO_GENERATE_PLATE_RULE_NOT_SUPPORT_RESETMODE = new ErrorCode(1_002_030_004, "自定义版编号板件序号规则中存在不支持的复位类型:{}"); + public static final ErrorCode CUSTOM_PLATENO_GENERATE_ORG_CUSTOM_PLATENO_SEQ_MODIFY_ERROR = new ErrorCode(1_002_030_005, "保存组织下自定义板编号序号配置失败,请联系客服处理"); } diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/dataobject/plate/PlateDO.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/dataobject/plate/PlateDO.java index b43a00a23..3bcf85f64 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/dataobject/plate/PlateDO.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/dataobject/plate/PlateDO.java @@ -189,15 +189,15 @@ public class PlateDO extends BaseDO { /** * 房间名 */ + @TableField(exist = false) private String roomName; /** * 柜体名 */ + @TableField(exist = false) private String bodyName; - /** - * 加工组名 - */ - private String processGroupName; + @TableField(exist = false) + private StringBuilder customPlateNo; } \ No newline at end of file diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/CustomPlateNoGenerateService.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/CustomPlateNoGenerateService.java index fa956ae83..941a70d6d 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/CustomPlateNoGenerateService.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/CustomPlateNoGenerateService.java @@ -1,5 +1,6 @@ package com.cf.imes.module.executor.service.customplateno; +import com.cf.imes.module.executor.dal.dataobject.order.OrderDO; import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO; import java.util.List; @@ -14,7 +15,8 @@ public interface CustomPlateNoGenerateService { /** * 生成自定义板编号 * + * @param orderDO 生产单号 * @param plateDOList 板件列表 */ - void generateCustomPlateNo(List plateDOList); + void generateCustomPlateNo(OrderDO orderDO, List plateDOList); } diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/CustomPlateNoGenerateServiceImpl.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/CustomPlateNoGenerateServiceImpl.java index eb1dbff85..10b63186f 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/CustomPlateNoGenerateServiceImpl.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/CustomPlateNoGenerateServiceImpl.java @@ -1,10 +1,32 @@ package com.cf.imes.module.executor.service.customplateno; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSON; +import com.cf.imes.framework.common.exception.ServiceException; +import com.cf.imes.framework.common.pojo.CommonResult; +import com.cf.imes.module.executor.dal.dataobject.order.OrderDO; import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO; +import com.cf.imes.module.executor.enums.ErrorCodeConstants; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoGenerateConfigVO; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoRuleVO; +import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqVO; +import com.cf.imes.module.executor.service.customplatenorule.CustomPlateNoGenerateRuleService; +import com.cf.imes.module.executor.service.order.OrderService; +import com.cf.imes.module.system.api.customplateno.CustomPlateNoSeqApi; +import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqDTO; +import com.cf.imes.module.system.api.systemconfig.SystemConfigApi; +import com.cf.imes.module.system.api.systemconfig.dto.SystemConfigRespDTO; +import com.cf.imes.module.system.enums.customplateno.CustomPlateNoRuleCodeEnum; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.Optional; /** * @author Gqr @@ -14,8 +36,125 @@ import java.util.List; @Slf4j public class CustomPlateNoGenerateServiceImpl implements CustomPlateNoGenerateService { + @Resource + @Lazy + private OrderService orderService; + + @Resource + private SystemConfigApi systemConfigApi; + + @Resource + private CustomPlateNoSeqApi customPlateNoSeqApi; + + @Resource + private List ruleServices; + + private static final DateTimeFormatter YEAR_FORMATTER = DateTimeFormatter.ofPattern("yyyy"); + private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM"); + private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd"); + @Override - public void generateCustomPlateNo(List plateDOList) { - // todo generateCustomPlateNo + public void generateCustomPlateNo(OrderDO orderDO, List plateDOList) { + Long orderId = orderDO.getId(); + // 1、获取生产配置 + CustomPlateNoGenerateConfigVO generateConfig = getGenerateConfig(orderId); + // 如果没有查到配置规则就不做后续生成操作了 + List orgCustomPlateNoRuleVOList = generateConfig.getOrgCustomPlateNoRuleVOList(); + if (CollUtil.isEmpty(orgCustomPlateNoRuleVOList)) { + return; + } + + // 开始生成时记录时间,用于后续年月日复位、上次年月日记录等 + LocalDateTime now = LocalDateTime.now(); + orgCustomPlateNoRuleVOList.forEach(rule -> rule.setNow(now)); + + // 2、遍历小板列表,生成板编号 + for (PlateDO plateDO : plateDOList) { + loopGenerateNo(orderId, plateDO, orgCustomPlateNoRuleVOList, generateConfig); + } + + // 3、保存生产单序号json + orderDO.setCustomPlatenoSeq(JSON.toJSONString(generateConfig.getOrderCustomPlateNoSeqVO())); + CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO = generateConfig.getOrgCustomPlateNoSeqRespDTO(); + orgCustomPlateNoSeqRespDTO.setLastOrderNo(orderId); + orgCustomPlateNoSeqRespDTO.setLastYear(Integer.parseInt(YEAR_FORMATTER.format(now))); + orgCustomPlateNoSeqRespDTO.setLastMonth(Integer.parseInt(MONTH_FORMATTER.format(now))); + orgCustomPlateNoSeqRespDTO.setLastDay(Integer.parseInt(DAY_FORMATTER.format(now))); + // 保存组织下全局序号配置 + CommonResult orgCustomPlateNoSeqModifyResult = customPlateNoSeqApi.modifyOrgCustomPlateNoSeq(orgCustomPlateNoSeqRespDTO); + if (orgCustomPlateNoSeqModifyResult.isError() || !orgCustomPlateNoSeqModifyResult.getData().booleanValue()) { + throw new ServiceException(ErrorCodeConstants.CUSTOM_PLATENO_GENERATE_ORG_CUSTOM_PLATENO_SEQ_MODIFY_ERROR); + } + } + + /** + * 循环规则和板件列表生成编号 + * + * @param orderId + * @param plateDO + * @param orgCustomPlateNoRuleVOList + * @param generateConfig + */ + private void loopGenerateNo(Long orderId, PlateDO plateDO, List orgCustomPlateNoRuleVOList, CustomPlateNoGenerateConfigVO generateConfig) { + // 遍历规则列表 + for (CustomPlateNoRuleVO plateNoRule : orgCustomPlateNoRuleVOList) { + if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.CUSTOM.getRuleCode(), plateNoRule.getRuleCode())) { + plateDO.getCustomPlateNo().append(plateNoRule.getValue()); + } + if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.DATE.getRuleCode(), plateNoRule.getRuleCode())) { + plateDO.getCustomPlateNo().append(plateNoRule.getNow().format(DateTimeFormatter.ofPattern(plateNoRule.getValue()))); + } + // 遍历规则生成服务列表,获取对应的规则服务 + for (CustomPlateNoGenerateRuleService ruleService : ruleServices) { + if (ruleService.match(plateNoRule.getRuleCode())) { + generateConfig = ruleService.generateNo(orderId, plateNoRule, generateConfig, plateDO); + break; + } + } + } + plateDO.setPlateNo(plateDO.getCustomPlateNo().toString()); + } + + private CustomPlateNoGenerateConfigVO getGenerateConfig(Long orderId) { + // 生成自定义版编号所需配置 + CustomPlateNoGenerateConfigVO customPlateNoGenerateConfigVO = new CustomPlateNoGenerateConfigVO(); + + // 机构下自定义板编号配置 + SystemConfigRespDTO orgCustomPlateNoConfig = null; + // 生产单下序号 + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = new OrderCustomPlateNoSeqVO(); + // 自定义板编号配置规则明细列表 + List customPlateNoRuleVOS = List.of(); + // 查询机构的自定义版编号配置 + CommonResult orgCustomPlateNoConfigResult = systemConfigApi.getOrgCustomPlateNoConfig(); + if (orgCustomPlateNoConfigResult.isSuccess()) { + orgCustomPlateNoConfig = orgCustomPlateNoConfigResult.getData(); + customPlateNoRuleVOS = Optional.ofNullable(orgCustomPlateNoConfig) + .map(config -> JSON.parseArray(config.getSetting(), CustomPlateNoRuleVO.class)) + .orElse(List.of()); + } + + OrderDO order = orderService.getOrder(orderId); + if (ObjectUtil.isNotNull(order) && ObjectUtil.isNotNull(orgCustomPlateNoConfig)) { + // 老单 + // 生产单上的自定义板编号配置id和当前最新的对比,不同用生产单号上的 + Long orderCustomPlatenoConfigId = order.getCustomPlatenoConfigId(); + if (ObjectUtil.isNotNull(orderCustomPlatenoConfigId) && ObjectUtil.notEqual(orgCustomPlateNoConfig.getId(), orderCustomPlatenoConfigId)) { + CommonResult previousCustomPlateNoConfig = systemConfigApi.getById(orderCustomPlatenoConfigId); + if (previousCustomPlateNoConfig.isSuccess()) { + customPlateNoRuleVOS = JSON.parseArray(previousCustomPlateNoConfig.getData().getSetting(), CustomPlateNoRuleVO.class); + } + } + + // 上一次的生产单内 自定义版编号序号 + orderCustomPlateNoSeqVO = JSON.parseObject(order.getCustomPlatenoSeq(), OrderCustomPlateNoSeqVO.class); + } + customPlateNoGenerateConfigVO.setOrderCustomPlateNoSeqVO(orderCustomPlateNoSeqVO); + customPlateNoGenerateConfigVO.setOrgCustomPlateNoRuleVOList(customPlateNoRuleVOS); + CommonResult orgCustomPlateNoSeq = customPlateNoSeqApi.getOrgCustomPlateNoSeq(); + if (orgCustomPlateNoSeq.isSuccess()) { + customPlateNoGenerateConfigVO.setOrgCustomPlateNoSeqRespDTO(orgCustomPlateNoSeq.getData()); + } + return customPlateNoGenerateConfigVO; } } diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/CustomPlateNoGenerateConfigVO.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/CustomPlateNoGenerateConfigVO.java index 178e45358..411687dc9 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/CustomPlateNoGenerateConfigVO.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/CustomPlateNoGenerateConfigVO.java @@ -1,6 +1,6 @@ package com.cf.imes.module.executor.service.customplateno.vo; -import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqRespDTO; +import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqDTO; import lombok.Data; import java.io.Serializable; @@ -27,5 +27,5 @@ public class CustomPlateNoGenerateConfigVO implements Serializable { /** * 机构下的自定义板编号序号 */ - private CustomPlateNoSeqRespDTO orgCustomPlateNoSeqRespDTO; + private CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO; } diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/CustomPlateNoRuleVO.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/CustomPlateNoRuleVO.java index 98cfbea73..47c8713d3 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/CustomPlateNoRuleVO.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/CustomPlateNoRuleVO.java @@ -3,6 +3,7 @@ package com.cf.imes.module.executor.service.customplateno.vo; import lombok.Data; import java.io.Serializable; +import java.time.LocalDateTime; /** * 系统配置-自定义板编号setting项 vo @@ -48,4 +49,9 @@ public class CustomPlateNoRuleVO implements Serializable { * 复位/清零模式 */ private Integer resetMode; + + /** + * 开始生成板编号的时间 + */ + private LocalDateTime now; } diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqBodyVO.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqBodyVO.java new file mode 100644 index 000000000..4b554cc20 --- /dev/null +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqBodyVO.java @@ -0,0 +1,26 @@ +package com.cf.imes.module.executor.service.customplateno.vo; + +import lombok.Builder; +import lombok.Data; + +import java.io.Serializable; + +@Data +@Builder +public class OrderCustomPlateNoSeqBodyVO implements Serializable { + private static final long serialVersionUID = 2686882895438975156L; + /** + * 柜体名 + */ + private String bodyName; + + /** + * 柜体下板件序号 + */ + private Integer plateNoSeq; + + /** + * 柜体序号 + */ + private Integer bodyNoSeq; +} diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqProcessGroupVO.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqProcessGroupVO.java new file mode 100644 index 000000000..3a436593c --- /dev/null +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqProcessGroupVO.java @@ -0,0 +1,26 @@ +package com.cf.imes.module.executor.service.customplateno.vo; + +import lombok.Builder; +import lombok.Data; + +import java.io.Serializable; + +@Data +@Builder +public class OrderCustomPlateNoSeqProcessGroupVO implements Serializable { + private static final long serialVersionUID = -6834098282222544638L; + /** + * 加工组名 + */ + private String processGroupName; + + /** + * 加工组下板件序号 + */ + private Integer plateNoSeq; + + /** + * 加工组序号 + */ + private Integer processGroupNoSeq; +} diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqRoomVO.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqRoomVO.java new file mode 100644 index 000000000..0ba456f16 --- /dev/null +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqRoomVO.java @@ -0,0 +1,37 @@ +package com.cf.imes.module.executor.service.customplateno.vo; + +import lombok.Builder; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +@Builder +public class OrderCustomPlateNoSeqRoomVO implements Serializable { + private static final long serialVersionUID = -127388898531267048L; + /** + * 房间名 + */ + private String roomName; + + /** + * 房间序号 + */ + private Integer roomNoSeq; + + /** + * 房间下板件序号 + */ + private Integer plateNoSeq; + + /** + * 房间下柜体序号 + */ + private Integer bodyNoSeq; + + /** + * 房间下柜体列表 + */ + private List bodys; +} diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqVO.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqVO.java index 810c3c6d8..cd3c1d93a 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqVO.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplateno/vo/OrderCustomPlateNoSeqVO.java @@ -1,6 +1,8 @@ package com.cf.imes.module.executor.service.customplateno.vo; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; @@ -12,92 +14,39 @@ import java.util.List; * @since 2024/11/15 10:41 */ @Data +@NoArgsConstructor +@AllArgsConstructor public class OrderCustomPlateNoSeqVO implements Serializable { private static final long serialVersionUID = 5841977329049878792L; + + /** + * 生产单序号 + */ + private Integer orderNoSeq; + /** * 生产单下房间序号 */ - private int roomSeq; + private Integer roomNoSeq; /** * 生产单下柜体序号 */ - private int bodySeq; - - /** - * 生产单下加工组序号 - */ - private int processGroupSeq; + private Integer bodyNoSeq; /** * 生产单下板件序号 */ - private int plateNoSeq; + private Integer plateNoSeq; /** * 生产单下房间列表 */ - private List rooms; + private List rooms; + + /** + * 生产单下柜体列表 + */ + private List bodys; } -@Data -class Room implements Serializable { - private static final long serialVersionUID = -127388898531267048L; - /** - * 房间名 - */ - private String roomNo; - - /** - * 房间下板件序号 - */ - private int plateNoSeq; - - /** - * 房间下柜体序号 - */ - private int bodySeq; - - /** - * 房间下柜体列表 - */ - private List bodys; - - /** - * 房间下加工组序号 - */ - private int processGroupSeq; - - /** - * 房间下加工组列表 - */ - private List processGroups; -} - -@Data -class Body implements Serializable { - private static final long serialVersionUID = 2686882895438975156L; - /** - * 柜体名 - */ - private String bodyNo; - - /** - * 柜体下板件序号 - */ - private int plateNoSeq; -} - -@Data -class ProcessGroup implements Serializable { - private static final long serialVersionUID = -6834098282222544638L; - /** - * 加工组名 - */ - private String processGroupNo; - - /** - * 加工组下板件序号 - */ - private int plateNoSeq; -} \ No newline at end of file diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/BodyNoGenerateRuleServiceImpl.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/BodyNoGenerateRuleServiceImpl.java new file mode 100644 index 000000000..65aed1fe1 --- /dev/null +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/BodyNoGenerateRuleServiceImpl.java @@ -0,0 +1,223 @@ +package com.cf.imes.module.executor.service.customplatenorule; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil; +import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoGenerateConfigVO; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoRuleVO; +import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqBodyVO; +import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqRoomVO; +import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqVO; +import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqDTO; +import com.cf.imes.module.system.enums.customplateno.CustomPlateNoRuleCodeEnum; +import com.cf.imes.module.system.enums.customplateno.ResetModeEnum; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static com.cf.imes.module.executor.enums.ErrorCodeConstants.CUSTOM_PLATENO_GENERATE_BODY_RULE_NOT_SUPPORT_RESETMODE; + +/** + * 柜体序号生成规则服务实现类 + * + * @author Gqr + * @since 2024/11/19 16:35 + */ +@Service("bodyNoGenerateRuleService") +public class BodyNoGenerateRuleServiceImpl implements CustomPlateNoGenerateRuleService { + @Override + public boolean match(String ruleCode) { + return ObjectUtil.equal(CustomPlateNoRuleCodeEnum.BODYNO.getRuleCode(), ruleCode); + } + + @Override + public CustomPlateNoGenerateConfigVO generateNo(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) { + // 初始化配置 + initConfig(generateConfig); + // 按复位模式走不同的生成方式 + ResetModeEnum resetModeEnum = ResetModeEnum.getByMode(plateNoRule.getResetMode()); + if (ObjectUtil.equal(ResetModeEnum.ORDER, resetModeEnum)) { + generateConfig = generateNoByOrderResetMode(orderId, plateNoRule, generateConfig, plateDO); + } else if (ObjectUtil.equal(ResetModeEnum.ROOM, resetModeEnum)) { + generateConfig = generateNoByRoomResetMode(plateNoRule, generateConfig, plateDO); + } else { + throw ServiceExceptionUtil.exception(CUSTOM_PLATENO_GENERATE_BODY_RULE_NOT_SUPPORT_RESETMODE, plateNoRule.getResetMode()); + } + return generateConfig; + } + + /** + * 初始化生成所需配置 + * + * @param generateConfigVO + */ + private static void initConfig(CustomPlateNoGenerateConfigVO generateConfigVO) { + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfigVO.getOrderCustomPlateNoSeqVO(); + if (ObjectUtil.isNull(orderCustomPlateNoSeqVO)) { + orderCustomPlateNoSeqVO = new OrderCustomPlateNoSeqVO(); + generateConfigVO.setOrderCustomPlateNoSeqVO(orderCustomPlateNoSeqVO); + } + List rooms = orderCustomPlateNoSeqVO.getRooms(); + if (CollUtil.isEmpty(rooms)) { + rooms = new ArrayList<>(); + orderCustomPlateNoSeqVO.setRooms(rooms); + } + List boyds = orderCustomPlateNoSeqVO.getBodys(); + if (CollUtil.isEmpty(boyds)) { + boyds = new ArrayList<>(); + orderCustomPlateNoSeqVO.setBodys(boyds); + } + } + + /** + * 按生产单复位模式下的板编号生成 + * + * @param orderId 生产单号 + * @param plateNoRule 当前规则配置 + * @param generateConfig 生成规则配置 + * @param plateDO 板件列表 + * @return + */ + private CustomPlateNoGenerateConfigVO generateNoByOrderResetMode(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) { + Integer incrementStep = plateNoRule.getIncrementStep(); + Integer initValue = plateNoRule.getInitValue() - incrementStep; + // 生产单下的序号 + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO(); + // 机构下的自定义板编号序号 + CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO = generateConfig.getOrgCustomPlateNoSeqRespDTO(); + // 生产单下柜体序号 + Integer orderBodyNoSeq = Optional.ofNullable(orderCustomPlateNoSeqVO.getBodyNoSeq()).orElse(initValue); + // 生产单序号下的房间序号列表 + List bodys = orderCustomPlateNoSeqVO.getBodys(); + // 上次导入的生产单号 + Long lastOrderNo = orgCustomPlateNoSeqRespDTO.getLastOrderNo(); + if (ObjectUtil.isNotNull(lastOrderNo) && ObjectUtil.notEqual(orderId, lastOrderNo)) { + // 跨单复位到初始值 + orderBodyNoSeq = initValue; + } + String bodyName = plateDO.getBodyName(); + // 根据柜体名获取生产单下序号json中第一层柜体列表的柜体序号 + OrderCustomPlateNoSeqBodyVO bodySeqVo = getBodySeqVOByBodyName(bodyName, bodys); + // 获取当前柜体序号值 + Integer bodyNoSeq = Optional.ofNullable(bodySeqVo).map(OrderCustomPlateNoSeqBodyVO::getBodyNoSeq).orElse(null); + if (bodySeqVo == null) { + // 生产单序号下柜体为空,新建柜体,取生产单下柜体序号 + bodySeqVo = OrderCustomPlateNoSeqBodyVO.builder() + .bodyName(bodyName) + .build(); + bodys.add(bodySeqVo); + // 累加步长 + bodyNoSeq = orderBodyNoSeq + incrementStep; + // 累加后的值同步到当前生产单序号中,生产单下柜体序号累加到多少了 + orderCustomPlateNoSeqVO.setBodyNoSeq(bodyNoSeq); + } else if (bodyNoSeq == null) { + // 柜体下序号为空,取生产单下房间序号 + // 累加步长 + bodyNoSeq = orderBodyNoSeq + incrementStep; + // 累加后的值同步到当前生产单序号中,生产单下柜体序号累加到多少了 + orderCustomPlateNoSeqVO.setBodyNoSeq(bodyNoSeq); + } + + // 补零 + String noPartAfterFillZero = fillZero(bodyNoSeq, plateNoRule); + plateDO.getCustomPlateNo().append(noPartAfterFillZero); + // 累加后同步到json:柜体下累加到多少了 + bodySeqVo.setBodyNoSeq(bodyNoSeq); + + return generateConfig; + } + + /** + * 按房间号复位模式下的板编号生成 + * + * @param plateNoRule + * @param generateConfig + * @param plateDO + * @return + */ + private CustomPlateNoGenerateConfigVO generateNoByRoomResetMode(CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) { + Integer incrementStep = plateNoRule.getIncrementStep(); + Integer initValue = plateNoRule.getInitValue() - incrementStep; + // 生产单下的序号 + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO(); + List rooms = orderCustomPlateNoSeqVO.getRooms(); + + String roomName = plateDO.getRoomName(); + // 根据房间名获取生产单下序号json中的房间下的柜体序号 + OrderCustomPlateNoSeqRoomVO roomSeqVo = getRoomSeqVOByRoomName(roomName, rooms); + Integer roomBodyNoRoomSeq = Optional.ofNullable(roomSeqVo) + .map(OrderCustomPlateNoSeqRoomVO::getBodyNoSeq) + .orElse(initValue); + + if (roomSeqVo == null) { + // 房间为空,新建对象,设置初始值 + roomSeqVo = OrderCustomPlateNoSeqRoomVO.builder() + .roomName(roomName) + .bodyNoSeq(roomBodyNoRoomSeq) + .bodys(new ArrayList<>()) + .build(); + rooms.add(roomSeqVo); + } + + // 如果是新的柜体vo,要把累加的值记录到生产单rooms下的柜体 + String bodyName = plateDO.getBodyName(); + // 根据柜体名获取生产单下序号中rooms下柜体列表的柜体序号 + List roomBodys = roomSeqVo.getBodys(); + OrderCustomPlateNoSeqBodyVO roomBodySeqVo = getBodySeqVOByBodyName(bodyName, roomBodys); + // 获取当前房间下柜体的序号值 + Integer roomBodyNoSeq = Optional.ofNullable(roomBodySeqVo).map(OrderCustomPlateNoSeqBodyVO::getBodyNoSeq).orElse(null); + if (roomBodySeqVo == null) { + // 房间下柜体为空,新建对象,设置房间下全局柜体序号值 + roomBodySeqVo = OrderCustomPlateNoSeqBodyVO.builder() + .bodyName(bodyName) + .build(); + roomBodys.add(roomBodySeqVo); + // 累加步长 + roomBodyNoSeq = roomBodyNoRoomSeq + incrementStep; + // 累加后的值同步到当前生产单序号中,生产单下房间中柜体累加到多少了 + roomSeqVo.setBodyNoSeq(roomBodyNoSeq); + } else if (roomBodyNoSeq == null) { + // 房间下柜体序号为空,设置房间下全局柜体序号值 + // 累加步长 + roomBodyNoSeq = roomBodyNoRoomSeq + incrementStep; + // 累加后的值同步到当前生产单序号中,生产单下房间中柜体累加到多少了 + roomSeqVo.setBodyNoSeq(roomBodyNoSeq); + } + + // 补零 + String noPartAfterFillZero = fillZero(roomBodyNoSeq, plateNoRule); + plateDO.getCustomPlateNo().append(noPartAfterFillZero); + // 累加后同步到json中,room下柜体累加到多少了 + roomBodySeqVo.setBodyNoSeq(roomBodyNoSeq); + + return generateConfig; + } + + /** + * 根据房间名从生产单序号json中获取房间序号 + * + * @param roomName + * @param roomVOList + * @return + */ + private OrderCustomPlateNoSeqRoomVO getRoomSeqVOByRoomName(String roomName, List roomVOList) { + return roomVOList.stream().filter(roomVO -> ObjectUtil.equal(roomName, roomVO.getRoomName())).findAny().orElse(null); + } + + /** + * 根据柜体名从生产单序号json中获取柜体序号 + * + * @param bodyName + * @param bodyVOList + * @return + */ + private OrderCustomPlateNoSeqBodyVO getBodySeqVOByBodyName(String bodyName, List bodyVOList) { + if (CollUtil.isEmpty(bodyVOList)) { + return null; + } + return bodyVOList.stream().filter(bodyVO -> ObjectUtil.equal(bodyName, bodyVO.getBodyName())).findAny().orElse(null); + } +} diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/CustomGenerateRuleServiceImpl.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/CustomGenerateRuleServiceImpl.java new file mode 100644 index 000000000..cc84974fe --- /dev/null +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/CustomGenerateRuleServiceImpl.java @@ -0,0 +1,33 @@ +//package com.cf.imes.module.executor.service.customplatenorule; +// +//import cn.hutool.core.util.ObjectUtil; +//import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO; +//import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoGenerateConfigVO; +//import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoRuleVO; +//import com.cf.imes.module.system.enums.customplateno.CustomPlateNoRuleCodeEnum; +//import org.springframework.stereotype.Service; +// +//import java.util.List; +// +///** +// * 自定义规则生成实现类 +// * +// * @author Gqr +// * @since 2024/11/18 16:37 +// */ +////@Service("customGenerateRuleService") +//public class CustomGenerateRuleServiceImpl implements CustomPlateNoGenerateRuleService { +// @Override +// public boolean match(String ruleCode) { +// return ObjectUtil.equal(CustomPlateNoRuleCodeEnum.CUSTOM.getRuleCode(), ruleCode); +// } +// +// @Override +// public CustomPlateNoGenerateConfigVO generateNo(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, List plateDOList) { +// for (PlateDO plateDO : plateDOList) { +// plateDO.getCustomPlateNo().append(plateNoRule.getValue()); +// } +// return generateConfig; +// } +// +//} diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/CustomPlateNoGenerateRuleService.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/CustomPlateNoGenerateRuleService.java new file mode 100644 index 000000000..8c7f4ac38 --- /dev/null +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/CustomPlateNoGenerateRuleService.java @@ -0,0 +1,47 @@ +package com.cf.imes.module.executor.service.customplatenorule; + +import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoGenerateConfigVO; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoRuleVO; + +/** + * 自定义板编号生成规则服务 + * + * @author Gqr + * @since 2024/11/18 16:30 + */ +public interface CustomPlateNoGenerateRuleService { + /** + * 是否匹配的规则编码 + * + * @param ruleCode + * @return + */ + boolean match(String ruleCode); + + /** + * 生成编号 + * + * @param orderId 生产单号 + * @param plateDO 板材列表 + * @param generateConfig 生成所需要的配置 + * @return 生成后改变的配置 + */ + CustomPlateNoGenerateConfigVO generateNo(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO); + + /** + * 左补零 + * + * @param curr 当前值 + * @param plateNoRule 生成规则 + * @return + */ + default String fillZero(int curr, CustomPlateNoRuleVO plateNoRule) { + boolean leftFillZero = plateNoRule.isLeftFillZero(); + Integer length = plateNoRule.getLength(); + if (leftFillZero) { + return String.format("%0" + length + "d", curr); + } + return String.valueOf(curr); + } +} diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/DateGenerateRuleServiceImpl.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/DateGenerateRuleServiceImpl.java new file mode 100644 index 000000000..eebf442b7 --- /dev/null +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/DateGenerateRuleServiceImpl.java @@ -0,0 +1,33 @@ +//package com.cf.imes.module.executor.service.customplatenorule; +// +//import cn.hutool.core.util.ObjectUtil; +//import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO; +//import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoGenerateConfigVO; +//import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoRuleVO; +//import com.cf.imes.module.system.enums.customplateno.CustomPlateNoRuleCodeEnum; +//import org.springframework.stereotype.Service; +// +//import java.time.format.DateTimeFormatter; +//import java.util.List; +// +///** +// * 日期规则生成服务实现类 +// * +// * @author Gqr +// * @since 2024/11/18 16:46 +// */ +//@Service("dateGenerateRuleService") +//public class DateGenerateRuleServiceImpl implements CustomPlateNoGenerateRuleService { +// @Override +// public boolean match(String ruleCode) { +// return ObjectUtil.equal(CustomPlateNoRuleCodeEnum.DATE.getRuleCode(), ruleCode); +// } +// +// @Override +// public CustomPlateNoGenerateConfigVO generateNo(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, List plateDOList) { +// for (PlateDO plateDO : plateDOList) { +// plateDO.getCustomPlateNo().append(plateNoRule.getNow().format(DateTimeFormatter.ofPattern(plateNoRule.getValue()))); +// } +// return generateConfig; +// } +//} diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/OrderNoGenerateRuleServiceImpl.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/OrderNoGenerateRuleServiceImpl.java new file mode 100644 index 000000000..fd4bbe703 --- /dev/null +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/OrderNoGenerateRuleServiceImpl.java @@ -0,0 +1,185 @@ +package com.cf.imes.module.executor.service.customplatenorule; + +import cn.hutool.core.util.ObjectUtil; +import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil; +import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoGenerateConfigVO; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoRuleVO; +import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqVO; +import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqDTO; +import com.cf.imes.module.system.enums.customplateno.CustomPlateNoRuleCodeEnum; +import com.cf.imes.module.system.enums.customplateno.ResetModeEnum; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Optional; + +import static com.cf.imes.module.executor.enums.ErrorCodeConstants.CUSTOM_PLATENO_GENERATE_ORDERNO_RULE_NOT_SUPPORT_RESETMODE; + +/** + * 生产单序号生成规则服务实现类 + * + * @author Gqr + * @since 2024/11/18 17:18 + */ +@Service("orderNoGenerateRuleService") +public class OrderNoGenerateRuleServiceImpl implements CustomPlateNoGenerateRuleService { + + private static final DateTimeFormatter YEAR_FORMATTER = DateTimeFormatter.ofPattern("yyyy"); + private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM"); + private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd"); + + @Override + public boolean match(String ruleCode) { + return ObjectUtil.equal(CustomPlateNoRuleCodeEnum.ORDERNO.getRuleCode(), ruleCode); + } + + /** + * 初始化生成所需配置 + * + * @param generateConfigVO + */ + private static void initConfig(CustomPlateNoGenerateConfigVO generateConfigVO) { + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfigVO.getOrderCustomPlateNoSeqVO(); + if (ObjectUtil.isNull(orderCustomPlateNoSeqVO)) { + orderCustomPlateNoSeqVO = new OrderCustomPlateNoSeqVO(); + generateConfigVO.setOrderCustomPlateNoSeqVO(orderCustomPlateNoSeqVO); + } + } + + @Override + public CustomPlateNoGenerateConfigVO generateNo(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) { + // 初始化配置 + initConfig(generateConfig); + // 生产单下的序号 + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO(); + Integer orderNoSeq = orderCustomPlateNoSeqVO.getOrderNoSeq(); + // 当前导入已有序号的,生产单内生产单序号不会再变直接用 + if (ObjectUtil.isNotNull(orderNoSeq)) { + // 补零 + String noPartAfterFill = this.fillZero(orderNoSeq, plateNoRule); + plateDO.getCustomPlateNo().append(noPartAfterFill); + return generateConfig; + } + // 机构下的自定义板编号序号 + CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO = generateConfig.getOrgCustomPlateNoSeqRespDTO(); + // 获取当前序号值 + int currOrderNoSeq = Optional.ofNullable(orgCustomPlateNoSeqRespDTO.getOrderNoSeq()).orElse(plateNoRule.getInitValue() - plateNoRule.getIncrementStep()); + // 上次导入的生产单号 + Long lastOrderNo = orgCustomPlateNoSeqRespDTO.getLastOrderNo(); + if (ObjectUtil.isNull(lastOrderNo) || ObjectUtil.notEqual(orderId, lastOrderNo)) { + // 跨单 + // 根据复位模式计算序号 + currOrderNoSeq = generateNoByResetMode(currOrderNoSeq, ResetModeEnum.getByMode(plateNoRule.getResetMode()), plateNoRule, orgCustomPlateNoSeqRespDTO); + } + // 补零 + String noPartAfterFill = this.fillZero(currOrderNoSeq, plateNoRule); + plateDO.getCustomPlateNo().append(noPartAfterFill); + + // 累加后的值同步到当前生产单序号和机构序号中 + orderCustomPlateNoSeqVO.setOrderNoSeq(currOrderNoSeq); + orgCustomPlateNoSeqRespDTO.setOrderNoSeq(currOrderNoSeq); + return generateConfig; + } + + /** + * 基于复位模式的板编号生成 + * + * @param orderNoSeq + * @param resetModeEnum + * @param plateNoRule + * @param orgCustomPlateNoSeqRespDTO + * @return 循环累加后的序号 + */ + private int generateNoByResetMode(int orderNoSeq, ResetModeEnum resetModeEnum, CustomPlateNoRuleVO plateNoRule, CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO) { + // 机构全局序号下的上一次年月日记录 + int year = orgCustomPlateNoSeqRespDTO.getLastYear(); + int month = orgCustomPlateNoSeqRespDTO.getLastMonth(); + int day = orgCustomPlateNoSeqRespDTO.getLastDay(); + + // 根据不同复位模式生成序号 + if (ObjectUtil.equal(ResetModeEnum.DIGIT, resetModeEnum)) { + orderNoSeq = resetByLength(orderNoSeq, plateNoRule); + } else if (ObjectUtil.equal(ResetModeEnum.YEAR, resetModeEnum)) { + orderNoSeq = resetByYear(orderNoSeq, year, plateNoRule); + } else if (ObjectUtil.equal(ResetModeEnum.MONTH, resetModeEnum)) { + orderNoSeq = resetByMonth(orderNoSeq, month, plateNoRule); + } else if (ObjectUtil.equal(ResetModeEnum.DAY, resetModeEnum)) { + orderNoSeq = resetByDay(orderNoSeq, day, plateNoRule); + } else { + throw ServiceExceptionUtil.exception(CUSTOM_PLATENO_GENERATE_ORDERNO_RULE_NOT_SUPPORT_RESETMODE, plateNoRule.getResetMode()); + } + return orderNoSeq; + } + + /** + * 按位数复位 + * + * @param curr 当前值 + * @param plateNoRule 规则配置 + */ + private int resetByLength(int curr, CustomPlateNoRuleVO plateNoRule) { + // 位数下的最大值 10的length次方-1 + int maxNum = (int) (Math.pow(10, plateNoRule.getLength()) - 1); + // 加上步长后的下一个序号 + int nextValue = curr + plateNoRule.getIncrementStep(); + // 超过最大值复位到初始值,没超过就继续下一个 + if (nextValue > maxNum) { + return plateNoRule.getInitValue(); + } else { + return nextValue; + } + } + + /** + * 按年复位 + * + * @param curr + * @param year + * @param plateNoRule + * @return + */ + private int resetByYear(int curr, int year, CustomPlateNoRuleVO plateNoRule) { + LocalDateTime now = plateNoRule.getNow(); + Integer initValue = plateNoRule.getInitValue(); + if (ObjectUtil.notEqual(String.valueOf(year), now.format(YEAR_FORMATTER))) { + return initValue; + } + return curr + plateNoRule.getIncrementStep(); + } + + /** + * 按月复位 + * + * @param curr + * @param month + * @param plateNoRule + * @return + */ + private int resetByMonth(int curr, int month, CustomPlateNoRuleVO plateNoRule) { + LocalDateTime now = plateNoRule.getNow(); + Integer initValue = plateNoRule.getInitValue(); + if (ObjectUtil.notEqual(String.valueOf(month), now.format(MONTH_FORMATTER))) { + return initValue; + } + return curr + plateNoRule.getIncrementStep(); + } + + /** + * 按天复位 + * + * @param curr + * @param day + * @param plateNoRule + * @return + */ + private int resetByDay(int curr, int day, CustomPlateNoRuleVO plateNoRule) { + LocalDateTime now = plateNoRule.getNow(); + Integer initValue = plateNoRule.getInitValue(); + if (ObjectUtil.notEqual(String.valueOf(day), now.format(DAY_FORMATTER))) { + return initValue; + } + return curr + plateNoRule.getIncrementStep(); + } +} diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/PlateNoGenerateRuleServiceImpl.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/PlateNoGenerateRuleServiceImpl.java new file mode 100644 index 000000000..d3030838f --- /dev/null +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/PlateNoGenerateRuleServiceImpl.java @@ -0,0 +1,311 @@ +package com.cf.imes.module.executor.service.customplatenorule; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil; +import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoGenerateConfigVO; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoRuleVO; +import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqBodyVO; +import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqRoomVO; +import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqVO; +import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqDTO; +import com.cf.imes.module.system.enums.customplateno.CustomPlateNoRuleCodeEnum; +import com.cf.imes.module.system.enums.customplateno.ResetModeEnum; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static com.cf.imes.module.executor.enums.ErrorCodeConstants.CUSTOM_PLATENO_GENERATE_PLATE_RULE_NOT_SUPPORT_RESETMODE; + +/** + * @author Gqr + * @since 2024/11/20 15:28 + */ +@Service("plateNoGenerateRuleService") +public class PlateNoGenerateRuleServiceImpl implements CustomPlateNoGenerateRuleService { + + private static final DateTimeFormatter YEAR_FORMATTER = DateTimeFormatter.ofPattern("yyyy"); + private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM"); + private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd"); + + @Override + public boolean match(String ruleCode) { + return ObjectUtil.equal(CustomPlateNoRuleCodeEnum.PLATENO.getRuleCode(), ruleCode); + } + + @Override + public CustomPlateNoGenerateConfigVO generateNo(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) { + // 初始化配置 + initConfig(generateConfig); + // 按复位模式走不同的生成方式 + ResetModeEnum resetModeEnum = ResetModeEnum.getByMode(plateNoRule.getResetMode()); + if (ObjectUtil.equal(ResetModeEnum.ORDER, resetModeEnum)) { + return generateNoByOrderResetMode(orderId, plateNoRule, generateConfig, plateDO); + } else if (ObjectUtil.equal(ResetModeEnum.ROOM, resetModeEnum)) { + return generateNoByRoomResetMode(plateNoRule, generateConfig, plateDO); + } else if (ObjectUtil.equal(ResetModeEnum.BODY, resetModeEnum)) { + return generateNoByBodyResetMode(plateNoRule, generateConfig, plateDO); + } else if (ObjectUtil.equal(ResetModeEnum.YEAR, resetModeEnum) || ObjectUtil.equal(ResetModeEnum.MONTH, resetModeEnum) || ObjectUtil.equal(ResetModeEnum.DAY, resetModeEnum)) { + return generateNoByDateResetMode(resetModeEnum, plateNoRule, generateConfig, plateDO); + } else { + throw ServiceExceptionUtil.exception(CUSTOM_PLATENO_GENERATE_PLATE_RULE_NOT_SUPPORT_RESETMODE, plateNoRule.getResetMode()); + } + } + + /** + * 按年/月/日复位模式下的板编号生成 + */ + private CustomPlateNoGenerateConfigVO generateNoByDateResetMode(ResetModeEnum resetModeEnum, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) { + // 机构下的自定义板编号序号 + CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO = generateConfig.getOrgCustomPlateNoSeqRespDTO(); + // 上一次自定义编号生成的年月日 + int year = orgCustomPlateNoSeqRespDTO.getLastYear(); + int month = orgCustomPlateNoSeqRespDTO.getLastMonth(); + int day = orgCustomPlateNoSeqRespDTO.getLastDay(); + // 从全局配置获取当前序号,取不到用初始值 + Integer orderNoSeq = orgCustomPlateNoSeqRespDTO.getPlateNoSeq(); + if (ObjectUtil.isNull(orderNoSeq)) { + orderNoSeq = plateNoRule.getInitValue() - plateNoRule.getIncrementStep(); + } + + if (ObjectUtil.equal(ResetModeEnum.YEAR, resetModeEnum)) { + orderNoSeq = resetByYear(orderNoSeq, year, plateNoRule); + } else if (ObjectUtil.equal(ResetModeEnum.MONTH, resetModeEnum)) { + orderNoSeq = resetByMonth(orderNoSeq, month, plateNoRule); + } else if (ObjectUtil.equal(ResetModeEnum.DAY, resetModeEnum)) { + orderNoSeq = resetByDay(orderNoSeq, day, plateNoRule); + } + // 跨板件累加步长,补零 + orderNoSeq += plateNoRule.getIncrementStep(); + String noPartAfterFillZero = fillZero(orderNoSeq, plateNoRule); + plateDO.getCustomPlateNo().append(noPartAfterFillZero); + + orgCustomPlateNoSeqRespDTO.setPlateNoSeq(orderNoSeq); + return generateConfig; + } + + /** + * 按生产单复位模式下的板编号生成 + * + * @param orderId + * @param plateNoRule + * @param generateConfig + * @param plateDO + */ + private CustomPlateNoGenerateConfigVO generateNoByOrderResetMode(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) { + Integer incrementStep = plateNoRule.getIncrementStep(); + Integer initValue = plateNoRule.getInitValue() - incrementStep; + // 生产单下的序号 + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO(); + // 机构下的自定义板编号序号 + CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO = generateConfig.getOrgCustomPlateNoSeqRespDTO(); + // 获取当前生产单下板件序号 + Integer orderPlateNoSeq = Optional.ofNullable(orderCustomPlateNoSeqVO.getPlateNoSeq()).orElse(initValue); + // 上次导入的生产单号 + Long lastOrderNo = orgCustomPlateNoSeqRespDTO.getLastOrderNo(); + if (ObjectUtil.isNotNull(lastOrderNo) && ObjectUtil.notEqual(orderId, lastOrderNo)) { + // 跨单复位到初始值 + orderPlateNoSeq = initValue; + } + // 跨板件累加步长,补零 + orderPlateNoSeq += incrementStep; + plateDO.getCustomPlateNo().append(fillZero(orderPlateNoSeq, plateNoRule)); + // 累加后的值同步到当前生产单序号中 + orderCustomPlateNoSeqVO.setPlateNoSeq(orderPlateNoSeq); + return generateConfig; + } + + /** + * 按房间复位模式下的板编号生成 + * + * @param plateNoRule + * @param generateConfig + * @param plateDO + * @return + */ + private CustomPlateNoGenerateConfigVO generateNoByRoomResetMode(CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) { + Integer incrementStep = plateNoRule.getIncrementStep(); + Integer initValue = plateNoRule.getInitValue() - incrementStep; + // 生产单下的序号 + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO(); + List rooms = orderCustomPlateNoSeqVO.getRooms(); + String roomName = plateDO.getRoomName(); + // 根据房间名获取生产单下序号json中的房间下的加工组序号 + OrderCustomPlateNoSeqRoomVO roomSeqVo = getSeqRoomByRoomName(roomName, rooms); + // 为空初始化,加入列表 + if (roomSeqVo == null) { + roomSeqVo = OrderCustomPlateNoSeqRoomVO.builder() + .roomName(roomName) + .bodys(new ArrayList<>()) + .build(); + rooms.add(roomSeqVo); + } + // 获取当前房间下板件序号 + // 累加步长 + Integer roomPlateNoSeq = Optional.ofNullable(roomSeqVo.getPlateNoSeq()) + .orElse(initValue) + incrementStep; + // 累加后的值同步到当前生产单序号中 + roomSeqVo.setPlateNoSeq(roomPlateNoSeq); + // 补零 + plateDO.getCustomPlateNo().append(fillZero(roomPlateNoSeq, plateNoRule)); + return generateConfig; + } + + /** + * 根据房间名从生产单序号json中获取房间序号列表 + * + * @param roomName + * @param roomVOList + * @return + */ + private OrderCustomPlateNoSeqRoomVO getSeqRoomByRoomName(String roomName, List roomVOList) { + return roomVOList.stream().filter(roomVO -> ObjectUtil.equal(roomName, roomVO.getRoomName())).findAny().orElse(null); + } + + /** + * 按柜体复位模式下的板编号生成 + * + * @param plateNoRule + * @param generateConfig + * @param plateDO + * @return + */ + private CustomPlateNoGenerateConfigVO generateNoByBodyResetMode(CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) { + Integer incrementStep = plateNoRule.getIncrementStep(); + Integer initValue = plateNoRule.getInitValue() - incrementStep; + // 生产单下的序号 + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO(); + List rooms = orderCustomPlateNoSeqVO.getRooms(); + + String roomName = plateDO.getRoomName(); + // 根据房间名获取生产单下序号json中的房间下的加工组序号 + OrderCustomPlateNoSeqRoomVO roomSeqVo = getSeqRoomByRoomName(roomName, rooms); + if (ObjectUtil.isNull(roomSeqVo)) { + // 房间为空,new房间 + roomSeqVo = OrderCustomPlateNoSeqRoomVO. + builder() + .roomName(roomName) + .bodys(new ArrayList<>()) + .build(); + rooms.add(roomSeqVo); + } + + String bodyName = plateDO.getBodyName(); + // 根据柜体名获取生产单下序号json中的房间下的加工组序号 + OrderCustomPlateNoSeqBodyVO bodySeqVO = getBodySeqByBodyName(bodyName, roomSeqVo); + + if (bodySeqVO == null) { + // 柜体为空,new柜体 + bodySeqVO = OrderCustomPlateNoSeqBodyVO.builder() + .bodyName(bodyName) + .build(); + roomSeqVo.getBodys().add(bodySeqVO); + } + + // 累加步长 + // 获取柜体下的板件序号 + Integer bodyPlateNoSeq = Optional.ofNullable(bodySeqVO.getPlateNoSeq()).orElse(initValue) + incrementStep; + // 累加后的值同步到当前生产单序号中 + bodySeqVO.setPlateNoSeq(bodyPlateNoSeq); + // 补零 + String noPartAfterFillZero = fillZero(bodyPlateNoSeq, plateNoRule); + plateDO.getCustomPlateNo().append(noPartAfterFillZero); + return generateConfig; + } + + /** + * 根据房间名从生产单序号json中获取房间序号列表 + * + * @param bodyName + * @param roomVO + * @return + */ + private OrderCustomPlateNoSeqBodyVO getBodySeqByBodyName(String bodyName, OrderCustomPlateNoSeqRoomVO roomVO) { + List bodys = roomVO.getBodys(); + if (ObjectUtil.isNotNull(bodys)) { + for (OrderCustomPlateNoSeqBodyVO bodyVO : bodys) { + if (ObjectUtil.equal(bodyVO.getBodyName(), bodyName)) { + return bodyVO; + } + } + } else { + bodys = new ArrayList<>(); + roomVO.setBodys(bodys); + } + return null; + } + + /** + * 初始化生成所需配置 + * + * @param generateConfigVO + */ + private void initConfig(CustomPlateNoGenerateConfigVO generateConfigVO) { + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfigVO.getOrderCustomPlateNoSeqVO(); + if (ObjectUtil.isNull(orderCustomPlateNoSeqVO)) { + orderCustomPlateNoSeqVO = new OrderCustomPlateNoSeqVO(); + generateConfigVO.setOrderCustomPlateNoSeqVO(orderCustomPlateNoSeqVO); + } + List rooms = orderCustomPlateNoSeqVO.getRooms(); + if (CollUtil.isEmpty(rooms)) { + rooms = new ArrayList<>(); + orderCustomPlateNoSeqVO.setRooms(rooms); + } + } + + /** + * 按年复位 + * + * @param curr + * @param year + * @param plateNoRule + * @return + */ + private int resetByYear(int curr, int year, CustomPlateNoRuleVO plateNoRule) { + LocalDateTime now = plateNoRule.getNow(); + Integer initValue = plateNoRule.getInitValue(); + if (ObjectUtil.notEqual(String.valueOf(year), now.format(YEAR_FORMATTER))) { + return initValue; + } + return curr + plateNoRule.getIncrementStep(); + } + + /** + * 按月复位 + * + * @param curr + * @param month + * @param plateNoRule + * @return + */ + private int resetByMonth(int curr, int month, CustomPlateNoRuleVO plateNoRule) { + LocalDateTime now = plateNoRule.getNow(); + Integer initValue = plateNoRule.getInitValue(); + if (ObjectUtil.notEqual(String.valueOf(month), now.format(MONTH_FORMATTER))) { + return initValue; + } + return curr + plateNoRule.getIncrementStep(); + } + + /** + * 按天复位 + * + * @param curr + * @param day + * @param plateNoRule + * @return + */ + private int resetByDay(int curr, int day, CustomPlateNoRuleVO plateNoRule) { + LocalDateTime now = plateNoRule.getNow(); + Integer initValue = plateNoRule.getInitValue(); + if (ObjectUtil.notEqual(String.valueOf(day), now.format(DAY_FORMATTER))) { + return initValue; + } + return curr + plateNoRule.getIncrementStep(); + } +} diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/ProcessGroupNoGenerateRuleServiceImpl.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/ProcessGroupNoGenerateRuleServiceImpl.java new file mode 100644 index 000000000..5ea697da3 --- /dev/null +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/ProcessGroupNoGenerateRuleServiceImpl.java @@ -0,0 +1,240 @@ +//package com.cf.imes.module.executor.service.customplatenorule; +// +//import cn.hutool.core.collection.CollUtil; +//import cn.hutool.core.util.ObjectUtil; +//import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil; +//import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO; +//import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoGenerateConfigVO; +//import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoRuleVO; +//import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqProcessGroupVO; +//import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqRoomVO; +//import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqVO; +//import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqRespDTO; +//import com.cf.imes.module.system.enums.customplateno.CustomPlateNoRuleCodeEnum; +//import com.cf.imes.module.system.enums.customplateno.ResetModeEnum; +//import org.springframework.stereotype.Service; +// +//import java.util.ArrayList; +//import java.util.List; +//import java.util.Map; +//import java.util.Optional; +//import java.util.concurrent.atomic.AtomicReference; +//import java.util.stream.Collectors; +// +//import static com.cf.imes.module.executor.enums.ErrorCodeConstants.CUSTOM_PLATENO_GENERATE_PROCESSGROUP_RULE_NOT_SUPPORT_RESETMODE; +// +///** +// * 加工组序号生成规则服务实现类 +// * +// * @author Gqr +// * @since 2024/11/20 13:42 +// */ +//@Service("processGroupNoGenerateRuleService") +//public class ProcessGroupNoGenerateRuleServiceImpl implements CustomPlateNoGenerateRuleService { +// @Override +// public boolean match(String ruleCode) { +// return false; +// } +// +// @Override +// public CustomPlateNoGenerateConfigVO generateNo(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, List plateDOList) { +// // 初始化配置 +// initConfig(generateConfig); +// // 按复位模式走不同的生成方式 +// ResetModeEnum resetModeEnum = ResetModeEnum.getByMode(plateNoRule.getResetMode()); +// if (ObjectUtil.equal(ResetModeEnum.ORDER, resetModeEnum)) { +// generateConfig = generateNoByOrderResetMode(orderId, plateNoRule, generateConfig, plateDOList); +// } else if (ObjectUtil.equal(ResetModeEnum.ROOM, resetModeEnum)) { +// generateConfig = generateNoByRoomResetMode(plateNoRule, generateConfig, plateDOList); +// } else { +// throw ServiceExceptionUtil.exception(CUSTOM_PLATENO_GENERATE_PROCESSGROUP_RULE_NOT_SUPPORT_RESETMODE, plateNoRule.getResetMode()); +// } +// return generateConfig; +// } +// +// /** +// * 初始化生成所需配置 +// * +// * @param generateConfigVO +// */ +// private static void initConfig(CustomPlateNoGenerateConfigVO generateConfigVO) { +// OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfigVO.getOrderCustomPlateNoSeqVO(); +// if (ObjectUtil.isNull(orderCustomPlateNoSeqVO)) { +// orderCustomPlateNoSeqVO = new OrderCustomPlateNoSeqVO(); +// generateConfigVO.setOrderCustomPlateNoSeqVO(orderCustomPlateNoSeqVO); +// } +// List rooms = orderCustomPlateNoSeqVO.getRooms(); +// if (CollUtil.isEmpty(rooms)) { +// rooms = new ArrayList<>(); +// orderCustomPlateNoSeqVO.setRooms(rooms); +// } +// List processGroups = orderCustomPlateNoSeqVO.getProcessGroups(); +// if (CollUtil.isEmpty(processGroups)) { +// processGroups = new ArrayList<>(); +// orderCustomPlateNoSeqVO.setProcessGroups(processGroups); +// } +// } +// +// +// /** +// * 按生产单复位模式下的板编号生成 +// * +// * @param orderId 生产单号 +// * @param plateNoRule 当前规则配置 +// * @param generateConfig 生成规则配置 +// * @param plateDOList 板件列表 +// * @return +// */ +// private CustomPlateNoGenerateConfigVO generateNoByOrderResetMode(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, List plateDOList) { +// Integer initValue = plateNoRule.getInitValue() - plateNoRule.getIncrementStep(); +// // 生产单下的序号 +// OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO(); +// // 机构下的自定义板编号序号 +// CustomPlateNoSeqRespDTO orgCustomPlateNoSeqRespDTO = generateConfig.getOrgCustomPlateNoSeqRespDTO(); +// // 生产单下加工组序号 +// Integer orderProcessGroupNoSeq = null; +// List processGroups = orderCustomPlateNoSeqVO.getProcessGroups(); +// if (ObjectUtil.equal(orderId, orgCustomPlateNoSeqRespDTO.getLastOrderNo())) { +// // 当次导入和上次导入是同一个生产单 +// // 取之前的生产单下加工组序号,没有就用初始值 +// orderProcessGroupNoSeq = Optional.ofNullable(orderCustomPlateNoSeqVO.getProcessGroupNoSeq()).orElse(initValue); +// } +// // 基于加工组名分组 +// Map> processGroupMap = plateDOList.stream().collect(Collectors.groupingBy(PlateDO::getProcessGroupName, Collectors.toList())); +// for (Map.Entry> processGroupEntry : processGroupMap.entrySet()) { +// // 如果是新的加工组vo,要把累加的值记录到生产单 +// boolean needRecordToOrder = false; +// String processGroupName = processGroupEntry.getKey(); +// // 根据加工组名获取生产单下序号json中第一层加工组列表的加工组序号 +// OrderCustomPlateNoSeqProcessGroupVO processSeqVO = getProcessGroupSeqVOByProcessGroupName(processGroupName, processGroups); +// // 获取当前加工组序号值 +// Integer processGroupNoSeq = Optional.ofNullable(processSeqVO).map(OrderCustomPlateNoSeqProcessGroupVO::getProcessGroupNoSeq).orElse(initValue); +// if (processSeqVO == null) { +// // 房间为空,新建对象,设置初始值 +// processSeqVO = OrderCustomPlateNoSeqProcessGroupVO.builder() +// .processGroupName(processGroupName) +// .build(); +// processGroups.add(processSeqVO); +// needRecordToOrder = true; +// } +// +// List processGroupPlateList = processGroupEntry.getValue(); +// processGroupNoSeq += plateNoRule.getIncrementStep(); +// // 跨柜体累加步长,补零 +// String noPartAfterFillZero = fillZero(processGroupNoSeq, plateNoRule); +// processGroupPlateList.forEach(processGroupPlate -> processGroupPlate.getCustomPlateNo().append(noPartAfterFillZero)); +// // 累加后同步到json:加工组下累加到多少了 +// processSeqVO.setProcessGroupNoSeq(processGroupNoSeq); +// if (needRecordToOrder) { +// // 新的房间下加工组vo,累加值同步到房间中 +// orderProcessGroupNoSeq = processGroupNoSeq; +// } +// } +// // 累加后的值同步到当前生产单序号中,生产单下加工组序号累加到多少了 +// orderCustomPlateNoSeqVO.setProcessGroupNoSeq(orderProcessGroupNoSeq); +// return generateConfig; +// } +// +// /** +// * 按房间号复位模式下的板编号生成 +// * +// * @param plateNoRule +// * @param generateConfig +// * @param plateDOList +// * @return +// */ +// private CustomPlateNoGenerateConfigVO generateNoByRoomResetMode(CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, List plateDOList) { +// Integer initValue = plateNoRule.getInitValue() - plateNoRule.getIncrementStep(); +// // 生产单下的序号 +// OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO(); +// List rooms = orderCustomPlateNoSeqVO.getRooms(); +// // 基于房间名分组 +// Map> roomGroupMap = plateDOList.stream().collect(Collectors.groupingBy(PlateDO::getRoomName, Collectors.toList())); +// +// for (Map.Entry> roomEntry : roomGroupMap.entrySet()) { +// List roomPlateList = roomEntry.getValue(); +// String roomName = roomEntry.getKey(); +// // 根据房间名获取生产单下序号json中的房间下的柜体序号 +// OrderCustomPlateNoSeqRoomVO roomSeqVo = getRoomSeqVOByRoomName(roomName, rooms); +// Integer roomProcessGroupNoRoomSeq = Optional.ofNullable(roomSeqVo) +// .map(OrderCustomPlateNoSeqRoomVO::getProcessGroupNoSeq) +// .orElse(initValue); +// +// if (roomSeqVo == null) { +// // 房间为空,新建对象,设置初始值 +// roomSeqVo = OrderCustomPlateNoSeqRoomVO.builder() +// .roomName(roomName) +// .processGroupNoSeq(roomProcessGroupNoRoomSeq) +// .processGroups(new ArrayList<>()) +// .build(); +// rooms.add(roomSeqVo); +// } +// +// // 基于加工组分组 +// Map> roomProcessGroupMap = roomPlateList.stream() +// .collect(Collectors.groupingBy(PlateDO::getProcessGroupName, Collectors.toList())); +// for (Map.Entry> roomPrcesssGroupEntry : roomProcessGroupMap.entrySet()) { +// // 如果是新的柜体vo,要把累加的值记录到生产单rooms下的柜体 +// boolean needRecordToOrder = false; +// String processGroupName = roomPrcesssGroupEntry.getKey(); +// // 根据加工组名获取生产单下序号中rooms下加工组列表的加工组序号 +// List roomProcessGroups = roomSeqVo.getProcessGroups(); +// OrderCustomPlateNoSeqProcessGroupVO roomProcessGroupSeqVo = getProcessGroupSeqVOByProcessGroupName(processGroupName, roomProcessGroups); +// // 获取当前房间下加工组的序号值 +// Integer roomProcessGroupNoSeq = Optional.ofNullable(roomProcessGroupSeqVo).map(OrderCustomPlateNoSeqProcessGroupVO::getProcessGroupNoSeq).orElse(null); +// if (roomProcessGroupSeqVo == null) { +// // 房间下柜体为空,新建对象,设置初始值 +// roomProcessGroupSeqVo = OrderCustomPlateNoSeqProcessGroupVO.builder() +// .processGroupName(processGroupName) +// .build(); +// roomProcessGroups.add(roomProcessGroupSeqVo); +// roomProcessGroupNoSeq= roomProcessGroupNoRoomSeq; +// needRecordToOrder = true; +// } else if(roomProcessGroupNoSeq == null){ +// roomProcessGroupNoSeq= roomProcessGroupNoRoomSeq; +// needRecordToOrder = true; +// } +// +// // 跨加工组累加步长 +// roomProcessGroupNoSeq += plateNoRule.getIncrementStep(); +// // 补零 +// String noPartAfterFillZero = fillZero(roomProcessGroupNoSeq, plateNoRule); +// roomPrcesssGroupEntry.getValue().forEach(roomPrcesssGroupPlate -> roomPrcesssGroupPlate.getCustomPlateNo().append(noPartAfterFillZero)); +// // 累加后同步到json中,room下柜体累加到多少了 +// roomProcessGroupSeqVo.setProcessGroupNoSeq(roomProcessGroupNoSeq); +// if (needRecordToOrder) { +// // 新的房间下柜体vo,累加值同步到房间中 +// roomProcessGroupNoRoomSeq = roomProcessGroupNoSeq; +// } +// } +// // 累加后的值同步到当前生产单序号中,生产单下房间中加工组累加到多少了 +// roomSeqVo.setProcessGroupNoSeq(roomProcessGroupNoRoomSeq); +// } +// return generateConfig; +// } +// +// /** +// * 根据房间名从生产单序号json中获取房间序号列表 +// * +// * @param roomName +// * @param roomVOList +// * @return +// */ +// private OrderCustomPlateNoSeqRoomVO getRoomSeqVOByRoomName(String roomName, List roomVOList) { +// return roomVOList.stream().filter(roomVO -> ObjectUtil.equal(roomName, roomVO.getRoomName())).findAny().orElse(null); +// } +// +// /** +// * 根据柜体名从生产单序号json中获取柜体序号列表 +// * +// * @param processGroupName +// * @param processGroupVOList +// * @return +// */ +// private OrderCustomPlateNoSeqProcessGroupVO getProcessGroupSeqVOByProcessGroupName(String processGroupName, List processGroupVOList) { +// if (CollUtil.isEmpty(processGroupVOList)) { +// return null; +// } +// return processGroupVOList.stream().filter(processGroupVO -> ObjectUtil.equal(processGroupName, processGroupVO.getProcessGroupName())).findAny().orElse(null); +// } +//} diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/RoomNoGenerateRuleServiceImpl.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/RoomNoGenerateRuleServiceImpl.java new file mode 100644 index 000000000..bb25a254b --- /dev/null +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/customplatenorule/RoomNoGenerateRuleServiceImpl.java @@ -0,0 +1,107 @@ +package com.cf.imes.module.executor.service.customplatenorule; + +import cn.hutool.core.util.ObjectUtil; +import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoGenerateConfigVO; +import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoRuleVO; +import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqRoomVO; +import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqVO; +import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqDTO; +import com.cf.imes.module.system.enums.customplateno.CustomPlateNoRuleCodeEnum; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * 房间序号生成规则服务实现类 + * + * @author Gqr + * @since 2024/11/19 13:41 + */ +@Service("roomNoGenerateRuleService") +public class RoomNoGenerateRuleServiceImpl implements CustomPlateNoGenerateRuleService { + @Override + public boolean match(String ruleCode) { + return ObjectUtil.equal(CustomPlateNoRuleCodeEnum.ROOMNO.getRuleCode(), ruleCode); + } + + @Override + public CustomPlateNoGenerateConfigVO generateNo(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) { + Integer incrementStep = plateNoRule.getIncrementStep(); + Integer initValue = plateNoRule.getInitValue() - incrementStep; + // 初始化配置 + initConfig(generateConfig); + // 生产单下的序号 + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO(); + // 机构下的自定义板编号序号 + CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO = generateConfig.getOrgCustomPlateNoSeqRespDTO(); + // 生产单下房间序号 + Integer orderRoomNoSeq = Optional.ofNullable(orderCustomPlateNoSeqVO.getRoomNoSeq()).orElse(initValue); + // 生产单序号下的的房间序号列表 + List rooms = orderCustomPlateNoSeqVO.getRooms(); + // 上次导入的生产单号 + Long lastOrderNo = orgCustomPlateNoSeqRespDTO.getLastOrderNo(); + if (ObjectUtil.isNotNull(lastOrderNo) && ObjectUtil.notEqual(orderId, lastOrderNo)) { + // 跨单复位到初始值 + orderRoomNoSeq = initValue; + } + + String roomName = plateDO.getRoomName(); + // 根据房间名获取生产单下序号json中的房间下的柜体序号 + OrderCustomPlateNoSeqRoomVO roomSeqVo = getRoomSeqVOByRoomName(roomName, rooms); + // 获取当前房间序号值 + Integer roomNoSeq = Optional.ofNullable(roomSeqVo).map(OrderCustomPlateNoSeqRoomVO::getRoomNoSeq).orElse(null); + if (roomSeqVo == null) { + // 房间为空,新建房间,取生产单下房间序号 + roomSeqVo = OrderCustomPlateNoSeqRoomVO.builder() + .roomName(roomName) + .bodys(new ArrayList<>()) + .build(); + rooms.add(roomSeqVo); + // 累加步长 + roomNoSeq = orderRoomNoSeq + incrementStep; + // 累加后的值同步到当前生产单序号中,生产单下房间序号累加到多少了 + orderCustomPlateNoSeqVO.setRoomNoSeq(roomNoSeq); + } else if (roomNoSeq == null) { + // 房间下序号为空,取生产单下房间序号 + // 累加步长 + roomNoSeq = orderRoomNoSeq + incrementStep; + // 累加后的值同步到当前生产单序号中,生产单下房间序号累加到多少了 + orderCustomPlateNoSeqVO.setRoomNoSeq(roomNoSeq); + } + + // 补零 + String noPartAfterFillZero = fillZero(roomNoSeq, plateNoRule); + plateDO.getCustomPlateNo().append(noPartAfterFillZero); + // 累加后同步到json:房间下累加到多少了 + roomSeqVo.setRoomNoSeq(roomNoSeq); + + return generateConfig; + } + + /** + * 初始化生成所需配置 + * + * @param generateConfigVO + */ + private static void initConfig(CustomPlateNoGenerateConfigVO generateConfigVO) { + OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfigVO.getOrderCustomPlateNoSeqVO(); + if (ObjectUtil.isNull(orderCustomPlateNoSeqVO)) { + orderCustomPlateNoSeqVO = new OrderCustomPlateNoSeqVO(); + generateConfigVO.setOrderCustomPlateNoSeqVO(orderCustomPlateNoSeqVO); + } + } + + /** + * 根据房间名从生产单序号json中获取房间序号列表 + * + * @param roomName + * @param roomVOList + * @return + */ + private OrderCustomPlateNoSeqRoomVO getRoomSeqVOByRoomName(String roomName, List roomVOList) { + return roomVOList.stream().filter(roomVO -> ObjectUtil.equal(roomName, roomVO.getRoomName())).findAny().orElse(null); + } +} diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/api/customplateno/CustomPlateNoSeqApi.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/api/customplateno/CustomPlateNoSeqApi.java index 45c9a4105..b932ece92 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/api/customplateno/CustomPlateNoSeqApi.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/api/customplateno/CustomPlateNoSeqApi.java @@ -1,12 +1,14 @@ package com.cf.imes.module.system.api.customplateno; import com.cf.imes.framework.common.pojo.CommonResult; -import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqRespDTO; +import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqDTO; import com.cf.imes.module.system.enums.ApiConstants; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; /** @@ -22,5 +24,9 @@ public interface CustomPlateNoSeqApi { @GetMapping(PREFIX + "/organ") @Operation(summary = "获取组织下自定义版编号序号") - CommonResult getOrgCustomPlateNoSeq(); + CommonResult getOrgCustomPlateNoSeq(); + + @PostMapping(PREFIX + "/organ") + @Operation(summary = "更新组织下自定义版编号序号") + CommonResult modifyOrgCustomPlateNoSeq(@RequestBody CustomPlateNoSeqDTO customPlateNoSeqDTO); } diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/api/customplateno/dto/CustomPlateNoSeqRespDTO.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/api/customplateno/dto/CustomPlateNoSeqDTO.java similarity index 86% rename from cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/api/customplateno/dto/CustomPlateNoSeqRespDTO.java rename to cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/api/customplateno/dto/CustomPlateNoSeqDTO.java index f4322d3f9..009fc9731 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/api/customplateno/dto/CustomPlateNoSeqRespDTO.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/api/customplateno/dto/CustomPlateNoSeqDTO.java @@ -15,7 +15,7 @@ import java.io.Serializable; @Data @NoArgsConstructor @AllArgsConstructor -public class CustomPlateNoSeqRespDTO implements Serializable { +public class CustomPlateNoSeqDTO implements Serializable { private static final long serialVersionUID = -3415615478757941611L; private Long id; @@ -48,15 +48,15 @@ public class CustomPlateNoSeqRespDTO implements Serializable { /** * 上次年 */ - private int lastYear; + private Integer lastYear; /** * 上次月 */ - private int lastMonth; + private Integer lastMonth; /** * 上次天 */ - private int lastDay; + private Integer lastDay; } diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java index e4b1ae094..537f4402a 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java @@ -349,5 +349,5 @@ public class ErrorCodeConstants { //=========== 系统配置 1-002-040-000 ============ public static final ErrorCode SYSTEM_CONFIG_NOT_EXISTS = new ErrorCode(1_002_040_001, "系统配置不存在"); public static final ErrorCode SYSTEM_CONFIG_TYPE_NOT_SUPPORT = new ErrorCode(1_002_040_002, "不支持的系统配置类型"); - public static final ErrorCode SYSTEM_CONFIG_CUSTOM_BOARD_NO_RULE_SAVE_CHECK_ERROR = new ErrorCode(1_002_040_003, "系统配置:自定义板编号保存解析失败,请检查配置规则或联系客服"); + public static final ErrorCode SYSTEM_CONFIG_CUSTOM_PLATE_NO_RULE_SAVE_CHECK_ERROR = new ErrorCode(1_002_040_003, "系统配置:自定义板编号保存解析失败,请检查配置规则或联系客服"); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/config/CustBoardRuleCodeEnum.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/customplateno/CustomPlateNoRuleCodeEnum.java similarity index 68% rename from cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/config/CustBoardRuleCodeEnum.java rename to cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/customplateno/CustomPlateNoRuleCodeEnum.java index 14971b049..3c8168bd3 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/config/CustBoardRuleCodeEnum.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/customplateno/CustomPlateNoRuleCodeEnum.java @@ -1,6 +1,7 @@ -package com.cf.imes.module.system.enums.config; +package com.cf.imes.module.system.enums.customplateno; import lombok.AllArgsConstructor; +import lombok.Getter; /** * 自定义板编号规则编码枚举 @@ -9,7 +10,7 @@ import lombok.AllArgsConstructor; * @since 2024/11/11 15:20 */ @AllArgsConstructor -public enum CustBoardRuleCodeEnum { +public enum CustomPlateNoRuleCodeEnum { /** * 自定义 */ @@ -38,22 +39,19 @@ public enum CustBoardRuleCodeEnum { /** * 柜体序号 */ - BODYNO("bodyNo"), - - /** - * 加工组序号 - */ - PROCESSGROUP("processGroupNo"); + BODYNO("bodyNo"); + @Getter private String ruleCode; /** * 是否匹配 + * * @param ruleCode * @return */ - public static CustBoardRuleCodeEnum match(String ruleCode) { - for (CustBoardRuleCodeEnum codeEnum : CustBoardRuleCodeEnum.values()) { + public static CustomPlateNoRuleCodeEnum match(String ruleCode) { + for (CustomPlateNoRuleCodeEnum codeEnum : CustomPlateNoRuleCodeEnum.values()) { if (codeEnum.ruleCode.equals(ruleCode)) { return codeEnum; } diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/customplateno/ResetModeEnum.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/customplateno/ResetModeEnum.java new file mode 100644 index 000000000..0b870eeb7 --- /dev/null +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/customplateno/ResetModeEnum.java @@ -0,0 +1,70 @@ +package com.cf.imes.module.system.enums.customplateno; + +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @author Gqr + * @since 2024/11/19 9:40 + */ +@AllArgsConstructor +public enum ResetModeEnum { + /** + * 不清零,累加 + */ + ACCUMULATION(0), + + /** + * 按位数 + */ + DIGIT(1), + + /** + * 按年 + */ + YEAR(2), + + /** + * 按月 + */ + MONTH(3), + + /** + * 按天 + */ + DAY(4), + + /** + * 按生产单 + */ + ORDER(5), + + /** + * 按房间 + */ + ROOM(6), + + /** + * 按柜体 + */ + BODY(7); + + @Getter + private int mode; + + /** + * 根据mode获取对应枚举 + * + * @param mode + * @return + */ + public static ResetModeEnum getByMode(int mode) { + for (ResetModeEnum modeEnum : ResetModeEnum.values()) { + if (ObjectUtil.equal(modeEnum.getMode(), mode)) { + return modeEnum; + } + } + return null; + } +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/api/customplateno/CustomPlateNoSeqApiImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/api/customplateno/CustomPlateNoSeqApiImpl.java index 140285783..d2e69c6d7 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/api/customplateno/CustomPlateNoSeqApiImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/api/customplateno/CustomPlateNoSeqApiImpl.java @@ -2,7 +2,8 @@ package com.cf.imes.module.system.api.customplateno; import com.cf.imes.framework.common.pojo.CommonResult; import com.cf.imes.framework.common.util.object.BeanUtils; -import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqRespDTO; +import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqDTO; +import com.cf.imes.module.system.dal.dataobject.customplateno.CustomPlateNoSeqDO; import com.cf.imes.module.system.service.customplateno.CustomPlateNoSeqService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; @@ -23,7 +24,12 @@ public class CustomPlateNoSeqApiImpl implements CustomPlateNoSeqApi { private CustomPlateNoSeqService customPlateNoSeqService; @Override - public CommonResult getOrgCustomPlateNoSeq() { - return CommonResult.success(BeanUtils.toBean(customPlateNoSeqService.getOrgCustomPlateNoSeq(), CustomPlateNoSeqRespDTO.class)); + public CommonResult getOrgCustomPlateNoSeq() { + return CommonResult.success(BeanUtils.toBean(customPlateNoSeqService.getOrgCustomPlateNoSeq(), CustomPlateNoSeqDTO.class)); + } + + @Override + public CommonResult modifyOrgCustomPlateNoSeq(CustomPlateNoSeqDTO customPlateNoSeqDTO) { + return CommonResult.success(customPlateNoSeqService.modifyOrgCustomPlateNoSeq(BeanUtils.toBean(customPlateNoSeqDTO, CustomPlateNoSeqDO.class))); } } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/CustomPlateNoServiceHandler.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/CustomPlateNoServiceHandler.java index 437213964..760807c23 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/CustomPlateNoServiceHandler.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/CustomPlateNoServiceHandler.java @@ -17,11 +17,11 @@ import com.cf.imes.module.system.controller.admin.systemconfig.vo.ConfigSaveReqV import com.cf.imes.module.system.controller.admin.systemconfig.vo.ConfigUpdateStatusReqVO; import com.cf.imes.module.system.dal.dataobject.systemconfig.SystemConfigDO; import com.cf.imes.module.system.dal.dataobject.dict.DictDataDO; -import com.cf.imes.module.system.dal.mysql.customplateno.CustomPlateNoSeqMapper; import com.cf.imes.module.system.dal.mysql.systemconfig.SystemConfigMapper; import com.cf.imes.module.system.dal.redis.RedisKeyConstants; -import com.cf.imes.module.system.enums.config.CustBoardRuleCodeEnum; +import com.cf.imes.module.system.enums.customplateno.CustomPlateNoRuleCodeEnum; import com.cf.imes.module.system.enums.config.SystemConfigTypeEnum; +import com.cf.imes.module.system.enums.customplateno.ResetModeEnum; import com.cf.imes.module.system.service.config.factory.service.AbstractSystemConfigServiceHandler; import com.cf.imes.module.system.service.dict.DictDataService; import lombok.extern.slf4j.Slf4j; @@ -35,7 +35,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import static com.cf.imes.module.system.enums.ErrorCodeConstants.SYSTEM_CONFIG_CUSTOM_BOARD_NO_RULE_SAVE_CHECK_ERROR; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.SYSTEM_CONFIG_CUSTOM_PLATE_NO_RULE_SAVE_CHECK_ERROR; /** * 自定义板编号服务处理器 @@ -48,21 +48,19 @@ import static com.cf.imes.module.system.enums.ErrorCodeConstants.SYSTEM_CONFIG_C public class CustomPlateNoServiceHandler extends AbstractSystemConfigServiceHandler { // 自定义板编号校验错误全部统一编号:1_002_040_003 - public static final ErrorCode CUSTOM_BOARD_NO_RULE_CHECK_RULECODE_EMPTY_ERROR = new ErrorCode(1_002_040_003, "规则编码不能为空"); - public static final ErrorCode CUSTOM_BOARD_NO_RULE_CHECK_RULECODE_NOT_MATCH_ERROR = new ErrorCode(1_002_040_003, "规则编码【{}】不合法,请检查配置规则"); - public static final ErrorCode CUSTOM_BOARD_NO_RULE_CHECK_DATE_TYPE_FORMAT_ERROR = new ErrorCode(1_002_040_003, "时间格式【{}】不合法,请检查配置规则"); - public static final ErrorCode CUSTOM_BOARD_NO_RULE_CHECK_RESETMODE_ERROR = new ErrorCode(1_002_040_003, "复位/清零模式【{}】不合法,请检查配置规则"); - public static final ErrorCode CUSTOM_BOARD_NO_RULE_CHECK_INT_TYPE_NO_EMPTY = new ErrorCode(1_002_040_003, "参数【{}】不能为空,请检查配置规则"); - public static final ErrorCode CUSTOM_BOARD_NO_RULE_CHECK_INT_TYPE_ERROR = new ErrorCode(1_002_040_003, "数值类型参数{}:【{}】转换异常,请检查配置规则"); - public static final ErrorCode CUSTOM_BOARD_NO_RULE_CHECK_BOL_TYPE_ERROR = new ErrorCode(1_002_040_003, "布尔类型参数{}:【{}】转换异常,请检查配置规则"); + public static final ErrorCode CUSTOM_PLATE_NO_RULE_CHECK_RULECODE_EMPTY_ERROR = new ErrorCode(1_002_040_003, "规则编码不能为空"); + public static final ErrorCode CUSTOM_PLATE_NO_RULE_CHECK_RULECODE_NOT_MATCH_ERROR = new ErrorCode(1_002_040_003, "规则编码【{}】不合法,请检查配置规则"); + public static final ErrorCode CUSTOM_PLATE_NO_RULE_CHECK_DATE_TYPE_FORMAT_ERROR = new ErrorCode(1_002_040_003, "时间格式【{}】不合法,请检查配置规则"); + public static final ErrorCode CUSTOM_PLATE_NO_RULE_CHECK_CUSTOM_VALUE_EMPTY_ERROR = new ErrorCode(1_002_040_003, "自定义字符值不能为空,请检查配置规则"); + public static final ErrorCode CUSTOM_PLATE_NO_RULE_CHECK_RESETMODE_ERROR = new ErrorCode(1_002_040_003, "规则【{}】复位/清零模式【{}】不合法,请检查配置规则"); + public static final ErrorCode CUSTOM_PLATE_NO_RULE_CHECK_INT_TYPE_NO_EMPTY = new ErrorCode(1_002_040_003, "参数【{}】不能为空,请检查配置规则"); + public static final ErrorCode CUSTOM_PLATE_NO_RULE_CHECK_INT_TYPE_ERROR = new ErrorCode(1_002_040_003, "数值类型参数{}:【{}】转换异常,请检查配置规则"); + public static final ErrorCode CUSTOM_PLATE_NO_RULE_CHECK_BOL_TYPE_ERROR = new ErrorCode(1_002_040_003, "布尔类型参数{}:【{}】转换异常,请检查配置规则"); @Resource private DictDataService dictDataService; - @Resource - private CustomPlateNoSeqMapper customPlateNoSeqMapper; - @Resource private SystemConfigMapper systemConfigMapper; @@ -78,30 +76,30 @@ public class CustomPlateNoServiceHandler extends AbstractSystemConfigServiceHand public void checkValid(String setting) { // 字典中的时间格式 List dateTypeFormatDictList = dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), "system_setting_date_type"); - // 字典中的复位模式 - List resetModeDictList = dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), "system_setting_rest_type"); - try { JSONArray jsonArray = JSON.parseArray(setting); for (int i = 0; i < jsonArray.size(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); String ruleCode = jsonObject.getString("ruleCode"); // 1.校验code - CustBoardRuleCodeEnum custBoardRuleCodeEnum = checkRoleCode(ruleCode); + CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum = checkRoleCode(ruleCode); - // 2.时间格式校验 + // 2.自定义格式校验 + checkCustom(custBoardRuleCodeEnum, jsonObject); + + // 3.时间格式校验 checkDateFormat(custBoardRuleCodeEnum, jsonObject.getString("value"), dateTypeFormatDictList); - // 3.序号类型校验数字和布尔类型 + // 4.序号类型校验数字和布尔类型 checkNoType(custBoardRuleCodeEnum, jsonObject); - // 4.复位类型校验 - checkResetMode(custBoardRuleCodeEnum, jsonObject.getInteger("resetMode"), resetModeDictList); + // 5.复位类型校验 + checkResetMode(custBoardRuleCodeEnum, jsonObject.getInteger("resetMode"), ruleCode); } } catch (ServiceException e) { throw e; } catch (Exception e) { - ErrorCode systemConfigCustomPlateNoRuleSaveCheckError = SYSTEM_CONFIG_CUSTOM_BOARD_NO_RULE_SAVE_CHECK_ERROR; + ErrorCode systemConfigCustomPlateNoRuleSaveCheckError = SYSTEM_CONFIG_CUSTOM_PLATE_NO_RULE_SAVE_CHECK_ERROR; log.error(systemConfigCustomPlateNoRuleSaveCheckError.getMsg(), e); throw new ServiceException(systemConfigCustomPlateNoRuleSaveCheckError); } @@ -112,13 +110,13 @@ public class CustomPlateNoServiceHandler extends AbstractSystemConfigServiceHand * * @param ruleCode 规则编码 */ - private CustBoardRuleCodeEnum checkRoleCode(String ruleCode) { + private CustomPlateNoRuleCodeEnum checkRoleCode(String ruleCode) { if (StringUtils.isEmpty(ruleCode)) { - throw new ServiceException(CUSTOM_BOARD_NO_RULE_CHECK_RULECODE_EMPTY_ERROR); + throw new ServiceException(CUSTOM_PLATE_NO_RULE_CHECK_RULECODE_EMPTY_ERROR); } - CustBoardRuleCodeEnum custBoardRuleCodeEnum = CustBoardRuleCodeEnum.match(ruleCode); + CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum = CustomPlateNoRuleCodeEnum.match(ruleCode); if (ObjectUtil.isNull(custBoardRuleCodeEnum)) { - throw ServiceExceptionUtil.exception(CUSTOM_BOARD_NO_RULE_CHECK_RULECODE_NOT_MATCH_ERROR, ruleCode); + throw ServiceExceptionUtil.exception(CUSTOM_PLATE_NO_RULE_CHECK_RULECODE_NOT_MATCH_ERROR, ruleCode); } return custBoardRuleCodeEnum; } @@ -129,11 +127,25 @@ public class CustomPlateNoServiceHandler extends AbstractSystemConfigServiceHand * @param custBoardRuleCodeEnum 规则编码枚举 * @param format 格式 */ - private void checkDateFormat(CustBoardRuleCodeEnum custBoardRuleCodeEnum, String format, List dateTypeFormatDictList) { - if (ObjectUtil.equal(CustBoardRuleCodeEnum.DATE, custBoardRuleCodeEnum) && StringUtils.isNotEmpty(format)) { + private void checkDateFormat(CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum, String format, List dateTypeFormatDictList) { + if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.DATE, custBoardRuleCodeEnum) && StringUtils.isNotEmpty(format)) { Optional dateFormatDictDataOptional = dateTypeFormatDictList.stream().filter(d -> format.equals(d.getValue())).findAny(); if (dateFormatDictDataOptional.isEmpty()) { - throw ServiceExceptionUtil.exception(CUSTOM_BOARD_NO_RULE_CHECK_DATE_TYPE_FORMAT_ERROR, format); + throw ServiceExceptionUtil.exception(CUSTOM_PLATE_NO_RULE_CHECK_DATE_TYPE_FORMAT_ERROR, format); + } + } + } + + /** + * 校验自定义格式 + * + * @param custBoardRuleCodeEnum + * @param jsonObject + */ + private void checkCustom(CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum, JSONObject jsonObject) { + if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.CUSTOM, custBoardRuleCodeEnum)) { + if (ObjectUtil.isEmpty(jsonObject.get("value"))) { + throw ServiceExceptionUtil.exception(CUSTOM_PLATE_NO_RULE_CHECK_CUSTOM_VALUE_EMPTY_ERROR, jsonObject.get("ruleCode")); } } } @@ -144,13 +156,13 @@ public class CustomPlateNoServiceHandler extends AbstractSystemConfigServiceHand * @param custBoardRuleCodeEnum * @param object */ - private void checkNoType(CustBoardRuleCodeEnum custBoardRuleCodeEnum, JSONObject object) { + private void checkNoType(CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum, JSONObject object) { // 序号类型才校验 - if (ObjectUtil.equal(CustBoardRuleCodeEnum.ORDERNO, custBoardRuleCodeEnum) - || ObjectUtil.equal(CustBoardRuleCodeEnum.PLATENO, custBoardRuleCodeEnum) - || ObjectUtil.equal(CustBoardRuleCodeEnum.ROOMNO, custBoardRuleCodeEnum) - || ObjectUtil.equal(CustBoardRuleCodeEnum.BODYNO, custBoardRuleCodeEnum) - || ObjectUtil.equal(CustBoardRuleCodeEnum.PROCESSGROUP, custBoardRuleCodeEnum)) { + if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.ORDERNO, custBoardRuleCodeEnum) + || ObjectUtil.equal(CustomPlateNoRuleCodeEnum.PLATENO, custBoardRuleCodeEnum) + || ObjectUtil.equal(CustomPlateNoRuleCodeEnum.ROOMNO, custBoardRuleCodeEnum) + || ObjectUtil.equal(CustomPlateNoRuleCodeEnum.BODYNO, custBoardRuleCodeEnum) + ) { Map intTypeFieldMap = new HashMap<>() {{ put("initValue", "起始值"); put("length", "位数"); @@ -173,10 +185,10 @@ public class CustomPlateNoServiceHandler extends AbstractSystemConfigServiceHand */ private void checkInt(Object intObj, String fieldName) { if (ObjectUtil.isNull(intObj)) { - throw ServiceExceptionUtil.exception(CUSTOM_BOARD_NO_RULE_CHECK_INT_TYPE_NO_EMPTY, fieldName); + throw ServiceExceptionUtil.exception(CUSTOM_PLATE_NO_RULE_CHECK_INT_TYPE_NO_EMPTY, fieldName); } if (!NumberUtil.isInteger(intObj.toString())) { - throw ServiceExceptionUtil.exception(CUSTOM_BOARD_NO_RULE_CHECK_INT_TYPE_ERROR, fieldName, intObj); + throw ServiceExceptionUtil.exception(CUSTOM_PLATE_NO_RULE_CHECK_INT_TYPE_ERROR, fieldName, intObj); } } @@ -188,10 +200,10 @@ public class CustomPlateNoServiceHandler extends AbstractSystemConfigServiceHand */ private void checkBol(Object bolObj, String fieldName) { if (ObjectUtil.isNull(bolObj)) { - throw ServiceExceptionUtil.exception(CUSTOM_BOARD_NO_RULE_CHECK_INT_TYPE_NO_EMPTY, fieldName); + throw ServiceExceptionUtil.exception(CUSTOM_PLATE_NO_RULE_CHECK_INT_TYPE_NO_EMPTY, fieldName); } if (!(bolObj instanceof Boolean)) { - throw ServiceExceptionUtil.exception(CUSTOM_BOARD_NO_RULE_CHECK_BOL_TYPE_ERROR, fieldName, bolObj); + throw ServiceExceptionUtil.exception(CUSTOM_PLATE_NO_RULE_CHECK_BOL_TYPE_ERROR, fieldName, bolObj); } } @@ -200,16 +212,22 @@ public class CustomPlateNoServiceHandler extends AbstractSystemConfigServiceHand * * @param resetMode */ - private void checkResetMode(CustBoardRuleCodeEnum custBoardRuleCodeEnum, Integer resetMode, List resetModeDictList) { - if (ObjectUtil.equal(CustBoardRuleCodeEnum.ORDERNO, custBoardRuleCodeEnum) - || ObjectUtil.equal(CustBoardRuleCodeEnum.PLATENO, custBoardRuleCodeEnum) - || ObjectUtil.equal(CustBoardRuleCodeEnum.ROOMNO, custBoardRuleCodeEnum) - || ObjectUtil.equal(CustBoardRuleCodeEnum.BODYNO, custBoardRuleCodeEnum) - || ObjectUtil.equal(CustBoardRuleCodeEnum.PROCESSGROUP, custBoardRuleCodeEnum)) { - Optional resetModeDictDataOptional = resetModeDictList.stream().filter(d -> resetMode.toString().equals(d.getValue())).findAny(); - if (resetModeDictDataOptional.isEmpty()) { - throw ServiceExceptionUtil.exception(CUSTOM_BOARD_NO_RULE_CHECK_RESETMODE_ERROR, resetMode); - } + private void checkResetMode(CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum, Integer resetMode, String ruleCode) { + boolean checkSuccess = true; + if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.ORDERNO, custBoardRuleCodeEnum)) { + checkSuccess = ObjectUtil.equal(resetMode, ResetModeEnum.DIGIT.getMode()) || ObjectUtil.equal(resetMode, ResetModeEnum.YEAR.getMode()) + || ObjectUtil.equal(resetMode, ResetModeEnum.MONTH.getMode()) || ObjectUtil.equal(resetMode, ResetModeEnum.DAY.getMode()); + } else if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.PLATENO, custBoardRuleCodeEnum)) { + checkSuccess = ObjectUtil.equal(resetMode, ResetModeEnum.ORDER.getMode()) || ObjectUtil.equal(resetMode, ResetModeEnum.YEAR.getMode()) + || ObjectUtil.equal(resetMode, ResetModeEnum.MONTH.getMode()) || ObjectUtil.equal(resetMode, ResetModeEnum.ROOM.getMode()) + || ObjectUtil.equal(resetMode, ResetModeEnum.BODY.getMode()); + } else if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.ROOMNO, custBoardRuleCodeEnum)) { + checkSuccess = ObjectUtil.equal(resetMode, ResetModeEnum.ORDER.getMode()); + } else if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.BODYNO, custBoardRuleCodeEnum)) { + checkSuccess = ObjectUtil.equal(resetMode, ResetModeEnum.ORDER.getMode()) || ObjectUtil.equal(resetMode, ResetModeEnum.ROOM.getMode()); + } + if (!checkSuccess) { + throw ServiceExceptionUtil.exception(CUSTOM_PLATE_NO_RULE_CHECK_RESETMODE_ERROR, ruleCode, resetMode); } } @@ -246,6 +264,11 @@ public class CustomPlateNoServiceHandler extends AbstractSystemConfigServiceHand .eq(SystemConfigDO::getType, SystemConfigTypeEnum.CUSTOM_PLATE_NO.getType()) .le(SystemConfigDO::getVersion, minReserveVersion)); } + // 移除机构下的板编号配置缓存 + // 禁用配置移除缓存 + String redisKey = String.format("%s:%d:%s", RedisKeyConstants.SYSTEM_CONFIG, OrganContextHolder.getOrganId(), RedisKeyConstants.CUSTOM_PLATE_NO); + Boolean delete = stringRedisTemplate.delete(redisKey); + log.info("[CustomPlateNoGenerateService][afterUpdateStatus]key:{}缓存删除结果:{}", redisKey, delete); } @Override diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/DefaultSystemConfigServiceHandler.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/DefaultSystemConfigServiceHandler.java index cc29a0002..b9e3950c8 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/DefaultSystemConfigServiceHandler.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/config/factory/service/impl/DefaultSystemConfigServiceHandler.java @@ -1,6 +1,7 @@ package com.cf.imes.module.system.service.config.factory.service.impl; import cn.hutool.core.util.ObjectUtil; +import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; import com.cf.imes.framework.organ.core.context.OrganContextHolder; import com.cf.imes.module.system.controller.admin.systemconfig.vo.ConfigDeleteReqVO; @@ -11,7 +12,6 @@ import com.cf.imes.module.system.dal.dataobject.systemconfig.SystemConfigDO; import com.cf.imes.module.system.dal.mysql.systemconfig.SystemConfigMapper; import com.cf.imes.module.system.enums.config.SystemConfigTypeEnum; import com.cf.imes.module.system.service.config.factory.service.AbstractSystemConfigServiceHandler; -import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -19,7 +19,6 @@ import javax.annotation.Resource; import java.util.Comparator; import java.util.List; import java.util.Optional; -import java.util.concurrent.CopyOnWriteArrayList; /** * @@ -35,15 +34,16 @@ public class DefaultSystemConfigServiceHandler extends AbstractSystemConfigServi @Override public List selectList(ConfigPageReqVO reqVO) { - List systemConfigDOS = systemConfigMapper.selectList(new LambdaQueryWrapperX() - .likeIfPresent(SystemConfigDO::getName, reqVO.getName()) - .eqIfPresent(SystemConfigDO::getStatus, reqVO.getStatus()) - .eqIfPresent(SystemConfigDO::getOrganId, OrganContextHolder.getOrganId()) - .orderByAsc(SystemConfigDO::getId)); // todo 后续所有configTypeEnum中的类型需要上到列表补全时通过遍历enum来补充 SystemConfigTypeEnum customplateNoEnum = SystemConfigTypeEnum.CUSTOM_PLATE_NO; - CopyOnWriteArrayList configDOS = Lists.newCopyOnWriteArrayList(systemConfigDOS); - Optional configDOOptional = configDOS.stream().filter(c -> ObjectUtil.equal(customplateNoEnum.getType(), c.getType())).findAny(); + List systemConfigDOS = systemConfigMapper.selectList(new LambdaQueryWrapperX() + .likeIfPresent(SystemConfigDO::getName, reqVO.getName()) + .eq(SystemConfigDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) + .eq(SystemConfigDO::getType, customplateNoEnum.getType()) + .eqIfPresent(SystemConfigDO::getOrganId, OrganContextHolder.getOrganId()) + .select(SystemConfigDO::getId, SystemConfigDO::getName, SystemConfigDO::getStatus, SystemConfigDO::getType) + .orderByAsc(SystemConfigDO::getId)); + Optional configDOOptional = systemConfigDOS.stream().filter(c -> ObjectUtil.equal(customplateNoEnum.getType(), c.getType())).findAny(); if (configDOOptional.isEmpty()) { SystemConfigDO initCustomPlateNoConfig = new SystemConfigDO().builder().id(null).name(customplateNoEnum.getName()).type(customplateNoEnum.getType()).build(); return List.of(initCustomPlateNoConfig); diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/customplateno/CustomPlateNoSeqService.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/customplateno/CustomPlateNoSeqService.java index 3887fc884..752cc036a 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/customplateno/CustomPlateNoSeqService.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/customplateno/CustomPlateNoSeqService.java @@ -15,4 +15,11 @@ public interface CustomPlateNoSeqService { * @return */ CustomPlateNoSeqDO getOrgCustomPlateNoSeq(); + + /** + * 修改机构的自定义版编号序号 + * + * @param seqDO + */ + Boolean modifyOrgCustomPlateNoSeq(CustomPlateNoSeqDO seqDO); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/customplateno/CustomPlateNoSeqServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/customplateno/CustomPlateNoSeqServiceImpl.java index d640e10e5..c9650f919 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/customplateno/CustomPlateNoSeqServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/customplateno/CustomPlateNoSeqServiceImpl.java @@ -24,4 +24,11 @@ public class CustomPlateNoSeqServiceImpl implements CustomPlateNoSeqService { return customPlateNoSeqMapper.selectOne(new LambdaQueryWrapperX() .eq(CustomPlateNoSeqDO::getOrganId, OrganContextHolder.getOrganId())); } -} + + @Override + public Boolean modifyOrgCustomPlateNoSeq(CustomPlateNoSeqDO seqDO) { + return customPlateNoSeqMapper.insertOrUpdate(seqDO); + } + + +} \ No newline at end of file From 3a4358a7aee6066f24cb8904b1b46ebdd049985d Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Wed, 27 Nov 2024 18:40:36 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=E6=8A=A5=E8=A1=A8=E4=BC=98=E5=8C=96?= =?UTF-8?q?=EF=BC=9A=E9=A2=84=E8=A7=88=E6=94=AF=E6=8C=81=E6=A0=87=E9=A2=98?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/ureport-core-2.3.0-SNAPSHOT.jar | Bin 929328 -> 929289 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cf-module-report/cf-module-report-biz/src/main/resources/lib/ureport-core-2.3.0-SNAPSHOT.jar b/cf-module-report/cf-module-report-biz/src/main/resources/lib/ureport-core-2.3.0-SNAPSHOT.jar index 6121e521afb135d42066020fef3de6aa4c1ef9b3..a4e48968e97cae748d3079d9efafbe5335219654 100644 GIT binary patch delta 27651 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 RpUu_t+c~T>9N#ww^gkNKFKPe) delta 27732 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

  • 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 RMfJ&tKH>D6o{rp)_z(FHe18A{