10 Commits c67109b508 ... 219109f74e

Author SHA1 Message Date
  刘嘉伟 219109f74e 增加全宗号筛选条件 3 years ago
  刘嘉伟 67a7612ed1 增加全宗号筛选条件 3 years ago
  刘嘉伟 1db8635a85 增加全宗号筛选条件 3 years ago
  刘嘉伟 30519d2c02 Merge remote-tracking branch 'origin/master' into 20210916 3 years ago
  刘嘉伟 958fb1479b 1 3 years ago
  刘嘉伟 3106602552 1 3 years ago
  刘嘉伟 c8cf4be090 :new: “激扬系统”爬取脚本 3 years ago
  刘嘉伟 cf8fbd8520 上传 4 years ago
  刘嘉伟 85a0872adf Merge remote-tracking branch 'origin/master' 4 years ago
  zhanghai a7e449b3d0 档案管理 4 years ago
30 changed files with 923 additions and 178 deletions
  1. 1 0
      README.md
  2. 65 61
      pom.xml
  3. 244 0
      py/档案数据.py
  4. 22 5
      src/main/java/com/gz/config/FileUploadConfig.java
  5. 0 1
      src/main/java/com/gz/config/MountArchiveFileConfig.java
  6. 0 1
      src/main/java/com/gz/controller/system/FileController.java
  7. 9 0
      src/main/java/com/gz/dto/archive/ArchiveDTO.java
  8. 0 2
      src/main/java/com/gz/scheduled/ScanArchiveFileScheduled.java
  9. 48 10
      src/main/java/com/gz/service/archive/impl/ArchiveFileServiceImpl.java
  10. 6 1
      src/main/java/com/gz/service/archive/impl/ArchiveServiceImpl.java
  11. 5 6
      src/main/java/com/gz/service/statistics/impl/SelectStatisticsServiceImpl.java
  12. 1 0
      src/main/java/com/gz/service/system/FileService.java
  13. 10 0
      src/main/java/com/gz/service/system/RoleService.java
  14. 7 0
      src/main/java/com/gz/service/system/impl/FileServiceImpl.java
  15. 18 7
      src/main/java/com/gz/service/system/impl/RoleServiceImpl.java
  16. 84 0
      src/main/java/com/gz/utils/WatermarkUtils.java
  17. 3 0
      src/main/java/com/gz/vo/archive/SearchArchiveVO.java
  18. 1 0
      src/main/resources/application-dev.yml
  19. 2 1
      src/main/resources/application-prod.yml
  20. 1 1
      src/main/resources/application.yml
  21. 6 0
      src/main/resources/mapper/archiveMapper.xml
  22. 8 0
      src/main/resources/static/js/lay-module/utils/base64.min.js
  23. 37 18
      src/main/resources/static/page/archive/edit.html
  24. 13 0
      src/main/resources/static/page/archive/list.html
  25. 6 3
      src/main/resources/static/page/archive/show.html
  26. 2 2
      src/main/resources/static/page/role/edit.html
  27. 196 0
      src/test/java/com/gz/ConverOldSystemData.java
  28. 23 0
      src/test/java/com/gz/DeleteRedisKey.java
  29. 56 0
      src/test/java/com/gz/HandleSource.java
  30. 49 59
      src/test/java/com/gz/WatermarkPdf.java

+ 1 - 0
README.md

@@ -109,6 +109,7 @@ ______
 
 > + 附件:南京NO.2018G46地块(奥特佳项目)规划设计方案
 > + 关于对建邺区江东中路377号南京金融城一期项目地下室进行确认的复函
+> + 卷内目录档号Excel处理公式:`=CONCAT(A2,"-",IF(COUNTIF(G2,"*-*"),TEXT(LEFT(G2,FIND("-",G2)-1),"0000"),TEXT(G2,"0000")))`
 
 > Excel卷内目录档号公式   `=A2&"-"&TEXT(IF(ISNUMBER(FIND("-",G2,1)),LEFT(G2,FIND("-",G2,1) - 1),G2),"0000")`
 

+ 65 - 61
pom.xml

@@ -149,18 +149,22 @@
             <artifactId>bboss-elasticsearch-spring-boot-starter</artifactId>
             <version>${bboss.elasticsearch.version}</version>
         </dependency>
-        <!--        <dependency>-->
-        <!--            <groupId>org.springframework.boot</groupId>-->
-        <!--            <artifactId>spring-boot-devtools</artifactId>-->
-        <!--            <optional>true</optional>-->
-        <!--        </dependency>-->
         <dependency>
-            <groupId>e-iceblue</groupId>
-            <artifactId>spire.pdf.free</artifactId>
-            <version>3.9.0</version>
+            <groupId>com.itextpdf</groupId>
+            <artifactId>itextpdf</artifactId>
+            <version>5.5.13</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>pdfbox</artifactId>
+            <version>2.0.12</version>
+        </dependency>
+        <dependency>
+            <groupId>com.lowagie</groupId>
+            <artifactId>itext</artifactId>
+            <version>4.2.1</version>
         </dependency>
     </dependencies>
-
     <build>
         <plugins>
             <plugin>
@@ -171,60 +175,60 @@
                 </configuration>
             </plugin>
 
-            <plugin>
-                <groupId>cn.smallbun.screw</groupId>
-                <artifactId>screw-maven-plugin</artifactId>
-                <version>1.0.3</version>
-                <dependencies>
-                    <!-- HikariCP -->
-                    <dependency>
-                        <groupId>com.zaxxer</groupId>
-                        <artifactId>HikariCP</artifactId>
-                        <version>3.4.5</version>
-                    </dependency>
-                    <!--mysql driver-->
-                    <dependency>
-                        <groupId>mysql</groupId>
-                        <artifactId>mysql-connector-java</artifactId>
-                        <version>8.0.20</version>
-                    </dependency>
-                </dependencies>
-                <configuration>
-                    <!--username-->
-                    <username>root</username>
-                    <!--password-->
-                    <password>abcd123456!@#</password>
-                    <!--driver-->
-                    <driverClassName>com.mysql.cj.jdbc.Driver</driverClassName>
-                    <!--jdbc url-->
-                    <jdbcUrl>
-                        <![CDATA[jdbc:mysql://115.159.38.225:3306/cmsga?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8]]></jdbcUrl>
-                    <!--生成文件类型-->
-                    <fileType>WORD</fileType>
-                    <!--打开文件输出目录-->
-                    <openOutputDir>false</openOutputDir>
-                    <!--生成模板-->
-                    <produceType>freemarker</produceType>
-                    <!--文档名称 为空时:将采用[数据库名称-描述-版本号]作为文档名称-->
-                    <!--                    <fileName>111</fileName>-->
-                    <!--描述-->
-                    <description>数据库文档生成</description>
-                    <!--版本-->
-                    <version>${project.version}</version>
-                    <!--标题-->
-                    <title>数据库文档</title>
-                </configuration>
-                <executions>
-                    <execution>
-                        <phase>compile</phase>
-                        <!--                        <goals>-->
-                        <!--                            <goal>run</goal>-->
-                        <!--                        </goals>-->
-                    </execution>
-                </executions>
-            </plugin>
+<!--            <plugin>-->
+<!--                <groupId>cn.smallbun.screw</groupId>-->
+<!--                <artifactId>screw-maven-plugin</artifactId>-->
+<!--                <version>1.0.3</version>-->
+<!--                <dependencies>-->
+<!--                    &lt;!&ndash; HikariCP &ndash;&gt;-->
+<!--                    <dependency>-->
+<!--                        <groupId>com.zaxxer</groupId>-->
+<!--                        <artifactId>HikariCP</artifactId>-->
+<!--                        <version>3.4.5</version>-->
+<!--                    </dependency>-->
+<!--                    &lt;!&ndash;mysql driver&ndash;&gt;-->
+<!--                    <dependency>-->
+<!--                        <groupId>mysql</groupId>-->
+<!--                        <artifactId>mysql-connector-java</artifactId>-->
+<!--                        <version>8.0.20</version>-->
+<!--                    </dependency>-->
+<!--                </dependencies>-->
+<!--                <configuration>-->
+<!--                    &lt;!&ndash;username&ndash;&gt;-->
+<!--                    <username>root</username>-->
+<!--                    &lt;!&ndash;password&ndash;&gt;-->
+<!--                    <password>abcd123456!@#</password>-->
+<!--                    &lt;!&ndash;driver&ndash;&gt;-->
+<!--                    <driverClassName>com.mysql.cj.jdbc.Driver</driverClassName>-->
+<!--                    &lt;!&ndash;jdbc url&ndash;&gt;-->
+<!--                    <jdbcUrl><![CDATA[jdbc:mysql://115.159.38.225:3306/guihua_archives?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8]]></jdbcUrl>-->
+<!--                    &lt;!&ndash;生成文件类型&ndash;&gt;-->
+<!--                    <fileType>WORD</fileType>-->
+<!--                    &lt;!&ndash;打开文件输出目录&ndash;&gt;-->
+<!--                    <openOutputDir>false</openOutputDir>-->
+<!--                    &lt;!&ndash;生成模板&ndash;&gt;-->
+<!--                    <produceType>freemarker</produceType>-->
+<!--                    &lt;!&ndash;文档名称 为空时:将采用[数据库名称-描述-版本号]作为文档名称&ndash;&gt;-->
+<!--&lt;!&ndash;                    <fileName>111</fileName>&ndash;&gt;-->
+<!--                    &lt;!&ndash;描述&ndash;&gt;-->
+<!--                    <description>数据库文档生成</description>-->
+<!--                    &lt;!&ndash;版本&ndash;&gt;-->
+<!--                    <version>${project.version}</version>-->
+<!--                    &lt;!&ndash;标题&ndash;&gt;-->
+<!--                    <title>数据库文档</title>-->
+<!--                </configuration>-->
+<!--                <executions>-->
+<!--                    <execution>-->
+<!--                        <phase>compile</phase>-->
+<!--                        <goals>-->
+<!--                            <goal>run</goal>-->
+<!--                        </goals>-->
+<!--                    </execution>-->
+<!--                </executions>-->
+<!--            </plugin>-->
         </plugins>
     </build>
 
 
+
 </project>

+ 244 - 0
py/档案数据.py

@@ -0,0 +1,244 @@
+import json
+import os
+from concurrent.futures import ThreadPoolExecutor
+from urllib.parse import urlencode
+from urllib.request import Request
+from urllib.request import urlopen
+import re
+import time
+
+# 请求地址
+base_url = 'http://192.168.1.153:3000'
+
+# 数据存储目录
+base_folder = 'H:\jy'
+
+# 线程池最大线程
+thread_count = 3
+
+# 用户id (目前没发现有啥用,不用改)
+user_id = 28
+
+headers = {
+    # 'User-Agent': UserAgent().chrome
+    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36',
+    # cookie模拟登录 过期了需要到网页登录抓取cookie替换这里
+    'Cookie': '_iChad_session=BAh7CCIPc2Vzc2lvbl9pZCIlOWExYTE5MGZlZDE1YTRmZGMxMjY4MDRmZTQxN2JmNjciGXdhcmRlbi51c2VyLnVzZXIua2V5WwgiCVVzZXJbBmkhIiIkMmEkMTAkUXRJMkkyNTQ0SGJoRkVCOHo2d0REdSIQX2NzcmZfdG9rZW4iMWRXQkRhL2NjbEdmL3k4ZWZrYXgzVE1rWksrdkxhL0FzclhPQWxSVkRXRmc9--8bf8e98234e136cc2512da7e36b33bc1580fa5da'
+}
+
+rstr = r"[\/\\\:\*\?\"\<\>\|]"  # '/ \ : * ? " < > |'
+
+
+# 写入到文件
+def save_to_file(file_name, contents):
+    fh = open(file_name, 'wb+')
+    contents = contents.encode('utf-8')
+    fh.write(contents)
+    fh.close()
+    print('写入数据到【' + file_name + '】完成')
+
+
+# 创建目录
+def mkdir(file_name):
+    folder = os.path.exists(file_name)
+    if not folder:
+        os.makedirs(file_name)
+        print('创建目录' + file_name)
+    else:
+        print(file_name + '目录已经存在,跳过创建')
+
+
+# 下载到本地
+def download(url, file_path):
+    print('开始下载' + url)
+    f = urlopen(url)
+    data = f.read()
+    with open(file_path, "wb") as code:
+        code.write(data)
+
+
+# 发送get请求
+def get(url):
+    # 创建请求
+    request = Request(url, headers=headers)
+    # 发起请求
+    response = urlopen(request)
+    # 读取响应内容
+    response_str = response.read()
+    # 转换unicode
+    # response_str = response_str.decode().encode("utf-8").decode("unicode_escape")
+    response_str = response_str.decode()
+    # 修正返回结果为json格式
+    response_str = response_str.replace('results', '"results"')
+    response_str = response_str.replace('rows', '"rows"')
+    return response_str
+
+
+# 发送post请求
+def post(url, body):
+    # 设置post为formdata提交方式
+    headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'
+    body = urlencode(body)
+    data = body.encode('utf-8')
+    request = Request(url, headers=headers, data=data, method='POST')
+    response = urlopen(request)
+    response_str = response.read()
+    return response_str
+
+
+# 获取所有的档案类型
+def getArchiveTypes():
+    api_path = '/desktop/get_dalb_print_grid'
+    params = {
+        '_dc': 1637722889393,
+        'userid': user_id,
+        'page': 1,
+        'start': 0,
+        'limit': 99999
+    }
+    finally_url = base_url + api_path + f'?' + urlencode(params)
+    result = get(finally_url)
+    response_obj = json.loads(result)
+    for index, type in enumerate(response_obj['rows']):
+        if index < 3:
+            print('跳过' + type['lbmc'])
+            continue;
+        print('开始爬取【' + type['lbmc'] + '】数据')
+        type_folder = base_folder + '\\' + str(type['id']) + '_' + type['lbmc']
+        mkdir(type_folder)
+        getArchives(type['id'], type_folder)
+    # with ThreadPoolExecutor(max_workers=thread_count) as t:
+    #     for type in response_obj['rows']:
+    #         print('开始爬取【' + type['lbmc'] + '】数据')
+    #         type_folder = base_folder + '\\' + str(type['id']) + '_' + type['lbmc']
+    #         mkdir(type_folder)
+    #         t.submit(getArchives, type['id'], type_folder)
+
+
+# 根据档案类型获取所有的档案数据
+def getArchives(type, folder):
+    api_path = '/desktop/archive_query_jygl'
+    for pageIndex in range(5):
+        params = {
+            "dalb": type,
+            "userid": user_id,
+            "page": pageIndex + 1,
+            "start": pageIndex * 1000,
+            "limit": 1000,
+        }
+        finally_url = base_url + api_path + f'?' + urlencode(params)
+        result = get(finally_url)
+        response_obj = json.loads(result)
+        print('读取该类型下数据完成,共有' + str(response_obj['results']) + '条数据')
+        for index, row in enumerate(response_obj['rows']):
+            # 当前这条数据的文件夹
+            tm = row['tm']
+            tm = re.sub(rstr, "_", tm)
+            data_folder = folder + '\\' + str(index + (pageIndex * 1000)) + '_' + tm
+            mkdir(data_folder)
+            getArchiveDetails(row, data_folder)
+        # with ThreadPoolExecutor(max_workers=thread_count) as t:
+        #     for row in response_obj['rows']:
+        #         # 当前这条数据的文件夹
+        #         data_folder = folder + '\\' + row['tm']
+        #         mkdir(data_folder)
+        #         # getArchiveDetails(row, data_folder)
+        #         t.submit(getArchiveDetails, row, data_folder)
+
+
+# 根据id获取详细信息
+def getArchiveDetails(row, data_folder):
+    print('开始读取【' + row['tm'] + '】详细信息')
+    local_json_path = data_folder + '\\' + 'data.json'
+    if not os.path.exists(local_json_path):
+        api_path = '/desktop/get_archivebyid'
+        body = {
+            'id': row['id'],
+            'dh': row['dh'],
+            'userid': user_id,
+        }
+        finally_url = base_url + api_path
+        result = post(finally_url, body)
+        # 保存数据到文件
+        save_to_file(local_json_path, result.decode())
+    else:
+        print(f'{row["tm"]} json数据已经存在,跳过保存')
+    # 获取卷内目录数据
+    getArchiveInner(row['id'], data_folder)
+    print('开始下载【' + row['tm'] + '】的文件')
+    getArchiveFile(row['dh'], data_folder)
+
+
+# 获取档案文件集合
+def getArchiveFile(dh, data_folder):
+    api_path = '/desktop/get_yx_tree?_dc=1637737132431'
+    body = {
+        'node': 'root',
+        'dh': dh
+    }
+    finally_url = base_url + api_path
+    result = post(finally_url, body)
+    result = result.decode()
+    result = result.replace('\'', '\"')
+    response_obj = json.loads(result)
+    for file in response_obj:
+        for index, file_item in enumerate(file['children']):
+            id = file_item['id']
+            file_id = id[:str(id).index('|')]
+            file_name = file_item['text']
+            cs = 0
+            while cs < 3:
+                try:
+                    getArchiveFileDownloadUrl(file_id, data_folder, str(index) + file_name)
+                    cs = 3  # 跳出循环
+                except BaseException:
+                    print(f'{file_name}出现错误休息3秒 再试')
+                    cs += 1  # 记录出错次数
+                    time.sleep(3)
+    # with ThreadPoolExecutor(max_workers=thread_count) as t:
+    #     for file in response_obj:
+    #         for file_item in file['children']:
+    #             id = file_item['id']
+    #             file_id = id[:str(id).index('|')]
+    #             file_name = file_item['text']
+    #             t.submit(getArchiveFileDownloadUrl, file_id, data_folder, file_name)
+
+
+# 获取文件下载地址
+def getArchiveFileDownloadUrl(file_id, data_folder, file_name):
+    api_path = '/desktop/get_timage_from_db'
+    local_path = data_folder + '\\' + file_name + '.jpg'
+    if os.path.exists(local_path):
+        print(file_name + '文件已经下载过了,跳过')
+        return
+    body = {
+        'gid': file_id,
+        'userid': user_id
+    }
+    finally_url = base_url + api_path
+    response_str = post(finally_url, body)
+    img_path = response_str.decode().replace('assets/./', 'assets/')
+    download(base_url + img_path, local_path)
+
+
+# 获取卷内目录数据
+def getArchiveInner(archive_id, data_folder):
+    print('开始读取' + str(archive_id) + '的卷内目录数据')
+    inner_json_path = data_folder + '\\' + 'inner.json'
+    if not os.path.exists(inner_json_path):
+        api_path = '/desktop/get_document'
+        params = {
+            "query": archive_id,
+            "page": 1,
+            "start": 0,
+            "limit": 99999,
+        }
+        finally_url = base_url + api_path + f'?' + urlencode(params)
+        response_str = get(finally_url)
+        save_to_file(data_folder + '\\' + 'inner.json', response_str)
+    else:
+        print(f'{archive_id} 卷内目录json数据已经存在 跳过保存')
+
+
+if __name__ == '__main__':
+    getArchiveTypes()

+ 22 - 5
src/main/java/com/gz/config/FileUploadConfig.java

@@ -12,27 +12,44 @@ import org.springframework.context.annotation.Configuration;
 @Configuration
 public class FileUploadConfig {
 
-    /** 文档附件根目录地址*/
+    /**
+     * 文档附件根目录地址
+     */
     public static String ARCHIVE_FILE_ROOT_DIRECTORY;
 
-    /** 附件根目录地址*/
+    /**
+     * 附件根目录地址
+     */
     public static String FILE_ROOT_DIRECTORY;
 
-    /** 附件上传目录 归档年份/全宗号-保管期限(归档年度)-文件格式   文件格式只有 PDF和TF*/
+    /**
+     * 生成的水印文件根目录地址
+     */
+    public static String WATERMARK_ARCHIVE_FILE_ROOT_DIRECTORY;
+
+    /**
+     * 附件上传目录 归档年份/全宗号-保管期限(归档年度)-文件格式   文件格式只有 PDF和TF
+     */
     public static final String ARCHIVE_UPLOAD_PATH_PDF_FOMAT = "/%s/%s-%s(%s)-%s";
 
     public static final String ARCHIVE_UPLOAD_PATH_TIF_FOMAT = "/%s/%s-%s(%s)-%s/%s";
 
     @Value("${upload-file.archive-file-root-directory}")
     public void setArchiveFileRootDirectory(String uploadFileRootDirectory) {
-        log.info("文档附件根目录地址:{}",uploadFileRootDirectory);
+        log.info("文档附件根目录地址:{}", uploadFileRootDirectory);
         ARCHIVE_FILE_ROOT_DIRECTORY = uploadFileRootDirectory;
     }
 
 
     @Value("${upload-file.file-root-directory}")
     public void setFileRootDirectory(String uploadFileRootDirectory) {
-        log.info("其他附件根目录地址:{}",uploadFileRootDirectory);
+        log.info("其他附件根目录地址:{}", uploadFileRootDirectory);
         FILE_ROOT_DIRECTORY = uploadFileRootDirectory;
     }
+
+    @Value("${upload-file.watermark-archive-file-root-directory}")
+    public void setWatermarkArchiveFileRootDirectory(String watermarkArchiveFileRootDirectory) {
+        log.info("其他附件根目录地址:{}", watermarkArchiveFileRootDirectory);
+        WATERMARK_ARCHIVE_FILE_ROOT_DIRECTORY = watermarkArchiveFileRootDirectory;
+    }
 }

+ 0 - 1
src/main/java/com/gz/config/MountArchiveFileConfig.java

@@ -5,7 +5,6 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Configuration;
 
-import javax.annotation.PostConstruct;
 import java.io.File;
 import java.util.HashMap;
 import java.util.concurrent.ExecutorService;

+ 0 - 1
src/main/java/com/gz/controller/system/FileController.java

@@ -2,7 +2,6 @@ package com.gz.controller.system;
 
 import com.gz.core.exception.BusinessException;
 import com.gz.dto.system.FileDTO;
-import com.gz.rvo.system.FileUploadRVO;
 import com.gz.service.system.FileService;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;

+ 9 - 0
src/main/java/com/gz/dto/archive/ArchiveDTO.java

@@ -116,4 +116,13 @@ public class ArchiveDTO extends BaseDTO {
 
     // 现地籍号
     private String xdjh;
+
+    // 来源
+    private String ly;
+
+    // 标签
+    private String bq;
+
+    // 行政区划
+    private String xzqh;
 }

+ 0 - 2
src/main/java/com/gz/scheduled/ScanArchiveFileScheduled.java

@@ -4,10 +4,8 @@ import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.util.StrUtil;
 import com.gz.config.MountArchiveFileConfig;
 import com.gz.core.exception.BusinessException;
-import com.gz.mapper.archive.ArchiveFileMapper;
 import lombok.extern.slf4j.Slf4j;
 import org.frameworkset.spi.annotations.Component;
-import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Profile;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.scheduling.annotation.Scheduled;

+ 48 - 10
src/main/java/com/gz/service/archive/impl/ArchiveFileServiceImpl.java

@@ -1,6 +1,7 @@
 package com.gz.service.archive.impl;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.util.IdUtil;
 import com.alibaba.fastjson.JSON;
 import com.github.pagehelper.PageHelper;
@@ -15,26 +16,30 @@ import com.gz.dto.system.MenuRoleDTO;
 import com.gz.mapper.archive.ArchiveFileMapper;
 import com.gz.mapper.archive.ArchiveMapper;
 import com.gz.mapper.system.MenuRoleMapper;
+import com.gz.mapper.system.RoleMapper;
 import com.gz.rvo.archive.ArchiveFileRVO;
 import com.gz.rvo.archive.ArchiveRVO;
 import com.gz.service.archive.ArchiveFileService;
+import com.gz.service.system.RoleService;
 import com.gz.utils.JwtUtils;
+import com.gz.utils.WatermarkUtils;
 import com.gz.vo.archive.SearchArchiveFileVO;
 import com.gz.vo.rabbitmq.OcrEtlVO;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.amqp.rabbit.core.RabbitTemplate;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
-import sun.text.resources.cldr.yav.FormatData_yav;
 
 import javax.annotation.Resource;
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Executable;
 import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 /**
  * @author LiuchangLan
@@ -55,6 +60,9 @@ public class ArchiveFileServiceImpl implements ArchiveFileService {
     @Resource
     private MenuRoleMapper menuRoleMapper;
 
+    @Resource
+    private RoleService roleService;
+
 
     @Value("${rabbitmq.data-exchange}")
     private String dataExchangeName;
@@ -66,9 +74,11 @@ public class ArchiveFileServiceImpl implements ArchiveFileService {
     private String serverFileUrlPrefix;
 
 
+    ExecutorService archiveWatermarkHandleThreadPool = Executors.newCachedThreadPool();
+
     @Override
     @Transactional
-    public ArchiveFileDTO upload(MultipartFile file, Integer archiveId, Integer fileType,Integer secondaryArchiveId) throws BusinessException, IOException {
+    public ArchiveFileDTO upload(MultipartFile file, Integer archiveId, Integer fileType, Integer secondaryArchiveId) throws BusinessException, IOException {
         if (file.isEmpty()) {
             throw new BusinessException(CustomExceptionEnum.File_NOT_EXISTS);
         }
@@ -87,18 +97,18 @@ public class ArchiveFileServiceImpl implements ArchiveFileService {
             switch (fileFormat) {
                 case "PDF":
 //                serverFileUploadPath = String.format(FileUploadConfig.ARCHIVE_UPLOAD_PATH_PDF_FOMAT, archiveDTO.getGdnd(), archiveDTO.getQzh(), archiveDTO.getBgqx(), archiveDTO.getGdnd(), fileFormat);
-                    serverFileUploadPath = "/" + archiveDTO.getQzh() + "/" + archiveDTO.getGdnd() + "/" + archiveDTO.getMl() + "/" + archiveDTO.getBgqx() + "/" + archiveDTO.getDh() + "/pdf";
+                    serverFileUploadPath = "/" + archiveDTO.getQzh() + "/" + archiveDTO.getGdnd() + "/" + archiveDTO.getMl() + "/" + archiveDTO.getBgqx() + "/" + archiveDTO.getDh() + "/pdf/";
                     // pdf文件名为档号
-                    if (secondaryArchiveId != null){
-                        fn = String.format("%s_%s.%s", archiveDTO.getDh(),secondaryArchiveId, fileFormat.toLowerCase());
-                    }else {
+                    if (secondaryArchiveId != null) {
+                        fn = String.format("%s_%s.%s", archiveDTO.getDh(), secondaryArchiveId, fileFormat.toLowerCase());
+                    } else {
                         fn = String.format("%s.%s", archiveDTO.getDh(), fileFormat.toLowerCase());
                     }
                     break;
                 case "TIF":
                     // tif文件名为页码 无法通过后台生成 读取上传文件的名称
                     fn = fileName;
-                    serverFileUploadPath = "/" + archiveDTO.getQzh() + "/" + archiveDTO.getGdnd() + "/" + archiveDTO.getMl() + "/" + archiveDTO.getBgqx() + "/" + archiveDTO.getDh() + "/tif";
+                    serverFileUploadPath = "/" + archiveDTO.getQzh() + "/" + archiveDTO.getGdnd() + "/" + archiveDTO.getMl() + "/" + archiveDTO.getBgqx() + "/" + archiveDTO.getDh() + "/tif/";
                     break;
                 default:
                     // 其他文件直接抛错
@@ -106,7 +116,7 @@ public class ArchiveFileServiceImpl implements ArchiveFileService {
             }
         } else {
             // 附件
-            serverFileUploadPath = "/" + archiveDTO.getQzh() + "/" + archiveDTO.getGdnd() + "/" + archiveDTO.getMl() + "/" + archiveDTO.getBgqx() + "/" + archiveDTO.getDh() + "/other";
+            serverFileUploadPath = "/" + archiveDTO.getQzh() + "/" + archiveDTO.getGdnd() + "/" + archiveDTO.getMl() + "/" + archiveDTO.getBgqx() + "/" + archiveDTO.getDh() + "/other/";
             fn = String.format("%s.%s", IdUtil.simpleUUID(), fileFormat.toLowerCase());
         }
 
@@ -174,6 +184,34 @@ public class ArchiveFileServiceImpl implements ArchiveFileService {
         if (menuRoleMapper.select(param).stream().filter(i -> i.getMenuId() == 2).count() <= 0) {
             throw new BusinessException(CustomExceptionEnum.NO_ROLE);
         }
-        return archiveFileMapper.selectFileAndJnml(vo);
+        List<ArchiveFileRVO> archiveFileRVOS = archiveFileMapper.selectFileAndJnml(vo);
+        // 是否需要水印
+        if (roleService.selectArchiveRole(JwtUtils.getCurrentUserJwtPayload().getRoleId(), 3)) {
+            archiveFileRVOS.forEach(this::converHasWatermarkPdf);
+        }
+
+        return archiveFileRVOS;
+    }
+
+    public void converHasWatermarkPdf(ArchiveFileDTO sourceFile) {
+        // 需要生成水印的pdf文件
+        String sourcePdfFile = FileUploadConfig.ARCHIVE_FILE_ROOT_DIRECTORY + sourceFile.getFilePath() + sourceFile.getFileName();
+        // 水印生成位置文件
+        String watermarkFilePathStr = FileUploadConfig.WATERMARK_ARCHIVE_FILE_ROOT_DIRECTORY + "/"
+                + JwtUtils.getCurrentUserJwtPayload().getId()
+                + sourceFile.getFilePath();
+        File watermarkFilePath = FileUtil.file(watermarkFilePathStr);
+        if (!watermarkFilePath.exists()) {
+            // 目录不存在,创建目录
+            watermarkFilePath.mkdirs();
+        }
+        // 水印文件夹不存在生成水印后的文件
+        if (!FileUtil.file(watermarkFilePath + sourceFile.getFileName()).exists()) {
+            String adminName = JwtUtils.getCurrentUserJwtPayload().getAdminName();
+            // 使用线程池后台进行生成 不影响正常响应速度
+//            archiveWatermarkHandleThreadPool.execute(() -> WatermarkUtils.generateWatermarkPdf(sourcePdfFile, watermarkFilePathStr + sourceFile.getFileName(), adminName));
+            WatermarkUtils.generateWatermarkPdf(sourcePdfFile, watermarkFilePathStr + sourceFile.getFileName(), adminName);
+        }
+        sourceFile.setFilePath(JwtUtils.getCurrentUserJwtPayload().getId() + sourceFile.getFilePath());
     }
 }

+ 6 - 1
src/main/java/com/gz/service/archive/impl/ArchiveServiceImpl.java

@@ -19,11 +19,13 @@ import com.gz.dto.system.ArchivesTreeDTO;
 import com.gz.dto.system.MenuRoleDTO;
 import com.gz.mapper.archive.ArchiveMapper;
 import com.gz.mapper.archive.SecondaryArchiveMapper;
+import com.gz.mapper.system.DeptMapper;
 import com.gz.mapper.system.MenuRoleMapper;
 import com.gz.rvo.archive.ArchiveRVO;
 import com.gz.rvo.borrow.ArchiveBorrowListRVO;
 import com.gz.service.archive.ArchiveService;
 import com.gz.service.system.ArchivesTreeService;
+import com.gz.service.system.DeptService;
 import com.gz.utils.ExcelUtils;
 import com.gz.utils.JwtUtils;
 import com.gz.utils.ObjectUtils;
@@ -85,10 +87,13 @@ public class ArchiveServiceImpl implements ArchiveService {
     @Resource
     private MenuRoleMapper menuRoleMapper;
 
+    @Resource
+    private DeptMapper deptMapper;
 
     @Override
     public Integer insert(InsertArchiveVO vo) throws Exception {
         vo.setCreated(JwtUtils.getCurrentUserJwtPayload().getId());
+        vo.setLy(JwtUtils.getCurrentUserJwtPayload().getDeptId());
         return mapper.insertSelective(vo);
     }
 
@@ -267,7 +272,7 @@ public class ArchiveServiceImpl implements ArchiveService {
             case "KU":
                 return String.format(DataGlobalVariable.KU_DH_FOMAT, vo.getQzh(), vo.getMlh(), vo.getGdnd(), vo.getHsdwdh(), vo.getBgqx(), jh);
             case "KJ":
-                return String.format(DataGlobalVariable.KJ_DH_FOMAT, vo.getQzh(), vo.getMlh(), vo.getMl(), vo.getBgqx(), vo.getXmdh(), jh);
+                return String.format(DataGlobalVariable.KJ_DH_FOMAT, vo.getQzh(), vo.getMlh(), vo.getSl(), vo.getBgqx(), vo.getXmdh(), jh);
             case "ZY":
                 return String.format(DataGlobalVariable.ZY_DH_FOMAT, vo.getQzh(), vo.getMlh(), vo.getMl(), vo.getBgqx(), jh);
             case "YX":

+ 5 - 6
src/main/java/com/gz/service/statistics/impl/SelectStatisticsServiceImpl.java

@@ -4,10 +4,9 @@ import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUnit;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.RuntimeUtil;
-import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.lang.tree.TreeNodeConfig;
+import cn.hutool.core.lang.tree.TreeUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ReUtil;
 import cn.hutool.core.util.RuntimeUtil;
@@ -20,6 +19,7 @@ import com.gz.dto.borrow.ArchiveBorrowDTO;
 import com.gz.dto.system.ArchivesTreeDTO;
 import com.gz.mapper.borrow.ArchiveBorrowMapper;
 import com.gz.mapper.statistics.SelectStatisticsMapper;
+import com.gz.mapper.system.ArchivesTreeMapper;
 import com.gz.rvo.statistics.ArchiveStatisticsRVO;
 import com.gz.rvo.statistics.ArchiveYearStatisticsRVO;
 import com.gz.rvo.statistics.BorrowStatisticsRVO;
@@ -35,15 +35,14 @@ import lombok.extern.slf4j.Slf4j;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.SearchStrategy;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 
 import javax.annotation.Resource;
+import javax.persistence.Id;
 import java.io.File;
-import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;

+ 1 - 0
src/main/java/com/gz/service/system/FileService.java

@@ -4,6 +4,7 @@ import com.gz.dto.system.FileDTO;
 import com.gz.rvo.system.FileUploadRVO;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.io.File;
 import java.io.IOException;
 
 public interface FileService {

+ 10 - 0
src/main/java/com/gz/service/system/RoleService.java

@@ -75,4 +75,14 @@ public interface RoleService {
      */
     List<JSONObject> selectShowArchive(Integer roleId);
 
+    /**
+     * 查看权限是否需要生成水印
+     *
+     * @param roleId    权限id
+     * @param roleLabel 权限标识 1:详情 2:文件 3:水印 4:下载
+     * @author LiuChangLan
+     * @since 2022/2/24 17:32
+     */
+    Boolean selectArchiveRole(Integer roleId, Integer roleLabel);
+
 }

+ 7 - 0
src/main/java/com/gz/service/system/impl/FileServiceImpl.java

@@ -1,15 +1,20 @@
 package com.gz.service.system.impl;
 
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.util.IdUtil;
 import com.gz.config.FileUploadConfig;
 import com.gz.core.exception.BusinessException;
 import com.gz.core.exception.CustomExceptionEnum;
+import com.gz.dto.system.ArchiveFileDTO;
 import com.gz.dto.system.FileDTO;
 import com.gz.mapper.system.FileMapper;
 import com.gz.rvo.system.FileUploadRVO;
 import com.gz.service.system.FileService;
+import com.gz.utils.JwtUtils;
+import com.gz.utils.WatermarkUtils;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.tomcat.util.http.fileupload.FileUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -71,4 +76,6 @@ public class FileServiceImpl implements FileService {
         log.info("文件上传完成,原文件名[{}],服务器地址[{}],现在文件名[{}]", fileName, serverFilePath, serverFileName);
         return fileDTO;
     }
+
+
 }

+ 18 - 7
src/main/java/com/gz/service/system/impl/RoleServiceImpl.java

@@ -136,13 +136,13 @@ public class RoleServiceImpl implements RoleService {
                 i = menuRoleMapper.insert(menuRoleDTO);
             }
         }
-            /** 查看所有部门权限控制  0:不能查看全部功能,1:可查看*/
-            if (vo.getBmqxRole() != null) {
-                MenuRoleDTO menuRoleDTO = new MenuRoleDTO();
-                menuRoleDTO.setRoleId(vo.getRoleId());
-                menuRoleDTO.setMenuId(vo.getBmqxRole());
-                menuRoleDTO.setRoleType(DataGlobalVariable.ARCHIVE_DEPT);
-                i = menuRoleMapper.insert(menuRoleDTO);
+        /** 查看所有部门权限控制  0:不能查看全部功能,1:可查看*/
+        if (vo.getBmqxRole() != null) {
+            MenuRoleDTO menuRoleDTO = new MenuRoleDTO();
+            menuRoleDTO.setRoleId(vo.getRoleId());
+            menuRoleDTO.setMenuId(vo.getBmqxRole());
+            menuRoleDTO.setRoleType(DataGlobalVariable.ARCHIVE_DEPT);
+            i = menuRoleMapper.insert(menuRoleDTO);
         }
         return i;
     }
@@ -200,6 +200,8 @@ public class RoleServiceImpl implements RoleService {
         List<JSONObject> result = new ArrayList<>();
         result.add(new JSONObject().put("title", "详情").put("id", 1));
         result.add(new JSONObject().put("title", "文件").put("id", 2));
+        result.add(new JSONObject().put("title", "水印").put("id", 3));
+        result.add(new JSONObject().put("title", "下载").put("id", 4));
         MenuRoleDTO menuRoleDTO = new MenuRoleDTO();
         menuRoleDTO.setRoleType(DataGlobalVariable.ARCHIVE_SHOW);
         menuRoleDTO.setRoleId(roleId);
@@ -216,4 +218,13 @@ public class RoleServiceImpl implements RoleService {
 
         return result;
     }
+
+    @Override
+    public Boolean selectArchiveRole(Integer roleId,Integer roleLabel) {
+        MenuRoleDTO menuRoleDTO = new MenuRoleDTO();
+        menuRoleDTO.setRoleId(roleId);
+        menuRoleDTO.setRoleType(DataGlobalVariable.ARCHIVE_SHOW);
+        menuRoleDTO.setMenuId(roleLabel);
+        return menuRoleMapper.selectCount(menuRoleDTO) > 0;
+    }
 }

+ 84 - 0
src/main/java/com/gz/utils/WatermarkUtils.java

@@ -0,0 +1,84 @@
+package com.gz.utils;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.system.SystemUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDPageContentStream;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDType0Font;
+import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
+import org.apache.pdfbox.util.Matrix;
+import org.apache.tomcat.util.http.fileupload.FileUtils;
+import org.apache.tomcat.util.http.fileupload.IOUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+@Slf4j
+public class WatermarkUtils {
+
+    /**
+     * 给pdf增加水印
+     *
+     * @author LiuChangLan
+     * @since 2022/2/24 15:42
+     */
+    public static void generateWatermarkPdf(String pdfFilePath, String newPdfPath, String watermarkContent) {
+        log.info("水印生成 原文件:{} 生成后文件:{} 水印内容:{}", pdfFilePath, newPdfPath, watermarkContent);
+        File pdfFile = FileUtil.file(pdfFilePath);
+        PDDocument pdf = null;
+        try {
+            //打开pdf文件
+            pdf = PDDocument.load(pdfFile);
+            pdf.setAllSecurityToBeRemoved(true);
+            for (PDPage page : pdf.getPages()) {
+                PDPageContentStream cs = new PDPageContentStream(pdf, page, PDPageContentStream.AppendMode.APPEND, true, true);
+                String ts = watermarkContent;
+                //引入字体文件 解决中文汉字乱码问题
+                PDFont font = null;
+                if (SystemUtil.getOsInfo().isWindows()) {
+                    font = PDType0Font.load(pdf, new FileInputStream("C:\\Windows\\Fonts\\STLITI.TTF"), true);
+                } else {
+                    font = PDType0Font.load(pdf, new FileInputStream("/data/project/STLITI.TTF"), true);
+                }
+                float fontSize = 26;
+                PDResources resources = page.getResources();
+                PDExtendedGraphicsState r0 = new PDExtendedGraphicsState();
+                // 水印透明度
+                r0.setNonStrokingAlphaConstant(0.2f);
+                r0.setAlphaSourceFlag(true);
+                cs.setGraphicsStateParameters(r0);
+                //水印颜色
+                cs.setNonStrokingColor(153, 153, 153);
+                cs.beginText();
+                cs.setFont(font, fontSize);
+                //根据水印文字大小长度计算横向坐标需要渲染几次水印
+                float h = ts.length() * fontSize;
+                for (int i = 0; i <= 5; i++) {
+                    // 获取旋转实例
+                    cs.setTextMatrix(Matrix.getRotateInstance(-150, i * 220, 0));
+                    cs.showText(ts);
+                    for (int j = 0; j < 10; j++) {
+                        cs.setTextMatrix(Matrix.getRotateInstance(-150, i * 220, j * h * 2));
+                        cs.showText(ts);
+                    }
+                }
+                cs.endText();
+                cs.restoreGraphicsState();
+                cs.close();
+                pdf.save(newPdfPath);
+
+            }
+        } catch (IOException e) {
+            log.error("pdf生成水印失败", e);
+            throw new RuntimeException("pdf生成水印失败");
+        } finally {
+            IoUtil.close(pdf);
+        }
+    }
+}

+ 3 - 0
src/main/java/com/gz/vo/archive/SearchArchiveVO.java

@@ -59,6 +59,9 @@ public class SearchArchiveVO extends PageVO {
     // 部门id
     private String deptId;
 
+    // 全宗号
+    private String qzh;
+
     public boolean getAgain(){
         return this.again;
     }

+ 1 - 0
src/main/resources/application-dev.yml

@@ -121,6 +121,7 @@ upload-file:
   server-file-url-prefix: http://examdasfda.cn.utools.club
   file-root-directory: E:\cache
   archive-file-root-directory: E:\cache\archive
+  watermark-archive-file-root-directory: /data/file/watermark_archive_file
 #logging:
 #  file:
 #    path: D:\logs\guihua_archive

+ 2 - 1
src/main/resources/application-prod.yml

@@ -2,7 +2,7 @@ server:
   port: 9091
 spring:
   resources:
-    static-locations: classpath:/static,classpath:/public,classpath:/resources,classpath:/META-INF/resources,file:${upload-file.file-root-directory},file:${upload-file.archive-file-root-directory}
+    static-locations: classpath:/static,classpath:/public,classpath:/resources,classpath:/META-INF/resources,file:${upload-file.file-root-directory},file:${upload-file.archive-file-root-directory},file:${upload-file.watermark-archive-file-root-directory}
   # 数据源配置
   datasource:
     # 连接池类型
@@ -126,6 +126,7 @@ upload-file:
   server-file-url-prefix: http://66.1.21.158:9091
   file-root-directory: /data/file
   archive-file-root-directory: /data/file/archive_file
+  watermark-archive-file-root-directory: /data/file/watermark_archive_file
 logging:
   file:
     path: /data/logs

+ 1 - 1
src/main/resources/application.yml

@@ -22,7 +22,7 @@ auth:
     # 进行登录验证的地址
     force-urls: /**
     # 跳过验证地址
-    skip-urls: /druid/**,/,/**/*.pdf,/**/*.png,/**/*.jpg,/**/*.html,/**/*.ico,/**/*.css,/**/*.gif,/**/*.js,/webSocket/**,/**/*.woff2,/**/*.less,/system/auth/login,/system/auth/refreshToken,/system/auth/generatePictureCaptcha,/template/*.xlsx,/rabbit/test,/system/auth/loginByBase64,/system/admin/synchronize
+    skip-urls: /druid/**,/,/reader/**,/**/*.pdf,/**/*.png,/**/*.jpg,/**/*.html,/**/*.ico,/**/*.css,/**/*.gif,/**/*.js,/webSocket/**,/**/*.woff2,/**/*.less,/system/auth/login,/system/auth/refreshToken,/system/auth/generatePictureCaptcha,/template/*.xlsx,/rabbit/test,/system/auth/loginByBase64,/system/admin/synchronize
 rabbitmq:
   # 数据交换机
   data-exchange: ARCHIVE_DATA_EXCHANGE

+ 6 - 0
src/main/resources/mapper/archiveMapper.xml

@@ -69,6 +69,9 @@
             <if test="ztc != null and ztc != ''">
                 AND (a.ztc like concat(concat('%',#{ztc}),'%') OR a.tm like concat(concat('%',#{ztc}),'%') OR sa.tm like concat(concat('%',#{ztc}),'%'))
             </if>
+            <if test="qzh != null and qzh != ''">
+                AND a.qzh = #{qzh}
+            </if>
             <if test="sql != null and sql != ''">
                 ${sql}
             </if>
@@ -111,6 +114,9 @@
             <if test="ztc != null and ztc != ''">
                 AND (a.ztc like concat(concat('%',#{ztc}),'%') OR a.tm like concat(concat('%',#{ztc}),'%'))
             </if>
+            <if test="qzh != null and qzh != ''">
+                AND a.qzh = #{qzh}
+            </if>
             <if test="sql != null and sql != ''">
                 ${sql}
             </if>

File diff suppressed because it is too large
+ 8 - 0
src/main/resources/static/js/lay-module/utils/base64.min.js


+ 37 - 18
src/main/resources/static/page/archive/edit.html

@@ -289,10 +289,6 @@
         let fileType = urlParam.fileType
         let curr = 1;
 
-
-        let isAddhsdw = false;
-        let isAddxmdh = false;
-
         let sl = '';
         let ml = '';
 
@@ -347,6 +343,19 @@
 
         }
 
+
+        let loadBgqx = ml => {
+            http.get('system/dict/selectDictByCode', {code: ml === 'WS' ? 'BAOGUANQIXIANYI' : 'BAOGUANQIXIANER'}, false, function (res) {
+                let html = '';
+                for (let i in res.data) {
+                    html += '<option value="' + res.data[i].dictCode + '">' + res.data[i].dictName + '</option>'
+                }
+                $("#bgqx").empty()
+                $("#bgqx").append(html)
+                form.render();//菜单渲染 把内容加载进去
+            })
+        }
+
         let initUpload = function () {
             let fileList = $('#file-list')
             let uploadListIns = upload.render({
@@ -487,7 +496,8 @@
                     sl = d.current.code
 
                     getJh()
-                    let jhLable = '';
+                    loadBgqx(code)
+                    let jhLable = ''
                     switch (code) {
                         case 'SJ':
                         case 'MT':
@@ -516,17 +526,16 @@
 
                     switch (code) {
                         case 'KU':
-                            if (!isAddhsdw) {
+                            if (!$("#hsdwdh_label")[0]) {
                                 html += ' <label class="layui-form-label required" id="hsdwdh_label">核算单位代号:</label>\n' +
                                     '        <div class="layui-input-inline" style="width: 540px;" id="hsdwdh_input">\n' +
                                     '            <input type="text" class="layui-input" name="hsdwdh" id="hsdwdh" placeholder="请输入核算单位代号" lay-filter="hsdwdh"\n' +
                                     '                   lay-verify="required" lay-reqtext="核算单位代号不能为空">\n' +
                                     '        </div>'
-                                isAddhsdw = !isAddhsdw
                             }
                             break;
                         case 'KJ':
-                            if (!isAddxmdh) {
+                            if (!$("#xmdh_label")[0]) {
                                 html += '<label class="layui-form-label required" id="xmdh_label" >项目代号:</label>\n' +
                                     '        <div class="layui-input-inline" style="width: 540px;" id="xmdh_input" >\n' +
                                     '            <input type="text" class="layui-input" name="xmdh" id="xmdh" placeholder="请输入项目代号" lay-filter="xmldh"\n' +
@@ -534,6 +543,15 @@
                                     '        </div>'
                             }
                             break;
+                        default :
+                            if ($("#xmdh_label")[0]) {
+                                $("#xmdh_label").remove()
+                                $("#xmdh_input").remove()
+                            }
+                            if ($("#hsdwdh_label")[0]) {
+                                $("#hsdwdh_label").remove()
+                                $("#hsdwdh_input").remove()
+                            }
                     }
                     $('#hide_div').append(html)
 
@@ -637,16 +655,17 @@
             }
             if (!bgqxappend) {
                 let ml = $("#ml").val()
-
-                // 加载保管期限
-                http.get('system/dict/selectDictByCode', {code: ml === 'WS' ? 'BAOGUANQIXIANYI' : 'BAOGUANQIXIANER'}, false, function (res) {
-                    let html = '';
-                    for (let i in res.data) {
-                        html += '<option value="' + res.data[i].dictCode + '">' + res.data[i].dictName + '</option>'
-                    }
-                    $("#bgqx").append(html)
-                    form.render();//菜单渲染 把内容加载进去
-                })
+                loadBgqx(ml)
+
+                // // 加载保管期限
+                // http.get('system/dict/selectDictByCode', {code: ml === 'WS' ? 'BAOGUANQIXIANYI' : 'BAOGUANQIXIANER'}, false, function (res) {
+                //     let html = '';
+                //     for (let i in res.data) {
+                //         html += '<option value="' + res.data[i].dictCode + '">' + res.data[i].dictName + '</option>'
+                //     }
+                //     $("#bgqx").append(html)
+                //     form.render();//菜单渲染 把内容加载进去
+                // })
                 bgqxappend = !bgqxappend
             }
             form.val("addDict", adata);

+ 13 - 0
src/main/resources/static/page/archive/list.html

@@ -47,6 +47,16 @@
                             <option value="">保管期限</option>
                         </select>
                     </div>
+
+                    <div class="layui-inline" style="width: 100px;">
+                        <select name="qzh" id="qzh">
+                            <option value="">全宗号</option>
+                            <option value="5179">5179</option>
+                            <option value="5098">5098</option>
+                            <option value="5134">5134</option>
+                        </select>
+                    </div>
+
                     <div class="layui-inline">
                         <input type="checkbox" name="allDocument" lay-skin="primary" title="全文检索">
                         <div class="layui-unselect layui-form-checkbox layui-form-checked" lay-skin="primary">
@@ -658,6 +668,7 @@
             $("#wjbh").val('')
             $("#mj").val('')
             $("#gdnd").val('')
+            $("#qzh").val('')
             $("#bgqx").val('')
             const ml = searchParam.ml
             searchParam = {}
@@ -673,6 +684,7 @@
             searchParam.bgqx = data.field.bgqx
             searchParam.gdnd = data.field.gdnd
             searchParam.mj = data.field.mj
+            searchParam.qzh = data.field.qzh
             searchParam.ztc = data.field.ztc
             searchParam.wjbh = data.field.wjbh
             searchParam.again = true
@@ -686,6 +698,7 @@
             searchParam.bgqx = data.field.bgqx
             searchParam.gdnd = data.field.gdnd
             searchParam.mj = data.field.mj
+            searchParam.qzh = data.field.qzh
             searchParam.ztc = data.field.ztc
             searchParam.wjbh = data.field.wjbh
             searchParam.allDocument = data.field.allDocument

+ 6 - 3
src/main/resources/static/page/archive/show.html

@@ -116,6 +116,7 @@
     </div>
 </div>
 <input id="archive_id" name="archive_id" type="hidden">
+<script src="../../js/lay-module/utils/base64.min.js"></script>
 <script src="../../lib/layui-v2.5.5/layui.js" charset="utf-8"></script>
 <script src="../../js/lay-config.js?v=1.0.4" charset="utf-8"></script>
 <script>
@@ -176,11 +177,13 @@
                     }
                     for (let i = 0; i < res.data.length; i++) {
                         let item = res.data[i]
+                        let pef_src = 'http://66.1.21.158:8012/onlinePreview?officePreviewType=pdf&disabledownload=true&url=' + encodeURIComponent(Base64.encode('http://66.1.21.158:9091/' + item.filePath + '/' + item.fileName))
                         if (i == 0) {
-                            html += '<li class="layui-bg-green"><a title="' + (i + 1) + '、' + (item.jnml ? item.jnml : '档案文件') + '" pdf_src="' + item.filePath + '/' + item.fileName + '">' + (i + 1) + '、' + (item.jnml ? item.jnml : '档案文件') + '</a></li>'
-                            $("#pdf_show").prop('src', item.filePath + '/' + item.fileName)
+                            html += '<li class="layui-bg-green"><a title="' + (i + 1) + '、' + (item.jnml ? item.jnml : '档案文件') + '" pdf_src="' + pef_src + '">' + (i + 1) + '、' + (item.jnml ? item.jnml : '档案文件') + '</a></li>'
+                            // let pef_src = 'http://66.1.21.158:8012/onlinePreview?officePreviewType=pdf&url=' + encodeURIComponent(Base64.encode('http://fit.zju.edu.cn/_upload/article/files/42/e5/4ad6f5a54563869e08dea8066b3d/df728b53-f325-4073-9057-87ff3d75b6ca.pdf'))
+                            $("#pdf_show").prop('src', pef_src)
                         } else {
-                            html += '<li><a title="' + (i + 1) + '、' + (item.jnml ? item.jnml : '档案文件') + '" pdf_src="' + item.filePath + '/' + item.fileName + '">' + (i + 1) + '、' + (item.jnml ? item.jnml : '档案文件') + '</a></li>'
+                            html += '<li><a title="' + (i + 1) + '、' + (item.jnml ? item.jnml : '档案文件') + '" pdf_src="' + pef_src + '">' + (i + 1) + '、' + (item.jnml ? item.jnml : '档案文件') + '</a></li>'
                         }
                     }
                     $("#file_list").append(html)

+ 2 - 2
src/main/resources/static/page/role/edit.html

@@ -56,7 +56,7 @@
 
             //保存方法
         let save = function (data) {
-                http.post(urlParam.id == '' ? 'system/role/insert' : 'system/role/update', data, true, function (res) {
+                http.post(urlParam.id ? 'system/role/insert' : 'system/role/update', data, true, function (res) {
                     if (res.code == 200) {
                         let index = layer.alert('保存成功!', {
                             title: urlParam.id == '' ? '添加' : '修改' + '信息'
@@ -72,7 +72,7 @@
 
         // 加载数据
         let initData = function () {
-            if (urlParam.id != '') {
+            if (urlParam.id) {
                 http.get('system/role/selectByPrimaryKey', {id: urlParam.id}, true, function (res) {
                     form.val("addPaper", res.data);
                     form.render();

+ 196 - 0
src/test/java/com/gz/ConverOldSystemData.java

@@ -0,0 +1,196 @@
+package com.gz;
+
+import cn.hutool.core.io.FileTypeUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSON;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.gz.dto.archive.ArchiveDTO;
+import com.itextpdf.text.Document;
+import com.itextpdf.text.DocumentException;
+import com.itextpdf.text.Image;
+import com.itextpdf.text.Rectangle;
+import com.itextpdf.text.pdf.PdfWriter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+@Slf4j
+public class ConverOldSystemData {
+
+    private static final Charset CHARSET = Charset.forName("UTF-8");
+
+
+    private static List<JSON> rows = new ArrayList<>();
+
+    public static void main(String[] args) throws FileNotFoundException {
+        final String archiveTypePath = "H:\\10_建设用地类";
+        // 数据目录文件夹
+        File archiveTypeFolder = FileUtil.file(archiveTypePath);
+        if (archiveTypeFolder == null || !archiveTypeFolder.exists()) {
+            throw new FileNotFoundException("档案分类文件夹不存在");
+        }
+        // 循环档案文件夹
+        for (File archiveFolder : archiveTypeFolder.listFiles()) {
+            if (archiveFolder.isDirectory()) {
+                // 存储图片文件
+                List<File> images = new ArrayList<>();
+                File[] files = archiveFolder.listFiles();
+                // 数据Json
+                JSON archiveJson = null;
+                // 卷内目录Json
+                JSON innerArchiveJson = null;
+                for (File file : files) {
+                    String fileType = FileTypeUtil.getType(file);
+                    if ("jpg".equals(fileType)) {
+                        // 图片文件
+                        images.add(file);
+                    } else if ("json".equals(fileType)) {
+                        // Json文件
+                        String fileName = FileUtil.getName(file);
+                        if (fileName.equals("data.json")) {
+                            archiveJson = JSONUtil.readJSON(file, CHARSET);
+                        } else if (fileName.equals("inner.json")) {
+                            innerArchiveJson = JSONUtil.readJSON(file, CHARSET);
+                        }
+
+                    }
+                }
+                // 排序图片
+                Collections.sort(images, Comparator.comparingInt(o -> Integer.parseInt(getQuantity(FileUtil.getName(o)))));
+                ArchiveDTO archiveDTO = convertArchiveData(archiveJson);
+                imgToPdf(images, StrUtil.format("F:/temp/{}.pdf", archiveDTO.getDh()));
+                log.info("读取档案文件成功 数据:{} 卷内目录:{} 图片文件:{}张", archiveJson, innerArchiveJson, images.size());
+//                break;
+            } else {
+                log.warn("档案分类文件夹下出现非目录文件夹,地址:{}", archiveFolder.getAbsolutePath());
+            }
+        }
+//        ExcelWriter writer = ExcelUtil.getWriter();
+////        writer.addHeaderAlias("bgqx", "保管期限");
+////        writer.addHeaderAlias("dh", "档号");
+////        writer.addHeaderAlias("zny", "止年月");
+////        writer.addHeaderAlias("js", "件数");
+////        writer.addHeaderAlias("bz", "备注");
+////        writer.addHeaderAlias("ys", "页数");
+////        writer.addHeaderAlias("mj", "密级");
+////        writer.addHeaderAlias("ajh", "案卷号");
+////        writer.addHeaderAlias("qny", "起年月");
+////        writer.addHeaderAlias("flh", "分类号");
+////        writer.addHeaderAlias("mlh", "目录号");
+////        writer.addHeaderAlias("nd", "年度");
+////        writer.addHeaderAlias("tm", "题名");
+//
+//        writer.write(rows, true);
+//        FileOutputStream out = new FileOutputStream("F:\\temp\\10_建设用地类.xls");
+//        writer.flush(out, true);
+//        writer.close();
+//        IoUtil.close(out);
+    }
+
+    private static ArchiveDTO convertArchiveData(JSON json) {
+        ArchiveDTO c = new ArchiveDTO();
+        JSONArray a = (JSONArray) json;
+        JSONObject b = (JSONObject) a.get(0);
+//        c.setBgqx(b.getStr("bgqx"));
+        c.setDh(b.getStr("dh"));
+        rows.add(b);
+        return c;
+    }
+
+    /**
+     * 图片转Pdf
+     *
+     * @param images  图片集合
+     * @param pdfPath pdf存储路径
+     * @author LiuChangLan
+     * @since 2022/1/25 14:07
+     */
+    private static void imgToPdf(List<File> images, String pdfPath) throws FileNotFoundException {
+        Document document = new Document();
+        // 设置文档页边距
+        document.setMargins(0, 0, 0, 0);
+        FileOutputStream fos = null;
+        try {
+            fos = new FileOutputStream(pdfPath);
+            PdfWriter.getInstance(document, fos);
+            // 打开文档
+            document.open();
+            float firstImageHeight = 0;
+            float firstImageWidth = 0;
+            for (int i = 0; i < images.size(); i++) {
+                File image = images.get(i);
+                if ("jpg".equals(FileTypeUtil.getType(image))) {
+                    Image instance = Image.getInstance(image.getAbsolutePath());
+                    // 图片宽度
+                    float imgWidth = instance.getWidth();
+                    // 图片高度
+                    float imgHeight = instance.getHeight();
+                    // 读取第一张图片高度
+                    if (i == 0) {
+                        firstImageWidth = imgWidth;
+                        firstImageHeight = imgHeight;
+                    }
+                    if (imgWidth != firstImageWidth) {
+                        instance.scaleAbsolute(firstImageWidth, firstImageHeight);
+                    }
+                    // 设置页面宽高与图片一致
+                    Rectangle rectangle = new Rectangle(firstImageWidth, firstImageHeight);
+                    document.setPageSize(rectangle);
+                    // 图片居中
+                    instance.setAlignment(Image.ALIGN_CENTER);
+                    // 新建一页添加图片
+                    document.newPage();
+                    document.add(instance);
+                }
+            }
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            document.close();
+            IoUtil.close(fos);
+            log.info("图片转换pdf成功");
+        }
+    }
+
+    /**
+     * 读取字符串中开头数字
+     *
+     * @author LiuChangLan
+     * @since 2022/1/25 14:08
+     */
+    public static String getQuantity(String regular) {
+        int index = 0;
+        for (int i = 0; i < regular.length(); i++) {
+            char c = regular.charAt(i);
+            if (Character.isDigit(c)) {
+                if (i == regular.length() - 1) {
+                    index = i + 1;
+                } else {
+                    index = i;
+                }
+                continue;
+            } else {
+                index = i;
+                break;
+            }
+        }
+        return regular.substring(0, index);
+    }
+}

+ 23 - 0
src/test/java/com/gz/DeleteRedisKey.java

@@ -0,0 +1,23 @@
+package com.gz;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.redis.core.StringRedisTemplate;
+
+import javax.annotation.Resource;
+import java.util.Set;
+
+@SpringBootTest
+public class DeleteRedisKey {
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    @Test
+    public void test(){
+        Set<String> keys = stringRedisTemplate.keys("MOUNT_ERROR*");
+        for (String key : keys) {
+            System.out.println(key);
+        }
+    }
+}

+ 56 - 0
src/test/java/com/gz/HandleSource.java

@@ -0,0 +1,56 @@
+package com.gz;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.poi.excel.ExcelReader;
+import cn.hutool.poi.excel.ExcelUtil;
+import com.gz.dto.archive.ArchiveDTO;
+import com.gz.mapper.archive.ArchiveMapper;
+import com.gz.rvo.archive.ArchiveRVO;
+import com.gz.service.archive.ArchiveService;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import tk.mybatis.mapper.entity.Example;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+
+@SpringBootTest
+public class HandleSource {
+
+    @Resource
+    private ArchiveService archiveService;
+
+    @Resource
+    private ArchiveMapper archiveMapper;
+
+    @Test
+    public void run() {
+        ExcelReader reader = ExcelUtil.getReader(FileUtil.file("C:\\Users\\ljw\\Desktop\\a.xlsx"));
+        List<Map<String, Object>> maps = reader.readAll();
+
+        for (Map<String, Object> map : maps) {
+            String dh = MapUtil.getStr(map, "a");
+            String ly = MapUtil.getStr(map, "b");
+            String xzqh = MapUtil.getStr(map, "c");
+            String bq = MapUtil.getStr(map, "d");
+
+            if (StrUtil.isNotBlank(bq)) {
+                System.out.println(bq);
+            }
+
+            ArchiveDTO archiveDTO = new ArchiveDTO();
+            archiveDTO.setDh(dh);
+            archiveDTO.setLy(ly);
+            archiveDTO.setXzqh(xzqh);
+            archiveDTO.setBq(bq);
+
+            Example dhParam = new Example(ArchiveDTO.class);
+            dhParam.createCriteria().andEqualTo("dh", dh);
+            archiveMapper.updateByExampleSelective(archiveDTO, dhParam);
+        }
+    }
+}

+ 49 - 59
src/test/java/com/gz/WatermarkPdf.java

@@ -1,69 +1,59 @@
 package com.gz;
 
-import com.spire.pdf.PdfDocument;
-import com.spire.pdf.PdfPageBase;
-import com.spire.pdf.graphics.*;
-
-import java.awt.*;
-import java.awt.geom.Dimension2D;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDPageContentStream;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDType0Font;
+import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
+import org.apache.pdfbox.util.Matrix;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
 
 public class WatermarkPdf {
 
 
-    public static void main(String[] args)
-    {
-        //加载PDF文档
-        PdfDocument pdf = new PdfDocument();
-        pdf.loadFromFile("D:\\Program Files (x86)\\Tencent\\WeChat\\WeChat_DATA\\WeChat Files\\wxid_p52tn1dpq62f22\\FileStorage\\File\\2021-11\\自检情况报告(南苑街道).pdf");
-
-        //调用AddImageWatermark方法给PDF第一页添加图片水印
-//        AddImageWatermark(pdf.getPages().get(0), "H:\\Pictures\\20210615105005_4d1f0.jpg");
-
-        //调用AddTextWatermark方法给PDF第二页添加文字水印
-        AddTextWatermark(pdf.getPages().get(0), "测试水印");
-
-        //保存
-        pdf.saveToFile("H:\\Desktop\\Watermark.pdf");
-        //关闭
-        pdf.close();
-    }
-    /**
-     * @param page
-     * 要添加水印的页面
-     * @param imageFile
-     * 水印图片路径
-     */
-    static void AddImageWatermark(PdfPageBase page, String imageFile)
-    {
-        page.setBackgroundImage(imageFile);
-        Rectangle2D rect = new Rectangle2D.Float();
-        rect.setFrame(page.getClientSize().getWidth()/2 - 100, page.getClientSize().getHeight()/2 - 100, 200, 200);
-        page.setBackgroundRegion(rect);
-    }
+    public static void main(String[] args) throws IOException {
+        File pdfFile = new File("F:\\错误\\5179-WS2020-001-0000-1145.pdf");
+        //打开pdf文件
+        PDDocument pdf = PDDocument.load(pdfFile);
+        pdf.setAllSecurityToBeRemoved(true);
+        for (PDPage page : pdf.getPages()) {
+            PDPageContentStream cs = new PDPageContentStream(pdf, page, PDPageContentStream.AppendMode.APPEND, true, true);
+            String ts = "刘长兰";
+            //引入字体文件 解决中文汉字乱码问题
+            PDFont font = PDType0Font.load(pdf, new FileInputStream("C:\\Windows\\Fonts\\STLITI.TTF"), true);
+            float fontSize = 26;
+            PDResources resources = page.getResources();
+            PDExtendedGraphicsState r0 = new PDExtendedGraphicsState();
+            // 水印透明度
+            r0.setNonStrokingAlphaConstant(0.2f);
+            r0.setAlphaSourceFlag(true);
+            cs.setGraphicsStateParameters(r0);
+            //水印颜色
+            cs.setNonStrokingColor(153, 153, 153);
+            cs.beginText();
+            cs.setFont(font, fontSize);
+            //根据水印文字大小长度计算横向坐标需要渲染几次水印
+            float h = ts.length() * fontSize;
+            for (int i = 0; i <= 5; i++) {
+                // 获取旋转实例
+                cs.setTextMatrix(Matrix.getRotateInstance(-150, i * 220, 0));
+                cs.showText(ts);
+                for (int j = 0; j < 10; j++) {
+                    cs.setTextMatrix(Matrix.getRotateInstance(-150, i * 220, j * h * 2));
+                    cs.showText(ts);
+                }
+            }
+            cs.endText();
+            cs.restoreGraphicsState();
+            cs.close();
+            pdf.save("F:\\Watermark.pdf");
+        }
 
-    /**
-     * @param page
-     * 要添加水印的页面
-     * @param textWatermark
-     * 水印文字
-     */
-    static void AddTextWatermark(PdfPageBase page, String textWatermark)
-    {
-        Dimension2D dimension2D = new Dimension();
-        dimension2D.setSize(page.getCanvas().getClientSize().getWidth() / 2, page.getCanvas().getClientSize().getHeight() / 3);
-        PdfTilingBrush brush = new PdfTilingBrush(dimension2D);
-        brush.getGraphics().setTransparency(0.3F);
-        brush.getGraphics().save();
-        brush.getGraphics().translateTransform((float) brush.getSize().getWidth() / 2, (float) brush.getSize().getHeight() / 2);
-        brush.getGraphics().rotateTransform(-45);
-        brush.getGraphics().drawString(textWatermark, new PdfTrueTypeFont(new Font("宋体",Font.PLAIN,30),true), PdfBrushes.getRed(), 0, 0, new PdfStringFormat(PdfTextAlignment.Center));
-        brush.getGraphics().restore();
-        brush.getGraphics().setTransparency(1);
-        Rectangle2D loRect = new Rectangle2D.Float();
-        loRect.setFrame(new Point2D.Float(0, 0), page.getCanvas().getClientSize());
-        page.getCanvas().drawRectangle(brush, loRect);
     }