Explorar o código

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	ruoyi-system/src/main/java/com/ruoyi/system/service/loan/impl/LoanApplicationServiceImpl.java
Administrator hai 1 ano
pai
achega
d81ee8cb8b
Modificáronse 29 ficheiros con 2543 adicións e 9 borrados
  1. 12 0
      ruoyi-admin/pom.xml
  2. 1 0
      ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
  3. 110 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/PageofficeController.java
  4. 100 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/UpdateAppController.java
  5. 38 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/webOffice/ConsoleController.java
  6. 14 1
      ruoyi-admin/src/main/resources/application-druid.yml
  7. 17 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
  8. 8 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
  9. 197 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelFillUtils.java
  10. 87 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/FileUtils.java
  11. 5 4
      ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/WordUtil.java
  12. 32 0
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/CrossFilter.java
  13. 44 0
      ruoyi-system/pom.xml
  14. 122 0
      ruoyi-system/src/main/java/com/ruoyi/system/domain/UpdateApp.java
  15. 181 0
      ruoyi-system/src/main/java/com/ruoyi/system/domain/webOffice/WebofficeFj.java
  16. 66 0
      ruoyi-system/src/main/java/com/ruoyi/system/mapper/UpdateAppMapper.java
  17. 62 0
      ruoyi-system/src/main/java/com/ruoyi/system/mapper/WebofficeFjMapper.java
  18. 64 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/IUpdateAppService.java
  19. 114 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UpdateAppServiceImpl.java
  20. 293 4
      ruoyi-system/src/main/java/com/ruoyi/system/service/loan/impl/LoanApplicationServiceImpl.java
  21. 130 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/webOfficeImpl/ExtendCapacityServiceImpl.java
  22. 128 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/webOfficeImpl/MultiPhaseFileStorageServiceImpl.java
  23. 91 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/webOfficeImpl/PreviewServiceImpl.java
  24. 73 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/webOfficeImpl/SinglePhaseFileStorageServiceImpl.java
  25. 67 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/webService/IWebofficeFjService.java
  26. 90 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/webService/QnFileService.java
  27. 197 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/webService/WebofficeFjServiceImpl.java
  28. 103 0
      ruoyi-system/src/main/resources/mapper/system/UpdateAppMapper.xml
  29. 97 0
      ruoyi-system/src/main/resources/mapper/system/WebofficeFjMapper.xml

+ 12 - 0
ruoyi-admin/pom.xml

@@ -60,6 +60,18 @@
             <artifactId>ruoyi-generator</artifactId>
             <artifactId>ruoyi-generator</artifactId>
         </dependency>
         </dependency>
 
 
+        <dependency>
+            <groupId>com.zhuozhengsoft</groupId>
+            <artifactId>pageoffice</artifactId>
+            <version>6.1.0.2-javax</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.qiniu</groupId>
+            <artifactId>qiniu-java-sdk</artifactId>
+            <version>7.15.0</version>
+        </dependency>
+
     </dependencies>
     </dependencies>
 
 
     <build>
     <build>

+ 1 - 0
ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java

@@ -3,6 +3,7 @@ package com.ruoyi;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.data.map.repository.config.EnableMapRepositories;
 
 
 /**
 /**
  * 启动程序
  * 启动程序

+ 110 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/PageofficeController.java

@@ -0,0 +1,110 @@
+
+package com.ruoyi.web.controller.common;
+
+
+
+import com.ruoyi.framework.config.CrossFilter;
+import com.zhuozhengsoft.pageoffice.FileSaver;
+import com.zhuozhengsoft.pageoffice.OpenModeType;
+import com.zhuozhengsoft.pageoffice.PageOfficeCtrl;
+import com.zhuozhengsoft.pageoffice.poserver.Server;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/pageoffice")
+public class PageofficeController {
+
+
+    @Value("${docpath}")
+    private String docPath;
+
+    @Value("${posyspath}")
+    private String poSysPath;
+
+    @Value("${popassword}")
+    private String poPassWord;
+
+
+
+    /**
+     * 添加PageOffice的服务器端授权程序Servlet(必须)
+     * @return
+     */
+
+    @Bean
+    public ServletRegistrationBean pageofficeRegistrationBean()  {
+        com.zhuozhengsoft.pageoffice.poserver.Server poserver
+                = new com.zhuozhengsoft.pageoffice.poserver.Server();
+        poserver.setSysPath(poSysPath);//设置PageOffice注册成功后,license.lic文件存放的目录
+
+        ServletRegistrationBean srb = new ServletRegistrationBean(poserver);
+        srb.addUrlMappings("/poserver.zz");
+        srb.addUrlMappings("/poclient");
+        srb.addUrlMappings("/pageoffice.js");
+        srb.addUrlMappings("/sealsetup.exe");
+        return srb;
+    }
+
+
+    /**
+     * 添加印章管理程序Servlet(可选)
+     * @return
+     */
+
+    @Bean
+    public ServletRegistrationBean servletRegistrationBean2() {
+        com.zhuozhengsoft.pageoffice.poserver.AdminSeal adminSeal = new com.zhuozhengsoft.pageoffice.poserver.AdminSeal();
+        adminSeal.setAdminPassword(poPassWord);//设置印章管理员admin的登录密码
+        adminSeal.setSysPath(poSysPath);//设置印章数据库文件poseal.db存放的目录
+        ServletRegistrationBean srb = new ServletRegistrationBean(adminSeal);
+        srb.addUrlMappings("/adminseal.zz");
+        srb.addUrlMappings("/sealimage.zz");
+        srb.addUrlMappings("/loginseal.zz");
+        return srb;//
+    }
+
+
+
+    @RequestMapping(value="/openFile")
+    public String openFile(HttpServletRequest request) {
+        PageOfficeCtrl poCtrl = new PageOfficeCtrl(request);
+        poCtrl.setSaveFilePage("/pageoffice/saveFile");
+        //webOpen的第一个参数支持能够输出下载文件的Url相对地址或者文件在服务器上的磁盘路径两种方式
+        //查看详细,请在本站搜索“PageOffice属性或方法中涉及到的URL路径或磁盘路径的说明”
+        poCtrl.webOpen("D:\\word\\告企业书.doc", OpenModeType.docNormalEdit, "张三");
+        return  poCtrl.getHtmlCode();
+    }
+
+    @RequestMapping("/saveFile")
+    public void saveFile(HttpServletRequest request, HttpServletResponse response) {
+        FileSaver fs = new FileSaver(request, response);
+        fs.saveToFile("D:\\word\\" + fs.getFileName());
+        fs.close();
+    }
+
+    /**
+     * 为pageoffice插件跨域用,自己项目的跨越没办法解决
+     * @return
+     */
+    @Bean
+    public FilterRegistrationBean crossFilterRegistration() {
+        FilterRegistrationBean registration = new FilterRegistrationBean(new CrossFilter());
+        registration.addUrlPatterns("/*");
+        registration.setName("crossFilter");
+        return registration;
+    }
+
+
+}
+

+ 100 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/UpdateAppController.java

@@ -0,0 +1,100 @@
+package com.ruoyi.web.controller.system;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.system.domain.UpdateApp;
+import com.ruoyi.system.service.IUpdateAppService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 【请填写功能名称】Controller
+ * 
+ * @author ruoyi
+ * @date 2023-02-16
+ */
+@RestController
+@RequestMapping("/system/app")
+public class UpdateAppController extends BaseController
+{
+    @Autowired
+    private IUpdateAppService updateAppService;
+
+    /**
+     * 查询【请填写功能名称】列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(UpdateApp updateApp)
+    {
+        startPage();
+        List<UpdateApp> list = updateAppService.selectUpdateAppList(updateApp);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出【请填写功能名称】列表
+     */
+    @Log(title = "【请填写功能名称】", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, UpdateApp updateApp)
+    {
+        List<UpdateApp> list = updateAppService.selectUpdateAppList(updateApp);
+        ExcelUtil<UpdateApp> util = new ExcelUtil<UpdateApp>(UpdateApp.class);
+        util.exportExcel(response, list, "【请填写功能名称】数据");
+    }
+
+    /**
+     * 获取【请填写功能名称】详细信息
+     */
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(updateAppService.selectUpdateAppById(id));
+    }
+
+    /**
+     * 新增【请填写功能名称】
+     */
+    @Log(title = "【请填写功能名称】", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody UpdateApp updateApp)
+    {
+        return toAjax(updateAppService.insertUpdateApp(updateApp));
+    }
+
+    /**
+     * 修改【请填写功能名称】
+     */
+    @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE)
+    @PostMapping("/put")
+    public AjaxResult edit(@RequestBody UpdateApp updateApp)
+    {
+        return toAjax(updateAppService.updateUpdateApp(updateApp));
+    }
+
+    /**
+     * 删除【请填写功能名称】
+     */
+    @Log(title = "【请填写功能名称】", businessType = BusinessType.DELETE)
+	@GetMapping("/delete/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(updateAppService.deleteUpdateAppByIds(ids));
+    }
+
+    /**
+     * 获取当前最新版本数据
+     */
+    @GetMapping(value = "/new")
+    public AjaxResult getInfoNew(UpdateApp updateApp)
+    {
+        return success(updateAppService.getInfoNew(updateApp));
+    }
+}

+ 38 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/webOffice/ConsoleController.java

@@ -0,0 +1,38 @@
+package com.ruoyi.web.controller.webOffice;
+
+
+import cn.ljserver.tool.weboffice.v3.exception.FileNotExist;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.system.service.ISysConfigService;
+import com.ruoyi.system.service.webService.IWebofficeFjService;
+import com.ruoyi.system.service.webService.QnFileService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+@RestController
+@RequestMapping("/console")
+public class ConsoleController {
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @Autowired
+    private IWebofficeFjService webofficeFjService;
+
+    @PutMapping("/upload")
+    public String upload(MultipartFile file) {
+        return webofficeFjService.upload(file);
+    }
+
+    @PutMapping(value = "/upload/{file_id}")
+    public String upload(@PathVariable("file_id") String fileId, @RequestBody byte[] content) {
+        // ATTENTION a dirty version is written into storage
+
+        if (redisCache.getCacheObject(fileId)==null) throw new FileNotExist();
+        // 从缓存中获取当前需要上传文件的文件类型
+        String suffix = redisCache.getCacheObject(fileId);
+        return webofficeFjService.upload(fileId,content, suffix);
+    }
+
+}

+ 14 - 1
ruoyi-admin/src/main/resources/application-druid.yml

@@ -110,4 +110,17 @@ spring:
                     merge-sql: true
                     merge-sql: true
                 wall:
                 wall:
                     config:
                     config:
-                        multi-statement-allow: true
+                        multi-statement-allow: true
+
+
+    thymeleaf:
+        prefix: classpath:/templates/
+        suffix: .html
+        cache: false
+
+# 用于存放注册的信息以及.db文件,这个db文件包含了签章的一些信息,pageoffice帮我们集成好了 我们不用管,只需要自己创建签章即可
+posyspath: D:/pageoffice
+# 默认密码,管理签章的默认账号  admin  111111
+popassword: 111111
+
+docPath: D:/word/

+ 17 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java

@@ -241,4 +241,21 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
         }
         }
         return dateString;
         return dateString;
     }
     }
+
+    /**
+     * 判断一个字字符串能不能转成LONG
+     *
+     * @return yyyyMMddHHmmssS
+     */
+    public static boolean isNumeric(String strNum) {
+        try {
+            // 尝试将字符串转换为数字
+            Long num = Long.parseLong(strNum);
+            // 是数字,返回true
+            return true;
+        } catch (NumberFormatException e) {
+            // 不是数字,捕获异常并返回false
+            return false;
+        }
+    }
 }
 }

+ 8 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java

@@ -168,6 +168,14 @@ public class FileUploadUtils {
                 FilenameUtils.getBaseName(originalFilename), Seq.getId(Seq.uploadSeqType), getExtension(file));
                 FilenameUtils.getBaseName(originalFilename), Seq.getId(Seq.uploadSeqType), getExtension(file));
     }
     }
 
 
+    /**
+     * 编码文件名根据合同编号
+     */
+    public static final String extractFilenameLoanApplicationNumberNoHzm(String originalFilename) {
+        return StringUtils.format("{}_{}",
+                FilenameUtils.getBaseName(originalFilename), Seq.getId(Seq.uploadSeqType));
+    }
+
     public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
     public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
         File desc = new File(uploadDir + File.separator + fileName);
         File desc = new File(uploadDir + File.separator + fileName);
 
 

+ 197 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelFillUtils.java

@@ -0,0 +1,197 @@
+package com.ruoyi.common.utils.poi;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellUtil;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.*;
+import java.util.regex.Pattern;
+
+public class ExcelFillUtils {
+
+    //    public static final String FILL_EXPRESSION_REGEX = "\\{\\.\\w+\\}";
+    private static final String FILL_EXPRESSION_REGEX = "\\{\\.[\\p{L}\\p{M}\\S]+\\}";
+
+    /**
+     * 给定模板,指定某个页签,将数据填充到模板中的指定页签,并在模板所在目录生成新的副本文件。
+     * @param template 模板文件地址
+     * @param sheetName 页签名称
+     * @param data 待填充的数据,数据格式如下
+     *                  [
+     *                      {"colName1":v1 ,"colName2":v2...},
+     *                      {"colName1":v1 ,"colName2":v2...}
+     *                      ,...
+     *                  ]
+     * @return 新生成的副本文件的地址
+     *
+     * */
+    public static String fillOneSheet(String template ,String sheetName , List<Map<String,Object>> data) {
+        return fillOneSheet(template ,FileUtils.getAvailableFullName(template) ,sheetName ,data);
+    }
+
+    /**
+     * 给定模板,指定某个页签,将数据填充到模板中的指定页签,并将数据导入到指定文件上。
+     * @param template 模板文件地址
+     * @param outputFile 新生成的文件的地址
+     * @param sheetName 页签名称
+     * @param data 待填充的数据,数据格式如下
+     *                  [
+     *                      {"colName1":v1 ,"colName2":v2...},
+     *                      {"colName1":v1 ,"colName2":v2...}
+     *                      ,...
+     *                  ]
+     * @return 新生成的副本文件的地址
+     *
+     * */
+    public static String fillOneSheet(String template , String outputFile,String sheetName , List<Map<String,Object>> data){
+
+        try (Workbook workbook = new XSSFWorkbook(new FileInputStream(template))) {
+
+            fill(workbook,sheetName,data);//填充数据
+            refreshFormula(workbook);//刷新公式
+
+            try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
+                workbook.write(outputStream);
+            }catch (Exception e){
+                throw new RuntimeException(e);
+            }
+
+        }catch (IOException e){
+            throw new RuntimeException(e);
+        }
+
+        return outputFile;
+    }
+
+    /**
+     * 给定模板,将数据填充到模板中的多个页签,并在模板所在目录生成新的副本文件。
+     * @param template 模板文件地址
+     * @param datas 待填充的数据集,数据格式如下
+     *              {
+     *                  "SheetName1":[
+     *                      {"colName1":v1 ,"colName2":v2...},
+     *                      {"colName1":v1 ,"colName2":v2...}
+     *                      ,...
+     *                  ],
+     *                  "SheetName2":[
+     *                      {"colName1":v1 ,"colName2":v2...}
+     *                      {"colName1":v1 ,"colName2":v2...}
+     *                      ,...
+     *                  ],
+     *                  ...
+     *              }
+     *
+     * */
+    public static String fillMultipleSheet(String template ,Map<String,List<Map<String,Object>>> datas) {
+        return fillMultipleSheet(template ,FileUtils.getAvailableFullName(template) ,datas);
+    }
+
+    /**
+     * 给定模板,将数据填充到模板中的多个页签,并将数据导入到指定文件上。
+     * @param template 模板文件地址
+     * @param datas 待填充的数据集,数据格式如下
+     *              {
+     *                  "SheetName1":[
+     *                      {"colName1":v1 ,"colName2":v2...},
+     *                      {"colName1":v1 ,"colName2":v2...}
+     *                      ,...
+     *                  ],
+     *                  "SheetName2":[
+     *                      {"colName1":v1 ,"colName2":v2...}
+     *                      {"colName1":v1 ,"colName2":v2...}
+     *                      ,...
+     *                  ],
+     *                  ...
+     *              }
+     *
+     * */
+    public static String fillMultipleSheet(String template ,String outputFile ,Map<String,List<Map<String,Object>>> datas){
+
+        try (Workbook workbook = new XSSFWorkbook(new FileInputStream(template))) {
+
+            datas.forEach( (sheetName ,data)-> fill(workbook,sheetName,data) );//填充数据
+            refreshFormula(workbook);//刷新公式
+
+            try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
+                workbook.write(outputStream);
+            }catch (Exception e){
+                throw new RuntimeException(e);
+            }
+
+        }catch (IOException e){
+            throw new RuntimeException(e);
+        }
+
+        return outputFile;
+    }
+
+    private static Workbook fill(Workbook workbook ,String sheetName ,List<Map<String,Object>> data) {
+
+        Sheet sheet = workbook.getSheet(sheetName);
+        if (sheet == null) {
+            throw new RuntimeException(String.format("sheet [%s] does not exist.",sheetName));
+        }
+
+        //找到所有的表达式单元格
+        Map<String,Cell> expressionCellMap = new HashMap<>();
+        for( int i = 0 ;i < sheet.getPhysicalNumberOfRows() ;i++){
+            Row row = sheet.getRow(i);
+            for( int j = 0 ;j< row.getPhysicalNumberOfCells() ;j++){
+                Cell cell = row.getCell(j);
+                if( !Objects.isNull(cell) && isFillExpression(cell.getStringCellValue()) ){//判断该单元格是否是填充公式
+                    expressionCellMap.put(getColNameFromEx(cell.getStringCellValue()),cell);
+                }
+            }
+        }
+
+        //填充数据
+        for(int i = 0 ;i< data.size() ;i++){
+            Map<String,Object> dataRow = data.get(i);
+            for (Map.Entry<String,Object> entry : dataRow.entrySet()){
+                String colName = entry.getKey();
+                Object value = entry.getValue();
+                if(expressionCellMap.containsKey(colName)){
+
+                    Cell cell = expressionCellMap.get(colName);//公式所在的单元格
+                    int rowID = cell.getRowIndex() + i;
+                    int colId = cell.getColumnIndex();
+
+                    Row fillRow = sheet.getRow(rowID);
+                    fillRow = Objects.isNull(fillRow) ? sheet.createRow(rowID) : fillRow;
+                    Cell fillCell = fillRow.getCell(colId);
+                    //创建的新单元格需要复制公式单元格的格式
+                    fillCell = Objects.isNull(fillCell) ? CellUtil.createCell(fillRow,colId,"", cell.getCellStyle()) : fillCell;
+
+                    if ( value instanceof String){
+                        fillCell.setCellValue( String.valueOf(value) );
+                    }else if( value instanceof Number ){
+                        fillCell.setCellValue( ((Number)value).doubleValue() );
+                    }else{
+                        throw new RuntimeException(String.format("Unsupported data type [%s].",value.getClass().toString()));
+                    }
+
+                }
+            }
+        }
+
+        return workbook;
+    }
+
+    private static void refreshFormula(Workbook workbook){
+        FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
+        evaluator.evaluateAll();
+    }
+
+    private static boolean isFillExpression(String ex){
+        if (ex.isEmpty()) return false;
+        return Pattern.matches(FILL_EXPRESSION_REGEX ,ex);
+    }
+
+    private static String getColNameFromEx(String ex){
+        if (!isFillExpression(ex)) throw new RuntimeException("Illegal expression " + ex );
+        return ex.substring(2,ex.length() - 1);
+    }
+
+}
+

+ 87 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/FileUtils.java

@@ -0,0 +1,87 @@
+package com.ruoyi.common.utils.poi;
+
+import java.io.*;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+public class FileUtils {
+
+    private static final String COPY_FILE_SUFFIX = "_副本";
+
+    /**
+     * 将输入流写入文件
+     * @param in 输入流
+     * @param path 输出文件的路径
+     * @param fileName 输出文件的名称
+     *
+     * */
+    public static void writeFile(InputStream in ,String path ,String fileName) throws FileNotFoundException {
+
+        FileOutputStream outputStream = new FileOutputStream("");
+
+    }
+
+
+    /**
+     * 给定一个目录和文件,若该目录存在名称相同的文件,则返回一个可用的副本文件名,否则直接返回输入的文件名。
+     * @param path 文件的目录
+     * @param fileName 文件名
+     * @return 可用的文件名
+     * */
+    public static String getAvailableName(String path ,String fileName){
+
+        File filePath = new File(path);
+
+        String suffix = fileName.substring(fileName.lastIndexOf("."));
+        File[] files = filePath.listFiles( f -> f.getName().endsWith(suffix) );
+        if ( Objects.isNull(files) ) return fileName;
+
+        Set<String> fileNameSet = new HashSet<>();
+        for (File file: files ) {
+            fileNameSet.add(file.getName().substring(0 , file.getName().lastIndexOf(".")));
+        }
+
+        boolean isExist = true;
+        int count = 1;
+        String tempFileName = fileName.substring(0,fileName.lastIndexOf("."));
+        String tempFileName1 = tempFileName;
+        while(isExist){
+
+            if (fileNameSet.contains(tempFileName)){
+                tempFileName = tempFileName1 + COPY_FILE_SUFFIX + count++;
+            }else{
+                isExist = false;
+            }
+
+        }
+
+        return tempFileName + suffix;
+    }
+
+
+    /**
+     * 给定一个文件的完整路径,若该文件已经存在,则返回一个可用的副本文件名,否则直接返回输入的文件名。
+     * @param fullPath 文件的完整路径
+     * @return 可用的文件名
+     * */
+    public static String getAvailableName( String fullPath ){
+        File file = new File(fullPath);
+        if ( !file.isFile() ) throw new RuntimeException( String.format("not a file [%s].",fullPath));
+
+        return getAvailableName( file.getParent() ,file.getName() );
+    }
+
+    /**
+     * 给定一个文件的完整路径,若该文件已经存在,则返回一个完整可用的副本文件名,否则直接返回输入的文件名。
+     * @param fullPath 文件的完整路径
+     * @return 完整可用的文件名
+     * */
+    public static String getAvailableFullName( String fullPath ){
+        File file = new File(fullPath);
+        if ( !file.isFile() ) throw new RuntimeException( String.format("not a file [%s].",fullPath));
+
+        return file.getParent() + File.separator + getAvailableName(fullPath);
+    }
+
+}

+ 5 - 4
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/WordUtil.java

@@ -70,14 +70,15 @@ public class WordUtil {
     public static void main(String[] args) {
     public static void main(String[] args) {
         Map<String, Object> params = new HashMap<>();
         Map<String, Object> params = new HashMap<>();
         // 渲染文本
         // 渲染文本
-        params.put("title", "XXX工程");
+        //params.put("title", "XXX工程");
+        params.put("enterpriseName", "XXX工程");
         //...
         //...
         // 渲染图片
         // 渲染图片
         //params.put("picture", new PictureRenderData(120, 120, "D:\\wx.png"));
         //params.put("picture", new PictureRenderData(120, 120, "D:\\wx.png"));
         // TODO 渲染其他类型的数据请参考官方文档
         // TODO 渲染其他类型的数据请参考官方文档
-        String templatePath = "D:\\zdd.docx";
-        String fileDir = "D:\\template";
-        String fileName = "zdd2";
+        String templatePath = "D:\\ruoyi\\uploadPath\\mb\\委托担保申请书.docx";
+        String fileDir = "D:\\ruoyi\\uploadPath\\mb\\temporarily";
+        String fileName = "wtdbsqs";
 
 
         String wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
         String wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
         System.out.println("生成文档路径:" + wordPath);
         System.out.println("生成文档路径:" + wordPath);

+ 32 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/config/CrossFilter.java

@@ -0,0 +1,32 @@
+package com.ruoyi.framework.config;
+
+import org.springframework.stereotype.Component;
+import javax.servlet.*;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+/**
+ * 拦截器,解决前端跨域问题
+ * 为了 pageoffice 使用的
+ */
+@Component
+public class CrossFilter implements Filter {
+
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+        HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+        response.setHeader("Access-Control-Allow-Origin","*");
+        response.setHeader("Access-Control-Allow-Credentials", "true");
+        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
+        response.setHeader("Access-Control-Max-Age", "3600");
+        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
+
+        filterChain.doFilter(servletRequest, servletResponse);
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}

+ 44 - 0
ruoyi-system/pom.xml

@@ -14,6 +14,18 @@
     <description>
     <description>
         system系统模块
         system系统模块
     </description>
     </description>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>9</source>
+                    <target>9</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 
 
     <dependencies>
     <dependencies>
 
 
@@ -23,6 +35,38 @@
             <artifactId>ruoyi-common</artifactId>
             <artifactId>ruoyi-common</artifactId>
         </dependency>
         </dependency>
 
 
+        <dependency>
+            <groupId>javax.persistence</groupId>
+            <artifactId>javax.persistence-api</artifactId>
+            <version>2.2</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.ljserver.tool</groupId>
+            <artifactId>web-office-v3</artifactId>
+            <version>3.1.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.qiniu</groupId>
+            <artifactId>qiniu-java-sdk</artifactId>
+            <version>7.15.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-mock</artifactId>
+            <version>2.0.8</version>
+        </dependency>
+
+
     </dependencies>
     </dependencies>
 
 
 </project>
 </project>

+ 122 - 0
ruoyi-system/src/main/java/com/ruoyi/system/domain/UpdateApp.java

@@ -0,0 +1,122 @@
+package com.ruoyi.system.domain;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 【请填写功能名称】对象 update_app
+ * 
+ * @author ruoyi
+ * @date 2023-02-16
+ */
+public class UpdateApp extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    private Long id;
+
+    /** 系统:Android:安卓系统,Apple:苹果系统 */
+    @Excel(name = "系统:Android:安卓系统,Apple:苹果系统")
+    private String model;
+
+    /** 版本名称 */
+    @Excel(name = "版本名称")
+    private String name;
+
+    /** 版本号 */
+    @Excel(name = "版本号")
+    private String code;
+
+    /** 版本描述 */
+    @Excel(name = "版本描述")
+    private String description;
+
+    /** 下载地址 */
+    @Excel(name = "下载地址")
+    private String path;
+
+    /** 是否有效 0:失效 1:有效 */
+    @Excel(name = "是否有效 0:失效 1:有效")
+    private String isDel;
+
+    public void setId(Long id) 
+    {
+        this.id = id;
+    }
+
+    public Long getId() 
+    {
+        return id;
+    }
+    public void setModel(String model) 
+    {
+        this.model = model;
+    }
+
+    public String getModel() 
+    {
+        return model;
+    }
+    public void setName(String name) 
+    {
+        this.name = name;
+    }
+
+    public String getName() 
+    {
+        return name;
+    }
+    public void setCode(String code) 
+    {
+        this.code = code;
+    }
+
+    public String getCode() 
+    {
+        return code;
+    }
+    public void setDescription(String description) 
+    {
+        this.description = description;
+    }
+
+    public String getDescription() 
+    {
+        return description;
+    }
+    public void setPath(String path) 
+    {
+        this.path = path;
+    }
+
+    public String getPath() 
+    {
+        return path;
+    }
+    public void setIsDel(String isDel) 
+    {
+        this.isDel = isDel;
+    }
+
+    public String getIsDel() 
+    {
+        return isDel;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("model", getModel())
+            .append("name", getName())
+            .append("code", getCode())
+            .append("description", getDescription())
+            .append("path", getPath())
+            .append("isDel", getIsDel())
+            .append("createTime", getCreateTime())
+            .toString();
+    }
+}

+ 181 - 0
ruoyi-system/src/main/java/com/ruoyi/system/domain/webOffice/WebofficeFj.java

@@ -0,0 +1,181 @@
+package com.ruoyi.system.domain.webOffice;
+
+import cn.ljserver.tool.weboffice.v3.model.FileInfo;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Builder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+
+/**
+ * webOffice附件记录对象 webOffice_fj
+ * 
+ * @author boman
+ * @date 2024-05-20
+ */
+public class WebofficeFj {
+    private static final long serialVersionUID = 1L;
+
+    /** webOffice附件ID */
+    private Long webofficeId;
+
+    /** 附件id */
+    @Excel(name = "附件id")
+    private Long fjId;
+
+    /** 版本号 */
+    @Excel(name = "版本号")
+    private int version;
+
+    /** 文件大小 */
+    @Excel(name = "文件大小")
+    private Long size;
+
+    /** 附件名称 */
+    @Excel(name = "附件名称")
+    private String name;
+
+    /** 附件地址 */
+    @Excel(name = "附件地址")
+    private String url;
+
+    /** 创建者 */
+    private String createBy;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    /** 更新者 */
+    private String updateBy;
+
+    /** 更新时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updateTime;
+
+    /** 备注 */
+    private String remark;
+
+    public Long getWebofficeId() {
+        return webofficeId;
+    }
+
+    public void setWebofficeId(Long webofficeId) {
+        this.webofficeId = webofficeId;
+    }
+
+    public Long getFjId() {
+        return fjId;
+    }
+
+    public void setFjId(Long fjId) {
+        this.fjId = fjId;
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    public void setVersion(int version) {
+        this.version = version;
+    }
+
+    public Long getSize() {
+        return size;
+    }
+
+    public void setSize(Long size) {
+        this.size = size;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getCreateBy() {
+        return createBy;
+    }
+
+    public void setCreateBy(String createBy) {
+        this.createBy = createBy;
+    }
+
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getUpdateBy() {
+        return updateBy;
+    }
+
+    public void setUpdateBy(String updateBy) {
+        this.updateBy = updateBy;
+    }
+
+    public LocalDateTime getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(LocalDateTime updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("webofficeId", getWebofficeId())
+            .append("fjId", getFjId())
+            .append("version", getVersion())
+            .append("size", getSize())
+            .append("name", getName())
+            .append("url", getUrl())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
+
+    /**
+     * 转换为适用与web office的FileInfo
+     */
+    public FileInfo toFileInfo() {
+        return FileInfo.builder()
+                .id(String.valueOf(this.fjId))
+                .name(this.name)
+                .version(this.version)
+                .size(this.size)
+                .createTime(this.createTime)
+                .modifyTime(this.updateTime)
+                .build();
+    }
+}

+ 66 - 0
ruoyi-system/src/main/java/com/ruoyi/system/mapper/UpdateAppMapper.java

@@ -0,0 +1,66 @@
+package com.ruoyi.system.mapper;
+
+import com.ruoyi.system.domain.UpdateApp;
+
+import java.util.List;
+
+/**
+ * 【请填写功能名称】Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2023-02-16
+ */
+public interface UpdateAppMapper 
+{
+    /**
+     * 查询【请填写功能名称】
+     * 
+     * @param id 【请填写功能名称】主键
+     * @return 【请填写功能名称】
+     */
+    public UpdateApp selectUpdateAppById(Long id);
+
+    /**
+     * 查询【请填写功能名称】列表
+     * 
+     * @param updateApp 【请填写功能名称】
+     * @return 【请填写功能名称】集合
+     */
+    public List<UpdateApp> selectUpdateAppList(UpdateApp updateApp);
+
+    /**
+     * 新增【请填写功能名称】
+     * 
+     * @param updateApp 【请填写功能名称】
+     * @return 结果
+     */
+    public int insertUpdateApp(UpdateApp updateApp);
+
+    /**
+     * 修改【请填写功能名称】
+     * 
+     * @param updateApp 【请填写功能名称】
+     * @return 结果
+     */
+    public int updateUpdateApp(UpdateApp updateApp);
+
+    /**
+     * 删除【请填写功能名称】
+     * 
+     * @param id 【请填写功能名称】主键
+     * @return 结果
+     */
+    public int deleteUpdateAppById(Long id);
+
+    /**
+     * 批量删除【请填写功能名称】
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteUpdateAppByIds(Long[] ids);
+
+    UpdateApp getInfo(UpdateApp updateApp);
+
+    void updateUpdateAppAll(UpdateApp update);
+}

+ 62 - 0
ruoyi-system/src/main/java/com/ruoyi/system/mapper/WebofficeFjMapper.java

@@ -0,0 +1,62 @@
+package com.ruoyi.system.mapper;
+
+import com.ruoyi.system.domain.webOffice.WebofficeFj;
+
+import java.util.List;
+
+/**
+ * webOffice附件记录Mapper接口
+ * 
+ * @author boman
+ * @date 2024-05-20
+ */
+public interface WebofficeFjMapper 
+{
+    /**
+     * 查询webOffice附件记录
+     * 
+     * @param webofficeId webOffice附件记录主键
+     * @return webOffice附件记录
+     */
+    public WebofficeFj selectWebofficeFjByWebofficeId(Long webofficeId);
+
+    /**
+     * 查询webOffice附件记录列表
+     * 
+     * @param webofficeFj webOffice附件记录
+     * @return webOffice附件记录集合
+     */
+    public List<WebofficeFj> selectWebofficeFjList(WebofficeFj webofficeFj);
+
+    /**
+     * 新增webOffice附件记录
+     * 
+     * @param webofficeFj webOffice附件记录
+     * @return 结果
+     */
+    public int insertWebofficeFj(WebofficeFj webofficeFj);
+
+    /**
+     * 修改webOffice附件记录
+     * 
+     * @param webofficeFj webOffice附件记录
+     * @return 结果
+     */
+    public int updateWebofficeFj(WebofficeFj webofficeFj);
+
+    /**
+     * 删除webOffice附件记录
+     * 
+     * @param webofficeId webOffice附件记录主键
+     * @return 结果
+     */
+    public int deleteWebofficeFjByWebofficeId(Long webofficeId);
+
+    /**
+     * 批量删除webOffice附件记录
+     * 
+     * @param webofficeIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteWebofficeFjByWebofficeIds(Long[] webofficeIds);
+}

+ 64 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/IUpdateAppService.java

@@ -0,0 +1,64 @@
+package com.ruoyi.system.service;
+
+import com.ruoyi.system.domain.UpdateApp;
+
+import java.util.List;
+
+/**
+ * 【请填写功能名称】Service接口
+ * 
+ * @author ruoyi
+ * @date 2023-02-16
+ */
+public interface IUpdateAppService 
+{
+    /**
+     * 查询【请填写功能名称】
+     * 
+     * @param id 【请填写功能名称】主键
+     * @return 【请填写功能名称】
+     */
+    public UpdateApp selectUpdateAppById(Long id);
+
+    /**
+     * 查询【请填写功能名称】列表
+     * 
+     * @param updateApp 【请填写功能名称】
+     * @return 【请填写功能名称】集合
+     */
+    public List<UpdateApp> selectUpdateAppList(UpdateApp updateApp);
+
+    /**
+     * 新增【请填写功能名称】
+     * 
+     * @param updateApp 【请填写功能名称】
+     * @return 结果
+     */
+    public int insertUpdateApp(UpdateApp updateApp);
+
+    /**
+     * 修改【请填写功能名称】
+     * 
+     * @param updateApp 【请填写功能名称】
+     * @return 结果
+     */
+    public int updateUpdateApp(UpdateApp updateApp);
+
+    /**
+     * 批量删除【请填写功能名称】
+     * 
+     * @param ids 需要删除的【请填写功能名称】主键集合
+     * @return 结果
+     */
+    public int deleteUpdateAppByIds(Long[] ids);
+
+    /**
+     * 删除【请填写功能名称】信息
+     * 
+     * @param id 【请填写功能名称】主键
+     * @return 结果
+     */
+    public int deleteUpdateAppById(Long id);
+
+    UpdateApp getInfoNew(UpdateApp updateApp);
+}

+ 114 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UpdateAppServiceImpl.java

@@ -0,0 +1,114 @@
+package com.ruoyi.system.service.impl;
+
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.system.domain.UpdateApp;
+import com.ruoyi.system.mapper.UpdateAppMapper;
+import com.ruoyi.system.service.IUpdateAppService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 【请填写功能名称】Service业务层处理
+ * 
+ * @author ruoyi
+ * @date 2023-02-16
+ */
+@Service
+public class UpdateAppServiceImpl implements IUpdateAppService 
+{
+    @Autowired
+    private UpdateAppMapper updateAppMapper;
+
+    /**
+     * 查询【请填写功能名称】
+     * 
+     * @param id 【请填写功能名称】主键
+     * @return 【请填写功能名称】
+     */
+    @Override
+    public UpdateApp selectUpdateAppById(Long id)
+    {
+        return updateAppMapper.selectUpdateAppById(id);
+    }
+
+    /**
+     * 查询【请填写功能名称】列表
+     * 
+     * @param updateApp 【请填写功能名称】
+     * @return 【请填写功能名称】
+     */
+    @Override
+    public List<UpdateApp> selectUpdateAppList(UpdateApp updateApp)
+    {
+        return updateAppMapper.selectUpdateAppList(updateApp);
+    }
+
+    /**
+     * 新增【请填写功能名称】
+     * 
+     * @param updateApp 【请填写功能名称】
+     * @return 结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int insertUpdateApp(UpdateApp updateApp)
+    {
+        //将之前的数据全改为失效
+        UpdateApp update = new UpdateApp();
+        update.setIsDel("0");
+        update.setModel(updateApp.getModel());
+        updateAppMapper.updateUpdateAppAll(update);
+        //保存当前数据
+        updateApp.setCreateTime(DateUtils.getNowDate());
+        return updateAppMapper.insertUpdateApp(updateApp);
+    }
+
+    /**
+     * 修改【请填写功能名称】
+     * 
+     * @param updateApp 【请填写功能名称】
+     * @return 结果
+     */
+    @Override
+    public int updateUpdateApp(UpdateApp updateApp)
+    {
+        return updateAppMapper.updateUpdateApp(updateApp);
+    }
+
+    /**
+     * 批量删除【请填写功能名称】
+     * 
+     * @param ids 需要删除的【请填写功能名称】主键
+     * @return 结果
+     */
+    @Override
+    public int deleteUpdateAppByIds(Long[] ids)
+    {
+        return updateAppMapper.deleteUpdateAppByIds(ids);
+    }
+
+    /**
+     * 删除【请填写功能名称】信息
+     * 
+     * @param id 【请填写功能名称】主键
+     * @return 结果
+     */
+    @Override
+    public int deleteUpdateAppById(Long id)
+    {
+        return updateAppMapper.deleteUpdateAppById(id);
+    }
+
+    @Override
+    public UpdateApp getInfoNew(UpdateApp updateApp) {
+        updateApp.setIsDel("Y");
+        UpdateApp app = updateAppMapper.getInfo(updateApp);
+        if(app == null){
+            app = new UpdateApp();
+        }
+        return app;
+    }
+}

+ 293 - 4
ruoyi-system/src/main/java/com/ruoyi/system/service/loan/impl/LoanApplicationServiceImpl.java

@@ -4,10 +4,17 @@ package com.ruoyi.system.service.loan.impl;
 import com.ruoyi.common.config.RuoYiConfig;
 import com.ruoyi.common.config.RuoYiConfig;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysRole;
 import com.ruoyi.common.core.domain.entity.SysRole;
+import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.SendSmsUtils;
+import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.common.utils.poi.ExcelFillUtils;
+import com.ruoyi.common.utils.poi.WordUtil;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.uuid.Seq;
 import com.ruoyi.common.utils.uuid.Seq;
+import com.ruoyi.common.utils.uuid.IdUtils;
+import com.ruoyi.common.utils.uuid.UUID;
 import com.ruoyi.system.domain.conference.SysUserConference;
 import com.ruoyi.system.domain.conference.SysUserConference;
 import com.ruoyi.system.domain.enterprise.SysUserEnterprise;
 import com.ruoyi.system.domain.enterprise.SysUserEnterprise;
 import com.ruoyi.system.domain.loan.LoanApplication;
 import com.ruoyi.system.domain.loan.LoanApplication;
@@ -25,7 +32,12 @@ import java.io.*;
 import java.nio.file.Files;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.Paths;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.io.File;
 import java.util.*;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 import java.util.zip.ZipOutputStream;
@@ -57,6 +69,10 @@ public class LoanApplicationServiceImpl implements ILoanApplicationService {
     @Resource
     @Resource
     private WaitRemindMapper waitRemindMapper;
     private WaitRemindMapper waitRemindMapper;
 
 
+    @Autowired
+    private RedisCache redisCache;
+
+
     /**
     /**
      * 查询贷款申请主
      * 查询贷款申请主
      *
      *
@@ -688,10 +704,283 @@ public class LoanApplicationServiceImpl implements ILoanApplicationService {
      */
      */
     @Override
     @Override
     public AjaxResult exportMb(LoanApplication loanApplication) {
     public AjaxResult exportMb(LoanApplication loanApplication) {
-        String path = "/profile/mb/";
-        if ("1".equals(loanApplication.getType())) {
-            path = path + "委托担保申请书.doc";
+        Map<String,Object> map = new HashMap<>();
+        String type = loanApplication.getType();
+        String loanApplicationNumber = loanApplication.getLoanApplicationNumber();
+        if(loanApplication.getLoanApplicationId()!=null || loanApplication.getLoanApplicationId()!=0L){
+            loanApplication = loanApplicationMapper.selectLoanApplicationByLoanApplicationId(loanApplication.getLoanApplicationId());
+            loanApplication.setType(type);
+            //判断附件存不存在
+            LoanApplicationFj loanApplicationFj = new LoanApplicationFj();
+            loanApplicationFj.setLoanApplicationId(loanApplication.getLoanApplicationId());
+            //返回附件表对应type
+            String fileType = contrastType(type);
+            loanApplicationFj.setType(fileType);
+            List<LoanApplicationFj> loanApplicationFjs = loanApplicationFjMapper.selectLoanApplicationFjList(loanApplicationFj);
+            if(loanApplicationFjs!=null && loanApplicationFjs.size()>0){
+                for (LoanApplicationFj applicationFj : loanApplicationFjs) {
+                    redisCache.setCacheObject(applicationFj.getFjId()+"info",applicationFj,2, TimeUnit.HOURS);
+                    map.put("fileId",applicationFj.getFjId());
+                    map.put("path",applicationFj.getUrl());
+                    map.put("fileName",applicationFj.getName());
+                    return AjaxResult.success(map);
+                }
+            }
         }
         }
-        return AjaxResult.success(path);
+
+        Map<String, Object> params = new HashMap<>();
+        String path = "/profile/mb/temporarily";
+        //查询公司信息
+        SysUserEnterprise sysUserEnterprise = sysUserEnterpriseMapper.selectSysUserEnterpriseByEnterpriseId(loanApplication.getEnterpriseId());
+        params.put("loanApplication", loanApplication);
+        params.put("sysUserEnterprise", sysUserEnterprise);
+        String templatePath = RuoYiConfig.getProfile();
+        String fileDir = RuoYiConfig.getProfile();
+        String fileName = "";
+        String fileNameHz = "";
+        String wordPath = "";
+        switch (type) {
+            case "1":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/委托担保申请书.docx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily"+loanApplicationNumber;
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("委托担保申请书");
+                fileName = loanApplication.getEnterpriseName() + "-委托担保申请书";
+                fileNameHz = fileName + ".docx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "2":
+                params.put("enterpriseAddres", sysUserEnterprise.getEnterpriseAddress());
+                params.put("corporationPhone", loanApplication.getCorporationPhone());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/委托保证合同.docx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily"+loanApplicationNumber;
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("委托担保申请书");
+                fileName = loanApplication.getEnterpriseName() + "-委托担保申请书";
+                fileNameHz = fileName + ".docx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "3":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = templatePath + "/mb/担保意向函.docx";
+                fileDir = fileDir + "/mb/temporarily"+loanApplicationNumber;
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("担保意向函");
+                fileName = loanApplication.getEnterpriseName() + "-担保意向函";
+                fileNameHz = fileName + ".docx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "4":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/放款(出票)通知书.docx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily/"+loanApplicationNumber;
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("放款(出票)通知书");
+                fileName = loanApplication.getEnterpriseName() + "-放款(出票)通知书";
+                fileNameHz = fileName + ".docx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "5":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/保证反担保合同(适用于法人).docx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily"+loanApplicationNumber;
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("保证反担保合同(适用于法人)");
+                fileName = loanApplication.getEnterpriseName() + "-保证反担保合同(适用于法人)";
+                fileNameHz = fileName + ".docx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "6":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/保证反担保合同(适用于自然人).docx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily"+loanApplicationNumber;
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("保证反担保合同(适用于自然人)");
+                fileName = loanApplication.getEnterpriseName() + "-保证反担保合同(适用于自然人)";
+                fileNameHz = fileName + ".docx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "7":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/抵押反担保合同(适用于法人).docx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily"+loanApplicationNumber;
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("抵押反担保合同(适用于法人)");
+                fileName = loanApplication.getEnterpriseName() + "-抵押反担保合同(适用于法人)";
+                fileNameHz = fileName + ".docx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "8":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/抵押反担保合同(适用于自然人).docx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily"+loanApplicationNumber;
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("抵押反担保合同(适用于自然人)");
+                fileName = loanApplication.getEnterpriseName() + "-抵押反担保合同(适用于自然人)";
+                fileNameHz = fileName + ".docx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "9":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/权利质权反担保合同(适用于法人).docx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily"+loanApplicationNumber;
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("权利质权反担保合同(适用于法人)");
+                fileName = loanApplication.getEnterpriseName() + "-权利质权反担保合同(适用于法人)";
+                fileNameHz = fileName + ".docx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "10":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/权利质权反担保合同(适用于自然人).docx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily"+loanApplicationNumber;
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("权利质权反担保合同(适用于自然人)");
+                fileName = loanApplication.getEnterpriseName() + "-权利质权反担保合同(适用于自然人)";
+                fileNameHz = fileName + ".docx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "11":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/股东会决议.docx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily"+loanApplicationNumber;
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("股东会决议");
+                fileName = loanApplication.getEnterpriseName() + "-股东会决议";
+                fileNameHz = fileName + ".docx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "12":
+
+                // 创建一个列表,用来存储要填充到Excel中的数据
+                List<Map<String,Object>> list = new ArrayList<>();
+                // 向列表中添加数据
+                list.add( Map.of("name","zou" ,"age" ,18) );
+                list.add( Map.of("name","li" ,"age" ,28) );
+                list.add( Map.of("name","wang" ,"age" ,15) );
+                list.add( Map.of("name","quan" ,"age" ,19) );
+                list.add( Map.of("name","zhao" ,"age" ,98) );
+
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("项目评审意见签批表");
+                fileName = loanApplication.getEnterpriseName() + "-项目评审意见签批表";
+                fileNameHz = fileName + ".xlsx";
+                templatePath = RuoYiConfig.getProfile() + "/mb/项目评审意见签批表.xlsx";
+                ExcelFillUtils.fillOneSheet(templatePath ,fileName ,list);
+
+                //templatePath = RuoYiConfig.getProfile() + "/mb/项目评审意见签批表.docx";
+                //fileDir = RuoYiConfig.getProfile() + "/mb/temporarily";
+                //fileName = loanApplication.getEnterpriseName() + "-项目评审意见签批表";
+                //wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".xlsx";
+                break;
+            case "13":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/担保项目合法合规表企业.docx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily";
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("担保项目合法合规表企业");
+                fileName = loanApplication.getEnterpriseName() + "-担保项目合法合规表企业";
+                if("2".equals(loanApplication.getApplicationType())){
+                    templatePath = RuoYiConfig.getProfile() + "/mb/担保项目合法合规表个人个体户.docx";
+                    fileDir = RuoYiConfig.getProfile() + "/mb/temporarily";
+                    //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("担保项目合法合规表个人个体户");
+                    fileName = loanApplication.getEnterpriseName() + "-担保项目合法合规表个人个体户";
+                }
+                fileNameHz = fileName + ".xlsx";
+                path = path + "/" + fileName + ".docx";
+                break;
+            case "14":
+                //params.put("enterpriseName", loanApplication.getEnterpriseName());
+                //path = path + "/委托担保申请书.doc";
+                templatePath = RuoYiConfig.getProfile() + "/mb/放款审批合规表企业.xlsx";
+                fileDir = RuoYiConfig.getProfile() + "/mb/temporarily";
+                //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("放款审批合规表企业");
+                fileName = loanApplication.getEnterpriseName() + "-放款审批合规表企业";
+                if("2".equals(loanApplication.getApplicationType())){
+                    templatePath = RuoYiConfig.getProfile() + "/mb/放款审批合规表个人个体户.docx";
+                    fileDir = RuoYiConfig.getProfile() + "/mb/temporarily";
+                    //fileName = FileUploadUtils.extractFilenameLoanApplicationNumberNoHzm("放款审批合规表个人个体户");
+                    fileName = loanApplication.getEnterpriseName() + "-放款审批合规表个人个体户";
+                }
+                fileNameHz = fileName + ".xlsx";
+                wordPath = WordUtil.createWord(templatePath, fileDir, fileName, params);
+                path = path + "/" + fileName + ".docx";
+                break;
+            default:
+                break;
+        }
+
+        LoanApplicationFj applicationFj = new LoanApplicationFj();
+        applicationFj.setType(type);
+        applicationFj.setLoanApplicationNumber(loanApplication.getLoanApplicationNumber());
+        applicationFj.setName(fileName);
+        String fileId = IdUtils.fastSimpleUUID();
+        redisCache.setCacheObject(fileId +"info",applicationFj,2, TimeUnit.HOURS);
+
+        map.put("fileId",fileId);
+        map.put("path",path);
+        map.put("fileName",fileNameHz);
+        return AjaxResult.success(map);
+    }
+
+    private String contrastType(String type) {
+        String fileType = "";
+        switch (type) {
+            case "1":
+                fileType = "wtdbsqs";
+                break;
+            case "2":
+                fileType = "wtdbht";
+                break;
+            case "3":
+                fileType = "dbyxh";
+                break;
+            case "4":
+                fileType = "fktzhsh";
+                break;
+            case "5":
+                fileType = "bzfdbhtfr";
+                break;
+            case "6":
+                fileType = "bzfdbhtzrr";
+                break;
+            case "7":
+                fileType = "dyfdbhtfr";
+                break;
+            case "8":
+                fileType = "dyfdbhtzrr";
+                break;
+            case "9":
+                fileType = "27";
+                break;
+            case "10":
+                fileType = "27";
+                break;
+            case "11":
+                fileType = "gdhyjy";
+                break;
+            case "12":
+                fileType = "psyjqpb";
+                break;
+            case "13":
+                fileType = "clhgb";
+                break;
+            default:
+                fileType = "fkhgb";
+                break;
+        }
+        return fileType;
     }
     }
 }
 }

+ 130 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/webOfficeImpl/ExtendCapacityServiceImpl.java

@@ -0,0 +1,130 @@
+package com.ruoyi.system.service.webOfficeImpl;
+
+
+import cn.ljserver.tool.weboffice.v3.exception.FileNotExist;
+import cn.ljserver.tool.weboffice.v3.exception.FileVersionNotExist;
+import cn.ljserver.tool.weboffice.v3.model.DownloadInfo;
+import cn.ljserver.tool.weboffice.v3.model.FileInfo;
+import cn.ljserver.tool.weboffice.v3.model.Notify;
+import cn.ljserver.tool.weboffice.v3.model.Watermark;
+import cn.ljserver.tool.weboffice.v3.service.ExtendCapacityService;
+import com.ruoyi.system.domain.webOffice.WebofficeFj;
+import com.ruoyi.system.mapper.WebofficeFjMapper;
+import com.ruoyi.system.service.webService.WebofficeFjServiceImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+/**
+ * 扩展能力实现
+ * <p>
+ * <a href="https://solution.wps.cn/docs/callback/extend.html">-详见官方文档-</a>
+ */
+@Service
+public class ExtendCapacityServiceImpl implements ExtendCapacityService {
+
+    private static final Logger log = LoggerFactory.getLogger(ExtendCapacityServiceImpl.class);
+    @Autowired
+    private WebofficeFjMapper webofficeFjMapper;
+    @Autowired
+    private WebofficeFjServiceImpl webofficeFjServiceImpl;
+
+    /**
+     * 文件重命名
+     */
+   /* @Override
+    public void renameFile(String fileId, String name) {
+        // 逻辑解释: 先查询是否有该文件对象,没有,抛出异常
+        // 有则 更新名称后,执行save动作
+        Optional.ofNullable(fileService.fetchFile(fileId))
+                .ifPresentOrElse(
+                        f -> {
+                            f.setName(name);
+                            fileService.repository().save(f);
+                        },
+                        FileNotExist::new
+                );
+    }*/
+
+    /**
+     * 获取文件版本列表
+     */
+    @Override
+    public List<FileInfo> fileVersions(String fileId, int offset, int limit) {
+
+        return Optional.ofNullable(fileId)
+                .map(webofficeFjServiceImpl::selectWebofficeFjList)
+                .map(List::stream)
+                .map(s -> StreamSupport.stream(s.spliterator(), false))
+                .map(s -> s.map(WebofficeFj::toFileInfo))
+                .map(s -> s.collect(Collectors.toList()))
+                .orElseThrow(FileNotExist::new);
+
+
+    }
+
+    /**
+     * 获取文件版本详情
+     */
+    @Override
+    public FileInfo fileVersion(String fileId, int version) {
+        // 通过文件id和版本号查询出来文件版本,然后将File对象转换为FileInfo给WPS服务
+        return Optional.ofNullable(webofficeFjServiceImpl.fetchFileVersion(fileId, version))
+                .map(WebofficeFj::toFileInfo)
+                .orElseThrow(FileNotExist::new);
+    }
+
+    /**
+     * 获取文件版本下载地址<br>
+     * 主要就是url 字段
+     */
+    @Override
+    public DownloadInfo fileVersionDownload(String fileId, int version) {
+        // 通过文件id和版本号查询出来文件版本,然后将FileUrl返回
+        return Optional.ofNullable(webofficeFjServiceImpl.fetchFileVersion(fileId, version))
+                .map(f -> DownloadInfo.builder()
+                        .url(String.format(f.getUrl()))
+                        .build())
+                .orElseThrow(FileVersionNotExist::new);
+    }
+
+    /**
+     * 获取文件水印
+     * <p>
+     * 官方文档有说明,但是没有给出具体示例,所以这里直接返回默认水印
+     * <p>
+     * 正式 应用 才生效
+     * <p>
+     * 测试 应用 会被替换为官方默认的水印
+     */
+    @Override
+    public Watermark fileWatermark(String fileId) {
+        return Watermark.builder()
+                .type(Watermark.Type.TEXT)
+                .value("this a test" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
+                .fillStyle(Watermark.FillStyle.builder().alpha(0.6).red(192).green(192).blue(192).build())
+                .rotate(-0.7853982)
+                .horizontal(50)
+                .vertical(100)
+                .font("bold 20px Serif")
+                .build();
+    }
+
+    /**
+     * 消息通知
+     * <p>
+     * 要想实现,结合官网和接口去玩吧
+     */
+    @Override
+    public void notify(Notify notify) {
+        log.info("notify: {}", notify);
+    }
+}

+ 128 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/webOfficeImpl/MultiPhaseFileStorageServiceImpl.java

@@ -0,0 +1,128 @@
+package com.ruoyi.system.service.webOfficeImpl;
+
+
+import cn.ljserver.tool.weboffice.v3.exception.FileUploadNotComplete;
+import cn.ljserver.tool.weboffice.v3.exception.InvalidArgument;
+import cn.ljserver.tool.weboffice.v3.model.DigestType;
+import cn.ljserver.tool.weboffice.v3.model.FileInfo;
+import cn.ljserver.tool.weboffice.v3.model.FileUploadMultiPhase;
+import cn.ljserver.tool.weboffice.v3.service.MultiPhaseFileStorageService;
+import cn.ljserver.tool.weboffice.v3.util.FileUtils;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.system.domain.webOffice.WebofficeFj;
+import com.ruoyi.system.service.webService.WebofficeFjServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 三阶段文件保存接口(复杂,建议用Single方式)
+ * <br>
+ * <a href="https://solution.wps.cn/docs/callback/save.html#%E4%B8%89%E9%98%B6%E6%AE%B5%E4%BF%9D%E5%AD%98">详见wps web office官网</a>
+ */
+@Service
+public class MultiPhaseFileStorageServiceImpl implements MultiPhaseFileStorageService {
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @Autowired
+    private WebofficeFjServiceImpl webofficeFjServiceImpl;
+
+    /**
+     * 准备上传阶段
+     *
+     * @param s 文件id <br>
+     *          <a href = "https://solution.wps.cn/docs/callback/save.html#准备上传阶段">-详见官方文档-</a>
+     */
+    @Override
+    public List<DigestType> uploadPrepare(String s) {
+        return Collections.singletonList(DigestType.SHA1);
+    }
+
+    /**
+     * 获取上传地址
+     *
+     * @param request 上传的文件 <br>
+     *                <a href = "https://solution.wps.cn/docs/callback/save.html#获取上传地址">-详见官方文档-</a>
+     */
+    @Override
+    public FileUploadMultiPhase.FileUploadAddress.Response uploadAddress(FileUploadMultiPhase.FileUploadAddress.Request request) {
+        // ATTENTION
+        // ConsoleController.upload() handle the upload request
+        // and store the new content of file, and create a new version of file
+        // without invoke uploadComplete method
+        // it is not good in the real world
+        // ***************************************************************
+        // ***************************************************************
+        // 这一步建议将fileName获取到后,拿到文件后缀,然后存到redis,或者其它地方
+        // ***************************************************************
+        // ***************************************************************
+        // 然后在调用 正真的 upload 方法的时候,需要确认当前的文件后缀
+        // ***************************************************************
+        // ***************************************************************
+
+        // 这里简单的放内存
+        String suffix = FileUtils.suffix(request.getName());
+        redisCache.setCacheObject(request.getFileId(), suffix, 2, TimeUnit.HOURS);
+
+        // 返回地址
+        return FileUploadMultiPhase.FileUploadAddress.Response.builder()
+                // 方法必须是PUT接口
+                .method(FileUploadMultiPhase.FileUploadAddress.Response.Method.PUT)
+                // 获取自定义上传接口方法
+                // 这里的url是自定义的,需要开发者自己实现,也就是自己的回调地址
+                .url(String.format("%s/prod-api/console/upload/" + request.getFileId(), "https://rzdb.qs163.cn", request.getFileId()))
+                .build();
+    }
+
+    /**
+     * 上传完成后,回调通知上传结果
+     *
+     * @param request 上传的文件 <br>
+     *                <a href = "https://solution.wps.cn/docs/callback/save.html#上传完成后,回调通知上传结果">-详见官方文档-</a>
+     */
+    @Override
+    public FileInfo uploadComplete(FileUploadMultiPhase.FileUploadComplete.Request request) {
+        if (request == null) throw new InvalidArgument();
+
+        // emm
+        Optional.of(request)
+                .map(FileUploadMultiPhase.FileUploadComplete.Request::getResponse)
+                .filter(r -> r.getStatus() == HttpStatus.OK.value())
+                .ifPresentOrElse(r -> {
+                }, FileUploadNotComplete::new);
+
+        // 获取当前用户,实际不是这么玩的,点进去看看
+        //SysUser user = SecurityUtils.getLoginUser().getUser();
+        // 回调中body返回的是url
+        // --------------------------------
+        // 这里不应该直接URL,而是不带domain的uri方便后续迁移等等
+        // 为了方便,就这么弄了
+        // --------------------------------
+        String url = request.getResponse().getBody();
+
+        // 获取文件 并 返回文件信息
+        WebofficeFj webofficeFj = webofficeFjServiceImpl.fetchFile(request.getFileId());
+        int version = 1;
+        LocalDateTime createTime = LocalDateTime.now();
+        if (webofficeFj != null) {
+            version = webofficeFj.getVersion();
+            createTime = webofficeFj.getCreateTime();
+        }
+        return FileInfo.builder()
+                .id(request.getFileId())
+                .name(request.getRequest().getName())
+                .version(version)
+                .size(request.getRequest().getSize())
+                .createTime(createTime)
+                .modifyTime(LocalDateTime.now())
+                .build();
+    }
+}

+ 91 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/webOfficeImpl/PreviewServiceImpl.java

@@ -0,0 +1,91 @@
+package com.ruoyi.system.service.webOfficeImpl;
+
+
+import cn.ljserver.tool.weboffice.v3.exception.FileNotExist;
+import cn.ljserver.tool.weboffice.v3.model.DownloadInfo;
+import cn.ljserver.tool.weboffice.v3.model.FileInfo;
+import cn.ljserver.tool.weboffice.v3.model.UserPermission;
+import cn.ljserver.tool.weboffice.v3.service.PreviewService;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.system.service.webService.WebofficeFjServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Optional;
+
+/**
+ * 文件预览服务必要的接口实现
+ * <br>
+ * <a href="https://solution.wps.cn/docs/callback/preview.html">-详见官方文档-</a>
+ */
+@Service
+public class PreviewServiceImpl implements PreviewService {
+
+    @Autowired
+    private WebofficeFjServiceImpl webofficeFjServiceImpl;
+
+    /**
+     * 获取文件信息
+     *
+     * @param fileId 文件id <br>
+     *               <a href="https://solution.wps.cn/docs/callback/preview.html#获取文件信息">-详见官方文档-</a>
+     */
+    @Override
+    public FileInfo fetchFileInfo(String fileId) {
+        // 解释说明下,这里在实际的设计中,需要将 文件信息 表 和历史文件版本表分开放
+        // 这里是通过文件id,获取到当前文件最新一个版本的文件信息,并返回
+        // 这里为了方便,所以设计成了一张表
+        return webofficeFjServiceImpl.fetchFile(fileId).toFileInfo();
+    }
+
+    /**
+     * 获取文件下载地址
+     *
+     * @param fileId 文件id <br>
+     *               <a href="https://solution.wps.cn/docs/callback/preview.html#获取文件下载地址">-详见官方文档-</a>
+     */
+    @Override
+    public DownloadInfo fetchDownloadInfo(String fileId) {
+        // 解释说明下,这里在实际的设计中,需要将 文件信息 表 和历史文件版本表分开放
+        // 然后这里就会获取最后一个版本的文件并返回
+        // 这里为了方便,所以设计成了一张表
+        return Optional.ofNullable(fileId)
+                .map(webofficeFjServiceImpl::selectWebofficeFjList)
+                .map(Collection::stream)
+                .flatMap(s -> s.max(Comparator.comparingInt(f -> f.getVersion())))
+                .map(f -> DownloadInfo.builder()
+                        .url(f.getUrl())
+                        .build())
+                .orElseThrow(FileNotExist::new);
+    }
+
+    /**
+     * 获取用户文件权限
+     *
+     * @param fileId 文件id <br>
+     *               <a href="https://solution.wps.cn/docs/callback/preview.html#文档用户权限">-详见官方文档-</a>
+     */
+    @Override
+    public UserPermission fetchUserPermission(String fileId) {
+        // 解释说明下,这里在实际的设计中,需要将 文件信息 表 和 用户权限 表 分开放
+        // 这里为了方便,并没有设计表,返回了所有权限到前端
+        // check file exists
+        webofficeFjServiceImpl.fetchFile(fileId);
+        // 获取user信息,这个方法点进去看看把!!!
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+        // 构建user对应的文件权限
+        return UserPermission.builder()
+                .userId(String.valueOf(user.getUserId()))
+                .read(true)
+                .update(true)
+                .rename(true)
+                .download(true)
+                .copy(true)
+                .comment(true)
+                .history(true)
+                .build();
+    }
+}

+ 73 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/webOfficeImpl/SinglePhaseFileStorageServiceImpl.java

@@ -0,0 +1,73 @@
+package com.ruoyi.system.service.webOfficeImpl;
+
+
+import cn.ljserver.tool.weboffice.v3.exception.FileNotExist;
+import cn.ljserver.tool.weboffice.v3.model.FileInfo;
+import cn.ljserver.tool.weboffice.v3.model.FileUploadSinglePhase;
+import cn.ljserver.tool.weboffice.v3.service.SinglePhaseFileStorageService;
+import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.system.domain.loan.LoanApplicationFj;
+import com.ruoyi.system.domain.webOffice.WebofficeFj;
+import com.ruoyi.system.service.webService.WebofficeFjServiceImpl;
+import lombok.SneakyThrows;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+
+/**
+ * 单阶段文件保存接口
+ * <p>
+ * <a href="https://solution.wps.cn/docs/callback/save.html#%E5%8D%95%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4">详见wps web office官网</a>
+ */
+@Service
+public class SinglePhaseFileStorageServiceImpl implements SinglePhaseFileStorageService {
+
+    @Autowired
+    private WebofficeFjServiceImpl webofficeFjServiceImpl;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    /**
+     * 上传文件
+     *
+     * @param request 上传文件请求
+     * @return 文件信息
+     * <p>
+     * <a href="https://solution.wps.cn/docs/callback/save.html#%E5%8D%95%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4">详见wps web office官网</a>
+     */
+    @SneakyThrows
+    @Override
+    public FileInfo uploadFile(FileUploadSinglePhase.Request request) {
+        // 获取用户信息 -> 这个方法点进去看看 ??!!
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+
+        //从redis取文件信息
+        LoanApplicationFj cacheObject = redisCache.getCacheObject(request.getFileId() + "info");
+        if (cacheObject == null) {
+            throw new FileNotExist();
+        }
+        // 上传文件路径
+        String filePath = RuoYiConfig.getUploadPath();
+        // 上传并返回新文件名称
+        String fileName = FileUploadUtils.uploadLoanApplicationNumber(filePath, request.getFile(), cacheObject.getLoanApplicationNumber(), request.getName());
+        //String url = serverConfig.getUrl() + fileName;
+        //将文件存入在线编辑预存表
+        WebofficeFj webofficeFj = webofficeFjServiceImpl.fetchFile(request.getFileId());
+        webofficeFj.setWebofficeId(0l);
+        webofficeFj.setVersion(webofficeFj.getVersion() + 1);
+        webofficeFj.setCreateTime(LocalDateTime.now());
+        webofficeFj.setUpdateTime(LocalDateTime.now());
+        webofficeFj.setSize(Long.valueOf(request.getSize()));
+        webofficeFj.setName(request.getName());
+        webofficeFj.setCreateBy(user.getNickName());
+        webofficeFjServiceImpl.insertWebofficeFj(webofficeFj);
+        // 返回文件信息
+        return webofficeFj.toFileInfo();
+    }
+}

+ 67 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/webService/IWebofficeFjService.java

@@ -0,0 +1,67 @@
+package com.ruoyi.system.service.webService;
+
+import com.ruoyi.system.domain.webOffice.WebofficeFj;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * webOffice附件记录Service接口
+ * 
+ * @author boman
+ * @date 2024-05-20
+ */
+public interface IWebofficeFjService 
+{
+    /**
+     * 查询webOffice附件记录
+     * 
+     * @param webofficeId webOffice附件记录主键
+     * @return webOffice附件记录
+     */
+    public WebofficeFj selectWebofficeFjByWebofficeId(Long webofficeId);
+
+    /**
+     * 查询webOffice附件记录列表
+     * 
+     * @param webofficeFj webOffice附件记录
+     * @return webOffice附件记录集合
+     */
+    public List<WebofficeFj> selectWebofficeFjList(WebofficeFj webofficeFj);
+
+    /**
+     * 新增webOffice附件记录
+     * 
+     * @param webofficeFj webOffice附件记录
+     * @return 结果
+     */
+    public int insertWebofficeFj(WebofficeFj webofficeFj);
+
+    /**
+     * 修改webOffice附件记录
+     * 
+     * @param webofficeFj webOffice附件记录
+     * @return 结果
+     */
+    public int updateWebofficeFj(WebofficeFj webofficeFj);
+
+    /**
+     * 批量删除webOffice附件记录
+     * 
+     * @param webofficeIds 需要删除的webOffice附件记录主键集合
+     * @return 结果
+     */
+    public int deleteWebofficeFjByWebofficeIds(Long[] webofficeIds);
+
+    /**
+     * 删除webOffice附件记录信息
+     * 
+     * @param webofficeId webOffice附件记录主键
+     * @return 结果
+     */
+    public int deleteWebofficeFjByWebofficeId(Long webofficeId);
+
+    String upload(MultipartFile file);
+
+    String upload(String fileId, byte[] content, String suffix);
+}

+ 90 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/webService/QnFileService.java

@@ -0,0 +1,90 @@
+package com.ruoyi.system.service.webService;
+
+import cn.ljserver.tool.weboffice.v3.exception.FileUploadNotComplete;
+import cn.ljserver.tool.weboffice.v3.util.FileUtils;
+import com.qiniu.storage.Configuration;
+import com.qiniu.storage.Region;
+import com.qiniu.storage.UploadManager;
+import com.qiniu.util.Auth;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+/**
+ * 七牛文件上传
+ */
+public class QnFileService {
+
+    // 创建上传token
+    static final String accessKey = "xxxxxxxxx";
+    static final String secretKey = "xxxxxxxxxxxxxxx";
+    static final String bucket = "xxxxxx";
+    // 注意下面的配置的 两个 “/” 别弄错了
+    //文件存放地址
+    static final String directory = "xxxx/";
+
+    // 上传文件
+    public static String upload(MultipartFile file) {
+        if (file.isEmpty()) {
+            throw new RuntimeException("文件是空的!");
+        }
+
+        // 文件名称
+        String originalFilename = file.getOriginalFilename();
+
+        // 构造文件目录和文件名
+        assert originalFilename != null;
+        //String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
+        String fileKey = directory + originalFilename;
+
+        // 上传文件
+        try {
+            uploadManager().put(file.getInputStream(), fileKey, upToken(), null, null);
+        } catch (IOException e) {
+            throw new FileUploadNotComplete();
+        }
+
+        // 返回文件url
+        // --------------------------------
+        // 这里不应该直接URL,而是不带domain的uri方便后续迁移等等
+        // 为了方便,就这么弄了
+        // --------------------------------
+        return fileKey;
+    }
+
+    // 上传文件
+    public static String upload(byte[] content, String suffix) {
+        if (content.length == 0) {
+            throw new RuntimeException("文件是空的!");
+        }
+
+        // 构造文件目录和文件名
+        String fileKey = directory + FileUtils.uuid() + "." + suffix;
+
+        // 上传文件
+        try {
+            uploadManager().put(content, fileKey, upToken());
+        } catch (IOException e) {
+            throw new FileUploadNotComplete();
+        }
+
+        // 返回文件url
+        // --------------------------------
+        // 这里不应该直接URL,而是不带domain的uri方便后续迁移等等
+        // 为了方便,就这么弄了
+        // --------------------------------
+        return fileKey;
+    }
+
+    private static String upToken(){
+        Auth auth = Auth.create(accessKey, secretKey);
+        return auth.uploadToken(bucket);
+    }
+
+    private static UploadManager uploadManager(){
+        // 设置上传配置,Region要与存储空间所属的存储区域保持一致
+        Configuration cfg = new Configuration(Region.createWithRegionId("z2"));
+        // 创建上传管理器
+        return new UploadManager(cfg);
+    }
+}

+ 197 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/webService/WebofficeFjServiceImpl.java

@@ -0,0 +1,197 @@
+package com.ruoyi.system.service.webService;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import cn.ljserver.tool.weboffice.v3.exception.FileNotExist;
+import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.system.domain.loan.LoanApplicationFj;
+import com.ruoyi.system.domain.webOffice.WebofficeFj;
+import com.ruoyi.system.mapper.WebofficeFjMapper;
+import lombok.SneakyThrows;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * webOffice附件记录Service业务层处理
+ * 
+ * @author boman
+ * @date 2024-05-20
+ */
+@Service
+public class WebofficeFjServiceImpl implements IWebofficeFjService 
+{
+    @Autowired
+    private WebofficeFjMapper webofficeFjMapper;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    /**
+     * 查询webOffice附件记录
+     * 
+     * @param webofficeId webOffice附件记录主键
+     * @return webOffice附件记录
+     */
+    @Override
+    public WebofficeFj selectWebofficeFjByWebofficeId(Long webofficeId)
+    {
+        return webofficeFjMapper.selectWebofficeFjByWebofficeId(webofficeId);
+    }
+
+    /**
+     * 查询webOffice附件记录列表
+     * 
+     * @param webofficeFj webOffice附件记录
+     * @return webOffice附件记录
+     */
+    @Override
+    public List<WebofficeFj> selectWebofficeFjList(WebofficeFj webofficeFj)
+    {
+        return webofficeFjMapper.selectWebofficeFjList(webofficeFj);
+    }
+
+    /**
+     * 新增webOffice附件记录
+     * 
+     * @param webofficeFj webOffice附件记录
+     * @return 结果
+     */
+    @Override
+    public int insertWebofficeFj(WebofficeFj webofficeFj)
+    {
+        webofficeFj.setCreateTime(LocalDateTime.now());
+        return webofficeFjMapper.insertWebofficeFj(webofficeFj);
+    }
+
+    /**
+     * 修改webOffice附件记录
+     * 
+     * @param webofficeFj webOffice附件记录
+     * @return 结果
+     */
+    @Override
+    public int updateWebofficeFj(WebofficeFj webofficeFj)
+    {
+        webofficeFj.setUpdateTime(LocalDateTime.now());
+        return webofficeFjMapper.updateWebofficeFj(webofficeFj);
+    }
+
+    /**
+     * 批量删除webOffice附件记录
+     * 
+     * @param webofficeIds 需要删除的webOffice附件记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteWebofficeFjByWebofficeIds(Long[] webofficeIds)
+    {
+        return webofficeFjMapper.deleteWebofficeFjByWebofficeIds(webofficeIds);
+    }
+
+    /**
+     * 删除webOffice附件记录信息
+     * 
+     * @param webofficeId webOffice附件记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteWebofficeFjByWebofficeId(Long webofficeId)
+    {
+        return webofficeFjMapper.deleteWebofficeFjByWebofficeId(webofficeId);
+    }
+
+    @Override
+    public String upload(MultipartFile file) {
+        return null;
+    }
+
+    @SneakyThrows
+    @Override
+    public String upload(String fileId, byte[] content, String suffix) {
+
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+        //从redis取文件信息
+        LoanApplicationFj cacheObject = redisCache.getCacheObject(fileId + "info");
+        if (cacheObject == null) {
+            throw new FileNotExist();
+        }
+
+        MultipartFile file = new MockMultipartFile(cacheObject.getName(), cacheObject.getName(), suffix, content);
+        // 上传文件路径
+        String filePath = RuoYiConfig.getUploadPath();
+        // 上传并返回新文件名称
+        String fileName = FileUploadUtils.uploadLoanApplicationNumber(filePath, file, cacheObject.getLoanApplicationNumber(), file.getOriginalFilename());
+        //String url = serverConfig.getUrl() + fileName;
+        //将文件存入在线编辑预存表
+        WebofficeFj webofficeFj = fetchFile(fileId);
+        webofficeFj.setWebofficeId(0l);
+        webofficeFj.setVersion(webofficeFj.getVersion() + 1);
+        webofficeFj.setCreateTime(LocalDateTime.now());
+        webofficeFj.setUpdateTime(LocalDateTime.now());
+        webofficeFj.setSize(Long.valueOf(file.getSize()));
+        webofficeFj.setName(file.getName());
+        webofficeFj.setCreateBy(user.getNickName());
+        webofficeFjMapper.insertWebofficeFj(webofficeFj);
+        return fileName;
+    }
+
+    public List<WebofficeFj> selectWebofficeFjList(String fileId)
+    {
+        if(!DateUtils.isNumeric(fileId)){
+            fileId = "0";
+        }
+        WebofficeFj webofficeFj = new WebofficeFj();
+        webofficeFj.setFjId(Long.valueOf(fileId));
+        return webofficeFjMapper.selectWebofficeFjList(webofficeFj);
+    }
+
+    /***
+     * 获取单个版本详情
+     * @param fileId
+     * @return
+     */
+    public WebofficeFj fetchFileVersion(String fileId, int version)
+    {
+        if(!DateUtils.isNumeric(fileId)){
+            fileId = "0";
+        }
+        WebofficeFj webofficeFj = new WebofficeFj();
+        webofficeFj.setFjId(Long.valueOf(fileId));
+        webofficeFj.setVersion(version);
+        List<WebofficeFj> webofficeFjs = webofficeFjMapper.selectWebofficeFjList(webofficeFj);
+        if(webofficeFjs!=null && webofficeFjs.size()>0){
+            return webofficeFjs.get(0);
+        }else {
+            return new WebofficeFj();
+        }
+
+    }
+
+    /***
+     * 查询最新版本的文件
+     * @param fileId
+     * @return
+     */
+    public WebofficeFj fetchFile(String fileId)
+    {
+        if(!DateUtils.isNumeric(fileId)){
+            fileId = "0";
+        }
+        WebofficeFj webofficeFj = new WebofficeFj();
+        webofficeFj.setFjId(Long.valueOf(fileId));
+        List<WebofficeFj> webofficeFjs = webofficeFjMapper.selectWebofficeFjList(webofficeFj);
+        if(webofficeFjs!=null && webofficeFjs.size()>0){
+            return webofficeFjs.get(0);
+        }else {
+            return new WebofficeFj();
+        }
+    }
+}

+ 103 - 0
ruoyi-system/src/main/resources/mapper/system/UpdateAppMapper.xml

@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.UpdateAppMapper">
+    
+    <resultMap type="UpdateApp" id="UpdateAppResult">
+        <result property="id"    column="id"    />
+        <result property="model"    column="model"    />
+        <result property="name"    column="name"    />
+        <result property="code"    column="code"    />
+        <result property="description"    column="description"    />
+        <result property="path"    column="path"    />
+        <result property="isDel"    column="is_del"    />
+        <result property="createTime"    column="create_time"    />
+    </resultMap>
+
+    <sql id="selectUpdateAppVo">
+        select id, model, name, code, description, path, is_del, create_time from update_app
+    </sql>
+
+    <select id="selectUpdateAppList" parameterType="UpdateApp" resultMap="UpdateAppResult">
+        <include refid="selectUpdateAppVo"/>
+        <where>  
+            <if test="model != null  and model != ''"> and model = #{model}</if>
+            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
+            <if test="code != null  and code != ''"> and code = #{code}</if>
+            <if test="description != null  and description != ''"> and description = #{description}</if>
+            <if test="path != null  and path != ''"> and path = #{path}</if>
+            <if test="isDel != null  and isDel != ''"> and is_del = #{isDel}</if>
+        </where>
+    </select>
+    
+    <select id="selectUpdateAppById" parameterType="Long" resultMap="UpdateAppResult">
+        <include refid="selectUpdateAppVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertUpdateApp" parameterType="UpdateApp">
+        insert into update_app
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="model != null">model,</if>
+            <if test="name != null">name,</if>
+            <if test="code != null">code,</if>
+            <if test="description != null">description,</if>
+            <if test="path != null">path,</if>
+            <if test="isDel != null">is_del,</if>
+            <if test="createTime != null">create_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">#{id},</if>
+            <if test="model != null">#{model},</if>
+            <if test="name != null">#{name},</if>
+            <if test="code != null">#{code},</if>
+            <if test="description != null">#{description},</if>
+            <if test="path != null">#{path},</if>
+            <if test="isDel != null">#{isDel},</if>
+            <if test="createTime != null">#{createTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateUpdateApp" parameterType="UpdateApp">
+        update update_app
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="model != null">model = #{model},</if>
+            <if test="name != null">name = #{name},</if>
+            <if test="code != null">code = #{code},</if>
+            <if test="description != null">description = #{description},</if>
+            <if test="path != null">path = #{path},</if>
+            <if test="isDel != null">is_del = #{isDel},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteUpdateAppById" parameterType="Long">
+        delete from update_app where id = #{id}
+    </delete>
+
+    <delete id="deleteUpdateAppByIds" parameterType="String">
+        delete from update_app where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+    <select id="getInfo" parameterType="UpdateApp" resultMap="UpdateAppResult">
+        <include refid="selectUpdateAppVo"/>
+        <where>
+            <if test="model != null  and model != ''"> and model = #{model}</if>
+            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
+            <if test="code != null  and code != ''"> and code = #{code}</if>
+            <if test="description != null  and description != ''"> and description = #{description}</if>
+            <if test="path != null  and path != ''"> and path = #{path}</if>
+            <if test="isDel != null  and isDel != ''"> and is_del = #{isDel}</if>
+        </where>
+    </select>
+    <update id="updateUpdateAppAll" parameterType="UpdateApp">
+        update update_app set is_del = #{isDel}
+        where model = #{model}
+    </update>
+</mapper>

+ 97 - 0
ruoyi-system/src/main/resources/mapper/system/WebofficeFjMapper.xml

@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.WebofficeFjMapper">
+    
+    <resultMap type="WebofficeFj" id="WebofficeFjResult">
+        <result property="webofficeId"    column="webOffice_id"    />
+        <result property="fjId"    column="fj_id"    />
+        <result property="version"    column="version"    />
+        <result property="size"    column="size"    />
+        <result property="name"    column="name"    />
+        <result property="url"    column="url"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="remark"    column="remark"    />
+    </resultMap>
+
+    <sql id="selectWebofficeFjVo">
+        select webOffice_id, fj_id, version, size, name, url, create_by, create_time, update_by, update_time, remark from webOffice_fj
+    </sql>
+
+    <select id="selectWebofficeFjList" parameterType="WebofficeFj" resultMap="WebofficeFjResult">
+        <include refid="selectWebofficeFjVo"/>
+        <where>  
+            <if test="fjId != null "> and fj_id = #{fjId}</if>
+            <if test="version != null  and version != ''"> and version = #{version}</if>
+            <if test="size != null  and size != ''"> and size = #{size}</if>
+            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
+            <if test="url != null  and url != ''"> and url = #{url}</if>
+        </where>
+        order by create_time desc
+    </select>
+    
+    <select id="selectWebofficeFjByWebofficeId" parameterType="Long" resultMap="WebofficeFjResult">
+        <include refid="selectWebofficeFjVo"/>
+        where webOffice_id = #{webofficeId}
+    </select>
+        
+    <insert id="insertWebofficeFj" parameterType="WebofficeFj" useGeneratedKeys="true" keyProperty="webofficeId">
+        insert into webOffice_fj
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="fjId != null">fj_id,</if>
+            <if test="version != null">version,</if>
+            <if test="size != null">size,</if>
+            <if test="name != null and name != ''">name,</if>
+            <if test="url != null">url,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="remark != null">remark,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="fjId != null">#{fjId},</if>
+            <if test="version != null">#{version},</if>
+            <if test="size != null">#{size},</if>
+            <if test="name != null and name != ''">#{name},</if>
+            <if test="url != null">#{url},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="remark != null">#{remark},</if>
+         </trim>
+    </insert>
+
+    <update id="updateWebofficeFj" parameterType="WebofficeFj">
+        update webOffice_fj
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="fjId != null">fj_id = #{fjId},</if>
+            <if test="version != null">version = #{version},</if>
+            <if test="size != null">size = #{size},</if>
+            <if test="name != null and name != ''">name = #{name},</if>
+            <if test="url != null">url = #{url},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="remark != null">remark = #{remark},</if>
+        </trim>
+        where webOffice_id = #{webofficeId}
+    </update>
+
+    <delete id="deleteWebofficeFjByWebofficeId" parameterType="Long">
+        delete from webOffice_fj where webOffice_id = #{webofficeId}
+    </delete>
+
+    <delete id="deleteWebofficeFjByWebofficeIds" parameterType="String">
+        delete from webOffice_fj where webOffice_id in 
+        <foreach item="webofficeId" collection="array" open="(" separator="," close=")">
+            #{webofficeId}
+        </foreach>
+    </delete>
+</mapper>