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.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.*;
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.sysConfig.util.SysPropertyUtil;
import com.artfess.uc.api.model.IUser;
import com.artfess.uc.api.service.IUserService;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
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.*;
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.*;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

@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);
	}

	@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 = "files", value = "上传的文件流") @RequestBody List<MultipartFile> files) throws Exception {
		DefaultFile file = new DefaultFile();
		String account = baseContext.getCurrentUserAccout();
		return fileManager.UploadFileForConfig(file, files, bizCode,bizId,userService.getUserByAccount(account));
	}


	@RequestMapping(value = "fileUpload", method = RequestMethod.POST, produces = { "application/json; charset=utf-8" })
	@ApiOperation(value = "附件上传操作", httpMethod = "POST", notes = "附件上传操作")
	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));
	}

	@RequestMapping(value = "/md5Check", method = RequestMethod.POST, produces = { "application/json; charset=utf-8" })
	@ApiOperation(value = "校验文件的MD5值", httpMethod = "POST", notes = "校验文件的MD5值")
	public Map<String,Object> md5Check(@RequestParam("fileSize") Long fileSize, @RequestParam("md5Value") String md5Value) throws Exception {
		DefaultFile file = this.baseService.queryByMd5AndSize(fileSize, md5Value);
		String fileID = "";
		if(BeanUtils.isNotEmpty(file)){
			fileID =file.getId();
		}

		List<FileZone> fileZoneList = new ArrayList<FileZone>();

		if (StringUtil.isEmpty(fileID)) {
			fileZoneList = this.fileZonedManager.queryByMd5Value(md5Value,fileSize);
		}

		Map<String, Object> returnMap = new HashMap<>();

		returnMap.put("uploaded", fileID);
		returnMap.put("uploadedChunkList", fileZoneList);
		return returnMap;
	}

	@RequestMapping(value = "/uploadZone", method = RequestMethod.POST, produces = { "application/json; charset=utf-8" })
	@ApiOperation(value = "上传切片文件", httpMethod = "POST", notes = "上传切片文件")
	public  Map<String,Object> upload(@RequestParam("zone") MultipartFile chunk, FileZone fileZone, String fileName,String bizCode,String bizId, String folder) throws IOException {
		String filePath = SysPropertyUtil.getByAlias("file.upload");
		String path_date = cn.hutool.core.date.DateUtil.format(new Date(), "yyyy") + File.separator + cn.hutool.core.date.DateUtil.format(new Date(), "MMdd") + File.separator + cn.hutool.core.date.DateUtil.format(new Date(), "HH");
		if(StringUtil.isNotEmpty(folder)){
			path_date = path_date+ File.separator+folder;
		}
		if(fileName.equals("blob")){
			fileName=fileZone.getZoneName();
		}
		String fullPath = filePath + File.separator + path_date+File.separator + fileName;
		String extName = FileUtil.getFileExt(fileName);
		File file = new File(filePath + File.separator + path_date+File.separator);
		if(!file.exists()){
			file.mkdirs();
		}
		Map<String, Object> returnMap = new HashMap<>();
		// 模拟上传出错
//        Integer uploadTimes = times.get(fileChunk.getChunkName());
//        if (uploadTimes == null) {
//            times.put(fileChunk.getChunkName(), 1);
//
//            return false;
//        }

		// 模块写入对应的位置
		try(RandomAccessFile rf = new RandomAccessFile(fullPath,"rw")) {
			rf.seek(fileZone.getZoneStartSize());
			rf.write(chunk.getBytes());
		} catch (Exception e) {
			returnMap.put("flag", false);
			returnMap.put("id", "");
			return returnMap;
		}

		// chunk 记录到数据库
		String filemd5= "";
		if(StringUtil.isEmpty(fileZone.getZoneMd5())){
			filemd5= DigestUtils.md5DigestAsHex(chunk.getInputStream());
			fileZone.setZoneMd5(filemd5);
		}else{
			filemd5=fileZone.getZoneMd5();
		}

		fileZone.setZoneRecordTime(LocalDateTime.now());
		fileZone.setZoneSuffix(extName);
		fileZone.setZonePath(fullPath);
		fileZonedManager.create(fileZone);
		Integer chunkSize = fileZonedManager.countByMd5AndSize(fileZone.getZoneTotalMd5(),fileZone.getZoneTotalSize());
		String fileId = "";
		if (chunkSize.equals(fileZone.getZoneTotalCount())) {
			// 删除 chunk 记录
			fileZonedManager.removeZoneByMd5AndSize(fileZone.getZoneTotalMd5(),fileZone.getZoneTotalSize());

			// 增加 file 记录
			DefaultFile fileRecord = new DefaultFile();
			fileRecord.setBizCode(bizCode);
			fileRecord.setBizId(bizId);
			fileRecord.setByteCount(fileZone.getZoneTotalSize());
			fileRecord.setMd5Value(fileZone.getZoneTotalMd5());
			fileRecord.setFileName(fileName);
			fileRecord.setServerLocalName(fileName);
			fileRecord.setServerLocalPath(fullPath);
			fileRecord.setFilePath(fullPath.replace(filePath, ""));
			fileRecord.setIsZone(1);
			fileRecord.setStoreType("folder");
			fileRecord.setExtensionName(extName);
			fileRecord.setZoneTotal(fileZone.getZoneTotalCount());
			fileId = this.baseService.insertFile(fileRecord);
		}
		returnMap.put("flag", true);
		returnMap.put("id", fileId);
		return returnMap;
	}

	@PostMapping("/updateBatch")
	@ApiOperation("批量更新附件信息")
	public CommonResult<String> updateBatch(@ApiParam(name="files", value="数据集合") @RequestBody List<DefaultFile> files){
		boolean result = baseService.updateBatchById(files);
		if(!result) {
			return new CommonResult<>(ResponseErrorEnums.FAIL_OPTION, null);
		}
		return new CommonResult<>();
	}

	@PostMapping("/relateBatch")
	@ApiOperation(value = "批量关联业务", notes = "只传id和bizId")
	public CommonResult<String> relateBatch(@ApiParam(name="files", value="数据集合") @RequestBody List<DefaultFile> files){
		String result = "";
		files = files.stream().filter(f->f.getId()!=null || f.getBizId() != null).collect(Collectors.toList());
		for (DefaultFile f : files ) {
			boolean r = baseService.update(new UpdateWrapper<DefaultFile>().set("biz_id_", f.getBizId()).eq("id_", f.getId()));
			if(r) {
				result += f.getId()+"更新成功";
			}else{
				result += f.getId()+"更新失败";
			}
		}
		return new CommonResult<>(result);
	}

}
