pruple_boy лет назад: 2
Родитель
Сommit
6192f8b160
33 измененных файлов с 899 добавлено и 138 удалено
  1. 71 18
      mjava-fengkaili/src/main/java/com/malk/fengkaili/controller/FKLController.java
  2. 16 0
      mjava-fengkaili/src/main/java/com/malk/fengkaili/repository/dao/FKLDdContactDao.java
  3. 54 0
      mjava-fengkaili/src/main/java/com/malk/fengkaili/repository/entity/FKLDdContactPo.java
  4. 19 0
      mjava-fengkaili/src/main/java/com/malk/fengkaili/service/FKLService.java
  5. 89 0
      mjava-fengkaili/src/main/java/com/malk/fengkaili/service/impl/FKLImplService.java
  6. 26 0
      mjava-gewu/pom.xml
  7. 20 0
      mjava-guyuan/pom.xml
  8. 2 0
      mjava-guyuan/src/main/java/Boot.java
  9. 53 2
      mjava-guyuan/src/main/java/com/malk/guyuan/controller/IVController.java
  10. 2 1
      mjava-guyuan/src/main/java/com/malk/guyuan/filter/CatchException_YXY.java
  11. 3 3
      mjava-guyuan/src/main/resources/application-dev.yml
  12. 3 3
      mjava-guyuan/target/classes/application-dev.yml
  13. 4 3
      mjava-hangshi/src/main/resources/application-prod.yml
  14. 4 3
      mjava-hangshi/target/classes/application-prod.yml
  15. 26 0
      mjava-pake/pom.xml
  16. 32 0
      mjava-shangfeng/pom.xml
  17. 26 47
      mjava-shangfeng/src/main/java/com/malk/shangfeng/controller/SFController.java
  18. 25 0
      mjava-shangfeng/src/main/java/com/malk/shangfeng/repository/dao/Fitemss97Dao.java
  19. 42 0
      mjava-shangfeng/src/main/java/com/malk/shangfeng/repository/entity/Fitemss97Po.java
  20. 14 26
      mjava-shangfeng/src/main/resources/application-dev.yml
  21. 14 13
      mjava-shangfeng/src/main/resources/application-prod.yml
  22. 56 0
      mjava-shangfeng/src/test/resource/winsw.xml
  23. 1 2
      mjava-zhuogao/src/main/java/com/malk/zhuogao/controller/ZGController.java
  24. 5 0
      mjava/src/main/java/com/malk/service/dingtalk/DDClient_Attendance.java
  25. 9 0
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Attendance.java
  26. 2 0
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Contacts.java
  27. 9 13
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplService.java
  28. 136 1
      mjava/src/main/java/com/malk/utils/UtilFile.java
  29. 1 0
      mjava/src/main/java/com/malk/utils/UtilList.java
  30. 15 1
      mjava/src/main/java/com/malk/utils/UtilNumber.java
  31. 0 1
      mjava/src/test/resources/driver.yml
  32. 120 0
      mjava/target/classes/META-INF/spring-configuration-metadata.json
  33. 0 1
      mjava/target/test-classes/driver.yml

+ 71 - 18
mjava-fengkaili/src/main/java/com/malk/fengkaili/controller/FKLController.java

@@ -4,20 +4,23 @@ package com.malk.fengkaili.controller;
  * 错误抛出与拦截详见 CatchException
  */
 
+import com.alibaba.fastjson.JSON;
+import com.malk.fengkaili.repository.entity.FKLDdContactPo;
+import com.malk.fengkaili.service.FKLService;
 import com.malk.server.common.McR;
 import com.malk.service.dingtalk.DDClient;
 import com.malk.service.dingtalk.DDClient_Attendance;
 import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.utils.UtilMap;
+import com.malk.utils.UtilNumber;
 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.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -34,31 +37,81 @@ public class FKLController {
     @Autowired
     private DDClient_Contacts ddClient_contacts;
 
+    @Autowired
+    private FKLService fklService;
+
+    @PostMapping("test1")
+    McR test1() {
+
+        fklService.syncUserInfo();
+
+        return McR.success(Arrays.asList(1, 3, 2, 4).stream().reduce(Integer::sum).orElse(0));
+//        return McR.success(ddClient_attendance.isOpenSmartReport(ddClient.getAccessToken()));
+    }
+
+    /// 累计月度汇总数字
+    private Object _reduceAttendance(Map column, String name, String keyList) {
+        Object value;
+        List<Map> vals = (List<Map>) column.get(keyList);
+        // 异常信息, 保留备注
+        if (name.equals("考勤结果")) {
+            value = String.join("\n", vals.stream().filter(item -> {
+                String content = UtilMap.getString(item, "value").replaceAll("正常", "").replaceAll("休息", "");
+                return StringUtils.isNotBlank(content);
+            }).map(item -> UtilMap.getString(item, "value")).collect(Collectors.toList()));
+        } else {
+            value = vals.stream().map(item -> UtilMap.getFloat(item, "value")).reduce((a, b) -> a + b).orElse(0f);
+        }
+        return value;
+    }
+
     @PostMapping("test")
     McR test() {
 
-        List<String> columnNames = Arrays.asList("下班1打卡结果", "上班1打卡结果", "旷工天数", "出勤天数", "工作时长", "考勤结果", "出差时长", "迟到次数", "早退次数", "下班缺卡次数", "上班缺卡次数", "外出时长", "休息日加班", "工作日加班", "节假日加班", "严重迟到次数", "应出勤天数");
-        List<String> leaveNames = new ArrayList<>();
+        // 考勤列, 假期信息定义
+        List<String> columnNames = Arrays.asList("旷工天数", "出勤天数", "工作时长", "考勤结果", "出差时长", "迟到次数", "早退次数", "下班缺卡次数", "上班缺卡次数", "外出时长", "休息日加班", "工作日加班", "节假日加班", "严重迟到次数", "应出勤天数");
         List<Map> columns = ddClient_attendance.getAttColumns(ddClient.getAccessToken());
-        List<String> columnIds = columns.stream().filter(column -> {
-
-                    if (column.get("alias").equals("leave_")) {
-                        leaveNames.add(String.valueOf(column.get("name")));
+        Map columnIds = new HashMap();
+        // 假期单独返回, 钉钉产品规则
+        List<String> leaveNames = columns.stream().filter(column -> {
+                    // 列类型储存id映射名称为map, 考勤数据返回仅保留列id
+                    if (columnNames.contains(column.get("name"))) {
+                        columnIds.put(column.get("id").toString(), column.get("name"));
                         return false;
                     }
-                    return columnNames.contains(column.get("name"));
+                    return column.get("alias").equals("leave_");
                 }
+        ).map(column -> String.valueOf(column.get("name"))).collect(Collectors.toList());
+
 
-        ).map(column -> String.valueOf(column.get("id"))).collect(Collectors.toList());
+        String start = "2023-07-01 00:00:00";
+        String end = "2023-07-22 23:59:59";
+        // 基于用户分页
+        List<FKLDdContactPo> userInfos = fklService.queryUserInfos(1, 200, null, null).getContent();
 
-//        ddClient_contacts.getDepartmentId_all(ddClient.getAccessToken(), true).forEach(deptId -> {
-//                
-//            
-//        });
+        List<Map> attendanceInfos = new ArrayList<>();
+        List<String> queryIds = new ArrayList<>(columnIds.keySet()); // 考勤列定义
+        userInfos.forEach(po -> {
+            Map attendanceInfo = UtilMap.map("员工ID, 员工姓名, 员工工号, 所属部门", po.getUserId(), po.getName(), po.getJobNumber(), po.getDeptName());
+            // 累计月度汇总
+            ddClient_attendance.getAttColumnVal(ddClient.getAccessToken(), po.getUserId(), queryIds, start, end).forEach(column -> {
+                String id = ((Map) column.get("column_vo")).get("id").toString();
+                String name = String.valueOf(columnIds.get(id)); // 接口仅返回列id, 通过map映射
+                attendanceInfo.put(name, _reduceAttendance(column, name, "column_vals"));
+            });
+            // 累计假期数据
+            for (Map column : ddClient_attendance.getLeaveTimeByNames(ddClient.getAccessToken(), po.getUserId(), leaveNames, start, end)) {
+                String name = ((Map) column.get("columnvo")).get("name").toString(); // 接口返回列名称
+                attendanceInfo.put(name, _reduceAttendance(column, name, "columnvals"));
+            }
+            // 数据处理
+            attendanceInfo.put("加班总时长", UtilNumber.formatPrecision(UtilMap.getFloat(attendanceInfo, "节假日加班") + UtilMap.getFloat(attendanceInfo, "节假日加班") + UtilMap.getFloat(attendanceInfo, "节假日加班")));
+            attendanceInfos.add(attendanceInfo);
+        });
+        log.info("xxx, {}", JSON.toJSONString(attendanceInfos));
 
+//        log.info("xxx, {}", JSON.toJSONString(userInfo));
 
-        ddClient_attendance.getAttColumnVal(ddClient.getAccessToken(), "01340563171287111,01386135062129166507", columnIds, "2023-07-01 00:00:00", "2023-07-22 23:59:59");
-        ddClient_attendance.getLeaveTimeByNames(ddClient.getAccessToken(), "01340563171287111", leaveNames, "2023-07-01 00:00:00", "2023-07-22 23:59:59");
 
 //        getLeaveTimeByNames
 //        ddClient_attendance.getAttColumns(ddClient.getAccessToken());

+ 16 - 0
mjava-fengkaili/src/main/java/com/malk/fengkaili/repository/dao/FKLDdContactDao.java

@@ -0,0 +1,16 @@
+package com.malk.fengkaili.repository.dao;
+
+import com.malk.fengkaili.repository.entity.FKLDdContactPo;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+import javax.transaction.Transactional;
+
+/**
+ * 钉钉花名册同步
+ */
+@Transactional
+public interface FKLDdContactDao extends JpaRepository<FKLDdContactPo, Long>, JpaSpecificationExecutor<FKLDdContactPo> {
+
+    boolean existsByUserId(String userId);
+}

+ 54 - 0
mjava-fengkaili/src/main/java/com/malk/fengkaili/repository/entity/FKLDdContactPo.java

@@ -0,0 +1,54 @@
+package com.malk.fengkaili.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 = "fkl_dd_contact")
+public class FKLDdContactPo extends BasePo {
+
+    /**
+     * 员工Id
+     */
+    private String userId;
+
+    /**
+     * 员工姓名
+     */
+    private String name;
+
+    /**
+     * 员工工号
+     */
+    private String jobNumber;
+
+    /**
+     * 手机号
+     */
+    private String mobile;
+
+    /**
+     * 部门Id
+     */
+    private long deptId;
+
+    /**
+     * 部门名称
+     */
+    private String deptName;
+
+    /**
+     * 同步备注
+     */
+    private String remark;
+}

+ 19 - 0
mjava-fengkaili/src/main/java/com/malk/fengkaili/service/FKLService.java

@@ -0,0 +1,19 @@
+package com.malk.fengkaili.service;
+
+import com.malk.fengkaili.repository.entity.FKLDdContactPo;
+import org.springframework.data.domain.Page;
+
+import java.util.List;
+
+public interface FKLService {
+
+    /**
+     * 同步用户信息
+     */
+    void syncUserInfo();
+
+    /**
+     * 查询用户列表
+     */
+    Page<FKLDdContactPo> queryUserInfos(int page, int size, String name, List<Long> deptIds);
+}

+ 89 - 0
mjava-fengkaili/src/main/java/com/malk/fengkaili/service/impl/FKLImplService.java

@@ -0,0 +1,89 @@
+package com.malk.fengkaili.service.impl;
+
+import com.malk.fengkaili.repository.dao.FKLDdContactDao;
+import com.malk.fengkaili.repository.entity.FKLDdContactPo;
+import com.malk.fengkaili.service.FKLService;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.utils.UtilList;
+import com.malk.utils.UtilMap;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+
+import javax.persistence.criteria.Predicate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@Slf4j
+public class FKLImplService implements FKLService {
+
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    @Autowired
+    private FKLDdContactDao fklDdContactDao;
+
+    /**
+     * 同步用户信息
+     */
+    @Override
+    public void syncUserInfo() {
+        // 匹配部门信息, 全量
+        ddClient_contacts.getDepartmentId_all(ddClient.getAccessToken(), true).forEach(deptId -> {
+            String deptName = ddClient_contacts.getDepartmentInfo(ddClient.getAccessToken(), deptId).get("name").toString();
+            for (String userId : ddClient_contacts.listDepartmentUserId(ddClient.getAccessToken(), deptId)) {
+                if (fklDdContactDao.existsByUserId(userId)) {
+                    continue;
+                }
+                Map userinfo = ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), userId);
+                // 员工信息表, 落库
+                fklDdContactDao.save(FKLDdContactPo.builder()
+                        .userId(userId)
+                        .name(UtilMap.getString(userinfo, "name"))
+                        .jobNumber(UtilMap.getString(userinfo, "job_number"))
+                        .deptId(deptId)
+                        .deptName(deptName)
+                        .mobile(UtilMap.getString(userinfo, "mobile"))
+                        .build());
+            }
+        });
+    }
+
+    /**
+     * 查询用户列表
+     */
+    @Override
+    public Page<FKLDdContactPo> queryUserInfos(int page, int size, String name, List<Long> deptIds) {
+
+        // 分页 & 排序
+        Sort sort = Sort.by(Sort.Direction.DESC, "deptId");
+        Pageable pageable = PageRequest.of(page - 1, size, sort);
+
+        // 查询条件: 姓名, 所属部门
+        Specification<FKLDdContactPo> specification = (root, criteriaQuery, criteriaBuilder) -> {
+            List<Predicate> predicateList = new ArrayList<>();
+            if (StringUtils.isNotBlank(name)) {
+                predicateList.add(criteriaBuilder.equal(root.get("name"), name));
+            }
+            if (UtilList.isNotEmpty(deptIds)) {
+                predicateList.add(criteriaBuilder.in(root.get("deptId")).value(deptIds));
+            }
+            return criteriaBuilder.and(predicateList.toArray(new javax.persistence.criteria.Predicate[predicateList.size()]));
+        };
+        // 无数据时返回空列表
+        return fklDdContactDao.findAll(specification, pageable);
+    }
+}

+ 26 - 0
mjava-gewu/pom.xml

@@ -25,4 +25,30 @@
             <version>${mjava.version}</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>

+ 20 - 0
mjava-guyuan/pom.xml

@@ -17,6 +17,13 @@
         <maven.compiler.target>8</maven.compiler.target>
     </properties>
 
+    <repositories>
+        <repository>
+            <id>com.e-iceblue</id>
+            <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
+        </repository>
+    </repositories>
+
     <dependencies>
         <!-- 核心模块-->
         <dependency>
@@ -29,11 +36,24 @@
             <groupId>com.tencentcloudapi</groupId>
             <artifactId>tencentcloud-sdk-java</artifactId>
         </dependency>
+        <!-- 图片压缩 -->
         <dependency>
             <groupId>net.coobird</groupId>
             <artifactId>thumbnailator</artifactId>
             <version>0.4.8</version>
         </dependency>
+        <!-- PDF压缩 -->
+        <dependency>
+            <groupId>com.twelvemonkeys.imageio</groupId>
+            <artifactId>imageio-tiff</artifactId>
+            <version>3.5</version>
+        </dependency>
+        <dependency>
+            <groupId>e-iceblue</groupId>
+            <artifactId>spire.pdf.free</artifactId>
+            <version>5.1.0</version>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 2 - 0
mjava-guyuan/src/main/java/Boot.java

@@ -1,3 +1,5 @@
+package com.malk.guyuan;
+
 import com.querydsl.jpa.impl.JPAQueryFactory;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;

+ 53 - 2
mjava-guyuan/src/main/java/com/malk/guyuan/controller/IVController.java

@@ -7,10 +7,16 @@ import com.malk.guyuan.server.tencent.TXYConf;
 import com.malk.guyuan.service.tencent.TXYInvoice;
 import com.malk.server.aliwork.YDConf;
 import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.FilePath;
 import com.malk.server.common.McException;
 import com.malk.server.common.McR;
 import com.malk.service.aliwork.YDClient;
 import com.malk.utils.*;
+import com.spire.pdf.PdfCompressionLevel;
+import com.spire.pdf.PdfDocument;
+import com.spire.pdf.PdfPageBase;
+import com.spire.pdf.exporting.PdfImageInfo;
+import com.spire.pdf.graphics.PdfBitmap;
 import com.tencentcloudapi.common.exception.TencentCloudSDKException;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
@@ -26,6 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
 import javax.servlet.http.HttpServletRequest;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.*;
@@ -78,6 +85,46 @@ public class IVController {
         return Base64.getEncoder().encodeToString(bytes);
     }
 
+    @Autowired
+    private FilePath filePath;
+
+    /// PDF压缩转base64
+    @SneakyThrows
+    private String pdfUrlConvertBase64(String pdfUrl) {
+
+        // 下载文件
+        File file = UtilFile.mkdirIfNot("tmp.pdf", filePath.getPath().getTmp());
+        UtilHttp.doDownload(pdfUrl, file);
+
+        // PDF压缩
+        PdfDocument doc = new PdfDocument(); // 创建PdfDocument类的对象
+        doc.loadFromFile(file.getAbsolutePath()); // 加载PDF文档
+        doc.getFileInfo().setIncrementalUpdate(false); // 禁用增量更新
+        doc.setCompressionLevel(PdfCompressionLevel.Best); // 将压缩级别设置为最佳
+        // 遍历文档页面
+        for (int i = 0; i < doc.getPages().getCount(); i++) {
+            PdfPageBase page = doc.getPages().get(i);  // 获取指定页面
+            PdfImageInfo[] images = page.getImagesInfo(); // 获取每个页面的图像信息集合
+            // 遍历集合中的所有项目
+            if (images != null && images.length > 0)
+                for (int j = 0; j < images.length; j++) {
+                    PdfImageInfo image = images[j];  // 获取指定图片
+                    PdfBitmap bp = new PdfBitmap(image.getImage());
+                    bp.setQuality(25); // 设置压缩质量
+                    page.replaceImage(j, bp); // 将原始图像替换为压缩图像
+                }
+            // 将结果文档保存至另一个PDF文档中: 覆盖
+            doc.saveToFile(file.getAbsolutePath());
+            doc.close();
+        }
+
+        // PDF转base64, 无需透出本地文件地址
+        String base64 = UtilFile.fileToBase64(file.getAbsolutePath());
+        // 删除临时PDF文件
+        UtilFile.deleteFile(file.getAbsolutePath());
+        return base64;
+    }
+
     // prd 校验发票抬头, 购买方范围
     private void validateBuyer(String BuyerName, String tips) {
         List<String> corpNames = Arrays.asList(
@@ -97,7 +144,8 @@ public class IVController {
                 "上海渝泽信息科技有限公司",
                 "厦门神谷飞流影视传媒有限公司",
                 "厦门谷钛数字科技有限公司",
-                "上海观情科技有限公司");
+                "上海观情科技有限公司",
+                "渔米可禧文化传媒(香港)有限公司");
         McException.assertAccessException(!corpNames.contains(BuyerName), tips + ", 购买方名称不合法!");
     }
 
@@ -111,9 +159,12 @@ public class IVController {
         String image = ydClient.convertTemporaryUrl(data.get("url"));
         log.info("混票识别, 免登地址, {}", image);
         // 非PDF, 且内存大于3M, 压缩后上传
-        if (!UtilMap.getBoolean(data, "isPdf") && UtilMap.getFloat(data, "size") > 3.0f) {
+        if (UtilMap.getFloat(data, "size") > 3.0f && !UtilMap.getBoolean(data, "isPdf")) {
             image = imageUrlConvertBase64(image);
         }
+        if (UtilMap.getFloat(data, "size") > 6.0f && UtilMap.getBoolean(data, "isPdf")) {
+            image = pdfUrlConvertBase64(image);
+        }
         // ppExt: 通用字段定义
         List<Map> invoices = (List<Map>) txyInvoice.doMixedInvoiceOCR(image).get("MixedInvoiceItems");
         List<McInvoiceDto> result = invoices.stream().map(item -> {

+ 2 - 1
mjava-guyuan/src/main/java/com/malk/guyuan/filter/CatchException_YXY.java

@@ -21,6 +21,7 @@ public class CatchException_YXY extends CatchException {
     @ExceptionHandler(TencentCloudSDKException.class)
     public McR TencentCloudSDKException(TencentCloudSDKException e) {
         log.error(e.getMessage(), e);  // 记录错误日志
-        return McR.errorVendor(e.getMessage(), "tencent");
+        // prd, 统一中文提示 return McR.errorVendor(e.getMessage(), "tencent");
+        return McR.errorVendor("发票识别异常!", "tencent");
     }
 }

+ 3 - 3
mjava-guyuan/src/main/resources/application-dev.yml

@@ -28,9 +28,9 @@ spring:
 # filepath
 file:
   path:
-    file: /Users/malk/server/_Tool/var/mjava/tmp/file
-    image: /Users/malk/server/_Tool/var/mjava/tmp/image
-    tmp: /Users/mcli/server/_Tool/var/mjava/tmp
+    file: /Users/malk/server/_Tool/var/mjava/file
+    image: /Users/malk/server/_Tool/var/mjava/image
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp
   source:
     fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
 logging:

+ 3 - 3
mjava-guyuan/target/classes/application-dev.yml

@@ -28,9 +28,9 @@ spring:
 # filepath
 file:
   path:
-    file: /Users/malk/server/_Tool/var/mjava/tmp/file
-    image: /Users/malk/server/_Tool/var/mjava/tmp/image
-    tmp: /Users/mcli/server/_Tool/var/mjava/tmp
+    file: /Users/malk/server/_Tool/var/mjava/file
+    image: /Users/malk/server/_Tool/var/mjava/image
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp
   source:
     fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
 logging:

+ 4 - 3
mjava-hangshi/src/main/resources/application-prod.yml

@@ -1,7 +1,8 @@
 # 环境配置
 server:
   port: 9009
-
+  servlet:
+    context-path: /api/hangshi
 # condition
 spel:
   scheduling: true        # 定时任务是否执行
@@ -14,8 +15,8 @@ spring:
       connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci           # SqlServer, Oracle 无需设置类型
     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
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
   jpa:
     database: MYSQL
     database-platform: org.hibernate.dialect.MySQL57Dialect

+ 4 - 3
mjava-hangshi/target/classes/application-prod.yml

@@ -1,7 +1,8 @@
 # 环境配置
 server:
   port: 9009
-
+  servlet:
+    context-path: /api/hangshi
 # condition
 spel:
   scheduling: true        # 定时任务是否执行
@@ -14,8 +15,8 @@ spring:
       connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci           # SqlServer, Oracle 无需设置类型
     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
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
   jpa:
     database: MYSQL
     database-platform: org.hibernate.dialect.MySQL57Dialect

+ 26 - 0
mjava-pake/pom.xml

@@ -25,4 +25,30 @@
             <version>${mjava.version}</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-shangfeng/pom.xml

@@ -24,5 +24,37 @@
             <artifactId>mjava</artifactId>
             <version>${mjava.version}</version>
         </dependency>
+        <!-- sqlserver 依赖 -->
+        <dependency>
+            <groupId>com.microsoft.sqlserver</groupId>
+            <artifactId>mssql-jdbc</artifactId>
+            <scope>runtime</scope>
+        </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>

+ 26 - 47
mjava-shangfeng/src/main/java/com/malk/shangfeng/controller/SFController.java

@@ -4,22 +4,23 @@ package com.malk.shangfeng.controller;
  * 错误抛出与拦截详见 CatchException
  */
 
+import com.alibaba.fastjson.JSON;
 import com.malk.server.common.McR;
+import com.malk.server.dingtalk.DDConf;
+import com.malk.server.dingtalk.DDFormComponentDto;
 import com.malk.service.dingtalk.DDClient;
-import com.malk.service.dingtalk.DDClient_Attendance;
-import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.service.dingtalk.DDClient_Workflow;
+import com.malk.shangfeng.repository.dao.Fitemss97Dao;
+import com.malk.shangfeng.repository.entity.Fitemss97Po;
 import com.malk.utils.UtilMap;
 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.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 @Slf4j
 @RestController
@@ -30,51 +31,29 @@ public class SFController {
     private DDClient ddClient;
 
     @Autowired
-    private DDClient_Attendance ddClient_attendance;
+    private DDConf ddConf;
 
     @Autowired
-    private DDClient_Contacts ddClient_contacts;
+    private DDClient_Workflow workflow;
 
-    @PostMapping("test")
-    McR test() {
-
-        List<String> columnNames = Arrays.asList("考勤结果", "下班1打卡结果", "下班1打卡时间", "旷工天数", "出勤天数", "休息天数", "工作时长", "考勤结果", "出差时长", "迟到次数", "早退次数", "下班缺卡次数", "上班缺卡次数", "外出时长", "休息日加班", "工作日加班", "节假日加班", "严重迟到次数", "应出勤天数");
-        List<Map> columns = ddClient_attendance.getAttColumns(ddClient.getAccessToken());
-        Map columnIds = new HashMap(); // 列id通过map提取, 月度汇总接口仅返回id, 存储映射关系
-        List<String> leaveNames = columns.stream().filter(column -> {
-                    if (columnNames.contains(column.get("name"))) {
-                        columnIds.put(column.get("id"), column.get("name"));
-                    }
-                    return column.get("alias").equals("leave_");
-                }
-        ).map(column -> String.valueOf(column.get("name"))).collect(Collectors.toList());
-
-//        ddClient_contacts.getDepartmentId_all(ddClient.getAccessToken(), true).forEach(deptId -> {
-//
-//            
-//        });
-
-
-        String start = "2023-07-01 00:00:00";
-        String end = "2023-07-22 23:59:59";
-        String userId = "196230404821883307";
-
-        Map userInfo = UtilMap.map("userId, userName", "196230404821883307", "吴迎梅");
-        ddClient_attendance.getAttColumnVal(ddClient.getAccessToken(), userId, (List<String>) columnIds.keySet(), start, end).forEach(attendance -> {
-
-            String columnId = ((Map) attendance.get("column_vo")).get("id").toString();
-            userInfo.put(columnIds.get(columnId), "");
-
-
-        });
-
-
-        List<Map> leaveList = ddClient_attendance.getLeaveTimeByNames(ddClient.getAccessToken(), userId, leaveNames, start, end);
+    @Autowired
+    private Fitemss97Dao dao;
 
+    @GetMapping("test")
+    McR test() {
 
-//        getLeaveTimeByNames
-//        ddClient_attendance.getAttColumns(ddClient.getAccessToken());
-//        getAttColumnVal
-        return McR.success(columns);
+        for (Fitemss97Po po : dao.queryProject()) {
+            Map data = (Map) JSON.parse(JSON.toJSONString(po));
+            // 组件数据格式化
+            Map ruleForm = UtilMap.map("citemcode, citemname", "项目编码, 项目名称");
+            // 推送钉钉审批单
+            List<Map> formValues = DDFormComponentDto.formatComponentValues(data, ruleForm, null);
+            Map extInfo = UtilMap.map("dept_id", DDConf.TOP_DEPARTMENT);
+            workflow.doProcessInstances(ddClient.getAccessToken(), ddConf.getOperator(), Fitemss97Po.PROCESS_CODE, formValues, extInfo);
+            dao.updateProject(po.getCitemcode());
+            log.info("同步项目信息, {}", po);
+        }
+
+        return McR.success();
     }
 }

+ 25 - 0
mjava-shangfeng/src/main/java/com/malk/shangfeng/repository/dao/Fitemss97Dao.java

@@ -0,0 +1,25 @@
+package com.malk.shangfeng.repository.dao;
+
+import com.malk.shangfeng.repository.entity.Fitemss97Po;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import javax.transaction.Transactional;
+import java.util.List;
+
+/**
+ * 钉钉花名册同步
+ */
+@Transactional
+public interface Fitemss97Dao extends JpaRepository<Fitemss97Po, Long> {
+
+    // 未同步项目信息
+    @Query(value = "select * from fitemss97 where syncdd is null", nativeQuery = true)
+    List<Fitemss97Po> queryProject();
+
+    // 同步后更新项目
+    @Query(value = "update fitemss97 set syncdd = 'sync' where citemcode = ?1", nativeQuery = true)
+    @Modifying
+    void updateProject(String citemcode);
+}

+ 42 - 0
mjava-shangfeng/src/main/java/com/malk/shangfeng/repository/entity/Fitemss97Po.java

@@ -0,0 +1,42 @@
+package com.malk.shangfeng.repository.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Table(name = "fitemss97")
+public class Fitemss97Po {
+
+    public static String PROCESS_CODE = "PROC-61D5E199-390D-4973-AD6C-E4237C89BC31";
+
+    /**
+     * ppExt: 不继承 BaseDto, 避免默认id与时间字段匹配异常
+     */
+    @Id
+    private int iId;
+
+    /**
+     * 项目编号
+     */
+    private String citemcode;
+
+    /**
+     * 项目名称
+     */
+    private String citemname;
+
+    /**
+     * 同步备注
+     */
+    private String syncdd;
+}

+ 14 - 26
mjava-shangfeng/src/main/resources/application-dev.yml

@@ -12,28 +12,16 @@ spel:
 spring:
   # database
   datasource:
-    hikari:
-      connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci           # SqlServer, Oracle 无需设置类型
-    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
-    # 主库
-    primary:
-      username: root
-      password: mu123
-      jdbc-url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
-    # 从库
-    slave:
-      username: root
-      password: mu123
-      jdbc-url: jdbc:mysql://127.0.0.1:3306/mjava_slave?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
+    url: jdbc:sqlserver://127.0.0.1:1433;SelectMethod=cursor;DatabaseName=UFDATA_003_2022
+    username: sa
+    password: Sa123456
+  # JPA
   jpa:
-    hibernate:
-      ddl-auto: none      # JPA对表没有任何操作
-    show-sql: true
-    database: MYSQL
-    database-platform: org.hibernate.dialect.MySQL57Dialect
+    database: sql_server
+    properties:
+      hibernate:
+        default_schema: dbo
 
 # filepath
 file:
@@ -49,12 +37,12 @@ logging:
 
 # dingtalk
 dingtalk:
-  agentId: 2664525556
-  appKey: dingmcbz0lceeusy2kk4
-  appSecret: nhNVAbjjtb1Y_Q3WM1SkV4Wk3qDxTjfKEVUZd2iMrF5DtlGVcVDi5aIK-8CundeZ
-  corpId: dingade22a8c4fd34b8535c2f4657eb6378f
+  agentId: 2666532993
+  appKey: dingu7ez7flr7qato6z1
+  appSecret: utUxpNRHWnvk_A9f25P7KLY9HCULPctLLfutXo24C2D8NWLXGepY86572C98RfLT
+  corpId: ding4c21a1403de71296a1320dcb25e91351
   aesKey:
   token:
-  operator: ""   # OA管理员账号 [0开头需要转一下字符串]
+  operator: "095358016621619612"   # OA管理员账号 [0开头需要转一下字符串]
 
 

+ 14 - 13
mjava-shangfeng/src/main/resources/application-prod.yml

@@ -12,22 +12,23 @@ spel:
 spring:
   # database
   datasource:
-    hikari:
-      connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci           # SqlServer, Oracle 无需设置类型
-    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
+    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
+    url: jdbc:sqlserver://127.0.0.1:1433;SelectMethod=cursor;DatabaseName=UFDATA_003_2022
+    username: sa
+    password: Sa123456
+  # JPA
   jpa:
-    database: MYSQL
-    database-platform: org.hibernate.dialect.MySQL57Dialect
+    database: sql_server
+    properties:
+      hibernate:
+        default_schema: dbo
 
 # dingtalk
 dingtalk:
-  agentId: 2664525556
-  appKey: dingmcbz0lceeusy2kk4
-  appSecret: nhNVAbjjtb1Y_Q3WM1SkV4Wk3qDxTjfKEVUZd2iMrF5DtlGVcVDi5aIK-8CundeZ
-  corpId: dingade22a8c4fd34b8535c2f4657eb6378f
+  agentId: 2666532993
+  appKey: dingu7ez7flr7qato6z1
+  appSecret: utUxpNRHWnvk_A9f25P7KLY9HCULPctLLfutXo24C2D8NWLXGepY86572C98RfLT
+  corpId: ding4c21a1403de71296a1320dcb25e91351
   aesKey:
   token:
-  operator: ""   # OA管理员账号 [0开头需要转一下字符串]
+  operator: "685960294423265853"   # OA管理员账号 [0开头需要转一下字符串]

+ 56 - 0
mjava-shangfeng/src/test/resource/winsw.xml

@@ -0,0 +1,56 @@
+<!--
+  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后面的是项目名 [-Dfile.encoding=UTF-8 Windows会乱码, 但Mac上VSCode正常] -->
+    <arguments>-Xms256m -Xmx256m -jar mjava-shangfeng.jar</arguments>
+    <!-- <arguments>-Xms256m -Xmx256m -Dfile.encoding=UTF-8 -jar mjava.jar</arguments> -->
+    <!-- 服务的启动模式:默认Automatic -->
+    <startmode>Automatic</startmode>
+    <!-- 日志地址 -->
+    <logpath>%BASE%\ws</logpath>
+    <!-- 日志模式 -->
+    <logmode>rotate</logmode>
+</service>
+

+ 1 - 2
mjava-zhuogao/src/main/java/com/malk/zhuogao/controller/ZGController.java

@@ -30,8 +30,7 @@ import java.util.stream.Collectors;
 @RestController
 @RequestMapping
 public class ZGController {
-
-
+    
     @Autowired
     private DDClient ddClient;
 

+ 5 - 0
mjava/src/main/java/com/malk/service/dingtalk/DDClient_Attendance.java

@@ -60,6 +60,11 @@ public interface DDClient_Attendance {
      */
     List<Map> getAttColumns(String access_token);
 
+    /**
+     * 查询是否启用智能统计报表
+     */
+    boolean isOpenSmartReport(String access_token);
+
     /**
      * 获取考勤报表列值
      *

+ 9 - 0
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Attendance.java

@@ -113,6 +113,15 @@ public class DDImplClient_Attendance implements DDClient_Attendance {
         return (List<Map>) ddr.getResult();
     }
 
+    /**
+     * 查询是否启用智能统计报表
+     */
+    @Override
+    public boolean isOpenSmartReport(String access_token) {
+        DDR ddr = DDR.doPost("https://oapi.dingtalk.com/topapi/attendance/isopensmartreport", null, DDConf.initTokenParams(access_token), null);
+        return UtilMap.getBoolean(((Map) ddr.getResult()), "smart_report");
+    }
+
     /**
      * 获取考勤报表列定义
      *

+ 2 - 0
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Contacts.java

@@ -92,6 +92,8 @@ public class DDImplClient_Contacts implements DDClient_Contacts {
 
     /**
      * 查询用户详情
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/query-user-details
      */
     @Override
     public Map getUserInfoById(String access_token, String userId) {

+ 9 - 13
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplService.java

@@ -88,24 +88,20 @@ public class DDImplService implements DDService {
 
     /// 递归: 判断员工是否在指定部门
     boolean _matchDepartment(String access_token, long dept_id, List<Long> deptIds) {
-        // 判断入参
+        boolean isMatch = false;
+        // 判断入参 [同样作为递归出口]
         if (dept_id == DDConf.TOP_DEPARTMENT) {
             return false;
         }
         if (deptIds.contains(dept_id)) {
-            return true;
-        }
-        Map deptInfo = ddClient_contacts.getDepartmentInfo(access_token, dept_id);
-        long parentId = UtilMap.getLong(deptInfo, "parent_id");
-        long deptId = UtilMap.getLong(deptInfo, "dept_id");
-        _matchDepartment(access_token, parentId, deptIds);
-        // 判断递归
-        if (deptId == DDConf.TOP_DEPARTMENT) {
-            return false;
+            isMatch = true;
         }
-        if (deptIds.contains(parentId)) {
-            return true;
+        // 递归出口 [查询上级部门匹配]
+        if (!isMatch) {
+            Map deptInfo = ddClient_contacts.getDepartmentInfo(access_token, dept_id);
+            long parentId = UtilMap.getLong(deptInfo, "parent_id");
+            return _matchDepartment(access_token, parentId, deptIds);
         }
-        return false;
+        return isMatch;
     }
 }

+ 136 - 1
mjava/src/main/java/com/malk/utils/UtilFile.java

@@ -3,6 +3,7 @@ package com.malk.utils;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import lombok.SneakyThrows;
+import org.apache.commons.codec.binary.Base64;
 import org.springframework.core.io.ClassPathResource;
 
 import javax.annotation.Nullable;
@@ -31,7 +32,7 @@ public abstract class UtilFile {
     /**
      * 文件转化为byte字节数组
      */
-    public static byte[] fileConvertToByteArray(File file) {
+    public static byte[] fileToByteArray(File file) {
         byte[] data = null;
         try {
             FileInputStream fis = new FileInputStream(file);
@@ -50,6 +51,71 @@ public abstract class UtilFile {
         return data;
     }
 
+    /**
+     * 文件全路径转Base64
+     */
+    public static String fileToBase64(String path) {
+        String base64 = null;
+        InputStream in = null;
+        try {
+            File file = new File(path);
+            in = new FileInputStream(file);
+            byte[] bytes = new byte[(int) file.length()];
+            in.read(bytes);
+            base64 = new String(Base64.encodeBase64(bytes), "UTF-8");
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return base64;
+    }
+
+    /**
+     * Base64转文件储存
+     */
+    public static void base64ToFile(String outFilePath, String base64, String outFileName) {
+        File file = null;
+        //创建文件目录
+        String filePath = outFilePath;
+        File dir = new File(filePath);
+        if (!dir.exists() && !dir.isDirectory()) {
+            dir.mkdirs();
+        }
+        BufferedOutputStream bos = null;
+        java.io.FileOutputStream fos = null;
+        try {
+            byte[] bytes = Base64.decodeBase64(base64);
+            file = new File(filePath + "/" + outFileName);
+            fos = new java.io.FileOutputStream(file);
+            bos = new BufferedOutputStream(fos);
+            bos.write(bytes);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (bos != null) {
+                try {
+                    bos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
     /**
      * 本地路径转json string
      */
@@ -97,4 +163,73 @@ public abstract class UtilFile {
         String json = readJsonStringFromFile(readPackageResourcePath(path));
         return JSON.parse(json);
     }
+
+    /**
+     * 根据路径删除指定的目录或文件,无论存在与否
+     */
+    public static boolean DeleteFolder(String sPath) {
+        boolean flag = false;
+        File file = new File(sPath);
+        // 判断目录或文件是否存在
+        if (!file.exists()) {  // 不存在返回 false
+            return flag;
+        } else {
+            // 判断是否为文件
+            if (file.isFile()) {  // 为文件时调用删除文件方法
+                return deleteFile(sPath);
+            } else {  // 为目录时调用删除目录方法
+                return deleteDirectory(sPath);
+            }
+        }
+    }
+
+    /**
+     * 删除单个文件
+     */
+    public static boolean deleteFile(String sPath) {
+        boolean flag = false;
+        File file = new File(sPath);
+        // 路径为文件且不为空则进行删除
+        if (file.isFile() && file.exists()) {
+            file.delete();
+            flag = true;
+        }
+        return flag;
+    }
+
+    /**
+     * 删除目录(文件夹)以及目录下的文件
+     */
+    public static boolean deleteDirectory(String sPath) {
+        // 如果sPath不以文件分隔符结尾,自动添加文件分隔符
+        if (!sPath.endsWith(File.separator)) {
+            sPath = sPath + File.separator;
+        }
+        File dirFile = new File(sPath);
+        // 如果dir对应的文件不存在,或者不是一个目录,则退出
+        if (!dirFile.exists() || !dirFile.isDirectory()) {
+            return false;
+        }
+        boolean flag = true;
+        // 删除文件夹下的所有文件(包括子目录)
+        File[] files = dirFile.listFiles();
+        for (int i = 0; i < files.length; i++) {
+            // 删除子文件
+            if (files[i].isFile()) {
+                flag = deleteFile(files[i].getAbsolutePath());
+                if (!flag) break;
+            } // 删除子目录
+            else {
+                flag = deleteDirectory(files[i].getAbsolutePath());
+                if (!flag) break;
+            }
+        }
+        if (!flag) return false;
+        // 删除当前目录
+        if (dirFile.delete()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
 }

+ 1 - 0
mjava/src/main/java/com/malk/utils/UtilList.java

@@ -35,6 +35,7 @@ public abstract class UtilList {
         return list[list.length - 1];
     }
 
+    // Arrays.asList 不可变, asList 为可变 [Set -> new ArrayList<>(Map.keySet())]
     public static List asList(Object... a) {
         List tList = new ArrayList<>();
         tList.addAll(Arrays.asList(a));

+ 15 - 1
mjava/src/main/java/com/malk/utils/UtilNumber.java

@@ -6,6 +6,7 @@ import java.math.BigDecimal;
 import java.text.DecimalFormat;
 import java.text.NumberFormat;
 import java.util.Locale;
+import java.util.regex.Pattern;
 
 /**
  * 数字格式化
@@ -25,10 +26,18 @@ public class UtilNumber {
         return cur.replace("¥", "").replace("¥", "");
     }
 
+    /**
+     * 判断是否数字
+     */
+    public static boolean matchNumber(String num) {
+        Pattern pattern = Pattern.compile("^-?\\d+(\\.\\d+)?$");
+        return pattern.matcher(num).matches();
+    }
+
     // 去除CHY货币标识
     public static final BigDecimal replaceCurrencyCHYToDecimal(String cur) {
         String num = replaceCurrencyCHY(cur);
-        if (StringUtils.isBlank(num)) {
+        if (StringUtils.isBlank(num) || !matchNumber(num)) {
             num = "0";
         }
         return new BigDecimal(num);
@@ -47,6 +56,11 @@ public class UtilNumber {
         return df.format(new BigDecimal(number));
     }
 
+    // 小数位精度格式
+    public static final String formatPrecision(float number) {
+        return formatPrecision(Double.valueOf(String.valueOf(number)));
+    }
+
     // 非数值型字符串, 空字符串兼容
     public static final BigDecimal setBigDecimal(String strNum) {
         BigDecimal decimal = null;

+ 0 - 1
mjava/src/test/resources/driver.yml

@@ -15,7 +15,6 @@ spring:
     username: root
     password: mu123
     url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
-
   # JPA
   jpa:
     database: MYSQL

+ 120 - 0
mjava/target/classes/META-INF/spring-configuration-metadata.json

@@ -35,6 +35,26 @@
       "type": "com.malk.server.common.FilePath$Path",
       "sourceType": "com.malk.server.common.FilePath$Path"
     },
+    {
+      "name": "file.path",
+      "type": "com.malk.server.common.FilePath$Path",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path",
+      "type": "com.malk.server.common.FilePath$Path",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path",
+      "type": "com.malk.server.common.FilePath$Path",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path",
+      "type": "com.malk.server.common.FilePath$Path",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
     {
       "name": "file.source",
       "type": "com.malk.server.common.FilePath$Source",
@@ -45,6 +65,26 @@
       "type": "com.malk.server.common.FilePath$Source",
       "sourceType": "com.malk.server.common.FilePath$Source"
     },
+    {
+      "name": "file.source",
+      "type": "com.malk.server.common.FilePath$Source",
+      "sourceType": "com.malk.server.common.FilePath$Source"
+    },
+    {
+      "name": "file.source",
+      "type": "com.malk.server.common.FilePath$Source",
+      "sourceType": "com.malk.server.common.FilePath$Source"
+    },
+    {
+      "name": "file.source",
+      "type": "com.malk.server.common.FilePath$Source",
+      "sourceType": "com.malk.server.common.FilePath$Source"
+    },
+    {
+      "name": "file.source",
+      "type": "com.malk.server.common.FilePath$Source",
+      "sourceType": "com.malk.server.common.FilePath$Source"
+    },
     {
       "name": "fxiaoke",
       "type": "com.malk.server.fxiaoke.FXKConf",
@@ -169,16 +209,96 @@
       "type": "java.lang.String",
       "sourceType": "com.malk.server.common.FilePath$Path"
     },
+    {
+      "name": "file.path.file",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path.file",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path.file",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path.file",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
     {
       "name": "file.path.image",
       "type": "java.lang.String",
       "sourceType": "com.malk.server.common.FilePath$Path"
     },
+    {
+      "name": "file.path.image",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path.image",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path.image",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path.image",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path.tmp",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path.tmp",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
     {
       "name": "file.path.tmp",
       "type": "java.lang.String",
       "sourceType": "com.malk.server.common.FilePath$Path"
     },
+    {
+      "name": "file.path.tmp",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path.tmp",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.source.fonts",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Source"
+    },
+    {
+      "name": "file.source.fonts",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Source"
+    },
+    {
+      "name": "file.source.fonts",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Source"
+    },
+    {
+      "name": "file.source.fonts",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Source"
+    },
     {
       "name": "file.source.fonts",
       "type": "java.lang.String",

+ 0 - 1
mjava/target/test-classes/driver.yml

@@ -15,7 +15,6 @@ spring:
     username: root
     password: mu123
     url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
-
   # JPA
   jpa:
     database: MYSQL