a9a5fba92b
- ImageCanvasProjectAssetPickerDialog.tsx:打开时的重置 effect 只依赖 `open`,父级每次渲染重建 `selectedAssetIds` 不再清空进行中的搜索 / 筛选 / 选择 - ImageCanvasProjectAssetPickerDialog.tsx:素材卡媒体渲染抽成 `AssetCardMedia`,顺带去掉该处嵌套三元 - projectAssetReferencePickerModel.ts:`image-sequence` 单列一类(新增「序列帧」页签),不再混进「图片」——参考图链路只接受 `mediaType === 'image'`,混进去就是「按图片选中、按图片文案拒掉」;缩略图口径由 `projectAssetPickerUsesThumbnail` 收口 - 用例:父级重渲染不清空在选状态;序列帧分类归属与其被参考图链路过滤掉的事实
118 lines
4.4 KiB
TypeScript
118 lines
4.4 KiB
TypeScript
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;
|
||
}
|