统一 HTML 生成技能 - 融合 phase-prototype 与 frontend-developer 双技能优势
将上游设计方案(phase-design 输出的 DSL JSON / SPEC YAML)转换为可直接运行的单文件 HTML 原型,实现 100% 设计还原。
| 层级 | 技术 |
|---|---|
| ------ | ------ |
| 图标库 | Font Awesome 6.4.0 CDN(多源降级) |
| 图表库 | ECharts 5.4.3(多源降级 + waitForECharts机制) |
| CSS框架 | 纯CSS (零框架依赖) |
| 布局引擎 | 固定侧边栏 240px + 主内容区 margin-left |
| 设计系统 | FTdesign |
unified-html-generator/
├── L7-DesignSystem/ # 设计系统层
│ └── references/
│ ├── ftdesign-tokens.md # Token定义
│ └── icons-mapping.md # Font Awesome映射表
│
├── L8-Components/ # 组件层
│ ├── references/
│ │ ├── component_tokens.md # 400+ 令牌映射
│ │ └── code_quality_checklist.md # 代码质量检查
│ ├── assets/
│ │ ├── css/
│ │ │ ├── ftdesign-vars.css # CSS变量
│ │ │ └── base-components.css # 基础组件样式
│ │ └── js/
│ │ └── chart-loader.js # ECharts加载器
│ └── templates/
│ ├── list-page.html
│ ├── form-page.html
│ ├── detail-page.html
│ └── dashboard-page.html
│
├── L9-Reference/ # 参考层 (精简)
│ └── examples/
│
├── L10-DSL/ # DSL规范层
│ └── references/
│ ├── dsl-schema.json
│ └── dsl-parser.py
│
└── design_engine.py # Python CLI引擎
{
"$schema": "phase-design-dsl-v1.0",
"designSystem": { "name": "ftdesign", "primaryColor": "#005DEB" },
"pages": [{
"id": "user-list",
"name": "用户管理",
"type": "list-page",
"layout": "LayoutPage-2",
"components": [
{ "token": "DISP::Table::selection", "props": {...} },
{ "token": "ENT::Input::search", "props": {...} }
]
}]
}
上游 phase-design 输出的设计解析文档,包含:
单文件 HTML (final.html),包含:
接收输入 (DSL JSON / 设计方案)
↓
Step 1: 解析设计系统
- 读取 designSystem.name → ftdesign-tokens.md
- 获取 CSS 变量、配色、间距
↓
Step 2: 查询组件令牌
- 使用 design_engine.py get_component <token>
- 或查询 component_tokens.md
- 将令牌转换为 HTML 结构
↓
Step 3: 应用布局规范
- 侧边栏固定 240px
- 主内容区 margin-left: 240px
- 白色内容卡片 + 24px padding
↓
Step 4: 整合代码
- 合并 CSS 变量 (ftdesign-vars.css)
- 合并基础组件 (base-components.css)
- 插入 Font Awesome CDN
- 按需插入 ECharts
↓
Step 5: 质量检查
- 代码质量检查清单
- 规范合规性检查
- 可运行性验证
↓
输出 final.html
# 获取设计系统
python3 design_engine.py get_design_system ftdesign
# 获取组件HTML
python3 design_engine.py get_component "GEN::Button::primary"
# 获取DSL映射
python3 design_engine.py get_dsl_mapping Table
# 验证设计
python3 design_engine.py validate list-page '{"layout":"LayoutPage-2"}'
# 列出所有令牌
python3 design_engine.py list_tokens
[类别]::[组件]::[变体]
| 前缀 | 类别 | 示例 |
|---|---|---|
| ------ | ------ | ------ |
GEN:: | General | GEN::Button::primary |
NAV:: | Navigation | NAV::Menu::sidebar |
ENT:: | Entry | ENT::Input::search |
DISP:: | Display | DISP::Table::selection |
LAY:: | Layout | LAY::Toolbar::default |
FB:: | Feedback | FB::Modal::default |
统一使用 Font Awesome 6.4.0:
<!-- 主CDN:BootCDN(国内推荐) -->
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- 备用CDN:unpkg -->
<link rel="stylesheet" href="https://unpkg.com/@fortawesome/fontawesome-free@6.4.0/css/all.min.css">
<!-- 备用CDN:jsdelivr -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css">
(function() {
var cdnSources = [
'https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/all.min.css',
'https://unpkg.com/@fortawesome/fontawesome-free@6.4.0/css/all.min.css',
'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css'
];
function loadCSS(index) {
if (index >= cdnSources.length) {
console.error('Font Awesome: 所有CDN源加载失败');
return;
}
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = cdnSources[index];
link.onload = function() {
console.log('Font Awesome 6.4.0 loaded from: ' + cdnSources[index]);
};
link.onerror = function() {
console.warn('Failed to load: ' + cdnSources[index] + ', trying next...');
loadCSS(index + 1);
};
document.head.appendChild(link);
}
loadCSS(0);
})();
<i class="fa-solid fa-plus"></i> <!-- 新增 -->
<i class="fa-solid fa-pen-to-square"></i> <!-- 编辑 -->
<i class="fa-solid fa-trash-can"></i> <!-- 删除 -->
<i class="fa-solid fa-magnifying-glass"></i> <!-- 搜索 -->
| 功能 | Font Awesome 6.4.0 |
|---|---|
| ------ | ------------------- |
| 仪表盘 | fa-solid fa-chart-line |
| 用户管理 | fa-solid fa-users |
| 角色管理 | fa-solid fa-user-tag |
| 权限管理 | fa-solid fa-shield-halved |
| 系统设置 | fa-solid fa-gears |
| 新增 | fa-solid fa-plus |
| 编辑 | fa-solid fa-pen-to-square |
| 删除 | fa-solid fa-trash-can |
| 搜索 | fa-solid fa-magnifying-glass |
| 筛选 | fa-solid fa-filter |
// ECharts 5.4.3 多CDN源自动降级
(function() {
var sources = [
'https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.min.js',
'https://unpkg.com/echarts@5.4.3/dist/echarts.min.js',
'https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js'
];
var idx = 0;
var startTime = Date.now();
function loadNext() {
if (idx >= sources.length) {
console.error('ECharts: 所有CDN源加载失败,用时 ' + (Date.now() - startTime) + 'ms');
showChartError('图表加载失败,请检查网络连接');
return;
}
var s = document.createElement('script');
s.src = sources[idx];
s.onload = function() {
console.log('ECharts: 从 ' + sources[idx] + ' 加载成功,用时 ' + (Date.now() - startTime) + 'ms');
};
s.onerror = function() {
console.warn('ECharts: ' + sources[idx] + ' 加载失败,切换下一个源');
idx++;
loadNext();
};
document.head.appendChild(s);
idx++;
}
function showChartError(message) {
var errorDiv = document.createElement('div');
errorDiv.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);padding:20px;background:#fff;border:1px solid #e6e8ec;border-radius:4px;box-shadow:0 4px 12px rgba(0,0,0,0.1);z-index:9999;';
errorDiv.innerHTML = '<div style="color:#39485e;font-size:14px;text-align:center;">' + message + '</div>';
document.body.appendChild(errorDiv);
}
console.log('ECharts: 开始加载,共 ' + sources.length + ' 个CDN源');
loadNext();
})();
// 等待ECharts加载完成后初始化图表
function waitForECharts(callback, retry) {
retry = retry || 0;
if (typeof echarts !== 'undefined') {
console.log('ECharts: 库加载完成,开始初始化图表');
callback();
} else if (retry < 100) {
console.log('ECharts: 等待加载中... (' + (retry + 1) + '/100)');
setTimeout(function() {
waitForECharts(callback, retry + 1);
}, 100);
} else {
console.error('ECharts: 加载超时,请检查网络连接');
}
}
// 使用方式
document.addEventListener('DOMContentLoaded', function() {
waitForECharts(function() {
// 所有图表初始化代码必须放在这里
initAllCharts();
});
});
// 图表响应式resize(防抖处理)
var resizeTimer = null;
window.addEventListener('resize', function() {
if (resizeTimer) clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
if (window._ftCharts) {
window._ftCharts.forEach(function(chart) {
if (chart && chart.resize) {
chart.resize();
}
});
}
}, 300);
});
// 初始化图表时注册到全局数组
function initChart(id, option) {
var el = document.getElementById(id);
if (!el) {
console.error('Chart element not found: ' + id);
return null;
}
var chart = echarts.init(el);
chart.setOption(option);
// 注册到全局图表数组
if (!window._ftCharts) window._ftCharts = [];
window._ftCharts.push(chart);
return chart;
}
// 初始化每个图表时必须传入
const FT_CHART_COLORS = ['#005DEB', '#00A870', '#FF9C00', '#E34D59', '#0052D9', '#7B61FF', '#14C9C9'];
// 使用示例
var option = {
color: FT_CHART_COLORS,
series: [...]
};
生成 HTML 后必须检查:
var(--ft-xxx){} 成对匹配fa-solid fa-*| 文件 | 用途 |
|---|---|
| ------ | ------ |
design_engine.py | CLI引擎,查询组件/设计系统/DSL |
L7-DesignSystem/references/ftdesign-tokens.md | Token定义 |
L8-Components/references/component_tokens.md | 400+ 令牌映射表 |
L8-Components/assets/css/ftdesign-vars.css | CSS变量 |
L8-Components/assets/css/base-components.css | 基础组件样式 |
L8-Components/templates/*.html | 页面模板 |
L10-DSL/references/dsl-schema.json | DSL Schema |
本技能融合了两个历史技能的优势:
| 特性 | phase-prototype (龚霞版) | frontend-developer (M版) | 融合后 |
|---|---|---|---|
| ------ | ------------------------- | ------------------------- | -------- |
| 图标库 | Font Awesome 6.4.0 | Font Awesome 6.4.0 | Font Awesome 6.4.0 |
| 架构 | L7-L10 分层 | 统一单层 | L7-L10 分层 |
| CLI引擎 | ✅ design_engine.py | ❌ | 保留 |
| 质量检查 | 基础 | 详细清单 | 融合详细清单 |
| 模板 | 4个完整模板 | 4个完整模板 | 统一优化 |
| CSS变量 | FTdesign | FTdesign | 完全一致 |
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>用户管理</title>
<!-- Font Awesome 6.4.0 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css">
<style>
/* FTdesign CSS变量 */
:root { --ft-primary: #005DEB; ... }
/* 基础组件样式 */
.ft-btn { ... }
.ft-table { ... }
</style>
</head>
<body>
<aside class="ft-sidebar">...</aside>
<main class="ft-main">
<!-- 页面内容 -->
</main>
</body>
</html>
共 1 个版本