Преглед изворни кода

running-闵教院,力辰,锡鼎、新天龙、航食、市建管,榕智

pruple_boy пре 2 година
комит
8ac92b4c21
100 измењених фајлова са 4356 додато и 0 уклоњено
  1. 37 0
      .gitignore
  2. 60 0
      mjava-hangshi/pom.xml
  3. 32 0
      mjava-hangshi/src/main/java/com/malk/hangshi/Boot.java
  4. 68 0
      mjava-hangshi/src/main/java/com/malk/hangshi/config/CxfConfig.java
  5. 40 0
      mjava-hangshi/src/main/java/com/malk/hangshi/config/WsInInterceptor.java
  6. 71 0
      mjava-hangshi/src/main/java/com/malk/hangshi/config/WsOutInterceptor.java
  7. 51 0
      mjava-hangshi/src/main/java/com/malk/hangshi/controller/HSController.java
  8. 41 0
      mjava-hangshi/src/main/java/com/malk/hangshi/service/IH3yunWebService.java
  9. 34 0
      mjava-hangshi/src/main/java/com/malk/hangshi/service/InvoiceWebService.java
  10. 46 0
      mjava-hangshi/src/main/java/com/malk/hangshi/service/impl/H3yunWebServiceImpl.java
  11. 56 0
      mjava-hangshi/src/main/java/com/malk/hangshi/service/impl/InvoiceWebServiceImpl.java
  12. 53 0
      mjava-hangshi/src/main/resources/application-dev.yml
  13. 39 0
      mjava-hangshi/src/main/resources/application-prod.yml
  14. 35 0
      mjava-hangshi/src/test/resources/server.sh
  15. 53 0
      mjava-hangshi/target/classes/application-dev.yml
  16. 39 0
      mjava-hangshi/target/classes/application-prod.yml
  17. 5 0
      mjava-hangshi/target/maven-archiver/pom.properties
  18. 0 0
      mjava-hangshi/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
  19. 7 0
      mjava-hangshi/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
  20. BIN
      mjava-hangshi/target/mjava-hangshi.jar.original
  21. 35 0
      mjava-hangshi/target/test-classes/server.sh
  22. 54 0
      mjava-jisuanji/pom.xml
  23. 32 0
      mjava-jisuanji/src/main/java/com/malk/jisuanji/Boot.java
  24. 74 0
      mjava-jisuanji/src/main/java/com/malk/jisuanji/controller/HSController.java
  25. 51 0
      mjava-jisuanji/src/main/resources/application-dev.yml
  26. 33 0
      mjava-jisuanji/src/main/resources/application-prod.yml
  27. 51 0
      mjava-jisuanji/target/classes/application-dev.yml
  28. 33 0
      mjava-jisuanji/target/classes/application-prod.yml
  29. 5 0
      mjava-jisuanji/target/maven-archiver/pom.properties
  30. 0 0
      mjava-jisuanji/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
  31. 2 0
      mjava-jisuanji/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
  32. BIN
      mjava-jisuanji/target/mjava-jisuanji.jar.original
  33. 54 0
      mjava-lichen/pom.xml
  34. 32 0
      mjava-lichen/src/main/java/com/malk/lichen/Boot.java
  35. 137 0
      mjava-lichen/src/main/java/com/malk/lichen/controller/LiChenController.java
  36. 51 0
      mjava-lichen/src/main/resources/application-dev.yml
  37. 33 0
      mjava-lichen/src/main/resources/application-prod.yml
  38. 35 0
      mjava-lichen/src/test/resources/server.sh
  39. 55 0
      mjava-lichen/src/test/resources/winsw.xml
  40. 51 0
      mjava-lichen/target/classes/application-dev.yml
  41. 33 0
      mjava-lichen/target/classes/application-prod.yml
  42. 5 0
      mjava-lichen/target/maven-archiver/pom.properties
  43. 2 0
      mjava-lichen/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
  44. 2 0
      mjava-lichen/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
  45. BIN
      mjava-lichen/target/mjava-lichen.jar.original
  46. 35 0
      mjava-lichen/target/test-classes/server.sh
  47. 55 0
      mjava-lichen/target/test-classes/winsw.xml
  48. 54 0
      mjava-minjiaoyuan/pom.xml
  49. 32 0
      mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/Boot.java
  50. 98 0
      mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/controller/InviteControl.java
  51. 442 0
      mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/controller/MJYController.java
  52. 161 0
      mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/controller/TestControl.java
  53. 36 0
      mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/schedule/MJYScheduleTask.java
  54. 27 0
      mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/service/MJYService.java
  55. 169 0
      mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/service/impl/MJYImplService.java
  56. 65 0
      mjava-minjiaoyuan/src/main/resources/application-dev.yml
  57. 47 0
      mjava-minjiaoyuan/src/main/resources/application-prod.yml
  58. 35 0
      mjava-minjiaoyuan/src/test/resources/server.sh
  59. 65 0
      mjava-minjiaoyuan/target/classes/application-dev.yml
  60. 47 0
      mjava-minjiaoyuan/target/classes/application-prod.yml
  61. 5 0
      mjava-minjiaoyuan/target/maven-archiver/pom.properties
  62. 7 0
      mjava-minjiaoyuan/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
  63. 7 0
      mjava-minjiaoyuan/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
  64. BIN
      mjava-minjiaoyuan/target/mjava-minjiaoyuan.jar.original
  65. 35 0
      mjava-minjiaoyuan/target/test-classes/server.sh
  66. 54 0
      mjava-rongzhi/pom.xml
  67. 32 0
      mjava-rongzhi/src/main/java/com/malk/rongzhi/Boot.java
  68. 42 0
      mjava-rongzhi/src/main/java/com/malk/rongzhi/controller/RongZhiController.java
  69. 85 0
      mjava-rongzhi/src/main/java/com/malk/rongzhi/controller/ShiJianGuanController.java
  70. 12 0
      mjava-rongzhi/src/main/java/com/malk/rongzhi/repository/dao/RzEkbRecordDao.java
  71. 29 0
      mjava-rongzhi/src/main/java/com/malk/rongzhi/repository/entity/RzEkbRecordPo.java
  72. 57 0
      mjava-rongzhi/src/main/java/com/malk/rongzhi/schedule/RZScheduleTask.java
  73. 34 0
      mjava-rongzhi/src/main/java/com/malk/rongzhi/server/RZConf.java
  74. 29 0
      mjava-rongzhi/src/main/java/com/malk/rongzhi/server/RZR.java
  75. 16 0
      mjava-rongzhi/src/main/java/com/malk/rongzhi/service/RZService.java
  76. 134 0
      mjava-rongzhi/src/main/java/com/malk/rongzhi/service/impl/RZServiceImpl.java
  77. 58 0
      mjava-rongzhi/src/main/resources/application-dev.yml
  78. 39 0
      mjava-rongzhi/src/main/resources/application-prod.yml
  79. 35 0
      mjava-rongzhi/src/test/resources/server.sh
  80. 58 0
      mjava-rongzhi/target/classes/application-dev.yml
  81. 39 0
      mjava-rongzhi/target/classes/application-prod.yml
  82. 50 0
      mjava-rongzhi/target/generated-sources/java/com/malk/rongzhi/repository/entity/QRzEkbRecordPo.java
  83. 5 0
      mjava-rongzhi/target/maven-archiver/pom.properties
  84. 13 0
      mjava-rongzhi/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
  85. 11 0
      mjava-rongzhi/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
  86. BIN
      mjava-rongzhi/target/mjava-rongzhi.jar.original
  87. 35 0
      mjava-rongzhi/target/test-classes/server.sh
  88. 54 0
      mjava-xiding/pom.xml
  89. 32 0
      mjava-xiding/src/main/java/com/malk/xiding/Boot.java
  90. 42 0
      mjava-xiding/src/main/java/com/malk/xiding/controller/XDController.java
  91. 21 0
      mjava-xiding/src/main/java/com/malk/xiding/repository/dao/XdDdApproveRecordDao.java
  92. 22 0
      mjava-xiding/src/main/java/com/malk/xiding/repository/dao/XdDdApproveRecordDao2.java
  93. 15 0
      mjava-xiding/src/main/java/com/malk/xiding/repository/dao/XdDdFxkRelationDao.java
  94. 14 0
      mjava-xiding/src/main/java/com/malk/xiding/repository/dao/XdFxkDdAttendanceDao.java
  95. 63 0
      mjava-xiding/src/main/java/com/malk/xiding/repository/entity/XdDdApproveRecordPo.java
  96. 44 0
      mjava-xiding/src/main/java/com/malk/xiding/repository/entity/XdDdFxkRelationPo.java
  97. 53 0
      mjava-xiding/src/main/java/com/malk/xiding/repository/entity/XdFxkDdAttendancePo.java
  98. 70 0
      mjava-xiding/src/main/java/com/malk/xiding/schedule/XDScheduleTask.java
  99. 10 0
      mjava-xiding/src/main/java/com/malk/xiding/server/XDConf.java
  100. 0 0
      mjava-xiding/src/main/java/com/malk/xiding/service/XDService.java

+ 37 - 0
.gitignore

@@ -0,0 +1,37 @@
+# IntelliJ project files
+.idea
+*.iml
+out
+gen
+### Java template
+# Compiled class file
+*.class
+
+# Log file
+*.log
+/log/
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+mvnw
+mvnw.cmd
+
+# tmp file
+.tmp
+/tmp/

+ 60 - 0
mjava-hangshi/pom.xml

@@ -0,0 +1,60 @@
+<?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">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-hangshi</artifactId>
+    <description>航食宜搭开发服务</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <!-- CXF webservice -->
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
+            <version>3.4.0</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 32 - 0
mjava-hangshi/src/main/java/com/malk/hangshi/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.hangshi;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 68 - 0
mjava-hangshi/src/main/java/com/malk/hangshi/config/CxfConfig.java

@@ -0,0 +1,68 @@
+package com.malk.hangshi.config;
+
+import com.malk.hangshi.service.IH3yunWebService;
+import com.malk.hangshi.service.impl.H3yunWebServiceImpl;
+import org.apache.cxf.Bus;
+import org.apache.cxf.bus.spring.SpringBus;
+import org.apache.cxf.jaxws.EndpointImpl;
+import org.apache.cxf.phase.Phase;
+import org.apache.cxf.transport.servlet.CXFServlet;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.xml.ws.Endpoint;
+
+
+@Configuration
+public class CxfConfig {
+
+    /**
+     * 访问路径: http://localhost:9001/api/webService/api?wsdl
+     * -
+     * invoke: mc可自定义, test为方法名称, arg0第一次参数
+     * -
+     * <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mc="http://service.hangshi.malk.com">
+     *   <soap:Body>
+     *     <mc:test>
+     *       <arg0>[{"assetNo":"1","barCode":"1","belongDept":"1","boxBarCode":"1","cap":"1","chkDate"madeDate":158688000000}]</arg0>
+     *     </mc:test>
+     *   </soap:Body>
+     * </soap:Envelope>
+     * -
+     *
+     * @WebParam 自定义参数名称, 否则就是 arg0, arg1, ...
+     */
+
+    @Bean
+    public ServletRegistrationBean disServlet() {
+        return new ServletRegistrationBean(new CXFServlet(), "/hangshi/ws/*");
+    }
+
+    @Bean(name = Bus.DEFAULT_BUS_ID)
+    public SpringBus springBus() {
+        return new SpringBus();
+    }
+
+//    @Bean
+//    public InvoiceWebService demoService() {
+//        return new InvoiceWebServiceImpl();
+//    }
+
+    @Bean
+    public IH3yunWebService demoService() {
+        return new H3yunWebServiceImpl();
+    }
+
+    @Bean
+    public Endpoint endpoint() {
+        EndpointImpl endpoint = new EndpointImpl(springBus(), demoService());
+        // 请求拦截器
+        endpoint.getInInterceptors().add(new WsInInterceptor(Phase.RECEIVE));
+        // 响应拦截器
+//        endpoint.getOutInterceptors().add(new WsOutInterceptor(Phase.PRE_STREAM));
+        endpoint.publish("/invoke.asmx");
+        return endpoint;
+    }
+
+}

+ 40 - 0
mjava-hangshi/src/main/java/com/malk/hangshi/config/WsInInterceptor.java

@@ -0,0 +1,40 @@
+package com.malk.hangshi.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.cxf.binding.soap.SoapMessage;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+@Slf4j
+public class WsInInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
+
+    public WsInInterceptor(String phase) {
+        super(phase);
+    }
+
+    @Override
+    public void handleMessage(SoapMessage message) throws Fault {
+        try {
+            // 从流中获取请求消息体并以字符串形式输出,注意IOUtils是cxf的包;
+            String input = IOUtils.toString(message.getContent(InputStream.class), "UTF-8");
+            // 如果内容不为空(第一次连接也会被拦截,此时input为空)
+            if (StringUtils.isNotBlank(input)) {
+                // 修改请求消息体为webservice服务要求的格式
+                input = input.replace("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">", "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"http://server.dandelion.com\">")
+                        .replace("<esb:getData xmlns:esb=\"mdm.stardand.com\">", "<ser:getData>")
+                        .replace("</esb:getData>", "</ser:getData>").replace("ns2:InvokeResponse", "InvokeResponse");
+                log.info("ns2:InvokeResponse, {}", input);
+            }
+
+            // 重新写入
+            message.setContent(InputStream.class, new ByteArrayInputStream(input.getBytes()));
+        } catch (Exception e) {
+            System.out.println(String.format("解析报文异常: %s", e.getMessage()));
+        }
+    }
+}

+ 71 - 0
mjava-hangshi/src/main/java/com/malk/hangshi/config/WsOutInterceptor.java

@@ -0,0 +1,71 @@
+package com.malk.hangshi.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.cxf.binding.soap.SoapMessage;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.io.CachedOutputStream;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+@Slf4j
+public class WsOutInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
+
+    public WsOutInterceptor(String phase) {
+        super(phase);
+    }
+
+    @Override
+    public void handleMessage(SoapMessage message) throws Fault {
+        try {
+            // 从流中获取返回内容
+            OutputStream os = message.getContent(OutputStream.class);
+            CachedStream cs = new CachedStream();
+            message.setContent(OutputStream.class, cs);
+            message.getInterceptorChain().doIntercept(message);
+            CachedOutputStream cachedOutputStream = (CachedOutputStream) message.getContent(OutputStream.class);
+            InputStream in = cachedOutputStream.getInputStream();
+            String output = IOUtils.toString(in, "UTF-8");
+            // 修改内容为集成平台要求的格式
+            output = output.replace("<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">", "<soapenv:Envelope xmlns:soapenv=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\">")
+                    .replace("</soap:Envelope>", "</soapenv:Envelope>")
+                    .replace("<soap:Body>", "<soapenv:Body>")
+                    .replace("</soap:Body>", "</soapenv:Body>")
+                    .replace("<ns2:getDataResponse xmlns:ns2=\"http://server.dandelion.com\">", "")
+                    .replace("</ns2:getDataResponse>", "").replace("ns2:InvokeResponse", "InvokeResponse");
+            ;
+            log.info("ns2:InvokeResponse, {}", output);
+            output = "<string xmlns=\"http://tempuri.org/\">{\"ResultCode\":\"0\",\"Message\":\"\",\"Schema\":{\"Code\":\"Student\",\"Items\":[]},\"Data\":{}}</string>";
+            // 处理完后写回流中
+            IOUtils.copy(new ByteArrayInputStream(output.getBytes()), os);
+            cs.close();
+            os.flush();
+            message.setContent(OutputStream.class, os);
+        } catch (Exception e) {
+            System.out.println(String.format("解析报文异常: %s", e.getMessage()));
+        }
+    }
+
+    private static class CachedStream extends CachedOutputStream {
+        public CachedStream() {
+            super();
+        }
+
+        @Override
+        protected void doFlush() throws IOException {
+            currentStream.flush();
+        }
+
+        @Override
+        protected void doClose() throws IOException {
+        }
+
+        @Override
+        protected void onWrite() throws IOException {
+        }
+    }
+}

+ 51 - 0
mjava-hangshi/src/main/java/com/malk/hangshi/controller/HSController.java

@@ -0,0 +1,51 @@
+package com.malk.hangshi.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.Util.UtilMap;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.server.common.McR;
+import com.malk.server.dingtalk.DDR_New;
+import com.malk.service.aliwork.YDClient;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/hangshi")
+public class HSController {
+
+    @Autowired
+    private YDClient ydClient;
+
+    /**
+     * 全局查询子表单
+     */
+    @PostMapping("query-all-details")
+    McR queryAll(@RequestBody Map data) {
+
+        log.info("全局查询子表单, {}", data);
+        McException.assertParamException_Null(data, "condition", "formUuid", "compId");
+
+        List conditions = Arrays.asList(UtilMap.map("key, value, type, operator, componentName", data.get("compId"), data.get("condition"), "TEXT", "contains", "TableField"));
+
+        YDParam ydParam = YDParam.builder()
+                .formUuid(String.valueOf(data.get("formUuid")))
+                .searchCondition(JSON.toJSONString(conditions))
+                .build();
+        DDR_New ddr_new = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list_all);
+        return McR.success(ddr_new);
+    }
+}

+ 41 - 0
mjava-hangshi/src/main/java/com/malk/hangshi/service/IH3yunWebService.java

@@ -0,0 +1,41 @@
+package com.malk.hangshi.service;
+
+import javax.jws.WebMethod;
+import javax.jws.WebParam;
+import javax.jws.WebResult;
+import javax.jws.WebService;
+
+/**
+ * @author shinka
+ * @date 2021/03/26
+ */
+
+@WebService(name = "IH3yunWebService", // 暴露服务名称
+        targetNamespace = "http://service.example.com/h3yun" // 命名空间,一般是接口的包名倒序
+)
+// @BindingType(value = SOAPBinding.SOAP12HTTP_BINDING) // soap1.1
+public interface IH3yunWebService {
+
+    public static final String NAMESPACE = "http://service.example.com/h3yun";
+
+    @WebMethod(operationName = "GetSchema", action = NAMESPACE + "/GetSchema")
+    @WebResult(name = "GetSchemaResult")
+    public String GetSchema(@WebParam(name = "schemaCode", targetNamespace = NAMESPACE) String schemaCode);
+
+    @WebMethod(operationName = "GetSchemaList", action = NAMESPACE + "/GetSchemaList")
+    @WebResult(name = "GetSchemaListResult")
+    public String GetSchemaList();
+
+    @WebMethod(operationName = "GetList", action = NAMESPACE + "/GetList")
+    @WebResult(name = "GetListResult")
+    public String GetList(@WebParam(name = "userCode", targetNamespace = NAMESPACE) String userCode,
+                          @WebParam(name = "schemaCode", targetNamespace = NAMESPACE) String schemaCode,
+                          @WebParam(name = "filter", targetNamespace = NAMESPACE) String filter);
+
+    @WebMethod(operationName = "Invoke", action = NAMESPACE + "/Invoke")
+    @WebResult(name = "InvokeResult")
+    public String Invoke(@WebParam(name = "userCode", targetNamespace = NAMESPACE) String userCode,
+                         @WebParam(name = "schemaCode", targetNamespace = NAMESPACE) String schemaCode,
+                         @WebParam(name = "methodName", targetNamespace = NAMESPACE) String methodName,
+                         @WebParam(name = "param", targetNamespace = NAMESPACE) String param);
+}

+ 34 - 0
mjava-hangshi/src/main/java/com/malk/hangshi/service/InvoiceWebService.java

@@ -0,0 +1,34 @@
+//package com.malk.hangshi.service;
+//
+//import javax.jws.WebMethod;
+//import javax.jws.WebParam;
+//import javax.jws.WebResult;
+//import javax.jws.WebService;
+//
+//@WebService(targetNamespace = "http://tempuri.org/")
+//public interface InvoiceWebService {
+//
+//    @WebResult(name = "InvokeResult")
+//    @WebMethod(operationName = "sayHello")
+//    String sayHello(@WebParam(name = "name", targetNamespace = "http://tempuri.org/") String name);
+//
+//    @WebMethod(operationName = "test")
+//    String test(String user);
+//
+//
+//    // 氚云
+//
+//    @WebMethod(operationName = "GetSchema")
+//    String GetSchema(@WebParam(name = "schemaCode") String schemaCode);
+//
+//    @WebMethod(operationName = "GetSchemaList")
+//    String GetSchemaList();
+//
+//    @WebMethod(operationName = "GetList")
+//    String GetList();
+//
+//    @WebResult(name = "InvokeResult")
+//    @WebMethod(operationName = "Invoke")
+//    String Invoke(@WebParam(name = "userCode", targetNamespace = "http://tempuri.org/") String userCode, @WebParam(name = "schemaCode", targetNamespace = "http://tempuri.org/") String schemaCode, @WebParam(name = "methodName", targetNamespace = "http://tempuri.org/") String methodName, @WebParam(name = "param", targetNamespace = "http://tempuri.org/") String param);
+//}
+//

+ 46 - 0
mjava-hangshi/src/main/java/com/malk/hangshi/service/impl/H3yunWebServiceImpl.java

@@ -0,0 +1,46 @@
+package com.malk.hangshi.service.impl;
+
+import com.malk.hangshi.service.IH3yunWebService;
+import org.springframework.stereotype.Component;
+
+import javax.jws.WebService;
+import javax.xml.ws.BindingType;
+import javax.xml.ws.soap.SOAPBinding;
+
+/**
+ * @author shinka
+ * @date 2021/03/26
+ */
+@WebService(serviceName = "H3yunWebService", // 与接口中指定的name一致
+        targetNamespace = "http://service.example.com/h3yun", // 与接口中的命名空间一致,一般是接口的包名倒
+        endpointInterface = "com.malk.hangshi.service.IH3yunWebService" // 接口地址
+)
+@BindingType(value = SOAPBinding.SOAP12HTTP_BINDING)
+@Component
+public class H3yunWebServiceImpl implements IH3yunWebService {
+
+    @Override
+    public String GetSchema(String schemaCode) {
+        // 氚云在集成的时候会调用GetSchema方法,该方法返回值仅支持如下两种,业务逻辑请写在其它方法上
+        return "{\"code\":\"\"}";
+        // return "";
+    }
+
+    @Override
+    public String GetSchemaList() {
+        return "{\"schemaCode\":\"D001062ceshi2\"}";
+    }
+
+    @Override
+    public String GetList(String userCode, String schemaCode, String filter) {
+        return "{\"userCode\":\"" + userCode + "\",\"schemaCode\":\"" + schemaCode + "\",\"filter\":\"" + filter
+                + "\"}";
+    }
+
+    @Override
+    public String Invoke(String userCode, String schemaCode, String methodName, String param) {
+        return "{\"userCode\":\"" + userCode + "\",\"schemaCode\":\"" + schemaCode + "\",\"methodName\":\"" + methodName
+                + "\",\"param\":\"" + methodName + "\"}";
+    }
+
+}

Разлика између датотеке није приказан због своје велике величине
+ 56 - 0
mjava-hangshi/src/main/java/com/malk/hangshi/service/impl/InvoiceWebServiceImpl.java


+ 53 - 0
mjava-hangshi/src/main/resources/application-dev.yml

@@ -0,0 +1,53 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/service/_Tool/var/mjava/tmp//file/
+    image: /Users/malk/service/_Tool/var/mjava/tmp//image/
+    tmp: /Users/malk/service/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/service/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/service/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2554541552
+  appKey: dingibsmij0bzwbtyfrr
+  appSecret: JEtzUtRjXBN3yiF6v9bw0uF_jWAVmVvIWfoCqIyaRTK-TEWVQLGU-xsYu7Ni_GKB
+  corpId: ding6bd8f2716554297135c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "81007710"   # 孙云嵩 [开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
+
+

+ 39 - 0
mjava-hangshi/src/main/resources/application-prod.yml

@@ -0,0 +1,39 @@
+# 环境配置
+server:
+  port: 9008
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# ekuaibao
+ekuaibao:
+  corpId: -yQbjbywbc640011                # 易快报的 corpId
+  platformApi: https://app.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
+
+# dingtalk
+dingtalk:
+  agentId: 2554541552
+  appKey: dingibsmij0bzwbtyfrr
+  appSecret: JEtzUtRjXBN3yiF6v9bw0uF_jWAVmVvIWfoCqIyaRTK-TEWVQLGU-xsYu7Ni_GKB
+  corpId: ding6bd8f2716554297135c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "81007710"   # 孙云嵩 [开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9

+ 35 - 0
mjava-hangshi/src/test/resources/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-hangshi'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 53 - 0
mjava-hangshi/target/classes/application-dev.yml

@@ -0,0 +1,53 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/service/_Tool/var/mjava/tmp//file/
+    image: /Users/malk/service/_Tool/var/mjava/tmp//image/
+    tmp: /Users/malk/service/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/service/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/service/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2554541552
+  appKey: dingibsmij0bzwbtyfrr
+  appSecret: JEtzUtRjXBN3yiF6v9bw0uF_jWAVmVvIWfoCqIyaRTK-TEWVQLGU-xsYu7Ni_GKB
+  corpId: ding6bd8f2716554297135c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "81007710"   # 孙云嵩 [开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
+
+

+ 39 - 0
mjava-hangshi/target/classes/application-prod.yml

@@ -0,0 +1,39 @@
+# 环境配置
+server:
+  port: 9008
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# ekuaibao
+ekuaibao:
+  corpId: -yQbjbywbc640011                # 易快报的 corpId
+  platformApi: https://app.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
+
+# dingtalk
+dingtalk:
+  agentId: 2554541552
+  appKey: dingibsmij0bzwbtyfrr
+  appSecret: JEtzUtRjXBN3yiF6v9bw0uF_jWAVmVvIWfoCqIyaRTK-TEWVQLGU-xsYu7Ni_GKB
+  corpId: ding6bd8f2716554297135c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "81007710"   # 孙云嵩 [开头需要转一下字符串], OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_YH7W0E5637YUBU5UJ837
+  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9

+ 5 - 0
mjava-hangshi/target/maven-archiver/pom.properties

@@ -0,0 +1,5 @@
+#Generated by Maven
+#Wed Apr 19 20:43:33 CST 2023
+version=1.0-SNAPSHOT
+groupId=com.malk
+artifactId=mjava-hangshi

+ 0 - 0
mjava-hangshi/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst


+ 7 - 0
mjava-hangshi/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst

@@ -0,0 +1,7 @@
+/Users/malk/server/java-mcli-2/mjava-hangshi/src/main/java/com/malk/hangshi/service/impl/InvoiceWebServiceImpl.java
+/Users/malk/server/java-mcli-2/mjava-hangshi/src/main/java/com/malk/hangshi/service/InvoiceWebService.java
+/Users/malk/server/java-mcli-2/mjava-hangshi/src/main/java/com/malk/hangshi/Boot.java
+/Users/malk/server/java-mcli-2/mjava-hangshi/src/main/java/com/malk/hangshi/config/CxfConfig.java
+/Users/malk/server/java-mcli-2/mjava-hangshi/src/main/java/com/malk/hangshi/controller/HSController.java
+/Users/malk/server/java-mcli-2/mjava-hangshi/src/main/java/com/malk/hangshi/config/WsOutInterceptor.java
+/Users/malk/server/java-mcli-2/mjava-hangshi/src/main/java/com/malk/hangshi/config/WsInInterceptor.java

BIN
mjava-hangshi/target/mjava-hangshi.jar.original


+ 35 - 0
mjava-hangshi/target/test-classes/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-hangshi'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 54 - 0
mjava-jisuanji/pom.xml

@@ -0,0 +1,54 @@
+<?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">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-jisuanji</artifactId>
+    <description>计算机氚云开发对接</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 32 - 0
mjava-jisuanji/src/main/java/com/malk/jisuanji/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.jisuanji;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 74 - 0
mjava-jisuanji/src/main/java/com/malk/jisuanji/controller/HSController.java

@@ -0,0 +1,74 @@
+package com.malk.jisuanji.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.malk.Util.UtilMap;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.server.common.McR;
+import com.malk.server.dingtalk.DDR_New;
+import com.malk.service.aliwork.YDClient;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/jisuanji")
+public class HSController {
+
+    @Autowired
+    private YDClient ydClient;
+
+    /**
+     * 供应商数据查询
+     */
+    @PostMapping("yd/supplier")
+    McR querySupplier(@RequestBody Map<String, String> data) {
+
+        log.info("供应商数据查询, {}", data);
+        McException.assertParamException_Null(data, "condition", "formUuid", "compId");
+        List conditions = Arrays.asList(UtilMap.map("key, value, type, operator, componentName", data.get("compId"), data.get("condition"), "TEXT", "eq", "TextField"));
+        YDParam ydParam = YDParam.builder()
+                .formUuid(String.valueOf(data.get("formUuid")))
+                .searchCondition(JSON.toJSONString(conditions))
+                .build();
+        DDR_New ddr_new = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list_all);
+        McException.assertAccessException(ddr_new.getTotalCount() == 0, "代码无效, 不在供应商库");
+        return McR.success(((List) ddr_new.getData()).get(0));
+    }
+
+    /**
+     * 供应商下单数据
+     */
+    @PostMapping("yd/order-list")
+    McR queryOrderStatus(@RequestBody Map<String, Map> data) {
+
+        log.info("供应商下单数据, {}", data);
+        querySupplier(data.get("supplier")); // 校验供应商信息
+        Map param = data.get("order");
+        List<Map> conditions = new ArrayList<>();
+        conditions.add(UtilMap.map("key, value, type, operator, componentName", param.get("compId_code"), param.get("condition_code"), "TEXT", "eq", "TextField"));
+        if (ObjectUtil.isNotNull(param.get("condition_date"))) {
+            conditions.add(UtilMap.map("key, value, type, operator, componentName", param.get("compId_date"), param.get("condition_date"), "DOUBLE", "between", "DateField"));
+        }
+        YDParam ydParam = YDParam.builder()
+                .formUuid(String.valueOf(param.get("formUuid")))
+                .searchCondition(JSON.toJSONString(conditions))
+                .build();
+        DDR_New ddr_new = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_process);
+        return McR.success(ddr_new);
+    }
+}

+ 51 - 0
mjava-jisuanji/src/main/resources/application-dev.yml

@@ -0,0 +1,51 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQLDialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/service/_Tool/var/mjava/tmp//file/
+    image: /Users/malk/service/_Tool/var/mjava/tmp//image/
+    tmp: /Users/malk/service/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/service/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/service/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2533464721
+  appKey: dingromjxexd1esgvwwg
+  appSecret: AcStrL5bdw69gqeUfTQiFoBsgqisL2g-egzaKyID9Q7d85f_z9EkuTSS9Vse6zDb
+  corpId: ding5e83ad92d917b47535c2f4657eb6378f
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_IW1FN8PPGGYQBWVMXS69
+  systemToken: UT866MB1WGX8VU029U93IA9DIKEG2GE9UU7FLI5
+

+ 33 - 0
mjava-jisuanji/src/main/resources/application-prod.yml

@@ -0,0 +1,33 @@
+# 环境配置
+server:
+  port: 9005
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# dingtalk
+dingtalk:
+  agentId: 2533464721
+  appKey: dingromjxexd1esgvwwg
+  appSecret: AcStrL5bdw69gqeUfTQiFoBsgqisL2g-egzaKyID9Q7d85f_z9EkuTSS9Vse6zDb
+  corpId: ding5e83ad92d917b47535c2f4657eb6378f
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_IW1FN8PPGGYQBWVMXS69
+  systemToken: UT866MB1WGX8VU029U93IA9DIKEG2GE9UU7FLI5

+ 51 - 0
mjava-jisuanji/target/classes/application-dev.yml

@@ -0,0 +1,51 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQLDialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/service/_Tool/var/mjava/tmp//file/
+    image: /Users/malk/service/_Tool/var/mjava/tmp//image/
+    tmp: /Users/malk/service/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/service/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/service/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2533464721
+  appKey: dingromjxexd1esgvwwg
+  appSecret: AcStrL5bdw69gqeUfTQiFoBsgqisL2g-egzaKyID9Q7d85f_z9EkuTSS9Vse6zDb
+  corpId: ding5e83ad92d917b47535c2f4657eb6378f
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_IW1FN8PPGGYQBWVMXS69
+  systemToken: UT866MB1WGX8VU029U93IA9DIKEG2GE9UU7FLI5
+

+ 33 - 0
mjava-jisuanji/target/classes/application-prod.yml

@@ -0,0 +1,33 @@
+# 环境配置
+server:
+  port: 9005
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# dingtalk
+dingtalk:
+  agentId: 2533464721
+  appKey: dingromjxexd1esgvwwg
+  appSecret: AcStrL5bdw69gqeUfTQiFoBsgqisL2g-egzaKyID9Q7d85f_z9EkuTSS9Vse6zDb
+  corpId: ding5e83ad92d917b47535c2f4657eb6378f
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_IW1FN8PPGGYQBWVMXS69
+  systemToken: UT866MB1WGX8VU029U93IA9DIKEG2GE9UU7FLI5

+ 5 - 0
mjava-jisuanji/target/maven-archiver/pom.properties

@@ -0,0 +1,5 @@
+#Generated by Maven
+#Sat Apr 22 21:33:02 CST 2023
+version=1.0-SNAPSHOT
+groupId=com.malk
+artifactId=mjava-jisuanji

+ 0 - 0
mjava-jisuanji/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst


+ 2 - 0
mjava-jisuanji/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst

@@ -0,0 +1,2 @@
+/Users/malk/server/java-mcli-2/mjava-jisuanji/src/main/java/com/malk/jisuanji/controller/HSController.java
+/Users/malk/server/java-mcli-2/mjava-jisuanji/src/main/java/com/malk/jisuanji/Boot.java

BIN
mjava-jisuanji/target/mjava-jisuanji.jar.original


+ 54 - 0
mjava-lichen/pom.xml

@@ -0,0 +1,54 @@
+<?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">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-lichen</artifactId>
+    <description>力辰同步金蝶数据到宜搭</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 32 - 0
mjava-lichen/src/main/java/com/malk/lichen/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.lichen;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 137 - 0
mjava-lichen/src/main/java/com/malk/lichen/controller/LiChenController.java

@@ -0,0 +1,137 @@
+package com.malk.lichen.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.Util.UtilMap;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 错误抛出与拦截详见 CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/lichen")
+@EnableAsync
+public class LiChenController {
+
+    /**** 力辰服务 ****/
+
+    @Autowired
+    private YDClient ydClient;
+
+    /**
+     * 查询实例详情
+     */
+    @GetMapping("form/{formInstId}")
+    McR getInstanceById(@PathVariable String formInstId) {
+
+        log.info("查询实例详情, {}", formInstId);
+
+        YDParam ydParam = YDParam.builder()
+                .appType("APP_BV3K6QNMINKYEDHQNI4N")
+                .systemToken("CH766981WHM8OEVBEAKCY7MYB9SV3ORPLIQELS5")
+                .formInstId(formInstId)
+                .build();
+        return McR.success(ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_id));
+    }
+
+    /**
+     * 写入往来单位
+     */
+    @PostMapping("form/wldx")
+    McR updateWangLaiDanWei(@RequestBody Map data) {
+
+        log.info("写入往来单位, {}", data);
+
+        List<Map> list = (List<Map>) data.get("data");
+        for (Map record : list) {
+            Map searchMap = UtilMap.map("textField_lgpz4fmf", record.get("FNumber"));
+            YDParam ydParam = YDParam.builder()
+                    .formUuid("FORM-A8666NA1404AITYX7V2NI9VHO2TK3TYOVYPGL0")
+                    .searchFieldJson(JSON.toJSONString(searchMap))
+                    .build();
+            long total = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list).getTotalCount();
+            if (total == 0) {
+                ydParam.formDataJson = JSON.toJSONString(UtilMap.map("textField_lgpz6rn1, textField_lgpz4fmf, selectField_lgpz4fm9", "FName, FNumber, Type", record));
+                ydClient.operateData(ydParam, YDConf.FORM_OPERATION.create);
+            }
+        }
+        return McR.success();
+    }
+
+    /**
+     * 写入付款申请
+     */
+    @SneakyThrows
+    @PostMapping("form/fksq")
+    McR updateFuKuanShenQing(@RequestBody Map data) {
+
+        log.info("写入付款申请, {}", data);
+
+        List<Map> list = (List<Map>) data.get("data");
+        for (Map record : list) {
+            String billNo = String.valueOf(record.get("FBillNo"));
+            if (billNo.contains("FKSQ")) {
+                Map searchMap = UtilMap.map("textField_lgov75ms", billNo);
+                YDParam ydParam = YDParam.builder()
+                        .appType("APP_BV3K6QNMINKYEDHQNI4N")
+                        .systemToken("CH766981WHM8OEVBEAKCY7MYB9SV3ORPLIQELS5")
+                        .formUuid("FORM-4V966QC142J8WYDD9PO74DD2QOME3ZG0MIQELK1")
+                        .searchFieldJson(JSON.toJSONString(searchMap))
+                        .build();
+                long total = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list).getTotalCount();
+                if (total == 0) {
+                    Map formData = UtilMap.map("textField_lgov75ms, radioField_lguqzv36", billNo, "是");//单据编号
+                    formData.put("textField_lglwgnl7", record.get("FCREATORID"));//创建人ID
+                    formData.put("textField_lguqqubv", record.get("FCREATORNAME"));//创建人姓名
+                    formData.put("textField_lgvpbhx0", record.get("FSETTLEORGID"));//结算组织
+                    formData.put("", record.get("FPURCHASEORGID")); //采购组织
+                    formData.put("textField_leqinlpz", record.get("FAPPLYORGID")); //申请组织
+                    formData.put("dateField_leqinlqd", record.get("FDATE")); //申请日期
+                    formData.put("selectField_lgvpbhwz", record.get("FBILLTYPEID"));//单据类型
+                    formData.put("selectField_lgpzoio6", record.get("FCONTACTUNITTYPE"));//往来单位类型
+                    formData.put("selectField_lexydxa5", record.get("FCONTACTUNIT"));//往来单位
+                    formData.put("textField_lgpzoio7", record.get("FCONTACTUNIT_Id"));//往来单位编码
+                    formData.put("", record.get("FBUSINESSTYPE"));//业务类型
+                    formData.put("textField_leqinlq3", record.get("FPAYORGID"));//付款组织
+                    formData.put("textField_lgvxe8q6", record.get("FRECTUNIT"));//收款单位
+                    formData.put("selectField_lgvpbhx1", record.get("F_BQB_Combo"));//付款类型
+                    formData.put("radioField_leqinlq7", record.get("F_BQB_FKDQ"));//付款地区
+                    formData.put("selectField_lgvz3r3j", record.get("F_BQB_FKGS"));//付款公司
+                    formData.put("textField_leqinlq2", record.get("FEXPENSEDEPTID"));//费用承担部门
+                    List<Map> details = new ArrayList<>();
+                    List<Map> dataTable = (List<Map>) JSON.parse(String.valueOf(record.get("DataTable")));
+                    for (Map detail : dataTable) {
+                        Map rowTable = UtilMap.map("selectField_lewl78sf", detail.get("FSETTLETYPEID"));//结算方式
+                        rowTable.put("textField_lfw71laq", detail.get("FEACHBANKACCOUNT"));//对方银行账号
+                        rowTable.put("numberField_leqinlqa", detail.get("FAPPLYAMOUNTFOR"));//申请付款金额
+                        rowTable.put("dateField_lewl78sh", detail.get("FENDDATE"));//到期日
+                        rowTable.put("dateField_lewl78sg", detail.get("FEXPECTPAYDATE"));//期望付款日期
+                        rowTable.put("textField_lfw71lar", detail.get("FEACHCCOUNTNAME"));//对方账户名称
+                        rowTable.put("textField_lfw71las", detail.get("FEACHBANKNAME"));//对方账户名称
+                        rowTable.put("selectField_lgqbuu2d", detail.get("FCOSTID"));//费用项目
+                        rowTable.put("textField_lgyosvjh", detail.get("FCOSTID_id"));//费用项目ID
+                        rowTable.put("textField_leqinlqb", detail.get("FDescription"));//备注
+                        details.add(rowTable);
+                    }
+                    formData.put("tableField_leqinlq8", details);
+                    ydParam.formDataJson = JSON.toJSONString(formData);
+                    ydParam.setProcessCode("TPROC--4V966QC142J8WYDD9PO74DD2QOME30H0MIQELL1");
+                    ydClient.operateData(ydParam, YDConf.FORM_OPERATION.start);
+                }
+            }
+        }
+        return McR.success();
+    }
+}

+ 51 - 0
mjava-lichen/src/main/resources/application-dev.yml

@@ -0,0 +1,51 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQLDialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/service/_Tool/var/mjava/tmp//file/
+    image: /Users/malk/service/_Tool/var/mjava/tmp//image/
+    tmp: /Users/malk/service/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/service/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/service/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2552123596
+  appKey: dingv4y2whqqanodtqbq
+  appSecret: vE8nJKHODp6zyQmCwZvWNwJS2nwehHdrqXz3FelddniIcgL7W7Yjaz7u8MPVG3wU
+  corpId: ding50c7c06e7f1d9394
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_BV3K6QNMINKYEDHQNI4N
+  systemToken: CH766981WHM8OEVBEAKCY7MYB9SV3ORPLIQELS5
+

+ 33 - 0
mjava-lichen/src/main/resources/application-prod.yml

@@ -0,0 +1,33 @@
+# 环境配置
+server:
+  port: 9001
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# dingtalk
+dingtalk:
+  agentId: 2552123596
+  appKey: dingv4y2whqqanodtqbq
+  appSecret: vE8nJKHODp6zyQmCwZvWNwJS2nwehHdrqXz3FelddniIcgL7W7Yjaz7u8MPVG3wU
+  corpId: ding50c7c06e7f1d9394
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_BV3K6QNMINKYEDHQNI4N
+  systemToken: CH766981WHM8OEVBEAKCY7MYB9SV3ORPLIQELS5

+ 35 - 0
mjava-lichen/src/test/resources/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-minjiaoyuan'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 55 - 0
mjava-lichen/src/test/resources/winsw.xml

@@ -0,0 +1,55 @@
+<!--
+  MIT License
+
+  Copyright (c) 2008-2020 Kohsuke Kawaguchi, Sun Microsystems, Inc., CloudBees,
+  Inc., Oleg Nenashev and other contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in all
+  copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+-->
+
+<!--
+ This is an example of a minimal Windows Service Wrapper configuration, which includes only mandatory options.
+ 
+ This configuration file should be placed near the WinSW executable, the name should be the same.
+ E.g. for myapp.exe the configuration file name should be myapp.xml
+ 
+ You can find more information about the configuration options here: https://github.com/kohsuke/winsw/blob/master/doc/xmlConfigFile.md
+ Full example: https://github.com/kohsuke/winsw/blob/master/examples/sample-allOptions.xml
+-->
+
+<service>
+    <!-- 注册服务ID -->
+    <id>mjava</id>
+    <!-- 启动服务名称 -->
+    <name>mjava</name>
+    <!-- 对服务的描述 -->
+    <description>标准化后端接口, 自用脚手架封装</description>
+    <!-- 「jdk需要安装」启动的可执行文件:若未配置环境变量executable需要执行绝对路径 -->
+    <!-- <executable>java</executable> -->
+    <executable>C:\Program Files\DingTalkServer\jdk1.8.0_221\bin\java</executable>
+    <!-- Xmx256m 代表堆内存最大值为256MB -jar后面的是项目名 -->
+    <arguments>-Xms256m -Xmx256m -jar mjava-lichen.jar</arguments>
+    <!-- 服务的启动模式:默认Automatic -->
+    <startmode>Automatic</startmode>
+    <!-- 日志地址 -->
+    <logpath>%BASE%\ws</logpath>
+    <!-- 日志模式 -->
+    <logmode>rotate</logmode>
+</service>
+

+ 51 - 0
mjava-lichen/target/classes/application-dev.yml

@@ -0,0 +1,51 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQLDialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/service/_Tool/var/mjava/tmp//file/
+    image: /Users/malk/service/_Tool/var/mjava/tmp//image/
+    tmp: /Users/malk/service/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/service/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/service/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2552123596
+  appKey: dingv4y2whqqanodtqbq
+  appSecret: vE8nJKHODp6zyQmCwZvWNwJS2nwehHdrqXz3FelddniIcgL7W7Yjaz7u8MPVG3wU
+  corpId: ding50c7c06e7f1d9394
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_BV3K6QNMINKYEDHQNI4N
+  systemToken: CH766981WHM8OEVBEAKCY7MYB9SV3ORPLIQELS5
+

+ 33 - 0
mjava-lichen/target/classes/application-prod.yml

@@ -0,0 +1,33 @@
+# 环境配置
+server:
+  port: 9001
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# dingtalk
+dingtalk:
+  agentId: 2552123596
+  appKey: dingv4y2whqqanodtqbq
+  appSecret: vE8nJKHODp6zyQmCwZvWNwJS2nwehHdrqXz3FelddniIcgL7W7Yjaz7u8MPVG3wU
+  corpId: ding50c7c06e7f1d9394
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_BV3K6QNMINKYEDHQNI4N
+  systemToken: CH766981WHM8OEVBEAKCY7MYB9SV3ORPLIQELS5

+ 5 - 0
mjava-lichen/target/maven-archiver/pom.properties

@@ -0,0 +1,5 @@
+#Generated by Maven
+#Tue Apr 25 17:46:10 CST 2023
+version=1.0-SNAPSHOT
+groupId=com.malk
+artifactId=mjava-lichen

+ 2 - 0
mjava-lichen/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst

@@ -0,0 +1,2 @@
+com/malk/lichen/controller/LiChenController.class
+com/malk/lichen/Boot.class

+ 2 - 0
mjava-lichen/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst

@@ -0,0 +1,2 @@
+/Users/malk/server/java-mcli-2/mjava-lichen/src/main/java/com/malk/lichen/Boot.java
+/Users/malk/server/java-mcli-2/mjava-lichen/src/main/java/com/malk/lichen/controller/LiChenController.java

BIN
mjava-lichen/target/mjava-lichen.jar.original


+ 35 - 0
mjava-lichen/target/test-classes/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-minjiaoyuan'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 55 - 0
mjava-lichen/target/test-classes/winsw.xml

@@ -0,0 +1,55 @@
+<!--
+  MIT License
+
+  Copyright (c) 2008-2020 Kohsuke Kawaguchi, Sun Microsystems, Inc., CloudBees,
+  Inc., Oleg Nenashev and other contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in all
+  copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+-->
+
+<!--
+ This is an example of a minimal Windows Service Wrapper configuration, which includes only mandatory options.
+ 
+ This configuration file should be placed near the WinSW executable, the name should be the same.
+ E.g. for myapp.exe the configuration file name should be myapp.xml
+ 
+ You can find more information about the configuration options here: https://github.com/kohsuke/winsw/blob/master/doc/xmlConfigFile.md
+ Full example: https://github.com/kohsuke/winsw/blob/master/examples/sample-allOptions.xml
+-->
+
+<service>
+    <!-- 注册服务ID -->
+    <id>mjava</id>
+    <!-- 启动服务名称 -->
+    <name>mjava</name>
+    <!-- 对服务的描述 -->
+    <description>标准化后端接口, 自用脚手架封装</description>
+    <!-- 「jdk需要安装」启动的可执行文件:若未配置环境变量executable需要执行绝对路径 -->
+    <!-- <executable>java</executable> -->
+    <executable>C:\Program Files\DingTalkServer\jdk1.8.0_221\bin\java</executable>
+    <!-- Xmx256m 代表堆内存最大值为256MB -jar后面的是项目名 -->
+    <arguments>-Xms256m -Xmx256m -jar mjava-lichen.jar</arguments>
+    <!-- 服务的启动模式:默认Automatic -->
+    <startmode>Automatic</startmode>
+    <!-- 日志地址 -->
+    <logpath>%BASE%\ws</logpath>
+    <!-- 日志模式 -->
+    <logmode>rotate</logmode>
+</service>
+

+ 54 - 0
mjava-minjiaoyuan/pom.xml

@@ -0,0 +1,54 @@
+<?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">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-minjiaoyuan</artifactId>
+    <description>闵教院宜搭对接服务</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 32 - 0
mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.minjiaoyuan;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 98 - 0
mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/controller/InviteControl.java

@@ -0,0 +1,98 @@
+package com.malk.minjiaoyuan.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.Util.UtilMap;
+import com.malk.minjiaoyuan.service.MJYService;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.server.common.McR;
+import com.malk.server.dingtalk.DDR_New;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/minjiaoyuan")
+public class InviteControl {
+
+
+    @Autowired
+    private YDClient ydClient;
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    @Autowired
+    private MJYService mjyService;
+
+    /**
+     * 同步学校 & 钉钉通讯录
+     */
+    @SneakyThrows
+    @PostMapping("sync/department")
+    McR department() {
+        log.info("同步学校 & 钉钉通讯录");
+        List<Map> deptList = ddClient.getDepartmentDetail_all(ddClient.getAccessToken());
+        for (Map dept : deptList) {
+            YDParam ydParam = YDParam.builder()
+                    .formUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLUE")
+                    .searchFieldJson(JSON.toJSONString(UtilMap.map("selectField_lgf41nj4", dept.get("name"))))
+                    .pageSize(1)
+                    .build();
+            DDR_New ddr_new = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_form);
+            if (ddr_new.getTotalCount() == 0) {
+                continue;
+            }
+            Map formData = ((List<Map>) ddr_new.getData()).get(0);
+            if (StringUtils.isNotBlank(String.valueOf(((Map) formData.get("formData")).get("textField_lhldcchn")))) {
+                continue;
+            }
+            Thread.sleep(100); // 避免限流
+            ydParam.setFormInstanceId(formData.get("formInstanceId").toString());
+            ydParam.setUpdateFormDataJson(JSON.toJSONString(UtilMap.map("textField_lhldcchn", dept.get("dept_id"))));
+            ydClient.operateData(ydParam, YDConf.FORM_OPERATION.update);
+        }
+        return McR.success();
+    }
+
+    /**
+     * 创建人员: 邀请到架构 [配置提交校验, 无需更新宜搭单据]
+     */
+    @PostMapping("invite/user")
+    McR createUser(@RequestBody Map data) {
+        log.info("创建员工, {}", data);
+        McException.assertParamException_Null(data, "userId", "name", "mobile", "deptId");
+        Map bodyInfo = UtilMap.map("userid", data.get("userId"));
+        ddClient_contacts.createUser(ddClient.getAccessToken(), String.valueOf(data.get("name")), String.valueOf(data.get("mobile")), Arrays.asList(String.valueOf(data.get("deptId"))), bodyInfo);
+        return McR.success();
+    }
+
+    /**
+     * 同步教师档案 [已邀请], 定时同步后更新为已同步
+     */
+    @PostMapping("sync/teacher")
+    McR syncTeacherStatus() {
+        mjyService.syncTeacherStatus();
+        return McR.success();
+    }
+}

+ 442 - 0
mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/controller/MJYController.java

@@ -0,0 +1,442 @@
+package com.malk.minjiaoyuan.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.Util.UtilList;
+import com.malk.Util.UtilMap;
+import com.malk.Util.UtilServlet;
+import com.malk.minjiaoyuan.service.MJYService;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.aliwork.YDService;
+import lombok.Synchronized;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/minjiaoyuan")
+public class MJYController {
+
+    @Autowired
+    private YDConf ydConf;
+
+    @Autowired
+    private YDClient ydClient;
+
+    @Autowired
+    private MJYService mjyService;
+
+    /**
+     * 同步名额数据
+     */
+    @Synchronized
+    @PostMapping("sync/quota")
+    McR quotaSync(@RequestBody Map<String, String> data) {
+
+        log.info("###### 同步名额数据 #####");
+
+        // 参数合法校验
+        McException.assertParamException_Null(data, "period");
+        String period = data.get("period");
+
+        // 是否重新计算
+        YDParam ydParam = YDParam.builder()
+                .formUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLLE")
+                .pageSize(1)
+                .searchCondition(JSON.toJSONString(UtilMap.map("selectField_lggd61a7", period)))
+                .build();
+        long totalCount = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list).getTotalCount();
+        McException.assertAccessException(totalCount > 0, period + "名额已计算, 若需重置请删除后台数据后重试");
+
+        // 查询教师档案
+        ydParam.setSearchCondition(null);
+        ydParam.setFormUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLAE");
+        List<Map> teacherList = mjyService.queryAllBySync(ydParam);
+        log.info("教师档案数据, {}", teacherList.size());
+
+        // 学校档案去重
+        List<Map> schoolList = new ArrayList<>();
+        for (Map teacher : teacherList) {
+            Map formData = (Map) teacher.get("formData");
+            // 条件: 学校全称
+            Optional matchData = schoolList.stream().filter(school -> formData.get("textField_lgeyihed").equals(school.get("textField_lgezb8r7"))).findAny();
+            Map schoolMap;
+            if (!matchData.isPresent()) {
+                schoolMap = UtilMap.map("selectField_lggd61a7, radioField_lgf7zdi5", period, "未开始");
+                schoolMap.put("textField_lgezb8r7", formData.get("textField_lgeyihed")); // 学校全称
+                schoolMap.put("textField_lggdp94o", formData.get("textField_lgeyihe8")); // 学校简称
+                schoolMap.put("selectField_lggdghio", formData.get("selectField_lggdghio")); // 所属学段
+                schoolMap.put("numberField_lgf2au4s", 0); // 在编在岗人数
+                schoolList.add(schoolMap);
+            } else {
+                schoolMap = (Map) matchData.get();
+            }
+            // prd: 档案教师计算比例都是在编在岗
+            if (formData.get("radioField_lgezgr8l").equals("是")) {
+                schoolMap.put("numberField_lgf2au4s", (int) schoolMap.get("numberField_lgf2au4s") + 1);
+            }
+            log.debug("教师档案处理, {}", formData);
+        }
+        log.info("学校档案数据, {}, {}", schoolList.size(), schoolList);
+
+        // 学校名额计算
+        for (Map schoolData : schoolList) {
+            String schoolName = String.valueOf(schoolData.get("textField_lgezb8r7"));
+            int numZBZG = Integer.valueOf(String.valueOf(schoolData.get("numberField_lgf2au4s")));
+            // 骨干系列: prd 骨干比例拆分比例分项计算, 合计数不一定匹配, 因此不计算骨干系列名额
+            int ratioGDXT = mjyService.getSchoolRatio(schoolName, "骨干系列");
+            schoolData.put("numberField_lgf2au4t", ratioGDXT);
+            // 学科带头人和骨干教师
+            int ratioXDGG = mjyService.getSchoolRatio(schoolName, "学科带头人和骨干教师");
+            schoolData.put("numberField_lgf2au51", ratioXDGG);
+            schoolData.put("numberField_lgf2au52", Math.round(numZBZG * ratioXDGG / 100));
+            // 骨干后备
+            int numGGHB = Math.round(numZBZG * (ratioGDXT - ratioXDGG) / 100);
+            schoolData.put("numberField_lghpgjyk", ratioGDXT - ratioXDGG);
+            schoolData.put("numberField_lgf2au4z", numGGHB);
+            // 写入学校档案
+            log.info("学校名额计算, {}", schoolData);
+            ydParam.setFormDataJson(JSON.toJSONString(schoolData));
+            ydParam.setFormUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLLE");
+            ydClient.operateData(ydParam, YDConf.FORM_OPERATION.create);
+        }
+        return McR.success(mjyService.matchQuery(schoolList));
+    }
+
+    /**
+     * 查询学校名额
+     */
+    @PostMapping("query/quota")
+    McR quotaQuery(@RequestBody Map<String, String> data) {
+        McException.assertParamException_Null(data, "period");
+        String period = data.get("period");
+        YDParam ydParam = YDParam.builder()
+                .formUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLLE")
+                .searchCondition(JSON.toJSONString(UtilMap.map("selectField_lggd61a7", period)))
+                .build();
+        List<Map> schoolList = mjyService.queryAllBySync(ydParam);
+        log.info("学校名额数据, {}", schoolList.size());
+        List list = schoolList.stream().map(item -> (Map) item.get("formData")).collect(Collectors.toList());
+        return McR.success(mjyService.matchQuery(list));
+    }
+
+    /**
+     * 推送学校名额确认
+     */
+    @PostMapping("confirm/quota")
+    McR quotaConfirm(HttpServletRequest request) {
+        Map data = UtilServlet.getParamMap(request);
+        McException.assertParamException_Null(data, "formInstanceId");
+        YDParam ydParam = YDParam.builder()
+                .formInstanceId(String.valueOf(data.get("formInstanceId")))
+                .build();
+        Map formData = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_id).getFormData();
+        List<Map> details = (List<Map>) formData.get("tableField_lgf41nj3");
+        // 创建学校确认流程: src - cur, 发起流程 - 学校确认; 明细内: 全称, 简称, 在编在岗, 学带 + 骨干教师, 后备, 学校负责人
+        Map<String, String> keyMap = UtilMap.map("selectField_lgf41nj4, selectField_lgi7oaqo, numberField_lgf2au4s, numberField_lgi7oaqq, numberField_lgi7oaqr, employeeField_lgf7ky0h",
+                "selectField_lgf41nj4, selectField_lgi7oaqo, numberField_lgf2au4s, numberField_lgi7oaqq, numberField_lgi7oaqr, employeeField_lgf7m9s4");
+        for (Map detail : details) {
+            // 主表读取: 届别, 提交人
+            Map formJson = UtilMap.map("selectField_lggd61a7, employeeField_lgf7ky0i", formData.get("selectField_lggd61a7"), formData.get("employeeField_lgf6dzrv_id"));
+            for (String key : keyMap.keySet()) {
+                if (key.contains("employeeField_")) {
+                    formJson.put(key, detail.get(keyMap.get(key) + "_id"));
+                } else {
+                    formJson.put(key, detail.get(keyMap.get(key)));
+                }
+            }
+            log.info("名额确认记录, {}, {}", formJson, detail);
+            ydParam.setFormDataJson(JSON.toJSONString(formJson));
+            ydParam.setFormUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLYD");
+            ydParam.setProcessCode("TPROC--G2666871DH3AGJ52BWGGY62N9HGV39Y1TRTGLL6");
+            ydClient.operateData(ydParam, YDConf.FORM_OPERATION.start);
+        }
+        return McR.success();
+    }
+
+    /**
+     * 汇总学校复核数据
+     */
+    @Synchronized
+    @PostMapping("approve/quota")
+    McR quotaApprove(HttpServletRequest request) {
+        Map data = UtilServlet.getParamMap(request);
+        McException.assertParamException_Null(data, "formInstanceId");
+        log.info("学校汇总, {}", data);
+
+        // 查询教师申请数据
+        YDParam ydParam = YDParam.builder()
+                .formInstanceId(String.valueOf(data.get("formInstanceId")))
+                .build();
+        Map teacherData = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_id).getFormData();
+
+        // 匹配学校汇总数据: 届别 + 学校全称
+        Map formData = UtilMap.map("selectField_lggd61a7, selectField_lgf41nj4", teacherData.get("selectField_lgs5yclt"), teacherData.get("textField_lgf4ppaw"));
+        ydParam.setFormUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLWD");
+        ydParam.setSearchCondition(JSON.toJSONString(formData));
+        List<Map> schoolApprove = (List<Map>) ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list_all).getData();
+
+        // 组装评审明细数据: 关联评选记录, 教师进修编号, 教师成员, 手机号, 评选类型, 行政职务
+        formData.put("selectField_lgi7oaqo", teacherData.get("textField_lgib58q3")); // 学校简称
+        formData.put("employeeField_lgf7ky0h", teacherData.get("employeeField_lgf7ky0h_id")); // 学校负责人
+        formData.put("radioField_lggd61a8", "进行中"); // 届别评选状态
+        List<Map> details = new ArrayList<>();
+        if (UtilList.isNotEmpty(schoolApprove)) {
+            Map recordData = schoolApprove.get(0);
+            details = (List<Map>) (((Map) recordData.get("formData"))).get("tableField_lgiacs44");
+            // 成员组件 && 关联表单数据处理
+            details.forEach(item -> {
+                item.put("employeeField_lgialujd", item.get("employeeField_lgialujd_id"));
+                item.put("associationFormField_lgiacs47", JSON.parse(String.valueOf(item.get("associationFormField_lgiacs47_id"))));
+            });
+            ydParam.setFormInstanceId(String.valueOf(recordData.get("formInstanceId")));
+        }
+        Map detail = UtilMap.map("textField_lgialujb, employeeField_lgialujd, numberField_lgeyihee, selectField_lgf4ppa6, textField_lgt9sb8f", teacherData.get("textField_lgf4ppax"), teacherData.get("employeeField_lgf4ppa7_id"), teacherData.get("numberField_lgeyihee"), teacherData.get("selectField_lgf4ppa6"), teacherData.get("textField_lgt9sb8f"));
+        detail.put("associationFormField_lgiacs47", Arrays.asList(UtilMap.map("appType, formUuid, instanceId, title, formType, subTitle", ydConf.getAppType(), "FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLVD", data.get("formInstanceId"), teacherData.get("textField_lgs8ej3g"), "receipt", teacherData.get("textField_lgf4ppax"))));
+        details.add(detail);
+        // prd 按照评选类型, 排序: 学带, 骨干, 特色, 后备
+        Map sortRule = UtilMap.map("学科带头人, 骨干教师, 骨干后备, 特色骨干", 1, 2, 3, 4);
+        details.forEach(item -> item.put("sort", sortRule.get(item.get("selectField_lgf4ppa6"))));
+        Collections.sort(details, Comparator.comparingInt(o -> Integer.parseInt(String.valueOf(o.get("sort")))));
+        formData.put("tableField_lgiacs44", details);
+        log.info("学校汇总记录, {}", JSON.toJSONString(formData));
+        ydParam.setFormDataJson(JSON.toJSONString(formData));
+        ydParam.setFormUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLWD");
+        ydParam.setProcessCode("TPROC--G2666871DH3AGJ52BWGGY62N9HGV39Y1TRTGLN6");
+        if (UtilList.isNotEmpty(schoolApprove)) {
+            ydParam.setUpdateFormDataJson(ydParam.getFormDataJson());
+            ydClient.operateData(ydParam, YDConf.FORM_OPERATION.update);
+            return McR.success();
+        }
+        ydClient.operateData(ydParam, YDConf.FORM_OPERATION.start);
+
+        return McR.success();
+    }
+
+    @Autowired
+    private YDService ydService;
+
+    /**
+     * 学校申报区里, 名额校验
+     */
+    @PostMapping("validate/quota")
+    McR quotaValidate(HttpServletRequest request) {
+        Map data = UtilServlet.getParamMap(request);
+        McException.assertParamException_Null(data, "formInstanceId");
+        log.info("名额校验, {}", data);
+
+        List usersZRMD = mjyService.getDirectList(); // 直入名单
+        // 学校申报数据
+        YDParam ydParam = YDParam.builder()
+                .formInstanceId(String.valueOf(data.get("formInstanceId")))
+                .build();
+        Map approveData = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_id).getFormData();
+        List<Map> details = (List<Map>) approveData.get("tableField_lgiacs44");
+        // 储存排名并进行排序
+        List arrSort = (List) JSON.parse(String.valueOf(data.get("details_sort")));
+        for (int i = 0; i < arrSort.size(); i++) {
+            details.get(i).put("numberField_lh8monwb", arrSort.get(i));
+        }
+        Collections.sort(details, Comparator.comparingInt(o -> Integer.parseInt(String.valueOf(o.get("numberField_lh8monwb")))));
+
+        // 匹配通过数据 & 未在直入名单 [进修编号]
+        List arrStatus = (List) JSON.parse(String.valueOf(data.get("details_status")));
+        List arrType = (List) JSON.parse(String.valueOf(data.get("details_type")));
+        List arrPeerRatio = (List) JSON.parse(String.valueOf(data.get("details_peer_ratio")));
+        List<Integer> approveList = new ArrayList();
+        int appXKDTR = 0, appGGJS = 0, appGGHB = 0, appTSGG = 0;
+        for (int i = 0; i < arrStatus.size(); i++) {
+            // prd 直入名单通过人员匹配, 不占用名额, 教师信息报区里
+            if (usersZRMD.contains(details.get(i).get("textField_lgialujb"))) {
+                details.get(i).put("isDirect", "直入名单");
+                approveList.add(i);
+                log.info("直入名单, {}", details.get(i));
+            } else if (arrStatus.get(i).equals("通过")) {
+                if (arrType.get(i).equals("学科带头人")) appXKDTR += 1;
+                if (arrType.get(i).equals("骨干教师")) appGGJS += 1;
+                if (arrType.get(i).equals("骨干后备")) appGGHB += 1;
+                if (arrType.get(i).equals("特色骨干")) appTSGG += 1;
+                approveList.add(i);
+            }
+            // 记录前台填写同职比
+            details.get(i).put("textField_lgst1j31", arrPeerRatio.get(i));
+        }
+        log.info("申报数量, appXKDTR = {}, appGGJS = {}, appGGHB = {}, appTSGG = {}", appXKDTR, appGGJS, appGGHB, appTSGG);
+
+        // 学校名额信息: 届别 + 学校全称
+        ydParam.setFormInstanceId(null);
+        ydParam.setFormUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLLE");
+        ydParam.setSearchCondition(JSON.toJSONString(UtilMap.map("selectField_lggd61a7, textField_lgezb8r7", approveData.get("selectField_lggd61a7"), approveData.get("selectField_lgf41nj4"))));
+        ydParam.setPageSize(1);
+        Map schoolData = (Map) ((List<Map>) ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list).getData()).get(0).get("formData");
+        int numXDGG = Integer.valueOf(String.valueOf(schoolData.get("numberField_lgf2au52")));
+        int numGGHB = Integer.valueOf(String.valueOf(schoolData.get("numberField_lgf2au4z")));
+        // 学带 + 骨干教师名额校验
+        McException.assertAccessException((appXKDTR + appGGJS) > numXDGG, "申报名额校验未通过,请核查!");
+        // 名额降级逻辑,骨干后备可以占骨干教师 + 学带名额 [prd 申报名额未用完或超标均不能上报]
+        McException.assertAccessException((appGGHB + appXKDTR + appGGJS) != (numGGHB + numXDGG), "申报名额校验未通过,请核查!");
+
+        // 更新申报信息: 进修编号, 评选类型, 同职比, 手机号
+        Map updateJson = UtilMap.map("numberField_lgstol7i, numberField_lgstol7k, numberField_lgstol7j, numberField_lgstol7l", appXKDTR, appGGJS, appGGHB, appTSGG);
+        List<Map> appDetails = approveList.stream().map(index -> {
+            Map item = details.get(index); // 记录索引
+            Map row = UtilMap.map("textField_lgst1j33, selectField_lgst1j35, textField_lgst1j3g, numberField_lgst1j37", item.get("textField_lgialujb"), item.get("selectField_lgf4ppa6"), item.get("textField_lgst1j31"), item.get("numberField_lgeyihee"));
+            row.put("textField_lgt59zeb", item.get("isDirect"));
+            row.put("employeeField_lgst1j34", item.get("employeeField_lgialujd_id"));
+            row.put("associationFormField_lgst1j32", JSON.parse(String.valueOf(item.get("associationFormField_lgiacs47_id"))));
+            return row;
+        }).collect(Collectors.toList());
+        updateJson.put("tableField_lgst1j3e", appDetails);
+        updateJson.put("tableField_lgiacs44", details); // 更新学校排序
+        ydParam.setFormInstanceId(String.valueOf(data.get("formInstanceId")));
+        ydParam.setUpdateFormDataJson(JSON.toJSONString(updateJson));
+        // 操作数据 [异步] - 审批通过立即更新, 会无效
+        ydService.operateData(ydParam, YDConf.FORM_OPERATION.update);
+        log.info("更新申报信息, {}", appDetails);
+
+        return McR.success();
+    }
+
+    // 宜搭审批页面弱校验提示框会被覆盖, 或另一个校验冲销. 添加记录, 第二次请求放行
+    private Map checkMap = new HashMap();
+
+    /**
+     * 学校申报区里, 学校中层或校级副职干部, 弱校验
+     */
+    @PostMapping("check/quota")
+    McR quotaCheck(HttpServletRequest request) {
+        Map data = UtilServlet.getParamMap(request);
+        McException.assertParamException_Null(data, "formInstanceId");
+        log.info("名额验证, {}", data);
+
+        List usersZRMD = mjyService.getDirectList(); // 直入名单
+        // 学校申报数据
+        YDParam ydParam = YDParam.builder()
+                .formInstanceId(String.valueOf(data.get("formInstanceId")))
+                .build();
+        Map approveData = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_id).getFormData();
+        List<Map> details = (List<Map>) approveData.get("tableField_lgiacs44");
+        // 匹配通过数据 & 未在直入名单 [进修编号]
+        List arrStatus = (List) JSON.parse(String.valueOf(data.get("details_status")));
+        List arrType = (List) JSON.parse(String.valueOf(data.get("details_type")));
+        List<Map> approveList = new ArrayList();
+        int appGGHB = 0;
+        for (int i = 0; i < arrStatus.size(); i++) {
+            // prd 直入名单通过人员匹配, 不占用名额, 教师信息报区里
+            if (usersZRMD.contains(details.get(i).get("textField_lgialujb"))) {
+                approveList.add(details.get(i));
+                details.get(i).put("isDirect", "直入名单");
+                log.info("直入名单, {}", details.get(i));
+            } else if (arrStatus.get(i).equals("通过")) {
+                approveList.add(details.get(i));
+                if (arrType.get(i).equals("骨干后备")) appGGHB += 1;
+            }
+        }
+        float numZCXF = approveList.stream().filter(item -> Arrays.asList("学校副职", "中层副职", "中层正职").contains(item.get("textField_lgt9sb8f"))).collect(Collectors.toList()).size();
+        log.info("学校中层或校级副职干部, 弱校验, appGGHB = {}, nunZCXF = {}", appGGHB, numZCXF);
+
+        // 学校名额信息: 届别 + 学校全称
+        ydParam.setFormInstanceId(null);
+        ydParam.setFormUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLLE");
+        ydParam.setSearchCondition(JSON.toJSONString(UtilMap.map("selectField_lggd61a7, textField_lgezb8r7", approveData.get("selectField_lggd61a7"), approveData.get("selectField_lgf41nj4"))));
+        ydParam.setPageSize(1);
+        Map schoolData = (Map) ((List<Map>) ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list).getData()).get(0).get("formData");
+        // prd 学校中层或校级副职干部,每周兼课时数需达到教育局规定课时量,比例不超过学校申报骨干后备教师人选的20%。(学校教师人在编在岗数不满30人,比例不超过学校申报骨干后备教师人选的25%)
+        float numZBZG = Integer.valueOf(String.valueOf(schoolData.get("numberField_lgf2au4s")));
+        int ratio = numZBZG >= 30 ? 25 : 20;
+        log.info("学校中层或校级副职干部, 弱校验, check = {}, ratio = {}", appGGHB / numZBZG, ratio / 100F);
+        if (!checkMap.containsKey(data.get("formInstanceId"))) {
+            checkMap.put(data.get("formInstanceId"), true);
+            McException.assertAccessException((appGGHB / numZBZG) > (ratio / 100F), "学校中层或校级副职干部, 占比骨干后备超标准");
+        }
+        return McR.success();
+    }
+
+    /**
+     * 是否直入名单
+     */
+    @PostMapping("direct/quota")
+    McR directQuota(@RequestBody Map data) {
+        log.info("是否直入名单", data);
+        McException.assertParamException_Null(data, "code");
+        List usersZRMD = mjyService.getDirectList(); // 直入名单
+        return McR.success(UtilMap.map("isDirect", usersZRMD.contains(data.get("code"))));
+    }
+
+    /**
+     * 退回卡片通知
+     * 被学校退回:某某老师,您的骨干系列评选材料已被学校退回。
+     * 被区级退回:某某老师,您的骨干系列评选材料已被区级退回;某某学校,您校某某老师的评选资料已被区级退回。
+     */
+    @PostMapping("notice/sendback")
+    McR sendBackNotice(HttpServletRequest request) {
+        Map data = UtilServlet.getParamMap(request);
+        log.info("退回卡片通知, {}", data);
+        McException.assertParamException_Null(data, "teachers, administrator, results, associations, createUserId, schoolName");
+        List<String> teachers = (List<String>) JSON.parse(String.valueOf(data.get("teachers")));
+        List<String> associations = (List<String>) JSON.parse(String.valueOf(data.get("associations")));
+        List<String> results = (List<String>) JSON.parse(String.valueOf(data.get("results")));
+        String createUserId = String.valueOf(data.get("createUserId"));
+        String schoolName = String.valueOf(data.get("schoolName"));
+        for (int i = 0; i < results.size(); i++) {
+            String status = results.get(i);
+            if (!Arrays.asList("不通过", "退回").contains(status)) {
+                continue;
+            }
+            List<Map> associationForm = (List<Map>) JSON.parse(associations.get(i));
+            String notice = associationForm.get(0).get("title") + "老师[" + associationForm.get(0).get("subTitle") + "]";
+            Map formData = UtilMap.map("employeeField_lhgj6tc7, employeeField_lhgj6tc9, associationFormField_lgiacs47", JSON.parse(teachers.get(i)), data.get("administrator"), associationForm);
+            if ("不通过".equals(status)) {
+                notice += ", 您好: \n您的骨干系列评选材料已被学校退回。";
+            }
+            if ("退回".equals(status)) {
+                notice += ", 您好: \n您的骨干系列评选材料已被区级退回。";
+                // 通知学校
+                String new_notice = schoolName + ", 管理员您好: \n您校" + associationForm.get(0).get("title") + "老师[" + associationForm.get(0).get("subTitle") + "]";
+                new_notice += "的评选资料已被区级退回。";
+                formData.put("textareaField_lhgj6tcu", new_notice);
+                mjyService.triggerNotice("FORM-NC966W81139A3Y5QEEXT5AZ6BU7M3TB0C9LHLO", createUserId, formData);
+            }
+            // 通知老师
+            formData.put("textareaField_lhgj6tcu", notice);
+            mjyService.triggerNotice("FORM-NT766881D48AF5W78VL7L6VLZTAJ2TOE6JGHL92", createUserId, formData);
+        }
+        return McR.success();
+    }
+
+    /**
+     * 评选信息变更
+     */
+    @PostMapping("update/details")
+    McR updateDetails(HttpServletRequest request) {
+        Map data = UtilServlet.getParamMap(request);
+        McException.assertParamException_Null(data, "formInstanceId");
+        log.info("信息变更, {}", data);
+
+        YDParam ydParam = YDParam.builder()
+                .formInstanceId(String.valueOf(data.get("formInstanceId")))
+                .build();
+        Map formData = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_id).getFormData();
+        List<Map> details = (List<Map>) formData.get("tableField_lgs5ycm5");
+
+        List<Map> association = (List<Map>) JSON.parse(String.valueOf(data.get("associationComp")));
+        ydParam.setFormInstanceId(String.valueOf(association.get(0).get("instanceId")));
+        ydParam.setUpdateFormDataJson(JSON.toJSONString(UtilMap.map("tableField_lgs5ycm5", details)));
+        ydClient.operateData(ydParam, YDConf.FORM_OPERATION.update);
+        return McR.success();
+    }
+}

+ 161 - 0
mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/controller/TestControl.java

@@ -0,0 +1,161 @@
+package com.malk.minjiaoyuan.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.Util.UtilMap;
+import com.malk.minjiaoyuan.service.MJYService;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.server.common.McR;
+import com.malk.server.dingtalk.DDR_New;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Profile;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 指定运行环境
+ *
+ * @Profile("prod"):一般添加于方法和类,标注该方法为指定环境运行 —>  若未找到指定环境会报错,多个环境与 @ActiveProfiles 一致
+ */
+@Profile({"dev"})
+@Slf4j
+@RestController
+@RequestMapping("/minjiaoyuan")
+public class TestControl {
+
+
+    @Autowired
+    private YDClient ydClient;
+
+    @Autowired
+    private YDConf ydConf;
+
+    @Autowired
+    private MJYService mjyService;
+
+    @PostMapping("test2")
+    McR test2() {
+        // 修改评选进修编号
+        String formInstanceId = "cefb90d5-9e8d-4cad-9fad-ac66d8f06362";
+        YDParam ydParam = YDParam.builder()
+                .formInstanceId(formInstanceId)
+                .build();
+        ydParam.setUpdateFormDataJson(JSON.toJSONString(UtilMap.map("selectField_lgf4ppa6", "骨干后备")));
+        ydClient.operateData(ydParam, YDConf.FORM_OPERATION.update);
+        return McR.success();
+    }
+
+    @PostMapping("test")
+    McR test() {
+
+        String formInstanceId = "98c7a6c9-bbbb-49e8-9838-f9f670e07859"; // 上海市金汇高级中学
+//        String formInstanceId = "9c256687-cdee-4ce8-bca6-99f574d81a97"; // 闵行区七宝中心幼儿园
+//        String formInstanceId = "60e7008a-6f11-410a-8019-d24be8c36abe"; // 上海市闵行区七宝幼儿园
+//        String formInstanceId = "808370ff-dfc3-44f0-960e-da5b7c77defb"; // 上海市七宝中学附属鑫都实验中学
+//        String formInstanceId = "86f436ae-0d19-4d6b-a909-346e1c30139e"; // 闵行区实验小学
+//        String formInstanceId = "11c6fb7b-0a8e-4595-b1cf-0a7648316eff"; // 上海市七宝实验小学
+//        String formInstanceId = "6f813646-d2c3-40f3-a72b-bf4fd2175724"; // 上海市民办文绮中学
+//        String formInstanceId = "4808e60e-d645-4ca3-895a-8bf9b582aa3a"; // 上海师范大学康城实验学校
+//        String formInstanceId = "616b546b-a41b-47df-8283-a6c719ca317c"; // 上海市闵行区爱博果果幼儿园
+//        String formInstanceId = "9e380af2-da2d-493e-8a37-39a685e952b1"; // 上海市闵行区颛桥中学
+//        String formInstanceId = "44b0a12d-b10f-4081-bbd7-2107427c675e"; // 上海市七宝中学
+
+
+        // 学校申报数据
+        YDParam ydParam = YDParam.builder()
+                .formInstanceId(formInstanceId)
+                .build();
+        Map approveData = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_id).getFormData();
+        List<Map> details = (List<Map>) approveData.get("tableField_lgiacs44");
+        // 匹配申报数据
+        ydParam.setFormInstanceId("");
+        for (Map detail : details) {
+            ydParam.setSearchFieldJson(JSON.toJSONString(UtilMap.map("textField_lgf4ppax", detail.get("textField_lgialujb"))));
+//            if (String.valueOf(detail.get("employeeField_lgialujd")).contains("刘欣")) {
+//                detail.put("textField_lgialujb", "120111015278");
+//                ydParam.setSearchFieldJson(JSON.toJSONString(UtilMap.map("textField_lgf4ppax", "120111015278")));
+//            }
+            ydParam.setApprovedResult("agree");
+            ydParam.setFormUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLVD");
+            DDR_New ddr_new = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_process);
+            Map data = ((List<Map>) ddr_new.getData()).get(0);
+            Map formData = (Map) data.get("data");
+            detail.put("associationFormField_lgiacs47", Arrays.asList(UtilMap.map("appType, formUuid, instanceId, title, formType, subTitle", ydConf.getAppType(), "FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLVD", data.get("processInstanceId"), formData.get("textField_lgs8ej3g"), "receipt", formData.get("textField_lgf4ppax"))));
+            detail.put("employeeField_lgialujd", formData.get("employeeField_lgf4ppa7_id"));
+//            detail.put("textField_lgivbkar", detail.get("radioField_lgialujc").equals("通过") ? "内通过" : "内拒绝");
+            log.info("xxx, {}, {}", detail.get("employeeField_lgialujd"), ddr_new.getTotalCount());
+            McException.assertAccessException(ddr_new.getTotalCount() != 1, "数据匹配异常");
+        }
+
+        Map update = UtilMap.map("tableField_lgiacs44", details);
+        ydParam.setFormInstanceId(formInstanceId);
+        ydParam.setUpdateFormDataJson(JSON.toJSONString(update));
+        log.info("update, {}, {}", formInstanceId, JSON.toJSONString(update));
+        ydClient.operateData(ydParam, YDConf.FORM_OPERATION.update);
+
+        return McR.success();
+    }
+
+    // 清理数据 [教师档案]
+    @PostMapping("delete")
+    McR delete() {
+//        YDParam ydParam = YDParam.builder()
+//                .formUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLAE")
+//                .build();
+//        List<Map> list = mjyService.queryAllBySync(ydParam);
+//        list.forEach(item -> {
+//            ydParam.setFormInstanceId(String.valueOf(item.get("formInstanceId")));
+//            ydClient.operateData(ydParam, YDConf.FORM_OPERATION.delete);
+//        });
+        return McR.success();
+    }
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    // 清理数据 [通讯录]
+    @SneakyThrows
+    @PostMapping("delete2")
+    McR delete2() {
+
+//        List<Long> deptList = ddClient.getDepartmentId_all(ddClient.getAccessToken());
+//        for (Long deptId : deptList) {
+//            List<String> userList = ddClient_contacts.listDepartmentUserId(ddClient.getAccessToken(), deptId.longValue());
+//            for (String userId : userList) {
+//                if (Arrays.asList("244859276337982323", "011063125337883469").contains(userId)) {
+//                    continue;
+//                }
+//                YDParam ydParam = YDParam.builder()
+//                        .formUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLAE")
+//                        .searchFieldJson(JSON.toJSONString(UtilMap.map("textField_lftczqr5", userId)))
+//                        .build();
+//                DDR_New ddr_new = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_form);
+//                if (ddr_new.getTotalCount() == 0) {
+//                    ddClient_contacts.deleteUser(ddClient.getAccessToken(), userId);
+//                    log.info("xxx, {}, {}, {}", userId, ddr_new.getTotalCount(), ddr_new.getData());
+//                }
+//                Thread.sleep(100); // 避免限流
+//            }
+//        }
+        return McR.success();
+    }
+
+
+    @PostMapping("h3yun-http")
+    McR http(@RequestBody Map data, @RequestParam("code") String code) {
+        log.info("氚云http调试, code = {}, body = {}", code, data);
+        return McR.success(UtilMap.map("name", "氚云http调试"));
+    }
+}

+ 36 - 0
mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/schedule/MJYScheduleTask.java

@@ -0,0 +1,36 @@
+package com.malk.minjiaoyuan.schedule;
+
+import com.malk.minjiaoyuan.service.MJYService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+
+/**
+ * @EnableScheduling 开启桑诺定时任务 [配置参考McScheduleTask]
+ */
+@Slf4j
+@Configuration
+@EnableScheduling
+@ConditionalOnProperty(name = {"spel.scheduling"})
+public class MJYScheduleTask {
+
+    @Autowired
+    private MJYService mjyService;
+
+    /**
+     * 定时同步后更新为已同步 [0...5分钟/次]
+     */
+    @Scheduled(cron = "0 0/5 6-23 * * ?")
+    public void Time_Period_1() {
+        try {
+            log.info("###### [MJY]同步教师档案开始 [已邀请] ######");
+            mjyService.syncTeacherStatus();
+        } catch (Exception e) {
+            log.error(e.getMessage(), e); // 记录错误日志
+        }
+        log.info("###### [MJY]同步教师档案结束 [已邀请] ######");
+    }
+}

+ 27 - 0
mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/service/MJYService.java

@@ -0,0 +1,27 @@
+package com.malk.minjiaoyuan.service;
+
+import com.malk.server.aliwork.YDParam;
+
+import java.util.List;
+import java.util.Map;
+
+public interface MJYService {
+
+    // 获取学校与类型比例
+    int getSchoolRatio(String schoolName, String typeName);
+
+    // 查询全部数据
+    List<Map> queryAllBySync(YDParam param);
+
+    // 获取直入名单
+    List<String> getDirectList();
+
+    // 触发通知 [宜搭平台账号不会触发通知]
+    void triggerNotice(String formUuid, String createUserId, Map formData);
+
+    // 匹配学校负责人
+    List<Map> matchQuery(List<Map> schoolQuotaList);
+
+    // 同步教师档案 [已邀请]
+    void syncTeacherStatus();
+}

+ 169 - 0
mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/service/impl/MJYImplService.java

@@ -0,0 +1,169 @@
+package com.malk.minjiaoyuan.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.Util.UtilMap;
+import com.malk.minjiaoyuan.service.MJYService;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.aliwork.YDService;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class MJYImplService implements MJYService {
+
+    @Autowired
+    private YDClient ydClient;
+
+    @Autowired
+    private YDService ydService;
+
+    // 名额配置
+    private List<Map> quotaList = new ArrayList<>();
+
+    // 获取学校与类型比例
+    @Override
+    public int getSchoolRatio(String schoolName, String typeName) {
+        if (quotaList.isEmpty()) {
+            List<Map> list = (List<Map>) ydClient.queryData(YDParam.builder()
+                    .formUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLKE")
+                    .pageSize(YDConf.PAGE_SIZE_LIMIT)
+                    .build(), YDConf.FORM_QUERY.retrieve_list_all).getData();
+            quotaList = list.stream().map(item -> (Map) item.get("formData")).collect(Collectors.toList());
+            log.info("名额配置数据, {}", quotaList.size());
+        }
+        Map formData = quotaList.stream().filter(item -> typeName.equals(item.get("selectField_lgf306u6"))).findAny().get();
+        int ratio = Integer.valueOf(String.valueOf(formData.get("numberField_lgezizyl")));
+        List<Map<String, ?>> details = (List<Map<String, ?>>) formData.get("tableField_lgezizyn");
+        Optional detail = details.stream().filter(item -> item.get("selectField_lgezizyo").equals(schoolName)).findAny();
+        if (detail.isPresent()) {
+            ratio = Integer.valueOf(String.valueOf(((Map) detail.get()).get("numberField_lgezizyq")));
+        }
+        return ratio;
+    }
+
+    // 查询全部数据
+    @Override
+    public List<Map> queryAllBySync(YDParam param) {
+        param.setPageSize(1);
+        long totalCount = ydClient.queryData(param, YDConf.FORM_QUERY.retrieve_list).getTotalCount();
+        List<Map> dataList = new ArrayList<>();
+        // Math.ceil 需要有浮点数, 否则转 int 类型忽略掉, 向上取整就会是当前值
+        for (int index = 1; index <= (int) Math.ceil(totalCount * 1.0 / YDConf.PAGE_SIZE_LIMIT); index++) {
+            // 对象拷贝: 避免并发下分页条件被修改导致数据混乱
+            YDParam ydParam = (YDParam) param.copyParam();
+            ydParam.setPageNumber(index);
+            ydParam.setPageSize(YDConf.PAGE_SIZE_LIMIT);
+            dataList.addAll((List) ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_list).getData());
+        }
+        return dataList;
+    }
+
+    // 获取直入名单
+    @Override
+    public List<String> getDirectList() {
+        YDParam ydParam = YDParam.builder()
+                .formUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLKE")
+                .searchCondition(JSON.toJSONString(UtilMap.map("selectField_lgf306u6", "直入名单")))
+                .pageSize(1)
+                .build();
+        String formInstanceId = (String) ((List<Map>) ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_form).getData()).get(0).get("formInstanceId");
+        ydParam.setFormInstanceId(formInstanceId);
+        ydParam.setTableFieldId("tableField_lgf2p2jm");
+        List<Map> details = ydService.queryDetails(ydParam);
+        log.info("直入名单, {}", details.size());
+        return details.stream().map(item -> (String) item.get("textField_lgt5j83x")).collect(Collectors.toList());
+    }
+
+    // 触发通知
+    @Override
+    public void triggerNotice(String formUuid, String createUserId, Map formData) {
+        YDParam ydParam = YDParam.builder()
+                .formUuid(formUuid)
+                .formDataJson(JSON.toJSONString(formData))
+                .userId(createUserId) // 触发通知
+                .build();
+        ydClient.operateData(ydParam, YDConf.FORM_OPERATION.create);
+    }
+
+    // 匹配学校负责人
+    @Override
+    public List<Map> matchQuery(List<Map> schoolQuotaList) {
+        YDParam ydParam = YDParam.builder()
+                .formUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLUE")
+                .build();
+        List<Map> schoolAuthList = queryAllBySync(ydParam);
+        List list = schoolQuotaList.stream().map(item -> {
+            // 条件: 学校全称
+            Optional optional = schoolAuthList.stream().filter(row -> ((Map) row.get("formData")).get("selectField_lgf41nj4").equals(item.get("textField_lgezb8r7"))).findAny();
+            if (optional.isPresent()) {
+                Map data = (Map) ((Map) optional.get()).get("formData");
+                // 前端展示格式: prd 学校负责人单选
+                List<String> empsName = (List<String>) data.get("employeeField_lgf7h60y");
+                List<String> empsId = (List<String>) data.get("employeeField_lgf7h60y_id");
+                List<Map> managers = new ArrayList<>();
+                for (int i = 0; i < empsName.size(); i++) {
+                    managers.add(UtilMap.map("name, value", empsName.get(i), empsId.get(i)));
+                }
+                item.put("employeeField_lgf7m9s4", managers);
+                log.info("匹配学校负责人, {}", data);
+            }
+            return item;
+        }).collect(Collectors.toList());
+        return list;
+    }
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    // 同步教师档案 [已邀请]
+    @Override
+    public void syncTeacherStatus() {
+        // 查询已邀请教师档案数据
+        YDParam ydParam = YDParam.builder()
+                .formUuid("FORM-AC666081555ANZAZ6D4IVCQLY5Y12P4ZSRTGLAE")
+                .searchFieldJson(JSON.toJSONString(UtilMap.map("radioField_lhlhshbc", "已邀请")))
+                .build();
+        List<Map> dataList = queryAllBySync(ydParam);
+        log.info("同步教师数量, {}", dataList.size());
+        for (Map formData : dataList) {
+            Map dataForm = (Map) formData.get("formData");
+            String userId = dataForm.get("textField_lftczqr5").toString();
+            String remark;
+            String status = "已邀请";
+            // 是否进入架构
+            try {
+                ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), userId);
+                remark = "已同步";
+                status = "已同步";
+            } catch (McException e) {
+                remark = e.getMessage();
+                log.error(e.getMessage(), e);
+            }
+            // 发送同步通知
+            if ("已同步".equals(remark)) {
+                String notice = dataForm.get("textField_lghs4pmx") + "老师[" + userId + "]";
+                notice += ", 您好: \n欢迎加入【闵行区教师梯队管理】架构, 您的档案已同步, 可发起骨干系列评选报名";
+                Map data = UtilMap.map("employeeField_lhgj6tc7, textField_lhlj3dgb, textareaField_lhgj6tcu", Arrays.asList(userId), userId, notice);
+                triggerNotice("FORM-8Y866XB1FGHAB037F4F7054SZMHI2RFZ1JLHLP", userId, data);
+            }
+            // 同步邀请状态
+            ydParam.setFormInstanceId(formData.get("formInstanceId").toString());
+            ydParam.setUpdateFormDataJson(JSON.toJSONString(UtilMap.map("textareaField_lhlqrv31, radioField_lhlhshbc, employeeField_lgeyfc4d", remark, status, Arrays.asList(userId))));
+            ydClient.operateData(ydParam, YDConf.FORM_OPERATION.update);
+            log.info("同步教师状态, {}, {}", userId, remark);
+        }
+    }
+}

+ 65 - 0
mjava-minjiaoyuan/src/main/resources/application-dev.yml

@@ -0,0 +1,65 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/service/_Tool/var/mjava/tmp//file/
+    image: /Users/malk/service/_Tool/var/mjava/tmp//image/
+    tmp: /Users/malk/service/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/service/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/service/_Tool/var/mjava/log
+
+## dingtalk
+#dingtalk:
+#  agentId: 2550726809
+#  appKey: dingtift81fcga4rmrmk
+#  appSecret: Oa_S7CYYAfa3CurDbaTk1CBlSvfpcFs6ROjt8OTS8fDsjnS45X1CmxGgWbpJ8lI0
+#  corpId: dingcc1b1ffad0d5ca1d
+#  aesKey:
+#  token:
+#
+## aliwork
+#aliwork:
+#  appType: APP_GHMWTMHNZFEX24QOUC63
+#  systemToken: 4A9667B1NXM9XUSBDNR208ZMA2UQ20A99XEGLIC
+
+
+# dingtalk
+dingtalk:
+  agentId: 2559056539
+  appKey: dingpd6ukkzzcbsczp0n
+  appSecret: 7tTurS8akT9OYegOIe9sBpqdLXOxNCtlNgIwqdolH3VkTxupXzN_fQwASzBQHE6A
+  corpId: ding0f12f2ed788f674ef5bf40eda33b7ba0
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_AD5T4ITVLW40MKR7V3LM
+  systemToken: 7N5664D1GX5A9VWICV06RCOARNMW273ZSRTGL7N7

+ 47 - 0
mjava-minjiaoyuan/src/main/resources/application-prod.yml

@@ -0,0 +1,47 @@
+# 环境配置
+server:
+  port: 9007
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+## dingtalk
+#dingtalk:
+#  agentId: 2550726809
+#  appKey: dingtift81fcga4rmrmk
+#  appSecret: Oa_S7CYYAfa3CurDbaTk1CBlSvfpcFs6ROjt8OTS8fDsjnS45X1CmxGgWbpJ8lI0
+#  corpId: dingcc1b1ffad0d5ca1d
+#  aesKey:
+#  token:
+#
+## aliwork
+#aliwork:
+#  appType: APP_GHMWTMHNZFEX24QOUC63
+#  systemToken: 4A9667B1NXM9XUSBDNR208ZMA2UQ20A99XEGLIC
+
+# dingtalk
+dingtalk:
+  agentId: 2559056539
+  appKey: dingpd6ukkzzcbsczp0n
+  appSecret: 7tTurS8akT9OYegOIe9sBpqdLXOxNCtlNgIwqdolH3VkTxupXzN_fQwASzBQHE6A
+  corpId: ding0f12f2ed788f674ef5bf40eda33b7ba0
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_AD5T4ITVLW40MKR7V3LM
+  systemToken: 7N5664D1GX5A9VWICV06RCOARNMW273ZSRTGL7N7

+ 35 - 0
mjava-minjiaoyuan/src/test/resources/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-minjiaoyuan'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 65 - 0
mjava-minjiaoyuan/target/classes/application-dev.yml

@@ -0,0 +1,65 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/service/_Tool/var/mjava/tmp//file/
+    image: /Users/malk/service/_Tool/var/mjava/tmp//image/
+    tmp: /Users/malk/service/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/service/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/service/_Tool/var/mjava/log
+
+## dingtalk
+#dingtalk:
+#  agentId: 2550726809
+#  appKey: dingtift81fcga4rmrmk
+#  appSecret: Oa_S7CYYAfa3CurDbaTk1CBlSvfpcFs6ROjt8OTS8fDsjnS45X1CmxGgWbpJ8lI0
+#  corpId: dingcc1b1ffad0d5ca1d
+#  aesKey:
+#  token:
+#
+## aliwork
+#aliwork:
+#  appType: APP_GHMWTMHNZFEX24QOUC63
+#  systemToken: 4A9667B1NXM9XUSBDNR208ZMA2UQ20A99XEGLIC
+
+
+# dingtalk
+dingtalk:
+  agentId: 2559056539
+  appKey: dingpd6ukkzzcbsczp0n
+  appSecret: 7tTurS8akT9OYegOIe9sBpqdLXOxNCtlNgIwqdolH3VkTxupXzN_fQwASzBQHE6A
+  corpId: ding0f12f2ed788f674ef5bf40eda33b7ba0
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_AD5T4ITVLW40MKR7V3LM
+  systemToken: 7N5664D1GX5A9VWICV06RCOARNMW273ZSRTGL7N7

+ 47 - 0
mjava-minjiaoyuan/target/classes/application-prod.yml

@@ -0,0 +1,47 @@
+# 环境配置
+server:
+  port: 9007
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+## dingtalk
+#dingtalk:
+#  agentId: 2550726809
+#  appKey: dingtift81fcga4rmrmk
+#  appSecret: Oa_S7CYYAfa3CurDbaTk1CBlSvfpcFs6ROjt8OTS8fDsjnS45X1CmxGgWbpJ8lI0
+#  corpId: dingcc1b1ffad0d5ca1d
+#  aesKey:
+#  token:
+#
+## aliwork
+#aliwork:
+#  appType: APP_GHMWTMHNZFEX24QOUC63
+#  systemToken: 4A9667B1NXM9XUSBDNR208ZMA2UQ20A99XEGLIC
+
+# dingtalk
+dingtalk:
+  agentId: 2559056539
+  appKey: dingpd6ukkzzcbsczp0n
+  appSecret: 7tTurS8akT9OYegOIe9sBpqdLXOxNCtlNgIwqdolH3VkTxupXzN_fQwASzBQHE6A
+  corpId: ding0f12f2ed788f674ef5bf40eda33b7ba0
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_AD5T4ITVLW40MKR7V3LM
+  systemToken: 7N5664D1GX5A9VWICV06RCOARNMW273ZSRTGL7N7

+ 5 - 0
mjava-minjiaoyuan/target/maven-archiver/pom.properties

@@ -0,0 +1,5 @@
+#Generated by Maven
+#Sun May 14 08:22:38 CST 2023
+version=1.0-SNAPSHOT
+groupId=com.malk
+artifactId=mjava-minjiaoyuan

+ 7 - 0
mjava-minjiaoyuan/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst

@@ -0,0 +1,7 @@
+com/malk/minjiaoyuan/service/MJYService.class
+com/malk/minjiaoyuan/controller/InviteControl.class
+com/malk/minjiaoyuan/schedule/MJYScheduleTask.class
+com/malk/minjiaoyuan/service/impl/MJYImplService.class
+com/malk/minjiaoyuan/controller/MJYController.class
+com/malk/minjiaoyuan/controller/TestControl.class
+com/malk/minjiaoyuan/Boot.class

+ 7 - 0
mjava-minjiaoyuan/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst

@@ -0,0 +1,7 @@
+/Users/malk/server/java-mcli-2/mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/Boot.java
+/Users/malk/server/java-mcli-2/mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/controller/MJYController.java
+/Users/malk/server/java-mcli-2/mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/controller/TestControl.java
+/Users/malk/server/java-mcli-2/mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/service/impl/MJYImplService.java
+/Users/malk/server/java-mcli-2/mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/schedule/MJYScheduleTask.java
+/Users/malk/server/java-mcli-2/mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/controller/InviteControl.java
+/Users/malk/server/java-mcli-2/mjava-minjiaoyuan/src/main/java/com/malk/minjiaoyuan/service/MJYService.java

BIN
mjava-minjiaoyuan/target/mjava-minjiaoyuan.jar.original


+ 35 - 0
mjava-minjiaoyuan/target/test-classes/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-minjiaoyuan'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 54 - 0
mjava-rongzhi/pom.xml

@@ -0,0 +1,54 @@
+<?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">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-rongzhi</artifactId>
+    <description>榕智钉钉考勤数据同步至易快报档案</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 32 - 0
mjava-rongzhi/src/main/java/com/malk/rongzhi/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.rongzhi;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 42 - 0
mjava-rongzhi/src/main/java/com/malk/rongzhi/controller/RongZhiController.java

@@ -0,0 +1,42 @@
+package com.malk.rongzhi.controller;
+
+import com.malk.rongzhi.server.RZConf;
+import com.malk.rongzhi.service.RZService;
+import com.malk.server.common.McR;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/shijianguan")
+public class RongZhiController {
+
+    @Autowired
+    private RZService rzService;
+
+    /**
+     * 钉钉考勤同步
+     */
+    @PostMapping("/attendance")
+    McR attendance(@RequestBody Map<String, String> param) {
+        rzService.uploadTravelData();
+        return McR.success();
+    }
+    
+    /**
+     * 推送易快报
+     */
+    @PostMapping("/form-push")
+    McR formPush(@RequestBody Map<String, String> param) {
+        return McR.success(rzService.getAccessToken(RZConf.TYPE.ekuaibao));
+    }
+}

+ 85 - 0
mjava-rongzhi/src/main/java/com/malk/rongzhi/controller/ShiJianGuanController.java

@@ -0,0 +1,85 @@
+package com.malk.rongzhi.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.malk.Util.UtilMap;
+import com.malk.Util.UtilServlet;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/shijianguan")
+public class ShiJianGuanController {
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private YDClient ydClient;
+
+    /**
+     * 创建人员
+     */
+    @PostMapping("user")
+    McR createUser(HttpServletRequest request) {
+        Map<String, Object> param = UtilServlet.getParamMap(request);
+        log.info("创建用户, {}", param);
+        McException.assertParamException_Null(param, "name", "mobile", "deptId");
+        List<String> deptIds = new ArrayList<>();
+        if (ObjectUtil.isNotNull(param.get("proDeptIds"))) {
+            deptIds.addAll((List<String>) JSON.parse(String.valueOf(param.get("proDeptIds"))));
+        }
+        deptIds.add(String.valueOf(param.get("deptId")));
+        ddClient_contacts.createUser(ddClient.getAccessToken(), String.valueOf(param.get("name")), String.valueOf(param.get("mobile")), deptIds, null);
+        return McR.success();
+    }
+
+    /**
+     * 创建部门
+     */
+    @PostMapping("department")
+    McR createDepartment(HttpServletRequest request) {
+        Map<String, Object> param = UtilServlet.getParamMap(request);
+        log.info("创建部门, {}", param);
+        McException.assertParamException_Null(param, "name", "parentId", "formInstId", "compId_dept");
+        Map extInfo = UtilMap.map("hide_dept, create_dept_group, auto_approve_apply", true, true, true);
+        Map rsp = ddClient_contacts.createDepartment(ddClient.getAccessToken(), String.valueOf(param.get("name")), Long.valueOf(String.valueOf(param.get("parentId"))), extInfo);
+        ydClient.operateData(YDParam.builder()
+                .formInstanceId(String.valueOf(param.get("formInstId")))
+                .updateFormDataJson(JSON.toJSONString(UtilMap.map(String.valueOf(param.get("compId_dept")), rsp.get("dept_id"))))
+                .build(), YDConf.FORM_OPERATION.update);
+        return McR.success();
+    }
+
+    @GetMapping("test")
+    McR test() {
+        ydClient.operateData(YDParam.builder()
+                .formInstanceId("FINST-96766PB1LPS9DBVSBKN988PIAFGM3HJBBACGLJO8")
+                .updateFormDataJson(JSON.toJSONString(UtilMap.map("title", "{\"en_US\":\"gao^sheng^hao(高圣昊)发起的UnNamed Process Form\",\"pureEn_US\":\"gao^sheng^hao(高圣昊)发起的UnNamed Process Form\",\"type\":\"i18n\",\"zh_CN\":\"高圣昊发起的付款申请单\"}")))
+                .build(), YDConf.FORM_OPERATION.update);
+        return McR.success();
+    }
+}

+ 12 - 0
mjava-rongzhi/src/main/java/com/malk/rongzhi/repository/dao/RzEkbRecordDao.java

@@ -0,0 +1,12 @@
+package com.malk.rongzhi.repository.dao;
+
+import com.malk.rongzhi.repository.entity.RzEkbRecordPo;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import javax.transaction.Transactional;
+
+@Transactional
+public interface RzEkbRecordDao extends JpaRepository<RzEkbRecordPo, Long> {
+
+    boolean existsByUserIdAndCheckDate(String userId, String checkDate);
+}

+ 29 - 0
mjava-rongzhi/src/main/java/com/malk/rongzhi/repository/entity/RzEkbRecordPo.java

@@ -0,0 +1,29 @@
+package com.malk.rongzhi.repository.entity;
+
+import com.malk.base.BasePo;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+@Entity
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Table(name = "rz_ebk_record")
+public class RzEkbRecordPo extends BasePo {
+
+    /**
+     * 考勤日期 [开始]
+     */
+    private String checkDate;
+
+    /**
+     * 用户id [易快报]
+     */
+    private String userId;
+}

+ 57 - 0
mjava-rongzhi/src/main/java/com/malk/rongzhi/schedule/RZScheduleTask.java

@@ -0,0 +1,57 @@
+package com.malk.rongzhi.schedule;
+
+import com.malk.rongzhi.service.RZService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+
+/**
+ * @EnableScheduling 开启桑诺定时任务 [配置参考McScheduleTask]
+ */
+@Slf4j
+@Configuration
+@EnableScheduling
+@ConditionalOnProperty(name = {"spel.scheduling"})
+public class RZScheduleTask {
+
+    @Autowired
+    private RZService rzService;
+
+    private void syncAttendance2EKB() {
+        try {
+            log.info("###### [RZ]同步考勤数据至易快报 ######");
+            rzService.uploadTravelData();
+
+        } catch (Exception e) {
+            log.error(e.getMessage(), e); // 记录错误日志
+        }
+        log.info("###### [RZ]同步考勤数据至易快报 ######");
+    }
+
+    /**
+     * 同步考勤数据☞易快报, [0...5分钟/次]
+     */
+    @Scheduled(cron = "0 0/5 22-23 * * ?")
+    public void Time_Period_1() {
+        syncAttendance2EKB();
+    }
+
+    /**
+     * 同步考勤数据☞易快报, [0...5分钟/次]
+     */
+    @Scheduled(cron = "0 0/5 0-6 * * ?")
+    public void Time_Period_2() {
+        syncAttendance2EKB();
+    }
+
+    /**
+     * 同步考勤数据☞易快报, [0...5分钟/次]
+     */
+    @Scheduled(cron = "0 0,5,10,15,20,25,30 7 * * ? ")
+    public void Time_Period_3() {
+        syncAttendance2EKB();
+    }
+}

+ 34 - 0
mjava-rongzhi/src/main/java/com/malk/rongzhi/server/RZConf.java

@@ -0,0 +1,34 @@
+package com.malk.rongzhi.server;
+
+import lombok.Getter;
+
+public class RZConf {
+
+    // 请求类型枚举, 避用条件判定
+    public enum TYPE {
+        dingtalk("/dingding"),
+        ekuaibao("/ekuaibao");
+
+        @Getter
+        private String path;
+
+        TYPE(String path) {
+            this.path = path;
+        }
+    }
+
+    /**
+     * 榕智加密字段
+     */
+    public static final String NONCE = "39350e21-d28c-423d-ae1c-97d9fdac6a60";
+
+    /**
+     * 申请单模板ID
+     */
+    public final static String REQUEST_TEMPLATE_ID = "ID01jaBqslI9LV:PRESET_REQUISITION_TEAM_BUILDING";
+
+    /**
+     * 提交人权限
+     */
+    public final static String SUBMITTED_ID = "ID01jaBqslI9LV:29356832401212740";
+}

+ 29 - 0
mjava-rongzhi/src/main/java/com/malk/rongzhi/server/RZR.java

@@ -0,0 +1,29 @@
+package com.malk.rongzhi.server;
+
+import com.malk.server.common.McException;
+import com.malk.server.common.VenR;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 返回值配置参考McR
+ */
+@Data
+@NoArgsConstructor
+public class RZR extends VenR {
+
+    private String err_code;
+    private String message;
+    private String data;
+
+    // 成功状态标记
+    private final static String SUC_CODE = "0";
+
+    /**
+     * 断言错误信息
+     */
+    @Override
+    public void assertSuccess() {
+        McException.assertException(!err_code.equals(SUC_CODE), err_code, message, "MC-RZ");
+    }
+}

+ 16 - 0
mjava-rongzhi/src/main/java/com/malk/rongzhi/service/RZService.java

@@ -0,0 +1,16 @@
+package com.malk.rongzhi.service;
+
+import com.malk.rongzhi.server.RZConf;
+
+public interface RZService {
+
+    /**
+     * 获取调用授权
+     */
+    String getAccessToken(RZConf.TYPE type);
+
+    /**
+     * 同步考勤数据到e快报
+     */
+    void uploadTravelData();
+}

+ 134 - 0
mjava-rongzhi/src/main/java/com/malk/rongzhi/service/impl/RZServiceImpl.java

@@ -0,0 +1,134 @@
+package com.malk.rongzhi.service.impl;
+
+import com.malk.Util.UtilDateTime;
+import com.malk.Util.UtilHttp;
+import com.malk.Util.UtilMap;
+import com.malk.rongzhi.repository.dao.RzEkbRecordDao;
+import com.malk.rongzhi.repository.entity.RzEkbRecordPo;
+import com.malk.rongzhi.server.RZConf;
+import com.malk.rongzhi.server.RZR;
+import com.malk.rongzhi.service.RZService;
+import com.malk.server.dingtalk.DDConf;
+import com.malk.server.ekuaibao.EKBR;
+import com.malk.service.dingtalk.DDClient_Attendance;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.service.ekuaibao.EKBClient;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class RZServiceImpl implements RZService {
+
+    @Autowired
+    private DDClient_Contacts ddClientImpl_contacts;
+
+    @Autowired
+    private DDClient_Attendance ddClient_attendance;
+
+    @Autowired
+    private EKBClient ekbClient;
+
+    @Autowired
+    private RzEkbRecordDao rzEkbRecordDao;
+
+    /// 获取调用授权
+    @Override
+    public String getAccessToken(RZConf.TYPE type) {
+        String timestamp = String.valueOf(new Date().getTime());
+        String signature = DigestUtils.md5Hex("Max" + timestamp + RZConf.NONCE);
+        Map header = new HashMap();
+        header.put("timestamp", timestamp);
+        header.put("nonce", RZConf.NONCE);
+        header.put("signature", signature);
+        RZR rsp = (RZR) UtilHttp.doGet("https://one-api.max-digital.cn/v1/token" + type.getPath(), header, null, RZR.class);
+        return rsp.getData();
+    }
+
+    // 同步考勤数据到e快报
+    @Override
+    public void uploadTravelData() {
+        // 获取用户数据
+        log.info("###### [DD]开始同步组织架构 ######");
+        List<String> userIds = new ArrayList<>();
+        syncOrganizationalStructure(DDConf.TOP_DEPARTMENT, userIds);
+        log.info("###### [DD]同步组织架构结束 ######");
+        // 获取用户考勤
+        for (int i = 0; i < userIds.size(); i += 50) {
+            int to = (i + 50) > userIds.size() ? userIds.size() : i + 50;
+            // 考勤范围从当日 7.30 到次日 7.30
+            String from = UtilDateTime.formatDate(new Date()) + " 07:30:00";
+            String end = UtilDateTime.formatDate(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000)) + " 07:30:00";
+//            String from = "2023-04-18 07:30:00";
+//            String end = "2023-04-19 07:30:00";
+            List<String> users = userIds.subList(i, to);
+            List<Map> list = ddClient_attendance.listAttendanceRecord(getAccessToken(RZConf.TYPE.dingtalk), users, from, end, false);
+            // 匹配数据考勤
+            users.forEach(user -> {
+                List<Map> records = list.stream().filter(item -> user.equals(item.get("userId"))).collect(Collectors.toList());
+                // 有下班打卡
+                if (records.size() > 1) {
+                    long checkIn = (long) records.get(0).get("userCheckTime");
+                    long checkOut = (long) records.get(records.size() - 1).get("userCheckTime");
+                    String userId = String.valueOf(records.get(0).get("userId"));
+                    LocalDateTime begin = UtilDateTime.getLocalDateTimeFromTimestamp(checkIn);
+                    LocalDateTime finish = UtilDateTime.getLocalDateTimeFromTimestamp(checkOut);
+                    // 下班超过22点, 且当天考勤超过11小时
+                    float hour = UtilDateTime.betweenHour(begin, finish);
+                    if (hour > 11.0f && finish.getHour() > 22) {
+                        String checkDate = UtilDateTime.formatLocalDate(begin.toLocalDate());
+                        if (!rzEkbRecordDao.existsByUserIdAndCheckDate(userId, checkDate)) {
+                            log.info("匹配符合数据, {}, {}, {}", userId, UtilDateTime.formatLocalDateTime(begin), UtilDateTime.formatLocalDateTime(finish));
+                            pushTemplateByRecord(userId, checkIn, checkOut, checkDate);
+                        } else {
+                            log.info("数据已经推送, {}, {}, {}", userId, UtilDateTime.formatLocalDateTime(begin), UtilDateTime.formatLocalDateTime(finish));
+                        }
+                    }
+                }
+            });
+        }
+    }
+
+    // 匹配userId, 以最新数据为准
+    private void syncOrganizationalStructure(Number deptId, List<String> userIds) {
+        // 同步一级部门用户
+        if (deptId.equals(DDConf.TOP_DEPARTMENT)) {
+            userIds.addAll(ddClientImpl_contacts.listDepartmentUserId(getAccessToken(RZConf.TYPE.dingtalk), DDConf.TOP_DEPARTMENT));
+        }
+        // 同步除一级部门外所有部门用户
+        ddClientImpl_contacts.listSubDepartmentId(getAccessToken(RZConf.TYPE.dingtalk), deptId).forEach(dept -> {
+            List<String> ids = ddClientImpl_contacts.listDepartmentUserId(getAccessToken(RZConf.TYPE.dingtalk), dept);
+            userIds.addAll(ids);
+            syncOrganizationalStructure(dept, userIds);
+        });
+    }
+
+    // 推送易快报
+    private void pushTemplateByRecord(String userId, long start, long end, String checkDate) {
+        // 获取用户Id [易快报corpId:钉钉userId]
+        Map userInfo = ekbClient.getStaffInfo(getAccessToken(RZConf.TYPE.ekuaibao), "USERID", Arrays.asList(userId)).get(0);
+        // 获取自定义模板Id [通过list接口查询到固定模板ID, 再实时换取单据版本ID]
+        Map template = ekbClient.getTemplateIdById(getAccessToken(RZConf.TYPE.ekuaibao), Arrays.asList(RZConf.REQUEST_TEMPLATE_ID)).get(0);
+        // 组装自定义模板数据 [手动创建一条记录查询比对模板字段]
+        Map formData = UtilMap.map("submitterId, specificationId", RZConf.SUBMITTED_ID, template.get("id"));  // 固定提交人, 查看权限
+        formData.put("travelers", Arrays.asList(userInfo.get("id")));           // 同行人, 即打车人
+        formData.put("expenseDepartment", userInfo.get("defaultDepartment"));
+        Map travel = UtilMap.map("E_e9101f64b75c7b57a3c0_name, E_e9101f64b75c7b57a3c0_住宿地", "上海市/上海市区", "[{\"key\":\"858\",\"label\":\"上海市/上海市区\"}]"); // 固定打车行程地点
+        travel.put("E_e9101f64b75c7b57a3c0_入住日期", start);  // 上班打卡日期
+        travel.put("E_e9101f64b75c7b57a3c0_离店日期", end);     // 下班打卡日期
+        formData.put("u_行程规划", Arrays.asList(UtilMap.map("dataLinkForm, dataLinkTemplateId", travel, "ID01nORyvKjEPJ"))); // 行程ID通过查询记录复制
+        // 创建单据数据, 推送易快报审批作为打车依据
+        EKBR ekbr = ekbClient.createFormInstance(getAccessToken(RZConf.TYPE.ekuaibao), true, false, formData, null);
+        // 记录当天的推送结果
+        rzEkbRecordDao.save(RzEkbRecordPo.builder()
+                .userId(userId)
+                .checkDate(checkDate).build());
+        log.info("易快报推送结果, {}", ekbr.getFlow());
+    }
+}

+ 58 - 0
mjava-rongzhi/src/main/resources/application-dev.yml

@@ -0,0 +1,58 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/service/_Tool/var/mjava/tmp//file/
+    image: /Users/malk/service/_Tool/var/mjava/tmp//image/
+    tmp: /Users/malk/service/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/service/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/service/_Tool/var/mjava/log
+
+# ekuaibao - 榕智
+ekuaibao:
+  corpId: ID01jaBqslI9LV                  # 易快报的 corpId
+  platformApi: https://dd2.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
+
+# dingtalk - 市建管
+dingtalk:
+  agentId: 2561043249
+  appKey: dingged8ayplgf8g9cjg
+  appSecret: GbNMRf9i970oiKY8cNE39KqpF-fxIwUNuCFvqs_KpbRTfW3GnjRqfYjtBqi5exHF
+  corpId: dingea1dc77298d50115ee0f45d8e4f7c288
+  aesKey:
+  token:
+  operator:
+
+# aliwork
+aliwork:
+  appType: APP_SZMBX0R7WC68M19JCJKG
+  systemToken: 2G766HA16IE97NYK6KTEL94YDW422EZNENRFLD3
+
+

+ 39 - 0
mjava-rongzhi/src/main/resources/application-prod.yml

@@ -0,0 +1,39 @@
+# 环境配置
+server:
+  port: 9006
+
+# condition
+spel:
+  scheduling: false       # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# ekuaibao - 榕智
+ekuaibao:
+  corpId: ID01jaBqslI9LV                  # 易快报的 corpId
+  platformApi: https://dd2.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
+
+# dingtalk - 市建管
+dingtalk:
+  agentId: 2561043249
+  appKey: dingged8ayplgf8g9cjg
+  appSecret: GbNMRf9i970oiKY8cNE39KqpF-fxIwUNuCFvqs_KpbRTfW3GnjRqfYjtBqi5exHF
+  corpId: dingea1dc77298d50115ee0f45d8e4f7c288
+  aesKey:
+  token:
+  operator:
+
+# aliwork
+aliwork:
+  appType: APP_SZMBX0R7WC68M19JCJKG
+  systemToken: 2G766HA16IE97NYK6KTEL94YDW422EZNENRFLD3

+ 35 - 0
mjava-rongzhi/src/test/resources/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-rongzhi'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 58 - 0
mjava-rongzhi/target/classes/application-dev.yml

@@ -0,0 +1,58 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/service/_Tool/var/mjava/tmp//file/
+    image: /Users/malk/service/_Tool/var/mjava/tmp//image/
+    tmp: /Users/malk/service/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/service/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/service/_Tool/var/mjava/log
+
+# ekuaibao - 榕智
+ekuaibao:
+  corpId: ID01jaBqslI9LV                  # 易快报的 corpId
+  platformApi: https://dd2.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
+
+# dingtalk - 市建管
+dingtalk:
+  agentId: 2561043249
+  appKey: dingged8ayplgf8g9cjg
+  appSecret: GbNMRf9i970oiKY8cNE39KqpF-fxIwUNuCFvqs_KpbRTfW3GnjRqfYjtBqi5exHF
+  corpId: dingea1dc77298d50115ee0f45d8e4f7c288
+  aesKey:
+  token:
+  operator:
+
+# aliwork
+aliwork:
+  appType: APP_SZMBX0R7WC68M19JCJKG
+  systemToken: 2G766HA16IE97NYK6KTEL94YDW422EZNENRFLD3
+
+

+ 39 - 0
mjava-rongzhi/target/classes/application-prod.yml

@@ -0,0 +1,39 @@
+# 环境配置
+server:
+  port: 9006
+
+# condition
+spel:
+  scheduling: false       # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: cp-root@2022++
+    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# ekuaibao - 榕智
+ekuaibao:
+  corpId: ID01jaBqslI9LV                  # 易快报的 corpId
+  platformApi: https://dd2.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
+
+# dingtalk - 市建管
+dingtalk:
+  agentId: 2561043249
+  appKey: dingged8ayplgf8g9cjg
+  appSecret: GbNMRf9i970oiKY8cNE39KqpF-fxIwUNuCFvqs_KpbRTfW3GnjRqfYjtBqi5exHF
+  corpId: dingea1dc77298d50115ee0f45d8e4f7c288
+  aesKey:
+  token:
+  operator:
+
+# aliwork
+aliwork:
+  appType: APP_SZMBX0R7WC68M19JCJKG
+  systemToken: 2G766HA16IE97NYK6KTEL94YDW422EZNENRFLD3

+ 50 - 0
mjava-rongzhi/target/generated-sources/java/com/malk/rongzhi/repository/entity/QRzEkbRecordPo.java

@@ -0,0 +1,50 @@
+package com.malk.rongzhi.repository.entity;
+
+import static com.querydsl.core.types.PathMetadataFactory.*;
+
+import com.querydsl.core.types.dsl.*;
+
+import com.querydsl.core.types.PathMetadata;
+import javax.annotation.Generated;
+import com.querydsl.core.types.Path;
+
+
+/**
+ * QRzEkbRecordPo is a Querydsl query type for RzEkbRecordPo
+ */
+@Generated("com.querydsl.codegen.EntitySerializer")
+public class QRzEkbRecordPo extends EntityPathBase<RzEkbRecordPo> {
+
+    private static final long serialVersionUID = 14758822L;
+
+    public static final QRzEkbRecordPo rzEkbRecordPo = new QRzEkbRecordPo("rzEkbRecordPo");
+
+    public final com.malk.base.QBasePo _super = new com.malk.base.QBasePo(this);
+
+    public final StringPath checkDate = createString("checkDate");
+
+    //inherited
+    public final DateTimePath<java.util.Date> createTime = _super.createTime;
+
+    //inherited
+    public final NumberPath<Long> id = _super.id;
+
+    //inherited
+    public final DateTimePath<java.util.Date> updateTime = _super.updateTime;
+
+    public final StringPath userId = createString("userId");
+
+    public QRzEkbRecordPo(String variable) {
+        super(RzEkbRecordPo.class, forVariable(variable));
+    }
+
+    public QRzEkbRecordPo(Path<? extends RzEkbRecordPo> path) {
+        super(path.getType(), path.getMetadata());
+    }
+
+    public QRzEkbRecordPo(PathMetadata metadata) {
+        super(RzEkbRecordPo.class, metadata);
+    }
+
+}
+

+ 5 - 0
mjava-rongzhi/target/maven-archiver/pom.properties

@@ -0,0 +1,5 @@
+#Generated by Maven
+#Fri Apr 21 13:52:13 CST 2023
+version=1.0-SNAPSHOT
+groupId=com.malk
+artifactId=mjava-rongzhi

+ 13 - 0
mjava-rongzhi/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst

@@ -0,0 +1,13 @@
+com/malk/rongzhi/service/impl/RZServiceImpl.class
+com/malk/rongzhi/repository/entity/RzEkbRecordPo$RzEkbRecordPoBuilder.class
+com/malk/rongzhi/schedule/RZScheduleTask.class
+com/malk/rongzhi/service/RZService.class
+com/malk/rongzhi/repository/entity/RzEkbRecordPo.class
+com/malk/rongzhi/Boot.class
+com/malk/rongzhi/controller/ShiJianGuanController.class
+com/malk/rongzhi/repository/dao/RzEkbRecordDao.class
+com/malk/rongzhi/server/RZConf$TYPE.class
+com/malk/rongzhi/server/RZConf.class
+com/malk/rongzhi/controller/RongZhiController.class
+com/malk/rongzhi/server/RZR.class
+com/malk/rongzhi/repository/entity/QRzEkbRecordPo.class

+ 11 - 0
mjava-rongzhi/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst

@@ -0,0 +1,11 @@
+/Users/malk/server/java-mcli-2/mjava-rongzhi/src/main/java/com/malk/rongzhi/Boot.java
+/Users/malk/server/java-mcli-2/mjava-rongzhi/src/main/java/com/malk/rongzhi/controller/ShiJianGuanController.java
+/Users/malk/server/java-mcli-2/mjava-rongzhi/src/main/java/com/malk/rongzhi/controller/RongZhiController.java
+/Users/malk/server/java-mcli-2/mjava-rongzhi/src/main/java/com/malk/rongzhi/schedule/RZScheduleTask.java
+/Users/malk/server/java-mcli-2/mjava-rongzhi/src/main/java/com/malk/rongzhi/repository/entity/RzEkbRecordPo.java
+/Users/malk/server/java-mcli-2/mjava-rongzhi/src/main/java/com/malk/rongzhi/service/RZService.java
+/Users/malk/server/java-mcli-2/mjava-rongzhi/src/main/java/com/malk/rongzhi/repository/dao/RzEkbRecordDao.java
+/Users/malk/server/java-mcli-2/mjava-rongzhi/src/main/java/com/malk/rongzhi/service/impl/RZServiceImpl.java
+/Users/malk/server/java-mcli-2/mjava-rongzhi/src/main/java/com/malk/rongzhi/server/RZR.java
+/Users/malk/server/java-mcli-2/mjava-rongzhi/src/main/java/com/malk/rongzhi/server/RZConf.java
+/Users/malk/server/java-mcli-2/mjava-rongzhi/target/generated-sources/java/com/malk/rongzhi/repository/entity/QRzEkbRecordPo.java

BIN
mjava-rongzhi/target/mjava-rongzhi.jar.original


+ 35 - 0
mjava-rongzhi/target/test-classes/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-rongzhi'
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 54 - 0
mjava-xiding/pom.xml

@@ -0,0 +1,54 @@
+<?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">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-xiding</artifactId>
+    <description>锡鼎crm考勤数据与钉钉审批同步机制</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 32 - 0
mjava-xiding/src/main/java/com/malk/xiding/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.xiding;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 42 - 0
mjava-xiding/src/main/java/com/malk/xiding/controller/XDController.java

@@ -0,0 +1,42 @@
+package com.malk.xiding.controller;
+
+import com.malk.Util.UtilDateTime;
+import com.malk.server.common.McR;
+import com.malk.xiding.server.XDConf;
+import com.malk.xiding.service.XDService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Date;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/xiding")
+public class XDController {
+
+    @Autowired
+    private XDService xdService;
+
+    @PostMapping("test")
+    McR test() {
+        long startTime = UtilDateTime.parseDateTime("2023-03-01" + " 00:00:00").getTime();
+        long endTime = UtilDateTime.parseDateTime("2023-04-30" + " 23:59:59").getTime();
+//        xdService.syncApprove(startTime, endTime, XDConf.TMP_CODE_CC, "出差");
+        xdService.syncApprove(startTime, endTime, XDConf.TMP_CODE_WC, "外出");
+        return McR.success();
+    }
+
+    @PostMapping("test2")
+    McR test2() {
+        Date eTime = UtilDateTime.parseDateTime("2023-04-30" + " 23:59:59");
+        Date sTime = UtilDateTime.parseDateTime("2023-04-01" + " 00:00:00");
+        xdService.syncAttendance(0, sTime, eTime);
+        return McR.success();
+    }
+}

+ 21 - 0
mjava-xiding/src/main/java/com/malk/xiding/repository/dao/XdDdApproveRecordDao.java

@@ -0,0 +1,21 @@
+package com.malk.xiding.repository.dao;
+
+import com.malk.xiding.repository.entity.XdDdApproveRecordPo;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import javax.transaction.Transactional;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 钉钉审批记录
+ */
+@Transactional
+public interface XdDdApproveRecordDao extends JpaRepository<XdDdApproveRecordPo, Long> {
+
+    // 匹配差集, 未同步数据
+    List<XdDdApproveRecordPo> findAllByInstanceIdIn(List<String> InstanceIds);
+
+    // 查询范围, 匹配考勤表
+    List<XdDdApproveRecordPo> findAllByStartTimeAfterAndEndTimeBeforeAndOpenUserIdIsNotNull(Date now1, Date now2);
+}

+ 22 - 0
mjava-xiding/src/main/java/com/malk/xiding/repository/dao/XdDdApproveRecordDao2.java

@@ -0,0 +1,22 @@
+package com.malk.xiding.repository.dao;
+
+import com.malk.xiding.repository.entity.XdDdApproveRecordPo;
+import com.sun.xml.bind.v2.model.core.ID;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.repository.CrudRepository;
+
+import javax.transaction.Transactional;
+import java.util.Date;
+
+/**
+ * 钉钉审批记录
+ */
+@Transactional
+public interface XdDdApproveRecordDao2 extends CrudRepository<XdDdApproveRecordPo, ID> {
+
+    // 查询范围, 匹配考勤表
+    Page<XdDdApproveRecordPo> findAllByStartTimeBeforeAndEndTimeAfter(Date now1, Date now2, Pageable page);
+
+    Page<XdDdApproveRecordPo> findAll(Pageable page);
+}

+ 15 - 0
mjava-xiding/src/main/java/com/malk/xiding/repository/dao/XdDdFxkRelationDao.java

@@ -0,0 +1,15 @@
+package com.malk.xiding.repository.dao;
+
+import com.malk.xiding.repository.entity.XdDdFxkRelationPo;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import javax.transaction.Transactional;
+
+/**
+ * 钉钉与纷享销客id, 同步记录
+ */
+@Transactional
+public interface XdDdFxkRelationDao extends JpaRepository<XdDdFxkRelationPo, Long> {
+
+    XdDdFxkRelationPo findByIdDd(String userId);
+}

+ 14 - 0
mjava-xiding/src/main/java/com/malk/xiding/repository/dao/XdFxkDdAttendanceDao.java

@@ -0,0 +1,14 @@
+package com.malk.xiding.repository.dao;
+
+import com.malk.xiding.repository.entity.XdFxkDdAttendancePo;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import javax.transaction.Transactional;
+
+/**
+ * 纷享销客外勤记录, 写入钉钉考勤记录
+ */
+@Transactional
+public interface XdFxkDdAttendanceDao extends JpaRepository<XdFxkDdAttendancePo, Long> {
+
+}

+ 63 - 0
mjava-xiding/src/main/java/com/malk/xiding/repository/entity/XdDdApproveRecordPo.java

@@ -0,0 +1,63 @@
+package com.malk.xiding.repository.entity;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.malk.base.BasePo;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import java.util.Date;
+
+
+@Entity
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Table(name = "xd_dd_approve_record")
+public class XdDdApproveRecordPo extends BasePo {
+
+    /**
+     * 钉钉用户ID
+     */
+    private String userId;
+
+    /**
+     * 纷享销客ID
+     */
+    private String openUserId;
+
+    /**
+     * 员工姓名
+     */
+    private String userName;
+
+    /**
+     * 实例id
+     */
+    private String instanceId;
+
+    /**
+     * 开始日期
+     */
+    @Temporal(TemporalType.TIMESTAMP)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date startTime;
+
+    /**
+     * 结束日期
+     */
+    @Temporal(TemporalType.TIMESTAMP)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date endTime;
+
+    /**
+     * 类型: 出差\外出
+     */
+    private String type;
+}

+ 44 - 0
mjava-xiding/src/main/java/com/malk/xiding/repository/entity/XdDdFxkRelationPo.java

@@ -0,0 +1,44 @@
+package com.malk.xiding.repository.entity;
+
+import com.malk.base.BasePo;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+@Entity
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Table(name = "xd_dd_fxk_relation")
+public class XdDdFxkRelationPo extends BasePo {
+
+    /**
+     * 钉钉ID
+     */
+    private String idDd;
+
+    /**
+     * 员工姓名
+     */
+    private String name;
+
+    /**
+     * 手机号
+     */
+    private String mobile;
+
+    /**
+     * 纷享销客ID
+     */
+    private String idFxxk;
+
+    /**
+     * 同步备注
+     */
+    private String remark;
+}

+ 53 - 0
mjava-xiding/src/main/java/com/malk/xiding/repository/entity/XdFxkDdAttendancePo.java

@@ -0,0 +1,53 @@
+package com.malk.xiding.repository.entity;
+
+import com.malk.base.BasePo;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import java.util.Date;
+
+@Entity
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Table(name = "xd_fxk_dd_attendance")
+public class XdFxkDdAttendancePo extends BasePo {
+
+    /**
+     * 钉钉ID
+     */
+    private String idDd;
+
+    /**
+     * 员工姓名
+     */
+    @Column(name = "name")
+    private String userName;
+
+    /**
+     * 纷享销客ID
+     */
+    @Column(name = "idFxxk")
+    private String openUserId;
+
+    /**
+     * 外勤时间
+     */
+    private Date checkTime;
+
+    /**
+     * 外勤地址
+     */
+    private String checkAddress;
+
+    /**
+     * 同步备注
+     */
+    private String remark;
+}

+ 70 - 0
mjava-xiding/src/main/java/com/malk/xiding/schedule/XDScheduleTask.java

@@ -0,0 +1,70 @@
+package com.malk.xiding.schedule;
+
+import com.malk.xiding.server.XDConf;
+import com.malk.xiding.service.XDService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+
+import java.util.Date;
+
+/**
+ * @EnableScheduling 开启桑诺定时任务 [配置参考McScheduleTask]
+ */
+@Slf4j
+@Configuration
+@EnableScheduling
+@ConditionalOnProperty(name = {"spel.scheduling"})
+public class XDScheduleTask {
+
+    @Autowired
+    private XDService xdService;
+
+    /**
+     * [定时同步审批单]
+     * 每天8点, 流程搜索按照发起和结束时间, 兼容性同步15内审批单
+     */
+    @Scheduled(cron = "0 0 8 1/1 * ?")
+    public void Time_Period_1() {
+        try {
+            log.info("###### [XD]同步审批单开始 ######");
+            long endTime = new Date().getTime();
+            long startTime = endTime - 15 * 24 * 60 * 60 * 1000L;
+            xdService.syncApprove(startTime, endTime, XDConf.TMP_CODE_CC, "出差");
+            xdService.syncApprove(startTime, endTime, XDConf.TMP_CODE_WC, "外出");
+        } catch (Exception e) {
+            log.error(e.getMessage(), e); // 记录错误日志
+        }
+        log.info("###### [XD]同步审批单结束 ######");
+    }
+
+    @Scheduled(cron = "0 5/10 9,10,15 1/1 * ?")
+    public void Time_Period_2() {
+        syncAttendance2DD();
+    }
+
+    @Scheduled(cron = "0 5/10 16-23 1/1 * ?")
+    public void Time_Period_3() {
+        syncAttendance2DD();
+    }
+
+    /**
+     * [频率为每10分钟查询一次]
+     * 09:00~11:00同步签到数据: 11点前纷享销客签到同步钉钉上班, 打卡为09:00
+     * 16:00 -23:59 同步签退数据: 下午4点前纷享销容签退, 同步钉钉打卡为18:00
+     */
+    private void syncAttendance2DD() {
+        log.info("###### [XD]同步考勤开始 ######");
+        Date eTime = new Date();
+        Date sTime = new Date(eTime.getTime() - 11 * 60 * 1000L);
+        try {
+            xdService.syncAttendance(0, sTime, eTime);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e); // 记录错误日志
+        }
+        log.info("###### [XD]同步考勤结束 ######");
+    }
+}

+ 10 - 0
mjava-xiding/src/main/java/com/malk/xiding/server/XDConf.java

@@ -0,0 +1,10 @@
+package com.malk.xiding.server;
+
+public class XDConf {
+
+    /// 出差申请单
+    public static final String TMP_CODE_CC = "PROC-3KYJ13FV-NJXKPWBMQ15WPFPZTQXN1-VS3HFS2J-E4";
+
+    // 外出申请单
+    public static final String TMP_CODE_WC = "PROC-3KYJ13FV-NJXKPWBMQ15WPFPZTQXN1-6T3HFS2J-F4";
+}

+ 0 - 0
mjava-xiding/src/main/java/com/malk/xiding/service/XDService.java


Неке датотеке нису приказане због велике количине промена