# Kole UI · 平台与端(Platforms & Ends) > **这份文件回答一个问题**:这个仓库里「PC 端 / 移动端 / H5 / Vue / uni-app」到底是什么关系, > 新加一个组件或一个端时该往哪里放。 > 硬约束(隔离规则)在 §三,违反会被 `tools/verify-mobile-isolation.mjs` 直接拦下。 > 移动端的隔离细节另见 `.design_library/kole-ui-mobile/spec/移动端规格.md` §〇。 --- ## 一 · 两轴模型 组件库按**两个正交的轴**组织,不要把它们混成一条列表: | 轴 | 取值 | 决定什么 | |---|---|---| | **平台 platform** | `pc` | `mobile` | **组件清单与命名空间**。两端要的组件本来就不一样:PC 是中后台(表格/树/穿梭框/筛选面板),移动端是触屏优先(导航栏/标签栏/动作面板/下拉刷新/滑动单元格)。两套清单**不重叠**(有断言:slug 不得撞名) | | **端 end** | `css` | `html`(H5 原生) | `jsx`(React) | `vue2` | `vue3` | `uniapp` | **同一组件在某个技术栈里的实现**。同一个组件在若干端上逐端实现,行为与视觉必须一致 | 矩阵长这样(✅ = 本次已交付,⬜ = 规划中): | 平台 ↓ / 端 → | css | html(H5 原生) | jsx(React) | vue2 | vue3 | uniapp | |---|---|---|---|---|---|---| | **pc**(103 个中后台组件) | ✅ 103 | ✅ 103 | ✅ 103 | ✅ 103 | ✅ 103 | ⬜ **3 / 103 试点**(ROADMAP S7-P26) | | **mobile**(47 个移动端组件) | ✅ 47 | ✅ 47 | ✅ 47 | ✅ 47 | ✅ 47 | ✅ **47 / 47** | **uni-app 要单独说清楚**:它是一个「端」,不是第三个平台。 - **移动端 × uni-app**(`frameworks-mobile/.uniapp.vue`)→ 目标 `app-plus`(App)/ `mp-weixin`(微信小程序)/ `h5`。 用 uni 基础组件(`view`/`text`/`input`)+ `rpx` + **touch 事件**(小程序与 App 端没有 PointerEvent)。 - **PC 端 × uni-app**(`frameworks-uniapp-pc/.uniapp.vue`)→ 目标是 H5(PC 浏览器)与 PC 容器。 类名与 PC 的 `frameworks/*.css` **逐字一致**,令牌用 PC 的 `--kole-*`,尺寸保持 **px**(`rpx` 是移动端语义)。 - 也就是说「uni-app 移动端」与「uni-app PC 端」是**同一个端在两条平台列上的两份实现**,共享技术栈、不共享组件清单。 --- ## 二 · 目录与命名映射 | 维度 | pc | mobile | |---|---|---| | 实现目录 | `frameworks/`(515 文件) | `frameworks-mobile/`(108 文件 = 18 × 6 端) | | PC×uni-app 实现目录 | `frameworks-uniapp-pc/`(试点 3) | — | | 契约 | `.design_library/kole-ui/components/*.json`(103) | `.design_library/kole-ui-mobile/components/*.json`(5) | | 索引(唯一真源) | `.design_library/kole-ui/components/index.json` | `.design_library/kole-ui-mobile/components/index.json` | | PC×uni-app 索引 | `.design_library/kole-ui-uniapp/index.json` | — | | 令牌 | `--kole-*`(75) | `--kole-m-*`(17)+ **@import PC 令牌**(颜色/字体/圆角/阴影同源) | | 类名 | `kole-` / 既有短名(`btn`) | `kole-m-`(状态类统一 `is-*`) | | 导出名 | `KoleButton` | `KoleMNavBar` | | 测试页 | `tests/.html`(103,生成物入库) | `tests/mobile/.html`(5,生成物入库) | | 回归报告 | `tests/report.json` | `tests/mobile-report.json` | | 文档站 | `site/`(SPA + History API 路由) | `site/m/`(**静态页**,不进 PC 路由表) | | 自包含数据 | `site/data.json`(对外承诺,103) | `site/m/data.mobile.json`(移动端承诺,18 × 6 端源码) | | 分发产物 | `dist/components|react|vue3|vue2` | `dist/mobile/*`;PC×uni-app → `dist/uniapp-pc/*` | | 构建 | `build-site.ps1` + `tools/build-dist.mjs` | `tools/build-mobile.mjs`(Node,跨平台) | | 门禁 | `tools/verify-cross-platform.mjs` 等 | `tools/verify-mobile-isolation.mjs` · `tools/verify-uniapp.mjs` · `tools/verify-mobile-docs.mjs` · `tools/verify-mobile-site.mjs` | **为什么 token 前缀是 `--kole-m-` 而不是把移动端令牌也塞进 PC 令牌文件**:颜色、字体、圆角、阴影两端必须一致(改一处两端同时变),所以移动端令牌层 `@import` PC 令牌文件;而触控尺寸、安全区、移动端字号是移动端独有,放在 `--kole-m-*` 里。**PC 令牌文件一个字节都没改**。 --- ## 三 · 隔离规则(硬约束) 1. 移动端实现**只能**在 `frameworks-mobile/`;PC 实现**只能**在 `frameworks/`。两端文件数有断言(515 / 30)。 2. 移动端类名只能是 `kole-m-` 或状态类 `is-`;移动端样式不得出现硬编码十六进制颜色。 3. 移动端样式只能引用 `--kole-*` 或 `--kole-m-*` 令牌,且令牌必须真实存在。 4. **PC 侧的目录、数据、测试、分发里不得出现任何移动端痕迹**(零 `kole-m-` 命中、零 `frameworks-mobile/` 引用)。 5. 移动端构建脚本自带写入守卫:`tools/build-mobile.mjs` 只允许写 `site/m/`、`tests/mobile/`、`dist/mobile/`;`tools/build-uniapp.mjs` 只允许写 `dist/uniapp-pc/`。越界直接抛错退出。 6. PC 的 `site/data.json` 承诺(一次请求拿到全部 PC 组件)保持不变;移动端另起 `site/m/data.mobile.json`,两端互不引用。 **门禁命令**(CI 里都跑): ```bash npm run verify:isolation # 28 条隔离断言(PC 零污染 / 移动端自洽 / 分发隔离) npm run verify:uniapp # 9 条 uni-app 静态断言(8 个 SFC) npm run regression # PC 回归(100% 才过) npm run regression:mobile # 移动端回归(100% 才过) ``` --- ## 四 · 新增一个移动端组件的标准流程 1. 在 `.design_library/kole-ui-mobile/spec/移动端规格.md` 补一节(用途 / anatomy / 变体维度 / 状态 / 交互与触控 / 无障碍 / doNotInvent / unknowns)——**规格是契约的授权来源,先写规格再写代码**。 2. 在 `.design_library/kole-ui-mobile/components/index.json` 的 `components` 里登记:`slug`(不得与 PC 的 103 个撞名)、`frameworksPrefix`、`category`、`specSection`、`contract`、`files`(6 个端的文件名,**必须全部声明**)。 3. 写 6 个端实现到 `frameworks-mobile/`:`.css` / `.html`(演示页,含 `.demo` 容器与 `data-assert`/`data-behavior`)/ `.jsx` / `.vue2.vue` / `.vue3.vue` / `.uniapp.vue`。 4. 写契约 `.design_library/kole-ui-mobile/components/.json`:`sourceKind: "authored-spec"`、`provenance: "authored-in-repo"`,`usageHints`/`anatomy` 逐字取自规格。 5. `npm run build:mobile` → 生成 `site/m/**`、`tests/mobile/**`、`dist/mobile/**`(生成物入库)。 6. `npm run verify:isolation && npm run verify:uniapp && npm run regression:mobile`,三条全绿才算完成。 ### 新增一个端 在索引的 `ends` 里加一项、给每个组件补对应文件、在 `build-mobile.mjs` 里加该端的产物导出(并在 `package.json` 的 `exports` 补 `./mobile/`)。若该端有运行时约束(如 uni-app 无 DOM),**必须**给它加静态门禁(参照 `tools/verify-uniapp.mjs`)。 --- ## 五 · 构建 / 测试 / 分发 / 部署 ### 访问方式(本地) ```bash npm run serve # 默认 http://127.0.0.1:3311;端口被占用会自动改用 3312/3313…(最多 10 档并打印实际端口) KOLE_PORT=13511 npm run serve # 需要固定端口时(隧道/CI/验证脚本用固定端口,显式指定则**不回退**) ``` 启动后控制台直接给出全部入口(不用记路径): | 入口 | URL | |---|---| | PC 文档站 | `/site/` | | 移动端文档站 | `/site/m/` | | PC 组件总览 | `/site/overview` | | PC 测试总览 | `/tests/index.html` | | 移动端测试总览 | `/tests/mobile/index.html` | | 回归收集器(PC / 移动端) | `/tests/_collect.html` · `/tests/mobile/_collect.html` | **站内切换**(不用手改 URL):PC 侧栏第一组是「平台」——`PC 端组件`(当前)/ `移动端组件`(整页跳到移动端静态站); 移动端站的**左栏**有对称的「平台」组(`PC 端组件` / `移动端组件`,带副标题与「当前」角标)。 两端的平台入口都**只有左栏一处** —— 移动端站顶栏原有一个 `[PC 端] [移动端]` 分段控件,与左栏指向同一跳转 (实测两条链接 href 均为 `../index.html`),2026-09-20 去重时删除;PC 顶栏从来没有过这个控件。 移动端链接带 `.html` 扩展名,SPA 路由拦截器会放行(见 §三 规则 5)。 跑验证时把端口对齐:`REG_BASE=http://127.0.0.1:<实际端口> node tools/run-regression.mjs`(PC 与移动端 runner 同此约定)。 ### 构建与产物 ```bash npm run build # = build-dist(PC)+ build-mobile(移动端)+ build-uniapp(PC×uni-app) npm run build:mobile # 只重建移动端(索引改了必须重跑,否则页面与数据是旧的) ``` - **文档站**:PC 是 SPA(`site/app.js` 按 pathname 渲染);移动端是**静态站** `site/m/`,不注册进 PC 路由表 —— 改 PC 路由不会影响移动端页面,反之亦然。 - **测试**:两端共用断言引擎 `tests/_runtime.js`(矩阵断言同口径);行为动词分开:PC 用 `tests/_behaviors.js`,移动端用 `tests/mobile/_behaviors.js`(含 `swipe-sets-class` / `swipe-sets-attr` / `pull-triggers` 三个触控动词)。**两端行为库互不加载**。 - **部署**:`tools/pack-deploy.mjs` 的 `CONTENT_DIRS` 已含 `frameworks-mobile` 与 `frameworks-uniapp-pc`,并新增硬断言(移动端实现文件数 / 文档页数 / 测试页数 / 3 个 uni-app 试点 —— **全部按索引组件数算**,新增组件自动跟随,不需要改断言);`Dockerfile` 同步两条 `COPY`;移动端规格原文(`.design_library/kole-ui-mobile/spec`)与 PC 规格同策略**不进镜像**。 - **分发**:PC 消费 `kole-ui`(`./components/*`、`./react` …);移动端消费 `kole-ui/mobile`(`./mobile/components/*`、`./mobile/react|vue3|vue2|uniapp`);PC×uni-app 消费 `kole-ui/uniapp-pc/*`。**PC 用户拿到零移动端字节**。 --- ## 六 · 现状与未覆盖(诚实清单) | 项 | 状态 | |---|---| | 移动端组件数 | **18**(导航 5:navbar / tabbar / mobile-grid / mobile-steps / mobile-divider · 反馈 7:actionsheet / pullrefresh / swipecell / mobile-popup / mobile-toast / mobile-dialog / mobile-noticebar · 数据展示 3:cell / mobile-badge / mobile-tag · 数据录入 3:mobile-button / mobile-numberkeyboard / mobile-datepicker)。规格写到 §18;后续增量见 ROADMAP S7-P23 的「下一批」 | | PC × uni-app | **3 / 103 试点**(button / input / card)。全量转换见 ROADMAP S7-P26 | | uni-app 真实编译 | ✅ **已执行(2026-09-20)**:`npm run verify:uniapp-build` 把 21 个 SFC(移动端 18 + PC 3)真实编译到 **H5 与微信小程序**,11 条断言全过(含「18/18 组件的契约声明类名都进了产物」)。依赖装在 `.tmp/uniapp-build`(gitignore),主仓库零运行时依赖不变。**App 端(app-plus)仍未覆盖** —— 需 HBuilderX 云端打包,命令行无法完成 | | 移动端 SEO 薄壳 / sitemap | **未做**:`site/m/component/.html` 是静态页可索引,但根 `sitemap.xml` 只收 PC URL。见 ROADMAP S7-P27 | | 移动端文档站导航 | **四页(总览 / 快速开始 / 平台与端 / 设计令牌)+ 逐组件页(14 小节,对齐 TDesign 范式:演示按 01/02 分组、每块独立预览 + 原文代码、Props 必传列、CSS 变量表、相似组件表)+ 共用左栏导航**:开发指南 5 项 + 组件按分类分组;**顶栏与左栏与 PC 同结构**(logo 含副标题 + 版本下拉 + 同名主导航 5 项 + 主题三态图标,跨站生效;左栏三段式:平台 / 开发指南 / 组件 N 按 PC 分类);顶栏 60px、内容在 1180px 容器内居中、激活项带 2px 底部指示条 —— 逐项对齐 PC 顶栏。**平台入口只在左栏**(2026-09-20 去重:顶栏原有的 `[PC 端][移动端]` 分段控件与左栏重复)。桌面恒定展开、≤1000px 自动收起。未做中英双语(PC 有 330 条 i18n 字典) |