明树Git Lab

Commit a38757d2 authored by zhangqi's avatar zhangqi

Merge branch 'dev' of gitlab.bridata.com:zengfanpei/jt_backend into dev

parents 300455a8 6ce89f36
function flattenTree(forest) { function flattenTree(forest, idDes = 'id', parentIdDes = 'parentId') {
const result = []; const result = [];
/** /**
* 递归处理节点 * 递归处理节点
* @param {Object} node - 当前节点 * @param {Object} node - 当前节点
...@@ -9,49 +9,82 @@ function flattenTree(forest) { ...@@ -9,49 +9,82 @@ function flattenTree(forest) {
function traverse(node, parentId) { function traverse(node, parentId) {
// 创建节点副本避免修改原数据 // 创建节点副本避免修改原数据
const nodeCopy = { ...node }; const nodeCopy = { ...node };
// 添加parentId属性 // 添加parentId属性
nodeCopy.parentId = parentId; nodeCopy[parentIdDes] = parentId;
// 移除children属性(使用正确拼写) // 移除children属性(使用正确拼写)
delete nodeCopy.children; delete nodeCopy.children;
// 添加当前节点到结果集 // 添加当前节点到结果集
result.push(nodeCopy); result.push(nodeCopy);
// 处理子节点(兼容chilrden拼写错误) // 处理子节点(兼容chilrden拼写错误)
const children = node.chilrden || node.children || []; const children = node.chilrden || node.children || [];
for (const child of children) { for (const child of children) {
traverse(child, node.id); traverse(child, node[idDes]);
} }
} }
// 遍历森林中的每棵树 // 遍历森林中的每棵树
for (const tree of forest) { for (const tree of forest) {
traverse(tree, null); // 根节点parentId为null traverse(tree, null); // 根节点parentId为null
} }
return result; return result;
} }
// 扩展测试:包含额外字段和标准children字段 // 扩展测试:包含额外字段和标准children字段
const complexForest = [ let complexForest = [
{
xh: "1",
zb: "项目资本金",
dw: "万元",
children: [
{
xh: "1.1",
zb: "能建方出资",
dw: "万元"
},
{
xh: "1.2",
zb: "外部股东",
dw: "万元"
}
]
},
{ {
id: 'A', xh: "2",
name: 'Root A', zb: "贷款",
chilrden: [ dw: "万元",
{ id: 'A1', value: 100 }, children: [
{ id: 'A2', value: 200, children: [{ id: 'A2a' }] } {
xh: "2.1",
zb: "其中:并非表项目我方贷款/投保额",
dw: "万元"
}
] ]
}, },
{ {
id: 'B', xh: "3",
name: 'Root B', zb: "其他出资",
children: [{ id: 'B1' }] dw: "万元",
children: [
{
xh: "3.1",
zb: "其中:能建方出资",
dw: "万元"
}
]
},
{
xh: "",
zb: "批复总出资",
dw: "万元"
} }
]; ]
console.log(flattenTree(complexForest)); console.log(flattenTree(complexForest, 'xh', 'parentXh'));
/* 输出: /* 输出:
[ [
{ id: 'A', name: 'Root A', parentId: null }, { id: 'A', name: 'Root A', parentId: null },
...@@ -61,4 +94,38 @@ console.log(flattenTree(complexForest)); ...@@ -61,4 +94,38 @@ console.log(flattenTree(complexForest));
{ id: 'B', name: 'Root B', parentId: null }, { id: 'B', name: 'Root B', parentId: null },
{ id: 'B1', parentId: 'B' } { id: 'B1', parentId: 'B' }
] ]
*/ */
\ No newline at end of file const _ = require('lodash');
function buildTree(nodes, keyid = 'id', keyParentId = 'parentId') {
// 创建一个映射,将节点ID映射到节点对象
const nodeMap = new Map(nodes.map(node => [String(node[keyid]), { ...node, children: [] }]));
// 遍历所有节点,并将它们添加到对应父节点的children数组中
nodes.forEach(node => {
const parentId = String(node[keyParentId]);
if (parentId !== null) {
// 确保父节点在映射中存在
if (nodeMap.has(parentId)) {
// 将当前节点添加到父节点的children数组中
nodeMap.get(parentId).children.push(nodeMap.get(String(node[keyid])));
nodeMap.get(parentId).children = _.orderBy(nodeMap.get(parentId).children, 'order')
}
}
});
// 从映射中提取顶级节点(parentId为null)
return _.orderBy(Array.from(nodeMap.values()).filter(node => node[keyParentId] == null), 'order');
}
console.log(JSON.stringify(buildTree([
{ xh: '1', zb: '项目资本金', dw: '万元', parentXh: null },
{ xh: '1.1', zb: '能建方出资', dw: '万元', parentXh: '1' },
{ xh: '1.2', zb: '外部股东', dw: '万元', parentXh: '1' },
{ xh: '2', zb: '贷款', dw: '万元', parentXh: null },
{ xh: '2.1', zb: '其中:并非表项目我方贷款/投保额', dw: '万元', parentXh: '2' },
{ xh: '3', zb: '其他出资', dw: '万元', parentXh: null },
{ xh: '3.1', zb: '其中:能建方出资', dw: '万元', parentXh: '3' },
{ xh: '', zb: '批复总出资', dw: '万元', parentXh: null }
], 'xh', 'parentXh')))
[{ "xh": "1", "zb": "项目资本金", "dw": "万元", "parentXh": null, "children": [{ "xh": "1.1", "zb": "能建方出资", "dw": "万元", "parentXh": "1", "children": [] }, { "xh": "1.2", "zb": "外部股东", "dw": "万元", "parentXh": "1", "children": [] }] }, { "xh": "2", "zb": "贷款", "dw": "万元", "parentXh": null, "children": [{ "xh": "2.1", "zb": "其中:并非表项目我方贷款/投保额", "dw": "万元", "parentXh": "2", "children": [] }] }, { "xh": "3", "zb": "其他出资", "dw": "万元", "parentXh": null, "children": [{ "xh": "3.1", "zb": "其中:能建方出资", "dw": "万元", "parentXh": "3", "children": [] }] }, { "xh": "", "zb": "批复总出资", "dw": "万元", "parentXh": null, "children": [] }]
\ No newline at end of file
This diff is collapsed.
...@@ -13,7 +13,7 @@ async function createResource(req, res, next) { ...@@ -13,7 +13,7 @@ async function createResource(req, res, next) {
ret = ret.toJSON(); ret = ret.toJSON();
console.log(ret); console.log(ret);
if (body.resourceInfos && body.resourceInfos.length && ret.id) { if (body.resourceInfos && body.resourceInfos.length && ret.id) {
if(type == 1){ if(body.type == 1){
let ris = []; let ris = [];
for (let index = 0; index < body.resourceInfos.length; index++) { for (let index = 0; index < body.resourceInfos.length; index++) {
const element = body.resourceInfos[index]; const element = body.resourceInfos[index];
...@@ -22,7 +22,7 @@ async function createResource(req, res, next) { ...@@ -22,7 +22,7 @@ async function createResource(req, res, next) {
} }
console.log(ris, "===") console.log(ris, "===")
await DB.ResourcesInfo.bulkCreate(ris); await DB.ResourcesInfo.bulkCreate(ris);
} else if(type == 2) { } else if(body.type == 2) {
//树结构 //树结构
let ris = []; let ris = [];
let data = utils.flattenTreeIterative(body.resourceInfos); let data = utils.flattenTreeIterative(body.resourceInfos);
......
...@@ -23,7 +23,11 @@ const Project = sequelize.define('Project', { ...@@ -23,7 +23,11 @@ const Project = sequelize.define('Project', {
}, },
projectLiuZhuanType: { projectLiuZhuanType: {
type: DataTypes.STRING, type: DataTypes.STRING,
comment: "项目流转状态 1. 待初审、3 待初审、1初审退回、5待终审、1终审退回、7待立项审批、立项审批退回、已立项、已暂停、已结束等", comment: "项目流转状态 1. 待提交、3 待初审、1初审退回、5待终审、1终审退回、7待立项审批、立项审批退回、已立项、已暂停、已结束等",
},
projectLiuZhuanTypeDes: {
type: DataTypes.STRING,
comment: "项目流转状态说明 待提交 待初审 初审退回 待终审 终审退回 待立项审批 立项审批退回 已立项 已结束等",
}, },
/** /**
* 项目基本信息 * 项目基本信息
...@@ -1765,9 +1769,9 @@ const Project = sequelize.define('Project', { ...@@ -1765,9 +1769,9 @@ const Project = sequelize.define('Project', {
// 同步模型到数据库(创建表) // 同步模型到数据库(创建表)
Project.sync({ Project.sync({
// force: false, force: false,
// force: true ,//会删除已存在表并重新创建 // force: true ,//会删除已存在表并重新创建
alter: true // alter: true
}) })
.then(() => { .then(() => {
console.log('Project 表同步成功'); console.log('Project 表同步成功');
......
...@@ -29,10 +29,10 @@ const ProjectXmtzze = sequelize.define('ProjectXmtzze', { ...@@ -29,10 +29,10 @@ const ProjectXmtzze = sequelize.define('ProjectXmtzze', {
type: DataTypes.DECIMAL(20, 4), type: DataTypes.DECIMAL(20, 4),
comment: "人民币计价" comment: "人民币计价"
}, },
// parentId: { parentXh: {
// type: DataTypes.INTEGER, type: DataTypes.STRING,
// comment: "上级ID" comment: "上级ID"
// }, },
projectId: { projectId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
...@@ -67,9 +67,9 @@ const ProjectXmtzze = sequelize.define('ProjectXmtzze', { ...@@ -67,9 +67,9 @@ const ProjectXmtzze = sequelize.define('ProjectXmtzze', {
// 同步模型到数据库(创建表) // 同步模型到数据库(创建表)
ProjectXmtzze.sync({ ProjectXmtzze.sync({
force: false, // force: false,
// force: true ,//会删除已存在表并重新创建 // force: true ,//会删除已存在表并重新创建
// alter: true alter: true
}) })
.then(() => { .then(() => {
console.log('ProjectXmtzze 表同步成功'); console.log('ProjectXmtzze 表同步成功');
......
...@@ -35,13 +35,13 @@ const flowRecord = sequelize.define('flowRecord', { ...@@ -35,13 +35,13 @@ const flowRecord = sequelize.define('flowRecord', {
comment: "0 正常 1 删除" comment: "0 正常 1 删除"
}, },
}, { }, {
tableName: 'system_user', // 指定表名(如果与模型名不同) tableName: 'system_flowrecord', // 指定表名(如果与模型名不同)
timestamps: true, // 是否自动添加 createdAt 和 updatedAt 字段(覆盖全局设置) timestamps: true, // 是否自动添加 createdAt 和 updatedAt 字段(覆盖全局设置)
}); });
// 同步模型到数据库(创建表) // 同步模型到数据库(创建表)
flowRecord.sync({ flowRecord.sync({
// force: false, force: false,
// force: true ,//会删除已存在表并重新创建 // force: true ,//会删除已存在表并重新创建
// alter: true // alter: true
}) })
......
...@@ -26,8 +26,8 @@ const RoleMenu = sequelize.define('RoleMenu', { ...@@ -26,8 +26,8 @@ const RoleMenu = sequelize.define('RoleMenu', {
// 同步模型到数据库(创建表) // 同步模型到数据库(创建表)
RoleMenu.sync({ RoleMenu.sync({
// force: false, // force: true 会删除已存在表并重新创建 force: false, // force: true 会删除已存在表并重新创建
alter: true // alter: true
}) })
.then(() => { .then(() => {
console.log('RoleMenu 表同步成功'); console.log('RoleMenu 表同步成功');
......
...@@ -134,7 +134,7 @@ async function getProjectApprover(userId, roleCode) { ...@@ -134,7 +134,7 @@ async function getProjectApprover(userId, roleCode) {
// 获取当前用户公司的 具体角色 的用户列表 // 获取当前用户公司的 具体角色 的用户列表
let user = await DB.User.findOne({ where: { id: userId } }); let user = await DB.User.findOne({ where: { id: userId } });
return []; return [user];
} }
module.exports = { module.exports = {
......
...@@ -18,7 +18,9 @@ router.post('/getProjectFields', projectController.getProjectFields); ...@@ -18,7 +18,9 @@ router.post('/getProjectFields', projectController.getProjectFields);
router.post('/exportExcel', projectController.exportExcel); router.post('/exportExcel', projectController.exportExcel);
router.post('/preJugProject', projectController.preJugProject); //初审 router.post('/preJugProject', projectController.preJugProject); //初审
router.post('/finalJugProject', projectController.finalJugProject); //终审 router.post('/finalJugProject', projectController.finalJugProject); //终审 --暂时没有
router.post('/getOwnProjects', projectController.getOwnProjects);
......
...@@ -68,22 +68,87 @@ function disTree(tree) { ...@@ -68,22 +68,87 @@ function disTree(tree) {
// 迭代替代递归(万级以上节点) // 迭代替代递归(万级以上节点)
function flattenTreeIterative(forest) { function flattenTreeIterative(forest) {
const result = []; const result = [];
const stack = [...forest.map(node => ({ node, parentId: null }))]; const stack = [...forest.map(node => ({ node, parentId: null }))];
while (stack.length) { while (stack.length) {
const { node, parentId } = stack.pop(); const { node, parentId } = stack.pop();
const { chilrden, children, ...rest } = node; const { chilrden, children, ...rest } = node;
result.push({ ...rest, parentId }); result.push({ ...rest, parentId });
const kids = chilrden || children || []; const kids = chilrden || children || [];
for (let i = kids.length - 1; i >= 0; i--) { for (let i = kids.length - 1; i >= 0; i--) {
stack.push({ node: kids[i], parentId: node.id }); stack.push({ node: kids[i], parentId: node.id });
}
}
return result;
}
/**
* 把带有chilrden的推平
* @param {*} forest
* @param {*} idDes
* @param {*} parentIdDes
* @returns
*/
function flattenTree(forest, idDes = 'id', parentIdDes = 'parentId') {
const result = [];
/**
* 递归处理节点
* @param {Object} node - 当前节点
* @param {string|null} parentId - 父节点ID
*/
function traverse(node, parentId) {
// 创建节点副本避免修改原数据
const nodeCopy = { ...node };
// 添加parentId属性
nodeCopy[parentIdDes] = parentId;
// 移除children属性(使用正确拼写)
delete nodeCopy.children;
// 添加当前节点到结果集
result.push(nodeCopy);
// 处理子节点(兼容chilrden拼写错误)
const children = node.chilrden || node.children || [];
for (const child of children) {
traverse(child, node[idDes]);
}
} }
}
// 遍历森林中的每棵树
return result; for (const tree of forest) {
traverse(tree, null); // 根节点parentId为null
}
return result;
}
//
function buildTree2(nodes, keyid = 'id', keyParentId = 'parentId') {
// 创建一个映射,将节点ID映射到节点对象
const nodeMap = new Map(nodes.map(node => [String(node[keyid]), { ...node, children: [] }]));
// 遍历所有节点,并将它们添加到对应父节点的children数组中
nodes.forEach(node => {
const parentId = String(node[keyParentId]);
if (parentId !== null) {
// 确保父节点在映射中存在
if (nodeMap.has(parentId)) {
// 将当前节点添加到父节点的children数组中
nodeMap.get(parentId).children.push(nodeMap.get(String(node[keyid])));
nodeMap.get(parentId).children = _.orderBy(nodeMap.get(parentId).children, 'order')
}
}
});
// 从映射中提取顶级节点(parentId为null)
return _.orderBy(Array.from(nodeMap.values()).filter(node => node[keyParentId] == null), 'order');
} }
...@@ -92,6 +157,7 @@ module.exports = { ...@@ -92,6 +157,7 @@ module.exports = {
checkUserPassword, checkUserPassword,
buildTree, buildTree,
disTree, disTree,
flattenTreeIterative flattenTreeIterative,
flattenTree,
buildTree2,
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment