function OaFormUtil(layui) {
    var $ = layui.$;
    var win = $(window);
    var layer = layui.layer;
    var upload = layui.upload;
    var form = layui.form;
    var restAjax = layui.restajax;
    var processImageEnlargeScale = 0;

    // 全屏
    function fullPage() {
        $('.layui-card-body').css('height', (win.height() - 75) + 'px');
        $('.save-report-form').css({
            height: (win.height() - 75) + 'px',
            overflow: 'auto'
        })
    }

    fullPage();

    // 消息位置
    function getMsgOffset(isApp) {
        return isApp ? '15px' : 'auto';
    }

    /**
     * 关闭按钮组
     */
    function closeBtns() {
        $('#formBtns').click();
        $('#appFormBtns').click();
    }

    /**
     * 设置保存历史字段列表
     * @param formData
     * @param fields
     */
    this.setEditHistoryFields = function (formData, fields) {
        var recordFields = [];
        for (var i = 0, field; field = fields[i++];) {
            if (field.editHistory === 'latest' || field.editHistory === 'all') {
                recordFields.push({
                    fieldName: field.fieldName,
                    fieldExplain: $('#' + field.fieldName + 'Box').find('label').text().replace(/[\*\:]/g, ''),
                    editHistory: field.editHistory
                });
            }
        }
        formData.field.recordFields = recordFields;
    }

    /**
     * 设置抄送列表
     * @param formData
     */
    this.setCcs = function (formData) {
        if (!formData.field.ccs) {
            formData.field.ccs = [];
            return;
        }
        var ccs = formData.field.ccs.split(',');
        var ccArray = [];
        for (var i = 0, item; item = ccs[i++];) {
            ccArray.push(item);
        }
        formData.field.ccs = ccArray;
    }

    /**
     * 设置签字列表
     * @param formData
     */
    this.initSignList = function (formData) {
        if (!formData.jointlySign) {
            return;
        }
        var jointlySign = formData.jointlySign;
        for (var key in formData) {
            var jointlySigns = jointlySign[key + 'JointlySign'];
            if (!jointlySigns) {
                continue;
            }
            var signListDom = '<div style="text-align: left;">';
            for (var i = 0, item; item = jointlySigns[i++];) {
                signListDom += [
                    '<div>',
                    '   <span>' + item.content + '</span>',
                    '   <span>　' + item.userName + '</span>',
                    '   <span> →' + item.time + '</span>',
                    '</div>'
                ].join('');
            }
            signListDom += '</div>';
            formData[key] = '';
            $('#' + key + 'Block').append(signListDom);
        }
    }

    /**
     * 初始化文本框签字列表
     * @param formData
     */
    this.initTextareaSignList = function (formData) {
        if (!formData.jointlySign) {
            return;
        }
        var jointlySign = formData.jointlySign;
        for (var key in formData) {
            var jointlySigns = jointlySign[key + 'JointlySign'];
            if (!jointlySigns) {
                continue;
            }
            var jointlySignListText = '';
            for (var i = 0, item; item = jointlySigns[i++];) {
                jointlySignListText += item.content + '　' + item.userName + ' →' + item.time + '\n';
            }
            formData[key] = jointlySignListText;
        }
    }

    /**
     * 初始化日志
     */
    function initProcessLog(processInstanceId, isApp, headers) {
        var url;
        if (isApp) {
            url = 'app/oa/list-process-log/process-instance-id/{processInstanceId}';
        } else {
            url = 'api/oa/list-process-log/process-instance-id/{processInstanceId}';
        }
        restAjax.get(restAjax.path(url, [processInstanceId]), {}, {
            headers: headers
        }, function (code, data) {
            var ul = '<ul class="layui-timeline">';
            for (var i = 0, item; item = data[i++];) {
                // 批注
                var commentText = '';
                var comment = item.comment;
                if (comment) {
                    if (comment.type === 'JOINTLY_SIGN') {
                        commentText = '动作：会签。批注：' + comment.content + '。时间：' + comment.time;
                    } else if (comment.type === 'GO_BACK') {
                        commentText = '动作：回退。批注：' + comment.content + '。时间：' + comment.time;
                    } else if (comment.type === 'FORCED_END') {
                        commentText = '动作：强制结束。批注：' + comment.content + '。时间：' + comment.time;
                    }
                }
                // 转交记录
                var transferCommentText = '';
                var transferComments = item.transferComments;
                for (var j = transferComments.length, transferComment; transferComment = transferComments[--j];) {
                    if (transferCommentText) {
                        transferCommentText += '\n'
                    }
                    transferCommentText += (transferComments.length - j) + '. 转交人：' + transferComment.userName + '。原因：' + transferComment.content + '。时间：' + transferComment.time;
                }
                var li = [
                    '<li class="layui-timeline-item">',
                    '   <i class="layui-icon layui-timeline-axis">&#xe63f;</i>',
                    '   <div class="layui-timeline-content layui-text">',
                    '       <h3 class="layui-timeline-title">' + item.startTime + '</h3>',
                    '       <table class="layui-table">',
                    '           <colgroup>',
                    '               <col width="100">',
                    '               <col>',
                    '           </colgroup>',
                    '           <tbody>',
                    '           <tr>',
                    '               <td class="row-title">任务名称</td>',
                    '               <td>' + item.taskName + '</td>',
                    '           </tr>',
                    '           <tr>',
                    '               <td class="row-title">节点状态</td>',
                    '               <td>' + (item.taskStatus == 'alreadyDone' ? '已办' : '待办') + '</td>',
                    '           </tr>',
                    '           <tr>',
                    '               <td class="row-title">结束时间</td>',
                    '               <td>' + (item.endTime ? item.endTime : '-') + '</td>',
                    '           </tr>',
                    '           <tr>',
                    '               <td class="row-title">耗时</td>',
                    '               <td>' + (item.usedTime ? item.usedTime : '0秒') + '</td>',
                    '           </tr>',
                    '           <tr>',
                    '               <td class="row-title">处理人</td>',
                    '               <td>' + (item.userNames == '1' ? '管理员' : item.userNames) + '</td>',
                    '           </tr>',
                    '           <tr>',
                    '               <td class="row-title">备注</td>',
                    '               <td>' + (commentText ? commentText : '无') + '</td>',
                    '           </tr>',
                    '           <tr>',
                    '               <td class="row-title">转交记录</td>',
                    '               <td>' + (transferCommentText ? '<pre>' + transferCommentText + '</pre>' : '无') + '</td>',
                    '           </tr>',
                    '           </tbody>',
                    '       </table>',
                    '   </div>',
                    '</li>'
                ].join('');
                ul += li;
            }
            ul += '</ul>';
            $('#processLog').append(ul);
        }, function (code, data) {
            layer.msg(data.msg, {offset: getMsgOffset(isApp)});
        });
    }

    /**
     * 初始化流程图
     * @param processInstanceId
     */
    function initProcessImage(processInstanceId, isApp, headers) {
        var src;
        if (isApp) {
            src = 'approute/oa/get-runtime-process-image/' + processInstanceId + '?token=' + headers.token;
        } else {
            src = 'route/activiti/model/get-runtime-process-image/' + processInstanceId;
        }

        function initRuntimeProcessImage() {
            var html = [
                '<div id="runtimeProcessImageBox">',
                '   <img id="runtimeProcessImage" src="' + src + '" alt="流转图" style="width: 100%;"/>',
                '</div>',
                '<div id="operationBtnBox" class="layui-btn-group">',
                '   <button id="searchPlus" type="button" class="layui-btn layui-btn-xs" title="放大">',
                '       <i class="fa fa-search-plus" aria-hidden="true"></i>',
                '   </button>',
                '   <button id="searchMinus" type="button" class="layui-btn layui-btn-xs layui-btn-default" title="缩小">',
                '       <i class="fa fa-search-minus" aria-hidden="true"></i>\n' +
                '   </button>',
                '   <button id="searchDefault" type="button" class="layui-btn layui-btn-xs layui-btn-primary" title="还原">',
                '       <i class="fa fa-search" aria-hidden="true"></i>',
                '   </button>',
                '</div>'
            ].join('');
            $('#processImage').css({
                position: 'relative',
                textAlign: 'center'
            })
            $('#processImage').append(html);
            $('#runtimeProcessImageBox').css({
                height: '100%',
            });
        }

        initRuntimeProcessImage();

        function setProcessImageSize() {
            $('#runtimeProcessImage').css('width', 100 + processImageEnlargeScale + '%');
        }

        $('#searchPlus').click(function () {
            processImageEnlargeScale += 10;
            setProcessImageSize();
        })
        $('#searchMinus').click(function () {
            processImageEnlargeScale -= 10;
            setProcessImageSize();
        })
        $('#searchDefault').click(function () {
            processImageEnlargeScale = 0;
            setProcessImageSize();
        })
    }

    /**
     * 初始化选择项
     */
    this.initTabItem = function (processInstanceId, opt) {
        var isApp = opt && opt.isApp ? opt.isApp : false;
        var headers = opt && opt.headers ? opt.headers : {};
        $('.layui-tab-item').css({
            height: (win.height() - 138) + 'px',
            overflow: 'auto'
        });
        initProcessLog(processInstanceId, isApp, headers);
        initProcessImage(processInstanceId, isApp, headers);
    }

    /**
     * 初始化提交按钮
     * @param confirmAssignees
     * @param opt
     */
    this.initSubmitBtns = function (confirmAssignees, opt) {
        var btnColor = ['', 'layui-btn-normal', 'layui-btn-warm'];
        var isApp = opt && opt.isApp ? opt.isApp : false;
        if (isApp) {
            var appButtonCount = 0;

            $('#submitBtnGroup').append('<button type="button" id="appShowSubmitFormBtns" class="layui-btn layui-btn-primary"><i class="fa fa-list-ul" aria-hidden="true"></i> 提交</button>');

            var html = '<div id="appSubmitFormBtns">';
            html += '<div id="appSubmitFormBtnsContainer">';
            html += '<div class="layui-btn-container">';
            html += '<div class="layui-row" style="padding: 15px;">';
            for (var i = 0, item; item = confirmAssignees[i++];) {
                appButtonCount++;
                html += '<button type="button" id="submitFormBtn' + i + '" class="layui-col-xs12 layui-btn ' + btnColor[(i - 1) % 3] + ' confirm-btn" lay-submit lay-filter="submit' + i + '" data-select-type="' + item.nodeType + '" data-index="' + (i - 1) + '" data-next-end-event="' + item.nextEndEvent + '" data-btn-exc="' + item.btnExc + '">' + item.btnText + '</button>'
            }
            html += '</div>';
            html += '</div>';
            html += '</div>';
            html += '</div>';

            $('#submitBtnGroup').append(html)

            var maxHeight = appButtonCount * 30 + (appButtonCount + 1) * 10;
            maxHeight = maxHeight > 160 ? 160 : maxHeight;

            $(document).on('click', '#appSubmitFormBtns', function () {
                $(this).hide();
                $('#appSubmitFormBtnsContainer').css('bottom', (-1 * maxHeight + 'px'));
            })

            $(document).on('click', '#appSubmitFormBtnsContainer', function (e) {
                e.stopPropagation()
            })

            $(document).on('click', '#appShowSubmitFormBtns', function () {
                $('#appSubmitFormBtns').show();
                $('#appSubmitFormBtnsContainer').animate({bottom: 0}, 200);
            })
        } else {
            if (confirmAssignees.length < 4) {
                var btns = '';
                for (var i = 0, item; item = confirmAssignees[i++];) {
                    btns += '<button type="button" id="submitFormBtn' + i + '" class="layui-btn layui-btn-sm ' + btnColor[(i - 1) % 3] + ' confirm-btn" lay-submit lay-filter="submit' + i + '" data-select-type="' + item.nodeType + '" data-index="' + (i - 1) + '" data-next-end-event="' + item.nextEndEvent + '" data-btn-exc="' + item.btnExc + '">' + item.btnText + '</button>'
                }
                $('#submitBtnGroup').append(btns);
            } else {
                $('#submitBtnGroup').append('<button type="button" id="showSubmitFormBtns" class="layui-btn layui-btn-primary layui-btn-xs"><i class="fa fa-list-ul" aria-hidden="true"></i> 提交</button>');

                var html = '<div id="submitFormBtns">';
                html += '<div id="submitFormBtnsContainer">';
                html += '<div class="layui-btn-container" style="padding: 10px;">'
                for (var i = 0, item; item = confirmAssignees[i++];) {
                    html += '<button type="button" id="submitFormBtn' + i + '" class="layui-col-xs12 layui-btn layui-btn-sm ' + btnColor[(i - 1) % 3] + ' confirm-btn" lay-submit lay-filter="submit' + i + '" data-select-type="' + item.nodeType + '" data-index="' + (i - 1) + '" data-next-end-event="' + item.nextEndEvent + '" data-btn-exc="' + item.btnExc + '">' + item.btnText + '</button>'
                }
                html += '</div>';
                html += '</div>';
                html += '</div>';

                $('#submitBtnGroup').append(html)

                $(document).on('click', '#submitFormBtns', function () {
                    $(this).hide();
                })

                $(document).on('click', '#submitFormBtnsContainer', function (e) {
                    e.stopPropagation()
                })

                $(document).on('click', '#showSubmitFormBtns', function () {
                    $('#submitFormBtns').show();
                })
            }
        }
    }

    /**
     * 初始化回填字段
     * @param fields
     * @param currentUser
     */
    this.backFillFields = function (fields, currentUser) {
        var obj = {};
        for (var i = 0, item; item = fields[i++];) {
            if (item.autoBackFill === 'currentUserName') {
                obj[item.fieldName] = currentUser.userName;
                continue;
            }
            if (item.autoBackFill === 'currentUserDepartment') {
                if (currentUser.departments.length == 1) {
                    obj[item.fieldName] = currentUser.departments[0].departmentName;
                    continue;
                }
                if (currentUser.departments.length > 1) {
                    obj[item.fieldName] = currentUser.departments[0].departmentName;
                    var options = '';
                    for (var j = 0, jItem; jItem = currentUser.departments[j++];) {
                        options += '<option value="' + jItem.departmentName + '">' + jItem.departmentName + '</option>'
                    }
                    var parent = $('#' + item.fieldName + 'Block');
                    parent.empty();
                    parent.append('<select name="' + item.fieldName + '">' + options + '</select>');
                    continue;
                }
            }
        }
        form.val('dataForm', obj);
        form.render(null, 'dataForm');
    }

    /**
     * @description 禁止字段操作，禁止操作的字段不参与提交
     * @param fields {Array} [{fieldName:'', isEditable: 0|1}]
     */
    this.disableFields = function (fields) {
        for (var i = 0, item; item = fields[i++];) {
            if (parseInt(item.isEditable) === 0) {
                // 普通控件
                var boxId = '#' + item.fieldName + 'Box';
                var blockId = '#' + item.fieldName + 'Block';
                // 文号控件
                if ($(boxId).hasClass('docno')) {
                    // 移除文号标识
                    $(boxId).removeClass('docno');
                    // 获取文本输入框
                    var docNoTextInput = $('#' + item.fieldName + 'Text');
                    docNoTextInput.removeAttr('name');
                    docNoTextInput.attr('disabled', 'disabled');
                    docNoTextInput.attr('lay-verify', '');
                    // 重新添加文本
                    $(blockId).empty();
                    $(blockId).append(docNoTextInput)
                } else {
                    $(boxId).css('position', 'relative');
                    $(boxId).append('<div style="width: 100%; height: 100%; background-color: #fff0; position: absolute; top: 0; left: 0; cursor: not-allowed;"></div>');
                    var doms = $(boxId).find('input,button,textarea,select');
                    doms.removeAttr('name');
                    doms.attr('disabled', 'disabled');
                    doms.attr('lay-verify', '');
                }
            }
        }
    }

    /**
     * 禁用表单全部字段
     */
    this.disableFormAllFields = function () {
        var doms = $('#reportForm').find('input,button,textarea,select');
        doms.attr('disabled', 'disabled');
        doms.attr('lay-verify', '');
    }

    /**
     * 禁用字段转div
     */
    this.disabledField2Div = function () {
        var doms = $('#reportForm').find('input,textarea,select');
        $.each(doms, function (index, item) {
            if (!item.disabled) {
                return;
            }

            var value = item.value;
            var parent = $(item).parent();
            parent.empty();
            if (item.nodeName === 'INPUT' || item.nodeName === 'SELECT') {
                parent.append('<div style="line-height: 36px;">' + value + '</div>')
            } else if (item.nodeName === 'TEXTAREA') {
                parent.append('<div style="line-height: 36px; text-align: left;">' + value + '</div>')

            }
        });
    }

    /**
     * @description 隐藏字段操作
     * @param fields {Array} [{fieldName:'', isVisible: 0|1}]
     */
    this.hideFields = function (fields) {
        for (var i = 0, item; item = fields[i++];) {
            if (parseInt(item.isVisible) === 0) {
                var boxId = '#' + item.fieldName + 'Box';
                $(boxId).hide();
            }
        }
    }

    /**
     * 初始化表单按钮
     * @param formButton
     */
    this.initFormButtons = function (formButton, opt) {
        var headers = opt.headers;
        headers = headers ? headers : {};
        var isApp = opt.isApp;
        var isAppShow = opt.isAppShow;
        var processInstanceId = opt.processInstanceId;
        var taskId = opt.taskId;
        var formCode = opt.formCode;
        var formVersion = opt.formVersion;
        var uid = opt.uid;
        var onPreview = typeof (opt.onPreview) === 'function' ? opt.onPreview : null;
        var appButtonCount = 0;

        function initButton() {
            var buttons = '';

            if (isApp && !isAppShow) {
                buttons += '<button type="button" id="appShowFormBtns" class="layui-btn layui-btn-primary"><i class="fa fa-list-ul" aria-hidden="true"></i> 操作</button>'
                buttons += '<div id="appFormBtns">';
                buttons += '<div id="appFormBtnsContainer">';
                buttons += '<div class="layui-btn-container">';
                buttons += '<div class="layui-row" style="padding: 15px;">';
                // app端无打印
                if (formButton.btnGoBack) {
                    buttons += '<button id="goBackBtn" type="button" class="layui-col-xs12 layui-btn layui-btn-warm confirm-btn">回退</button>';
                    appButtonCount++;
                }
                if (formButton.btnForcedEnd) {
                    buttons += '<button id="forcedEndBtn" type="button" class="layui-col-xs12 layui-btn layui-btn-danger confirm-btn">强制结束</button>';
                    appButtonCount++;
                }
                if (formButton.btnCc) {
                    buttons += '<button id="ccBtn" type="button" class="layui-col-xs12 layui-btn layui-btn-normal confirm-btn">抄送</button>';
                    appButtonCount++;
                }
                if (formButton.btnTransfer) {
                    buttons += '<button id="transferBtn" type="button" class="layui-col-xs12 layui-btn layui-btn-primary confirm-btn">转交</button>';
                    appButtonCount++;
                }
                if (formButton.btnAttachment) {
                    buttons += '<button id="attachmentBtn" type="button" class="layui-col-xs12 layui-btn layui-btn-default confirm-btn">上传附件</button>';
                    appButtonCount++;
                }
                buttons += '</div>';
                buttons += '</div>';
                buttons += '</div>';
                buttons += '</div>';
            } else {
                buttons += '<div class="layui-btn-group">'
                if (formButton.btnPrint) {
                    buttons += '<button id="printBtn" type="button" class="layui-btn layui-btn-xs layui-btn-primary confirm-btn">打印</button>';
                }
                if (formButton.btnGoBack) {
                    buttons += '<button id="goBackBtn" type="button" class="layui-btn layui-btn-xs layui-btn-warm confirm-btn">回退</button>';
                }
                if (formButton.btnForcedEnd) {
                    buttons += '<button id="forcedEndBtn" type="button" class="layui-btn layui-btn-xs layui-btn-danger confirm-btn">强制结束</button>';
                }
                if (formButton.btnCc) {
                    buttons += '<button id="ccBtn" type="button" class="layui-btn layui-btn-xs layui-btn-normal confirm-btn">抄送</button>';
                }
                if (formButton.btnTransfer) {
                    buttons += '<button id="transferBtn" type="button" class="layui-btn layui-btn-xs layui-btn-primary confirm-btn">转交</button>';
                }
                if (formButton.btnAttachment) {
                    buttons += '<button id="attachmentBtn" type="button" class="layui-btn layui-btn-xs layui-btn-default confirm-btn">上传附件</button>';
                }
                buttons += '</div>';
            }
            buttons += '<div class="layui-btn-group">';
            buttons += '<button id="showAttachmentBtn" type="button" class="layui-btn ' + (isApp ? '' : 'layui-btn-xs') + ' layui-btn-primary" title="附件列表"><i class="fa fa-list-ul" aria-hidden="true"></i></button>';
            buttons += '<input type="hidden" name="attachments" id="attachments"/>';
            buttons += '<input type="hidden" name="ccs" id="ccs"/>';
            buttons += '</div>';
            $('#formButtonGroup').append(buttons);
        }

        function addClick() {
            if (isApp) {
                var maxHeight = appButtonCount * 30 + (appButtonCount + 1) * 10;
                maxHeight = maxHeight > 160 ? 160 : maxHeight;
                $(document).on('click', '#appFormBtns', function () {
                    $(this).hide();
                    $('#appFormBtnsContainer').css('bottom', (-1 * maxHeight + 'px'));
                })

                $(document).on('click', '#appFormBtnsContainer', function (e) {
                    e.stopPropagation()
                })

                $(document).on('click', '#appShowFormBtns', function () {
                    $('#appFormBtns').show();
                    $('#appFormBtnsContainer').animate({bottom: 0}, 200);
                })
            }

            if (formButton.btnAttachment) {
                var layerLoadingIndex;
                var url = 'api/file/v2/upload-file';
                if (isApp) {
                    url = 'app/file/v2/upload-file'
                }
                upload.render({
                    elem: '#attachmentBtn',
                    url: url,
                    accept: 'file',
                    acceptMime: [
                        'application/pdf',
                        'application/msword',
                        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                        'application/vnd.ms-excel',
                        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                        'application/vnd.ms-powerpoint',
                        'application/vnd.openxmlformats-officedocument.presentationml.presentation',
                        'application/vnd.ms-works',
                        'text/plain',
                        'application/x-rar',
                        'application/x-zip-compressed',
                        'image/*',
                        'video/mp4',
                        'audio/wav',
                        'audio/mp3'
                    ].join(''),
                    field: 'file',
                    exts: 'pdf|doc|docx|xls|xlsx|ppt|pptx|wps|txt|rar|zip|jpg|png|gif|bmp|jpeg|mp4|wav|mp3',
                    headers: headers,
                    before: function (obj) {
                        closeBtns();
                        layerLoadingIndex = layer.msg('上传中...', {icon: 16, time: 0, shade: 0.3})
                    },
                    done: function (res, index, upload) {
                        layer.close(layerLoadingIndex);
                        layer.msg('上传成功')
                        var attachments = $('#attachments').val();
                        var data = res.data;
                        if (attachments.length > 0) {
                            attachments += ',';
                        }
                        attachments += data.fileId + ':' + data.fileName.replace(/\,/g, '，');
                        $('#attachments').val(attachments);
                    },
                    error: function (index, upload) {
                        layer.close(layerLoadingIndex);
                        layer.msg('文件上传失败');
                    },
                    progress: function (n, elem, res, index) {
                    }
                });
            }

            // 附件
            $(document.body).on('click', '#showAttachmentBtn', function () {
                var attachments = $('#attachments').val();
                var attachmentArray = attachments.split(',');
                var html = [
                    '<div class="form-upload-file" style="margin: 0 10px;">',
                    '   <table class="layui-table" lay-size="sm">',
                    '       <colgroup>',
                    '           <col>',
                    onPreview && formButton.btnAttachment ? '<col width="120">' : '<col width="60">',
                    '       </colgroup>',
                    '       <thead>',
                    '       <tr>',
                    '           <th>文件名</th>',
                    '           <th class="operation">操作</th>',
                    '       </tr>',
                    '       </thead>',
                    '       <tbody>',
                ].join('');
                if (attachmentArray.length > 0) {
                    for (var i = 0, file; file = attachmentArray[i++];) {
                        var idNameArray = file.split(':');
                        var fileId = idNameArray[0];
                        var fileName = idNameArray[1];
                        html += [
                            '<tr>',
                            '   <td><a href="route/file/v2/download/false/' + fileId + '" target="_blank" title="下载">' + fileName + '</a></td>',
                            '   <td class="operation">',
                            '       <div class="layui-btn-group">',
                            onPreview ? '<button type="button" class="layui-btn layui-btn-xs layui-btn-primary preview-btn" data-id="' + fileId + '" data-name="' + fileName + '">预览</button>' : '',
                            formButton.btnAttachment ? '<button type="button" class="layui-btn layui-btn-xs layui-btn-danger delete-btn delete-attachment-btn" data-id="' + fileId + '" data-name="' + fileName + '">删除</button>' : '',
                            '       </div>',
                            '   </td>',
                            '</tr>',
                        ].join('');
                    }
                } else {
                    html += '<tr><td colspan="2" style="text-align: center;">没有附件</td></tr>';
                }
                html += [
                    '       </tbody>',
                    '   </table>',
                    '</div>'
                ].join('');

                var area;
                var offset;
                if (isApp) {
                    area = ['100%', '400px'];
                    offset = 'b';
                } else {
                    area = ['400px', '100%'];
                    offset = 'r';
                }
                layer.open({
                    type: 1,
                    title: false,
                    area: area,
                    offset: offset,
                    anim: 2,
                    isOutAnim: false,
                    closeBtn: 0,
                    shadeClose: true,
                    content: html
                });
            });

            // 附件删除
            $(document.body).on('click', '.delete-attachment-btn', function () {
                var id = this.dataset.id;
                var name = this.dataset.name;
                var files = $('#attachments').val().replace(id + ':' + name, '');
                files = files.replace(/\,+/g, ',');
                if (files.charAt(0) == ',') {
                    files = files.substring(1);
                }
                if (files.charAt(files.length - 1) == ',') {
                    files = files.substring(0, files.length - 1);
                }
                $('#attachments').val(files);
                $(this).parent().parent().parent().remove();
            });

            // 附件预览
            $(document.body).on('click', '.operation .preview-btn', function () {
                var id = this.dataset.id;
                var name = this.dataset.name;
                if (onPreview) {
                    onPreview({
                        data: {
                            fileId: id,
                            fileName: name
                        },
                        elem: this
                    });
                }
            });

            // 打印
            $(document.body).on('click', '#printBtn', function () {
                closeBtns();
                if (!formCode || !formVersion || !uid) {
                    return;
                }
                window.open(restAjax.path('route/oa-form-report/print/code/{formCode}/version/{formVersion}/uid/{uid}', [formCode, formVersion, uid]), '_blank');
            });

            // 回退页面
            $(document.body).on('click', '#goBackBtn', function () {
                closeBtns();
                if (!taskId) {
                    return;
                }
                if (!processInstanceId) {
                    return;
                }
                var goBackUserTasks = formButton.goBackUserTasks;
                var html = [
                    '<div class="form-upload-file" style="margin: 0 10px;">',
                    '   <table class="layui-table" lay-size="sm">',
                    '       <colgroup>',
                    '           <col>',
                    '           <col width="60">',
                    '       </colgroup>',
                    '       <thead>',
                    '       <tr>',
                    '           <th>节点名称</th>',
                    '           <th class="operation">操作</th>',
                    '       </tr>',
                    '       </thead>',
                    '       <tbody>',
                ].join('');
                for (var i = 0, goBackUserTask; goBackUserTask = goBackUserTasks[i++];) {
                    html += [
                        '<tr>',
                        '   <td>' + goBackUserTask.taskName + '</a></td>',
                        '   <td class="operation">',
                        '       <button type="button" class="layui-btn layui-btn-xs layui-btn-danger go-back-btn" data-node-id="' + goBackUserTask.nodeId + '">回退</button>',
                        '   </td>',
                        '</tr>',
                    ].join('');
                }
                html += [
                    '       </tbody>',
                    '   </table>',
                    '</div>'
                ].join('');
                layer.open({
                    type: 1,
                    title: false,
                    area: ['350px', '100%'],
                    offset: 'r',
                    anim: 2,
                    isOutAnim: false,
                    closeBtn: 0,
                    shadeClose: true,
                    content: html
                });
            });

            // 回退
            $(document.body).on('click', '.go-back-btn', function () {
                closeBtns();
                if (!taskId) {
                    return;
                }
                if (!processInstanceId) {
                    return;
                }
                var nodeId = this.dataset.nodeId;
                layer.confirm('确定回退吗?', function (confirmLayerIndex) {
                    layer.close(confirmLayerIndex);

                    layer.prompt({title: '请输入回退原因', formType: 2}, function (reason, promptIndex) {
                        layer.close(promptIndex);

                        var loadLayerIndex;
                        var url;
                        if (isApp) {
                            url = 'app/oa-form-report/update-go-back/process-instance-id/{processInstanceId}/task-id/{taskId}/node-id/{nodeId}';
                        } else {
                            url = 'api/oa-form-report/update-go-back/process-instance-id/{processInstanceId}/task-id/{taskId}/node-id/{nodeId}';
                        }
                        restAjax.put(restAjax.path(url, [processInstanceId, taskId, nodeId]), {
                            reason: reason
                        }, null, function (code, data) {
                            layer.msg('回退成功', {offset: getMsgOffset(isApp)});
                            formButton.btnAttachment = 0;
                        }, function (code, data) {
                            $('.confirm-btn, .go-back-btn, .delete-btn').show();
                            layer.msg(data.msg, {offset: getMsgOffset(isApp)});
                        }, function () {
                            $('.confirm-btn, .go-back-btn, .delete-btn').hide();
                            loadLayerIndex = layer.msg('提交中...', {icon: 16, time: 0, shade: 0.3});
                        }, function () {
                            layer.close(loadLayerIndex);
                        });
                    });
                });
            })

            // 强制结束
            $(document.body).on('click', '#forcedEndBtn', function () {
                closeBtns();
                $('#appFormBtns').click();
                $('#formBtns').click();
                layer.confirm('确定结束吗?', {title: false}, function (confirmLayerIndex) {
                    layer.close(confirmLayerIndex);

                    layer.prompt({
                        title: '请输入结束原因',
                        formType: 2,
                        offset: getMsgOffset(isApp)
                    }, function (reason, promptIndex) {
                        layer.close(promptIndex);

                        var loadLayerIndex;
                        var url;
                        if (isApp) {
                            url = 'app/oa-form-report/update-forced-end/process-instance-id/{processInstanceId}/task-id/{taskId}';
                        } else {
                            url = 'api/oa-form-report/update-forced-end/process-instance-id/{processInstanceId}/task-id/{taskId}';
                        }

                        restAjax.put(restAjax.path(url, [processInstanceId, taskId]), {
                            reason: reason
                        }, {
                            headers: headers
                        }, function (code, data) {
                            layer.msg('结束成功', {offset: getMsgOffset(isApp)});
                            formButton.btnAttachment = 0;
                        }, function (code, data) {
                            $('.confirm-btn, .go-back-btn').show();
                            layer.msg(data.msg, {offset: getMsgOffset(isApp)});
                        }, function () {
                            $('.confirm-btn, .go-back-btn').hide();
                            loadLayerIndex = layer.msg('提交中...', {icon: 16, time: 0, shade: 0.3});
                        }, function () {
                            layer.close(loadLayerIndex);
                        });
                    });
                });
            })

            // 抄送
            $(document.body).on('click', '#ccBtn', function () {
                closeBtns();

                function getCcArray() {
                    var selectedUserIdArray = [];
                    if (!$('#ccs').val()) {
                        return selectedUserIdArray;
                    }
                    var ccsArray = $('#ccs').val().split(',');
                    for (var i = 0, item; item = ccsArray[i++];) {
                        if (!item) {
                            continue;
                        }
                        selectedUserIdArray.push(item);
                    }
                    return selectedUserIdArray;
                }

                var oaUserSelect = new OaUserSelect(layui, {
                    isApp: isApp,
                    headers: headers,
                    departmentRootId: 0,
                    selectedUserIdArray: getCcArray(),
                    onConfirm: function (selectedUserArray) {
                        var ccs = '';
                        for (var i = 0, item; item = selectedUserArray[i++];) {
                            if (ccs.length > 0) {
                                ccs += ',';
                            }
                            ccs += item.userId;
                        }
                        $('#ccs').val(ccs);
                    }
                });
                oaUserSelect.open();
            })

            // 转交
            $(document.body).on('click', '#transferBtn', function () {
                closeBtns();
                var osUserSelect = new OaUserSelect(layui, {
                    isApp: isApp,
                    headers: headers,
                    departmentRootId: 0,
                    selectType: 'radio',
                    onConfirm: function (selectedUserArray) {
                        if (selectedUserArray.length == 0) {
                            return;
                        }
                        layer.confirm('确定转交吗?', {title: false}, function (confirmLayerIndex) {
                            layer.close(confirmLayerIndex);
                            layer.prompt({
                                title: '请输入转交原因',
                                formType: 2,
                                offset: getMsgOffset(isApp)
                            }, function (reason, promptIndex) {
                                layer.close(promptIndex);

                                var loadLayerIndex;
                                var url;
                                if (isApp) {
                                    url = 'app/oa-form-report/update-assignee/process-instance-id/{processInstanceId}/task-id/{taskId}';
                                } else {
                                    url = 'api/oa-form-report/update-assignee/process-instance-id/{processInstanceId}/task-id/{taskId}';
                                }

                                restAjax.put(restAjax.path(url, [processInstanceId, taskId]), {
                                    assignee: selectedUserArray[0].userId,
                                    reason: reason
                                }, {
                                    headers: headers
                                }, function (code, data) {
                                    layer.msg('转交成功', {offset: getMsgOffset(isApp)});
                                    formButton.btnAttachment = 0;
                                }, function (code, data) {
                                    $('.confirm-btn, .go-back-btn, .delete-btn').show();
                                    layer.msg(data.msg, {offset: getMsgOffset(isApp)});
                                }, function () {
                                    $('.confirm-btn, .go-back-btn, .delete-btn').hide();
                                    loadLayerIndex = layer.msg('转交中...', {icon: 16, time: 0, shade: 0.3});
                                }, function () {
                                    layer.close(loadLayerIndex);
                                });
                            });
                        });
                    }
                });
                osUserSelect.open();
            })
        }

        initButton();
        addClick();
    }

    /**
     * @callback onConfirm
     * @param selectedUsers {Array} [{userId: '', userName: '', userUsername: ''}]
     */
    /**
     * @description 选择用户列表
     * @param opt {object}
     * @param {String} opt.selectType 'radio|checkbox' 必传，2选1
     * @param {onConfirm} opt.onConfirm 确定按钮回调函数，必传
     * @param {Array} opt.users 参与选择的用户列表，必传，格式：[{userId: '', userUsername: '', userName: ''}]
     * @param {Array} opt.selectedUserIds 默认选中的用户ID列表，非必传，如果selectType为 radio，默认选中[0]。格式：['userId1', 'userId2']
     */
    this.selectUsers = function (opt) {
        var selectType = opt.selectType,
            onConfirm = opt.onConfirm,
            users = opt.users,
            selectedUserIds = opt.selectedUserIds;
        if (selectType != 'radio' && selectType != 'checkbox') {
            throw 'selectType(arg1): [radio|checkbox]';
            return;
        }
        if (!users && !(users instanceof Array)) {
            onConfirm([]);
        }

        selectedUserIds = selectedUserIds && (selectedUserIds instanceof Array) ? selectedUserIds : [];
        selectedUserIds = selectType == 'radio' && selectedUserIds.length > 1 ? selectedUserIds[0] : selectedUserIds;

        var selectedUserMap = {};
        var selectedUsers = [];
        var itemHtml = '';

        function addUserToMap(userId, userUsername, userName) {
            selectedUserMap[userId] = {
                userId: userId,
                userUsername: userUsername,
                userName: userName,
            }
        }

        function addClick() {
            $('.select-user .list .item').click(function () {
                var dataset = this.dataset;
                var userId = dataset.userId;
                if (selectType === 'radio') {
                    $('.select-user .list .item').removeClass('active');
                    $(this).addClass('active');
                    selectedUserMap = {};
                    addUserToMap(userId, dataset.userUsername, dataset.userName);
                } else {
                    if (selectedUserMap[userId]) {
                        delete selectedUserMap[userId];
                        $(this).removeClass('active');
                    } else {
                        addUserToMap(userId, dataset.userUsername, dataset.userName);
                        $(this).addClass('active');
                    }
                }
            });
            $('.select-user .foot .confirm-btn').click(function () {
                for (var key in selectedUserMap) {
                    selectedUsers.push(selectedUserMap[key]);
                }
                if (selectedUsers.length == 0) {
                    layer.msg('请选择人员');
                    return;
                }
                layer.close(layIndex);
            });
            $('.select-user .foot .close-btn').click(function () {
                selectedUsers = null;
                layer.close(layIndex);
            });
        }

        // 添加用户到map
        for (var i = 0, user; user = users[i++];) {
            var isActive = false;
            for (var j = 0, selectedUserId; selectedUserId = selectedUserIds[j++];) {
                if (user.userId === selectedUserId) {
                    isActive = true;
                    addUserToMap(user.userId, user.userUsername, user.userName);
                    break;
                }
            }
            itemHtml += '<div class="item' + (isActive ? ' active' : '') + '" data-user-id="' + user.userId + '" data-user-username="' + user.userUsername + '" data-user-name="' + user.userName + '">';
            itemHtml += '<div class="avatar">';
            if (user.avatar) {
                itemHtml += '<img src="route/file/v2/download/true/' + user.avatar + '"/>';
            } else {
                itemHtml += '<img src="assets/images/profile-photo.jpg"/>';
            }
            itemHtml += '</div>';
            itemHtml += '<div class="info">';
            itemHtml += '<div class="text">' + user.userUsername + '</div>';
            itemHtml += '<div class="text">' + user.userName + '</div>';
            itemHtml += '</div>';
            itemHtml += '<div class="checkbox">';
            itemHtml += '<i class="fa fa-check-square-o"></i>';
            itemHtml += '</div>';
            itemHtml += '</div>';
        }

        var layIndex = layer.open({
            type: 1,
            area: ['300px', '400px'],
            closeBtn: 0,
            title: '选择候选人',
            shadeClose: false,
            scrollbar: false,
            content: '<div class="select-user">' +
                '<div class="list">'
                + itemHtml +
                '</div>' +
                '<div class="foot">' +
                '<div class="layui-btn-group">' +
                '<button type="button" class="layui-btn layui-btn-sm confirm-btn">确定</button>' +
                '<button type="button" class="layui-btn layui-btn-sm layui-btn-primary close-btn">关闭</button>' +
                '</div>' +
                '</div>' +
                '</div>',
            end: function () {
                onConfirm(selectedUsers);
            }
        });

        addClick();
    }

}