464 lines
16 KiB
Markdown
464 lines
16 KiB
Markdown
# CSLAB-DCS-Web
|
||
|
||
**DCS(分布式控制系统)跨平台可视化组态编辑器**
|
||
|
||
面向工业控制场景的画布组态设计、数据绑定、实时仿真与运行监控平台,支持 Web、Electron、Tauri 三端部署。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
- [项目简介](#项目简介)
|
||
- [技术栈](#技术栈)
|
||
- [项目结构](#项目结构)
|
||
- [环境要求](#环境要求)
|
||
- [快速开始](#快速开始)
|
||
- [开发命令](#开发命令)
|
||
- [构建与部署](#构建与部署)
|
||
- [核心架构](#核心架构)
|
||
- [功能模块](#功能模块)
|
||
- [数据模型](#数据模型)
|
||
- [API 层](#api-层)
|
||
- [测试](#测试)
|
||
- [CI/CD](#cicd)
|
||
|
||
---
|
||
|
||
## 项目简介
|
||
|
||
CSLAB-DCS-Web 是一个 **工业分布式控制系统可视化组态编辑器**,采用 pnpm monorepo 架构。用户可在画布上拖放、编排工业控制组件(如 PID 控制器、阀门控制器、仪表等),配置数据绑定与表达式,并通过 WebSocket 实现运行时的实时数据推送和仿真监控。
|
||
|
||
### 核心能力
|
||
|
||
- **画布组态设计**:基于可视化画布的工业控制界面设计,支持多图层、组件拖放、对齐辅助线、缩放漫游
|
||
- **丰富组件库**:矩形、文本、数字显示、柱状图、按钮、PID 控制器、阀门控制器、画布切换器等
|
||
- **数据绑定与表达式**:支持将组件属性绑定到运行时变量,内置表达式引擎(tokenizer → parser → evaluator)
|
||
- **条件样式**:根据运行时条件动态切换组件样式
|
||
- **事件与动作**:组件支持 click/dblclick 事件触发,执行自定义动作
|
||
- **实时运行监控**:通过 WebSocket 连接运行时服务,RAF 帧批处理数据更新
|
||
- **仿真执行**:对接 chemical-chaos 微服务,支持任务创建、启停、暂停/恢复
|
||
- **导入导出**:画布/项目的导入导出,Zod schema 校验数据完整性
|
||
- **跨平台**:Web 浏览器 / Electron 桌面 / Tauri 轻量桌面三端统一
|
||
|
||
---
|
||
|
||
## 技术栈
|
||
|
||
| 类别 | 技术 |
|
||
|------|------|
|
||
| **框架** | Vue 3 (Composition API + `<script setup>`) |
|
||
| **路由** | Vue Router 4(Hash 模式,兼容桌面端) |
|
||
| **状态管理** | Pinia 3 |
|
||
| **UI 组件库** | Element Plus(中文本地化) |
|
||
| **原子化 CSS** | UnoCSS |
|
||
| **组合式工具** | VueUse |
|
||
| **HTTP 客户端** | ofetch |
|
||
| **Schema 校验** | Zod |
|
||
| **构建工具** | Vite 6 / electron-vite |
|
||
| **桌面框架** | Electron 22 / Tauri 2 |
|
||
| **包管理器** | pnpm(workspace) |
|
||
| **TypeScript** | 5.9+(严格模式) |
|
||
| **代码规范** | ESLint + @antfu/eslint-config |
|
||
| **单元测试** | Vitest + @vue/test-utils + happy-dom |
|
||
| **E2E 测试** | Playwright(Chromium) |
|
||
| **样式预处理** | SCSS |
|
||
| **图标** | FontAwesome 7 |
|
||
|
||
---
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
cslab-dcs-web/
|
||
├── apps/ # 应用入口层
|
||
│ ├── web/ # Web 浏览器版
|
||
│ ├── electron/ # Electron 桌面版
|
||
│ └── tauri/ # Tauri 桌面版
|
||
│
|
||
├── packages/ # 共享包层
|
||
│ ├── core/ # 核心业务逻辑与 UI
|
||
│ │ └── src/
|
||
│ │ ├── api/ # API 服务层
|
||
│ │ ├── assets/ # 静态资源(字体、图片、样式)
|
||
│ │ ├── bootstrap/ # 应用初始化(Bridge、编辑器、路由状态同步)
|
||
│ │ ├── components/ # 组件库
|
||
│ │ │ └── editor/ # 编辑器组件
|
||
│ │ │ ├── canvas/ # 画布引擎(Stage、图层面板、属性面板、组件面板)
|
||
│ │ │ ├── components/# 可渲染组件(rect、text、number、bar、button、PID…)
|
||
│ │ │ ├── controls/ # UI 控件(输入框、颜色选择器、开关…)
|
||
│ │ │ ├── header/ # 顶部工具栏
|
||
│ │ │ └── ... # 运行时控制台、状态栏等
|
||
│ │ ├── composables/ # 组合式函数
|
||
│ │ ├── config/ # 运行时配置
|
||
│ │ ├── constants/ # 常量定义
|
||
│ │ ├── layout/ # 布局组件
|
||
│ │ ├── request/ # 请求层(HTTP / IndexedDB 双适配器)
|
||
│ │ ├── router/ # 路由配置
|
||
│ │ ├── stores/ # Pinia 状态管理
|
||
│ │ ├── utils/ # 工具函数
|
||
│ │ └── views/ # 页面视图
|
||
│ │
|
||
│ ├── bridge/ # 平台抽象桥接层
|
||
│ │ └── src/
|
||
│ │ ├── adapters/ # Web / Electron / Tauri 适配器
|
||
│ │ └── types.ts # IPlatformBridge 接口定义
|
||
│ │
|
||
│ └── schema/ # 数据模型与校验
|
||
│ └── src/
|
||
│ ├── dcs.ts # DCS 配置类型
|
||
│ ├── types.ts # 通用类型
|
||
│ └── validators.ts # Zod 校验器
|
||
│
|
||
├── tests/ # 测试
|
||
│ ├── e2e/ # Playwright E2E 测试
|
||
│ └── unit/ # Vitest 单元测试
|
||
│
|
||
├── references/ # 参考文档与竞品截图
|
||
├── eslint.config.js
|
||
├── vitest.config.ts
|
||
├── playwright.config.ts
|
||
├── tsconfig.base.json
|
||
├── pnpm-workspace.yaml
|
||
└── package.json
|
||
```
|
||
|
||
### 包职责说明
|
||
|
||
| 包名 | 描述 |
|
||
|------|------|
|
||
| `@cslab-dcs/core` | 核心业务层——路由、Store、API、视图、组件、组合式函数,是应用的主体 |
|
||
| `@cslab-dcs/bridge` | 平台抽象层——定义 `IPlatformBridge` 接口,提供文件操作、对话框、系统信息的跨平台实现 |
|
||
| `@cslab-dcs/schema` | 数据模型层——Canvas、Layer、Component、Variable 的 Zod Schema 定义与校验 |
|
||
| `@cslab-dcs/web` | Web 入口——挂载 Vue 应用到浏览器 |
|
||
| `@cslab-dcs/electron` | Electron 入口——主进程 IPC、窗口管理、文件授权 |
|
||
| `@cslab-dcs/tauri` | Tauri 入口——Tauri Plugin API 绑定 |
|
||
|
||
---
|
||
|
||
## 环境要求
|
||
|
||
| 依赖 | 版本 |
|
||
|------|------|
|
||
| Node.js | >= 20.0.0 |
|
||
| pnpm | >= 9.0.0 |
|
||
| Rust(仅 Tauri) | latest stable |
|
||
|
||
---
|
||
|
||
## 快速开始
|
||
|
||
```bash
|
||
# 1. 安装依赖
|
||
pnpm install
|
||
|
||
# 2. 启动 Web 开发服务
|
||
pnpm dev:web
|
||
# 访问 http://localhost:5173/dcs-web#/
|
||
|
||
# 3. 或启动 Electron 桌面版
|
||
pnpm dev:electron
|
||
|
||
# 4. 或启动 Tauri 桌面版
|
||
pnpm dev:tauri
|
||
```
|
||
|
||
---
|
||
|
||
## 开发命令
|
||
|
||
### 开发
|
||
|
||
| 命令 | 说明 |
|
||
|------|------|
|
||
| `pnpm dev:web` | 启动 Web 版开发服务器(端口 5173) |
|
||
| `pnpm dev:electron` | 启动 Electron 桌面版 |
|
||
| `pnpm dev:tauri` | 启动 Tauri 桌面版 |
|
||
|
||
### 构建
|
||
|
||
| 命令 | 说明 |
|
||
|------|------|
|
||
| `pnpm build:web` | 构建 Web 生产包 |
|
||
| `pnpm build:electron:win` | 构建 Windows Electron 安装包 |
|
||
| `pnpm build:tauri` | 构建 Tauri 跨平台安装包 |
|
||
|
||
### 质量保障
|
||
|
||
| 命令 | 说明 |
|
||
|------|------|
|
||
| `pnpm format` | ESLint 自动修复 |
|
||
| `pnpm typecheck` | 全包 TypeScript 类型检查 |
|
||
| `pnpm test` | 运行单元测试 |
|
||
| `pnpm test:watch` | 监听模式单元测试 |
|
||
| `pnpm test:coverage` | 生成覆盖率报告 |
|
||
| `pnpm test:e2e` | 运行 E2E 测试 |
|
||
| `pnpm test:e2e:ui` | E2E 测试(带 UI) |
|
||
|
||
---
|
||
|
||
## 构建与部署
|
||
|
||
### Web 构建产物
|
||
|
||
```bash
|
||
pnpm build:web
|
||
# 输出目录:apps/web/dist/
|
||
```
|
||
|
||
构建产物为纯静态资源(HTML/JS/CSS),可直接部署到任意 Web 服务器或 CDN。
|
||
|
||
### 环境变量
|
||
|
||
| 变量 | 说明 |
|
||
|------|------|
|
||
| `VITE_API_BASE_URL` | 后端 API 地址 |
|
||
| `VITE_BASE_URL` | 前端部署路径 |
|
||
|
||
---
|
||
|
||
## 核心架构
|
||
|
||
### 分层架构
|
||
|
||
```
|
||
┌────────────────────────────────────────────┐
|
||
│ Views(页面视图) │
|
||
├────────────────────────────────────────────┤
|
||
│ Components(UI 组件层) │
|
||
├────────────────────────────────────────────┤
|
||
│ Composables(组合式函数层) │
|
||
├────────────────────────────────────────────┤
|
||
│ Pinia Stores(状态管理层) │
|
||
├────────────────────────────────────────────┤
|
||
│ API Layer(服务接口层) │
|
||
├────────────────────────────────────────────┤
|
||
│ Request Adapters(HTTP / IndexedDB 适配) │
|
||
├────────────────────────────────────────────┤
|
||
│ Platform Bridge(Web / Electron / Tauri) │
|
||
└────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 路由
|
||
|
||
| 路由 | 页面 | 说明 |
|
||
|------|------|------|
|
||
| `/canvases` | 画布列表 | 项目下的画布管理 |
|
||
| `/editor` | 画布编辑器 | 核心组态编辑界面 |
|
||
| `/preview` | 预览模式 | 只读画布预览 |
|
||
| `/runtime` | 运行模式 | 实时仿真与监控 |
|
||
| `/settings` | 设置 | 桌面端专属 |
|
||
| `/welcome` | 欢迎页 | 桌面端专属 |
|
||
|
||
### 状态管理(Pinia Stores)
|
||
|
||
| Store | 职责 | 持久化 |
|
||
|-------|------|--------|
|
||
| `useAppStore` | 主题、平台信息、应用版本 | — |
|
||
| `useUserStore` | JWT Token、设备类型、用户信息 | localStorage |
|
||
| `useProjectStore` | 项目列表、当前项目、最近项目 | sessionStorage |
|
||
| `useCanvasStore` | 画布列表、缩放级别、视口状态 | sessionStorage |
|
||
| `useLayerStore` | 选中图层、图层列表、基础图层 | sessionStorage |
|
||
|
||
### 平台桥接(Bridge)
|
||
|
||
```typescript
|
||
interface IPlatformBridge {
|
||
platform: 'web' | 'electron' | 'tauri'
|
||
file: IFileService // 读写文件、打开/保存对话框
|
||
dialog: IDialogService // 消息弹窗、确认弹窗
|
||
system: ISystemService // 应用版本、平台信息、打开外部链接
|
||
}
|
||
```
|
||
|
||
三端适配器各自实现该接口,上层业务代码无需关心平台差异。
|
||
|
||
---
|
||
|
||
## 功能模块
|
||
|
||
### 画布编辑器
|
||
|
||
- **画布引擎**:支持缩放(最大 300%)、平移、网格对齐(10px)
|
||
- **画布尺寸**:默认 1920×1080,最小 360×240,最大 20000×20000
|
||
- **图层管理**:多选、分组、排序、锁定
|
||
- **属性面板**:根据选中组件类型动态展示配置项
|
||
- **对齐辅助线**:智能吸附对齐
|
||
- **Minimap**:画布缩略图导航
|
||
- **撤销/重做**:完整的操作历史记录
|
||
- **自动保存**:编辑内容自动持久化
|
||
|
||
### 可渲染组件
|
||
|
||
| 组件 | 说明 |
|
||
|------|------|
|
||
| `rect` | 矩形/容器 |
|
||
| `text` | 文本标签 |
|
||
| `number` | 数字显示 |
|
||
| `bar` | 柱状图 |
|
||
| `button` | 可交互按钮 |
|
||
| `pidController` | PID 控制器面板 |
|
||
| `valveController` | 阀门控制器 |
|
||
| `canvasSwitcher` | 画布切换导航 |
|
||
| `custom` | 自定义组件 |
|
||
|
||
### 数据绑定与表达式引擎
|
||
|
||
组件属性支持绑定到运行时变量,内置完整的表达式解析引擎:
|
||
|
||
```
|
||
表达式字符串 → Tokenizer(词法分析)→ Parser(语法分析)→ Evaluator(求值)
|
||
```
|
||
|
||
支持条件样式:根据表达式结果动态切换组件外观,支持优先级配置。
|
||
|
||
### 运行时监控
|
||
|
||
- WebSocket 实时数据推送
|
||
- RequestAnimationFrame 帧批处理,保证渲染性能
|
||
- 运行时控制台输出
|
||
- 手动控制面板
|
||
- PID 参数调节面板
|
||
- 阀门开度控制面板
|
||
|
||
### 组合式函数(Composables)
|
||
|
||
| 函数 | 职责 |
|
||
|------|------|
|
||
| `useBridge()` | 获取平台桥接实例 |
|
||
| `useOperationLog()` | 操作日志记录(上限 500 条) |
|
||
| `useRuntimeSocket()` | WebSocket 运行时连接与帧批更新 |
|
||
| `useDataConnection()` | 数据连接管理与写入命令 |
|
||
| `useExportImport()` | 画布/项目导入导出 |
|
||
| `useRuntimeConsole()` | 运行时控制台日志 |
|
||
| `useComponentTemplates()` | 组件模板存取(localStorage) |
|
||
|
||
---
|
||
|
||
## 数据模型
|
||
|
||
### Canvas(画布)
|
||
|
||
```typescript
|
||
{
|
||
id: string
|
||
projectId: string
|
||
name: string
|
||
description?: string
|
||
width: number // 默认 1920
|
||
height: number // 默认 1080
|
||
type: CanvasType
|
||
version: string
|
||
components: Layer[] // 组件/图层列表
|
||
vars?: Variable[] // 运行时变量
|
||
config?: CanvasConfig
|
||
thumbnail?: string // 缩略图
|
||
updatedAt: string
|
||
}
|
||
```
|
||
|
||
### Layer(图层/组件)
|
||
|
||
```typescript
|
||
{
|
||
id: string // UUID
|
||
type: ComponentType // rect | number | text | bar | button | ...
|
||
x: number // X 坐标
|
||
y: number // Y 坐标
|
||
width: number
|
||
height: number
|
||
config?: object // 组件特定配置
|
||
style?: object // CSS 样式
|
||
bindings?: Record<string, string | BindingExpression> // 数据绑定
|
||
tagNumber?: string // 设备标签号
|
||
events?: EventConfig[] // 事件处理器
|
||
conditionalStyles?: ConditionalStyle[] // 条件样式
|
||
}
|
||
```
|
||
|
||
所有数据模型均使用 Zod Schema 定义,提供运行时校验和 TypeScript 类型推导。
|
||
|
||
---
|
||
|
||
## API 层
|
||
|
||
### 请求架构
|
||
|
||
采用 **Repository 模式** + **双适配器**:
|
||
|
||
- **HTTP 适配器** → 对接 `/cslab-server` 后端
|
||
- **IndexedDB 适配器** → 浏览器本地存储(离线模式)
|
||
|
||
HTTP 客户端基于 `ofetch`,支持 JWT Token 自动刷新、401 会话过期处理、错误提示。
|
||
|
||
### API 模块
|
||
|
||
| 模块 | 接口 |
|
||
|------|------|
|
||
| **Project** | `getProjectListApi()` / `createProjectApi()` / `updateProjectApi()` |
|
||
| **Canvas** | `listCanvasesApi()` / `getCanvasByIdApi()` / `createCanvasApi()` / `updateCanvasApi()` / `saveCanvasComponentsApi()` / `duplicateCanvasApi()` |
|
||
| **Runtime** | `addJobApi()` / `stopJobApi()` / `pauseJobApi()` / `resumeJobApi()` / `getProjectJobApi()` / `pushFullDataApi()` / `getExecSequenceApi()` |
|
||
| **Dynamic Project** | 动态项目更新 |
|
||
|
||
### 运行时 RPC
|
||
|
||
对接 `chemical-chaos` 微服务,通过 `/v1/rpc/common/` 和 `/v1/rpc/zero_rpc/` 端点进行仿真调度。
|
||
|
||
---
|
||
|
||
## 测试
|
||
|
||
### 单元测试
|
||
|
||
- **框架**:Vitest + happy-dom + @vue/test-utils
|
||
- **位置**:`tests/unit/`
|
||
- **覆盖范围**:Composables、Stores、Schema 校验、表达式引擎
|
||
|
||
```bash
|
||
pnpm test # 运行全部单元测试
|
||
pnpm test:watch # 监听模式
|
||
pnpm test:coverage # 覆盖率报告
|
||
```
|
||
|
||
### E2E 测试
|
||
|
||
- **框架**:Playwright(Chromium)
|
||
- **位置**:`tests/e2e/`
|
||
- **测试场景**:画布编辑器操作、图层交互、页面导航
|
||
|
||
```bash
|
||
pnpm test:e2e # 运行 E2E 测试
|
||
pnpm test:e2e:ui # 带 UI 的 E2E 测试
|
||
```
|
||
|
||
---
|
||
|
||
## CI/CD
|
||
|
||
项目配置了 Jenkins Pipeline,支持两套部署环境:
|
||
|
||
| 环境 | 配置文件 | 目标 |
|
||
|------|----------|------|
|
||
| 开发环境(110) | `Jenkinsfile.dev110` | Windows 服务器部署 |
|
||
| 测试环境(139) | `Jenkinsfile.dev139` | Linux 服务器部署 |
|
||
|
||
### Pipeline 流程
|
||
|
||
1. **环境检查** → 验证 Node 22 / pnpm 版本
|
||
2. **安装依赖** → `pnpm install`
|
||
3. **构建** → `pnpm build:web`
|
||
4. **部署** → SSH 拷贝静态资源到目标服务器
|
||
5. **通知** → 企业微信 Webhook 通知构建结果
|
||
|
||
### 部署要点
|
||
|
||
- 构建产物:`apps/web/dist/` 下的静态文件
|
||
- 构建超时:15 分钟
|
||
- 跳过 Electron 二进制下载:`ELECTRON_SKIP_BINARY_DOWNLOAD=1`
|
||
- 测试环境支持旧版本自动清理(>7 天)
|
||
|
||
---
|
||
|
||
## License
|
||
|
||
Private — 内部项目
|