diff --git a/reports/advanced-drag-layout-20260909/01-lower-grid.png b/reports/advanced-drag-layout-20260909/01-lower-grid.png
new file mode 100644
index 0000000..deb5196
Binary files /dev/null and b/reports/advanced-drag-layout-20260909/01-lower-grid.png differ
diff --git a/reports/advanced-drag-layout-20260909/02-horizontal-scroll.png b/reports/advanced-drag-layout-20260909/02-horizontal-scroll.png
new file mode 100644
index 0000000..1294057
Binary files /dev/null and b/reports/advanced-drag-layout-20260909/02-horizontal-scroll.png differ
diff --git a/reports/advanced-drag-layout-20260909/failure.png b/reports/advanced-drag-layout-20260909/failure.png
new file mode 100644
index 0000000..f5b6f37
Binary files /dev/null and b/reports/advanced-drag-layout-20260909/failure.png differ
diff --git a/reports/advanced-drag-layout-20260909/index.html b/reports/advanced-drag-layout-20260909/index.html
new file mode 100644
index 0000000..15e81f7
--- /dev/null
+++ b/reports/advanced-drag-layout-20260909/index.html
@@ -0,0 +1,8 @@
+
高级编排拖动边界修复验证
+高级编排拖动边界修复验证
2026-09-09 · 开发环境 127.0.0.1:6180 · 验证通过
+原因:节点拖动使用画布可见区域的宽高限制坐标,未使用完整滚动区域,也未考虑拖动时的滚动偏移。下方仍有网格时,节点会提前被拦住。
+修复:边界按完整画布及节点实际尺寸计算,鼠标坐标转换为滚动后的画布坐标。重新选中节点等界面重绘保留同一工程的滚动位置;切换工程时从起点显示。
+| 检查项 | 结果 |
|---|
| 拖到下方网格 | 通过:原限制 y=365,实际拖到 y=535.75,节点与连线正常显示。 |
| 拖动中滚动画布 | 通过:滚动 180px、鼠标移动 5px,节点准确移动 185px。 |
| 重新选中节点 | 通过:节点坐标及画布滚动位置保持。 |
| 窄窗口横向滚动后拖动 | 通过:节点从 (769,307) 移至 (779,317),与鼠标 10px 位移一致。 |
| 基础/高级编排切换 | 通过:返回高级编排后保留调整后的节点坐标。 |
| 构建及检查 | pnpm run build 通过,包含类型检查与模型编辑器生成包校验;git diff --check 通过。 |
+自动化测试结果
下方网格拖动结果
+横向滚动后小幅拖动
+测试范围与数据
使用账号文件中的内部维护账号,在已有测试工程 410 上操作,仅修改临时浏览器草稿,未点击保存或发布。没有新增或删除业务记录;本轮不包含服务端保存后重载验收。
复现脚本:ute2e/tools/advanced-drag-layout.mjs。未修改接口、数据库或训练执行逻辑。
diff --git a/reports/advanced-drag-layout-20260909/results.json b/reports/advanced-drag-layout-20260909/results.json
new file mode 100644
index 0000000..218c78a
--- /dev/null
+++ b/reports/advanced-drag-layout-20260909/results.json
@@ -0,0 +1,40 @@
+{
+ "passed": true,
+ "projectId": "410",
+ "accountType": "内部维护",
+ "initial": {
+ "x": 27,
+ "y": 48
+ },
+ "checks": [
+ {
+ "name": "拖入下方网格,拖动中滚动不跳位",
+ "result": "PASS",
+ "before": 350.75,
+ "after": 535.75,
+ "scrollDelta": 180,
+ "formerLimit": 365
+ },
+ {
+ "name": "选择节点后保留画布滚动位置",
+ "result": "PASS"
+ },
+ {
+ "name": "窄窗口横向滚动后拖动不跳位",
+ "result": "PASS",
+ "previous": {
+ "x": 769,
+ "y": 307
+ },
+ "next": {
+ "x": 779,
+ "y": 317
+ }
+ },
+ {
+ "name": "切换编排模式保留节点坐标",
+ "result": "PASS"
+ }
+ ],
+ "dataChanges": "仅调整已有测试工程的浏览器草稿,未点击保存或发布。"
+}
\ No newline at end of file
diff --git a/reports/digital-human-open-api-20260908/01-open-applications.png b/reports/digital-human-open-api-20260908/01-open-applications.png
new file mode 100644
index 0000000..abf7ff5
Binary files /dev/null and b/reports/digital-human-open-api-20260908/01-open-applications.png differ
diff --git a/reports/digital-human-open-api-20260908/02-application-grants.png b/reports/digital-human-open-api-20260908/02-application-grants.png
new file mode 100644
index 0000000..1e9aa98
Binary files /dev/null and b/reports/digital-human-open-api-20260908/02-application-grants.png differ
diff --git a/reports/digital-human-open-api-20260908/03-open-api-docs.png b/reports/digital-human-open-api-20260908/03-open-api-docs.png
new file mode 100644
index 0000000..470f14a
Binary files /dev/null and b/reports/digital-human-open-api-20260908/03-open-api-docs.png differ
diff --git a/reports/digital-human-open-api-20260908/04-workshop-library.png b/reports/digital-human-open-api-20260908/04-workshop-library.png
new file mode 100644
index 0000000..983da74
Binary files /dev/null and b/reports/digital-human-open-api-20260908/04-workshop-library.png differ
diff --git a/reports/digital-human-open-api-20260908/05-video-preview.png b/reports/digital-human-open-api-20260908/05-video-preview.png
new file mode 100644
index 0000000..257e3b7
Binary files /dev/null and b/reports/digital-human-open-api-20260908/05-video-preview.png differ
diff --git a/reports/digital-human-open-api-20260908/06-persisted-binding.png b/reports/digital-human-open-api-20260908/06-persisted-binding.png
new file mode 100644
index 0000000..890a713
Binary files /dev/null and b/reports/digital-human-open-api-20260908/06-persisted-binding.png differ
diff --git a/reports/digital-human-open-api-20260908/07-generation-settings.png b/reports/digital-human-open-api-20260908/07-generation-settings.png
new file mode 100644
index 0000000..2976442
Binary files /dev/null and b/reports/digital-human-open-api-20260908/07-generation-settings.png differ
diff --git a/reports/digital-human-open-api-20260908/08-job-restored.png b/reports/digital-human-open-api-20260908/08-job-restored.png
new file mode 100644
index 0000000..e16ad47
Binary files /dev/null and b/reports/digital-human-open-api-20260908/08-job-restored.png differ
diff --git a/reports/digital-human-open-api-20260908/09-generated-truck-narration.png b/reports/digital-human-open-api-20260908/09-generated-truck-narration.png
new file mode 100644
index 0000000..ae0073a
Binary files /dev/null and b/reports/digital-human-open-api-20260908/09-generated-truck-narration.png differ
diff --git a/reports/digital-human-open-api-20260908/10-playback-fox.png b/reports/digital-human-open-api-20260908/10-playback-fox.png
new file mode 100644
index 0000000..eb73ce7
Binary files /dev/null and b/reports/digital-human-open-api-20260908/10-playback-fox.png differ
diff --git a/reports/digital-human-open-api-20260908/10-playback-truck.png b/reports/digital-human-open-api-20260908/10-playback-truck.png
new file mode 100644
index 0000000..d5b0faa
Binary files /dev/null and b/reports/digital-human-open-api-20260908/10-playback-truck.png differ
diff --git a/reports/digital-human-open-api-20260908/cleanup-results.json b/reports/digital-human-open-api-20260908/cleanup-results.json
new file mode 100644
index 0000000..ba3b7e8
--- /dev/null
+++ b/reports/digital-human-open-api-20260908/cleanup-results.json
@@ -0,0 +1,35 @@
+{
+ "cleaned": [
+ {
+ "type": "temporary-platform-video",
+ "id": 51,
+ "deleted": true,
+ "filesRetained": true,
+ "jobHistoryRetained": true
+ },
+ {
+ "type": "temporary-platform-video",
+ "id": 52,
+ "deleted": true,
+ "filesRetained": true,
+ "jobHistoryRetained": true
+ },
+ {
+ "type": "isolated-test-application",
+ "appId": "AP_617ADA153EFCA5EBC66DA5AF",
+ "enabled": false
+ }
+ ],
+ "retained": {
+ "configuredApplication": "AP_238179E0A10F97927EA49FA3",
+ "workshopProjectIds": [
+ "410",
+ "411"
+ ],
+ "draftAssignmentIds": [
+ "52",
+ "53"
+ ],
+ "reason": "Teaching API has no draft delete endpoint; fixed-version training copies and controlled imported video copies remain for review. No learner runs were created. Platform video deletion retains files and job audit by existing contract."
+ }
+}
\ No newline at end of file
diff --git a/reports/digital-human-open-api-20260908/failure.png b/reports/digital-human-open-api-20260908/failure.png
new file mode 100644
index 0000000..2dd2562
Binary files /dev/null and b/reports/digital-human-open-api-20260908/failure.png differ
diff --git a/reports/digital-human-open-api-20260908/fox-narration.mp4 b/reports/digital-human-open-api-20260908/fox-narration.mp4
new file mode 100644
index 0000000..a24bf07
Binary files /dev/null and b/reports/digital-human-open-api-20260908/fox-narration.mp4 differ
diff --git a/reports/digital-human-open-api-20260908/index.html b/reports/digital-human-open-api-20260908/index.html
new file mode 100644
index 0000000..d993c19
--- /dev/null
+++ b/reports/digital-human-open-api-20260908/index.html
@@ -0,0 +1,43 @@
+
+数字人开放 API 与数字车间讲解联调报告
+开发环境实测 · 2026-09-08—09 · 资料 → 原型 → 设计 → 开发 → 测试
数字人开放 API 与数字车间讲解联调
三阶段实施完成:独立应用授权、真实资源库、服务端生成成片并绑定训练步骤。
联调 APPID:AP_238179E0A10F97927EA49FA3。密钥已配置在数字车间服务端加密存储,报告不包含密钥、令牌或账号口令。
3 / 3实施阶段完成
533后端自动化检查通过
18真实接口边界检查
2发布版本视频播放验证
+
+实施结果
| 阶段 | 交付内容 | 结果 |
+| 1. 数字人开放平台 | 开放应用管理;AP_ APPID;一次性密钥;重置/停用/令牌撤销;接口 Scope、形象/音色/背景/目录/视频授权;限频与并发;公开 API 文档和 OpenAPI 下载。 | 通过 |
+| 2. 数字车间接入 | 数字人类型独立配置;Auth 加密保管 Secret;Tran 使用受保护的内部短期令牌接口;真实资源分页、视频预览、导入、步骤绑定、保存和刷新。 | 通过 |
+| 3. 现场生成成片 | 服务端 TTS + 配对 Viewer + FFmpeg;数据库任务/租约/幂等;关闭刷新恢复、取消重试;生成背景与字幕;成片保存后导入;发布版本受控播放。 | 通过 |
+
公开文档:数字人开放 API 说明。应用管理:数字人系统 → 系统设置 → 开放应用。数字车间:系统管理 → 接口对接 → 数字人。
+
+真实业务链路
| 测试副本 | 过程 | 最终证据 |
+| 狐狸 · 工程 410 | 资源库选择真实成片 → 播放 → 导入为 VIDEO → 绑定第一步 → 保存 → 刷新验证 → 发布 → 对抗训练预览播放。 | 发布版本 466,预览任务 52;640 × 360,4.52 秒。 |
+| 牛奶卡车 · 工程 411 | 选择形象与音色、数字化教室背景 → 输入文稿 → 提交生成 → 关闭/刷新 → 恢复同一任务 → 成片预览 → 导入绑定 → 发布 → 实装实训预览播放。 | 发布版本 467,预览任务 53;1280 × 720,4.60 秒。 |
+
以下视频为本次接口下载的真实生成文件,可直接播放。数字车间保存了独立的受控文件副本;数字人平台临时视频清理后,固定发布版本仍能播放。
+
+过程发现与修复
| 问题 | 修复与验证 |
+| 并发资源查询占满小连接池 | 调用审计移到完整请求释放数据库连接后执行;三个目录并发真实请求 516 ms 完成,均为 200,补充顺序回归。 |
+| 本地缓存缺失时无法读取远端文件 | 复用统一文件服务的受控取回及完整性校验;不再仅判断本地路径。真正缺失的背景文件给出明确失败原因。 |
+| 教学资源不识别 fsvc:// | 在原固定版本、数据权限及考试白名单基础上支持统一文件服务地址,验证发布后实际播放及跨版本拒绝访问。 |
+| 生成提交后关闭/刷新导致上下文丢失 | 保存工程、步骤、APPID、请求键与远程任务映射;重开恢复,提交结果不确定时用原幂等键确认,应用切换不能串用任务。 |
+| 旧视频绑定与已删除步骤 | 切换来源清除旧活动绑定;生成前确认步骤存在与版本一致;数字人来源没有 READY VIDEO 时不能发布。 |
+| 上传凭证篡改检查存在偶发失败 | 拒绝带非规范补位的 Base64 表示,保持原 HMAC、人员/工程/版本和文件摘要校验;已有失败用例回归通过。 |
+
两条历史背景记录(85、79)的源文件在当前环境无法取回,未修改原资料。本次为联调应用授权实际可用的“数字化教室”背景(11)。缺失素材需补传后使用,系统不会伪造成功结果。
+
+
+
+验证范围与证据文件
- Python:31 项通过;Auth:123 项通过;Tran:379 项通过。两个前端通过类型检查与生产构建,Java 包构建通过。
- 真实接口:未认证拒绝、应用/用户令牌隔离、跨应用生成视频拒绝、Range、公开契约、密钥轮换与旧令牌撤销、并发资源查询、删除步骤/旧版本/只读管理员拒绝、内部服务密钥保护及搜索边界。
- 任务幂等、并发、取消/重试、跨应用任务隔离和租约失效由自动化回归覆盖;真实浏览器覆盖实际生成、恢复、导入及发布后播放。
- 没有把本次视频播放测试扩写为完整实装识别或对抗计分验收。纯本地对抗演示尚无正式发布版本引用,本次不重构该业务域;正式任务宿主已补充讲解媒体入口。
Java 测试汇总 · 真实开放接口检查 · 数字车间权限与版本边界 · 编辑器导入与生成 · 发布播放验证 · 清理与残留记录
+
+部署、清理与保留数据
开发库已执行数字人 033、数字车间 037/038,增量 DDL、完整 SQL、设计和接口文档同步。成片服务使用配置的共享数字人 Viewer、TTS、FFmpeg 与受控文件服务;运行浏览器及加密密钥文件需要随部署配置,不能只复制前端。
已清理数字人平台临时视频 51/52,并停用隔离测试应用;按平台原有删除契约,文件及任务审计历史保留。联调应用继续启用,APPID/密钥已配置,供继续使用。
数字车间保留测试副本 410/411、其独立导入视频及草稿教学任务 52/53。现有教学 API 没有草稿删除入口,保留清单供检查;未创建学员运行、成绩,未修改原有狐狸/卡车模型、场景或训练工程。两个草稿任务尚未面向学员发布。
本报告仅对应开发环境。修改尚未提交或推送 Git。
+
diff --git a/reports/digital-human-open-api-20260908/java-test-results.json b/reports/digital-human-open-api-20260908/java-test-results.json
new file mode 100644
index 0000000..225d980
--- /dev/null
+++ b/reports/digital-human-open-api-20260908/java-test-results.json
@@ -0,0 +1,14 @@
+{
+ "ut_auth": {
+ "tests": 123,
+ "failures": 0,
+ "errors": 0,
+ "skipped": 0
+ },
+ "ut_tran": {
+ "tests": 379,
+ "failures": 0,
+ "errors": 0,
+ "skipped": 0
+ }
+}
\ No newline at end of file
diff --git a/reports/digital-human-open-api-20260908/playback-results.json b/reports/digital-human-open-api-20260908/playback-results.json
new file mode 100644
index 0000000..32ca0eb
--- /dev/null
+++ b/reports/digital-human-open-api-20260908/playback-results.json
@@ -0,0 +1,26 @@
+[
+ {
+ "projectId": "410",
+ "publishedVersionId": "466",
+ "assignmentId": "52",
+ "channel": "CONFRONTATION",
+ "assetCode": "DH_B66C365A317E448BBD7D513B5DC65FFF",
+ "media": {
+ "duration": 4.52,
+ "width": 640,
+ "height": 360
+ }
+ },
+ {
+ "projectId": "411",
+ "publishedVersionId": "467",
+ "assignmentId": "53",
+ "channel": "PHYSICAL",
+ "assetCode": "DH_C20425C1EDE14E7DB88BAD697E3D5AFD",
+ "media": {
+ "duration": 4.6,
+ "width": 1280,
+ "height": 720
+ }
+ }
+]
\ No newline at end of file
diff --git a/reports/digital-human-open-api-20260908/report-overview.png b/reports/digital-human-open-api-20260908/report-overview.png
new file mode 100644
index 0000000..7c14e52
Binary files /dev/null and b/reports/digital-human-open-api-20260908/report-overview.png differ
diff --git a/reports/digital-human-open-api-20260908/security-results.json b/reports/digital-human-open-api-20260908/security-results.json
new file mode 100644
index 0000000..08b6601
--- /dev/null
+++ b/reports/digital-human-open-api-20260908/security-results.json
@@ -0,0 +1,59 @@
+{
+ "checks": [
+ {
+ "name": "Unauthenticated catalog denied",
+ "status": 401
+ },
+ {
+ "name": "Other application cannot download generated video",
+ "status": 404
+ },
+ {
+ "name": "Application token cannot access management",
+ "status": 401
+ },
+ {
+ "name": "User token cannot access application API",
+ "status": 401
+ },
+ {
+ "name": "Controlled Range download",
+ "status": 206
+ },
+ {
+ "name": "Public OpenAPI schema",
+ "status": 200
+ },
+ {
+ "name": "Old token revoked after secret rotation",
+ "status": 401
+ },
+ {
+ "name": "Old secret rejected",
+ "status": 401
+ },
+ {
+ "name": "Rotated credentials accepted",
+ "status": 200
+ },
+ {
+ "name": "Parallel resource avatars",
+ "status": 200
+ },
+ {
+ "name": "Parallel resource voices",
+ "status": 200
+ },
+ {
+ "name": "Parallel resource backgrounds",
+ "status": 200
+ },
+ {
+ "name": "Concurrent resource requests complete",
+ "milliseconds": 516
+ }
+ ],
+ "appId": "AP_238179E0A10F97927EA49FA3",
+ "isolatedAppId": "AP_617ADA153EFCA5EBC66DA5AF",
+ "time": "2026-09-08T17:14:33.315Z"
+}
\ No newline at end of file
diff --git a/reports/digital-human-open-api-20260908/truck-narration.mp4 b/reports/digital-human-open-api-20260908/truck-narration.mp4
new file mode 100644
index 0000000..f6f1b20
Binary files /dev/null and b/reports/digital-human-open-api-20260908/truck-narration.mp4 differ
diff --git a/reports/digital-human-open-api-20260908/workshop-boundaries.json b/reports/digital-human-open-api-20260908/workshop-boundaries.json
new file mode 100644
index 0000000..92eaeab
--- /dev/null
+++ b/reports/digital-human-open-api-20260908/workshop-boundaries.json
@@ -0,0 +1,22 @@
+[
+ {
+ "name": "Deleted step cannot create generation",
+ "status": 400
+ },
+ {
+ "name": "Stale project version rejected",
+ "status": 409
+ },
+ {
+ "name": "Administrator viewing permission does not grant editing",
+ "status": 403
+ },
+ {
+ "name": "Internal runtime endpoint requires service key",
+ "status": 401
+ },
+ {
+ "name": "Search keyword does not alter fixed endpoint path",
+ "status": 200
+ }
+]
\ No newline at end of file
diff --git a/reports/digital-human-open-api-20260908/workshop-results.json b/reports/digital-human-open-api-20260908/workshop-results.json
new file mode 100644
index 0000000..ab601dd
--- /dev/null
+++ b/reports/digital-human-open-api-20260908/workshop-results.json
@@ -0,0 +1,27 @@
+{
+ "fixtures": [
+ {
+ "key": "fox",
+ "id": "410",
+ "name": "APE2E-数字人讲解-狐狸-20260909"
+ },
+ {
+ "key": "truck",
+ "id": "411",
+ "name": "APE2E-数字人讲解-牛奶-20260909"
+ }
+ ],
+ "foxVideoAssetCode": "DH_B66C365A317E448BBD7D513B5DC65FFF",
+ "truckVideoAssetCode": "DH_C20425C1EDE14E7DB88BAD697E3D5AFD",
+ "tests": [
+ "real catalog",
+ "video preview",
+ "import and persist",
+ "reload binding",
+ "server generation",
+ "close and reload task",
+ "background and captions",
+ "generated import and persist"
+ ],
+ "time": "2026-09-08T17:08:55.642Z"
+}
\ No newline at end of file
diff --git a/reports/narration-dialog-layout-20260909/01-desktop-preview.png b/reports/narration-dialog-layout-20260909/01-desktop-preview.png
new file mode 100644
index 0000000..ce986a5
Binary files /dev/null and b/reports/narration-dialog-layout-20260909/01-desktop-preview.png differ
diff --git a/reports/narration-dialog-layout-20260909/02-short-preview.png b/reports/narration-dialog-layout-20260909/02-short-preview.png
new file mode 100644
index 0000000..e9eb6cf
Binary files /dev/null and b/reports/narration-dialog-layout-20260909/02-short-preview.png differ
diff --git a/reports/narration-dialog-layout-20260909/03-mobile-preview.png b/reports/narration-dialog-layout-20260909/03-mobile-preview.png
new file mode 100644
index 0000000..60c559b
Binary files /dev/null and b/reports/narration-dialog-layout-20260909/03-mobile-preview.png differ
diff --git a/reports/narration-dialog-layout-20260909/04-dark-preview.png b/reports/narration-dialog-layout-20260909/04-dark-preview.png
new file mode 100644
index 0000000..7b40d50
Binary files /dev/null and b/reports/narration-dialog-layout-20260909/04-dark-preview.png differ
diff --git a/reports/narration-dialog-layout-20260909/05-generation-form.png b/reports/narration-dialog-layout-20260909/05-generation-form.png
new file mode 100644
index 0000000..bf8e023
Binary files /dev/null and b/reports/narration-dialog-layout-20260909/05-generation-form.png differ
diff --git a/reports/narration-dialog-layout-20260909/failure.png b/reports/narration-dialog-layout-20260909/failure.png
new file mode 100644
index 0000000..6c29ec9
Binary files /dev/null and b/reports/narration-dialog-layout-20260909/failure.png differ
diff --git a/reports/narration-dialog-layout-20260909/index.html b/reports/narration-dialog-layout-20260909/index.html
new file mode 100644
index 0000000..7c81a16
--- /dev/null
+++ b/reports/narration-dialog-layout-20260909/index.html
@@ -0,0 +1,12 @@
+数字人讲解弹窗布局验证
+数字人讲解弹窗布局验证
2026-09-09 · 布局修复通过 · 开发环境 6180 → 6100 Gateway
+原弹窗叠加固定高度列表和视频后超过窗口。现限制弹窗最大高度,标题及底部关闭按钮固定,正文独立滚动;列表改为最大高度,少量记录不再保留大块空白。窄屏筛选和生成表单改为单列,预览视频保持比例并适应窗口。
+| 检查 | 结果 |
|---|
| 1920 × 911 桌面 | 通过,列表、视频与底部关闭完整显示。 |
| 1366 × 600 矮窗口 | 通过,正文滚动,关闭按钮保留在窗口内。 |
| 390 × 844 手机宽度 | 通过,筛选单列,表格可横向滚动,弹窗不越界。 |
| 1366 × 768 暗色主题 | 通过,使用系统主题切换检查。 |
| 生成表单、生成任务与关闭 | 通过,可访问表单、切换页签并关闭。 |
| 实际授权视频 | 1920 × 1080,175.76 秒;预览接口 HTTP 200,视频元数据及画面正常。 |
| 本机与局域网 | 本机完成操作;192.168.31.168:6180 入口 HTTP 200。 |
| 构建 | pnpm run build 通过,包含类型检查及模型编辑器生成包校验。 |
+机器验证结果
+桌面预览
+矮窗口滚动
+手机宽度
+暗色主题
+生成表单
+另外观察到的问题
首条“数控机床产品讲解”的预览接口返回 404,本轮使用第二条授权视频验证布局,未修复资源文件问题。另外一次进入弹窗前,测试工程保存提示封面生成或上传失败,内容已保存并保留原封面;本轮未修改封面功能。
+测试数据与范围
使用账号文件中的内部维护账号及已有测试工程 410。打开数字人服务前,编辑器按既有逻辑保存测试工程。未提交新生成任务、导入绑定或发布。仅调整弹窗布局,不涉及 API 或数据库改动。本轮没有重新验收完整成片生成流程。
复现脚本:ute2e/tools/narration-dialog-layout.mjs。
diff --git a/reports/narration-dialog-layout-20260909/results.json b/reports/narration-dialog-layout-20260909/results.json
new file mode 100644
index 0000000..d1b173d
--- /dev/null
+++ b/reports/narration-dialog-layout-20260909/results.json
@@ -0,0 +1,73 @@
+{
+ "passed": true,
+ "projectId": "410",
+ "accountType": "内部维护",
+ "checks": [
+ {
+ "label": "01-desktop-preview",
+ "viewport": {
+ "width": 1920,
+ "height": 911
+ },
+ "theme": "light",
+ "result": "PASS",
+ "video": {
+ "width": 1920,
+ "height": 1080,
+ "duration": 175.76
+ }
+ },
+ {
+ "label": "02-short-preview",
+ "viewport": {
+ "width": 1366,
+ "height": 600
+ },
+ "theme": "light",
+ "result": "PASS",
+ "video": {
+ "width": 1920,
+ "height": 1080,
+ "duration": 175.76
+ }
+ },
+ {
+ "label": "03-mobile-preview",
+ "viewport": {
+ "width": 390,
+ "height": 844
+ },
+ "theme": "light",
+ "result": "PASS",
+ "video": {
+ "width": 1920,
+ "height": 1080,
+ "duration": 175.76
+ }
+ },
+ {
+ "label": "04-dark-preview",
+ "viewport": {
+ "width": 1366,
+ "height": 768
+ },
+ "theme": "dark",
+ "result": "PASS",
+ "video": {
+ "width": 1920,
+ "height": 1080,
+ "duration": 175.76
+ }
+ },
+ {
+ "label": "生成表单、任务页签与底部关闭",
+ "result": "PASS"
+ },
+ {
+ "label": "局域网入口",
+ "result": "PASS"
+ }
+ ],
+ "dataChanges": "使用已有测试工程和授权视频。打开数字人服务前编辑器按既有逻辑保存测试工程;未提交生成、导入绑定或发布。",
+ "observations": ["首条数控机床产品讲解视频预览返回 HTTP 404,改用第二条真实授权视频完成布局验证。", "一次打开弹窗前保存测试工程时出现封面生成或上传失败提示,内容已保存并保留原封面;本轮未修改封面功能。"]
+}
diff --git a/reports/open-platform-pdf-20260909/01-pdf-download.png b/reports/open-platform-pdf-20260909/01-pdf-download.png
new file mode 100644
index 0000000..05a9bb5
Binary files /dev/null and b/reports/open-platform-pdf-20260909/01-pdf-download.png differ
diff --git a/reports/open-platform-pdf-20260909/02-pdf-parameters.png b/reports/open-platform-pdf-20260909/02-pdf-parameters.png
new file mode 100644
index 0000000..a864bcb
Binary files /dev/null and b/reports/open-platform-pdf-20260909/02-pdf-parameters.png differ
diff --git a/reports/open-platform-pdf-20260909/digital-human-open-api.pdf b/reports/open-platform-pdf-20260909/digital-human-open-api.pdf
new file mode 100644
index 0000000..a456aae
Binary files /dev/null and b/reports/open-platform-pdf-20260909/digital-human-open-api.pdf differ
diff --git a/reports/open-platform-pdf-20260909/index.html b/reports/open-platform-pdf-20260909/index.html
new file mode 100644
index 0000000..5c409cb
--- /dev/null
+++ b/reports/open-platform-pdf-20260909/index.html
@@ -0,0 +1,18 @@
+
+开放 API 文档 PDF 验证报告
+
+开放 API 文档 PDF 验证报告
2026-09-09 · 后端生成,页面直接下载 · 验证通过
+文档页新增“导出 PDF”。网页与 PDF 共用后端接口说明,输入参数来自 OpenAPI 契约。保留原有契约下载入口。无需打印窗口、外部转换服务或数据库变更。
+查看下载样例(29 页) · 浏览器测试结果
+| 检查项 | 结果 |
+| 匿名文档页加载与实际文件下载 | 通过:13 个接口,PDF 文件头、文件名与响应类型正确。 |
+| 失败提示与重试 | 通过:浏览器拦截下载请求模拟 503,显示 message;按钮恢复后可重新下载。 |
+| 目录滚动联动 | 通过:滚动至第 9 个接口时,左侧目录对应选中。 |
+| 后端自动化测试 | 通过:接口覆盖与契约一致;每个接口包含描述、输入、输出、错误码;14 个书签;字体嵌入;缓存返回一致。 |
+| 前端类型检查 | 通过:vue-tsc --noEmit。 |
+| PDF 排版检查 | 29 页全部渲染检查,中文、表格、示例与页码可读,无内容重叠或裁切。 |
+
+页面下载
+PDF 参数表预览
+实施与验证范围
后端使用 ReportLab,随包提供获许可的中文字体并嵌入 PDF。新增公开文档数据接口与 PDF 下载接口,仅输出静态说明和占位示例。开发服务已重启并实测;本轮未重复测试数字人业务生成流程,也未部署到生产环境。
+复现脚本:ute2e/tools/open-platform-pdf.mjs;后端测试:tests/test_open_api_documentation.py。
diff --git a/reports/open-platform-pdf-20260909/results.json b/reports/open-platform-pdf-20260909/results.json
new file mode 100644
index 0000000..d82f0c9
--- /dev/null
+++ b/reports/open-platform-pdf-20260909/results.json
@@ -0,0 +1,9 @@
+{
+ "passed": true,
+ "endpoints": 13,
+ "backendPdfDownload": true,
+ "errorMessage": true,
+ "retry": true,
+ "scrollSync": true,
+ "scriptErrors": []
+}
\ No newline at end of file
diff --git a/reports/open-platform-style-20260909/01-applications-light.png b/reports/open-platform-style-20260909/01-applications-light.png
new file mode 100644
index 0000000..4149ab2
Binary files /dev/null and b/reports/open-platform-style-20260909/01-applications-light.png differ
diff --git a/reports/open-platform-style-20260909/02-docs-overview-light.png b/reports/open-platform-style-20260909/02-docs-overview-light.png
new file mode 100644
index 0000000..86cc1f7
Binary files /dev/null and b/reports/open-platform-style-20260909/02-docs-overview-light.png differ
diff --git a/reports/open-platform-style-20260909/03-generation-document.png b/reports/open-platform-style-20260909/03-generation-document.png
new file mode 100644
index 0000000..316252e
Binary files /dev/null and b/reports/open-platform-style-20260909/03-generation-document.png differ
diff --git a/reports/open-platform-style-20260909/04-docs-dark.png b/reports/open-platform-style-20260909/04-docs-dark.png
new file mode 100644
index 0000000..81df667
Binary files /dev/null and b/reports/open-platform-style-20260909/04-docs-dark.png differ
diff --git a/reports/open-platform-style-20260909/05-applications-dark.png b/reports/open-platform-style-20260909/05-applications-dark.png
new file mode 100644
index 0000000..54a0626
Binary files /dev/null and b/reports/open-platform-style-20260909/05-applications-dark.png differ
diff --git a/reports/open-platform-style-20260909/06-application-dialog-dark.png b/reports/open-platform-style-20260909/06-application-dialog-dark.png
new file mode 100644
index 0000000..8b3c139
Binary files /dev/null and b/reports/open-platform-style-20260909/06-application-dialog-dark.png differ
diff --git a/reports/open-platform-style-20260909/07-docs-mobile.png b/reports/open-platform-style-20260909/07-docs-mobile.png
new file mode 100644
index 0000000..df9b064
Binary files /dev/null and b/reports/open-platform-style-20260909/07-docs-mobile.png differ
diff --git a/reports/open-platform-style-20260909/08-docs-mobile-parameters.png b/reports/open-platform-style-20260909/08-docs-mobile-parameters.png
new file mode 100644
index 0000000..e104874
Binary files /dev/null and b/reports/open-platform-style-20260909/08-docs-mobile-parameters.png differ
diff --git a/reports/open-platform-style-20260909/09-generation-input.png b/reports/open-platform-style-20260909/09-generation-input.png
new file mode 100644
index 0000000..a7635e7
Binary files /dev/null and b/reports/open-platform-style-20260909/09-generation-input.png differ
diff --git a/reports/open-platform-style-20260909/10-applications-spacing.png b/reports/open-platform-style-20260909/10-applications-spacing.png
new file mode 100644
index 0000000..3a46032
Binary files /dev/null and b/reports/open-platform-style-20260909/10-applications-spacing.png differ
diff --git a/reports/open-platform-style-20260909/11-docs-scroll-sync.png b/reports/open-platform-style-20260909/11-docs-scroll-sync.png
new file mode 100644
index 0000000..ced2a8f
Binary files /dev/null and b/reports/open-platform-style-20260909/11-docs-scroll-sync.png differ
diff --git a/reports/open-platform-style-20260909/index.html b/reports/open-platform-style-20260909/index.html
new file mode 100644
index 0000000..b47aecd
--- /dev/null
+++ b/reports/open-platform-style-20260909/index.html
@@ -0,0 +1,28 @@
+
+
+开放应用与 API 文档调整验收 · 2026-09-09
+
+
+验收通过开放应用与 API 文档调整
数字人服务系统 · 2026-09-09 · 开发环境真实页面验证
开放应用统一使用现有系统的标题、搜索工具栏、列表和底部分页。API 文档从开放应用页内进入,采用目录导航与完整正文,每个接口直接展示描述、输入参数、输出参数、返回示例和错误码。
13 / 13业务接口完整展示
8浏览器检查组通过
33相关后端测试通过
6真实数据库搜索检查通过
+本次变更与验证
| 项目 | 结果 |
+| 页面风格 | 使用统一语义色、系统页面容器、Element Plus 表格、工具按钮和分页;浅色、深色均截图检查。 |
+| 文档入口 | 菜单仅保留开放应用,右上角按钮进入文档二级页;当前菜单继续高亮开放应用,返回按钮可正常回到列表。 |
+| 文档内容 | 13 个接口与运行中的 OpenAPI 契约逐项比对;无折叠组件,每个接口均包含四个章节和返回示例。参数类型、默认值与范围取自服务端契约。 |
+| 参数与错误码 | 明确请求头、路径、查询和 JSON 参数;注明幂等键必填、视频尺寸范围、授权要求;区分 HTTP 业务码、任务失败码和二进制响应。 |
+| 移动端与外部访问 | 公共文档 /developer 无需登录;390px 窄屏无页面横向溢出,宽参数表在表格内滚动。 |
+| 附带修复 | KingBase MySQL 兼容模式下,原 contains 查询中的 || 被解释为逻辑运算,造成搜索返回全部数据。改为绑定完整 LIKE 参数,并转义通配符;应用名称、APPID 和授权资源搜索验证通过。 |
+
前端 pnpm exec vue-tsc --noEmit 通过。后端菜单测试 5 项、迁移测试 23 项、开放平台测试 5 项通过;后者包含新增关键词和字面通配符回归用例。真实 KingBase 对应用及五类资源的不匹配关键词均返回 0 条。浏览器无未捕获脚本错误。
数据库迁移 20260909_034_open_api_docs_secondary.sql 已在开发库执行并复核:软删除文档菜单及其权限关联,保留访问权限本身;恢复默认菜单不会重新出现文档。全量 DDL 和接口说明已同步。
环境说明:测试期间发现开发配置使用 2 个数据库连接且无溢出连接,后台任务和页面并发曾触发连接池等待。本次运行进程按代码默认值使用 pool_size=10、max_overflow=20,未修改持久化连接配置。本轮未重复视频生成业务测试,也未更改应用密钥、授权数据或成片协议。
浏览器检查结果 JSON · 可复跑的 E2E 脚本
+页面截图
点击截图可查看原图。
+
开放应用:标题、搜索、重置、新建、列表和底部分页统一。
+
文档二级页:左侧系统菜单不展示文档,页内目录提供接口定位。
+
接口正文:请求方式、路径、权限和输入参数表直接呈现。
+
文档深色主题。
+
开放应用深色主题。
+
配置弹窗沿用系统主题,授权资源区域正常显示;测试未保存修改。
+
移动端:公共文档与目录。
+
移动端:宽参数表内部滚动,页面本身不溢出。
+
+单个接口完整展示
以“提交成片生成任务”为例,以下完整截图覆盖描述、输入参数、输出参数、返回示例和错误码。
+
diff --git a/reports/open-platform-style-20260909/report-overview.png b/reports/open-platform-style-20260909/report-overview.png
new file mode 100644
index 0000000..e0bc799
Binary files /dev/null and b/reports/open-platform-style-20260909/report-overview.png differ
diff --git a/reports/open-platform-style-20260909/results.json b/reports/open-platform-style-20260909/results.json
new file mode 100644
index 0000000..348431e
--- /dev/null
+++ b/reports/open-platform-style-20260909/results.json
@@ -0,0 +1,16 @@
+{
+ "passed": true,
+ "operationCount": 13,
+ "checks": [
+ "服务端菜单移除文档,保留开放应用",
+ "应用搜索、重置、分页区域正常",
+ "文档作为二级页,开放应用菜单正确高亮",
+ "13 个接口与服务端契约一致,均直接展示四个章节和返回示例",
+ "目录定位、生成幂等请求头必填和默认尺寸参数正确",
+ "浅色与深色页面及配置弹窗正常,返回开放应用正常",
+ "公共文档无需登录,390px 窄屏无页面横向溢出",
+ "浏览器无未捕获脚本错误"
+ ],
+ "errors": [],
+ "timestamp": "2026-09-09T00:44:37.634Z"
+}
\ No newline at end of file
diff --git a/reports/training-step-layout-20260908/after-1440x768.png b/reports/training-step-layout-20260908/after-1440x768.png
new file mode 100644
index 0000000..578065f
Binary files /dev/null and b/reports/training-step-layout-20260908/after-1440x768.png differ
diff --git a/reports/training-step-layout-20260908/after-1440x900-dark.png b/reports/training-step-layout-20260908/after-1440x900-dark.png
new file mode 100644
index 0000000..51f858e
Binary files /dev/null and b/reports/training-step-layout-20260908/after-1440x900-dark.png differ
diff --git a/reports/training-step-layout-20260908/after-1440x900-system-dark.png b/reports/training-step-layout-20260908/after-1440x900-system-dark.png
new file mode 100644
index 0000000..2a73ae9
Binary files /dev/null and b/reports/training-step-layout-20260908/after-1440x900-system-dark.png differ
diff --git a/reports/training-step-layout-20260908/after-1440x900.png b/reports/training-step-layout-20260908/after-1440x900.png
new file mode 100644
index 0000000..6da4a7a
Binary files /dev/null and b/reports/training-step-layout-20260908/after-1440x900.png differ
diff --git a/reports/training-step-layout-20260908/after-1920x1080.png b/reports/training-step-layout-20260908/after-1920x1080.png
new file mode 100644
index 0000000..7d90fbb
Binary files /dev/null and b/reports/training-step-layout-20260908/after-1920x1080.png differ
diff --git a/reports/training-step-layout-20260908/after-1920x900.png b/reports/training-step-layout-20260908/after-1920x900.png
new file mode 100644
index 0000000..b708092
Binary files /dev/null and b/reports/training-step-layout-20260908/after-1920x900.png differ
diff --git a/reports/training-step-layout-20260908/after-last-step.png b/reports/training-step-layout-20260908/after-last-step.png
new file mode 100644
index 0000000..31bfabf
Binary files /dev/null and b/reports/training-step-layout-20260908/after-last-step.png differ
diff --git a/reports/training-step-layout-20260908/after.json b/reports/training-step-layout-20260908/after.json
new file mode 100644
index 0000000..0069a5f
--- /dev/null
+++ b/reports/training-step-layout-20260908/after.json
@@ -0,0 +1,3126 @@
+{
+ "mode": "after",
+ "contentWrites": 0,
+ "checks": [
+ {
+ "width": 1920,
+ "height": 1080,
+ "theme": "light",
+ "cards": [
+ {
+ "card": {
+ "top": 334,
+ "bottom": 426,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 335,
+ "bottom": 425,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 343,
+ "bottom": 386.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 392.25,
+ "bottom": 416.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 433,
+ "bottom": 525,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 434,
+ "bottom": 524,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 442,
+ "bottom": 485.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 491.25,
+ "bottom": 515.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 532,
+ "bottom": 624,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 533,
+ "bottom": 623,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 541,
+ "bottom": 584.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 590.25,
+ "bottom": 614.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 631,
+ "bottom": 723,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 632,
+ "bottom": 722,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 640,
+ "bottom": 683.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 689.25,
+ "bottom": 713.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 730,
+ "bottom": 822,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 731,
+ "bottom": 821,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 739,
+ "bottom": 782.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 788.25,
+ "bottom": 812.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 829,
+ "bottom": 921,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 830,
+ "bottom": 920,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 838,
+ "bottom": 881.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 887.25,
+ "bottom": 911.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 928,
+ "bottom": 1020,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 929,
+ "bottom": 1019,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 937,
+ "bottom": 980.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 986.25,
+ "bottom": 1010.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 1027,
+ "bottom": 1119,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 1028,
+ "bottom": 1118,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 1036,
+ "bottom": 1079.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 1085.25,
+ "bottom": 1109.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "width": 1920,
+ "height": 900,
+ "theme": "light",
+ "cards": [
+ {
+ "card": {
+ "top": 334,
+ "bottom": 426,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 335,
+ "bottom": 425,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 343,
+ "bottom": 386.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 392.25,
+ "bottom": 416.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 433,
+ "bottom": 525,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 434,
+ "bottom": 524,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 442,
+ "bottom": 485.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 491.25,
+ "bottom": 515.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 532,
+ "bottom": 624,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 533,
+ "bottom": 623,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 541,
+ "bottom": 584.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 590.25,
+ "bottom": 614.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 631,
+ "bottom": 723,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 632,
+ "bottom": 722,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 640,
+ "bottom": 683.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 689.25,
+ "bottom": 713.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 730,
+ "bottom": 822,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 731,
+ "bottom": 821,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 739,
+ "bottom": 782.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 788.25,
+ "bottom": 812.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 829,
+ "bottom": 921,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 830,
+ "bottom": 920,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 838,
+ "bottom": 881.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 887.25,
+ "bottom": 911.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 928,
+ "bottom": 1020,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 929,
+ "bottom": 1019,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 937,
+ "bottom": 980.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 986.25,
+ "bottom": 1010.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 1027,
+ "bottom": 1119,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 1028,
+ "bottom": 1118,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 1036,
+ "bottom": 1079.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 1085.25,
+ "bottom": 1109.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "width": 1440,
+ "height": 900,
+ "theme": "light",
+ "cards": [
+ {
+ "card": {
+ "top": 334,
+ "bottom": 426,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 335,
+ "bottom": 425,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 343,
+ "bottom": 386.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 392.25,
+ "bottom": 416.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 433,
+ "bottom": 525,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 434,
+ "bottom": 524,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 442,
+ "bottom": 485.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 491.25,
+ "bottom": 515.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 532,
+ "bottom": 624,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 533,
+ "bottom": 623,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 541,
+ "bottom": 584.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 590.25,
+ "bottom": 614.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 631,
+ "bottom": 723,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 632,
+ "bottom": 722,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 640,
+ "bottom": 683.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 689.25,
+ "bottom": 713.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 730,
+ "bottom": 822,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 731,
+ "bottom": 821,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 739,
+ "bottom": 782.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 788.25,
+ "bottom": 812.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 829,
+ "bottom": 921,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 830,
+ "bottom": 920,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 838,
+ "bottom": 881.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 887.25,
+ "bottom": 911.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 928,
+ "bottom": 1020,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 929,
+ "bottom": 1019,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 937,
+ "bottom": 980.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 986.25,
+ "bottom": 1010.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 1027,
+ "bottom": 1119,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 1028,
+ "bottom": 1118,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 1036,
+ "bottom": 1079.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 1085.25,
+ "bottom": 1109.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "width": 1440,
+ "height": 768,
+ "theme": "light",
+ "cards": [
+ {
+ "card": {
+ "top": 334,
+ "bottom": 426,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 335,
+ "bottom": 425,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 343,
+ "bottom": 386.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 392.25,
+ "bottom": 416.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 433,
+ "bottom": 525,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 434,
+ "bottom": 524,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 442,
+ "bottom": 485.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 491.25,
+ "bottom": 515.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 532,
+ "bottom": 624,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 533,
+ "bottom": 623,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 541,
+ "bottom": 584.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 590.25,
+ "bottom": 614.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 631,
+ "bottom": 723,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 632,
+ "bottom": 722,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 640,
+ "bottom": 683.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 689.25,
+ "bottom": 713.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 730,
+ "bottom": 822,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 731,
+ "bottom": 821,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 739,
+ "bottom": 782.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 788.25,
+ "bottom": 812.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 829,
+ "bottom": 921,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 830,
+ "bottom": 920,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 838,
+ "bottom": 881.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 887.25,
+ "bottom": 911.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 928,
+ "bottom": 1020,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 929,
+ "bottom": 1019,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 937,
+ "bottom": 980.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 986.25,
+ "bottom": 1010.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 1027,
+ "bottom": 1119,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 1028,
+ "bottom": 1118,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 1036,
+ "bottom": 1079.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 1085.25,
+ "bottom": 1109.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "width": 1440,
+ "height": 900,
+ "theme": "dark",
+ "cards": [
+ {
+ "card": {
+ "top": 334,
+ "bottom": 426,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 335,
+ "bottom": 425,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 343,
+ "bottom": 386.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 392.25,
+ "bottom": 416.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 433,
+ "bottom": 525,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 434,
+ "bottom": 524,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 442,
+ "bottom": 485.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 491.25,
+ "bottom": 515.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 532,
+ "bottom": 624,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 533,
+ "bottom": 623,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 541,
+ "bottom": 584.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 590.25,
+ "bottom": 614.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 631,
+ "bottom": 723,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 632,
+ "bottom": 722,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 640,
+ "bottom": 683.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 689.25,
+ "bottom": 713.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 730,
+ "bottom": 822,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 731,
+ "bottom": 821,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 739,
+ "bottom": 782.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 788.25,
+ "bottom": 812.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 829,
+ "bottom": 921,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 830,
+ "bottom": 920,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 838,
+ "bottom": 881.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 887.25,
+ "bottom": 911.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 928,
+ "bottom": 1020,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 929,
+ "bottom": 1019,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 937,
+ "bottom": 980.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 986.25,
+ "bottom": 1010.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 1027,
+ "bottom": 1119,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 1028,
+ "bottom": 1118,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 1036,
+ "bottom": 1079.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 1085.25,
+ "bottom": 1109.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "width": 1440,
+ "height": 900,
+ "theme": "system-dark",
+ "cards": [
+ {
+ "card": {
+ "top": 334,
+ "bottom": 426,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 335,
+ "bottom": 425,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 343,
+ "bottom": 386.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 392.25,
+ "bottom": 416.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 433,
+ "bottom": 525,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 434,
+ "bottom": 524,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 442,
+ "bottom": 485.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 491.25,
+ "bottom": 515.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 532,
+ "bottom": 624,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 533,
+ "bottom": 623,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 541,
+ "bottom": 584.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 590.25,
+ "bottom": 614.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 631,
+ "bottom": 723,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 632,
+ "bottom": 722,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 640,
+ "bottom": 683.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 689.25,
+ "bottom": 713.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 730,
+ "bottom": 822,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 731,
+ "bottom": 821,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 739,
+ "bottom": 782.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 788.25,
+ "bottom": 812.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 829,
+ "bottom": 921,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 830,
+ "bottom": 920,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 838,
+ "bottom": 881.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 887.25,
+ "bottom": 911.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 928,
+ "bottom": 1020,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 929,
+ "bottom": 1019,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 937,
+ "bottom": 980.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 986.25,
+ "bottom": 1010.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 1027,
+ "bottom": 1119,
+ "height": 92,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 1028,
+ "bottom": 1118,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 1036,
+ "bottom": 1079.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 1085.25,
+ "bottom": 1109.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "project": {
+ "id": "409",
+ "name": "ZDS-虚拟仿真1"
+ },
+ "lastStepSelection": "PASS",
+ "status": "PASS"
+}
\ No newline at end of file
diff --git a/reports/training-step-layout-20260908/before-1440.png b/reports/training-step-layout-20260908/before-1440.png
new file mode 100644
index 0000000..e12891f
Binary files /dev/null and b/reports/training-step-layout-20260908/before-1440.png differ
diff --git a/reports/training-step-layout-20260908/before-1440x768.png b/reports/training-step-layout-20260908/before-1440x768.png
new file mode 100644
index 0000000..88a0591
Binary files /dev/null and b/reports/training-step-layout-20260908/before-1440x768.png differ
diff --git a/reports/training-step-layout-20260908/before-1440x900.png b/reports/training-step-layout-20260908/before-1440x900.png
new file mode 100644
index 0000000..fdebe57
Binary files /dev/null and b/reports/training-step-layout-20260908/before-1440x900.png differ
diff --git a/reports/training-step-layout-20260908/before-1920.png b/reports/training-step-layout-20260908/before-1920.png
new file mode 100644
index 0000000..f0b09bc
Binary files /dev/null and b/reports/training-step-layout-20260908/before-1920.png differ
diff --git a/reports/training-step-layout-20260908/before-1920x1080.png b/reports/training-step-layout-20260908/before-1920x1080.png
new file mode 100644
index 0000000..fbdd080
Binary files /dev/null and b/reports/training-step-layout-20260908/before-1920x1080.png differ
diff --git a/reports/training-step-layout-20260908/before-1920x900.png b/reports/training-step-layout-20260908/before-1920x900.png
new file mode 100644
index 0000000..496964e
Binary files /dev/null and b/reports/training-step-layout-20260908/before-1920x900.png differ
diff --git a/reports/training-step-layout-20260908/before.json b/reports/training-step-layout-20260908/before.json
new file mode 100644
index 0000000..ef93d98
--- /dev/null
+++ b/reports/training-step-layout-20260908/before.json
@@ -0,0 +1,2083 @@
+{
+ "mode": "before",
+ "contentWrites": 0,
+ "checks": [
+ {
+ "width": 1920,
+ "height": 1080,
+ "cards": [
+ {
+ "card": {
+ "top": 334,
+ "bottom": 426,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 335,
+ "bottom": 425,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 343,
+ "bottom": 386.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 392.25,
+ "bottom": 416.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 433,
+ "bottom": 525,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 434,
+ "bottom": 524,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 442,
+ "bottom": 485.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 491.25,
+ "bottom": 515.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 490.5,
+ "bottom": 516,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 532,
+ "bottom": 624,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 533,
+ "bottom": 623,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 541,
+ "bottom": 584.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 590.25,
+ "bottom": 614.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 589.5,
+ "bottom": 615,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 631,
+ "bottom": 723,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 632,
+ "bottom": 722,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 640,
+ "bottom": 683.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 689.25,
+ "bottom": 713.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 688.5,
+ "bottom": 714,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 730,
+ "bottom": 822,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 731,
+ "bottom": 821,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 739,
+ "bottom": 782.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 788.25,
+ "bottom": 812.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 787.5,
+ "bottom": 813,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 829,
+ "bottom": 921,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 830,
+ "bottom": 920,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 838,
+ "bottom": 881.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 887.25,
+ "bottom": 911.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 886.5,
+ "bottom": 912,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 928,
+ "bottom": 1020,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 929,
+ "bottom": 1019,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 937,
+ "bottom": 980.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 986.25,
+ "bottom": 1010.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 985.5,
+ "bottom": 1011,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 1027,
+ "bottom": 1119,
+ "height": 92,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 1028,
+ "bottom": 1118,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 1036,
+ "bottom": 1079.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 1085.25,
+ "bottom": 1109.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 1084.5,
+ "bottom": 1110,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "width": 1920,
+ "height": 900,
+ "cards": [
+ {
+ "card": {
+ "top": 334,
+ "bottom": 416,
+ "height": 82,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 335,
+ "bottom": 425,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 343,
+ "bottom": 386.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 392.25,
+ "bottom": 416.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 423,
+ "bottom": 505,
+ "height": 82,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 424,
+ "bottom": 514,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 432,
+ "bottom": 475.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 480.5,
+ "bottom": 506,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 481.25,
+ "bottom": 505.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 480.5,
+ "bottom": 506,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 512,
+ "bottom": 594,
+ "height": 82,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 513,
+ "bottom": 603,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 521,
+ "bottom": 564.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 569.5,
+ "bottom": 595,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 570.25,
+ "bottom": 594.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 569.5,
+ "bottom": 595,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 601,
+ "bottom": 683,
+ "height": 82,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 602,
+ "bottom": 692,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 610,
+ "bottom": 653.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 658.5,
+ "bottom": 684,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 659.25,
+ "bottom": 683.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 658.5,
+ "bottom": 684,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 690,
+ "bottom": 772,
+ "height": 82,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 691,
+ "bottom": 781,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 699,
+ "bottom": 742.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 747.5,
+ "bottom": 773,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 748.25,
+ "bottom": 772.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 747.5,
+ "bottom": 773,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 779,
+ "bottom": 861,
+ "height": 82,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 780,
+ "bottom": 870,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 788,
+ "bottom": 831.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 836.5,
+ "bottom": 862,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 837.25,
+ "bottom": 861.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 836.5,
+ "bottom": 862,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 868,
+ "bottom": 950,
+ "height": 82,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 869,
+ "bottom": 959,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 877,
+ "bottom": 920.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 925.5,
+ "bottom": 951,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 926.25,
+ "bottom": 950.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 925.5,
+ "bottom": 951,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 957,
+ "bottom": 1039,
+ "height": 82,
+ "width": 319.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 958,
+ "bottom": 1048,
+ "height": 90,
+ "width": 281.5625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 966,
+ "bottom": 1009.5,
+ "height": 43.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 1014.5,
+ "bottom": 1040,
+ "height": 25.5,
+ "width": 221.5625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 1015.25,
+ "bottom": 1039.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 1014.5,
+ "bottom": 1040,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "width": 1440,
+ "height": 900,
+ "cards": [
+ {
+ "card": {
+ "top": 334,
+ "bottom": 416,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 335,
+ "bottom": 425,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 343,
+ "bottom": 386.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 392.25,
+ "bottom": 416.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 423,
+ "bottom": 505,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 424,
+ "bottom": 514,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 432,
+ "bottom": 475.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 480.5,
+ "bottom": 506,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 481.25,
+ "bottom": 505.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 480.5,
+ "bottom": 506,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 512,
+ "bottom": 594,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 513,
+ "bottom": 603,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 521,
+ "bottom": 564.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 569.5,
+ "bottom": 595,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 570.25,
+ "bottom": 594.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 569.5,
+ "bottom": 595,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 601,
+ "bottom": 683,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 602,
+ "bottom": 692,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 610,
+ "bottom": 653.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 658.5,
+ "bottom": 684,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 659.25,
+ "bottom": 683.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 658.5,
+ "bottom": 684,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 690,
+ "bottom": 772,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 691,
+ "bottom": 781,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 699,
+ "bottom": 742.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 747.5,
+ "bottom": 773,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 748.25,
+ "bottom": 772.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 747.5,
+ "bottom": 773,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 779,
+ "bottom": 861,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 780,
+ "bottom": 870,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 788,
+ "bottom": 831.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 836.5,
+ "bottom": 862,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 837.25,
+ "bottom": 861.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 836.5,
+ "bottom": 862,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 868,
+ "bottom": 950,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 869,
+ "bottom": 959,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 877,
+ "bottom": 920.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 925.5,
+ "bottom": 951,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 926.25,
+ "bottom": 950.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 925.5,
+ "bottom": 951,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 957,
+ "bottom": 1039,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 958,
+ "bottom": 1048,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 966,
+ "bottom": 1009.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 1014.5,
+ "bottom": 1040,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 1015.25,
+ "bottom": 1039.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 1014.5,
+ "bottom": 1040,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "width": 1440,
+ "height": 768,
+ "cards": [
+ {
+ "card": {
+ "top": 334,
+ "bottom": 416,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 335,
+ "bottom": 425,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 343,
+ "bottom": 386.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 392.25,
+ "bottom": 416.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 391.5,
+ "bottom": 417,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 423,
+ "bottom": 505,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 424,
+ "bottom": 514,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 432,
+ "bottom": 475.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 480.5,
+ "bottom": 506,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 481.25,
+ "bottom": 505.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 480.5,
+ "bottom": 506,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 512,
+ "bottom": 594,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 513,
+ "bottom": 603,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 521,
+ "bottom": 564.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 569.5,
+ "bottom": 595,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 570.25,
+ "bottom": 594.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 569.5,
+ "bottom": 595,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 601,
+ "bottom": 683,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 602,
+ "bottom": 692,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 610,
+ "bottom": 653.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 658.5,
+ "bottom": 684,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 659.25,
+ "bottom": 683.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 658.5,
+ "bottom": 684,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 690,
+ "bottom": 772,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 691,
+ "bottom": 781,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 699,
+ "bottom": 742.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 747.5,
+ "bottom": 773,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 748.25,
+ "bottom": 772.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 747.5,
+ "bottom": 773,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 779,
+ "bottom": 861,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 780,
+ "bottom": 870,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 788,
+ "bottom": 831.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 836.5,
+ "bottom": 862,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 837.25,
+ "bottom": 861.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 836.5,
+ "bottom": 862,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 868,
+ "bottom": 950,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 869,
+ "bottom": 959,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 877,
+ "bottom": 920.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 925.5,
+ "bottom": 951,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 926.25,
+ "bottom": 950.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 925.5,
+ "bottom": 951,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ },
+ {
+ "card": {
+ "top": 957,
+ "bottom": 1039,
+ "height": 82,
+ "width": 222.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "button": {
+ "top": 958,
+ "bottom": 1048,
+ "height": 90,
+ "width": 184.90625,
+ "lineHeight": "21px",
+ "padding": "8px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "copy": {
+ "top": 966,
+ "bottom": 1009.5,
+ "height": 43.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "tags": {
+ "top": 1014.5,
+ "bottom": 1040,
+ "height": 25.5,
+ "width": 124.90625,
+ "lineHeight": "21px",
+ "padding": "0px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ "badges": [
+ {
+ "top": 1015.25,
+ "bottom": 1039.25,
+ "height": 24,
+ "width": 60,
+ "lineHeight": "18px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ },
+ {
+ "top": 1014.5,
+ "bottom": 1040,
+ "height": 25.5,
+ "width": 44.90625,
+ "lineHeight": "19.5px",
+ "padding": "3px 6px",
+ "overflow": "visible",
+ "alignSelf": "auto"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "project": {
+ "id": "409",
+ "name": "ZDS-虚拟仿真1"
+ },
+ "status": "PASS"
+}
\ No newline at end of file
diff --git a/reports/training-step-layout-20260908/index.html b/reports/training-step-layout-20260908/index.html
new file mode 100644
index 0000000..a9bd255
--- /dev/null
+++ b/reports/training-step-layout-20260908/index.html
@@ -0,0 +1,12 @@
+
+
+训练步骤布局修复与讲解来源核查 · 2026-09-08
+
+训练步骤布局修复与讲解来源核查
2026-09-08 · 正式 Web 6180 · 训练编排基础编排入口
+修复结果:通过
复现项目:ZDS-虚拟仿真1(409)。较矮视口下,步骤网格压缩至 82px,内容需要约 92px,标签越过底边 1px。修复为按内容高度分配网格行,标签允许换行,不裁切内容、不隐藏信息。
变更仅 1 个 CSS 文件、4 行:src/features/guide-legacy/demo-src/training-editor.css。未修改讲解来源逻辑,未提交 Git。
+| 验证范围 | 结果 |
|---|
| 1920×1080、1920×900、1440×900、1440×768 | 每个视口检查 8 个步骤,标签最小底部留白均为 9px |
| 1440×900 暗色与跟随系统暗色的 CSS 渲染 | 8 个步骤均通过;未修改用户服务端主题偏好 |
| 列表滚动、末步点击与选中状态 | 通过 |
| pnpm run build(含 TypeScript 与 iframe 产物校验) | 通过;保留既有 chunk 大小提醒 |
| 业务数据 | 管理员只读会话;0 次内容写请求,没有创建、保存或发布测试项目,会话已退出 |
证据:修复前测量 · 修复后测量。修复前 JSON 的 PASS 表示采集成功,越界数值记录在 card/badges 坐标中;修复后另有标签留白断言。
+
+提交 3130346
作者与提交者均为 zhuds(zhudasen@126.com);时间为 2026-09-06 23:20:30 +08:00;标题为“feat:样式调整”。
| 文件 | 改动 |
|---|
| src/styles/index.scss | 滚动容器 wrap 改用 flex 传递高度,route-view-content 增加 flex: 1 0 auto,支持长页面正确触发滚动条。 |
| src/styles/integration.scss | 维修知识页桌面增加 contain: size,防止内容反向撑高外层;1000px 及以下解除该限制。 |
+讲解设置来源:当前仍是内置演示逻辑
核查实际挂载入口 LegacyTrainingPageView.vue:268、training-editor.js 的目录、渲染、生成和试听方法,以及 training-legacy/bridge.ts 保存映射。宿主注入场景列表、场景加载、保存与发布回调,没有覆盖数字人目录或生成函数。
+| 界面项 | 实际来源与行为 | 代码位置 |
|---|
| 数字人资源库 | 3 个硬编码目录、5 段站点静态 MP4;另将当前训练项目步骤中已有 generatedVideoId/generatedVideoUrl 汇总为“我的作品”,不是从数字人平台作品库查询。 | training-editor.js:68、1243 |
| 形象、声音、背景 | 各 3 项硬编码选项。形象与背景是 public/images 中的静态图片。 | training-editor.js:98、104、110 |
| 现场生成 | 检查必填项后,在前端生成时间戳 ID,将固定 musetalk15_teacher-m_kb-script-18s.mp4 写入步骤;没有提交真实生成任务,文稿不会改变该视频。 | training-editor.js:226、1598 |
| “已同步到作品集” | 仅更新当前项目步骤元数据并标记未保存,“我的作品”从这些步骤汇总;没有向数字人系统创建作品的请求。 | training-editor.js:1243、1613 |
| “数字人系统已连接” | 直接渲染的固定文案,没有根据健康检查或连接接口返回值判断。 | training-editor.js:1346、1376 |
| 声音试听 | 调用 previewSoftChime(640) 提示音;不是对应声音的真实试听片段。 | training-editor.js:1633 |
+静态素材位置:unreal_tran_web/public/video/digital-instructor-v3/clips/,固定生成示例位于 examples/musetalk15_teacher-m_kb-script-18s.mp4。对 5 段目录视频和 1 段生成示例逐个 HEAD 检查,均返回 HTTP 200、video/mp4。
本次仅核查这些入口的实现,没有调用生成按钮或变更绑定。真正接入属于后续功能调整:建议资源库通过数字车间后端查询数字人平台可用作品;现场生成提交真实任务,显示进度与失败状态,完成后绑定受控视频资源。“已连接”和“已同步”须由真实接口结果驱动,等待产品确认后实施。
diff --git a/tools/advanced-drag-layout.mjs b/tools/advanced-drag-layout.mjs
new file mode 100644
index 0000000..7a3a46b
--- /dev/null
+++ b/tools/advanced-drag-layout.mjs
@@ -0,0 +1,75 @@
+import fs from 'node:fs'
+import path from 'node:path'
+import assert from 'node:assert/strict'
+import { createRequire } from 'node:module'
+import { fileURLToPath } from 'node:url'
+import { login, call } from './role-permissions-live.mjs'
+const require = createRequire(new URL('../package.json', import.meta.url))
+const { chromium, expect } = require('@playwright/test')
+const report = fileURLToPath(new URL('../reports/advanced-drag-layout-20260909/', import.meta.url))
+fs.mkdirSync(report, { recursive: true })
+const session = await login('root')
+const project = (await call('tran/v1/content/projects?type=TRAINING&size=100', session.accessToken)).data.records.find(row => row.name.includes('APE2E-数字人讲解-狐狸'))
+assert.ok(project)
+const browser = await chromium.launch({ channel: 'msedge', headless: true, args: ['--enable-unsafe-swiftshader'] })
+let page
+const checks = []
+try {
+ const context = await browser.newContext({ viewport: { width: 1920, height: 911 } })
+ await context.addInitScript(({ accessToken, refreshToken }) => {
+ sessionStorage.setItem('unreal-tran:web:access-token:v1', accessToken)
+ sessionStorage.setItem('unreal-tran:web:refresh-token:v1', refreshToken)
+ localStorage.setItem('unreal-tran:web:preferences:v1', JSON.stringify({ themeMode: 'military' }))
+ }, session)
+ page = await context.newPage()
+ await page.goto(`http://127.0.0.1:6180/content/training-projects/${project.id}/legacy`)
+ await page.getByRole('radio', { name: '高级编排', exact: true }).click({ timeout: 60000 })
+ const canvas = page.locator('[data-role="flow-canvas"]')
+ const node = page.locator('[data-flow-node="flow-start"]')
+ const head = node.locator('.tfa-node-head')
+ await head.scrollIntoViewIfNeeded()
+ const initial = await node.evaluate(el => ({ x: parseFloat(el.style.left), y: parseFloat(el.style.top) }))
+ const box = await head.boundingBox(), area = await canvas.boundingBox()
+ await page.mouse.move(box.x + 45, box.y + 22)
+ await page.mouse.down()
+ const pointerY = area.y + area.height - 100
+ await page.mouse.move(box.x + 45, pointerY, { steps: 12 })
+ const before = await node.evaluate(el => parseFloat(el.style.top))
+ const scrollDelta = await canvas.evaluate(el => { const old = el.scrollTop; el.scrollTop += 180; return el.scrollTop - old })
+ assert.ok(scrollDelta > 80)
+ await page.mouse.move(box.x + 45, pointerY + 5, { steps: 2 })
+ const after = await node.evaluate(el => parseFloat(el.style.top))
+ assert.ok(Math.abs(after - before - scrollDelta - 5) < 3, 'Node follows pointer in scrolled coordinates')
+ const oldLimit = await canvas.evaluate(el => el.clientHeight - 110)
+ assert.ok(after > oldLimit + 80, 'Node reaches grid below the former viewport limit')
+ await page.mouse.up()
+ checks.push({ name: '拖入下方网格,拖动中滚动不跳位', result: 'PASS', before, after, scrollDelta, formerLimit: oldLimit })
+ const scrollBefore = await canvas.evaluate(el => el.scrollTop)
+ await head.click()
+ await expect.poll(() => canvas.evaluate(el => el.scrollTop)).toBe(scrollBefore)
+ await expect.poll(() => node.evaluate(el => parseFloat(el.style.top))).toBe(after)
+ await page.screenshot({ path: path.join(report, '01-lower-grid.png'), animations: 'disabled' })
+ checks.push({ name: '选择节点后保留画布滚动位置', result: 'PASS' })
+ await page.setViewportSize({ width: 1366, height: 768 })
+ const last = page.locator('.tfa-node').last(), lastHead = last.locator('.tfa-node-head')
+ await lastHead.scrollIntoViewIfNeeded()
+ const previous = await last.evaluate(el => ({ x: parseFloat(el.style.left), y: parseFloat(el.style.top) }))
+ const lastBox = await lastHead.boundingBox()
+ await page.mouse.move(lastBox.x + 45, lastBox.y + 22)
+ await page.mouse.down()
+ await page.mouse.move(lastBox.x + 55, lastBox.y + 32, { steps: 4 })
+ await page.mouse.up()
+ const next = await last.evaluate(el => ({ x: parseFloat(el.style.left), y: parseFloat(el.style.top) }))
+ assert.ok(Math.abs(next.x - previous.x - 10) < 2 && Math.abs(next.y - previous.y - 10) < 2, 'Small drag after horizontal scroll must not jump to viewport limit')
+ await page.screenshot({ path: path.join(report, '02-horizontal-scroll.png'), animations: 'disabled' })
+ checks.push({ name: '窄窗口横向滚动后拖动不跳位', result: 'PASS', previous, next })
+ await page.getByRole('radio', { name: '基础编排', exact: true }).click()
+ await page.getByRole('radio', { name: '高级编排', exact: true }).click()
+ assert.equal(await node.evaluate(el => parseFloat(el.style.top)), after)
+ checks.push({ name: '切换编排模式保留节点坐标', result: 'PASS' })
+ fs.writeFileSync(path.join(report, 'results.json'), JSON.stringify({ passed: true, projectId: project.id, accountType: '内部维护', initial, checks, dataChanges: '仅调整已有测试工程的浏览器草稿,未点击保存或发布。' }, null, 2))
+ console.log('Advanced drag layout checks passed')
+} catch (error) {
+ if (page) await page.screenshot({ path: path.join(report, 'failure.png'), animations: 'disabled' }).catch(() => {})
+ throw error
+} finally { await browser.close() }
diff --git a/tools/narration-dialog-layout.mjs b/tools/narration-dialog-layout.mjs
new file mode 100644
index 0000000..191791c
--- /dev/null
+++ b/tools/narration-dialog-layout.mjs
@@ -0,0 +1,79 @@
+import fs from 'node:fs'
+import path from 'node:path'
+import assert from 'node:assert/strict'
+import { createRequire } from 'node:module'
+import { fileURLToPath } from 'node:url'
+import { login, call } from './role-permissions-live.mjs'
+const require = createRequire(new URL('../package.json', import.meta.url))
+const { chromium, expect } = require('@playwright/test')
+const report = fileURLToPath(new URL('../reports/narration-dialog-layout-20260909/', import.meta.url))
+fs.mkdirSync(report, { recursive: true })
+const session = await login('root')
+const project = (await call('tran/v1/content/projects?type=TRAINING&size=100', session.accessToken)).data.records.find(row => row.name.includes('APE2E-数字人讲解-狐狸'))
+assert.ok(project, 'Existing narration test project available')
+const browser = await chromium.launch({ channel: 'msedge', headless: true, args: ['--enable-unsafe-swiftshader'] })
+const checks = []
+let page
+try {
+ const context = await browser.newContext({ viewport: { width: 1920, height: 911 } })
+ await context.addInitScript(({ accessToken, refreshToken }) => {
+ sessionStorage.setItem('unreal-tran:web:access-token:v1', accessToken)
+ sessionStorage.setItem('unreal-tran:web:refresh-token:v1', refreshToken)
+ }, session)
+ page = await context.newPage()
+ await page.goto(`http://127.0.0.1:6180/content/training-projects/${project.id}/legacy`)
+ await page.locator('[data-action="set-tab"]').filter({ hasText: '讲解' }).click({ timeout: 60000 })
+ await page.locator('[data-action="set-narration-source"][data-source="digital-library"]').click()
+ await page.locator('[data-action="manage-digital-human"]').click()
+ const dialog = page.locator('.digital-human-narration-dialog')
+ console.log('Narration dialog opened')
+ await expect(dialog.locator('.connection-state')).toContainText('已连接数字人服务', { timeout: 30000 })
+ const preview = dialog.getByRole('button', { name: '预览', exact: true }).last()
+ const previewResponse = page.waitForResponse(response => response.url().includes('/digital-human/videos/') && response.url().endsWith('/preview'), { timeout: 125000 })
+ await preview.click({ timeout: 30000 })
+ console.log('Authorized video preview requested')
+ assert.equal((await previewResponse).status(), 200, 'Authorized video preview response')
+ await page.waitForFunction(() => document.querySelector('.video-preview video')?.readyState >= 1, null, { timeout: 20000 })
+ await dialog.locator('video').evaluate(video => { video.currentTime = 0.1 })
+ async function verify(label, width, height, theme = 'light') {
+ await page.setViewportSize({ width, height })
+ await page.evaluate(async value => {
+ const { usePreferencesStore } = await import('/src/stores/preferences.ts')
+ usePreferencesStore().setThemeMode(value === 'dark' ? 'dark' : 'military')
+ }, theme)
+ await expect.poll(async () => dialog.evaluate(el => {
+ const box = el.getBoundingClientRect(), footer = el.querySelector('.el-dialog__footer').getBoundingClientRect()
+ const body = el.querySelector('.el-dialog__body')
+ return box.top >= 0 && box.bottom <= innerHeight + 1 && box.left >= 0 && box.right <= innerWidth + 1 && footer.bottom <= innerHeight && body.scrollWidth <= body.clientWidth + 1
+ })).toBe(true)
+ await dialog.locator('.video-preview').scrollIntoViewIfNeeded()
+ await expect(dialog.locator('.el-dialog__footer').getByRole('button', { name: '关闭', exact: true })).toBeVisible()
+ const video = await dialog.locator('video').evaluate(el => ({ width: el.videoWidth, height: el.videoHeight, duration: el.duration }))
+ assert.ok(video.width > 0 && video.duration > 0)
+ await page.screenshot({ path: path.join(report, `${label}.png`), animations: 'disabled' })
+ checks.push({ label, viewport: { width, height }, theme, result: 'PASS', video })
+ }
+ await verify('01-desktop-preview', 1920, 911)
+ await verify('02-short-preview', 1366, 600)
+ await verify('03-mobile-preview', 390, 844)
+ await verify('04-dark-preview', 1366, 768, 'dark')
+ await dialog.getByRole('tab', { name: '现场生成成片' }).click()
+ await expect(dialog.getByRole('button', { name: '提交生成', exact: true })).toBeAttached()
+ await dialog.getByRole('button', { name: '提交生成', exact: true }).scrollIntoViewIfNeeded()
+ await page.screenshot({ path: path.join(report, '05-generation-form.png'), animations: 'disabled' })
+ await dialog.getByRole('tab', { name: '生成任务', exact: true }).click()
+ await dialog.locator('.el-dialog__footer').getByRole('button', { name: '关闭', exact: true }).click()
+ await expect(dialog).toBeHidden()
+ checks.push({ label: '生成表单、任务页签与底部关闭', result: 'PASS' })
+ const lan = await context.request.get('http://192.168.31.168:6180/')
+ assert.equal(lan.status(), 200)
+ checks.push({ label: '局域网入口', result: 'PASS' })
+ fs.writeFileSync(path.join(report, 'results.json'), JSON.stringify({ passed: true, projectId: project.id, accountType: '内部维护', checks, dataChanges: '使用已有测试工程和授权视频。打开数字人服务前编辑器按既有逻辑保存测试工程;未提交生成、导入绑定或发布。' }, null, 2))
+ console.log('Narration dialog layout checks passed')
+} catch (error) {
+ if (page) {
+ await page.screenshot({ path: path.join(report, 'failure.png'), animations: 'disabled' }).catch(() => {})
+ console.error(await page.locator('.el-message').allTextContents())
+ }
+ throw error
+} finally { await browser.close() }
diff --git a/tools/open-platform-pdf.mjs b/tools/open-platform-pdf.mjs
new file mode 100644
index 0000000..9ec8ef0
--- /dev/null
+++ b/tools/open-platform-pdf.mjs
@@ -0,0 +1,40 @@
+import fs from 'node:fs'
+import path from 'node:path'
+import { fileURLToPath } from 'node:url'
+import { createRequire } from 'node:module'
+import assert from 'node:assert/strict'
+const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..')
+const require = createRequire(path.join(root, 'ai_person/ape2e/package.json'))
+const { chromium, expect } = require('@playwright/test')
+const report = path.join(root, 'unreal_tran/ute2e/reports/open-platform-pdf-20260909')
+fs.mkdirSync(report, { recursive: true })
+const browser = await chromium.launch({ channel: 'msedge', headless: true })
+try {
+ const page = await browser.newPage({ viewport: { width: 1600, height: 1000 } })
+ const errors = []
+ page.on('pageerror', error => errors.push(error.message))
+ await page.goto('http://127.0.0.1:8003/developer')
+ await expect(page.locator('.endpoint-section')).toHaveCount(13)
+ const button = page.getByRole('button', { name: '导出 PDF', exact: true })
+ const downloadPromise = page.waitForEvent('download')
+ await button.click()
+ const download = await downloadPromise
+ assert.equal(download.suggestedFilename(), 'digital-human-open-api.pdf')
+ await download.saveAs(path.join(report, 'digital-human-open-api.pdf'))
+ assert.equal(fs.readFileSync(path.join(report, 'digital-human-open-api.pdf')).subarray(0, 5).toString(), '%PDF-')
+ await expect(button).toBeEnabled()
+ await page.screenshot({ path: path.join(report, '01-pdf-download.png'), animations: 'disabled' })
+ await page.route('**/open-api/v1/documentation.pdf', route => route.fulfill({ status: 503, contentType: 'application/json', body: JSON.stringify({ code: 50000, message: '导出服务暂不可用', data: null }) }))
+ await button.click()
+ await expect(page.locator('.el-message--error')).toBeVisible()
+ await expect(button).toBeEnabled()
+ await page.unroute('**/open-api/v1/documentation.pdf')
+ const retry = page.waitForEvent('download')
+ await button.click()
+ assert.equal((await retry).suggestedFilename(), 'digital-human-open-api.pdf')
+ await page.locator('#endpoint-9').evaluate(el => window.scrollTo({ top: window.scrollY + el.getBoundingClientRect().top - 20, behavior: 'instant' }))
+ await expect(page.locator('.docs-nav a.active')).toHaveAttribute('href', '#endpoint-9')
+ assert.deepEqual(errors, [])
+ fs.writeFileSync(path.join(report, 'results.json'), JSON.stringify({ passed: true, endpoints: 13, backendPdfDownload: true, errorMessage: true, retry: true, scrollSync: true, scriptErrors: errors }, null, 2))
+ console.log('PDF download, error message, retry and scroll sync passed')
+} finally { await browser.close() }
diff --git a/tools/open-platform-style.mjs b/tools/open-platform-style.mjs
new file mode 100644
index 0000000..451e184
--- /dev/null
+++ b/tools/open-platform-style.mjs
@@ -0,0 +1,98 @@
+import fs from 'node:fs'
+import { fileURLToPath } from 'node:url'
+import path from 'node:path'
+import assert from 'node:assert/strict'
+import { createRequire } from 'node:module'
+const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..')
+const require = createRequire(path.join(root, 'ai_person/ape2e/package.json'))
+const { chromium, expect: baseExpect } = require('@playwright/test')
+const expect = baseExpect.configure({ timeout: 25000 })
+const report = path.join(root, 'unreal_tran/ute2e/reports/open-platform-style-20260909')
+fs.mkdirSync(report, { recursive: true })
+const values = new Map()
+for (const line of fs.readFileSync(path.join(root, 'ai_person/账号.MD'), 'utf8').split(/\r?\n/)) {
+ const match = line.match(/^\s*([^::]+)\s*[::]\s*(.*?)\s*$/)
+ if (match?.[1] && match[2]) values.set(match[1].trim(), match[2].trim())
+}
+const base = 'http://127.0.0.1:8003'
+const response = await fetch(base + '/api/auth/v1/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: values.get('账号') || values.get('用户名'), password: values.get('密码'), roleCode: 'admin' }) })
+const payload = await response.json()
+assert.equal(payload.code, 0, 'login must succeed')
+const token = payload.data.accessToken || payload.data.tokens?.accessToken
+const nav = await fetch(base + '/api/auth/v1/menus/navigation', { headers: { Authorization: 'Bearer ' + token } }).then(r => r.json())
+assert.equal(nav.code, 0)
+assert(!JSON.stringify(nav.data).includes('settings-open-api-docs'), 'docs must not be in server menu')
+assert(JSON.stringify(nav.data).includes('settings-open-applications'))
+const schema = await fetch(base + '/open-api/v1/openapi.json').then(r => r.json())
+const operationCount = Object.values(schema.paths).reduce((n, methods) => n + Object.keys(methods).length, 0)
+const checks = ['服务端菜单移除文档,保留开放应用']
+const browser = await chromium.launch({ channel: 'msedge', headless: true })
+const errors = []
+try {
+ const page = await browser.newPage({ viewport: { width: 1600, height: 1000 } })
+ page.on('pageerror', error => errors.push(error.message))
+ await page.goto(base + '/login')
+ await page.evaluate(token => sessionStorage.setItem('ai-person:web:access-token:v1', token), token)
+ await page.goto(base + '/settings/open-applications')
+ await page.getByText('数字车间开发联调', { exact: true }).waitFor()
+ await expect(page.locator('#main-sidebar')).not.toContainText('开放 API 文档')
+ const search = page.getByPlaceholder('搜索应用名称或 APPID')
+ const searchResponse = page.waitForResponse(response => response.url().includes('open-applications?keyword=%') && response.request().method() === 'GET')
+ await search.fill('数字车间开发联调')
+ await page.getByRole('button', { name: '搜索', exact: true }).click()
+ assert.equal((await (await searchResponse).json()).data.total, 1)
+ await expect(page.locator('.applications-table .el-table__row')).toHaveCount(1)
+ await page.getByRole('button', { name: '重置', exact: true }).click()
+ await expect(search).toHaveValue('')
+ await expect(page.locator('.applications-table .el-table__row')).toHaveCount(2)
+ checks.push('应用搜索、重置、分页区域正常')
+ await page.screenshot({ path: path.join(report, '01-applications-light.png') })
+ await page.getByRole('button', { name: '开放 API 文档', exact: true }).click()
+ await expect(page).toHaveURL(/settings\/open-api-docs/)
+ await expect(page.locator('.endpoint-section')).toHaveCount(operationCount)
+ assert.equal(operationCount, 13)
+ assert.equal(await page.locator('.el-collapse').count(), 0)
+ for (const heading of ['1. 接口描述', '2. 输入参数', '3. 输出参数', '4. 错误码']) {
+ await expect(page.locator('.endpoint-section').getByRole('heading', { name: heading, exact: true })).toHaveCount(13)
+ }
+ await expect(page.locator('#main-sidebar')).not.toContainText('开放 API 文档')
+ await expect(page.locator('#main-sidebar .el-menu-item.is-active')).toContainText('开放应用')
+ checks.push('文档作为二级页,开放应用菜单正确高亮', '13 个接口与服务端契约一致,均直接展示四个章节和返回示例')
+ await page.screenshot({ path: path.join(report, '02-docs-overview-light.png') })
+ await page.locator('.docs-nav a[href="#endpoint-9"]').click()
+ await expect(page.locator('#endpoint-9')).toBeInViewport()
+ await page.screenshot({ path: path.join(report, '09-generation-input.png') })
+ await page.locator('#endpoint-9').screenshot({ path: path.join(report, '03-generation-document.png') })
+ const idem = page.locator('#endpoint-9 .parameter-table').first().getByRole('row').filter({ hasText: 'Idempotency-Key' })
+ await expect(idem).toContainText('是')
+ await expect(page.locator('#endpoint-9')).toContainText('默认值:1280')
+ checks.push('目录定位、生成幂等请求头必填和默认尺寸参数正确')
+ await page.getByRole('button', { name: '切换到深色主题' }).click()
+ await page.getByRole('link', { name: '接入说明', exact: true }).click()
+ await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark')
+ await page.screenshot({ path: path.join(report, '04-docs-dark.png') })
+ await page.getByRole('button', { name: '返回开放应用', exact: true }).click()
+ await page.getByText('数字车间开发联调', { exact: true }).waitFor()
+ await page.screenshot({ path: path.join(report, '05-applications-dark.png') })
+ await page.locator('tr').filter({ hasText: '数字车间开发联调' }).getByRole('button', { name: '配置', exact: true }).click()
+ await expect(page.getByRole('dialog')).toBeVisible()
+ await expect(page.getByRole('dialog').getByText('授权资源', { exact: true })).toBeVisible()
+ await page.screenshot({ path: path.join(report, '06-application-dialog-dark.png') })
+ await page.getByRole('dialog').getByRole('button', { name: '取消', exact: true }).click()
+ checks.push('浅色与深色页面及配置弹窗正常,返回开放应用正常')
+ const publicPage = await browser.newPage({ viewport: { width: 390, height: 844 } })
+ publicPage.on('pageerror', error => errors.push(error.message))
+ await publicPage.goto(base + '/developer')
+ await expect(publicPage.locator('.endpoint-section')).toHaveCount(13)
+ await expect(publicPage.getByRole('button', { name: '返回开放应用' })).toHaveCount(0)
+ const dimensions = await publicPage.evaluate(() => ({ width: document.documentElement.clientWidth, scroll: document.documentElement.scrollWidth }))
+ assert(dimensions.scroll <= dimensions.width + 1, `mobile overflow: ${JSON.stringify(dimensions)}`)
+ await publicPage.screenshot({ path: path.join(report, '07-docs-mobile.png') })
+ await publicPage.locator('#endpoint-1').scrollIntoViewIfNeeded()
+ await publicPage.screenshot({ path: path.join(report, '08-docs-mobile-parameters.png') })
+ checks.push('公共文档无需登录,390px 窄屏无页面横向溢出')
+ assert.deepEqual(errors, [])
+ checks.push('浏览器无未捕获脚本错误')
+ fs.writeFileSync(path.join(report, 'results.json'), JSON.stringify({ passed: true, operationCount, checks, errors, timestamp: new Date().toISOString() }, null, 2))
+ console.log(JSON.stringify({ passed: true, operationCount, checks: checks.length, report }))
+} finally { await browser.close() }