You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
6.7 KiB
181 lines
6.7 KiB
'use strict';
|
|
|
|
const { TEMP_POSITION_BASE } = require('./constants');
|
|
const { hasOwn, toInt, ensureObjectPayload } = require('./helpers');
|
|
const { ensureChapter, ensureBlock, ensureInstance } = require('./repository');
|
|
const { normalizeBlockConfigForStorage } = require('./dataSourceQuery');
|
|
const { resolveBlockPayload } = require('./blockPayloadResolver');
|
|
const {
|
|
reorderBlockSiblingsWithInsert,
|
|
reorderBlockSiblings,
|
|
} = require('./ordering');
|
|
|
|
const resolveInstanceBlockStoragePayload = async (
|
|
ctx,
|
|
instanceId,
|
|
blockType,
|
|
config,
|
|
contentSnapshot,
|
|
transaction
|
|
) => {
|
|
const normalizedBlockType = String(blockType || 'text').trim().toLowerCase();
|
|
const instance = await ensureInstance(ctx, instanceId, transaction);
|
|
const dataSourceId = toInt(instance.dataSourceId);
|
|
if (!dataSourceId && ['chart', 'table', 'kpi'].includes(normalizedBlockType)) {
|
|
throw '报表实例未绑定数据源';
|
|
}
|
|
const normalizedConfig = ['chart', 'table'].includes(normalizedBlockType)
|
|
? await normalizeBlockConfigForStorage(
|
|
ctx,
|
|
instanceId,
|
|
normalizedBlockType,
|
|
config || {},
|
|
transaction
|
|
)
|
|
: ensureObjectPayload(config || {}, 'config');
|
|
|
|
return resolveBlockPayload(ctx, {
|
|
blockType: normalizedBlockType,
|
|
dataSourceId,
|
|
config: normalizedConfig,
|
|
contentSnapshot: contentSnapshot || null,
|
|
transaction,
|
|
});
|
|
};
|
|
|
|
module.exports.createBlock = async (ctx, next) => {
|
|
const transaction = await ctx.app.fs.dc.orm.transaction();
|
|
try {
|
|
const { models } = ctx.app.fs.dc;
|
|
const instanceId = toInt(ctx.params.instanceId);
|
|
const chapterId = toInt(ctx.params.chapterId);
|
|
if (!instanceId || !chapterId) throw '缺少参数';
|
|
await ensureChapter(ctx, instanceId, chapterId, transaction);
|
|
|
|
const { blockType, position, config, contentSnapshot } = ctx.request.body || {};
|
|
const normalizedBlockType = String(blockType || 'text').trim().toLowerCase();
|
|
const storagePayload = await resolveInstanceBlockStoragePayload(
|
|
ctx,
|
|
instanceId,
|
|
normalizedBlockType,
|
|
config || {},
|
|
contentSnapshot || null,
|
|
transaction
|
|
);
|
|
const created = await models.ReportBlock.create({
|
|
instanceId,
|
|
chapterId,
|
|
blockType: normalizedBlockType,
|
|
position: TEMP_POSITION_BASE - 1,
|
|
config: storagePayload.config,
|
|
contentSnapshot: storagePayload.contentSnapshot,
|
|
updatedAt: new Date(),
|
|
}, {
|
|
transaction,
|
|
returning: true,
|
|
});
|
|
await reorderBlockSiblingsWithInsert(ctx, chapterId, created.id, position, transaction);
|
|
const fresh = await models.ReportBlock.findByPk(created.id, { transaction });
|
|
await transaction.commit();
|
|
ctx.body = fresh;
|
|
ctx.status = 200;
|
|
} catch (error) {
|
|
await transaction.rollback();
|
|
ctx.logger.log(error);
|
|
ctx.status = 400;
|
|
ctx.body = { message: typeof error === 'string' ? error : '创建内容块失败' };
|
|
}
|
|
};
|
|
|
|
module.exports.updateBlock = async (ctx, next) => {
|
|
const transaction = await ctx.app.fs.dc.orm.transaction();
|
|
try {
|
|
const { models } = ctx.app.fs.dc;
|
|
const instanceId = toInt(ctx.params.instanceId);
|
|
const blockId = toInt(ctx.params.blockId);
|
|
if (!instanceId || !blockId) throw '缺少参数';
|
|
const block = await ensureBlock(ctx, instanceId, blockId, transaction);
|
|
const body = ctx.request.body || {};
|
|
const updateData = {};
|
|
if (hasOwn(body, 'blockType')) {
|
|
updateData.blockType = String(body.blockType || 'text').trim().toLowerCase();
|
|
}
|
|
updateData.updatedAt = new Date();
|
|
if (hasOwn(body, 'config') || hasOwn(body, 'blockType')) {
|
|
const finalBlockType = hasOwn(body, 'blockType') ? updateData.blockType : block.blockType;
|
|
const finalConfig = hasOwn(body, 'config') ? (body.config || {}) : (block.config || {});
|
|
const finalContentSnapshot = hasOwn(body, 'contentSnapshot')
|
|
? body.contentSnapshot
|
|
: block.contentSnapshot;
|
|
const storagePayload = await resolveInstanceBlockStoragePayload(
|
|
ctx,
|
|
instanceId,
|
|
finalBlockType,
|
|
finalConfig,
|
|
finalContentSnapshot,
|
|
transaction
|
|
);
|
|
updateData.config = storagePayload.config;
|
|
updateData.contentSnapshot = storagePayload.contentSnapshot;
|
|
} else if (hasOwn(body, 'contentSnapshot')) {
|
|
updateData.contentSnapshot = body.contentSnapshot || null;
|
|
}
|
|
|
|
const oldChapterId = block.chapterId;
|
|
const nextChapterId = hasOwn(body, 'chapterId') ? toInt(body.chapterId) : block.chapterId;
|
|
if (!nextChapterId) throw '参数错误: chapterId';
|
|
await ensureChapter(ctx, instanceId, nextChapterId, transaction);
|
|
const needMove = hasOwn(body, 'chapterId') || hasOwn(body, 'position');
|
|
|
|
if (!needMove) {
|
|
await models.ReportBlock.update(updateData, { where: { id: blockId }, transaction });
|
|
await transaction.commit();
|
|
ctx.status = 204;
|
|
return;
|
|
}
|
|
|
|
updateData.chapterId = nextChapterId;
|
|
updateData.position = TEMP_POSITION_BASE - 1;
|
|
await models.ReportBlock.update(updateData, { where: { id: blockId }, transaction });
|
|
|
|
if (oldChapterId !== nextChapterId) {
|
|
await reorderBlockSiblings(ctx, oldChapterId, transaction);
|
|
}
|
|
|
|
const targetPosition = hasOwn(body, 'position')
|
|
? body.position
|
|
: (oldChapterId === nextChapterId ? block.position : undefined);
|
|
await reorderBlockSiblingsWithInsert(ctx, nextChapterId, blockId, targetPosition, transaction);
|
|
|
|
await transaction.commit();
|
|
ctx.status = 204;
|
|
} catch (error) {
|
|
await transaction.rollback();
|
|
ctx.logger.log(error);
|
|
ctx.status = 400;
|
|
ctx.body = { message: typeof error === 'string' ? error : '更新内容块失败' };
|
|
}
|
|
};
|
|
|
|
module.exports.deleteBlock = async (ctx, next) => {
|
|
const transaction = await ctx.app.fs.dc.orm.transaction();
|
|
try {
|
|
const { models } = ctx.app.fs.dc;
|
|
const instanceId = toInt(ctx.params.instanceId);
|
|
const blockId = toInt(ctx.params.blockId);
|
|
if (!instanceId || !blockId) throw '缺少参数';
|
|
const block = await ensureBlock(ctx, instanceId, blockId, transaction);
|
|
await models.ReportBlock.destroy({
|
|
where: { id: blockId, instanceId },
|
|
transaction,
|
|
});
|
|
await reorderBlockSiblings(ctx, block.chapterId, transaction);
|
|
await transaction.commit();
|
|
ctx.status = 204;
|
|
} catch (error) {
|
|
await transaction.rollback();
|
|
ctx.logger.log(error);
|
|
ctx.status = 400;
|
|
ctx.body = { message: typeof error === 'string' ? error : '删除内容块失败' };
|
|
}
|
|
};
|
|
|