瀏覽代碼

1. idTree, 根据Setting加载, 6项基本树结构操作
2. idTree,显示到Sheet, idTree6项基本树结构操作同步到Sheet
3. 暂定Model(project, bills, rations, gljs)

MaiXinRong 8 年之前
父節點
當前提交
0f8c30e51c

+ 448 - 0
public/web/idTree.js

@@ -0,0 +1,448 @@
+/**
+ * Created by Mai on 2017/3/17.
+ */
+var idTree = {
+    createNew: function (setting) {
+        var _setting = {
+            id: 'id',
+            pid: 'pid',
+            nid: 'nid',
+            rootId: -1
+        };
+
+        var tools = {
+            findNode: function (nodes, check) {
+                for (var i = 0; i < nodes.length; i++) {
+                    if (check(nodes[i])) {
+                        return nodes[i];
+                    }
+                }
+                return null;
+            },
+            reSortNodes: function (nodes, recursive) {
+                var temp = [], first;
+                var findFirstNode = function (nodes) {
+                    return tools.findNode(nodes, function (node) {
+                        return node.preSibling === null;
+                    });
+                };
+                var moveNode = function (node, orgArray, newArray, newIndex) {
+                    var next;
+                    orgArray.splice(orgArray.indexOf(node), 1);
+                    newArray.splice(newIndex, 0, node);
+                    if (node.getNextSiblingID() !== -1) {
+                        next = node.nextSibling;
+                        if (next && (orgArray.indexOf(next) >= 0)) {
+                            moveNode(next, orgArray, newArray, newIndex + 1);
+                        }
+                    }
+                };
+                if (nodes.length === 0) {
+                    return nodes;
+                }
+                if (recursive) {
+                    nodes.forEach(function (node) {
+                        node.children = tools.reSortNodes(node.children, recursive);
+                    });
+                }
+                while (nodes.length > 0) {
+                    first = findFirstNode(nodes);
+                    first = first ? first : nodes[0];
+                    moveNode(first, nodes, temp, temp.length);
+                }
+                nodes = null;
+                tools.reSiblingNodes(temp);
+                return temp;
+            },
+            reSiblingNodes: function (nodes) {
+                var i;
+                for (i = 0; i < nodes.length; i++) {
+                    nodes[i].preSibling = (i === 0) ? null : nodes[i - 1];
+                    nodes[i].nextSibling = (i === nodes.length - 1) ? null : nodes[i + 1];
+                }
+            },
+            // 在nodes中,从iIndex(包括)开始全部移除
+            removeNodes: function (tree, parent, iIndex, count) {
+                var children = parent ? parent.children : tree.roots;
+                var pre = (iIndex < 0 || iIndex >= children.length) ? null : children[iIndex].preSibling;
+                var next = (pre && iIndex + count - 1 < children.length) ? children[iIndex + count] : null;
+                if (pre) {
+                    pre.nextSibling = next;
+                }
+                if (next) {
+                    next.preSibling = pre;
+                }
+                if (arguments.length === 4) {
+                    children.splice(iIndex, count);
+                } else {
+                    children.splice(iIndex, children.length - iIndex);
+                }
+            },
+            // 在nodes中增加addNodes, 位置从index开始
+            addNodes: function (tree, parent, nodes, iIndex) {
+                var children = parent ? parent.children : tree.roots;
+                var pre, next, i;
+                if (nodes.length === 0) { return; }
+                if (arguments.length === 4) {
+                    pre = (iIndex <= 0 || iIndex > children.length) ? null : children[iIndex - 1];
+                    next = pre ? pre.nextSibling : null;
+                } else if (arguments.length === 3) {
+                    pre = children.length === 0 ? null : children[children.length - 1];
+                    next = null;
+                }
+                if (pre) {
+                    pre.nextSibling = nodes[0];
+                }
+                nodes[0].preSibling = pre;
+                if (next) {
+                    next.preSibling = nodes[nodes.length - 1];
+                }
+                nodes[nodes.length - 1].nextSibling = next;
+                for (i = 0; i < nodes.length; i++) {
+                    if (arguments.length === 4) {
+                        children.splice(iIndex + i, 0, nodes[i]);
+                    } else if (arguments.length === 3) {
+                        children.push(nodes[i]);
+                    }
+                    nodes[i].parent = parent;
+                }
+            },
+            sortTreeItems: function (tree) {
+                var addItems = function (items) {
+                    var i;
+                    for (i = 0; i < items.length; i++) {
+                        tree.items.push(items[i]);
+                        addItems(items[i].children);
+                    }
+                };
+                tree.items.splice(0, tree.items.length);
+                addItems(tree.roots);
+            }
+        };
+
+        var Node = function (tree, data) {
+            // 以下的属性,本单元外均不可直接修改
+            this.tree = tree;
+            this.data = data;
+            this.children = [];
+
+            this.parent = null;
+            this.nextSibling = null;
+            this.preSibling = null;
+
+            this.expanded = true;
+            this.visible = true;
+
+            this.visible = true;
+
+            this.isUpdate = false;
+            this.isNew = false;
+        };
+
+        Node.prototype.getID = function () {
+            return this.data[this.tree.setting.id];
+        };
+        Node.prototype.getParentID = function () {
+            return this.parent ? this.parent.getID() : -1;
+        };
+        Node.prototype.getNextSiblingID = function () {
+            return this.nextSibling ? this.nextSibling.getID() : -1;
+        };
+
+        Node.prototype.firstChild = function () {
+            return this.children.length === 0 ? null : this.children[0];
+        };
+        Node.prototype.depth = function () {
+            return this.parent ? this.parent.depth() + 1 : 0;
+        };
+        Node.prototype.isFirst = function () {
+            if (this.parent) {
+                return this.parent.children.indexOf(this) === 0 ? true : false;
+            } else {
+                return this.tree.roots.indexOf(this) === 0 ? true : false;
+            }
+        };
+        Node.prototype.isLast = function () {
+            if (this.parent) {
+                return this.parent.children.indexOf(this) === this.parent.children.length - 1 ? true : false;
+            } else {
+                return this.tree.roots.indexOf(this) === this.tree.roots.length - 1 ? true : false;
+            }
+        };
+        Node.prototype.siblingIndex = function () {
+            return this.parent ? this.parent.children.indexOf(this) : this.tree.roots.indexOf(this);
+        }
+        Node.prototype.posterityCount = function () {
+            var iCount = 0;
+            if (this.children.length !== 0) {
+                iCount += this.children.length;
+                this.children.forEach(function (child) {
+                    iCount += child.posterityCount();
+                });
+            }
+            return iCount;
+            /*return (node.children.length === 0) ? 0 : node.children.reduce(function (x, y) {
+                return x.posterityCount() + y.posterityCount();
+            }) + node.children.count;*/
+        };
+
+        Node.prototype.setExpanded = function (expanded) {
+            var setNodesVisible = function (nodes, visible) {
+                nodes.forEach(function (node) {
+                    node.visible = visible;
+                    setNodesVisible(node.children, visible && node.expanded);
+                })
+            };
+            this.expanded = expanded;
+            setNodesVisible(this.children, expanded);
+        };
+        /*Node.prototype.vis = function () {
+            return this.parent ? this.parent.vis() && this.parent.expanded() : true;
+        };*/
+        Node.prototype.serialNo = function () {
+            return this.tree.items.indexOf(this);
+        }
+        /*Node.prototype.serialNo = function () {
+            if (this.preSibling) {
+                return this.preSibling.serialNo() + this.preSibling.posterityCount() + 1;
+            } else if (this.parent) {
+                return this.parent.serialNo() + 1;
+            } else {
+                return 0;
+            }
+        };*/
+
+        Node.prototype.addChild = function (node) {
+            var preSibling = this.children.length === 0 ? null : this.children[this.children.length - 1];
+            node.parent = this;
+            if (preSibling) {
+                preSibling.nextSibling = node;
+            }
+            node.preSibling = preSibling;
+            this.children.push(node);
+        };
+        Node.prototype.removeChild = function (node) {
+            var preSibling = node.preSibling, nextSibling = node.nextSibling;
+            if (preSibling) {
+                preSibling.nextSibling = nextSibling;
+            }
+            if (nextSibling) {
+                nextSibling.preSibling = preSibling;
+            }
+            this.children.splice(this.children.re)
+        };
+
+        Node.prototype.canUpLevel = function () {
+            return this.parent ? true : false;
+        };
+        Node.prototype.canDownLevel = function () {
+            return !this.isFirst();
+        };
+        Node.prototype.canUpMove = function () {
+            return !this.isFirst();
+        };
+        Node.prototype.canDownMove = function () {
+            return !this.isLast();
+        }
+
+        Node.prototype.upLevel = function () {
+            var success = false,
+                iIndex = this.parent.children.indexOf(this), orgParent = this.parent, newNextSibling = this.parent.nextSibling;
+            if (this.canUpLevel) {
+                // NextSiblings become child
+                tools.addNodes(this.tree, this, this.parent.children.slice(iIndex + 1));
+                // Orginal Parent remove node and nextSiblings
+                tools.removeNodes(this.tree, this.parent, iIndex);
+                // New Parent add node
+                tools.addNodes(this.tree, this.parent.parent, [this], this.parent.siblingIndex() + 1);
+                if (!this.expanded) {
+                    this.setExpanded(true);
+                }
+                success = true;
+            }
+            return success;
+        };
+        Node.prototype.downLevel = function () {
+            var success = false, iIndex = this.parent ? this.parent.children.indexOf(this) : this.tree.roots.indexOf(this);
+            var newParent = this.preSibling;
+            if (this.canDownLevel()) {
+                tools.removeNodes(this.tree, this.parent, this.siblingIndex(), 1);
+                tools.addNodes(this.tree, this.preSibling, [this]);
+                if (!newParent.expanded) {
+                    newParent.setExpanded(true);
+                }
+                success = true;
+            }
+            return success;
+        };
+        Node.prototype.upMove = function () {
+            var success = false;
+            var iIndex = this.siblingIndex(), belongArray = this.parent ? this.parent.children : this.tree.roots, orgPre = this.preSibling;
+            if (this.canUpMove()) {
+                orgPre.nextSibling = this.nextSibling;
+                this.preSibling = orgPre.preSibling;
+                orgPre.preSibling = this;
+                this.nextSibling = orgPre;
+                belongArray.splice(iIndex, 1);
+                belongArray.splice(iIndex - 1, 0, this);
+                tools.sortTreeItems(this.tree);
+                success = true;
+            }
+            return success;
+        };
+        Node.prototype.downMove = function () {
+            var success = false;
+            var iIndex = this.siblingIndex(), belongArray = this.parent ? this.parent.children : this.tree.roots, orgNext = this.nextSibling;
+            if (this.canDownMove()) {
+                orgNext.preSibling = this.preSibling;
+                this.nextSibling = orgNext.nextSibling;
+                orgNext.nextSibling = this;
+                this.preSibling = orgNext;
+                belongArray.splice(iIndex, 1);
+                belongArray.splice(iIndex + 1, 0, this);
+                tools.sortTreeItems(this.tree);
+                success = true;
+            }
+            return success;
+        }
+
+        var Tree = function (setting) {
+            this.nodes = {};
+            this.roots = [];
+            this.items = [];
+            this.setting = setting;
+            this.prefix = 'id_';
+            this.selected = null;
+        };
+
+        Tree.prototype.maxNodeID = (function () {
+            var maxID = 0;
+            return function (ID) {
+                if (arguments.length === 0) {
+                    return maxID;
+                } else {
+                    maxID = Math.max(maxID, ID);
+                }
+            };
+        })();
+        Tree.prototype.rangeNodeID = (function () {
+            var rangeID = -1;
+            return function (ID) {
+                if (arguments.length === 0) {
+                    return rangeID;
+                } else {
+                    rangeID = Math.max(rangeID, ID);
+                }
+            }
+        })();
+        Tree.prototype.newNodeID = function () {
+            if (this.rangeNodeID() === -1) {
+                return this.maxNodeID() + 1;
+            } else {
+                if (this.maxNodeID() >= this.rangeNodeID()) {
+                    return this.maxNodeID() + 1;
+                } else {
+                    return -1;
+                }
+            }
+            /*if (this.maxID >= this.rangeNodeID() || this.rangeNodeID === -1) {
+                return -1;
+            } else {
+                return this.maxNodeID() + 1;
+            }*/
+        };
+
+        Tree.prototype.loadDatas = function (datas) {
+            var prefix = this.prefix, i, node, parent, next, that = this;
+            // prepare index
+            datas.forEach(function (data) {
+                var node = new Node(that, data);
+                that.nodes[prefix + data[that.setting.id]] = node;
+                that.maxNodeID(data[that.setting.id]);
+            });
+            // set parent by pid, set nextSibling by nid
+            datas.forEach(function (data) {
+                node = that.nodes[prefix + data[that.setting.id]];
+                if (data[that.setting.pid] === that.setting.rootId) {
+                    that.roots.push(node);
+                } else {
+                    parent = that.nodes[prefix + data[that.setting.pid]];
+                    if (parent) {
+                        node.parent = parent;
+                        parent.children.push(node);
+                    }
+                }
+                if (data[that.setting.nid] !== that.setting.rootId) {
+                    next = that.nodes[prefix + data[that.setting.nid]];
+                    if (next) {
+                        node.nextSibling = next;
+                        next.preSibling = node;
+                    }
+                }
+            })
+            // sort by nid
+            this.roots = tools.reSortNodes(this.roots, true);
+            tools.sortTreeItems(this);
+        };
+        Tree.prototype.firstNode = function () {
+            return this.roots.length === 0 ? null : this.roots[0];
+        };
+        Tree.prototype.findNode = function (id) {
+            return this.nodes[this.prefix + id];
+        };
+        Tree.prototype.count = function () {
+            var iCount = 0;
+            if (this.roots.length !== 0) {
+                iCount += this.roots.length;
+                this.roots.forEach(function (node) {
+                    iCount += node.posterityCount();
+                });
+            }
+            return iCount;
+        };
+
+        Tree.prototype.insert = function (parentID, nextSiblingID) {
+            var newID = this.newNodeID(), node = null, data = {};
+            var parent = parentID === -1 ? null : this.nodes[this.prefix + parentID];
+            var nextSibling = nextSiblingID === -1 ? null: this.nodes[this.prefix + nextSiblingID];
+            if (newID !== -1) {
+                data = {};
+                data[this.setting.id] = newID;
+                data[this.setting.pid] = parentID;
+                data[this.setting.nid] = nextSiblingID;
+                node = new Node(this, data);
+                if (nextSibling) {
+                    tools.addNodes(this, parent, [node], nextSibling.siblingIndex());
+                } else {
+                    tools.addNodes(this, parent, [node]);
+                }
+                this.nodes[this.prefix + newID] = node;
+                tools.sortTreeItems(this);
+                this.maxNodeID(newID);
+            }
+            return node;
+        };
+        Tree.prototype.delete = function (node) {
+            var success = false;
+            if (node) {
+                delete this.nodes[this.prefix + node.getID()];
+                if (node.preSibling) {
+                    node.preSibling.nextSibling = node.nextSibling;
+                }
+                if (node.nextSibling) {
+                    node.nextSibling.preSibling = node.preSibling;
+                }
+                if (node.parent) {
+                    node.parent.children.splice(node.siblingIndex(), 1);
+                } else {
+                    this.roots.splice(node.siblingIndex(), 1);
+                }
+                tools.sortTreeItems(this);
+                success = true;
+            }
+            return success;
+        }
+
+        return new Tree(setting);
+    }
+};

+ 104 - 0
public/web/tree_sheet_controller.js

@@ -0,0 +1,104 @@
+/**
+ * Created by Mai on 2017/4/1.
+ */
+
+var TREE_SHEET_CONTROLLER = {
+    createNew: function (tree, sheet, setting) {
+        var controller = function () {
+            this.tree = tree;
+            this.sheet = sheet;
+            this.setting = setting;
+        };
+
+        controller.prototype.showTreeData = function () {
+            var that = this;
+            TREE_SHEET_HELPER.loadSheetHeader(this.setting, this.sheet);
+            TREE_SHEET_HELPER.showTreeData(this.setting, this.sheet, this.tree);
+
+            this.sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e, info) {
+                that.tree.selected = that.tree.findNode(info.sheet.getTag(info.newSelections[0].row, info.newSelections[0].col));
+            });
+        };
+
+        controller.prototype.insert = function () {
+            var newNode = null, that = this;
+            if (this.tree && this.tree.selected) {
+                newNode = this.tree.insert(this.tree.selected.getParentID(), this.tree.selected.getNextSiblingID());
+                if (newNode) {
+                    TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
+                        var sels = that.sheet.getSelections();
+                        var iRow = sels[0].row, newNodeRow = iRow + that.tree.selected.posterityCount() + 1;
+                        that.sheet.addRows(newNodeRow, 1);
+                        TREE_SHEET_HELPER.refreshTreeNodeData(that.setting, that.sheet, [newNode], false);
+                        that.tree.selected = newNode;
+                        that.sheet.setSelection(newNode.serialNo(), sels[0].col, 1, 1);
+                        that.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center)
+                    })
+                }
+            }
+        };
+        controller.prototype.delete = function () {
+            var that = this;
+            if (this.tree.selected) {
+                if (this.tree.delete(this.tree.selected)) {
+                    TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
+                        var sels = that.sheet.getSelections();
+                        var iRow = sels[0].row;
+                        that.sheet.deleteRows(iRow, that.tree.selected.posterityCount() + 1);
+                        that.tree.selected = that.tree.findNode(that.sheet.getTag(iRow, 0, GC.Spread.Sheets.SheetArea.viewport));
+                    });
+                }
+            }
+        };
+        controller.prototype.upLevel = function () {
+            var that = this;
+            if (this.tree.selected) {
+                if (this.tree.selected.upLevel()) {
+                    TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
+                        TREE_SHEET_HELPER.refreshNodesVisible([that.tree.selected], that.sheet, true);
+                        that.sheet.showRow(that.tree.selected.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+                    });
+                }
+            }
+        };
+        controller.prototype.downLevel = function () {
+            var that = this;
+            if (this.tree.selected) {
+                if (this.tree.selected.downLevel()) {
+                    TREE_SHEET_HELPER.massOperationSheet(that.sheet, function () {
+                        TREE_SHEET_HELPER.refreshNodesVisible([that.tree.selected.parent], that.sheet, true);
+                        that.sheet.showRow(that.tree.selected.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+                    });
+                }
+            }
+        };
+        controller.prototype.upMove = function () {
+            var that = this;
+            if (this.tree.selected) {
+                if (this.tree.selected.upMove()) {
+                    TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
+                        var sels = that.sheet.getSelections();
+                        var iRow = sels[0].row;
+                        TREE_SHEET_HELPER.refreshTreeNodeData(that.setting, that.sheet, [that.tree.selected, that.tree.selected.nextSibling], true);
+                        that.sheet.setSelection(that.tree.selected.serialNo(), sels[0].col, 1, 1);
+                    });
+                }
+            }
+        };
+        controller.prototype.downMove = function () {
+            var that = this;
+            if (this.tree.selected) {
+                if (this.tree.selected.downMove()) {
+                    TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
+                        var sels = that.sheet.getSelections();
+                        var iRow = sels[0].row;
+                        TREE_SHEET_HELPER.refreshTreeNodeData(that.setting, that.sheet, [that.tree.selected, that.tree.selected.preSibling], true);
+                        that.sheet.setSelection(that.tree.selected.serialNo(), sels[0].col, 1, 1);
+                    });
+                }
+            }
+        };
+
+        return new controller();
+    }
+};

+ 234 - 0
public/web/tree_sheet_helper.js

@@ -0,0 +1,234 @@
+/**
+ * Created by Mai on 2017/4/1.
+ */
+
+var TREE_SHEET_HELPER = {
+    getSheetCellStyle: function (setting) {
+        var style = new GC.Spread.Sheets.Style();
+        style.locked = setting.readOnly;
+        style.name = setting.id;
+        style.font = setting.data.font;
+        style.hAlign = setting.data.hAlign;
+        style.vAlign = setting.data.vAlign;
+        //style.wordWrap = setting.data.wordWrap;
+        return style;
+    },
+    loadSheetHeader: function (setting, sheet) {
+        sheet.setColumnCount(setting.cols.length);
+        sheet.setRowCount(setting.headRows, GC.Spread.Sheets.SheetArea.colHeader);
+        setting.headRowHeight.forEach(function (rowHeight, index) {
+            sheet.setRowHeight(index, rowHeight, GC.Spread.Sheets.SheetArea.colHeader);
+        });
+        setting.cols.forEach(function (col, index) {
+            var i, iRow = 0, cell;
+            for (i = 0; i < col.head.spanCols.length; i++) {
+                if (col.head.spanCols[i] !== 0) {
+                    cell = sheet.getCell(iRow, index, GC.Spread.Sheets.SheetArea.colHeader);
+                    cell.value(col.head.titleNames[i]).font(col.head.font).hAlign(col.head.hAlign[i]).vAlign(col.head.vAlign[i]);
+                }
+                if (col.head.spanCols[i] > 1 || col.head.spanRows[i] > 1) {
+                    sheet.addSpan(iRow, index, col.head.spanRows[i], col.head.spanCols[i], GC.Spread.Sheets.SheetArea.colHeader);
+                }
+                iRow += col.head.spanRows[i];
+            };
+            sheet.setColumnWidth(index, col.width);
+        });
+    },
+    protectdSheet: function (sheet) {
+        var option = {
+            allowSelectLockedCells: true,
+            allowSelectUnlockedCells: true,
+            allowResizeRows: true,
+            allowResizeColumns: true
+        };
+
+        sheet.options.protectionOptions = option;
+        sheet.options.isProtected = true;
+    },
+    massOperationSheet: function (sheet, Operation) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        Operation();
+        sheet.resumeEvent();
+        sheet.resumePaint();
+    },
+    refreshNodesVisible: function (nodes, sheet, recursive) {
+        nodes.forEach(function (node) {
+            var iRow;
+            iRow = node.serialNo();
+            sheet.setRowVisible(iRow, node.visible, GC.Spread.Sheets.SheetArea.viewport);
+            if (recursive) {
+                TREE_SHEET_HELPER.refreshNodesVisible(node.children, sheet, recursive);
+            }
+        })
+    },
+    refreshTreeNodeData: function (setting, sheet, nodes, recursive) {
+        nodes.forEach(function (node) {
+            setting.cols.forEach(function (colSetting, iCol) {
+                var iRow = node.serialNo();
+                var cell = sheet.getCell(iRow, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                if (node.data[colSetting.data.field]) {
+                    cell.value(node.data[colSetting.data.field]);
+                } else {
+                    cell.text('');
+                }
+                sheet.setTag(iRow, iCol, node.getID());
+            });
+            if (recursive) {
+                TREE_SHEET_HELPER.refreshTreeNodeData(setting, sheet, node.children, recursive);
+            }
+        });
+    },
+    showTreeData: function (setting, sheet, tree) {
+        var indent = 20;
+        var halfBoxLength = 5;
+        var halfExpandLength = 3;
+
+        var TreeNodeCellType = function () {
+        };
+        TreeNodeCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
+        TreeNodeCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
+            // 画布,(x1, y1)起点(横, 竖), (x2, y2)终点(横, 竖), 颜色
+            var drawLine = function (canvas, x1, y1, x2, y2, color) {
+                ctx.save();
+                // 修正偏移量
+                ctx.translate(0.5, 0.5);
+                ctx.beginPath();
+                ctx.moveTo(x1, y1);
+                ctx.lineTo(x2, y2);
+                ctx.strokeStyle = color;
+                ctx.stroke();
+                ctx.restore();
+            };
+            var drawExpandBox = function (ctx, x, y, w, h, centerX, centerY, expanded) {
+                var rect = {}, h1, h2, offset = 1;
+                rect.top = centerY - halfBoxLength;
+                rect.bottom = centerY + halfBoxLength;
+                rect.left = centerX - halfBoxLength;
+                rect.right = centerX + halfBoxLength;
+
+                if (rect.left < x + w) {
+                    rect.right = Math.min(rect.right, x + w);
+
+                    ctx.save();
+                    // 修正偏移量
+                    ctx.translate(0.5, 0.5);
+                    ctx.strokeStyle = 'black';
+                    ctx.beginPath();
+                    ctx.moveTo(rect.left, rect.top);
+                    ctx.lineTo(rect.left, rect.bottom);
+                    ctx.lineTo(rect.right, rect.bottom);
+                    ctx.lineTo(rect.right, rect.top);
+                    ctx.lineTo(rect.left, rect.top);
+                    ctx.stroke();
+                    ctx.fillStyle = 'white';
+                    ctx.fill();
+                    ctx.restore();
+
+                    // Draw Horizontal Line
+                    h1 = centerX - halfExpandLength;
+                    h2 = Math.min(centerX + halfExpandLength, x + w);
+                    if (h2 > h1) {
+                        drawLine(ctx, h1, centerY, h2, centerY, 'black');
+                    }
+                    // Draw Vertical Line
+                    if (!expanded && (centerX < x + w)) {
+                        drawLine(ctx, centerX, centerY - halfExpandLength, centerX, centerY + halfExpandLength, 'black');
+                    }
+                }
+            }
+            var node = tree.findNode(options.sheet.getTag(options.row, options.col, options.SheetArea));
+            var showTreeLine = true;
+
+            if (!node) { return; }
+
+            var iLevel = node.depth();
+            var centerX = Math.floor(x) + node.depth() * indent + indent / 2;
+            var x1 = centerX + indent / 2;
+            var centerY = Math.floor((y + (y + h)) / 2);
+            var y1;
+            // Draw Sibling Line
+            if (showTreeLine) {
+                // Draw Horizontal Line
+                if (centerX < x + w) {
+                    drawLine(ctx, centerX, centerY, Math.min(x1, x + w), centerY, 'gray');
+                }
+                // Draw Vertical Line
+                if (centerX < x + w) {
+                    y1 = node.isLast() ? centerY : y + h;
+                    if (node.isFirst() && !node.parent) {
+                        drawLine(ctx, centerX, centerY, centerX, y1, 'gray');
+                    } else {
+                        drawLine(ctx, centerX, y, centerX, y1, 'gray');
+                    }
+                }
+            }
+            // Draw Expand Box
+            if (node.children.length > 0) {
+                drawExpandBox(ctx, x, y, w, h, centerX, centerY, node.expanded);
+            }
+            // Draw Parent Line
+            if (showTreeLine) {
+                var parent = node.parent, parentCenterX = centerX - indent;
+                while (parent) {
+                    if (!parent.isLast()) {
+                        if (parentCenterX < x + w) {
+                            drawLine(ctx, parentCenterX, y, parentCenterX, y + h, 'gray');
+                        }
+                    }
+                    parent = parent.parent;
+                    parentCenterX -= indent;
+                }
+            };
+            // Draw Text
+            x = x + (node.depth() + 1) * indent;
+            GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
+        };
+        TreeNodeCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
+            return {
+                x: x,
+                y: y,
+                row: context.row,
+                col: context.col,
+                cellStyle: cellStyle,
+                cellRect: cellRect,
+                sheetArea: context.sheetArea
+            };
+        }
+        TreeNodeCellType.prototype.processMouseDown = function (hitinfo) {
+            var offset = -1;
+            var node = tree.findNode(hitinfo.sheet.getTag(hitinfo.row, hitinfo.col, hitinfo.sheetArea));
+            tree.selected = node;
+            if (!node || node.children.length === 0) { return; }
+            var centerX = hitinfo.cellRect.x + offset + node.depth() * indent + indent / 2;
+            var centerY = (hitinfo.cellRect.y + offset + (hitinfo.cellRect.y + offset + hitinfo.cellRect.height)) / 2;
+
+            if (hitinfo.x > centerX - halfBoxLength && hitinfo.x < centerX + halfBoxLength && hitinfo.y > centerY - halfBoxLength && hitinfo.y < centerY + halfBoxLength) {
+                node.setExpanded(!node.expanded);
+                TREE_SHEET_HELPER.massOperationSheet(hitinfo.sheet, function () {
+                    var iCount = node.posterityCount(), i, child;
+                    for (i = 0; i < iCount; i++) {
+                        child = tree.findNode(hitinfo.sheet.getTag(hitinfo.row + i + 1, hitinfo.col, hitinfo.sheetArea));
+                        hitinfo.sheet.setRowVisible(hitinfo.row + i + 1, child.visible, hitinfo.sheetArea);
+                        //hitinfo.sheet.setRowVisible(hitinfo.row + i + 1, child.vis(), hitinfo.sheetArea);
+                    }
+                    hitinfo.sheet.invalidateLayout();
+                });
+                hitinfo.sheet.repaint();
+            }
+        };
+
+        TREE_SHEET_HELPER.protectdSheet(sheet);
+        TREE_SHEET_HELPER.massOperationSheet(sheet, function () {
+            sheet.rowOutlines.direction(GC.Spread.Sheets.Outlines.OutlineDirection.backward);
+            sheet.showRowOutline(false);
+            sheet.setRowCount(tree.count() + setting.emptyRows, GC.Spread.Sheets.SheetArea.viewport);
+            setting.cols.forEach(function (colSetting, iCol) {
+                sheet.setStyle(-1, iCol, TREE_SHEET_HELPER.getSheetCellStyle(colSetting));
+            });
+            sheet.getRange(-1, setting.treeCol, -1, 1).cellType(new TreeNodeCellType());
+            TREE_SHEET_HELPER.refreshTreeNodeData(setting, sheet, tree.roots, true);
+            TREE_SHEET_HELPER.refreshNodesVisible(tree.roots, sheet, true);
+        });
+    }
+};

File diff suppressed because it is too large
+ 133 - 2119
web/main/html/main.html


+ 33 - 0
web/main/js/models/bills.js

@@ -0,0 +1,33 @@
+/**
+ * Created by Mai on 2017/4/1.
+ */
+
+var Bills = {
+    createNew: function (project) {
+        var billsTreeSetting = {
+            id: 'ID',
+            pid: 'ParentID',
+            nid: 'NextSiblingID',
+            rootId: -1
+        };
+
+        // 用户定义private方法
+        var tools = {};
+
+        // 所有通过this访问的属性,都不应在此单元外部进行写入操作
+        var bills = function (proj) {
+            this.project = proj;
+            this.datas = null;
+            this.tree = null;
+        };
+
+        // prototype用于定义public方法
+        bills.prototype.loadDatas = function (datas) {
+            this.datas = datas;
+            this.tree = idTree.createNew(billsTreeSetting);
+            this.tree.loadDatas(this.datas);
+        };
+
+        return new bills(project);
+    }
+};

+ 22 - 0
web/main/js/models/gljs.js

@@ -0,0 +1,22 @@
+/**
+ * Created by Mai on 2017/4/1.
+ */
+var GLJs = {
+    createNew: function (project) {
+        // 用户定义private方法
+        var tools = {};
+
+        // 所有通过this访问的属性,都不应在此单元外部进行写入操作
+        var gljs = function (proj) {
+            this.project = proj;
+            this.datas = null;
+        };
+
+        // prototype用于定义public方法
+        gljs.prototype.loadDatas = function (datas) {
+            this.datas = datas;
+        };
+
+        return new gljs(project);
+    }
+};

+ 23 - 0
web/main/js/models/project.js

@@ -0,0 +1,23 @@
+/**
+ * Created by Mai on 2017/4/1.
+ */
+var PROJECT = {
+    createNew: function () {
+        // 定义private方法
+        var tools = {};
+
+        // 所有通过this访问的属性,都不应在此单元外部进行写入操作
+        var project = function () {
+            this.Bills = Bills.createNew(this);
+            this.Rations = Rations.createNew(this);
+            this.GLJ = GLJs.createNew(this);
+        };
+
+        // prototype用于定义public方法
+        project.prototype.modify = function (modifyDatas, callback) {
+            // To Do
+        };
+
+        return new project();
+    }
+};

+ 23 - 0
web/main/js/models/rations.js

@@ -0,0 +1,23 @@
+/**
+ * Created by Mai on 2017/4/1.
+ */
+
+var Rations = {
+    createNew: function (project) {
+        // 用户定义private方法
+        var tools = {};
+
+        // 所有通过this访问的属性,都不应在此单元外部进行写入操作
+        var rations = function (proj) {
+            this.project = proj;
+            this.datas = null;
+        };
+
+        // prototype用于定义public方法
+        rations.prototype.loadDatas = function (datas) {
+            this.datas = datas;
+        };
+
+        return new rations(project);
+    }
+};

+ 7 - 7
web/pm/html/project-management.html

@@ -112,12 +112,12 @@
                 <div class="col-lg-10">
                     <div class="toolsbar">
                         <div class="tools-btn btn-group align-top">
-                            <a href="javacript:void(0);" class="btn btn-sm" id="addProjBtn">新建工程</a>
-                            <a href="javacript:void(0);" class="btn btn-sm" id="addFolderBtn"><i class="fa fa-folder-o"></i>&nbsp;新建文件夹</a>
-                            <a href="javacript:void(0);" class="btn btn-sm" id="renameBtn">重命名</a>
-                            <a href="javacript:void(0);" class="btn btn-sm" id="delBtn">删除</a>
-                            <a href="javacript:void(0);" class="btn btn-sm" id="movetoBtn">移动到...</a>
-                            <a href="javacript:void(0);" class="btn btn-sm" id="copytoBtn">复制到...</a>
+                            <a href="javascript:void(0);" class="btn btn-sm" id="addProjBtn">新建工程</a>
+                            <a href="javascript:void(0);" class="btn btn-sm" id="addFolderBtn"><i class="fa fa-folder-o"></i>&nbsp;新建文件夹</a>
+                            <a href="javascript:void(0);" class="btn btn-sm" id="renameBtn">重命名</a>
+                            <a href="javascript:void(0);" class="btn btn-sm" id="delBtn">删除</a>
+                            <a href="javascript:void(0);" class="btn btn-sm" id="movetoBtn">移动到...</a>
+                            <a href="javascript:void(0);" class="btn btn-sm" id="copytoBtn">复制到...</a>
                             <a href="" class="btn btn-sm" id="shareBtn">共享</a>
                             <a href="" class="btn btn-sm" id="cooperateBtn">协同</a>
                         </div>
@@ -383,7 +383,7 @@
                 </div>
                 <div class="modal-footer">
                     <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                    <a href="javacript:void(0);" class="btn btn-primary" id="renameOk">确定</a>
+                    <a href="javascript:void(0);" class="btn btn-primary" id="renameOk">确定</a>
                 </div>
             </div>
         </div>