mirror of
https://github.com/panatgithub/AnkiHeadingSync.git
synced 2026-07-22 06:51:43 +00:00
- 修复 QA Group model 管理的 AnkiConnect payload 契约,模板与样式更新改为嵌套 model payload - 修复 QA Group model 自检与更新链路,补充带 action/model 上下文的错误信息与回归测试 - 解耦 QA Group 与旧 semantic-qa mapping 路径,设置页移除保留 model 的旧映射入口并增加只读状态说明 - Fix the AnkiConnect payload contract for QA Group model management by using nested model payloads for template and styling updates - Repair the QA Group model ensure/update flow with action/model-aware errors and regression tests - Decouple QA Group from the legacy semantic-qa mapping path by removing the reserved model from old mapping controls and adding read-only status guidance
107 lines
No EOL
3.2 KiB
TypeScript
107 lines
No EOL
3.2 KiB
TypeScript
import type { AnkiGroupGateway } from "@/application/ports/AnkiGateway";
|
|
|
|
import { buildQaGroupModelDefinition } from "./QaGroupModelDefinition";
|
|
|
|
export class QaGroupModelService {
|
|
constructor(private readonly ankiGateway: AnkiGroupGateway) {}
|
|
|
|
async ensureModel(): Promise<void> {
|
|
const definition = buildQaGroupModelDefinition();
|
|
const modelNames = await this.runModelAction(
|
|
"listNoteModels",
|
|
definition.modelName,
|
|
undefined,
|
|
() => this.ankiGateway.listNoteModels(),
|
|
);
|
|
|
|
if (!modelNames.includes(definition.modelName)) {
|
|
await this.runModelAction(
|
|
"createModel",
|
|
definition.modelName,
|
|
`fields=${definition.fieldNames.length}, templates=${definition.templates.length}`,
|
|
() => this.ankiGateway.createModel(definition),
|
|
);
|
|
return;
|
|
}
|
|
|
|
const existingFieldNames = await this.runModelAction(
|
|
"getModelFieldNames",
|
|
definition.modelName,
|
|
undefined,
|
|
() => this.ankiGateway.getModelFieldNames(definition.modelName),
|
|
);
|
|
|
|
for (const fieldName of definition.fieldNames) {
|
|
if (existingFieldNames.includes(fieldName)) {
|
|
continue;
|
|
}
|
|
|
|
await this.runModelAction(
|
|
"addModelField",
|
|
definition.modelName,
|
|
`field=${fieldName}`,
|
|
() => this.ankiGateway.addModelField(definition.modelName, fieldName),
|
|
);
|
|
}
|
|
|
|
const existingTemplates = await this.runModelAction(
|
|
"getModelTemplates",
|
|
definition.modelName,
|
|
undefined,
|
|
() => this.ankiGateway.getModelTemplates(definition.modelName),
|
|
);
|
|
|
|
for (const template of definition.templates) {
|
|
const existingTemplate = existingTemplates[template.name];
|
|
if (!existingTemplate) {
|
|
await this.runModelAction(
|
|
"addModelTemplate",
|
|
definition.modelName,
|
|
`template=${template.name}`,
|
|
() => this.ankiGateway.addModelTemplate(definition.modelName, template),
|
|
);
|
|
continue;
|
|
}
|
|
|
|
if (existingTemplate.front !== template.front || existingTemplate.back !== template.back) {
|
|
await this.runModelAction(
|
|
"updateModelTemplate",
|
|
definition.modelName,
|
|
`template=${template.name}`,
|
|
() => this.ankiGateway.updateModelTemplate(definition.modelName, template),
|
|
);
|
|
}
|
|
}
|
|
|
|
const existingCss = await this.runModelAction(
|
|
"getModelStyling",
|
|
definition.modelName,
|
|
undefined,
|
|
() => this.ankiGateway.getModelStyling(definition.modelName),
|
|
);
|
|
|
|
if (existingCss !== definition.css) {
|
|
await this.runModelAction(
|
|
"updateModelStyling",
|
|
definition.modelName,
|
|
`cssLength=${definition.css.length}`,
|
|
() => this.ankiGateway.updateModelStyling(definition.modelName, definition.css),
|
|
);
|
|
}
|
|
}
|
|
|
|
private async runModelAction<T>(
|
|
action: string,
|
|
modelName: string,
|
|
summary: string | undefined,
|
|
operation: () => Promise<T>,
|
|
): Promise<T> {
|
|
try {
|
|
return await operation();
|
|
} catch (error) {
|
|
const details = summary ? ` (${summary})` : "";
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
throw new Error(`QA Group model sync failed during ${action} for "${modelName}"${details}: ${message}`);
|
|
}
|
|
}
|
|
} |