/* =========================================================
* bootstrap-treeview.js v1.2.0
* =========================================================
* Copyright 2013 Jonathan Miles
* Project URL : http://www.jondmiles.com/bootstrap-treeview
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================= */
(function($, window, document, undefined) {
/*global jQuery, console*/
"use strict";
var pluginName = "treeview";
var _default = {};
_default.settings = {
injectStyle: true,
levels: 2,
expandIcon: "glyphicon glyphicon-folder-open",
collapseIcon: "glyphicon glyphicon-folder-open",
emptyIcon: "glyphicon glyphicon-file",
nodeIcon: "glyphicon",
selectedIcon: "",
checkedIcon: "glyphicon glyphicon-check",
uncheckedIcon: "glyphicon glyphicon-unchecked",
color: undefined, // '#000000',
backColor: undefined, // '#FFFFFF',
borderColor: undefined, // '#dddddd',
onhoverColor: "#F5F5F5",
selectedColor: "#337ab7",
selectedBackColor: "#f5f5f5",
searchResultColor: "#D9534F",
searchResultBackColor: undefined, //'#FFFFFF',
enableLinks: false,
highlightSelected: true,
highlightSearchResults: true,
showBorder: true,
showIcon: true,
showCheckbox: false,
showTags: false,
multiSelect: false,
// Event handlers
onNodeChecked: undefined,
onNodeCollapsed: undefined,
onNodeDisabled: undefined,
onNodeEnabled: undefined,
onNodeExpanded: undefined,
onNodeSelected: undefined,
onNodeUnchecked: undefined,
onNodeUnselected: undefined,
onSearchComplete: undefined,
onSearchCompleteV2: undefined,
onSearchCleared: undefined
};
_default.options = {
silent: false,
ignoreChildren: false
};
_default.searchOptions = {
ignoreCase: true,
exactMatch: false,
revealResults: true
};
var Tree = function(element, options) {
this.$element = $(element);
this.elementId = element.id;
this.styleId = this.elementId + "-style";
this.init(options);
return {
// Options (public access)
options: this.options,
// Initialize / destroy methods
init: $.proxy(this.init, this),
initTree: $.proxy(this.initTree, this),
remove: $.proxy(this.remove, this),
addNode: $.proxy(this.addNode, this),
refreshTree: $.proxy(this.refreshTree, this),
updateNode: $.proxy(this.updateNode, this),
//删除节点
deleteNode: $.proxy(this.deleteNode, this),
setDeleteNode: $.proxy(this.setDeleteNode, this),
// Get methods
getNode: $.proxy(this.getNode, this),
getNodeV2: $.proxy(this.getNodeV2, this),
getParent: $.proxy(this.getParent, this),
getSiblings: $.proxy(this.getSiblings, this),
getSelected: $.proxy(this.getSelected, this),
getUnselected: $.proxy(this.getUnselected, this),
getExpanded: $.proxy(this.getExpanded, this),
getCollapsed: $.proxy(this.getCollapsed, this),
getChecked: $.proxy(this.getChecked, this),
getUnchecked: $.proxy(this.getUnchecked, this),
getDisabled: $.proxy(this.getDisabled, this),
getEnabled: $.proxy(this.getEnabled, this),
// Select methods
selectNode: $.proxy(this.selectNode, this),
unselectNode: $.proxy(this.unselectNode, this),
toggleNodeSelected: $.proxy(this.toggleNodeSelected, this),
// Expand / collapse methods
collapseAll: $.proxy(this.collapseAll, this),
collapseNode: $.proxy(this.collapseNode, this),
expandAll: $.proxy(this.expandAll, this),
expandNode: $.proxy(this.expandNode, this),
toggleNodeExpanded: $.proxy(this.toggleNodeExpanded, this),
revealNode: $.proxy(this.revealNode, this),
// Expand / collapse methods
checkAll: $.proxy(this.checkAll, this),
checkNode: $.proxy(this.checkNode, this),
uncheckAll: $.proxy(this.uncheckAll, this),
uncheckNode: $.proxy(this.uncheckNode, this),
toggleNodeChecked: $.proxy(this.toggleNodeChecked, this),
// Disable / enable methods
disableAll: $.proxy(this.disableAll, this),
disableNode: $.proxy(this.disableNode, this),
enableAll: $.proxy(this.enableAll, this),
enableNode: $.proxy(this.enableNode, this),
toggleNodeDisabled: $.proxy(this.toggleNodeDisabled, this),
// Search methods
search: $.proxy(this.search, this),
clearSearch: $.proxy(this.clearSearch, this),
searchV2: $.proxy(this.searchV2, this)
};
};
Tree.prototype.init = function(options) {
this.tree = [];
this.nodes = [];
if (options.data) {
if (typeof options.data === "string") {
options.data = $.parseJSON(options.data);
}
this.tree = $.extend(true, [], options.data);
delete options.data;
}
this.options = $.extend({}, _default.settings, options);
this.destroy();
this.subscribeEvents();
this.setInitialStates({ nodes: this.tree }, 0);
this.render();
};
// Tree.prototype.initTree = function(data) {
// this.tree = [];
// this.nodes = [];
// console.log("initTree data", data);
// if (data) {
// if (typeof data === "string") {
// data = $.parseJSON(data);
// }
// this.tree = $.extend(true, [], data);
// //delete data;
// }
// //this.options = $.extend({}, _default.settings, options);
// this.setInitialStates({ nodes: this.tree }, 0);
// this.render();
// };
Tree.prototype.remove = function() {
this.destroy();
$.removeData(this, pluginName);
$("#" + this.styleId).remove();
};
Tree.prototype.destroy = function() {
if (!this.initialized) return;
this.$wrapper.remove();
this.$wrapper = null;
// Switch off events
this.unsubscribeEvents();
// Reset this.initialized flag
this.initialized = false;
};
Tree.prototype.unsubscribeEvents = function() {
this.$element.off("click");
this.$element.off("nodeChecked");
this.$element.off("nodeCollapsed");
this.$element.off("nodeDisabled");
this.$element.off("nodeEnabled");
this.$element.off("nodeExpanded");
this.$element.off("nodeSelected");
this.$element.off("nodeUnchecked");
this.$element.off("nodeUnselected");
this.$element.off("searchComplete");
this.$element.off("searchCompleteV2");
this.$element.off("searchCleared");
};
Tree.prototype.subscribeEvents = function() {
this.unsubscribeEvents();
this.$element.on("click", $.proxy(this.clickHandler, this));
if (typeof this.options.onNodeChecked === "function") {
this.$element.on("nodeChecked", this.options.onNodeChecked);
}
if (typeof this.options.onNodeCollapsed === "function") {
this.$element.on("nodeCollapsed", this.options.onNodeCollapsed);
}
if (typeof this.options.onNodeDisabled === "function") {
this.$element.on("nodeDisabled", this.options.onNodeDisabled);
}
if (typeof this.options.onNodeEnabled === "function") {
this.$element.on("nodeEnabled", this.options.onNodeEnabled);
}
if (typeof this.options.onNodeExpanded === "function") {
this.$element.on("nodeExpanded", this.options.onNodeExpanded);
}
if (typeof this.options.onNodeSelected === "function") {
this.$element.on("nodeSelected", this.options.onNodeSelected);
}
if (typeof this.options.onNodeUnchecked === "function") {
this.$element.on("nodeUnchecked", this.options.onNodeUnchecked);
}
if (typeof this.options.onNodeUnselected === "function") {
this.$element.on("nodeUnselected", this.options.onNodeUnselected);
}
if (typeof this.options.onSearchComplete === "function") {
this.$element.on("searchComplete", this.options.onSearchComplete);
}
if (typeof this.options.onSearchCompleteV2 === "function") {
this.$element.on("searchCompleteV2", this.options.onSearchCompleteV2);
}
if (typeof this.options.onSearchCleared === "function") {
this.$element.on("searchCleared", this.options.onSearchCleared);
}
};
/*
Recurse the tree structure and ensure all nodes have
valid initial states. User defined states will be preserved.
For performance we also take this opportunity to
index nodes in a flattened structure
*/
Tree.prototype.setInitialStates = function(node, level) {
if (!node.nodes) return;
level += 1;
// debugger;
var parent = node;
var _this = this;
$.each(node.nodes, function checkStates(index, node) {
// nodeId : unique, incremental identifier
//console.log("setInitialStates=node", node);
//node.nodeId = _this.nodes.length;
node.nodeId = _this.nodes.length;
// parentId : transversing up the tree
//node.parentId = parent.nodeId;
node.parentId = parent.nodeId;
// if not provided set selectable default value
if (!node.hasOwnProperty("selectable")) {
node.selectable = true;
}
// where provided we should preserve states
node.state = node.state || {};
// set checked state; unless set always false
if (!node.state.hasOwnProperty("checked")) {
node.state.checked = false;
}
// set enabled state; unless set always false
if (!node.state.hasOwnProperty("disabled")) {
node.state.disabled = false;
}
// set expanded state; if not provided based on levels
if (!node.state.hasOwnProperty("expanded")) {
if (
!node.state.disabled &&
level < _this.options.levels &&
(node.nodes && node.nodes.length > 0)
) {
node.state.expanded = true;
} else {
node.state.expanded = false;
}
}
// set selected state; unless set always false
if (!node.state.hasOwnProperty("selected")) {
node.state.selected = false;
}
// index nodes in a flattened structure for use later
_this.nodes.push(node);
// recurse child nodes and transverse the tree
if (node.nodes) {
_this.setInitialStates(node, level);
}
});
};
Tree.prototype.clickHandler = function(event) {
if (!this.options.enableLinks) event.preventDefault();
//console.log("event", event);
var target = $(event.target);
//console.log("target", target);
var node = this.findNode(target);
if (!node || node.state.disabled) return;
var classList = target.attr("class") ? target.attr("class").split(" ") : [];
if (classList.indexOf("expand-icon") !== -1) {
this.toggleExpandedState(node, _default.options);
this.render();
} else if (classList.indexOf("check-icon") !== -1) {
this.toggleCheckedState(node, _default.options);
this.render();
} else {
if (node.selectable) {
this.toggleSelectedState(node, _default.options);
} else {
this.toggleExpandedState(node, _default.options);
}
this.render();
}
};
Tree.prototype.refreshTree = function(identifiers, options) {
this.setInitialStates({ nodes: this.tree }, 0);
this.render();
};
/**
Updates / replaces a given tree node
@param {Object} node - A single node to be replaced
@param {Object} newNode - THe replacement node
@param {optional Object} options
*/
Tree.prototype.updateNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, newnode, options) {
// console.log("updateNode", node);
// console.log("options", options);
var parentNode = this.getParent(node);
//console.log("parentNode", parentNode);
this.setUpdateNode(parentNode, newnode, options);
}, this)
);
};
Tree.prototype.setUpdateNode = function(node, newnode, options) {
// console.log("newnode", newnode);
// console.log("node", node);
//当修改最上级的名称时node==undefined
//debugger;
if (node == undefined) {
node = this.tree;
for (var i = this.tree.length - 1; i >= 0; i--) {
//console.log("this.tree[i]", this.tree[i]);
var mynode = this.tree[i];
// console.log("mynode", mynode);
// console.log("newnode", newnode);
if (mynode.id === newnode.id) {
// this.tree[i].text = newnode.text;
// this.tree[i].spdd_orderid = newnode.spdd_orderid;
this.tree[i] = newnode;
break;
}
}
} else if (node.nodes != null) {
for (var i = node.nodes.length - 1; i >= 0; i--) {
var mynode = node.nodes[i];
// console.log("mynode", mynode);
// console.log("newnode", newnode);
if (mynode.id === newnode.id) {
node.nodes[i] = newnode;
break;
// node.nodes[i].text = newnode.text;
// node.nodes[i].spdd_orderid = newnode.spdd_orderid;
}
}
// console.log("this.tree_finish", this.tree);
// console.log("node.nodes", this.tree.nodes);
}
this.nodes = [];
this.setInitialStates({ nodes: this.tree }, 0);
this.render();
};
Tree.prototype.addNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
//console.log("node", node);
this.setAddNode(node, options);
}, this)
);
this.nodes = [];
this.setInitialStates({ nodes: this.tree }, 0);
this.render();
};
Tree.prototype.setAddNode = function(node, options) {
if (node.nodes == null) node.nodes = [];
if (options.node) {
node.nodes.push(options.node);
}
//console.log("node-v2", node);
};
Tree.prototype.deleteNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
var parentNode = this.getParent(node);
//console.log("parentNode", parentNode);
this.setDeleteNode(parentNode, node, options);
}, this)
);
};
Tree.prototype.setDeleteNode = function(node, deletenode, options) {
if (node == undefined) {
//如果父级为空,直接在最外层删除
//如果树节点在最外层删除,没有父节点,那么直接删除最后一个
for (var i = this.tree.length - 1; i >= 0; i--) {
var mynode = this.tree[i];
if (mynode.id === deletenode.id) {
this.tree.splice(i, 1);
}
}
} else if (node.nodes != null) {
for (var i = node.nodes.length - 1; i >= 0; i--) {
var mynode = node.nodes[i];
if (mynode.id === deletenode.id) {
node.nodes.splice(i, 1);
}
}
}
this.nodes = [];
this.setInitialStates({ nodes: this.tree }, 0);
this.render();
};
// Looks up the DOM for the closest parent list item to retrieve the
// data attribute nodeid, which is used to lookup the node in the flattened structure.
Tree.prototype.findNodeV2 = function(id) {
var _this = this;
return this.nodes.find((item, index) => {
var val = _this.getNodeValueV2(item, id);
if (val != undefined) {
return val;
}
});
};
/**
Recursive find for retrieving nested attributes values
All values are return as strings, unless invalid
@param {Object} obj - Typically a node, could be any object
@param {String} attr - Identifies an object property using dot notation
@return {String} value - Matching attributes string representation
*/
Tree.prototype.getNodeValueV2 = function(obj, id) {
if (obj.id == id) {
return obj;
} else {
return undefined;
}
};
// Looks up the DOM for the closest parent list item to retrieve the
// data attribute nodeid, which is used to lookup the node in the flattened structure.
Tree.prototype.findNode = function(target) {
var nodeId = target.closest("li.list-group-item").attr("data-nodeid");
//console.log("this.nodes", this.nodes);
//console.log("findNode-nodeId", nodeId);
var node = this.nodes[nodeId];
if (!node) {
console.log("Error: node does not exist");
}
return node;
};
Tree.prototype.toggleExpandedState = function(node, options) {
if (!node) return;
this.setExpandedState(node, !node.state.expanded, options);
};
Tree.prototype.setExpandedState = function(node, state, options) {
if (state === node.state.expanded) return;
if (state && node.nodes) {
// Expand a node
node.state.expanded = true;
if (!options.silent) {
this.$element.trigger("nodeExpanded", $.extend(true, {}, node));
}
} else if (!state) {
// Collapse a node
node.state.expanded = false;
if (!options.silent) {
this.$element.trigger("nodeCollapsed", $.extend(true, {}, node));
}
// Collapse child nodes
if (node.nodes && !options.ignoreChildren) {
$.each(
node.nodes,
$.proxy(function(index, node) {
this.setExpandedState(node, false, options);
}, this)
);
}
}
};
Tree.prototype.toggleSelectedState = function(node, options) {
if (!node) return;
this.setSelectedState(node, !node.state.selected, options);
};
Tree.prototype.setSelectedState = function(node, state, options) {
if (state === node.state.selected) return;
if (state) {
// If multiSelect false, unselect previously selected
if (!this.options.multiSelect) {
$.each(
this.findNodes("true", "g", "state.selected"),
$.proxy(function(index, node) {
this.setSelectedState(node, false, options);
}, this)
);
}
// Continue selecting node
node.state.selected = true;
if (!options.silent) {
this.$element.trigger("nodeSelected", $.extend(true, {}, node));
}
} else {
// Unselect node
node.state.selected = false;
if (!options.silent) {
this.$element.trigger("nodeUnselected", $.extend(true, {}, node));
}
}
};
Tree.prototype.toggleCheckedState = function(node, options) {
if (!node) return;
this.setCheckedState(node, !node.state.checked, options);
};
Tree.prototype.setCheckedState = function(node, state, options) {
if (state === node.state.checked) return;
if (state) {
// Check node
node.state.checked = true;
if (!options.silent) {
this.$element.trigger("nodeChecked", $.extend(true, {}, node));
}
} else {
// Uncheck node
node.state.checked = false;
if (!options.silent) {
this.$element.trigger("nodeUnchecked", $.extend(true, {}, node));
}
}
};
Tree.prototype.setDisabledState = function(node, state, options) {
if (state === node.state.disabled) return;
if (state) {
// Disable node
node.state.disabled = true;
// Disable all other states
this.setExpandedState(node, false, options);
this.setSelectedState(node, false, options);
this.setCheckedState(node, false, options);
if (!options.silent) {
this.$element.trigger("nodeDisabled", $.extend(true, {}, node));
}
} else {
// Enabled node
node.state.disabled = false;
if (!options.silent) {
this.$element.trigger("nodeEnabled", $.extend(true, {}, node));
}
}
};
Tree.prototype.render = function() {
if (!this.initialized) {
// Setup first time only components
this.$element.addClass(pluginName);
this.$wrapper = $(this.template.list);
this.injectStyle();
this.initialized = true;
}
this.$element.empty().append(this.$wrapper.empty());
// Build tree
this.buildTree(this.tree, 0);
};
// Starting from the root node, and recursing down the
// structure we build the tree one node at a time
Tree.prototype.buildTree = function(nodes, level) {
if (!nodes) return;
level += 1;
var _this = this;
$.each(nodes, function addNodes(id, node) {
var treeItem = $(_this.template.item)
.addClass("node-" + _this.elementId)
.addClass(node.state.checked ? "node-checked" : "")
.addClass(node.state.disabled ? "node-disabled" : "")
.addClass(node.state.selected ? "node-selected" : "")
.addClass(node.searchResult ? "search-result" : "")
.attr("data-nodeid", node.nodeId)
.attr("id", node.id)
.attr("style", _this.buildStyleOverride(node));
// Add indent/spacer to mimic tree structure
for (var i = 0; i < level - 1; i++) {
treeItem.append(_this.template.indent);
}
// Add expand, collapse or empty spacer icons
var classList = [];
if (node.nodes) {
classList.push("expand-icon");
if (node.state.expanded) {
classList.push(_this.options.collapseIcon);
} else {
classList.push(_this.options.expandIcon);
}
} else {
classList.push(_this.options.emptyIcon);
}
treeItem.append($(_this.template.icon).addClass(classList.join(" ")));
// Add node icon
if (_this.options.showIcon) {
var classList = ["node-icon"];
classList.push(node.icon || _this.options.nodeIcon);
if (node.state.selected) {
classList.pop();
classList.push(
node.selectedIcon ||
_this.options.selectedIcon ||
node.icon ||
_this.options.nodeIcon
);
}
treeItem.append($(_this.template.icon).addClass(classList.join(" ")));
}
// Add check / unchecked icon
if (_this.options.showCheckbox) {
var classList = ["check-icon"];
if (node.state.checked) {
classList.push(_this.options.checkedIcon);
} else {
classList.push(_this.options.uncheckedIcon);
}
treeItem.append($(_this.template.icon).addClass(classList.join(" ")));
}
// Add text
if (_this.options.enableLinks) {
// Add hyperlink
treeItem.append(
$(_this.template.link)
.attr("href", node.href)
.append(node.text)
);
} else {
// otherwise just text
treeItem.append(node.text);
}
// Add tags as badges
if (_this.options.showTags && node.tags) {
$.each(node.tags, function addTag(id, tag) {
treeItem.append($(_this.template.badge).append(tag));
});
}
//如果有html内容,增加
if (_this.options.showAfterHtml && node.after_html) {
treeItem.append(node.after_html);
}
// Add item to the tree
_this.$wrapper.append(treeItem);
// Recursively add child ndoes
if (node.nodes && node.state.expanded && !node.state.disabled) {
return _this.buildTree(node.nodes, level);
}
});
};
// Define any node level style override for
// 1. selectedNode
// 2. node|data assigned color overrides
Tree.prototype.buildStyleOverride = function(node) {
if (node.state.disabled) return "";
var color = node.color;
var backColor = node.backColor;
if (this.options.highlightSelected && node.state.selected) {
if (this.options.selectedColor) {
color = this.options.selectedColor;
}
if (this.options.selectedBackColor) {
backColor = this.options.selectedBackColor;
}
}
if (
this.options.highlightSearchResults &&
node.searchResult &&
!node.state.disabled
) {
if (this.options.searchResultColor) {
color = this.options.searchResultColor;
}
if (this.options.searchResultBackColor) {
backColor = this.options.searchResultBackColor;
}
}
return "color:" + color + ";background-color:" + backColor + ";";
};
// Add inline style into head
Tree.prototype.injectStyle = function() {
if (this.options.injectStyle && !document.getElementById(this.styleId)) {
$(
'<style type="text/css" id="' +
this.styleId +
'"> ' +
this.buildStyle() +
" </style>"
).appendTo("head");
}
};
// Construct trees style based on user options
Tree.prototype.buildStyle = function() {
var style = ".node-" + this.elementId + "{";
if (this.options.color) {
style += "color:" + this.options.color + ";";
}
if (this.options.backColor) {
style += "background-color:" + this.options.backColor + ";";
}
if (!this.options.showBorder) {
style += "border:none;";
} else if (this.options.borderColor) {
style += "border:1px solid " + this.options.borderColor + ";";
}
style += "}";
if (this.options.onhoverColor) {
style +=
".node-" +
this.elementId +
":not(.node-disabled):hover{" +
"background-color:" +
this.options.onhoverColor +
";" +
"}";
}
return this.css + style;
};
Tree.prototype.template = {
list: '<ul class="list-group"></ul>',
item: '<li class="list-group-item"></li>',
indent: '<span class="indent"></span>',
icon: '<span class="icon"></span>',
link: '<a href="#" style="color:inherit;"></a>',
badge: '<span class="badge"></span>'
};
Tree.prototype.css =
".treeview .list-group-item{cursor:pointer}.treeview span.indent{margin-left:10px;margin-right:10px}.treeview span.icon{width:12px;margin-right:5px}.treeview .node-disabled{color:silver;cursor:not-allowed}";
/**
Returns a single node object that matches the given node id.
@param {Number} nodeId - A node's unique identifier
@return {Object} node - Matching node
*/
Tree.prototype.getNode = function(nodeId) {
return this.nodes[nodeId];
};
/**
Returns a single node object that matches the given node id.
@param {Number} nodeId - A node's unique identifier
@return {Object} node - Matching node
*/
Tree.prototype.getNodeV2 = function(id) {
return this.findNodeV2(id);
};
/**
Returns the parent node of a given node, if valid otherwise returns undefined.
@param {Object|Number} identifier - A valid node or node id
@returns {Object} node - The parent node
*/
Tree.prototype.getParent = function(identifier) {
var node = this.identifyNode(identifier);
return this.nodes[node.parentId];
};
/**
Returns an array of sibling nodes for a given node, if valid otherwise returns undefined.
@param {Object|Number} identifier - A valid node or node id
@returns {Array} nodes - Sibling nodes
*/
Tree.prototype.getSiblings = function(identifier) {
var node = this.identifyNode(identifier);
var parent = this.getParent(node);
var nodes = parent ? parent.nodes : this.tree;
return nodes.filter(function(obj) {
return obj.nodeId !== node.nodeId;
});
};
/**
Returns an array of selected nodes.
@returns {Array} nodes - Selected nodes
*/
Tree.prototype.getSelected = function() {
return this.findNodes("true", "g", "state.selected");
};
/**
Returns an array of unselected nodes.
@returns {Array} nodes - Unselected nodes
*/
Tree.prototype.getUnselected = function() {
return this.findNodes("false", "g", "state.selected");
};
/**
Returns an array of expanded nodes.
@returns {Array} nodes - Expanded nodes
*/
Tree.prototype.getExpanded = function() {
return this.findNodes("true", "g", "state.expanded");
};
/**
Returns an array of collapsed nodes.
@returns {Array} nodes - Collapsed nodes
*/
Tree.prototype.getCollapsed = function() {
return this.findNodes("false", "g", "state.expanded");
};
/**
Returns an array of checked nodes.
@returns {Array} nodes - Checked nodes
*/
Tree.prototype.getChecked = function() {
return this.findNodes("true", "g", "state.checked");
};
/**
Returns an array of unchecked nodes.
@returns {Array} nodes - Unchecked nodes
*/
Tree.prototype.getUnchecked = function() {
return this.findNodes("false", "g", "state.checked");
};
/**
Returns an array of disabled nodes.
@returns {Array} nodes - Disabled nodes
*/
Tree.prototype.getDisabled = function() {
return this.findNodes("true", "g", "state.disabled");
};
/**
Returns an array of enabled nodes.
@returns {Array} nodes - Enabled nodes
*/
Tree.prototype.getEnabled = function() {
return this.findNodes("false", "g", "state.disabled");
};
/**
Set a node state to selected
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.selectNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setSelectedState(node, true, options);
}, this)
);
this.render();
};
/**
Set a node state to unselected
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.unselectNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setSelectedState(node, false, options);
}, this)
);
this.render();
};
/**
Toggles a node selected state; selecting if unselected, unselecting if selected.
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.toggleNodeSelected = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.toggleSelectedState(node, options);
}, this)
);
this.render();
};
/**
Collapse all tree nodes
@param {optional Object} options
*/
Tree.prototype.collapseAll = function(options) {
var identifiers = this.findNodes("true", "g", "state.expanded");
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setExpandedState(node, false, options);
}, this)
);
this.render();
};
/**
Collapse a given tree node
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.collapseNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setExpandedState(node, false, options);
}, this)
);
this.render();
};
/**
Expand all tree nodes
@param {optional Object} options
*/
Tree.prototype.expandAll = function(options) {
options = $.extend({}, _default.options, options);
if (options && options.levels) {
this.expandLevels(this.tree, options.levels, options);
} else {
var identifiers = this.findNodes("false", "g", "state.expanded");
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setExpandedState(node, true, options);
}, this)
);
}
this.render();
};
/**
Expand a given tree node
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.expandNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
//console.log("expandNode node", node);
this.setExpandedState(node, true, options);
if (node.nodes && (options && options.levels)) {
this.expandLevels(node.nodes, options.levels - 1, options);
}
}, this)
);
this.render();
};
Tree.prototype.expandLevels = function(nodes, level, options) {
options = $.extend({}, _default.options, options);
$.each(
nodes,
$.proxy(function(index, node) {
this.setExpandedState(node, level > 0 ? true : false, options);
if (node.nodes) {
this.expandLevels(node.nodes, level - 1, options);
}
}, this)
);
};
/**
Reveals a given tree node, expanding the tree from node to root.
@param {Object|Number|Array} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.revealNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
var parentNode = this.getParent(node);
while (parentNode) {
this.setExpandedState(parentNode, true, options);
parentNode = this.getParent(parentNode);
}
}, this)
);
this.render();
};
/**
Toggles a nodes expanded state; collapsing if expanded, expanding if collapsed.
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.toggleNodeExpanded = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.toggleExpandedState(node, options);
}, this)
);
this.render();
};
/**
Check all tree nodes
@param {optional Object} options
*/
Tree.prototype.checkAll = function(options) {
var identifiers = this.findNodes("false", "g", "state.checked");
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setCheckedState(node, true, options);
}, this)
);
this.render();
};
/**
Check a given tree node
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.checkNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setCheckedState(node, true, options);
}, this)
);
this.render();
};
/**
Uncheck all tree nodes
@param {optional Object} options
*/
Tree.prototype.uncheckAll = function(options) {
var identifiers = this.findNodes("true", "g", "state.checked");
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setCheckedState(node, false, options);
}, this)
);
this.render();
};
/**
Uncheck a given tree node
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.uncheckNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setCheckedState(node, false, options);
}, this)
);
this.render();
};
/**
Toggles a nodes checked state; checking if unchecked, unchecking if checked.
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.toggleNodeChecked = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.toggleCheckedState(node, options);
}, this)
);
this.render();
};
/**
Disable all tree nodes
@param {optional Object} options
*/
Tree.prototype.disableAll = function(options) {
var identifiers = this.findNodes("false", "g", "state.disabled");
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setDisabledState(node, true, options);
}, this)
);
this.render();
};
/**
Disable a given tree node
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.disableNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setDisabledState(node, true, options);
}, this)
);
this.render();
};
/**
Enable all tree nodes
@param {optional Object} options
*/
Tree.prototype.enableAll = function(options) {
var identifiers = this.findNodes("true", "g", "state.disabled");
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setDisabledState(node, false, options);
}, this)
);
this.render();
};
/**
Enable a given tree node
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.enableNode = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setDisabledState(node, false, options);
}, this)
);
this.render();
};
/**
Toggles a nodes disabled state; disabling is enabled, enabling if disabled.
@param {Object|Number} identifiers - A valid node, node id or array of node identifiers
@param {optional Object} options
*/
Tree.prototype.toggleNodeDisabled = function(identifiers, options) {
this.forEachIdentifier(
identifiers,
options,
$.proxy(function(node, options) {
this.setDisabledState(node, !node.state.disabled, options);
}, this)
);
this.render();
};
/**
Common code for processing multiple identifiers
*/
Tree.prototype.forEachIdentifier = function(identifiers, options, callback) {
options = $.extend({}, _default.options, options);
if (!(identifiers instanceof Array)) {
identifiers = [identifiers];
}
$.each(
identifiers,
$.proxy(function(index, identifier) {
callback(this.identifyNode(identifier), options);
}, this)
);
};
/*
Identifies a node from either a node id or object
*/
Tree.prototype.identifyNode = function(identifier) {
return typeof identifier === "number" ? this.nodes[identifier] : identifier;
};
/**
Searches the tree for nodes (text) that match given criteria
@param {String} pattern - A given string to match against
@param {optional Object} options - Search criteria options
@return {Array} nodes - Matching nodes
*/
Tree.prototype.search = function(pattern, options) {
options = $.extend({}, _default.searchOptions, options);
this.clearSearch({ render: false });
var results = [];
if (pattern && pattern.length > 0) {
if (options.exactMatch) {
pattern = "^" + pattern + "$";
}
var modifier = "g";
if (options.ignoreCase) {
modifier += "i";
}
results = this.findNodes(pattern, modifier);
// Add searchResult property to all matching nodes
// This will be used to apply custom styles
// and when identifying result to be cleared
$.each(results, function(index, node) {
node.searchResult = true;
});
}
// If revealResults, then render is triggered from revealNode
// otherwise we just call render.
if (options.revealResults) {
this.revealNode(results);
} else {
this.render();
}
this.$element.trigger("searchComplete", $.extend(true, {}, results));
return results;
};
/**
Clears previous search results
*/
Tree.prototype.clearSearch = function(options) {
options = $.extend({}, { render: true }, options);
var results = $.each(this.findNodes("true", "g", "searchResult"), function(
index,
node
) {
node.searchResult = false;
});
if (options.render) {
this.render();
}
this.$element.trigger("searchCleared", $.extend(true, {}, results));
};
/**
Searches the tree for nodes (text) that match given criteria
@param {String} pattern - A given string to match against
@param {optional Object} options - Search criteria options
@return {Array} nodes - Matching nodes
*/
Tree.prototype.searchV2 = function(id, options) {
//console.log(" search: $.proxy(this.search, this),", id);
options = $.extend({}, _default.searchOptions, options);
this.clearSearch({ render: false });
var results = [];
results = this.findNodesV2(id);
// Add searchResult property to all matching nodes
// This will be used to apply custom styles
// and when identifying result to be cleared
$.each(results, function(index, node) {
node.searchResult = true;
});
// If revealResults, then render is triggered from revealNode
// otherwise we just call render.
if (options.revealResults) {
this.revealNode(results);
} else {
this.render();
}
this.$element.trigger("searchCompleteV2", $.extend(true, {}, results));
return results;
};
// /**
// Clears previous search results
// */
// Tree.prototype.clearSearchV2 = function(options) {
// options = $.extend({}, { render: true }, options);
// var results = $.each(this.findNodes("true", "g", "searchResult"), function(
// index,
// node
// ) {
// node.searchResult = false;
// });
// if (options.render) {
// this.render();
// }
// this.$element.trigger("searchCleared", $.extend(true, {}, results));
// };
/**
Find nodes that match a given criteria
@param {String} pattern - A given string to match against
@param {optional String} modifier - Valid RegEx modifiers
@param {optional String} attribute - Attribute to compare pattern against
@return {Array} nodes - Nodes that match your criteria
*/
Tree.prototype.findNodes = function(pattern, modifier, attribute) {
modifier = modifier || "g";
attribute = attribute || "text";
var _this = this;
return $.grep(this.nodes, function(node) {
var val = _this.getNodeValue(node, attribute);
if (typeof val === "string") {
return val.match(new RegExp(pattern, modifier));
}
});
};
/**
Find nodes that match a given criteria
@param {String} pattern - A given string to match against
@param {optional String} modifier - Valid RegEx modifiers
@param {optional String} attribute - Attribute to compare pattern against
@return {Array} nodes - Nodes that match your criteria
*/
Tree.prototype.findNodesV2 = function(id) {
// modifier = modifier || "g";
// attribute = attribute || "text";
var _this = this;
return $.grep(this.nodes, function(node) {
var val = _this.getNodeValueV2(node, id);
if (val != undefined) {
return val;
//return val.match(new RegExp(pattern, modifier));
}
});
};
/**
Recursive find for retrieving nested attributes values
All values are return as strings, unless invalid
@param {Object} obj - Typically a node, could be any object
@param {String} attr - Identifies an object property using dot notation
@return {String} value - Matching attributes string representation
*/
Tree.prototype.getNodeValue = function(obj, attr) {
var index = attr.indexOf(".");
if (index > 0) {
var _obj = obj[attr.substring(0, index)];
var _attr = attr.substring(index + 1, attr.length);
return this.getNodeValue(_obj, _attr);
} else {
if (obj.hasOwnProperty(attr)) {
return obj[attr].toString();
} else {
return undefined;
}
}
};
var logError = function(message) {
if (window.console) {
window.console.error(message);
}
};
// Prevent against multiple instantiations,
// handle updates and method calls
$.fn[pluginName] = function(options, args) {
var result;
this.each(function() {
var _this = $.data(this, pluginName);
if (typeof options === "string") {
if (!_this) {
logError("Not initialized, can not call method : " + options);
} else if (!$.isFunction(_this[options]) || options.charAt(0) === "_") {
logError("No such method : " + options);
} else {
if (!(args instanceof Array)) {
args = [args];
}
result = _this[options].apply(_this, args);
}
} else if (typeof options === "boolean") {
result = _this;
} else {
$.data(this, pluginName, new Tree(this, $.extend(true, {}, options)));
}
});
return result || this;
};
})(jQuery, window, document);
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1, maximum-scale=1, user-scalable=no" />
<!--表头设置禁止缓存-->
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="Cache-Control" content="no-cache, must-revalidate" />
<meta http-equiv="expires" content="0" />
<title>铁将军项目文档</title>
<link rel="shortcut icon" href="./icon/favicon.ico" />
<link rel="stylesheet" href="css/index.css?id=9090705" />
<link href="css/layer.css" rel="stylesheet" type="text/css" media="all" />
<link href="css/bootstrap.css" rel="stylesheet" type="text/css" />
<link href="css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="css/vditor.css" rel="stylesheet" type="text/css" />
<!-- <link href="js/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css" /> -->
<script type="text/javascript" src="js/jquery-1.8.3.js"></script>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript" src="js/bootstrap-treeview.js?id=9090705"></script>
<!-- <script type="text/javascript" src="js/bootstrap/js/bootstrap.min.js"></script> -->
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/layer.js"></script>
<script type="text/javascript" src="js/axios.js"></script>
<script type="text/javascript" src="js/vditor.js"></script>
</head>
<body>
<div id="app">
<div class="treeNav">
<div class="searchBox">
<div class="input-group">
<input type="text" class="searchInput form-control" placeholder="请输入关键词查找" aria-describedby="basic-addon2" />
<span class="input-group-btn">
<button class="btn btn-primary" type="button" @click="searchDocument">
查询
</button>
</span>
</div>
</div>
<div class="left_nav">
<!-- 默认显示目录 -->
<div id="treeview"></div>
</div>
</div>
<div class="main">
<div class="head_title">
<!-- 默认显示 -->
<p class="project-doc-name"></p>
<div class="head_desc">
发布时间:<span class="project-doc-publish-time"></span> 版本:<span class="project-doc-version"></span>
</div>
</div>
<div class="right_content">
<div class="edit_desc">
最后编辑时间:<span class="doc-end-edit-time"></span> 版本:<span class="project-doc-internal-version"></span>
</div>
<div class="detailsBox">
<!-- 富文本内容示例start -->
<!-- <div id="editor-md"> -->
<div id="vditor"></div>
<!-- <div style="margin-top:5px;margin-left:455px;">
<button class="el-button el-button--primary el-button--mini" type="button" @click="updateContent">
临时保存
</button>
<button class="el-button el-button--danger el-button--mini" type="button" @click="releaseData">
发布正式版本
</button>
</div> -->
<!-- </div> -->
<!-- 富文本内容示例end -->
</div>
</div>
</div>
<!-- 新增文件填写弹层 -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
×
</button>
<!-- <h4 v-if="isAdd" class="modal-title" id="myModalLabel">上级:{{model.text}}</h4> -->
<h4 v-if="isAdd" class="modal-title">添加</h4>
<h4 v-else class="modal-title">编辑</h4>
</div>
<div class="modal-body">
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle xlBtn" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
选择上级
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<button type="button" class="btn btn-default selectBtn disabled">{{model.parentid_name}}</button>
<ul class="dropdown-menu">
<li :class="{ docu_active: index==checkIndex }" @click="select_up(item,index)"
v-for="(item,index) in docDetailsOptions" :key="index"><a
href="#">{{item.name}}-({{item.orderid}})</a>
</li>
</ul>
</div>
<div class="input-group" style="margin-top:10px;">
<span class="input-group-addon" id="basic-addon1">名称</span>
<input type="text" class="form-control" placeholder="请输入文件名称" v-model="model.name">
</div>
<div v-if="!isAdd" style="margin-top:10px;" class="input-group">
<span class="input-group-addon" id="basic-addon1">排序</span>
<input type="text" class="form-control" placeholder="请输入排序ID" v-model="model.spdd_orderid">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button v-if="isAdd" type="button" class="btn btn-primary" id="submit" @click="addDocInfo()">添加</button>
<button v-else type="button" class="btn btn-primary" id="submit" @click="editDocInfo()">编辑</button>
</div>
</div>
</div>
</div>
<!-- 删除弹层 -->
<div class="modal fade" id="removeModal" tabindex="-1" role="dialog" aria-labelledby="removeModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-body">确定删除该文档吗?</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" id="removeBtn" @click="delDocInfo()">确定</button>
</div>
</div>
</div>
</div>
<!-- 悬浮按钮 保存和发布 -->
<div class="func_btn">
<div class="saveBtn" @click="updateContent">保存</div>
<div class="releaseBtn" @click="releaseData">发布</div>
</div>
</div>
<script type="text/javascript">
function getRequestArgs(query) {
var url = query; //获取url中"?"符后的字串
var theRequest = new Object();
if (url.indexOf("?") != -1) {
var str = url.substr(1);
strs = str.split("&");
if (strs.length > 1) {
for (var i = 0; i < strs.length; i++) {
theRequest[strs[i].split("=")[0]] = decodeURI(
strs[i].split("=")[1]
);
}
} else {
theRequest[str.split("=")[0]] = decodeURI(str.split("=")[1]);
}
} else {
return null;
}
return theRequest;
}
new Vue({
el: "#app",
data: {
pathType: 10,
search_text: "测试文档",
defaultData: [], // 示例数据 [{text:'测试文夹',nodes:[{text:'测试文档'}]}]
contentEditor: null,
value: "",
height: window.innerHeight - 130,
model: {
after_html: "",
child_count: "",
id: 0,
name: "",
nodeId: 0,
nodes: [],
parentId: "",
selectable: true,
spdd_id: 0,
spdd_parent_id: 0,
spdd_spd_id: 0,
parentid_name: "",
},
tempNode: null,
tempParentNode: null,
docid: 0,
docDetailid: 0,
childData: {},
isDisable: false,
operateType: 0, //30=添加;40=编辑;50=删除
isAdd: true,
getDefaultContentNum: 0,
checkIndex: 0,
docDetailsOptions: {}, //文档细节下拉框
// downList: [{
// id: 0,
// name: '项目文档1'
// }, {
// id: 1,
// name: '项目文档2'
// }, {
// id: 2,
// name: '项目文档3'
// }, {
// id: 3,
// name: '项目文档4'
// }]
},
created() {
window.addDoc = this.addDoc
window.editDoc = this.editDoc
window.delDoc = this.delDoc
},
async mounted() {
this.initVditor()
const obj = getRequestArgs(location.search);
try {
this.docDetailid = parseInt(obj.spdd_id)
this.docid = parseInt(obj.spdd_spd_id)
this.initTree()
} catch (err) {
console.error(err);
return;
}
this.getDocDetailsOptions()
},
methods: {
//重新加载整棵树
initTree(detailid) {
try {
let params = new URLSearchParams();
params.append('spdd_spd_id', parseInt(this.docid));
axios.post("/api/manage/v1/projectdoc/systemprojectdocumentinfo?type=100", params)
.then(({
data
}) => {
this.isDisable = false;
if (data.status) {
this.defaultData = data.data.tree || this.defaultData;
// 设置项目文档名称
$(".project-doc-name").text(data.data.spd_name);
// 设置项目文档发布时间
$(".project-doc-publish-time").text(data.data.spd_creation_time);
$(".doc-end-edit-time").text(data.data.spd_creation_time);
// 设置项目文档版本
$(".project-doc-version").text(data.data.spd_show_version);
$(".project-doc-internal-version").text(data.data.spd_show_version);
if (!detailid){
detailid=this.docDetailid
}
this.getData()
this.getDefaultContentNum=0
setTimeout(() => {
this.getDefaultContent(detailid);
}, 300)
} else {
//错误提示
layer.msg(data.msg);
}
})
.catch((err) => {
this.isDisable = false;
console.error(err);
});
} catch (err) {
console.error(err);
return;
}
},
// 选择上级
select_up(item, index) {
this.checkIndex = index
this.model.spdd_parent_id = item.id
this.model.parentid_name = item.name
this.$forceUpdate()
},
setDefaultOptionIndex(id) {
this.docDetailsOptions.find((item, index) => {
if (item.id == id) {
this.select_up(item, index)
return
}
});
},
searchNodeByid(id) {
var tempid = this.docDetailid
if (id) {
tempid = id
}
$("#treeview").treeview("searchV2", [
tempid,
{
ignoreCase: true, // case insensitive
exactMatch: false, // like or equals
revealResults: true, // reveal matching nodes
},
]);
},
addDoc(id) {
this.isAdd = true
//阻止事件冒泡
window.event.cancelBubble = true;
var node = $("#treeview").treeview("getNodeV2", id);
this.model = JSON.parse(JSON.stringify(node))
this.model.name = ""
this.tempNode = JSON.parse(JSON.stringify(node))
var defaultParentid=this.model.spdd_id
if (this.model.spdd_orderid==0){
defaultParentid=0
}
this.setDefaultOptionIndex(defaultParentid)
this.$forceUpdate()
$('#filename').val('');
$("#myModal").modal();
},
editDoc(id) {
this.isAdd = false
//阻止事件冒泡
window.event.cancelBubble = true;
var node = $("#treeview").treeview("getNodeV2", id);
this.model = JSON.parse(JSON.stringify(node))
this.model.name = this.model.text
this.model.parentid_name = ""
this.model.old_spdd_parent_id = this.model.spdd_parent_id
$('#filename').val('');
$("#myModal").modal();
this.setDefaultOptionIndex(this.model.spdd_parent_id)
this.$forceUpdate()
},
delDoc(id) {
//阻止事件冒泡
window.event.cancelBubble = true;
var node = $("#treeview").treeview("getNodeV2", id);
this.tempNode = JSON.parse(JSON.stringify(node))
tempParentNodeData= $("#treeview").treeview("getNode", this.tempNode.parentId);
this.tempParentNode = JSON.parse(JSON.stringify(tempParentNodeData))
$("#removeModal").modal();
},
delDocInfo() {
let params = new URLSearchParams();
params.append('spdd_id', this.tempNode.spdd_id);
axios.post("/api/manage/v1/projectdoc/systemprojectdocumentdetail?type=50", params)
.then(({
data
}) => {
this.isDisable = false;
if (data.status) {
if (this.model.spdd_id == this.tempNode.spdd_id) {
this.model = {}
this.value = ""
this.contentEditor.setValue("")
}
//请求成功
$("#removeModal").modal('hide');
layer.msg(`删除成功`);
if (this.tempParentNode && this.tempParentNode.nodes && this.tempParentNode.nodes.length == 1) {
this.tempParentNode.nodes = null
$('#treeview').treeview('updateNode', [this.tempNode.parentId, this.tempParentNode, {
silent: true
}]);
} else{
$("#treeview").treeview("deleteNode", [this.tempNode.nodeId, {
silent: true
}]);
}
this.getDocDetailsOptions()
} else {
//错误提示
layer.msg(data.msg);
}
})
.catch((err) => {
this.isDisable = false;
console.error(err);
});
},
addDocInfo() {
if (this.model.name.trim() == "") {
layer.msg("请填写文件名称");
return false
}
this.isDisable = true;
let params = new URLSearchParams();
params.append('spdd_id', 0);
params.append('spdd_parent_id', this.model.spdd_parent_id);
params.append('spdd_spd_id', this.model.spdd_spd_id);
params.append('spdd_name', this.model.name);
params.append('spdd_state', 10);
params.append('spdd_orderid', 1);
axios.post("/api/manage/v1/projectdoc/systemprojectdocumentdetail?type=30", params)
.then(({
data
}) => {
this.isDisable = false;
if (data.status) {
//请求成功
$("#myModal").modal('hide');
layer.msg(`添加成功`);
//如果上级是点击添加的节点,那么数据追加在节点下面,
if (this.model.spdd_parent_id== this.tempNode.spdd_id){
$("#treeview").treeview("addNode", [this.model.nodeId, {
node: data.data
}]);
// $("#treeview").treeview("addNode", [this.tempNode, {
// node: data.data
// }]);
}else{//重新加载整棵树
this.initTree( data.data.spdd_id)
}
this.getDocDetailsOptions()
} else {
//错误提示
layer.msg(data.msg);
}
})
.catch((err) => {
this.isDisable = false;
//console.error(err);
});
},
editDocInfo() {
if (this.model.name.trim() == "") {
layer.msg("请填写文件名称");
return false
}
if (parseInt(this.model.spdd_orderid) < 0) {
layer.msg("请填写大于0的排序id");
return false
}
if (this.model.spdd_orderid.length > 9 || this.model.spdd_orderid.length == 0) {
layer.msg("请填写9位数字的排序id");
return false
}
//this.model.text = this.model.name
newNode = this.model
//console.log("newNode",newNode)
this.isDisable = true;
let params = new URLSearchParams();
params.append('spdd_id', this.model.spdd_id);
params.append('spdd_orderid', this.model.spdd_orderid);
params.append('spdd_parent_id', this.model.spdd_parent_id);
params.append('spdd_spd_id', this.model.spdd_spd_id);
params.append('spdd_state', this.model.spdd_state);
params.append('old_spdd_name', this.model.text);
params.append('spdd_name', this.model.name);
axios.post("/api/manage/v1/projectdoc/systemprojectdocumentdetail?type=40", params)
.then(({
data
}) => {
this.isDisable = false;
if (data.status) {
//请求成功
$("#myModal").modal('hide');
layer.msg(`保存成功`);
this.model.text = this.model.name
if (this.model.old_spdd_parent_id == this.model.spdd_parent_id) {
$('#treeview').treeview('updateNode', [this.model.nodeId, newNode, {
silent: true
}]);
} else {//修改了父级,重新加载整棵树
this.initTree(this.model.spdd_id)
}
this.getDocDetailsOptions()
} else {
//错误提示
layer.msg(data.msg);
}
})
.catch((err) => {
this.isDisable = false;
console.error(err);
});
},
getData() {
const that = this;
// treeview参考文档: https://www.jq22.com/jquery-info10461
$("#treeview").treeview({
levels: 1,
highlightSelected: true,
highlightSearchResults: true,
enableLinks: true, //必须在节点属性给出href属性
//searchResultBackColor: "#00ff00", // TODO: 这里需要改一个合适的颜色
data: this.defaultData,
showAfterHtml: true,
searchResultColor: "#409eff",
//onhoverColor:"#409eff",
onNodeSelected: function (event, node) {
if (JSON.stringify(node) === "{}") {
return;
}
// 1.有点击节点的操作, 先清空搜索高亮的状态
$("#treeview").treeview("clearSearch");
// 2.选择选中了文件夹, 则让文件夹展开(组件本身只能点击图标展开文件夹, 这里需要做一个兼容处理)
if (node.nodes) {
if (node.nodes.length > 0 && node.state.selected) {
// 10=文件夹 20=文件
if (!node.state.expanded) {
// 展开文件夹
$("#treeview").treeview("expandNode", [
node.nodeId,
{
levels: 1,
silent: true
},
]);
} else {
// 折叠文件夹
$("#treeview").treeview("collapseNode", [
node.nodeId,
{
silent: true,
ignoreChildren: false
},
]);
}
return;
}
}
// 3.选中了文件, 去请求文档详细内容, 渲染内容
let params = new URLSearchParams();
that.model = JSON.parse(JSON.stringify(node))
params.append('spdd_id', node.spdd_id);
params.append('spdd_parent_id', node.spdd_parent_id);
params.append('spdd_spd_id', node.spdd_spd_id);
//console.log("getDocContent",node)
that.getDocContent(params)
},
onSearchComplete: function (event, node) {
if (JSON.stringify(node) === "{}") {
// 未搜索到该文档
const searchInput = $(".searchInput").val().trim();
layer.msg(`未搜索到相关文档 "${searchInput}"`);
return;
}
},
onSearchCompleteV2: function (event, node) {
if (JSON.stringify(node) === "{}") {
//layer.msg(`文档不存在`);
return;
} else {
let params = new URLSearchParams();
that.model = JSON.parse(JSON.stringify(node[0]))
params.append('spdd_id', that.model.spdd_id);
params.append('spdd_parent_id', that.model.spdd_parent_id);
params.append('spdd_spd_id', that.model.spdd_spd_id);
that.getDocContent(params)
}
},
});
},
getDefaultContent(id) {
if (id > 0) {
this.getDefaultContentNum++;
} else {
this.getDefaultContentNum = 2
}
if (this.getDefaultContentNum > 2) {
return
}
let params = new URLSearchParams();
params.append('spdd_id', id);
params.append('spdd_spd_id', this.docid);
axios.post("/api/manage/v1/projectdoc/systemprojectdocumentinfo?type=111", params)
.then(({
data
}) => {
if (data.status) {
// 最后编辑时间
$(".doc-end-edit-time").text(data.data.spdd_update_time);
$(".project-doc-internal-version").text(data.data.spddc_internal_version);
this.model = data.data
this.value = this.model.spdd_content
this.contentEditor.setValue(this.model.spdd_content)
this.searchNodeByid(this.model.spdd_id)
} else {
if (this.getDefaultContentNum >= 2) {
//layer.msg(data.msg);
} else {
this.getDefaultContent(0)
}
}
})
.catch((err) => {
console.error(err);
});
},
getDocContent(params) {
axios.post("/api/manage/v1/projectdoc/systemprojectdocumentinfo?type=110", params)
.then(({
data
}) => {
if (data.status) {
// 最后编辑时间
$(".doc-end-edit-time").text(
data.data.spdd_update_time
);
$(".project-doc-internal-version").text(data.data.spddc_internal_version);
this.model = data.data
this.value = this.model.spdd_content
this.contentEditor.setValue(this.model.spdd_content)
} else {
layer.msg(data.msg);
}
})
.catch((err) => {
console.error(err);
});
},
edit(data) {
console.log("编辑", data)
},
getDocDetailsOptions() {
let params = new URLSearchParams();
params.append('spdd_spd_id', this.docid);
axios.post("/api/manage/v1/projectdoc/systemprojectdocumentdetail?type=12", params)
.then(({
data
}) => {
if (data.status) {
var arr = [{ "id": 0, "name": "顶级", "parent_id": 0, "spdd_spd_id": 0, "orderid": -1 }]
this.docDetailsOptions = arr.concat(data.data);
} else {
layer.msg(data.msg);
}
})
.catch((err) => {
console.error(err);
});
},
edit(data) {
console.log("编辑", data)
},
//======================临时保存=========================
updateContent() {
if (this.model.spdd_id == undefined) {
layer.msg("文档找不到了请重新选中文档");
return false
}
this.model.spdd_content = this.contentEditor.getValue()
if (this.model.spdd_content.trim() == "") {
layer.msg("请填写项目文档细节内容");
return false
}
this.isDisable = true;
let params = new URLSearchParams();
params.append('spdd_id', this.model.spdd_id);
params.append('spdd_content', this.model.spdd_content);
axios.post("/api/manage/v1/projectdoc/systemprojectdocumentdetail?type=45", params)
.then(({
data
}) => {
this.isDisable = false;
if (data.status) {
//请求成功
layer.msg(`保存成功`);
let params = new URLSearchParams();
params.append('spdd_id', this.model.spdd_id);
params.append('spdd_parent_id', this.model.spdd_parent_id);
params.append('spdd_spd_id', this.model.spdd_spd_id);
this.getDocContent(params)
} else {
//错误提示
layer.msg(data.msg);
}
})
.catch(err => {
this.isDisable = false;
layer.msg(err);
});
},
//======================发布=========================
releaseData() {
if (this.model.spdd_id == undefined) {
layer.msg("文档找不到了请重新选中文档");
return false
}
this.model.spdd_content = this.contentEditor.getValue()
if (this.model.spdd_content.trim() == "") {
layer.msg("请填写项目文档细节内容");
return false
}
this.isDisable = true;
let params = new URLSearchParams();
params.append('spdd_id', this.model.spdd_id);
params.append('spdd_spd_id', this.model.spdd_spd_id);
params.append('spdd_content', this.model.spdd_content);
axios.post("/api/manage/v1/projectdoc/systemprojectdocumentdetail?type=48", params)
.then(({
data
}) => {
this.isDisable = false;
if (data.status) {
//请求成功
layer.msg(`发布成功`);
let params = new URLSearchParams();
params.append('spdd_id', this.model.spdd_id);
params.append('spdd_parent_id', this.model.spdd_parent_id);
params.append('spdd_spd_id', this.model.spdd_spd_id);
this.getDocContent(params)
} else {
//错误提示
layer.msg(data.msg);
}
})
.catch(err => {
this.isDisable = false;
layer.msg(err);
});
},
// 搜索文档
searchDocument() {
var searchInput = $('.searchInput').val().trim();
if (searchInput.length < 1) {
layer.msg('请输入关键词');
return
}
$("#treeview").treeview("search", [
searchInput,
{
ignoreCase: true, // case insensitive
exactMatch: false, // like or equals
revealResults: true, // reveal matching nodes
},
]);
},
// vditor start
initVditor() {
const that = this
const options = {
height: this.height,
value: this.value,
cache: {
enable: false
},
outline :{
enable:true,
},
toolbar: [
// "emoji",
"headings",
"bold",
"italic",
"strike",
"link",
"|",
"list",
"ordered-list",
"check",
"outdent",
"indent",
"|",
"quote",
"line",
"code",
"inline-code",
"insert-before",
"insert-after",
"|",
{ //自定义上传
hotkey: "",
name: "upload",
tip: "上传图片",
className: "right",
},
"table",
"|",
"undo",
"redo",
"|",
"edit-mode",
{
name: "more",
toolbar: [
//"both",
"code-theme",
"content-theme",
"export",
"outline",
"preview",
],
},
],
after: () => {
this.contentEditor.setValue(this.value)
},
mode: "ir",
preview: {
mode: "both",
actions: []
},
//这里写上传
upload: {
accept: 'image/jpg, image/jpeg, image/png', //规定上传的图片格式
url: "/api/admin/uploadFile?type=99", //请求的接口
multiple: false,
fieldName: 'file',
max: 2 * 1024 * 1024, //上传图片的大小
// extraData: { 'access_token': this.token }, //为 FormData 添加额外的参数
linkToImgUrl: "/api/admin/uploadFile?type=99",
filename(name) {
return name.replace(/[^(a-zA-Z0-9\u4e00-\u9fa5\.)]/g, "")
.replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, "")
.replace("/\\s/g", "");
},
validate(files) {
const isLt2M = files[0].size / 1024 / 1024 < 2
if (!isLt2M) {
layer.msg("上传图片大小不能超过 2MB!");
}
},
//粘贴图片回显处理,如果有图片加了防盗链,则让后台代理替换成自己的图片
linkToImgFormat(files) {
let code = 0
let msg = ''
},
//上传图片回显处理
format(files, responseText) {
var self = this;
var data = JSON.parse(responseText)
//上传图片请求状态
if (data.status) {
let filName = data.msg
let lastTipNum = filName.substr(filName.lastIndexOf('/', filName.lastIndexOf(
'/') - 1) + 1);
let index = lastTipNum.lastIndexOf("\/");
let succ = {}
succ[filName] = "/api" + data.data
//图片回显
return JSON.stringify({
data,
data,
data: {
errFiles: [],
succMap: succ
}
})
} else {
layer.msg("图片上传失败!");
}
},
error(msg) {
console.log(msg + "上传失败了")
},
}
}
this.contentEditor = new Vditor('vditor', options)
}
// /vditor end/
},
});
</script>
<style scoped>
/deep/ #app {
height: 100%;
overflow-y: hidden;
}
/deep/.glyphicon-file:before {
content: "";
}
/deep/ a:hover,
a:focus {
color: #409eff !important;
}
.el-button--primary:focus,
.el-button--primary:hover {
background: #66b1ff;
border-color: #66b1ff;
color: #fff;
}
.el-button:focus,
.el-button:hover {
color: #409eff;
border-color: #c6e2ff;
background-color: #ecf5ff;
}
.el-button+.el-button {
margin-left: 10px;
}
[type=reset],
[type=submit],
button,
html [type=button] {
-webkit-appearance: button;
}
.el-button--mini,
.el-button--mini.is-round {
padding: 7px 15px;
}
.el-button--mini,
.el-button--small {
font-size: 12px;
border-radius: 3px;
}
.el-button--primary {
color: #fff;
background-color: #409eff;
border-color: #409eff;
}
.el-button--danger {
color: #FFF;
background-color: #F56C6C;
border-color: #F56C6C;
}
.button_z {
float: right;
}
.imgbtn {
width: 22px;
height: 22px;
}
.el-button {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
border: 1px solid #dcdfe6;
text-align: center;
box-sizing: border-box;
outline: 0;
margin: 0;
transition: .1s;
font-weight: 500;
}
.glyphicon-folder-open {
color: #efc013;
}
.glyphicon-file:before {
content: "";
display: inline-block;
background-image: url(img/file.png);
width: 18px;
height: 18px;
/* border: 1px solid red; */
background-size: cover;
}
.list-group-item {
border: none;
}
.el-button,
.el-checkbox,
.el-image-viewer__btn,
.el-step__icon-inner {
-webkit-user-select: none;
}
button,
select {
text-transform: none;
}
button,
input {
overflow: visible;
}
button,
input,
optgroup,
select,
textarea {
font-family: sans-serif;
}
button {
writing-mode: horizontal-tb !important;
font-style: ;
font-variant-ligatures: ;
font-variant-caps: ;
font-variant-numeric: ;
font-variant-east-asian: ;
font-stretch: ;
text-rendering: auto;
letter-spacing: normal;
word-spacing: normal;
text-indent: 0px;
text-shadow: none;
align-items: flex-start;
}
.treeview span.icon {
width: 18px;
height: 18px;
margin-right: -5px;
}
</style>
</body>
</html>