jordium-gantt-vue3 1.6.1 → 1.7.0

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 CHANGED
@@ -29,6 +29,12 @@
29
29
 
30
30
  <p align="center">现代化的 Vue 3 甘特图组件库,为项目管理和任务调度提供完整解决方案</p>
31
31
 
32
+ <p align="center">
33
+ <a href="https://gitee.com/activity/2025opensource?ident=IOUNZP" target="_blank">
34
+ <img src="https://img.shields.io/badge/🥇_Gitee_2025年度开源项目评选-👉_感谢您的参与投票-gold?style=for-the-badge&labelColor=C71D23&logoColor=white" alt="Gitee 2025年度开源项目评选" height="40">
35
+ </a>
36
+ </p>
37
+
32
38
  <p align="center">
33
39
  <a href="https://nelson820125.github.io/jordium-gantt-vue3/">
34
40
  <strong>📱 在线演示</strong>
@@ -189,6 +195,8 @@ npm run dev
189
195
  | `autoSortByStartDate` | `boolean` | `false` | 是否根据开始时间自动排序任务 |
190
196
  | `allowDragAndResize` | `boolean` | `true` | 是否允许拖拽和调整任务/里程碑大小 |
191
197
  | `enableTaskRowMove` | `boolean` | `false` | 是否允许拖拽和摆放TaskRow |
198
+ | `enableTaskListContextMenu` | `boolean` | `true` | 是否启用 TaskList(TaskRow)右键菜单功能。为 `true` 时:未声明 `task-list-context-menu` 插槽则使用内置菜单,声明了插槽则使用自定义菜单;为 `false` 时右键菜单完全禁用 |
199
+ | `enableTaskBarContextMenu` | `boolean` | `true` | 是否启用 TaskBar 右键菜单功能。为 `true` 时:未声明 `task-bar-context-menu` 插槽则使用内置菜单,声明了插槽则使用自定义菜单;为 `false` 时右键菜单完全禁用 |
192
200
  | `assigneeOptions` | `Array<{ key?: string \| number; value: string \| number; label: string }>` | `[]` | 任务编辑抽屉中负责人下拉菜单的选项列表 |
193
201
 
194
202
  #### TaskListColumn 属性
@@ -224,6 +232,110 @@ npm run dev
224
232
  > - 列的显示顺序由 `TaskListColumn` 组件的声明顺序决定
225
233
  > - 关于列内容自定义和插槽的详细使用方法,请参考 [插槽 (Slots)](#插槽-slots) 章节
226
234
 
235
+ #### TaskListContextMenu 属性
236
+
237
+ `TaskListContextMenu` 组件用于声明式定义 TaskList(TaskRow)的右键菜单。当 `enableTaskListContextMenu` 为 `true` 时生效。
238
+
239
+ | 属性名 | 类型 | 默认值 | 说明 |
240
+ | ---------- | ---------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------- |
241
+ | `taskType` | `string \| string[]` | `undefined` | 指定哪些任务类型显示此右键菜单。不设置时遵循现有逻辑(所有任务都显示),设置后仅对指定类型任务显示。支持单个类型(如 `'task'`)或多个类型(如 `['task', 'milestone']`) |
242
+
243
+ **使用示例**:
244
+
245
+ ```vue
246
+ <GanttChart
247
+ :tasks="tasks"
248
+ :enable-task-list-context-menu="true"
249
+ >
250
+ <!-- 默认行为:所有任务都显示此右键菜单 -->
251
+ <TaskListContextMenu>
252
+ <template #default="scope">
253
+ <div class="custom-menu">
254
+ <div class="menu-item" @click="editTask(scope.row)">编辑</div>
255
+ <div class="menu-item" @click="deleteTask(scope.row)">删除</div>
256
+ </div>
257
+ </template>
258
+ </TaskListContextMenu>
259
+
260
+ <!-- 仅对 type='task' 的任务显示此菜单 -->
261
+ <TaskListContextMenu task-type="task">
262
+ <template #default="scope">
263
+ <div class="custom-menu">
264
+ <div class="menu-item">任务专属菜单</div>
265
+ </div>
266
+ </template>
267
+ </TaskListContextMenu>
268
+
269
+ <!-- 对多种类型显示菜单 -->
270
+ <TaskListContextMenu :task-type="['task', 'milestone']">
271
+ <template #default="scope">
272
+ <div class="custom-menu">
273
+ <div class="menu-item">任务和里程碑菜单</div>
274
+ </div>
275
+ </template>
276
+ </TaskListContextMenu>
277
+ </GanttChart>
278
+ ```
279
+
280
+ > **💡 提示**:
281
+ > - `TaskListContextMenu` 组件本身不渲染任何内容,仅用于声明菜单配置
282
+ > - 必须在 `GanttChart` 组件内部使用,且设置 `enable-task-list-context-menu="true"`
283
+ > - 菜单定位和显示状态由内部自动管理,用户只需关心菜单内容的 HTML 结构
284
+ > - 菜单会在点击外部或滚动时自动关闭
285
+ > - 关于插槽的详细使用方法,请参考 [插槽 (Slots)](#插槽-slots) 章节
286
+
287
+ #### TaskBarContextMenu 属性
288
+
289
+ `TaskBarContextMenu` 组件用于声明式定义 TaskBar(时间线任务条)的右键菜单。当 `enableTaskBarContextMenu` 为 `true` 时生效。
290
+
291
+ | 属性名 | 类型 | 默认值 | 说明 |
292
+ | ---------- | ---------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------- |
293
+ | `taskType` | `string \| string[]` | `undefined` | 指定哪些任务类型显示此右键菜单。不设置时遵循现有逻辑(所有任务都显示),设置后仅对指定类型任务显示。支持单个类型(如 `'task'`)或多个类型(如 `['task', 'milestone']`) |
294
+
295
+ **使用示例**:
296
+
297
+ ```vue
298
+ <GanttChart
299
+ :tasks="tasks"
300
+ :enable-task-bar-context-menu="true"
301
+ >
302
+ <!-- 默认行为:所有任务都显示此右键菜单 -->
303
+ <TaskBarContextMenu>
304
+ <template #default="scope">
305
+ <div class="custom-menu">
306
+ <div class="menu-item" @click="extendTask(scope.row)">延长任务</div>
307
+ <div class="menu-item" @click="moveTask(scope.row)">移动任务</div>
308
+ </div>
309
+ </template>
310
+ </TaskBarContextMenu>
311
+
312
+ <!-- 仅对 type='task' 的任务显示此菜单 -->
313
+ <TaskBarContextMenu task-type="task">
314
+ <template #default="scope">
315
+ <div class="custom-menu">
316
+ <div class="menu-item">任务条专属菜单</div>
317
+ </div>
318
+ </template>
319
+ </TaskBarContextMenu>
320
+
321
+ <!-- 对多种类型显示菜单 -->
322
+ <TaskBarContextMenu :task-type="['task', 'story']">
323
+ <template #default="scope">
324
+ <div class="custom-menu">
325
+ <div class="menu-item">任务和故事菜单</div>
326
+ </div>
327
+ </template>
328
+ </TaskBarContextMenu>
329
+ </GanttChart>
330
+ ```
331
+
332
+ > **💡 提示**:
333
+ > - `TaskBarContextMenu` 组件本身不渲染任何内容,仅用于声明菜单配置
334
+ > - 必须在 `GanttChart` 组件内部使用,且设置 `enable-task-bar-context-menu="true"`
335
+ > - 菜单定位和显示状态由内部自动管理,用户只需关心菜单内容的 HTML 结构
336
+ > - 菜单会在点击外部或滚动时自动关闭
337
+ > - 关于插槽的详细使用方法,请参考 [插槽 (Slots)](#插槽-slots) 章节
338
+
227
339
  #### 配置对象属性
228
340
 
229
341
  完整的配置对象说明请参考 [⚙️ 配置与扩展](#⚙️-配置与扩展) 章节。
@@ -2011,7 +2123,7 @@ const handleLanguageChange = (lang: 'zh-CN' | 'en-US') => {
2011
2123
 
2012
2124
  #### 自定义翻译
2013
2125
 
2014
- 通过 `localeMessages` 属性覆盖或扩展默认翻译:
2126
+ 通过 `localeMessages` 属性传入自定义多语言文本,组件内部会自动合并到默认翻译中:
2015
2127
 
2016
2128
  ```vue
2017
2129
  <template>
@@ -2022,7 +2134,7 @@ const handleLanguageChange = (lang: 'zh-CN' | 'en-US') => {
2022
2134
  const customMessages = {
2023
2135
  "zh-CN": {
2024
2136
  // 任务列表相关
2025
- name: '任务名称(自定义)',
2137
+ taskName: '任务名称(自定义)',
2026
2138
  startDate: '开始日期',
2027
2139
  endDate: '结束日期',
2028
2140
  duration: '工期',
@@ -2030,55 +2142,183 @@ const customMessages = {
2030
2142
  predecessor: '前置任务',
2031
2143
  assignee: '负责人',
2032
2144
  estimatedHours: '预估工时',
2033
- actualHours: '实际工时'
2034
-
2035
- // 工具栏相关
2036
- addTask: '新建任务',
2037
- addMilestone: '新建里程碑',
2038
- today: '今天',
2039
- exportCsv: '导出 CSV',
2040
- exportPdf: '导出 PDF',
2041
- fullscreen: '全屏',
2042
- exitFullscreen: '退出全屏',
2043
- language: '语言',
2044
- theme: '主题',
2045
- expandAll: '全部展开',
2046
- collapseAll: '全部折叠'
2047
-
2048
- // 内置任务编辑器相关
2049
- title: '任务详情',
2050
- titleEdit: '编辑任务',
2051
- titleNew: '新建任务',
2052
- name: '任务名称',
2053
- startDate: '开始日期',
2054
- endDate: '结束日期',
2055
- assignee: '负责人',
2056
- predecessor: '前置任务',
2057
- description: '描述',
2058
- estimatedHours: '预估工时',
2059
2145
  actualHours: '实际工时',
2060
- progress: '进度',
2061
- save: '保存',
2062
- cancel: '取消',
2063
- delete: '删除'
2064
-
2065
- // 其他文本
2066
- days: '',
2067
- hours: '小时',
2068
- overtime: '超时',
2069
- overdue: '逾期',
2070
- // ... 更多自定义翻译
2146
+
2147
+ // 自定义字段(支持嵌套结构)
2148
+ department: '部门',
2149
+ status: '状态',
2150
+ gantt: {
2151
+ planEndDate: '计划结束时间',
2152
+ planStartDate: '计划开始时间'
2153
+ }
2071
2154
  },
2072
- "en-US": {......}
2155
+ "en-US": {
2156
+ department: 'Department',
2157
+ status: 'Status',
2158
+ gantt: {
2159
+ planEndDate: 'Plan End Date',
2160
+ planStartDate: 'Plan Start Date'
2161
+ }
2162
+ }
2073
2163
  }
2074
2164
  </script>
2075
2165
  ```
2076
2166
 
2077
2167
  > **💡 提示**:
2078
2168
  >
2079
- > - `localeMessages` 采用**深度合并**策略,只需传递需要覆盖的字段即可
2080
- > - 支持嵌套对象,如 `taskList.name`、`toolbar.addTask`
2081
- > - 完整的翻译键请参考组件内置的 `messages['zh-CN']` 对象
2169
+ > - `localeMessages` 采用**深度合并**策略,只需传递需要覆盖或新增的字段即可
2170
+ > - 支持嵌套对象结构,如 `gantt.planEndDate`
2171
+ > - 完整的内置翻译键请参考组件源码中的 `useI18n.ts`
2172
+
2173
+ ##### 在自定义插槽中使用翻译
2174
+
2175
+ 组件导出了 `useI18n` composable,可在自定义插槽中访问翻译文本,支持两种访问方式:
2176
+
2177
+ **方式一:引用式访问(`t.field`)**
2178
+
2179
+ 通过响应式对象直接访问翻译文本,语法简洁,适合模板中使用:
2180
+
2181
+ ```vue
2182
+ <script setup>
2183
+ import { GanttChart, TaskListColumn, useI18n } from 'jordium-gantt-vue3'
2184
+
2185
+ const { t } = useI18n()
2186
+
2187
+ const customMessages = {
2188
+ 'zh-CN': {
2189
+ department: '部门'
2190
+ }
2191
+ }
2192
+ </script>
2193
+
2194
+ <template>
2195
+ <GanttChart :tasks="tasks" :locale-messages="customMessages" />
2196
+
2197
+ <!-- 引用式:直接通过 t 对象访问 -->
2198
+ <TaskListColumn prop="startDate" label="开始时间" width="250">
2199
+ <template #header>
2200
+ <strong style="color: #1890ff;">{{ t.department }}</strong>
2201
+ </template>
2202
+ </TaskListColumn>
2203
+ </template>
2204
+ ```
2205
+
2206
+ **方式二:函数式访问(`getTranslation()`)**
2207
+
2208
+ 支持嵌套键和默认值,适合访问深层结构或动态键:
2209
+
2210
+ ```vue
2211
+ <script setup>
2212
+ import { GanttChart, TaskListColumn, useI18n } from 'jordium-gantt-vue3'
2213
+
2214
+ const { getTranslation } = useI18n()
2215
+
2216
+ const customMessages = {
2217
+ 'zh-CN': {
2218
+ gantt: {
2219
+ planEndDate: '计划结束时间'
2220
+ }
2221
+ }
2222
+ }
2223
+ </script>
2224
+
2225
+ <template>
2226
+ <GanttChart :tasks="tasks" :locale-messages="customMessages" />
2227
+
2228
+ <!-- 函数式:支持嵌套键和默认值 -->
2229
+ <TaskListColumn prop="endDate" :label="getTranslation('gantt.planEndDate')" width="250" />
2230
+ </template>
2231
+ ```
2232
+
2233
+ **完整示例(结合语言切换):**
2234
+
2235
+ ```vue
2236
+ <script setup>
2237
+ import { ref } from 'vue'
2238
+ import { GanttChart, TaskListColumn, useI18n } from 'jordium-gantt-vue3'
2239
+
2240
+ // 自定义多语言配置
2241
+ const customMessages = {
2242
+ 'zh-CN': {
2243
+ department: '部门',
2244
+ gantt: {
2245
+ planEndDate: '计划结束时间'
2246
+ }
2247
+ },
2248
+ 'en-US': {
2249
+ department: 'Department',
2250
+ gantt: {
2251
+ planEndDate: 'Plan End Date'
2252
+ }
2253
+ }
2254
+ }
2255
+
2256
+ // 使用 useI18n 访问翻译
2257
+ const { t, getTranslation, locale, setLocale } = useI18n()
2258
+ const tasks = ref([...])
2259
+
2260
+ // 语言切换
2261
+ const switchLanguage = () => {
2262
+ setLocale(locale.value === 'zh-CN' ? 'en-US' : 'zh-CN')
2263
+ }
2264
+ </script>
2265
+
2266
+ <template>
2267
+ <button @click="switchLanguage">切换语言</button>
2268
+
2269
+ <GanttChart :tasks="tasks" :locale-messages="customMessages" />
2270
+
2271
+ <!-- 引用式:直接通过 t 对象访问 -->
2272
+ <TaskListColumn prop="startDate" label="开始时间" width="250">
2273
+ <template #header>
2274
+ <strong style="color: #1890ff;">{{ t.department }}</strong>
2275
+ </template>
2276
+ </TaskListColumn>
2277
+
2278
+ <!-- 函数式:支持嵌套键和默认值 -->
2279
+ <TaskListColumn prop="endDate" :label="getTranslation('gantt.planEndDate')" width="250" />
2280
+ </template>
2281
+ ```
2282
+
2283
+ **`useI18n` API 说明:**
2284
+
2285
+ | 导出项 | 类型 | 说明 |
2286
+ |--------|------|------|
2287
+ | `t` | `Ref<object>` | 响应式翻译对象,通过 `t.key` 或 `t.nested.key` 访问翻译文本 |
2288
+ | `getTranslation(key, defaultValue?)` | `Function` | 函数式访问翻译文本<br>• `key`: 翻译键,支持嵌套路径(如 `'gantt.planEndDate'`)<br>• `defaultValue`: 可选,找不到翻译时返回的默认值<br>• 返回:翻译文本、默认值或 key 本身 |
2289
+ | `formatTranslation(key, params)` | `Function` | 格式化带参数的翻译文本<br>• `key`: 翻译键<br>• `params`: 参数对象,如 `{ name: '任务1' }`<br>• 返回:替换占位符后的文本(如 `'任务{name}'` → `'任务任务1'`) |
2290
+ | `locale` | `Ref<string>` | 当前语言(`'zh-CN'` 或 `'en-US'`) |
2291
+ | `setLocale(locale)` | `Function` | 切换语言,会自动更新所有使用 `useI18n` 的组件 |
2292
+ | `formatYearMonth(year, month)` | `Function` | 格式化年月显示<br>• 中文:`formatYearMonth(2024, 3)` → `'2024年03月'`<br>• 英文:`formatYearMonth(2024, 3)` → `'2024/03'` |
2293
+ | `formatMonth(month)` | `Function` | 格式化月份显示<br>• 中文:`formatMonth(3)` → `'3月'`<br>• 英文:`formatMonth(3)` → `'03'` |
2294
+
2295
+ **使用示例:**
2296
+
2297
+ ```vue
2298
+ <script setup>
2299
+ import { useI18n } from 'jordium-gantt-vue3'
2300
+
2301
+ const { t, getTranslation, formatTranslation, formatYearMonth, formatMonth } = useI18n()
2302
+
2303
+ // 1. 基础访问
2304
+ const text1 = t.taskName // '任务名称'
2305
+ const text2 = getTranslation('gantt.planEndDate', '计划结束') // '计划结束时间' 或默认值
2306
+
2307
+ // 2. 带参数的翻译
2308
+ const message = formatTranslation('taskNotFound', { id: '123' }) // '未找到要更新的任务,ID:123'
2309
+
2310
+ // 3. 日期格式化
2311
+ const yearMonth = formatYearMonth(2024, 3) // '2024年03月' (zh-CN) 或 '2024/03' (en-US)
2312
+ const month = formatMonth(3) // '3月' (zh-CN) 或 '03' (en-US)
2313
+ </script>
2314
+ ```
2315
+
2316
+ > **💡 使用提示**:
2317
+ >
2318
+ > - **引用式** (`t.key`):语法简洁,适合模板中直接使用
2319
+ > - **函数式** (`getTranslation('nested.key', 'default')`):支持嵌套键和默认值,适合访问深层结构
2320
+ > - 通过 `localeMessages` 属性传入自定义翻译,再通过 `useI18n` 访问并翻译
2321
+ > - 语言切换通过 `setLocale()` 实现,所有组件会自动响应更新
2082
2322
 
2083
2323
  ### 自定义扩展
2084
2324
 
@@ -2248,6 +2488,208 @@ const props = defineProps<Props>()
2248
2488
  > - TaskRow 和 TaskBar 的可用空间不同,需要适配布局
2249
2489
  > - 避免在插槽内容中使用过于复杂的组件,可能影响性能
2250
2490
 
2491
+ ##### TaskListContextMenu 插槽
2492
+
2493
+ 用于自定义 TaskRow(任务列表行)的右键菜单内容。
2494
+
2495
+ **菜单显示逻辑:**
2496
+ - 当 `enableTaskListContextMenu=true` 且**未声明** TaskListContextMenu 组件时 → 使用**系统内置**的右键菜单
2497
+ - 当 `enableTaskListContextMenu=true` 且**声明了** TaskListContextMenu 组件时 → 使用**自定义**的右键菜单
2498
+ - 当 `enableTaskListContextMenu=false` 时 → 右键菜单**完全禁用**(无论是否声明组件)
2499
+
2500
+ **插槽列表:**
2501
+
2502
+ | 插槽名 | 参数 | 说明 |
2503
+ | --------- | --------------------------------- | ---------------------------------------------------------------------------------------------- |
2504
+ | `default` | `scope: { row: Task, $index: number }` | 自定义TaskRow的右键菜单。通过 `scope.row` 访问当前任务对象,通过 `scope.$index` 访问任务索引。 |
2505
+
2506
+ **使用示例:**
2507
+
2508
+ ```vue
2509
+ <template>
2510
+ <GanttChart
2511
+ :tasks="tasks"
2512
+ :enable-task-list-context-menu="true"
2513
+ >
2514
+ <TaskListContextMenu>
2515
+ <template #default="scope">
2516
+ <div class="custom-menu">
2517
+ <div class="custom-item" @click="handleEdit('extend', scope.row)">
2518
+ ✏️ 编辑任务
2519
+ </div>
2520
+ <div class="custom-item" @click="handleDelete('move', scope.row)">
2521
+ 🗑️ 删除任务
2522
+ </div>
2523
+ <div class="custom-divider"></div>
2524
+ <div class="custom-item" @click="handleDuplicate('copy', scope.row)">
2525
+ 📄 复制任务
2526
+ </div>
2527
+ </div>
2528
+ </template>
2529
+ </TaskListContextMenu>
2530
+ </GanttChart>
2531
+ </template>
2532
+
2533
+ <script setup lang="ts">
2534
+ import { ref } from 'vue'
2535
+ import { GanttChart, TaskListContextMenu } from 'jordium-gantt-vue3'
2536
+ import 'jordium-gantt-vue3/dist/assets/jordium-gantt-vue3.css'
2537
+ import type { Task } from 'jordium-gantt-vue3'
2538
+
2539
+ const tasks = ref<Task[]>([])
2540
+
2541
+ const handleEdit = (task: Task) => {
2542
+ console.log('编辑任务:', task)
2543
+ }
2544
+
2545
+ const handleDelete = (task: Task) => {
2546
+ console.log('删除任务:', task)
2547
+ }
2548
+
2549
+ const handleDuplicate = (task: Task) => {
2550
+ console.log('复制任务:', task)
2551
+ }
2552
+ </script>
2553
+
2554
+ <style scoped>
2555
+ .custom-context-menu {
2556
+ position: fixed;
2557
+ background: white;
2558
+ border: 1px solid #e0e0e0;
2559
+ border-radius: 4px;
2560
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
2561
+ z-index: 9999;
2562
+ min-width: 120px;
2563
+ }
2564
+
2565
+ .menu-item {
2566
+ padding: 8px 16px;
2567
+ cursor: pointer;
2568
+ transition: background-color 0.2s;
2569
+ }
2570
+
2571
+ .menu-item:hover {
2572
+ background-color: #f5f5f5;
2573
+ }
2574
+
2575
+ .menu-divider {
2576
+ height: 1px;
2577
+ background-color: #e0e0e0;
2578
+ margin: 4px 0;
2579
+ }
2580
+ </style>
2581
+ ```
2582
+
2583
+ ##### TaskBarContextMenu 插槽
2584
+
2585
+ 用于自定义 TaskBar(时间轴任务条)的右键菜单内容。
2586
+
2587
+ **菜单显示逻辑:**
2588
+ - 当 `enableTaskBarContextMenu=true` 且**未声明** TaskBarContextMenu 组件时 → 使用**系统内置**的右键菜单
2589
+ - 当 `enableTaskBarContextMenu=true` 且**声明了** TaskBarContextMenu 组件时 → 使用**自定义**的右键菜单
2590
+ - 当 `enableTaskBarContextMenu=false` 时 → 右键菜单**完全禁用**(无论是否声明组件)
2591
+
2592
+ **插槽列表:**
2593
+
2594
+ | 插槽名 | 参数 | 说明 |
2595
+ | --------- | --------------------------------- | ---------------------------------------------------------------------------------------------- |
2596
+ | `default` | `scope: { row: Task, $index: number }` | 自定义TaskBar的右键菜单。通过 `scope.row` 访问当前任务对象,通过 `scope.$index` 访问任务索引。 |
2597
+
2598
+ **使用示例:**
2599
+
2600
+ ```vue
2601
+ <template>
2602
+ <GanttChart
2603
+ :tasks="tasks"
2604
+ :enable-task-bar-context-menu="true"
2605
+ >
2606
+ <TaskBarContextMenu>
2607
+ <template #default="scope">
2608
+ <div class="custom-context-menu">
2609
+ <div class="menu-item" @click="handleViewDetails(scope.row)">
2610
+ 👁️ 查看详情
2611
+ </div>
2612
+ <div class="menu-item" @click="handleAdjustTime(scope.row)">
2613
+ ⏰ 调整时间
2614
+ </div>
2615
+ <div class="menu-divider"></div>
2616
+ <div class="menu-item" @click="handleSetDependency(scope.row)">
2617
+ 🔗 设置依赖
2618
+ </div>
2619
+ </div>
2620
+ </template>
2621
+ </TaskBarContextMenu>
2622
+ </GanttChart>
2623
+ </template>
2624
+
2625
+ <script setup lang="ts">
2626
+ import { ref } from 'vue'
2627
+ import { GanttChart, TaskBarContextMenu } from 'jordium-gantt-vue3'
2628
+ import 'jordium-gantt-vue3/dist/assets/jordium-gantt-vue3.css'
2629
+ import type { Task } from 'jordium-gantt-vue3'
2630
+
2631
+ const tasks = ref<Task[]>([])
2632
+
2633
+ const handleViewDetails = (task: Task) => {
2634
+ console.log('查看详情:', task)
2635
+ }
2636
+
2637
+ const handleAdjustTime = (task: Task) => {
2638
+ console.log('调整时间:', task)
2639
+ }
2640
+
2641
+ const handleSetDependency = (task: Task) => {
2642
+ console.log('设置依赖:', task)
2643
+ }
2644
+ </script>
2645
+
2646
+ <style scoped>
2647
+ .custom-context-menu {
2648
+ position: fixed;
2649
+ background: white;
2650
+ border: 1px solid #e0e0e0;
2651
+ border-radius: 4px;
2652
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
2653
+ z-index: 9999;
2654
+ min-width: 120px;
2655
+ }
2656
+
2657
+ .menu-item {
2658
+ padding: 8px 16px;
2659
+ cursor: pointer;
2660
+ transition: background-color 0.2s;
2661
+ }
2662
+
2663
+ .menu-item:hover {
2664
+ background-color: #f5f5f5;
2665
+ }
2666
+
2667
+ .menu-divider {
2668
+ height: 1px;
2669
+ background-color: #e0e0e0;
2670
+ margin: 4px 0;
2671
+ }
2672
+ </style>
2673
+ ```
2674
+
2675
+ > **💡 使用场景**:
2676
+ >
2677
+ > - 自定义右键菜单样式和布局
2678
+ > - 添加业务特定的操作项
2679
+ > - 根据任务状态动态显示菜单项
2680
+ > - 添加权限控制逻辑
2681
+ > - 集成第三方 UI 组件库的菜单组件
2682
+
2683
+ > **⚠️ 注意事项**:
2684
+ >
2685
+ > - 当 `enableTaskListContextMenu=false` 或 `enableTaskBarContextMenu=false` 时,即使声明了组件也不会显示菜单
2686
+ > - 右键菜单会在滚动或点击菜单外部时自动关闭
2687
+ > - 推荐使用 `<Teleport to="body">` 将菜单渲染到 body 下,避免定位和层级问题
2688
+ > - 记得在菜单项点击后调用 `onClose()` 关闭菜单
2689
+ > - TaskRow 和 TaskBar 的右键菜单是独立的,可以分别自定义
2690
+ > - 默认情况下,系统会提供内置的右键菜单,包含常用操作
2691
+ > - 声明式组件不会渲染任何内容,仅用于传递配置
2692
+
2251
2693
  ##### TaskListColumn 插槽
2252
2694
 
2253
2695
  `TaskListColumn` 组件提供了两个插槽,用于自定义任务列表的列头和单元格内容。必须在声明式模式(`taskListColumnRenderMode="declarative"`)下使用。
@@ -2560,25 +3002,90 @@ const taskListConfig = ref<TaskListConfig>({
2560
3002
 
2561
3003
  ```
2562
3004
  jordium-gantt-vue3/
2563
- ├── src/ # 源代码
2564
- │ ├── components/ # Vue 组件
2565
- │ │ ├── GanttChart.vue # 甘特图主组件
2566
- │ │ ├── TaskList.vue # 任务列表
2567
- │ │ ├── Timeline.vue # 时间轴
2568
- │ │ └── ...
2569
- │ ├── models/ # 数据模型
2570
- │ │ ├── classes/ # 类定义
2571
- │ │ ├── configs/ # 配置接口
2572
- │ │ └── types/ # 类型定义
2573
- │ ├── composables/ # 组合式函数
2574
- │ ├── styles/ # 样式文件
2575
- └── utils/ # 工具函数
2576
- ├── demo/ # 示例代码
2577
- ├── docs/ # 文档
2578
- ├── public/ # 公共资源
2579
- └── package.json # 项目配置
3005
+ ├── src/ # 源代码
3006
+ │ ├── components/ # Vue 组件
3007
+ │ │ ├── GanttChart.vue # 甘特图主组件
3008
+ │ │ ├── GanttToolbar.vue # 工具栏组件
3009
+ │ │ ├── Timeline.vue # 时间轴组件
3010
+ │ │ ├── TaskBar.vue # 任务条组件
3011
+ ├── TaskRow.vue # 任务行组件
3012
+ │ │ ├── TaskDrawer.vue # 任务编辑抽屉
3013
+ │ │ ├── MilestonePoint.vue # 里程碑点组件
3014
+ │ │ ├── MilestoneDialog.vue # 里程碑编辑对话框
3015
+ ├── TaskContextMenu.vue # 右键菜单组件
3016
+ ├── TaskList/ # 任务列表模块(模块化重构)
3017
+ │ │ ├── TaskList.vue # 任务列表主组件
3018
+ │ │ │ ├── TaskListColumn.vue # 声明式列组件
3019
+ │ │ │ ├── index.ts # 模块导出
3020
+ │ │ │ └── composables/ # 任务列表相关组合式函数
3021
+ │ │ │ ├── useTaskListLayout.ts # 虚拟滚动和布局计算
3022
+ │ │ │ ├── useTaskListColumns.ts # 列配置管理
3023
+ │ │ │ ├── useTaskListResize.ts # 容器尺寸管理
3024
+ │ │ │ ├── useTaskListEventHandlers.ts # 事件处理逻辑
3025
+ │ │ │ └── useTaskParentCalculation.ts # 父任务数据计算
3026
+ │ │ └── index.ts # 组件统一导出
3027
+ │ ├── models/ # 数据模型
3028
+ │ │ ├── classes/ # 类定义
3029
+ │ │ │ ├── Task.ts # 任务类
3030
+ │ │ │ ├── Milestone.ts # 里程碑类
3031
+ │ │ │ └── Language.ts # 语言配置类
3032
+ │ │ ├── configs/ # 配置接口
3033
+ │ │ │ ├── TaskListConfig.ts # 任务列表配置
3034
+ │ │ │ ├── TaskBarConfig.ts # 任务条配置
3035
+ │ │ │ ├── TimelineConfig.ts # 时间轴配置
3036
+ │ │ │ └── ToolbarConfig.ts # 工具栏配置
3037
+ │ │ └── types/ # 类型定义
3038
+ │ │ ├── TimelineDataTypes.ts # 时间轴数据类型
3039
+ │ │ ├── TimelineScale.ts # 时间刻度类型
3040
+ │ │ └── TimelineCompat.ts # 兼容性类型
3041
+ │ ├── composables/ # 全局组合式函数
3042
+ │ │ ├── useI18n.ts # 国际化
3043
+ │ │ ├── useMessage.ts # 消息提示
3044
+ │ │ ├── useTaskRowDrag.ts # 任务行拖拽
3045
+ │ │ └── useTaskListColumns.ts # 列配置(已迁移至 TaskList/composables)
3046
+ │ ├── styles/ # 样式文件
3047
+ │ │ ├── app.css # 主样式
3048
+ │ │ ├── list.css # 列表样式
3049
+ │ │ ├── theme-variables.css # 主题变量
3050
+ │ │ └── index.ts # 样式导出
3051
+ │ ├── utils/ # 工具函数
3052
+ │ │ ├── canvasUtils.ts # Canvas 工具
3053
+ │ │ ├── perfMonitor.ts # 性能监控
3054
+ │ │ ├── predecessorUtils.ts # 前置任务工具
3055
+ │ │ └── taskTreeUtils.ts # 任务树工具
3056
+ │ └── index.ts # 主入口文件
3057
+ ├── demo/ # 在线演示代码
3058
+ │ ├── App.vue # 演示应用
3059
+ │ ├── data.json # 示例数据
3060
+ │ ├── locales/ # 多语言文件
3061
+ │ └── ...
3062
+ ├── docs/ # 文档
3063
+ │ └── TaskList-重构测试清单.md # 重构文档
3064
+ ├── npm-demo/ # NPM 包使用示例
3065
+ ├── npm-webpack-demo/ # Webpack 集成示例
3066
+ ├── public/ # 公共资源
3067
+ │ └── assets/ # 静态资源
3068
+ └── package.json # 项目配置
2580
3069
  ```
2581
3070
 
3071
+ ### 模块化设计亮点
3072
+
3073
+ #### TaskList 模块化重构
3074
+
3075
+ TaskList 组件经过深度重构,采用模块化设计,提升了代码可维护性:
3076
+
3077
+ **重构成果:**
3078
+ - 主组件从 686 行精简至 361 行(-47%)
3079
+ - 逻辑按职责分离到 5 个专门的 composables
3080
+ - 每个模块职责单一,便于测试和维护
3081
+
3082
+ **Composables 职责划分:**
3083
+ - `useTaskListLayout` - 虚拟滚动和布局计算
3084
+ - `useTaskListColumns` - 列配置管理和样式计算
3085
+ - `useTaskListResize` - 容器尺寸监听和 ResizeObserver 管理
3086
+ - `useTaskListEventHandlers` - 全局事件处理和滚动同步
3087
+ - `useTaskParentCalculation` - 父任务数据计算和任务树遍历
3088
+
2582
3089
  ---
2583
3090
 
2584
3091
  ## 🔗 相关链接