# 작업 운영

## Content

간트 시트에서 프로젝트 일정 관리를 위해 다양한 작업(Task) 작업을 수행할 수 있습니다. 아래에서 각 기능을 설명합니다.

## 일반 작업 추가

지정된 위치에 일반 작업을 추가하거나 삽입할 수 있습니다. 작업의 레벨을 지정하지 않고 삽입할 경우, 대상 작업 앞에 위치하며 인접한 작업에 따라 레벨이 결정됩니다.

* 이전 작업이 요약(Summary) 작업인 경우, 새로 삽입된 작업은 해당 작업의 하위 작업이 됩니다.
* 이전 작업이 아웃라인으로 축소된 경우, 삽입된 작업은 대상 작업과 동일한 레벨이 됩니다. 그렇지 않은 경우, 삽입된 작업의 레벨은 바로 이전 작업의 레벨과 동일합니다.

> **참고**: SpreadJS에서는 루트 작업(Root Task) 앞에 작업을 삽입할 수 없습니다. 루트 작업은 읽기 전용이며 필드 값을 편집할 수 없습니다.

아래 이미지는 지속 기간이 1일이고 선행 작업이 없는 새 작업을 삽입한 예입니다.
![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/image.93edd8.png?width=900)
새 작업은 [GC.Spread.Sheets.GanttSheet.Project](/spreadjs/api/v19/classes/GC.Spread.Sheets.GanttSheet.Project) 클래스의 `addTasks` 또는 `insertTasks` 메서드를 사용하여 추가/삽입할 수 있습니다.

```javascript
// 새 작업 추가
function addTask(ganttSheet) {
    ganttSheet.suspendPaint()
    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: "<New Task>" }));
    project.insertTasksByRow(insertedRow, taskData); 
    ganttSheet.resumePaint();
}
function createTaskDataList(count, initializer) {
    var array = new Array(count);
    for (var index = 0; index < count; index++) {
         array[index] = initializer();
    }
    return array;
}
```

## 요약 작업 추가

요약 작업(Summary Task)은 다른 작업의 부모 역할을 합니다. 관련 작업을 그룹화하여 프로젝트 관리와 보기 편의성을 높일 수 있습니다.
![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/image.7a18ea.png?width=900)
간트 시트에 요약 작업을 삽입하려면 `insertTasks` 메서드를 사용합니다.

```auto
// 새 요약 작업 추가
function addSummary(ganttSheet) {
    ganttSheet.suspendPaint()
    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: "<New Summary Task>" }, { name: "<New Task>" }]);
            project.indentTasks(insertedTaskNumbers + 1);
        } else {
            project.insertTasks(insertedTaskNumbers, { name: "<New Summary Task>" }, selectedTasks[0].level);
            project.indentTasks(selectedTasks.map((t) => t.taskNumber));
        }
        ganttSheet.setSelection(insertedRow, -1, 1, -1);
        ganttSheet.resumePaint();
}
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;
}
```

## 마일스톤 작업 추가

마일스톤(Milestone)은 기간이 0인 작업으로, 프로젝트 일정에서 중요한 성과를 나타냅니다. 마일스톤 작업을 설정하면 간트 차트 영역에서 날짜 텍스트가 마일스톤 아이콘과 함께 표시됩니다.
![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/image.c097e8.png?width=900)
마일스톤 작업은 `insertTasksByRow` 메서드를 사용하여 삽입할 수 있습니다.

```javascript
// 새 마일스톤 작업 추가
function addMilestone(ganttSheet) {
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: "<New Milestone>", duration: 0 }));
project.insertTasksByRow(insertedRow, taskData);
ganttSheet.setSelection(insertedRow, -1, rowCount, -1);
}
```

## 작업 크기 조정

간트 시트에서는 Spread 디자이너 컴포넌트 UI를 통해 작업의 기간을 조정할 수 있습니다. 마우스 포인터가 화살표와 선 모양으로 바뀌면 작업을 드래그하여 기간을 변경할 수 있습니다.
![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/image.b951b9.png?width=400)

## 작업 이동

작업 일정 모드가 "수동(Manual)"로 설정된 경우, `moveInWeeks` 및 `moveInWorkingDays` API를 사용하여 간트 시트 내에서 작업을 이동할 수 있습니다.

> **참고**: 루트 작업은 읽기 전용이므로 필드 값을 편집할 수 없습니다.

## 작업 삭제

간트 시트에서 사용되지 않는 작업은 삭제할 수 있습니다. 단, 루트 작업은 삭제할 수 없습니다. 요약 작업 또는 해당 범위에 있는 작업을 삭제하면, 하위 작업도 모두 함께 삭제됩니다. 작업 삭제 메서드는 다음과 같습니다.

* `removeTasks`
* `removeTasksByRange`
* `clearTasks`
* `clearTasksByRange`

```auto
// 작업 삭제
function deleteTask(ganttSheet) {   
    var project = ganttSheet.project;   
    var rowIds = getSelectedTaskNumbers();   
    project.removeTasks(rowIds);
}
```

## 작업 들여쓰기/내어쓰기

각 작업은 간트 시트에서 레벨을 가지며, 루트 작업은 레벨 0입니다. 선택한 작업을 들여쓰기/내어쓰기하여 레벨을 조정할 수 있습니다.

* 들여쓰기: 레벨이 1 증가하고, 이전 작업이 요약 작업이 됩니다.
* 내어쓰기: 레벨이 1 감소하고, 선택한 작업이 요약 작업이 됩니다.

![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/image.6e9607.png?width=900)
하나 이상의 작업을 동시에 들여쓰기/내어쓰기 할 수 있습니다. 메서드는 [GC.Spread.Sheets.GanttSheet.Project](/spreadjs/api/v19/classes/GC.Spread.Sheets.GanttSheet.Project) 클래스에서 다음과 같이 제공합니다.

* `indentTasks`
* `indentTasksByRange`
* `outdentTasks`
* `outdentTasksByRange`

```auto
// 작업 들여쓰기
function indentTask(ganttSheet) {            
var project = ganttSheet.project;            
var rowIds = getSelectedTaskNumbers();            
project.indentTasks(rowIds);        
}        

// 작업 내어쓰기
function outdentTask(ganttSheet) {            
var project = ganttSheet.project;            
var rowIds = getSelectedTaskNumbers();            
project.outdentTasks(rowIds);        
}
```

## 작업 연결/연결 해제

작업을 연결하여 선행 작업과의 관계를 설정할 수 있습니다. `addDependency` 메서드를 사용하여 `fromTaskNumber`와 `toTaskNumber`를 지정하여 작업 간 의존성을 만들 수 있습니다. 의존성 유형은 다음과 같습니다.

| **작업 의존성 유형** | **예제 이미지** |
| --------- | ------ |
| FS (Finish to Start) | ![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/image.d34202.png) |
| SS (Start to Start) | ![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/image.1bd64e.png) |
| FF (Finish to Finish) | ![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/image.26f48d.png) |
| SF (Start to Finish) | ![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/image.fac05e.png) |

작업 간 의존성 유형은 [GC.Spread.Sheets.TaskDependencyType](/spreadjs/api/v19/modules/GC.Spread.Sheets.GanttSheet#taskdependencytype) API를 사용하여 설정할 수 있으며, 기본값은 FS(Finish to Start)입니다. 또한 `removeDependency` 메서드를 사용하여 작업 연결을 해제하고 의존성을 제거할 수 있습니다.
아래 이미지는 연결된 작업과 연결이 해제된 작업의 예시를 보여줍니다.
![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/image.aec3e9.png?width=900)

```auto
// 작업 연결
function linkTask(ganttSheet) {
        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(ganttSheet) {
            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);
            }
        }
```

> **참고**:
>
> * 요약 작업은 자식 노드와 연결할 수 없습니다.
> * 이미 연결된 작업은 중복 연결할 수 없습니다.
> * 링크 선은 교차할 수 없습니다.
> * 요약 작업의 선행 의존성은 FS 또는 SS만 가능합니다.

## 작업 진행률 변경

간트 시트에서는 작업 완료율을 0\~100%로 표시합니다. 소스 데이터에 `complete` 필드가 있어야 하며, 해당 필드가 추가되면 간트 차트에서 작업 막대 안에 진행률 바가 표시됩니다.
![image](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/image.f31b11.png?width=900)
작업 막대 위에 마우스를 올리고 진행률 바를 드래그하면 완료율을 변경할 수 있습니다. 일반 작업은 수동으로 완료율을 변경할 수 있으며, Spread Designer에서는 0%, 25%, 50%, 75%, 100% 버튼으로 빠르게 조정 가능합니다.
요약 작업의 완료율은 하위 작업을 기준으로 자동 계산됩니다.
**요약 작업 완료율 = (하위 작업 실제 지속 기간 합 / 하위 작업 예상 지속 기간 합) × 100%**
재일정(reschedule) 시, 하위 작업의 추가/삭제/들여쓰기/내어쓰기, 기간 변경, 완료율 변경에 따라 요약 작업이 자동 계산됩니다.

```auto
// GanttSheet 생성 및 "complete" 필드 정의
var ganttSheet = spread.addSheetTab(0, "GanttSheet1", GC.Spread.Sheets.SheetType.ganttSheet);
    var view = myTable1.addView("myView1", [
                { 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 },
                { value: "complete", caption: "% Complete", width: 120 }
    ]);
```

[GC.Spread.Sheets.GanttSheet.Task](/spreadjs/api/v19/classes/GC.Spread.Sheets.GanttSheet.Task) 클래스의 `complete` 속성을 사용하여 완료율을 가져오거나 설정할 수 있으며, `completeThrough` 속성으로 특정 시점까지의 진행률을 표시할 수 있습니다.

```auto
var task = ganttSheet.getTaskByRow(10);
// 완료율 가져오기
console.log(task.complete);
// 완료율 설정
task.complete = 0.5;
// 특정 시점까지 완료율 가져오기
console.log(task.completeThrough);
// 특정 시점까지 완료율 설정
task.completeThrough = task.finish;
```