feat(web-platform): release V0.8.1 常规地图优化
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled

This commit is contained in:
2026-09-03 13:18:35 +08:00
parent deead17a9a
commit a9b07e0abf
49 changed files with 4987 additions and 569 deletions
+118 -11
View File
@@ -11,6 +11,7 @@ const common = {
showMapCollision: false,
editorDocument: null,
onEditorPreview: () => {},
onEditorDraftChange: () => {},
onEditorApply: async () => true,
onEditorExport: () => {},
onEditorConvert: async () => true,
@@ -19,13 +20,42 @@ const common = {
onEditorTransformMode: () => {},
onEditorSnapping: () => {},
onMapDisplay: () => {},
onDraft: () => {},
};
describe('PhysicalMapPanel', () => {
it('无选中实例时显示引导空态', () => {
render(<PhysicalMapPanel {...common} value={{ kind: 'none' }} onApply={() => {}} />);
expect(screen.getByText('未选择地图实例')).toBeInTheDocument();
expect(screen.getByLabelText('地图来源')).toHaveValue('none');
});
it('已有场景草稿时无需再次改参数也可一次编译', () => {
const onApply = vi.fn();
render(
<PhysicalMapPanel
{...common}
value={{ kind: 'builtin', config: { ...DEFAULT_PHYSICAL_MAP_CONFIG, preset: 'rough' } }}
sceneDirty
onApply={onApply}
/>,
);
expect(screen.getByText(/场景草稿正在轻量预览/)).toBeInTheDocument();
const apply = screen.getByRole('button', { name: '应用并重新编译' });
expect(apply).toBeEnabled();
fireEvent.click(apply);
expect(onApply).toHaveBeenCalledTimes(1);
});
it('选择楼梯参数后请求重新编译', () => {
const onApply = vi.fn();
render(<PhysicalMapPanel {...common} value={{ kind: 'none' }} onApply={onApply} />);
fireEvent.change(screen.getByLabelText('地图来源'), { target: { value: 'builtin' } });
render(
<PhysicalMapPanel
{...common}
value={{ kind: 'builtin', config: { ...DEFAULT_PHYSICAL_MAP_CONFIG, preset: 'flat' } }}
onApply={onApply}
/>,
);
fireEvent.change(screen.getByLabelText('物理地图预设'), { target: { value: 'stairs' } });
fireEvent.change(screen.getByLabelText('台阶数量'), { target: { value: '6' } });
fireEvent.click(screen.getByRole('button', { name: '应用并重新编译' }));
@@ -37,8 +67,13 @@ describe('PhysicalMapPanel', () => {
it('在右侧参数面板调整系统地形并提交', () => {
const onApply = vi.fn();
render(<PhysicalMapPanel {...common} value={{ kind: 'none' }} onApply={onApply} />);
fireEvent.change(screen.getByLabelText('地图来源'), { target: { value: 'builtin' } });
render(
<PhysicalMapPanel
{...common}
value={{ kind: 'builtin', config: { ...DEFAULT_PHYSICAL_MAP_CONFIG, preset: 'flat' } }}
onApply={onApply}
/>,
);
fireEvent.change(screen.getByLabelText('物理地图预设'), { target: { value: 'rough' } });
fireEvent.change(screen.getByLabelText('地形难度(0–1)'), { target: { value: '0.8' } });
fireEvent.change(screen.getByLabelText('随机种子'), { target: { value: '9' } });
@@ -53,10 +88,73 @@ describe('PhysicalMapPanel', () => {
});
});
it('参数地形与认证资产共用视口变换界面', () => {
const onTransformMode = vi.fn();
const onSnapping = vi.fn();
render(
<PhysicalMapPanel
{...common}
value={{ kind: 'builtin', config: { ...DEFAULT_PHYSICAL_MAP_CONFIG, preset: 'rough' } }}
onEditorTransformMode={onTransformMode}
onEditorSnapping={onSnapping}
onApply={() => {}}
/>,
);
expect(screen.getByLabelText('视口选择与变换')).toBeInTheDocument();
expect(screen.getByText(/点击空白区域取消选择/)).toBeInTheDocument();
expect(screen.getByRole('button', { name: '缩放工具 S' })).toBeDisabled();
fireEvent.click(screen.getByRole('button', { name: '旋转工具 E' }));
expect(onTransformMode).toHaveBeenLastCalledWith('rotate');
fireEvent.click(screen.getByLabelText('地图编辑吸附'));
expect(onSnapping).toHaveBeenLastCalledWith(null, null);
});
it('表单参数与外部视口变换合并到同一份草稿', () => {
const onDraft = vi.fn();
const onApply = vi.fn();
const initial = {
kind: 'builtin' as const,
config: { ...DEFAULT_PHYSICAL_MAP_CONFIG, preset: 'rough' as const },
};
const view = render(
<PhysicalMapPanel
{...common}
value={initial}
sceneDirty
onDraft={onDraft}
onApply={onApply}
/>,
);
fireEvent.change(screen.getByLabelText('地形边长(m)'), { target: { value: '7' } });
const staged = onDraft.mock.calls.at(-1)?.[0];
expect(staged).toMatchObject({ kind: 'builtin', config: { size: 7 } });
const moved = {
...staged,
config: { ...staged.config, positionX: 2.4, positionY: -1.2 },
};
view.rerender(
<PhysicalMapPanel {...common} value={moved} sceneDirty onDraft={onDraft} onApply={onApply} />,
);
expect(screen.getByLabelText('地形边长(m)')).toHaveValue(7);
expect(screen.getByLabelText('位置 X(m)')).toHaveValue(2.4);
fireEvent.click(screen.getByRole('button', { name: '应用并重新编译' }));
expect(onApply).toHaveBeenLastCalledWith(
expect.objectContaining({
kind: 'builtin',
config: expect.objectContaining({ size: 7, positionX: 2.4, positionY: -1.2 }),
}),
);
});
it('可以移动并旋转资产地图', () => {
const onApply = vi.fn();
render(<PhysicalMapPanel {...common} value={{ kind: 'none' }} onApply={onApply} />);
fireEvent.change(screen.getByLabelText('地图来源'), { target: { value: 'builtin' } });
render(
<PhysicalMapPanel
{...common}
value={{ kind: 'builtin', config: { ...DEFAULT_PHYSICAL_MAP_CONFIG, preset: 'flat' } }}
onApply={onApply}
/>,
);
fireEvent.change(screen.getByLabelText('位置 X(m)'), { target: { value: '2.5' } });
fireEvent.change(screen.getByLabelText('位置 Y(m)'), { target: { value: '-1.5' } });
fireEvent.change(screen.getByLabelText('旋转 Z(°)'), { target: { value: '45' } });
@@ -67,12 +165,13 @@ describe('PhysicalMapPanel', () => {
});
});
it('显示工程地图、出生点和根 Body', () => {
it('显示工程地图、实例变换、出生点和根 Body', () => {
const onApply = vi.fn();
const onDraft = vi.fn();
render(
<PhysicalMapPanel
{...common}
value={{ kind: 'none' }}
value={{ kind: 'project', descriptorPath: 'maps/warehouse/map.json' }}
maps={[
{
descriptorPath: 'maps/warehouse/map.json',
@@ -83,12 +182,14 @@ describe('PhysicalMapPanel', () => {
},
]}
rootBodies={['robot', 'payload']}
onDraft={onDraft}
onApply={onApply}
/>,
);
fireEvent.change(screen.getByLabelText('地图来源'), {
target: { value: 'project:maps/warehouse/map.json' },
});
fireEvent.change(screen.getByLabelText('位置 X(m)'), { target: { value: '2.5' } });
fireEvent.change(screen.getByLabelText('位置 Y(m)'), { target: { value: '-1.5' } });
fireEvent.change(screen.getByLabelText('旋转 Z(°)'), { target: { value: '45' } });
fireEvent.change(screen.getByLabelText('地图出生点'), { target: { value: 'door' } });
expect(screen.getByLabelText('地图出生点')).toHaveValue('door');
fireEvent.change(screen.getByLabelText('机器人根 Body'), { target: { value: 'robot' } });
fireEvent.click(screen.getByRole('button', { name: '应用并重新编译' }));
@@ -96,10 +197,16 @@ describe('PhysicalMapPanel', () => {
expect.objectContaining({
kind: 'project',
descriptorPath: 'maps/warehouse/map.json',
positionX: 2.5,
positionY: -1.5,
yawDeg: 45,
spawnPointId: 'door',
robotRootBody: 'robot',
}),
);
expect(onDraft).toHaveBeenLastCalledWith(
expect.objectContaining({ kind: 'project', robotRootBody: 'robot' }),
);
});
it('原生 URDF 模式只允许移除地图', () => {