@microi.net/cli 6.2.4 → 6.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/.codebuddy-plugin/marketplace.json +2 -2
  2. package/.codebuddy-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.workbuddy-plugin/marketplace.json +2 -2
  5. package/.workbuddy-plugin/plugin.json +1 -1
  6. package/assets/build-meta.json +6 -6
  7. package/cordis.patch.yml +1 -1
  8. package/package.json +1 -1
  9. package/scripts/mcp-server.js +118 -118
  10. package/scripts/microi-cli.js +64 -59
  11. package/scripts/microi-codex-broker.js +2 -0
  12. package/scripts/microi-skills.meta.json +318 -279
  13. package/skills/.microi-skills-version.json +2 -2
  14. package/skills/.progressive-disclosure-manifest.json +109 -106
  15. package/skills/ai-engine/SKILL.md +32 -2
  16. package/skills/ai-engine/references/cpu-timeline-export.md +31 -0
  17. package/skills/ai-engine/references/local-speech-s2v.md +35 -0
  18. package/skills/app-store/SKILL.md +567 -553
  19. package/skills/app-store/references/platform-row-format.md +7 -0
  20. package/skills/dos-orm/SKILL.md +5 -0
  21. package/skills/dos-orm/references/oceanbase-mysql.md +8 -0
  22. package/skills/job-engine/SKILL.md +12 -0
  23. package/skills/message-notification/SKILL.md +2 -0
  24. package/skills/microi-ai-application/SKILL.md +1 -0
  25. package/skills/microi-client-frontend/SKILL.md +13 -49
  26. package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +18 -1
  27. package/skills/microi-client-frontend/references/progressive-04-/345/211/215/347/253/257/346/216/245/345/217/243/344/270/216/347/274/223/345/255/230/346/201/242/345/244/215.md +45 -0
  28. package/skills/microi-codex/SKILL.md +5 -0
  29. package/skills/microi-codex-installer/SKILL.md +18 -2
  30. package/skills/microi-deployment/SKILL.md +376 -366
  31. package/skills/microi-deployment/references/deployment-matrix.md +167 -145
  32. package/skills/microi-deployment/references/offline-installer.md +66 -64
  33. package/skills/microi-docs-coverage/SKILL.md +1 -1
  34. package/skills/microi-docs-coverage/references/capability-map.md +11 -5
  35. package/skills/microi-form-engine/references/form-generation-quality.md +12 -0
  36. package/skills/microi-frontend-sdk/SKILL.md +12 -1
  37. package/skills/microi-left-right-layout/SKILL.md +176 -163
  38. package/skills/microi-microservice/SKILL.md +19 -0
  39. package/skills/microi-microservice/references/runtime-delivery.md +6 -0
  40. package/skills/microi-microservice/references/v3-committed-status-read.md +13 -0
  41. package/skills/microi-mobile-app-quality/SKILL.md +2 -0
  42. package/skills/microi-mobile-app-quality/references/mobile-first-delivery.md +2 -1
  43. package/skills/microi-system-delivery/SKILL.md +8 -1
  44. package/skills/microi-system-delivery/references/delivery-pitfalls.md +19 -0
  45. package/skills/microi-ui/SKILL.md +19 -4
  46. package/skills/microi-uniapp-frontend/SKILL.md +10 -1
  47. package/skills/microi.v8.js +17 -3
  48. package/skills/module-engine/SKILL.md +32 -2
  49. package/skills/ocr-engine/SKILL.md +30 -0
  50. package/skills/playwright-e2e/SKILL.md +11 -3
  51. package/skills/playwright-e2e/references/progressive-02-/346/226/207/345/255/227/345/257/271/346/257/224/345/272/246/344/270/216/345/217/257/350/257/273/346/200/247/350/207/252/345/212/250/345/214/226/346/243/200/346/237/245-/345/277/205/345/201/232.md +4 -4
  52. package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +2 -2
  53. package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +2 -2
  54. package/skills/system-observability/SKILL.md +24 -0
  55. package/skills/system-observability/references/framework-status-widgets.md +51 -0
  56. package/skills/system-observability/references/memory-incident-triage.md +14 -0
  57. package/skills/ui-design/SKILL.md +32 -5
  58. package/skills/ui-design/assets/pattern-showcase/app.js +57 -0
  59. package/skills/ui-design/assets/pattern-showcase/index.html +35 -4
  60. package/skills/ui-design/assets/pattern-showcase/scenario-state.js +34 -0
  61. package/skills/ui-design/assets/pattern-showcase/styles.css +115 -0
  62. package/skills/ui-design/references/controls-and-motion-research.md +49 -0
  63. package/skills/ui-design/references/data-workspace-density.md +8 -0
  64. package/skills/ui-design/references/design-pattern-library.md +50 -1
  65. package/skills/ui-design/references/media-geometry-and-pointer.md +42 -0
  66. package/skills/ui-design/references/mobile-product-language.md +95 -0
  67. package/skills/ui-design/references/motion-and-media.md +4 -2
  68. package/skills/ui-design/references/product-flow-recipes.md +3 -0
  69. package/skills/uniapp-mall-assets/SKILL.md +3 -0
  70. package/skills/v8-api-config/SKILL.md +2 -2
  71. package/skills/v8-crud-api/SKILL.md +2 -1
  72. package/skills/v8-file-upload/SKILL.md +2 -2
  73. package/skills/v8-frontend-events/SKILL.md +2 -1
  74. package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +21 -1
  75. package/skills/v8-security/SKILL.md +22 -5
  76. package/skills/v8-security/references/payment-gateway.md +25 -0
  77. package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +20 -0
  78. package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +19 -1
  79. package/skills/v8-sql-query/SKILL.md +2 -0
  80. package/skills/v8-table-event/SKILL.md +15 -2
  81. package/skills/v8-workflow/SKILL.md +8 -0
  82. package/skills/vision-engine/SKILL.md +284 -280
  83. package/skills/vision-engine/references/architecture-and-acceptance.md +14 -0
  84. package/skills/vision-engine/references/realtime-cpu-profiles.md +80 -0
  85. package/skills/vision-engine/references/video-timeline.md +189 -0
  86. package/skills/workspace-conventions/SKILL.md +3 -0
  87. package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +9 -9
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ui-design
3
- description: Microi UI 设计系统指南。用于设计 PC Vue、Element Plus、uni-app H5、仪表盘、表单、卡片、渐变、响应式布局、骨架屏、移动安全区和视觉打磨。
3
+ description: Microi UI 设计系统指南。用于 PC 微服务与 uni-app 产品的视觉方向、独特构图、主题、组件、动效及真实状态验收,也覆盖标准后台表单和数据页。
4
4
  ---
5
5
 
6
6
  > **Microi吾码基础规范(强制):** 任何 AI 模型与宿主每次新建或接续吾码任务,先完整读取 `../workspace-conventions/SKILL.md`,必须执行版本播报、`@microi.net/cli` 后台自动升级、Skills/MCP 同步和进度播报。安装与诊断读取 `../microi-codex-installer/SKILL.md`;更新失败延后重试,不阻断当前工作。
@@ -13,12 +13,12 @@ description: Microi UI 设计系统指南。用于设计 PC Vue、Element Plus
13
13
  > **核心理念**:结构服务任务,主题保持一致,密度按场景选择;动效可选,多端尊重实际可用空间。
14
14
  > **变量前缀**:所有 CSS 变量统一使用 `--mci-` 前缀(Microi Interface)
15
15
 
16
- **默认紧凑适度**:不鼓励大标题、大圆角、大间距,不把放大、留白或圆润等同于品质。标题按层级而非面积强调,常规卡片建议 6–10px、控件 4–8px 圆角、页面间距 12–16px;只有用户明确选择表现性视觉,或可读性/触控用途确有需要时才增大并说明理由。现有宿主组件由其主题契约控制,改 Skill 不等于修改或部署平台组件。
16
+ **先区分标准后台与定制产品**:标准表单、数据表和高频操作区默认紧凑适度,常规卡片可从 6–10px、控件 4–8px 圆角、页面间距 12–16px 起步;这些是效率场景基线,不是所有产品的视觉上限。移动消费产品、会员门户和定制微服务按产品任务选择排版、尺度、媒体和构图,用户要求鲜明、个性或提供表现性参考时应主动实现有辨识度的方向。放大、圆润、留白或渐变本身不构成品质;也不能因“默认紧凑”把所有页面做成同一标题加等大白卡。现有宿主组件仍由其主题契约控制,改 Skill 不等于修改或部署平台组件。
17
17
 
18
18
  ---
19
19
 
20
20
  <!-- microi-progressive:begin -->
21
- <!-- microi-progressive:chunk id=ui-design-000 sha256=b8b3dedc3fc95b9d32189e094b8b90fbf67b9f7c2e4a0307fa3e58ccce6d5de1 -->
21
+ <!-- microi-progressive:chunk id=ui-design-000 sha256=59e6f7670a706097cb998754b392a6b7e94fd940b963c99a7dbd52e1294365d7 -->
22
22
  ## 整体风格定义
23
23
 
24
24
  - **禁止弧形包边**:Tab、卡片、导航项、提示条和分组标题不得把强调色 `border-left` / `border-right` 与容器圆角组合成沿上下圆角弯曲的侧框,也不得用渐变、阴影或伪元素模拟同样的包边。默认不加侧框;需要强调时使用与容器边框独立的直竖线,垂直居中、与上下边缘留出间距且不随容器圆角弯折。直线端点可以有轻微圆角,容器本身仍可使用中性圆角边框。横向 Tabs 继续使用独立选中表面,不添加装饰线。亮色、暗色与移动端截图都必须核对这一规则。
@@ -31,11 +31,12 @@ description: Microi UI 设计系统指南。用于设计 PC Vue、Element Plus
31
31
  - **视觉验收**:至少选择浅色、暗色及一个非默认租户主题色,检查文本对比度、焦点态、状态色、悬停与禁用状态。
32
32
  - **按模式取舍**:数据工作台以中性表面、细边界、紧凑对齐和清楚数字为默认;品牌/内容展示可以选择表现性字体、材质或动效。不要把“高级、科技感”等形容词当作必须增加渐变、发光、重阴影或留白的指令。
33
33
  - **主题继承**:嵌入式页面继承当前租户和用户的主题、明暗及密度;独立产品再声明自己的默认。不得为重设计覆盖用户已选主题。
34
- - **参考吸收**:可参考成熟移动端 UI 灵感库的组件完整度、色彩节奏、入场动效和模板化能力,但 Microi 视觉必须通过 `--mci-*` token 与 MCI-UI 组件形成自己的品牌系统,不照搬第三方外观,也不在吾码源码、文档或样式命名中保留外部 UI 品牌痕迹。
34
+ - **参考吸收**:可参考成熟移动端 UI 灵感库的组件完整度、色彩节奏、入场动效和模板化能力,但 Microi 视觉必须通过 `--mci-*` token 与 MCI-UI 组件形成自己的品牌系统。成品文案、公开组件和样式命名不冒用外部品牌;研究引用与必要版权、许可归因必须保留,不得为“去品牌”删除授权声明或掩盖素材来源。
35
35
 
36
36
  ### Microi 设计模式选择(必须)
37
37
 
38
38
  - 当需求只描述“高级、主流、好看”而没有明确视觉方向时,先从 Microi 内置模式中确定一种主结构:品牌叙事、真实产品流程、趋势构图、沉浸互动、动态首屏或数据工作台;再选择至多两种辅助能力。禁止把多套视觉语言堆成拼盘。
39
+ - 定制产品与整站重设计还应按 [项目设计签名与场景配方](references/design-pattern-library.md#项目设计签名与场景配方) 先确定可辨认的构图特征,再选 token;记录首页、内容/列表、资产、表单和工作台如何在同一系统内形成任务差异。调换颜色、把圆角加大或只替换 Hero 不算完成整站重设计。
39
40
  - 管理、监控、分析、报表和高频操作页必须读取 [数据工作台密度规范](references/data-workspace-density.md)。它优先于下文展示模式的通用字号、圆角、阴影与动效示例:使用宿主可用区的 100% 宽度、实际容器断点、紧凑操作和逐路由几何/截图验收,不套固定最大宽度的营销页壳。
40
41
  - 设计结果必须被拆成可执行规则:首屏目标、信息层级、栅格与最大宽度、字体层级、语义颜色、间距、圆角/阴影、组件状态、动效时间线、响应式重排、低性能降级和 `prefers-reduced-motion`。
41
42
  - 先完成默认、加载、空、错误、成功、权限、禁用等真实业务状态,再增加装饰和动效;任何看起来可点击的元素都必须有真实结果。
@@ -46,6 +47,8 @@ description: Microi UI 设计系统指南。用于设计 PC Vue、Element Plus
46
47
 
47
48
  ### 可执行设计契约(整站与长期项目强制)
48
49
 
50
+ 移动产品另必读 [移动产品设计语言与可执行视觉门禁](references/mobile-product-language.md),按任务区分消费展示、资料录入和桌面业务工作台;呈现目的不能由 `embedded` 布尔值推导。此规则与用户明确视觉方向优先于后台紧凑 token 的示例值。
51
+
49
52
  - `MCI-DESIGN.md` 必须同时维护机器可读层和人类可读层:前者保存精确 token、引用和组件状态,后者保存目标用户、情绪、具体视觉隐喻、选择理由和禁区。只有 token 会失去取舍依据,只有形容词无法稳定实现。
50
53
  - 设计意图按“用户任务 → 主情绪 → 具体视觉隐喻 → 应当/禁止 → token 与组件”收敛。具体隐喻必须能自然约束色彩、材质、密度、形状和动效;禁止只堆“高级、现代、极简、科技”等宽泛词。
51
54
  - 核心章节固定为:产品与用户、视觉性格、颜色、字体、布局与间距、层级与形状、组件与状态、页面模式、动效与媒体、响应式、安全与降级、应当与禁止。扩展章节放在末尾,未知扩展要保留,核心章节不得重复或用近似拼写另起一套。
@@ -69,7 +72,7 @@ description: Microi UI 设计系统指南。用于设计 PC Vue、Element Plus
69
72
  ---
70
73
 
71
74
  <!-- /microi-progressive:chunk -->
72
- <!-- microi-progressive:chunk id=ui-design-002 sha256=72fea6fc01b6bd0de8b0c7a1766f45e9dc92a9a0dbb0e5ad9b38b626e0dfd27a -->
75
+ <!-- microi-progressive:chunk id=ui-design-002 sha256=c8c59054fae6fcd9db153827ca5f79d5348aeae3a0d9cd056d47528115c1e309 -->
73
76
  ## 高端视觉标准
74
77
 
75
78
  - 每个新页面必须有首屏视觉重心:核心数据、主任务、产品/品牌对象或可操作内容应在第一屏明确出现,不能只有说明文字或空白装饰。
@@ -91,6 +94,17 @@ description: Microi UI 设计系统指南。用于设计 PC Vue、Element Plus
91
94
  - 日志、告警、监控和审计表格的主标题与副标题默认各最多两行,使用 CSS line clamp 与原文 Tooltip/title 保留完整可读性;异常行、异常值和风险标签必须使用主题兼容的红色语义,并在悬停/聚焦时同时说明“可能原因、排查顺序、解决方案”,不能只显示红色数字。
92
95
  - 驾驶舱/数据大屏风格必须跟随当前主题令牌并保持紧凑信息密度。持续动效仅允许少量低振幅 `transform`、`opacity`、`background-position`,页面隐藏、微服务 `afterhidden` 或低性能模式时暂停;必须实现 `prefers-reduced-motion` 静态降级,长表格启用虚拟化或 `content-visibility`,禁止每个单元格独立定时器、持续阴影/模糊重绘和高频全量图表重算。
93
96
 
97
+ ## 玻璃材质的分层与真实清晰度(强制)
98
+
99
+ - `Solid/Glass/Frosted/Liquid` 是独立材质维度,不替换明暗模式、主题色或用户密度。沿用吾码语义变量;不导入外部 Skill 命令、自动 DOM 接管或另一套持久偏好。表单 `CodeEditor` 例外:工具栏、原生 Monaco 画布/语法及 AI 内部控件保留独立固定暗色域,不跟随平台外观,也不逐项重写语法 token。
100
+ - 背景应保留壁纸色彩与明暗结构,不通过全局去饱和滤镜或厚重白/黑 veil 把整页压成灰底,再用更多透明层补救。一个独立外壳只采样一次背景;导航、表格/表单外壳、Dialog/Drawer、Popover 与 WebOS 窗口各有明确所有者,内层画布透明、按钮与控件轻填充,不给每个字段或表格单元格再套独立模糊。
101
+ - 背景采样、局部填充、边缘与正文分层。正文和图标保持正常 opacity,不用 `filter` 或 `mix-blend-mode` 混合文字;静态边为细暗边,有限方向反光只帮助识别轮廓,不画泛白整圈或发光外框。圆角、焦点与字号仍服从宿主、小密度及输入设备约定,不照搬展示型玻璃的尺寸。
102
+ - 弹窗、嵌套弹窗、普通下拉与列菜单必须阻止后方业务文字透穿,保留背景色块与纹理;不能只减低填充数值而让两套文字重叠,也不能为单个浮层加厚全局底。`body` Teleport 的浮层继续接收本宿主语义 token,保留焦点、层级、拖动、滚动和权限行为。
103
+ - 浅色玻璃使用明亮珍珠色局部填充,导航与内容明度一致、卡片轻填充并保留层次,不能把整屏等量染色。连续外壳必须覆盖四边 padding,内部页签条与路由画布不再铺独立玻璃;验收检查弹窗真实 Loading 骨架、分页和默认 Banner 指标的 DOM,不能只验证演示样板或变量,遗漏纯白底和二次模糊。
104
+ - 光学增强只作用于明确少量外壳;不全页创建 SVG/WebGL 滤镜、复制实时 DOM 或持续重绘。区分 stacking context 与 backdrop root,不按外部注释盲删布局 transform;检查父级 filter、opacity、mask/clip-path、自身 backdrop-filter 等真实采样边界,并以目标浏览器画面确认。
105
+ - 验收同时覆盖亮/暗、普通/磨砂/液态、真实彩色与明暗壁纸、表格/表单/微服务/WebOS、单层与嵌套浮层。除既有文字/焦点对比度外,核对背景纹理透射、层次、边缘与文字不受滤镜影响;不能用纯色板、构建成功或一次截图替代实页检查。无 backdrop-filter、减少透明度或 forced-colors 时降级可读实色;减少动态只停止动态,不改变静态材质开关。
106
+ - 设计研究可查看 [GlassDesk](https://github.com/everlosttime/glassdesk-open-source)(新增原创部分 PolyForm Noncommercial,历史 Apache/第三方范围另计)、[DeskBox](https://github.com/Tianyu199509/DeskBox)(GPL-3.0)、[Liquid Glass Components](https://github.com/jcm-developer/liquid-glass-components) 与 [sohumsuthar/liquid-glass](https://github.com/sohumsuthar/liquid-glass)(后二者 MIT)。前两者仅作本项目视觉参考;MIT 片段如直接复用须保留版权及许可,并审查交互/浏览器边界。外部规则不覆盖用户要求或吾码业务契约。
107
+
94
108
  ---
95
109
 
96
110
  <!-- /microi-progressive:chunk -->
@@ -203,6 +217,10 @@ Microi 项目必须支持用户或项目级形态偏好:`data-mci-shape="round
203
217
 
204
218
  ## 按钮文本可读性与多端验收(强制)
205
219
 
220
+ 按钮、图标、主题或持续动效打磨时,读取 [交互控件、动效与有声媒体](references/controls-and-motion-research.md)。参考成熟 Vue 组件与 Skills 的可测行为,落实到现有 Mci 组件;不要以引入新库替代修复实际页面。
221
+
222
+ 涉及图片、图集、海报或鼠标跟随时,还必须执行 [媒体比例、响应式与指针效果门禁](references/media-geometry-and-pointer.md)。保留原图/子图的等比绘制并检查主体裁切,不能以无横向溢出替代人物和圆形物体比例检查;手机以实际 CSS 视口、触控、安全区和表单可达性验收,指针特效必须有静止与隐藏停机证据。
223
+
206
224
  - 主按钮、下载按钮、CTA、标签式链接必须在组件自己的命名空间内显式声明默认、hover、focus-visible、active、disabled 的文字色、背景色和边框色;不得依赖父级文字色、全局 `a` 样式、浏览器默认色或透明背景上的偶然对比度。图标的 `color` / `stroke` / `fill` 必须跟随同一语义前景色。
207
225
  - 普通文字与背景的对比度至少达到 4.5:1;大号文字至少达到 3:1;有意义的图标、边框和焦点指示至少达到 3:1。渐变、透明、毛玻璃和背景图片上的按钮,要按实际可出现的最差背景位置验收,不能只检查 CSS 变量名或设计稿色值。
208
226
  - 每个关键按钮必须在真实渲染页逐一核对“按钮存在、完整文案可见、前景色和背景色可区分、hover/focus 后仍可读、点击区域未被遮挡”。自动化至少读取最终 computed style 并断言颜色不是透明或同色;视觉验收至少覆盖 1440px 桌面与约 390px 手机宽度的浅色、暗色截图。
@@ -225,3 +243,12 @@ Microi 项目必须支持用户或项目级形态偏好:`data-mci-shape="round
225
243
  - **侧栏清爽但层级清晰**:压缩无效间距,保留足够点击区域、选中态、父子层级和键盘焦点;颜色、圆角、阴影必须来自主题 token。
226
244
  - **纵向导航使用短圆角侧标**:侧栏、纵向 Tab、分组导航等选中态的左/右侧强调线统一参照平台左侧菜单:宽 3–4px、高度约为选中项的 45%–60%,垂直居中,端点使用小圆角;禁止铺满 100% 高度,也禁止做折线或包边。右侧 Tab 镜像到右边;横向 Tabs 不使用这条侧标,也不额外增加上下指示线。
227
245
  - **主题与可访问性验收**:至少验证亮色/暗色、租户主题色、1366/1440/1920 桌面与 390px 移动宽度、三种标签对齐、慢接口和接口失败;动效必须服从 `prefers-reduced-motion`。
246
+
247
+
248
+ ## 账号入口与受信权益状态
249
+
250
+ - 账户冷启动/刷新未完成权威本人核验时,账号入口显示正在核验骨架或checking状态,不闪现缓存账号、旧头像积分或登录成功。网络失败保留明确重试状态;只有真实会话失效才展示登录入口。账号区、工作台内容和请求状态必须消费同一个已核验身份状态,避免左下角说已登录而业务仍匿名。
251
+ - 桌面左下角或等效固定账号入口展示真实本人头像/姓名和当前服务端权益摘要;图片等比绘制,缺图使用可辨识用户图标。普通用户显示真实积分,0是有效值;未配置、未知、失败分别显示对应状态,不能编造0余额或无限。
252
+ - 管理员或可信Level>=9999的无限/免积分标识必须来自同次服务端本人核验和后端业务权益判定,或实际Quote返回的Exempt/0收费合同;不能按缓存Level、显示名含admin或客户端开关授予。未知余额用“管理员免积分/无限”表达受信权益,不伪造巨大余额;硬件排队、内存/显存预算、模型故障、本人资产权限与幂等仍照常执行。
253
+ - 账号展开菜单提供明确的“退出登录”文字和可识别退出图标(如当前已注册SwitchButton),不以X当退出。X只负责关闭弹层。账号按钮/退出项支持键盘焦点、aria-expanded、明暗主题和手机触控,退出或换号立即清除旧姓名/头像/积分并关闭私有面板,不能等下个接口报错。
254
+ - 验收覆盖冷启动、刷新、账号切换、跨标签撤销、普通真实0积分、受信管理员免积分、未知/错误余额、退出项与关闭项区分。运行时/普通账号/手机浏览器未执行时保留待验,不从设计文档或组件测试推定客户已部署。
@@ -10,6 +10,63 @@
10
10
  var status = document.getElementById('formStatus');
11
11
  var submit = document.getElementById('flowSubmit');
12
12
 
13
+ // 两个场景共用纯本地状态;所有数字均由示例集合推导,不代表在线业务结果。
14
+ var scene = window.MciPatternScenario;
15
+ var life = scene.lifeInitial();
16
+ var work = scene.workInitial();
17
+ var lifeRoot = document.getElementById('lifeScene');
18
+ var queueRoot = document.getElementById('workQueue');
19
+ var detailRoot = document.getElementById('workDetail');
20
+ var actionMessage = '';
21
+ function syncSceneVisibility() { root.dataset.mciPaused = document.hidden ? 'true' : 'false'; }
22
+ document.addEventListener('visibilitychange', syncSceneVisibility);
23
+ syncSceneVisibility();
24
+ function escapeText(value) { return String(value).replace(/[&<>"']/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]; }); }
25
+ function renderLife() {
26
+ var claimed = life.claimed.length;
27
+ document.getElementById('lifeClaimCount').textContent = claimed;
28
+ document.querySelectorAll('[data-life-view]').forEach(function (button) { button.setAttribute('aria-pressed', String(button.dataset.lifeView === life.view)); });
29
+ if (life.view === 'profile') {
30
+ lifeRoot.innerHTML = '<div class="mci-life-profile"><span class="mci-life-profile__seal" aria-hidden="true">' +
31
+ '<svg viewBox="0 0 48 48"><path d="M12 15h24v18H12zM18 10v10m12-10v10M18 25h12"/></svg></span><p>我的通行证</p><h3>从一次体验,<br>到喜欢的日常。</h3><dl><div><dt>已领取</dt><dd>' + claimed + ' 份</dd></div><div><dt>尚可体验</dt><dd>' + (scene.benefits.length - claimed) + ' 项</dd></div></dl><p class="mci-life-meta">此场景没有真实用户身份。接入项目后,从当前会话读取会员与授权权益。</p><button class="mci-life-action" type="button" data-life-view="benefits">查看已领取权益 <span aria-hidden="true">↗</span></button></div>';
32
+ return;
33
+ }
34
+ var hero = life.view === 'discover' ? '<section class="mci-life-editorial"><p>给忙碌留一点空隙</p><h3>城市与日常,<br>都有新鲜感。</h3><span class="mci-life-editorial__caption">从街角开始,发现一点不同</span><svg class="mci-life-city" viewBox="0 0 180 190" aria-label="原创城市路线插画" role="img"><circle class="mci-life-city__sun" cx="124" cy="35" r="24"/><path class="mci-life-city__ground" d="M0 150 180 107v83H0z"/><path class="mci-life-city__building" d="m28 66 60-14v86l-60 14zM100 84l43-11v45l-43 11z"/><path class="mci-life-city__window" d="m39 81 10-2v14l-10 2zm21-5 10-2v14l-10 2zm-21 29 10-2v14l-10 2zm21-5 10-2v14l-10 2z"/><path class="mci-life-city__route" d="M14 171c28-28 52 14 78-11s30-5 64-35"/><path class="mci-life-city__tree" d="M157 69v75m0-30c-23-3-25-26-25-26 23 1 25 26 25 26m0-18c24-6 22-29 22-29-24 5-22 29-22 29"/></svg></section>' : '';
35
+ var categories = [['all', '全部'], ['travel', '出行'], ['life', '日常'], ['service', '服务']].map(function (item) { return '<button type="button" data-life-category="' + item[0] + '" aria-pressed="' + (life.category === item[0]) + '">' + item[1] + '</button>'; }).join('');
36
+ var rows = scene.lifeVisible(life);
37
+ lifeRoot.innerHTML = hero + '<div class="mci-life-section-title"><h3>' + (life.view === 'benefits' ? '已经在你的通行证里' : '为日常,添一点喜欢') + '</h3><span>' + rows.length + ' 项</span></div><div class="mci-life-categories" role="group" aria-label="权益分类">' + categories + '</div><div class="mci-life-benefits">' + (rows.length ? rows.map(function (b) {
38
+ var received = life.claimed.indexOf(b.id) !== -1;
39
+ return '<article class="mci-life-benefit mci-life-benefit--' + b.tone + '"><div class="mci-life-benefit__mark" aria-hidden="true"><span>' + b.mark + '</span><i></i></div><div class="mci-life-benefit__body"><small>' + b.label + '</small><h4>' + escapeText(b.title) + '</h4><p>' + escapeText(b.detail) + '</p><button type="button" data-life-claim="' + b.id + '"' + (received ? ' disabled' : '') + '>' + (received ? '已领取' : '领取演示权益') + '<span aria-hidden="true">' + (received ? '✓' : '↗') + '</span></button></div></article>';
40
+ }).join('') : '<div class="mci-life-empty"><strong>这里还没有已领取权益</strong><p>回到精选领取一份,新的记录就会在这里出现。</p><button type="button" data-life-view="discover">去看看精选</button></div>') + '</div>';
41
+ }
42
+ function renderWork() {
43
+ var rows = scene.workRows(work), counts = scene.workCounts(work);
44
+ var selected = rows.find(function (t) { return t.id === work.selected; }) || rows[0];
45
+ if (selected) work.selected = selected.id;
46
+ document.getElementById('workSummary').textContent = '全部示例:' + counts.open + ' 项待处理 · ' + counts.done + ' 项已完成';
47
+ document.getElementById('workQueueCount').textContent = rows.length + ' 项匹配';
48
+ document.querySelectorAll('[data-work-day]').forEach(function (button) { button.setAttribute('aria-pressed', String(button.dataset.workDay === work.day)); });
49
+ document.getElementById('workFilter').value = work.filter;
50
+ queueRoot.innerHTML = rows.length ? rows.map(function (t) { return '<button class="mci-briefing-row" type="button" data-work-select="' + t.id + '" aria-pressed="' + (selected.id === t.id) + '"><span class="mci-briefing-row__signal" data-priority="' + t.priority + '" aria-hidden="true"></span><span class="mci-briefing-row__copy"><strong>' + escapeText(t.title) + '</strong><small>' + escapeText(t.team) + ' · ' + escapeText(t.time) + '</small></span><span class="mci-briefing-row__state">' + (t.state === 'done' ? '已完成' : t.priority === 1 ? '优先关注' : '待处理') + '</span><span aria-hidden="true">↗</span></button>'; }).join('') : '<div class="mci-workroom__empty"><strong>当前范围没有待处理事项</strong><p>可以切换日期或查看全部状态。</p><button type="button" data-work-show-all>查看全部任务</button></div>';
51
+ detailRoot.innerHTML = selected ? '<span class="mci-workroom__detail-label">本次行动</span><h4>' + escapeText(selected.title) + '</h4><p>' + escapeText(selected.summary) + '</p><dl><div><dt>负责小组</dt><dd>' + escapeText(selected.team) + '</dd></div><div><dt>约定时间</dt><dd>' + escapeText(selected.time) + '</dd></div></dl><button class="mci-life-action" type="button" data-work-complete="' + selected.id + '"' + (selected.state === 'done' ? ' disabled' : '') + '>' + (selected.state === 'done' ? '已完成复核' : '标记本地示例完成') + '<span aria-hidden="true">✓</span></button>' : '<span class="mci-workroom__detail-label">保持清晰</span><h4>把注意力留给真正要做的事。</h4><p>空队列保留上下文,筛选与统计仍然可用。</p>';
52
+ var feedback = document.createElement('p'); feedback.className = 'mci-workroom__feedback'; feedback.setAttribute('role', 'status'); feedback.textContent = actionMessage; detailRoot.appendChild(feedback);
53
+ }
54
+ document.getElementById('expressive').addEventListener('click', function (event) {
55
+ var button = event.target.closest('button'); if (!button || button.disabled) return;
56
+ if (button.dataset.lifeView) { life = scene.lifeReduce(life, { type: 'view', value: button.dataset.lifeView }); renderLife(); }
57
+ if (button.dataset.lifeCategory) { life = scene.lifeReduce(life, { type: 'category', value: button.dataset.lifeCategory }); renderLife(); lifeRoot.querySelector('[data-life-category="' + life.category + '"]').focus(); }
58
+ if (button.dataset.lifeClaim) { life = scene.lifeReduce(life, { type: 'claim', id: button.dataset.lifeClaim }); renderLife(); var heading = lifeRoot.querySelector('.mci-life-section-title h3'); heading.setAttribute('tabindex', '-1'); heading.focus(); }
59
+ if (button.dataset.workSelect) { work = scene.workReduce(work, { type: 'select', id: button.dataset.workSelect }); renderWork(); queueRoot.querySelector('[data-work-select="' + work.selected + '"]').focus(); }
60
+ if (button.dataset.workDay) { work = scene.workReduce(work, { type: 'day', value: button.dataset.workDay }); renderWork(); }
61
+ if (button.dataset.workComplete) { work = scene.workReduce(work, { type: 'complete', id: button.dataset.workComplete }); actionMessage = '已更新本地示例状态;接入业务时应等待后端成功回执。'; renderWork(); }
62
+ if (button.hasAttribute('data-work-show-all')) { work = scene.workReduce(scene.workReduce(work, { type: 'day', value: 'all' }), { type: 'filter', value: 'all' }); renderWork(); }
63
+ });
64
+ document.getElementById('workFilter').addEventListener('change', function (event) { work = scene.workReduce(work, { type: 'filter', value: event.target.value }); renderWork(); });
65
+ document.getElementById('scenePaletteToggle').addEventListener('click', function () { var violet = root.dataset.mciPalette !== 'violet'; root.dataset.mciPalette = violet ? 'violet' : 'forest'; this.setAttribute('aria-pressed', String(violet)); this.textContent = '场景配色:' + (violet ? '紫藤' : '海松'); });
66
+ document.getElementById('sceneMotionToggle').addEventListener('click', function () { var reduced = root.dataset.mciMotion !== 'reduced'; root.dataset.mciMotion = reduced ? 'reduced' : 'full'; this.setAttribute('aria-pressed', String(reduced)); this.textContent = '减少动态:' + (reduced ? '开启' : '关闭'); });
67
+ document.getElementById('sceneReset').addEventListener('click', function () { life = scene.lifeInitial(); work = scene.workInitial(); actionMessage = ''; renderLife(); renderWork(); });
68
+ renderLife(); renderWork();
69
+
13
70
  themeToggle.addEventListener('click', function () {
14
71
  var nextTheme = root.dataset.mciTheme === 'dark' ? 'light' : 'dark';
15
72
  root.dataset.mciTheme = nextTheme;
@@ -15,6 +15,7 @@
15
15
  <span>Microi Pattern Lab</span>
16
16
  </a>
17
17
  <nav class="mci-lab__nav-links" aria-label="页面导航">
18
+ <a href="#expressive">可运行场景</a>
18
19
  <a href="#patterns">设计模式</a>
19
20
  <a href="#flow">产品流程</a>
20
21
  <a href="#contract">设计契约</a>
@@ -32,20 +33,49 @@
32
33
  <div class="mci-hero__content">
33
34
  <span class="mci-eyebrow">MICROI ORIGINAL DESIGN SYSTEM</span>
34
35
  <h1>让业务界面先有<br><em>清晰的设计意图</em></h1>
35
- <p>本页展示多种明确视觉方向下的可选模式,不是通用页面的默认尺寸。默认紧凑适度,不鼓励大标题、大圆角和大间距;数据操作页按宿主可用区设计。</p>
36
+ <p>先决定主要对象和阅读顺序,再选择色彩与形状。下方两个原创交互场景展示:同一套语义主题怎样支撑不同的任务与构图,标准后台操作区仍保持清楚稳定。</p>
36
37
  <div class="mci-hero__actions">
37
- <a class="mci-button mci-button--primary" href="#patterns">浏览设计模式 <span aria-hidden="true">↘</span></a>
38
+ <a class="mci-button mci-button--primary" href="#expressive">体验原创场景 <span aria-hidden="true">↘</span></a>
38
39
  <a class="mci-button mci-button--quiet" href="#flow">查看真实流程</a>
39
40
  </div>
40
41
  </div>
41
42
  <div class="mci-hero__console" aria-label="设计系统实时状态">
42
43
  <div class="mci-console__head"><span></span><span></span><span></span><b>MCI-DESIGN</b></div>
43
44
  <div class="mci-console__orbit" aria-hidden="true"><i></i><i></i><i></i></div>
44
- <div class="mci-console__metric"><small>组件状态覆盖率</small><strong>08</strong><span>default → error</span></div>
45
+ <div class="mci-console__metric"><small>组件状态示意</small><strong>08</strong><span>default → error</span></div>
45
46
  <div class="mci-console__footer"><span>responsive</span><span>accessible</span><span>reduced-motion</span></div>
46
47
  </div>
47
48
  </section>
48
49
 
50
+ <section class="mci-expression" id="expressive" aria-labelledby="expressiveTitle">
51
+ <div class="mci-expression__heading">
52
+ <div><p class="mci-expression__kicker">原创交互样例 · 本地演示数据</p><h2 id="expressiveTitle">让同一套设计语言,长出不同的产品。</h2></div>
53
+ <div class="mci-expression__controls">
54
+ <button id="scenePaletteToggle" type="button" aria-pressed="false">场景配色:海松</button>
55
+ <button id="sceneMotionToggle" type="button" aria-pressed="false">减少动态:关闭</button>
56
+ <button id="sceneReset" type="button">重置演示</button>
57
+ </div>
58
+ </div>
59
+ <p class="mci-expression__notice">这里的领取、筛选和完成只改变本页状态,不连接租户、不执行交易。原生按钮可键盘操作;可切明暗、场景配色与减少动态。</p>
60
+ <div class="mci-expression__mobile-layout">
61
+ <article class="mci-life-phone" aria-label="编辑式会员服务场景">
62
+ <header class="mci-life-head"><span class="mci-life-mark" aria-hidden="true"><svg viewBox="0 0 32 32"><path d="M7 9h18v14H7zM11 5v8m10-8v8M11 18h10"/></svg></span><span>城市生活通行证<small>把时间留给喜欢的日常</small></span><span class="mci-life-head__dot" aria-hidden="true"></span></header>
63
+ <div id="lifeScene" class="mci-life-body" aria-live="polite"></div>
64
+ <nav class="mci-life-dock" aria-label="会员场景导航">
65
+ <button type="button" data-life-view="discover" aria-pressed="true"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m3 11 9-8 9 8v10h-6v-7H9v7H3z"/></svg><span>精选</span></button>
66
+ <button type="button" data-life-view="benefits" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 5h18v5a2 2 0 0 0 0 4v5H3v-5a2 2 0 0 0 0-4zM15 7v2m0 2v2m0 2v2"/></svg><span>权益</span><span id="lifeClaimCount" class="mci-life-dock__count">0</span></button>
67
+ <button type="button" data-life-view="profile" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 21v-2a8 8 0 0 1 16 0v2"/></svg><span>我的</span></button>
68
+ </nav>
69
+ </article>
70
+ <aside class="mci-expression__notes"><span>移动产品 · 编辑式会员页</span><h3>一张通行证,<br>串起权益与生活。</h3><p>标题、主体插画、票券形态与不同尺度分区形成阅读顺序。选择分类会改变内容,领取会去重并更新导航计数;切到“权益”可查看已领取记录。</p><dl><div><dt>设计签名</dt><dd>票券切口、轻纸感、路线插画与悬浮导航</dd></div><div><dt>页面任务</dt><dd>先发现内容,再领取并管理权益</dd></div><div><dt>接入业务时</dt><dd>用真实商品、规则、身份和后端命令替换演示数据</dd></div></dl></aside>
71
+ </div>
72
+ <article class="mci-workroom" aria-labelledby="workroomTitle">
73
+ <header class="mci-workroom__head"><div><span>PC 定制微服务 · 运营简报</span><h3 id="workroomTitle">今天的服务,先处理要紧的事。</h3></div><span class="mci-workroom__stamp">本地示例状态</span></header>
74
+ <div class="mci-workroom__toolbar"><div role="group" aria-label="任务日期"><button type="button" data-work-day="today" aria-pressed="true">今天</button><button type="button" data-work-day="all" aria-pressed="false">全部日期</button></div><label>任务范围<select id="workFilter"><option value="open">待处理</option><option value="risk">优先关注</option><option value="all">全部状态</option></select></label><p id="workSummary" role="status"></p></div>
75
+ <div class="mci-workroom__canvas"><section class="mci-workroom__queue" aria-labelledby="workQueueTitle"><div class="mci-workroom__section-head"><h4 id="workQueueTitle">行动队列</h4><span id="workQueueCount"></span></div><div id="workQueue"></div></section><aside class="mci-workroom__detail" id="workDetail" aria-live="polite"></aside></div>
76
+ </article>
77
+ </section>
78
+
49
79
  <section class="mci-section" id="patterns">
50
80
  <div class="mci-section__head">
51
81
  <div><span class="mci-eyebrow">PATTERN LIBRARY</span><h2>六种模式,一套品牌语言</h2></div>
@@ -112,7 +142,7 @@
112
142
  <article class="mci-pattern mci-pattern--data" data-kind="data">
113
143
  <div class="mci-pattern__visual">
114
144
  <span class="mci-pattern__index">06</span>
115
- <div class="mci-data-head"><span>运营总览</span><b>实时</b></div>
145
+ <div class="mci-data-head"><span>运营总览</span><b>本地示例</b></div>
116
146
  <div class="mci-data-metrics"><span><small>服务中</small><b>128</b></span><span><small>完成率</small><b>96%</b></span><span><small>风险项</small><b>07</b></span></div>
117
147
  <div class="mci-data-chart" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div>
118
148
  </div>
@@ -158,6 +188,7 @@
158
188
 
159
189
  <footer class="mci-lab__footer"><span>Microi.UI Original Pattern Asset</span><span>Local only · No external dependency</span></footer>
160
190
  </main>
191
+ <script src="./scenario-state.js"></script>
161
192
  <script src="./app.js"></script>
162
193
  </body>
163
194
  </html>
@@ -0,0 +1,34 @@
1
+ /* 原创演示状态,与渲染分离;不读取会话、不请求网络、不模拟真实交易受理。 */
2
+ (function (scope) {
3
+ 'use strict';
4
+ var benefits = [
5
+ { id: 'city', kind: 'travel', label: '出行', title: '沿着街角,重新认识城市', detail: '城市漫游通行体验', mark: '路线', tone: 'route' },
6
+ { id: 'coffee', kind: 'life', label: '日常', title: '留一个下午,给咖啡香', detail: '周末到店体验权益', mark: '时光', tone: 'coffee' },
7
+ { id: 'care', kind: 'service', label: '服务', title: '让忙碌的日子,轻一点', detail: '到店洗护服务体验', mark: '轻松', tone: 'care' }
8
+ ];
9
+ var tasks = [
10
+ { id: 'reply', title: '服务异常待回应', team: '服务支持组', time: '今天 14:00', day: 'today', priority: 1, summary: '先核对影响范围,再联系提交人确认恢复结果。', state: 'open' },
11
+ { id: 'visit', title: '交付后的第一次回访', team: '客户成功组', time: '今天 16:30', day: 'today', priority: 2, summary: '确认使用情况,整理反馈并给出可执行的下一步。', state: 'open' },
12
+ { id: 'info', title: '资料补全与交接', team: '运营协作组', time: '明天 10:00', day: 'later', priority: 3, summary: '对照清单补齐缺失资料,保留处理记录与负责人。', state: 'open' },
13
+ { id: 'review', title: '服务记录已复核', team: '运营协作组', time: '今天 09:30', day: 'today', priority: 3, summary: '归档已确认的结果,之后仍可查看处理依据。', state: 'done' }
14
+ ];
15
+ function lifeInitial() { return { view: 'discover', category: 'all', claimed: [] }; }
16
+ function lifeReduce(state, action) {
17
+ if (action.type === 'view' && ['discover', 'benefits', 'profile'].indexOf(action.value) !== -1) return Object.assign({}, state, { view: action.value });
18
+ if (action.type === 'category' && ['all', 'travel', 'life', 'service'].indexOf(action.value) !== -1) return Object.assign({}, state, { category: action.value });
19
+ if (action.type === 'claim' && benefits.some(function (b) { return b.id === action.id; })) return Object.assign({}, state, { claimed: state.claimed.indexOf(action.id) === -1 ? state.claimed.concat(action.id) : state.claimed.slice() });
20
+ return state;
21
+ }
22
+ function lifeVisible(state) { return benefits.filter(function (b) { return (state.category === 'all' || b.kind === state.category) && (state.view !== 'benefits' || state.claimed.indexOf(b.id) !== -1); }); }
23
+ function workInitial() { return { day: 'today', filter: 'open', selected: 'reply', completed: [] }; }
24
+ function workRows(state) { return tasks.map(function (t) { return Object.assign({}, t, { state: state.completed.indexOf(t.id) !== -1 ? 'done' : t.state }); }).filter(function (t) { return (state.day === 'all' || t.day === state.day) && (state.filter === 'all' || t.state === 'open' && (state.filter !== 'risk' || t.priority === 1)); }).sort(function (a, b) { return a.priority - b.priority; }); }
25
+ function workReduce(state, action) {
26
+ if (action.type === 'day' && ['today', 'all'].indexOf(action.value) !== -1) return Object.assign({}, state, { day: action.value });
27
+ if (action.type === 'filter' && ['all', 'open', 'risk'].indexOf(action.value) !== -1) return Object.assign({}, state, { filter: action.value });
28
+ if (action.type === 'select' && tasks.some(function (t) { return t.id === action.id; })) return Object.assign({}, state, { selected: action.id });
29
+ if (action.type === 'complete' && tasks.some(function (t) { return t.id === action.id && t.state !== 'done'; })) return Object.assign({}, state, { completed: state.completed.indexOf(action.id) === -1 ? state.completed.concat(action.id) : state.completed.slice() });
30
+ return state;
31
+ }
32
+ function workCounts(state) { var done = tasks.filter(function (t) { return t.state === 'done' || state.completed.indexOf(t.id) !== -1; }).length; return { open: tasks.length - done, done: done }; }
33
+ scope.MciPatternScenario = { benefits: benefits, tasks: tasks, lifeInitial: lifeInitial, lifeReduce: lifeReduce, lifeVisible: lifeVisible, workInitial: workInitial, workReduce: workReduce, workRows: workRows, workCounts: workCounts };
34
+ }(typeof globalThis !== 'undefined' ? globalThis : this));
@@ -257,6 +257,121 @@ button, a { -webkit-tap-highlight-color: transparent; }
257
257
  .mci-contract__code span { color: #72e7ff; }
258
258
  .mci-lab__footer { display: flex; justify-content: space-between; width: min(1180px, calc(100% - 40px)); margin: 0 auto; padding: 30px 0 42px; border-top: 1px solid var(--mci-border); color: var(--mci-text-muted); font-size: 10px; letter-spacing: .08em; }
259
259
 
260
+ /* 场景维度独立于明暗与强调色;构图和业务状态不随换色改变。 */
261
+ :root {
262
+ --mci-scene-canvas: #14221a;
263
+ --mci-scene-paper: #1c2c22;
264
+ --mci-scene-soft: #293c30;
265
+ --mci-scene-text: #f1f5ed;
266
+ --mci-scene-muted: #b0c0b3;
267
+ --mci-scene-line: #48604f;
268
+ --mci-scene-accent: #c9e5cb;
269
+ --mci-scene-on-accent: #1d3526;
270
+ --mci-scene-warm: #484231;
271
+ --mci-scene-sky: #30494e;
272
+ --mci-scene-risk: #f4cda1;
273
+ }
274
+ :root[data-mci-theme="light"] {
275
+ --mci-scene-canvas: #eef1e9;
276
+ --mci-scene-paper: #fafbf7;
277
+ --mci-scene-soft: #e0e9da;
278
+ --mci-scene-text: #1d3024;
279
+ --mci-scene-muted: #536557;
280
+ --mci-scene-line: #c2cdc0;
281
+ --mci-scene-accent: #29563f;
282
+ --mci-scene-on-accent: #ffffff;
283
+ --mci-scene-warm: #f0e2cd;
284
+ --mci-scene-sky: #dbe9e9;
285
+ --mci-scene-risk: #835122;
286
+ }
287
+ :root[data-mci-palette="violet"] { --mci-scene-accent: #e1d3f3; --mci-scene-on-accent: #39264e; --mci-scene-soft: #383046; }
288
+ :root[data-mci-theme="light"][data-mci-palette="violet"] { --mci-scene-accent: #624779; --mci-scene-on-accent: #fff; --mci-scene-soft: #e8e1f0; }
289
+ .mci-expression { width: min(1180px, calc(100% - 40px)); margin: 0 auto; padding: 64px 0 84px; border-top: 1px solid var(--mci-border); }
290
+ .mci-expression__heading { display: flex; align-items: end; justify-content: space-between; flex-wrap: wrap; gap: 24px; }
291
+ .mci-expression__heading h2 { max-width: 620px; margin: 8px 0 0; font-size: clamp(26px, 3vw, 38px); line-height: 1.25; letter-spacing: -.04em; }
292
+ .mci-expression__kicker, .mci-expression__notice { color: var(--mci-text-muted); font-size: 13px; line-height: 1.7; }
293
+ .mci-expression__kicker { margin: 0; }
294
+ .mci-expression__controls { display: flex; flex-wrap: wrap; gap: 8px; }
295
+ .mci-expression__controls button { min-height: 44px; padding: 0 12px; border: 1px solid var(--mci-border); border-radius: 8px; color: var(--mci-text); background: var(--mci-bg-soft); font-size: 12px; cursor: pointer; }
296
+ .mci-expression__notice { max-width: 760px; margin: 18px 0 32px; }
297
+ .mci-expression__mobile-layout { display: grid; grid-template-columns: minmax(0, 390px) minmax(0, 1fr); align-items: center; gap: clamp(28px, 7vw, 100px); }
298
+ .mci-expression__notes { max-width: 480px; }
299
+ .mci-expression__notes > span { color: var(--mci-text-muted); font-size: 13px; }
300
+ .mci-expression__notes h3 { margin: 20px 0; font-size: clamp(30px, 3.6vw, 48px); line-height: 1.22; letter-spacing: -.04em; }
301
+ .mci-expression__notes p { color: var(--mci-text-muted); font-size: 15px; line-height: 1.8; }
302
+ .mci-expression__notes dl { margin-top: 32px; }
303
+ .mci-expression__notes dl > div { padding: 16px 0; border-top: 1px solid var(--mci-border); }
304
+ .mci-expression__notes dt { margin-bottom: 6px; font-size: 13px; font-weight: 700; }
305
+ .mci-expression__notes dd { margin: 0; color: var(--mci-text-muted); font-size: 13px; line-height: 1.7; }
306
+ .mci-life-phone { display: flex; flex-direction: column; height: 740px; min-width: 0; overflow: hidden; border: 1px solid var(--mci-scene-line); border-radius: 28px; color: var(--mci-scene-text); background: var(--mci-scene-canvas); box-shadow: var(--mci-shadow-card); }
307
+ .mci-life-head { display: flex; flex: 0 0 auto; align-items: center; gap: 10px; padding: 18px; background: var(--mci-scene-paper); }
308
+ .mci-life-head > span:nth-child(2) { font-size: 14px; font-weight: 750; }
309
+ .mci-life-head small { display: block; margin-top: 5px; color: var(--mci-scene-muted); font-size: 11px; font-weight: 400; }
310
+ .mci-life-mark { display: grid; width: 36px; height: 36px; place-items: center; border-radius: 12px; color: var(--mci-scene-on-accent); background: var(--mci-scene-accent); }
311
+ .mci-life-mark svg { width: 26px; height: 26px; fill: none; stroke: currentColor; stroke-width: 1.7; }
312
+ .mci-life-head__dot { width: 8px; height: 8px; margin-left: auto; border-radius: 50%; background: var(--mci-scene-accent); }
313
+ .mci-life-body { flex: 1; min-height: 0; padding: 20px 16px 12px; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; }
314
+ .mci-life-editorial { position: relative; min-height: 250px; margin: 0 0 26px; }
315
+ .mci-life-editorial > p { position: relative; z-index: 1; margin: 2px 0 14px; color: var(--mci-scene-muted); font-size: 12px; }
316
+ .mci-life-editorial h3 { position: relative; z-index: 1; margin: 0; font-size: 30px; line-height: 1.22; letter-spacing: -.055em; }
317
+ .mci-life-editorial__caption { position: absolute; bottom: 8px; left: 0; z-index: 1; max-width: 120px; font-size: 12px; line-height: 1.7; color: var(--mci-scene-muted); }
318
+ .mci-life-city { position: absolute; right: -8px; bottom: -7px; width: 174px; height: 184px; animation: mci-city-rest 8s ease-in-out infinite; }
319
+ .mci-life-city__sun { fill: var(--mci-scene-warm); }
320
+ .mci-life-city__ground { fill: var(--mci-scene-soft); }
321
+ .mci-life-city__building { fill: var(--mci-scene-accent); }
322
+ .mci-life-city__window { fill: var(--mci-scene-on-accent); }
323
+ .mci-life-city__route { fill: none; stroke: var(--mci-scene-text); stroke-width: 2; stroke-dasharray: 4 5; }
324
+ .mci-life-city__tree { fill: none; stroke: var(--mci-scene-text); stroke-width: 2; }
325
+ .mci-life-section-title { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
326
+ .mci-life-section-title h3 { margin: 0; font-size: 18px; line-height: 1.5; letter-spacing: -.03em; }
327
+ .mci-life-section-title > span { color: var(--mci-scene-muted); font-size: 12px; white-space: nowrap; }
328
+ .mci-life-categories { display: flex; gap: 6px; padding: 12px 0 16px; overflow-x: auto; scrollbar-width: none; }
329
+ .mci-life-categories button { display: inline-flex; min-width: 52px; min-height: 44px; align-items: center; justify-content: center; padding: 0 12px; border: 1px solid transparent; border-radius: 999px; color: var(--mci-scene-muted); background: transparent; font-size: 13px; line-height: 1; cursor: pointer; }
330
+ .mci-life-categories button[aria-pressed="true"] { color: var(--mci-scene-on-accent); background: var(--mci-scene-accent); }
331
+ .mci-life-benefits { display: grid; gap: 12px; }
332
+ .mci-life-benefit { position: relative; display: grid; grid-template-columns: 84px minmax(0, 1fr); overflow: hidden; border-radius: 14px; background: var(--mci-scene-paper); }
333
+ .mci-life-benefit::before, .mci-life-benefit::after { position: absolute; z-index: 1; left: 78px; width: 12px; height: 12px; border-radius: 50%; content: ''; background: var(--mci-scene-canvas); }
334
+ .mci-life-benefit::before { top: -6px; }.mci-life-benefit::after { bottom: -6px; }
335
+ .mci-life-benefit__mark { position: relative; display: flex; min-height: 148px; align-items: center; justify-content: center; overflow: hidden; border-right: 1px dashed var(--mci-scene-line); background: var(--mci-scene-soft); }
336
+ .mci-life-benefit__mark span { position: relative; z-index: 1; writing-mode: vertical-rl; font-size: 23px; font-weight: 650; letter-spacing: .25em; }
337
+ .mci-life-benefit__mark i { position: absolute; right: -24px; bottom: -25px; width: 110px; height: 110px; border: 1px solid var(--mci-scene-accent); border-radius: 50%; }
338
+ .mci-life-benefit--coffee .mci-life-benefit__mark { background: var(--mci-scene-warm); }.mci-life-benefit--care .mci-life-benefit__mark { background: var(--mci-scene-sky); }
339
+ .mci-life-benefit__body { padding: 16px 14px 14px; }
340
+ .mci-life-benefit__body > small { color: var(--mci-scene-muted); font-size: 11px; }.mci-life-benefit h4 { margin: 6px 0; font-size: 15px; line-height: 1.5; overflow-wrap: anywhere; }
341
+ .mci-life-benefit__body > p { margin: 0; color: var(--mci-scene-muted); font-size: 12px; }
342
+ .mci-life-benefit button { display: flex; width: 100%; min-height: 44px; align-items: center; justify-content: space-between; gap: 8px; margin-top: 6px; padding: 4px 0 0; border: 0; color: var(--mci-scene-accent); background: transparent; font-size: 12px; font-weight: 750; cursor: pointer; }
343
+ .mci-life-benefit button:disabled { color: var(--mci-scene-muted); cursor: default; }
344
+ .mci-life-dock { display: flex; flex: 0 0 auto; align-items: center; gap: 3px; margin: 12px; padding: 5px; border: 1px solid var(--mci-scene-line); border-radius: 999px; background: var(--mci-scene-paper); box-shadow: 0 6px 24px #00000012; }
345
+ .mci-life-dock button { position: relative; display: flex; flex: 1; min-height: 50px; align-items: center; justify-content: center; gap: 7px; padding: 0 9px; border: 0; border-radius: 999px; color: var(--mci-scene-muted); background: transparent; font-size: 12px; cursor: pointer; }
346
+ .mci-life-dock button[aria-pressed="true"] { color: var(--mci-scene-on-accent); background: var(--mci-scene-accent); }
347
+ .mci-life-dock svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
348
+ .mci-life-dock__count { font-variant-numeric: tabular-nums; }
349
+ .mci-life-profile { padding: 12px 4px; }.mci-life-profile > p:first-of-type { margin: 16px 0 8px; color: var(--mci-scene-muted); font-size: 13px; }
350
+ .mci-life-profile h3 { margin: 0 0 28px; font-size: 29px; line-height: 1.35; letter-spacing: -.045em; }
351
+ .mci-life-profile__seal { display: grid; width: 64px; height: 64px; place-items: center; border-radius: 50%; color: var(--mci-scene-on-accent); background: var(--mci-scene-accent); }
352
+ .mci-life-profile__seal svg { width: 42px; height: 42px; fill: none; stroke: currentColor; stroke-width: 1.6; }
353
+ .mci-life-profile dl { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; padding: 22px 0; border-block: 1px solid var(--mci-scene-line); }.mci-life-profile dt { color: var(--mci-scene-muted); font-size: 12px; }.mci-life-profile dd { margin: 12px 0 0; font-size: 26px; font-variant-numeric: tabular-nums; }
354
+ .mci-life-meta { color: var(--mci-scene-muted); font-size: 13px; line-height: 1.8; }.mci-life-empty { padding: 30px 0; }.mci-life-empty p { color: var(--mci-scene-muted); font-size: 13px; line-height: 1.7; }.mci-life-empty button, .mci-workroom__empty button { min-height: 44px; padding: 0; border: 0; color: var(--mci-scene-accent); background: transparent; font-weight: 700; cursor: pointer; }
355
+ .mci-life-action { display: inline-flex; width: 100%; min-height: 46px; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 14px; border: 1px solid var(--mci-scene-accent); border-radius: 8px; color: var(--mci-scene-on-accent); background: var(--mci-scene-accent); font-size: 13px; line-height: 1.5; cursor: pointer; }.mci-life-action:disabled { color: var(--mci-scene-muted); border-color: var(--mci-scene-line); background: transparent; cursor: default; }
356
+ .mci-workroom { container: mci-workroom / inline-size; margin-top: 54px; overflow: hidden; border: 1px solid var(--mci-scene-line); border-radius: 16px; color: var(--mci-scene-text); background: var(--mci-scene-paper); }
357
+ .mci-workroom__head { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding: 24px; border-bottom: 1px solid var(--mci-scene-line); }
358
+ .mci-workroom__head span:first-child { color: var(--mci-scene-muted); font-size: 12px; }.mci-workroom__head h3 { margin: 8px 0 0; font-size: 24px; line-height: 1.35; letter-spacing: -.04em; }.mci-workroom__stamp { padding: 7px 10px; border: 1px solid var(--mci-scene-line); border-radius: 5px; color: var(--mci-scene-muted); font-size: 12px; white-space: nowrap; }
359
+ .mci-workroom__toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; padding: 14px 24px; border-bottom: 1px solid var(--mci-scene-line); }
360
+ .mci-workroom__toolbar > div { display: flex; gap: 4px; }.mci-workroom__toolbar button { min-height: 44px; padding: 0 12px; border: 0; border-radius: 7px; color: var(--mci-scene-muted); background: transparent; cursor: pointer; }.mci-workroom__toolbar button[aria-pressed="true"] { color: var(--mci-scene-on-accent); background: var(--mci-scene-accent); }
361
+ .mci-workroom__toolbar label { display: flex; align-items: center; gap: 8px; font-size: 12px; }.mci-workroom__toolbar select { min-height: 44px; max-width: 160px; padding: 0 12px; border: 1px solid var(--mci-scene-line); border-radius: 7px; color: var(--mci-scene-text); background: var(--mci-scene-paper); }.mci-workroom__toolbar > p { margin: 0 0 0 auto; color: var(--mci-scene-muted); font-size: 12px; }
362
+ .mci-workroom__canvas { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(240px, .8fr); }
363
+ .mci-workroom__queue { padding: 20px 24px; }.mci-workroom__section-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; }.mci-workroom__section-head h4 { margin: 0; font-size: 14px; }.mci-workroom__section-head span { color: var(--mci-scene-muted); font-size: 12px; }
364
+ .mci-briefing-row { display: grid; grid-template-columns: 9px minmax(0, 1fr) auto 14px; width: 100%; align-items: center; gap: 13px; margin-top: 6px; padding: 16px 12px; border: 1px solid transparent; border-radius: 8px; text-align: left; color: var(--mci-scene-text); background: transparent; cursor: pointer; }.mci-briefing-row[aria-pressed="true"] { border-color: var(--mci-scene-line); background: var(--mci-scene-soft); }
365
+ .mci-briefing-row__signal { width: 8px; height: 8px; border-radius: 50%; background: var(--mci-scene-muted); }.mci-briefing-row__signal[data-priority="1"] { background: var(--mci-scene-risk); }.mci-briefing-row__copy strong, .mci-briefing-row__copy small { display: block; }.mci-briefing-row__copy strong { font-size: 14px; line-height: 1.6; }.mci-briefing-row__copy small { margin-top: 5px; color: var(--mci-scene-muted); font-size: 12px; line-height: 1.5; }.mci-briefing-row__state { color: var(--mci-scene-muted); font-size: 12px; white-space: nowrap; }
366
+ .mci-workroom__detail { min-width: 0; padding: 24px; border-left: 1px solid var(--mci-scene-line); background: var(--mci-scene-soft); }.mci-workroom__detail-label { color: var(--mci-scene-muted); font-size: 12px; }.mci-workroom__detail h4 { margin: 20px 0 12px; font-size: 21px; line-height: 1.45; }.mci-workroom__detail > p { color: var(--mci-scene-muted); font-size: 13px; line-height: 1.8; }.mci-workroom__detail dl { margin: 24px 0; }.mci-workroom__detail dl > div { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; font-size: 12px; }.mci-workroom__detail dt { color: var(--mci-scene-muted); }.mci-workroom__detail dd { margin: 0; text-align: right; }.mci-workroom__feedback { min-height: 44px; margin-bottom: 0; }.mci-workroom__empty { padding: 24px 0; }.mci-workroom__empty p { color: var(--mci-scene-muted); font-size: 13px; }
367
+ .mci-expression button:focus-visible, .mci-expression select:focus-visible { outline: 3px solid var(--mci-scene-accent); outline-offset: 3px; }.mci-expression button:active:not(:disabled) { transform: translateY(1px); }
368
+ @keyframes mci-city-rest { 50% { transform: translateY(-4px) rotate(1deg); } }
369
+ @container mci-workroom (max-width: 700px) { .mci-workroom__canvas { grid-template-columns: 1fr; }.mci-workroom__detail { border-top: 1px solid var(--mci-scene-line); border-left: 0; }.mci-workroom__head { align-items: start; padding: 18px; }.mci-workroom__stamp { display: none; }.mci-workroom__head h3 { font-size: 21px; }.mci-workroom__toolbar { padding: 12px 18px; }.mci-workroom__toolbar > p { width: 100%; margin: 0; }.mci-workroom__queue { padding: 18px; }.mci-briefing-row { gap: 9px; padding-inline: 8px; }.mci-briefing-row__state { font-size: 11px; } }
370
+ @media (max-width: 780px) { .mci-expression__mobile-layout { grid-template-columns: 1fr; }.mci-life-phone { width: min(390px, 100%); margin-inline: auto; }.mci-expression__notes { max-width: 100%; }.mci-expression__notes h3 br { display: none; } }
371
+ @media (max-width: 680px) { .mci-expression { width: calc(100% - 28px); padding-block: 48px; }.mci-expression__heading h2 { font-size: 27px; }.mci-expression__controls { gap: 6px; }.mci-expression__controls button { padding-inline: 9px; font-size: 11px; }.mci-expression__notes h3 { font-size: 27px; }.mci-workroom { margin-top: 32px; } }
372
+ :root[data-mci-paused="true"] .mci-lab *, :root[data-mci-paused="true"] .mci-lab *::before, :root[data-mci-paused="true"] .mci-lab *::after { animation-play-state: paused !important; }
373
+ :root[data-mci-motion="reduced"] .mci-lab *, :root[data-mci-motion="reduced"] .mci-lab *::before, :root[data-mci-motion="reduced"] .mci-lab *::after { animation: none !important; transition: none !important; }
374
+
260
375
  @keyframes mci-drift { to { transform: translate3d(-18px, 14px, 0) scale(1.03); } }
261
376
  @keyframes mci-orbit { to { transform: rotate(360deg); } }
262
377
  @keyframes mci-orbit-pulse { 50% { transform: scale(.94) rotate(8deg); filter: drop-shadow(0 0 46px rgba(83, 120, 255, .62)); } }
@@ -0,0 +1,49 @@
1
+ # 按钮、交互组件与有声媒体
2
+
3
+ 适用于按钮文字不可见、主题切换失效、图标与动效打磨,以及创作平台的作品播放。先修正组件实际行为,再更新契约;更换 Skill 或增加动效不能代替页面验收。
4
+
5
+ ## 经核验的参考与吸收边界
6
+
7
+ 2026-11-12 查阅的第一方项目:
8
+
9
+ | 来源 | 可吸收的做法 | 在吾码中的落实 |
10
+ | --- | --- | --- |
11
+ | [UI UX Pro Max Skill](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill)及其[正文](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill/blob/main/.claude/skills/ui-ux-pro-max/SKILL.md) | 先检查可访问性、触控与性能,再选择表现性样式 | 用可测的对比度、命中区域和状态反馈约束组件;按当前技术栈收窄检索 |
12
+ | [shadcn-vue Skill](https://www.shadcn-vue.com/docs/skills)及[按钮](https://www.shadcn-vue.com/docs/components/button) | 组件组合、语义颜色、明确变体、图标槽位与真实加载态 | 复用 MciButton 或项目级包装,避免页面逐个重写颜色和布局;不执行其初始化命令覆盖吾码项目 |
13
+ | [Reka UI](https://reka-ui.com/docs/overview/accessibility) | 键盘、焦点与可访问名称作为组件行为的一部分 | 对话框/菜单/选择器沿用宿主或经过封装的成熟原语,视觉重设计保留行为 |
14
+ | [Inspira UI](https://github.com/unovue/inspira-ui) | 组件级悬停反馈与局部装饰动效 | 按场景采用轻量扫光或边缘光点,不把整套动画依赖引入普通表单 |
15
+
16
+ 这些是参考来源,并不表示本机安装了相应 Skill 或组件库。Stars 会变化,不把人气作为质量证明。落地前检查当前许可证与接口;若实际复制代码,保留必要版权/许可声明。吾码继续使用 `--mci-*`、Mci 组件、原有 SDK 与租户权限。
17
+
18
+ ## 消除“悬停后才看得见”
19
+
20
+ 按钮应自己拥有 `foreground/background/border/focus` 成对语义 token。默认、hover、focus-visible、pressed、loading、disabled 均从同一组件变体派生;不能仅给 hover 写文字色,也不能给浅底继续继承深色页面的白文字。图标使用 `currentColor`,装饰性 SVG 使用 `aria-hidden="true"`。
21
+
22
+ - 主操作使用图标加完整文案;图标有助识别即可,不给每个行内文字链接强制加图标。纯图标按钮须提供可访问名称。
23
+ - 默认和悬停文字至少 4.5:1;焦点可辨,disabled 不靠完全透明处理。浅/深/租户主题、visited 链接、表单 reset、共享微服务根样式都要纳入计算。
24
+ - 文字层保持正常 opacity;扫光、遮罩和伪元素在独立装饰层,不覆盖文字、焦点、点击与选中。不以 `mix-blend-mode` 修复低对比。
25
+ - 按钮优先固定可读高度、inline-flex 居中和 gap;loading 保留原始宽度,防重复提交,错误后恢复正确可操作状态。手机目标至少 44px。
26
+ - 用真实渲染 computed style 检查组件最终颜色及遮挡,并检查桌面/手机的默认截图。文字在 DOM 中、颜色 token 存在或构建通过都不代表验收。
27
+
28
+ ## 默认持续动效的场景取舍
29
+
30
+ 用户明确要求持续动效的创作门户,可给首屏少量主要操作添加低频光点或扫光;其它按钮保留清楚的 hover/focus/pressed 反馈。不要把该偏好推广成所有后台控件必须持续闪动。
31
+
32
+ - 动效不承担文字可读性,静态状态必须完整可用。持续装饰建议至少 4 秒一个周期,常用微交互约 140–220ms,pressed 可更快。
33
+ - 优先 transform/opacity;避免持续阴影、blur、布局变化与每个按钮独立 RAF/定时器。只对必要、可见的少量层提升合成,不全站常驻 will-change。
34
+ - 页面隐藏、微服务隐藏或离开视口时自动暂停;系统 reduced-motion 保持静态最终状态。用户不需要在页面上看到技术性“关闭 CSS 动画”开关。
35
+ - 深浅主题、触控、键盘和无 hover 输入均可用。离开、卸载与切换路由清理监听和调度;性能结论需要实际采样,不以 CSS-only 推断零开销。
36
+
37
+ ## 区分悬停预览与显式播放
38
+
39
+ 悬停卡片仅静音预览。用户点击作品、播放键或打开播放器属于主动播放意图:在同一次操作链将 `defaultMuted=false`、`muted=false`,使用可用的默认音量并显示标准声音控件。复用同一 video 元素从 hover 切到详情时也要重新应用模式。
40
+
41
+ 浏览器阻止播放时,显示清楚的“开启声音并播放”按钮,再由真实点击执行;不能静默回退为无声播放,也不能声称所有浏览器都会放行有声自动播放。无音轨作品要按真实素材标注,打开声音按钮不会生成音轨。
42
+
43
+ 配乐、对白和口型是三个独立质量项:音轨存在/无削波只是技术检查;还需实际试听音色、表演、语言、情绪、场景匹配、对白可懂度、混音,以及观看人物说话镜头检查唇形。附加单音或简单循环音轨不能作为成熟配音交付。作品详情记录实际图像/视频/语音模型和人工素材来源,不把计划使用模型写成实际生成来源。
44
+
45
+ ## 创作平台功能状态
46
+
47
+ 导航按钮应进入可执行任务页:提交、真实任务状态、结果和错误恢复属于同一条链。尚未接入时给出具体可理解原因,不能用漂亮目录或固定成功提示代替生成。开发进度留在交付文档;面向客户的页脚保留品牌、法律和联系信息,具体模型、声音与生成状态放作品详情和任务页,不删除必要的 AI 标识。
48
+
49
+ ComfyUI 客户端优先呈现可理解的工作流画布:素材、模型、生成、声音、口型、质检、导出;允许在获准模板中改参数,复刻只创建本人草稿并进入统一服务端队列。作品工作流需来自真实模板或执行记录并明确版本,禁止画固定流程图冒充该作品的执行来源。原始 ComfyUI 编辑器只作为有权限的专业入口,不能把无鉴权推理端口、服务秘密或任意节点执行暴露给公众。
@@ -66,6 +66,14 @@
66
66
  5. 实际执行筛选、排序、分页、图表图例/tooltip、穿透、关闭、错误恢复及键盘焦点。操作可用与视觉可接受分别给结果;构建、DOM 存在和 CSS 静态扫描都不能代替截图批判。
67
67
  6. 逐页截图后明确指出最大的三项缺陷并修正;没有问题时说明按哪些任务标准通过。某尺寸或主题受工具限制未完成时如实记录,不复制另一尺寸截图冒充通过。
68
68
 
69
+ ## 有明确参考图的经营驾驶舱
70
+
71
+ 用户提供高品质看板参考时,先拆解标题与筛选、KPI、趋势、状态分布、排行和明细的视觉权重,在相同实际容器、主题与业务数据下比较。紧凑表示高效可读,不能退化为一排数字加无层次白卡;允许使用有依据的品牌标题区、浅/暗双套表面、渐变图形、圆环分布和横向排行,但图表类型必须服务真实比较任务,不凑图形和假走势。
72
+
73
+ 外画布填满宿主可用宽高,内区块按容器重排;只有明细或真正长内容产生滚动,不固定整页最大宽度或使用缩放充满。空值、当前快照与期间发生量分别标识,图例、单位、状态文字和来源可解释;刷新、筛选、图表/明细穿透继续用同一授权数据源。复杂视觉由微服务/原生界面引擎承担,不能将整页 HTML 塞进接口引擎再称已迁移。
74
+
75
+ 首轮视觉批判至少检查:主次是否明显、图表是否可读、是否单调重复、实际宽高是否充分利用、浅/暗主题是否协调;逐项修正后再记录通过。需要动效时使用有限入场与实际交互,不为“科技感”加入所有卡片循环发光或随机数字。
76
+
69
77
  ## 方法来源与改写边界
70
78
 
71
79
  2026-11-06 检查以下公开 Skill,吸收“先任务和设计系统、区分操作与展示、反思真实渲染、语义颜色与数值对齐、可访问交互”的方法,按吾码 Vue/宿主契约重新组织上述原创规则。未复制外部 Skill 原文、品牌、类名、资产或设计 token。star 是仓库总数,不能证明单个 Skill 的质量,也不能据用户参考截图判定作者使用了哪一个 Skill。
@@ -1,6 +1,6 @@
1
1
  # Microi 设计模式库
2
2
 
3
- 本文件是 Microi.UI 的内部设计知识库。默认紧凑适度,不鼓励大标题、大圆角或大间距;只有用户明确的表现性要求或真实可读/触控用途才扩大相应尺度。它把成熟数字产品中反复有效的构图、流程、动效和设计系统方法统一为 Microi 自有规则;不得在成品、类名、文案或资源中保留外部品牌痕迹。
3
+ 本文件是 Microi.UI 的内部设计知识库。标准后台操作区使用紧凑基线;定制产品与微服务从任务、内容和视觉性格决定尺度与构图。它把成熟数字产品中反复有效的构图、流程、动效和设计系统方法归纳为 Microi 原创规则,不把任何一套配色、圆角或行业视觉当成所有用户的统一外观。
4
4
 
5
5
  ## 目录
6
6
 
@@ -12,6 +12,7 @@
12
12
  6. [动态首屏](#动态首屏)
13
13
  7. [数据工作台](#数据工作台)
14
14
  8. [组合与验收](#组合与验收)
15
+ 9. [项目设计签名与场景配方](#项目设计签名与场景配方)
15
16
 
16
17
  ## 模式选择
17
18
 
@@ -184,3 +185,51 @@
184
185
  ### 完成定义
185
186
 
186
187
  构建通过不等于 UI 完成。只有真实内容与全部状态可操作、桌面和移动截图通过、控制台无错误、外部资源失败有降级、动效关闭后页面仍完整,才算完成。
188
+
189
+ ## 项目设计签名与场景配方
190
+
191
+ 适用于新的定制产品、门户、移动端及后台微服务的显著重设计。目标是让构图来自业务对象与用户任务,而不是让所有项目共用同一“渐变标题 + 一排统计 + 等大白卡”模板。现有标准表单、表格、主题和权限契约继续保留;同一产品可以有表现性首页与稳定紧凑的工作区。
192
+
193
+ ### 从参考转译到自己的产品
194
+
195
+ 先在 `MCI-DESIGN.md` 的视觉性格和页面模式章节记录:参考中值得吸收的具体结构、它如何帮助原任务、如何改写为当前业务对象,以及来源/许可和不复用的资产。医疗参考里的“医生大肖像 + 预约时段”可以启发“核心服务对象 + 可行动选项”,不能直接把医生照片、医院品牌、医疗数据和预约业务塞进不相关产品。
196
+
197
+ 形成一组简洁的**设计签名**:例如票券切口与进度刻度、编辑式标题与场景留白、时间轨道与状态节点、照片裁切与文字叠层。签名要同时体现在结构、主要对象和交互中;只给主色起新名字或给通用卡片加图案不够。选择少量能贯穿产品的特征,别把所有参考拼在同一屏。
198
+
199
+ 实现前可先用首页与一个任务页验证方向,随即把规则扩展到完整路由;原型不是最终交付。用户已经要求直接完成时不把“等风格确认”变成默认停工点。重要取舍写入契约,后续 AI 应读理由并延续,而不是每页重新选一套潮流效果。
200
+
201
+ ### 页面族共享系统,不共享同一构图
202
+
203
+ | 页面任务 | 可选择的主要构图 | 对象与动作的关系 | 应避免 |
204
+ |---|---|---|---|
205
+ | 发现、会员、生活服务首页 | 编辑式标题、一个有来源的主场景、大小有别的服务分区 | 先看清当前价值,再进入核心任务;主视觉与 CTA 有明确锚点 | 每区同高白卡、重复眉题、随机装饰数字 |
206
+ | 资产、券包、订阅权益 | 清晰资产总览、凭证/通行证式对象、规则与流水连续布局 | 数额、可用/冻结、有效期与动作在同一阅读链 | 把资金数字做成玩具、用图形隐藏限制、只有余额没有状态 |
207
+ | 商品、服务或内容目录 | 真实媒体占有合适面积,分类与筛选清楚;精选与普通记录有层次 | 图像帮助识别对象,排序/分类真实改变内容 | 同一礼盒/头像反复填充、用无关照片冒充真实商品 |
208
+ | 订单、工单和进度记录 | 收据、时间线或状态轨道,节点与当前动作连续 | 先显示当前阶段,再呈现可执行下一步与历史 | 每个字段套卡、状态与可用操作相离、彩色标签无语义 |
209
+ | 登录、资料与确认表单 | 安静连续画布、清楚标签、稳定控件与总结 | 装饰退后,输入、错误与提交反馈相邻 | 主视觉占去输入空间、移动键盘遮住动作、持续动画干扰填写 |
210
+ | PC 定制工作台/运营简报 | 满宽任务画布、优先队列、主次有别的指标/趋势、可追溯明细 | 先知道要处理什么,再看原因与授权操作 | 把手机页拉宽、固定四张大卡、无内容的大 Hero、重复宿主导航 |
211
+
212
+ 这些是配方,不是硬模板。数据基数、触控和业务顺序可以决定对称/不对称、单列/双栏;相同来源的一组记录保持可比较的几何,不为制造“新颖”随机打散列表。PC 断点按微服务实际内容宽度触发,密度继续服从 [数据工作台规范](data-workspace-density.md)。
213
+
214
+ ### 让个性来自关系,而非装饰数量
215
+
216
+ - **排版**:用标题、正文、辅助和数值建立可辨认的层级;中文按真实文案与字号测试换行。表现性标题可以具有尺度对比,后台字段和数字仍需稳定扫读。不要用满屏全大写英文、装饰序号或孤立巨型数字替代内容。
217
+ - **面积与颜色**:主对象占据较大面积,次对象保持克制;色块表达区域、身份或任务层级。主题切换后保留这些关系,不要求所有项目选蓝色、绿色、浅底或深底。
218
+ - **形状**:票据、切口、连续轨道、方圆组合或胶囊只用于与任务相符的对象。普通列表、输入和长表格不为了统一“个性”全部改为特殊形状。
219
+ - **媒体**:使用自有、明确授权或原创生成的真实业务素材;大图有稳定比例、裁切重心和弱网降级。没有可信素材时采用诚实的业务图形,不让版权不明照片或伪商品照片承担真实性证明。
220
+ - **导航**:浮动 Dock、分段导航或主动作可以形成产品识别,但必须保持所有入口、文字、选中态和足够触控面积。按所属容器预留一次实测覆盖高度;不用中间加号暗示不存在的功能,也不复制另一产品的导航身份。
221
+ - **动效**:采用与选择、展开、切换和对象状态一致的运动语法。设计感不靠所有卡片循环漂浮,数据变化不能靠循环图表伪装;隐藏暂停和 reduced-motion 保留最终内容与操作。
222
+
223
+ ### 三层观察门禁
224
+
225
+ | 层次 | 实际需要观察的结果 | 不能代替它的证据 |
226
+ |---|---|---|
227
+ | 业务 | 原入口、角色与按钮仍工作,状态和数据有来源,失败可恢复 | 静态参考图、设计稿、演示 Toast |
228
+ | 几何与可访问性 | 实际尺寸下文案/图标对齐、触控和焦点、滚动与安全区、媒体就绪、主题可读 | CSS 类存在、构建成功、骨架屏截图 |
229
+ | 设计表达 | 同视口前后对比中能说明主要对象、阅读顺序、版面节奏和页面族差异;设计签名在不同任务页可辨认 | 只有换色、换圆角、同一 Hero、测试数量或“高级感”自评 |
230
+
231
+ 截图先匹配当前路由与身份,等骨架消失、真实内容/媒体出现及入场动画结束,再复核。至少查看一个展示页、资产/列表页、表单页和范围内的 PC 工作台;同一组真实长数据、空态和错误要保留。视觉批判写出具体位置与修改理由,失败留为待修,不编造美观百分比或用某个仓库 star 数保证设计效果。
232
+
233
+ ### 原创可运行场景
234
+
235
+ [模式实验室](../assets/pattern-showcase/index.html#expressive) 提供编辑式会员服务与 PC 运营简报两个原创场景:本地分类/导航、领取去重、优先队列、筛选和完成动作可实际操作;支持明暗、非默认强调色和 reduced-motion。它们是说明结构与状态的演示数据,不连接租户或执行真实交易;项目接入时使用实际 SDK、数据与权限,不能只复制演示数。来源与许可约束见 [移动设计资料边界](mobile-product-language.md#方法来源与适用边界)。