Files
Genarrative/src/components/image-editor/projectAssetReferencePickerModel.ts
T
suzmii a9a5fba92b 修复 PR #316 review(前端 TS/TSX):图片编辑器素材弹窗
- ImageCanvasProjectAssetPickerDialog.tsx:打开时的重置 effect 只依赖 `open`,父级每次渲染重建 `selectedAssetIds` 不再清空进行中的搜索 / 筛选 / 选择
- ImageCanvasProjectAssetPickerDialog.tsx:素材卡媒体渲染抽成 `AssetCardMedia`,顺带去掉该处嵌套三元
- projectAssetReferencePickerModel.ts:`image-sequence` 单列一类(新增「序列帧」页签),不再混进「图片」——参考图链路只接受 `mediaType === 'image'`,混进去就是「按图片选中、按图片文案拒掉」;缩略图口径由 `projectAssetPickerUsesThumbnail` 收口
- 用例:父级重渲染不清空在选状态;序列帧分类归属与其被参考图链路过滤掉的事实
2026-09-12 20:49:37 +08:00

118 lines
4.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 type { PlatformResourceFilterOption } from '../../../packages/shared/src/components/PlatformResourceFilterBar';
import {
type CharacterReferenceImage,
type EditorAsset,
} from './ImageCanvasEditorTypes';
/**
* 参考图弹窗的分类口径:只按素材的媒体类型分组,与画布的「功能分类」各自独立
* (画布用 manifest `category`,这里是编辑器素材库自己的可读分类)。
*
* `image-sequence` 单列一类,不并进「图片」:序列帧是逐帧动画资产,不是静态图片,
* 而参考图链路(`appendLimitedImageReferences`)只接受 `mediaType === 'image'`。
* 混进「图片」会变成「按图片选中、按图片的文案拒掉」——用户看到的分类与它为什么被拒
* 互相矛盾。单列之后行为与音频 / 视频一致:看得见、选得中、给了明确提示。
*/
export type ProjectAssetPickerMediaCategory =
| 'image'
| 'video'
| 'audio'
| 'image-sequence';
export type ProjectAssetPickerCategory =
| 'all'
| ProjectAssetPickerMediaCategory;
export const PROJECT_ASSET_PICKER_CATEGORY_OPTIONS: readonly PlatformResourceFilterOption<ProjectAssetPickerCategory>[] =
[
{ id: 'all', label: '全部' },
{ id: 'image', label: '图片' },
{ id: 'video', label: '视频' },
{ id: 'audio', label: '音频' },
{ id: 'image-sequence', label: '序列帧' },
];
export function projectAssetPickerCategory(
asset: Pick<EditorAsset, 'mediaType'>,
): ProjectAssetPickerMediaCategory {
const mediaType = asset.mediaType ?? 'image';
if (mediaType === 'video') return 'video';
if (mediaType === 'audio') return 'audio';
if (mediaType === 'image-sequence') return 'image-sequence';
return 'image';
}
/**
* 卡片缩略图能不能直接画:图片与序列帧的 `src` 都是图片字节
* (序列帧是首帧 / 当前帧),其它媒体类型退回类型图标。
*
* 这条只决定「怎么画」,不决定「能不能当参考图」——后者由参考图链路按
* `mediaType === 'image'` 收口。
*/
export function projectAssetPickerUsesThumbnail(
category: ProjectAssetPickerMediaCategory,
): boolean {
return category === 'image' || category === 'image-sequence';
}
/**
* 弹窗筛选判据:分类 + 搜索词,两者叠加。
* 与资源画布、`@` 面板的筛选状态无关,调用方各自持有输入值。
*/
export function projectAssetMatchesPickerFilter(
asset: EditorAsset,
{ category, query }: { category: ProjectAssetPickerCategory; query: string },
): boolean {
if (category !== 'all' && projectAssetPickerCategory(asset) !== category) {
return false;
}
const normalizedQuery = query.trim().toLowerCase();
if (!normalizedQuery) return true;
return [asset.label, asset.assetKind ?? ''].some((value) =>
value.toLowerCase().includes(normalizedQuery),
);
}
/**
* 从项目素材弹窗加进参考图列表的引用 id 前缀。
* 用于在确认时整组替换,避免画布点选 / 上传来的参考图被一并清掉。
*/
export const PROJECT_ASSET_REFERENCE_ID_PREFIX = 'project-asset-';
export function isProjectAssetPickerReference(reference: {
id: string;
}): boolean {
return reference.id.startsWith(PROJECT_ASSET_REFERENCE_ID_PREFIX);
}
/**
* 把弹窗里选中的素材转成参考图。`sourceAssetId` 用素材自身 id
* 因此提交时 `createGenerationInputReference` 会按 `asset` 记下这份 ID 快照,
* 源素材后续变化不影响已提交任务。
*/
export function projectAssetPickerReferences(
assets: readonly EditorAsset[],
selectedAssetIds: readonly string[],
): CharacterReferenceImage[] {
if (selectedAssetIds.length === 0) return [];
const assetById = new Map(assets.map((asset) => [asset.id, asset]));
const references: CharacterReferenceImage[] = [];
const seen = new Set<string>();
for (const assetId of selectedAssetIds) {
const asset = assetById.get(assetId);
if (!asset || seen.has(asset.id)) continue;
seen.add(asset.id);
references.push({
id: `${PROJECT_ASSET_REFERENCE_ID_PREFIX}${asset.id}`,
label: asset.label,
src: asset.objectKey?.trim() || asset.src,
mediaType: asset.mediaType ?? 'image',
...(asset.objectKey ? { objectKey: asset.objectKey } : {}),
...(asset.assetObjectId ? { assetObjectId: asset.assetObjectId } : {}),
resourceId: asset.sourceResourceId ?? null,
sourceAssetId: asset.id,
});
}
return references;
}