3D 开关互斥:打开分件就关掉四边面 / 智能减面,反之亦然

- `applyModel3dSwitchChange` 不再原样套用改动:收到「生成部件 = 开」时清掉四边面与智能减面,收到任一几何模式打开时清掉生成部件;让刚刚打开的那个赢,面板上不留提交前校验必然拒绝的组合
- 只关掉某个开关时不动其它开关(关分件不该顺带清空几何模式)
- 用例:两个方向的互斥各一例 + 只关一个开关不动其它
This commit is contained in:
2026-09-24 21:12:43 +08:00
parent 8e169e17b8
commit 2204df139c
2 changed files with 61 additions and 1 deletions
@@ -577,6 +577,48 @@ describe('3D 生成面板的参数变更', () => {
).not.toBe(failedDialog.model3dAttemptNonce);
});
it('分件与四边面 / 智能减面互斥:后打开的赢,先打开的自动关掉', () => {
const geometryDialog = createDialog({
model3dTier: 'geometry-only',
model3dGenerateParts: true,
});
const quad = applyModel3dSwitchChange(geometryDialog, {
model3dQuad: true,
});
expect(quad).toMatchObject({
model3dQuad: true,
model3dGenerateParts: false,
});
const smartLowPoly = applyModel3dSwitchChange(
{ ...geometryDialog, model3dGenerateParts: false },
{ model3dSmartLowPoly: true },
);
expect(smartLowPoly.model3dQuad).toBe(false);
const parts = applyModel3dSwitchChange(
{ ...geometryDialog, model3dQuad: true, model3dSmartLowPoly: true },
{ model3dGenerateParts: true },
);
expect(parts).toMatchObject({
model3dGenerateParts: true,
model3dQuad: false,
model3dSmartLowPoly: false,
});
});
it('只关掉一个开关时不动其它开关', () => {
const dialog = createDialog({
model3dTier: 'geometry-only',
model3dQuad: true,
});
expect(
applyModel3dSwitchChange(dialog, { model3dGenerateParts: false }),
).toMatchObject({ model3dQuad: true, model3dGenerateParts: false });
});
it('删掉参考图回到空槽位并清掉失败态', () => {
const dialog = createDialog({
mode: 'model3d-image-to-model',
@@ -447,6 +447,13 @@ export function applyModel3dModelChange(
});
}
/**
* 改开关:换代次、清失败态,并把互斥项一起收干净。
*
* 「生成部件」与「四边面」/「智能减面」不能同时打开(提交前校验会直接拒绝,见
* `Model3dGenerationValidation`)。这里让刚刚打开的那个赢、另一个自动关掉:面板上不留
* 一个永远提交不了的组合,也不用用户自己去猜该关哪一个(评审 #86)。
*/
export function applyModel3dSwitchChange(
dialog: GenerateDialogState,
patch: Partial<
@@ -456,7 +463,18 @@ export function applyModel3dSwitchChange(
>
>,
): GenerateDialogState {
return withNewAttemptNonce({ ...resetFailedStatus(dialog), ...patch });
const next = { ...resetFailedStatus(dialog), ...patch };
if (patch.model3dGenerateParts === true) {
return withNewAttemptNonce({
...next,
model3dQuad: false,
model3dSmartLowPoly: false,
});
}
if (patch.model3dQuad === true || patch.model3dSmartLowPoly === true) {
return withNewAttemptNonce({ ...next, model3dGenerateParts: false });
}
return withNewAttemptNonce(next);
}
export function applyModel3dPromptChange(