'use strict'; /** * * * @author Mai * @date * @version */ const rootId = '-1'; module.exports = app => { class SubProject extends app.BaseService { /** * 构造函数 * * @param {Object} ctx - egg全局变量 * @param {String} tableName - 表名 * @return {void} */ constructor(ctx) { super(ctx); this.tableName = 'sub_project'; } async getSubProject(pid, uid, admin) { let result = await this.getAllDataByCondition({ where: { project_id: pid, is_delete: 0 } }); if (admin) return result; const permission = await this.ctx.service.subProjPermission.getUserPermission(pid, uid); result = result.filter(x => { if (x.is_folder) return true; const pb = permission.find(y => { return x.id === y.spid}); if (!pb) return false; x.user_permission = pb; return x.user_permission.budget_permission.length > 0 || x.user_permission.file_permission.length > 0 || x.user_permission.manage_permission.length > 0; }); return result; } _filterEmptyFolder(data) { data.sort((a, b) => { return b.tree_level - a.tree_level}); const result = []; for (const d of data) { if (!d.is_folder) result.push(d); if (result.find(x => { return x.tree_pid === d.id; })) result.push(d); } return result; } async getBudgetProject(pid, uid, admin) { let result = await this.getAllDataByCondition({ where: { project_id: pid, is_delete: 0 } }); const adminPermission = this.ctx.service.subProjPermission.adminPermission; const permission = admin ? [] : await this.ctx.service.subProjPermission.getUserPermission(pid, uid); result = result.filter(x => { if (!x.is_folder && !x.budget_id) return false; if (x.is_folder) return true; if (admin) { x.permission = adminPermission.budget_permission; x.manage_permission = adminPermission.manage_permission; return true; } else { const pb = permission.find(y => { return x.id === y.spid}); if (!pb) return false; x.permission = pb.budget_permission; x.manage_permission = pb.manage_permission; return x.permission.length > 0; } }); return this._filterEmptyFolder(result); } async getFileProject(pid, uid, admin) { let result = await this.getAllDataByCondition({ where: { project_id: pid, is_delete: 0 } }); const adminPermission = this.ctx.service.subProjPermission.adminPermission; const permission = await this.ctx.service.subProjPermission.getUserPermission(pid, uid); result = result.filter(x => { if (!x.is_folder && !x.management) return false; if (x.is_folder) return true; if (admin) { x.permission = adminPermission.file_permission; x.manage_permission = adminPermission.manage_permission; return true; } else { const pb = permission.find(y => { return x.id === y.spid}); if (!pb) return false; x.permission = pb.file_permission; x.manage_permission = pb.manage_permission; return x.permission.length > 0; } }); return this._filterEmptyFolder(result); } async getLastChild(tree_pid) { const result = await this.getAllDataByCondition({ where: { tree_pid, project_id: this.ctx.session.sessionProject.id }, orders: [['tree_order', 'desc']], limit: 1, offset: 0 }); return result[0]; } async getPosterityData(id){ const result = []; let cur = await this.getAllDataByCondition({ where: { tree_pid: id, project_id: this.ctx.session.sessionProject.id } }); let iLevel = 1; while (cur.length > 0 && iLevel < 6) { result.push(...cur); cur = await this.getAllDataByCondition({ where: { tree_pid: cur.map(x => { return x.id })} }); iLevel += 1; } return result; } async getStepNode(node, step) { const tree_order = []; while(step) { tree_order.push(node.tree_order + step); if (step > 0) { step = step - 1; } else { step = step + 1; } } return await this.getAllDataByCondition({ where: { tree_pid: node.tree_pid, tree_order, project_id: this.ctx.session.sessionProject.id }, orders: [['tree_order', 'asc']]}); } async addFolder(data) { const parent = await this.getDataById(data.tree_pid); if (parent && !parent.is_folder) throw '添加数据结构错误'; const lastChild = await this.getLastChild(parent ? parent.id : rootId); const conn = await this.db.beginTransaction(); try { // 获取当前用户信息 const sessionUser = this.ctx.session.sessionUser; // 获取当前项目信息 const sessionProject = this.ctx.session.sessionProject; const insertData = { id: this.uuid.v4(), project_id: sessionProject.id, user_id: sessionUser.accountId, tree_pid: data.tree_pid, tree_level: parent ? parent.tree_level + 1 : 1, tree_order: lastChild ? lastChild.tree_order + 1 : 1, name: data.name, is_folder: 1, }; const operate = await conn.insert(this.tableName, insertData); if (operate.affectedRows === 0) throw '新增文件夹失败'; await conn.commit(); return await this.getSubProject(sessionProject.id, sessionUser.accountId, sessionUser.is_admin); } catch (error) { await conn.rollback(); throw error; } } async addSubProject(data) { const parent = await this.getDataById(data.tree_pid); if (parent && !parent.is_folder) throw '添加数据结构错误'; const lastChild = await this.getLastChild(parent ? parent.id : rootId); const conn = await this.db.beginTransaction(); try { // 获取当前用户信息 const sessionUser = this.ctx.session.sessionUser; // 获取当前项目信息 const sessionProject = this.ctx.session.sessionProject; const insertData = { id: this.uuid.v4(), project_id: sessionProject.id, user_id: sessionUser.accountId, tree_pid: data.tree_pid, tree_level: parent ? parent.tree_level + 1 : 1, tree_order: lastChild ? lastChild.tree_order + 1 : 1, name: data.name, is_folder: 0, }; const operate = await conn.insert(this.tableName, insertData); // todo 根据节点新增时的其他操作 if (operate.affectedRows === 0) throw '新增文件夹失败'; await conn.commit(); return await this.getSubProject(sessionProject.id, sessionUser.accountId, sessionUser.is_admin); } catch (error) { await conn.rollback(); throw error; } } async dragTo(data) { const dragNode = await this.getDataById(data.drag_id); const dropNode = await this.getDataById(data.drop_id); if (!dragNode || !dropNode || !dropNode.is_folder) throw '拖拽数据结构错误'; const lastChild = await this.getLastChild(dropNode.id); const posterity = await this.getPosterityData(dragNode.id); const conn = await this.db.beginTransaction(); try { const updateData = { id: dragNode.id, tree_pid: dropNode.id, tree_level: dropNode.tree_level + 1, tree_order: lastChild ? lastChild.tree_order + 1 : 1, }; await conn.update(this.tableName, updateData); if (dragNode.tree_level !== dropNode.tree_level + 1 && posterity.length > 0) { const posterityUpdateData = posterity.map(x => { return { id: x.id, tree_level: dropNode.tree_level + 1 - dragNode.tree_level + x.tree_level } }); await conn.updateRows(this.tableName, posterityUpdateData); } // 升级原来的后项的order await conn.query(`UPDATE ${this.tableName} SET tree_order = tree_order-1 WHERE tree_pid = ? AND tree_order > ?`, [dragNode.tree_pid, dragNode.tree_order]); await conn.commit(); } catch (error) { await conn.rollback(); throw error; } return await this.getSubProject(this.ctx.session.sessionProject.id, this.ctx.session.sessionUser.accountId, this.ctx.session.sessionUser.is_admin); } async _siblingMove(node, step) { const stepNode = await this.getStepNode(node, step); const conn = await this.db.beginTransaction(); try { const updateData = []; updateData.push({ id: node.id, tree_order: node.tree_order + step }); for (const sn of stepNode) { updateData.push({ id: node.id, tree_order: step > 0 ? sn.tree_order - 1 : sn.tree_order + 1 }); } await conn.updateRows(this.tableName, updateData); await conn.commit(); } catch (error) { await conn.rollback(); throw error; } } async _siblingMoveForce(node, step) { const sibling = await this.getAllDataByCondition({ where: { tree_pid: node.tree_pid, project_id: this.ctx.session.sessionProject.id }, orders: [['tree_order', 'asc']] }); const nodeIndex = sibling.findIndex(x => { return x.id === node.id }); if (nodeIndex + step < 0) throw '移动数据结构错误'; if (nodeIndex + step > sibling.length - 1) throw '移动数据结构错误'; const conn = await this.db.beginTransaction(); try { const updateData = []; updateData.push({ id: node.id, tree_order: sibling[nodeIndex + step].tree_order }); while(step) { const stepNode = sibling[nodeIndex + step]; if (step > 0) { updateData.push({ id: stepNode.id, tree_order: sibling[nodeIndex + step - 1].tree_order }); step = step - 1; } else { updateData.push({ id: stepNode.id, tree_order: sibling[nodeIndex + step + 1].tree_order}); step = step + 1; } } await conn.updateRows(this.tableName, updateData); await conn.commit(); } catch (error) { await conn.rollback(); throw error; } } async _topMove(node) { const lastChild = await this.getLastChild(rootId); const posterity = await this.getPosterityData(node.id); const conn = await this.db.beginTransaction(); try { const updateData = { id: node.id, tree_pid: rootId, tree_level: 1, tree_order: lastChild ? lastChild.tree_order + 1 : 1 }; await conn.update(this.tableName, updateData); if (node.tree_level !== 1 && posterity.length > 0) { const posterityUpdateData = posterity.map(x => { return { id: x.id, tree_level: x.tree_level - node.tree_level + 1 } }); await conn.updateRows(this.tableName, posterityUpdateData); } // 升级原来的后项的order await conn.query(`UPDATE ${this.tableName} SET tree_order = tree_order-1 WHERE tree_pid = ? AND tree_order > ?`, [node.tree_pid, node.tree_order]); await conn.commit(); } catch (error) { await conn.rollback(); throw error; } } async move(data) { const node = await this.getDataById(data.id); if (!node) throw '移动数据结构错误'; switch(data.type) { case 'up': await this._siblingMoveForce(node, -1); break; case 'down': await this._siblingMoveForce(node, 1); break; case 'top': await this._topMove(node); break; default: throw '未知移动类型'; } return await this.getSubProject(this.ctx.session.sessionProject.id, this.ctx.session.sessionUser.accountId, this.ctx.session.sessionUser.is_admin); } async del(id) { const node = await this.getDataById(id); if (!node) throw '删除的数据不存在'; const posterity = await this.getPosterityData(node.id); const updateData = [ { id: node.id, is_delete: 1 }, ]; posterity.forEach(x => { updateData.push({ id: x.id, is_delete: 1}); }); await this.db.updateRows(this.tableName, updateData); return await this.getSubProject(this.ctx.session.sessionProject.id, this.ctx.session.sessionUser.accountId, this.ctx.session.sessionUser.is_admin); } async save(data) { const result = await this.db.update(this.tableName, data); if (result.affectedRows > 0) { return data; } else { throw '更新数据失败'; } } async setBudgetStd(data) { const subProject = await this.getDataById(data.id); const budgetStd = await this.ctx.service.budgetStd.getDataById(data.std_id); if (!budgetStd) throw '选择的概算标准不存在,请刷新页面重试'; const conn = await this.db.beginTransaction(); try { const budget_id = await this.ctx.service.budget.add(conn, { pid: subProject.project_id, user_id: subProject.user_id, rela_tender: subProject.rela_tender }, budgetStd); const updateData = { id: data.id, std_id: budgetStd.id, std_name: budgetStd.name, budget_id }; await conn.update(this.tableName, updateData); await conn.commit(); return updateData; } catch (error) { await conn.rollback(); throw error; } } async setRelaTender(data) { const subProject = await this.getDataById(data.id); const conn = await this.db.beginTransaction(); try { await conn.update(this.tableName, data); await conn.update(this.ctx.service.budget.tableName, { id: subProject.budget_id, rela_tender: data.rela_tender }); await conn.commit(); return data; } catch (error) { await conn.rollback(); throw error; } } async setManagement(data) { const subProject = await this.getDataById(data.id); if (subProject.management === data.management) return data; const users = await this.ctx.service.projectAccount.getAllDataByCondition({ where: { project_id: subProject.project_id, company: data.management }}); const orgMember = await this.ctx.service.subProjPermission.getAllDataByCondition({ where: { spid: subProject.id } }); const dm = [], um = [], im = []; const filing_type = this.ctx.service.filing.allFilingType.join(','), file_permission = '1,2'; for (const u of users) { const nm = orgMember.find(x => { return u.id === x.uid; }); if (nm) { if (!nm.file_permission) um.push({ id: nm.id, file_permission, filing_type }); } else { im.push({ id: this.uuid.v4(), spid: subProject.id, pid: subProject.project_id, uid: u.id, file_permission, filing_type }); } } const conn = await this.db.beginTransaction(); try { await conn.update(this.tableName, { id: subProject.id, management: data.management }); await this.ctx.service.filing.initFiling(subProject.id, conn); if (dm.length > 0) await conn.delete(this.ctx.service.subProjPermission.tableName, { id: dm }); if (um.length > 0) await conn.updateRows(this.ctx.service.subProjPermission.tableName, um); if (im.length > 0) await conn.insert(this.ctx.service.subProjPermission.tableName, im); await conn.commit(); return data; } catch (error) { await conn.rollback(); throw error; } } async refreshManagementPermission(data) { const subProject = await this.getDataById(data.id); const users = await this.ctx.service.projectAccount.getAllDataByCondition({ where: { project_id: subProject.project_id, company: subProject.management }}); const orgMember = await this.ctx.service.subProjPermission.getAllDataByCondition({ where: { spid: subProject.id } }); const dm = [], um = [], im = []; const filing_type = this.ctx.service.filing.allFilingType.join(','), file_permission = '1,2'; for (const u of users) { const nm = orgMember.find(x => { return u.id === x.uid; }); if (nm) { if (!nm.file_permission) um.push({ id: nm.id, file_permission, filing_type }); } else { im.push({ id: this.uuid.v4(), spid: subProject.id, pid: subProject.project_id, uid: u.id, file_permission, filing_type }); } } const conn = await this.db.beginTransaction(); try { if (dm.length > 0) await conn.delete(this.ctx.service.subProjPermission.tableName, { id: dm }); if (um.length > 0) await conn.updateRows(this.ctx.service.subProjPermission.tableName, um); if (im.length > 0) await conn.insert(this.ctx.service.subProjPermission.tableName, im); await conn.commit(); return { dm: dm.length, um: um.length, im: im.length }; } catch (error) { await conn.rollback(); throw error; } } } return SubProject; };