鸿蒙智能体开发实战:39.鸿蒙壁纸大师 - 前端卡片显示与交互优化 引言在前端展示层面鸿蒙壁纸大师充分利用了鸿蒙 A2A 协议的卡片能力通过DisplayFaCard实现丰富的交互式 UI而非简单的文本对话。整个壁纸创作流程中用户看到的是可点击的选择列表、生动的进度提示和精美的壁纸展示卡片。本文将深入解析前端的卡片交互设计涵盖selectList选择卡片、wallpaper展示卡片、SSE 事件驱动的前端更新以及内容安全策略。上图展示了鸿蒙壁纸大师中的两种核心卡片类型selectList 选择卡片和 wallpaper 壁纸展示卡片以及它们在交互流程中的切换关系一、卡片体系总览1.1 三种卡片类型鸿蒙壁纸大师使用了三种卡片类型卡片类型用途展示阶段selectList交互式选择列表风格选择、主题选择、场景选择wallpaper壁纸结果展示壁纸生成完成text文本消息闲聊、进度提示核心概念DisplayFaCard是鸿蒙 A2A 协议中卡片展示的统一入口通过cardName字段区分不同卡片类型前端根据cardName渲染对应的 UI 组件。1.2 卡片 JSON 结构规范所有卡片都通过 A2A 协议的artifact-update事件的parts字段传递{jsonrpc:2.0,id:request_id,result:{taskId:task_id,kind:artifact-update,append:false,lastChunk:true,final:true,artifact:{artifactId:task_id-options,parts:[{kind:data,data:{cardsInfo:[{cardName:selectList,cardData:{...},displayType:DisplayFaCard}]}}]}},error:{code:0,message:success}}二、selectList 选择卡片2.1 卡片构建函数# agent_routes.pydefbuild_style_options_card(title:str,options:List[str],task_id:str,request_id:str,has_next_batch:boolTrue,can_replay:boolTrue,)-dict:构建风格/主题选项的卡片 SSE 事件items[{text:opt,value:opt}foroptinoptions]return{jsonrpc:2.0,id:request_id,result:{taskId:task_id,kind:artifact-update,append:False,lastChunk:True,final:True,artifact:{artifactId:f{task_id}-options,parts:[{kind:data,data:{cardsInfo:[{cardName:selectList,cardData:{title:title,items:items,canReplay:can_replay,},displayType:DisplayFaCard}]}}]}},error:{code:0,message:success}}2.2 三级选择流程的卡片展示第一级风格选择{cardName:selectList,cardData:{title:你可以从下面挑选喜欢的风格也可以直接告诉我你想要的其他风格。,items:[{text:极简主义,value:极简主义},{text:弥散风,value:弥散风},{text:水墨国风,value:水墨国风},{text:莫兰迪风,value:莫兰迪风}],canReplay:true}}第二级主题选择{cardName:selectList,cardData:{title:选一个喜欢的主题打造你的专属壁纸。,items:[{text:青峦远山,value:青峦远山},{text:寒梅疏枝,value:寒梅疏枝},{text:江上孤舟,value:江上孤舟},{text:竹林清风,value:竹林清风}],canReplay:true}}第三级场景选择{cardName:selectList,cardData:{title:最后选择你的壁纸尺寸和使用场景。,items:[{text:竖屏 · 锁屏,value:竖屏 · 锁屏},{text:竖屏 · 主屏,value:竖屏 · 主屏},{text:横屏 · 锁屏,value:横屏 · 锁屏},{text:横屏 · 主屏,value:横屏 · 主屏}],canReplay:false}}2.3 卡片交互的用户体验阶段卡片标题选项数支持换一批支持重选选择风格引导选择风格4✅✅选择主题引导选择主题4✅✅选择场景引导选择场景4❌❌交互流程用户看到 selectList 卡片 ↓ 点击某个选项如水墨国风 ↓ 前端将选项文本作为用户消息发送 ↓ 服务端识别关键词跳过 LLM 意图识别 ↓ 构建下一级 selectList 卡片并推送 ↓ 前端自动刷新卡片2.4 快捷命令与卡片的联动当用户输入换一批时服务端重新生成当前级别的选项并重新推送卡片# agent_routes.py - 换一批处理if换一批inuser_text:ifflow_manager.current_stepFlowStep.SELECT_STYLE:flow_resultflow_manager.handle_style_batch_refresh()elifflow_manager.current_stepFlowStep.SELECT_THEME:flow_resultawaitflow_manager.handle_theme_batch_refresh()# 重新构建并推送 selectList 卡片batch_eventbuild_style_options_card(titleflow_result[guidance],optionsflow_result[options],# 新的随机选项task_idtask_id,request_idrequest_id,has_next_batchTrue,can_replayTrue,)yieldfdata:{json.dumps(batch_event,ensure_asciiFalse)}\n\n三、wallpaper 展示卡片3.1 壁纸结果卡片壁纸生成完成后服务端推送wallpaper卡片展示结果# services/wallpaper_service.py# 步骤 5: 发送完成状态卡片格式text_event{jsonrpc:2.0,id:task_id,result:{taskId:task_id,kind:artifact-update,append:False,lastChunk:True,final:True,artifact:{artifactId:f{task_id}-complete,parts:[{kind:data,data:{cardsInfo:[{cardName:wallpaper,cardData:{title:壁纸生成完成,imageUrl:image_url,},displayType:DisplayFaCard}]}}]}},error:{code:0,message:success}}3.2 壁纸卡片的呈现生成的 JSON 使前端呈现类似以下效果┌─────────────────────────┐ │ ✨ 壁纸生成完成 │ │ │ │ ┌───────────────┐ │ │ │ │ │ │ │ 壁纸图片 │ │ │ │ │ │ │ └───────────────┘ │ │ │ │ 风格水墨国风 │ │ 主题青峦远山 │ │ │ │ [换一张] [重新开始] │ └─────────────────────────┘3.3 与流程管理器的状态同步# wallpaper_flow_service.pydefhandle_generate_complete(self,image_urls:List[str])-Dict[str,Any]:处理生成完成self.current_stepFlowStep.RESULT# 记录生成的壁纸forurlinimage_urls:self.generated_wallpapers.append({url:url,style:self.selected_style,theme:self.selected_theme,})# 扣除免费次数ifself.free_credits_remaining0:self.free_credits_remaining-1return{step:result,message:你的专属艺术壁纸已生成完成,wallpapers:[{url:url,style:self.selected_style,theme:self.selected_theme}forurlinimage_urls],credits_remaining:self.free_credits_remaining,has_regenerate:self.free_credits_remaining0,}四、SSE 事件驱动的前端更新4.1 完整事件序列从前端视角看一次完整的壁纸生成过程如下前端发送 message/stream 请求 ↓后端返回 SSE 流 事件1: status-update → state: submitted → 正在理解您的需求... 事件2: status-update → state: working → 正在优化描述... 事件3: status-update → state: working → 正在生成图片... 事件4: status-update → state: working → 正在构思画面构图... 事件5: status-update → state: working → 正在勾勒轮廓... ... 事件N: artifact-update → final: true → wallpaper 卡片4.2 前端处理逻辑示意// 前端 SSE 事件处理示意代码consteventSourcenewEventSource(/agent/message);eventSource.onmessage(event){constdataJSON.parse(event.data);constresultdata.result;switch(result.kind){casestatus-update:// 更新进度状态updateProgress(result.status.message.parts[0].text);break;caseartifact-update:// 处理最终产物constcardsInforesult.artifact.parts[0].data.cardsInfo;cardsInfo.forEach(card{switch(card.cardName){caseselectList:renderSelectListCard(card.cardData);break;casewallpaper:renderWallpaperCard(card.cardData);break;}});break;}};4.3 卡片替换逻辑每次推送新的selectList卡片时前端需要替换上一张卡片append: false替换上一张卡片风格→主题→场景的步骤推进append: true追加到已有内容闲聊的逐 token 输出风格选择卡片 (append: false) ↓ 用户选择风格 主题选择卡片 (append: false) → 替换风格卡片 ↓ 用户选择主题 场景选择卡片 (append: false) → 替换主题卡片 ↓ 用户选择场景 进度文本 (append: false) ↓ 逐条追加 进度文本 (append: true) ... ↓ 壁纸卡片 (append: false) → 替换所有内容五、内容安全策略5.1 肖像检测# wallpaper_flow_service.pydefcheck_content_policy(user_text:str)-Tuple[bool,Optional[str]]:检查内容是否符合规范肖像、文字等限制# 肖像检测关键词portrait_keywords[我,自己,本人,照片,肖像,人脸,头像,明星,网红,模特,人物,人像,自拍,]# 文字/水印检测关键词text_keywords[文字,字体,写字,名字,姓名,签名,水印,logo,LOGO,标志,品牌,]# 检测肖像请求forkeywordinportrait_keywords:ifkeywordinuser_text:ifany(phraseinuser_textforphrasein[像我,我的照片,加入,添加,包含]):returnFalse,抱歉呀为了版权和隐私安全我暂时不能生成包含人物肖像的壁纸哦# 检测文字/水印请求forkeywordintext_keywords:ifkeywordinuser_text:ifany(phraseinuser_textforphrasein[添加,写上,显示,包含,要有]):returnFalse,抱歉目前暂时无法在壁纸上添加文字、水印或 LOGOreturnTrue,None5.2 无关话题检测# wallpaper_flow_service.pydefis_irrelevant_topic(user_text:str)-bool:判断是否是无关话题闲聊、知识问答等# 壁纸相关关键词wallpaper_keywords[壁纸,背景,桌面,风格,主题,画面,图片,生成,创作,设计,图案,色彩,色调,锁屏,主屏,横屏,竖屏,尺寸,分辨率,]# 检查是否包含壁纸相关关键词forkeywordinwallpaper_keywords:ifkeywordinuser_text:returnFalse# 常见的无关问题类型irrelevant_patterns[你是谁,你能做什么,天气,新闻,股票,帮我,写代码,翻译,计算,]forpatterninirrelevant_patterns:ifpatterninuser_text:returnTruereturnFalsedefget_irrelevant_response()-str:获取无关问题的统一回应return我是你的专属壁纸创作助手只专注于为你生成精美鸿蒙壁纸哦我们继续设计你的专属壁纸吧5.3 安全策略在流程中的位置# agent_routes.py - generate_sse() 中的安全检查# 1. 内容政策检查肖像、文字等policy_passed,policy_reject_reasoncheck_content_policy(user_text)ifnotpolicy_passed:# 返回拒绝卡片reject_event{...text:policy_reject_reason}yieldfdata:{json.dumps(reject_event)}\n\nreturn# 2. 无关话题检查闲聊、知识问答等ifis_irrelevant_topic(user_text):# 引导回壁纸主题irrelevant_event{...text:get_irrelevant_response()}yieldfdata:{json.dumps(irrelevant_event)}\n\nreturn# 3. 通过检查后继续处理正常流程5.4 内容安全的交互设计安全策略被触发时用户看到的是友好的引导信息而非冷冰冰的错误提示违规类型用户输入示例系统回复肖像请求“加入我的照片”“为了版权和隐私安全不能生成包含人物肖像的壁纸哦”文字请求“写上’我爱你’”“暂时无法在壁纸上添加文字、水印或 LOGO”无关话题“帮我写代码”“只专注于为你生成精美鸿蒙壁纸哦”安全设计原则内容安全策略应始终返回友好的引导信息而非冷冰冰的错误码让用户感受到智能体的温度。同时所有安全检查必须在进入主流程之前完成避免浪费 API 调用资源。六、卡片的扩展设计6.1 卡片数据的可扩展性当前cardData结构预留了扩展字段cardData{title:标题文本,items:[{text:选项,value:value}],# selectListcanReplay:True,# 支持重新选择# 可扩展字段imageUrl:...,# 壁纸展示卡片style:水墨国风,# 壁纸元信息theme:青峦远山,credits_remaining:5,# 剩余免费次数has_regenerate:True,# 是否支持重新生成}6.2 未来可扩展的卡片类型卡片类型用途状态imageGrid多张壁纸网格展示未实现colorPicker颜色选择器未实现progressBar自定义进度条未实现shareCard壁纸分享卡片未实现七、常见问题与解决方案在前端卡片开发中常见问题及解决方案如下问题原因解决方案卡片不显示cardName或displayType字段错误检查 JSON 结构确保使用DisplayFaCard卡片重叠append设置为true多级选择流程中使用false选项点击无响应前端未正确处理点击事件确保将选项文本作为用户消息发送SSE 连接断开网络超时或服务端异常前端实现自动重连机制图片加载失败imageUrl无效或过期检查图片 URL 的有效期八、最佳实践总结在鸿蒙壁纸大师的前端卡片交互开发中以下最佳实践值得参考最佳实践说明收益三级选择流程风格→主题→场景的渐进式引导降低用户决策成本卡片替换机制使用append: false替换上一张卡片保持界面简洁SSE 事件驱动实时推送进度和卡片更新提升用户体验内容安全前置在主流程前完成安全检查避免 API 资源浪费友好引导设计违规请求返回引导提示提升用户满意度卡片可扩展性预留字段支持未来扩展降低维护成本开发建议卡片交互设计应以用户为中心每一步的选择都应有明确的引导和反馈。同时合理使用append字段控制卡片的替换与追加避免界面混乱。九、总结本文深入解析了鸿蒙壁纸大师的前端卡片交互体系核心要点三种卡片类型selectList选择、wallpaper展示、text文本三级选择流程风格→主题→场景每级通过卡片替换推进SSE 事件驱动status-update 推送进度artifact-update 推送卡片内容安全策略肖像检测、文字检测、无关话题过滤确保合规友好的交互设计违规请求返回引导提示而非错误信息卡片可扩展性预留字段支持未来更多交互类型如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源华为 A2A DisplayFaCard 卡片规范华为智能体交互设计指南A2A 协议规范 - 华为华为开发者联盟 - 文档中心JSON-RPC 2.0 规范FastAPI 官方文档火山引擎 - 豆包大模型Python asyncio 官方文档