/**
 * Created by Zhong on 2018/1/19.
 **/
const locked = lockUtil.getLocked();
$(document).ready(function () {
    feeItemObj.buildSheet();
    const lockedSpreads = [
        feeItemObj.workBook,
        sectionObj.workBook,
        feeRuleObj.workBook
    ];
    lockUtil.lockSpreads(lockedSpreads, locked);
    $('#sectionTreeModal').on('shown.bs.modal', function (e) {
        batchSectionObj.workBook.refresh();
        //bind confirm btn
        batchSectionObj.onConfirmBtn();
    });
    $('#sectionTreeModal').on('hidden.bs.modal', function () {
        batchSectionObj.clearChecked();
    });
    $('#delConfirm').click(function () {
        if(curDeleteType === feeItemObj.deleteType){
            let me = feeItemObj, se = sectionObj, fr = feeRuleObj;
            let fiPostData = [], sePostData = [];
            let sels = me.workBook.getSheet(0).getSelections();
            for(let i = 0, len = sels.length; i < len; i++){
                let sel = sels[i];
                //delete
                if(sel.colCount === me.setting.header.length){
                    for(let j = 0, jLen = sel.rowCount; j < jLen; j++){
                        let row = sel.row + j;
                        let feeItem = me.cache[row];
                        //有数据，删除数据
                        if(me.isDef(feeItem)){
                            fiPostData.push({updateType: me.updateType.update, updateData: {ID: feeItem.ID, deleted: true}});
                            //delete feeItem section
                            for(let section of feeItem.section){
                                sePostData.push({updateType: me.updateType.update, updateData: {ID: section.ID, deleted: true}});
                            }
                        }
                    }
                    //front delete
                    me.cache.splice(sel.row, sel.rowCount);
                }
            }
            //update currentFeeItem
            me.currentFeeItem = me.getCurrentData(me.sheet, me.cache);
            se.cache = me.isDef(me.currentFeeItem) ? me.currentFeeItem.section : [];
            if(fiPostData.length > 0){
                me.updateFeeItem(fiPostData, function () {
                    me.sheet.setRowCount(me.cache.length + 10);
                    sheetCommonObj.showData(me.sheet, me.setting, me.cache);
                    $('#delAlert').modal('hide');
                });
                if(sePostData.length > 0){
                    se.updateSection(sePostData);
                }
                sheetCommonObj.cleanData(se.sheet, se.setting, 10);
                sheetCommonObj.cleanData(fr.sheet, fr.setting, 10);
            }
            else {
                $('#delAlert').modal('hide');
            }
        }
        else if(curDeleteType === sectionObj.deleteType){
            let me = sectionObj, fi = feeItemObj, fr = feeRuleObj;
            let sePostData = [], fiPostData = [];
            let sels = me.workBook.getSheet(0).getSelections();
            for(let i = 0, len = sels.length; i < len; i++){
                let sel = sels[i];
                //delete
                if(sel.colCount === me.setting.header.length){
                    for(let j = 0, jLen = sel.rowCount; j < jLen; j++){
                        let row = sel.row + j;
                        let section = me.cache[row];
                        //有数据，删除数据
                        if(me.isDef(section)){
                            sePostData.push({updateType: me.updateType.update, updateData: {ID: section.ID, deleted: true}});
                            fiPostData.push({updateType: me.updateType.update, updateData: {ID: fi.currentFeeItem.ID, $pull: {section: {ID: section.ID}}}});
                        }
                    }
                    //front delete
                    me.cache.splice(sel.row, sel.rowCount);
                }
            }
            //update currentSection
            me.currentSection = fi.getCurrentData(me.sheet, me.cache);
            fr.cache = me.isDef(me.currentSection) ? me.currentSection.feeRule : [];
            if(sePostData.length > 0){
                me.updateSection(sePostData, function () {
                    me.sheet.setRowCount(me.cache.length + 5);
                    sheetCommonObj.showData(me.sheet, me.setting, me.cache);
                    $('#delAlert').modal('hide');
                });
                if(fiPostData.length > 0){
                    fi.updateFeeItem(fiPostData);
                }
                sheetCommonObj.cleanData(fr.sheet, fr.setting, 10);
            }
            else{
                $('#delAlert').modal('hide');
            }
        }
    });
});
let curDeleteType = null;
//费用项
let feeItemObj = {
    rationRepId: null,
    workBook: null,
    sheet: null,
    cache: [],
    currentFeeItem: null,
    feeType: {ZM: '子目费用', FX: '分项费用', CS: '措施费用'},
    updateType: {update: 'update', new: 'new'},
    deleteType: 'feeItem',
    setting: {
        header:[
            {headerName:"费用项",headerWidth:200,dataCode:"feeItem", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
            {headerName:"费用类型",headerWidth:80,dataCode:"feeType", dataType: "String", hAlign: "center", vAlign: "center"},
            {headerName:"记取位置",headerWidth:100,dataCode:"position", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"}
        ],
        view: {lockColumns: []},
        comboItems: {feeType: ['子目费用', '分项费用', '措施费用']},
        options: {
            tabStripVisible:  false,
            allowCopyPasteExcelStyle : false,
            allowExtendPasteRange: true,
            allowUserDragDrop : false,
            allowUserDragFill: false,
            scrollbarMaxAlign : true
        }
    },
    isDef: function (v) {
        return v !== undefined && v !== null;
    },
    //sheet things
    setOptions: function (workbook, opts) {
        for(let opt in opts){
            workbook.options[opt] = opts[opt];
        }
    },
    setCombo: function (sheet, col, comboItems) {
        let combo = sheetCommonObj.getDynamicCombo();
        combo.items(comboItems).editable = false;
        sheet.getRange(-1, col, -1, 1).cellType(combo);
    },
    getCurrentData: function (sheet, cache) {
        let acRow = sheet.getActiveRowIndex();
        return this.isDef(cache[acRow]) ? cache[acRow] : null;
    },
    buildSheet: function () {
        let me = this, se = sectionObj, fr = feeRuleObj, bs = batchSectionObj;
        if(!this.isDef(this.workBook)){
            this.workBook = sheetCommonObj.buildSheet($('#feeItemSpread')[0], this.setting, 10);
            this.sheet = this.workBook.getActiveSheet();
            sheetCommonObj.bindEscKey(this.workBook, [{sheet: this.sheet, editStarting: me.onEditStarting, editEnded: me.onEditEnded}]);
            this.setOptions(this.workBook, this.setting.options);
            this.sheet.options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;
            this.bindEvents(this.sheet);
            this.rationRepId = parseInt(getQueryString("repository"));
            //init combo
            this.setCombo(this.sheet, 1, this.setting.comboItems.feeType);
            //init sectionSpread
            se.buildSheet();
            //init feeRuleSpread
            fr.buildSheet();
            //init installation
            this.getInstallation(this.rationRepId, function (rstData) {
                me.cache = rstData;
                me.sheet.setRowCount(me.cache.length + 10);
                sheetCommonObj.showData(me.sheet, me.setting, me.cache);
                me.initSelection(me.cache[0]);
            });
            //init batchSectionSpread
            bs.getSectionTree(this.rationRepId);
        }
    },
    bindEvents: function (sheet) {
        let me = this;
        const Events = GC.Spread.Sheets.Events;
        sheet.bind(Events.SelectionChanged, me.onSelectionChanged);
        sheet.bind(Events.EnterCell, me.onEnterCell);
        sheet.bind(Events.EditStarting, me.onEditStarting);
        sheet.bind(Events.EditEnded, me.onEditEnded);
        sheet.bind(Events.ClipboardPasting, me.onClipboardPasting);
        sheet.bind(Events.ClipboardPasted, me.onClipboardPasted);
        me.feeItemDelOpr();
    },
    initSelection: function (feeItem) {
        let me = this, se = sectionObj, fr = feeRuleObj;
        sheetCommonObj.cleanSheet(se.sheet, se.setting, -1);
        sheetCommonObj.cleanSheet(fr.sheet, fr.setting, -1);
        if(!me.isDef(feeItem)){
            me.workBook.focus(true);
            me.currentFeeItem = null;
            se.cache= [];
            return;
        }
        fr.addObj = null;
        fr.updateObj = null;
        me.currentFeeItem = feeItem;
        se.cache = me.currentFeeItem.section;
        se.sheet.setRowCount(se.cache.length + 5);
        sheetCommonObj.showData(se.sheet, se.setting, se.cache);
        se.initSelection(se.cache[0]);
        me.workBook.focus(true);

    },
    onSelectionChanged: function (sender, info) {
        let me = feeItemObj;
        if(!info.oldSelections || info.oldSelections.length === 0 && info.newSelections.length > 0 || info.oldSelections[0].row !== info.newSelections[0].row){
            let row = info.newSelections[0].row;
            let node = me.cache[row];
            me.initSelection(node);
        }
    },
    onEnterCell: function (sender, args) {
        let me = feeItemObj;
        me.sheet.repaint();
    },
    onEditStarting: function (sender, args) {
        let me = feeItemObj;
        //费用类型为子目时，记取位置不可编辑
        let feeItem = me.cache[args.row];
        if(me.isDef(feeItem) && (feeItem.feeType === me.feeType.ZM || !me.isDef(feeItem.feeType) || feeItem.feeType == '') && args.col === 2){
            args.cancel = true;
        }
    },
    onEditEnded: function (sender, args) {
        let me = feeItemObj, se = sectionObj;
        let v = me.isDef(args.editingText) ? args.editingText.toString().trim() : '';
        let feeItem = me.cache[args.row];
        let updateObj = {updateType: '', updateData: {}};
        //update
        if(me.isDef(feeItem)){
            feeItem[me.setting.header[args.col]['dataCode']] = !me.isDef(feeItem[me.setting.header[args.col]['dataCode']]) ? '' : feeItem[me.setting.header[args.col]['dataCode']];
            if(v == feeItem[me.setting.header[args.col]['dataCode']]){
                return;
            }
            updateObj.updateType = me.updateType.update;
            //当费用类型切换为子目费用时，自动清空记取位置
            if(args.col === 1 && v  === me.feeType.ZM){
                feeItem.position = '';
                args.sheet.setValue(args.row, 2, '');
                updateObj.updateData.position = '';
            }
            feeItem[me.setting.header[args.col]['dataCode']] = v;
            updateObj.updateData.ID = feeItem.ID;
            updateObj.updateData[me.setting.header[args.col]['dataCode']] = v;
        }
        //insert
        else {
            if(v === ''){
                return;
            }
            updateObj.updateType = me.updateType.new;
            updateObj.updateData[me.setting.header[args.col]['dataCode']] = v;
            updateObj.updateData.rationRepId = me.rationRepId;
            updateObj.updateData.ID = uuid.v1();
            updateObj.updateData.section = [];
            me.cache.push(updateObj.updateData);
            me.currentFeeItem = updateObj.updateData;
            se.cache = me.currentFeeItem.section;
        }
        me.sheet.setRowCount(me.cache.length + 10);
        sheetCommonObj.showData(me.sheet, me.setting, me.cache);
        //ajax
        me.updateFeeItem([updateObj]);
    },
    onClipboardPasting: function (sender, info) {
        let me = feeItemObj;
        if(info.cellRange.col + info.cellRange.colCount > me.setting.header.length){
            info.cancel = true;
        }
    },
    onClipboardPasted: function (sender, info) {
        let me = feeItemObj, se = sectionObj;
        let postData = [];
        let items = sheetCommonObj.analyzePasteData(me.setting, info);
        for(let i = 0, len = items.length; i < len; i++){
            let row = info.cellRange.row + i;
            let feeItem = me.cache[row];
            //update
            if(me.isDef(feeItem)){
                if(me.validData(items[i])){
                    for(let attr in items[i]){
                        feeItem[attr] = items[i][attr];
                    }
                    postData.push(me.getUpdateObj(me.updateType.update, feeItem));
                }
            }
            //insert
            else{
                if(me.validData(items[i])){
                    items[i].ID = uuid.v1();
                    items[i].rationRepId = me.rationRepId;
                    items[i].section = [];
                    postData.push(me.getUpdateObj(me.updateType.new, items[i]));
                    me.cache.push(items[i]);
                }
            }
        }
        //update currentFeeItem
        me.currentFeeItem = me.getCurrentData(me.sheet, me.cache);
        se.cache = me.currentFeeItem.section;
        me.sheet.setRowCount(me.cache.length + 10);
        sheetCommonObj.showData(me.sheet, me.setting, me.cache);
        if(postData.length > 0){
            //ajax then refresh
            me.updateFeeItem(postData);
        }
    },
    feeItemDelOpr: function () {
        if (locked) {
            return;
        }
        let me = this;
        me.workBook.commandManager().register('feeItemDel', function () {
            curDeleteType = me.deleteType;
            let sels = me.workBook.getSheet(0).getSelections();
            for(let i = 0, len = sels.length; i < len; i++){
                let sel = sels[i];
                //delete
                if(sel.colCount === me.setting.header.length){
                    $('#delAlert').modal('show');
                    break;
                }
            }
        });
        me.workBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.del, false, false, false, false);
        me.workBook.commandManager().setShortcutKey('feeItemDel', GC.Spread.Commands.Key.del, false, false, false, false);
    },
    getUpdateObj: function (updateType, data) {
        let rst = {updateType: '', updateData: {}};
        rst.updateType = updateType;
        for(let attr in data){
            rst.updateData[attr] = data[attr];
        }
        return rst;
    },
    validData: function (pasteData) {
        if(this.isDef(pasteData.feeType)){
            if(this.setting.comboItems.feeType.indexOf(pasteData.feeType) < 0){
                return false;
            }
            //费用类型为子目时，不可有记取位置
            if(pasteData.feeType === this.feeType.ZM && this.isDef(pasteData.position) && pasteData.position !== ''){
                return false;
            }
        }
        return true;
    },
    getInstallation: function (rationRepId, callback) {
        let me = this;
        CommonAjax.post('/rationRepository/api/getInstallation', {rationRepId: rationRepId}, function (rstData) {
            me.cache = rstData;
            if(callback){
                callback(rstData);
            }
        });
    },
    updateFeeItem: function (updateData, callback) {
        let me = this;
        CommonAjax.post('/rationRepository/api/updateFeeItem', {updateData: updateData}, function (rstData) {
            if(callback){
                callback();
            }
        });
    }
};

//分册章节
let sectionObj = {
    workBook: null,
    sheet: null,
    cache: [],
    currentSection: null,
    updateType: {update: 'update', new: 'new'},
    deleteType: 'section',
    setting: {
        header:[
            {headerName:"分册章节",headerWidth:330,dataCode:"name", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"}
        ],
        view: {lockColumns: []},
        options: {
            tabStripVisible:  false,
            allowCopyPasteExcelStyle : false,
            allowExtendPasteRange: true,
            allowUserDragDrop : false,
            allowUserDragFill: false,
            scrollbarMaxAlign : true
        }
    },
    isDef: function (v) {
        return v !== undefined && v !== null;
    },
    //sheet things
    setOptions: function (workbook, opts) {
        for(let opt in opts){
            workbook.options[opt] = opts[opt];
        }
    },
    renderFunc: function (sheet, func) {
        sheet.suspendPaint();
        sheet.suspendEvent();
        if(this.isFunc(func)){
            func();
        }
        sheet.resumePaint();
        sheet.resumeEvent();
    },
    buildSheet: function () {
        if(!this.isDef(this.workBook)){
            this.workBook = sheetCommonObj.buildSheet($('#instSectionSpread')[0], this.setting, 10);
            this.sheet = this.workBook.getActiveSheet();
            sheetCommonObj.bindEscKey(this.workBook, [{sheet: this.sheet, editStarting: this.onEditStarting, editEnded: this.onEditEnded}]);
            this.setOptions(this.workBook, this.setting.options);
            this.sheet.options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;
            this.bindEvents(this.sheet);
        }
    },
    bindEvents: function (sheet) {
        let me = sectionObj;
        const Events = GC.Spread.Sheets.Events;
        sheet.bind(Events.SelectionChanged, me.onSelectionChanged);
        sheet.bind(Events.EditStarting, me.onEditStarting);
        sheet.bind(Events.EditEnded, me.onEditEnded);
        sheet.bind(Events.ClipboardPasting, me.onClipboardPasting);
        sheet.bind(Events.ClipboardPasted, me.onClipboardPasted);
        me.sectionDelOpr();
        me.onContextmenuOpr();
    },
    initSelection: function (section) {
        let me = sectionObj, fr = feeRuleObj;
        sheetCommonObj.cleanSheet(fr.sheet, fr.setting, -1);
        this.workBook.focus(true);
        if(!this.isDef(section)){
            me.currentSection = null;
            return;
        }
        me.currentSection = section;
        fr.addObj = null;
        fr.updateObj = null;
        fr.cache = section.feeRule;
        fr.sheet.setRowCount(fr.cache.length + 5);
        sheetCommonObj.showData(fr.sheet, fr.setting, fr.cache);
    },
    onContextmenuOpr: function () {
        let me = this;
        $.contextMenu({
            selector: '#instSectionSpread',
            build: function($triggerElement, e){
                //控制允许右键菜单在哪个位置出现
                let sheet = me.sheet;
                let offset = $("#instSectionSpread").offset(),
                    x = e.pageX - offset.left,
                    y = e.pageY - offset.top;
                let target = sheet.hitTest(x, y);
                if(target.hitTestType === 3 && me.isDef(target.row) && me.isDef(target.col)){//在表格内
                    sheet.setActiveCell(target.row, target.col);
                    me.initSelection(me.cache[target.row]);
                    return {
                        callback: function(){},
                        items: {
                            "ref": {
                                name: "批量关联至定额",
                                disabled: function () {
                                    const inValidCell = !commonUtil.isDef(target.row) || !commonUtil.isDef(target.col);
                                    const inValidData = target.row >= me.cache.length;
                                    return locked || inValidCell || inValidData;
                                },
                                icon: "fa-arrow-left",
                                callback: function (key, opt) {
                                    $('#sectionTreeModal').modal('show');
                                }
                            }
                        }
                    };
                }
                else{
                    return false;
                }
            }
        });
    },
    onSelectionChanged: function (sender, info) {
        let me = sectionObj;
        if(info.oldSelections && info.oldSelections.length === 0 && info.newSelections.length > 0 || info.oldSelections[0].row !== info.newSelections[0].row){
            let row = info.newSelections[0].row;
            let section = me.cache[row];
            me.initSelection(section);
        }
    },
    onEditStarting: function (sender, args) {
        let me = sectionObj, fi = feeItemObj;
        if(!me.isDef(fi.currentFeeItem)){
            args.cancel = true;
        }
    },
    onEditEnded: function (sender, args) {
        let me = sectionObj, fi = feeItemObj, fr = feeRuleObj;
        let v = me.isDef(args.editingText) ? args.editingText.toString().trim() : '';
        let section = me.cache[args.row];
        let updateObj = {updateType: '', updateData: {}};
        //update
        if(me.isDef(section)){
            section.name = !me.isDef(section.name) ? '' : section.name;
            if(section.name === v){
                return;
            }
            if(v === ''){
                me.sheet.setValue(args.row, args.col, section.name);
                return;
            }
            section.name = v;
            updateObj.updateType = me.updateType.update;
            updateObj.updateData.ID = section.ID;
            updateObj.updateData.name = v;
        }
        //insert
        else{
            if(v === ''){
                return;
            }
            updateObj.updateType = me.updateType.new;
            updateObj.updateData.ID = uuid.v1();
            updateObj.updateData.rationRepId = fi.rationRepId;
            updateObj.updateData.name = v;
            updateObj.updateData.feeItemId = fi.currentFeeItem.ID;
            updateObj.updateData.feeRule = [];
            me.cache.push(updateObj.updateData);
            me.currentSection = updateObj.updateData;
            fr.cache = me.currentSection.feeRule;
        }
        me.sheet.setRowCount(me.cache.length + 5);
        sheetCommonObj.showData(me.sheet, me.setting, me.cache);
        me.updateSection([updateObj]);
        fi.updateFeeItem([{updateType: fi.updateType.update, updateData: {ID: fi.currentFeeItem.ID, $addToSet: {section: {ID: updateObj.updateData.ID}}}}]);
    },
    onClipboardPasting: function (sender, info) {
        let me = sectionObj, fi = feeItemObj;
        if(info.cellRange.col + info.cellRange.colCount > me.setting.header.length || !me.isDef(fi.currentFeeItem)){
            info.cancel = true;
        }
    },
    onClipboardPasted: function (sender, info) {
        let me = sectionObj, fi = feeItemObj, fr = feeRuleObj;
        let sePostData = [], fiPostData = [];
        let items = sheetCommonObj.analyzePasteData(me.setting, info);
        for(let i = 0, len = items.length; i < len; i++){
            let row = info.cellRange.row + i;
            let section = me.cache[row];

            //update
            if(me.isDef(section)){
                section.name = items[i].name;
                let updateObj = {updateType: me.updateType.update, updateData: {ID: section.ID, name: items[i].name}};
                sePostData.push(updateObj);
            }
            //insert
            else{
                let updateObj = {updateType: me.updateType.new, updateData: {ID: uuid.v1(), rationRepId: fi.rationRepId, name: items[i].name, feeItemId: fi.currentFeeItem.ID, feeRule: []}};
                sePostData.push(updateObj);
                me.cache.push(updateObj.updateData);
                fiPostData.push({updateType: fi.updateType.update, updateData: {ID: fi.currentFeeItem.ID, $addToSet: {section: {ID: updateObj.updateData.ID}}}});
            }
        }
        //update currentSection
        me.currentSection = fi.getCurrentData(me.sheet, me.cache);
        fr.cache = me.currentSection.feeRule;
        me.sheet.setRowCount(me.cache.length + 5);
        sheetCommonObj.showData(me.sheet, me.setting, me.cache);
        if(sePostData.length > 0){
            me.updateSection(sePostData);
            if(fiPostData.length > 0){
                fi.updateFeeItem(fiPostData);
            }
        }
    },
    sectionDelOpr: function () {
        if (locked) {
            return;
        }
        let me = this;
        me.workBook.commandManager().register('sectionDel', function () {
            curDeleteType = me.deleteType;
            let sels = me.workBook.getSheet(0).getSelections();
            for(let i = 0, len = sels.length; i < len; i++){
                let sel = sels[i];
                //delete
                if(sel.colCount === me.setting.header.length){
                    $('#delAlert').modal('show');
                    break;
                }
            }
        });
        me.workBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.del, false, false, false, false);
        me.workBook.commandManager().setShortcutKey('sectionDel', GC.Spread.Commands.Key.del, false, false, false, false);
    },
    updateSection: function (updateData, callback) {
        CommonAjax.post('/rationRepository/api/updateSection', {updateData: updateData}, function (rstData) {
            if(callback){
                callback();
            }
        });
    }
};

//费用规则
let feeRuleObj = {
    workBook: null,
    sheet: null,
    addObj: null,
    updateObj: null,
    avtiveCell: {row: 0, col: 0},
    cache: [],
    base: {RCJ: '分别按人材机乘系数', RG: '人工', CL: '材料', JX: '机械'},
    setting: {
        header:[
            {headerName:"编码",headerWidth:80,dataCode:"code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center", span:{row: 0, rowCount: 2, colCount: 1}},
            {headerName:"费用规则",headerWidth:280,dataCode:"rule", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center", span:{row: 0, rowCount: 2, colCount: 1}},
            {headerName:"基数",headerWidth:140,dataCode:"base", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center", span:{row: 0, rowCount: 2, colCount: 1}},
            {headerName:"费率(%)",headerWidth:70,dataCode:"feeRate", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center", span:{row: 0, rowCount: 2, colCount: 1}},
            {headerName:"人工(%)",headerWidth:70,dataCode:"labour", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center", span:{row: 1, rowCount: 1, colCount: 1}},
            {headerName:"材料(%)",headerWidth:70,dataCode:"material", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center", span:{row: 1, rowCount: 1, colCount: 1}},
            {headerName:"机械(%)",headerWidth:70,dataCode:"machine", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center", span:{row: 1, rowCount: 1, colCount: 1}}
        ],
        view: {lockColumns: []},
        comboItems: {base: ['分别按人材机乘系数', '人工', '材料', '机械']},
        options: {
            tabStripVisible:  false,
            allowCopyPasteExcelStyle : false,
            allowExtendPasteRange: true,
            allowUserDragDrop : false,
            allowUserDragFill: false,
            scrollbarMaxAlign : true
        }
    },
    isDef: function (v) {
        return v !== undefined && v !== null;
    },
    //sheet things
    setOptions: function (workbook, opts) {
        for(let opt in opts){
            workbook.options[opt] = opts[opt];
        }
    },
    buildHeader: function () {
        if(!this.sheet){
            return;
        }
        this.sheet.suspendPaint();
        this.sheet.suspendEvent();
        let ch = GC.Spread.Sheets.SheetArea.colHeader;
        this.sheet.setRowCount(2, ch);
        for(let i = 0; i < this.setting.header.length; i++){
            let header = this.setting.header[i];
            this.sheet.addSpan(header.span.row, i, header.span.rowCount, header.span.colCount, ch);
            this.sheet.setValue(header.span.row, i, header.headerName, ch);
            if(header.dataCode === 'feeRate'){
                this.sheet.addSpan(header.span.row, i + 1, 1, 3, ch);
                this.sheet.setValue(header.span.row, i + 1, '其中', ch);
            }
        }
        this.sheet.resumePaint();
        this.sheet.resumeEvent();
    },
    buildSheet: function () {
        let fi = feeItemObj;
        if(!this.isDef(this.workBook)){
            this.workBook = sheetCommonObj.buildSheet($('#instFeeRuleSpread')[0], this.setting, 10);
            this.sheet = this.workBook.getActiveSheet();
            this.buildHeader();
            this.sheet.setRowCount();

            this.sheet.options.allowCellOverflow = false;
            sheetCommonObj.bindEscKey(this.workBook, [{sheet: this.sheet, editStarting: this.onEditStarting, editEnded: this.onEditEnded}])
            this.setOptions(this.workBook, this.setting.options);
            this.sheet.options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;
            this.bindEvents(this.sheet);
            //init combo
            fi.setCombo(this.sheet, 2, this.setting.comboItems.base);
        }
    },
    bindEvents: function (sheet) {
        let me = feeRuleObj;
        const Events = GC.Spread.Sheets.Events;
        sheet.bind(Events.SelectionChanged, me.onSelectionChanged);
        sheet.bind(Events.EnterCell, me.onEnterCell);
        sheet.bind(Events.EditStarting, me.onEditStarting);
        sheet.bind(Events.EditEnded, me.onEditEnded);
        sheet.bind(Events.ClipboardPasting, me.onClipboardPasting);
        sheet.bind(Events.ClipboardPasted, me.onClipboardPasted);
        me.feeRuleDelOpr();
    },
    canSave: function (addObj) {
        return this.isDef(addObj.code) && addObj.code !== '' && !this.hasCode(addObj) && this.validRCJ(addObj);
    },
    hasCode: function (obj) {
        let fi = feeItemObj;
        for(let feeItem of fi.cache){
            for(let section of feeItem.section){
                for(let feeRule of section.feeRule){
                    if(obj.code == feeRule.code && (this.isDef(obj.ID) && obj.ID !== feeRule.ID || !this.isDef(obj.ID))){
                        return true;
                    }
                }
            }
        }
        return false;
    },
    //费用类型为人、材、机时人材机总和一定要为100
    validRCJ: function (feeRule) {
        if(!this.isDef(feeRule.base) || feeRule.base === this.base.RCJ){
            return true;
        }
        let sum = 0;
        if(this.isDef(feeRule.labour)){
            sum = parseFloat(sum + feeRule.labour).toDecimal(2);
        }
        if(this.isDef(feeRule.material)){
            sum = parseFloat(sum + feeRule.material).toDecimal(2);
        }
        if(this.isDef(feeRule.machine)){
            sum = parseFloat(sum + feeRule.machine).toDecimal(2);
        }
        return sum == 100;
    },
    validPasteData: function (data) {
        //插入须有编码
        if(!this.isDef(data.code)){
            alert('粘贴时，编码不能为空，或者粘贴的数据中需包含编码');
            return false;
        }
        //编码须唯一
        if(this.isDef(data.code) && this.hasCode(data)){
            alert('编码须唯一！');
            return false;
        }
        //基数要合法
        if(this.isDef(data.base) && this.setting.comboItems.base.indexOf(data.base) < 0){
            alert('基数不正确！');
            return false;
        }
        //费率、人工、材料、机械，须数字
        if(this.isDef(data.feeRate) && isNaN(data.feeRate)){
            alert('费率须为数字！');
            return false;
        }
        if(this.isDef(data.labour) && isNaN(data.labour)){
            alert('人工须为数字！');
            return false;
        }
        if(this.isDef(data.material) && isNaN(data.material)){
            alert('材料须为数字！');
            return false;
        }
        if(this.isDef(data.machine) && isNaN(data.machine)){
            alert('机械须为数字！');
            return false;
        }
        //基数为分别按人材机时，费率须为空
        if(this.isDef(data.base) && data.base === this.base.RCJ && this.isDef(data.feeRate) && data.feeRate !== ''){
            alert("基数为分别按人材机时，费率须为空!");
            return false;
        }
        //基数为 人工、材料、机械时 三者之和须为100
        if(this.isDef(data.base) && data.base !== this.base.RCJ && this.validRCJ(data)){
            alert("基数为 人工、材料、机械时 三者之和须为100");
            return false;
        }
        return true;
    },
    decimalPasteData: function (data) {
        if(this.isDef(data.feeRate) && isNaN(data.feeRate)){
            data.feeRate = parseFloat(data.feeRate).toDecimal(2);
        }
        if(this.isDef(data.labour) && isNaN(data.labour)){
            data.labour = parseFloat(data.labour).toDecimal(2);
        }
        if(this.isDef(data.material) && isNaN(data.material)){
            data.material = parseFloat(data.material).toDecimal(2);
        }
        if(this.isDef(data.machine) && isNaN(data.machine)){
            data.machine = parseFloat(data.machine).toDecimal(2);
        }
    },
    getFocusToCol: function (feeRule) {
        if(!this.isDef(feeRule.labour) || feeRule.labour === '' || feeRule.labour > 100 || feeRule.labour == 0){
            return 4;
        }
        if(!this.isDef(feeRule.material) || feeRule.material === '' || feeRule.material > 100 || feeRule.material == 0){
            return 5;
        }
        if(!this.isDef(feeRule.machine) || feeRule.machine === '' || feeRule.machine > 100 || feeRule.machine == 0){
            return 6;
        }
        return 4;
    },
    onSelectionChanged: function (sender, info) {
        let me = feeRuleObj, se = sectionObj;
        if(info.oldSelections && info.oldSelections.length === 0 && info.newSelections.length > 0 || info.oldSelections[0].row !== info.newSelections[0].row){
            if(me.isDef(me.updateObj) && !me.validRCJ(me.updateObj)){
                $('#rcjAlert').modal('show');
                $('#aleCanceBtn').bind('click', function () {
                    me.updateObj.base = me.base.RCJ;
                    me.updateObj.labour = 0;
                    me.updateObj.material = 0;
                    me.updateObj.machine = 0;
                    me.sheet.setRowCount(me.cache.length + 5);
                    sheetCommonObj.showData(me.sheet, me.setting, me.cache);
                    se.updateSection([{updateType: se.updateType.update, updateData: se.currentSection}]);
                    $(this).unbind();
                });
                $('#aleConfBtn').bind('click', function () {
                    me.sheet.setActiveCell(me.avtiveCell.row, me.getFocusToCol(me.updateObj));
                    $(this).unbind();
                });
            }
            if(me.isDef(me.addObj)){
                if(!me.isDef(me.addObj.code) || me.addObj.code === ''){
                    $('#alertText').text('请输入编码');
                    $('#codeAlert').modal('show');
                    $('#codAleClose').click(function () {
                        me.addObj.code = '';
                        me.sheet.setActiveCell(me.avtiveCell.row, 0);
                        $(this).unbind();
                    });
                    $('#codAlertQR').click(function () {
                        me.addObj.code = '';
                        me.sheet.setActiveCell(me.avtiveCell.row, 0);
                        $(this).unbind();
                    });
                    //取消插入
                    $('#codAlertQX').click(function () {
                        me.addObj = null;
                        me.sheet.setRowCount(me.cache.length + 5);
                        sheetCommonObj.showData(me.sheet, me.setting, me.cache);
                        $(this).unbind();
                    });
                }
                else if(me.isDef(me.addObj.code) && me.hasCode(me.addObj)){
                    $('#alertText').text('输入的编号已存在，请重新输入');
                    $('#codeAlert').modal('show');
                    $('#codAleClose').click(function () {
                        me.addObj.code = '';
                        me.sheet.setValue(me.avtiveCell.row, 0, '');
                        me.sheet.setActiveCell(me.avtiveCell.row,0);
                        $(this).unbind();
                    });
                    $('#codAlertQR').click(function () {
                        me.addObj.code = '';
                        me.sheet.setValue(me.avtiveCell.row, 0, '');
                        me.sheet.setActiveCell(me.avtiveCell.row, 0);
                        $(this).unbind();
                    });
                    //取消插入
                    $('#codAlertQX').click(function () {
                        me.addObj = null;
                        me.sheet.setRowCount(me.cache.length + 5);
                        sheetCommonObj.showData(me.sheet, me.setting, me.cache);
                        $(this).unbind();
                    });
                }
                else if(!me.validRCJ(me.addObj)){
                    $('#rcjAlert').modal('show');
                    $('#aleCanceBtn').bind('click', function () {
                        me.addObj = null;
                        me.sheet.setRowCount(me.cache.length + 5);
                        sheetCommonObj.showData(me.sheet, me.setting, me.cache);
                        $(this).unbind();
                    });
                    $('#aleConfBtn').bind('click', function () {
                        me.sheet.setActiveCell(me.avtiveCell.row, me.getFocusToCol(me.addObj));
                        $(this).unbind();
                    });
                }
            }
        }
    },
    onEnterCell: function (sender, args) {
        let me = feeRuleObj;
        me.sheet.repaint();
    },
    onEditStarting: function (sender, args) {
        let me = feeRuleObj, se = sectionObj;
        let feeRule = me.cache[args.row];
        let rcjCols = [4, 5, 6];
        if(!me.isDef(se.currentSection)){
            args.cancel = true;
        }
        if(me.isDef(feeRule) && me.isDef(feeRule.base) && feeRule.base === me.base.RCJ && args.col === 3){
            args.cancel = true;
        }
        else if(!me.isDef(feeRule) && rcjCols.indexOf(args.col) > 0){
            args.cancel = true;
        }
    },
    onEditEnded: function (sender, args) {
        let me = feeRuleObj, se = sectionObj;
        let v = me.isDef(args.editingText) ? args.editingText.toString().trim() : '';
        let updateObj = {updateType: '', updateData: {}};
        let feeRule = me.cache[args.row];
        let field = me.setting.header[args.col]['dataCode'];
        let orgV =  me.isDef(feeRule) && me.isDef(feeRule[field]) ? feeRule[field] : '';
        me.updateObj = feeRule;
        me.avtiveCell.row = args.row;
        me.avtiveCell.col = args.col;
        //update
        if(me.isDef(feeRule)){
            feeRule[field] = me.isDef(feeRule[field]) ? feeRule[field] : '';
            if(v === feeRule[field]){
                return;
            }
            if(field === 'base' && v === me.base.RCJ){
                //基数为人材机时，费率清空
                feeRule.feeRate = '';
                me.sheet.setValue(args.row, 3, '');
            }
            else if(field === 'base' && (v === me.base.RG || v === me.base.CL || v === me.base.JX)){
                if(!me.validRCJ(feeRule)){//基数变为人工、材料、机械时，若人材机之和不为100，则清空
                    feeRule.labour = 0;
                    feeRule.material = 0;
                    feeRule.machine = 0;
                }
            }
            else if(field === 'labour' || field === 'material' || field === 'machine' || field === 'feeRate'){
                if(isNaN(v)){
                    alert('只能输入数值');
                    me.sheet.setValue(args.row, args.col, orgV);
                    return;
                }
                v = parseFloat(v).toDecimal(2);
                me.sheet.setValue(args.row, args.col, v);
            }
            feeRule[field] = v;
            //编码重复，不可更新
            if(field === 'code'){
                if(v == ''){
                    me.sheet.setValue(args.row, args.col, orgV);
                    return;
                    feeRule[field] = orgV;
                }
                if(me.hasCode(feeRule)){
                    $('#codeAlert').modal('show');
                    $('#codAleClose').bind('click', function () {
                        me.sheet.setActiveCell(args.row, 0);
                        me.sheet.setValue(args.row, args.col, orgV);
                    });
                    $('#codAlertQR').bind('click', function () {
                        me.sheet.setActiveCell(args.row, 0);
                        me.sheet.setValue(args.row, args.col, orgV);
                    });
                    feeRule[field] = orgV;
                    return;
                }
            }
            //是否能更新
            //人材机之和不为100,不解决之和为100取消操作的话，则基数自动换成分别按人材机
            if(!me.validRCJ(feeRule)){
                return;
            }
            updateObj.updateType = se.updateType.update;
            updateObj.updateData.ID = se.currentSection.ID;
            updateObj.updateData.feeRule = me.cache;
            me.updateObj = null;
            se.updateSection([{updateType: se.updateType.update, updateData: se.currentSection}]);
        }
        //insert
        else{
            if(v === ''){
                return;
            }
            if(!me.isDef(me.addObj)){
                me.addObj = Object.create(null);
            }
            me.addObj[me.setting.header[args.col]['dataCode']] = v;
            if(me.canSave(me.addObj)){
                me.addObj.ID = uuid.v1();
                me.cache.push(me.addObj);
                updateObj.updateType = se.updateType.update;
                updateObj.updateData.ID = se.currentSection.ID;
                updateObj.updateData.feeRule = me.cache;
                me.sheet.setRowCount(me.cache.length + 5);
                sheetCommonObj.showData(me.sheet, me.setting, me.cache);
                se.updateSection([{updateType: se.updateType.update, updateData: se.currentSection}]);
                me.addObj = null;
            }
        }
    },
    onClipboardPasting: function (sender, info) {
        let me = feeRuleObj, se = sectionObj;
        if(info.cellRange.col + info.cellRange.colCount > me.setting.header.length){
            info.cancel = true;
        }
        if(!me.isDef(se.currentSection)){
            info.cancel = true;
        }
    },
    onClipboardPasted: function (sender, info) {
        let me = feeRuleObj, se = sectionObj, fi = feeItemObj;
        let items = sheetCommonObj.analyzePasteData(me.setting, info);
        me.toUpdate = false;
        for(let i = 0, len = items.length; i < len; i++){
            let row = info.cellRange.row + i;
            let feeRule = me.cache[row];
            //update
            if(me.isDef(feeRule)){
                let tempObj = {};
                for(let attr in feeRule){
                    tempObj[attr] = feeRule[attr];
                }
                for(let attr in items[i]){
                    tempObj[attr] = items[i][attr]
                }
                if(me.validPasteData(tempObj)){
                    me.decimalPasteData(tempObj);
                    //front
                    me.cache[row] = tempObj;
                    me.toUpdate = true;
                }
            } else{//  //insert
                if(me.validPasteData(items[i])){
                    me.decimalPasteData(items[i]);
                    items[i].ID = uuid.v1();
                    //front
                    me.cache.push(items[i]);
                    me.toUpdate = true;
                }
            }
        }
        me.sheet.setRowCount(me.cache.length + 5);
        sheetCommonObj.showData(me.sheet, me.setting, me.cache);
        if(me.toUpdate){
            se.updateSection([{updateType: se.updateType.update, updateData: se.currentSection}]);
        }
    },
    feeRuleDelOpr: function () {
        if (locked) {
            return;
        }
        let me = feeRuleObj, se = sectionObj;
        me.workBook.commandManager().register('feeRuleDel', function () {
            me.toUpdate = false;
            let sels = me.workBook.getSheet(0).getSelections();
            for(let i = 0, len = sels.length; i < len; i++){
                let sel = sels[i];
                //delete
                if(sel.colCount === me.setting.header.length){
                    for(let j = 0, jLen = sel.rowCount; j < jLen; j++){
                        let row = sel.row + j;
                        let feeRule = me.cache[row];
                        //有数据，删除数据
                        if(me.isDef(feeRule)){
                            me.toUpdate = true;
                        }
                    }
                    //front delete
                    me.cache.splice(sel.row, sel.rowCount);
                }
            }
            if(me.toUpdate){
                se.updateSection([{updateType: se.updateType.update, updateData: se.currentSection}], function () {
                    me.sheet.setRowCount(me.cache.length + 5);
                    sheetCommonObj.showData(me.sheet, me.setting, me.cache);
                });
            }
        });
        me.workBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.del, false, false, false, false);
        me.workBook.commandManager().setShortcutKey('feeRuleDel', GC.Spread.Commands.Key.del, false, false, false, false);
    }
};

let batchSectionObj = {
    cache: null,
    tree: null,
    controller: null,
    workBook: null,
    sheet: null,
    IDRowMapping: null, //树节点ID与行号映射
    setting: {
        sheet: {
            cols:[
                {
                    head: {
                        titleNames: ['选择'],
                        spanCols: [1],
                        spanRows: [2],
                        vAlign: [1, 1],
                        hAlign: [1, 1],
                        font: 'Arial'
                    },
                    data: {
                        field: 'select',
                        vAlign: 1,
                        hAlign: 0,
                        font: 'Arial'
                    },
                    width: 50
                },
                {
                    head: {
                        titleNames: ['名称'],
                        spanCols: [1],
                        spanRows: [2],
                        vAlign: [1, 1],
                        hAlign: [1, 1],
                        font: 'Arial'
                    },
                    data: {
                        field: 'name',
                        vAlign: 1,
                        hAlign: 0,
                        font: 'Arial'
                    },
                    width: 400
                }
            ],
            headRows: 1,
            headRowHeight: [47],
            emptyRows: 0,
            treeCol: 1
        },
        tree: {
            id: 'ID',
            pid: 'ParentID',
            nid: 'NextSiblingID',
            rootId: -1
        },
        options: {
            tabStripVisible:  false,
            allowCopyPasteExcelStyle : false,
            allowExtendPasteRange: true,
            allowUserDragDrop : false,
            allowUserDragFill: false,
            scrollbarMaxAlign : true
        }
    },
    isDef: function (v) {
        return v !== undefined && v !== null;
    },
    renderFunc: function (sheet, func) {
        sheet.suspendPaint();
        sheet.suspendEvent();
        if(func){
            func();
        }
        sheet.resumePaint();
        sheet.resumeEvent();
    },
    setOptions: function (workbook, opts) {
        for(let opt in opts){
            workbook.options[opt] = opts[opt];
        }
    },
    buildSheet: function () {
        if(!this.isDef(this.workBook)){
            this.workBook = new GC.Spread.Sheets.Workbook($('#batchSectionSpread')[0], {sheetCount: 1});
            this.sheet = this.workBook.getActiveSheet();
            this.setOptions(this.workBook, this.setting.options);
            this.bindEvents(this.sheet);
        }
    },
    bindEvents: function (sheet) {
        let me = this;
        const Events = GC.Spread.Sheets.Events;
        sheet.bind(Events.EditStarting, me.onEditStarting);
        sheet.bind(Events.EditEnded, me.onEditEnded);
        sheet.bind(Events.ClipboardPasting, me.onClipboardPasting);
        me.workBook.bind(Events.ButtonClicked, me.onButtonClicked);//复选框点击事件
    },
    getSectionTree: function (repId) {
        let me = this;
        let url = 'api/getRationTree';
        let postData = {rationLibId: repId};
        let sucFunc = function (rstData) {
            //init
            me.buildSheet();
            me.initTree(rstData);
            me.buildMapping(me.tree.items);
            me.cache = me.tree.items;
            me.initController(me.tree, me.sheet, me.setting.sheet);
            me.controller.showTreeData();
            me.sheet.setFormatter(-1, 1, '@');
            //init checkBox
            let checkBox = new GC.Spread.Sheets.CellTypes.CheckBox();
            me.sheet.getRange(-1, 0, -1, 1).cellType(checkBox);
            me.sheet.getRange(-1, 0, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
        };
        let errFunc = function () {

        };
        CommonAjax.post(url, postData, sucFunc, errFunc);
    },
    buildMapping: function (items) {
        this.IDRowMapping = {};
        for(let i = 0, len = items.length; i < len; i++){
            this.IDRowMapping[items[i].data.ID] = i;
        }
    },
    initTree: function (datas) {
        this.tree = idTree.createNew(this.setting.tree);
        this.tree.loadDatas(datas);
        this.tree.selected = this.tree.items.length > 0 ? this.tree.items[0] : null;
    },
    initController: function (tree, sheet, setting) {
        this.controller = TREE_SHEET_CONTROLLER.createNew(tree, sheet, setting);
    },
    onEditStarting: function (sender, args) {
        args.cancel = true;
    },
    onButtonClicked: function (sender, args) {
        let me = batchSectionObj;
        if(args.sheet.isEditing()){
            args.sheet.endEdit(true);
        }
        let node = me.cache[args.row];
        let checked = args.sheet.getValue(args.row, args.col);
        if(!me.isDef(node)){
            return;
        }
        let rows = me.getChildRows(node);
        me.setChecked(rows, checked);
    },
    onClipboardPasting: function (sender, info) {
        info.cancel = true;
    },
    getChildRows: function (node) {
        let rst = [], ids = [];
        getChildIds(node);
        for(id of ids){
            let row = this.IDRowMapping[id];
            if(this.isDef(row)){
                rst.push(row);
            }
        }
        return rst;
        function getChildIds(node){
            ids.push(node.data.ID);
            for(let child of node.children){
                getChildIds(child);
            }
        }
    },
    //设置勾选，跟随父节点
    setChecked: function (rows, checked) {
        let me = this;
        this.renderFunc(this.sheet, function () {
            for(let row of rows){
                me.sheet.setValue(row, 0, checked);
            }
        });
    },
    //获得勾选的章节ID
    getCheckedSection: function (sheet) {
        let rst = [];
        let rowCount = sheet.getRowCount();
        for(let i = 0, len = rowCount; i < len; i++){
            let checked = sheet.getValue(i, 0);
            //只返回叶子节点
            if(this.isDef(checked) && checked == true && this.isDef(this.cache[i]) && this.isDef(this.cache[i].data.ID) && this.cache[i].children.length === 0){
                rst.push(this.cache[i].data.ID);
            }
        }
        return Array.from(new Set(rst));
    },
    clearChecked: function () {
        let me = this;
        this.renderFunc(this.sheet, function () {
            let rowCount = me.sheet.getRowCount();
            for(let i = 0, len = rowCount; i < len; i++){
                me.sheet.setValue(i, 0, false);
            }
        });
    },
    onConfirmBtn: function () {
        let me = this, fi = feeItemObj, se = sectionObj;
        $('#bsTree_conf').bind('click', function () {
            let feeItemId = fi.currentFeeItem.ID;
            let sectionId = se.currentSection.ID;
            let rationSection = me.getCheckedSection(me.sheet);
            me.batchUpdate(feeItemId, sectionId, rationSection);
            $(this).unbind();
        });
    },
    //inst: 定额安装费用, rationSection: 定额章节树IDs
    batchUpdate: function (feeItemId, sectionId, rationSection) {
        CommonAjax.post('/rationRepository/api/batchUpdateInst', {inst: {feeItemId: feeItemId, sectionId: sectionId}, rationSection: rationSection}, function (rstData) {
            $('#sectionTreeModal').modal('hide');
        });
    }
};