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.
229 lines
8.9 KiB
229 lines
8.9 KiB
'use strict';
|
|
|
|
const { hasOwn, toInt, parsePagination, ensureCreatedBy, normalizeNullableInt } = require('./helpers');
|
|
const {
|
|
ensureDataSource,
|
|
ensureInstance,
|
|
ensureTemplate,
|
|
resolveSchemaVersion,
|
|
getInstanceChapterTree,
|
|
createChapterTreeFromPayload,
|
|
} = require('./repository');
|
|
const {
|
|
ensureHttpUrl,
|
|
downloadDocxFile,
|
|
convertDocxToHtml,
|
|
parseDocxHtmlToChapters,
|
|
} = require('./docxImport');
|
|
const { buildDocxImportChapterPayload } = require('./tree');
|
|
|
|
module.exports.getInstances = async (ctx, next) => {
|
|
try {
|
|
const { models, ORM: { Op } } = ctx.app.fs.dc;
|
|
const { offset, limit } = parsePagination(ctx.request.query);
|
|
const where = {};
|
|
const name = String(ctx.request.query.name || '').trim();
|
|
const type = String(ctx.request.query.type || '').trim();
|
|
const createdBy = String(ctx.request.query.createdBy || '').trim();
|
|
const templateId = toInt(ctx.request.query.templateId);
|
|
const departmentId = normalizeNullableInt(ctx.request.query.departmentId, 'departmentId');
|
|
if (name) where.name = { [Op.like]: `%${name}%` };
|
|
if (type) where.type = type;
|
|
if (createdBy) where.createdBy = createdBy;
|
|
if (templateId) where.templateId = templateId;
|
|
if (departmentId) where.departmentId = departmentId;
|
|
const list = await models.ReportInstance.findAndCountAll({
|
|
where,
|
|
order: [['id', 'DESC']],
|
|
include: [
|
|
{ model: models.ReportTemplate, required: false },
|
|
{ model: models.ReportDataSource, required: false },
|
|
{ model: models.ReportSchemaVersion, required: false },
|
|
],
|
|
offset,
|
|
limit,
|
|
});
|
|
ctx.body = { count: list.count, rows: list.rows };
|
|
ctx.status = 200;
|
|
} catch (error) {
|
|
ctx.logger.log(error);
|
|
ctx.status = 400;
|
|
ctx.body = { message: typeof error === 'string' ? error : '获取报表实例列表失败' };
|
|
}
|
|
};
|
|
|
|
module.exports.createInstance = async (ctx, next) => {
|
|
const transaction = await ctx.app.fs.dc.orm.transaction();
|
|
try {
|
|
const { models } = ctx.app.fs.dc;
|
|
const body = ctx.request.body || {};
|
|
const { name, dataSourceId, schemaVersionId, type, templateId, chapters } = body;
|
|
const createdBy = ensureCreatedBy(body);
|
|
const departmentId = normalizeNullableInt(body.departmentId, 'departmentId');
|
|
if (!String(name || '').trim()) throw '缺少参数: name';
|
|
await ensureDataSource(ctx, dataSourceId, transaction);
|
|
const schemaVersion = await resolveSchemaVersion(ctx, schemaVersionId, transaction);
|
|
let parsedTemplateId = null;
|
|
if (templateId !== null && templateId !== undefined && templateId !== '') {
|
|
const template = await ensureTemplate(ctx, templateId, transaction);
|
|
parsedTemplateId = template.id;
|
|
}
|
|
const created = await models.ReportInstance.create({
|
|
templateId: parsedTemplateId,
|
|
schemaVersionId: schemaVersion.id,
|
|
name: String(name).trim(),
|
|
type: String(type || 'general'),
|
|
dataSourceId: toInt(dataSourceId),
|
|
createdBy,
|
|
departmentId,
|
|
}, {
|
|
transaction,
|
|
returning: true,
|
|
});
|
|
if (Array.isArray(chapters) && chapters.length) {
|
|
await createChapterTreeFromPayload(ctx, created.id, null, chapters, transaction);
|
|
}
|
|
const chapterTree = await getInstanceChapterTree(ctx, created.id, transaction);
|
|
await transaction.commit();
|
|
ctx.body = {
|
|
...created.toJSON(),
|
|
chapters: chapterTree,
|
|
};
|
|
ctx.status = 200;
|
|
} catch (error) {
|
|
await transaction.rollback();
|
|
ctx.logger.log(error);
|
|
ctx.status = 400;
|
|
ctx.body = { message: typeof error === 'string' ? error : '创建报表实例失败' };
|
|
}
|
|
};
|
|
|
|
module.exports.importInstanceFromDocx = async (ctx, next) => {
|
|
const transaction = await ctx.app.fs.dc.orm.transaction();
|
|
try {
|
|
const { models } = ctx.app.fs.dc;
|
|
const body = ctx.request.body || {};
|
|
const { name, dataSourceId, schemaVersionId, type, sourceFileUrl } = body;
|
|
const createdBy = ensureCreatedBy(body);
|
|
const departmentId = normalizeNullableInt(body.departmentId, 'departmentId');
|
|
if (!String(name || '').trim()) throw 'missing param: name';
|
|
|
|
const normalizedSourceFileUrl = ensureHttpUrl(sourceFileUrl, 'sourceFileUrl');
|
|
await ensureDataSource(ctx, dataSourceId, transaction);
|
|
const schemaVersion = await resolveSchemaVersion(ctx, schemaVersionId, transaction);
|
|
|
|
const downloadedFile = await downloadDocxFile(normalizedSourceFileUrl);
|
|
const sourceFileName = String(downloadedFile.sourceFileName || '').trim() || 'import.docx';
|
|
const html = await convertDocxToHtml(ctx, downloadedFile.fileBuffer);
|
|
const chapterNodes = parseDocxHtmlToChapters(html);
|
|
const chapterPayload = buildDocxImportChapterPayload(
|
|
chapterNodes,
|
|
normalizedSourceFileUrl,
|
|
sourceFileName
|
|
);
|
|
|
|
const created = await models.ReportInstance.create({
|
|
templateId: null,
|
|
schemaVersionId: schemaVersion.id,
|
|
name: String(name).trim(),
|
|
type: String(type || 'general'),
|
|
dataSourceId: toInt(dataSourceId),
|
|
createdBy,
|
|
departmentId,
|
|
sourceFileUrl: normalizedSourceFileUrl,
|
|
sourceFileName,
|
|
}, {
|
|
transaction,
|
|
returning: true,
|
|
});
|
|
|
|
await createChapterTreeFromPayload(ctx, created.id, null, chapterPayload, transaction);
|
|
const chapters = await getInstanceChapterTree(ctx, created.id, transaction);
|
|
await transaction.commit();
|
|
ctx.body = {
|
|
...created.toJSON(),
|
|
chapters,
|
|
};
|
|
ctx.status = 200;
|
|
} catch (error) {
|
|
await transaction.rollback();
|
|
ctx.logger.log(error);
|
|
ctx.status = 400;
|
|
ctx.body = {
|
|
message: typeof error === 'string'
|
|
? error
|
|
: (error?.message || 'failed to import report instance from docx'),
|
|
};
|
|
}
|
|
};
|
|
|
|
module.exports.getInstanceDetail = async (ctx, next) => {
|
|
try {
|
|
const { models } = ctx.app.fs.dc;
|
|
const instanceId = toInt(ctx.params.instanceId);
|
|
if (!instanceId) throw '缺少参数: instanceId';
|
|
const instance = await models.ReportInstance.findByPk(instanceId, {
|
|
include: [
|
|
{ model: models.ReportTemplate, required: false },
|
|
{ model: models.ReportDataSource, required: false },
|
|
{ model: models.ReportSchemaVersion, required: false },
|
|
],
|
|
});
|
|
if (!instance) throw '报表实例不存在';
|
|
const chapters = await getInstanceChapterTree(ctx, instanceId);
|
|
ctx.body = {
|
|
...instance.toJSON(),
|
|
chapters,
|
|
};
|
|
ctx.status = 200;
|
|
} catch (error) {
|
|
ctx.logger.log(error);
|
|
ctx.status = 400;
|
|
ctx.body = { message: typeof error === 'string' ? error : '获取报表实例详情失败' };
|
|
}
|
|
};
|
|
|
|
module.exports.updateInstance = async (ctx, next) => {
|
|
try {
|
|
const { models } = ctx.app.fs.dc;
|
|
const instanceId = toInt(ctx.params.instanceId);
|
|
if (!instanceId) throw '缺少参数: instanceId';
|
|
await ensureInstance(ctx, instanceId);
|
|
const body = ctx.request.body || {};
|
|
const updateData = {};
|
|
if (hasOwn(body, 'name')) updateData.name = body.name ? String(body.name).trim() : '';
|
|
if (hasOwn(body, 'type')) updateData.type = body.type ? String(body.type).trim() : 'general';
|
|
if (hasOwn(body, 'templateId')) updateData.templateId = body.templateId ? toInt(body.templateId) : null;
|
|
if (hasOwn(body, 'exportedAt')) updateData.exportedAt = body.exportedAt ? new Date(body.exportedAt) : null;
|
|
if (hasOwn(body, 'dataSourceId')) {
|
|
await ensureDataSource(ctx, body.dataSourceId);
|
|
updateData.dataSourceId = toInt(body.dataSourceId);
|
|
}
|
|
if (hasOwn(body, 'departmentId')) updateData.departmentId = normalizeNullableInt(body.departmentId, 'departmentId');
|
|
if (hasOwn(body, 'schemaVersionId')) {
|
|
const schemaVersion = await resolveSchemaVersion(ctx, body.schemaVersionId);
|
|
updateData.schemaVersionId = schemaVersion.id;
|
|
}
|
|
await models.ReportInstance.update(updateData, { where: { id: instanceId } });
|
|
ctx.status = 204;
|
|
} catch (error) {
|
|
ctx.logger.log(error);
|
|
ctx.status = 400;
|
|
ctx.body = { message: typeof error === 'string' ? error : '更新报表实例失败' };
|
|
}
|
|
};
|
|
|
|
module.exports.deleteInstance = async (ctx, next) => {
|
|
try {
|
|
const { models } = ctx.app.fs.dc;
|
|
const instanceId = toInt(ctx.params.instanceId);
|
|
if (!instanceId) throw '缺少参数: instanceId';
|
|
await ensureInstance(ctx, instanceId);
|
|
await models.ReportInstance.destroy({ where: { id: instanceId } });
|
|
ctx.status = 204;
|
|
} catch (error) {
|
|
ctx.logger.log(error);
|
|
ctx.status = 400;
|
|
ctx.body = { message: typeof error === 'string' ? error : '删除报表实例失败' };
|
|
}
|
|
};
|
|
|