import type {
|
TemplateAnnotationContext,
|
TemplateBinding,
|
TemplateCancelForm,
|
TemplateChangeCheckboxGroupForm,
|
TemplateChangeCheckboxGroupRuleForm,
|
TemplateChangeCheck,
|
TemplateChangeConfirmForm,
|
TemplateOperationForm,
|
TemplatePrivateFieldForm,
|
TemplateRepairContext,
|
TemplateReserveCrossTemplateScalarBindingForm,
|
TemplateReserveBindingForm,
|
TemplateUpgradeCheckForm,
|
TemplateUpgradeConfirmForm,
|
TemplateVersionCopyConfirmForm,
|
} from '../domain/types';
|
import type {
|
FormulaBindingRequest,
|
FormulaBindingLockSnapshot,
|
FormulaMappingCheck,
|
FormulaMappingContext,
|
TemplateFormulaBinding,
|
} from '../domain/formula-mapping';
|
import type { CrossTemplateScalarCandidate, CrossTemplateSourceTemplate } from '../domain/types';
|
|
const ANNOTATION_PATH = '/api/eln/onlyoffice/templateAnnotation';
|
|
interface ActionResult<T> {
|
code: number;
|
data?: T;
|
msg: string;
|
}
|
|
export interface TemplateAnnotationApiContext {
|
apiBaseUrl: string;
|
signal?: AbortSignal;
|
ticket: string;
|
}
|
|
export interface TemplateAnnotationClient {
|
activateBinding: typeof activateBinding;
|
cancelBinding: typeof cancelBinding;
|
changeCheckboxGroup: typeof changeCheckboxGroup;
|
changeCheckboxGroupRule: typeof changeCheckboxGroupRule;
|
checkBindingRemoval: typeof checkBindingRemoval;
|
checkBindingVersionUpgrade: typeof checkBindingVersionUpgrade;
|
checkReferencePromotion: typeof checkReferencePromotion;
|
confirmBindingRemoval: typeof confirmBindingRemoval;
|
confirmBindingVersionUpgrade: typeof confirmBindingVersionUpgrade;
|
confirmReferencePromotion: typeof confirmReferencePromotion;
|
confirmRepair: typeof confirmRepair;
|
confirmVersionCopy: typeof confirmVersionCopy;
|
fetchAnnotationContext: typeof fetchAnnotationContext;
|
fetchCrossTemplateScalarCandidates: typeof fetchCrossTemplateScalarCandidates;
|
fetchCrossTemplateSourceTemplates: typeof fetchCrossTemplateSourceTemplates;
|
fetchRepairContext: typeof fetchRepairContext;
|
reservePrimaryBinding: typeof reservePrimaryBinding;
|
reserveCrossTemplateScalarBinding: typeof reserveCrossTemplateScalarBinding;
|
reservePrivateField: typeof reservePrivateField;
|
reserveReferenceBinding: typeof reserveReferenceBinding;
|
suggestCode: typeof suggestCode;
|
activateFormulaBinding: typeof activateFormulaBinding;
|
cancelFormulaBinding: typeof cancelFormulaBinding;
|
checkFormulaBindingRemoval: typeof checkFormulaBindingRemoval;
|
checkFormulaBindingUpgrade: typeof checkFormulaBindingUpgrade;
|
confirmFormulaBindingRemoval: typeof confirmFormulaBindingRemoval;
|
confirmFormulaBindingUpgrade: typeof confirmFormulaBindingUpgrade;
|
confirmFormulaVersionCopy: typeof confirmFormulaVersionCopy;
|
fetchFormulaMappings: typeof fetchFormulaMappings;
|
reserveFormulaBinding: typeof reserveFormulaBinding;
|
}
|
|
export class TemplateAnnotationApiError extends Error {
|
readonly status: number;
|
|
constructor(status: number, message: string) {
|
super(message);
|
this.name = 'TemplateAnnotationApiError';
|
this.status = status;
|
}
|
}
|
|
async function requestJson<T>(context: TemplateAnnotationApiContext, path: string, method: 'GET' | 'POST', body?: unknown): Promise<T> {
|
const headers: Record<string, string> = { Authorization: `Ticket ${context.ticket}` };
|
if (body !== undefined) headers['Content-Type'] = 'application/json';
|
const response = await fetch(`${context.apiBaseUrl.replace(/\/+$/u, '')}${ANNOTATION_PATH}${path}`, {
|
method,
|
headers,
|
body: body === undefined ? undefined : JSON.stringify(body),
|
signal: context.signal,
|
});
|
const payload = await readActionResult<T>(response);
|
|
if (!response.ok) {
|
throw new TemplateAnnotationApiError(response.status, payload?.msg || response.statusText || '标注请求失败');
|
}
|
if (!payload || typeof payload.code !== 'number' || typeof payload.msg !== 'string') {
|
throw new TemplateAnnotationApiError(response.status, '标注接口响应无效');
|
}
|
if (payload.code !== 200) {
|
throw new TemplateAnnotationApiError(payload.code, payload.msg);
|
}
|
|
return payload.data as T;
|
}
|
|
async function readActionResult<T>(response: Response): Promise<ActionResult<T> | null> {
|
try {
|
return (await response.json()) as ActionResult<T>;
|
} catch {
|
return null;
|
}
|
}
|
|
function bindingPath(bindingId: string, suffix: string): string {
|
return `/bindings/${encodeURIComponent(bindingId)}/${suffix}`;
|
}
|
|
function formulaBindingPath(bindingId: string, suffix: string): string {
|
return `/formulaBindings/${encodeURIComponent(bindingId)}/${suffix}`;
|
}
|
|
export function fetchAnnotationContext(context: TemplateAnnotationApiContext): Promise<TemplateAnnotationContext> {
|
return requestJson(context, '/context', 'GET');
|
}
|
|
export async function suggestCode(context: TemplateAnnotationApiContext, form: { text: string }): Promise<string> {
|
const result = await requestJson<{ code: string }>(context, '/codeSuggestions', 'POST', form);
|
if (!result || typeof result.code !== 'string' || !/^[a-z0-9_]{1,80}$/u.test(result.code)) {
|
throw new TemplateAnnotationApiError(200, '编码生成接口响应无效');
|
}
|
return result.code;
|
}
|
|
export function reservePrivateField(context: TemplateAnnotationApiContext, form: TemplatePrivateFieldForm): Promise<TemplateBinding> {
|
return requestJson(context, '/privateFields/reserve', 'POST', form);
|
}
|
|
export function reservePrimaryBinding(context: TemplateAnnotationApiContext, form: TemplateReserveBindingForm): Promise<TemplateBinding> {
|
return requestJson(context, '/bindings/reserve', 'POST', form);
|
}
|
|
export function changeCheckboxGroup(
|
context: TemplateAnnotationApiContext,
|
bindingId: string,
|
form: TemplateChangeCheckboxGroupForm,
|
): Promise<TemplateBinding> {
|
return requestJson(context, bindingPath(bindingId, 'checkboxGroup'), 'POST', form);
|
}
|
|
export function changeCheckboxGroupRule(
|
context: TemplateAnnotationApiContext,
|
groupCode: string,
|
form: TemplateChangeCheckboxGroupRuleForm,
|
): Promise<import('../domain/types').TemplateCheckboxGroup> {
|
return requestJson(context, `/checkboxGroups/${encodeURIComponent(groupCode)}`, 'POST', form);
|
}
|
|
export function fetchCrossTemplateSourceTemplates(context: TemplateAnnotationApiContext): Promise<CrossTemplateSourceTemplate[]> {
|
return requestJson(context, '/crossTemplateSourceTemplates', 'GET');
|
}
|
|
export function fetchCrossTemplateScalarCandidates(
|
context: TemplateAnnotationApiContext,
|
sourceTemplateId: string,
|
): Promise<CrossTemplateScalarCandidate[]> {
|
return requestJson(context, `/crossTemplateTextCandidates?sourceTemplateId=${encodeURIComponent(sourceTemplateId)}`, 'GET');
|
}
|
|
export function reserveCrossTemplateScalarBinding(
|
context: TemplateAnnotationApiContext,
|
form: TemplateReserveCrossTemplateScalarBindingForm,
|
): Promise<TemplateBinding> {
|
return requestJson(context, '/crossTemplateTextBindings/reserve', 'POST', form);
|
}
|
|
export function reserveReferenceBinding(context: TemplateAnnotationApiContext, bindingId: string, form: TemplateOperationForm): Promise<TemplateBinding> {
|
return requestJson(context, bindingPath(bindingId, 'references/reserve'), 'POST', form);
|
}
|
|
export function activateBinding(context: TemplateAnnotationApiContext, bindingId: string, form: TemplateOperationForm): Promise<void> {
|
return requestJson(context, bindingPath(bindingId, 'activate'), 'POST', form);
|
}
|
|
export function cancelBinding(context: TemplateAnnotationApiContext, bindingId: string, form: TemplateCancelForm): Promise<void> {
|
return requestJson(context, bindingPath(bindingId, 'cancel'), 'POST', form);
|
}
|
|
export function fetchRepairContext(context: TemplateAnnotationApiContext, bindingId: string): Promise<TemplateRepairContext> {
|
return requestJson(context, bindingPath(bindingId, 'repairContext'), 'GET');
|
}
|
|
export function confirmRepair(context: TemplateAnnotationApiContext, bindingId: string, form: TemplateChangeConfirmForm): Promise<void> {
|
return requestJson(context, bindingPath(bindingId, 'repairConfirm'), 'POST', form);
|
}
|
|
export function checkBindingVersionUpgrade(
|
context: TemplateAnnotationApiContext,
|
bindingId: string,
|
form: TemplateUpgradeCheckForm,
|
): Promise<TemplateChangeCheck> {
|
return requestJson(context, bindingPath(bindingId, 'versionUpgradeCheck'), 'POST', form);
|
}
|
|
export function confirmBindingVersionUpgrade(context: TemplateAnnotationApiContext, bindingId: string, form: TemplateUpgradeConfirmForm): Promise<void> {
|
return requestJson(context, bindingPath(bindingId, 'versionUpgradeConfirm'), 'POST', form);
|
}
|
|
export function checkBindingRemoval(context: TemplateAnnotationApiContext, bindingId: string): Promise<TemplateChangeCheck> {
|
return requestJson(context, bindingPath(bindingId, 'removeCheck'), 'POST');
|
}
|
|
export function confirmBindingRemoval(context: TemplateAnnotationApiContext, bindingId: string, form: TemplateChangeConfirmForm): Promise<void> {
|
return requestJson(context, bindingPath(bindingId, 'removeConfirm'), 'POST', form);
|
}
|
|
export function checkReferencePromotion(context: TemplateAnnotationApiContext, bindingId: string): Promise<TemplateChangeCheck> {
|
return requestJson(context, bindingPath(bindingId, 'promoteCheck'), 'POST');
|
}
|
|
export function confirmReferencePromotion(context: TemplateAnnotationApiContext, bindingId: string, form: TemplateChangeConfirmForm): Promise<void> {
|
return requestJson(context, bindingPath(bindingId, 'promoteConfirm'), 'POST', form);
|
}
|
|
export function confirmVersionCopy(context: TemplateAnnotationApiContext, form: TemplateVersionCopyConfirmForm): Promise<void> {
|
return requestJson(context, '/versionCopy/confirm', 'POST', form);
|
}
|
|
export function fetchFormulaMappings(context: TemplateAnnotationApiContext): Promise<FormulaMappingContext> {
|
return requestJson(context, '/formulaContext', 'GET');
|
}
|
|
export function reserveFormulaBinding(
|
context: TemplateAnnotationApiContext,
|
form: FormulaBindingRequest & { jieguoSuoKuaizhao: FormulaBindingLockSnapshot[] },
|
): Promise<TemplateFormulaBinding> {
|
return requestJson(context, '/formulaBindings/reserve', 'POST', form);
|
}
|
|
export function activateFormulaBinding(
|
context: TemplateAnnotationApiContext,
|
bindingId: string,
|
form: { controls: FormulaControlSnapshot[]; expectedVersion: number; operationCode: string },
|
): Promise<void> {
|
return requestJson(context, formulaBindingPath(bindingId, 'activate'), 'POST', form);
|
}
|
|
export function cancelFormulaBinding(
|
context: TemplateAnnotationApiContext,
|
bindingId: string,
|
form: { expectedVersion: number; operationCode: string; reason: string },
|
): Promise<void> {
|
return requestJson(context, formulaBindingPath(bindingId, 'cancel'), 'POST', form);
|
}
|
|
export function checkFormulaBindingUpgrade(
|
context: TemplateAnnotationApiContext,
|
bindingId: string,
|
form: { formulaVersionId: string; operationCode: string; parameterBindings: Record<string, string>; resultBindingId: string },
|
): Promise<FormulaMappingCheck> {
|
return requestJson(context, formulaBindingPath(bindingId, 'upgradeCheck'), 'POST', form);
|
}
|
|
export function confirmFormulaBindingUpgrade(
|
context: TemplateAnnotationApiContext,
|
bindingId: string,
|
form: { controls: FormulaControlSnapshot[]; expectedVersion: number; operationCode: string; target: FormulaBindingRequest },
|
): Promise<void> {
|
return requestJson(context, formulaBindingPath(bindingId, 'upgradeConfirm'), 'POST', form);
|
}
|
|
export function checkFormulaBindingRemoval(context: TemplateAnnotationApiContext, bindingId: string): Promise<FormulaMappingCheck> {
|
return requestJson(context, formulaBindingPath(bindingId, 'removeCheck'), 'POST');
|
}
|
|
export function confirmFormulaBindingRemoval(
|
context: TemplateAnnotationApiContext,
|
bindingId: string,
|
form: { controls: FormulaControlSnapshot[]; expectedVersion: number; operationCode: string },
|
): Promise<void> {
|
return requestJson(context, formulaBindingPath(bindingId, 'removeConfirm'), 'POST', form);
|
}
|
|
export function confirmFormulaVersionCopy(
|
context: TemplateAnnotationApiContext,
|
form: { controls: FormulaControlSnapshot[]; expectedVersions: Record<string, number>; upgradeOperationCode: string },
|
): Promise<void> {
|
return requestJson(context, '/formulaBindings/versionCopy/confirm', 'POST', form);
|
}
|
|
export interface FormulaControlSnapshot {
|
bindingId: string;
|
controlRole: string;
|
controlTag: string;
|
lock: string;
|
}
|
|
export const templateAnnotationClient: TemplateAnnotationClient = {
|
activateBinding,
|
cancelBinding,
|
changeCheckboxGroup,
|
changeCheckboxGroupRule,
|
checkBindingRemoval,
|
checkBindingVersionUpgrade,
|
checkReferencePromotion,
|
confirmBindingRemoval,
|
confirmBindingVersionUpgrade,
|
confirmReferencePromotion,
|
confirmRepair,
|
confirmVersionCopy,
|
fetchAnnotationContext,
|
fetchCrossTemplateScalarCandidates,
|
fetchCrossTemplateSourceTemplates,
|
fetchRepairContext,
|
reservePrimaryBinding,
|
reserveCrossTemplateScalarBinding,
|
reservePrivateField,
|
reserveReferenceBinding,
|
suggestCode,
|
activateFormulaBinding,
|
cancelFormulaBinding,
|
checkFormulaBindingRemoval,
|
checkFormulaBindingUpgrade,
|
confirmFormulaBindingRemoval,
|
confirmFormulaBindingUpgrade,
|
confirmFormulaVersionCopy,
|
fetchFormulaMappings,
|
reserveFormulaBinding,
|
};
|