package cn.myapps.runtime.activity.controller;

import cn.myapps.authtime.logger.model.LogVO;
import cn.myapps.base.web.WebUser;
import cn.myapps.common.Environment;
import cn.myapps.common.RunnableMeta;
import cn.myapps.common.auth.IUser;
import cn.myapps.common.controller.ErrorMessage;
import cn.myapps.common.controller.Resource;
import cn.myapps.common.data.ParamsTable;
import cn.myapps.common.model.activity.*;
import cn.myapps.common.model.resource.ResourceVO;
import cn.myapps.common.model.view.AbstractView;
import cn.myapps.common.model.view.ExcelFileBuilder;
import cn.myapps.common.util.PropertyUtil;
import cn.myapps.common.util.StringUtil;
import cn.myapps.common.util.cache.MemoryCacheUtil;
import cn.myapps.designtime.activity.service.ActivityDesignTimeService;
import cn.myapps.designtime.common.service.DesignTimeServiceManager;
import cn.myapps.designtime.form.service.FormDesignTimeService;
import cn.myapps.designtime.resource.service.ResourceDesignTimeService;
import cn.myapps.designtime.view.service.ViewDesignTimeService;
import cn.myapps.runtime.activity.service.ActivityRunTimeService;
import cn.myapps.runtime.common.controller.AbstractRuntimeController;
import cn.myapps.runtime.common.service.RunTimeServiceManager;
import cn.myapps.runtime.common.utils.ExportToPdf;
import cn.myapps.runtime.dynaform.document.ejb.Document;
import cn.myapps.runtime.dynaform.document.ejb.DocumentProcess;
import cn.myapps.runtime.dynaform.document.ejb.DocumentProcessBean;
import cn.myapps.runtime.dynaform.document.ejb.Item;
import cn.myapps.runtime.dynaform.dts.excelimport.config.AbstractImportProvider;
import cn.myapps.runtime.dynaform.form.FormDataPacket;
import cn.myapps.runtime.dynaform.form.ejb.ButtonField;
import cn.myapps.runtime.dynaform.form.ejb.Form;
import cn.myapps.runtime.dynaform.form.ejb.FormField;
import cn.myapps.runtime.dynaform.form.ejb.ValidateMessage;
import cn.myapps.runtime.logger.service.LogHelper;
import cn.myapps.runtime.logger.service.LogProcess;
import cn.myapps.runtime.macro.runner.IRunner;
import cn.myapps.runtime.macro.runner.JavaScriptFactory;
import cn.myapps.util.DocumentRequestUtil;
import cn.myapps.util.ParamsTableUtil;
import cn.myapps.util.ProcessFactory;
import cn.myapps.util.sequence.Sequence;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bcxin.saas.core.exceptions.SaasBadException;
import com.bcxin.saas.core.utils.ExceptionUtils;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.Option;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.time.Instant;
import java.util.*;

import static com.jayway.jsonpath.JsonPath.parse;

/**
 * 操作（Activitys）
 *
 * @author ahan
 *
 */
@Api(tags = "操作执行模块")
@Component
@RequestMapping(path = "/api/runtime", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class ActivityController extends AbstractRuntimeController {

	@Autowired
	private ActivityRunTimeService activityRuntimeService;

	@Autowired
	private HttpServletResponse response;

	/**
	 * 运行执行前脚本
	 *
	 * @param id            操作id
	 * @param applicationId 软件id
	 * @param content       请求包体
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/activities/{id}/runbeforeactionscript")
	@ApiOperation(value = "运行执行前脚本", notes = "运行执行前脚本")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "id", value = "操作id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public Resource runBeforeActionScript(@PathVariable String id, @PathVariable String applicationId,
										  @RequestBody String content)
			throws Exception {
		ParamsTable params = getParams();
		params = ParamsTableUtil.parseAndMergeActionB_A(params, id, content,true);


		Document doc = this.prepareDocument(content, applicationId, "$.document", params);

		JSONObject result = activityRuntimeService.runbeforeactionscript(applicationId, id, doc, params, getUser());

		return success("ok", result);
	}

	/**
	 * 执行后脚本
	 *
	 * @param id 操作id
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/activities/{id}/runafteractionscript")
	@ApiOperation(value = "执行后脚本", notes = "执行后脚本")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "id", value = "操作id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public Resource runAfterActionScript(@PathVariable String id, @PathVariable String applicationId, @RequestBody String content)
			throws Exception {
		ParamsTable params = getParams();
		params = ParamsTableUtil.parseAndMergeActionB_A(params, id, content, false);

		JSONObject result = activityRuntimeService.runafteractionscript(id, applicationId, content, params, getUser());

		return success("ok", result);
	}

	/**
	 * 执行按钮指定的字段脚本
	 *
	 * @param id            按钮id
	 * @param applicationId 软件id
	 * @param docId         文档id
	 * @param fieldName     类型
	 * @return
	 * @throws Exception
	 */
	@GetMapping("/{applicationId}/activities/{id}/runScript")
	@ResponseBody
	@ApiOperation(value = "执行按钮的某个字段脚本", notes = "执行按钮的某个字段脚本")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "id", value = "操作id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "docid", value = "文档id", required = false, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "fieldName", value = "字段名", required = false, paramType = "query", dataType = "string")

	})
	public Resource doRunScript(@PathVariable String id, @PathVariable String applicationId, @RequestParam String docId, @RequestParam String fieldName) {
		String stringResult = "";
		try {
			fieldName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, fieldName.length());
			stringResult = runActivityScript(id, applicationId, docId, fieldName);
		} catch (Exception e) {
			return error(403, "字段名不存或者脚本报错" + ExceptionUtils.getStackMessage(e), null);
		}


		return success("ok", stringResult);
	}

	private String runActivityScript(String id, String applicationId, String docId, String fieldName) throws Exception {
		DocumentProcess dProcess = RunTimeServiceManager.documentProcess(applicationId);
		ActivityDesignTimeService actService = DesignTimeServiceManager.activityDesignTimeService();
		// 从Session中获取Document
		FormDesignTimeService formService = DesignTimeServiceManager.formDesignTimeService();
		Document doc = (Document) MemoryCacheUtil.getFromPrivateSpace(docId, getUser());
		if (doc == null) {
			doc = (Document) dProcess.doView(docId);
		}

		Activity act = actService.findById(id);
		ButtonField buttonField = null;
		String dispatcherUrl = "";
		String name = "";
		RunnableMeta control = null;
		if (act != null) {
			Method method = act.getClass().getMethod(fieldName);
			Object result = method.invoke(act);
			if (result != null) {
				dispatcherUrl = result.toString();
			}
			name = act.getName();
			control = act;
		} else {
			Form form = formService.doView(doc.getFormid());
			Map<String, FormField> map = form.getAllFieldMap();
			FormField formField = map.get(id);
			if (formField instanceof ButtonField) {
				buttonField = (ButtonField) formField;
			}

			if(buttonField==null) {
				throw new SaasBadException(String.format("系统异常, 表单(%s)内部找不到对应的按钮(id=%s)", form.getUri(), id));
			}

			dispatcherUrl = buttonField.getDispatcherUrl();
			name = buttonField.getName();
			control = buttonField;
		}
		Object result = null;


		IUser user = getUser();
		IRunner runner = JavaScriptFactory.getInstance(user.getSessionid(), applicationId);
		runner.initBSFManager(doc, getParams(), user, new ArrayList<ValidateMessage>());
		StringBuffer label = new StringBuffer();
		if (doc != null) {
			label.append("FormName:").append(doc.getFormname());
		}
		label.append(" Activity(").append(id).append(")." + name).append(".").append(fieldName);
		result = runner.run(control, label.toString(), StringUtil.dencodeHTML(dispatcherUrl));

		return (String) result;
	}

	/**
	 * 执行动作
	 *
	 * @param id 操作id
	 * @return
	 * @throws Exception
	 */
	@PutMapping("/{applicationId}/activities/{id}/execute")
	@ApiOperation(value = "执行动作", notes = "执行动作")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "id", value = "操作id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public Resource execute(@PathVariable String applicationId, @PathVariable String id, @RequestBody String content) throws Exception {
		ParamsTable params = DocumentRequestUtil.parseRequestParams(request, getDomain(), id, content, false);

		JSONObject result = activityRuntimeService.execute(applicationId, id, content, params, getUser());
		return success("ok", result);
	}

	/**
	 * 归档按钮
	 *
	 * @param applicationId 软件id
	 * @param docId         文档id
	 * @return
	 * @throws Exception
	 */
	@GetMapping("/{applicationId}/documents/{docId}/activities/archive")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "归档按钮", notes = "归档按钮")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "docId", value = "文档id", required = true, paramType = "path", dataType = "string")
	})
	public Resource archive(@PathVariable String applicationId,
							@PathVariable String docId) throws Exception {
		String result = activityRuntimeService.archive(applicationId, docId,
				getUser(), getParams());
		return success("ok", result);
	}

	/**
	 * 保存文档并启动流程按钮
	 *
	 * @param applicationId 软件id
	 * @param docId         文档id
	 * @param content       请求包体
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/documents/activities/saveStartWorkFlow")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "保存文档并启动流程按钮", notes = "保存文档并启动流程按钮")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public Resource saveStartWorkFlow(@PathVariable String applicationId, @RequestBody String content)
			throws Exception {
		ParamsTable params = getParams();
		Document doc = this.prepareDocument(content, applicationId, "$.document", params);

		DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
				applicationId);

		IUser webUser = getUser();
		Collection<Document> subDocuments = doc.getFrontSubDocuments();
		Collection<ErrorMessage> errors = validateDocument(params, doc, applicationId, webUser);
		if (errors.isEmpty()) {
			if (subDocuments != null) {
				List<Document> copySubDocuments = new ArrayList<Document>();
				copySubDocuments.addAll(doc.getSubDocuments());
				for (Document document : copySubDocuments) {
					//保存子表
					if (document.isDelete()) {
						dProcess.doRemove(document.getId());
						doc.removeSubDocument(document.getId());
					} else if (document.isEdit()) {
						Collection<ErrorMessage> subErrors = validateDocument(params, document, applicationId, webUser);
						if (!subErrors.isEmpty()) {
							return error(4001, "子表单校验不通过", subErrors);
						}
						document.setVersions(-1);
						dProcess.doCreateOrUpdate(document, webUser);
					}
				}
				//在保存完子表之后重计算一下主表
				doc = doc.getForm().recalculateDocument(doc, params, webUser);
			}
			Document result = activityRuntimeService.saveStartWorkFlow(applicationId, doc,
					webUser, params);
			return success("ok", result);
		} else {
			return error(4001, "表单校验不通过", errors);
		}
	}

	/**
	 * 复制文档按钮
	 *
	 * @param applicationId 软件id
	 * @param docId         文档id
	 * @param content       请求包体
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/documents/{docId}/activities/copy")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "复制文档按钮", notes = "复制文档按钮")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "docId", value = "文档id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public Resource copy(@PathVariable String applicationId,
						 @PathVariable String docId, @RequestBody String content) throws Exception {
		Configuration configuration = Configuration.defaultConfiguration();
		configuration = configuration
				.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);

		DocumentContext parse = parse(content, configuration);

		Map<String, Object> items = parse.read("$.document.items");

		DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
				applicationId);
		Document doc = (Document) MemoryCacheUtil.getFromPrivateSpace(docId, getUser());
		if (doc == null) {
			doc = (Document) dProcess.doView(docId);
		}
		ParamsTable params = getParams();
		for (Map.Entry<String, Object> entry : items.entrySet()) {
			String key = entry.getKey();
			Object value = entry.getValue();
			Item item = doc.findItem(key);
			if (item != null) {
				params.setParameter(key, value);
			}
		}

		IUser user = getUser();
		doc.setId(Sequence.getSequence());
		List<ErrorMessage> errors = validateDocument(params, doc, applicationId, user);
		if (!errors.isEmpty()) {
			ErrorMessage error = new ErrorMessage();
			error.setErrcode(40001);
			error.setErrmsg("复制表单校验不通过");
			errors.add(0, error);
			return error(4001, "复制表单校验不通过", errors);
		}

		Document result = activityRuntimeService.copy(applicationId, doc,
				user, params);
		return success("ok", result);
	}

	/**
	 * 清除所有数据
	 *
	 * @param applicationId 软件id
	 * @param formId        表单id
	 * @return
	 * @throws Exception
	 */
	@DeleteMapping("/{applicationId}/forms/{formId}/activities/clear")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "清除所有数据", notes = "清除所有数据")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "formId", value = "表单id", required = true, paramType = "path", dataType = "string")
	})
	public Resource clear(@PathVariable String applicationId,
						  @PathVariable String formId) throws Exception {
		activityRuntimeService.clear(applicationId, getUser(), formId);
		return success("ok", "清除成功");
	}

	/**
	 * 签章
	 *
	 * @param applicationId 软件id
	 * @param docId         文档id
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/documents/{docId}/activities/sign")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "签章", notes = "签章")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "docId", value = "文档id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public Resource sign(@PathVariable String applicationId,
						 @PathVariable String docId, @RequestBody String content) throws Exception {
		Configuration configuration = Configuration.defaultConfiguration();
		configuration = configuration
				.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);

		DocumentContext parse = parse(content, configuration);

		String sign = parse.read("$.document.sign");
		Map<String, Object> items = parse.read("$.document.items");

		DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
				applicationId);
		Document doc = (Document) MemoryCacheUtil.getFromPrivateSpace(docId, getUser());
		if (doc == null) {
			doc = (Document) dProcess.doView(docId);
		}
		ParamsTable params = getParams();
		for (Map.Entry<String, Object> entry : items.entrySet()) {
			String key = entry.getKey();
			Object value = entry.getValue();
			Item item = doc.findItem(key);
			if (item == null)
				throw new Exception(key + " 值不存在");
			item.setValue(value);
			params.setParameter(key, value);
		}

		doc.setSign(sign);
		dProcess.doCreateOrUpdate(doc, getUser());

		return success("ok", "签章成功");
	}

	/**
	 * 文件下载按钮
	 *
	 * @param applicationId 软件id
	 * @param docId         文档id
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/activities/{id}/download")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "文件下载按钮", notes = "文件下载按钮")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "docId", value = "文档id", required = false, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "id", value = "按钮id", required = true, paramType = "path", dataType = "string")
	})
	public Resource downloadFile(@PathVariable String applicationId,
								 @RequestParam(required = false) String docId, @PathVariable String id) throws Exception {
		Document doc = new Document();
		if (!StringUtil.isBlank(docId)) {
			DocumentProcess proxy = (DocumentProcess) ProcessFactory.createRuntimeProcess(DocumentProcess.class, applicationId);
			doc = (Document) MemoryCacheUtil.getFromPrivateSpace(docId, getUser());
			if (doc == null) {
				doc = (Document) proxy.doView(docId);
			}
		}
		IRunner runner = JavaScriptFactory.getInstance(getUser().getSessionid(),
				applicationId);
		runner.initBSFManager(doc, getParams(), getUser(), new ArrayList<ValidateMessage>());
		ActivityDesignTimeService activityService = DesignTimeServiceManager.activityDesignTimeService();
		Activity act = activityService.findById(id);
		if (act == null) {
			FormDesignTimeService formService = DesignTimeServiceManager.formDesignTimeService();
			ActivityParent actParent = doc.getForm();
			act = actParent.findActivity(id);
		}

		String result = "";
		// 处理文件下载按钮
		if (!StringUtil.isBlank(act.getFileNameScript())) {
			StringBuffer label = new StringBuffer();
			label.append("Activity(").append(act.getId()).append(
					")." + act.getName()).append("fileNameScript");
			result = (String) runner.run(act,label.toString(), act
					.getFileNameScript());
		}

		if (!StringUtil.isBlank(result)) {
			if (result.contains("https://") || result.contains("http://")) {
				return success("ok", result);
			}
			String path = result;
			if (result.indexOf("?") > -1) {
				path = result.substring(0, result.indexOf("?"));
			}
			String filePath = PropertyUtil.getPath() + path;
			if (!new File(filePath).isFile()) {
				return error(40001, "文件不存在", null);
			}
		} else {
			return error(40001, "文件不存在", null);
		}
		return success("ok", result);
	}

	/**
	 * 导出Excel操作
	 *
	 * @param response      响应对象
	 * @param applicationId 软件id
	 * @param viewId        视图id
	 * @param actId         按钮id
	 * @param filename      文件名
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/views/{viewId}/activities/exportExcel")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "导出Excel操作", notes = "导出Excel操作")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "viewId", value = "视图id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "actId", value = "按钮id", required = true, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "filename", value = "文件名", required = true, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public void exportExcel(HttpServletResponse response, HttpServletRequest request,
							@PathVariable String applicationId, @PathVariable String viewId,
							String actId, String filename, @RequestBody String content) throws Exception {
		WebUser user = getUser();
		MemoryCacheUtil.putToPrivateSpace(ExcelFileBuilder.EXCELEXPORTCOUNT, 0, user);
		MemoryCacheUtil.putToPrivateSpace(ExcelFileBuilder.EXCELROWCOUNT, 0, user);
		MemoryCacheUtil.removeFromPrivateSpace(ExcelFileBuilder.EXPORTEXCELRESULT, user);
		if(StringUtil.isBlank(filename)) {
			filename = String.format("导出文件-%s", Instant.now().getEpochSecond());
		}

		ParamsTable params = getParams();
		filename = URLDecoder.decode(filename, "utf-8");
		params.setParameter("filename", filename);
		String agent = request.getHeader("USER-AGENT");
		String fileNameExcel = filename + ".xlsx";
		String encoding = Environment.getInstance().getEncoding();
		response.setContentType("application/x-download; charset=" + encoding + "");
		if (null != agent && -1 != agent.indexOf("Firefox")) {
			response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileNameExcel.getBytes("UTF-8"), "iso-8859-1"));
		} else {
			response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileNameExcel.getBytes("UTF-8"), "iso-8859-1"));
		}

		JSONObject json = JSONObject.parseObject(content);
		String selectColumns = json.getString("selectColumns");
		params.setParameter("selectColumns", selectColumns);

		JSONArray jsonArray = json.getJSONArray("selectDocIds");
		String[] docIds = jsonArray.toArray(new String[]{});

		Object items = json.get("items");
		if (items != null) {
			JSONObject jsonObject = (JSONObject) items;
			for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
				String key = entry.getKey();
				Object value = entry.getValue();
				if (value != null && !"".equals(String.valueOf(value))) {
					params.setParameter(key, value);
				}
			}
		}

		String result = activityRuntimeService.exportExcel(viewId, actId, getUser(), params, response.getOutputStream(), docIds);
		MemoryCacheUtil.putToPrivateSpace(ExcelFileBuilder.EXPORTEXCELRESULT, result, user);
	}

	/*
	 * 读取导出excel进度
	 */
	@GetMapping("/exportExcel/readProcess")
	public Resource exportExcelProcess() {
		JSONObject jsonObject = new JSONObject();
		try {
			WebUser user = getUser();
			jsonObject.put("excelExportCount", MemoryCacheUtil.getFromPrivateSpace(ExcelFileBuilder.EXCELEXPORTCOUNT, user));
			jsonObject.put("excelRowCount", MemoryCacheUtil.getFromPrivateSpace(ExcelFileBuilder.EXCELROWCOUNT, user));
			jsonObject.put("exportExcelResult", MemoryCacheUtil.getFromPrivateSpace(ExcelFileBuilder.EXPORTEXCELRESULT, user));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return success("ok", jsonObject);
	}

	/**
	 * 通过邮件或手机短信分享按钮
	 *
	 * @param applicationId 软件id
	 * @param docId         文档id
	 * @param content
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/documents/{docId}/activities/share")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "通过邮件或手机短信分享按钮", notes = "通过邮件或手机短信分享按钮")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "docId", value = "文档id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public Resource share(@PathVariable String applicationId,
						  @PathVariable String docId, @RequestBody String content)
			throws Exception {
		Configuration configuration = Configuration.defaultConfiguration();
		configuration = configuration
				.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);

		DocumentContext parse = parse(content, configuration);
		String transpond = parse.read("$.transpond");
		String handleUrl = parse.read("$.handleUrl");
		String receiverid = parse.read("$.receiverid");
		Boolean email = parse.read("$.email");
		Boolean msm = parse.read("$.msm");
		String result = activityRuntimeService.share(applicationId, docId,
				getUser(), getParams(), transpond, handleUrl, receiverid,
				email, msm);
		return success("ok", result);
	}

	/**
	 * 批量提交操作
	 *
	 * @param applicationId 软件id
	 * @param content       请求包体
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/forms/activities/batchApprove")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "批量提交操作", notes = "批量提交操作")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public Resource batchApprove(@PathVariable String applicationId, @RequestBody String content) throws Exception {
		WebUser user = getUser();
		//重置进度条
		MemoryCacheUtil.putToPrivateSpace(DocumentProcessBean.HANDLEDCOUNT, 0, user);
		MemoryCacheUtil.putToPrivateSpace(DocumentProcessBean.BATCHAPPROVECOUNT, 0, user);
		MemoryCacheUtil.removeFromPrivateSpace(DocumentProcessBean.BATCHAPPROVERESULT, user);

		Configuration configuration = Configuration.defaultConfiguration();
		configuration = configuration
				.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);

		DocumentContext parse = parse(content, configuration);
		String limistStrList = parse.read("$.limistStrList");
		List<String> docIdsList = parse.read("$.docIds");
		String[] docIds = docIdsList.toArray(new String[0]);
		String actId = parse.read("$.actId");
		String attitude = parse.read("$.attitude");
		String remark = parse.read("$.remark");
		net.sf.json.JSONObject result = activityRuntimeService.batchApprove(applicationId, limistStrList, docIds, actId, attitude, remark, getParams(), user);
		//塞入返回结果
		MemoryCacheUtil.putToPrivateSpace(DocumentProcessBean.BATCHAPPROVERESULT, result, user);
		return success("ok", result);
	}

	/*
	 * 读取批量提交进度
	 */
	@GetMapping("/batchApprove/readProcess")
	public Resource batchApproveProcess() {
		JSONObject jsonObject = new JSONObject();
		try {
			WebUser user = getUser();
			jsonObject.put("handledCount", MemoryCacheUtil.getFromPrivateSpace(DocumentProcessBean.HANDLEDCOUNT, user));
			jsonObject.put("batchApproveCount", MemoryCacheUtil.getFromPrivateSpace(DocumentProcessBean.BATCHAPPROVECOUNT, user));
			jsonObject.put("batchApproveResult", MemoryCacheUtil.getFromPrivateSpace(DocumentProcessBean.BATCHAPPROVERESULT, user));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return success("ok", jsonObject);
	}

	/**
	 * pdf导出操作
	 *
	 * @param formId        表单id
	 * @param applicationId 软件id
	 * @param docId         文档id
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/forms/{formId}/documents/{docId}/activities/exportPdf")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "pdf导出操作", notes = "pdf导出操作")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "formId", value = "表单id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "docId", value = "文档id", required = true, paramType = "path", dataType = "string")
	})
	public Resource exportPdf(@PathVariable String formId, @PathVariable String applicationId, @PathVariable String docId, @RequestBody String content, HttpServletRequest request, HttpServletResponse response) throws Exception {
		ExportToPdf exportToPdf = new ExportToPdf(new Activity());
		request.setAttribute("formId", formId);
		request.setAttribute("docId", docId);
		JSONObject json = JSONObject.parseObject(content);
		String htmlBody = json.getString("htmlBody");
		//String htmlBody = "<body><input type=\"text\" id=\"userId\" name=\"userId\" value=\"1\"></body>";
		ActionContent action = new ActionContent(request, response);
		DocumentProcess proxy = RunTimeServiceManager.documentProcess(applicationId);
		Document doc = (Document) proxy.doView(docId);
		ActivityResult activityResult = exportToPdf.doProcess(action, doc, getUser(), htmlBody);
		return success("ok", activityResult.getResultData());
	}

	/**
	 * 网页打印操作
	 *
	 * @param applicationId 软件id
	 * @param formId        表单id
	 * @param docId         文档id
	 * @return
	 * @throws Exception
	 */
	@GetMapping("/{applicationId}/forms/{formId}/documents/{docId}/activities/print")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "网页打印操作", notes = "网页打印操作")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "formId", value = "表单id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "docId", value = "文档id", required = true, paramType = "path", dataType = "string")
	})
	public Resource print(@PathVariable String applicationId, @PathVariable String formId, @PathVariable String docId) throws Exception {
		FormDataPacket result = activityRuntimeService.print(applicationId, formId, docId, getParams(), getUser());
		return success("ok", result);
	}

	/**
	 * 导入excel操作
	 *
	 * @param applicationId 软件id
	 * @param viewId        视图id
	 * @param content       请求包体
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/views/{viewId}/activities/importExcel")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "导入excel操作", notes = "导入excel操作")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "viewId", value = "视图id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public Resource importExcel(@PathVariable String applicationId, @PathVariable String viewId, @RequestBody String content) throws Exception {
		WebUser user = getUser();
		try {
			MemoryCacheUtil.putToPrivateSpace(AbstractImportProvider.EXCELIMPORTCOUNT, 0, user);
			MemoryCacheUtil.putToPrivateSpace(AbstractImportProvider.EXCELIMPORTROWCOUNT, 0, user);
			MemoryCacheUtil.removeFromPrivateSpace(AbstractImportProvider.IMPORTEXCELRESULT, user);

			Configuration configuration = Configuration.defaultConfiguration();
			configuration = configuration
					.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);

			DocumentContext parse = parse(content, configuration);
			String impmappingconfigid = parse.read("$.impmappingconfigid");
			String path = parse.read("$.path");
			String actId = parse.read("$.actId");

			String parentId = parse.read("$.parentId");
			String isRelate = parse.read("$.isRelate");

			Map exparams = parse.read("$.exparams");

			ParamsTable params = getParams();

			if (exparams != null) {
				for (Iterator<Map.Entry<String, Object>> iterator = exparams.entrySet().iterator(); iterator.hasNext(); ) {
					Map.Entry<String, Object> obj = iterator.next();
					Object value = obj.getValue();
					String key = obj.getKey();
					params.setParameter(key, value);
				}
			}

			if (!StringUtil.isBlank(parentId)) {
				params.setParameter("parentid", parentId);
			}
			if (!StringUtil.isBlank(isRelate)) {
				params.setParameter("isRelate", isRelate);
			}

			String result = activityRuntimeService.improtExcel(applicationId, impmappingconfigid, path, user, params, actId, viewId);
			if (result.indexOf("cn.myapps.runtime.dynaform.dts.excelimport.success.total.imported") > -1) {
				Resource success = success("ok", result);
				MemoryCacheUtil.putToPrivateSpace(AbstractImportProvider.IMPORTEXCELRESULT, success, user);
				return success;
			} else {
				String[] msg = result.split("\\$\\$");
				Resource error = new Resource(4001, "导入出错", msg, null);
				MemoryCacheUtil.putToPrivateSpace(AbstractImportProvider.IMPORTEXCELRESULT, error, user);
				return error;
			}
		} catch (Exception e) {
			e.printStackTrace();
			Resource error = new Resource(5000, e.getMessage(), null);
			MemoryCacheUtil.putToPrivateSpace(AbstractImportProvider.IMPORTEXCELRESULT, error, user);
			return error;
		}
	}

	/**
	 * 导入excel操作
	 *
	 * @param applicationId 软件id
	 * @param viewId        视图id
	 * @param content       请求包体
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/{applicationId}/views/{viewId}/activities/validationExcel")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "导入excel操作", notes = "导入excel操作")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "viewId", value = "视图id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public Resource validationExcel(@PathVariable String applicationId, @PathVariable String viewId, @RequestBody String content) throws Exception {
		WebUser user = getUser();
		try {
			MemoryCacheUtil.putToPrivateSpace(AbstractImportProvider.EXCELIMPORTCOUNT, 0, user);
			MemoryCacheUtil.putToPrivateSpace(AbstractImportProvider.EXCELIMPORTROWCOUNT, 0, user);
			MemoryCacheUtil.removeFromPrivateSpace(AbstractImportProvider.IMPORTEXCELRESULT, user);

			Configuration configuration = Configuration.defaultConfiguration();
			configuration = configuration
					.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);

			DocumentContext parse = parse(content, configuration);
			String impmappingconfigid = parse.read("$.impmappingconfigid");
			String path = parse.read("$.path");
			String actId = parse.read("$.actId");

			String parentId = parse.read("$.parentId");
			String isRelate = parse.read("$.isRelate");

			Map exparams = parse.read("$.exparams");

			ParamsTable params = getParams();

			if (exparams != null) {
				for (Iterator<Map.Entry<String, Object>> iterator = exparams.entrySet().iterator(); iterator.hasNext(); ) {
					Map.Entry<String, Object> obj = iterator.next();
					Object value = obj.getValue();
					String key = obj.getKey();
					params.setParameter(key, value);
				}
			}

			if (!StringUtil.isBlank(parentId)) {
				params.setParameter("parentid", parentId);
			}
			if (!StringUtil.isBlank(isRelate)) {
				params.setParameter("isRelate", isRelate);
			}

			String result = activityRuntimeService.validationExcel(applicationId, impmappingconfigid, path, user, params, actId, viewId);
			if (result.indexOf("cn.myapps.runtime.dynaform.dts.excelimport.success.total.imported") > -1) {
				Resource success = success("ok", result);
				MemoryCacheUtil.putToPrivateSpace(AbstractImportProvider.IMPORTEXCELRESULT, success, user);
				return success;
			} else {
				String[] msg = result.split("\\$\\$");
				Resource error = new Resource(4001, "校验出错", msg, null);
				MemoryCacheUtil.putToPrivateSpace(AbstractImportProvider.IMPORTEXCELRESULT, error, user);
				return error;
			}
		} catch (Exception e) {
			e.printStackTrace();
			Resource error = new Resource(5000, e.getMessage(), null);
			MemoryCacheUtil.putToPrivateSpace(AbstractImportProvider.IMPORTEXCELRESULT, error, user);
			return error;
		}
	}


	/*
	 * 读取导入excel进度
	 */
	@GetMapping("/importExcel/readProcess")
	public Resource readProcess() {
		String result = "success";
		JSONObject jsonObject = new JSONObject();
		try {
			IUser user = getUser();
			jsonObject.put("excelImportCount", MemoryCacheUtil.getFromPrivateSpace(AbstractImportProvider.EXCELIMPORTCOUNT, user));
			jsonObject.put("excelRowCount", MemoryCacheUtil.getFromPrivateSpace(AbstractImportProvider.EXCELIMPORTROWCOUNT, user));
			jsonObject.put("importExcelResult", MemoryCacheUtil.getFromPrivateSpace(AbstractImportProvider.IMPORTEXCELRESULT, user));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return success("ok", jsonObject);
	}

	/**
	 * 执行地址脚本
	 *
	 * @param applicationId 软件id
	 * @param docId         文档id
	 * @param actId         按钮id
	 * @return
	 * @throws Exception
	 */
	@PutMapping("/{applicationId}/activities/{actId}/executeAddress")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "执行地址脚本", notes = "执行地址脚本")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "docId", value = "文档id", required = false, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "actId", value = "按钮id", required = true, paramType = "path", dataType = "string"),
			@ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")
	})
	public Resource executeAddress(@PathVariable String applicationId, @RequestParam(required = false) String docId, @PathVariable String actId, @RequestBody String content) throws Exception {
		Configuration configuration = Configuration.defaultConfiguration();
		configuration = configuration.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);
		DocumentContext parse = parse(content, configuration);

		ParamsTable params = getParams();
		Map<String, Object> items = parse.read("$.document");
		if (items != null) {
			for (Map.Entry<String, Object> entry : items.entrySet()) {
				String key = entry.getKey();
				Object value = entry.getValue();
				params.setParameter(key, value);
			}
		}
		List<String> selects = parse.read("$._selects");
		if (selects != null)
			params.setParameter("_selects", StringUtil.unite(selects.toArray()));

		JSONObject result = activityRuntimeService.executeAddress(applicationId, actId, params, getUser(), docId);
		return success("ok", result);
	}

	/**
	 * 记录操作日志
	 *
	 * @param formId  表单id
	 * @param viewId  视图id
	 * @param actType 操作类型
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/activities/recordHandleLog")
	@ResponseStatus(HttpStatus.OK)
	@ApiOperation(value = "记录操作日志", notes = "记录操作日志")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "formId", value = "表单id", required = false, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "viewId", value = "视图id", required = false, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "actType", value = "操作类型", required = true, paramType = "query", dataType = "string"),
			@ApiImplicitParam(name = "menuId", value = "菜单id", required = false, paramType = "query", dataType = "String")
	})
	public Resource recordHandleLog(@RequestParam(required = false) String formId, @RequestParam(required = false) String viewId, @RequestParam String actType, @RequestParam(required = false) String menuId) throws Exception {
		String description = "";
		if (!StringUtil.isBlank(formId)) {
			FormDesignTimeService formService = DesignTimeServiceManager.formDesignTimeService();
			Form form = (Form) formService.doView(formId);
			description = "{*[" + form.getSimpleClassName() + "]*}-" + form.getName();
		}
		if (!StringUtil.isBlank(viewId)) {
			ViewDesignTimeService viewProcess = DesignTimeServiceManager.viewDesignTimeService();
			AbstractView view = viewProcess.doView(viewId);
			description = "{*[" + view.getSimpleClassName() + "]*}-" + view.getName();
		}
		if (!StringUtil.isBlank(menuId)) {
			ResourceDesignTimeService resourceService = DesignTimeServiceManager.resourceDesignTimeService();
			ResourceVO menu = resourceService.doView(menuId);
			if (menu != null) {
				description = "菜单-" + getHierarchyResourceName(resourceService, menu.getSuperior(), menu.getName());
				actType = "进入菜单";
			}
		}
		String ip = LogHelper.getRequestIp(request);
		LogVO logVo = LogVO.valueOf(getUser(), actType, description, ip);
		LogProcess logProcess = (LogProcess) ProcessFactory.createProcess(LogProcess.class);
		logProcess.doCreate(logVo);
		return success("ok", null);
	}

	/**
	 * 校验方法
	 *
	 * @param params
	 * @param doc
	 * @param applicationId
	 * @param webUser
	 * @return
	 * @throws Exception
	 */
	private List<ErrorMessage> validateDocument(ParamsTable params, Document doc, String applicationId,
												IUser webUser) throws Exception {
		List<ErrorMessage> errmsgs = new ArrayList<ErrorMessage>();
		doc.setDomainid(getDomain());
		DocumentProcess proxy = RunTimeServiceManager.documentProcess(
				applicationId);
		Collection<ValidateMessage> errors = proxy.doValidate(doc, params, webUser);
		if (errors != null && errors.size() > 0) {
			for (Iterator<ValidateMessage> iter = errors.iterator(); iter.hasNext(); ) {
				ValidateMessage err = (ValidateMessage) iter.next();
				ErrorMessage msg = new ErrorMessage();
				msg.setErrcode(40001);
				msg.setErrmsg(err.getErrmessage());
				msg.setField(err.getFieldname());
				errmsgs.add(msg);
			}
		}
		return errmsgs;
	}

	/**
	 * 获取此菜单层级结构名称
	 */
	private String getHierarchyResourceName(ResourceDesignTimeService resourceService, String superior, String rootResourceName) {
		try {
			if (!StringUtil.isBlank(superior)) {
				ResourceVO resourceVO = resourceService.doView(superior);
				rootResourceName = resourceVO.getName() + "/" + rootResourceName;
				return getHierarchyResourceName(resourceService, resourceVO.getSuperior(), rootResourceName);
			}
			return rootResourceName;
		} catch (Exception e) {
			e.printStackTrace();
			return e.getMessage();
		}
	}
}
