diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..b1e3f8f
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,166 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.7.RELEASE
+
+
+ com.xdap
+ self_development
+ 1.0-SNAPSHOT
+ self_development
+ 自开发后端
+
+
+
+ dcloud-public
+ https://registry.dfy.definesys.cn/repository/maven-public/
+
+
+
+
+ 1.8
+ 2.9.2-01
+ 2.4.3-01
+ 4.0.7-rc
+ apaas-1.1.18.4-RELEASE
+ 1.18.12
+ 2.0.0
+
+
+
+
+ cn.hutool
+ hutool-all
+ 5.7.15
+
+
+ com.xdap
+ runtime
+ ${papaas.version}
+
+
+ com.definesys.mpaas
+ query-mongodb
+
+
+ com.xdap
+ xdap-plugins-common
+
+
+ com.xdap
+ common
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.12
+ true
+
+
+
+ com.definesys.mpaas
+ query-mongodb
+ ${mpaas.version}
+
+
+ com.xdap
+ xdap-plugins-common
+ ${plugins.version}
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.14.0-rc1
+
+
+ com.xdap
+ common
+ ${papaas.version}
+
+
+
+
+ single
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ maven-compiler-plugin
+ 3.6.0
+
+ 1.8
+ 1.8
+ UTF-8
+ groovy-eclipse-compiler
+ true
+
+
+
+ lombok.launch.Agent
+
+ true
+
+
+
+ org.codehaus.groovy
+ groovy-eclipse-compiler
+ ${groovy.eclipse.compiler.version}
+
+
+
+ org.codehaus.groovy
+ groovy-eclipse-batch
+ ${groovy.eclipse.batch.version}
+
+
+ org.codehaus.plexus
+ plexus-compiler-api
+ 2.8.1
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+
+
+
+
+ src/main/resources
+
+ **/application.properties
+ **/*.yml
+
+
+
+
+
+
+ lib
+
+
+
+ src/main/resources
+
+ **/*.properties
+ **/*.yml
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/MainApplication.java b/src/main/java/com/xdap/self_development/MainApplication.java
new file mode 100644
index 0000000..0244593
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/MainApplication.java
@@ -0,0 +1,21 @@
+package com.xdap.self_development;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@SpringBootApplication(
+ exclude = {EmbeddedMongoAutoConfiguration.class}
+)
+@EnableTransactionManagement
+@EnableScheduling
+@ComponentScan(basePackages = {"com.definesys.mpaas", "com.xdap.*"})
+public class MainApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MainApplication.class, args);
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/config/BusinessDatabase.java b/src/main/java/com/xdap/self_development/config/BusinessDatabase.java
new file mode 100644
index 0000000..863e2e7
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/config/BusinessDatabase.java
@@ -0,0 +1,19 @@
+package com.xdap.self_development.config;
+
+import com.definesys.mpaas.query.MpaasQuery;
+import com.definesys.mpaas.query.MpaasQueryFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+@Component
+public class BusinessDatabase {
+ @Resource
+ private MpaasQueryFactory queryFactory;
+
+ @Bean
+ public MpaasQuery getBusinessDatabase() {
+ return queryFactory.buildFromDatasource("xdap_app_223770822127386625");
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/config/CorsConfig.java b/src/main/java/com/xdap/self_development/config/CorsConfig.java
new file mode 100644
index 0000000..f075dfe
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/config/CorsConfig.java
@@ -0,0 +1,16 @@
+package com.xdap.self_development.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class CorsConfig implements WebMvcConfigurer {
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedOrigins("*")
+ .allowedMethods("GET", "POST", "PUT", "DELETE")
+ .allowedHeaders("*");
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/config/CustomAllowUrlConfig.java b/src/main/java/com/xdap/self_development/config/CustomAllowUrlConfig.java
new file mode 100644
index 0000000..47a0632
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/config/CustomAllowUrlConfig.java
@@ -0,0 +1,17 @@
+package com.xdap.self_development.config;
+
+import com.xdap.api.moudle.custom.AllowUrlManage;
+import org.springframework.stereotype.Component;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@Component
+public class CustomAllowUrlConfig implements AllowUrlManage {
+ @Override
+ public Set getCustomAllowUrls() {
+ Set urlSet = new HashSet<>();
+ urlSet.add("/custom/*");
+ return urlSet;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/controller/BenchmarkingReportController.java b/src/main/java/com/xdap/self_development/controller/BenchmarkingReportController.java
new file mode 100644
index 0000000..ff86e5a
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/BenchmarkingReportController.java
@@ -0,0 +1,90 @@
+package com.xdap.self_development.controller;
+
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.definesys.mpaas.common.http.Response;
+import com.xdap.self_development.controller.form.BenchmarkingReportPageForm;
+import com.xdap.self_development.controller.form.HandleApprovalRequest;
+import com.xdap.self_development.controller.form.SaveBenchmarkingReportForm;
+import com.xdap.self_development.pojo.BenchmarkingReport;
+import com.xdap.self_development.pojo.view.ApprovalFlowView;
+import com.xdap.self_development.pojo.view.TodoAndReportView;
+import com.xdap.self_development.service.BenchmarkingReportService;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import java.util.List;
+
+@RestController
+@RequestMapping("/custom/benchmark")
+public class BenchmarkingReportController {
+ @Resource
+ private BenchmarkingReportService benchmarkingReportService;
+
+ // 新增对标报告并发起审批
+ @PostMapping("/startReportApproval")
+ public Response startReportApproval(
+ @Valid @RequestBody SaveBenchmarkingReportForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ benchmarkingReportService.saveBenchmarkingReport(form);
+ return Response.ok().setMessage("保存成功");
+ }
+
+ // 筛选对标报告及待办
+ @PostMapping("/getReportAndTodoByCondition")
+ public Response getBenchmarkingReportByCondition(
+ @Valid @RequestBody BenchmarkingReportPageForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ List list = benchmarkingReportService
+ .getBenchmarkingReportByCondition(form);
+ return Response.ok().data(list);
+ }
+
+ // 处理审批
+ @PostMapping("/handleReportApproval")
+ public Response handleReportApproval(
+ @RequestBody @Valid HandleApprovalRequest request,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ benchmarkingReportService.handleReportApproval(request);
+ return Response.ok().setMessage("处理成功");
+ }
+
+ // 查看对标报告详情
+ @GetMapping("/getReportDetail")
+ public Response getReportDetail(
+ @NotBlank String reportId
+ ) {
+ BenchmarkingReport report = benchmarkingReportService
+ .getReportDetail(reportId);
+ return Response.ok().data(report);
+ }
+
+ // 获取审批流程
+ @GetMapping("/getReportProcess")
+ public Response getReportProcess(
+ @NotBlank String flowId
+ ) {
+ ApprovalFlowView approvalFlowView = benchmarkingReportService.getReportProcess(flowId);
+ return Response.ok().data(approvalFlowView);
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/controller/DeleteController.java b/src/main/java/com/xdap/self_development/controller/DeleteController.java
new file mode 100644
index 0000000..6a095b7
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/DeleteController.java
@@ -0,0 +1,171 @@
+package com.xdap.self_development.controller;
+
+import com.definesys.mpaas.common.http.Response;
+import com.xdap.api.moudle.user.vo.LoginUserVo;
+import com.xdap.runtime.service.RuntimeAppContextService;
+import com.xdap.runtime.service.RuntimeUserService;
+import com.xdap.self_development.config.BusinessDatabase;
+import com.xdap.self_development.feign.ApaasMyTokenFeign;
+import com.xdap.self_development.feign.dto.AppTokenDTO;
+import com.xdap.self_development.pojo.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/custom/delete")
+public class DeleteController {
+ @Resource
+ private BusinessDatabase bd;
+ @Resource
+ private RuntimeAppContextService runtimeAppContextService;
+ @Resource
+ private RuntimeUserService runtimeUserService;
+ @Autowired
+ private ApaasMyTokenFeign apaasMyTokenFeign;
+
+ @GetMapping("/loginVo")
+ public Response loginVo(@RequestParam String userId) {
+ Map map = new HashMap<>();
+ AppTokenDTO token = apaasMyTokenFeign.token(
+ "client_credentials",
+ "2b5b3de8-e7fd-406a-a59a-d5568457b1f4",
+ "94bddc6a-27a4-4204-885b-b075812ec535"
+ );
+ map.put("token", token);
+ return Response.ok().data(map);
+ }
+
+ @GetMapping("getAll")
+ public Response getAll() {
+ List templates = bd.getBusinessDatabase().doQuery(Template.class);
+ List parameters = bd.getBusinessDatabase().doQuery(Parameter.class);
+ List templateAndParameters = bd.getBusinessDatabase().doQuery(TemplateAndParameter.class);
+ List revisionRecords = bd.getBusinessDatabase().doQuery(RevisionRecord.class);
+
+ Map result = new HashMap<>();
+ result.put("templates", templates);
+ result.put("parameters", parameters);
+ result.put("templateAndParameters", templateAndParameters);
+ result.put("revisionRecords", revisionRecords);
+
+ return Response.ok().data(result);
+ }
+
+ @GetMapping("/deleteAll")
+ @Transactional
+ public Response deleteAll(@RequestParam String templateRowId) {
+ Template template = bd.getBusinessDatabase().rowid("id", templateRowId).doQueryFirst(Template.class);
+ List templateAndParameters = bd.getBusinessDatabase()
+ .eq("template_id", template.getId())
+ .doQuery(TemplateAndParameter.class);
+ List ids = templateAndParameters.stream()
+ .map(TemplateAndParameter::getId)
+ .collect(Collectors.toList());
+ List parameterIds = templateAndParameters.stream()
+ .map(TemplateAndParameter::getParameterId)
+ .collect(Collectors.toList());
+ List revisionRecords = bd.getBusinessDatabase()
+ .eq("template_id", template.getId())
+ .doQuery(RevisionRecord.class);
+ List rIds = revisionRecords.stream()
+ .map(RevisionRecord::getId)
+ .collect(Collectors.toList());
+
+ if (!parameterIds.isEmpty()) {
+ bd.getBusinessDatabase()
+ .in("id", parameterIds)
+ .doDelete(Parameter.class);
+ }
+ if (!ids.isEmpty()) {
+ bd.getBusinessDatabase()
+ .in("id", ids)
+ .doDelete(TemplateAndParameter.class);
+ }
+
+ if (template.getId() != null) {
+ bd.getBusinessDatabase()
+ .eq("id", template.getId())
+ .doDelete(Template.class);
+ }
+ if (!rIds.isEmpty()) {
+ bd.getBusinessDatabase()
+ .in("id", rIds)
+ .doDelete(RevisionRecord.class);
+ }
+ return Response.ok();
+ }
+
+ @GetMapping("/deleteOne")
+ public Response deleteOne(
+ @RequestParam String rowId,
+ @RequestParam String parameterRowId,
+ @RequestParam String templateRowId,
+ @RequestParam String revisionRowId
+ ) {
+ if (parameterRowId != null && !parameterRowId.isEmpty()) {
+ bd.getBusinessDatabase()
+ .rowid("id", parameterRowId)
+ .doDelete(Parameter.class);
+ }
+ if (rowId != null && !rowId.isEmpty()) {
+ bd.getBusinessDatabase()
+ .rowid("id", rowId)
+ .doDelete(TemplateAndParameter.class);
+ }
+ if (templateRowId != null && !templateRowId.isEmpty()) {
+ bd.getBusinessDatabase()
+ .rowid("id", templateRowId)
+ .doDelete(Template.class);
+ }
+ if (revisionRowId != null && !revisionRowId.isEmpty()) {
+ bd.getBusinessDatabase()
+ .rowid("id", revisionRowId)
+ .doDelete(RevisionRecord.class);
+ }
+ return Response.ok();
+ }
+
+ @GetMapping("/getAllFlow")
+ public Response getAllFlow() {
+ List flows = bd.getBusinessDatabase().doQuery(ApprovalFlow.class);
+ List records = bd.getBusinessDatabase().doQuery(ApprovalRecord.class);
+
+ Map result = new HashMap<>();
+ result.put("flows", flows);
+ result.put("records", records);
+ return Response.ok().data(result);
+ }
+
+ @GetMapping("/deleteAllFlow")
+ public Response deleteAllFlow(
+ @RequestParam String flowId
+ ) {
+ bd.getBusinessDatabase().eq("flow_id", flowId).doDelete(ApprovalRecord.class);
+ bd.getBusinessDatabase().eq("id", flowId).doDelete(ApprovalFlow.class);
+ return Response.ok().setMessage("删除成功");
+ }
+
+ @GetMapping("/deleteOneFlow")
+ public Response deleteOneFlow(
+ @RequestParam String flowId,
+ @RequestParam String id
+ ) {
+ if (flowId != null && !flowId.isEmpty()) {
+ bd.getBusinessDatabase().eq("id", flowId).doDelete(ApprovalFlow.class);
+ }
+ if (id != null && !id.isEmpty()) {
+ bd.getBusinessDatabase().eq("id", id).doDelete(ApprovalRecord.class);
+ }
+ return Response.ok();
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/controller/ParameterController.java b/src/main/java/com/xdap/self_development/controller/ParameterController.java
new file mode 100644
index 0000000..e304b0a
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/ParameterController.java
@@ -0,0 +1,53 @@
+package com.xdap.self_development.controller;
+
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.definesys.mpaas.common.http.Response;
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.self_development.controller.form.ParameterPageForm;
+import com.xdap.self_development.controller.form.UpdateParameterForm;
+import com.xdap.self_development.pojo.Parameter;
+import com.xdap.self_development.pojo.view.TemplateInfoView;
+import com.xdap.self_development.service.ParameterService;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+
+@RestController
+@RequestMapping("/custom/parameter")
+public class ParameterController {
+ @Resource
+ private ParameterService parameterService;
+
+ // 参数的模糊搜索
+ @GetMapping("/getParameterByCondition")
+ public Response getParameterByCondition(
+ @Valid ParameterPageForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ PageQueryResult list = parameterService.getParameterByCondition(form);
+ return Response.ok().data(list);
+ }
+
+
+ // 维护参数
+ @PostMapping("/maintenanceParameters")
+ public Response maintenanceParameters(
+ @Valid @RequestBody UpdateParameterForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ TemplateInfoView templateRowIdForm = parameterService.maintenanceParameters(form);
+ return Response.ok().setMessage("维护成功").data(templateRowIdForm);
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/controller/ResponsiblePersonController.java b/src/main/java/com/xdap/self_development/controller/ResponsiblePersonController.java
new file mode 100644
index 0000000..9f02997
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/ResponsiblePersonController.java
@@ -0,0 +1,143 @@
+package com.xdap.self_development.controller;
+
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.definesys.mpaas.common.http.Response;
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.api.moudle.department.pojo.entity.XdapDepartments;
+import com.xdap.api.moudle.user.pojo.XdapUsers;
+import com.xdap.runtime.service.RuntimeDatasourceService;
+import com.xdap.self_development.config.BusinessDatabase;
+import com.xdap.self_development.controller.form.DepartmentUserForm;
+import com.xdap.self_development.controller.form.DeptResponsiblePageForm;
+import com.xdap.self_development.controller.form.ResponsiblePersonForm;
+import com.xdap.self_development.controller.form.UpdateResponsiblePersonForm;
+import com.xdap.self_development.pojo.ResponsiblePerson;
+import com.xdap.self_development.pojo.Template;
+import com.xdap.self_development.pojo.view.DepartmentUserView;
+import com.xdap.self_development.service.ResponsiblePersonService;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import java.util.List;
+import java.util.Set;
+
+@RestController
+@RequestMapping("/custom/responsible")
+public class ResponsiblePersonController {
+ @Resource
+ private RuntimeDatasourceService runtimeDatasourceService;
+ @Resource
+ private ResponsiblePersonService responsiblePersonService;
+
+ // 判断是否为责任人
+ @GetMapping("/isResponsiblePerson")
+ public Response isResponsiblePerson(
+ @NotBlank String userId
+ ) {
+ return Response.ok().data(responsiblePersonService.isResponsiblePerson(userId));
+ }
+
+ // 查询所有部门责任人
+ @GetMapping("/getDeptResponsible")
+ public Response getDeptResponsible(
+ @Valid DeptResponsiblePageForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ PageQueryResult deptResponsible =
+ responsiblePersonService.getDeptResponsible(form);
+ return Response.ok().data(deptResponsible);
+ }
+
+ // 根据部门id获取子部门
+ @GetMapping("/getSubDepartmentById")
+ public Response getSubDepartmentById(
+ @RequestParam(defaultValue = "") String departmentId
+ ) {
+ List xdapDepartments;
+ if (departmentId == null || departmentId.isEmpty()) {
+ xdapDepartments = runtimeDatasourceService.
+ buildTenantNoSchemaMpaasQuery()
+ .eq("level", 1)
+ .eq("status", "ENABLE")
+ .doQuery(XdapDepartments.class);
+ } else {
+ xdapDepartments = runtimeDatasourceService.
+ buildTenantNoSchemaMpaasQuery()
+ .eq("parent_id", departmentId)
+ .eq("status", "ENABLE")
+ .doQuery(XdapDepartments.class);
+ }
+
+ return Response.ok().data(xdapDepartments);
+ }
+
+ // 根据部门id获取部门的用户
+ @GetMapping("/getUserByDepartmentId")
+ public Response getUserByDepartmentId(
+ @Valid DepartmentUserForm form
+ ) {
+ List responsiblePeoples = runtimeDatasourceService
+ .buildTenantNoSchemaMpaasQuery()
+ .viewQueryMode(true)
+ .view("getUserByDepartment")
+ .setVar("departmentId", form.getDepartmentId())
+ .like("username", form.getKey())
+ .doQuery(DepartmentUserView.class);
+ return Response.ok().data(responsiblePeoples);
+ }
+
+ // 获取全部子系统名
+ @GetMapping("/getAllSubsystem")
+ public Response getAllSubsystem() {
+ Set set = responsiblePersonService.getAllSubsystem();
+ return Response.ok().data(set);
+ }
+
+ // 保存部门责任人
+ @PostMapping("/saveResponsiblePerson")
+ public Response saveResponsiblePerson(
+ @Valid @RequestBody ResponsiblePersonForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ responsiblePersonService.saveResponsiblePerson(form);
+ return Response.ok().setMessage(form.toString());
+ }
+
+ // 修改部门责任人
+ @PostMapping("/updateResponsiblePerson")
+ public Response updateResponsiblePerson(
+ @Valid @RequestBody UpdateResponsiblePersonForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+
+ responsiblePersonService.updateResponsiblePerson(form);
+ return Response.ok().setMessage(form.toString());
+ }
+
+ // 删除部门责任人
+ @GetMapping("/deleteResponsiblePerson")
+ public Response deleteResponsiblePerson(
+ @NotBlank @RequestParam String rowId
+ ) {
+ responsiblePersonService.deleteResponsiblePerson(rowId);
+ return Response.ok();
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/controller/TemplateApprovalController.java b/src/main/java/com/xdap/self_development/controller/TemplateApprovalController.java
new file mode 100644
index 0000000..da63916
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/TemplateApprovalController.java
@@ -0,0 +1,112 @@
+package com.xdap.self_development.controller;
+
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.definesys.mpaas.common.http.Response;
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.runtime.service.RuntimeDatasourceService;
+import com.xdap.self_development.controller.form.*;
+import com.xdap.self_development.pojo.view.ApprovalFlowView;
+import com.xdap.self_development.pojo.view.DepartmentUserView;
+import com.xdap.self_development.pojo.view.TemplateChangeView;
+import com.xdap.self_development.service.TemplateApprovalService;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import java.util.List;
+
+@RestController
+@RequestMapping("/custom/approval")
+public class TemplateApprovalController {
+ @Resource
+ private TemplateApprovalService templateApprovalService;
+ @Resource
+ private RuntimeDatasourceService runtimeDatasourceService;
+
+ @GetMapping("/getUsersByCondition")
+ public Response getUsersByCondition(
+ @RequestParam String name
+ ) {
+ List users = runtimeDatasourceService.buildTenantNoSchemaMpaasQuery()
+ .viewQueryMode(true)
+ .view("getUserAndDept")
+ .like("username", name)
+ .doQuery(DepartmentUserView.class);
+ return Response.ok().data(users);
+ }
+ // 发起审批
+ @PostMapping("/startApproval")
+ public Response startApproval(
+ @RequestBody @Valid StartApprovalRequest request,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ return Response.ok().data(templateApprovalService.startApproval(request));
+ }
+
+ // 查询审批列表
+ @GetMapping("/getApprovalList")
+ public Response getTodoList(
+ @Valid ApprovalListForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ return Response.ok().data(templateApprovalService.getApprovalList(form));
+ }
+
+ // 处理审批
+ @PostMapping("/handleApproval")
+ public Response handleApproval(
+ @RequestBody @Valid HandleApprovalRequest request,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ templateApprovalService.handleApproval(request);
+ return Response.ok();
+ }
+
+ // 获取模板变动
+ @GetMapping("/getTemplateChanges")
+ public Response getTemplateChanges(
+ @Valid ApprovalAndParameterForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ PageQueryResult result = templateApprovalService.getTemplateChanges(form);
+ return Response.ok().data(result);
+ }
+
+ // 获取审批流程
+ @GetMapping("/getApprovalProcess")
+ public Response getApprovalProcess(
+ @Valid ApprovalFlowForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ ApprovalFlowView approvalFlowView = templateApprovalService.getApprovalProcess(form);
+ return Response.ok().data(approvalFlowView);
+ }
+
+}
diff --git a/src/main/java/com/xdap/self_development/controller/TemplateController.java b/src/main/java/com/xdap/self_development/controller/TemplateController.java
new file mode 100644
index 0000000..34d884d
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/TemplateController.java
@@ -0,0 +1,113 @@
+package com.xdap.self_development.controller;
+
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.definesys.mpaas.common.http.Response;
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.api.moudle.department.pojo.entity.XdapDepartments;
+import com.xdap.runtime.service.RuntimeDatasourceService;
+import com.xdap.self_development.controller.form.*;
+import com.xdap.self_development.pojo.Template;
+import com.xdap.self_development.service.TemplateService;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.util.List;
+
+@RestController
+@RequestMapping("/custom/template")
+public class TemplateController {
+ @Resource
+ private TemplateService templateService;
+
+
+ // 模板名的模糊搜索
+ @GetMapping("/getTemplateByCondition")
+ public Response getTemplateByCondition(
+ @Valid TemplatePageForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+
+ PageQueryResult page = templateService.getTemplateByCondition(form);
+ return Response.ok().data(page);
+ }
+
+ // 导入模板 导入全部模板参数和单页模板参数
+ @PostMapping("/import")
+ public Response importTemplate(
+ @RequestPart("file") MultipartFile file,
+ @RequestPart(value = "templateRowId", required = false) String templateRowId,
+ @RequestPart("createBy") String createBy
+ ) {
+ templateService.importTemplate(file, templateRowId, createBy);
+ return Response.ok().setMessage("导入成功");
+ }
+
+ // 添加模板
+ @PostMapping("/insertTemplate")
+ public Response insertTemplate(
+ @Valid @RequestBody InsertTemplateForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ templateService.insertTemplate(form);
+ return Response.ok().setMessage("添加成功");
+ }
+
+ // 修改模板
+ @PostMapping("/updateTemplate")
+ public Response updateTemplate(
+ @Valid @RequestBody UpdateTemplateForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ templateService.updateTemplate(form);
+ return Response.ok().setMessage("修改成功");
+ }
+
+ // 下载 空模板或全参模板
+ @GetMapping("/export")
+ public void exportTemplate(
+ @Valid ExportTemplateForm form,
+ HttpServletResponse response,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ templateService.exportTemplate(form, response);
+ }
+
+ // 查看版本 某个模板的全部版本
+ @GetMapping("getTemplateVersion")
+ public Response getTemplateVersion(
+ @Valid TemplateRowIdForm form,
+ BindingResult bindingResult
+ ) {
+ if (bindingResult.hasErrors()) {
+ bindingResult.getFieldErrors().forEach(error -> {
+ throw new MpaasBusinessException(error.getDefaultMessage());
+ });
+ }
+ List list = templateService.getTemplateVersion(form);
+ return Response.ok().data(list);
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/ApprovalAndParameterForm.java b/src/main/java/com/xdap/self_development/controller/form/ApprovalAndParameterForm.java
new file mode 100644
index 0000000..fb548d5
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/ApprovalAndParameterForm.java
@@ -0,0 +1,23 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class ApprovalAndParameterForm {
+ @NotBlank(message = "流程不能为空")
+ private String flowId;
+ @NotBlank(message = "模板不能为空")
+ private String templateId;
+
+ @NotNull(message = "页码不能为空")
+ @Min(value = 1, message = "页码不能小于1")
+ private Integer pageNumber;
+
+ @NotNull(message = "每页条数不能为空")
+ @Min(value = 1, message = "每页条数不能小于1")
+ private Integer pageSize;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/ApprovalFlowForm.java b/src/main/java/com/xdap/self_development/controller/form/ApprovalFlowForm.java
new file mode 100644
index 0000000..bce5bc2
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/ApprovalFlowForm.java
@@ -0,0 +1,13 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class ApprovalFlowForm {
+ @NotBlank(message = "流程不能为空")
+ private String flowId;
+ @NotBlank(message = "模板不能为空")
+ private String templateId;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/ApprovalListForm.java b/src/main/java/com/xdap/self_development/controller/form/ApprovalListForm.java
new file mode 100644
index 0000000..66ff1ad
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/ApprovalListForm.java
@@ -0,0 +1,14 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class ApprovalListForm {
+ @NotBlank(message = "用户不能为空")
+ private String userId;
+
+ private String templateName;
+ private String status;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/BenchmarkingReportPageForm.java b/src/main/java/com/xdap/self_development/controller/form/BenchmarkingReportPageForm.java
new file mode 100644
index 0000000..6d5efcc
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/BenchmarkingReportPageForm.java
@@ -0,0 +1,35 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class BenchmarkingReportPageForm {
+ private String title;
+ private String manufacturerName;
+ private String modelName;
+ private String productNumber;
+ private String module;
+ private String plate;
+ private String platform;
+ private String series;
+ private String marketSegment;
+ private String projectName;
+ private String projectNumber;
+ private String status;
+
+ @NotBlank(message = "上传用户不能为空")
+ private String createBy;
+
+// @NotNull(message = "页码不能为空")
+// @Min(value = 1, message = "页码不能小于1")
+// private Integer pageNumber;
+//
+// @NotNull(message = "每页条数不能为空")
+// @Min(value = 1, message = "每页条数不能小于1")
+// private Integer pageSize;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/DepartmentUserForm.java b/src/main/java/com/xdap/self_development/controller/form/DepartmentUserForm.java
new file mode 100644
index 0000000..472c9bc
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/DepartmentUserForm.java
@@ -0,0 +1,13 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class DepartmentUserForm {
+ @NotBlank
+ private String departmentId;
+ private String key;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/DeptResponsiblePageForm.java b/src/main/java/com/xdap/self_development/controller/form/DeptResponsiblePageForm.java
new file mode 100644
index 0000000..775b2df
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/DeptResponsiblePageForm.java
@@ -0,0 +1,18 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class DeptResponsiblePageForm {
+
+ @NotNull(message = "页码不能为空")
+ @Min(value = 1, message = "页码不能小于1")
+ private Integer pageNumber;
+
+ @NotNull(message = "每页条数不能为空")
+ @Min(value = 1, message = "每页条数不能小于1")
+ private Integer pageSize;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/ExportTemplateForm.java b/src/main/java/com/xdap/self_development/controller/form/ExportTemplateForm.java
new file mode 100644
index 0000000..e90212b
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/ExportTemplateForm.java
@@ -0,0 +1,14 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class ExportTemplateForm {
+ @NotBlank(message = "请选择模板")
+ private String templateRowId;
+ @NotNull(message = "请选择是否下载空模板")
+ private boolean templateEmpty;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/HandleApprovalRequest.java b/src/main/java/com/xdap/self_development/controller/form/HandleApprovalRequest.java
new file mode 100644
index 0000000..6bf153a
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/HandleApprovalRequest.java
@@ -0,0 +1,16 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class HandleApprovalRequest {
+ @NotBlank(message = "审批表不能为空")
+ private String flowId;
+ @NotBlank(message = "审批人不能为空")
+ private String userId;
+ private String opinion;
+ @NotBlank(message = "审核结果不能为空")
+ private String result; // PASS, REJECT, RETURN
+}
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/controller/form/InsertTemplateForm.java b/src/main/java/com/xdap/self_development/controller/form/InsertTemplateForm.java
new file mode 100644
index 0000000..3be832c
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/InsertTemplateForm.java
@@ -0,0 +1,14 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class InsertTemplateForm {
+ @NotBlank(message = "模板名不能为空")
+ private String templateName;
+
+ @NotBlank(message = "创建者不能为空")
+ private String createBy;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/ParameterForm.java b/src/main/java/com/xdap/self_development/controller/form/ParameterForm.java
new file mode 100644
index 0000000..d2e5878
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/ParameterForm.java
@@ -0,0 +1,38 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class ParameterForm {
+ private Integer parameterNumber;
+
+ @NotBlank(message = "子系统不能为空")
+ private String subsystemName;
+
+ @NotBlank(message = "类型不能为空")
+ private String parameterType;
+
+ @NotBlank(message = "零部件名称不能为空")
+ private String partsName;
+
+ @NotBlank(message = "参数名不能为空")
+ private String parameterName;
+
+ private String unit;
+
+ @NotBlank(message = "参数来源不能为空")
+ private String parameterSource;
+
+ private String numberOrFormula;
+
+ @NotBlank(message = "子部门不能为空")
+ private String department;
+
+ private String remarks;
+
+ @NotNull
+ private String operation;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/ParameterPageForm.java b/src/main/java/com/xdap/self_development/controller/form/ParameterPageForm.java
new file mode 100644
index 0000000..1317277
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/ParameterPageForm.java
@@ -0,0 +1,25 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class ParameterPageForm {
+ @NotBlank(message = "请选择模板")
+ private String templateRowId;
+
+ @NotNull(message = "页码不能为空")
+ @Min(value = 1, message = "页码不能小于1")
+ private Integer pageNumber;
+
+ @NotNull(message = "每页条数不能为空")
+ @Min(value = 1, message = "每页条数不能小于1")
+ private Integer pageSize;
+
+ private String parameterType;
+ private String partsName;
+ private String parameterName;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/ParameterRowIdForm.java b/src/main/java/com/xdap/self_development/controller/form/ParameterRowIdForm.java
new file mode 100644
index 0000000..c5adbf7
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/ParameterRowIdForm.java
@@ -0,0 +1,11 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class ParameterRowIdForm {
+ @NotBlank(message = "请选择参数")
+ private String parameterRowId;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/ResponsiblePersonForm.java b/src/main/java/com/xdap/self_development/controller/form/ResponsiblePersonForm.java
new file mode 100644
index 0000000..f8b47ee
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/ResponsiblePersonForm.java
@@ -0,0 +1,17 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class ResponsiblePersonForm {
+ @NotBlank(message = "部门不能为空")
+ private String departmentId;
+ @NotBlank(message = "用户不能为空")
+ private String userId;
+ @NotBlank(message = "部门名不能为空")
+ private String department;
+ @NotBlank(message = "子部门不能为空")
+ private String subsystem;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/SaveBenchmarkingReportForm.java b/src/main/java/com/xdap/self_development/controller/form/SaveBenchmarkingReportForm.java
new file mode 100644
index 0000000..6d814d2
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/SaveBenchmarkingReportForm.java
@@ -0,0 +1,50 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+@Data
+public class SaveBenchmarkingReportForm {
+ @NotBlank(message = "标题不能为空")
+ private String title;
+ @NotBlank(message = "厂家名称不能为空")
+ private String manufacturerName;
+ @NotBlank(message = "产品型号不能为空")
+ private String modelName;
+ @NotBlank(message = "厂家简称不能为空")
+ private String manufacturerAbbreviation;
+ @NotBlank(message = "产品型号简称不能为空")
+ private String modelAbbreviation;
+ @NotBlank(message = "产品编号不能为空")
+ private String productNumber;
+ @NotBlank(message = "模块不能为空")
+ private String module;
+ @NotBlank(message = "板块不能为空")
+ private String plate;
+ @NotBlank(message = "平台不能为空")
+ private String platform;
+ @NotBlank(message = "系列不能为空")
+ private String series;
+ @NotBlank(message = "细分市场不能为空")
+ private String marketSegment;
+ @NotBlank(message = "项目名称不能为空")
+ private String projectName;
+ @NotBlank(message = "项目编号不能为空")
+ private String projectNumber;
+
+ private String fileUrl;
+
+ @NotEmpty(message = "校对人员不能为空")
+ private List proofreadUsers;
+ @NotEmpty(message = "审核人员不能为空")
+ private List reviewUsers;
+ private List countersignUsers; // 可选
+ @NotEmpty(message = "批准人员不能为空")
+ private List approveUsers;
+ @NotBlank(message = "发起人不能为空")
+ private String createBy;
+ private String explanation;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/StartApprovalRequest.java b/src/main/java/com/xdap/self_development/controller/form/StartApprovalRequest.java
new file mode 100644
index 0000000..e8d80ed
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/StartApprovalRequest.java
@@ -0,0 +1,25 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+@Data
+public class StartApprovalRequest {
+ @NotBlank(message = "请选择审核内容")
+ private String templateRowId;
+ @NotEmpty(message = "校对人员不能为空")
+ private List proofreadUsers;
+ @NotEmpty(message = "审核人员不能为空")
+ private List reviewUsers;
+
+ private List countersignUsers; // 可选
+ @NotEmpty(message = "批准人员不能为空")
+ private List approveUsers;
+
+ @NotBlank(message = "发起人不能为空")
+ private String createBy;
+ private String explanation;
+}
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/controller/form/TemplatePageForm.java b/src/main/java/com/xdap/self_development/controller/form/TemplatePageForm.java
new file mode 100644
index 0000000..4e8b334
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/TemplatePageForm.java
@@ -0,0 +1,19 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class TemplatePageForm {
+ private String templateName;
+
+ @NotNull(message = "页码不能为空")
+ @Min(value = 1, message = "页码不能小于1")
+ private Integer pageNumber;
+
+ @NotNull(message = "每页条数不能为空")
+ @Min(value = 1, message = "每页条数不能小于1")
+ private Integer pageSize;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/TemplateRowIdForm.java b/src/main/java/com/xdap/self_development/controller/form/TemplateRowIdForm.java
new file mode 100644
index 0000000..0c3e313
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/TemplateRowIdForm.java
@@ -0,0 +1,11 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class TemplateRowIdForm {
+ @NotBlank(message = "请选择模板")
+ private String templateRowId;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/TodoResponse.java b/src/main/java/com/xdap/self_development/controller/form/TodoResponse.java
new file mode 100644
index 0000000..9b50264
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/TodoResponse.java
@@ -0,0 +1,14 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import java.sql.Timestamp;
+
+@Data
+public class TodoResponse {
+ private Long flowId;
+ private Long templateId;
+ private String templateName;
+ private String currentNode;
+ private Timestamp createTime;
+}
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/controller/form/UpdateParameterForm.java b/src/main/java/com/xdap/self_development/controller/form/UpdateParameterForm.java
new file mode 100644
index 0000000..ee404c8
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/UpdateParameterForm.java
@@ -0,0 +1,20 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@Data
+public class UpdateParameterForm {
+ @NotBlank(message = "模板不能为空")
+ private String templateRowId;
+ @NotBlank(message = "创建者不能为空")
+ private String createBy;
+ @Valid
+ @NotEmpty(message = "请至少修改一项参数")
+ private List parameterForms;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/UpdateResponsiblePersonForm.java b/src/main/java/com/xdap/self_development/controller/form/UpdateResponsiblePersonForm.java
new file mode 100644
index 0000000..af9be6e
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/UpdateResponsiblePersonForm.java
@@ -0,0 +1,19 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class UpdateResponsiblePersonForm {
+ @NotBlank
+ private String rowId;
+ @NotBlank(message = "部门不能为空")
+ private String departmentId;
+ @NotBlank(message = "用户不能为空")
+ private String userId;
+ @NotBlank(message = "部门名不能为空")
+ private String department;
+ @NotBlank(message = "子部门不能为空")
+ private String subsystem;
+}
diff --git a/src/main/java/com/xdap/self_development/controller/form/UpdateTemplateForm.java b/src/main/java/com/xdap/self_development/controller/form/UpdateTemplateForm.java
new file mode 100644
index 0000000..bbe4c6b
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/controller/form/UpdateTemplateForm.java
@@ -0,0 +1,17 @@
+package com.xdap.self_development.controller.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class UpdateTemplateForm {
+ @NotBlank(message = "模板名不能为空")
+ private String templateName;
+
+ @NotBlank(message = "创建者不能为空")
+ private String createBy;
+
+ @NotBlank(message = "请选择模板")
+ private String templateRowId;
+}
diff --git a/src/main/java/com/xdap/self_development/feign/ApaasMyTokenFeign.java b/src/main/java/com/xdap/self_development/feign/ApaasMyTokenFeign.java
new file mode 100644
index 0000000..985ec09
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/feign/ApaasMyTokenFeign.java
@@ -0,0 +1,14 @@
+package com.xdap.self_development.feign;
+
+import com.xdap.self_development.feign.dto.AppTokenDTO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+@FeignClient(name = "apaas-client", url = "http://apaas-meim.app.yuchai.com/apaas/backend/a5e8e08/ycgf-yf-rddata")
+public interface ApaasMyTokenFeign {
+ @PostMapping("/xdap-open/token")
+ AppTokenDTO token(@RequestParam("grant type") String grant_type,
+ @RequestParam("client id") String client_id,
+ @RequestParam("client secret")String client_secret);
+}
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/feign/dto/AppTokenDTO.java b/src/main/java/com/xdap/self_development/feign/dto/AppTokenDTO.java
new file mode 100644
index 0000000..1c16921
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/feign/dto/AppTokenDTO.java
@@ -0,0 +1,16 @@
+package com.xdap.self_development.feign.dto;
+
+import lombok.Data;
+
+@Data
+public class AppTokenDTO {
+ private String access_token;
+ private String token_type;
+ private Integer expires_in;
+ private String scope;
+ private String tenant_id;
+ private String app_id;
+ private String jti;
+
+}
+
diff --git a/src/main/java/com/xdap/self_development/interceptor/CustomRequestInterceptor.java b/src/main/java/com/xdap/self_development/interceptor/CustomRequestInterceptor.java
new file mode 100644
index 0000000..45d39be
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/interceptor/CustomRequestInterceptor.java
@@ -0,0 +1,51 @@
+package com.xdap.self_development.interceptor;
+
+import com.xdap.api.moudle.user.vo.LoginUserVo;
+import com.xdap.runtime.service.RuntimeAppContextService;
+import com.xdap.runtime.service.RuntimeUserService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Slf4j
+//@Component
+public class CustomRequestInterceptor implements HandlerInterceptor {
+// @Resource
+// private RuntimeAppContextService runtimeAppContextService;
+// @Resource
+// private RuntimeUserService runtimeUserService;
+
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
+ Object handler) throws Exception {
+ log.info("=== 请求开始 ===");
+ log.info("请求URL: {}", request.getRequestURL());
+ log.info("请求方法: {}", request.getMethod());
+ log.info("客户端IP: {}", request.getRemoteAddr());
+
+
+
+ return true; // 返回true表示继续处理
+ }
+
+ @Override
+ public void postHandle(HttpServletRequest request, HttpServletResponse response,
+ Object handler, ModelAndView modelAndView) throws Exception {
+ log.info("=== 请求处理完成,准备渲染视图 ===");
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
+ Object handler, Exception ex) throws Exception {
+ log.info("=== 请求结束 ===");
+ if (ex != null) {
+ log.error("请求处理过程中发生异常: {}", ex.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/listener/SheetDataListener.java b/src/main/java/com/xdap/self_development/listener/SheetDataListener.java
new file mode 100644
index 0000000..d608221
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/listener/SheetDataListener.java
@@ -0,0 +1,68 @@
+package com.xdap.self_development.listener;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.metadata.data.ReadCellData;
+import com.alibaba.excel.read.listener.ReadListener;
+import com.xdap.self_development.pojo.Parameter;
+import com.xdap.self_development.service.TemplateService;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+public class SheetDataListener implements ReadListener {
+ private static final int BATCH_SIZE = 100;
+
+ private final TemplateService templateService;
+ private final String templateRowId;
+ private final String createBy;
+ private List cachedDataList;
+ private String currentSheetName;
+
+ public SheetDataListener(TemplateService templateService,
+ String templateRowId, String createBy) {
+ this.templateService = templateService;
+ this.templateRowId = templateRowId;
+ this.createBy = createBy;
+ this.cachedDataList = new ArrayList<>(BATCH_SIZE);
+ }
+
+ @Override
+ public void invokeHead(Map> headMap, AnalysisContext context) {
+ // 可以在这里处理表头验证
+ currentSheetName = context.readSheetHolder().getSheetName();
+ log.info("开始解析Sheet: {}", currentSheetName);
+ }
+
+ @Override
+ public void invoke(Parameter data, AnalysisContext context) {
+ if (currentSheetName == null) {
+ currentSheetName = context.readSheetHolder().getSheetName();
+ }
+ cachedDataList.add(data);
+
+ // 达到批处理大小时提前处理
+ if (cachedDataList.size() >= BATCH_SIZE) {
+ processBatch(context);
+ }
+ }
+
+ @Override
+ public void doAfterAllAnalysed(AnalysisContext context) {
+ if (!cachedDataList.isEmpty()) {
+ processBatch(context);
+ }
+ }
+
+ private void processBatch(AnalysisContext context) {
+ templateService.processSheetData(
+ new ArrayList<>(cachedDataList),
+ currentSheetName,
+ templateRowId,
+ createBy
+ );
+ cachedDataList.clear();
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/ApprovalFlow.java b/src/main/java/com/xdap/self_development/pojo/ApprovalFlow.java
new file mode 100644
index 0000000..102dfc2
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/ApprovalFlow.java
@@ -0,0 +1,32 @@
+package com.xdap.self_development.pojo;
+
+import com.definesys.mpaas.query.annotation.*;
+import com.definesys.mpaas.query.model.MpaasBasePojo;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Table("yfsjglpt_model_approval_flow")
+public class ApprovalFlow extends MpaasBasePojo {
+ @RowID(sequence = "approval_flow_s", type = RowIDType.UUID)
+ private String id;
+ private String templateId;
+ private String currentNode; // 节点:PROOFREAD, REVIEW, COUNTERSIGN, APPROVE
+ private String flowStatus;
+
+ private String proofreadUsers; // 校对人员
+ private String reviewUsers; // 审核人员
+ private String countersignUsers; // 会签人员
+ private String approveUsers; // 批准人员
+
+ private String createBy;
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Timestamp createdTime;
+ private Integer flowType;
+ private String explanation;
+}
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/pojo/ApprovalRecord.java b/src/main/java/com/xdap/self_development/pojo/ApprovalRecord.java
new file mode 100644
index 0000000..f67ad51
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/ApprovalRecord.java
@@ -0,0 +1,27 @@
+package com.xdap.self_development.pojo;
+
+import com.definesys.mpaas.query.annotation.RowID;
+import com.definesys.mpaas.query.annotation.RowIDType;
+import com.definesys.mpaas.query.annotation.Table;
+import com.definesys.mpaas.query.model.MpaasBasePojo;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.sql.Timestamp;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Table("yfsjglpt_model_approval_record")
+public class ApprovalRecord extends MpaasBasePojo {
+ @RowID(sequence = "approval_record_s", type = RowIDType.UUID)
+ private String id;
+ private String flowId;
+ private String node;
+ private String userId;
+ // 审批说明
+ private String opinion;
+ private String result; // PASS, REJECT
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Timestamp approvalTime;
+}
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/pojo/ApprovalXdapUsers.java b/src/main/java/com/xdap/self_development/pojo/ApprovalXdapUsers.java
new file mode 100644
index 0000000..a61869f
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/ApprovalXdapUsers.java
@@ -0,0 +1,16 @@
+package com.xdap.self_development.pojo;
+
+import com.definesys.mpaas.query.annotation.SQL;
+import com.definesys.mpaas.query.annotation.SQLQuery;
+import com.definesys.mpaas.query.annotation.Table;
+import com.xdap.api.moudle.base.entity.NoTenBasePojo;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Table("xdap_users")
+@Data
+public class ApprovalXdapUsers extends NoTenBasePojo {
+ private String id;
+ private String username;
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/BenchmarkingReport.java b/src/main/java/com/xdap/self_development/pojo/BenchmarkingReport.java
new file mode 100644
index 0000000..692d68f
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/BenchmarkingReport.java
@@ -0,0 +1,39 @@
+package com.xdap.self_development.pojo;
+
+import com.definesys.mpaas.query.annotation.*;
+import com.definesys.mpaas.query.model.MpaasBasePojo;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.sql.Timestamp;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Table("yfsjglpt_model_benchmarking_report")
+@NoArgsConstructor
+public class BenchmarkingReport extends MpaasBasePojo {
+ @RowID(sequence = "benchmarking_report_s", type = RowIDType.UUID)
+ private String id;
+
+ private String title;
+ private String manufacturerName;
+ private String modelName;
+ private String module;
+ private String manufacturerAbbreviation;
+ private String modelAbbreviation;
+ private String productNumber;
+ private String plate;
+ private String platform;
+ private String series;
+ private String marketSegment;
+ private String projectName;
+ private String projectNumber;
+ private String createBy;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Timestamp uploadTime;
+ private String filePath;
+ private String status;
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/Parameter.java b/src/main/java/com/xdap/self_development/pojo/Parameter.java
new file mode 100644
index 0000000..b419c7e
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/Parameter.java
@@ -0,0 +1,63 @@
+package com.xdap.self_development.pojo;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.definesys.mpaas.query.annotation.*;
+import com.definesys.mpaas.query.model.MpaasBasePojo;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+@SQLQuery(value = {
+ @SQL(view = "selectParametersByTemplateId", sql =
+ "select p.* from yfsjglpt_model_parameter p left join yfsjglpt_model_parameter_and_template tap on p.id = tap.parameter_id where tap.template_id = #templateId"),
+ @SQL(view = "selectMaxNumber", sql =
+ "SELECT max(parameter_number) AS max_number FROM yfsjglpt_model_parameter p LEFT JOIN yfsjglpt_model_parameter_and_template tap ON p.id = tap.parameter_id WHERE tap.template_id = #templateId")
+})
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Table("yfsjglpt_model_parameter")
+@NoArgsConstructor
+public class Parameter extends MpaasBasePojo {
+ @RowID(sequence = "parameter_s", type = RowIDType.UUID)
+ private String id;
+ @ExcelProperty("序号")
+ private Integer parameterNumber;
+ @ExcelProperty("子系统")
+ private String subsystemName;
+ @ExcelProperty("类型")
+ private String parameterType;
+ @ExcelProperty("零部件名称")
+ private String partsName;
+ @ExcelProperty("参数名称")
+ private String parameterName;
+ @ExcelProperty("单位")
+ private String unit;
+ @ExcelProperty("参数计划来源")
+ private String parameterSource;
+ @ExcelProperty("当前可适用的分类属性表编号(需要修订)或公式")
+ private String numberOrFormula;
+ @ExcelProperty("填写部门")
+ private String department;
+ @ExcelProperty("备注")
+ private String remarks;
+
+ @ExcelIgnore
+ @Column(value = "max_number",type=ColumnType.CALCULATE)
+ private Integer maxNumber;
+
+ public Parameter(Integer parameterNumber, String subsystemName, String parameterType,
+ String partsName, String parameterName, String unit, String parameterSource,
+ String numberOrFormula, String department, String remarks) {
+ this.parameterNumber = parameterNumber;
+ this.subsystemName = subsystemName;
+ this.parameterType = parameterType;
+ this.partsName = partsName;
+ this.parameterName = parameterName;
+ this.unit = unit;
+ this.parameterSource = parameterSource;
+ this.numberOrFormula = numberOrFormula;
+ this.department = department;
+ this.remarks = remarks;
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/ResponsiblePerson.java b/src/main/java/com/xdap/self_development/pojo/ResponsiblePerson.java
new file mode 100644
index 0000000..066d9a2
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/ResponsiblePerson.java
@@ -0,0 +1,25 @@
+package com.xdap.self_development.pojo;
+
+import com.definesys.mpaas.query.annotation.*;
+import com.definesys.mpaas.query.model.MpaasBasePojo;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Table("yfsjglpt_model_responsible_person")
+@SQLQuery(value = {
+ @SQL(view = "getResponsibleAndName",
+ sql = "SELECT ymrp.*, xu.username FROM yfsjglpt_model_responsible_person ymrp JOIN xdap_users xu ON ymrp.user_id = xu.id")
+})
+public class ResponsiblePerson extends MpaasBasePojo {
+ @RowID(sequence = "responsible_person_s", type = RowIDType.UUID)
+ private String id;
+ private String departmentId;
+ private String userId;
+ private String department;
+ private String subsystem;
+
+ @Column(type = ColumnType.CALCULATE)
+ private String username;
+}
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/pojo/RevisionRecord.java b/src/main/java/com/xdap/self_development/pojo/RevisionRecord.java
new file mode 100644
index 0000000..41ee16c
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/RevisionRecord.java
@@ -0,0 +1,33 @@
+package com.xdap.self_development.pojo;
+
+import com.definesys.mpaas.query.annotation.RowID;
+import com.definesys.mpaas.query.annotation.RowIDType;
+import com.definesys.mpaas.query.annotation.Table;
+import com.definesys.mpaas.query.model.MpaasBasePojo;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@NoArgsConstructor
+@Table("yfsjglpt_model_revision_record")
+public class RevisionRecord extends MpaasBasePojo {
+ @RowID(sequence = "revision_record_s", type = RowIDType.UUID)
+ private String id;
+ private String templateName;
+ private Integer version;
+ private Integer parameterNumber;
+ private String modifyDetails;
+ private String templateId;
+ private String preTemplateId;
+
+ public RevisionRecord(String templateName, Integer version, Integer parameterNumber, String modifyDetails, String templateId, String preTemplateId) {
+ this.templateName = templateName;
+ this.version = version;
+ this.parameterNumber = parameterNumber;
+ this.modifyDetails = modifyDetails;
+ this.templateId = templateId;
+ this.preTemplateId = preTemplateId;
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/Template.java b/src/main/java/com/xdap/self_development/pojo/Template.java
new file mode 100644
index 0000000..f1b8f16
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/Template.java
@@ -0,0 +1,44 @@
+package com.xdap.self_development.pojo;
+
+import com.definesys.mpaas.query.annotation.*;
+import com.definesys.mpaas.query.model.MpaasBasePojo;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.sql.Timestamp;
+
+@SQLQuery(value = {
+ @SQL(view = "getLatestTemplate",
+ sql = "SELECT * FROM ( SELECT t.*, ROW_NUMBER() OVER (PARTITION BY template_name ORDER BY CASE WHEN status = 'COMPLETE' THEN 1 WHEN status = 'DRAFT' THEN 2 ELSE 3 END, version DESC) AS rn FROM yfsjglpt_model_template t WHERE status IN ('COMPLETE', 'DRAFT') ) ranked WHERE rn = 1"
+ ),
+ @SQL(view = "getNewTemplate",
+ sql = "SELECT t.* FROM yfsjglpt_model_template t JOIN ( SELECT template_name, MAX(version) AS latest_version FROM yfsjglpt_model_template GROUP BY template_name ) latest_template ON t.template_name = latest_template.template_name AND t.version = latest_template.latest_version")
+})
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Table("yfsjglpt_model_template")
+@NoArgsConstructor
+public class Template extends MpaasBasePojo {
+ @RowID(sequence = "template_s", type = RowIDType.UUID)
+ private String id;
+ private String templateName;
+ private Integer version;
+ //DRAFT(草稿)、APPROVING(审批中)、COMPLETE(已完成)、RETURNED(已撤回)、REJECTED(已拒绝)
+ private String status;
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Timestamp createdTime;
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Timestamp publishedTime;
+ private String createBy;
+
+ public Template(String templateName, Integer version, String status, Timestamp createdTime, Timestamp publishedTime, String createBy) {
+ this.templateName = templateName;
+ this.version = version;
+ this.status = status;
+ this.createdTime = createdTime;
+ this.publishedTime = publishedTime;
+ this.createBy = createBy;
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/TemplateAndParameter.java b/src/main/java/com/xdap/self_development/pojo/TemplateAndParameter.java
new file mode 100644
index 0000000..44a3ac4
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/TemplateAndParameter.java
@@ -0,0 +1,18 @@
+package com.xdap.self_development.pojo;
+
+import com.definesys.mpaas.query.annotation.RowID;
+import com.definesys.mpaas.query.annotation.RowIDType;
+import com.definesys.mpaas.query.annotation.Table;
+import com.definesys.mpaas.query.model.MpaasBasePojo;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Table("yfsjglpt_model_parameter_and_template")
+public class TemplateAndParameter extends MpaasBasePojo {
+ @RowID(sequence = "template_and_parameter_s", type = RowIDType.UUID)
+ private String id;
+ private String templateId;
+ private String parameterId;
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/view/ApprovalFlowView.java b/src/main/java/com/xdap/self_development/pojo/view/ApprovalFlowView.java
new file mode 100644
index 0000000..c02ac4c
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/view/ApprovalFlowView.java
@@ -0,0 +1,17 @@
+package com.xdap.self_development.pojo.view;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ApprovalFlowView {
+ private String explanation;
+
+ private List proofreadNodes;
+ private List reviewNodes;
+ private List countersignNodes;
+ private List approveNodes;
+
+ private String flowStatus;
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/view/ApprovalNodeView.java b/src/main/java/com/xdap/self_development/pojo/view/ApprovalNodeView.java
new file mode 100644
index 0000000..f10fa97
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/view/ApprovalNodeView.java
@@ -0,0 +1,23 @@
+package com.xdap.self_development.pojo.view;
+
+import com.definesys.mpaas.query.annotation.SQL;
+import com.definesys.mpaas.query.annotation.SQLQuery;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.sql.Timestamp;
+
+@SQLQuery(value = {
+ @SQL(view = "getApprovalNodeInfo",
+ sql = "SELECT * FROM yfsjglpt_model_approval_record WHERE flow_id = #flowId AND node = #node")
+})
+@Data
+public class ApprovalNodeView {
+ private String node;
+ private String userId;
+ private String userName;
+ private String opinion;
+ private String result; // PASS, REJECT
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Timestamp approvalTime;
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/view/CalculationParameterView.java b/src/main/java/com/xdap/self_development/pojo/view/CalculationParameterView.java
new file mode 100644
index 0000000..94a669c
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/view/CalculationParameterView.java
@@ -0,0 +1,20 @@
+package com.xdap.self_development.pojo.view;
+
+import com.definesys.mpaas.query.annotation.SQL;
+import com.definesys.mpaas.query.annotation.SQLQuery;
+import lombok.Data;
+
+@SQLQuery(value = {
+ @SQL(view = "getModelParameterValue",
+ sql = "SELECT epd.id AS \"id\", deem.id AS \"modelId\", ymp.parameter_name AS \"parameterName\", ymp.id AS \"parameterId\", epd.parameter_value AS \"parameterValue\", ymp.parameter_source AS \"parameterSource\", ymp.number_or_formula AS \"numberOrFormula\" FROM data_entry_engine_model deem JOIN engine_param_detail epd ON epd.engine_model_id = deem.id JOIN yfsjglpt_model_parameter ymp ON ymp.id = epd.parameter_id")
+})
+@Data
+public class CalculationParameterView {
+ private String id;
+ private String modelId;
+ private String parameterId;
+ private String parameterName;
+ private String parameterValue;
+ private String parameterSource;
+ private String numberOrFormula;
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/view/DepartmentUserView.java b/src/main/java/com/xdap/self_development/pojo/view/DepartmentUserView.java
new file mode 100644
index 0000000..8a527c2
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/view/DepartmentUserView.java
@@ -0,0 +1,21 @@
+package com.xdap.self_development.pojo.view;
+
+import com.definesys.mpaas.query.annotation.SQL;
+import com.definesys.mpaas.query.annotation.SQLQuery;
+import lombok.Data;
+
+@SQLQuery(value = {
+ @SQL(view = "getUserByDepartment",
+ sql = "SELECT u.id AS \"userId\", u.username AS \"username\", u.user_number AS \"userNumber\", d.id AS \"departmentId\", d.name AS \"department\" FROM xdap_users u LEFT JOIN xdap_dept_users du ON du.user_id = u.id LEFT JOIN xdap_departments d ON d.id = du.department_id WHERE u.exit_status = 'ENABLE' and d.id = #departmentId"),
+ @SQL(view = "getUserAndDept",
+ sql = "SELECT u.id AS \"userId\", u.username AS \"username\", d.name AS \"department\" FROM xdap_users u LEFT JOIN xdap_dept_users du ON u.id = du.user_id LEFT JOIN xdap_departments d ON d.id = du.department_id")
+
+})
+@Data
+public class DepartmentUserView {
+ private String userId;
+ private String username;
+ private String userNumber;
+ private String departmentId;
+ private String department;
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/view/TemplateChangeView.java b/src/main/java/com/xdap/self_development/pojo/view/TemplateChangeView.java
new file mode 100644
index 0000000..758631c
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/view/TemplateChangeView.java
@@ -0,0 +1,27 @@
+package com.xdap.self_development.pojo.view;
+
+import com.definesys.mpaas.query.annotation.SQL;
+import com.definesys.mpaas.query.annotation.SQLQuery;
+import lombok.Data;
+
+@SQLQuery(value = {
+ @SQL(view = "getParameterAndChange",
+ sql = "SELECT p.*, r.modify_details FROM yfsjglpt_model_parameter_and_template tap INNER JOIN yfsjglpt_model_parameter p ON tap.parameter_id = p.id LEFT JOIN yfsjglpt_model_revision_record r ON tap.template_id = r.template_id AND p.parameter_number = r.parameter_number WHERE tap.template_id = #templateId ORDER BY p.parameter_number")
+})
+@Data
+public class TemplateChangeView {
+ private Integer parameterNumber;
+ private String subsystemName;
+ private String parameterType;
+ private String partsName;
+ private String parameterName;
+ private String unit;
+ private String parameterSource;
+ private String numberOrFormula;
+ private String department;
+ private String remarks;
+
+ private String modifyDetails;
+
+ private String preTemplateId;
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/view/TemplateInfoView.java b/src/main/java/com/xdap/self_development/pojo/view/TemplateInfoView.java
new file mode 100644
index 0000000..0126543
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/view/TemplateInfoView.java
@@ -0,0 +1,9 @@
+package com.xdap.self_development.pojo.view;
+
+import lombok.Data;
+
+@Data
+public class TemplateInfoView {
+ private String templateRowId;
+ private Integer version;
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/view/TodoAndReportView.java b/src/main/java/com/xdap/self_development/pojo/view/TodoAndReportView.java
new file mode 100644
index 0000000..a3b75d3
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/view/TodoAndReportView.java
@@ -0,0 +1,39 @@
+package com.xdap.self_development.pojo.view;
+
+import com.definesys.mpaas.query.annotation.SQL;
+import com.definesys.mpaas.query.annotation.SQLQuery;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.sql.Timestamp;
+
+@SQLQuery(value = {
+ @SQL(view = "getReportByUserIdAndIds",
+ sql = "SELECT br.id AS \"reportId\", af.id AS \"flowId\", br.* FROM yfsjglpt_model_approval_flow af JOIN yfsjglpt_model_benchmarking_report br ON af.template_id = br.id WHERE br.title like CONCAT('%', #title, '%') and br.manufacturer_name like CONCAT('%', #manufacturerName, '%') and br.model_name like CONCAT('%', #modelName, '%') and br.product_number like CONCAT('%', #productNumber, '%') and br.module like CONCAT('%', #module, '%') and br.plate like CONCAT('%', #plate, '%') and br.platform like CONCAT('%', #platform, '%') and br.series like CONCAT('%', #series, '%') and br.market_segment like CONCAT('%', #marketSegment, '%') and br.project_name like CONCAT('%', #projectName, '%') and br.project_number like CONCAT('%', #projectNumber, '%') and br.status like CONCAT('%', #status, '%') and af.flow_type = 2 AND af.id NOT IN (#ids) AND af.create_by = #createBy"),
+ @SQL(view = "getTodoAndReport",
+ sql = "SELECT br.id AS \"reportId\", af.id AS \"flowId\", br.* FROM yfsjglpt_model_approval_flow af JOIN yfsjglpt_model_benchmarking_report br ON af.template_id = br.id WHERE br.title like CONCAT('%', #title, '%') and br.manufacturer_name like CONCAT('%', #manufacturerName, '%') and br.model_name like CONCAT('%', #modelName, '%') and br.product_number like CONCAT('%', #productNumber, '%') and br.module like CONCAT('%', #module, '%') and br.plate like CONCAT('%', #plate, '%') and br.platform like CONCAT('%', #platform, '%') and br.series like CONCAT('%', #series, '%') and br.market_segment like CONCAT('%', #marketSegment, '%') and br.project_name like CONCAT('%', #projectName, '%') and br.project_number like CONCAT('%', #projectNumber, '%') and br.status like CONCAT('%', #status, '%') and af.flow_type = 2 AND af.id IN (#ids)")
+})
+@Data
+public class TodoAndReportView {
+ private String reportId;
+ private String flowId;
+
+ private String title;
+ private String manufacturerName;
+ private String modelName;
+ private String module;
+ private String manufacturerAbbreviation;
+ private String modelAbbreviation;
+ private String productNumber;
+ private String plate;
+ private String platform;
+ private String series;
+ private String marketSegment;
+ private String projectName;
+ private String projectNumber;
+ private String createBy;
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Timestamp uploadTime;
+ private String filePath;
+ private String status;
+}
diff --git a/src/main/java/com/xdap/self_development/pojo/view/TodoAndTemplateView.java b/src/main/java/com/xdap/self_development/pojo/view/TodoAndTemplateView.java
new file mode 100644
index 0000000..f6ccb2d
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/pojo/view/TodoAndTemplateView.java
@@ -0,0 +1,30 @@
+package com.xdap.self_development.pojo.view;
+
+import com.definesys.mpaas.query.annotation.SQL;
+import com.definesys.mpaas.query.annotation.SQLQuery;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.xdap.self_development.pojo.ApprovalXdapUsers;
+import lombok.Data;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+@SQLQuery(value = {
+ @SQL(view = "getApprovalByUserIdAndIds",
+ sql = "SELECT af.id AS \"flowId\", t.id AS \"templateId\", t.template_name AS \"templateName\", t.version AS \"version\", t.status AS \"status\" , af.create_by AS \"createBy\", af.created_time AS \"createdTime\" , CASE WHEN current_node = 'PROOFREAD' THEN proofread_users WHEN current_node = 'REVIEW' THEN review_users WHEN current_node = 'COUNTERSIGN' THEN countersign_users WHEN current_node = 'APPROVE' THEN approve_users END AS current_users FROM yfsjglpt_model_approval_flow af JOIN yfsjglpt_model_template t ON af.template_id = t.id WHERE t.template_name like CONCAT('%',#templateName, '%') and t.status like CONCAT('%',#status, '%') and af.flow_type = 1 and af.id NOT IN (#ids) AND af.create_by = #createBy"),
+ @SQL(view = "getTodoAndTemplate",
+ sql = "SELECT af.id AS \"flowId\", t.id AS \"templateId\", t.template_name AS \"templateName\", t.version AS \"version\", t.status AS \"status\" , af.create_by AS \"createBy\", af.created_time AS \"createdTime\" , CASE WHEN current_node = 'PROOFREAD' THEN proofread_users WHEN current_node = 'REVIEW' THEN review_users WHEN current_node = 'COUNTERSIGN' THEN countersign_users WHEN current_node = 'APPROVE' THEN approve_users END AS current_users FROM yfsjglpt_model_approval_flow af JOIN yfsjglpt_model_template t ON af.template_id = t.id WHERE t.template_name like CONCAT('%',#templateName, '%') and t.status like CONCAT('%',#status, '%') and af.flow_type = 1 and af.id IN (#ids)")
+})
+@Data
+public class TodoAndTemplateView {
+ private String templateId;
+ private String flowId;
+ private String templateName;
+ private String version;
+ private String status;
+ private String createBy;
+ private String currentUsers;
+ private List currentApprovers;
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Timestamp createdTime;
+}
diff --git a/src/main/java/com/xdap/self_development/schedule/ModifiedTodoTimer.java b/src/main/java/com/xdap/self_development/schedule/ModifiedTodoTimer.java
new file mode 100644
index 0000000..f6f6c77
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/schedule/ModifiedTodoTimer.java
@@ -0,0 +1,100 @@
+package com.xdap.self_development.schedule;
+
+import com.alibaba.fastjson2.JSON;
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.xdap.self_development.config.BusinessDatabase;
+import com.xdap.self_development.pojo.ApprovalFlow;
+import com.xdap.self_development.pojo.ApprovalRecord;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+@Transactional(rollbackFor = MpaasBusinessException.class)
+public class ModifiedTodoTimer {
+ @Resource
+ private BusinessDatabase bd;
+ @Autowired
+ private StringRedisTemplate redisTemplate;
+ private static final String TODO_PREFIX = "approval:todo:";
+ private static final String TODO_PREFIX_2 = "report:todo:";
+
+ private static final String NODE_PROCESSED_PREFIX = "approval:node:processed:";
+ private static final String NODE_PROCESSED_PREFIX_2 = "report:node:processed:";
+
+// @Scheduled(cron = "0 */1 * * * *")
+ public void modifiedTodo() {
+ // 获取审批中的所有流程
+ List flows1 = bd.getBusinessDatabase()
+ .eq("flow_status", "APPROVING")
+ .eq("flow_type", 1)
+ .doQuery(ApprovalFlow.class);
+ checkFlows(flows1, TODO_PREFIX, NODE_PROCESSED_PREFIX);
+
+ List flows2 = bd.getBusinessDatabase()
+ .eq("flow_status", "APPROVING")
+ .eq("flow_type", 2)
+ .doQuery(ApprovalFlow.class);
+ checkFlows(flows2, TODO_PREFIX_2, NODE_PROCESSED_PREFIX_2);
+ }
+
+ // 检查流程
+ private void checkFlows(List flows, String todoFlag, String prefixFlag) {
+ // 遍历每一个流程
+ flows.forEach(flow -> {
+ List nodeUsers = getNodeUsers(flow, flow.getCurrentNode());
+ List records = bd.getBusinessDatabase()
+ .eq("flow_id", flow.getId())
+ .eq("node", flow.getCurrentNode())
+ .doQuery(ApprovalRecord.class)
+ .stream().map(ApprovalRecord::getUserId)
+ .collect(Collectors.toList());
+
+ if (Objects.equals(flow.getCurrentNode(), "COUNTERSIGN")) {
+ log.info("{}审批流,的COUNTERSIGN的已完成的人:{}", flow.getId(), records);
+ records.forEach(record -> {
+ Boolean isMember = redisTemplate.opsForSet()
+ .isMember(prefixFlag + flow.getId() + ":" + flow.getCurrentNode(), record);
+ if (Boolean.FALSE.equals(isMember)) {
+ redisTemplate.opsForSet().add(prefixFlag + flow.getId() + ":" + flow.getCurrentNode(), record);
+ }
+ });
+ }
+
+ // 未完成当前节点审批任务的人
+ List collected = nodeUsers.stream()
+ .filter(element -> !records.contains(element))
+ .collect(Collectors.toList());
+
+ collected.forEach(element -> {
+ // 检查redis是否存在该待办节点
+ Boolean isMember = redisTemplate.opsForSet().isMember(todoFlag + element, flow.getId());
+ log.info("{}{} is member: {}", todoFlag + element, flow.getId(), isMember);
+ if (Boolean.FALSE.equals(isMember)) {
+ redisTemplate.opsForSet().add(todoFlag + element, flow.getId());
+ log.info("{}{} is added", todoFlag, element);
+ }
+ });
+ });
+ }
+
+ private List getNodeUsers(ApprovalFlow flow, String node) {
+ switch (node) {
+ case "PROOFREAD": return JSON.parseArray(flow.getProofreadUsers()).toJavaList(String.class);
+ case "REVIEW": return JSON.parseArray(flow.getReviewUsers()).toJavaList(String.class);
+ case "COUNTERSIGN": return JSON.parseArray(flow.getCountersignUsers()).toJavaList(String.class);
+ case "APPROVE": return JSON.parseArray(flow.getApproveUsers()).toJavaList(String.class);
+ default: return Collections.emptyList();
+ }
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/schedule/ParameterValueCalculationTimer.java b/src/main/java/com/xdap/self_development/schedule/ParameterValueCalculationTimer.java
new file mode 100644
index 0000000..df5fd62
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/schedule/ParameterValueCalculationTimer.java
@@ -0,0 +1,171 @@
+package com.xdap.self_development.schedule;
+
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.xdap.self_development.config.BusinessDatabase;
+import com.xdap.self_development.pojo.view.CalculationParameterView;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import java.time.LocalDate;
+import java.util.*;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+@Transactional(rollbackFor = MpaasBusinessException.class)
+public class ParameterValueCalculationTimer {
+ @Resource
+ private BusinessDatabase bd;
+// @Scheduled(cron = "0 0 0 * * ?")
+// @Scheduled(cron = "0 */1 * * * *")
+ public void dailyCalculate() {
+ LocalDate today = LocalDate.now();
+ log.info("开始执行{}参数计算任务", today);
+ // 查询所有参数配置
+ List parameterValues = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("getModelParameterValue")
+ .doQuery(CalculationParameterView.class);
+ if (parameterValues.isEmpty()) {
+ log.info("无参数配置,跳过计算");
+ return;
+ }
+ // 维护所有参数的原始值
+ Map> originalValueMap = convertMap(parameterValues);
+ // 构建参数名列表,按长度降序排列
+ List parameterNames = originalValueMap.keySet().stream()
+ .sorted((a, b) -> Integer.compare(b.length(), a.length()))
+ .collect(Collectors.toList());
+ // 遍历参数,计算需运算的参数值
+ List toUpdate = new ArrayList<>();
+ for (CalculationParameterView parameterValue : parameterValues) {
+ if (Objects.equals(parameterValue.getParameterSource(), "公式计算")) {
+ String formula = parameterValue.getNumberOrFormula();
+ String modelId = parameterValue.getModelId();
+
+ try {
+ log.info("原始公式:{}", formula);
+ String replacedFormula = replaceParametersInFormula(formula, parameterNames, originalValueMap, modelId);
+ log.info("替换后公式:{}", replacedFormula);
+ Double result = calculateExpression(replacedFormula);
+ String formattedResult = String.format("%.6f", result);
+ log.info("计算结果:{}", formattedResult);
+ parameterValue.setParameterValue(formattedResult);
+ toUpdate.add(parameterValue);
+ log.info("参数【{}】计算结果:{}", parameterValue.getParameterName(), formattedResult);
+
+ } catch (Exception e) {
+ log.error("参数【{}】计算失败:{},公式:{},模型ID:{}",
+ parameterValue.getParameterName(), e.getMessage(), formula, modelId);
+ throw new RuntimeException("参数【" + parameterValue.getParameterName() + "】计算失败:" + e.getMessage());
+ }
+ }
+ }
+
+ // 批量插入或更新计算结果
+ if (!toUpdate.isEmpty()) {
+ toUpdate.forEach(parameterValue -> {
+ bd.getBusinessDatabase()
+ .table("engine_param_detail")
+ .eq("id", parameterValue.getId())
+ .update("parameter_value", parameterValue.getParameterValue())
+ .doUpdate();
+ });
+ }
+ log.info("{}参数计算完成,共处理{}个参数", today, toUpdate.size());
+ }
+
+ private String replaceParametersInFormula(String formula, List parameterNames,
+ Map> valueMap, String modelId) {
+ String result = formula;
+ result = result.replace("π", "PI").replace("PI", "Math.PI");
+ result = result.replace("e", "Math.E");
+ for (String paramName : parameterNames) {
+ String pattern = "\\b" + Pattern.quote(paramName) + "\\b";
+ String value = getParameterValue(valueMap, paramName, modelId);
+ result = result.replaceAll(pattern, value);
+ }
+
+ return result;
+ }
+
+ private String getParameterValue(Map> valueMap, String paramName, String modelId) {
+ Map modelValues = valueMap.get(paramName);
+ if (modelValues != null) {
+ String value = modelValues.get(modelId);
+ if (value != null && !value.trim().isEmpty()) {
+ return value;
+ }
+ }
+ return "0";
+ }
+
+ private Double calculateExpression(String expression) {
+
+ Double result = calculateWithScriptEngine(expression);
+ if (result != null) {
+ return result;
+ }
+
+ throw new RuntimeException("无法计算表达式: " + expression);
+ }
+
+ private Double calculateWithScriptEngine(String expression) {
+ try {
+ ScriptEngineManager manager = new ScriptEngineManager();
+ ScriptEngine engine = manager.getEngineByName("JavaScript");
+ if (!isSafeExpression(expression)) {
+ throw new SecurityException("表达式包含不安全内容");
+ }
+ Object result = engine.eval(expression);
+ if (result instanceof Number) {
+ return ((Number) result).doubleValue();
+ }
+ return null;
+ } catch (Exception e) {
+ log.warn("ScriptEngine计算失败: {}, 错误: {}", expression, e.getMessage());
+ return null;
+ }
+ }
+
+ private boolean isSafeExpression(String expression) {
+ // 允许的字符:数字、基本运算符、括号、数学常量和函数
+ String safePattern = "^[0-9+\\-*/().\\sMathPIEsincostanlogsqrtabs]*$";
+ if (!expression.matches(safePattern)) {
+ return false;
+ }
+ String[] dangerousKeywords = {"java", "class", "runtime", "exec", "system", "process", "file"};
+ for (String keyword : dangerousKeywords) {
+ if (expression.toLowerCase().contains(keyword)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static Map> convertMap(List list) {
+ if (list == null) {
+ return new HashMap<>();
+ }
+
+ return list.stream()
+ .filter(Objects::nonNull)
+ .filter(item -> item.getParameterName() != null)
+ .filter(item -> item.getModelId() != null)
+ .collect(Collectors.groupingBy(
+ CalculationParameterView::getParameterName,
+ Collectors.toMap(
+ CalculationParameterView::getModelId,
+ item -> item.getParameterValue() != null ? item.getParameterValue() : "0",
+ (existing, replacement) -> replacement
+ )
+ ));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/service/BenchmarkingReportService.java b/src/main/java/com/xdap/self_development/service/BenchmarkingReportService.java
new file mode 100644
index 0000000..256b19a
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/service/BenchmarkingReportService.java
@@ -0,0 +1,24 @@
+package com.xdap.self_development.service;
+
+import com.xdap.self_development.controller.form.BenchmarkingReportPageForm;
+import com.xdap.self_development.controller.form.HandleApprovalRequest;
+import com.xdap.self_development.controller.form.SaveBenchmarkingReportForm;
+import com.xdap.self_development.pojo.BenchmarkingReport;
+import com.xdap.self_development.pojo.view.ApprovalFlowView;
+import com.xdap.self_development.pojo.view.TodoAndReportView;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import java.util.List;
+
+public interface BenchmarkingReportService {
+ List getBenchmarkingReportByCondition(@Valid BenchmarkingReportPageForm form);
+
+ void saveBenchmarkingReport(@Valid SaveBenchmarkingReportForm form);
+
+ void handleReportApproval(@Valid HandleApprovalRequest request);
+
+ BenchmarkingReport getReportDetail(@NotBlank String reportId);
+
+ ApprovalFlowView getReportProcess(@NotBlank String flowId);
+}
diff --git a/src/main/java/com/xdap/self_development/service/ParameterService.java b/src/main/java/com/xdap/self_development/service/ParameterService.java
new file mode 100644
index 0000000..7ceb553
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/service/ParameterService.java
@@ -0,0 +1,15 @@
+package com.xdap.self_development.service;
+
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.self_development.controller.form.ParameterPageForm;
+import com.xdap.self_development.controller.form.TemplateRowIdForm;
+import com.xdap.self_development.controller.form.UpdateParameterForm;
+import com.xdap.self_development.pojo.Parameter;
+import com.xdap.self_development.pojo.view.TemplateInfoView;
+
+public interface ParameterService {
+ PageQueryResult getParameterByCondition(ParameterPageForm form);
+
+ TemplateInfoView maintenanceParameters(UpdateParameterForm form);
+
+}
diff --git a/src/main/java/com/xdap/self_development/service/ResponsiblePersonService.java b/src/main/java/com/xdap/self_development/service/ResponsiblePersonService.java
new file mode 100644
index 0000000..318e715
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/service/ResponsiblePersonService.java
@@ -0,0 +1,27 @@
+package com.xdap.self_development.service;
+
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.self_development.controller.form.DeptResponsiblePageForm;
+import com.xdap.self_development.controller.form.ResponsiblePersonForm;
+import com.xdap.self_development.controller.form.UpdateResponsiblePersonForm;
+import com.xdap.self_development.pojo.ResponsiblePerson;
+import com.xdap.self_development.pojo.Template;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import java.util.List;
+import java.util.Set;
+
+public interface ResponsiblePersonService {
+ void saveResponsiblePerson(@Valid ResponsiblePersonForm form);
+
+ void updateResponsiblePerson(@Valid UpdateResponsiblePersonForm form);
+
+ void deleteResponsiblePerson(@NotBlank String rowId);
+
+ PageQueryResult getDeptResponsible(@Valid DeptResponsiblePageForm form);
+
+ Boolean isResponsiblePerson(String userId);
+
+ Set getAllSubsystem();
+}
diff --git a/src/main/java/com/xdap/self_development/service/TemplateApprovalService.java b/src/main/java/com/xdap/self_development/service/TemplateApprovalService.java
new file mode 100644
index 0000000..02766a0
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/service/TemplateApprovalService.java
@@ -0,0 +1,18 @@
+package com.xdap.self_development.service;
+
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.self_development.controller.form.*;
+import com.xdap.self_development.pojo.view.ApprovalFlowView;
+import com.xdap.self_development.pojo.view.TemplateChangeView;
+import com.xdap.self_development.pojo.view.TodoAndTemplateView;
+
+import javax.validation.Valid;
+import java.util.List;
+
+public interface TemplateApprovalService {
+ String startApproval(StartApprovalRequest request);
+ List getApprovalList(ApprovalListForm form);
+ void handleApproval(HandleApprovalRequest request);
+ PageQueryResult getTemplateChanges(@Valid ApprovalAndParameterForm form);
+ ApprovalFlowView getApprovalProcess(@Valid ApprovalFlowForm form);
+}
diff --git a/src/main/java/com/xdap/self_development/service/TemplateService.java b/src/main/java/com/xdap/self_development/service/TemplateService.java
new file mode 100644
index 0000000..1f59a65
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/service/TemplateService.java
@@ -0,0 +1,27 @@
+package com.xdap.self_development.service;
+
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.self_development.controller.form.*;
+import com.xdap.self_development.pojo.Parameter;
+import com.xdap.self_development.pojo.Template;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+public interface TemplateService {
+ PageQueryResult getTemplateByCondition(TemplatePageForm form);
+
+ void importTemplate(MultipartFile file, String templateRowId, String createBy);
+
+ void processSheetData(List dataList, String sheetName,
+ String templateRowId, String createBy);
+
+ void insertTemplate(InsertTemplateForm form);
+
+ void updateTemplate(UpdateTemplateForm form);
+
+ void exportTemplate(ExportTemplateForm form, HttpServletResponse response);
+
+ List getTemplateVersion(TemplateRowIdForm form);
+}
diff --git a/src/main/java/com/xdap/self_development/service/impl/BenchmarkingReportServiceImpl.java b/src/main/java/com/xdap/self_development/service/impl/BenchmarkingReportServiceImpl.java
new file mode 100644
index 0000000..5de956f
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/service/impl/BenchmarkingReportServiceImpl.java
@@ -0,0 +1,410 @@
+package com.xdap.self_development.service.impl;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson2.JSON;
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.xdap.runtime.service.RuntimeAppContextService;
+import com.xdap.self_development.config.BusinessDatabase;
+import com.xdap.self_development.controller.form.BenchmarkingReportPageForm;
+import com.xdap.self_development.controller.form.HandleApprovalRequest;
+import com.xdap.self_development.controller.form.SaveBenchmarkingReportForm;
+import com.xdap.self_development.pojo.ApprovalFlow;
+import com.xdap.self_development.pojo.ApprovalRecord;
+import com.xdap.self_development.pojo.ApprovalXdapUsers;
+import com.xdap.self_development.pojo.BenchmarkingReport;
+import com.xdap.self_development.pojo.view.ApprovalFlowView;
+import com.xdap.self_development.pojo.view.ApprovalNodeView;
+import com.xdap.self_development.pojo.view.TodoAndReportView;
+import com.xdap.self_development.service.BenchmarkingReportService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+@Service
+public class BenchmarkingReportServiceImpl implements BenchmarkingReportService {
+ @Resource
+ private BusinessDatabase bd;
+ @Autowired
+ private StringRedisTemplate redisTemplate;
+ @Resource
+ private RuntimeAppContextService runtimeAppContextService;
+
+ private static final String TODO_PREFIX = "report:todo:";
+ private static final String NODE_PROCESSED_PREFIX = "report:node:processed:";
+ private static final String FLOW_LOCK_PREFIX = "report:lock:";
+ private static final int FLOW_LOCK_EXPIRE_SECONDS = 5;
+
+ @Override
+ @Transactional
+ public void saveBenchmarkingReport(SaveBenchmarkingReportForm form) {
+ // 1. 创建对标报告并保存
+ String currentTenantId = runtimeAppContextService.getCurrentTenantId();
+ Map map = new HashMap<>();
+ map.put("xdaptenantid", currentTenantId);
+ cn.hutool.json.JSON json = JSONUtil.parse(map);
+ String token = Base64.encode(json.toString());
+ String realUrl = form.getFileUrl()+"&download=download&token="+token;
+ BenchmarkingReport report = new BenchmarkingReport();
+ BeanUtils.copyProperties(form, report);
+ report.setFilePath(realUrl);
+ report.setUploadTime(Timestamp.valueOf(LocalDateTime.now()));
+ report.setStatus("APPROVING");
+ report.setCreateBy(form.getCreateBy());
+ bd.getBusinessDatabase().doInsert(report);
+ // 2. 创建审批流程
+ ApprovalFlow flow = new ApprovalFlow();
+ flow.setTemplateId(report.getId());
+ flow.setCurrentNode("PROOFREAD");
+ flow.setFlowStatus("APPROVING");
+ flow.setProofreadUsers(JSON.toJSONString(form.getProofreadUsers()));
+ flow.setReviewUsers(JSON.toJSONString(form.getReviewUsers()));
+ flow.setCountersignUsers(JSON.toJSONString(form.getCountersignUsers()));
+ flow.setApproveUsers(JSON.toJSONString(form.getApproveUsers()));
+ flow.setCreateBy(form.getCreateBy());
+ flow.setCreatedTime(Timestamp.valueOf(LocalDateTime.now()));
+ flow.setFlowType(2); // 设置为报告审批流程
+ flow.setExplanation(form.getExplanation());
+ bd.getBusinessDatabase().doInsert(flow);
+
+ // 3. 初始化Redis待办信息(校对节点)
+ form.getProofreadUsers().forEach(userId -> {
+ redisTemplate.opsForSet().add(TODO_PREFIX + userId, flow.getId());
+ });
+ }
+
+ @Override
+ public List getBenchmarkingReportByCondition(BenchmarkingReportPageForm form) {
+ List approvalList = new ArrayList<>();
+ Set flowIds = redisTemplate.opsForSet().members(TODO_PREFIX + form.getCreateBy());
+
+ if (flowIds != null && !flowIds.isEmpty()) {
+ List ids = new ArrayList<>(flowIds);
+ List todoList =bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("getTodoAndReport")
+ .setVar("ids", ids)
+ .setVar("title", form.getTitle())
+ .setVar("manufacturerName", form.getManufacturerName())
+ .setVar("modelName", form.getModelName())
+ .setVar("productNumber", form.getProductNumber())
+ .setVar("module", form.getModule())
+ .setVar("plate", form.getPlate())
+ .setVar("platform", form.getPlatform())
+ .setVar("series", form.getSeries())
+ .setVar("marketSegment", form.getMarketSegment())
+ .setVar("projectName", form.getProjectName())
+ .setVar("projectNumber", form.getProjectNumber())
+ .setVar("status", form.getStatus())
+ .doQuery(TodoAndReportView.class);
+ setCurrentApprovers(approvalList, todoList);
+
+ }
+
+ List ids = (flowIds == null || flowIds.isEmpty()) ? new ArrayList<>(Collections.singleton("")) : new ArrayList<>(flowIds);
+ List todoAndTemplateViews = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("getReportByUserIdAndIds")
+ .setVar("ids", ids)
+ .setVar("createBy", form.getCreateBy())
+ .setVar("title", form.getTitle())
+ .setVar("manufacturerName", form.getManufacturerName())
+ .setVar("modelName", form.getModelName())
+ .setVar("productNumber", form.getProductNumber())
+ .setVar("module", form.getModule())
+ .setVar("plate", form.getPlate())
+ .setVar("platform", form.getPlatform())
+ .setVar("series", form.getSeries())
+ .setVar("marketSegment", form.getMarketSegment())
+ .setVar("projectName", form.getProjectName())
+ .setVar("projectNumber", form.getProjectNumber())
+ .setVar("status", form.getStatus())
+ .doQuery(TodoAndReportView.class);
+ setCurrentApprovers(approvalList, todoAndTemplateViews);
+
+ return approvalList;
+ }
+
+ private void setCurrentApprovers(List approvalList, List todoAndReportViews) {
+ todoAndReportViews.forEach(item -> {
+ ApprovalXdapUsers approvalXdapUser = bd.getBusinessDatabase()
+ .eq("id", item.getCreateBy())
+ .doQueryFirst(ApprovalXdapUsers.class);
+ item.setCreateBy(approvalXdapUser == null ? item.getCreateBy() : approvalXdapUser.getUsername());
+ });
+ approvalList.addAll(todoAndReportViews);
+ }
+
+ @Override
+ @Transactional
+ public void handleReportApproval(HandleApprovalRequest request) {
+ ApprovalFlow flow = bd.getBusinessDatabase()
+ .eq("id", request.getFlowId())
+ .eq("flow_type", 2)
+ .doQueryFirst(ApprovalFlow.class);
+ if (flow == null || !"APPROVING".equals(flow.getFlowStatus())) {
+ throw new MpaasBusinessException("流程不存在或已结束");
+ }
+
+ String currentNode = flow.getCurrentNode();
+ // 验证当前用户是否有权限处理
+ if (!hasPermission(flow, currentNode, request.getUserId())) {
+ throw new MpaasBusinessException("无权限处理或已被处理");
+ }
+
+ if (!"COUNTERSIGN".equals(currentNode)) {
+ String lockKey = FLOW_LOCK_PREFIX + flow.getId() + ":" + currentNode;
+ Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", FLOW_LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS);
+ if (Boolean.FALSE.equals(lock)) {
+ throw new MpaasBusinessException("当前节点正在处理,请稍后重试");
+ }
+ try {
+ // 校验抢签节点是否已被处理
+ String processedKey = NODE_PROCESSED_PREFIX + flow.getId() + ":" + currentNode;
+ long result = Optional.ofNullable(redisTemplate.opsForSet().size(processedKey))
+ .orElse(0L);
+ if (result > 0) {
+ throw new MpaasBusinessException("此节点已被他人处理");
+ }
+ processApprovalLogic(flow, request, currentNode);
+ } finally {
+ redisTemplate.delete(lockKey);
+ }
+ } else {
+ processApprovalLogic(flow, request, currentNode);
+ }
+
+ }
+
+ @Override
+ public BenchmarkingReport getReportDetail(String reportId) {
+ BenchmarkingReport report = bd.getBusinessDatabase().eq("id", reportId)
+ .doQueryFirst(BenchmarkingReport.class);
+ return report;
+ }
+
+ @Override
+ public ApprovalFlowView getReportProcess(String flowId) {
+ ApprovalFlowView approvalFlowView = new ApprovalFlowView();
+ ApprovalFlow flow = bd.getBusinessDatabase()
+ .eq("id", flowId)
+ .eq("flow_type", 2)
+ .doQueryFirst(ApprovalFlow.class);
+ approvalFlowView.setExplanation(flow.getExplanation());
+ approvalFlowView.setProofreadNodes(getNodeList(flowId, "PROOFREAD"));
+ approvalFlowView.setReviewNodes(getNodeList(flowId, "REVIEW"));
+ approvalFlowView.setCountersignNodes(getNodeList(flowId, "COUNTERSIGN"));
+ approvalFlowView.setApproveNodes(getNodeList(flowId, "APPROVE"));
+
+ approvalFlowView.setFlowStatus(flow.getFlowStatus());
+ return approvalFlowView;
+ }
+
+ private List getNodeList(String flowId, String node) {
+ List list = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("getApprovalNodeInfo")
+ .setVar("flowId", flowId)
+ .setVar("node", node)
+ .doQuery(ApprovalNodeView.class);
+ if (list != null && !list.isEmpty()) {
+ list.forEach(approvalNodeView -> {
+ ApprovalXdapUsers user = bd.getBusinessDatabase()
+ .eq("id", approvalNodeView.getUserId())
+ .doQueryFirst(ApprovalXdapUsers.class);
+ approvalNodeView.setUserName(user.getUsername());
+ approvalNodeView.setUserId(null);
+ });
+ }
+ return list;
+ }
+
+ private boolean hasPermission(ApprovalFlow flow, String node, String userId) {
+ switch (node) {
+ case "PROOFREAD":
+ return JSON.parseArray(flow.getProofreadUsers()).toJavaList(String.class).contains(userId);
+ case "REVIEW":
+ return JSON.parseArray(flow.getReviewUsers()).toJavaList(String.class).contains(userId);
+ case "COUNTERSIGN":
+ return flow.getCountersignUsers() != null && JSON.parseArray(flow.getCountersignUsers()).toJavaList(String.class).contains(userId);
+ case "APPROVE":
+ return JSON.parseArray(flow.getApproveUsers()).toJavaList(String.class).contains(userId);
+ default:
+ return false;
+ }
+ }
+
+ private void processApprovalLogic(ApprovalFlow flow, HandleApprovalRequest request, String currentNode) {
+ // 记录审批结果
+ ApprovalRecord record = new ApprovalRecord();
+ record.setFlowId(flow.getId());
+ record.setNode(currentNode);
+ record.setUserId(request.getUserId());
+ record.setOpinion(request.getOpinion());
+ record.setResult(request.getResult());
+ record.setApprovalTime(Timestamp.valueOf(LocalDateTime.now()));
+ bd.getBusinessDatabase().doInsert(record);
+
+ redisTemplate.opsForSet().add(NODE_PROCESSED_PREFIX + flow.getId() + ":" + currentNode,
+ request.getUserId());
+
+ // 处理驳回逻辑
+ if ("REJECT".equals(request.getResult())) {
+ cancelProcess(flow, "REJECTED");
+ return;
+ } else if ("RETURN".equals(request.getResult())) {
+ cancelProcess(flow, "RETURNED");
+ return;
+ }
+ // 处理通过逻辑,流转到下一节点
+ processNextNode(flow, currentNode);
+ }
+
+ private void processNextNode(ApprovalFlow flow, String currentNode) {
+ // 检查当前节点是否满足流转条件
+ if (!checkNodeComplete(flow, currentNode)) {
+ return; // 未满足条件,不流转
+ }
+
+ // 更新报告状态
+ BenchmarkingReport report = bd.getBusinessDatabase()
+ .eq("id", flow.getTemplateId())
+ .doQueryFirst(BenchmarkingReport.class);
+ String nextNode = getNextNode(currentNode, flow);
+
+ if (nextNode == null) {
+ // 流程结束
+ flow.setFlowStatus("COMPLETE");
+ flow.setCurrentNode(null);
+ report.setStatus("COMPLETE");
+ bd.getBusinessDatabase()
+ .rowid("id", report.getRowId())
+ .update("status", report.getStatus())
+ .doUpdate(BenchmarkingReport.class);
+ clearProcessed(flow);
+ } else {
+ flow.setCurrentNode(nextNode);
+ addNodeTodo(flow, nextNode);
+ }
+
+ bd.getBusinessDatabase()
+ .rowid("id", flow.getRowId())
+ .update("flow_status", flow.getFlowStatus())
+ .update("current_node", flow.getCurrentNode())
+ .doUpdate(ApprovalFlow.class);
+ // 清除当前节点待办
+ clearNodeTodoSmart(flow, currentNode, nextNode);
+ }
+
+ private void clearNodeTodoSmart(ApprovalFlow flow, String currentNode, String nextNode) {
+ List currentNodeUsers = getNodeUsers(flow, currentNode);
+ List nextNodeUsers = nextNode != null ? getNodeUsers(flow, nextNode) : Collections.emptyList();
+
+ // 只清除那些不在下一节点的用户的待办
+ for (String userId : currentNodeUsers) {
+ if (!nextNodeUsers.contains(userId)) {
+ redisTemplate.opsForSet().remove(TODO_PREFIX + userId, flow.getId());
+ }
+ }
+ }
+
+ private void addNodeTodo(ApprovalFlow flow, String node) {
+ List users = getNodeUsers(flow, node);
+ users.forEach(userId -> {
+ redisTemplate.opsForSet().add(TODO_PREFIX+ userId, flow.getId());
+ });
+ }
+
+ private boolean checkNodeComplete(ApprovalFlow flow, String node) {
+ String key = NODE_PROCESSED_PREFIX + flow.getId() + ":" + node;
+ Long processedCount = redisTemplate.opsForSet().size(key);
+ if (processedCount == null) processedCount = 0L;
+
+ // 会签节点需要所有人处理,其他节点只需1人
+ if ("COUNTERSIGN".equals(node)) {
+ return processedCount.equals((long) JSON.parseArray(flow.getCountersignUsers()).size());
+ } else {
+ return processedCount >= 1;
+ }
+ }
+
+ private String getNextNode(String currentNode, ApprovalFlow flow) {
+ switch (currentNode) {
+ case "PROOFREAD":
+ return "REVIEW";
+ case "REVIEW":
+ return flow.getCountersignUsers() != null && !JSON.parseArray(flow.getCountersignUsers()).isEmpty()
+ ? "COUNTERSIGN" : "APPROVE";
+ case "COUNTERSIGN":
+ return "APPROVE";
+ case "APPROVE":
+ return null; // 流程结束
+ default:
+ return null;
+ }
+ }
+
+ private void cancelProcess(ApprovalFlow flow, String status) {
+ flow.setFlowStatus(status);
+ bd.getBusinessDatabase()
+ .rowid("id", flow.getRowId())
+ .update("status", flow.getFlowStatus())
+ .doUpdate(ApprovalFlow.class);
+ // 更新报告状态
+ BenchmarkingReport report = bd.getBusinessDatabase()
+ .eq("id", flow.getTemplateId())
+ .doQueryFirst(BenchmarkingReport.class);
+ report.setStatus(status);
+ bd.getBusinessDatabase()
+ .rowid("id", report.getRowId())
+ .update("status", report.getStatus())
+ .doUpdate(BenchmarkingReport.class);
+ // 清除所有待办
+ clearAllTodo(flow);
+ clearProcessed(flow);
+ }
+
+ private void clearAllTodo(ApprovalFlow flow) {
+ clearNodeTodo(flow, "PROOFREAD");
+ clearNodeTodo(flow, "REVIEW");
+ if (flow.getCountersignUsers() != null) {
+ clearNodeTodo(flow, "COUNTERSIGN");
+ }
+ clearNodeTodo(flow, "APPROVE");
+ }
+
+ private void clearProcessed(ApprovalFlow flow) {
+ redisTemplate.delete(NODE_PROCESSED_PREFIX + flow.getId() + ":" + "PROOFREAD");
+ redisTemplate.delete(NODE_PROCESSED_PREFIX + flow.getId() + ":" + "REVIEW");
+ if (flow.getCountersignUsers() != null) {
+ redisTemplate.delete(NODE_PROCESSED_PREFIX + flow.getId() + ":" + "COUNTERSIGN");
+ }
+ redisTemplate.delete(NODE_PROCESSED_PREFIX + flow.getId() + ":" + "APPROVE");
+ }
+
+ private void clearNodeTodo(ApprovalFlow flow, String node) {
+ List users = getNodeUsers(flow, node);
+ users.forEach(userId -> {
+ redisTemplate.opsForSet().remove(TODO_PREFIX+ userId, flow.getId());
+ });
+ }
+
+ private List getNodeUsers(ApprovalFlow flow, String node) {
+ switch (node) {
+ case "PROOFREAD": return JSON.parseArray(flow.getProofreadUsers()).toJavaList(String.class);
+ case "REVIEW": return JSON.parseArray(flow.getReviewUsers()).toJavaList(String.class);
+ case "COUNTERSIGN": return JSON.parseArray(flow.getCountersignUsers()).toJavaList(String.class);
+ case "APPROVE": return JSON.parseArray(flow.getApproveUsers()).toJavaList(String.class);
+ default: return Collections.emptyList();
+ }
+ }
+
+}
diff --git a/src/main/java/com/xdap/self_development/service/impl/ParameterServiceImpl.java b/src/main/java/com/xdap/self_development/service/impl/ParameterServiceImpl.java
new file mode 100644
index 0000000..69c8001
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/service/impl/ParameterServiceImpl.java
@@ -0,0 +1,387 @@
+package com.xdap.self_development.service.impl;
+
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.self_development.config.BusinessDatabase;
+import com.xdap.self_development.controller.form.ParameterForm;
+import com.xdap.self_development.controller.form.ParameterPageForm;
+import com.xdap.self_development.controller.form.TemplateRowIdForm;
+import com.xdap.self_development.controller.form.UpdateParameterForm;
+import com.xdap.self_development.pojo.Parameter;
+import com.xdap.self_development.pojo.RevisionRecord;
+import com.xdap.self_development.pojo.Template;
+import com.xdap.self_development.pojo.TemplateAndParameter;
+import com.xdap.self_development.pojo.view.TemplateInfoView;
+import com.xdap.self_development.service.ParameterService;
+import com.xdap.self_development.utils.FormulaValidator;
+import com.xdap.self_development.utils.ParameterOperation;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class ParameterServiceImpl implements ParameterService {
+ @Resource
+ private BusinessDatabase bd;
+
+ @Override
+ public PageQueryResult getParameterByCondition(ParameterPageForm form) {
+ Template template = bd.getBusinessDatabase()
+ .rowid("id", form.getTemplateRowId())
+ .doQueryFirst(Template.class);
+
+ if (template == null) {
+ throw new MpaasBusinessException("模板未找到");
+ }
+
+ return bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("selectParametersByTemplateId")
+ .setVar("templateId", template.getId())
+ .like("parameter_name", form.getParameterName())
+ .like("parts_name", form.getPartsName())
+ .like("parameter_type", form.getParameterType())
+ .doPageQuery(form.getPageNumber(), form.getPageSize(), Parameter.class);
+ }
+
+ @Override
+ @Transactional(rollbackFor = MpaasBusinessException.class)
+ public TemplateInfoView maintenanceParameters(UpdateParameterForm form) {
+ // 公式格式检查
+ form.getParameterForms().forEach(parameter -> {
+ if (Objects.equals(parameter.getParameterSource(), "公式计算")) {
+ Map validationResult = FormulaValidator.validateFormulaDetailed(
+ parameter.getNumberOrFormula());
+ if (!(Boolean) validationResult.get("isValid")) {
+ String errorMsg = String.format("参数 '%s' 公式格式错误: %s",
+ parameter.getParameterName(),
+ validationResult.get("errorMessage"));
+ throw new MpaasBusinessException(errorMsg);
+ }
+ }
+ });
+ // 获取基准模板和最新模板
+ TemplateBenchmark benchmark = getTemplateBenchmark(form.getTemplateRowId());
+ // 创建新版本模板
+ Template newTemplate;
+ if (benchmark.getParameters().isEmpty()) {
+ newTemplate = benchmark.getBaseTemplate();
+ } else {
+ newTemplate = new Template(
+ benchmark.getLastTemplate().getTemplateName(), calculateNextVersion(benchmark.getLastTemplate().getVersion()),
+ "DRAFT", Timestamp.valueOf(LocalDateTime.now()), null, form.getCreateBy()
+ );
+ // 保存新模板
+ bd.getBusinessDatabase().doInsert(newTemplate);
+ }
+
+ // 4. 处理参数变更
+ ParameterProcessingResult processingResult = processParameters(
+ form.getParameterForms(),
+ benchmark.getParameters(),
+ benchmark.getBaseTemplate(),
+ newTemplate
+ );
+
+ // 5. 保存所有数据
+ saveAllData(newTemplate, processingResult);
+ TemplateInfoView result = new TemplateInfoView();
+ result.setTemplateRowId(newTemplate.getRowId());
+ result.setVersion(newTemplate.getVersion());
+ return result;
+ }
+
+ private TemplateBenchmark getTemplateBenchmark(String templateRowId) {
+ // 基准模板(用户选择的要比较的版本)
+ Template baseTemplate = bd.getBusinessDatabase()
+ .rowid("id", templateRowId)
+ .doQueryFirst(Template.class);
+
+ if (baseTemplate == null) {
+ throw new IllegalArgumentException("未找到对应的模板,ID: " + templateRowId);
+ }
+
+ // 最新版本模板
+ Template lastTemplate = bd.getBusinessDatabase()
+ .eq("template_name", baseTemplate.getTemplateName())
+ .orderBy("version", "desc")
+ .doQueryFirst(Template.class);
+
+ if (lastTemplate == null) {
+ throw new IllegalStateException("未找到模板的最新版本: " + baseTemplate.getTemplateName());
+ }
+
+ // 基准模板的参数
+ List parameters = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("selectParametersByTemplateId")
+ .setVar("templateId", baseTemplate.getId())
+ .doQuery(Parameter.class);
+
+ return new TemplateBenchmark(baseTemplate, lastTemplate, parameters);
+ }
+
+ /**
+ * 模板基准信息封装类
+ */
+ @Data
+ @AllArgsConstructor
+ private static class TemplateBenchmark {
+ private final Template baseTemplate;
+ private final Template lastTemplate;
+ private final List parameters;
+ }
+
+ /**
+ * 参数处理结果封装类
+ */
+ @Data
+ @AllArgsConstructor
+ private static class ParameterProcessingResult {
+ private final List newParameters;
+ private final List revisionRecords;
+ }
+
+ private Integer calculateNextVersion(Integer currentVersion) {
+ try {
+ return currentVersion + 1;
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("版本号格式错误: " + currentVersion, e);
+ }
+ }
+
+ private ParameterProcessingResult processParameters(
+ List parameterForms,
+ List existingParameters,
+ Template baseTemplate,
+ Template newTemplate)
+ {
+ Map parameterMap = createParameterMap(existingParameters);
+ List newParameters = new ArrayList<>();
+ List revisionRecords = new ArrayList<>();
+
+ for (ParameterForm parameterForm : parameterForms) {
+ ParameterOperation operation = ParameterOperation.fromCode(parameterForm.getOperation());
+
+ switch (operation) {
+ case INSERT:
+ handleInsertOperation(parameterForm, newTemplate, newParameters, revisionRecords, baseTemplate);
+ break;
+ case UPDATE:
+ handleUpdateOperation(parameterForm, parameterMap, newTemplate, newParameters, revisionRecords, baseTemplate);
+ break;
+ case DELETE:
+ handleDeleteOperation(parameterForm, parameterMap, newTemplate, revisionRecords, baseTemplate);
+ break;
+ case UNCHANGED:
+ handleUnchangedOperation(parameterForm, parameterMap, newParameters);
+ break;
+ }
+ }
+
+ return new ParameterProcessingResult(newParameters, revisionRecords);
+ }
+
+ private Map createParameterMap(List parameters) {
+ Map map = new HashMap<>();
+ Set duplicateNumbers = new HashSet<>();
+ for (Parameter parameter : parameters) {
+ if (map.containsKey(parameter.getParameterNumber())) {
+ duplicateNumbers.add(parameter.getParameterNumber());
+ } else {
+ map.put(parameter.getParameterNumber(), parameter);
+ }
+ }
+ if (!duplicateNumbers.isEmpty()) {
+ throw new IllegalStateException("发现重复的参数编号: " + duplicateNumbers);
+ }
+ return map;
+ }
+
+ /**
+ * 处理新增参数
+ */
+ private void handleInsertOperation(
+ ParameterForm form, Template newTemplate,
+ List newParameters, List revisionRecords,
+ Template baseTemplate
+ ) {
+ Parameter newParameter = new Parameter();
+ BeanUtils.copyProperties(form, newParameter);
+
+ //TODO:编号问题(目前是前端传入编号,后端检查编号是否重复;或者我可以给他自动生成最大值)
+ if (form.getParameterNumber() == null ) {
+ Parameter parameter = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("selectMaxNumber")
+ .setVar("templateId", baseTemplate.getId())
+ .doQueryFirst(Parameter.class);
+ if (parameter == null || parameter.getMaxNumber() == null) {
+ int maxNumber = newParameters.stream()
+ .mapToInt(Parameter::getParameterNumber)
+ .max()
+ .orElse(0);
+ newParameter.setParameterNumber(maxNumber + 1);
+ } else {
+ int i = parameter.getMaxNumber() + 1;
+ newParameter.setParameterNumber(i);
+ }
+ } else {
+ List parameters = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("selectParametersByTemplateId")
+ .setVar("templateId", baseTemplate.getId())
+ .eq("parameter_number", newParameter.getParameterNumber())
+ .doQuery(Parameter.class);
+ if (parameters != null && !parameters.isEmpty()) {
+ throw new MpaasBusinessException("参数编号重复");
+ }
+ }
+
+ newParameters.add(newParameter);
+ revisionRecords.add(new RevisionRecord(
+ newTemplate.getTemplateName(),
+ newTemplate.getVersion(),
+ newParameter.getParameterNumber(),
+ "新增参数",
+ newTemplate.getId(),
+ null
+ ));
+ }
+
+ /**
+ * 处理更新参数
+ */
+ private void handleUpdateOperation(
+ ParameterForm form, Map parameterMap,
+ Template newTemplate, List newParameters,
+ List revisionRecords, Template baseTemplate
+ ) {
+ Parameter originalParameter = parameterMap.get(form.getParameterNumber());
+
+ if (originalParameter == null) {
+ throw new IllegalArgumentException("未找到要更新的参数,编号: " + form.getParameterNumber());
+ }
+
+ Parameter updatedParameter = new Parameter();
+ BeanUtils.copyProperties(form, updatedParameter);
+
+ String detail = getParameterChange(originalParameter, updatedParameter);
+
+ newParameters.add(updatedParameter);
+
+ revisionRecords.add(new RevisionRecord(
+ newTemplate.getTemplateName(),
+ newTemplate.getVersion(),
+ form.getParameterNumber(),
+ "更新参数:" + detail,
+ newTemplate.getId(),
+ null
+ ));
+ }
+
+ private String getParameterChange(Parameter originalParameter, Parameter updatedParameter) {
+ StringBuilder sb = new StringBuilder();
+ if (!Objects.equals(originalParameter.getParameterName(), updatedParameter.getParameterName())) {
+ sb.append("参数名:'").append(originalParameter.getParameterName()).append("'变更到'").append(updatedParameter.getParameterName()).append("'\n");
+ }
+ if (!Objects.equals(originalParameter.getParameterType(), updatedParameter.getParameterType())) {
+ sb.append("参数类型:'").append(originalParameter.getParameterType()).append("'变更到'").append(updatedParameter.getParameterType()).append("'\n");
+ }
+ if (!Objects.equals(originalParameter.getSubsystemName(), updatedParameter.getSubsystemName())) {
+ sb.append("子系统:'").append(originalParameter.getSubsystemName()).append("'变更到'").append(updatedParameter.getSubsystemName()).append("'\n");
+ }
+ if (!Objects.equals(originalParameter.getPartsName(), updatedParameter.getPartsName())) {
+ sb.append("部件名:'").append(originalParameter.getPartsName()).append("'变更到'").append(updatedParameter.getPartsName()).append("'\n");
+ }
+ if (!Objects.equals(originalParameter.getUnit(), updatedParameter.getUnit())) {
+ sb.append("单位名:'").append(originalParameter.getUnit()).append("'变更到'").append(updatedParameter.getUnit()).append("'\n");
+ }
+ if (!Objects.equals(originalParameter.getParameterSource(), updatedParameter.getParameterSource())) {
+ sb.append("参数来源:'").append(originalParameter.getParameterSource()).append("'变更到'").append(updatedParameter.getParameterSource()).append("'\n");
+ }
+ if (!Objects.equals(originalParameter.getNumberOrFormula(), updatedParameter.getNumberOrFormula())) {
+ sb.append("公式或编号:'").append(originalParameter.getNumberOrFormula()).append("'变更到'").append(updatedParameter.getNumberOrFormula()).append("'\n");
+ }
+ if (!Objects.equals(originalParameter.getDepartment(), updatedParameter.getDepartment())) {
+ sb.append("部门名:'").append(originalParameter.getDepartment()).append("'变更到'").append(updatedParameter.getDepartment()).append("'\n");
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * 处理删除参数
+ */
+ private void handleDeleteOperation(
+ ParameterForm form, Map parameterMap,
+ Template newTemplate, List revisionRecords,
+ Template baseTemplate
+ ) {
+ Parameter deletedParameter = parameterMap.get(form.getParameterNumber());
+
+ if (deletedParameter != null) {
+ revisionRecords.add(new RevisionRecord(
+ newTemplate.getTemplateName(),
+ newTemplate.getVersion(),
+ form.getParameterNumber(),
+ "删除参数",
+ newTemplate.getId(),
+ baseTemplate.getId()
+ ));
+ }
+ }
+
+ /**
+ * 处理未修改参数
+ */
+ private void handleUnchangedOperation(
+ ParameterForm form, Map parameterMap,
+ List newParameters
+ ) {
+ Parameter unchangedParameter = parameterMap.get(form.getParameterNumber());
+
+ if (unchangedParameter != null) {
+ Parameter parameterCopy = new Parameter();
+ BeanUtils.copyProperties(unchangedParameter, parameterCopy);
+ parameterCopy.setId(null);
+ parameterCopy.setRowId(null);
+ newParameters.add(parameterCopy);
+ }
+ }
+
+ /**
+ * 保存所有数据
+ */
+ private void saveAllData(Template newTemplate, ParameterProcessingResult result) {
+ // 批量保存参数
+ bd.getBusinessDatabase().doBatchInsert(result.getNewParameters());
+ // 创建并保存模板参数关联
+ List templateAndParameters = result.getNewParameters().stream()
+ .map(parameter -> createTemplateAndParameter(newTemplate.getId(), parameter.getId()))
+ .collect(Collectors.toList());
+ bd.getBusinessDatabase().doBatchInsert(templateAndParameters);
+ // 保存修订记录
+ if (!result.getRevisionRecords().isEmpty()) {
+ bd.getBusinessDatabase().doBatchInsert(result.getRevisionRecords());
+ }
+ }
+
+ /**
+ * 创建模板参数关联
+ */
+ private TemplateAndParameter createTemplateAndParameter(String templateId, String parameterId) {
+ TemplateAndParameter tap = new TemplateAndParameter();
+ tap.setTemplateId(templateId);
+ tap.setParameterId(parameterId);
+ return tap;
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/service/impl/ResponsiblePersonServiceImpl.java b/src/main/java/com/xdap/self_development/service/impl/ResponsiblePersonServiceImpl.java
new file mode 100644
index 0000000..690c3f2
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/service/impl/ResponsiblePersonServiceImpl.java
@@ -0,0 +1,88 @@
+package com.xdap.self_development.service.impl;
+
+
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.runtime.service.RuntimeDatasourceService;
+import com.xdap.self_development.config.BusinessDatabase;
+import com.xdap.self_development.controller.form.DeptResponsiblePageForm;
+import com.xdap.self_development.controller.form.ResponsiblePersonForm;
+import com.xdap.self_development.controller.form.UpdateResponsiblePersonForm;
+import com.xdap.self_development.pojo.ApprovalXdapUsers;
+import com.xdap.self_development.pojo.ResponsiblePerson;
+import com.xdap.self_development.pojo.Template;
+import com.xdap.self_development.service.ResponsiblePersonService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Service
+public class ResponsiblePersonServiceImpl implements ResponsiblePersonService {
+ @Resource
+ private BusinessDatabase bd;
+ @Resource
+ private RuntimeDatasourceService runtimeDatasourceService;
+
+ @Override
+ public void saveResponsiblePerson(ResponsiblePersonForm form) {
+ List responsiblePeople = bd.getBusinessDatabase()
+ .eq("department_id", form.getDepartmentId())
+ .doQuery(ResponsiblePerson.class);
+ if (!responsiblePeople.isEmpty()) {
+ throw new MpaasBusinessException("该部门已有责任人");
+ }
+ ResponsiblePerson responsiblePerson = new ResponsiblePerson();
+ responsiblePerson.setDepartment(form.getDepartment());
+ responsiblePerson.setDepartmentId(form.getDepartmentId());
+ responsiblePerson.setUserId(form.getUserId());
+ responsiblePerson.setSubsystem(form.getSubsystem());
+ bd.getBusinessDatabase().doInsert(responsiblePerson);
+ }
+
+ @Override
+ public void updateResponsiblePerson(UpdateResponsiblePersonForm form) {
+ List responsiblePeople = bd.getBusinessDatabase()
+ .eq("department_id", form.getDepartmentId())
+ .doQuery(ResponsiblePerson.class);
+ if (!responsiblePeople.isEmpty()) {
+ throw new MpaasBusinessException("该部门已有责任人");
+ }
+
+ bd.getBusinessDatabase()
+ .rowid("id", form.getRowId())
+ .update("department_id", form.getDepartmentId())
+ .update("user_id", form.getUserId())
+ .update("department", form.getDepartment())
+ .update("subsystem", form.getSubsystem())
+ .doUpdate(ResponsiblePerson.class);
+ }
+
+ @Override
+ public void deleteResponsiblePerson(String rowId) {
+ bd.getBusinessDatabase().rowid("id", rowId).doDelete(ResponsiblePerson.class);
+ }
+
+ @Override
+ public PageQueryResult getDeptResponsible(DeptResponsiblePageForm form) {
+
+ return bd.getBusinessDatabase()
+ .viewQueryMode(true).view("getResponsibleAndName")
+ .doPageQuery(form.getPageNumber(), form.getPageSize(), ResponsiblePerson.class);
+ }
+
+ @Override
+ public Boolean isResponsiblePerson(String userId) {
+ List responsiblePeople = bd.getBusinessDatabase().eq("userId", userId).doQuery(ResponsiblePerson.class);
+ return !responsiblePeople.isEmpty();
+ }
+
+ @Override
+ public Set getAllSubsystem() {
+ List templates = bd.getBusinessDatabase().select("template_name").doQuery(Template.class);
+ return templates.stream().map(Template::getTemplateName).collect(Collectors.toSet());
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/service/impl/TemplateApprovalServiceImpl.java b/src/main/java/com/xdap/self_development/service/impl/TemplateApprovalServiceImpl.java
new file mode 100644
index 0000000..956d3eb
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/service/impl/TemplateApprovalServiceImpl.java
@@ -0,0 +1,440 @@
+package com.xdap.self_development.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.runtime.service.RuntimeDatasourceService;
+import com.xdap.self_development.config.BusinessDatabase;
+import com.xdap.self_development.controller.form.*;
+import com.xdap.self_development.pojo.*;
+import com.xdap.self_development.pojo.view.ApprovalFlowView;
+import com.xdap.self_development.pojo.view.ApprovalNodeView;
+import com.xdap.self_development.pojo.view.TemplateChangeView;
+import com.xdap.self_development.pojo.view.TodoAndTemplateView;
+import com.xdap.self_development.service.TemplateApprovalService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+@Service
+@Slf4j
+public class TemplateApprovalServiceImpl implements TemplateApprovalService {
+ @Autowired
+ private StringRedisTemplate redisTemplate;
+ @Resource
+ private BusinessDatabase bd;
+ @Resource
+ private RuntimeDatasourceService runtimeDatasourceService;
+
+ // 待办标志: userId -> flowId集合
+ private static final String TODO_PREFIX = "approval:todo:";
+ // 节点已处理用户标志: flowId:node -> userId集合
+ private static final String NODE_PROCESSED_PREFIX = "approval:node:processed:";
+ // 分布式锁标志
+ private static final String FLOW_LOCK_PREFIX = "approval:lock:";
+ // 分布式锁有效时间
+ private static final int FLOW_LOCK_EXPIRE_SECONDS = 5;
+
+ @Override
+ @Transactional
+ public String startApproval(StartApprovalRequest request) {
+ // 验证模板存在
+ Template template = bd.getBusinessDatabase()
+ .rowid("id", request.getTemplateRowId())
+ .doQueryFirst(Template.class);
+ if (template == null) {
+ throw new MpaasBusinessException("模板不存在");
+ }
+
+ if (!Objects.equals("DRAFT", template.getStatus())) {
+ throw new MpaasBusinessException("非草稿不允许发起审批");
+ }
+
+ List templateFlows = bd.getBusinessDatabase()
+ .eq("template_id", template.getId())
+ .eq("flow_type", 1)
+ .doQuery(ApprovalFlow.class);
+ if (templateFlows != null && !templateFlows.isEmpty()) {
+ throw new MpaasBusinessException("模板已发起审批");
+ }
+
+ // 2. 创建审批流程
+ ApprovalFlow flow = new ApprovalFlow();
+ flow.setTemplateId(template.getId());
+ flow.setCurrentNode("PROOFREAD");
+ flow.setFlowStatus("APPROVING");
+ flow.setProofreadUsers(JSON.toJSONString(request.getProofreadUsers()));
+ flow.setReviewUsers(JSON.toJSONString(request.getReviewUsers()));
+ flow.setCountersignUsers(JSON.toJSONString(request.getCountersignUsers()));
+ flow.setApproveUsers(JSON.toJSONString(request.getApproveUsers()));
+ flow.setCreateBy(request.getCreateBy());
+ flow.setCreatedTime(Timestamp.valueOf(LocalDateTime.now()));
+ flow.setFlowType(1); // 设置为模板审批流程
+ flow.setExplanation(request.getExplanation());
+ bd.getBusinessDatabase().doInsert(flow);
+
+ // 3. 更新模板状态为校对中
+ template.setStatus("APPROVING");
+ bd.getBusinessDatabase()
+ .rowid("id", template.getRowId())
+ .update("status", template.getStatus())
+ .doUpdate(Template.class);
+
+ // 4. 初始化Redis待办信息(校对节点)
+ request.getProofreadUsers().forEach(userId -> {
+ redisTemplate.opsForSet().add(TODO_PREFIX + userId, flow.getId());
+ });
+
+ return flow.getId();
+ }
+
+ @Override
+ @Transactional
+ public List getApprovalList(ApprovalListForm form) {
+ List approvalList = new ArrayList<>();
+ Set flowIds = redisTemplate.opsForSet().members(TODO_PREFIX + form.getUserId());
+
+ if (flowIds != null && !flowIds.isEmpty()) {
+ List ids = new ArrayList<>(flowIds);
+ List todoList =bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("getTodoAndTemplate")
+ .setVar("ids", ids)
+ .setVar("templateName", form.getTemplateName())
+ .setVar("status", form.getStatus())
+ .doQuery(TodoAndTemplateView.class);
+ setCurrentApprovers(approvalList, todoList);
+
+ }
+
+ List ids = (flowIds == null || flowIds.isEmpty()) ? new ArrayList<>(Collections.singleton("")) : new ArrayList<>(flowIds);
+ List todoAndTemplateViews = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("getApprovalByUserIdAndIds")
+ .setVar("ids", ids)
+ .setVar("createBy", form.getUserId())
+ .setVar("templateName", form.getTemplateName())
+ .setVar("status", form.getStatus())
+ .doQuery(TodoAndTemplateView.class);
+ setCurrentApprovers(approvalList, todoAndTemplateViews);
+
+ return approvalList;
+ }
+
+ private void setCurrentApprovers(List approvalList, List todoAndTemplateViews) {
+ todoAndTemplateViews.forEach(item -> {
+ if (item.getCurrentUsers() == null || item.getCurrentUsers().isEmpty()) {
+ item.setCurrentApprovers(null);
+ item.setCurrentUsers(null);
+ } else {
+ List userIds = JSON.parseArray(item.getCurrentUsers()).toJavaList(String.class);
+ List approvalXdapUsers = bd.getBusinessDatabase()
+ .in("id", userIds)
+ .doQuery(ApprovalXdapUsers.class);
+ item.setCurrentApprovers(approvalXdapUsers);
+ item.setCurrentUsers(null);
+ }
+ ApprovalXdapUsers approvalXdapUser = bd.getBusinessDatabase()
+ .eq("id", item.getCreateBy())
+ .doQueryFirst(ApprovalXdapUsers.class);
+ item.setCreateBy(approvalXdapUser == null ? item.getCreateBy() : approvalXdapUser.getUsername());
+ });
+ approvalList.addAll(todoAndTemplateViews);
+ }
+
+ @Override
+ @Transactional
+ public void handleApproval(HandleApprovalRequest request) {
+ ApprovalFlow flow = bd.getBusinessDatabase()
+ .eq("id", request.getFlowId())
+ .eq("flow_type", 1)
+ .doQueryFirst(ApprovalFlow.class);
+ if (flow == null || !"APPROVING".equals(flow.getFlowStatus())) {
+ throw new MpaasBusinessException("流程不存在或已结束");
+ }
+
+ String currentNode = flow.getCurrentNode();
+ // 验证当前用户是否有权限处理
+ if (!hasPermission(flow, currentNode, request.getUserId())) {
+ throw new MpaasBusinessException("无权限处理或已被处理");
+ }
+
+ if (!"COUNTERSIGN".equals(currentNode)) {
+ String lockKey = FLOW_LOCK_PREFIX + flow.getId() + ":" + currentNode;
+ Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", FLOW_LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS);
+ if (Boolean.FALSE.equals(lock)) {
+ throw new MpaasBusinessException("当前节点正在处理,请稍后重试");
+ }
+ try {
+ // 校验抢签节点是否已被处理
+ String processedKey = NODE_PROCESSED_PREFIX + flow.getId() + ":" + currentNode;
+ long result = Optional.ofNullable(redisTemplate.opsForSet().size(processedKey))
+ .orElse(0L);
+ if (result > 0) {
+ throw new MpaasBusinessException("此节点已被他人处理");
+ }
+ processApprovalLogic(flow, request, currentNode);
+ } finally {
+ redisTemplate.delete(lockKey);
+ }
+ } else {
+ processApprovalLogic(flow, request, currentNode);
+ }
+ }
+
+ private void processApprovalLogic(ApprovalFlow flow, HandleApprovalRequest request, String currentNode) {
+ // 记录审批结果
+ ApprovalRecord record = new ApprovalRecord();
+ record.setFlowId(flow.getId());
+ record.setNode(currentNode);
+ record.setUserId(request.getUserId());
+ record.setOpinion(request.getOpinion());
+ record.setResult(request.getResult());
+ record.setApprovalTime(Timestamp.valueOf(LocalDateTime.now()));
+ bd.getBusinessDatabase().doInsert(record);
+
+ redisTemplate.opsForSet().add(NODE_PROCESSED_PREFIX + flow.getId() + ":" + currentNode,
+ request.getUserId());
+
+ if ("COUNTERSIGN".equals(flow.getCurrentNode())) {
+ redisTemplate.opsForSet().remove(TODO_PREFIX + request.getUserId(), flow.getId());
+ }
+
+ // 处理驳回逻辑
+ if ("REJECT".equals(request.getResult())) {
+ cancelProcess(flow, "REJECTED");
+ return;
+ } else if ("RETURN".equals(request.getResult())) {
+ cancelProcess(flow, "RETURNED");
+ return;
+ }
+ // 处理通过逻辑,流转到下一节点
+ processNextNode(flow, currentNode);
+ }
+
+ @Override
+ public PageQueryResult getTemplateChanges(ApprovalAndParameterForm form) {
+ PageQueryResult results = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("getParameterAndChange")
+ .setVar("templateId", form.getTemplateId())
+ .doPageQuery(form.getPageNumber(), form.getPageSize(), TemplateChangeView.class);
+
+ results.getResult().forEach(item -> {
+ if (item.getPreTemplateId() != null) {
+ Parameter parameter = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("selectParametersByTemplateId")
+ .setVar("templateId", item.getPreTemplateId())
+ .eq("parameter_number", item.getParameterNumber())
+ .doQueryFirst(Parameter.class);
+ BeanUtils.copyProperties(item, parameter);
+ }
+ });
+
+ return results;
+ }
+
+ @Override
+ public ApprovalFlowView getApprovalProcess(ApprovalFlowForm form) {
+ ApprovalFlowView approvalFlowView = new ApprovalFlowView();
+ ApprovalFlow flow = bd.getBusinessDatabase()
+ .eq("id", form.getFlowId())
+ .eq("flow_type", 1)
+ .doQueryFirst(ApprovalFlow.class);
+ approvalFlowView.setExplanation(flow.getExplanation());
+ approvalFlowView.setProofreadNodes(getNodeList(form.getFlowId(), "PROOFREAD"));
+ approvalFlowView.setReviewNodes(getNodeList(form.getFlowId(), "REVIEW"));
+ approvalFlowView.setCountersignNodes(getNodeList(form.getFlowId(), "COUNTERSIGN"));
+ approvalFlowView.setApproveNodes(getNodeList(form.getFlowId(), "APPROVE"));
+
+ approvalFlowView.setFlowStatus(flow.getFlowStatus());
+ return approvalFlowView;
+ }
+
+ private List getNodeList(String flowId, String node) {
+ List list = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("getApprovalNodeInfo")
+ .setVar("flowId", flowId)
+ .setVar("node", node)
+ .doQuery(ApprovalNodeView.class);
+ if (list != null && !list.isEmpty()) {
+ list.forEach(approvalNodeView -> {
+ ApprovalXdapUsers user = runtimeDatasourceService.buildTenantNoSchemaMpaasQuery()
+ .eq("id", approvalNodeView.getUserId())
+ .doQueryFirst(ApprovalXdapUsers.class);
+ approvalNodeView.setUserName(user.getUsername());
+ approvalNodeView.setUserId(null);
+ });
+ }
+ return list;
+ }
+
+ // 处理下一节点流转
+ private void processNextNode(ApprovalFlow flow, String currentNode) {
+ // 检查当前节点是否满足流转条件
+ if (!checkNodeComplete(flow, currentNode)) {
+ return; // 未满足条件,不流转
+ }
+
+ // 更新模板状态
+ Template template = bd.getBusinessDatabase()
+ .eq("id", flow.getTemplateId())
+ .doQueryFirst(Template.class);
+ String nextNode = getNextNode(currentNode, flow);
+
+ if (nextNode == null) {
+ // 流程结束
+ flow.setFlowStatus("COMPLETE");
+ flow.setCurrentNode(null);
+ template.setStatus("COMPLETE");
+ bd.getBusinessDatabase()
+ .rowid("id", template.getRowId())
+ .update("status", template.getStatus())
+ .update("published_time", Timestamp.valueOf(LocalDateTime.now()))
+ .doUpdate(Template.class);
+ clearProcessed(flow);
+ } else {
+ flow.setCurrentNode(nextNode);
+ addNodeTodo(flow, nextNode);
+ }
+
+ bd.getBusinessDatabase()
+ .rowid("id", flow.getRowId())
+ .update("flow_status", flow.getFlowStatus())
+ .update("current_node", flow.getCurrentNode())
+ .doUpdate(ApprovalFlow.class);
+ // 清除当前节点待办
+ clearNodeTodoSmart(flow, currentNode, nextNode);
+ }
+
+ // 获取下一节点
+ private String getNextNode(String currentNode, ApprovalFlow flow) {
+ switch (currentNode) {
+ case "PROOFREAD":
+ return "REVIEW";
+ case "REVIEW":
+ return flow.getCountersignUsers() != null && !JSON.parseArray(flow.getCountersignUsers()).isEmpty()
+ ? "COUNTERSIGN" : "APPROVE";
+ case "COUNTERSIGN":
+ return "APPROVE";
+ case "APPROVE":
+ return null; // 流程结束
+ default:
+ return null;
+ }
+ }
+
+ // 检查节点是否完成
+ private boolean checkNodeComplete(ApprovalFlow flow, String node) {
+ String key = NODE_PROCESSED_PREFIX + flow.getId() + ":" + node;
+ Long processedCount = redisTemplate.opsForSet().size(key);
+ if (processedCount == null) processedCount = 0L;
+
+ // 会签节点需要所有人处理,其他节点只需1人
+ if ("COUNTERSIGN".equals(node)) {
+ return processedCount.equals((long) JSON.parseArray(flow.getCountersignUsers()).size());
+ } else {
+ return processedCount >= 1;
+ }
+ }
+
+ private void cancelProcess(ApprovalFlow flow, String status) {
+ flow.setFlowStatus(status);
+ bd.getBusinessDatabase()
+ .rowid("id", flow.getRowId())
+ .update("status", flow.getFlowStatus())
+ .doUpdate(ApprovalFlow.class);
+ // 更新模板状态
+ Template template = bd.getBusinessDatabase()
+ .eq("id", flow.getTemplateId())
+ .doQueryFirst(Template.class);
+ template.setStatus(status);
+ bd.getBusinessDatabase()
+ .rowid("id", template.getRowId())
+ .update("status", template.getStatus())
+ .doUpdate(Template.class);
+ // 清除所有待办
+ clearAllTodo(flow);
+ clearProcessed(flow);
+ }
+
+ private boolean hasPermission(ApprovalFlow flow, String node, String userId) {
+ switch (node) {
+ case "PROOFREAD":
+ return JSON.parseArray(flow.getProofreadUsers()).toJavaList(String.class).contains(userId);
+ case "REVIEW":
+ return JSON.parseArray(flow.getReviewUsers()).toJavaList(String.class).contains(userId);
+ case "COUNTERSIGN":
+ return flow.getCountersignUsers() != null && JSON.parseArray(flow.getCountersignUsers()).toJavaList(String.class).contains(userId);
+ case "APPROVE":
+ return JSON.parseArray(flow.getApproveUsers()).toJavaList(String.class).contains(userId);
+ default:
+ return false;
+ }
+ }
+
+ private void addNodeTodo(ApprovalFlow flow, String node) {
+ List users = getNodeUsers(flow, node);
+ users.forEach(userId -> {
+ redisTemplate.opsForSet().add(TODO_PREFIX+ userId, flow.getId());
+ });
+ }
+
+ private void clearNodeTodo(ApprovalFlow flow, String node) {
+ List users = getNodeUsers(flow, node);
+ users.forEach(userId -> {
+ redisTemplate.opsForSet().remove(TODO_PREFIX+ userId, flow.getId());
+ });
+ }
+
+ private void clearProcessed(ApprovalFlow flow) {
+ redisTemplate.delete(NODE_PROCESSED_PREFIX + flow.getId() + ":" + "PROOFREAD");
+ redisTemplate.delete(NODE_PROCESSED_PREFIX + flow.getId() + ":" + "REVIEW");
+ if (flow.getCountersignUsers() != null) {
+ redisTemplate.delete(NODE_PROCESSED_PREFIX + flow.getId() + ":" + "COUNTERSIGN");
+ }
+ redisTemplate.delete(NODE_PROCESSED_PREFIX + flow.getId() + ":" + "APPROVE");
+ }
+
+ private void clearAllTodo(ApprovalFlow flow) {
+ clearNodeTodo(flow, "PROOFREAD");
+ clearNodeTodo(flow, "REVIEW");
+ if (flow.getCountersignUsers() != null) {
+ clearNodeTodo(flow, "COUNTERSIGN");
+ }
+ clearNodeTodo(flow, "APPROVE");
+ }
+
+ private void clearNodeTodoSmart(ApprovalFlow flow, String currentNode, String nextNode) {
+ List currentNodeUsers = getNodeUsers(flow, currentNode);
+ List nextNodeUsers = nextNode != null ? getNodeUsers(flow, nextNode) : Collections.emptyList();
+
+ // 只清除那些不在下一节点的用户的待办
+ for (String userId : currentNodeUsers) {
+ if (!nextNodeUsers.contains(userId)) {
+ redisTemplate.opsForSet().remove(TODO_PREFIX + userId, flow.getId());
+ }
+ }
+ }
+
+ private List getNodeUsers(ApprovalFlow flow, String node) {
+ switch (node) {
+ case "PROOFREAD": return JSON.parseArray(flow.getProofreadUsers()).toJavaList(String.class);
+ case "REVIEW": return JSON.parseArray(flow.getReviewUsers()).toJavaList(String.class);
+ case "COUNTERSIGN": return JSON.parseArray(flow.getCountersignUsers()).toJavaList(String.class);
+ case "APPROVE": return JSON.parseArray(flow.getApproveUsers()).toJavaList(String.class);
+ default: return Collections.emptyList();
+ }
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/service/impl/TemplateServiceImpl.java b/src/main/java/com/xdap/self_development/service/impl/TemplateServiceImpl.java
new file mode 100644
index 0000000..0ab7067
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/service/impl/TemplateServiceImpl.java
@@ -0,0 +1,273 @@
+package com.xdap.self_development.service.impl;
+
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
+import com.definesys.mpaas.common.exception.MpaasBusinessException;
+import com.definesys.mpaas.common.exception.MpaasRuntimeException;
+import com.definesys.mpaas.query.db.PageQueryResult;
+import com.xdap.self_development.config.BusinessDatabase;
+import com.xdap.self_development.controller.form.*;
+import com.xdap.self_development.listener.SheetDataListener;
+import com.xdap.self_development.pojo.Parameter;
+import com.xdap.self_development.pojo.RevisionRecord;
+import com.xdap.self_development.pojo.Template;
+import com.xdap.self_development.pojo.TemplateAndParameter;
+import com.xdap.self_development.service.TemplateService;
+import com.xdap.self_development.utils.FormulaValidator;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class TemplateServiceImpl implements TemplateService {
+ @Resource
+ private BusinessDatabase bd;
+
+ @Override
+ public PageQueryResult getTemplateByCondition(TemplatePageForm form) {
+ return bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("getLatestTemplate")
+ .like("template_name", form.getTemplateName())
+ .doPageQuery(form.getPageNumber(), form.getPageSize(), Template.class);
+ }
+
+ @Override
+ public void insertTemplate(InsertTemplateForm form) {
+ Template template = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("getNewTemplate")
+ .eq("template_name", form.getTemplateName())
+ .doQueryFirst(Template.class);
+
+ Template newTemplate = new Template(
+ form.getTemplateName(), 1, "DRAFT", Timestamp.valueOf(LocalDateTime.now()),
+ null, form.getCreateBy()
+ );
+
+ if (template != null) {
+ newTemplate.setVersion(template.getVersion()+1);
+ }
+
+ bd.getBusinessDatabase().doInsert(newTemplate);
+ }
+
+ @Override
+ public void updateTemplate(UpdateTemplateForm form) {
+ Template template = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("getLatestTemplate")
+ .eq("template_name", form.getTemplateName())
+ .doQueryFirst(Template.class);
+ if (template != null) {
+ //TODO:可能要在修改为其他模板名也要成功
+ throw new MpaasBusinessException("模板重复");
+ }
+
+ Template newTemplate = new Template(
+ form.getTemplateName(), 1, "DRAFT", Timestamp.valueOf(LocalDateTime.now()),
+ null, form.getCreateBy()
+ );
+
+ bd.getBusinessDatabase()
+ .rowid("id", form.getTemplateRowId())
+ .doUpdate(newTemplate);
+ }
+
+ @Override
+ @Transactional(rollbackFor = MpaasBusinessException.class)
+ public void importTemplate(MultipartFile file, String templateRowId, String createBy) {
+ if (file == null) {
+ throw new MpaasBusinessException("模板文件异常");
+ }
+
+ try (InputStream inputStream = file.getInputStream()){
+ EasyExcel.read(
+ inputStream,
+ Parameter.class,
+ new SheetDataListener(this, templateRowId, createBy)
+ ).doReadAll();
+ } catch (IOException e) {
+ throw new MpaasRuntimeException("读取文件失败");
+ }
+ }
+
+ @Override
+ public void exportTemplate(ExportTemplateForm form, HttpServletResponse response) {
+ Template templateDB = bd.getBusinessDatabase()
+ .rowid("id", form.getTemplateRowId())
+ .doQueryFirst(Template.class);
+
+ String fileName = templateDB.getTemplateName() +
+ (form.isTemplateEmpty() ? "空模板_" : "参数模板_") +
+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"));
+
+ try {
+ String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
+ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+ response.setCharacterEncoding("UTF-8");
+ response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + encodedFileName + ".xlsx");
+ response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+ response.setHeader("Pragma", "no-cache");
+ response.setDateHeader("Expires", 0);
+
+ List list;
+ if (form.isTemplateEmpty()) {
+ list = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("selectParametersByTemplateId")
+ .setVar("templateId", templateDB.getId())
+ .select("parameterName", "parameterNumber")
+ .orderBy("parameterNumber", "asc")
+ .doQuery(Parameter.class);
+ } else {
+ list = bd.getBusinessDatabase()
+ .viewQueryMode(true)
+ .view("selectParametersByTemplateId")
+ .setVar("templateId", templateDB.getId())
+ .orderBy("parameterNumber", "asc")
+ .doQuery(Parameter.class);
+ }
+ EasyExcel.write(response.getOutputStream(), Parameter.class)
+ .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
+ .includeColumnFieldNames(getIncludeColumnFieldNames())
+ .sheet(templateDB.getTemplateName())
+ .doWrite(list);
+
+ } catch (Exception e) {
+ throw new MpaasRuntimeException("导出Excel失败: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public List getTemplateVersion(TemplateRowIdForm form) {
+ Template template = bd.getBusinessDatabase()
+ .rowid("id", form.getTemplateRowId())
+ .doQueryFirst(Template.class);
+ return bd.getBusinessDatabase()
+ .eq("template_name", template.getTemplateName())
+ .orderBy("version", "desc")
+ .doQuery(Template.class);
+ }
+
+
+ public void processSheetData(List dataList, String sheetName,
+ String templateRowId, String createBy) {
+ if (dataList.isEmpty()) {
+ log.warn("Sheet {} 没有数据", sheetName);
+ return;
+ }
+ // 验证公式
+ for (Parameter data : dataList) {
+ if (Objects.equals(data.getParameterSource(), "公式计算")||Objects.equals(data.getParameterSource(), "公式运算")) {
+ Map validationResult = FormulaValidator.validateFormulaDetailed(
+ data.getNumberOrFormula());
+ if (!(Boolean) validationResult.get("isValid")) {
+ String errorMsg = String.format("Sheet '%s' 的参数 '%s' 公式格式错误: %s",
+ sheetName, data.getParameterName(),
+ validationResult.get("errorMessage"));
+ throw new MpaasBusinessException(errorMsg);
+ }
+ }
+ }
+ // 处理模板版本
+ String templateName = sheetName;
+ if (templateRowId != null && !templateRowId.isEmpty()) {
+ Template t = bd.getBusinessDatabase()
+ .rowid("id", templateRowId)
+ .doQueryFirst(Template.class);
+ templateName = t.getTemplateName();
+
+ if (!Objects.equals(templateName, sheetName)) {
+ throw new MpaasBusinessException("Excel页名不正确或模板名不正确");
+ }
+ }
+ Template lastTemplate = bd.getBusinessDatabase()
+ .eq("template_name", templateName)
+ .orderBy("version", "desc")
+ .doQueryFirst(Template.class);
+
+ // 有最新版本
+ if (lastTemplate != null) {
+ List list = bd.getBusinessDatabase()
+ .eq("template_id", lastTemplate.getId())
+ .doQuery(TemplateAndParameter.class);
+ // 最新版本不为空,创建新版本
+ if (!list.isEmpty()) {
+ Integer v = lastTemplate.getVersion()+1;
+ lastTemplate = new Template(
+ templateName, v, "DRAFT", Timestamp.valueOf(LocalDateTime.now()),
+ null, createBy
+ );
+ bd.getBusinessDatabase()
+ .doInsert(lastTemplate);
+ }
+ // 否则延用该版本
+ } else {
+ lastTemplate = new Template(
+ templateName, 1, "DRAFT", Timestamp.valueOf(LocalDateTime.now()),
+ null, createBy
+ );
+ bd.getBusinessDatabase()
+ .doInsert(lastTemplate);
+ }
+
+
+ // TODO:导入参数时的日志先不记录
+ // 保存参数和关联关系
+ bd.getBusinessDatabase().doBatchInsert(dataList);
+
+ Template finalLastTemplate = lastTemplate;
+ List relations = dataList.stream()
+ .map(parameter -> {
+ TemplateAndParameter relation = new TemplateAndParameter();
+ relation.setTemplateId(finalLastTemplate.getId());
+ relation.setParameterId(parameter.getId());
+ return relation;
+ })
+ .collect(Collectors.toList());
+ List revisionRecords = dataList.stream()
+ .map(parameter -> {
+ RevisionRecord revision = new RevisionRecord();
+ revision.setTemplateName(finalLastTemplate.getTemplateName());
+ revision.setVersion(finalLastTemplate.getVersion());
+ revision.setParameterNumber(parameter.getParameterNumber());
+ revision.setModifyDetails("新增参数");
+ revision.setTemplateId(finalLastTemplate.getId());
+ return revision;
+ })
+ .collect(Collectors.toList());
+
+ bd.getBusinessDatabase().doBatchInsert(relations);
+ bd.getBusinessDatabase().doBatchInsert(revisionRecords);
+ log.info("Sheet '{}' 导入完成,共处理 {} 个参数", sheetName, dataList.size());
+ }
+
+ private static Set getIncludeColumnFieldNames() {
+ Set includeColumnFieldNames;
+ includeColumnFieldNames = new HashSet<>();
+ includeColumnFieldNames.add("parameterNumber");
+ includeColumnFieldNames.add("subsystemName");
+ includeColumnFieldNames.add("parameterType");
+ includeColumnFieldNames.add("partsName");
+ includeColumnFieldNames.add("parameterName");
+ includeColumnFieldNames.add("unit");
+ includeColumnFieldNames.add("parameterSource");
+ includeColumnFieldNames.add("numberOrFormula");
+ includeColumnFieldNames.add("department");
+ includeColumnFieldNames.add("remarks");
+ return includeColumnFieldNames;
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/utils/FormulaValidator.java b/src/main/java/com/xdap/self_development/utils/FormulaValidator.java
new file mode 100644
index 0000000..83bb841
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/utils/FormulaValidator.java
@@ -0,0 +1,142 @@
+package com.xdap.self_development.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class FormulaValidator {
+
+ public static Map validateFormulaDetailed(String formula) {
+ Map result = new HashMap<>();
+
+ // 检查公式是否为空
+ if (formula == null || formula.trim().isEmpty()) {
+ result.put("isValid", false);
+ result.put("errorMessage", "公式不能为空");
+ return result;
+ }
+
+ // 定义允许的字符:中文、数字、英文括号、运算符和空格
+ Pattern allowedPattern = Pattern.compile("^[\\u4e00-\\u9fa50-9()*/+\\-\\s.π]+$");
+ Matcher matcher = allowedPattern.matcher(formula);
+
+ if (!matcher.matches()) {
+ result.put("isValid", false);
+
+ // 找出非法字符
+ StringBuilder illegalChars = new StringBuilder();
+ Pattern illegalPattern = Pattern.compile("[^\\u4e00-\\u9fa50-9()*/+\\-\\s.π]");
+ Matcher illegalMatcher = illegalPattern.matcher(formula);
+
+ while (illegalMatcher.find()) {
+ String illegalChar = illegalMatcher.group();
+ if (!illegalChars.toString().contains(illegalChar)) {
+ if (illegalChars.length() > 0) {
+ illegalChars.append(", ");
+ }
+ illegalChars.append("'").append(illegalChar).append("'");
+ }
+ }
+
+ result.put("errorMessage", "公式包含非法字符: " + illegalChars.toString());
+ return result;
+ }
+
+ // 检查括号是否匹配
+ if (!isParenthesesBalanced(formula)) {
+ result.put("isValid", false);
+ result.put("errorMessage", "括号不匹配");
+ return result;
+ }
+
+ // 检查运算符使用是否合理
+ if (hasInvalidOperatorUsage(formula)) {
+ result.put("isValid", false);
+ result.put("errorMessage", "运算符使用不合理");
+ return result;
+ }
+
+ // 检查数字格式是否正确(避免多个小数点等)
+ if (hasInvalidNumberFormat(formula)) {
+ result.put("isValid", false);
+ result.put("errorMessage", "数字格式不正确");
+ return result;
+ }
+
+ result.put("isValid", true);
+ result.put("errorMessage", "公式格式正确");
+ return result;
+ }
+
+ // 检查括号是否匹配
+ private static boolean isParenthesesBalanced(String formula) {
+ int balance = 0;
+ for (char c : formula.toCharArray()) {
+ if (c == '(') {
+ balance++;
+ } else if (c == ')') {
+ balance--;
+ if (balance < 0) {
+ return false; // 闭括号多于开括号
+ }
+ }
+ }
+ return balance == 0;
+ }
+
+ // 检查运算符使用是否合理
+ private static boolean hasInvalidOperatorUsage(String formula) {
+ // 移除所有空格以便检查
+ String cleaned = formula.replaceAll("\\s+", "");
+
+ // 检查开头和结尾的运算符(除了开头的负号)
+ if (cleaned.matches("^[*/+].*") || cleaned.matches(".*[*/+\\-]$")) {
+ return true;
+ }
+
+ // 检查连续的运算符(允许负号的情况)
+ Pattern operatorPattern = Pattern.compile("[*/+\\-]{2,}");
+ Matcher matcher = operatorPattern.matcher(cleaned);
+
+ while (matcher.find()) {
+ String operators = matcher.group();
+ // 允许的运算符组合:*- /- +- -- (负号情况)
+ if (!operators.matches("\\*\\-|/\\-|\\+\\-|\\-\\-")) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // 检查数字格式是否正确
+ private static boolean hasInvalidNumberFormat(String formula) {
+ // 匹配数字模式(包括小数)
+ Pattern numberPattern = Pattern.compile("\\d+\\.\\d*\\.|\\.[\\u4e00-\\u9fa5]|\\.\\.[\\d\\u4e00-\\u9fa5]");
+ Matcher matcher = numberPattern.matcher(formula);
+
+ if (matcher.find()) {
+ return true; // 找到无效的数字格式
+ }
+
+ // 检查以小数点开头或结尾的数字
+ if (formula.matches("^\\..*|.*[^0-9]\\.$")) {
+ return true;
+ }
+
+ return false;
+ }
+
+ // 提取公式中的所有参数(中文参数名和数字)
+ public static void extractParameters(String formula) {
+ // 匹配中文参数名和数字
+ Pattern paramPattern = Pattern.compile("[\\u4e00-\\u9fa5]+|\\d+(?:\\.\\d+)?");
+ Matcher matcher = paramPattern.matcher(formula);
+
+ System.out.println("公式中的参数:");
+ while (matcher.find()) {
+ System.out.println(" - " + matcher.group());
+ }
+ }
+}
diff --git a/src/main/java/com/xdap/self_development/utils/ParameterOperation.java b/src/main/java/com/xdap/self_development/utils/ParameterOperation.java
new file mode 100644
index 0000000..4bb0daf
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/utils/ParameterOperation.java
@@ -0,0 +1,29 @@
+package com.xdap.self_development.utils;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+
+@Getter
+public enum ParameterOperation {
+ INSERT("insert", "新增"),
+ UPDATE("update", "更新"),
+ DELETE("delete", "删除"),
+ UNCHANGED("unchanged", "未修改");
+
+ private final String code;
+ private final String description;
+
+ ParameterOperation(String code, String description) {
+ this.code = code;
+ this.description = description;
+ }
+
+ public static ParameterOperation fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(operation -> operation.code.equals(code))
+ .findFirst()
+ .orElse(UNCHANGED);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/xdap/self_development/utils/RedisLockUtil.java b/src/main/java/com/xdap/self_development/utils/RedisLockUtil.java
new file mode 100644
index 0000000..28ddb3b
--- /dev/null
+++ b/src/main/java/com/xdap/self_development/utils/RedisLockUtil.java
@@ -0,0 +1,38 @@
+package com.xdap.self_development.utils;
+
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class RedisLockUtil {
+ private final StringRedisTemplate redisTemplate;
+
+ public RedisLockUtil(StringRedisTemplate redisTemplate) {
+ this.redisTemplate = redisTemplate;
+ }
+
+ /**
+ * 获取分布式锁
+ * @param key 锁的键(如 "task:lock:任务ID")
+ * @param value 锁的持有者(如用户名)
+ * @param expire 过期时间(避免死锁)
+ * @param unit 时间单位
+ * @return 是否获取成功
+ */
+ public boolean tryLock(String key, String value, long expire, TimeUnit unit) {
+ return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, expire, unit));
+ }
+
+ /**
+ * 释放锁(需校验持有者,避免误释放)
+ * @param key 锁的键
+ * @param value 锁的持有者
+ */
+ public void unlock(String key, String value) {
+ String currentValue = redisTemplate.opsForValue().get(key);
+ if (value.equals(currentValue)) {
+ redisTemplate.delete(key);
+ }
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..38cf3a9
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,267 @@
+apaas.token.url=http://apaas-meim.app.yuchai.com/apaas/backend/a5e8e08/ycgf-yf-rddata
+
+feign.hystrix.enabled=false
+deploy.backend.platform.port=30607
+deploy.rabbit.host=127.0.0.1
+deploy.redis.password=xdapredis
+deploy.redis.host=127.0.0.1
+deploy.front.workbench.port=443
+deploy.front.singleapp.app.prefix=app/a5e8e08/ycgf-yf-rddata
+deploy.front.platform.port=443
+deploy.front.platform.host=apaas-meim.app.yuchai.com
+deploy.rabbit.password=guest
+deploy.front.singleapp.m.prefix=m/a5e8e08/ycgf-yf-rddata
+deploy.front.singleapp.host=apaas-meim.app.yuchai.com
+deploy.redis.port=6379
+deploy.front.workbench.host=apaas-meim.app.yuchai.com
+deploy.backend.platform.host=10.20.52.11
+deploy.powerjob.address=127.0.0.1:7700
+deploy.backend.singleapp.host=apaas-meim.app.yuchai.com
+deploy.rabbit.username=guest
+deploy.rabbit.port=5672
+mpaas.datasource[0].name=xdap_app_223770822127386625
+mpaas.datasource[0].password=qwer12
+activiti.datasource.driverClassName=com.mysql.cj.jdbc.Driver
+apaas.single.datasource.mongoPoolConfig.minSize=0
+apaas.admin.datasource.type=mysql
+apaas.single.datasource.mongoDbName=xdap_app_223770822127386625
+apaas.tenant.init.db.initial-pool-size=30
+activiti.datasource.username=root
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+activiti.datasource.maxActive=50
+apaas.single.datasource.mongoUrl=mongodb://localhost:27017/xdap_app_223770822127386625
+apaas.single.datasource.mongoPoolConfig.maxConnectionLifeTime=3600
+apaas.single.datasource.mongoPoolConfig.maintenanceFrequency=600
+mpaas.datasource[0].minPoolSize=50
+mpaas.datasource[0].url=jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT%2B8&characterEncoding=utf-8
+mpaas.datasource[0].driver-class-name=com.mysql.cj.jdbc.Driver
+apaas.single.datasource.mongoPoolConfig.maxWaitQueueSize=500
+apaas.admin.datasource.username=root
+mpaas.datasource[0].username=root
+apaas.admin.datasource.url=jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT%2B8&characterEncoding=utf-8
+mpaas.datasource[0].maxPoolSize=1000
+mpaas.datasource[0].type=mysql
+
+mpaas.datasource[1].url=jdbc:mysql://127.0.0.1:3306/test_demo?serverTimezone=GMT%2B8&characterEncoding=utf-8
+mpaas.datasource[1].username=root
+mpaas.datasource[1].password=qwer12
+mpaas.datasource[1].type=mysql
+mpaas.datasource[1].name=test_demo
+
+mpaas.datasource[2].url=jdbc:mysql://127.0.0.1:3306/template_db2?serverTimezone=GMT%2B8&characterEncoding=utf-8
+mpaas.datasource[2].username=root
+mpaas.datasource[2].password=qwer12
+mpaas.datasource[2].type=mysql
+mpaas.datasource[2].name=template_db2
+
+apaas.tenant.init.db.max-pool-size=1000
+apaas.hikariConfig.maxLifetimeMs=28800000
+activiti.datasource.inIdle=5
+activiti.datasource.initialSize=5
+activiti.datasource.password=qwer12
+spring.datasource.password=qwer12
+apaas.admin.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+apaas.admin.datasource.password=qwer12
+spring.datasource.username=root
+apaas.single.datasource.mongoPoolConfig.maxSize=100
+spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai&characterEncoding=utf-8
+apaas.single.datasource.mongoPoolConfig.maxConnectionIdleTime=3600
+apaas.single.datasource.mongoPoolConfig.maintenanceInitialDelay=240
+activiti.datasource.url=jdbc:mysql://127.0.0.1:3306/activiti_demo?serverTimezone=Asia/Shanghai&characterEncoding=utf-8
+apaas.single.datasource.mongoPoolConfig.maxWaitTime=120
+spring.activiti.process-definition-location-prefix=classpath:/processes/
+spring.activiti.check-process-definitions=true
+spring.activiti.database-schema-update=true
+spring.activiti.deployment-mode=default
+server.compression.enabled=true
+server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
+token.refreshTtlMillis=1209600000
+token.openTokenRefreshTtlMillis=1209600000
+token.openTokenTtlMillis=7200000
+apaas.single.tenantId=223770822127386625
+server.compression.min-response-size=2048
+apaas.single.appId=771297120740179968
+apaas.single.app-group-app-ids=2b5b3de8-e7fd-406a-a59a-d5568457b1f4
+token.ttlMillis=7200000
+apaas.oauth.app.appOauthTokenUrl=http://mpaas.app.yuchai.com/oauth2/oauth/token
+apaas.oauth.app.appOauthUserSchemaJsonPath=$.userName
+apaas.oauth.app.appOauthOAuthUserUrl=http://mpaas.app.yuchai.com/oauth2/oauth/user
+license.path=/data/resources/license.lic
+license.publicKeyStorePath=/data/resources/publicCerts.keystore
+xdap.apaas.dbselectPriv=false
+spring.application.name=a5e8e08-ycgf-yf-rddata
+baidu.ocr.vatInvoiceUrl=https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice
+dingding.redirectUri=redirect_uri=https%3A%2F%2Fapaas-meim.app.yuchai.com%2Fapp%2Fa5e8e08%2Fycgf-yf-rddata%2Fcallback%2Fdingding%2Findex.html&response_type=code&prompt=consent&scope=openid
+baidu.ocr.appId=23499932
+dingding.pageLink=null
+dingding.userIdByMobileUrl=https://oapi.dingtalk.com/topapi/v2/user/getbymobile
+baidu.ocr.apiKey=HHRFL3VPtnj7Nle60ytbGMls
+baidu.ocr.basicGeneralUrl=https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic
+dingding.userAccessTokenUrl=https://api.dingtalk.com/v1.0/oauth2/userAccessToken
+dingding.sendMessageUrl=https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend
+feishu.feiShuUrlPre=https://open.feishu.cn/open-apis/authen/v1/index?
+dingding.authUrlPre=https://login.dingtalk.com/oauth2/auth?
+aliyun.oss.accessKeyId=LTAI4GEC6ssfFDuVDUL3TbLp
+dingding.userInfoUrl=https://api.dingtalk.com/v1.0/contact/users/me
+aliyun.oss.endpoint=http://oss-cn-shanghai.aliyuncs.com
+feishu.getOpenIdUrl=https://open.feishu.cn/open-apis/user/v1/batch_get_id?mobiles=
+apaasworkwechat.message.wxOAuth2url=https://open.weixin.qq.com/connect/oauth2/authorize?appid=${CORPID!""}&redirect_uri=${URL!""}callback%2Fwe-com%2Findex.html&response_type=code&scope=snsapi_privateinfo&state=${STATE!""}&agentid=${AGENTID!""}#wechat_redirect
+baidu.ocr.secretKey=VTvrrMjZZC1xtYfu82cfUhjeYgNTRIHe
+baidu.ocr.accessTokenUrl=https://aip.baidubce.com/oauth/2.0/token?
+aliyun.oss.accessKeySecret=ZpbgWTt2qfK68lQILqj0H3EdIun1Qf
+feishu.getTokenUrl=https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal/
+dingding.appAccessTokenUrl=https://oapi.dingtalk.com/gettoken
+apaasworkwechat.message.workWechatUrlPre=null
+baidu.ocr.businessCardUrl=https://aip.baidubce.com/rest/2.0/ocr/v1/business_card
+feishu.feiShuRedirectUri=redirect_uri=https%3A%2F%2Fapaas-meim.app.yuchai.com%2Fapp%2Fa5e8e08%2Fycgf-yf-rddata%2Fcallback%2Ffeishu%2Findex.html
+baidu.ocr.accessTokenKey=BAIDU_OCR_KEY
+management.endpoints.web.exposure.include=*
+spring.rabbitmq.password=guest
+spring.redis.host=127.0.0.1
+powerjob.akka-port=27777
+powerjob.worker.akka-port=27777
+spring.rabbitmq.host=127.0.0.1
+spring.redis.jedis.pool.min-idle=0
+powerjob.server-address=127.0.0.1:7700
+powerjob.worker.server-address=127.0.0.1:7700
+server.port=9091
+management.health.db.enabled=false
+spring.redis.database=0
+spring.redis.jedis.pool.max-wait=-1
+spring.rabbitmq.port=5672
+spring.redis.port=6379
+powerjob.app-name=49b90be5-eebe-4359-a
+spring.rabbitmq.username=guest
+powerjob.store-strategy=disk
+powerjob.worker.app-name=49b90be5-eebe-4359-a
+powerjob.enable-test-mode=false
+management.endpoint.health.show-details=always
+powerjob.worker.enabled=false
+powerjob.worker.enable-test-mode=true
+spring.redis.jedis.pool.max-idle=8
+spring.redis.timeout=10000
+powerjob.worker.store-strategy=disk
+spring.redis.jedis.pool.max-active=20
+xdap.jobServerUrl=http://localhost:7700
+xdap.adminUrl=gateway.yctp.yuchaidev.com/apaas/xdap-admin
+feign.client.config.default.read-timeout=50000
+xdap.gatewayUrl=gateway.yctp.yuchaidev.com/apaas/gateway
+xdap.jobUrl=http://127.0.0.1:${server.port:9091}/xdap-job
+xdap.openappUrl=http://127.0.0.1:${server.port:9091}/xdap-app
+xdap.appUrl=http://127.0.0.1:${server.port:9091}/xdap-app
+feign.client.config.default.connect-timeout=20000
+#xdap.singleAdminAppUrl=http://10.20.52.58:30607/xdap-app
+xdap.snow.data-center-id=0
+xdap.snow.workId=192
+mpaas.security=false
+xdap.avatar.prefix=/xdap-app/attachments/downloadFile?file=
+xdap.share.frontSingleAppHost=https://apaas-meim.app.yuchai.com/app/a5e8e08/ycgf-yf-rddata/
+xdap.avatar.path=/resource/head_portrait/
+xdap.skipDetailurl=https://apaas-meim.app.yuchai.com/app/a5e8e08/ycgf-yf-rddata/%s/app/app-page?appId=%s&formId=%s&title=%s¤tMenu=%s&documentId=%s
+xdap.share.pcSkipUrl=blank/public-form?shareId=
+xdap.share.frontSingleMobileHost=https://apaas-meim.app.yuchai.com/m/a5e8e08/ycgf-yf-rddata/
+xdap.avatar.adminBucketName=xdap-admin-dev
+apaas.single.private=true
+xdap.avatar.enableDynamicsPrefix=false
+spring.jackson.default-property-inclusion=non_null
+xdap.avatar.bucketName=xdap-app-dev
+xdap.share.editAfterShareUrl=/xdap-app/formShareSkip/skip/shareUrl?shareId=
+xdap.todourl=https://apaas-meim.app.yuchai.com/workbench/app/%s/todoCenter/myTodo/?formId=%s&documentId=%s&processId=%s
+logging.file=log/xdap-app.log
+xdap.skipurl=https://apaas-meim.app.yuchai.com/app/a5e8e08/ycgf-yf-rddata/%s/app/app-page?appId=%s&formId=%s&title=%s¤tMenu=%s
+xdap.avatar.localPath=/data/resources/attachments/
+spring.servlet.multipart.max-file-size=150MB
+logging.config=classpath:logback-spring.xml
+xdap.apaas.private=true
+xdap.todocenter=https://apaas-meim.app.yuchai.com/workbench/app/%s/todoCenter/myTodo
+mpaas.query.dbadatper=mysql
+mpaas.query.security.mode=custom
+xdap.avatar.adminPrefix=https://apaas-meim.app.yuchai.com/apaas/platform/xdap-admin/attachments/downloadFile?file=
+xdap.invitation.prefix=http://k8s.definesys.com:31005/x-project-app/blank/invite?inviteCode=
+mpaas.query.dbvendor=mysql
+xdap.share.mobileSkipUrl=blank/public-form?shareId=
+spring.servlet.multipart.max-request-size=200MB
+xdap.resource.path=i18n/platform/platform_en_US.properties,i18n/platform/platform_zh_CN.properties,i18n/workbench/workbench_en_US.properties,i18n/workbench/workbench_zh_CN.properties,i18n/app/app_en_US.properties,i18n/app/app_zh_CN.properties,i18n/app/app_ja_JP.properties
+fileformat.whiteList[8]=.ppt
+fileformat.whiteList[29]=.xlsm
+fileformat.whiteList[6]=.doc
+fileformat.whiteList[19]=.md
+fileformat.whiteList[23]=.gz
+fileformat.whiteList[0]=.jpg
+fileformat.whiteList[13]=.zip
+fileformat.whiteList[35]=.dfyx
+fileformat.whiteList[21]=.7z
+fileformat.whiteList[11]=.pdf
+fileformat.whiteList[33]=.xml
+fileformat.whiteList[27]=.log
+fileformat.whiteList[4]=.xls
+fileformat.whiteList[17]=.avi
+fileformat.whiteList[25]=.xml
+fileformat.whiteList[2]=.jfif
+fileformat.whiteList[15]=.mp3
+fileformat.whiteList[37]=.hex
+fileformat.whiteList[31]=.yaml
+fileformat.whiteList[7]=.docx
+fileformat.whiteList[5]=.xlsx
+fileformat.whiteList[18]=.mov
+fileformat.whiteList[9]=.pptx
+fileformat.whiteList[12]=.txt
+fileformat.whiteList[34]=.dfy
+fileformat.whiteList[24]=.csv
+fileformat.whiteList[10]=.gif
+fileformat.whiteList[32]=.properties
+fileformat.whiteList[22]=.tar
+fileformat.whiteList[3]=.png
+fileformat.whiteList[16]=.mp4
+fileformat.whiteList[28]=.keystore
+fileformat.whiteList[1]=.jpeg
+fileformat.whiteList[14]=.rar
+fileformat.whiteList[36]=.svg
+fileformat.whiteList[26]=.jar
+fileformat.whiteList[30]=.yml
+fileformat.whiteList[20]=.json
+spring.cloud.nacos.discovery.enabled=false
+spring.cloud.nacos.config.refresh-enabled=false
+spring.cloud.nacos.discovery.instance-enabled=false
+apaas.deploy.type=null
+spring.cloud.nacos.config.enabled=false
+standard.plan.appTtlMillis=3600000
+standard.plan.userTtlMillis=7200000
+xdap.apaas.interface.encrypt.appEncryptionForceOpen=DISABLE
+xdap.apaas.interface.encrypt.appEncryptionType=SM2
+xdap.apaas.interface.encrypt.appEncryptionStatus=DISABLE
+xdap.apaas.interface.encrypt.encryptType=DISABLE
+xdap.apaas.decryptProperties=DO_ENCRYPT
+xdap.apaas.interface.encrypt.privateKeyHex=4b6b9fa1be0757bf4977344c634c4ac2b0c907cd3b225ea16b674b8348ffdcde
+xdap.apaas.interface.encrypt.publicKeyHex=04919f2130b035e29f079b4dace907e3cad716556f93574f1f2d61685f6a5ac251cba81822062353a07fd69f2c544f2263f217e04b3af327453c1f9157a434e0de
+xdap.apaas.zuc.iv=null
+xdap.apaas.zuc.k=null
+xdap.password.forceModify=DISABLE
+xdap.password.passwordValidateMessage=\u5bc6\u7801\u9700\u5305\u542b\u6570\u5b57\u3001\u5b57\u6bcd\u5927\u5c0f\u5199\u548c\u7279\u6b8a\u5b57\u7b26\uff0c\u4e0d\u5c11\u4e8e8\u4f4d
+xdap.password.passwordValidateRule=^.*(?=.{8,32})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*?.() +-_~,=]).*$
+xdap.header.accessControlAllowOrigin[0]=*
+apaas.cache.usemq=true
+apaas.bizevent.async=false
+xdap.apaas.cache.run.init=true
+mpaas.query.bigdatathresholdvalue=100000
+xdap.process.suspendTimeFlag=ENABLE
+xdap.process.batchOption=20
+apaas.tenant.initDataModel=true
+download.config.downloadType=PERMANENT
+download.config.effectiveTime=168
+download.config.publicKeyHex=04919f2130b035e29f079b4dace907e3cad716556f93574f1f2d61685f6a5ac251cba81822062353a07fd69f2c544f2263f217e04b3af327453c1f9157a434e0de
+download.config.privateKeyHex=4b6b9fa1be0757bf4977344c634c4ac2b0c907cd3b225ea16b674b8348ffdcde
+i18n.frontProjects[8]=x-dcloud-page-mobile
+i18n.frontProjects[9]=x-dcloud-page-web
+i18n.frontProjects[6]=x-dcloud-business-event
+i18n.frontProjects[7]=x-dcloud-page-engine
+i18n.frontProjects[10]=xui
+i18n.backendProjects[0]=app
+i18n.backendProjects[2]=workbench
+i18n.backendProjects[1]=platform
+i18n.frontProjects[0]=app
+i18n.frontProjects[1]=app-h5
+i18n.frontProjects[4]=workbench
+i18n.frontProjects[5]=workbench-h5
+i18n.frontProjects[2]=common
+i18n.frontProjects[3]=platform-admin
\ No newline at end of file