henryyan
8/2/2012 - 8:29 AM

jquery.workflow.js

jquery.workflow.js

/**
 * jquery.workflow.js
 * 说明:工作流相关的功能
 * @author HenryYan
 */
;
(function($) {
    $.workflow = $.workflow || {};
    $.workflow.trace = $.workflow.trace || {};
    $.extend($.workflow.trace, {
        /*
         * 跟踪流转记录
         */
        traceList: function(pid, containerId, listId, pagerId) {
        
            // 如果已经打开列表了,只刷新数据
            if ($('#gbox_' + listId).length == 1) {
                $("#" + listId).jqGrid('setGridParam', {
                    url: ctx + '/activiti/activiti-task!historicActivityInstances.action',
                    postData: {
                        processInstanceId: pid
                    }
                }).trigger('reloadGrid');
                return;
            }
            
            // 对话框高度
            var size = {
                height: $('#' + containerId + ' .ui-accordion-content').height() - 55,
                width: $('#' + containerId + ' .ui-accordion-content').width() - 2
            };
            
            $("#" + listId).jqGrid($.extend({}, $.common.plugin.jqGrid.settings({
                size: size,
                pager: '#' + pagerId
            }), {
                url: ctx + '/activiti/activiti-task!historicActivityInstances.action',
                postData: {
                    processInstanceId: pid
                },
                colNames: ['节点', '操作人', '任务创建时间', '任务结束时间', '任务耗时'/*, '信息点', '描述'*/],
                colModel: [{
                    name: 'activityName',
                    align: 'center',
                    formatter: function(cellValue, options, rowObject) {
                        if (rowObject.activityType == 'startEvent') {
                            return "<font color='green'><b>启动流程</b></font>";
                        } else {
                            return cellValue;
                        }
                    }
                }, {
                    name: 'assigneeUser',
                    align: 'center',
                    formatter: function(cellValue, options, rowObject) {
                        if (!cellValue) {
                            return "";
                        }
                        var userName = !cellValue.name ? "" : cellValue.name;
                        var loginName = !cellValue.loginName ? "" : cellValue.loginName;
                        var orgName = !cellValue.org ? "" : cellValue.org.name;
                        
                        var text = userName + "/" + loginName + "/" + orgName;
                        return text == "/" ? "" : text;
                    }
                }, {
                    name: 'startTime',
                    align: 'center',
                    formatter: function(cellValue, options, rowObject) {
                        return new Date(cellValue).format("yyyy-MM-dd hh:mm:ss");
                    }
                }, {
                    name: 'endTime',
                    align: 'center',
                    formatter: function(cellValue, options, rowObject) {
                        if (!cellValue) {
                            return '';
                        }
                        return new Date(cellValue).format("yyyy-MM-dd hh:mm:ss");
                    }
                }, {
                    name: 'durationInMillis',
                    align: 'center',
                    formatter: function(cellValue, options, rowObject) {
                        return $.common.custom.timeRange(parseInt(cellValue));
                    }
                }                /*, {
                 name: 'variables',
                 formatter: function(cellValue, options, rowObject) {
                 if (cellValue != null && cellValue != undefined) {
                 var contents = '';
                 $.each(cellValue, function(i, v) {
                 $.log.debug('rowObject.taskDefinitionKey=' + rowObject.taskDefinitionKey);
                 $.log.debug('i=' + i);
                 // 逐层判断配置是否存在
                 if ($.workflow.trace.variables) {
                 var variablesForProcess = $.workflow.trace.variables[rowObject.processDefinitionKey];
                 if (variablesForProcess) {
                 var variablesForTask = variablesForProcess[rowObject.taskDefinitionKey];
                 if (variablesForTask && variablesForTask[i]) {
                 var variableText = variablesForTask[i].text;
                 if (variableText) {
                 if (contents.length > 0) {
                 contents += "<br/>";
                 }
                 var varValue = v;
                 if ($.isFunction(variablesForTask[i].formatter)) {
                 varValue = variablesForTask[i].formatter(v);
                 }
                 contents += variableText + ":" + varValue;
                 }
                 }
                 }
                 }
                 });
                 return contents;
                 }
                 return '';
                 }
                 }, {
                 name: 'description'
                 }*/
                ],
                loadComplete: function(data) {
                },
                pgbuttons: false,
                pagerpos: false,
                pginput: false,
                pgtext: false
            })).jqGrid('navGrid', '#' + pagerId, $.extend({}, $.common.plugin.jqGrid.pager, {
                add: false,
                edit: false,
                del: false,
                search: false
            }), {}, {}, {}, $.extend({}, $.common.plugin.jqGrid.form.search), {});
        }
    });
    
    $.extend($.workflow, {
        /*
         * 图片形式跟踪流程
         */
        graphTrace: function(options) {
        
            var _defaults = {
                srcEle: this,
                pid: $(this).attr('pid')
            };
            var opts = $.extend(true, _defaults, options);
            
            var imageUrl = ctx + "/activiti/activiti!loadResource.action?resourceType=image&processInstanceId=" + opts.pid;
            $.getJSON(ctx + '/activiti/activiti!traceProcess.action?processInstanceId=' + opts.pid, function(infos) {
            
                var positionHtml = "";
                
                var varsArray = new Array();
                
                $.each(infos, function(i, v) {
                    var $positionDiv = $('<div/>', {
                        'class': 'activiyAttr'
                    }).css({
                        position: 'absolute',
                        left: (v.x - 1),
                        top: (v.y - 1),
                        width: (v.width - 2),
                        height: (v.height - 2)
                    })
                    if (v.currentActiviti) {
                        $positionDiv.addClass('ui-corner-all-12').css({
                            border: '2px solid red'
                        });
                    }
                    positionHtml += $positionDiv.outerHTML();
                    
                    varsArray[varsArray.length] = v.vars;
                });
                
                if ($('#workflowTraceDialog').length == 0) {
                    $('<div/>', {
                        id: 'workflowTraceDialog',
                        title: '查看流程(按ESC键可以关闭)',
                        html: "<div id='workflowTraceAccordion'><h3><a href='#'>图片形式</a></h3><div><img src='" + imageUrl + "' style='position:absolute; left:0px; top:0px;' />" +
                        "<div id='processImageBorder'>" +
                        positionHtml +
                        "</div>" +
                        "</div><h3><a href='#'>文字形式</a></h3><div id='workflowTrace' class='workflow-trace-container'>" +
                        "<table id='workflowTraceList'></table><div id='workflowTracePager'></div></div></div>"
                    }).appendTo('body');
                } else {
                    $('#workflowTraceDialog img').attr('src', imageUrl);
                    $('#workflowTraceDialog #processImageBorder').html(positionHtml);
                }
                
                // 设置每个节点的data
                $('#workflowTraceDialog .activiyAttr').each(function(i, v) {
                    $(this).data('vars', varsArray[i]);
                });
                
                $('#workflowTraceDialog').dialog({
                    modal: true,
                    resizable: false,
                    dragable: false,
                    open: function() {
                        $("#workflowTraceAccordion").accordion();
                        $('#workflowTraceDialog').css('padding', '0.2em');
                        $('#workflowTraceDialog .ui-accordion-content').css('padding', '0.2em').height($('#workflowTraceDialog').height() - 75);
                        $.workflow.trace.traceList(opts.pid, 'workflowTraceDialog', 'workflowTraceList', 'workflowTracePager');
                        
                        $('.activiyAttr').qtip({
                            content: function() {
                                var vars = $(this).data('vars');
                                var tipContent = "<table class='need-border'>";
                                $.each(vars, function(varKey, varValue) {
                                    if (varValue) {
                                        tipContent += "<tr><td class='label'>" + varKey + "</td><td>" + varValue + "<td/></tr>";
                                    }
                                });
                                tipContent += "</table>";
                                return tipContent;
                            },
                            position: {
                                at: 'bottom left',
                                adjust: {
                                    x: 5
                                }
                            }
                        });
                    },
                    width: $.common.window.getClientWidth(),
                    height: $.common.window.getClientHeight()
                });
                
            });
        },
        /*
         * 打开跟踪流程流转记录对话框
         */
        showTraceList: function() {
            var pid = $(this).attr('pid');
            if ($('#workflowTraceHistoricDialog').length == 0) {
                $('<div/>', {
                    id: 'workflowTraceHistoricDialog',
                    title: '查看流程(按ESC键可以关闭)',
                    html: "<table id='workflowTraceHistoricList'></table><div id='workflowTraceHistoricPager'></div>"
                }).appendTo('body');
            }
            
            $('#workflowTraceHistoricDialog').dialog({
                modal: true,
                resizable: false,
                dragable: false,
                open: function() {
                    $.workflow.trace.traceList(pid, 'workflowTraceHistoricDialog', 'workflowTraceHistoricList', 'workflowTraceHistoricPager');
                },
                width: $.common.window.getClientWidth(),
                height: $.common.window.getClientHeight()
            });
        },
        /*
         * 删除流程实例
         */
        deleteProcess: function(pid, callback) {
            $('#deleteProcessTemplate').remove();
            $('<div/>', {
                id: 'deleteProcessTemplate',
                title: '删除流程',
                html: "<textarea id='deleteProcessReason' style='width:100%;height: 100%'></textarea>"
            }).dialog({
                modal: true,
                buttons: [{
                    text: '删除',
                    click: function() {
                        var dialog = this;
                        if ($('#deleteProcessReason').val() == '') {
                            alert('请输入原因!');
                            return;
                        }
                        $.post(ctx + '/activiti/activiti!deleteProcessInstance.action', {
                            processInstanceId: pid,
                            deleteReason: $('#deleteProcessReason').val()
                        }, function(resp) {
                            $(dialog).dialog('close');
                            if (resp == 'success') {
                                if ($.isFunction(callback)) {
                                    callback();
                                }
                            } else {
                                alert('删除流程失败');
                            }
                        });
                    }
                }, {
                    text: '取消',
                    click: function() {
                        $(this).dialog('close');
                    }
                }]
            });
        },
        /*
         * 完成任务
         */
        complete: function(options) {
        	
            var opts;
            var _success = function(data, textStatus, jqXHR) {
                if (data == 'success') {
                    if (opts.closeDialog && opts.dialog) {
                        $(opts.dialog).dialog('close');
                    }
                    $('#' + opts.row.listId).jqGrid().trigger('reloadGrid');
                } else {
                    alert('操作失败,原因:' + data);
                }
                if ($.isFunction(opts.callback)) {
                    opts.callback(data, textStatus, jqXHR);
                }
            };
            var _error = function(jqXHR, textStatus, errorThrown) {
                alert('操作失败!');
            };
            
            // 选择人员
            var selectUser = false;
            try {
	            if ($.isFunction(options.settings.selectUser)) {
	            	selectUser = options.settings.selectUser(options.row.rowData);
	            } else {
	            	selectUser = options.settings.selectUser;
	            }
            } catch (e) {
            	
            }
            if (options.settings && selectUser) {
            	var nextTaskParam = {};
            	if ($.isFunction(options.settings.nextTask)) {
            		nextTaskParam = options.settings.nextTask.call(this, options.row.rowData);
            	} else {
            		nextTaskParam = options.settings.nextTask; 
            	}
            	
                var taskName = "";
                if (typeof nextTaskParam.taskName == 'string') {
                    taskName = nextTaskParam.taskName;
                } else if ($.isFunction(nextTaskParam.taskName)) {
                	// 通过函数方式获取节点名称,因为考虑到可能需要条件判断
                    taskName = nextTaskParam.taskName(options);
                }
                var taskZhName = options.row.rowData.taskNames[taskName] || taskName;
                $.roleuser({
                    role: nextTaskParam.role,
                    title: '选择[' + taskZhName + ']节点任务处理人',
                    confirmSelect: function(data) {
                        options.vars.push({
                            key: nextTaskParam.assingee,
                            value: data.id,
                            type: 'S'
                        });
                        sendRequest();
                    },
                    tree: {
                        loadComplete: function(data) {
                            // 单个用户时自动选择并确定
                            if (data.length == 1) {
                                if (confirm('是否由系统将自动提交给[' + data[0].attr.userName + ']?')) {
                                    options.vars.push({
                                        key: nextTaskParam.assingee,
                                        value: data[0].attr.id,
                                        type: 'S'
                                    });
                                    sendRequest();
                                    $(this).dialog('close');
                                }
                            }
                        }
                    }
                });
            } else {
                sendRequest();
            }
            
            function sendRequest() {
                // ajax params
                var _ajaxParams = {
                    url: ctx + '/activiti/activiti-task!complete.action',
                    type: 'post',
                    data: {
                        taskId: options.row.rowData.task.id,
                        variables: $.jsonToString(options.vars)
                    },
                    beforeSend: function() {
                        if (confirm('提交流程到下个节点?')) {
                            return true;
                        }
                        return false;
                    },
                    success: _success,
                    error: _error
                };
                $.log.debug('compelte variables:' + $.jsonToString(options.vars));
                var _defaults = {
                    row: {},
                    vars: {},
                    dialog: null, // 需要关闭的对话框,支持多个对话框,传入参数的时候可以$('#aaa').add('#bbb')
                    closeDialog: true, // 提交完成是否关闭对话框
                    ajaxOpts: _ajaxParams,
                    callback: null
                };
                opts = $.extend(true, _defaults, options);
                
                // send ajax request
                $.ajax($.extend({}, opts.ajaxOpts));
            }
            
        },
        /*
         * 驳回row, vars
         */
        reject: function(options) {
            var _btns = [{
                text: '驳回',
                icons: 'ui-icon-arrowreturnthick-1-w',
                click: function() {
                    var turnDownReason = $('#turnDownReason', this).val();
                    if (turnDownReason == '') {
                        alert('请输入驳回理由!');
                        $('#turnDownReason', this).focus();
                        return;
                    }
                    options.vars[options.vars.length] = {
                        key: 'turnDownReason',
                        type: 'S',
                        value: turnDownReason
                    };
                    
                    var _innerDialog = this;
                    $.workflow.complete({
                        row: options.row,
                        vars: options.vars,
                        dialog: $(options.dialog).add(_innerDialog)
                    });
                }
            }, {
                text: '取消',
                icons: 'ui-icon-cancel',
                click: function() {
                    $(this).dialog('close');
                    if ($.isFunction(options.settings.afterClose)) {
                        options.settings.afterClose();
                    }
                }
            }];
            $('<div/>', {
                title: '驳回理由?',
                html: "<textarea id='turnDownReason' title='请填写驳回理由' style='height: 70px;width: 100%'></textarea>"
            }).dialog({
                modal: true,
                zIndex: 16000,
                open: function() {
                    $.common.plugin.jqui.dialog.button.setAttrs(_btns);
                },
                close: function() {
                    if ($.isFunction(options.settings.beforeClose)) {
                        options.settings.beforeClose();
                    }
                },
                buttons: _btns
            });
        },
        /*
         * 返回代理实现
         */
        getAccessor: function(obj, expr) {
            var ret, p, prm = [], i;
            if (typeof expr === 'function') {
                return expr(obj);
            }
            ret = obj[expr];
            if (ret === undefined) {
                try {
                    if (typeof expr === 'string') {
                        prm = expr.split('.');
                    }
                    i = prm.length;
                    if (i) {
                        ret = obj;
                        while (ret && i--) {
                            p = prm.shift();
                            ret = ret[p];
                        }
                    }
                } catch (e) {
                }
            }
            return ret;
        },
        extend: function(methods) {
            $.extend($.fn.workflow, methods);
        }
    });
    
    $.fn.workflow = function(pin) {
        if (typeof pin == 'string') {
            var fn = $.workflow.getAccessor($.fn.workflow, pin);
            if (!fn) {
                throw ("workflow - No such method: " + pin);
            }
            var args = $.makeArray(arguments).slice(1);
            return fn.apply(this, args);
        }
        
        return this.each(function() {
            // empty
        });
    };
    
    // 各种工作流中使用的功能
    $.workflow.extend({
    
        /*
         * 签收
         */
        claim: function(options) {
            var _defaults = {
                listId: 'list',
                confirm: true,
                callback: null
            };
            var opts = $.extend(true, _defaults, options);
            
            /**
             * 签收动作
             */
            function claim(srcEle, opts) {
                $.ajax({
                    url: ctx + '/activiti/activiti-task!claim.action',
                    data: 'taskId=' + $(srcEle).attr('taskId')
                }).success(function(resp) {
                    if (resp == 'success') {
                        $('#' + opts.listId).jqGrid().trigger('reloadGrid');
                    } else {
						alert('签收任务失败,原因:' + resp);
					}
                    if ($.isFunction(opts.callback)) {
                        opts.callback();
                    }
                });
            };
            
            // 循环处理
            this.each(function() {
                var _this = $(this);
                
                // 美化按钮
                if (_this.get(0).nodeName == 'BUTTON') {
                    _this.button({
                        icons: {
                            primary: 'ui-icon-person'
                        }
                    });
                } else {
                    alert('目前仅支持按钮');
                    return;
                }
                
                _this.off('click').on('click', function() {
                    if (opts.confirm) {
                        if (confirm('签收此任务?')) {
                            claim(this, opts);
                        }
                    } else {
                        claim(this, opts);
                    }
                });
            });
        },
        /*
         * 办理
         */
        handle: function(options) {
            var _defaults = {
                listId: 'list',
                template: '', // 最外层模板
                map: {}
            };
            var opts = $.extend(true, _defaults, options);
            
            // 循环处理
            this.each(function() {
                var _this = $(this);
                var pid = _this.attr('pid');
                var taskId = $(this).attr('taskId');
                
                // 美化按钮
                if (_this.get(0).nodeName == 'BUTTON') {
                    _this.button({
                        icons: {
                            primary: 'ui-icon-check'
                        }
                    });
                } else {
                    alert('目前仅支持按钮');
                    return;
                }
                
                _this.on('click', function() {
                    var rowId = $(this).parents('tr').attr('id');
                    // 当前节点英文、中文名称
                    var currentNode = {
                        en: $(this).attr('taskDefinitionKey'),
                        cn: $(this).attr('taskName')
                    };
                    
                    var _handleDefault = {
                        form: {
                            autoSetValue: true,
                            fieldContainer: null,
                            afterSetValue: null,
                            valueFilter: null
                        },
                        dialog: {
                            modal: true,
                            width: 300,
                            height: 300,
                            title: {
                                pre: '任务办理—[',
                                text: '',
                                suffix: ']'
                            },
                            afterOpen: null
                        },
                        flow: {
                            buttons: {
                                complete: {
                                    show: true,
                                    text: '提交',
                                    title: '提交至下一节点',
                                    icons: 'ui-icon-circle-arrow-e'
                                },
                                sendBack: {
                                    show: false,
                                    text: '退回',
                                    title: '退回至下一节点',
                                    icons: 'ui-icon-arrowreturnthick-1-w'
                                },
                                reject: {
                                    show: false,
                                    text: '驳回',
                                    title: '驳回请求',
                                    icons: 'ui-icon-closethick'
                                },
                                redirect: {
                                    show: false,
                                    text: '转办',
                                    title: '把当前任务转给其他人处理',
                                    icons: 'ui-icon-person'
                                },
                                delProc: {
                                    show: false,
                                    text: '删除流程',
                                    title: '删除流程实例',
                                    icons: 'ui-icon-trash'
                                },
                                close: {
                                    show: true,
                                    text: '关闭',
                                    title: '关闭对话框',
                                    icons: 'ui-icon-cancel',
                                    click: function() {
                                        $(this).dialog("close");
                                    }
                                },
                                attachs: []
                            },
                            buttonSettings: {
                                complete: {
                                    variables: [],
                                    ajaxOpts: {},
                                    beforeShow: null,
                                    afterShow: null,
                                    beforeSubmit: null,
                                    afterSubmit: null,
                                    beforeClose: null,
                                    afterClose: null,
                                    selectUser: false,
                                    click: $.workflow.complete,
                                    selectUser: false
                                },
                                sendBack: {
                                    variables: [],
                                    ajaxOpts: {},
                                    beforeShow: null,
                                    afterShow: null,
                                    beforeSubmit: null,
                                    afterSubmit: null,
                                    beforeClose: null,
                                    afterClose: null,
                                    click: function(data) {
                                        alert('暂未实现');
                                    }
                                },
                                reject: {
                                    variables: [],
                                    ajaxOpts: {},
                                    beforeShow: null,
                                    afterShow: null,
                                    beforeSubmit: null,
                                    afterSubmit: null,
                                    beforeClose: null,
                                    afterClose: null,
                                    click: $.workflow.reject
                                },
                                redirect: {
                                    variables: [],
                                    ajaxOpts: {},
                                    beforeShow: null,
                                    afterShow: null,
                                    beforeSubmit: null,
                                    afterSubmit: null,
                                    beforeClose: null,
                                    afterClose: null,
                                    click: function(data) {
                                        alert('暂未实现');
                                    }
                                },
                                delProc: {
                                    variables: [],
                                    ajaxOpts: {},
                                    beforeShow: null,
                                    afterShow: null,
                                    beforeSubmit: null,
                                    afterSubmit: null,
                                    beforeClose: null,
                                    afterClose: null,
                                    click: function(data) {
                                        var dialogBtn = this;
                                        $.workflow.deleteProcess(pid, function() {
                                            $(dialogBtn).dialog('close');
                                            $('#' + opts.listId).jqGrid().trigger('reloadGrid');
                                        });
                                    }
                                },
                                attachs: {}
                            }
                        }
                    };
                    var handleOpts = $.extend(true, _handleDefault, opts.map[currentNode.en]);
                    
                    var _handle_dialog = {
                        getButtons: function(ele) {
                            var btns = [];
                            // 扩展按钮
                            $.each(handleOpts.flow.buttons.attachs, function() {
                                btns[btns.length] = this;
                            });
                            
                            // 流程按钮
                            $.each(handleOpts.flow.buttons, function(i, v) {
                                if (v.show) {
                                    try {
                                        if (!v.click) {
                                            v.click = function() {
                                                var _srcEle = this;
                                                var _cbtns = handleOpts.flow.buttonSettings[i];
                                                
                                                var _rowId = rowId;
                                                var _listId = opts.listId;
                                                var _rowData = $('body').data('jqgridResult_' + opts.listId)[rowId];
                                                var _callback = null;
                                                
                                                // 处理列表中出现多余一个业务对象对应多个task,所以需要把taskId用按钮的属性替换
                                                _rowData.task.id = taskId;
                                                
                                                var _rowParams = {
                                                    rowId: _rowId,
                                                    listId: _listId,
                                                    rowData: _rowData
                                                };
                                                
                                                // 设置值
                                                var _vars = [];
                                                $.each(_cbtns.variables, function() {
                                                    var map = {};
                                                    $.each(this, function(j, jv) {
                                                        if ($.isFunction(jv)) {
                                                            map[j] = jv(_rowParams.rowData);
                                                        } else {
                                                            map[j] = jv;
                                                        }
                                                    });
                                                    _vars[_vars.length] = map;
                                                });
                                                
                                                // 按钮事件--执行前确认
                                                if ($.isFunction(_cbtns.beforeShow)) {
                                                    var result = _cbtns.beforeShow(_rowParams);
                                                    if (!result) {
                                                        return;
                                                    }
                                                }
                                                
                                                // 按钮的click事件
                                                _cbtns.click.call(_srcEle, {
                                                    row: _rowParams,
                                                    vars: _vars,
                                                    settings: _cbtns,
                                                    ajaxOpts: _cbtns.ajaxOpts,
                                                    dialog: $(_srcEle).dialog(),
                                                    callback: _cbtns.afterSubmit
                                                })
                                            };
                                        }
                                    } catch (e) {
                                    }
                                    btns[btns.length] = v;
                                }
                            });
                            return btns;
                        }
                    };
                    
                    // 对话框标题
                    var title = $(this).attr('taskName');
                    if (typeof handleOpts.dialog.title == 'string') {
                        title = handleOpts.dialog.title;
                    } else {
						var _pre = handleOpts.dialog.title.pre;
						if ($.isFunction(_pre)) {
							_pre.call(this, rowId);
						}
						
						var _text = handleOpts.dialog.title.text || title;
                        if ($.isFunction(_text)) {
							_text = _text.call(this, rowId);
						}
						
						var _suffix = handleOpts.dialog.title.suffix;
						if ($.isFunction(_suffix)) {
							_suffix = _suffix.call(this, rowId);
						}
						
                        title = _pre + _text + _suffix;
                    }
                    
                    // 显示对话框
                    var dialogTemplate = $('#' + currentNode.en, opts.template);
                    if (dialogTemplate.length == 0) {
                        dialogTemplate = $('#' + currentNode.en, '.ui-dialog');
                    }
                    var buttons = _handle_dialog.getButtons(_this);
                    dialogTemplate.addClass('workflow-handle-dialog').dialog($.extend(handleOpts.dialog, {
                        title: title,
                        buttons: buttons,
                        open: function() {
                            var _dialog = this;
                            var _listId = opts.listId;
                            var _attachBtns = handleOpts.flow.buttonSettings.attachs;
                            
                            // 错误提示的滚动条
                        	$(_dialog).scroll(function() {
                        		$('.validator-error').each(function() {
                        			var elem = $(this).data('elem');
                        			var position = elem.position();
                        			$(this).css({
                        				top: position.top + elem.height() + elem.height() + 8
                        			});
                        		});
                        	});
                            
                            // 如果handleOpts.form.fieldContainer没有设置默认使用当前的dialog
                            if (!handleOpts.form.fieldContainer) {
                                handleOpts.form.fieldContainer = _dialog;
                            }
                            
                            // 设置按钮属性、功能
                            $.common.plugin.jqui.dialog.button.setAttrs(buttons);
                            
                            // 自定义按钮事件,目的是拦截之后传递一系列参数
                            $.each(_attachBtns, function(i, v) {
                                var attachClick = v.click;
                                if ($.isFunction(attachClick)) {
                                    // 先接触click事件,因为jqueryui在初始化的时候绑定了,否则会报错
                                    $('.ui-button-text').filter(function() {
                                        return $(this).text() == i;
                                    }).parent().off('click').click(function() {
                                        var _rowData = $('body').data('jqgridResult_' + opts.listId)[rowId];
                                        
                                        // 处理列表中出现多余一个业务对象对应多个task,所以需要把taskId用按钮的属性替换
                                        _rowData.task.id = taskId;
                                        
                                        var _rowParams = {
                                            rowId: rowId,
                                            listId: _listId,
                                            rowData: _rowData,
                                            dialog: _dialog
                                        };
                                        
                                        // beforeShow回调
                                        if ($.isFunction(v.beforeShow)) {
                                            var result = v.beforeShow(_vars);
                                            if (!result) {
                                                return;
                                            }
                                        }
                                        
                                        // 自定义的变量,用来控制流程走向或者业务数据
                                        var _vars = [];
                                        if (v.variables) {
                                            $.each(v.variables, function() {
                                                var map = {};
                                                $.each(this, function(j, jv) {
                                                    if ($.isFunction(jv)) {
                                                        map[j] = jv(_rowParams.rowData);
                                                    } else {
                                                        map[j] = jv;
                                                    }
                                                });
                                                _vars[_vars.length] = map;
                                            });
                                        }
                                        
                                        // 回调click事件
                                        attachClick.call(_dialog, _rowParams, _vars, v.afterSubmit);
                                    });
                                }
                            });
                            
                            // 设置表单内容
                            var gridData = $('body').data('jqgridResult_' + opts.listId);
                            if (handleOpts.form.autoSetValue) {
                            
                                // 设置数据
                                $('*[name]', handleOpts.form.fieldContainer).each(function() {
                                    var colModel = $('#' + opts.listId).jqGrid('getGridParam', 'colModel');
                                    var colModelMap = {};
                                    $.each(colModel, function() {
                                        colModelMap[this.name] = this;
                                    });
                                    var nodeName = $(this).get(0).nodeName;
                                    var value = '';
                                    
                                    var eleName = $(this).attr('name');
                                    var objs = eleName.split('.');
                                    if (objs.length > 1) {
                                        // 排除多级属性中为空的情况
                                        try {
                                        	if (eval('(gridData[rowId].' + eleName + ')')) {
                                        		value = eval('(gridData[rowId].' + eleName + ')');
                                        	}
                                        } catch (e) {
                                        	// error
                                        }
                                    } else {
	                                    if ($(this).hasClass('variable')) {
	                            			if (gridData[rowId].variables[eleName]) {
	                            				value = gridData[rowId].variables[eleName];
	                            			}
	                            		} else {
	                            			if (gridData[rowId][eleName]) {
	                            				value = gridData[rowId][eleName];
	                            			}
	                            		}
                                    }
                                    
                                    // 再次让业务处理valueFilter
                                    if ($.isFunction(handleOpts.form.valueFilter)) {
                                    	var newValue = handleOpts.form.valueFilter.call(this, eleName, value, gridData[rowId]);
                                        value = newValue;
                                    }
                                    
                                    
                                    /*
                                     * 只读
                                     */
                                    if (nodeName == 'TD' || nodeName == 'SPAN' || nodeName == 'P' || nodeName == 'DIV' ||
                                    nodeName == 'LI') {
                                        if (colModelMap[$(this).attr('name')] && colModelMap[$(this).attr('name')].formatter == 'date') {
                                            $(this).html($('#' + opts.listId + ' #' + rowId + ' td[aria-describedby=' + opts.listId + '_' + $(this).attr('name') + ']').text());
                                        } else {
                                        	$(this).html(value);
                                        }
                                    } else if (nodeName == 'INPUT' || nodeName == 'SELECT' || nodeName == 'TEXTAREA') {
                                    	/*
                                    	 * 可编辑
                                    	 */
                                        if (!$(this).hasClass('no-auto-set-value')) {
                                            $(this).val(value);
                                        }
                                    }
                                });
                                
                                if ($.isFunction(handleOpts.form.afterSetValue)) {
                                    handleOpts.form.afterSetValue.call(this, gridData[rowId]);
                                }
                            }
                            
                            if ($.isFunction(handleOpts.dialog.afterOpen)) {
                                handleOpts.dialog.afterOpen.call(this, gridData[rowId]);
                            }
                        },
                        close: function() {
                        	
                        	// 销毁验证用的qtip
                        	if ($('.validator-error').length > 0) {
                        		$('.validator-error').qtip('destroy');
                        	}
                        }
                    }));
                });
                
            });
            return this;
        } // end handle
    });
    
})(jQuery);

/*
 * jqgrid支持
 */
(function($) {
    $.workflow.jqgrid = $.workflow.jqgrid || {};
    $.extend($.workflow.jqgrid, {
        /*
         * 列表完成时绑定事件
         */
        gridComplete: function() {
            $('.trace-grpah').off('click').on('click', $.workflow.graphTrace);
            $('.trace-historic').off('click').on('click', $.workflow.showTraceList);
            $('.workflow-claim').workflow('claim');
        },
        
        /*
         * 按钮扩展
         */
        button: {
            /**
             * 任务列表的签收和办理按钮,实现jqgrid的formatter
             * @param {Object} cellValue
             * @param {Object} options
             * @param {Object} rowObject
             */
            handle: function(cellValue, options, rowObject) {
                if (!cellValue) {
                    return '';
                }
                var flowDataType = $('body').data('flowDataType_' + options.gid);
                if (!flowDataType) {
                    flowDataType = 'todo';
                }
                if (flowDataType == 'todo') {
                    var procDef = rowObject.processDefinition;
                    var attrs = "pid='" + cellValue.processInstanceId + "' taskId='" + cellValue.id + "'";
                    attrs += " taskName='" + cellValue.name + "' procDefId='" + procDef.id + "'";
                    attrs += " proDefKey='" + procDef.name + "' version='" + procDef.version + "'";
                    attrs += " taskDefinitionKey='" + cellValue.taskDefinitionKey + "'";
                    return "<button class='workflow-do' + " + attrs + ">办理</button>";
                } else if (flowDataType == 'unsigned') {
                    var attrs = "' taskId='" + cellValue.id + "'";
                    return "<button class='workflow-claim'" + attrs + ">签收</button>";
                }
            }
        }
    });
    
    
    // task类型的流程数据列
    var taskColModels = [{
        name: 'task.createTime',
        align: 'center',
        title: false,
        search: false,
        formatter: "date",
        formatoptions: {
            srcformat: 'Y-m-dTH:i:s',
            newformat: 'Y-m-d H:i:s'
        }
    }, {
        name: 'task.name',
        align: 'center',
        title: false,
        formatter: function(cellValue, options, rowObject) {
            return "<a href='#' class='trace-grpah' title='跟踪流程图' pid='" + rowObject.processInstanceId + "'>" +
            cellValue +
            "</a> " +
            "[<span title='流程版本号'>V:<span style='color:red'>" +
            rowObject.processDefinition.version +
            "</span></span>]";
        }
    }, {
        name: 'task.priority',
        align: 'center',
        width: 70,
		formatter: function(cellValue, options, rowObject) {
			var priority = parseInt(cellValue);
			if (priority >= 0 && priority <50) {
				return "<span class='task-priority-minium'>低</span>";
			} else if (priority >= 50 && priority < 100) {
				return "<span class='task-priority-normal'>一般</span>";
			} else if (priority >= 100) {
				return "<span class='task-priority-maximum'>高</span>";
			}
		}
    }, {
        name: 'historicProcessInstance.startUser',
        index: 'historicProcessInstance.startUserId',
        align: 'center',
        width: 90,
        search: false,
        formatter: function(cellValue, options, rowObject) {
            return !cellValue ? "" : cellValue.name + "/" + cellValue.loginName;
        }
    }, {
        name: 'task',
        align: 'center',
        title: false,
        search: false,
        sortable: false,
        formatter: $.workflow.jqgrid.button.handle
    }];
    
    /**
     * 针对jqgrid的静态定义
     */
    $.extend($.workflow.jqgrid, {
        static: {
            colNames: {
                unsigned: ['发送时间', '当前节点', '优先级', '发起人', '操作'],
                todo: ['发送时间', '当前节点', '优先级', '发起人', '操作'],
                unfinished: ['当前节点', '状态', '发起人'],
                finished: ['发起时间', '发起人', '完成时间', '查看流转']
            },
            colModels: {
                unsigned: taskColModels,
                todo: taskColModels,
                unfinished: [{
                    name: 'task.name',
                    align: 'center',
                    title: false,
                    formatter: function(cellValue, options, rowObject) {
                        var taskName = rowObject.taskNames[rowObject.processInstance.activityId];
                        return "<a href='#' class='trace-grpah' title='跟踪流程图' pid='" + rowObject.processInstanceId + "'>" +
                        taskName +
                        "</a>";
                    }
                }, {
                    name: 'task.status',
                    sortable: false,
                    search: false,
                    align: 'center',
                    formatter: function(cellValue, options, rowObject) {
                        if (rowObject.task == null || rowObject.task.assignee == null) {
                            return '未签收';
                        } else {
                        	var user = rowObject.task.assigneeUser;
                            return '办理中(' + (user ? user.name + "/" + user.loginName : "") + ')';
                        }
                    }
                }, {
                    name: 'historicProcessInstance.startUser',
                    index: 'historicProcessInstance.startUserId',
                    align: 'center',
                    width: 90,
                    search: false,
                    formatter: function(cellValue, options, rowObject) {
                        return !cellValue ? "" : cellValue.name + "/" + cellValue.loginName;
                    }
                }],
                finished: [{
                    name: 'historicProcessInstance.startTime',
                    align: 'center',
                    title: false,
                    width: 80,
                    formatter: "date",
                    formatoptions: {
                        srcformat: 'Y-m-dTH:i:s',
                        newformat: 'Y-m-d H:i:s'
                    }
                }, {
                    name: 'historicProcessInstance.startUser',
                    index: 'historicProcessInstance.startUserId',
                    align: 'center',
                    width: 90,
                    search: false,
                    formatter: function(cellValue, options, rowObject) {
                        return !cellValue ? "" : cellValue.name + "/" + cellValue.loginName;
                    }
                }, {
                    name: 'historicProcessInstance.endTime',
                    align: 'center',
                    title: false,
                    width: 80,
                    formatter: "date",
                    formatoptions: {
                        srcformat: 'Y-m-dTH:i:s',
                        newformat: 'Y-m-d H:i:s'
                    }
                }, {
                    name: 'traceHistoricProcessInstance',
                    align: 'center',
                    width: 80,
                    search: false,
                    sortable: false,
                    formatter: function(cellValue, options, rowObject) {
                        return "<a href='#' class='trace-historic' pid='" + rowObject.processInstanceId + "'>查看</a>";
                    }
                }]
            },
            groupHeaders: {
                unfinished: {
                    startColumnName: 'task.name',
                    numberOfColumns: 5,
                    titleText: '流程信息'
                },
                finished: {
                    startColumnName: 'historicProcessInstance.startTime',
                    numberOfColumns: 4,
                    titleText: '流程信息'
                },
                tasks: {
                    startColumnName: 'task.createTime',
                    numberOfColumns: 4,
                    titleText: '流程信息'
                }
            }
        },
        /**
         * 列表头部的4个状态按钮
         * @param {Object} listId	列表ID
         * @param {Object} data		列表数据,可以通过body的data获取,参见common.js中的loadComplete实现
         * @param {Object} autoResize	自动设置列表高度和宽度参数
         */
        statusBtns: function(listId, data, autoResize) {
            var gridData = data;
            var workflowCounter = gridData.page.attachValues.workflowCounter;
            var taskForGroupCounter = !workflowCounter ? 0 : workflowCounter.unsigned;
            var todoTaskCounter = !workflowCounter ? 0 : workflowCounter.todo;
            var unFinishedCounter = !workflowCounter ? 0 : workflowCounter.unfinished;
            var finishedCounter = !workflowCounter ? 0 : workflowCounter.finished;
            
            if ($('#t_' + listId + ' .workflow-list-status').length == 0) {
                var btns = "<div class='workflow-list-status'>";
                btns += "<input type='radio' id='status1' name='workflowStatus' value='unsigned' /><label for='status1'>未签收:<span class='ui-state-error'>" + taskForGroupCounter + "</span></label>";
                btns += "<input type='radio' id='status2' name='workflowStatus' value='todo' /><label for='status2'>待处理:<span class='ui-state-error'>" + todoTaskCounter + "</span></label>";
                btns += "<input type='radio' id='status3' name='workflowStatus' value='unfinished' /><label for='status3'>运行中:<span class='ui-state-error'>" + unFinishedCounter + "</span></label>";
                btns += "<input type='radio' id='status4' name='workflowStatus' value='finished' /><label for='status4'>已结束:<span class='ui-state-error'>" + finishedCounter + "</span></label>";
                btns += "</div>";
                $('#t_list').css('textAlign', 'center').html(btns);
                $('.workflow-list-status').find(':radio[value=' + $('body').data('flowDataType_list') + ']').attr('checked', 'checked');
                $('.workflow-list-status').buttonset();
                $(':radio[name=workflowStatus]').change(function() {
                    var selectedFlowDataType = $(this).val();
                    
                    // 上次数据类型
                    var lastFlowDataType = $('body').data('flowDataType_' + listId);
                    
                    // 设置本次数据类型
                    $('body').data('flowDataType_' + listId, selectedFlowDataType);
                    
                    // 签收和待处理是一类,运行中和已结束是一类
                    if ((selectedFlowDataType == 'unsigned' || selectedFlowDataType == 'todo') && (lastFlowDataType == 'unsigned' || lastFlowDataType == 'todo')) {
                        listParams = '?flowDataType=' + selectedFlowDataType;
                        $('#list').jqGrid('setGridParam', {
                            url: listDataUrl + '?flowDataType=' + selectedFlowDataType
                        }).trigger('reloadGrid');
                    } else {
                        $('#' + listId).jqGrid('GridUnload', '#' + listId);
                        // 不同类型切换
                        $.common.plugin.jqGrid.autoResize($.extend({
                            dataGrid: '#' + listId,
                            callback: function(size) {
                                var url = listDataUrl + '?flowDataType=' + selectedFlowDataType;
                                listDatas(size, url)
                            }
                        }, autoResize));
                    }
                });
            } else {
                $('.workflow-list-status').show();
                $('label[for=status1] .ui-state-error').text(taskForGroupCounter);
                $('label[for=status2] .ui-state-error').text(todoTaskCounter);
                $('label[for=status3] .ui-state-error').text(unFinishedCounter);
                $('label[for=status4] .ui-state-error').text(finishedCounter);
            }
        }
    });
})(jQuery);