'use strict'; const { TEMP_POSITION_BASE } = require('./constants'); const { toInt, normalizeInsertPosition } = require('./helpers'); const reorderPositions = async (Model, orderedIds, transaction = null) => { if (!orderedIds.length) return; let tempPosition = TEMP_POSITION_BASE; for (const id of orderedIds) { await Model.update({ position: tempPosition++ }, { where: { id }, transaction }); } let finalPosition = 1; for (const id of orderedIds) { await Model.update({ position: finalPosition++ }, { where: { id }, transaction }); } }; const findChapterSiblings = async (ctx, instanceId, parentId, excludeChapterId = null, transaction = null) => { const { models, ORM: { Op } } = ctx.app.fs.dc; const where = { instanceId: toInt(instanceId), parentId: parentId === null ? null : toInt(parentId), }; if (excludeChapterId) { where.id = { [Op.ne]: toInt(excludeChapterId) }; } return models.ReportChapter.findAll({ where, attributes: ['id', 'position'], order: [['position', 'ASC'], ['id', 'ASC']], raw: true, transaction, }); }; const findTemplateChapterSiblings = async (ctx, templateId, parentId, excludeChapterId = null, transaction = null) => { const { models, ORM: { Op } } = ctx.app.fs.dc; const where = { templateId: toInt(templateId), parentId: parentId === null ? null : toInt(parentId), }; if (excludeChapterId) { where.id = { [Op.ne]: toInt(excludeChapterId) }; } return models.ReportTemplateChapter.findAll({ where, attributes: ['id', 'position'], order: [['position', 'ASC'], ['id', 'ASC']], raw: true, transaction, }); }; const findBlockSiblings = async (ctx, chapterId, excludeBlockId = null, transaction = null) => { const { models, ORM: { Op } } = ctx.app.fs.dc; const where = { chapterId: toInt(chapterId), }; if (excludeBlockId) { where.id = { [Op.ne]: toInt(excludeBlockId) }; } return models.ReportBlock.findAll({ where, attributes: ['id', 'position'], order: [['position', 'ASC'], ['id', 'ASC']], raw: true, transaction, }); }; const findTemplateBlockSiblings = async (ctx, chapterId, excludeBlockId = null, transaction = null) => { const { models, ORM: { Op } } = ctx.app.fs.dc; const where = { chapterId: toInt(chapterId), }; if (excludeBlockId) { where.id = { [Op.ne]: toInt(excludeBlockId) }; } return models.ReportTemplateBlock.findAll({ where, attributes: ['id', 'position'], order: [['position', 'ASC'], ['id', 'ASC']], raw: true, transaction, }); }; const reorderChapterSiblingsWithInsert = async (ctx, instanceId, parentId, chapterId, targetPosition, transaction = null) => { const { models } = ctx.app.fs.dc; const siblings = await findChapterSiblings(ctx, instanceId, parentId, chapterId, transaction); const insertPosition = normalizeInsertPosition(targetPosition, siblings.length + 1); const orderedIds = siblings.map(item => item.id); orderedIds.splice(insertPosition - 1, 0, toInt(chapterId)); await reorderPositions(models.ReportChapter, orderedIds, transaction); return insertPosition; }; const reorderBlockSiblingsWithInsert = async (ctx, chapterId, blockId, targetPosition, transaction = null) => { const { models } = ctx.app.fs.dc; const siblings = await findBlockSiblings(ctx, chapterId, blockId, transaction); const insertPosition = normalizeInsertPosition(targetPosition, siblings.length + 1); const orderedIds = siblings.map(item => item.id); orderedIds.splice(insertPosition - 1, 0, toInt(blockId)); await reorderPositions(models.ReportBlock, orderedIds, transaction); return insertPosition; }; const reorderChapterSiblings = async (ctx, instanceId, parentId, transaction = null) => { const { models } = ctx.app.fs.dc; const siblings = await findChapterSiblings(ctx, instanceId, parentId, null, transaction); await reorderPositions(models.ReportChapter, siblings.map(item => item.id), transaction); }; const reorderTemplateChapterSiblingsWithInsert = async (ctx, templateId, parentId, chapterId, targetPosition, transaction = null) => { const { models } = ctx.app.fs.dc; const siblings = await findTemplateChapterSiblings(ctx, templateId, parentId, chapterId, transaction); const insertPosition = normalizeInsertPosition(targetPosition, siblings.length + 1); const orderedIds = siblings.map(item => item.id); orderedIds.splice(insertPosition - 1, 0, toInt(chapterId)); await reorderPositions(models.ReportTemplateChapter, orderedIds, transaction); return insertPosition; }; const reorderTemplateBlockSiblingsWithInsert = async (ctx, chapterId, blockId, targetPosition, transaction = null) => { const { models } = ctx.app.fs.dc; const siblings = await findTemplateBlockSiblings(ctx, chapterId, blockId, transaction); const insertPosition = normalizeInsertPosition(targetPosition, siblings.length + 1); const orderedIds = siblings.map(item => item.id); orderedIds.splice(insertPosition - 1, 0, toInt(blockId)); await reorderPositions(models.ReportTemplateBlock, orderedIds, transaction); return insertPosition; }; const reorderTemplateChapterSiblings = async (ctx, templateId, parentId, transaction = null) => { const { models } = ctx.app.fs.dc; const siblings = await findTemplateChapterSiblings(ctx, templateId, parentId, null, transaction); await reorderPositions(models.ReportTemplateChapter, siblings.map(item => item.id), transaction); }; const reorderBlockSiblings = async (ctx, chapterId, transaction = null) => { const { models } = ctx.app.fs.dc; const siblings = await findBlockSiblings(ctx, chapterId, null, transaction); await reorderPositions(models.ReportBlock, siblings.map(item => item.id), transaction); }; const reorderTemplateBlockSiblings = async (ctx, chapterId, transaction = null) => { const { models } = ctx.app.fs.dc; const siblings = await findTemplateBlockSiblings(ctx, chapterId, null, transaction); await reorderPositions(models.ReportTemplateBlock, siblings.map(item => item.id), transaction); }; const ensureNoChapterCycle = async (ctx, instanceId, chapterId, parentId, transaction = null) => { if (parentId === null) return; const { models } = ctx.app.fs.dc; if (toInt(chapterId) === toInt(parentId)) throw '父章节不能是自身'; let current = await models.ReportChapter.findOne({ where: { id: toInt(parentId), instanceId: toInt(instanceId) }, attributes: ['id', 'parentId'], raw: true, transaction, }); if (!current) throw '父章节不存在'; while (current) { if (toInt(current.id) === toInt(chapterId)) { throw '不允许将章节移动到自己的子节点'; } if (!current.parentId) break; current = await models.ReportChapter.findOne({ where: { id: current.parentId, instanceId: toInt(instanceId) }, attributes: ['id', 'parentId'], raw: true, transaction, }); } }; const ensureNoTemplateChapterCycle = async (ctx, templateId, chapterId, parentId, transaction = null) => { if (parentId === null) return; const { models } = ctx.app.fs.dc; if (toInt(chapterId) === toInt(parentId)) throw '父章节不能是自身'; let current = await models.ReportTemplateChapter.findOne({ where: { id: toInt(parentId), templateId: toInt(templateId) }, attributes: ['id', 'parentId'], raw: true, transaction, }); if (!current) throw '父章节不存在'; while (current) { if (toInt(current.id) === toInt(chapterId)) { throw '不允许将章节移动到自己的子节点'; } if (!current.parentId) break; current = await models.ReportTemplateChapter.findOne({ where: { id: current.parentId, templateId: toInt(templateId) }, attributes: ['id', 'parentId'], raw: true, transaction, }); } }; module.exports = { reorderPositions, findChapterSiblings, findTemplateChapterSiblings, findBlockSiblings, findTemplateBlockSiblings, reorderChapterSiblingsWithInsert, reorderBlockSiblingsWithInsert, reorderChapterSiblings, reorderTemplateChapterSiblingsWithInsert, reorderTemplateBlockSiblingsWithInsert, reorderTemplateChapterSiblings, reorderBlockSiblings, reorderTemplateBlockSiblings, ensureNoChapterCycle, ensureNoTemplateChapterCycle, };