显示图标规范输入字符计数
在一键优化与撤销操作行右侧实时显示 Unicode 字符数和 200 字符上限。 补充计数更新、emoji 截断和右对齐布局测试,并同步编辑器方案文档。
This commit is contained in:
@@ -40,7 +40,7 @@
|
||||
- 生成视频:`你希望生成什么视频?`
|
||||
8. 多输入框面板必须保留每个字段标题和输入框边界,例如生成规范。图标素材生成不再使用多描述列表,改为复用角色形象生成面板同款单文本输入框;该完整文本按 Unicode 字符限制为 `200`,输入时按 code point 截断,不能用 UTF-16 `maxLength` 误截 emoji。
|
||||
9. 生成规范下的角色规范、图标规范和自定义规范都使用同一生成类 shell:首行参考图区域、中央字段区、底部生成按钮区,不再出现缺首行参考区或单独 footer 样式。
|
||||
10. 图标规范只使用 `specType="icon"`,历史 `specType="ui"` 快照在恢复边界迁移为 `icon`。表单字段使用 `playSetting / artStyle`,界面标题继续使用「玩法设定 / 美术风格」。两项初始为空且必填;每项独立支持一键优化、处理中锁定自身、成功后单次撤销,手工编辑后立即清除该字段已经失效的撤销快照,失败只保留当前文本与仍然有效的旧撤销快照。LLM 返回空文本、超长文本或 Markdown / 结构化内容时,后续有界重试必须携带上次无效输出和对应修正要求,不能原样重放同一请求。优化请求必须绑定发起时的生成对象 ID 和请求代次;活动对象身份只在 React effect 提交后更新,并在 cleanup 中失效,丢弃的并发 render 不得改变请求归属;对象切换或新请求取代旧请求后,旧成功或失败结果都不得更新当前面板。任一项处理中或任一项为空时禁用生成。控件继续使用平台默认样式,不新增图标规范专属 CSS。
|
||||
10. 图标规范只使用 `specType="icon"`,历史 `specType="ui"` 快照在恢复边界迁移为 `icon`。表单字段使用 `playSetting / artStyle`,界面标题继续使用「玩法设定 / 美术风格」。两项初始为空且必填;每项独立支持一键优化、处理中锁定自身、成功后单次撤销,操作行最右侧按 Unicode 字符实时显示 `当前数/200`,手工编辑后立即清除该字段已经失效的撤销快照,失败只保留当前文本与仍然有效的旧撤销快照。LLM 返回空文本、超长文本或 Markdown / 结构化内容时,后续有界重试必须携带上次无效输出和对应修正要求,不能原样重放同一请求。优化请求必须绑定发起时的生成对象 ID 和请求代次;活动对象身份只在 React effect 提交后更新,并在 cleanup 中失效,丢弃的并发 render 不得改变请求归属;对象切换或新请求取代旧请求后,旧成功或失败结果都不得更新当前面板。任一项处理中或任一项为空时禁用生成。控件继续使用平台默认样式,不新增图标规范专属 CSS。
|
||||
11. 图标规范最终生成改走 `POST /api/editor/icon-specs/generations`。前端只提交业务字段和统一参考图 / 项目完成包络,不拼最终 prompt,不提交 `kind / assetKind / ExtraParam`;后端固定图片参数。HTTP handler 先调用可复用的图片请求预检,完成参考图稳定性、owner 授权、Provider 配置和运行时定价校验;全部通过后才调用文本 LLM 补齐 `ExtraParam` 和最终 prompt,再把完整图片请求交给既有 `editor_image_generation` inline / queue 分流。不得为图标规范新增独立外部任务类型;最终 worker 仍按执行时事实重新校验,避免排队期间状态变化产生 TOCTOU。
|
||||
12. 图片快速编辑不展示额外参考图入口;原图或绘制了红框和序号的标注图始终作为 `/api/editor/images/edits` 的 `sourceImageSrc` 直接提交,不作为 `referenceImageSrcs`。
|
||||
13. 快速编辑打开后,画布视口应调整到原图完整展示,且面板位于原图下方并不遮挡原图;原图右侧显示竖向框选工具,支持矩形、椭圆和画笔自由框选。快速编辑进入时不默认启用框选工具,点击工具后出现选中态并保持高亮,再点同一工具取消启用;红色圈选框使用细描边。每完成一次框选,红色圈选框按完成顺序标注 `1 / 2 / 3...`,并在快速编辑提示词中追加一行 `对N号红色圈选框里的内容做以下修改:`。
|
||||
|
||||
@@ -355,6 +355,15 @@ describe('ImageCanvasSpecGenerationPanelView', () => {
|
||||
'玩法设定',
|
||||
) as HTMLTextAreaElement;
|
||||
const artStyle = screen.getByLabelText('美术风格') as HTMLTextAreaElement;
|
||||
expect(screen.getByLabelText('玩法设定字符计数').textContent).toBe(
|
||||
'5/200',
|
||||
);
|
||||
expect(screen.getByLabelText('美术风格字符计数').textContent).toBe(
|
||||
'4/200',
|
||||
);
|
||||
expect(screen.getByLabelText('玩法设定字符计数').className).toContain(
|
||||
'ml-auto',
|
||||
);
|
||||
expect(playSetting.hasAttribute('maxlength')).toBe(false);
|
||||
expect(artStyle.hasAttribute('maxlength')).toBe(false);
|
||||
|
||||
@@ -362,6 +371,9 @@ describe('ImageCanvasSpecGenerationPanelView', () => {
|
||||
expect(Array.from(playSetting.value)).toHaveLength(200);
|
||||
fireEvent.change(playSetting, { target: { value: '🎮'.repeat(201) } });
|
||||
expect(Array.from(playSetting.value)).toHaveLength(200);
|
||||
expect(screen.getByLabelText('玩法设定字符计数').textContent).toBe(
|
||||
'200/200',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '提交生成规范' }));
|
||||
expect(onSubmit).toHaveBeenCalledTimes(1);
|
||||
|
||||
|
||||
@@ -554,6 +554,13 @@ export function ImageCanvasSpecGenerationPanelView({
|
||||
撤销
|
||||
</PlatformActionButton>
|
||||
) : null}
|
||||
<span
|
||||
className="ml-auto text-[10px] leading-4 tabular-nums text-slate-400"
|
||||
aria-label={`${item.title}字符计数`}
|
||||
>
|
||||
{getIconSpecPromptLength(value)}/
|
||||
{EDITOR_ICON_SPEC_PROMPT_MAX_LENGTH}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user