1509235c1b
将 UI 编辑器第三步和内部流程 ID 统一为自动切分素材。 重命名前端切分概览模块并更新完成、恢复和导航文案。 同步 Runtime 最终编辑器路由、测试与相关技术文档。
134 lines
3.5 KiB
TypeScript
134 lines
3.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import {
|
|
getSeparationOverview,
|
|
nodeHasBlockedComponents,
|
|
nodeHasPendingSeparation,
|
|
nodeNeedsComponentReview,
|
|
} from '../src/features/ui-editor/separationOverview';
|
|
import { getNextMatchingUiTreeNodeTarget } from '../src/features/ui-editor/stageStatusOverview';
|
|
import type { Component } from '../src/features/ui-editor/types/Component';
|
|
import type { Node } from '../src/features/ui-editor/types/Node';
|
|
import type { SpriteAsset } from '../src/features/ui-editor/types/SpriteAsset';
|
|
import type { UITree } from '../src/features/ui-editor/types/UITree';
|
|
|
|
function image(targetGraphic: string | null): Component {
|
|
return {
|
|
Image: {
|
|
target_graphic: targetGraphic,
|
|
image_type: { Simple: { preserve_aspect: false } },
|
|
},
|
|
};
|
|
}
|
|
|
|
function text(font: 'SystemFont' | { Bound: string }): Component {
|
|
return {
|
|
Text: {
|
|
content: '文本',
|
|
font,
|
|
font_style: 'Normal',
|
|
font_sizing: { Fixed: 14 },
|
|
color: [255, 255, 255, 255],
|
|
alignment: 'UpperLeft',
|
|
horizontal_overflow: 'Wrap',
|
|
vertical_overflow: 'Truncate',
|
|
line_spacing: 1,
|
|
},
|
|
};
|
|
}
|
|
|
|
function node(
|
|
id: string,
|
|
component: Component | null,
|
|
componentStatus: Node['metadata']['component_status'] = 'NoProblem',
|
|
children: Node[] = [],
|
|
): Node {
|
|
return {
|
|
id,
|
|
layout: {
|
|
transform: {
|
|
anchor_min: [0, 0],
|
|
anchor_max: [1, 1],
|
|
offset_min: [0, 0],
|
|
offset_max: [0, 0],
|
|
},
|
|
custom_minimum_size: [0, 0],
|
|
size_flags_horizontal: 1,
|
|
size_flags_vertical: 1,
|
|
size_flags_stretch_ratio: 1,
|
|
container: 'None',
|
|
},
|
|
metadata: {
|
|
name: id,
|
|
description: '',
|
|
layout_status: 'NoProblem',
|
|
component_status: componentStatus,
|
|
allow_llm_edit_layout: true,
|
|
allow_llm_edit_component: true,
|
|
source: 'System',
|
|
},
|
|
component,
|
|
children,
|
|
};
|
|
}
|
|
|
|
function sprite(id: string): SpriteAsset {
|
|
return {
|
|
asset_id: id,
|
|
metadata: { name: id, asset_type: 'Normal' },
|
|
path: `${id}.png`,
|
|
pixel_size: [16, 16],
|
|
pixels_per_unit: 1,
|
|
border: { left: 0, right: 0, top: 0, bottom: 0 },
|
|
};
|
|
}
|
|
|
|
const sprites = {
|
|
validSprite: sprite('validSprite'),
|
|
unused: sprite('unused'),
|
|
};
|
|
const trees: UITree[] = [
|
|
{
|
|
src_ui_design: 'page-a',
|
|
root: node('root', image('validSprite'), 'NoProblem', [
|
|
node('review', image(null), { NeedReview: '确认素材' }),
|
|
node('blocked', text('SystemFont'), { Blocked: '素材绑定失败' }),
|
|
]),
|
|
},
|
|
];
|
|
|
|
describe('getSeparationOverview', () => {
|
|
it('uses per-component helpers to include both image and text slots', () => {
|
|
expect(getSeparationOverview(trees, sprites)).toEqual({
|
|
componentsNeedingAssets: 2,
|
|
assetSlots: 2,
|
|
boundSlots: 1,
|
|
pendingSlots: 1,
|
|
needsAttention: 2,
|
|
blocked: 1,
|
|
independentAssets: 2,
|
|
});
|
|
});
|
|
|
|
it('reuses the common preorder next-target search for every separation queue', () => {
|
|
expect(
|
|
getNextMatchingUiTreeNodeTarget(trees, null, (target) =>
|
|
nodeHasPendingSeparation(target),
|
|
)?.node.id,
|
|
).toBe('review');
|
|
expect(
|
|
getNextMatchingUiTreeNodeTarget(trees, 'review', (target) =>
|
|
nodeHasPendingSeparation(target),
|
|
)?.node.id,
|
|
).toBe('review');
|
|
expect(
|
|
getNextMatchingUiTreeNodeTarget(trees, null, nodeNeedsComponentReview)
|
|
?.node.id,
|
|
).toBe('review');
|
|
expect(
|
|
getNextMatchingUiTreeNodeTarget(trees, null, nodeHasBlockedComponents)
|
|
?.node.id,
|
|
).toBe('blocked');
|
|
});
|
|
});
|