package com.artfess.file.controller;

import com.artfess.base.annotation.ApiGroup;
import com.artfess.base.constants.ApiGroupConsts;
import com.artfess.base.context.BaseContext;
import com.artfess.base.controller.BaseController;
import com.artfess.base.enums.ResponseErrorEnums;
import com.artfess.base.exception.BaseException;
import com.artfess.base.exception.NotFoundException;
import com.artfess.base.feign.UCFeignService;
import com.artfess.base.feign.WorkflowFeignService;
import com.artfess.base.groovy.GroovyScriptEngine;
import com.artfess.base.handler.MultiTenantHandler;
import com.artfess.base.handler.MultiTenantIgnoreResult;
import com.artfess.base.model.CommonResult;
import com.artfess.base.query.PageList;
import com.artfess.base.query.QueryField;
import com.artfess.base.query.QueryFilter;
import com.artfess.base.query.QueryOP;
import com.artfess.base.util.Base64;
import com.artfess.base.util.BeanUtils;
import com.artfess.base.util.FileUtil;
import com.artfess.base.util.JsonUtil;
import com.artfess.base.util.StringUtil;
import com.artfess.base.util.UniqueIdUtil;
import com.artfess.base.util.time.DateUtil;
import com.artfess.file.config.UploadResult;
import com.artfess.file.extend.DetailTablePolicy;
import com.artfess.file.extend.InstanceFlowOpinions;
import com.artfess.file.model.DefaultFile;
import com.artfess.file.model.FileZone;
import com.artfess.file.persistence.manager.CatalogManager;
import com.artfess.file.persistence.manager.FileManager;
import com.artfess.file.persistence.manager.FileZoneManager;
import com.artfess.file.util.AppFileUtil;
import com.artfess.file.util.HtmlUtil;
import com.artfess.file.util.SignaturePictureRenderPolicy;
import com.artfess.file.util.UploadM3u8;
import com.artfess.file.vo.FileReqVo;
import com.artfess.file.vo.MultipartCompleteParam;
import com.artfess.file.vo.MultipartInitParam;
import com.artfess.file.vo.MultipartInitRespVo;
import com.artfess.sysConfig.util.SysPropertyUtil;
import com.artfess.uc.api.model.IUser;
import com.artfess.uc.api.service.IUserService;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.Configure.ELMode;
import com.deepoove.poi.data.DocxRenderData;
import com.deepoove.poi.template.MetaTemplate;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.activation.MimetypesFileTypeMap;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;

@RestController
@RequestMapping("/file/v1")
@Api(tags = "附件管理")
@ApiGroup(group = {ApiGroupConsts.GROUP_SYSTEM})
@SuppressWarnings({"unchecked", "rawtypes"})
public class FileController extends BaseController<FileManager, DefaultFile> {
    private Logger logger = LoggerFactory.getLogger(FileController.class);
    @Resource
    FileManager fileManager;
    @Resource
    IUserService userService;

    @Resource
    CatalogManager catalogManager;
    @Resource
    FileZoneManager fileZonedManager;
    @Resource
    BaseContext baseContext;
    @Resource
    WorkflowFeignService workflowFeignService;
    @Resource
    GroovyScriptEngine groovyScriptEngine;
    @Resource
    UCFeignService ucFeignService;

    @RequestMapping(value = "list", method = RequestMethod.POST, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "附件列表(分页条件查询)数据", httpMethod = "POST", notes = "附件列表(分页条件查询)数据")
    public PageList<DefaultFile> list(
            @ApiParam(name = "queryFilter", value = "通用查询对象") @RequestBody QueryFilter queryFilter) {
        List<QueryField> listQueryField = queryFilter.getQuerys();
        List<String> listId = new ArrayList<>();
        QueryField query = new QueryField();
        String xbTypeId = "";
        for (QueryField queryField : listQueryField) {
            if ("xbTypeId".equals(queryField.getProperty())) {
                xbTypeId = queryField.getValue() + "";
                query.setProperty(queryField.getProperty());
                query.setRelation(queryField.getRelation());
                listQueryField.remove(queryField);
                break;
            }
        }
        if (StringUtil.isNotEmpty(xbTypeId)) {
            List<String> ids = catalogManager.getDepartmentList(xbTypeId, listId);
            ids.add(xbTypeId);
            query.setValue(ids);
            query.setOperation(QueryOP.IN);
            listQueryField.add(query);
            queryFilter.setQuerys(listQueryField);
        }
        return fileManager.query(queryFilter);
    }

    @PostMapping(value = "getFileInfo", produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "根据附件类型和业务id获得附件对象", notes = "获得附件对象")
    public DefaultFile getFileInfo(@RequestBody FileReqVo fileReqVo) {
        DefaultFile file = fileManager.getFileInfo(fileReqVo);
        return file;
    }

    @RequestMapping(value = "fileGet", method = RequestMethod.GET, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "获得附件对象", httpMethod = "GET", notes = "获得附件对象")
    public DefaultFile edit(@ApiParam(name = "id", value = "主键") @RequestParam String id) {
        DefaultFile file = null;
        if (StringUtil.isNotEmpty(id)) {
            file = fileManager.get(id);
        }
        return file;
    }


    @RequestMapping(value = "remove", method = RequestMethod.POST, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "批量删除附件", httpMethod = "POST", notes = "批量删除附件")
    public CommonResult remove(@ApiParam(name = "ids", value = "附件ID!多个ID用,分割") @RequestBody String ids)
            throws Exception {
        String[] aryIds = null;
        if (StringUtil.isNotEmpty(ids)) {
            aryIds = ids.split(",");
        }
        fileManager.delSysFileByIds(aryIds);
        return new CommonResult(true, "删除附件成功", null);
    }

    @RequestMapping(value = "uploadFileForConfig", method = RequestMethod.POST, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "批量附件上传操作", httpMethod = "POST", notes = "批量附件上传操作")
    public UploadResult uploadForConfig(@ApiParam(name = "bizCode", value = "附件上传编码", required = true) @RequestParam String bizCode,
                                        @ApiParam(name = "bizId", value = "业务ID", required = false) @RequestParam String bizId,
                                        @ApiParam(name = "bizType", value = "业务分类，业务内部的类别", required = false) @RequestParam String bizType,
                                        @ApiParam(name = "files", value = "上传的文件流") @RequestBody List<MultipartFile> files) throws Exception {
        DefaultFile file = new DefaultFile();
        String account = baseContext.getCurrentUserAccout();
        return fileManager.UploadFileForConfig(file, files, bizCode, bizId, bizType, userService.getUserByAccount(account));
    }


    @RequestMapping(value = "fileUpload", method = RequestMethod.POST, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "附件上传操作", httpMethod = "POST", notes = "附件上传操作，minio参数：file: {\"storeType\":\"minio\"}")
    public UploadResult fileUpload(@ApiParam(name = "params", value = "格式限定") @RequestParam Map<String, Object> params,
                                   @ApiParam(name = "files", value = "上传的文件流") @RequestBody List<MultipartFile> files,
                                   @ApiParam(name = "flowKey", value = "流程key") @RequestParam Optional<String> flowKey) throws Exception {
        DefaultFile file = new DefaultFile();
        if (params.containsKey("file")) {
            file = JsonUtil.toBean(params.getOrDefault("file", "{}").toString(), DefaultFile.class);
        }
        String account = baseContext.getCurrentUserAccout();
        return fileManager.uploadFile(file, files, params.getOrDefault("fileFormates", "").toString(),
                userService.getUserByAccount(account), flowKey.orElse(""));
    }

    @RequestMapping(value = "upload", method = RequestMethod.POST, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "附件上传操作", httpMethod = "POST", notes = "附件上传操作")
    public UploadResult upload(MultipartHttpServletRequest request,
                               @ApiParam(name = "fileFormates", value = "格式要求,多个用逗号隔开") @RequestParam Optional<String> fileFormates,
                               @ApiParam(name = "flowKey", value = "流程key") @RequestParam Optional<String> flowKey,
                               @ApiParam(name = "fileId", value = "文件id") @RequestParam(required = false) String fileId) throws Exception {
        IUser user = null;
        String account = baseContext.getCurrentUserAccout();
        if (StringUtil.isNotEmpty(account)) {
            user = userService.getUserByAccount(account);
        }
        Map<String, MultipartFile> fileMaps = request.getFileMap();
        Iterator<MultipartFile> it = fileMaps.values().iterator();
        List<MultipartFile> files = new ArrayList<MultipartFile>();
        while (it.hasNext()) {
            files.add(it.next());
        }
        DefaultFile file = new DefaultFile();
        if (StringUtil.isNotEmpty(fileId)) {
            file = fileManager.get(fileId);
            //设文件名称为null，保存时不检查名称
            file.setFileName(null);
        }
        return fileManager.uploadFile(file, files, fileFormates.orElse(""), user, flowKey.orElse(""));
    }

    @RequestMapping(value = "downloadFile", method = RequestMethod.GET, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "附件下载", httpMethod = "GET", notes = "附件下载")
    public void downloadFile(HttpServletRequest request, HttpServletResponse response,
                             @ApiParam(name = "fileId", value = "附件ID") @RequestParam String fileId) throws Exception {
        // response.reset();
        response.setContentType("APPLICATION/OCTET-STREAM");
        DefaultFile file = null;
        try (MultiTenantIgnoreResult setThreadLocalIgnore = MultiTenantHandler.setThreadLocalIgnore()) {
            file = fileManager.get(fileId);
        }
        if (BeanUtils.isEmpty(file)) {
            throw new NotFoundException(String.format("未找到fileId为: %s 的文件", fileId));
        }
        String fileName = file.getFileName() + "." + file.getExtensionName();
        String filedisplay = URLEncoder.encode(fileName, "utf-8");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.addHeader("Content-Disposition", "attachment;filename=" + filedisplay);
        response.addHeader("filename", filedisplay);
        response.setHeader("Access-Control-Allow-Origin", "*");
        String type = new MimetypesFileTypeMap().getContentType(new File(file.getFilePath()));
        response.setContentType(type);
        fileManager.downloadFile(fileId, response.getOutputStream());
    }

    @RequestMapping(value = "getLogoFile", method = RequestMethod.GET, produces = {
            "application/json; charset=utf-8"})
    @ApiOperation(value = "获取租户logo文件", httpMethod = "GET", notes = "根据租户id获取租户logo文件")
    public void getLogoFile(HttpServletRequest request, HttpServletResponse response,
                            @ApiParam(name = "tenantId", value = "租户id") @RequestParam String tenantId,
                            @ApiParam(name = "logoType", value = "logo类型：manage(管理端)、front(应用端)") @RequestParam String logoType) throws Exception {
        response.setContentType("APPLICATION/OCTET-STREAM");
        DefaultFile file = null;
        JsonNode tenantNode = ucFeignService.getTenantById(tenantId);
        String logoTypeField = "manageLogo";
        if ("front".equals(logoType)) {
            logoTypeField = "frontLogo";
        }
        ArrayNode logoNode = (ArrayNode) JsonUtil.toJsonNode(tenantNode.get(logoTypeField).asText());
        String fileId = logoNode.get(0).get("id").asText();
        file = fileManager.get(fileId);
        if (BeanUtils.isEmpty(file)) {
            throw new NotFoundException(String.format("未找到fileId为: %s 的文件", fileId));
        }
        String fileName = file.getFileName() + "." + file.getExtensionName();
        String filedisplay = URLEncoder.encode(fileName, "utf-8");
        response.addHeader("Content-Disposition", "attachment;filename=" + filedisplay);
        response.addHeader("filename", filedisplay);
        response.setHeader("Access-Control-Allow-Origin", "*");
        String type = new MimetypesFileTypeMap().getContentType(new File(file.getFilePath()));
        response.setContentType(type);
        fileManager.downloadFile(fileId, response.getOutputStream());
    }

    @RequestMapping(value = "getFileType", method = RequestMethod.POST, produces = {
            "application/json; charset=utf-8"})
    @ApiOperation(value = "根据附件id取得附件类型。", httpMethod = "POST", notes = "根据附件id取得附件类型。")
    public String getFileType(@ApiParam(name = "fileId", value = "附件id") @RequestBody String fileId)
            throws IOException {
        DefaultFile DefaultFile = null;
        String type = "doc";
        if (StringUtil.isNotEmpty(fileId)) {
            DefaultFile = fileManager.get(fileId);
            type = DefaultFile.getExtensionName().toLowerCase();
        }
        return type;
    }

    @RequestMapping(value = "setXbTypeId", method = RequestMethod.POST, produces = {
            "application/json; charset=utf-8"})
    @ApiOperation(value = "修改附件分类。", httpMethod = "POST", notes = "修改附件分类。")
    public CommonResult setXbTypeId(@ApiParam(name = "fileId", value = "附件id") @RequestBody List<String> fileId,
                                    @ApiParam(name = "xbTypeId", value = "分类ID") @RequestParam String xbTypeId,
                                    @ApiParam(name = "type", value = "分类名称") @RequestParam String type) throws Exception {
        fileManager.setXbTypeId(fileId, xbTypeId, type);
        return new CommonResult(true, "设置附件分类成功", null);
    }

    @RequestMapping(value = "updateFileExtraProp", method = RequestMethod.POST, produces = {
            "application/json; charset=utf-8"})
    @ApiOperation(value = "更新附件的属性成功", httpMethod = "POST", notes = "更新附件的属性成功（包含扩展属性、流程实例ID、节点名称、流程标题、附件来源、所属分类）")
    public CommonResult updateFileExtraProp(
            @ApiParam(name = "files", value = "附件列表") @RequestBody List<DefaultFile> files) throws Exception {
        fileManager.updateFileExtraProp(files);
        return new CommonResult(true, "更新附件的属性成功", null);
    }

    @RequestMapping(value = "preview", method = RequestMethod.GET, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "附件预览", httpMethod = "GET", notes = "附件预览")
    public void preview(HttpServletRequest request, HttpServletResponse response,
                        @ApiParam(name = "fileId", value = "附件ID") @RequestParam String fileId) throws Exception {
        // response.reset();
        try (MultiTenantIgnoreResult setThreadLocalIgnore = MultiTenantHandler.setThreadLocalIgnore()) {
            response.setContentType("text/html; charset=UTF-8");
            response.setContentType("image/jpeg");

            DefaultFile file = null;
            file = fileManager.get(fileId);
            if (BeanUtils.isEmpty(file)) {
                return;
            }
            String fileName = file.getFileName() + "." + file.getExtensionName();
            String filedisplay = fileName;
            String agent = request.getHeader("USER-AGENT");
            if (agent != null && agent.indexOf("MSIE") == -1 && agent.indexOf("Trident") == -1) {
                filedisplay = "=?UTF-8?B?" + (new String(Base64.getBase64(filedisplay))) + "?=";
            } else {
                filedisplay = URLEncoder.encode(filedisplay, "utf-8");
            }
            response.addHeader("filename", filedisplay);
            response.setHeader("Access-Control-Allow-Origin", "*");
            fileManager.downloadFile(fileId, response.getOutputStream());
        } catch (Exception e) {
            logger.error("预览附件失败");
        }
    }

    @RequestMapping(value = "wordPrint", method = RequestMethod.POST, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "word模板打印", httpMethod = "POST", notes = "word模板打印")
    public String wordPrint(@ApiParam(name = "objectNode", value = "Json对象") @RequestBody ObjectNode objectNode)
            throws Exception {
        String boData = objectNode.get("boData").toString();
        String fileId = objectNode.get("fileId").asText();
        String subject = objectNode.get("subject").asText();
        ArrayNode flowOpinions = (ArrayNode) objectNode.get("flowOpinions");
        String scriptStr = objectNode.get("scriptStr").asText();
        DefaultFile defaultFile = fileManager.get(fileId);
        DefaultFile model = new DefaultFile();
        model.setId(UniqueIdUtil.getSuid());
        String outputFilePath = AppFileUtil
                .createFilePath("print" + File.separator
                                + baseContext.getCurrentUserAccout(),
                        model.getId() + "." + defaultFile.getExtensionName());
        String saveOutputFilePath = this.printFile(boData, defaultFile, outputFilePath, flowOpinions, scriptStr, model.getId());
        // 新增打印记录
        try {
            if (flowOpinions.size() > 0) {
                String defId = objectNode.get("defId").asText();
                String nodeId = objectNode.get("nodeId").asText();
                ObjectNode opinion = (ObjectNode) flowOpinions.get(0);
                ObjectNode record = JsonUtil.getMapper().createObjectNode();
                record.put("procInstId", opinion.get("procInstId").asText());// procInstId
                record.put("nodeId", nodeId);
                record.put("procDefId", defId);
                record.put("formKey", objectNode.get("formKey").asText());
                record.put("templateId", fileId);
                record.put("templateName", defaultFile.getFileName());
                record.put("fileId", model.getId());
                workflowFeignService.addPrintLog(record);
            }
        } catch (Exception e) {
            System.out.println("新增打印记录失败：" + e.getMessage());
        }
        model.setFileName(subject);
        model.setStoreType(AppFileUtil.getSaveType(""));
        model.setFilePath(outputFilePath.replace(AppFileUtil.getAttachPath() + File.separator, ""));
        model.setExtensionName(defaultFile.getExtensionName());
        model.setIsDel((short) 0);
        model.setCreateTime(DateUtil.getCurrentDate());
        if (!model.getStoreType().equals(DefaultFile.SAVE_TYPE_FOLDER)) {
            fileManager.uploadFile(model, new FileInputStream(saveOutputFilePath));

        } else {
            fileManager.create(model);
        }
        return model.getId();
    }

    private String printFile(String boData, DefaultFile defaultFile, String outputFilePath, ArrayNode flowOpinions,
                             String scriptStr, String fileId) throws Exception {
        Map boMap = new HashMap();
        Map<String, Object> twiceMap = new HashMap<String, Object>();

        AtomicBoolean isSubHtml = new AtomicBoolean(false);
        // 配置
        Configure config = Configure.newBuilder().setElMode(ELMode.SPEL_MODE).setValidErrorHandler(new Configure.ClearHandler()).build();
        JsonUtil.toMap(boData).values().forEach(item -> {
            ((Map) item).forEach((key, val) -> {
                Object printObj = val;//模板支持Sping表达式之后1对1子表套打有问题
                if (key.toString().startsWith("sub_")) {
                    if (HtmlUtil.isHtml(printObj.toString())) {
                        isSubHtml.set(true);
                    }
                    if (val instanceof List && ((List) val).size() == 1) {
                        Map subMapKey = (Map) ((List) val).get(0);
                        printObj = subMapKey;
                    }
                    config.customPolicy(key.toString(), new DetailTablePolicy());
                }
                boMap.put(key, printObj);
                if (HtmlUtil.isHtml(printObj.toString())) {//如果是富文本，则套打子文档
                    handRichtext(key.toString(), val.toString(), boMap);
                } else if (BeanUtils.isNotEmpty(val)) {//判断是否签章和图片，如果是则进行特殊套打
                    HtmlUtil.printPicture(key.toString(), printObj.toString(), boMap, twiceMap);
                }
            });
        });
        config.customPolicy("flowOpinions", new InstanceFlowOpinions());
        boMap.put("flowOpinions", flowOpinions);
        String filePath = defaultFile.getFilePath();
        String fullPath = StringUtil.trimSufffix(AppFileUtil.getAttachPath(), File.separator) + File.separator
                + filePath.replace("/", File.separator);
        outputFilePath = StringUtil.trimSufffix(AppFileUtil.getAttachPath(), File.separator) + outputFilePath.replace("/", File.separator);
        String[] paths = outputFilePath.split(fileId);
        if (paths.length > 1) {
            if (!FileUtil.isExistFile(paths[0])) {
                FileUtil.createFolder(paths[0], false);
            }
        }
        // 在生成word前先执行脚本,用于替换打印的值(比如实际值为1或者2,想显示的值为男与女,用java 脚本进行判断处理)
        if (StringUtil.isNotEmpty(scriptStr)) {
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("boMap", boMap);
            params.putAll(boMap);
            groovyScriptEngine.executeString(scriptStr, params);
        }
        //如果是ftp存储，需要先从ftp下载文件到磁盘目录
        if (!new File(fullPath).exists()) {
            fileManager.downloadFileToPath(defaultFile, fullPath);
        }
        XWPFTemplate template = XWPFTemplate.compile(fullPath, config);
        //处理模板中存在富文本标识，但是富文本值为空的情况
        List<MetaTemplate> templates = template.getElementTemplates();
        for (MetaTemplate metaTemplate : templates) {
            String code = metaTemplate.variable();
            if (code.startsWith("{{+")) {
                code = code.replaceAll("\\{", "");
                code = code.replaceAll("\\+", "");
                code = code.replaceAll("\\}", "");
                if (BeanUtils.isEmpty(boMap.get(code))) {
                    handRichtext(code, "", boMap);
                }

            }
        }
        template.render(boMap);

        FileOutputStream out = new FileOutputStream(outputFilePath);
        template.write(out);
        out.flush();
        out.close();
        template.close();
        if (isSubHtml.get()) {//如果子表里面有富文本  再次套打
            Configure subConfig = Configure.newBuilder().setElMode(ELMode.SPEL_MODE).build();
            XWPFTemplate template2 = XWPFTemplate.compile(outputFilePath, subConfig).render(boMap);
            FileOutputStream out2 = new FileOutputStream(outputFilePath);
            template2.write(out2);
            out2.flush();
            out2.close();
            template2.close();
        }
        if (!twiceMap.isEmpty()) {
            //签章图片用#作为标示符（仅在二次套打中使用）
            Configure twiceConfig = Configure.newBuilder().setElMode(ELMode.SPEL_MODE).addPlugin('#', new SignaturePictureRenderPolicy()).build();
            XWPFTemplate template2 = XWPFTemplate.compile(outputFilePath, twiceConfig).render(twiceMap);
            FileOutputStream out2 = new FileOutputStream(outputFilePath);
            template2.write(out2);
            out2.flush();
            out2.close();
            template2.close();
        }

        return outputFilePath;
    }

    /**
     * 富文本套打处理
     *
     * @param key
     * @param boMap
     */

    private void handRichtext(String key, String text, Map boMap) {

        if (boMap.get(key) instanceof List) {
            List<Map> subList = (List<Map>) boMap.get(key);
            subList.forEach(subMap -> {
                subMap.forEach((subKey, subValue) -> {
                    if (HtmlUtil.isHtml(subValue.toString())) {
                        File docxFile = HtmlUtil.getRichtextToDocx(subValue.toString());
                        subMap.put(subKey, new DocxRenderData(docxFile));
                        if (docxFile != null && docxFile.exists()) {
                            docxFile.delete();
                        }
                    }
                });
            });
        } else if (boMap.get(key) instanceof Map) {
            Map subMap = (Map) boMap.get(key);
            subMap.forEach((subKey, subValue) -> {
                if (HtmlUtil.isHtml(subValue.toString())) {
                    File docxFile = HtmlUtil.getRichtextToDocx(subValue.toString());
                    subMap.put(subKey, new DocxRenderData(docxFile));
                    if (docxFile != null && docxFile.exists()) {
                        docxFile.delete();
                    }
                }
            });
        } else {
            File docxFile = HtmlUtil.getRichtextToDocx(text);
            boMap.put(key, new DocxRenderData(docxFile));
            //删除临时docx文件
            if (docxFile != null && docxFile.exists()) {
                docxFile.delete();
            }
        }
    }

    @RequestMapping(value = "getFileBytesById", method = RequestMethod.GET, produces = {
            "application/json; charset=utf-8"})
    @ApiOperation(value = "附件下载", httpMethod = "GET", notes = "附件下载")
    public byte[] getFileBytesById(@ApiParam(name = "fileId", value = "附件ID") @RequestParam String fileId)
            throws Exception {
        return fileManager.getFileBytesById(fileId);
    }

    @RequestMapping(value = "/importSignature", method = RequestMethod.POST, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "批量导入签章", httpMethod = "POST", notes = "批量导入签章")
    public CommonResult<String> importSignature(@ApiParam(name = "file", value = "导入的压缩文件（.zip或.rar）", required = true) @RequestBody MultipartFile file,
                                                @ApiParam(name = "repeatConver", value = "当用户已存在签章时是否覆盖", required = false) @RequestParam Optional<Boolean> repeatConver) throws Exception {
        return fileManager.importSignature(file, repeatConver.orElse(true));
    }

    @ApiOperation(value = "分片初始化", httpMethod = "POST", notes = "分片上传，分片大小为10兆")
    @PostMapping("init")
    public CommonResult<String> initMultiPartUpload(@RequestBody MultipartInitParam requestParam) {

        MultipartInitRespVo multipartInitBO = fileManager.initMultiPartUpload(requestParam);
        if (Objects.nonNull(multipartInitBO)) {
            return CommonResult.success(multipartInitBO, null);
        } else {
            throw new BaseException("分片初始化失败！");
        }
    }

    @ApiOperation(value = "分片上传", httpMethod = "POST", notes = "由uploadId和chunk查到minio生成的分片url, 上传文件part到minio")
    @PostMapping("/chunkUpload")
    public CommonResult<String> chunkUpload(@RequestPart("file") MultipartFile file, @RequestParam("uploadId") String uploadId, @RequestParam("chunk") String chunk) {
        boolean status = fileManager.chunkUpload(file, uploadId, chunk);
        return CommonResult.success(status, null);
    }

    @ApiOperation(value = "完成上传", httpMethod = "POST", notes = "当所有分片上传接口返回200后，调用此方法，合并分片（minio文件服务器合并），完成上传。")
    @PostMapping("completeUpload")
    public CommonResult<String> completeMultiPartUpload(@RequestBody MultipartCompleteParam param) {

        UploadResult uploadResult = fileManager.mergeMultipartUpload(param);

        return CommonResult.success(uploadResult, null);
    }

    @ApiOperation(value = "测试视屏转M3U8")
    @GetMapping("uploadVideoToM3U8")
    public CommonResult<String> uploadVideoToM3U8(String fileId) {

        UploadM3u8 uploadM3u8 = new UploadM3u8();
        DefaultFile defaultFile = fileManager.get(fileId);
        String s = uploadM3u8.uploadVideoToM3U8(defaultFile);

        return CommonResult.success(s, null);
    }

}
