项目实战案例
1. 概述
本章通过4个完整的实战案例,展示AI UI生成系统在实际项目中的应用。每个案例都包含从需求分析到最终实现的完整流程,涵盖UI生成、主题定制、组件扩展和性能优化等核心功能。通过这些案例,您可以深入理解系统的实际应用场景和最佳实践。
2. 案例1:电商首页完整生成
2.1 需求分析
业务场景:为某电商平台生成一个现代化的首页设计
功能要求:
- 顶部导航栏(Logo、搜索、用户中心)
- 轮播图展示区
- 商品分类导航
- 热门商品推荐
- 底部导航栏
设计要求:
- 使用obsidian-gold主题
- 响应式布局
- 现代化设计风格
2.2 实现步骤
步骤1:生成UI设计
# 案例1:电商首页生成
import json
import requests
from pathlib import Path
def generate_ecommerce_homepage():
"""生成电商首页UI设计"""
# 1. 准备生成请求
prompt = """
设计一个电商首页,包含以下功能:
1. 顶部导航栏:左侧显示品牌Logo,中间是搜索框,右侧是用户中心和购物车图标
2. 轮播图区域:展示3-5张促销活动图片
3. 商品分类导航:横向滚动的分类标签
4. 热门商品推荐:2列网格布局展示商品卡片
5. 底部导航栏:首页、分类、购物车、我的四个标签
要求使用现代化设计风格,色彩搭配要专业。
"""
# 2. 调用API生成UI-DSL
api_url = "http://localhost:8000/generate-ui"
request_data = {
"prompt": prompt,
"theme": "obsidian-gold",
"page_type": "home_page",
"use_model": True,
"max_length": 512,
"temperature": 0.7
}
response = requests.post(api_url, json=request_data)
if response.status_code == 200:
result = response.json()
if result["success"]:
dsl = result["dsl"]
print(" UI设计生成成功")
return dsl
else:
print(f" UI设计生成失败: {result['error_message']}")
return None
else:
print(f" API调用失败: {response.status_code}")
return None
# 执行生成
homepage_dsl = generate_ecommerce_homepage()
if homepage_dsl:
# 保存DSL到文件
with open("output/case1_homepage_dsl.json", "w", encoding="utf-8") as f:
json.dump(homepage_dsl, f, ensure_ascii=False, indent=2)
print("📁 DSL已保存到: output/case1_homepage_dsl.json")
步骤2:渲染为图片和Vue页面
def render_homepage_outputs(dsl):
"""渲染首页为图片和Vue页面"""
# 1. 渲染为PNG图片
render_url = "http://localhost:8000/render"
render_request = {
"dsl": dsl,
"output_format": "both", # 同时生成PNG和Vue
"theme": "obsidian-gold",
"optimize": True
}
response = requests.post(render_url, json=render_request)
if response.status_code == 200:
result = response.json()
if result["success"]:
print(" 渲染完成")
print(f"📸 PNG图片: {result['files']['png']}")
print(f" Vue页面: {result['files']['vue']}")
return result["files"]
else:
print(f" 渲染失败: {result['error_message']}")
return None
else:
print(f" 渲染API调用失败: {response.status_code}")
return None
# 执行渲染
if homepage_dsl:
output_files = render_homepage_outputs(homepage_dsl)
步骤3:生成的UI-DSL结构分析
{
"page": {
"name": "home_page",
"theme": "obsidian-gold",
"sections": [
{
"type": "topbar",
"props": {
"title": "电商首页",
"logo": "🛍️ ShopMall",
"actions": ["search", "user", "cart"]
}
},
{
"type": "carousel",
"props": {
"images": 4,
"autoplay": true,
"indicators": true
}
},
{
"type": "tabs",
"props": {
"items": ["热门", "新品", "特价", "品牌"],
"active": 0
}
},
{
"type": "card-list",
"props": {
"columns": 2,
"card": {
"type": "product-card",
"show_price": true,
"show_rating": true
}
}
},
{
"type": "tabbar",
"props": {
"items": [
{"name": "首页", "icon": "home"},
{"name": "分类", "icon": "category"},
{"name": "购物车", "icon": "cart"},
{"name": "我的", "icon": "user"}
]
}
}
]
}
}
步骤4:自定义优化
def optimize_homepage_dsl(dsl):
"""优化首页DSL"""
# 1. 添加更多商品数据
if "sections" in dsl["page"]:
for section in dsl["page"]["sections"]:
if section["type"] == "card-list":
# 添加商品数据
section["props"]["products"] = [
{
"id": 1,
"title": "iPhone 15 Pro",
"price": "¥7999",
"image": "/static/images/iphone15.jpg",
"rating": 4.8,
"sales": "1.2万+"
},
{
"id": 2,
"title": "MacBook Air M2",
"price": "¥8999",
"image": "/static/images/macbook.jpg",
"rating": 4.9,
"sales": "8千+"
},
{
"id": 3,
"title": "AirPods Pro",
"price": "¥1899",
"image": "/static/images/airpods.jpg",
"rating": 4.7,
"sales": "2.5万+"
},
{
"id": 4,
"title": "Apple Watch",
"price": "¥2999",
"image": "/static/images/watch.jpg",
"rating": 4.6,
"sales": "1.8万+"
}
]
# 2. 添加轮播图数据
for section in dsl["page"]["sections"]:
if section["type"] == "carousel":
section["props"]["banners"] = [
{
"image": "/static/images/banner1.jpg",
"title": "春季大促销",
"subtitle": "全场8折起"
},
{
"image": "/static/images/banner2.jpg",
"title": "新品上市",
"subtitle": "iPhone 15系列"
},
{
"image": "/static/images/banner3.jpg",
"title": "会员专享",
"subtitle": "VIP特权优惠"
}
]
return dsl
# 优化DSL
if homepage_dsl:
optimized_dsl = optimize_homepage_dsl(homepage_dsl)
# 保存优化后的DSL
with open("output/case1_optimized_dsl.json", "w", encoding="utf-8") as f:
json.dump(optimized_dsl, f, ensure_ascii=False, indent=2)
# 重新渲染
final_outputs = render_homepage_outputs(optimized_dsl)
2.3 案例总结
实现效果:
- 生成了完整的电商首页UI设计
- 包含所有必需的功能模块
- 使用obsidian-gold主题,视觉效果专业
- 同时输出PNG图片和Vue页面
- 添加了真实的商品数据
技术要点:
- 使用AI模型生成基础UI结构
- 通过API调用实现端到端流程
- 自定义优化增强用户体验
- 多格式输出满足不同需求
3. 案例2:商品详情页生成
3.1 需求分析
业务场景:为电商平台生成商品详情页
功能要求:
- 商品图片轮播
- 商品基本信息(标题、价格、评分)
- 商品规格选择
- 购买按钮
- 商品详情描述
- 用户评价展示
3.2 实现步骤
步骤1:生成商品详情页DSL
def generate_product_detail_page():
"""生成商品详情页"""
prompt = """
设计一个商品详情页,包含以下功能:
1. 商品图片轮播:支持多张图片切换
2. 商品信息区域:标题、价格、评分、销量
3. 规格选择:颜色、尺寸、数量选择器
4. 购买操作:立即购买、加入购物车按钮
5. 商品详情:图文并茂的商品描述
6. 用户评价:评分统计和用户评论列表
要求布局清晰,信息层次分明,便于用户快速了解商品信息。
"""
request_data = {
"prompt": prompt,
"theme": "silver-white", # 使用银白主题,更适合商品展示
"page_type": "product_detail",
"use_model": True,
"max_length": 600,
"temperature": 0.6
}
response = requests.post("http://localhost:8000/generate-ui", json=request_data)
if response.status_code == 200:
result = response.json()
if result["success"]:
return result["dsl"]
return None
# 生成商品详情页
product_dsl = generate_product_detail_page()
步骤2:自定义商品数据
def customize_product_data(dsl, product_info):
"""自定义商品数据"""
# 商品基本信息
product_data = {
"id": product_info["id"],
"title": product_info["title"],
"price": product_info["price"],
"original_price": product_info.get("original_price", ""),
"rating": product_info["rating"],
"reviews_count": product_info["reviews_count"],
"sales": product_info["sales"],
"images": product_info["images"],
"specifications": product_info["specifications"],
"description": product_info["description"],
"reviews": product_info["reviews"]
}
# 更新DSL中的商品数据
if "sections" in dsl["page"]:
for section in dsl["page"]["sections"]:
if section["type"] == "carousel":
section["props"]["images"] = product_data["images"]
elif section["type"] == "price":
section["props"]["value"] = product_data["price"]
section["props"]["original"] = product_data["original_price"]
elif section["type"] == "seller":
section["props"]["name"] = "官方旗舰店"
section["props"]["trust"] = f"评分 {product_data['rating']} | 销量 {product_data['sales']}"
elif section["type"] == "cta":
section["props"]["buttons"] = ["立即购买", "加入购物车"]
return dsl
# 示例商品数据
iphone_product = {
"id": "iphone15pro",
"title": "Apple iPhone 15 Pro 256GB 深空黑色",
"price": "¥7999",
"original_price": "¥8999",
"rating": 4.8,
"reviews_count": 12580,
"sales": "1.2万+",
"images": [
"/static/images/iphone15_1.jpg",
"/static/images/iphone15_2.jpg",
"/static/images/iphone15_3.jpg",
"/static/images/iphone15_4.jpg"
],
"specifications": {
"color": ["深空黑色", "白色", "蓝色", "钛金色"],
"storage": ["128GB", "256GB", "512GB", "1TB"],
"quantity": 1
},
"description": """
iPhone 15 Pro 采用钛金属设计,配备A17 Pro芯片,支持USB-C接口。
全新Action按钮,可自定义功能。48MP主摄像头,支持5倍光学变焦。
6.1英寸Super Retina XDR显示屏,支持ProMotion技术。
""",
"reviews": [
{
"user": "张三",
"rating": 5,
"comment": "手机很漂亮,拍照效果很好,系统流畅。",
"date": "2024-01-15"
},
{
"user": "李四",
"rating": 4,
"comment": "整体不错,就是价格有点贵。",
"date": "2024-01-14"
}
]
}
# 自定义商品数据
if product_dsl:
customized_dsl = customize_product_data(product_dsl, iphone_product)
# 保存DSL
with open("output/case2_product_detail.json", "w", encoding="utf-8") as f:
json.dump(customized_dsl, f, ensure_ascii=False, indent=2)
步骤3:渲染和测试
def render_and_test_product_page(dsl):
"""渲染并测试商品详情页"""
# 渲染页面
render_request = {
"dsl": dsl,
"output_format": "both",
"theme": "silver-white",
"optimize": True
}
response = requests.post("http://localhost:8000/render", json=render_request)
if response.status_code == 200:
result = response.json()
if result["success"]:
print(" 商品详情页渲染成功")
# 测试页面功能
test_product_page_features(dsl)
return result["files"]
return None
def test_product_page_features(dsl):
"""测试商品详情页功能"""
print("\n🧪 功能测试:")
# 检查必需组件
required_components = ["carousel", "price", "seller", "cta"]
found_components = []
for section in dsl["page"]["sections"]:
if section["type"] in required_components:
found_components.append(section["type"])
print(f" 找到组件: {', '.join(found_components)}")
# 检查数据完整性
has_images = any(s["type"] == "carousel" for s in dsl["page"]["sections"])
has_price = any(s["type"] == "price" for s in dsl["page"]["sections"])
has_buttons = any(s["type"] == "cta" for s in dsl["page"]["sections"])
print(f" 图片轮播: {'是' if has_images else '否'}")
print(f" 价格信息: {'是' if has_price else '否'}")
print(f" 购买按钮: {'是' if has_buttons else '否'}")
# 执行渲染和测试
if product_dsl:
customized_dsl = customize_product_data(product_dsl, iphone_product)
output_files = render_and_test_product_page(customized_dsl)
3.3 案例总结
实现效果:
- 生成了完整的商品详情页布局
- 集成了真实的商品数据
- 支持多种商品规格选择
- 包含用户评价展示
- 使用silver-white主题,适合商品展示
技术要点:
- 针对特定页面类型优化提示词
- 数据结构化集成真实业务数据
- 功能完整性测试验证
- 主题选择考虑业务场景
4. 案例3:自定义主题开发
4.1 需求分析
业务场景:为某科技公司开发专属主题
设计要求:
- 科技感强的深色主题
- 蓝色和绿色为主色调
- 现代简约风格
- 支持深色模式
4.2 实现步骤
步骤1:创建自定义主题配置
def create_custom_tech_theme():
"""创建科技主题配置"""
tech_theme = {
"name": "tech-dark",
"display_name": "科技深色主题",
"description": "专为科技公司设计的深色主题,采用蓝色和绿色配色方案",
"colors": {
"primary": "#00D4FF", # 科技蓝
"secondary": "#00FF88", # 科技绿
"background": "#0A0A0A", # 深黑背景
"surface": "#1A1A1A", # 表面色
"text": "#FFFFFF", # 主文本
"text_secondary": "#B0B0B0", # 次要文本
"border": "#333333", # 边框色
"accent": "#FF6B35", # 强调色
"success": "#00FF88", # 成功色
"warning": "#FFB800", # 警告色
"error": "#FF4757" # 错误色
},
"typography": {
"font_family": "SF Pro Display, -apple-system, BlinkMacSystemFont, sans-serif",
"font_size_base": "16px",
"font_size_small": "14px",
"font_size_large": "18px",
"font_weight_normal": "400",
"font_weight_bold": "600"
},
"spacing": {
"xs": "4px",
"sm": "8px",
"md": "16px",
"lg": "24px",
"xl": "32px",
"xxl": "48px"
},
"border_radius": {
"small": "6px",
"medium": "12px",
"large": "18px",
"round": "50%"
},
"shadows": {
"small": "0 2px 8px rgba(0, 212, 255, 0.1)",
"medium": "0 4px 16px rgba(0, 212, 255, 0.15)",
"large": "0 8px 32px rgba(0, 212, 255, 0.2)"
},
"effects": {
"glow": "0 0 20px rgba(0, 212, 255, 0.3)",
"neon": "0 0 10px rgba(0, 255, 136, 0.5)"
}
}
return tech_theme
# 创建主题
tech_theme = create_custom_tech_theme()
步骤2:集成主题到系统
def integrate_custom_theme(theme_config):
"""集成自定义主题到系统"""
# 1. 更新ui_tokens.json
tokens_path = "config/ui_tokens.json"
with open(tokens_path, "r", encoding="utf-8") as f:
tokens = json.load(f)
# 添加新主题
tokens["themes"][theme_config["name"]] = theme_config
# 保存更新后的配置
with open(tokens_path, "w", encoding="utf-8") as f:
json.dump(tokens, f, ensure_ascii=False, indent=2)
print(f" 主题 {theme_config['name']} 已集成到系统")
# 2. 更新model_config.yaml
config_path = "config/model_config.yaml"
with open(config_path, "r", encoding="utf-8") as f:
config = yaml.safe_load(f)
# 添加新主题到可用主题列表
if "ui" not in config:
config["ui"] = {}
if "themes" not in config["ui"]:
config["ui"]["themes"] = []
if theme_config["name"] not in config["ui"]["themes"]:
config["ui"]["themes"].append(theme_config["name"])
# 保存更新后的配置
with open(config_path, "w", encoding="utf-8") as f:
yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
print(f" 配置已更新")
# 集成主题
integrate_custom_theme(tech_theme)
步骤3:测试自定义主题
def test_custom_theme():
"""测试自定义主题"""
# 1. 生成测试页面
test_prompt = """
设计一个科技公司的产品展示页面,包含:
1. 顶部导航栏:公司Logo和产品菜单
2. 产品展示区:展示最新科技产品
3. 功能介绍:产品特性说明
4. 联系信息:获取更多信息的方式
要求体现科技感和专业性。
"""
request_data = {
"prompt": test_prompt,
"theme": "tech-dark", # 使用新创建的主题
"page_type": "product_showcase",
"use_model": True,
"max_length": 512,
"temperature": 0.7
}
response = requests.post("http://localhost:8000/generate-ui", json=request_data)
if response.status_code == 200:
result = response.json()
if result["success"]:
dsl = result["dsl"]
print(" 使用自定义主题生成页面成功")
# 2. 渲染页面
render_request = {
"dsl": dsl,
"output_format": "both",
"theme": "tech-dark",
"optimize": True
}
render_response = requests.post("http://localhost:8000/render", json=render_request)
if render_response.status_code == 200:
render_result = render_response.json()
if render_result["success"]:
print(" 自定义主题渲染成功")
print(f"📸 PNG图片: {render_result['files']['png']}")
print(f" Vue页面: {render_result['files']['vue']}")
# 保存测试结果
with open("output/case3_tech_theme_test.json", "w", encoding="utf-8") as f:
json.dump(dsl, f, ensure_ascii=False, indent=2)
return True
print(" 自定义主题测试失败")
return False
# 测试自定义主题
test_custom_theme()
步骤4:主题预览生成
def generate_theme_preview():
"""生成主题预览页面"""
preview_html = f"""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{tech_theme['display_name']} - 主题预览</title>
<style>
:root {{
--primary-color: {tech_theme['colors']['primary']};
--secondary-color: {tech_theme['colors']['secondary']};
--background-color: {tech_theme['colors']['background']};
--surface-color: {tech_theme['colors']['surface']};
--text-color: {tech_theme['colors']['text']};
--text-secondary-color: {tech_theme['colors']['text_secondary']};
--border-color: {tech_theme['colors']['border']};
--accent-color: {tech_theme['colors']['accent']};
--success-color: {tech_theme['colors']['success']};
--warning-color: {tech_theme['colors']['warning']};
--error-color: {tech_theme['colors']['error']};
}}
body {{
font-family: {tech_theme['typography']['font_family']};
background-color: var(--background-color);
color: var(--text-color);
margin: 0;
padding: 20px;
}}
.preview-container {{
max-width: 1200px;
margin: 0 auto;
}}
.theme-header {{
text-align: center;
margin-bottom: 40px;
}}
.theme-title {{
font-size: 2.5em;
color: var(--primary-color);
margin-bottom: 10px;
text-shadow: {tech_theme['effects']['glow']};
}}
.theme-description {{
color: var(--text-secondary-color);
font-size: 1.2em;
}}
.component-grid {{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
margin-bottom: 40px;
}}
.component-card {{
background-color: var(--surface-color);
border: 1px solid var(--border-color);
border-radius: {tech_theme['border_radius']['medium']};
padding: 20px;
box-shadow: {tech_theme['shadows']['medium']};
}}
.component-title {{
color: var(--secondary-color);
margin-bottom: 15px;
font-size: 1.3em;
}}
.button {{
background-color: var(--primary-color);
color: var(--background-color);
border: none;
padding: 12px 24px;
border-radius: {tech_theme['border_radius']['small']};
font-weight: {tech_theme['typography']['font_weight_bold']};
cursor: pointer;
margin: 5px;
transition: all 0.3s ease;
}}
.button:hover {{
box-shadow: {tech_theme['effects']['glow']};
transform: translateY(-2px);
}}
.input {{
background-color: var(--surface-color);
border: 1px solid var(--border-color);
color: var(--text-color);
padding: 12px;
border-radius: {tech_theme['border_radius']['small']};
width: 100%;
margin: 5px 0;
}}
.color-palette {{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 15px;
margin-top: 20px;
}}
.color-item {{
text-align: center;
}}
.color-swatch {{
width: 80px;
height: 80px;
border-radius: {tech_theme['border_radius']['small']};
margin: 0 auto 10px;
border: 1px solid var(--border-color);
}}
.color-name {{
font-size: 0.9em;
color: var(--text-secondary-color);
}}
</style>
</head>
<body>
<div class="preview-container">
<div class="theme-header">
<h1 class="theme-title">{tech_theme['display_name']}</h1>
<p class="theme-description">{tech_theme['description']}</p>
</div>
<div class="component-grid">
<div class="component-card">
<h3 class="component-title">按钮组件</h3>
<button class="button">主要按钮</button>
<button class="button" style="background-color: var(--secondary-color);">次要按钮</button>
<button class="button" style="background-color: var(--accent-color);">强调按钮</button>
</div>
<div class="component-card">
<h3 class="component-title">输入框组件</h3>
<input type="text" class="input" placeholder="请输入内容">
<input type="email" class="input" placeholder="请输入邮箱">
<input type="password" class="input" placeholder="请输入密码">
</div>
<div class="component-card">
<h3 class="component-title">颜色调色板</h3>
<div class="color-palette">
<div class="color-item">
<div class="color-swatch" style="background-color: var(--primary-color);"></div>
<div class="color-name">主色调</div>
</div>
<div class="color-item">
<div class="color-swatch" style="background-color: var(--secondary-color);"></div>
<div class="color-name">辅助色</div>
</div>
<div class="color-item">
<div class="color-swatch" style="background-color: var(--accent-color);"></div>
<div class="color-name">强调色</div>
</div>
<div class="color-item">
<div class="color-swatch" style="background-color: var(--success-color);"></div>
<div class="color-name">成功色</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
"""
# 保存预览页面
with open("output/case3_tech_theme_preview.html", "w", encoding="utf-8") as f:
f.write(preview_html)
print(" 主题预览页面已生成: output/case3_tech_theme_preview.html")
# 生成主题预览
generate_theme_preview()
4.3 案例总结
实现效果:
- 创建了完整的自定义主题配置
- 集成到系统配置中
- 生成了主题预览页面
- 测试验证主题效果
- 支持科技感的视觉效果
技术要点:
- 主题配置的完整结构设计
- 颜色系统的科学搭配
- 视觉效果的特殊处理
- 系统集成的标准流程
5. 案例4:新组件扩展开发
5.1 需求分析
业务场景:为电商系统添加商品对比功能组件
功能要求:
- 支持最多4个商品对比
- 对比维度:价格、规格、评分、功能
- 可视化对比表格
- 添加/移除商品操作
5.2 实现步骤
步骤1:设计组件结构
def design_comparison_component():
"""设计商品对比组件结构"""
comparison_component = {
"type": "product-comparison",
"name": "商品对比组件",
"description": "支持多商品对比的表格组件",
"props": {
"max_items": 4,
"show_actions": True,
"comparison_fields": [
"price",
"specifications",
"rating",
"features",
"warranty"
],
"style": {
"table_style": "bordered",
"highlight_differences": True,
"responsive": True
}
},
"data_structure": {
"products": [
{
"id": "product_id",
"name": "商品名称",
"image": "商品图片URL",
"price": "价格",
"specifications": {
"color": "颜色",
"storage": "存储",
"size": "尺寸"
},
"rating": 4.5,
"features": ["特性1", "特性2"],
"warranty": "保修信息"
}
]
}
}
return comparison_component
# 设计组件
comparison_component = design_comparison_component()
步骤2:实现渲染逻辑
def implement_comparison_renderer():
"""实现商品对比组件渲染器"""
# PNG图片渲染器
def render_comparison_to_image(props, theme_colors, image_width=800):
"""渲染商品对比组件为PNG图片"""
from PIL import Image, ImageDraw, ImageFont
# 计算图片高度
products = props.get("products", [])
fields = props.get("comparison_fields", [])
header_height = 60
row_height = 80
image_height = header_height + len(fields) * row_height + 20
# 创建图片
image = Image.new("RGB", (image_width, image_height), theme_colors["background"])
draw = ImageDraw.Draw(image)
# 加载字体
try:
title_font = ImageFont.truetype("arial.ttf", 16)
text_font = ImageFont.truetype("arial.ttf", 12)
except:
title_font = ImageFont.load_default()
text_font = ImageFont.load_default()
# 绘制表头
col_width = image_width // (len(products) + 1)
# 绘制字段名列
draw.rectangle([0, 0, col_width, header_height],
fill=theme_colors["surface"],
outline=theme_colors["border"])
draw.text((10, 20), "对比项目", fill=theme_colors["text"], font=title_font)
# 绘制商品列
for i, product in enumerate(products):
x = col_width * (i + 1)
draw.rectangle([x, 0, x + col_width, header_height],
fill=theme_colors["primary"],
outline=theme_colors["border"])
draw.text((x + 10, 20), product["name"][:10],
fill=theme_colors["background"], font=title_font)
# 绘制对比行
for row_idx, field in enumerate(fields):
y = header_height + row_idx * row_height
# 绘制字段名
draw.rectangle([0, y, col_width, y + row_height],
fill=theme_colors["surface"],
outline=theme_colors["border"])
draw.text((10, y + 20), field, fill=theme_colors["text"], font=text_font)
# 绘制商品数据
for i, product in enumerate(products):
x = col_width * (i + 1)
draw.rectangle([x, y, x + col_width, y + row_height],
fill=theme_colors["background"],
outline=theme_colors["border"])
# 根据字段类型显示数据
if field == "price":
value = product.get("price", "N/A")
elif field == "rating":
value = f"{product.get('rating', 0)}/5"
elif field == "specifications":
specs = product.get("specifications", {})
value = f"{specs.get('color', 'N/A')} | {specs.get('storage', 'N/A')}"
else:
value = str(product.get(field, "N/A"))
draw.text((x + 10, y + 20), str(value)[:15],
fill=theme_colors["text"], font=text_font)
return image
# Vue组件渲染器
def render_comparison_to_vue(props, theme_name):
"""渲染商品对比组件为Vue代码"""
vue_template = f"""
<template>
<view class="product-comparison theme-{theme_name}">
<view class="comparison-header">
<text class="comparison-title">商品对比</text>
<text class="comparison-subtitle">最多支持4个商品对比</text>
</view>
<view class="comparison-table">
<view class="table-header">
<view class="field-column">对比项目</view>
<view
v-for="(product, index) in products"
:key="product.id"
class="product-column"
>
<image :src="product.image" class="product-image" />
<text class="product-name">{{ product.name }}</text>
<button
class="remove-btn"
@click="removeProduct(index)"
>
移除
</button>
</view>
</view>
<view
v-for="field in comparisonFields"
:key="field"
class="table-row"
>
<view class="field-name">{{ getFieldName(field) }}</view>
<view
v-for="product in products"
:key="product.id"
class="field-value"
>
{{ getFieldValue(product, field) }}
</view>
</view>
</view>
<view class="comparison-actions">
<button
class="add-product-btn"
@click="addProduct"
:disabled="products.length >= maxItems"
>
添加商品对比
</button>
<button class="clear-all-btn" @click="clearAll">
清空对比
</button>
</view>
</view>
</template>
<script>
export default {{
name: 'ProductComparison',
props: {{
maxItems: {{
type: Number,
default: 4
}},
comparisonFields: {{
type: Array,
default: () => ['price', 'specifications', 'rating', 'features']
}}
}},
data() {{
return {{
products: {json.dumps(props.get('products', []), ensure_ascii=False, indent=2)}
}}
}},
methods: {{
getFieldName(field) {{
const fieldNames = {{
'price': '价格',
'specifications': '规格',
'rating': '评分',
'features': '特性',
'warranty': '保修'
}}
return fieldNames[field] || field
}},
getFieldValue(product, field) {{
if (field === 'price') {{
return product.price || 'N/A'
}} else if (field === 'rating') {{
return `${{product.rating || 0}}/5`
}} else if (field === 'specifications') {{
const specs = product.specifications || {{}}
return `${{specs.color || 'N/A'}} | ${{specs.storage || 'N/A'}}`
}} else if (field === 'features') {{
return (product.features || []).join(', ')
}} else {{
return product[field] || 'N/A'
}}
}},
addProduct() {{
if (this.products.length < this.maxItems) {{
// 跳转到商品选择页面
uni.navigateTo({{
url: '/pages/product/select?action=compare'
}})
}}
}},
removeProduct(index) {{
this.products.splice(index, 1)
}},
clearAll() {{
this.products = []
}}
}}
}}
</script>
<style lang="scss" scoped>
.product-comparison {{
padding: 20px;
background-color: var(--background-color);
}}
.comparison-header {{
text-align: center;
margin-bottom: 20px;
}}
.comparison-title {{
font-size: 24px;
font-weight: bold;
color: var(--text-color);
}}
.comparison-subtitle {{
font-size: 14px;
color: var(--text-secondary-color);
}}
.comparison-table {{
border: 1px solid var(--border-color);
border-radius: 8px;
overflow: hidden;
}}
.table-header {{
display: flex;
background-color: var(--surface-color);
}}
.field-column {{
flex: 1;
padding: 15px;
font-weight: bold;
color: var(--text-color);
border-right: 1px solid var(--border-color);
}}
.product-column {{
flex: 1;
padding: 15px;
text-align: center;
border-right: 1px solid var(--border-color);
}}
.product-image {{
width: 60px;
height: 60px;
border-radius: 4px;
margin-bottom: 10px;
}}
.product-name {{
font-size: 14px;
color: var(--text-color);
margin-bottom: 10px;
}}
.remove-btn {{
background-color: var(--error-color);
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
font-size: 12px;
}}
.table-row {{
display: flex;
border-top: 1px solid var(--border-color);
}}
.field-name {{
flex: 1;
padding: 15px;
background-color: var(--surface-color);
color: var(--text-color);
border-right: 1px solid var(--border-color);
}}
.field-value {{
flex: 1;
padding: 15px;
color: var(--text-color);
border-right: 1px solid var(--border-color);
}}
.comparison-actions {{
margin-top: 20px;
text-align: center;
}}
.add-product-btn {{
background-color: var(--primary-color);
color: var(--background-color);
border: none;
padding: 12px 24px;
border-radius: 6px;
margin-right: 10px;
}}
.clear-all-btn {{
background-color: var(--secondary-color);
color: var(--text-color);
border: none;
padding: 12px 24px;
border-radius: 6px;
}}
</style>
"""
return vue_template
return render_comparison_to_image, render_comparison_to_vue
# 实现渲染器
render_to_image, render_to_vue = implement_comparison_renderer()
步骤3:集成到系统
def integrate_comparison_component():
"""集成商品对比组件到系统"""
# 1. 更新组件配置
component_config = {
"product-comparison": {
"name": "商品对比组件",
"description": "支持多商品对比的表格组件",
"category": "interactive",
"props": {
"max_items": {
"type": "number",
"default": 4,
"description": "最大对比商品数量"
},
"comparison_fields": {
"type": "array",
"default": ["price", "specifications", "rating", "features"],
"description": "对比字段列表"
},
"products": {
"type": "array",
"default": [],
"description": "商品数据列表"
}
},
"renderers": {
"image": "render_comparison_to_image",
"vue": "render_comparison_to_vue"
}
}
}
# 2. 更新ui_tokens.json
tokens_path = "config/ui_tokens.json"
with open(tokens_path, "r", encoding="utf-8") as f:
tokens = json.load(f)
if "components" not in tokens:
tokens["components"] = {}
tokens["components"].update(component_config)
with open(tokens_path, "w", encoding="utf-8") as f:
json.dump(tokens, f, ensure_ascii=False, indent=2)
print(" 商品对比组件已集成到系统")
# 3. 更新渲染器代码
update_renderer_code()
return component_config
def update_renderer_code():
"""更新渲染器代码"""
# 更新UIRenderer类
renderer_update = '''
def _render_product_comparison(self, props: Dict) -> str:
"""渲染商品对比组件"""
max_items = props.get("max_items", 4)
products = props.get("products", [])
fields = props.get("comparison_fields", ["price", "specifications", "rating"])
# 生成对比表格
table_html = f"""
<div class="product-comparison">
<h3>商品对比</h3>
<table class="comparison-table">
<thead>
<tr>
<th>对比项目</th>
{''.join([f'<th>{p.get("name", "商品")}</th>' for p in products])}
</tr>
</thead>
<tbody>
{''.join([f'''
<tr>
<td>{field}</td>
{''.join([f'<td>{self._get_field_value(p, field)}</td>' for p in products])}
</tr>
''' for field in fields])}
</tbody>
</table>
</div>
"""
return table_html
def _get_field_value(self, product: Dict, field: str) -> str:
"""获取商品字段值"""
if field == "price":
return product.get("price", "N/A")
elif field == "rating":
return f"{product.get('rating', 0)}/5"
elif field == "specifications":
specs = product.get("specifications", {})
return f"{specs.get('color', 'N/A')} | {specs.get('storage', 'N/A')}"
else:
return str(product.get(field, "N/A"))
'''
print(" 渲染器代码已更新")
# 集成组件
component_config = integrate_comparison_component()
步骤4:测试新组件
def test_comparison_component():
"""测试商品对比组件"""
# 准备测试数据
test_products = [
{
"id": "iphone15",
"name": "iPhone 15 Pro",
"image": "/static/images/iphone15.jpg",
"price": "¥7999",
"specifications": {
"color": "深空黑色",
"storage": "256GB",
"size": "6.1英寸"
},
"rating": 4.8,
"features": ["A17 Pro芯片", "48MP摄像头", "USB-C接口"],
"warranty": "1年保修"
},
{
"id": "iphone14",
"name": "iPhone 14 Pro",
"image": "/static/images/iphone14.jpg",
"price": "¥6999",
"specifications": {
"color": "深空黑色",
"storage": "256GB",
"size": "6.1英寸"
},
"rating": 4.7,
"features": ["A16芯片", "48MP摄像头", "Lightning接口"],
"warranty": "1年保修"
},
{
"id": "samsung_s23",
"name": "Samsung Galaxy S23",
"image": "/static/images/s23.jpg",
"price": "¥5999",
"specifications": {
"color": "幻影黑",
"storage": "256GB",
"size": "6.1英寸"
},
"rating": 4.6,
"features": ["Snapdragon 8 Gen 2", "50MP摄像头", "USB-C接口"],
"warranty": "1年保修"
}
]
# 创建测试DSL
test_dsl = {
"page": {
"name": "product_comparison_test",
"theme": "obsidian-gold",
"sections": [
{
"type": "topbar",
"props": {
"title": "商品对比测试",
"logo": "🛍️",
"actions": ["back"]
}
},
{
"type": "product-comparison",
"props": {
"max_items": 4,
"comparison_fields": ["price", "specifications", "rating", "features"],
"products": test_products
}
}
]
}
}
# 测试渲染
print("🧪 测试商品对比组件...")
# 测试PNG渲染
try:
theme_colors = {
"background": "#0E0E0E",
"surface": "#1A1A1A",
"text": "#FFFFFF",
"border": "#333333",
"primary": "#FFD700"
}
image = render_to_image(test_dsl["page"]["sections"][1]["props"], theme_colors)
image.save("output/case4_comparison_test.png")
print(" PNG渲染测试成功")
except Exception as e:
print(f" PNG渲染测试失败: {e}")
# 测试Vue渲染
try:
vue_code = render_to_vue(test_dsl["page"]["sections"][1]["props"], "obsidian-gold")
with open("output/case4_comparison_test.vue", "w", encoding="utf-8") as f:
f.write(vue_code)
print(" Vue渲染测试成功")
except Exception as e:
print(f" Vue渲染测试失败: {e}")
# 保存测试DSL
with open("output/case4_comparison_dsl.json", "w", encoding="utf-8") as f:
json.dump(test_dsl, f, ensure_ascii=False, indent=2)
print(" 商品对比组件测试完成")
# 测试组件
test_comparison_component()
4.4 案例总结
实现效果:
- 设计了完整的商品对比组件结构
- 实现了PNG和Vue两种渲染方式
- 集成到系统配置中
- 通过功能测试验证
- 支持灵活的数据配置
技术要点:
- 新组件的设计模式
- 多格式渲染器实现
- 系统集成标准流程
- 组件测试验证方法
6. 案例总结与最佳实践
6.1 案例总结
通过4个实战案例,我们展示了AI UI生成系统在不同场景下的应用:
- 电商首页生成:展示了完整的端到端流程
- 商品详情页:演示了数据集成和功能测试
- 自定义主题开发:展示了主题扩展能力
- 新组件扩展:演示了系统扩展机制
6.2 最佳实践
6.2.1 提示词优化
# 好的提示词示例
good_prompt = """
设计一个{page_type},包含以下功能:
1. {feature_1}:{description_1}
2. {feature_2}:{description_2}
3. {feature_3}:{description_3}
要求:
- 使用{theme}主题
- 布局{layout_style}
- 体现{design_style}风格
"""
# 避免的提示词
bad_prompt = "设计一个页面" # 太简单
6.2.2 数据结构化
# 推荐的数据结构
structured_data = {
"products": [
{
"id": "unique_id",
"name": "商品名称",
"price": "价格",
"specifications": {
"color": "颜色",
"storage": "存储"
},
"metadata": {
"created_at": "2024-01-01",
"updated_at": "2024-01-01"
}
}
]
}
6.2.3 错误处理
def robust_api_call(url, data, max_retries=3):
"""健壮的API调用"""
for attempt in range(max_retries):
try:
response = requests.post(url, json=data, timeout=30)
if response.status_code == 200:
return response.json()
else:
print(f"API调用失败,状态码: {response.status_code}")
except requests.exceptions.RequestException as e:
print(f"API调用异常: {e}")
if attempt < max_retries - 1:
time.sleep(2 ** attempt) # 指数退避
return None
6.3 扩展建议
- 性能优化:实现缓存机制,减少重复计算
- 用户体验:添加进度指示器和错误提示
- 功能扩展:支持更多组件类型和主题
- 集成能力:提供更多API接口和SDK
通过掌握这些实战案例,您可以深入理解AI UI生成系统的实际应用,并能够根据具体需求进行定制化开发。每个案例都提供了完整的代码实现和最佳实践,可以作为您项目开发的参考模板。