甘特图组件,有点改炸了
This commit is contained in:
43
components/Gantt/core/DataManager.js
Normal file
43
components/Gantt/core/DataManager.js
Normal file
@@ -0,0 +1,43 @@
|
||||
// DataManager:任务数据管理器,负责任务的增删改查、分组、校验和变更通知
|
||||
export default class DataManager {
|
||||
constructor(tasks = [], dimensions = []) {
|
||||
this.tasks = tasks;
|
||||
this.dimensions = dimensions;
|
||||
this.listeners = [];
|
||||
}
|
||||
// 新增任务
|
||||
addTask(task) {
|
||||
this.tasks.push(task);
|
||||
this.notify();
|
||||
}
|
||||
// 更新任务
|
||||
updateTask(id, data) {
|
||||
const idx = this.tasks.findIndex(t => t.id === id);
|
||||
if (idx !== -1) {
|
||||
this.tasks[idx] = { ...this.tasks[idx], ...data };
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
// 删除任务
|
||||
removeTask(id) {
|
||||
this.tasks = this.tasks.filter(t => t.id !== id);
|
||||
this.notify();
|
||||
}
|
||||
// 按维度分组
|
||||
groupByDimension(dim) {
|
||||
const groups = {};
|
||||
this.tasks.forEach(task => {
|
||||
const key = task.dimensions && task.dimensions[dim] ? task.dimensions[dim].id : '未分组';
|
||||
if (!groups[key]) groups[key] = { id: key, name: task.dimensions && task.dimensions[dim] ? task.dimensions[dim].name : '未分组', tasks: [] };
|
||||
groups[key].tasks.push(task);
|
||||
});
|
||||
return Object.values(groups);
|
||||
}
|
||||
// 变更监听
|
||||
onChange(cb) {
|
||||
this.listeners.push(cb);
|
||||
}
|
||||
notify() {
|
||||
this.listeners.forEach(cb => cb(this.tasks));
|
||||
}
|
||||
}
|
||||
27
components/Gantt/core/Interaction.js
Normal file
27
components/Gantt/core/Interaction.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// Interaction:交互控制器,处理用户交互逻辑,输出标准化事件
|
||||
export default class Interaction {
|
||||
constructor(dataManager, timeCalculator) {
|
||||
this.dataManager = dataManager;
|
||||
this.timeCalculator = timeCalculator;
|
||||
}
|
||||
// 处理拖拽开始
|
||||
handleDragStart(taskId) {
|
||||
// 可扩展:记录初始状态
|
||||
}
|
||||
// 处理拖拽过程
|
||||
handleDragUpdate(taskId, newDate) {
|
||||
// 校验新日期是否合法,可扩展
|
||||
this.dataManager.updateTask(taskId, { start: newDate });
|
||||
}
|
||||
// 处理拖拽结束
|
||||
handleDragEnd(taskId, newDate) {
|
||||
// 最终更新数据
|
||||
this.dataManager.updateTask(taskId, { start: newDate });
|
||||
}
|
||||
// 处理维度切换
|
||||
handleSwitchDimension(dim) {
|
||||
// 重新分组并通知视图层
|
||||
this.dataManager.dimensions = [dim];
|
||||
this.dataManager.notify();
|
||||
}
|
||||
}
|
||||
57
components/Gantt/core/Layout.js
Normal file
57
components/Gantt/core/Layout.js
Normal file
@@ -0,0 +1,57 @@
|
||||
// Layout:布局计算器,负责任务条和依赖线的布局
|
||||
export default class Layout {
|
||||
constructor(tasks, config) {
|
||||
this.tasks = tasks;
|
||||
this.config = config;
|
||||
}
|
||||
// 计算任务条布局
|
||||
computeTaskLayout() {
|
||||
// 简单实现:每个任务一行,计算左侧(start)、宽度(end-start)
|
||||
const layout = [];
|
||||
this.tasks.forEach((task, idx) => {
|
||||
const startPixel = this.dateToPixel(task.start);
|
||||
const endPixel = this.dateToPixel(task.end);
|
||||
layout.push({
|
||||
id: task.id,
|
||||
top: idx * 32,
|
||||
left: startPixel,
|
||||
width: endPixel - startPixel,
|
||||
height: 28,
|
||||
color: this.getTaskColor(task)
|
||||
});
|
||||
});
|
||||
return layout;
|
||||
}
|
||||
// 计算依赖线布局(可扩展)
|
||||
computeDependencyLines() {
|
||||
// 返回依赖线的起止坐标
|
||||
return [];
|
||||
}
|
||||
// 工具:日期转像素
|
||||
dateToPixel(date) {
|
||||
const start = new Date(this.config.startDate);
|
||||
const d = new Date(date);
|
||||
const scaleMap = { day: 40, week: 80, month: 200, quarter: 600 };
|
||||
const scale = scaleMap[this.config.timeScale] || 80;
|
||||
let diff = 0;
|
||||
if (this.config.timeScale === 'day') {
|
||||
diff = (d - start) / (1000 * 3600 * 24);
|
||||
} else if (this.config.timeScale === 'week') {
|
||||
diff = (d - start) / (1000 * 3600 * 24 * 7);
|
||||
} else if (this.config.timeScale === 'month') {
|
||||
diff = (d.getFullYear() - start.getFullYear()) * 12 + (d.getMonth() - start.getMonth());
|
||||
} else if (this.config.timeScale === 'quarter') {
|
||||
diff = ((d.getFullYear() - start.getFullYear()) * 12 + (d.getMonth() - start.getMonth())) / 3;
|
||||
}
|
||||
return diff * scale;
|
||||
}
|
||||
// 工具:获取任务颜色
|
||||
getTaskColor(task) {
|
||||
const group = this.config.groupBy;
|
||||
if (group && task.dimensions && task.dimensions[group]) {
|
||||
const id = task.dimensions[group].id;
|
||||
return this.config.colors && this.config.colors[group] && this.config.colors[group][id] ? this.config.colors[group][id] : '#409EFF';
|
||||
}
|
||||
return '#409EFF';
|
||||
}
|
||||
}
|
||||
82
components/Gantt/core/TimeCalculator.js
Normal file
82
components/Gantt/core/TimeCalculator.js
Normal file
@@ -0,0 +1,82 @@
|
||||
// TimeCalculator:时间轴计算器,负责时间与像素的转换、生成时间刻度等
|
||||
export default class TimeCalculator {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.scaleMap = { day: 40, week: 80, month: 200, quarter: 600 }; // 每单位像素宽度
|
||||
}
|
||||
// 日期转像素坐标
|
||||
dateToPixel(date) {
|
||||
const start = new Date(this.config.startDate);
|
||||
const d = new Date(date);
|
||||
const scale = this.scaleMap[this.config.timeScale] || 80;
|
||||
let diff = 0;
|
||||
if (this.config.timeScale === 'day') {
|
||||
diff = (d - start) / (1000 * 3600 * 24);
|
||||
} else if (this.config.timeScale === 'week') {
|
||||
diff = (d - start) / (1000 * 3600 * 24 * 7);
|
||||
} else if (this.config.timeScale === 'month') {
|
||||
diff = (d.getFullYear() - start.getFullYear()) * 12 + (d.getMonth() - start.getMonth());
|
||||
} else if (this.config.timeScale === 'quarter') {
|
||||
diff = ((d.getFullYear() - start.getFullYear()) * 12 + (d.getMonth() - start.getMonth())) / 3;
|
||||
}
|
||||
return diff * scale;
|
||||
}
|
||||
// 像素转日期(仅简单实现,实际可扩展)
|
||||
pixelToDate(pixel) {
|
||||
const start = new Date(this.config.startDate);
|
||||
const scale = this.scaleMap[this.config.timeScale] || 80;
|
||||
let d = new Date(start);
|
||||
if (this.config.timeScale === 'day') {
|
||||
d.setDate(start.getDate() + pixel / scale);
|
||||
} else if (this.config.timeScale === 'week') {
|
||||
d.setDate(start.getDate() + (pixel / scale) * 7);
|
||||
} else if (this.config.timeScale === 'month') {
|
||||
d.setMonth(start.getMonth() + pixel / scale);
|
||||
} else if (this.config.timeScale === 'quarter') {
|
||||
d.setMonth(start.getMonth() + (pixel / scale) * 3);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
// 生成时间轴刻度
|
||||
getTimelineTicks() {
|
||||
const ticks = [];
|
||||
const start = new Date(this.config.startDate);
|
||||
const end = new Date(this.config.endDate);
|
||||
let cur = new Date(start);
|
||||
while (cur <= end) {
|
||||
ticks.push({
|
||||
label: this.formatTick(cur),
|
||||
date: new Date(cur)
|
||||
});
|
||||
if (this.config.timeScale === 'day') {
|
||||
cur.setDate(cur.getDate() + 1);
|
||||
} else if (this.config.timeScale === 'week') {
|
||||
cur.setDate(cur.getDate() + 7);
|
||||
} else if (this.config.timeScale === 'month') {
|
||||
cur.setMonth(cur.getMonth() + 1);
|
||||
} else if (this.config.timeScale === 'quarter') {
|
||||
cur.setMonth(cur.getMonth() + 3);
|
||||
}
|
||||
}
|
||||
return ticks;
|
||||
}
|
||||
// 格式化刻度
|
||||
formatTick(date) {
|
||||
if (this.config.timeScale === 'day') {
|
||||
return date.toISOString().slice(5, 10);
|
||||
} else if (this.config.timeScale === 'week') {
|
||||
return 'W' + this.getWeekNumber(date);
|
||||
} else if (this.config.timeScale === 'month') {
|
||||
return date.getFullYear() + '-' + (date.getMonth() + 1);
|
||||
} else if (this.config.timeScale === 'quarter') {
|
||||
return date.getFullYear() + ' Q' + (Math.floor(date.getMonth() / 3) + 1);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
// 获取周数
|
||||
getWeekNumber(date) {
|
||||
const firstDay = new Date(date.getFullYear(), 0, 1);
|
||||
const dayOfYear = ((date - firstDay) / 86400000) + 1;
|
||||
return Math.ceil(dayOfYear / 7);
|
||||
}
|
||||
}
|
||||
14
components/Gantt/core/types.js
Normal file
14
components/Gantt/core/types.js
Normal file
@@ -0,0 +1,14 @@
|
||||
// 任务数据模型
|
||||
export const TaskModel = {
|
||||
id: '', name: '', start: '', end: '', progress: 0,
|
||||
dependencies: [], children: [],
|
||||
dimensions: {}
|
||||
};
|
||||
|
||||
// 视图配置参数
|
||||
export const ViewConfig = {
|
||||
timeScale: 'week',
|
||||
startDate: '', endDate: '',
|
||||
groupBy: '', visibleDimensions: [],
|
||||
colors: {}
|
||||
};
|
||||
Reference in New Issue
Block a user