175 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { buildMaterialPrivacyWhere } from '@/lib/task-detail-privacy';
import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { prisma } from '@/lib/prisma';
import { normalizeMaterial } from '@/lib/utils';
import { rewriteMaterialStorageUrlsForClient } from '@/lib/url-rewrite';
// 解析 displayImages 字段
function parseDisplayImages(displayImages: any): string[] {
if (!displayImages) return [];
if (Array.isArray(displayImages)) {
return displayImages.filter(img => typeof img === 'string' && img.trim().length > 0);
}
if (typeof displayImages === 'string') {
try {
const parsed = JSON.parse(displayImages);
if (Array.isArray(parsed)) {
return parsed.filter(img => typeof img === 'string' && img.trim().length > 0);
}
} catch (e) {
console.warn('[user/materials] Failed to parse displayImages JSON, fallback to single value:', e);
}
return displayImages.trim() ? [displayImages] : [];
}
return [];
}
// GET - 获取当前用户上传的素材
export async function GET(request: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session?.user || !(session.user as any).id) {
return NextResponse.json({ error: '未登录' }, { status: 401 });
}
const userId = (session.user as any).id;
const materials = await prisma.material.findMany({
where: {
userId,
AND: [await buildMaterialPrivacyWhere(userId)],
deletedAt: null,
},
select: {
id: true,
userId: true,
productModel: true,
previewUrl: true,
displayImages: true,
materialType: true,
categoryName: true,
sceneName: true,
platformName: true,
productCategoryName: true,
renderer: true,
downloadCount: true,
likeCount: true,
createdAt: true,
videoSourceUrl: true,
videoPreview540Url: true,
videoPreviewClipUrl: true,
videoCoverUrl: true,
videoProcessingStatus: true,
videoDuration: true,
zipFileName: true,
zipFileSize: true,
} as any,
orderBy: {
createdAt: 'desc',
},
});
const formattedMaterials = materials.map((material: any) => {
const zipFileSize = typeof material.zipFileSize === 'bigint'
? material.zipFileSize.toString()
: material.zipFileSize ?? null;
const formatted = {
...material,
zipFileSize,
displayImages: parseDisplayImages(material.displayImages || null),
};
// 使用智能 URL 重写(根据用户网络位置选择内网或外网地址)
return rewriteMaterialStorageUrlsForClient(normalizeMaterial(formatted), request);
});
return NextResponse.json(formattedMaterials, { headers: { 'Cache-Control': 'private, no-store' } });
} catch (error: any) {
// 兼容旧版本数据库(没有deletedAt字段)
if (error?.meta?.column?.includes('deletedAt')) {
try {
const session = await getServerSession(authOptions);
if (!session?.user || !(session.user as any).id) {
return NextResponse.json({ error: '未登录' }, { status: 401 });
}
const userId = (session.user as any).id;
const materials = await prisma.material.findMany({
where: {
userId,
AND: [await buildMaterialPrivacyWhere(userId)],
},
select: {
id: true,
userId: true,
productModel: true,
previewUrl: true,
displayImages: true,
materialType: true,
categoryName: true,
sceneName: true,
platformName: true,
productCategoryName: true,
renderer: true,
downloadCount: true,
likeCount: true,
createdAt: true,
videoSourceUrl: true,
videoPreview540Url: true,
videoPreviewClipUrl: true,
videoCoverUrl: true,
videoProcessingStatus: true,
videoDuration: true,
zipFileName: true,
zipFileSize: true,
} as any,
orderBy: {
createdAt: 'desc',
},
});
const formattedMaterials = materials.map((material: any) => {
const zipFileSize = typeof material.zipFileSize === 'bigint'
? material.zipFileSize.toString()
: material.zipFileSize ?? null;
const formatted = {
...material,
zipFileSize,
displayImages: Array.isArray(material.displayImages)
? material.displayImages
: material.displayImages
? [material.displayImages]
: [],
};
return normalizeMaterial(formatted);
});
return NextResponse.json(formattedMaterials, { headers: { 'Cache-Control': 'private, no-store' } });
} catch (fallbackError) {
console.error('[UserMaterials] Fallback query error:', fallbackError);
return NextResponse.json(
{ error: '获取素材列表失败' },
{ status: 500 }
);
}
}
console.error('[UserMaterials] GET error:', error);
return NextResponse.json(
{ error: '获取素材列表失败' },
{ status: 500 }
);
}
}