first changes
gitea/salix/1625-worker_department_treeview This commit looks good
Details
gitea/salix/1625-worker_department_treeview This commit looks good
Details
This commit is contained in:
parent
daeb4bed09
commit
183d770483
|
@ -0,0 +1,73 @@
|
|||
ALTER TABLE `vn2008`.`department`
|
||||
ADD COLUMN `parentFk` INT UNSIGNED NULL AFTER `sons`,
|
||||
ADD COLUMN `path` VARCHAR(255) NULL AFTER `parentFk`,
|
||||
CHANGE COLUMN `sons` `sons` DECIMAL(10,0) NOT NULL DEFAULT '0' ;
|
||||
|
||||
USE `vn`;
|
||||
CREATE
|
||||
OR REPLACE ALGORITHM = UNDEFINED
|
||||
DEFINER = `root`@`%`
|
||||
SQL SECURITY DEFINER
|
||||
VIEW `department` AS
|
||||
SELECT
|
||||
`b`.`department_id` AS `id`,
|
||||
`b`.`name` AS `name`,
|
||||
`b`.`production` AS `isProduction`,
|
||||
`b`.`parentFk` AS `parentFk`,
|
||||
`b`.`path` AS `path`,
|
||||
`b`.`lft` AS `lft`,
|
||||
`b`.`rgt` AS `rgt`,
|
||||
`b`.`isSelected` AS `isSelected`,
|
||||
`b`.`depth` AS `depth`,
|
||||
`b`.`sons` AS `sons`
|
||||
FROM
|
||||
`vn2008`.`department` `b`;
|
||||
|
||||
DROP TRIGGER IF EXISTS `vn2008`.`department_AFTER_DELETE`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn2008`$$
|
||||
CREATE DEFINER = CURRENT_USER TRIGGER `vn2008`.`department_AFTER_DELETE`
|
||||
AFTER DELETE ON `department` FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE vn.department_recalc SET isChanged = TRUE;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS `vn2008`.`department_BEFORE_INSERT`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn2008`$$
|
||||
CREATE DEFINER = CURRENT_USER TRIGGER `vn2008`.`department_BEFORE_INSERT`
|
||||
BEFORE INSERT ON `department` FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE vn.department_recalc SET isChanged = TRUE;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS `vn2008`.`department_AFTER_UPDATE`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn2008`$$
|
||||
CREATE DEFINER = CURRENT_USER TRIGGER `vn2008`.`department_AFTER_UPDATE`
|
||||
AFTER UPDATE ON `department` FOR EACH ROW
|
||||
BEGIN
|
||||
IF !(OLD.parentFk <=> NEW.parentFk) THEN
|
||||
UPDATE vn.department_recalc SET isChanged = TRUE;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CREATE TABLE `vn`.`department_recalc` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`isChanged` TINYINT(4) NOT NULL,
|
||||
PRIMARY KEY (`id`));
|
||||
|
||||
INSERT INTO `vn`.`department_recalc` (`id`, `isChanged`) VALUES ('1', '0');
|
||||
|
||||
|
||||
ALTER TABLE `vn2008`.`department`
|
||||
CHANGE COLUMN `lft` `lft` INT(11) NULL ,
|
||||
CHANGE COLUMN `rgt` `rgt` INT(11) NULL ;
|
||||
|
||||
UPDATE vn.department SET lft = NULL, rgt = NULL;
|
|
@ -0,0 +1,37 @@
|
|||
USE `vn`;
|
||||
DROP procedure IF EXISTS `department_calcTree`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` PROCEDURE `department_calcTree`()
|
||||
BEGIN
|
||||
/**
|
||||
* Calculates the #path, #lft, #rgt, #sons and #depth columns of
|
||||
* the #department table. To build the tree, it uses the #parentFk
|
||||
* column.
|
||||
*/
|
||||
DECLARE vIndex INT DEFAULT 0;
|
||||
DECLARE vSons INT;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tNestedTree;
|
||||
CREATE TEMPORARY TABLE tNestedTree
|
||||
SELECT id, path, lft, rgt, depth, sons
|
||||
FROM department LIMIT 0;
|
||||
|
||||
SET max_sp_recursion_depth = 5;
|
||||
CALL department_calcTreeRec(NULL, '/', 0, vIndex, vSons);
|
||||
SET max_sp_recursion_depth = 0;
|
||||
|
||||
UPDATE department z
|
||||
JOIN tNestedTree t ON t.id = z.id
|
||||
SET z.path = t.path,
|
||||
z.lft = t.lft,
|
||||
z.rgt = t.rgt,
|
||||
z.depth = t.depth,
|
||||
z.sons = t.sons;
|
||||
|
||||
DROP TEMPORARY TABLE tNestedTree;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
USE `vn`;
|
||||
DROP procedure IF EXISTS `department_calcTreeRec`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` PROCEDURE `department_calcTreeRec`(
|
||||
vSelf INT,
|
||||
vPath VARCHAR(255),
|
||||
vDepth INT,
|
||||
INOUT vIndex INT,
|
||||
OUT vSons INT
|
||||
)
|
||||
BEGIN
|
||||
/**
|
||||
* Calculates and sets the #path, #lft, #rgt, #sons and #depth
|
||||
* columns for all children of the passed node. Once calculated
|
||||
* the last node rgt index and the number of sons are returned.
|
||||
* To update it's children, this procedure calls itself recursively
|
||||
* for each one.
|
||||
*
|
||||
* @vSelf The node identifier
|
||||
* @vPath The initial path
|
||||
* @vDepth The initial depth
|
||||
* @vIndex The initial lft index
|
||||
* @vSons The number of direct sons
|
||||
*/
|
||||
DECLARE vChildFk INT;
|
||||
DECLARE vLft INT;
|
||||
DECLARE vMySons INT;
|
||||
DECLARE vDone BOOL;
|
||||
DECLARE vChildren CURSOR FOR
|
||||
SELECT id FROM department
|
||||
WHERE (vSelf IS NULL AND parentFk IS NULL)
|
||||
OR (vSelf IS NOT NULL AND parentFk = vSelf);
|
||||
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||
|
||||
SET vSons = 0;
|
||||
|
||||
OPEN vChildren;
|
||||
myLoop: LOOP
|
||||
SET vDone = FALSE;
|
||||
FETCH vChildren INTO vChildFk;
|
||||
|
||||
IF vDone THEN
|
||||
LEAVE myLoop;
|
||||
END IF;
|
||||
|
||||
SET vIndex = vIndex + 1;
|
||||
SET vLft = vIndex;
|
||||
SET vSons = vSons + 1;
|
||||
|
||||
CALL department_calcTreeRec(
|
||||
vChildFk,
|
||||
CONCAT(vPath, vChildFk, '/'),
|
||||
vDepth + 1,
|
||||
vIndex,
|
||||
vMySons
|
||||
);
|
||||
|
||||
SET vIndex = vIndex + 1;
|
||||
|
||||
INSERT INTO tNestedTree
|
||||
SET id = vChildFk,
|
||||
path = vPath,
|
||||
lft = vLft,
|
||||
rgt = vIndex,
|
||||
depth = vDepth,
|
||||
sons = vMySons;
|
||||
END LOOP;
|
||||
CLOSE vChildren;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
USE `vn`;
|
||||
DROP procedure IF EXISTS `department_doCalc`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` PROCEDURE `department_doCalc`()
|
||||
proc: BEGIN
|
||||
/**
|
||||
* Recalculates the department tree.
|
||||
*/
|
||||
DECLARE vIsChanged BOOL;
|
||||
|
||||
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
|
||||
BEGIN
|
||||
DO RELEASE_LOCK('vn.department_doCalc');
|
||||
RESIGNAL;
|
||||
END;
|
||||
|
||||
IF !GET_LOCK('vn.department_doCalc', 0) THEN
|
||||
LEAVE proc;
|
||||
END IF;
|
||||
|
||||
SELECT isChanged INTO vIsChanged
|
||||
FROM department_recalc;
|
||||
|
||||
IF vIsChanged THEN
|
||||
UPDATE department_recalc SET isChanged = FALSE;
|
||||
CALL vn.department_calcTree;
|
||||
END IF;
|
||||
|
||||
DO RELEASE_LOCK('vn.department_doCalc');
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
USE `vn`;
|
||||
DROP procedure IF EXISTS `department_getLeaves`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` PROCEDURE `department_getLeaves`(
|
||||
vParentFk INT,
|
||||
vSearch VARCHAR(255)
|
||||
)
|
||||
BEGIN
|
||||
DECLARE vIsNumber BOOL;
|
||||
DECLARE vIsSearch BOOL DEFAULT vSearch IS NOT NULL AND vSearch != '';
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tNodes;
|
||||
CREATE TEMPORARY TABLE tNodes
|
||||
(UNIQUE (id))
|
||||
ENGINE = MEMORY
|
||||
SELECT id FROM department LIMIT 0;
|
||||
|
||||
IF vIsSearch THEN
|
||||
SET vIsNumber = vSearch REGEXP '^[0-9]+$';
|
||||
|
||||
INSERT INTO tNodes
|
||||
SELECT id FROM department
|
||||
WHERE (vIsNumber AND `name` = vSearch)
|
||||
OR (!vIsNumber AND `name` LIKE CONCAT('%', vSearch, '%'))
|
||||
LIMIT 1000;
|
||||
END IF;
|
||||
|
||||
IF vParentFk IS NULL THEN
|
||||
DROP TEMPORARY TABLE IF EXISTS tChilds;
|
||||
CREATE TEMPORARY TABLE tChilds
|
||||
ENGINE = MEMORY
|
||||
SELECT id FROM tNodes;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tParents;
|
||||
CREATE TEMPORARY TABLE tParents
|
||||
ENGINE = MEMORY
|
||||
SELECT id FROM department LIMIT 0;
|
||||
|
||||
myLoop: LOOP
|
||||
DELETE FROM tParents;
|
||||
INSERT INTO tParents
|
||||
SELECT parentFk id
|
||||
FROM department g
|
||||
JOIN tChilds c ON c.id = g.id
|
||||
WHERE g.parentFk IS NOT NULL;
|
||||
|
||||
INSERT IGNORE INTO tNodes
|
||||
SELECT id FROM tParents;
|
||||
|
||||
IF ROW_COUNT() = 0 THEN
|
||||
LEAVE myLoop;
|
||||
END IF;
|
||||
|
||||
DELETE FROM tChilds;
|
||||
INSERT INTO tChilds
|
||||
SELECT id FROM tParents;
|
||||
END LOOP;
|
||||
|
||||
DROP TEMPORARY TABLE
|
||||
tChilds,
|
||||
tParents;
|
||||
END IF;
|
||||
|
||||
IF !vIsSearch THEN
|
||||
INSERT IGNORE INTO tNodes
|
||||
SELECT id FROM department
|
||||
WHERE parentFk <=> vParentFk;
|
||||
END IF;
|
||||
|
||||
SELECT d.id,
|
||||
d.`name`,
|
||||
d.parentFk,
|
||||
d.sons
|
||||
FROM department d
|
||||
JOIN tNodes n ON n.id = d.id
|
||||
ORDER BY depth, `name`;
|
||||
|
||||
DROP TEMPORARY TABLE tNodes;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
|
|
@ -14,7 +14,8 @@
|
|||
icon="keyboard_arrow_down"
|
||||
translate-attr="{title: 'Toggle'}">
|
||||
</vn-icon>
|
||||
<vn-check
|
||||
<section class="tplItem"></section>
|
||||
<!-- <vn-check
|
||||
vn-acl="{{$ctrl.aclRole}}"
|
||||
ng-if="$ctrl.selectable"
|
||||
field="item.selected"
|
||||
|
@ -29,9 +30,9 @@
|
|||
ng-click="$ctrl.onIconClick(icon, item, $ctrl.parent, $parent.$index)"
|
||||
vn-acl="{{$ctrl.aclRole}}"
|
||||
vn-acl-action="remove">
|
||||
</vn-icon-button>
|
||||
</vn-icon-button> -->
|
||||
</div>
|
||||
<vn-treeview-child
|
||||
<!-- <vn-treeview-child
|
||||
items="item.childs"
|
||||
parent="item"
|
||||
selectable="$ctrl.selectable"
|
||||
|
@ -42,9 +43,9 @@
|
|||
icons="::$ctrl.icons"
|
||||
parent-scope="::$ctrl.parentScope"
|
||||
acl-role="$ctrl.aclRole">
|
||||
</vn-treeview-child>
|
||||
</vn-treeview-child> -->
|
||||
</li>
|
||||
<li
|
||||
<!-- <li
|
||||
ng-if="$ctrl.isInsertable && $ctrl.editable"
|
||||
ng-click="$ctrl.onCreate($ctrl.parent)"
|
||||
vn-acl="{{$ctrl.aclRole}}"
|
||||
|
@ -57,5 +58,5 @@
|
|||
Create new one
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</li> -->
|
||||
</ul>
|
|
@ -2,9 +2,14 @@ import ngModule from '../../module';
|
|||
import Component from '../../lib/component';
|
||||
|
||||
class Controller extends Component {
|
||||
constructor($element, $scope) {
|
||||
constructor($element, $scope, $transclude) {
|
||||
super($element, $scope);
|
||||
this.$scope = $scope;
|
||||
this.$transclude = $transclude;
|
||||
|
||||
$transclude($scope.$parent, tClone => {
|
||||
this.element.querySelector('.tplItem').appendChild(tClone[0]);
|
||||
}, null, 'tplItem');
|
||||
}
|
||||
|
||||
toggle(event, item) {
|
||||
|
@ -35,6 +40,8 @@ class Controller extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope', '$transclude'];
|
||||
|
||||
ngModule.component('vnTreeviewChild', {
|
||||
template: require('./child.html'),
|
||||
controller: Controller,
|
||||
|
@ -50,6 +57,9 @@ ngModule.component('vnTreeviewChild', {
|
|||
aclRole: '<?',
|
||||
parentScope: '<'
|
||||
},
|
||||
transclude: {
|
||||
tplItem: '?tplItem'
|
||||
},
|
||||
require: {
|
||||
treeview: '^vnTreeview'
|
||||
}
|
||||
|
|
|
@ -8,10 +8,18 @@ import './style.scss';
|
|||
* @property {String} position The relative position to the parent
|
||||
*/
|
||||
export default class Treeview extends Component {
|
||||
constructor($element, $scope) {
|
||||
constructor($element, $scope, $transclude) {
|
||||
super($element, $scope);
|
||||
this.$scope = $scope;
|
||||
this.$transclude = $transclude;
|
||||
this.data = [];
|
||||
|
||||
$transclude($scope.$parent, tClone => {
|
||||
this.element.querySelector('vn-treeview-child').appendChild(tClone[0]);
|
||||
// Object.assign(scope, option);
|
||||
// li.appendChild(clone[0]);
|
||||
// this.scopes[i] = scope;
|
||||
}, null, 'tplItem');
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
|
@ -76,7 +84,7 @@ export default class Treeview extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
Treeview.$inject = ['$element', '$scope'];
|
||||
Treeview.$inject = ['$element', '$scope', '$transclude'];
|
||||
|
||||
ngModule.component('vnTreeview', {
|
||||
template: require('./index.html'),
|
||||
|
@ -90,5 +98,8 @@ ngModule.component('vnTreeview', {
|
|||
draggable: '<?',
|
||||
droppable: '<?',
|
||||
aclRole: '@?'
|
||||
},
|
||||
transclude: {
|
||||
tplItem: '?tplItem'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,20 +1,14 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('getLeaves', {
|
||||
description: 'Returns the first shipped and landed possible for params',
|
||||
description: 'Returns the nodes for a department',
|
||||
accepts: [{
|
||||
arg: 'parentFk',
|
||||
type: 'Number',
|
||||
default: 1,
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'Object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
description: 'Get the children of the specified father',
|
||||
}, {
|
||||
arg: 'search',
|
||||
type: 'String',
|
||||
description: 'Filter nodes whose name starts with',
|
||||
}],
|
||||
returns: {
|
||||
type: ['object'],
|
||||
|
@ -26,61 +20,30 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.getLeaves = async(parentFk = 1, filter) => {
|
||||
let conn = Self.dataSource.connector;
|
||||
let stmt = new ParameterizedSQL(
|
||||
`SELECT
|
||||
child.id,
|
||||
child.name,
|
||||
child.lft,
|
||||
child.rgt,
|
||||
child.depth,
|
||||
child.sons
|
||||
FROM department parent
|
||||
JOIN department child ON child.lft > parent.lft
|
||||
AND child.rgt < parent.rgt
|
||||
AND child.depth = parent.depth + 1
|
||||
WHERE parent.id = ?`, [parentFk]);
|
||||
Self.getLeaves = async(parentFk = null, search) => {
|
||||
let [res] = await Self.rawSql(
|
||||
`CALL department_getLeaves(?, ?)`,
|
||||
[parentFk, search]
|
||||
);
|
||||
|
||||
// Get nodes from depth greather than Origin
|
||||
stmt.merge(conn.makeSuffix(filter));
|
||||
|
||||
const nodes = await Self.rawStmt(stmt);
|
||||
|
||||
if (nodes.length == 0)
|
||||
return nodes;
|
||||
|
||||
// Get parent nodes
|
||||
const minorDepth = nodes.reduce((a, b) => {
|
||||
return b < a ? b : a;
|
||||
}).depth;
|
||||
|
||||
const parentNodes = nodes.filter(element => {
|
||||
return element.depth === minorDepth;
|
||||
});
|
||||
const leaves = Object.assign([], parentNodes);
|
||||
|
||||
nestLeaves(leaves);
|
||||
|
||||
function nestLeaves(elements) {
|
||||
elements.forEach(element => {
|
||||
let childs = Object.assign([], getLeaves(element));
|
||||
if (childs.length > 0) {
|
||||
element.childs = childs;
|
||||
nestLeaves(element.childs);
|
||||
}
|
||||
});
|
||||
let map = new Map();
|
||||
for (let node of res) {
|
||||
if (!map.has(node.parentFk))
|
||||
map.set(node.parentFk, []);
|
||||
map.get(node.parentFk).push(node);
|
||||
}
|
||||
|
||||
function getLeaves(parent) {
|
||||
let elements = nodes.filter(element => {
|
||||
return element.lft > parent.lft && element.rgt < parent.rgt
|
||||
&& element.depth === parent.depth + 1;
|
||||
});
|
||||
|
||||
return elements;
|
||||
function setLeaves(nodes) {
|
||||
if (!nodes) return;
|
||||
for (let node of nodes) {
|
||||
node.childs = map.get(node.id);
|
||||
setLeaves(node.childs);
|
||||
}
|
||||
}
|
||||
|
||||
return leaves;
|
||||
let leaves = map.get(parentFk);
|
||||
setLeaves(leaves);
|
||||
|
||||
return leaves || [];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/worker/api/departments/getLeaves"
|
||||
params="::$ctrl.params"
|
||||
auto-load="false">
|
||||
</vn-crud-model>
|
||||
|
||||
<form name="form">
|
||||
<div margin-medium>
|
||||
<div class="content-block" compact>
|
||||
<form name="form" compact>
|
||||
<vn-card margin-medium-v pad-medium>
|
||||
<vn-treeview vn-id="treeview" model="model"
|
||||
on-selection="$ctrl.onSelection(item, value)"
|
||||
on-create="$ctrl.onCreate(parent)"
|
||||
on-drop="$ctrl.onDrop(item, dragged, dropped)"
|
||||
icons="$ctrl.icons"
|
||||
draggable="true" droppable="true"
|
||||
acl-role="hr" editable="true">
|
||||
icons="$ctrl.icons">
|
||||
<tpl-item>
|
||||
test
|
||||
</tpl-item>
|
||||
</vn-treeview>
|
||||
</vn-card>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<vn-button-bar>
|
||||
<vn-button ui-sref="worker.index" label="Back"></vn-button>
|
||||
</vn-button-bar>
|
||||
</form>
|
||||
</div>
|
||||
<vn-confirm
|
||||
vn-id="deleteNode"
|
||||
on-response="$ctrl.onRemoveResponse(response)"
|
||||
|
|
|
@ -6,7 +6,6 @@ class Controller {
|
|||
this.$http = $http;
|
||||
this.vnApp = vnApp;
|
||||
this.$translate = $translate;
|
||||
this.params = {parentFk: 1};
|
||||
this.icons = [{icon: 'delete', tooltip: 'Delete', callback: this.onDelete}];
|
||||
this.newNode = {
|
||||
name: ''
|
||||
|
|
Loading…
Reference in New Issue