模板管理

This commit is contained in:
zjh 2025-12-02 10:03:59 +08:00
parent 83c8be6230
commit 5a11390c19
69 changed files with 4435 additions and 0 deletions

166
pom.xml Normal file
View File

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xdap</groupId>
<artifactId>self_development</artifactId>
<version>1.0-SNAPSHOT</version>
<name>self_development</name>
<description>自开发后端</description>
<repositories>
<repository>
<id>dcloud-public</id>
<url>https://registry.dfy.definesys.cn/repository/maven-public/</url>
</repository>
</repositories>
<properties>
<java.version>1.8</java.version>
<groovy.eclipse.compiler.version>2.9.2-01</groovy.eclipse.compiler.version>
<groovy.eclipse.batch.version>2.4.3-01</groovy.eclipse.batch.version>
<papaas.version>4.0.7-rc</papaas.version>
<mpaas.version>apaas-1.1.18.4-RELEASE</mpaas.version>
<lombok.version>1.18.12</lombok.version>
<plugins.version>2.0.0</plugins.version>
</properties>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.15</version>
</dependency>
<dependency>
<groupId>com.xdap</groupId>
<artifactId>runtime</artifactId>
<version>${papaas.version}</version>
<exclusions>
<exclusion>
<groupId>com.definesys.mpaas</groupId>
<artifactId>query-mongodb</artifactId>
</exclusion>
<exclusion>
<groupId>com.xdap</groupId>
<artifactId>xdap-plugins-common</artifactId>
</exclusion>
<exclusion>
<groupId>com.xdap</groupId>
<artifactId>common</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.definesys.mpaas</groupId>
<artifactId>query-mongodb</artifactId>
<version>${mpaas.version}</version>
</dependency>
<dependency>
<groupId>com.xdap</groupId>
<artifactId>xdap-plugins-common</artifactId>
<version>${plugins.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.14.0-rc1</version>
</dependency>
<dependency>
<groupId>com.xdap</groupId>
<artifactId>common</artifactId>
<version>${papaas.version}</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>single</id>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerId>groovy-eclipse-compiler</compilerId>
<verbose>true</verbose>
<compilerArguments>
<javaAgentClass>lombok.launch.Agent</javaAgentClass>
</compilerArguments>
<fork>true</fork>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-compiler</artifactId>
<version>${groovy.eclipse.compiler.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-batch</artifactId>
<version>${groovy.eclipse.batch.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-api</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/application.properties</exclude>
<exclude>**/*.yml</exclude>
</excludes>
</resource>
</resources>
</build>
</profile>
<profile>
<id>lib</id>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.yml</exclude>
</excludes>
</resource>
</resources>
</build>
</profile>
</profiles>
</project>

View File

@ -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);
}
}

View File

@ -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");
}
}

View File

@ -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("*");
}
}

View File

@ -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<String> getCustomAllowUrls() {
Set<String> urlSet = new HashSet<>();
urlSet.add("/custom/*");
return urlSet;
}
}

View File

@ -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<TodoAndReportView> 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);
}
}

View File

@ -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<String, Object> 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<Template> templates = bd.getBusinessDatabase().doQuery(Template.class);
List<Parameter> parameters = bd.getBusinessDatabase().doQuery(Parameter.class);
List<TemplateAndParameter> templateAndParameters = bd.getBusinessDatabase().doQuery(TemplateAndParameter.class);
List<RevisionRecord> revisionRecords = bd.getBusinessDatabase().doQuery(RevisionRecord.class);
Map<String, Object> 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<TemplateAndParameter> templateAndParameters = bd.getBusinessDatabase()
.eq("template_id", template.getId())
.doQuery(TemplateAndParameter.class);
List<String> ids = templateAndParameters.stream()
.map(TemplateAndParameter::getId)
.collect(Collectors.toList());
List<String> parameterIds = templateAndParameters.stream()
.map(TemplateAndParameter::getParameterId)
.collect(Collectors.toList());
List<RevisionRecord> revisionRecords = bd.getBusinessDatabase()
.eq("template_id", template.getId())
.doQuery(RevisionRecord.class);
List<String> 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<ApprovalFlow> flows = bd.getBusinessDatabase().doQuery(ApprovalFlow.class);
List<ApprovalRecord> records = bd.getBusinessDatabase().doQuery(ApprovalRecord.class);
Map<String, Object> 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();
}
}

View File

@ -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<Parameter> 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);
}
}

View File

@ -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<ResponsiblePerson> deptResponsible =
responsiblePersonService.getDeptResponsible(form);
return Response.ok().data(deptResponsible);
}
// 根据部门id获取子部门
@GetMapping("/getSubDepartmentById")
public Response getSubDepartmentById(
@RequestParam(defaultValue = "") String departmentId
) {
List<XdapDepartments> 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<DepartmentUserView> 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<String> 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();
}
}

View File

@ -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<DepartmentUserView> 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<TemplateChangeView> 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);
}
}

View File

@ -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<Template> 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<Template> list = templateService.getTemplateVersion(form);
return Response.ok().data(list);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<String> proofreadUsers;
@NotEmpty(message = "审核人员不能为空")
private List<String> reviewUsers;
private List<String> countersignUsers; // 可选
@NotEmpty(message = "批准人员不能为空")
private List<String> approveUsers;
@NotBlank(message = "发起人不能为空")
private String createBy;
private String explanation;
}

View File

@ -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<String> proofreadUsers;
@NotEmpty(message = "审核人员不能为空")
private List<String> reviewUsers;
private List<String> countersignUsers; // 可选
@NotEmpty(message = "批准人员不能为空")
private List<String> approveUsers;
@NotBlank(message = "发起人不能为空")
private String createBy;
private String explanation;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<ParameterForm> parameterForms;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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());
}
}
}

View File

@ -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<Parameter> {
private static final int BATCH_SIZE = 100;
private final TemplateService templateService;
private final String templateRowId;
private final String createBy;
private List<Parameter> 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<Integer, ReadCellData<?>> 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();
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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<ApprovalNodeView> proofreadNodes;
private List<ApprovalNodeView> reviewNodes;
private List<ApprovalNodeView> countersignNodes;
private List<ApprovalNodeView> approveNodes;
private String flowStatus;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,9 @@
package com.xdap.self_development.pojo.view;
import lombok.Data;
@Data
public class TemplateInfoView {
private String templateRowId;
private Integer version;
}

View File

@ -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;
}

View File

@ -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<ApprovalXdapUsers> currentApprovers;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp createdTime;
}

View File

@ -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<ApprovalFlow> flows1 = bd.getBusinessDatabase()
.eq("flow_status", "APPROVING")
.eq("flow_type", 1)
.doQuery(ApprovalFlow.class);
checkFlows(flows1, TODO_PREFIX, NODE_PROCESSED_PREFIX);
List<ApprovalFlow> 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<ApprovalFlow> flows, String todoFlag, String prefixFlag) {
// 遍历每一个流程
flows.forEach(flow -> {
List<String> nodeUsers = getNodeUsers(flow, flow.getCurrentNode());
List<String> 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<String> 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<String> 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();
}
}
}

View File

@ -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<CalculationParameterView> parameterValues = bd.getBusinessDatabase()
.viewQueryMode(true)
.view("getModelParameterValue")
.doQuery(CalculationParameterView.class);
if (parameterValues.isEmpty()) {
log.info("无参数配置,跳过计算");
return;
}
// 维护所有参数的原始值
Map<String, Map<String, String>> originalValueMap = convertMap(parameterValues);
// 构建参数名列表按长度降序排列
List<String> parameterNames = originalValueMap.keySet().stream()
.sorted((a, b) -> Integer.compare(b.length(), a.length()))
.collect(Collectors.toList());
// 遍历参数计算需运算的参数值
List<CalculationParameterView> 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<String> parameterNames,
Map<String, Map<String, String>> 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<String, Map<String, String>> valueMap, String paramName, String modelId) {
Map<String, String> 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<String, Map<String, String>> convertMap(List<CalculationParameterView> 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
)
));
}
}

View File

@ -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<TodoAndReportView> getBenchmarkingReportByCondition(@Valid BenchmarkingReportPageForm form);
void saveBenchmarkingReport(@Valid SaveBenchmarkingReportForm form);
void handleReportApproval(@Valid HandleApprovalRequest request);
BenchmarkingReport getReportDetail(@NotBlank String reportId);
ApprovalFlowView getReportProcess(@NotBlank String flowId);
}

View File

@ -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<Parameter> getParameterByCondition(ParameterPageForm form);
TemplateInfoView maintenanceParameters(UpdateParameterForm form);
}

View File

@ -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<ResponsiblePerson> getDeptResponsible(@Valid DeptResponsiblePageForm form);
Boolean isResponsiblePerson(String userId);
Set<String> getAllSubsystem();
}

View File

@ -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<TodoAndTemplateView> getApprovalList(ApprovalListForm form);
void handleApproval(HandleApprovalRequest request);
PageQueryResult<TemplateChangeView> getTemplateChanges(@Valid ApprovalAndParameterForm form);
ApprovalFlowView getApprovalProcess(@Valid ApprovalFlowForm form);
}

View File

@ -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<Template> getTemplateByCondition(TemplatePageForm form);
void importTemplate(MultipartFile file, String templateRowId, String createBy);
void processSheetData(List<Parameter> dataList, String sheetName,
String templateRowId, String createBy);
void insertTemplate(InsertTemplateForm form);
void updateTemplate(UpdateTemplateForm form);
void exportTemplate(ExportTemplateForm form, HttpServletResponse response);
List<Template> getTemplateVersion(TemplateRowIdForm form);
}

View File

@ -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<String, String> 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<TodoAndReportView> getBenchmarkingReportByCondition(BenchmarkingReportPageForm form) {
List<TodoAndReportView> approvalList = new ArrayList<>();
Set<String> flowIds = redisTemplate.opsForSet().members(TODO_PREFIX + form.getCreateBy());
if (flowIds != null && !flowIds.isEmpty()) {
List<String> ids = new ArrayList<>(flowIds);
List<TodoAndReportView> 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<String> ids = (flowIds == null || flowIds.isEmpty()) ? new ArrayList<>(Collections.singleton("")) : new ArrayList<>(flowIds);
List<TodoAndReportView> 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<TodoAndReportView> approvalList, List<TodoAndReportView> 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<ApprovalNodeView> getNodeList(String flowId, String node) {
List<ApprovalNodeView> 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<String> currentNodeUsers = getNodeUsers(flow, currentNode);
List<String> 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<String> 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<String> users = getNodeUsers(flow, node);
users.forEach(userId -> {
redisTemplate.opsForSet().remove(TODO_PREFIX+ userId, flow.getId());
});
}
private List<String> 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();
}
}
}

View File

@ -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<Parameter> 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<String, Object> 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<Parameter> 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<Parameter> parameters;
}
/**
* 参数处理结果封装类
*/
@Data
@AllArgsConstructor
private static class ParameterProcessingResult {
private final List<Parameter> newParameters;
private final List<RevisionRecord> revisionRecords;
}
private Integer calculateNextVersion(Integer currentVersion) {
try {
return currentVersion + 1;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("版本号格式错误: " + currentVersion, e);
}
}
private ParameterProcessingResult processParameters(
List<ParameterForm> parameterForms,
List<Parameter> existingParameters,
Template baseTemplate,
Template newTemplate)
{
Map<Integer, Parameter> parameterMap = createParameterMap(existingParameters);
List<Parameter> newParameters = new ArrayList<>();
List<RevisionRecord> 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<Integer, Parameter> createParameterMap(List<Parameter> parameters) {
Map<Integer, Parameter> map = new HashMap<>();
Set<Integer> 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<Parameter> newParameters, List<RevisionRecord> 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<Parameter> 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<Integer, Parameter> parameterMap,
Template newTemplate, List<Parameter> newParameters,
List<RevisionRecord> 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<Integer, Parameter> parameterMap,
Template newTemplate, List<RevisionRecord> 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<Integer, Parameter> parameterMap,
List<Parameter> 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<TemplateAndParameter> 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;
}
}

View File

@ -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<ResponsiblePerson> 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<ResponsiblePerson> 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<ResponsiblePerson> getDeptResponsible(DeptResponsiblePageForm form) {
return bd.getBusinessDatabase()
.viewQueryMode(true).view("getResponsibleAndName")
.doPageQuery(form.getPageNumber(), form.getPageSize(), ResponsiblePerson.class);
}
@Override
public Boolean isResponsiblePerson(String userId) {
List<ResponsiblePerson> responsiblePeople = bd.getBusinessDatabase().eq("userId", userId).doQuery(ResponsiblePerson.class);
return !responsiblePeople.isEmpty();
}
@Override
public Set<String> getAllSubsystem() {
List<Template> templates = bd.getBusinessDatabase().select("template_name").doQuery(Template.class);
return templates.stream().map(Template::getTemplateName).collect(Collectors.toSet());
}
}

View File

@ -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<ApprovalFlow> 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<TodoAndTemplateView> getApprovalList(ApprovalListForm form) {
List<TodoAndTemplateView> approvalList = new ArrayList<>();
Set<String> flowIds = redisTemplate.opsForSet().members(TODO_PREFIX + form.getUserId());
if (flowIds != null && !flowIds.isEmpty()) {
List<String> ids = new ArrayList<>(flowIds);
List<TodoAndTemplateView> 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<String> ids = (flowIds == null || flowIds.isEmpty()) ? new ArrayList<>(Collections.singleton("")) : new ArrayList<>(flowIds);
List<TodoAndTemplateView> 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<TodoAndTemplateView> approvalList, List<TodoAndTemplateView> todoAndTemplateViews) {
todoAndTemplateViews.forEach(item -> {
if (item.getCurrentUsers() == null || item.getCurrentUsers().isEmpty()) {
item.setCurrentApprovers(null);
item.setCurrentUsers(null);
} else {
List<String> userIds = JSON.parseArray(item.getCurrentUsers()).toJavaList(String.class);
List<ApprovalXdapUsers> 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<TemplateChangeView> getTemplateChanges(ApprovalAndParameterForm form) {
PageQueryResult<TemplateChangeView> 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<ApprovalNodeView> getNodeList(String flowId, String node) {
List<ApprovalNodeView> 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<String> users = getNodeUsers(flow, node);
users.forEach(userId -> {
redisTemplate.opsForSet().add(TODO_PREFIX+ userId, flow.getId());
});
}
private void clearNodeTodo(ApprovalFlow flow, String node) {
List<String> 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<String> currentNodeUsers = getNodeUsers(flow, currentNode);
List<String> 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<String> 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();
}
}
}

View File

@ -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<Template> 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<Parameter> 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<Template> 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<Parameter> 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<String, Object> 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<TemplateAndParameter> 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<TemplateAndParameter> relations = dataList.stream()
.map(parameter -> {
TemplateAndParameter relation = new TemplateAndParameter();
relation.setTemplateId(finalLastTemplate.getId());
relation.setParameterId(parameter.getId());
return relation;
})
.collect(Collectors.toList());
List<RevisionRecord> 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<String> getIncludeColumnFieldNames() {
Set<String> 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;
}
}

View File

@ -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<String, Object> validateFormulaDetailed(String formula) {
Map<String, Object> 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());
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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&currentMenu=%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&currentMenu=%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