# OIP-Lite **Repository Path**: orginone/OIP-Lite ## Basic Information - **Project Name**: OIP-Lite - **Description**: 前端轻量 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-09-25 - **Last Updated**: 2026-10-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # OIP-Lite > **文档版本**:v1.2 | **更新**:2026-10-16 | **状态**:详细设计 > > OIP(开放互联协议)**轻量端** —— 小程序原生 + TypeScript 的极简实现,**一套代码适配 > 微信 / 钉钉 / 支付宝小程序与 WebView 嵌入**。能力等级:**L1 基础可互操作**。 > > **关联**:[English](README.en.md) · [AGENTS.md](AGENTS.md) · [docs/OIP-Lite-Design.md](docs/OIP-Lite-Design.md) ## 它是什么 OIP-Lite 是奥集能 V6 架构中 HCI 端的**轻量端**形态(OIP-Frontend-Design.md §1.1), 面向「小程序框架或 WebView 嵌入」场景,核心约束是**离线缓存与受限环境适配**。 它不是 oiocns-uniapp 的简化版,而是按 OIP 协议面**重新对齐**的实现: 所有用户操作最终映射为 OIP 协议定义的权利操作,不直连数据核、不私建通道。 **多端适配**是它的第一性问题:宿主差异(传输 / 存储 / 反馈 / 导航 / 扫码 / 免登 / 生命周期)全部收口在 `miniprogram/platform/`;业务代码只依赖 `Host` 契约, **换端零改动**。跨端能力差异由**机器可读的能力矩阵**显式声明 (`platform/manifest.json` 与 `platform/capabilities.ts` 逐项比对,漂移即门禁失败)。 它承载三类入口并各有其出口(来源决定出口): | 入口 | 来源 | 本端出口 | | --- | --- | --- | | **系统应用** | 本端服务登记(办事 / 发现 / 工作台 / 关系 / 我的) | 打开 | | **分发的应用** | 平台方 / 单位分发(`application.List`) | 打开 | | **订阅的应用** | 订阅台账(`application.ListSubscribed`,无副本、回源只读) | 打开 · 退订 | **一键登录**有三条通道:**跨端扫码授权**(QrAuth,本端发起、他端批准——需要私钥签名的 一步发生在已具备密钥库的那一端)、**宿主平台免登**(宿主凭据作为**证据**换既有 DID 的会话)、 **账号口令 / 注册**。宿主账号是证据不是主体:DID 恒为 `did:oip:*`,MUST NOT 派生 `did:wechat:*` 一类标识。 ## 技术栈 | 项 | 取值 | 依据 | | --- | --- | --- | | 运行时 | 小程序原生(WXML / WXSS / JSON / TS 四件套) | `project.config.json` | | **宿主平台** | 微信小程序 · 钉钉小程序 · 支付宝小程序 · WebView / H5 嵌入 | `miniprogram/platform/manifest.json` | | **多端适配** | `platform/` 适配层(`Host` 契约 + 四端适配器 + 能力矩阵 + 载体声明) | `miniprogram/platform/index.ts` | | **工程配置派生** | `tools/gen_platforms.py`(按清单生成各端 `app.json` / IDE 工程描述到 `dist/`) | `package.json` 的 `platform:gen` | | 语言 | TypeScript 5.4+,仅作类型检查(`tsc --noEmit`),运行期由各端 IDE 编译 | `package.json` · `miniprogram/tsconfig.json` | | 编译插件 | 微信开发者工具内置 TypeScript 编译(`setting.useCompilerPlugins: ["typescript"]`) | `project.config.json` | | 基础库 | `libVersion: 3.5.0` | `project.config.json` | | 渲染 | `renderer: "webview"`,`lazyCodeLoading: "requiredComponents"` | `miniprogram/app.json` | | 包体 | **零运行时依赖**:`setting.nodeModules: false`,且 `packOptions.ignore` 排除 `package.json` | `project.config.json` | | TS 目标 | `target: ES2018` / `module: ESNext` / `strict: true` | `miniprogram/tsconfig.json` | | 工具链 | Python 3(协议面生成校验、静态一致性自检、多端配置派生,纯标准库实现) | `tools/` | `node_modules/` 仅供本地类型检查使用,不进入小程序包体。 ## 目录结构 ``` OIP-Lite/ ├── miniprogram/ 小程序根目录(project.config.json 的 miniprogramRoot) │ ├── app.ts / app.json 应用入口与全局配置(pages / tabBar / window) │ ├── app.wxss 全局样式 │ ├── state.ts 全局运行态 │ ├── sitemap.json 索引配置 │ ├── tsconfig.json TypeScript 配置(noEmit) │ ├── protocol/ 协议面生成物(@generated,勿手改)+ 派生层 index.ts │ ├── platform/ 多端适配层:Host 契约 / 能力矩阵 / 四端适配器 / 载体声明 / 协商 / manifest.json │ ├── kernel/ 插件内核:Context(服务 / 事件 / 生命周期 / inject / 可逆挂载)+ 事件表 + 组合根 │ ├── plugins/ 插件:platform / session / space / catalog / login-bridge / system-apps │ ├── domain/ L1 领域层:vet / did / token / work / relation / plaza / market / asset / space / app / service-table / event / result │ ├── infra/ 基础设施:storage(带新鲜度)/ http / gateway(REST + Mock 双模)/ mock │ ├── provider/ L2:OIP State Provider 三契约(vet-store / did-auth / event-sync) │ ├── services/ L3:业务服务(work / relation / plaza / market / asset) │ ├── pages/ L5 表现层:12 个页面(含工作台与应用页容器) │ ├── components/ 共用组件:vet-card(VET 卡片)、status-view(四态容器)、oip-topbar(顶部工具栏) │ ├── config/ 配置注入层(env.ts)与功能开关(feature.ts) │ ├── styles/ 设计令牌(tokens.wxss,派生自 oiocns-uniapp 的 oip_tokens 原始层) │ ├── typings/ 宿主类型声明(wx.d.ts / hosts.d.ts,自持,不入包体) │ └── utils/ 守卫与格式化(guard / format) ├── tools/check_consistency.py 静态一致性自检(含宿主纯度 / 载体声明 / 服务表) ├── tools/gen_platforms.py 多端工程配置派生与校验(能力矩阵漂移即失败) ├── docs/OIP-Lite-Design.md 本仓详细设计 ├── package.json 本地校验脚本与 TypeScript 开发依赖 └── project.config.json 微信开发者工具团队共享配置(入库) ``` 分层依据 OIP-Frontend-Design.md §2.1(L1 领域 → L2 服务 → L5 表现), **依赖方向单向向下**:页面 → 服务 / 插件 → Provider → 基础设施 → 领域。 `kernel/` 与 `plugins/` 是 L4 编排层:内核只提供容器(服务、事件、生命周期), 插件负责组装能力——页面经 `useService()` 取用能力,不直接依赖插件实现。 ## 快速开始 ### 在微信开发者工具中运行 ```bash # 1. 用微信开发者工具导入:目录选 OIP-Lite,appid 选「测试号」或填入自己的 appid # 2. 编译预览 —— 默认连接体验节点 dataexp.orginone.cn(OIP_USE_MOCK: false) # 在登录页「注册」创建账号,再以账号 + 口令登录 ``` 开发者工具读取 `project.config.json`(团队共享配置,入库);窗口布局等本地差异写入 `project.private.config.json`(不入库)。 需要**无后端离线演示**时,在「我的」页打开「内置 Mock 数据源」开关(运行期覆盖,落本地存储), 此时任意账号(或 DID)+ 任意口令即可登录。 ### 在其他宿主中运行(多端) 一份源码四端运行:**宿主差异在 `platform/`,工程差异由清单派生**。 ```bash npm run platform:gen # 生成四端工程配置到 dist/platforms// npm run platform:gen -- --platform alipay # 只生成一端 npm run platform:check # 只校验能力矩阵与载体声明,不写文件 ``` | 宿主 | 工程文件 | 导入方式 | 平台免登 | | --- | --- | --- | --- | | 微信小程序 | `dist/platforms/wechat/project.config.json` | 微信开发者工具导入仓库根(`project.config.json` 已在库) | `wx.login` | | 钉钉小程序 | `dist/platforms/dingtalk/project.config.json` | 钉钉小程序 IDE 导入 `dist/platforms/dingtalk/` 并指向 `miniprogram/` | `dd.getAuthCode` | | 支付宝小程序 | `dist/platforms/alipay/mini.project.json` | 支付宝小程序 IDE 导入 `dist/platforms/alipay/` 并指向 `miniprogram/` | `my.getAuthCode` | | WebView / H5 | `dist/platforms/webview/{app.json,carrier.json}` | 由宿主壳加载(无 tabBar;无扫码 / 免登 / 跨应用跳转能力) | 不具备 | 每个平台目录同时产出 `carrier.json`:该端**载体能力声明**的运行期快照 (`carrier` / `representationVersion` / `rendersBody` / `bodyNotice` / `capabilities`), 便于与「我的」页的自报逐项比对。 **一键登录**(三种通道,均不派生主体 DID): 1. **跨端扫码授权**:本端登录页点「其他平台已登录?一键授权本端」→ 展示授权内容 → 在**另一个已登录的 OIP 端**(Web / 桌面端,持有密钥库)批准 → 本端轮询建立会话 (协议 QrAuth,`/oip/v1/auth/qr-auth/*`,2s / 次,会话 TTL 120s); 2. **宿主平台免登**:具备 `hostLogin` 能力的宿主上,以宿主凭据换取**既有 DID** 的会话; 3. **账号口令 / 注册**:`POST /oip/v1/auth/login|register`。 未接线的通道一律**可见失败**并给出可操作指引,MUST NOT 伪造会话。 ### 接入节点 默认指向 OIP-GoInOne **体验节点**(`GET /oip/v1/bootstrap` 实测 api v5.18): ```ts OIP_REST_ENDPOINT: "https://dataexp.orginone.cn/oip/v1", OIP_L3_ENDPOINT: "https://dataexp.orginone.cn", OIP_NODE_DID: "did:oip:org_alpha_goinone", OIP_USE_MOCK: false, ``` 换部署时改 `miniprogram/config/env.ts` 的 `DEFAULTS`,或在「我的」页切数据源开关。 切换后需重新登录——Mock 签发的会话对真实节点无效。 登录与注册入口的当前契约(按实测节点 `dataexp.orginone.cn` 核对,未接线者一律诚实降级): | 入口 | 通道 | 说明 | | --- | --- | --- | | 登录(口令) | `POST /oip/v1/auth/login`(`method: "password"`) | **要求 `account` 字段**;缺则 `4001 password 登录形态缺少 account`。DID 由服务端按账号反查返回 | | 注册(账号) | `POST /oip/v1/auth/register` | 同时落账号口令凭据,注册完即可登录;返回主体 DID | | 微信快捷登录 | OIP-Login `login/authorize-url` + `login/poll` | 小程序无法内嵌浏览器完成跳转,授权链接需在已登录的桌面端打开;`login/complete` 需 DID 私钥签名的 Proof,本端不具备 | | 匿名建主体 | `POST /api/v1/did/person` | 实测节点返回 **405**,已不作为注册入口;且该通道只建主体不建凭据 | | 忘记密码 | — | 权威面未提供找回入口,仅给出指引,不向不存在的端点发请求 | ## 命令 以下脚本定义于 `package.json`,均需在仓库根目录执行: | 命令 | 实际执行 | 说明 | | --- | --- | --- | | `npm install` | — | 安装 `typescript`(仅本地校验用,不进入小程序包体) | | `npm run typecheck` | `tsc --noEmit -p miniprogram/tsconfig.json` | TypeScript 类型检查 | | `npm run check:consistency` | `python3 tools/check_consistency.py` | 静态一致性自检(含宿主纯度 / 载体声明 / 服务表) | | `npm run platform:check` | `python3 tools/gen_platforms.py --check` | 多端能力矩阵与工程配置派生校验 | | `npm run platform:gen` | `python3 tools/gen_platforms.py` | 生成各端工程配置到 `dist/platforms//` | | `npm run protocol:check` | `python3 ../OIP/tools/gen_protocol.py --check` | 协议面漂移校验 | | `npm run protocol:gen` | `python3 ../OIP/tools/gen_protocol.py` | 重新生成协议面产物 | | `npm run verify` | 上述四道门禁串联 | 一键门禁:协议面漂移 + 静态一致性 + 多端清单 + TS 类型,全绿才算通过 | ### 静态一致性自检 校验 `app.json` 页面四件套、tabBar、`usingComponents` 路径、wxml 标签声明、 TS 相对 import 可解析性、协议面生成物头部: ```bash python3 tools/check_consistency.py ``` ### 协议面产物 协议面(错误码 / 事件主题 / 内核六元组 / CloudEvents 字段)由 `OIP/spec/*.json` 经生成器产出,**禁止手工编辑**: ```bash python3 ../OIP/tools/gen_protocol.py --check # 校验是否漂移 python3 ../OIP/tools/gen_protocol.py # 重新生成 ``` ## 功能 `miniprogram/app.json` 声明 12 个页面。底部工具栏为 5 个一级入口(tabBar): | 一级入口 | 路径 | 说明 | | --- | --- | --- | | 办事 | `pages/todo/index` | 工作流任务列表与审批;审批提交服务端 PDP 裁决 | | 发现 | `pages/plaza/index` | 可发现主体的检索与加入申请(申请须经对方管理者审批后生效) | | 工作台 | `pages/workbench/index` | **个人桌面 / 单位工作台**——同一界面的两个上下文剖面(**宿主容器**,非服务) | | 关系 | `pages/relation/index` | 人员 / 群组 / 组织只读浏览(含搜索) | | 我的 | `pages/mine/index` | 身份、**载体与多端自报**、平台服务就绪、协议面自报、数据源切换、退出登录 | **工作台**是登录落地页,也是个人尺度与组织尺度(OIP.md §1.3.5 分形同构)的两个剖面: - **顶部工具栏**:左侧为个人 / 单位上下文切换(仅换上下文,不重新认证),右侧为扫一扫; - **提示条**:当前宿主 + 载体正文渲染口径(`no-body` 的如实告知); - **主体区三段**:**系统应用** / **分发的应用** / **订阅的应用**——订阅段提供**退订**; - **打开闸**:来源出口闸 → 依赖就绪闸(`using[]`,任一不就绪即不装载并如实告知)→ 落点分派 (本端页面 / 其他小程序 / ``);落点未接线时如实提示"尚未接入本端"; - 上下文切换后由内核广播 `SPACE_CHANGED` 驱动重算,页面不持有上下文副本。 其余页面: | 页面 | 路径 | 说明 | | --- | --- | --- | | 登录 | `pages/login/index` | 跨端扫码授权 / 宿主免登 / 账号口令 / 注册(Mock 模式接受任意 DID + 口令) | | 商城 | `pages/market/index` | **可订阅的应用**(P3 商城通道:订阅 / 退订)+ 可申领权利的目录与申领发起(自「我的」进入) | | 权利详情 | `pages/vet-detail/index` | 单个 VET 的内核六元组与委托链 | | 办事详情 | `pages/work-detail/index` | 任务详情与审批提交 | | 数据空间 | `pages/asset/index` | 数据胶囊只读浏览,标注授权来源与派生客体约束 | | 智能体 | `pages/agent/index` | L2/L3 能力说明页(默认不在一级入口) | | 应用页容器 | `pages/webview/index` | 承载分发 / 订阅应用的**外部应用页**;不注入凭据、不注入正文,失败可见 | ### 插件化(kernel / plugins) 内核是 Cordis 风格的极简插件容器,只做四件事:**服务注册**(`ctx.set` / `ctx.get`)、 **事件**(`ctx.on` / `ctx.emit`)、**依赖注入**(`inject`,依赖未就绪即挂起等待)、 **可逆挂载**(`ctx.plugin()` 返回 `Fork`,卸载即回收副作用)。 | 插件 | 职责 | 依赖 | | --- | --- | --- | | `platform` | 宿主标识、能力矩阵、**载体能力声明**、平台服务就绪判定(K4) | — | | `session` | 把 L2 的 DID Auth 投影为 `session` 服务,并广播会话变化 | — | | `space` | 个人 / 单位上下文:空间列表、当前空间、切换(广播 `SPACE_CHANGED`) | `session` | | `catalog` | 应用目录:系统 / 分发 / **订阅**三段;依赖就绪闸;落点分派(`register` 可逆) | `space` · `platform` | | `login-bridge` | 登录桥:宿主平台免登 + 跨端扫码授权(QrAuth)编排 | `platform` | | `system-apps` | 把 5 枚系统应用瓦片登记进目录,与分发 / 订阅应用**同一条登记通道** | `catalog` | 应用清单走两条**独立通道**:`application.List`(分发的应用)与 `application.ListSubscribed`(订阅的应用)——订阅**无副本、回源只读**,合并成一条会让 "订阅读空"看起来像"没有分发"。两者在 GoInOne 前门**尚未挂载**:真实节点下呈现为 **可见的失败态与重试入口**(订阅退订同理:找不到订阅跳如实失败,MUST NOT 伪造成功), 内置 Mock 覆盖演示通路——未接线的能力 MUST 以失败可见收尾,不得伪造"已就绪"。 ## 与 OIP 其他仓库的关系 本仓是 OIP 工作区的 L6 人机交互端之一,与其他仓库**零代码级依赖**,通过 HTTP 经 OIP-GoInOne 前门耦合。工作区内的相对路径(纯文本): | 路径 | 关系 | | --- | --- | | `../OIP` | 协议与设计文档仓:`../OIP/spec/protocol.json`、`../OIP/spec/events.json` 是协议面单一真相源;`../OIP/tools/gen_protocol.py` 是本仓协议面产物的生成器 | | `../OIP/docs/OIP.md` | 架构总纲:本仓的定位与分层依据 | | `../OIP/docs/OIP-Frontend-Design.md` | L6 前端契约:节点发现、Hub 方法、错误码、能力等级 | | `../OIP-IoT` | L1 物联网网关,经前门路由(本仓不直连) | | `../OIP-Mobile` | L6 移动端(Flutter),与本仓同层不同形态 | | `../OIP-Desktop` / `../OIP-Web` | L6 PC 本地终端与 Web 端,与本仓同层不同形态 | | `../OIP-GoInOne` | 统一接入前门:认证、路由、上行转发 | ## 设计约束(实现时严格遵守) - **协议面单一来源**:错误码等常量由生成器产出,本仓只派生不手写(OIP.md §1.6 原则 12)。 - **多端一套代码**:宿主全局对象只允许出现在 `miniprogram/platform/**`,其余一律经 `host()`; 新增宿主 MUST 同时登记能力矩阵(`capabilities.ts` / `manifest.json`)与适配器,MUST NOT 代填他端矩阵。 - **载体能力显式声明**:跨端差异由机器可读的能力矩阵声明(RT.6.4);未接线即可见失败,MUST NOT 静默降级。 - **不渲染应用正文**:轻量端为 `no-body` 载体(宿主无同源沙箱,RT.1.1 / RT.6.2),只承载应用入口; 应用页容器不注入任何凭据(RT.6.3)。 - **应用不得自带路由**(A8):落点由**载体**派生;应用的依赖声明 `using[]` **未知即拒**, 任一依赖不就绪即**不装载**并如实告知。 - **默认拒绝**:未显式授权一律拒绝;前端缓存 NEVER 作为放行依据,权利行使回源由服务端裁决。 - **主体标识主权**:DID 不由微信 / 钉钉 / 支付宝等外部账号派生;外部账号是**证据**不是主体。 - **四态覆盖**:所有数据加载型视图覆盖 加载中 / 空 / 失败 / 成功,**静默失败不可接受**。 - **品牌克制**:每视图至多 1 个品牌 CTA,动效 ≤ 300ms,最小交互区 88rpx(≈44px)。 详细架构见 [`docs/OIP-Lite-Design.md`](./docs/OIP-Lite-Design.md)。 ## 许可 MIT(与其他 OIP 代码仓一致)。