唯杰地图 logo唯杰地图
VJMAP
EN

应用骨架与模块脚手架

vjvp/references/sdk-app/scaffold.md 6.1 KB100 行
原文

返回 SKILL.md。下文结构提炼自官方参考实现(park 能源站、safety 罐区两套应用,模块结构相同)。

包名:外部工程用发布包名 vjvpsdk("file:./vendor/vjvpsdk" 或私有 registry 版本号),拿到包即可用,无需构建 SDK。下文示例的 @vp/sdk 与 vjvpsdk 等价互换;CSS 子路径分别为 @vp/sdk/vp-runtime.css 与 vjvpsdk/vp-runtime.css。

1. 应用骨架(npm 消费形态,默认推荐)

四个文件起步:

package.json(依赖 vjvpsdk + vue;vjvpsdk 也可换成私有 registry 版本号):

{
  "name": "<name>",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "typecheck": "vue-tsc --noEmit"
  },
  "dependencies": { "vjvpsdk": "file:./vendor/vjvpsdk", "vue": "^3.5.13" },
  "devDependencies": { "@vitejs/plugin-vue": "^5.2.1", "typescript": "^5.6.3", "vite": "^5.4.11", "vue-tsc": "^2.1.10" }
}

vite.config.ts(不配置任何别名——import 'vjvpsdk' 走包入口解析到 dist/vp-runtime.mjs):

import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'

export default defineConfig({
  base: './',
  plugins: [vue()],
  server: { port: 5181, host: true },
})

index.html:<div id="app"></div> + <script type="module" src="/src/main.ts"></script>(深色底 body 样式防白闪)。

src/main.ts(样式经包子路径引入;自定义组件经挂载选项注册):

import { createVpViewer } from 'vjvpsdk'
import 'vjvpsdk/vp-runtime.css'
import { appInit } from './project'
import { buildAll } from './build'
import { myWidgetModule } from './widgets/myWidget'

createVpViewer('#app', appInit, {
  widgets: [{ type: 'my-widget', module: myWidgetModule }],
  onReady: (ctx) => void buildAll(ctx),
})

⚠️ 外部工程用 vjvpsdk 包无需构建 SDK。类型解析走包内 dist/vp-runtime.d.ts(发布包 types 字段所指)。

2. 模块目录(配置层 / 代码层)

src/
├── main.ts               # 入口:注册自定义组件 + createVpViewer + onReady
├── project/              # ◆配置层:数据源
│   ├── connections.ts    #   连接/表/字段定义(uid=alias 中文字段,helper 压缩重复)
│   ├── connectionData.ts #   初始行(测点初值从 sim 单一事实源导入,静态报表手写)
│   └── index.ts          #   body 外壳(页面级选项 + 首页空壳)+ mergeFieldSchema
├── scenes/               # ◆配置层:重场景 pieces 静态定义
│   ├── scene3dPieces.ts  #   三维场景(导出 UID 常量 + pieces() + interactions())
│   ├── scadaPieces.ts    #   组态工艺图(node/link 用 helper 生成)
│   └── mapPieces.ts      #   2D 地图(map-body + 数据源 + 图层)
├── sim/                  # ◆代码层:模拟引擎与业务状态机(纯函数 + 单测)
│   ├── points.ts         #   测点/设备/映射表 单一事实源(含 DEVICE_PIECE_MAP 类映射)
│   ├── simulator.ts      #   物理模型 tick(纯函数,注入 rng)
│   ├── alarms.ts         #   告警状态机(raise/resolve/ack + 派生视图)
│   ├── <domain>.ts       #   领域状态机(隐患/作业票/演练…)
│   └── runtime.ts        #   接线:setInterval tick → ctx.setData;对页面暴露控制 API
├── pages/                # ◆代码层:每页一个 builder(ctx/screen/sim 注入)
├── widgets/              # ◆代码层:自定义组件(模型类 + 渲染 + 纯函数内核分离)
├── ui.ts                 # 主题常量 + addPanel/addCartesian/addPie/addTable/addButton/addValueText + buildNav/buildHeader
├── windows.ts            # 工程级窗口(趋势/详情/应急……内容组件带 uid 供程序化刷写)
└── build.ts              # 总装:启动 sim → addScreen 建页 → 逐页 builder → 窗口 → 跨页联动

3. 数据层模板要点

  • connections.ts:用 F(uid)/S(uid)/conn(...) 小 helper 压缩;字段 uid = alias(中文列名直接当字段 id,绑定与行键一致零转换)。
  • connectionData.ts:测点初值 必须 从 sim/points.ts 的 initialPoints() 导入生成(单一事实源,防两处漂移);静态报表(月度/分项)手写;历史窗口可用初始 sim 状态回放 N 拍生成,与实时数据无缝衔接。
  • index.ts:内核 VpDataTable 要求每张表带 fields/tableName(图表 getFieldMeta 直读),mergeFieldSchema 从 connections 合并进 connectionData。
  • body 外壳:只带数据层 + 一个空首页(页面级选项 layout-profile: canvas-percent + fullscreen-mode: responsive + 1920×1080 + 深色渐变背景);其余页面全部 ctx.addScreen 程序化创建。

4. 页面构建要点

  • 全部几何按 1920×1080 设计基准 + 'geometry-unit': 'percent' 写,全屏自适应。
  • 导航条每页重建(当前页高亮、其余 btn.onClick(() => ctx.setActiveScreen(id)));PAGES 清单集中定义。
  • 面板套路:addPanel(group-panel 百分比几何)→ addPanelHeader(光条+标题+分隔线)→ 内容组件(图表绑 category-field/metric-fields,表格绑 table-data-fields,指标文本绑 value-field)。
  • 程序化刷写文本:创建时给 uid,回调里 ctx.getWidget(uid)?.setOption('text', ...)。
  • 表格点行:table.onSelect((data, index) => ...)——data 是选中维度 {别名:值}(取联动键 / table-key-fields / select-sync-fields 各列,都未配时为被点击列;再点同行取消时为 undefined),不是行 payload;要 {rowNumber(1基), rowIndex(0基), columnUID, value, row:{别名:值}, …} 用 table.onValueChange(v => …) 或 table.getValue()(即 currentValue)。业务主键(如 _id)要出现在 data 里,就把它配进 table-key-fields;数据行本身另带运行时注入的 _index 字段(1 基行号,vxe keyField 也用它)。