优化模型上传与预览体验

This commit is contained in:
zhangshun
2026-05-25 20:35:07 +08:00
parent a31c620420
commit efddf5adee
7 changed files with 878 additions and 79 deletions

View File

@@ -37,6 +37,9 @@ function buildFolderNodes(rows: FolderRow[], userInfo: { id: number; username: s
ownerUserId: row.owner_user_id,
isSystem: Boolean(row.is_system)
},
state: {
opened: row.library_type === "system" && row.parent_id === null
},
children: [] as unknown[]
}));
}
@@ -52,6 +55,9 @@ function buildTree(rows: FolderRow[], userInfo: { id: number; username: string;
permissions: { read: true, write: false },
virtual: true
},
state: {
opened: true
},
children: [] as unknown[]
};
const byId = new Map(nodes.map((node) => [Number(node.id), node]));

View File

@@ -41,6 +41,24 @@ function getProperties(modelId: number) {
return Object.fromEntries(rows.map((row) => [row.property_key, row.property_value]));
}
function getPropertiesMap(modelIds: number[]) {
const properties = new Map<number, Record<string, string>>();
if (modelIds.length === 0) return properties;
const placeholders = modelIds.map(() => "?").join(",");
const rows = db.prepare(`
SELECT model_id, property_key, property_value
FROM model_properties
WHERE model_id IN (${placeholders})
`).all(...modelIds) as { model_id: number; property_key: string; property_value: string }[];
for (const row of rows) {
const modelProperties = properties.get(row.model_id) ?? {};
modelProperties[row.property_key] = row.property_value;
properties.set(row.model_id, modelProperties);
}
return properties;
}
function saveProperties(modelId: number, properties: Record<string, string>) {
const stmt = db.prepare(`
INSERT INTO model_properties (model_id, property_key, property_value)
@@ -67,6 +85,22 @@ function modelPayload(row: ModelRow, userInfo?: { id: number; username: string;
};
}
function modelListPayload(
rows: ModelRow[],
userInfo?: { id: number; username: string; role: "admin" | "user" }
) {
const propertiesMap = getPropertiesMap(rows.map((row) => row.id));
return rows.map((row) => ({
...row,
file_url: publicObjectUrl(row.file_path, row.storage_provider),
thumbnail_url: row.thumbnail_path && row.thumbnail_provider
? publicObjectUrl(row.thumbnail_path, row.thumbnail_provider)
: null,
permissions: userInfo ? modelPermissions(userInfo, row) : { read: true, write: false },
properties: propertiesMap.get(row.id) ?? {}
}));
}
function dataImageToBuffer(dataUrl: string) {
const match = dataUrl.match(/^data:(image\/png|image\/jpeg|image\/webp);base64,(.+)$/);
if (!match) {
@@ -193,28 +227,32 @@ export async function modelRoutes(app: FastifyInstance) {
whereParts.push("m.type_id = ?");
params.push(query.typeId);
}
if (query.keyword?.trim()) {
const keyword = query.keyword?.trim() ?? "";
const hasKeyword = Boolean(keyword);
if (hasKeyword) {
whereParts.push("(m.name LIKE ? OR m.original_filename LIKE ? OR mp.property_value LIKE ?)");
const like = `%${query.keyword.trim()}%`;
const like = `%${keyword}%`;
params.push(like, like, like);
}
const where = whereParts.length > 0 ? `WHERE ${whereParts.join(" AND ")}` : "";
const propertyJoin = hasKeyword ? "LEFT JOIN model_properties mp ON mp.model_id = m.id" : "";
const distinct = hasKeyword ? "DISTINCT" : "";
const totalStmt = db.prepare(`
SELECT COUNT(DISTINCT m.id) as count
SELECT COUNT(${distinct} m.id) as count
FROM models m
LEFT JOIN model_properties mp ON mp.model_id = m.id
${propertyJoin}
${where}
`);
const total = totalStmt.get(...params) as { count: number };
const listStmt = db.prepare(`
SELECT DISTINCT
SELECT ${distinct}
m.*,
b.name AS brand_name,
t.name AS type_name
FROM models m
LEFT JOIN brands b ON b.id = m.brand_id
LEFT JOIN model_types t ON t.id = m.type_id
LEFT JOIN model_properties mp ON mp.model_id = m.id
${propertyJoin}
${where}
ORDER BY m.updated_at DESC, m.id DESC
LIMIT ? OFFSET ?
@@ -225,7 +263,7 @@ export async function modelRoutes(app: FastifyInstance) {
total: total.count,
page: query.page,
pageSize: query.pageSize,
items: rows.map((row) => modelPayload(row, request.userInfo))
items: modelListPayload(rows, request.userInfo)
};
});