摘要:本文由葡萄城技術團隊於OSCHINA發佈。轉載請註明出處:葡萄城官網,葡萄城爲開發者提供專業的開發工具、解決方案和服務,賦能開發者。
前言
甘特圖是項目管理、生產排程、節點管理中非常常見的一個功能。那麼,有沒有一種方法能夠幫助將甘特圖引入到系統中,讓數據的進度、排程數據的展示更加直觀,讓管理更加高效。
本葡萄今天爲大家帶來一個新的插件——甘特圖插件。該插件是結合 SpreadJS 本身強大電子表格能力提供的一種全新的可視化展示方案,能夠有效地將生產計劃、預算排期中的日程管理信息展示出來,顯示關鍵路徑上關鍵節點的進展或狀態。其數據來自與集算表同源的數據管理器(DataManager),通過綁定 -> 視圖的方式,將層級化的任務數據通過甘特圖插件進行展示。
(通過甘特圖插件展示層級化的數據)
1. 縮放和時間刻度滾動
(通過甘特圖插件實現縮放及刻度滾動)
JavaScript代碼:
var myTable;
var ganttSheet;
var adjustTierUnit = true;
window.onload = function() {
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 0 });
initSpread(spread);
initSplitView(spread);
};
function initSpread(spread) {
spread.suspendPaint();
initDataSource(spread);
initGanttSheet(spread);
spread.resumePaint();
}
function initDataSource(spread) {
var tableName = "Gantt_Id";
var baseApiUrl = getBaseApiUrl();
var apiUrl = baseApiUrl + "/" + tableName;
var dataManager = spread.dataManager();
myTable = dataManager.addTable("myTable", {
batch: true,
remote: {
read: {
url: apiUrl
}
},
schema: {
hierarchy: {
type: "Parent",
column: "parentId"
},
columns: {
id: { isPrimaryKey: true },
taskNumber: { dataType: "rowOrder" }
}
}
});
}
function initGanttSheet(spread) {
ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet);
var view = myTable.addView("ganttView", [
{ value: "taskNumber", caption: "NO.", width: 60 },
{ value: "name", caption: "Task Name", width: 200 },
{ value: "duration", caption: "Duration", width: 90 },
{ value: "predecessors", caption: "Predecessors", width: 120 }
]);
view.fetch().then(function() {
ganttSheet.bindGanttView(view);
}).then(function() {
ganttSheet.project.timescale.zoomOut();
});
initSidePanel(ganttSheet);
}
(通過甘特圖插件實現的任務欄和網格線的樣式)
JavaScript代碼:
/*REPLACE_MARKER*/
/*DO NOT DELETE THESE COMMENTS*/
var myTable;
var ganttSheet;
window.onload = function() {
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 0 });
initSpread(spread);
initSplitView(spread);
};
function initSpread(spread) {
spread.suspendPaint();
initDataSource(spread);
initGanttSheet(spread);
spread.resumePaint();
}
function initDataSource(spread) {
var tableName = "Gantt_Id";
var baseApiUrl = getBaseApiUrl();
var apiUrl = baseApiUrl + "/" + tableName;
var dataManager = spread.dataManager();
myTable = dataManager.addTable("myTable", {
batch: true,
remote: {
read: {
url: apiUrl
}
},
schema: {
hierarchy: {
type: "Parent",
column: "parentId"
},
columns: {
id: { isPrimaryKey: true },
taskNumber: { dataType: "rowOrder" }
}
}
});
}
function initGanttSheet(spread) {
ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet);
var view = myTable.addView("ganttView", [
{ value: "taskNumber", caption: "NO.", width: 60 },
{ value: "name", caption: "Task Name", width: 200 },
{ value: "duration", caption: "Duration", width: 90 },
{ value: "predecessors", caption: "Predecessors", width: 120, visible: false }
]);
view.fetch().then(function() {
ganttSheet.bindGanttView(view);
ganttSheet.project.timescale.tierMode = GC.Spread.Sheets.GanttSheet.TimescaleTierMode.topMiddleBottom;
ganttSheet.project.timescale.topTier.unit = GC.Spread.Sheets.GanttSheet.TimescaleUnit.thirdsOfMonth;
}).then(function() {
ganttSheet.gridlines.bottomTierColumn = {
lineType: GC.Spread.Sheets.GanttSheet.GanttGridlineType.dashed,
lineColor: "#c85b11"
};
ganttSheet.gridlines.ganttRows.lineType = GC.Spread.Sheets.GanttSheet.GanttGridlineType.thin;
ganttSheet.gridlines.ganttRows.lineColor = "#abd08f";
ganttSheet.gridlines.ganttRows.interval = 2;
ganttSheet.gridlines.ganttRows.intervalLineType = GC.Spread.Sheets.GanttSheet.GanttGridlineType.dashDot;
ganttSheet.gridlines.ganttRows.intervalLineColor = "#9cc3e5";
});
initSidePanel(ganttSheet);
}
function initSidePanel(ganttSheet) {
var setButton = document.getElementById("set-gridline");
var intervalPanel = document.getElementById("interval-panel");
var affectItemOption = document.getElementById("affectItem");
var lineTypeOption = document.getElementById("lineType");
var lineColorOption = document.getElementById("lineColor");
var intervalLineTypeOption = document.getElementById("intervalLineType");
var intervalLineColorOption = document.getElementById("intervalLineColor");
var intervalOption = document.getElementById("interval");
var option = convertToNormalOptions(ganttSheet, "ganttRows");
syncOptionToPanel(option);
affectItemOption.addEventListener('change', function(e) {
var target = affectItemOption.value;
if (affectItemOption.value === "ganttRows") {
intervalPanel.classList.remove("hide");
} else {
intervalPanel.classList.add("hide");
}
var option = convertToNormalOptions(ganttSheet, target);
syncOptionToPanel(option);
});
setButton.addEventListener('click', function() {
var target = affectItemOption.value;
var lineType = Number(lineTypeOption.value);
var lineColor = lineColorOption.value;
var intervalLineType = Number(intervalLineTypeOption.value);
var intervalLineColor = intervalLineColorOption.value;
var interval = Number(intervalOption.value);
var option = convertToGanttGridlineOptions(lineType, lineColor, intervalLineType, intervalLineColor, interval);
if (option) {
ganttSheet.gridlines[target] = option;
}
});
3.數據展示佈局調整
(通過甘特圖插件實現佈局的調整)
JavaScript代碼:
/*REPLACE_MARKER*/
/*DO NOT DELETE THESE COMMENTS*/
var myTable;
var ganttSheet;
var roundBarsToWholeDays = true;
window.onload = function() {
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 0 });
initSpread(spread);
initSplitView(spread);
};
function initSpread(spread) {
spread.suspendPaint();
initDataSource(spread);
initGanttSheet(spread);
spread.resumePaint();
}
function initDataSource(spread) {
var tableName = "Gantt_Id";
var baseApiUrl = getBaseApiUrl();
var apiUrl = baseApiUrl + "/" + tableName;
var dataManager = spread.dataManager();
myTable = dataManager.addTable("myTable", {
batch: true,
remote: {
read: {
url: apiUrl
}
},
schema: {
hierarchy: {
type: "Parent",
column: "parentId"
},
columns: {
id: { isPrimaryKey: true },
taskNumber: { dataType: "rowOrder" }
}
}
});
}
function initGanttSheet(spread) {
ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet);
var view = myTable.addView("ganttView", [
{ value: "taskNumber", caption: "NO.", width: 60 },
{ value: "name", caption: "Task Name", width: 200 },
{ value: "duration", caption: "Duration", width: 90 },
{ value: "predecessors", caption: "Predecessors", width: 120, visible: false }
]);
view.fetch().then(function() {
ganttSheet.bindGanttView(view);
ganttSheet.suspendPaint();
var summaryStyleRule = ganttSheet.project.taskStyleRules.getRule("summary");
var summaryStyle = summaryStyleRule.style.taskbarStyle;
summaryStyle.leftText = "start";
summaryStyle.rightText = "finish";
summaryStyleRule.style.taskbarStyle = summaryStyle;
var layout = ganttSheet.project.layout;
layout.linkLineMode = "noLinks";
layout.barHeight = 18;
ganttSheet.resumePaint();
});
initSidePanel(ganttSheet);
}
function initSidePanel(ganttSheet) {
var roundBarItem = document.getElementById("round-bar");
var linkTypeItem = document.getElementById("link-type");
var barHeightItem = document.getElementById("bar-height");
var dateFormatItem = document.getElementById("date-format");
var setLayoutItem = document.getElementById("set-layout");
roundBarItem.addEventListener("click", function() {
if (roundBarItem.classList.contains("active")) {
roundBarItem.classList.remove("active");
roundBarsToWholeDays = false;
} else {
roundBarItem.classList.add("active");
roundBarsToWholeDays = true;
}
});
setLayoutItem.addEventListener("click", function() {
var layout = ganttSheet.project.layout;
ganttSheet.suspendPaint();
layout.linkLineMode = linkTypeItem.value;
layout.barHeight = Number(barHeightItem.value);
layout.barTextDateFormat = dateFormatItem.value;
layout.roundBarsToWholeDays = roundBarsToWholeDays;
ganttSheet.resumePaint();
});
}
4.任務操作
(可在甘特圖插件實現任務操作)
JavaScript代碼:
/*REPLACE_MARKER*/
/*DO NOT DELETE THESE COMMENTS*/
var myTable;
var ganttSheet;
var roundBarsToWholeDays = true;
window.onload = function () {
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 0 });
initSpread(spread);
initSplitView(spread);
};
function initSpread(spread) {
spread.suspendPaint();
initDataSource(spread);
initGanttSheet(spread);
spread.resumePaint();
}
function initDataSource(spread) {
var tableName = "Gantt_Id";
var baseApiUrl = getBaseApiUrl();
var apiUrl = baseApiUrl + "/" + tableName;
var dataManager = spread.dataManager();
myTable = dataManager.addTable("myTable", {
batch: true,
remote: {
read: {
url: apiUrl
},
batch: {
url: apiUrl + "Collection"
}
},
schema: {
hierarchy: {
type: "Parent",
column: "parentId"
},
columns: {
id: { isPrimaryKey: true },
taskNumber: { dataType: "rowOrder" }
}
}
});
}
function initGanttSheet(spread) {
ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet);
var view = myTable.addView("ganttView", [
{ value: "id", caption: "Id", width: 40 },
{ value: "taskNumber", caption: "NO.", width: 60 },
{ value: "name", caption: "Task Name", width: 200 },
{ value: "duration", caption: "Duration", width: 90 },
{ value: "predecessors", caption: "Predecessors", width: 120 }
]);
view.fetch().then(function () {
ganttSheet.bindGanttView(view);
});
initSidePanel(ganttSheet);
}
function initSidePanel(ganttSheet) {
var addTaskItem = document.getElementById("add-task");
var addSummayItem = document.getElementById("add-summary");
var addMilestoneItem = document.getElementById("add-milestone");
var deleteItem = document.getElementById("delete-task");
var indentTaskItem = document.getElementById("indent-task");
var outdentTaskItem = document.getElementById("outdent-task");
var linkTaskItem = document.getElementById("link-task");
var unlinkTaskItem = document.getElementById("unlink-task");
var submitItem = document.getElementById("submit-changes");
var cancelItem = document.getElementById("cancel-changes");
addTaskItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
addTask();
ganttSheet.resumePaint();
});
addSummayItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
addSummary();
ganttSheet.resumePaint();
});
addMilestoneItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
addMilestone();
ganttSheet.resumePaint();
});
deleteItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
deleteTask();
ganttSheet.resumePaint();
});
indentTaskItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
indentTask();
ganttSheet.resumePaint();
});
outdentTaskItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
outdentTask();
ganttSheet.resumePaint();
});
linkTaskItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
linkTask();
ganttSheet.resumePaint();
});
unlinkTaskItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
unlinkTask();
ganttSheet.resumePaint();
});
submitItem.addEventListener("click", function () {
ganttSheet.submitChanges();
});
cancelItem.addEventListener("click", function () {
ganttSheet.cancelChanges();
});
function addTask() {
var project = ganttSheet.project;
var selections = ganttSheet.getSelections();
var insertedRow = Math.min(...selections.map(r => r.row), project.tasks.length)
var rowCount = selections.map(r => r.rowCount).reduce((pre, current) => { return pre + current });
var taskData = createTaskDataList(rowCount, () => ({ name: "<新任務>" }));
project.insertTasksByRow(insertedRow, taskData);
}
function addSummary() {
var project = ganttSheet.project;
var selectedRange = ganttSheet.getSelections()[0];
var insertedRow = selectedRange.row;
var insertedTaskNumbers = ganttSheet.getTaskByRow(insertedRow).taskNumber || project.count;
var selectedTasks = getSelectedRowIndexes().map((row) => ganttSheet.getTaskByRow(row)).filter((row) => !!row);
if (selectedTasks.length == 0) {
project.insertTasks(insertedTaskNumbers, [{ name: "<新摘要任務>" }, { name: "<新任務>" }]);
project.indentTasks(insertedTaskNumbers + 1);
} else {
project.insertTasks(insertedTaskNumbers, { name: "<新摘要任務>" }, selectedTasks[0].level);
project.indentTasks(selectedTasks.map((t) => t.taskNumber));
}
ganttSheet.setSelection(insertedRow, -1, 1, -1);
}
function addMilestone() {
var project = ganttSheet.project;
var selections = ganttSheet.getSelections();
var rowCount = selections.map(r => r.rowCount).reduce((pre, current) => { return pre + current });
var insertedRow = Math.min(...selections.map(r => r.row), project.tasks.length);
var taskData = createTaskDataList(rowCount, () => ({ name: "<新里程碑>", duration: 0 }));
project.insertTasksByRow(insertedRow, taskData);
ganttSheet.setSelection(insertedRow, -1, rowCount, -1);
}
function deleteTask() {
var project = ganttSheet.project;
var rowIds = getSelectedTaskNumbers();
project.removeTasks(rowIds);
}
function indentTask() {
var project = ganttSheet.project;
var rowIds = getSelectedTaskNumbers();
project.indentTasks(rowIds);
}
function outdentTask() {
var project = ganttSheet.project;
var rowIds = getSelectedTaskNumbers();
project.outdentTasks(rowIds);
}
function linkTask() {
var project = ganttSheet.project;
var links = [];
var selections = ganttSheet.getSelections();
var previous = -1;
for (var range of selections) {
if (previous != -1) {
links.push([previous, range.row]);
}
for (var row = range.row + 1; row < range.row + range.rowCount; row++) {
links.push([row - 1, row]);
}
previous = range.row + range.rowCount - 1;
}
if (links.length <= 0) {
return;
}
project.suspendSchedule();
for (var link of links) {
var [fromTaskNumber, toTaskNumber] = link;
try {
project.addDependency({ fromTaskNumber, toTaskNumber });
} catch { }
}
project.resumeSchedule();
}
5.日曆
(可在甘特圖插件內實現日曆內容的調整)
JavaScript代碼:
/*REPLACE_MARKER*/
/*DO NOT DELETE THESE COMMENTS*/
var myTable;
var ganttSheet;
var roundBarsToWholeDays = true;
window.onload = function () {
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 0 });
initSpread(spread);
initSplitView(spread);
};
function initSpread(spread) {
spread.suspendPaint();
initDataSource(spread);
initGanttSheet(spread);
spread.resumePaint();
}
function initGanttSheet(spread) {
ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet);
var view = myTable.addView("ganttView", [
{ value: "id", caption: "Id", width: 40 },
{ value: "taskNumber", caption: "NO.", width: 60 },
{ value: "name", caption: "Task Name", width: 200 },
{ value: "duration", caption: "Duration", width: 90 },
{ value: "predecessors", caption: "Predecessors", width: 120 }
]);
view.fetch().then(function () {
ganttSheet.bindGanttView(view);
});
initSidePanel(ganttSheet);
}
function initSidePanel(ganttSheet) {
var addTaskItem = document.getElementById("add-task");
var addSummayItem = document.getElementById("add-summary");
var addMilestoneItem = document.getElementById("add-milestone");
var deleteItem = document.getElementById("delete-task");
var indentTaskItem = document.getElementById("indent-task");
var outdentTaskItem = document.getElementById("outdent-task");
var linkTaskItem = document.getElementById("link-task");
var unlinkTaskItem = document.getElementById("unlink-task");
var submitItem = document.getElementById("submit-changes");
var cancelItem = document.getElementById("cancel-changes");
addTaskItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
addTask();
ganttSheet.resumePaint();
});
addSummayItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
addSummary();
ganttSheet.resumePaint();
});
addMilestoneItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
addMilestone();
ganttSheet.resumePaint();
});
deleteItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
deleteTask();
ganttSheet.resumePaint();
});
indentTaskItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
indentTask();
ganttSheet.resumePaint();
});
outdentTaskItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
outdentTask();
ganttSheet.resumePaint();
});
linkTaskItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
linkTask();
ganttSheet.resumePaint();
});
unlinkTaskItem.addEventListener("click", function () {
ganttSheet.suspendPaint()
unlinkTask();
ganttSheet.resumePaint();
});
submitItem.addEventListener("click", function () {
ganttSheet.submitChanges();
});
cancelItem.addEventListener("click", function () {
ganttSheet.cancelChanges();
});
function addTask() {
var project = ganttSheet.project;
var selections = ganttSheet.getSelections();
var insertedRow = Math.min(...selections.map(r => r.row), project.tasks.length)
var rowCount = selections.map(r => r.rowCount).reduce((pre, current) => { return pre + current });
var taskData = createTaskDataList(rowCount, () => ({ name: "<新任務>" }));
project.insertTasksByRow(insertedRow, taskData);
}
function addSummary() {
var project = ganttSheet.project;
var selectedRange = ganttSheet.getSelections()[0];
var insertedRow = selectedRange.row;
var insertedTaskNumbers = ganttSheet.getTaskByRow(insertedRow).taskNumber || project.count;
var selectedTasks = getSelectedRowIndexes().map((row) => ganttSheet.getTaskByRow(row)).filter((row) => !!row);
if (selectedTasks.length == 0) {
project.insertTasks(insertedTaskNumbers, [{ name: "<新摘要任務>" }, { name: "<新任務>" }]);
project.indentTasks(insertedTaskNumbers + 1);
} else {
project.insertTasks(insertedTaskNumbers, { name: "<新摘要任務>" }, selectedTasks[0].level);
project.indentTasks(selectedTasks.map((t) => t.taskNumber));
}
ganttSheet.setSelection(insertedRow, -1, 1, -1);
}
function addMilestone() {
var project = ganttSheet.project;
var selections = ganttSheet.getSelections();
var rowCount = selections.map(r => r.rowCount).reduce((pre, current) => { return pre + current });
var insertedRow = Math.min(...selections.map(r => r.row), project.tasks.length);
var taskData = createTaskDataList(rowCount, () => ({ name: "<新里程碑>", duration: 0 }));
project.insertTasksByRow(insertedRow, taskData);
ganttSheet.setSelection(insertedRow, -1, rowCount, -1);
}
function deleteTask() {
var project = ganttSheet.project;
var rowIds = getSelectedTaskNumbers();
project.removeTasks(rowIds);
}
function indentTask() {
var project = ganttSheet.project;
var rowIds = getSelectedTaskNumbers();
project.indentTasks(rowIds);
}
function outdentTask() {
var project = ganttSheet.project;
var rowIds = getSelectedTaskNumbers();
project.outdentTasks(rowIds);
}
function linkTask() {
var project = ganttSheet.project;
var links = [];
var selections = ganttSheet.getSelections();
var previous = -1;
for (var range of selections) {
if (previous != -1) {
links.push([previous, range.row]);
}
for (var row = range.row + 1; row < range.row + range.rowCount; row++) {
links.push([row - 1, row]);
}
previous = range.row + range.rowCount - 1;
}
if (links.length <= 0) {
return;
}
project.suspendSchedule();
for (var link of links) {
var [fromTaskNumber, toTaskNumber] = link;
try {
project.addDependency({ fromTaskNumber, toTaskNumber });
} catch { }
}
project.resumeSchedule();
}
function unlinkTask() {
var project = ganttSheet.project;
var taskNumbers = getSelectedTaskNumbers();
var dependencies = [];
if (taskNumbers.length == 1) {
var task = project.getTaskByRow(taskNumbers[0]);
dependencies = [...task.predecessorDependencies, ...task.successorDependencies];
} else {
var taskNumberSet = {};
for (var taskNumber of taskNumbers) {
taskNumberSet[taskNumber] = true;
}
dependencies = project.dependencies.filter(dp => taskNumberSet[dp.from.taskNumber] && taskNumberSet[dp.to.taskNumber]);
}
if (dependencies.length >= 1) {
project.removeDependency(dependencies);
}
}
function getSelectedRowIndexes() {
var rows = [];
var selections = ganttSheet.getSelections();
for (var range of selections) {
for (var row = range.row; row < range.row + range.rowCount; row++) {
rows.push(row);
}
}
return rows;
}
6.導入和導出操作
甘特圖插件中展示的內容導出至PDF及Excel的格式。
(支持導入導出能力)
JavaScript代碼:
/*REPLACE_MARKER*/
/*DO NOT DELETE THESE COMMENTS*/
var myTable;
var ganttSheet;
var roundBarsToWholeDays = true;
window.onload = function() {
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 0 });
initSpread(spread);
initSplitView(spread);
};
function initSpread(spread) {
spread.suspendPaint();
initDataSource(spread);
initGanttSheet(spread);
spread.resumePaint();
}
function initDataSource(spread) {
var tableName = "Gantt_Id";
var baseApiUrl = getBaseApiUrl();
var apiUrl = baseApiUrl + "/" + tableName;
var dataManager = spread.dataManager();
myTable = dataManager.addTable("myTable", {
batch: true,
remote: {
read: {
url: apiUrl
}
},
schema: {
hierarchy: {
type: "Parent",
column: "parentId"
},
columns: {
id: { isPrimaryKey: true },
taskNumber: { dataType: "rowOrder" }
}
}
});
}
function initGanttSheet(spread) {
ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet);
var view = myTable.addView("ganttView", [
{ value: "taskNumber", caption: "NO.", width: 60 },
{ value: "name", caption: "Task Name", width: 200 },
{ value: "duration", caption: "Duration", width: 90 },
{ value: "predecessors", caption: "Predecessors", width: 120, visible: false }
]);
view.fetch().then(function() {
ganttSheet.bindGanttView(view);
});
initSidePanel(spread, ganttSheet);
}
function initSidePanel(spread, ganttSheet) {
var excelIo = new GC.Spread.Excel.IO();
var fileInput = document.getElementById("file-input");
var openFileItem = document.getElementById("open-file");
var fileNameItem = document.getElementById("file-name");
var exportJSONItem = document.getElementById("export-to-json");
var exportSJSItem = document.getElementById("export-to-sjs");
var exportExcelItem = document.getElementById("export-to-excel");
var printItem = document.getElementById("print");
var pdfItem = document.getElementById("pdf");
var exportFileName = "export";
openFileItem.addEventListener('click', function() {
fileInput.click();
});
fileInput.addEventListener('change', function(e) {
fileNameItem.value = 'Loading file...';
var file = fileInput.files[0];
if (!file) {
alert("Upload a file first.");
return;
}
var fileName = file.name;
var suffix = fileName.substr(fileName.lastIndexOf('.'));
if (suffix === '.xlsx' || suffix === '.xlsm') {
// here is excel IO API
excelIo.open(file, function(json) {
spread.fromJSON(json);
fileNameItem.value = fileName;
fileInput.value = '';
}, function(e) {
// process error
console.log(e);
});
} else if (suffix === '.ssjson' || suffix === '.json') {
var reader = new FileReader();
reader.onload = function() {
var spreadJson = JSON.parse(this.result);
spread.fromJSON(spreadJson);
fileNameItem.value = fileName;
fileInput.value = '';
};
reader.readAsText(file);
} else if (suffix === '.sjs') {
spread.open(file, () => {
fileNameItem.value = fileName;
fileInput.value = '';
}, (e) => {
console.log(e);
}, {
openMode: GC.Spread.Sheets.OpenMode.normal,
fullRecalc: true,
});
}
});
exportJSONItem.addEventListener('click', function () {
var fileName = exportFileName + ".ssjson";
var json = spread.toJSON();
saveAs(new Blob([JSON.stringify(json)], { type: "text/plain;charset=utf-8" }), fileName);
});
exportSJSItem.addEventListener('click', function () {
var fileName = exportFileName + ".sjs";
spread.save(function (blob) {
saveAs(blob, fileName);
}, function (e) {
// process error
console.log(e);
}, {
fileType: GC.Spread.Sheets.FileType.ssjson,
includeBindingSource: true,
saveAsView: true
});
});
exportExcelItem.addEventListener('click', function () {
var fileName = exportFileName + ".xlsx";
var json = spread.toJSON({ includeBindingSource: true, saveAsView: true });
// here is excel IO API
excelIo.save(json, function(blob) {
saveAs(blob, fileName);
}, function(e) {
// process error
console.log(e);
}, { xlsxStrictMode: false });
});
printItem.addEventListener('click', function() {
spread.print();
});
pdfItem.addEventListener('click', function() {
spread.savePDF(function (blob) {
var url = URL.createObjectURL(blob);
pwin = window.open(url);
});
});
}
總結
甘特圖是一種強大的項目管理工具,通過直觀的時間軸展示任務的安排和進度。它能幫助項目經理們創建詳細的項目計劃,有效跟蹤進度,併合理分配資源。甘特圖還可以管理任務間的依賴關係,及時調整時間表,並識別風險與關鍵路徑。它在項目管理中扮演着重要的角色,提高了團隊的協作效率和項目的成功率。通過使用甘特圖,項目團隊能夠更好地掌握項目進展,作出決策,並確保項目按時交付。
如果您對該插件感興趣,可以訪問葡萄城官網下載SpreadJS產品。