103 lines
3.4 KiB
TypeScript
103 lines
3.4 KiB
TypeScript
import express from "express";
|
|
import u from "@/utils";
|
|
import { error, success } from "@/lib/responseFormat";
|
|
import fs from "fs";
|
|
import path from "path";
|
|
import { validateFields } from "@/middleware/middleware";
|
|
import { z } from "zod";
|
|
const router = express.Router();
|
|
|
|
// 编辑视觉手册
|
|
export default router.post(
|
|
"/",
|
|
validateFields({
|
|
name: z.string(),
|
|
images: z.array(z.string()),
|
|
data: z.array(
|
|
z.object({
|
|
label: z.string(),
|
|
value: z.string(),
|
|
data: z.string(),
|
|
}),
|
|
),
|
|
}),
|
|
async (req, res) => {
|
|
try {
|
|
const { name, images, data } = req.body as {
|
|
name: string;
|
|
images: string[];
|
|
data: { label: string; value: string; data: string }[];
|
|
};
|
|
|
|
if (/^\d+$/.test(name)) {
|
|
res.status(400).send(error("名称不能为纯数字"));
|
|
return;
|
|
}
|
|
|
|
const mainPath = u.getPath(["skills", "art_prompts", name]);
|
|
if (!fs.existsSync(mainPath)) {
|
|
return res.status(400).send(error("视觉手册不存在"));
|
|
}
|
|
// 字段映射表(与 getVisualManual 保持一致)
|
|
const DATA_MAP: { value: string; subDir?: string }[] = [
|
|
{ value: "README" },
|
|
{ value: "prefix" },
|
|
{ value: "art_character", subDir: "art_prompt" },
|
|
{ value: "art_character_derivative", subDir: "art_prompt" },
|
|
{ value: "art_prop", subDir: "art_prompt" },
|
|
{ value: "art_prop_derivative", subDir: "art_prompt" },
|
|
{ value: "art_scene", subDir: "art_prompt" },
|
|
{ value: "art_scene_derivative", subDir: "art_prompt" },
|
|
{ value: "art_storyboard", subDir: "art_prompt" },
|
|
{ value: "art_storyboard_video", subDir: "art_prompt" },
|
|
{ value: "director_planning", subDir: "driector_skills" },
|
|
{ value: "director_storyboard_table", subDir: "driector_skills" },
|
|
];
|
|
|
|
// 根据 DATA_MAP 构建 value -> subDir 的映射
|
|
const SUB_DIR_MAP = new Map(DATA_MAP.map(({ value, subDir }) => [value, subDir ?? ""]));
|
|
|
|
// 合法的 value 值集合,用于校验
|
|
const VALID_KEYS = new Set(DATA_MAP.map(({ value }) => value));
|
|
|
|
for (const item of data) {
|
|
if (!VALID_KEYS.has(item.value)) continue;
|
|
|
|
const subDir = SUB_DIR_MAP.get(item.value)!;
|
|
const dirArr = subDir ? [mainPath, subDir] : [mainPath];
|
|
const filePath = u.getPath([...dirArr, `${item.value}.md`]);
|
|
|
|
const fileDir = path.dirname(filePath);
|
|
// 目录不存在时递归创建
|
|
if (!fs.existsSync(fileDir)) {
|
|
fs.mkdirSync(fileDir, { recursive: true });
|
|
}
|
|
fs.writeFileSync(filePath, item.data, "utf-8");
|
|
}
|
|
const ossImagesDir = u.getPath(["oss", name]);
|
|
|
|
let existingFiles: string[] = [];
|
|
try {
|
|
const allFiles = fs.readdirSync(ossImagesDir);
|
|
existingFiles = allFiles.filter((f) => /\.(png|jpe?g|gif|webp|svg)$/i.test(f));
|
|
} catch {}
|
|
|
|
const retainedFileNames = new Set(images.filter((item) => item.startsWith("http")).map((url) => path.basename(new URL(url).pathname)));
|
|
|
|
for (const file of existingFiles) {
|
|
if (!retainedFileNames.has(file)) {
|
|
await u.oss.deleteFile(`${name}/${file}`);
|
|
}
|
|
}
|
|
|
|
for (const item of images) {
|
|
if (!item.startsWith("http")) await u.oss.writeFile(`${name}/${u.uuid()}.jpg`, item);
|
|
}
|
|
|
|
res.status(200).send(success());
|
|
} catch (err) {
|
|
res.status(500).send({ error: String(err) });
|
|
}
|
|
},
|
|
);
|