chbim-time-axis-v2 0.0.8 → 0.0.9
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 +70 -20
- package/dist/chbim-time-axis-v2.umd.js +1 -1
- 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
|
|
@@ -11865,7 +11865,9 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
11865
11865
|
}
|
|
11866
11866
|
});
|
|
11867
11867
|
resizeObserver.observe(containerRef.value);
|
|
11868
|
-
containerRef.value.addEventListener("wheel", handleWheelNative, {
|
|
11868
|
+
containerRef.value.addEventListener("wheel", handleWheelNative, {
|
|
11869
|
+
passive: false
|
|
11870
|
+
});
|
|
11869
11871
|
}
|
|
11870
11872
|
});
|
|
11871
11873
|
onUnmounted(() => {
|
|
@@ -11940,7 +11942,9 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
11940
11942
|
return;
|
|
11941
11943
|
const deltaPixels = e.clientX - resizeStartX.value;
|
|
11942
11944
|
const deltaTime = deltaPixels * props.scale;
|
|
11943
|
-
const taskItem = flatTasks.value.find(
|
|
11945
|
+
const taskItem = flatTasks.value.find(
|
|
11946
|
+
(item) => item.task.id === resizeTaskId.value
|
|
11947
|
+
);
|
|
11944
11948
|
if (taskItem) {
|
|
11945
11949
|
let newStart = resizeInitialStart.value;
|
|
11946
11950
|
let newEnd = resizeInitialEnd.value;
|
|
@@ -12011,7 +12015,9 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
12011
12015
|
const incrementalPixels = currentClientX - dragLastX.value;
|
|
12012
12016
|
const incrementalTime = incrementalPixels * props.scale;
|
|
12013
12017
|
dragLastX.value = currentClientX;
|
|
12014
|
-
const taskItem = flatTasks.value.find(
|
|
12018
|
+
const taskItem = flatTasks.value.find(
|
|
12019
|
+
(item) => item.task.id === dragTaskId.value
|
|
12020
|
+
);
|
|
12015
12021
|
if (taskItem) {
|
|
12016
12022
|
if (taskItem.task.type === "group") {
|
|
12017
12023
|
if (incrementalTime !== 0) {
|
|
@@ -12208,7 +12214,9 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
12208
12214
|
document.removeEventListener("mousemove", handleTimeDragMove);
|
|
12209
12215
|
document.removeEventListener("mouseup", handleTimeDragEnd);
|
|
12210
12216
|
};
|
|
12211
|
-
const totalWidth = computed(
|
|
12217
|
+
const totalWidth = computed(
|
|
12218
|
+
() => (props.viewEndTime - props.viewStartTime) / props.scale
|
|
12219
|
+
);
|
|
12212
12220
|
const getPosition = (timeIso) => {
|
|
12213
12221
|
const t = dayjs(timeIso).valueOf();
|
|
12214
12222
|
return (t - props.viewStartTime) / props.scale;
|
|
@@ -12252,7 +12260,10 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
12252
12260
|
const tasksEndX = (maxTaskEnd - props.viewStartTime) / props.scale;
|
|
12253
12261
|
const currentScrollEnd = scrollLeft.value + containerWidth.value;
|
|
12254
12262
|
const neededWidthForBuffer = currentScrollEnd + containerWidth.value * 0.6;
|
|
12255
|
-
const nominalWidth = Math.max(
|
|
12263
|
+
const nominalWidth = Math.max(
|
|
12264
|
+
Math.min(totalWidth.value, 3e7),
|
|
12265
|
+
containerWidth.value
|
|
12266
|
+
);
|
|
12256
12267
|
const widthWithTasks = Math.max(nominalWidth, tasksEndX);
|
|
12257
12268
|
return Math.max(widthWithTasks, neededWidthForBuffer);
|
|
12258
12269
|
});
|
|
@@ -12436,7 +12447,9 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
12436
12447
|
}
|
|
12437
12448
|
const endTimeVal = visibleEndTime + bufferTime;
|
|
12438
12449
|
const unit = bestStep.unit;
|
|
12439
|
-
const useMathLoop = ["second", "minute", "hour", "day"].includes(
|
|
12450
|
+
const useMathLoop = ["second", "minute", "hour", "day"].includes(
|
|
12451
|
+
bestStep.unit
|
|
12452
|
+
);
|
|
12440
12453
|
let currentVal = t.valueOf();
|
|
12441
12454
|
const stepDuration = getDuration(bestStep.step, bestStep.unit);
|
|
12442
12455
|
while (currentVal < endTimeVal) {
|
|
@@ -12577,7 +12590,14 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
12577
12590
|
style: normalizeStyle({ top: bar.top + "px", height: "30px" }),
|
|
12578
12591
|
onMouseenter: ($event) => _ctx.$emit("row-mouseenter", bar.id),
|
|
12579
12592
|
onMouseleave: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("row-mouseleave")),
|
|
12580
|
-
onContextmenu: withModifiers(
|
|
12593
|
+
onContextmenu: withModifiers(
|
|
12594
|
+
(e) => _ctx.$emit("row-contextmenu", {
|
|
12595
|
+
event: e,
|
|
12596
|
+
task: bar.originalTask,
|
|
12597
|
+
time: getTimeFromEvent(e)
|
|
12598
|
+
}),
|
|
12599
|
+
["stop", "prevent"]
|
|
12600
|
+
)
|
|
12581
12601
|
}, [
|
|
12582
12602
|
bar.limitLeft !== void 0 ? (openBlock(), createElementBlock("div", {
|
|
12583
12603
|
key: 0,
|
|
@@ -12596,18 +12616,27 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
12596
12616
|
backgroundColor: bar.color
|
|
12597
12617
|
}),
|
|
12598
12618
|
onMousedown: (e) => handleDragStart(e, bar.originalTask),
|
|
12599
|
-
onContextmenu: withModifiers(
|
|
12619
|
+
onContextmenu: withModifiers(
|
|
12620
|
+
(e) => _ctx.$emit("bar-contextmenu", { event: e, task: bar.originalTask }),
|
|
12621
|
+
["stop", "prevent"]
|
|
12622
|
+
)
|
|
12600
12623
|
}, [
|
|
12601
12624
|
bar.originalTask.type !== "group" ? (openBlock(), createElementBlock("div", {
|
|
12602
12625
|
key: 0,
|
|
12603
12626
|
class: "resize-handle left",
|
|
12604
|
-
onMousedown: withModifiers(
|
|
12627
|
+
onMousedown: withModifiers(
|
|
12628
|
+
(e) => handleResizeStart(e, bar.originalTask, "left"),
|
|
12629
|
+
["stop"]
|
|
12630
|
+
)
|
|
12605
12631
|
}, null, 40, _hoisted_6$1)) : createCommentVNode("", true),
|
|
12606
12632
|
bar.width > 50 ? (openBlock(), createElementBlock("span", _hoisted_7$1, toDisplayString(bar.name), 1)) : createCommentVNode("", true),
|
|
12607
12633
|
bar.originalTask.type !== "group" ? (openBlock(), createElementBlock("div", {
|
|
12608
12634
|
key: 2,
|
|
12609
12635
|
class: "resize-handle right",
|
|
12610
|
-
onMousedown: withModifiers(
|
|
12636
|
+
onMousedown: withModifiers(
|
|
12637
|
+
(e) => handleResizeStart(e, bar.originalTask, "right"),
|
|
12638
|
+
["stop"]
|
|
12639
|
+
)
|
|
12611
12640
|
}, null, 40, _hoisted_8$1)) : createCommentVNode("", true)
|
|
12612
12641
|
], 44, _hoisted_5$1)) : createCommentVNode("", true),
|
|
12613
12642
|
bar.originalTask.type === "block" && bar.blocks ? (openBlock(true), createElementBlock(Fragment, { key: 2 }, renderList(bar.blocks, (blk, idx) => {
|
|
@@ -12622,16 +12651,29 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
12622
12651
|
}),
|
|
12623
12652
|
title: blk.name,
|
|
12624
12653
|
onMousedown: (e) => handleBlockDragStart(e, bar.originalTask, idx),
|
|
12625
|
-
onContextmenu: withModifiers(
|
|
12654
|
+
onContextmenu: withModifiers(
|
|
12655
|
+
(e) => _ctx.$emit("bar-contextmenu", {
|
|
12656
|
+
event: e,
|
|
12657
|
+
task: bar.originalTask,
|
|
12658
|
+
block: blk
|
|
12659
|
+
}),
|
|
12660
|
+
["stop", "prevent"]
|
|
12661
|
+
)
|
|
12626
12662
|
}, [
|
|
12627
12663
|
createElementVNode("div", {
|
|
12628
12664
|
class: "resize-handle left",
|
|
12629
|
-
onMousedown: withModifiers(
|
|
12665
|
+
onMousedown: withModifiers(
|
|
12666
|
+
(e) => handleBlockResizeStart(e, bar.originalTask, idx, "left"),
|
|
12667
|
+
["stop"]
|
|
12668
|
+
)
|
|
12630
12669
|
}, null, 40, _hoisted_10$1),
|
|
12631
12670
|
blk.width > 50 ? (openBlock(), createElementBlock("span", _hoisted_11$1, toDisplayString(blk.name), 1)) : createCommentVNode("", true),
|
|
12632
12671
|
createElementVNode("div", {
|
|
12633
12672
|
class: "resize-handle right",
|
|
12634
|
-
onMousedown: withModifiers(
|
|
12673
|
+
onMousedown: withModifiers(
|
|
12674
|
+
(e) => handleBlockResizeStart(e, bar.originalTask, idx, "right"),
|
|
12675
|
+
["stop"]
|
|
12676
|
+
)
|
|
12635
12677
|
}, null, 40, _hoisted_12$1)
|
|
12636
12678
|
], 44, _hoisted_9$1);
|
|
12637
12679
|
}), 128)) : createCommentVNode("", true),
|
|
@@ -12641,7 +12683,6 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
12641
12683
|
class: "instantTaskPoint draggable",
|
|
12642
12684
|
style: normalizeStyle({
|
|
12643
12685
|
left: inst.left - 10 + "px",
|
|
12644
|
-
/* 居中圆圈 */
|
|
12645
12686
|
width: "18px",
|
|
12646
12687
|
height: "18px",
|
|
12647
12688
|
backgroundColor: inst.color || "#ffffff",
|
|
@@ -12650,9 +12691,18 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
12650
12691
|
position: "absolute",
|
|
12651
12692
|
cursor: "pointer"
|
|
12652
12693
|
}),
|
|
12653
|
-
title: `${inst.name ? inst.name + "\n" : ""}${unref(dayjs)(
|
|
12694
|
+
title: `${inst.name ? inst.name + "\n" : ""}${unref(dayjs)(
|
|
12695
|
+
inst.time
|
|
12696
|
+
).format("YYYY-MM-DD")}`,
|
|
12654
12697
|
onMousedown: (e) => handleInstantDragStart(e, bar.originalTask, idx),
|
|
12655
|
-
onContextmenu: withModifiers(
|
|
12698
|
+
onContextmenu: withModifiers(
|
|
12699
|
+
(e) => _ctx.$emit("bar-contextmenu", {
|
|
12700
|
+
event: e,
|
|
12701
|
+
task: bar.originalTask,
|
|
12702
|
+
instant: inst
|
|
12703
|
+
}),
|
|
12704
|
+
["stop", "prevent"]
|
|
12705
|
+
)
|
|
12656
12706
|
}, null, 44, _hoisted_13$1);
|
|
12657
12707
|
}), 128)) : createCommentVNode("", true)
|
|
12658
12708
|
], 46, _hoisted_4$1);
|
|
@@ -12670,8 +12720,8 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
12670
12720
|
};
|
|
12671
12721
|
}
|
|
12672
12722
|
});
|
|
12673
|
-
const
|
|
12674
|
-
const TimelineChart = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-
|
|
12723
|
+
const TimelineChart_vue_vue_type_style_index_0_scoped_1692bade_lang = "";
|
|
12724
|
+
const TimelineChart = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-1692bade"]]);
|
|
12675
12725
|
const _hoisted_1 = { class: "toolbar" };
|
|
12676
12726
|
const _hoisted_2 = { style: { "flex": "1", "display": "flex", "align-items": "center", "height": "100%" } };
|
|
12677
12727
|
const _hoisted_3 = { class: "left-controls" };
|
|
@@ -13517,8 +13567,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
13517
13567
|
};
|
|
13518
13568
|
}
|
|
13519
13569
|
});
|
|
13520
|
-
const
|
|
13521
|
-
const CesiumGantt = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
13570
|
+
const CesiumGantt_vue_vue_type_style_index_0_scoped_e6696098_lang = "";
|
|
13571
|
+
const CesiumGantt = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-e6696098"]]);
|
|
13522
13572
|
CesiumGantt.install = (app) => {
|
|
13523
13573
|
app.component("CesiumGantt", CesiumGantt);
|
|
13524
13574
|
};
|