chbim-time-axis-v2 0.0.8 → 0.0.11
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.
- package/README.md +228 -129
- package/dist/chbim-time-axis-v2.es.js +141 -42
- package/dist/chbim-time-axis-v2.umd.js +1 -1
- package/dist/components/CesiumGantt.vue.d.ts +21 -0
- package/dist/components/TimelineChart.vue.d.ts +22 -1
- package/dist/components/types.d.ts +9 -3
- package/dist/style.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,67 +4,54 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/chbim-time-axis-v2)
|
|
5
5
|
[](https://www.npmjs.com/package/chbim-time-axis-v2)
|
|
6
6
|
|
|
7
|
-
一个专为 Vue 3
|
|
8
|
-
|
|
9
|
-
## ✨
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
7
|
+
一个专为 Vue 3 + Cesium 设计的甘特图组件。它不仅是一个任务管理工具,更是连接二维时间数据与三维空间展示的桥梁。
|
|
8
|
+
|
|
9
|
+
## ✨ 核心特性
|
|
10
|
+
|
|
11
|
+
- **🤝 深度 Cesium 集成**:
|
|
12
|
+
- **双向同步**: 甘特图的时间轴与 Cesium Viewer 的时钟(Clock)完全同步。拖动甘特图时间轴会更新 Cesium 场景时间,反之亦然。
|
|
13
|
+
- **二三维联动**: 当时间轴播放到特定任务时,会触发事件,方便开发者在三维场景中控制模型的显隐、动画等。
|
|
14
|
+
- **📅 多维任务模型**:
|
|
15
|
+
- **普通任务 (Task)**: 标准的起止时间任务。
|
|
16
|
+
- **任务组 (Group)**: 可折叠的任务容器,支持自动计算时间范围和手动限制范围。
|
|
17
|
+
- **时间块 (Block)**: 单个任务行内包含多个不连续的时间段(如间歇性作业)。
|
|
18
|
+
- **瞬时点 (Instant)**: 标记特定时间点的关键事件(如里程碑、检查点)。
|
|
19
|
+
- **🎨 高度可定制**:
|
|
20
|
+
- **插槽 (Slots)**: 提供工具栏、任务操作列、右键菜单等多个插槽,满足个性化 UI 需求。
|
|
21
|
+
- **样式**: 支持自定义任务颜色、瞬时点颜色等。
|
|
22
|
+
- **⚡ 开发体验**:
|
|
23
|
+
- **TypeScript**: 提供完整的类型定义。
|
|
24
|
+
- **Vue 3**: 基于 Composition API 构建,响应式性能优秀。
|
|
15
25
|
|
|
16
26
|
## 📦 安装
|
|
17
27
|
|
|
18
|
-
使用 npm 或 yarn 安装:
|
|
19
|
-
|
|
20
28
|
```bash
|
|
21
29
|
npm install chbim-time-axis-v2
|
|
22
|
-
# 或者
|
|
23
|
-
yarn add chbim-time-axis-v2
|
|
24
30
|
```
|
|
25
31
|
|
|
26
|
-
## 🚀
|
|
32
|
+
## 🚀 快速开始
|
|
27
33
|
|
|
28
|
-
### 1.
|
|
34
|
+
### 1. 引入样式
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
在你的入口文件(如 `main.ts`)中引入 CSS:
|
|
31
37
|
|
|
32
38
|
```typescript
|
|
33
|
-
|
|
34
|
-
import { createApp } from "vue";
|
|
35
|
-
import App from "./App.vue";
|
|
36
|
-
import CesiumGantt from "chbim-time-axis-v2";
|
|
37
|
-
import "chbim-time-axis-v2/dist/style.css"; // 引入样式文件
|
|
38
|
-
|
|
39
|
-
const app = createApp(App);
|
|
40
|
-
app.use(CesiumGantt);
|
|
41
|
-
app.mount("#app");
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
之后可以在任意组件中直接使用,无需再次导入:
|
|
45
|
-
|
|
46
|
-
```vue
|
|
47
|
-
<CesiumGantt :viewer="viewer" v-model:tasks="tasks" />
|
|
39
|
+
import "chbim-time-axis-v2/style.css";
|
|
48
40
|
```
|
|
49
41
|
|
|
50
|
-
### 2.
|
|
42
|
+
### 2. 基本使用
|
|
51
43
|
|
|
52
|
-
|
|
44
|
+
在 Vue 组件中使用:
|
|
53
45
|
|
|
54
46
|
```vue
|
|
55
47
|
<template>
|
|
56
|
-
<div class="
|
|
57
|
-
|
|
58
|
-
<div
|
|
59
|
-
|
|
60
|
-
<!-- 甘特图组件容器 -->
|
|
61
|
-
<div class="gantt-container">
|
|
48
|
+
<div class="layout">
|
|
49
|
+
<div ref="cesiumContainer" class="cesium-view"></div>
|
|
50
|
+
<div class="gantt-view">
|
|
62
51
|
<CesiumGantt
|
|
63
|
-
v-if="
|
|
64
|
-
:viewer="
|
|
52
|
+
v-if="isViewerReady"
|
|
53
|
+
:viewer="getViewer()"
|
|
65
54
|
v-model:tasks="tasks"
|
|
66
|
-
@task-enter="handleTaskEnter"
|
|
67
|
-
@task-leave="handleTaskLeave"
|
|
68
55
|
/>
|
|
69
56
|
</div>
|
|
70
57
|
</div>
|
|
@@ -72,133 +59,245 @@ app.mount("#app");
|
|
|
72
59
|
|
|
73
60
|
<script setup lang="ts">
|
|
74
61
|
import { ref, onMounted, onUnmounted } from "vue";
|
|
75
|
-
import {
|
|
76
|
-
CesiumGantt,
|
|
77
|
-
type GanttTask,
|
|
78
|
-
type GanttGroup,
|
|
79
|
-
} from "chbim-time-axis-v2";
|
|
80
|
-
import "chbim-time-axis-v2/dist/style.css"; // 务必引入样式
|
|
62
|
+
import { CesiumGantt, type GanttTask } from "chbim-time-axis-v2";
|
|
81
63
|
import * as Cesium from "cesium";
|
|
82
64
|
import dayjs from "dayjs";
|
|
83
65
|
|
|
84
|
-
// Cesium
|
|
85
|
-
|
|
86
|
-
|
|
66
|
+
// 建议将 Cesium 对象挂载到 window 上,避免 Vue 的响应式代理带来的性能开销
|
|
67
|
+
// @ts-ignore
|
|
68
|
+
window.Cesium = Cesium;
|
|
69
|
+
|
|
70
|
+
const cesiumContainer = ref<HTMLElement>();
|
|
71
|
+
const isViewerReady = ref(false);
|
|
72
|
+
|
|
73
|
+
const getViewer = () => {
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
return window.viewer;
|
|
76
|
+
};
|
|
87
77
|
|
|
88
|
-
|
|
89
|
-
const tasks = ref<(GanttTask | GanttGroup)[]>([
|
|
78
|
+
const tasks = ref<GanttTask[]>([
|
|
90
79
|
{
|
|
91
80
|
id: "1",
|
|
92
|
-
name: "
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
id: "1-1",
|
|
97
|
-
name: "任务 1",
|
|
98
|
-
startTime: dayjs().toISOString(),
|
|
99
|
-
endTime: dayjs().add(2, "day").toISOString(),
|
|
100
|
-
},
|
|
101
|
-
],
|
|
81
|
+
name: "基础工程",
|
|
82
|
+
startTime: dayjs().toISOString(),
|
|
83
|
+
endTime: dayjs().add(5, "day").toISOString(),
|
|
84
|
+
type: "task",
|
|
102
85
|
},
|
|
103
86
|
]);
|
|
104
87
|
|
|
105
|
-
// 初始化 Cesium
|
|
106
88
|
onMounted(() => {
|
|
107
89
|
if (cesiumContainer.value) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
90
|
+
// 初始化 Cesium Viewer 并挂载到 window
|
|
91
|
+
// @ts-ignore
|
|
92
|
+
window.viewer = new Cesium.Viewer(cesiumContainer.value, {
|
|
93
|
+
timeline: false, // 建议关闭原生 timeline,使用本组件代替
|
|
94
|
+
animation: false,
|
|
112
95
|
});
|
|
96
|
+
|
|
97
|
+
isViewerReady.value = true;
|
|
113
98
|
}
|
|
114
99
|
});
|
|
115
100
|
|
|
116
101
|
onUnmounted(() => {
|
|
117
|
-
|
|
118
|
-
|
|
102
|
+
// @ts-ignore
|
|
103
|
+
if (window.viewer) {
|
|
104
|
+
// @ts-ignore
|
|
105
|
+
window.viewer.destroy();
|
|
106
|
+
// @ts-ignore
|
|
107
|
+
window.viewer = undefined;
|
|
119
108
|
}
|
|
120
109
|
});
|
|
121
|
-
|
|
122
|
-
// 事件处理
|
|
123
|
-
const handleTaskEnter = (items: any[]) => {
|
|
124
|
-
console.log("进入任务时间段:", items);
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const handleTaskLeave = (items: any[]) => {
|
|
128
|
-
console.log("离开任务时间段:", items);
|
|
129
|
-
};
|
|
130
110
|
</script>
|
|
131
111
|
|
|
132
112
|
<style>
|
|
133
|
-
.
|
|
113
|
+
.layout {
|
|
134
114
|
display: flex;
|
|
135
115
|
flex-direction: column;
|
|
136
116
|
height: 100vh;
|
|
137
117
|
}
|
|
138
|
-
.cesium-
|
|
118
|
+
.cesium-view {
|
|
139
119
|
flex: 1;
|
|
140
|
-
width: 100%;
|
|
141
120
|
}
|
|
142
|
-
.gantt-
|
|
143
|
-
height: 300px;
|
|
144
|
-
background: #2b2b2b;
|
|
121
|
+
.gantt-view {
|
|
122
|
+
height: 300px;
|
|
145
123
|
}
|
|
146
124
|
</style>
|
|
147
125
|
```
|
|
148
126
|
|
|
149
|
-
##
|
|
150
|
-
|
|
151
|
-
| 属性名 | 类型 | 描述 |
|
|
152
|
-
| :------- | :---------------------------- | :------------------------------------------------------------- |
|
|
153
|
-
| `viewer` | `Cesium.Viewer` | **必传**。Cesium Viewer 实例,用于时间轴同步。 |
|
|
154
|
-
| `clock` | `Cesium.Clock` | (可选) 如果不使用 viewer.clock,可显式传入 Cesium Clock 实例。 |
|
|
155
|
-
| `tasks` | `(GanttTask \| GanttGroup)[]` | 任务列表数据。支持 `v-model:tasks` 双向绑定。 |
|
|
156
|
-
|
|
157
|
-
## 📡 事件系统 (Events)
|
|
127
|
+
## 📊 数据结构详解
|
|
158
128
|
|
|
159
|
-
|
|
160
|
-
| :------------- | :------------- | :---------------------------------------------------------------------------------------- |
|
|
161
|
-
| `update:tasks` | `tasks[]` | 当任务被更新(拖拽、编辑)时触发。 |
|
|
162
|
-
| `task-enter` | `items[]` | 当时间轴播放**进入**某个任务的时间范围时触发。Payload 包含 `{ task, block?, instant? }`。 |
|
|
163
|
-
| `task-leave` | `items[]` | 当时间轴播放**离开**某个任务的时间范围时触发。 |
|
|
164
|
-
| `add` | `parentId` | 点击组(group)上的新增按钮时触发(如果使用默认插槽)。 |
|
|
165
|
-
| `delete` | `taskId` | 点击任务上的删除按钮时触发(如果使用默认插槽)。 |
|
|
129
|
+
组件的核心是 `tasks` 数组。理解不同的任务类型对于发挥组件潜力至关重要。
|
|
166
130
|
|
|
167
|
-
|
|
131
|
+
### 1. 通用接口
|
|
168
132
|
|
|
169
|
-
|
|
133
|
+
所有任务类型都遵循的基本结构:
|
|
170
134
|
|
|
171
135
|
```typescript
|
|
172
136
|
interface GanttTask {
|
|
173
137
|
id: string;
|
|
174
138
|
name: string;
|
|
175
|
-
startTime: string; // ISO 8601
|
|
176
|
-
endTime: string; // ISO 8601
|
|
177
|
-
type?: "task" | "group" | "block" | "instant";
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
blocks?: {
|
|
182
|
-
startTime: string;
|
|
183
|
-
endTime: string;
|
|
184
|
-
name: string;
|
|
185
|
-
color?: string;
|
|
186
|
-
}[];
|
|
187
|
-
|
|
188
|
-
// 当 type 为 'instant' 时使用
|
|
189
|
-
instants?: {
|
|
190
|
-
id: string;
|
|
191
|
-
time: string;
|
|
192
|
-
name: string;
|
|
193
|
-
color?: string;
|
|
194
|
-
}[];
|
|
139
|
+
startTime: string; // ISO 8601 格式 (e.g., "2023-01-01T09:00:00Z")
|
|
140
|
+
endTime: string; // ISO 8601 格式
|
|
141
|
+
type?: "task" | "group" | "block" | "instant"; // 默认为 'task'
|
|
142
|
+
parentId?: string;
|
|
143
|
+
warning?: string; // 内部计算的警告信息
|
|
144
|
+
allowInstant?: boolean; // 是否允许在此任务行上右键添加瞬时点
|
|
195
145
|
}
|
|
196
146
|
```
|
|
197
147
|
|
|
198
|
-
|
|
148
|
+
### 2. 任务组 (Group)
|
|
149
|
+
|
|
150
|
+
用于组织子任务。时间范围通常由子任务决定,但也可以设置限制范围。
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
interface GanttGroup extends GanttTask {
|
|
154
|
+
type: "group";
|
|
155
|
+
children: GanttTask[]; // 子任务列表
|
|
156
|
+
collapsed?: boolean; // 是否折叠
|
|
157
|
+
|
|
158
|
+
// 如果设置,子任务超出此范围会显示警告
|
|
159
|
+
limitStartTime?: string;
|
|
160
|
+
limitEndTime?: string;
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 3. 块状任务 (Block)
|
|
165
|
+
|
|
166
|
+
适用于同一行展示多个不连续的时间段。
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
interface TaskBlock {
|
|
170
|
+
startTime: string;
|
|
171
|
+
endTime: string;
|
|
172
|
+
name?: string;
|
|
173
|
+
color?: string; // 支持 HEX, RGB 等 CSS 颜色值
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 在 GanttTask 中使用
|
|
177
|
+
interface BlockTask extends GanttTask {
|
|
178
|
+
type: "block";
|
|
179
|
+
blocks: TaskBlock[]; // 时间块数组
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 4. 瞬时任务 (Instant)
|
|
184
|
+
|
|
185
|
+
适用于展示时间点事件。
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
interface TaskInstant {
|
|
189
|
+
id: string;
|
|
190
|
+
time: string;
|
|
191
|
+
name?: string;
|
|
192
|
+
color?: string;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// 在 GanttTask 中使用
|
|
196
|
+
interface InstantTask extends GanttTask {
|
|
197
|
+
type: "instant";
|
|
198
|
+
instants: TaskInstant[]; // 瞬时点数组
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## ⚙️ 组件 API
|
|
203
|
+
|
|
204
|
+
### Props (属性)
|
|
205
|
+
|
|
206
|
+
| 属性名 | 类型 | 必填 | 默认值 | 描述 |
|
|
207
|
+
| :------- | :-------------- | :--- | :----- | :------------------------------------------------------------------------- |
|
|
208
|
+
| `tasks` | `GanttTask[]` | ✅ | `[]` | 任务数据源,支持 `v-model:tasks` 双向绑定。 |
|
|
209
|
+
| `viewer` | `Cesium.Viewer` | ❌ | - | Cesium Viewer 实例。传入后组件会自动绑定时钟。 |
|
|
210
|
+
| `clock` | `Cesium.Clock` | ❌ | - | 单独传入 Cesium Clock 实例。如果传入 `viewer`,则优先使用 `viewer.clock`。 |
|
|
211
|
+
|
|
212
|
+
### Events (事件)
|
|
213
|
+
|
|
214
|
+
| 事件名 | 参数 (Payload) | 描述 |
|
|
215
|
+
| :------------- | :------------------------------------ | :----------------------------------------------------------------------------- |
|
|
216
|
+
| `update:tasks` | `tasks: GanttTask[]` | 当任务数据发生变化(拖拽、调整大小、编辑属性)时触发。 |
|
|
217
|
+
| `taskUpdate` | `task: GanttTask` | 单个任务发生更新时触发。 |
|
|
218
|
+
| `task-enter` | `items: { task, block?, instant? }[]` | 当时间轴播放**进入**任务/块/瞬时点的时间范围时触发。这是二三维联动的核心事件。 |
|
|
219
|
+
| `task-leave` | `items: { task, block?, instant? }[]` | 当时间轴播放**离开**任务/块/瞬时点的时间范围时触发。 |
|
|
220
|
+
| `add` | `parentId: string` | 点击分组行的 "+" 按钮时触发。 |
|
|
221
|
+
| `delete` | `taskId: string` | 点击删除按钮时触发。 |
|
|
222
|
+
|
|
223
|
+
### Slots (插槽)
|
|
224
|
+
|
|
225
|
+
组件提供了丰富的插槽用于自定义 UI。
|
|
226
|
+
|
|
227
|
+
#### 1. `toolbar` (顶部工具栏)
|
|
228
|
+
|
|
229
|
+
自定义时间轴上方的控制区域。
|
|
230
|
+
|
|
231
|
+
```vue
|
|
232
|
+
<template #toolbar="{ togglePlay, isPlaying, handleResetView }">
|
|
233
|
+
<button @click="togglePlay">{{ isPlaying ? "暂停" : "开始" }}</button>
|
|
234
|
+
<button @click="handleResetView">重置视角</button>
|
|
235
|
+
<!-- 添加自定义按钮 -->
|
|
236
|
+
<button @click="myCustomAction">导出报表</button>
|
|
237
|
+
</template>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### 2. `taskOp` (任务列表操作列)
|
|
241
|
+
|
|
242
|
+
自定义任务列表右侧的操作按钮。
|
|
243
|
+
|
|
244
|
+
```vue
|
|
245
|
+
<template #taskOp="{ item }">
|
|
246
|
+
<button @click="editTask(item)">编辑</button>
|
|
247
|
+
<button @click="deleteTask(item.id)" style="color: red">删除</button>
|
|
248
|
+
</template>
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### 3. `barContextMenu` (右键菜单)
|
|
252
|
+
|
|
253
|
+
自定义在甘特图条上右键点击时出现的菜单。
|
|
254
|
+
|
|
255
|
+
```vue
|
|
256
|
+
<template #barContextMenu="{ task, block, instant, close }">
|
|
257
|
+
<div class="my-context-menu">
|
|
258
|
+
<div class="menu-header">
|
|
259
|
+
{{ block ? block.name : instant ? instant.name : task.name }}
|
|
260
|
+
</div>
|
|
261
|
+
<div
|
|
262
|
+
@click="
|
|
263
|
+
viewDetails(task);
|
|
264
|
+
close();
|
|
265
|
+
"
|
|
266
|
+
>
|
|
267
|
+
查看详情
|
|
268
|
+
</div>
|
|
269
|
+
<div
|
|
270
|
+
@click="
|
|
271
|
+
deleteItem(task);
|
|
272
|
+
close();
|
|
273
|
+
"
|
|
274
|
+
>
|
|
275
|
+
删除
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
</template>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## 🧩 Cesium 联动机制
|
|
282
|
+
|
|
283
|
+
组件通过 `Cesium.Clock.onTick` 事件与 Cesium 保持高频同步:
|
|
284
|
+
|
|
285
|
+
1. **时间同步**: 甘特图的 `currentTime` 会实时更新为 Cesium 的当前时间。
|
|
286
|
+
2. **播放控制**: 点击甘特图的播放按钮会控制 `viewer.clock.shouldAnimate`。
|
|
287
|
+
3. **视口跟随**: 当播放时间超出当前甘特图可视范围时,时间轴会自动滚动以保持当前时间可见。
|
|
288
|
+
|
|
289
|
+
## ❓ 常见问题
|
|
290
|
+
|
|
291
|
+
**Q: 如何自定义任务条的颜色?**
|
|
292
|
+
A:
|
|
293
|
+
|
|
294
|
+
- 对于 `block` 类型,在 `blocks` 数组中指定 `color` 属性。
|
|
295
|
+
- 对于 `instant` 类型,在 `instants` 数组中指定 `color` 属性。
|
|
296
|
+
- 对于普通 `task`,目前默认使用内置颜色(分组为蓝色,普通任务为青色),可通过 CSS 覆盖 `.taskBar` 样式或等待后续版本支持 `color` 字段。
|
|
297
|
+
|
|
298
|
+
**Q: 添加瞬时点(Instant)的功能在哪里?**
|
|
299
|
+
A: 在设置了 `allowInstant: true` 的任务行(非分组)对应的空白时间轴区域**右键点击**,会弹出内置菜单 "添加瞬时任务"。
|
|
300
|
+
|
|
301
|
+
## 📄 License
|
|
199
302
|
|
|
200
|
-
|
|
201
|
-
| :--------------- | :------------------------------------------- | :----------------------------------- |
|
|
202
|
-
| `toolbar` | `{ togglePlay, isPlaying, handleResetView }` | 自定义顶部工具栏区域的内容。 |
|
|
203
|
-
| `taskOp` | `{ item }` | 自定义任务列表每一行的操作按钮区域。 |
|
|
204
|
-
| `barContextMenu` | `{ task, block, instant, close }` | 自定义右键点击任务条时的上下文菜单。 |
|
|
303
|
+
MIT
|