feat: 实现标签合并维护接口与n8n每日工作流

This commit is contained in:
2026-02-21 09:52:51 +08:00
parent 6cb4545a17
commit 220e9f8b71
12 changed files with 829 additions and 241 deletions
+63 -7
View File
@@ -269,23 +269,79 @@ export const TagUpdateSchema = z.object({
nameEn: z.string().min(1, "English name is required").max(100),
});
export const MergeTargetSchema = z.union([
z.object({ id: z.string().min(1) }),
z.object({
name: z.string().min(1).max(100),
nameEn: z.string().min(1).max(100),
}),
]);
const ExistingMergeTargetSchema = z.object({
id: z.string().min(1, "Target tag ID is required"),
name: z.string().min(1).max(100).optional(),
nameEn: z.string().min(1).max(100).optional(),
});
const NewMergeTargetSchema = z.object({
name: z.string().min(1, "Target name is required").max(100),
nameEn: z.string().min(1, "Target English name is required").max(100),
});
export const MergeTargetSchema = z.union([ExistingMergeTargetSchema, NewMergeTargetSchema]);
export const TagMergeSchema = z.object({
target: MergeTargetSchema,
sourceTagIds: z.array(z.string().min(1)).min(1, "At least one source tag required"),
}).superRefine((data, ctx) => {
const seenSourceIds = new Set<string>();
data.sourceTagIds.forEach((sourceTagId, index) => {
if (seenSourceIds.has(sourceTagId)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["sourceTagIds", index],
message: `Duplicate source tag ID: ${sourceTagId}`,
});
return;
}
seenSourceIds.add(sourceTagId);
});
if ("id" in data.target && seenSourceIds.has(data.target.id)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["sourceTagIds"],
message: "Self merge is not allowed: target tag cannot be in sourceTagIds",
});
}
});
export const TagMaintenanceRequestSchema = z.object({
apiKey: z.string().min(32, "Invalid API key format"),
updates: z.array(TagUpdateSchema).default([]),
merges: z.array(TagMergeSchema).default([]),
}).superRefine((data, ctx) => {
const seenUpdateTagIds = new Set<string>();
const seenMergeSourceTagIds = new Set<string>();
data.updates.forEach((update, index) => {
if (seenUpdateTagIds.has(update.tagId)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["updates", index, "tagId"],
message: `Duplicate update tag ID: ${update.tagId}`,
});
return;
}
seenUpdateTagIds.add(update.tagId);
});
data.merges.forEach((merge, mergeIndex) => {
merge.sourceTagIds.forEach((sourceTagId, sourceIndex) => {
if (seenMergeSourceTagIds.has(sourceTagId)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["merges", mergeIndex, "sourceTagIds", sourceIndex],
message: `Source tag ID appears in multiple merges: ${sourceTagId}`,
});
return;
}
seenMergeSourceTagIds.add(sourceTagId);
});
});
});
// ================================