'use strict';
// @ts-check
const express = require("express");
const router = express.Router();
const { requireAuthentication } = require("@steedos/auth");
const _ = require('lodash');
const { getCollection } = require("../utils/collection");
const WorkflowManager = require('../manager/workflow_manager');
const getHandlersManager = require('../manager/handlers_manager');
const { t } = require('@steedos/i18n')

const FlowversionAPI = {
    traceMaxApproveCount: 10,
    traceSplitApprovesIndex: 5,
    isExpandApprove: false,

    getAbsoluteUrl: function (url) {
        const rootUrl = (typeof __meteor_runtime_config__ !== "undefined" && __meteor_runtime_config__?.ROOT_URL_PATH_PREFIX) || "";
        if (rootUrl) {
            url = rootUrl + url;
        }
        return url;
    },

    writeResponse: function (res, httpCode, body) {
        res.statusCode = httpCode;
        res.end(body);
    },

    sendInvalidURLResponse: function (res) {
        return this.writeResponse(res, 404, "url must has querys as instance_id.");
    },

    sendAuthTokenExpiredResponse: function (res) {
        return this.writeResponse(res, 401, "the auth_token has expired.");
    },

    replaceErrorSymbol: function (str) {
        return str.replace(/\"/g, "&quot;").replace(/\n/g, "<br/>");
    },

    getStepHandlerName: async function (step, insId, instance) {
        const db = {
            users: await getCollection('users'),
            // flow_roles: await getCollection('flow_roles')
        };
        // 获取当前用户userId，默认空字符串即可
        let loginUserId = '';
        let stepId = step._id;
        let stepHandlerName = "";
        try {
            if (step.step_type === "condition") {
                return stepHandlerName;
            }
            let userIds = await getHandlersManager.getHandlers(insId, stepId, loginUserId);
            
            // 如果没有找到处理人，从instance的step_approve中查找
            if ((!userIds || userIds.length === 0) && instance?.step_approve && stepId) {
                let stepApproveUserId = instance.step_approve[stepId];
                if (stepApproveUserId) {
                    if (typeof stepApproveUserId === 'string') {
                        userIds = [stepApproveUserId];
                    } else if (Array.isArray(stepApproveUserId)) {
                        userIds = stepApproveUserId;
                    }
                }
            }
            
            let usersCol = db.users;
            let approverNames = [];
            for (let userId of userIds || []) {
                let user = await usersCol.findOne({ _id: userId }, { projection: { name: 1 } });
                if (user) {
                    approverNames.push(user.name);
                } else {
                    approverNames.push("");
                }
            }
            if (approverNames.length > 3) {
                stepHandlerName = approverNames.slice(0, 3).join(",") + "...";
            } else {
                stepHandlerName = approverNames.join(",");
            }
            return stepHandlerName;
        } catch (e) {
            return "";
        }
        /*
        // switch step.deal_type
        // 	when 'specifyUser'
        // 		approverNames = step.approver_users.map (userId)->
        // 			user = db.users.findOne(userId)
        // 			if user
        // 				return user.name
        // 			else
        // 				return ""
        // 		stepHandlerName = approverNames.join(",")
        // 	when 'applicantRole'
        // 		approverNames = step.approver_roles.map (roleId)->
        // 			role = db.flow_roles.findOne(roleId)
        // 			if role
        // 				return role.name
        // 			else
        // 				return ""
        // 		stepHandlerName = approverNames.join(",")
        // 	else
        // 		stepHandlerName = ''
        // 		break
        // return stepHandlerName
        */
    },

    getStepLabel: function (stepName, stepHandlerName) {
        // 返回sstepName与stepHandlerName结合的步骤显示名称
        let nodeStr = "";
        if (stepName) {
            nodeStr = `<div class='graph-node'>
				<div class='step-name'>${stepName}</div>
				<div class='step-handler-name'>${stepHandlerName}</div>
			</div>`;
            // 把特殊字符清空或替换，以避免mermaidAPI出现异常
            nodeStr = FlowversionAPI.replaceErrorSymbol(nodeStr);
        }
        return nodeStr;
    },

    getStepName: async function (step, cachedStepNames, instance_id, instance) {
        // 返回step节点名称，优先从缓存cachedStepNames中取，否则调用getStepLabel生成
        let cachedStepName = cachedStepNames[step._id];
        if (cachedStepName) {
            return cachedStepName;
        }
        let stepHandlerName = await FlowversionAPI.getStepHandlerName(step, instance_id, instance);
        let stepName = FlowversionAPI.getStepLabel(step.name, stepHandlerName);
        cachedStepNames[step._id] = stepName;
        return stepName;
    },

    generateStepsGraphSyntax: async function (steps, currentStepId, isConvertToString, direction, instance_id, instance) {
        let nodes = [`graph ${direction}`];
        let cachedStepNames = {};
        let skipSteps = new Set(instance?.skip_steps || []);
        for (let step of steps) {
            let lines = step.lines;
            if (lines?.length) {
                for (let line of lines) {
                    let stepName = "";
                    // 标记条件节点
                    if (step.name) {
                        if (step.step_type === "condition") {
                            nodes.push(`	class ${step._id} condition;`);
                        }
                        stepName = await FlowversionAPI.getStepName(step, cachedStepNames, instance_id, instance);
                    } else {
                        stepName = "";
                    }
                    // Mark skipped steps
                    if (skipSteps.has(step._id)) {
                        nodes.push(`	class ${step._id} skip-step;`);
                    }
                    // 原findPropertyByPK("_id",line.to_step)，转为find
                    let toStep = steps.find(s => s._id === line.to_step);
                    let toStepName = await FlowversionAPI.getStepName(toStep, cachedStepNames, instance_id, instance);
                    nodes.push(`	${step._id}("${stepName}")-->${line.to_step}("${toStepName}")`);
                }
            }
        }
        if (currentStepId) {
            nodes.push(`	class ${currentStepId} current-step-node;`);
        }
        if (isConvertToString) {
            let graphSyntax = nodes.join("\n");
            return graphSyntax;
        } else {
            return nodes;
        }
    },

    getApproveJudgeText: function (judge) {
        let locale = "zh-CN";
        let judgeText = '';
        switch (judge) {
            case 'approved':
                // 已核准
                judgeText = t('Instance State approved', {}, locale); break;
            case 'rejected':
                // 已驳回
                judgeText = t('Instance State rejected', {}, locale); break;
            case 'terminated':
                // 已取消
                judgeText = t('Instance State terminated', {}, locale); break;
            case 'reassigned':
                // 转签核
                judgeText = t('Instance State reassigned', {}, locale); break;
            case 'relocated':
                // 重定位
                judgeText = t('Instance State relocated', {}, locale); break;
            case 'retrieved':
                // 已取回
                judgeText = t('Instance State retrieved', {}, locale); break;
            case 'returned':
                // 已退回
                judgeText = t('Instance State returned', {}, locale); break;
            case 'readed':
                // 已阅
                judgeText = t('Instance State readed', {}, locale); break;
            default:
                judgeText = '';
        }
        return judgeText;
    },

    getTraceName: function (traceName, approveHandlerName) {
        // 返回trace节点名称
        let nodeStr = "";
        if (traceName) {
            nodeStr = `<div class='graph-node'>
				<div class='trace-name'>${traceName}</div>
				<div class='trace-handler-name'>${approveHandlerName}</div>
			</div>`;
            nodeStr = FlowversionAPI.replaceErrorSymbol(nodeStr);
        }
        return nodeStr;
    },

    getTraceFromApproveCountersWithType: function (trace) {
        // 该函数生成json结构，表现出所有传阅、分发、转发节点有有后续子节点的计数情况，其结构为：
        // counters = {
        // 	[fromApproveId(来源节点ID)]:{
        // 		[toApproveType(目标结点类型)]:目标节点在指定类型下的后续节点个数
        // 	}
        // }
        let counters = {};
        let approves = trace.approves;
        if (!approves) return null;
        approves.forEach(function (approve) {
            if (approve.from_approve_id) {
                if (!counters[approve.from_approve_id]) counters[approve.from_approve_id] = {};
                if (counters[approve.from_approve_id][approve.type]) {
                    counters[approve.from_approve_id][approve.type]++;
                } else {
                    counters[approve.from_approve_id][approve.type] = 1;
                }
            }
        });
        return counters;
    },

    getTraceCountersWithType: function (trace, traceFromApproveCounters) {
        // 该函数生成json结构，表现出所有传阅、分发、转发的节点流向，其结构为：
        // counters = {
        // 	[fromApproveId(来源节点ID)]:{
        // 		[toApproveType(目标结点类型)]:[{
        // 			from_type: 来源节点类型
        // 			from_approve_handler_name: 来源节点处理人
        // 			to_approve_id: 目标节点ID
        // 			to_approve_handler_names: [多个目标节点汇总处理人集合]
        // 			is_total: true/false，是否汇总节点
        // 		},...]
        // 	}
        // }
        // 上述目标结点内容中有一个属性is_total表示是否汇总节点，如果是，则把多个节点汇总合并成一个，
        // 但是本身有后续子节点的节点不参与汇总及计数。
        let counters = {};
        let approves = trace.approves;
        if (!approves) return null;
        let traceMaxApproveCount = FlowversionAPI.traceMaxApproveCount;
        let isExpandApprove = FlowversionAPI.isExpandApprove;
        approves.forEach(function (toApprove) {
            let toApproveType = toApprove.type;
            let toApproveFromId = toApprove.from_approve_id;
            let toApproveHandlerName = toApprove.handler_name;
            if (!toApproveFromId) return;
            approves.forEach(function (fromApprove) {
                if (fromApprove._id == toApproveFromId) {
                    let counter = counters[toApproveFromId];
                    if (!counter) counter = counters[toApproveFromId] = {};
                    if (!counter[toApprove.type]) counter[toApprove.type] = [];
                    let counter2 = counter[toApprove.type];
                    if (traceFromApproveCounters[toApprove._id]?.[toApproveType]) {
                        // 有后续子节点，则不参与汇总及计数
                        counter2.push({
                            from_type: fromApprove.type,
                            from_approve_handler_name: fromApprove.handler_name,
                            to_approve_id: toApprove._id,
                            to_approve_handler_name: toApprove.handler_name
                        });
                    } else {
                        // 原findPropertyByPK("is_total", true)，转为find
                        let counterContent = isExpandApprove ? null : counter2.find(item => item.is_total === true);
                        // 如果强制要求展开所有节点，则不做汇总处理
                        if (counterContent) {
                            counterContent.count++;
                            if (!(counterContent.count > traceMaxApproveCount)) {
                                counterContent.to_approve_handler_names.push(toApprove.handler_name);
                            }
                        } else {
                            counter2.push({
                                from_type: fromApprove.type,
                                from_approve_handler_name: fromApprove.handler_name,
                                to_approve_id: toApprove._id,
                                count: 1,
                                to_approve_handler_names: [toApprove.handler_name],
                                is_total: true
                            });
                        }
                    }
                }
            });
        });
        return counters;
    },

    pushApprovesWithTypeGraphSyntax: function (nodes, trace) {
        let traceFromApproveCounters = FlowversionAPI.getTraceFromApproveCountersWithType(trace);
        let traceCounters = FlowversionAPI.getTraceCountersWithType(trace, traceFromApproveCounters);
        if (!traceCounters) return;
        let extraHandlerNamesCounter = {}; //记录需要额外生成所有处理人姓名的被传阅、分发、转发节点
        let traceMaxApproveCount = FlowversionAPI.traceMaxApproveCount;
        let splitIndex = FlowversionAPI.traceSplitApprovesIndex;
        let currentTraceName = trace.name;
        for (let fromApproveId in traceCounters) {
            let fromApprove = traceCounters[fromApproveId];
            for (let toApproveType in fromApprove) {
                let toApproves = fromApprove[toApproveType];
                toApproves.forEach(function (toApprove) {
                    let typeName = "";
                    switch (toApproveType) {
                        case 'cc': typeName = "传阅"; break;
                        case 'forward': typeName = "转发"; break;
                        case 'distribute': typeName = "分发"; break;
                    }
                    let isTypeNode = ["cc", "forward", "distribute"].indexOf(toApprove.from_type) >= 0;
                    let traceName;
                    if (isTypeNode) {
                        traceName = toApprove.from_approve_handler_name;
                    } else {
                        traceName = FlowversionAPI.getTraceName(currentTraceName, toApprove.from_approve_handler_name);
                    }
                    let strToHandlerNames = "";
                    if (toApprove.is_total) {
                        let toHandlerNames = toApprove.to_approve_handler_names;
                        if (splitIndex && toApprove.count > splitIndex) {
                            // 在姓名集合中插入回车符号换行
                            toHandlerNames.splice(splitIndex, 0, "<br/>,");
                        }
                        strToHandlerNames = toHandlerNames.join(",").replace(",,", "");
                        let extraCount = toApprove.count - traceMaxApproveCount;
                        if (extraCount > 0) {
                            strToHandlerNames += `等${toApprove.count}人`;
                            if (!extraHandlerNamesCounter[fromApproveId]) extraHandlerNamesCounter[fromApproveId] = {};
                            extraHandlerNamesCounter[fromApproveId][toApproveType] = toApprove.to_approve_id;
                        }
                    } else {
                        strToHandlerNames = toApprove.to_approve_handler_name;
                    }
                    if (isTypeNode) {
                        nodes.push(`	${fromApproveId}>\"${traceName}\"]--${typeName}-->${toApprove.to_approve_id}>\"${strToHandlerNames}\"]`);
                    } else {
                        nodes.push(`	${fromApproveId}(\"${traceName}\")--${typeName}-->${toApprove.to_approve_id}>\"${strToHandlerNames}\"]`);
                    }
                });
            }
        }
        // 为需要额外生成所有处理人姓名的被传阅、分发、转发节点，增加鼠标弹出详细层事件
        // extraHandlerNamesCounter的结构为：
        // counters = {
        // 	[fromApproveId(来源节点ID)]:{
        // 		[toApproveType(目标结点类型)]:目标结点ID
        // 	}
        // }
        let approves = trace.approves;
        if (!_.isEmpty(extraHandlerNamesCounter)) {
            for (let fromApproveId in extraHandlerNamesCounter) {
                let fromApprove = extraHandlerNamesCounter[fromApproveId];
                for (let toApproveType in fromApprove) {
                    let toApproveId = fromApprove[toApproveType];
                    let tempHandlerNames = [];
                    approves.forEach(function (approve) {
                        if (fromApproveId == approve.from_approve_id) {
                            if (!(traceFromApproveCounters?.[approve._id]?.[toApproveType])) {
                                // 有后续子节点，则不参与汇总及计数
                                tempHandlerNames.push(approve.handler_name);
                            }
                        }
                    });
                    nodes.push(`	click ${toApproveId} callback \"${tempHandlerNames.join(",")}\"`);
                }
            }
        }
    },

    generateTracesGraphSyntax: function (traces, isConvertToString, direction) {
        let nodes = [`graph ${direction}`];
        let lastTrace = null;
        let lastApproves = [];
        traces.forEach(function (trace) {
            let lines = trace.previous_trace_ids;
            let currentTraceName = trace.name;
            if (lines?.length) {
                for (let line of lines) {
                    // 原findPropertyByPK("_id",line)，转为find
                    let fromTrace = traces.find(s => s._id == line);
                    let currentFromTraceName = fromTrace.name;
                    let fromApproves = fromTrace.approves;
                    let toApproves = trace.approves;
                    lastTrace = trace;
                    lastApproves = toApproves;
                    fromApproves.forEach(function (fromApprove) {
                        let fromApproveHandlerName = fromApprove.handler_name;
                        if (toApproves?.length) {
                            toApproves.forEach(function (toApprove) {
                                if (["cc", "forward", "distribute"].indexOf(toApprove.type) < 0) {
                                    if (["cc", "forward", "distribute"].indexOf(fromApprove.type) < 0) {
                                        let fromTraceName = FlowversionAPI.getTraceName(currentFromTraceName, fromApproveHandlerName);
                                        let toTraceName = FlowversionAPI.getTraceName(currentTraceName, toApprove.handler_name);
                                        // 不是传阅、分发、转发，则连接到下一个trace
                                        let judgeText = FlowversionAPI.getApproveJudgeText(fromApprove.judge);
                                        if (judgeText) {
                                            nodes.push(`	${fromApprove._id}("${fromTraceName}")--${judgeText}-->${toApprove._id}("${toTraceName}")`);
                                        } else {
                                            nodes.push(`	${fromApprove._id}("${fromTraceName}")-->${toApprove._id}("${toTraceName}")`);
                                        }
                                    }
                                }
                            });
                        } else {
                            // 最后一个步骤的trace
                            if (["cc", "forward", "distribute"].indexOf(fromApprove.type) < 0) {
                                let fromTraceName = FlowversionAPI.getTraceName(currentFromTraceName, fromApproveHandlerName);
                                let toTraceName = FlowversionAPI.replaceErrorSymbol(currentTraceName);
                                // 不是传阅、分发、转发，则连接到下一个trace
                                let judgeText = FlowversionAPI.getApproveJudgeText(fromApprove.judge);
                                if (judgeText) {
                                    nodes.push(`	${fromApprove._id}("${fromTraceName}")--${judgeText}-->${trace._id}("${toTraceName}")`);
                                } else {
                                    nodes.push(`	${fromApprove._id}("${fromTraceName}")-->${trace._id}("${toTraceName}")`);
                                }
                            }
                        }
                    });
                }
            } else {
                // 第一个trace，因traces可能只有一个，这时需要单独显示出来
                trace.approves.forEach(function (approve) {
                    let traceName = FlowversionAPI.getTraceName(currentTraceName, approve.handler_name);
                    nodes.push(`	${approve._id}("${traceName}")`);
                });
            }
            FlowversionAPI.pushApprovesWithTypeGraphSyntax(nodes, trace);
        });
        // 签批历程中最后的approves高亮显示，结束步骤的trace中是没有approves的，所以结束步骤不高亮显示
        lastApproves?.forEach(function (lastApprove) {
            nodes.push(`	class ${lastApprove._id} current-step-node;`);
        });
        if (isConvertToString) {
            let graphSyntax = nodes.join("\n");
            return graphSyntax;
        } else {
            return nodes;
        }
    },

    sendHtmlResponse: async function (req, res, type) {
        const db = {
            instances: await getCollection('instances')
        };
        let query = req.query;
        let instance_id = query.instance_id;
        let direction = query.direction || 'TD';
        let noAutoFit = query.noAutoFit === '1' || query.noAutoFit === 'true';
        const allowDirections = ['TB', 'BT', 'RL', 'LR', 'TD'];
        if (!_.includes(allowDirections, direction)) {
            return this.writeResponse(res, 500, "Invalid direction. The value of direction should be in ['TB', 'BT', 'RL', 'LR', 'TD']");
        }
        if (!instance_id) {
            return FlowversionAPI.sendInvalidURLResponse(res);
        }
        let title = query.title;
        if (title) {
            title = decodeURIComponent(decodeURIComponent(title));
        } else {
            title = "Workflow Chart";
        }
        let error_msg = "";
        let graphSyntax = "";
        FlowversionAPI.isExpandApprove = false;
        if (type === "traces_expand") {
            type = "traces";
            FlowversionAPI.isExpandApprove = true;
        }
        switch (type) {
            case 'traces': {
                let instance = await db.instances.findOne({ _id: instance_id }, { projection: { traces: 1 } });
                if (instance) {
                    let traces = instance.traces;
                    if (traces?.length) {
                        graphSyntax = FlowversionAPI.generateTracesGraphSyntax(traces, false, direction);
                    } else {
                        error_msg = "没有找到当前申请单的流程步骤数据";
                    }
                } else {
                    error_msg = "当前申请单不存在或已被删除";
                }
                break;
            }
            default: {
                let instance = await db.instances.findOne({ _id: instance_id }, { projection: { flow_version: 1, flow: 1, step_approve: 1, skip_steps: 1, traces: { $slice: -1 } } });
                if (instance) {
                    let currentStepId = instance.traces?.[0]?.step;
                    let flowversion = await WorkflowManager.getInstanceFlowVersion(instance);
                    let steps = flowversion?.steps;
                    if (steps?.length) {
                        graphSyntax = await FlowversionAPI.generateStepsGraphSyntax(steps, currentStepId, false, direction, instance_id, instance);
                    } else {
                        error_msg = "没有找到当前申请单的流程步骤数据";
                    }
                } else {
                    error_msg = "当前申请单不存在或已被删除";
                }
            }
        }
        res.setHeader('Content-Type', 'text/html');
        return this.writeResponse(res, 200, `
			<!DOCTYPE html>
			<html>
				<head>
					<meta charset="utf-8">
					<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=yes">
					<title>${title}</title>
					<meta name="mobile-web-app-capable" content="yes">
					<meta name="theme-color" content="#000">
					<meta name="application-name">
					<script type="text/javascript" src="/unpkg.com/jquery@3.7.1/dist/jquery.min.js"></script>
					<script type="text/javascript" src="/unpkg.com/mermaid@9.1.2/dist/mermaid.min.js"></script>
					<style>
						body { 
							font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
							text-align: center;
							background-color: #fff;
						}
						.loading{
							position: absolute;
							left: 0px;
							right: 0px;
							top: 50%;
							z-index: 1100;
							text-align: center;
							margin-top: -30px;
							font-size: 36px;
							color: #dfdfdf;
						}
						.error-msg{
							position: absolute;
							left: 0px;
							right: 0px;
							bottom: 20px;
							z-index: 1100;
							text-align: center;
							font-size: 20px;
							color: #a94442;
						}
						#flow-steps-svg .node rect{
							fill: #ccccff;
							stroke: rgb(144, 144, 255);
							stroke-width: 2px;
						}
						#flow-steps-svg .node.current-step-node rect{
							fill: #cde498;
							stroke: #13540c;
							stroke-width: 2px;
						}
						#flow-steps-svg .node.condition rect{
							fill: #ececff;
							stroke: rgb(204, 204, 255);
							stroke-width: 1px;
						}
						#flow-steps-svg .node.skip-step rect{
							fill: #e8e8e8;
							stroke: #999999;
							stroke-width: 2px;
							stroke-dasharray: 5, 5;
							opacity: 0.7;
						}
						#flow-steps-svg .node.skip-step .step-name{
							color: #666666;
							text-decoration: line-through;
						}
						#flow-steps-svg .node.skip-step .step-handler-name{
							color: #999999;
						}
						#flow-steps-svg .node .trace-handler-name{
							color: #777;
						}
						#flow-steps-svg .node .step-handler-name{
							color: #777;
						}
						div.mermaidTooltip{
							position: fixed!important;
							text-align: left!important;
							padding: 4px!important;
							font-size: 14px!important;
							max-width: 500px!important;
							left: auto!important;
							top: 15px!important;
							right: 15px;
						}
						.btn-zoom{
							background: rgba(0, 0, 0, 0.1);
							border-color: transparent;
							display: inline-block;
							padding: 2px 10px;
							font-size: 26px;
							border-radius: 20px;
							background: #eee;
							color: #777;
							position: fixed;
							bottom: 15px;
							outline: none;
							cursor: pointer;
							z-index: 99999;
							-webkit-user-select: none;
							-moz-user-select: none;
							-ms-user-select: none;
							user-select: none;
							line-height: 1.2;
						}
						@media (max-width: 768px) {
							.btn-zoom{
								display:none;
							}
						}
						.btn-zoom:hover{
							background: rgba(0, 0, 0, 0.2);
						}
						.btn-zoom-up{
							left: 15px;
						}
						.btn-zoom-down{
							left: 60px;
							padding: 1px 13px 3px 13px;
						}
					</style>
				</head>
				<body>
					<div class = "loading">Loading...</div>
					<div class = "error-msg">${error_msg}</div>
					<div class="mermaid"></div>
					<script type="text/javascript">
						mermaid.initialize({
							startOnLoad:false
						});
						$(function(){
							var graphNodes = ${JSON.stringify(graphSyntax)};
							var noAutoFit = ${noAutoFit ? 'true' : 'false'};
							//方便前面可以通过调用mermaid.currentNodes调式，特意增加currentNodes属性。
							mermaid.currentNodes = graphNodes;
							var graphSyntax = graphNodes.join("\\n");
							console.log(graphNodes);
							console.log(graphSyntax);
							console.log("You can access the graph nodes by 'mermaid.currentNodes' in the console of browser.");
							$(".loading").remove();
							var id = "flow-steps-svg";
							var element = $('.mermaid');
							var insertSvg = function(svgCode, bindFunctions) {
								element.html(svgCode);
								if(typeof callback !== 'undefined'){
									callback(id);
								}
								bindFunctions(element[0]);
								
								// 修复SVG左侧内容被裁剪的问题
								if(!noAutoFit) {
									setTimeout(function() {
										var svg = $("svg");
										if(svg.length > 0) {
											// 关键修复：允许SVG溢出显示,解决左侧节点被裁剪的问题
											svg.css('overflow', 'visible');
										}
									}, 50);
								}
							};
							mermaid.render(id, graphSyntax, insertSvg, element[0]);
							
							var currentZoom = 1;
							var zoomSVG = function(zoom){
								var svg = $("svg");
								currentZoom = currentZoom * zoom;
								var baseWidth = svg.data('baseWidth') || svg.width();
								if(!svg.data('baseWidth')) {
									svg.data('baseWidth', baseWidth);
								}
								var newWidth = baseWidth * currentZoom;
								svg.css("maxWidth",newWidth + "px").width(newWidth);
							}
							//支持鼠标滚轮缩放画布
							$(window).on("mousewheel",function(event){
								if(event.ctrlKey){
									event.preventDefault();
									var zoom = event.originalEvent.wheelDelta > 0 ? 1.1 : 0.9;
									zoomSVG(zoom);
								}
							});
							$(".btn-zoom").on("click",function(){
								zoomSVG($(this).attr("zoom"));
							});
						});
					</script>
					<a class="btn-zoom btn-zoom-up" zoom=1.1 title="点击放大">+</a>
					<a class="btn-zoom btn-zoom-down" zoom=0.9 title="点击缩小">-</a>
				</body>
			</html>
		`);
    }
};

// /api/workflow/chart?instance_id=:instance_id
// 流程图
router.get('/api/workflow/chart', requireAuthentication, async function (req, res) {
    await FlowversionAPI.sendHtmlResponse(req, res);
});

// /api/workflow/chart/traces?instance_id=:instance_id
// 汇总签批历程图
router.get('/api/workflow/chart/traces', requireAuthentication, async function (req, res) {
    await FlowversionAPI.sendHtmlResponse(req, res, "traces");
});

// /api/workflow/chart/traces_expand?instance_id=:instance_id
// 展开所有节点的签批历程图
router.get('/api/workflow/chart/traces_expand', requireAuthentication, async function (req, res) {
    await FlowversionAPI.sendHtmlResponse(req, res, "traces_expand");
});
exports.default = router;