import type { SharedFillExecuteCommand, SharedFillPreview } from '#/api/x/eln/records';
|
|
export class ElnSharedFillParamError extends Error {}
|
|
export function resolveTestWorkItemIds(value: unknown): string[] {
|
if (!Array.isArray(value)) throw new ElnSharedFillParamError('请选择至少两个检验项');
|
const ids = value.map((item) => {
|
if (typeof item !== 'string' || !item.trim()) throw new ElnSharedFillParamError('检验项选择无效');
|
return item.trim();
|
});
|
const unique = [...new Set(ids)];
|
if (unique.length < 2) throw new ElnSharedFillParamError('请选择至少两个检验项');
|
return unique;
|
}
|
|
interface BuildOptions {
|
fieldValues: Record<string, string | undefined>;
|
operationCode: string;
|
overwriteReasons: Record<string, string | undefined>;
|
selectedFieldIds: string[];
|
selectedTargetIds: string[];
|
}
|
|
function normalizedDecimal(value: string | undefined) {
|
const text = value?.trim();
|
if (!text) return undefined;
|
const match = /^([+-]?)(?:(\d+)(?:\.(\d*))?|\.(\d+))(?:e([+-]?\d+))?$/i.exec(text);
|
if (!match) return text;
|
const integer = match[2] || '';
|
const fraction = match[3] ?? match[4] ?? '';
|
let digits = `${integer}${fraction}`.replace(/^0+/, '');
|
if (!digits) return '0';
|
let scale = BigInt(fraction.length) - BigInt(match[5] || '0');
|
while (digits.endsWith('0')) {
|
digits = digits.slice(0, -1);
|
scale -= 1n;
|
}
|
return `${match[1] === '-' ? '-' : ''}${digits}e${scale}`;
|
}
|
|
export function requiresTargetOverwrite(
|
preview: SharedFillPreview,
|
testWorkItemId: string,
|
fieldVersionIds: string[],
|
fieldValues: Record<string, string | undefined>,
|
) {
|
const target = preview.targets.find((item) => item.testWorkItemId === testWorkItemId);
|
if (!target) return false;
|
return preview.fields.some(
|
(field) =>
|
fieldVersionIds.includes(field.fieldVersionId) &&
|
field.defaultExcludedTestWorkItemIds.includes(testWorkItemId) &&
|
normalizedDecimal(target.currentValues[field.fieldVersionId]) !== normalizedDecimal(fieldValues[field.fieldVersionId]),
|
);
|
}
|
|
export function buildSharedFillCommand(preview: SharedFillPreview, options: BuildOptions): SharedFillExecuteCommand {
|
if (!options.selectedFieldIds.length) throw new ElnSharedFillParamError('请选择至少一个共享字段');
|
if (!options.selectedTargetIds.length) throw new ElnSharedFillParamError('请选择至少一个填写目标');
|
const fields = options.selectedFieldIds.map((fieldVersionId) => {
|
const field = preview.fields.find((item) => item.fieldVersionId === fieldVersionId);
|
if (!field) throw new ElnSharedFillParamError('共享字段预览已失效');
|
const value = options.fieldValues[fieldVersionId]?.trim();
|
if (!value) throw new ElnSharedFillParamError(`请填写${field.fieldName || field.fieldCode}`);
|
return { field, value };
|
});
|
const targets = options.selectedTargetIds.map((testWorkItemId) => {
|
const target = preview.targets.find((item) => item.testWorkItemId === testWorkItemId);
|
if (!target?.eligible || !target.recordId || target.recordVersion === undefined) {
|
throw new ElnSharedFillParamError(`${testWorkItemId} 当前不可批量填写`);
|
}
|
if (fields.some(({ field }) => !field.targetTestWorkItemIds.includes(testWorkItemId))) {
|
throw new ElnSharedFillParamError(`${testWorkItemId} 不包含全部选中字段`);
|
}
|
const requiresOverwrite = requiresTargetOverwrite(preview, testWorkItemId, options.selectedFieldIds, options.fieldValues);
|
const overwriteReason = options.overwriteReasons[testWorkItemId]?.trim();
|
if (requiresOverwrite && !overwriteReason) throw new ElnSharedFillParamError(`请填写 ${testWorkItemId} 的覆盖原因`);
|
return {
|
expectedRecordVersion: target.recordVersion,
|
overwrite: requiresOverwrite,
|
...(overwriteReason ? { overwriteReason } : {}),
|
recordId: target.recordId,
|
testWorkItemId,
|
};
|
});
|
return {
|
operationCode: options.operationCode,
|
previewToken: preview.previewToken,
|
targets,
|
testWorkItemIds: preview.targets.map((target) => target.testWorkItemId),
|
values: fields.map(({ field, value }) => ({ fieldVersionId: field.fieldVersionId, value })),
|
};
|
}
|
|
export function defaultTargetIds(preview: SharedFillPreview, selectedFieldIds: string[]) {
|
if (!selectedFieldIds.length) return [];
|
const fields = preview.fields.filter((field) => selectedFieldIds.includes(field.fieldVersionId));
|
return preview.targets
|
.filter(
|
(target) =>
|
target.eligible &&
|
fields.every(
|
(field) => field.targetTestWorkItemIds.includes(target.testWorkItemId) && !field.defaultExcludedTestWorkItemIds.includes(target.testWorkItemId),
|
),
|
)
|
.map((target) => target.testWorkItemId);
|
}
|