From e50b78db2f5e74f88b7e5c736f1fca4ca3cbe29b Mon Sep 17 00:00:00 2001
From: jhjang <jhjang@maprex.co.kr>
Date: 목, 25 11월 2021 10:57:04 +0900
Subject: [PATCH] - 워크플로우 담당부서 설정 기능 추가

---
 src/main/java/kr/wisestone/owl/domain/WorkflowTransition.java                    |    2 
 src/main/java/kr/wisestone/owl/vo/IssueStatusVo.java                             |    9 
 src/main/java/kr/wisestone/owl/domain/WorkflowDepartment.java                    |   61 ++++
 src/main/java/kr/wisestone/owl/web/form/WorkflowForm.java                        |   29 +
 src/main/java/kr/wisestone/owl/service/WorkflowDepartmentService.java            |   26 +
 src/main/webapp/views/workflow/workflowAdd.html                                  |    3 
 src/main/java/kr/wisestone/owl/web/condition/WorkflowDepartmentCondition.java    |   42 +++
 src/main/java/kr/wisestone/owl/repository/WorkflowDepartmentRepository.java      |   12 
 src/main/java/kr/wisestone/owl/vo/WorkflowVo.java                                |    6 
 src/main/webapp/custom_components/js-workflow/js-workflow.directive.js           |  126 ++++++++
 src/main/java/kr/wisestone/owl/constant/MsgConstants.java                        |    2 
 src/main/webapp/scripts/app/workflow/workflowList.controller.js                  |    6 
 src/main/java/kr/wisestone/owl/service/impl/WorkflowServiceImpl.java             |   49 ++
 src/main/webapp/custom_components/js-autocomplete-multi/js-autocomplete-multi.js |    2 
 src/main/resources/system_prod.properties                                        |   85 +++--
 src/main/java/kr/wisestone/owl/service/impl/WorkflowDepartmentServiceImpl.java   |  134 +++++++++
 src/main/java/kr/wisestone/owl/vo/WorkflowDepartmentVo.java                      |   46 +++
 src/main/webapp/scripts/app/workflow/workflowAdd.controller.js                   |   35 ++
 src/main/resources/mybatis/query-template/workflow-department-template.xml       |   24 +
 src/main/java/kr/wisestone/owl/mapper/WorkflowDepartmentMapper.java              |   14 +
 src/main/java/kr/wisestone/owl/web/controller/WorkflowController.java            |   20 +
 src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js     |   16 +
 src/main/webapp/custom_components/js-workflow/js-workflow.html                   |   31 +-
 src/main/webapp/scripts/components/workflow/workflow.service.js                  |    6 
 24 files changed, 716 insertions(+), 70 deletions(-)

diff --git a/src/main/java/kr/wisestone/owl/constant/MsgConstants.java b/src/main/java/kr/wisestone/owl/constant/MsgConstants.java
index cdb4a8b..3672534 100644
--- a/src/main/java/kr/wisestone/owl/constant/MsgConstants.java
+++ b/src/main/java/kr/wisestone/owl/constant/MsgConstants.java
@@ -78,6 +78,8 @@
     public static final String WORKFLOW_REQUIRE_ISSUE_STATUS_TYPE_TO_OPEN = "WORKFLOW_REQUIRE_ISSUE_STATUS_TYPE_TO_OPEN"; //  �썙�겕�뵆濡쒖슦�뿉�뒗 �긽�깭 �냽�꽦 '吏꾪뻾' �씤 �씠�뒋 �긽�깭媛� 1媛� �씠�긽 議댁옱�빐�빞 �빀�땲�떎.
     public static final String WORKFLOW_REQUIRE_ISSUE_STATUS_TYPE_TO_CLOSE = "WORKFLOW_REQUIRE_ISSUE_STATUS_TYPE_TO_CLOSE"; //  �썙�겕�뵆濡쒖슦�뿉�뒗 �긽�깭 �냽�꽦 '醫낅즺' �씤 �씠�뒋 �긽�깭媛� 1媛� �씠�긽 議댁옱�빐�빞 �빀�땲�떎.
 
+    public static final String WORKFLOW_DEPARTMENT_NOT_EXIST = "WORKFLOW_DEPARTMENT_NOT_EXIST";   //  �썙�겕�뵆濡쒖슦 遺��꽌媛� 議댁옱�븯吏� �븡�뒿�땲�떎.
+
     public static final String CUSTOM_FIELD_NOT_EXIST = "CUSTOM_FIELD_NOT_EXIST";   //  �궗�슜�옄 �젙�쓽 �븘�뱶媛� 議댁옱�븯吏� �븡�뒿�땲�떎.
     public static final String CUSTOM_FIELD_NOT_NAME = "CUSTOM_FIELD_NOT_NAME"; //  �궗�슜�옄 �젙�쓽 �븘�뱶紐낆씠 �엯�젰�릺吏� �븡�븯�뒿�땲�떎.
     public static final String CUSTOM_FIELD_NAME_MAX_LENGTH_OUT = "CUSTOM_FIELD_NAME_MAX_LENGTH_OUT";   //  �궗�슜�옄 �젙�쓽 �븘�뱶紐낆� 理쒕� 50湲��옄源뚯� �엯�젰�븷 �닔 �엳�뒿�땲�떎.
diff --git a/src/main/java/kr/wisestone/owl/domain/WorkflowDepartment.java b/src/main/java/kr/wisestone/owl/domain/WorkflowDepartment.java
new file mode 100644
index 0000000..3b433ed
--- /dev/null
+++ b/src/main/java/kr/wisestone/owl/domain/WorkflowDepartment.java
@@ -0,0 +1,61 @@
+package kr.wisestone.owl.domain;
+
+import org.hibernate.annotations.Type;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+@Entity
+public class WorkflowDepartment extends BaseEntity implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "workflow_id")
+    private Workflow workflow;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "department_id")
+    private Department department;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "issue_status_id")
+    private IssueStatus issueStatus;
+
+    public WorkflowDepartment(){}
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Workflow getWorkflow() {
+        return workflow;
+    }
+
+    public void setWorkflow(Workflow workflow) {
+        this.workflow = workflow;
+    }
+
+    public Department getDepartment() {
+        return department;
+    }
+
+    public void setDepartment(Department department) {
+        this.department = department;
+    }
+
+    public IssueStatus getIssueStatus() {
+        return issueStatus;
+    }
+
+    public void setIssueStatus(IssueStatus issueStatus) {
+        this.issueStatus = issueStatus;
+    }
+}
diff --git a/src/main/java/kr/wisestone/owl/domain/WorkflowTransition.java b/src/main/java/kr/wisestone/owl/domain/WorkflowTransition.java
index 650d2c1..3274bb7 100644
--- a/src/main/java/kr/wisestone/owl/domain/WorkflowTransition.java
+++ b/src/main/java/kr/wisestone/owl/domain/WorkflowTransition.java
@@ -1,5 +1,6 @@
 package kr.wisestone.owl.domain;
 
+import org.hibernate.annotations.DynamicInsert;
 import org.hibernate.annotations.Type;
 
 import javax.persistence.*;
@@ -9,6 +10,7 @@
  * Created by wisestone on 2018-03-07.
  */
 @Entity
+@DynamicInsert
 public class WorkflowTransition extends BaseEntity implements Serializable {
     private static final long serialVersionUID = 1L;
 
diff --git a/src/main/java/kr/wisestone/owl/mapper/WorkflowDepartmentMapper.java b/src/main/java/kr/wisestone/owl/mapper/WorkflowDepartmentMapper.java
new file mode 100644
index 0000000..6153c94
--- /dev/null
+++ b/src/main/java/kr/wisestone/owl/mapper/WorkflowDepartmentMapper.java
@@ -0,0 +1,14 @@
+package kr.wisestone.owl.mapper;
+
+import kr.wisestone.owl.web.condition.WorkflowCondition;
+import kr.wisestone.owl.web.condition.WorkflowDepartmentCondition;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Map;
+
+@Repository
+public interface WorkflowDepartmentMapper {
+    List<Map<String, Object>> find(WorkflowDepartmentCondition workflowCondition);
+    void deleteAll(WorkflowDepartmentCondition workflowCondition);
+}
diff --git a/src/main/java/kr/wisestone/owl/repository/WorkflowDepartmentRepository.java b/src/main/java/kr/wisestone/owl/repository/WorkflowDepartmentRepository.java
new file mode 100644
index 0000000..55f89cb
--- /dev/null
+++ b/src/main/java/kr/wisestone/owl/repository/WorkflowDepartmentRepository.java
@@ -0,0 +1,12 @@
+package kr.wisestone.owl.repository;
+
+import kr.wisestone.owl.domain.WorkflowDepartment;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
+
+public interface WorkflowDepartmentRepository extends JpaRepository<WorkflowDepartment, Long> {
+    List<WorkflowDepartment> findByWorkflowIdAndIssueStatusId(@Param("workflowId") Long workflowId, @Param("issueStatusId") Long issueStatusId);
+    List<WorkflowDepartment> findByWorkflowId(@Param("workflowId") Long workflowId);
+}
diff --git a/src/main/java/kr/wisestone/owl/service/WorkflowDepartmentService.java b/src/main/java/kr/wisestone/owl/service/WorkflowDepartmentService.java
new file mode 100644
index 0000000..8e6474f
--- /dev/null
+++ b/src/main/java/kr/wisestone/owl/service/WorkflowDepartmentService.java
@@ -0,0 +1,26 @@
+package kr.wisestone.owl.service;
+
+import kr.wisestone.owl.domain.IssueStatus;
+import kr.wisestone.owl.domain.Workflow;
+import kr.wisestone.owl.domain.WorkflowDepartment;
+import kr.wisestone.owl.domain.WorkflowTransition;
+import kr.wisestone.owl.domain.enumType.ProjectType;
+import kr.wisestone.owl.util.MapUtil;
+import kr.wisestone.owl.vo.IssueStatusVo;
+import kr.wisestone.owl.vo.WorkflowDepartmentVo;
+import kr.wisestone.owl.vo.WorkflowTransitionVo;
+import kr.wisestone.owl.web.condition.WorkflowDepartmentCondition;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public interface WorkflowDepartmentService extends AbstractService<WorkflowDepartment, Long, JpaRepository<WorkflowDepartment, Long>> {
+
+    WorkflowDepartment getWorkflowDepartment(Long id);
+    List<WorkflowDepartmentVo> find(WorkflowDepartmentCondition condition);
+    void modify(Workflow workflow, List<IssueStatusVo> issueStatusVos);
+    void remove(Long workflowId);
+}
diff --git a/src/main/java/kr/wisestone/owl/service/impl/WorkflowDepartmentServiceImpl.java b/src/main/java/kr/wisestone/owl/service/impl/WorkflowDepartmentServiceImpl.java
new file mode 100644
index 0000000..517cd31
--- /dev/null
+++ b/src/main/java/kr/wisestone/owl/service/impl/WorkflowDepartmentServiceImpl.java
@@ -0,0 +1,134 @@
+package kr.wisestone.owl.service.impl;
+
+
+import com.google.common.collect.Lists;
+import kr.wisestone.owl.constant.MsgConstants;
+import kr.wisestone.owl.domain.*;
+import kr.wisestone.owl.domain.enumType.IssueStatusType;
+import kr.wisestone.owl.domain.enumType.ProjectType;
+import kr.wisestone.owl.exception.OwlRuntimeException;
+import kr.wisestone.owl.mapper.WorkflowDepartmentMapper;
+import kr.wisestone.owl.repository.WorkflowDepartmentRepository;
+import kr.wisestone.owl.repository.WorkflowTransitionRepository;
+import kr.wisestone.owl.service.*;
+import kr.wisestone.owl.util.ConvertUtil;
+import kr.wisestone.owl.util.MapUtil;
+import kr.wisestone.owl.vo.*;
+import kr.wisestone.owl.web.condition.WorkflowCondition;
+import kr.wisestone.owl.web.condition.WorkflowDepartmentCondition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+
+
+@Service
+public class WorkflowDepartmentServiceImpl extends AbstractServiceImpl<WorkflowDepartment, Long, JpaRepository<WorkflowDepartment, Long>> implements WorkflowDepartmentService {
+
+    private static final Logger log = LoggerFactory.getLogger(WorkflowDepartmentServiceImpl.class);
+
+    @Autowired
+    private WorkflowDepartmentMapper workflowDepartmentMapper;
+
+    @Autowired
+    private WorkflowDepartmentRepository workflowDepartmentRepository;
+
+    @Autowired
+    private IssueStatusService issueStatusService;
+
+    @Autowired
+    private DepartmentService departmentService;
+
+    @Override
+    protected JpaRepository<WorkflowDepartment, Long> getRepository() {
+        return workflowDepartmentRepository;
+    }
+
+    @Override
+    public WorkflowDepartment getWorkflowDepartment(Long id) {
+        if (id == null) {
+            throw new OwlRuntimeException(
+                    this.messageAccessor.getMessage(MsgConstants.WORKFLOW_DEPARTMENT_NOT_EXIST));
+        }
+
+        WorkflowDepartment workflowDepartment = this.findOne(id);
+
+        if (workflowDepartment == null) {
+            throw new OwlRuntimeException(
+                    this.messageAccessor.getMessage(MsgConstants.WORKFLOW_DEPARTMENT_NOT_EXIST));
+        }
+
+        return workflowDepartment;
+    }
+
+    // �떞�떦 遺��꽌�젙蹂대�� 議고쉶�븳�떎.
+    @Transactional(readOnly = true)
+    @Override
+    public List<WorkflowDepartmentVo> find(WorkflowDepartmentCondition condition) {
+
+        List<WorkflowDepartment> workflowDepartmentList = null;
+        List<WorkflowDepartmentVo> workflowDepartmentVos = Lists.newArrayList();
+        //�썙�겕�뵆濡쒖슦, �씠�뒋 �긽�깭蹂� �떞�떦遺��꽌 議고쉶
+        if (condition.getWorkflowId() != null && condition.getIssueStatusId() != null) {
+            workflowDepartmentList = this.workflowDepartmentRepository.findByWorkflowIdAndIssueStatusId(condition.getWorkflowId(), condition.getIssueStatusId());
+
+            for(int i = 0; i < workflowDepartmentList.size(); i++){
+                WorkflowDepartment workflowDepartment = workflowDepartmentList.get(i);
+                WorkflowDepartmentVo workflowDepartmentVo = ConvertUtil.copyProperties(workflowDepartment, WorkflowDepartmentVo.class);
+                DepartmentVo departmentVo = ConvertUtil.copyProperties(workflowDepartment.getDepartment(), DepartmentVo.class);
+                departmentVo.setByName(departmentVo.getDepartmentName());
+                workflowDepartmentVo.setDepartmentVo(departmentVo);
+
+                workflowDepartmentVos.add(workflowDepartmentVo);
+            }
+        } else {
+            // �썙�겕�뵆濡쒖슦 紐⑤뱺 �떞�떦 遺��꽌 議고쉶
+            List<Map<String, Object>> results = this.workflowDepartmentMapper.find(condition);
+            List<WorkflowDepartmentCondition> conditions = ConvertUtil.convertListToListClass(results, WorkflowDepartmentCondition.class);
+
+            for (WorkflowDepartmentCondition cond : conditions) {
+                WorkflowDepartmentVo workflowDepartmentVo = new WorkflowDepartmentVo();
+                Department department = this.departmentService.getDepartment(cond.getDepartmentId());
+                DepartmentVo departmentVo = ConvertUtil.copyProperties(department, DepartmentVo.class);
+                departmentVo.setByName(department.getDepartmentName());
+                workflowDepartmentVo.setDepartmentVo(departmentVo);
+                workflowDepartmentVos.add(workflowDepartmentVo);
+            }
+        }
+
+        return  workflowDepartmentVos;
+    }
+
+    //  �썙�겕�뵆濡쒖슦�쓽 �긽�깭�뿉 吏��젙�맂 �떞�떦遺��꽌瑜� 蹂�寃쏀븳�떎
+    @Override
+    @Transactional
+    public void modify(Workflow workflow, List<IssueStatusVo> issueStatusVos) {
+        this.remove(workflow.getId());
+        List<WorkflowDepartment> workflowDepartmentList = Lists.newArrayList();
+        for (IssueStatusVo issueStatusVo : issueStatusVos) {
+            for (WorkflowDepartmentVo workflowDepartmentVo : issueStatusVo.getWorkflowDepartmentVos()) {
+                WorkflowDepartment workflowDepartment = ConvertUtil.copyProperties(workflowDepartmentVo, WorkflowDepartment.class);
+                workflowDepartment.setIssueStatus(this.issueStatusService.getIssueStatus(issueStatusVo.getId()));
+                workflowDepartment.setWorkflow(workflow);
+                Department department = this.departmentService.getDepartment(workflowDepartmentVo.getDepartmentVo().getId());
+                workflowDepartment.setDepartment(department);
+
+                workflowDepartmentList.add(workflowDepartment);
+             }
+        }
+        this.workflowDepartmentRepository.saveAll(workflowDepartmentList);
+    }
+
+    @Override
+    @Transactional
+    public void remove(Long workflowId) {
+        WorkflowDepartmentCondition condition = new WorkflowDepartmentCondition();
+        condition.setWorkflowId(workflowId);
+
+        this.workflowDepartmentMapper.deleteAll(condition);
+    }
+}
diff --git a/src/main/java/kr/wisestone/owl/service/impl/WorkflowServiceImpl.java b/src/main/java/kr/wisestone/owl/service/impl/WorkflowServiceImpl.java
index 5f72e5d..be7a902 100644
--- a/src/main/java/kr/wisestone/owl/service/impl/WorkflowServiceImpl.java
+++ b/src/main/java/kr/wisestone/owl/service/impl/WorkflowServiceImpl.java
@@ -13,6 +13,7 @@
 import kr.wisestone.owl.util.ConvertUtil;
 import kr.wisestone.owl.vo.*;
 import kr.wisestone.owl.web.condition.WorkflowCondition;
+import kr.wisestone.owl.web.condition.WorkflowDepartmentCondition;
 import kr.wisestone.owl.web.form.WorkflowForm;
 import kr.wisestone.owl.web.view.ExcelView;
 import org.apache.commons.lang3.StringUtils;
@@ -26,9 +27,7 @@
 import org.springframework.ui.Model;
 import org.springframework.web.servlet.ModelAndView;
 import javax.servlet.http.HttpServletRequest;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 @Service
 public class WorkflowServiceImpl extends AbstractServiceImpl<Workflow, Long, JpaRepository<Workflow, Long>>
@@ -44,6 +43,9 @@
 
     @Autowired
     private WorkflowTransitionService workflowTransitionService;
+
+    @Autowired
+    private WorkflowDepartmentService workflowDepartmentService;
 
     @Autowired
     private WorkspaceService workspaceService;
@@ -123,9 +125,9 @@
         Workspace workspace = this.workspaceService.getWorkspace(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());
         workflow.setWorkspace(workspace);
 
-        this.workflowRepository.saveAndFlush(workflow);
-
+        workflow = this.workflowRepository.saveAndFlush(workflow);
         this.workflowTransitionService.modify(workflow, workflowForm.getIssueStatusVos());
+        this.workflowDepartmentService.modify(workflow, workflowForm.getIssueStatusVos());
 
         return workflow;
     }
@@ -173,6 +175,8 @@
         List<WorkflowVo> workflowVos = ConvertUtil.convertListToListClass(results, WorkflowVo.class); //workflow 由ъ뒪�듃
         //  �썙�겕�뵆濡쒖슦瑜� �궗�슜�븯�뒗 �씠�뒋 �쑀�삎 �젙蹂대�� 異붽��븳�떎.
         this.setIssueTypeVos(workflowVos);
+        //  �썙�겕�뵆濡쒖슦 �떞�떦遺��꽌 �젙蹂대�� 異붽��븳�떎.
+        this.setDepartmentVos(workflowVos);
 
         resJsonData.put(Constants.REQ_KEY_PAGE_VO, new ResPage(pageable.getPageNumber(), pageable.getPageSize(),
                 totalPage, totalCount));
@@ -191,6 +195,22 @@
         }
     }
 
+    //  �썙�겕�뵆濡쒖슦瑜� �궗�슜�븯�뒗 遺��꽌 �젙蹂대�� 異붽��븳�떎.
+    private void setDepartmentVos(List<WorkflowVo> workflowVos) {
+        for (WorkflowVo workflowVo : workflowVos) {
+            Workflow workflow = this.getWorkflow(workflowVo.getId());
+
+            WorkflowDepartmentCondition condition = new WorkflowDepartmentCondition();
+            condition.setWorkflowId(workflow.getId());
+            List<WorkflowDepartmentVo> workflowDepartmentVos = this.workflowDepartmentService.find(condition);
+            if (workflowDepartmentVos != null && workflowDepartmentVos.size() > 0) {
+                IssueStatusVo issueStatusVo = new IssueStatusVo();
+                issueStatusVo.setWorkflowDepartmentVos(workflowDepartmentVos);
+                workflowVo.addIssueStatusVos(issueStatusVo);
+            }
+        }
+    }
+
     //  �썙�겕�뵆濡쒖슦 �긽�꽭 �젙蹂대�� 議고쉶�븳�떎.
     @Override
     @Transactional(readOnly = true)
@@ -203,7 +223,15 @@
 
             switch (workflowCondition.getDeep()) {
                 case "01" : //  �뿰愿��맂 �씠�뒋 �긽�깭�� �쟾�씠�꽑 �젙蹂대�� 媛��졇�삩�떎.
-                    workflowVo.setIssueStatusVos(this.issueStatusService.findByWorkflowId(workflowCondition.getId()));
+                    List<IssueStatusVo> issueStatusVos = this.issueStatusService.findByWorkflowId(workflowCondition.getId());
+                    for (IssueStatusVo issueStatusVo : issueStatusVos) {
+                        WorkflowDepartmentCondition condition = new WorkflowDepartmentCondition();
+                        condition.setWorkflowId(workflowVo.getId());
+                        condition.setIssueStatusId(issueStatusVo.getId());
+                        List<WorkflowDepartmentVo> workflowDepartmentVos = this.workflowDepartmentService.find(condition);
+                        issueStatusVo.setWorkflowDepartmentVos(workflowDepartmentVos);
+                    }
+                    workflowVo.setIssueStatusVos(issueStatusVos);
                     break;
             }
         }
@@ -223,6 +251,8 @@
         this.verifyName(workflowForm.getName(), workflowForm.getId());
         workflow.setName(workflowForm.getName());
 
+        // �떞�떦 遺��꽌 �젙蹂� 蹂�寃�
+        this.workflowDepartmentService.modify(workflow, workflowForm.getIssueStatusVos());
         this.workflowTransitionService.modify(workflow, workflowForm.getIssueStatusVos());
         //  �썙�겕�뵆濡쒖슦媛� 蹂�寃쎈릺�뿀�뒗吏� �솗�씤�븯怨� 蹂�寃쎈릺�뿀�쓣 寃쎌슦 �씠�뒋 �긽�깭媛� �뾾�뒗 �씠�뒋�뒗 '�깮�꽦' �씤 �씠�뒋 �긽�깭濡� �씠�룞�븳�떎.
         this.checkWorkflowChange(workflow);
@@ -267,15 +297,16 @@
                     this.messageAccessor.getMessage(MsgConstants.WORKFLOW_REMOVE_NOT_SELECT));
         }
 
-        for (Long projectId : workflowForm.getRemoveIds()) {
-            this.removeWorkflow(projectId);
+        for (Long workflowId : workflowForm.getRemoveIds()) {
+            this.removeWorkflow(workflowId);
         }
-
         this.workflowRepository.flush();
     }
 
     private void removeWorkflow(Long workflowId) {
         Workflow workflow = this.getWorkflow(workflowId);
+        // �썙�겕�뵆濡쒖슦 �떞�떦遺��꽌 �궘�젣
+        this.workflowDepartmentService.remove(workflowId);
         //  �썙�겕�뵆濡쒖슦瑜� �씠�뒋 ���엯�뿉�꽌 �궗�슜�븯怨� �엳�뒗吏� �솗�씤
         this.checkIssueTypeWorkflow(workflow);
         this.workflowRepository.delete(workflow);
diff --git a/src/main/java/kr/wisestone/owl/vo/IssueStatusVo.java b/src/main/java/kr/wisestone/owl/vo/IssueStatusVo.java
index 7bad8e9..c7beda3 100644
--- a/src/main/java/kr/wisestone/owl/vo/IssueStatusVo.java
+++ b/src/main/java/kr/wisestone/owl/vo/IssueStatusVo.java
@@ -18,6 +18,7 @@
     private Long xLocation; //  �떎�씠�뼱洹몃옩 x異� 醫뚰몴 - workflowTransition �뿉�꽌 ���옣�븯怨� �엳�떎.
     private Long yLocation; //  �떎�씠�뼱洹몃옩 y異� 醫뚰몴 - workflowTransition �뿉�꽌 ���옣�븯怨� �엳�떎.
     private List<WorkflowTransitionVo> workflowTransitionVos = Lists.newArrayList();
+    private List<WorkflowDepartmentVo> workflowDepartmentVos = Lists.newArrayList();
     private List<WorkflowVo> workflowVos = Lists.newArrayList();    //  �씠�뒋 �긽�깭 紐⑸줉�뿉�꽌 �씠�뒋 �긽�깭瑜� �궗�슜�븯怨� �엳�뒗 �썙�겕�뵆濡쒖슦 紐⑸줉 �젙蹂�
     private Boolean modifyPermissionCheck = Boolean.TRUE;   //  �씠�뒋 �긽�깭�뒗 紐⑤뱺 �궗�엺�뱾�씠 �닔�젙, �궘�젣�븷 �닔 �엳�뼱�꽌 湲곕낯 媛믪씠 True
 
@@ -132,4 +133,12 @@
     public int compareTo(IssueStatusVo issueStatusVo) {
         return this.issueStatusType.compareTo(issueStatusVo.getIssueStatusType());
     }
+
+    public List<WorkflowDepartmentVo> getWorkflowDepartmentVos() {
+        return workflowDepartmentVos;
+    }
+
+    public void setWorkflowDepartmentVos(List<WorkflowDepartmentVo> workflowDepartmentVos) {
+        this.workflowDepartmentVos = workflowDepartmentVos;
+    }
 }
diff --git a/src/main/java/kr/wisestone/owl/vo/WorkflowDepartmentVo.java b/src/main/java/kr/wisestone/owl/vo/WorkflowDepartmentVo.java
new file mode 100644
index 0000000..d10e371
--- /dev/null
+++ b/src/main/java/kr/wisestone/owl/vo/WorkflowDepartmentVo.java
@@ -0,0 +1,46 @@
+package kr.wisestone.owl.vo;
+
+import kr.wisestone.owl.domain.IssueStatus;
+
+import java.util.List;
+
+public class WorkflowDepartmentVo extends BaseVo {
+    private Long id;
+    private WorkflowVo workflowVo;
+    private IssueStatusVo issueStatusVo;
+    private DepartmentVo departmentVo;
+
+    public WorkflowDepartmentVo(){}
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public WorkflowVo getWorkflowVo() {
+        return workflowVo;
+    }
+
+    public void setWorkflowVo(WorkflowVo workflowVo) {
+        this.workflowVo = workflowVo;
+    }
+
+    public DepartmentVo getDepartmentVo() {
+        return departmentVo;
+    }
+
+    public void setDepartmentVo(DepartmentVo departmentVo) {
+        this.departmentVo = departmentVo;
+    }
+
+    public IssueStatusVo getIssueStatusVo() {
+        return issueStatusVo;
+    }
+
+    public void setIssueStatusVo(IssueStatusVo issueStatusVo) {
+        this.issueStatusVo = issueStatusVo;
+    }
+}
diff --git a/src/main/java/kr/wisestone/owl/vo/WorkflowVo.java b/src/main/java/kr/wisestone/owl/vo/WorkflowVo.java
index ae316a6..21f50a8 100644
--- a/src/main/java/kr/wisestone/owl/vo/WorkflowVo.java
+++ b/src/main/java/kr/wisestone/owl/vo/WorkflowVo.java
@@ -64,4 +64,10 @@
     public void setIssueTypeVos(List<IssueTypeVo> issueTypeVos) {
         this.issueTypeVos = issueTypeVos;
     }
+
+    public void addIssueStatusVos(IssueStatusVo issueStatusVo) {
+        if (this.issueStatusVos != null) {
+            this.issueStatusVos.add(issueStatusVo);
+        }
+    }
 }
diff --git a/src/main/java/kr/wisestone/owl/web/condition/WorkflowDepartmentCondition.java b/src/main/java/kr/wisestone/owl/web/condition/WorkflowDepartmentCondition.java
new file mode 100644
index 0000000..3032f39
--- /dev/null
+++ b/src/main/java/kr/wisestone/owl/web/condition/WorkflowDepartmentCondition.java
@@ -0,0 +1,42 @@
+package kr.wisestone.owl.web.condition;
+
+public class WorkflowDepartmentCondition {
+    private Long id;
+    private Long workflowId;
+    private Long issueStatusId;
+    private Long departmentId;
+
+    public WorkflowDepartmentCondition(){}
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getWorkflowId() {
+        return workflowId;
+    }
+
+    public void setWorkflowId(Long workflowId) {
+        this.workflowId = workflowId;
+    }
+
+    public Long getIssueStatusId() {
+        return issueStatusId;
+    }
+
+    public void setIssueStatusId(Long issueStatusId) {
+        this.issueStatusId = issueStatusId;
+    }
+
+    public Long getDepartmentId() {
+        return departmentId;
+    }
+
+    public void setDepartmentId(Long departmentId) {
+        this.departmentId = departmentId;
+    }
+}
diff --git a/src/main/java/kr/wisestone/owl/web/controller/WorkflowController.java b/src/main/java/kr/wisestone/owl/web/controller/WorkflowController.java
index 1320cee..6fad2bd 100644
--- a/src/main/java/kr/wisestone/owl/web/controller/WorkflowController.java
+++ b/src/main/java/kr/wisestone/owl/web/controller/WorkflowController.java
@@ -1,9 +1,12 @@
 package kr.wisestone.owl.web.controller;
 
 import kr.wisestone.owl.constant.Constants;
+import kr.wisestone.owl.service.DepartmentService;
+import kr.wisestone.owl.service.UserDepartmentService;
 import kr.wisestone.owl.service.WorkflowService;
 import kr.wisestone.owl.util.ConvertUtil;
 import kr.wisestone.owl.vo.AttachedFileVo;
+import kr.wisestone.owl.web.condition.DepartmentCondition;
 import kr.wisestone.owl.web.condition.WorkflowCondition;
 import kr.wisestone.owl.web.form.WorkflowForm;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -30,6 +33,9 @@
 
     @Autowired
     private WorkflowService workflowService;
+
+    @Autowired
+    private DepartmentService departmentService;
 
     //  �썙�겕�뵆濡쒖슦 �깮�꽦
     @RequestMapping(value = "/workflow/add", produces = MediaType.APPLICATION_JSON_VALUE)
@@ -80,7 +86,6 @@
     }
 
     //  �썙�겕�뵆濡쒖슦 �궘�젣
-    @SuppressWarnings("unchecked")
     @RequestMapping(value = "/workflow/remove", produces = MediaType.APPLICATION_JSON_VALUE)
     public
     @ResponseBody
@@ -97,4 +102,17 @@
     public ModelAndView downloadExcel(HttpServletRequest request, Model model) {
         return this.workflowService.downloadExcel(request, model);
     }
+
+    //  �썙�겕�뵆濡쒖슦 �떞�떦遺��꽌 媛��졇�삤湲�
+    @RequestMapping(value = "/workflow/findDepartments", produces = MediaType.APPLICATION_JSON_VALUE)
+    public
+    @ResponseBody
+    Map<String, Object> findDepartments(@RequestBody Map<String, Map<String, Object>> params) {
+        Map<String, Object> resJsonData = new HashMap<>();
+        Pageable pageable = this.pageUtil.convertPageable(this.getPageVo(params));
+
+        this.departmentService.find(resJsonData, DepartmentCondition.make(params.get(Constants.REQ_KEY_CONTENT)), pageable);
+
+        return this.setSuccessMessage(resJsonData);
+    }
 }
diff --git a/src/main/java/kr/wisestone/owl/web/form/WorkflowForm.java b/src/main/java/kr/wisestone/owl/web/form/WorkflowForm.java
index f42ace5..69f3a1a 100644
--- a/src/main/java/kr/wisestone/owl/web/form/WorkflowForm.java
+++ b/src/main/java/kr/wisestone/owl/web/form/WorkflowForm.java
@@ -3,9 +3,9 @@
 import com.google.common.collect.Lists;
 import kr.wisestone.owl.util.ConvertUtil;
 import kr.wisestone.owl.util.MapUtil;
-import kr.wisestone.owl.vo.IssueStatusVo;
-import kr.wisestone.owl.vo.WorkflowTransitionVo;
+import kr.wisestone.owl.vo.*;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -19,6 +19,7 @@
     private String description;
     private List<IssueStatusVo> issueStatusVos = Lists.newArrayList();
     private List<Long> removeIds = Lists.newArrayList();
+    private List<WorkflowDepartmentVo> workflowDepartmentVos = Lists.newArrayList();
 
     public WorkflowForm(){}
 
@@ -39,6 +40,8 @@
 
         for (Map<String, Object> issueStatusVo : tempIssueStatusVos) {
             IssueStatusVo addIssueStatusVo = ConvertUtil.convertMapToClass(issueStatusVo, IssueStatusVo.class);
+
+
             //  issueStatus x, y 醫뚰몴 媛� 蹂�寃� �젙蹂� �뀑�똿
             for (Map<String, Object> node : nodes) {
                 Long nodeId = MapUtil.getLong(node, "id");
@@ -77,6 +80,20 @@
                     }
                 }
             }
+
+            // �떞�떦 遺��꽌 �뀑�똿
+            List<Map<String, Object>> workflowDepartments = (List)issueStatusVo.get("workflowDepartmentVos");
+            List<WorkflowDepartmentVo> departmentVos = Lists.newArrayList();
+            for (Map<String, Object> workflowDepartment : workflowDepartments) {
+                Map<String, Object> department = (Map<String, Object>)workflowDepartment.get("departmentVo");
+                DepartmentVo departmentVo = ConvertUtil.convertMapToClass(department, DepartmentVo.class);
+                WorkflowDepartmentVo workflowDepartmentVo = new WorkflowDepartmentVo();
+                workflowDepartmentVo.setDepartmentVo(departmentVo);
+                workflowDepartmentVo.setIssueStatusVo(addIssueStatusVo);
+
+                departmentVos.add(workflowDepartmentVo);
+            }
+            addIssueStatusVo.setWorkflowDepartmentVos(departmentVos);
 
 
             addIssueStatusVo.setWorkflowTransitionVos(ConvertUtil.convertListToListClass(workflowTransitionVos, WorkflowTransitionVo.class));
@@ -141,4 +158,12 @@
     public void addRemoveIds(Long removeId) {
         this.removeIds.add(removeId);
     }
+
+    public List<WorkflowDepartmentVo> getWorkflowDepartmentVos() {
+        return workflowDepartmentVos;
+    }
+
+    public void setWorkflowDepartmentVos(List<WorkflowDepartmentVo> workflowDepartmentVos) {
+        this.workflowDepartmentVos = workflowDepartmentVos;
+    }
 }
diff --git a/src/main/resources/mybatis/query-template/workflow-department-template.xml b/src/main/resources/mybatis/query-template/workflow-department-template.xml
new file mode 100644
index 0000000..4215dc0
--- /dev/null
+++ b/src/main/resources/mybatis/query-template/workflow-department-template.xml
@@ -0,0 +1,24 @@
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="kr.wisestone.owl.mapper.WorkflowDepartmentMapper">
+
+    <select id="find" resultType="java.util.HashMap" parameterType="kr.wisestone.owl.web.condition.WorkflowDepartmentCondition">
+        SELECT
+        wd.id as id,
+        wd.workflow_id as workflowId,
+        wd.issue_status_id as issueStatusId,
+        wd.department_id as departmentId
+        FROM
+        workflow_department wd
+        WHERE 1=1
+        AND wd.workflow_id = #{workflowId}
+        GROUP BY wd.department_id
+    </select>
+
+    <select id="deleteAll" resultType="java.util.HashMap" parameterType="kr.wisestone.owl.web.condition.WorkflowDepartmentCondition">
+       delete wd FROM
+           workflow_department wd
+       WHERE wd.workflow_id = #{workflowId}
+    </select>
+</mapper>
\ No newline at end of file
diff --git a/src/main/resources/system_prod.properties b/src/main/resources/system_prod.properties
index d7b5a81..139801f 100644
--- a/src/main/resources/system_prod.properties
+++ b/src/main/resources/system_prod.properties
@@ -1,92 +1,103 @@
 db.primary.driverName=org.mariadb.jdbc.Driver
-db.primary.url=jdbc:mariadb://IP\uC8FC\uC18C \uC785\uB825/dev_db?allowMultiQueries=true
-db.replica1.url=jdbc:mariadb://IP\uC8FC\uC18C \uC785\uB825/dev_db?allowMultiQueries=true
+db.primary.url=jdbc:mariadb://127.0.0.1/prod_db?allowMultiQueries=true
+db.replica1.url=jdbc:mariadb://127.0.0.1/prod_db?allowMultiQueries=true
 db.replica2.url=
 db.replica3.url=
 db.replica4.url=
 db.replica5.url=
-db.primary.userName=ID
-db.primary.password=\uBE44\uBC00\uBC88\uD638
+db.primary.userName=root
+db.primary.password=maponrex
 
 
 # elasticSearch \uC124\uC815
 elastic.search.hosts=http://52.78.198.178:9200
 
 # kafka \uC124\uC815
-kafka.bootstrap.servers=ec2-52-78-150-61.ap-northeast-2.compute.amazonaws.com:9092,ec2-52-79-150-7.ap-northeast-2.compute.amazonaws.com:9092,ec2-52-79-193-191.ap-northeast-2.compute.amazonaws.com:9092
-kafka.consumer.group.id=prod-common-group
-kafka.common.topic=prod-common-topic
+# use kafka or not
+# kafka by zenith at 20200625
+use.kafka=false
 
+# kafka.bootstrap.servers=ec2-52-78-150-61.ap-northeast-2.compute.amazonaws.com:9092,ec2-52-79-150-7.ap-northeast-2.compute.amazonaws.com:9092,ec2-52-79-193-191.ap-northeast-2.compute.amazonaws.com:9092
+kafka.bootstrap.servers=127.0.0.2:9092
+kafka.consumer.group.id=dev-common-group
+kafka.common.topic=dev-common-topic
 
-# redis setting
-redis.host=prd-session-01.80nhsk.ng.0001.apn2.cache.amazonaws.com
+# redis \uC124\uC815
+redis.host=127.0.0.1
 redis.port=6379
-redis.common.topic=prod-common-topic
+redis.common.topic=dev-common-topic
 spring.session.timeout=36000
+
+
+# License Key \uC124\uC815
+owl.license.key=1234
 
 # mail attached file path
 mail.file.path=C:/downloads/
 mail.account=
 mail.password=
 
-# email send
-email.host=mail.g2works.kr
+# email \uC124\uC815
+email.host=mail.g2works.kra
 email.port=587
-email.userName=supportowl@wisestone.kr
-email.password=Stone0620**
+email.userName=wyu@maprex.co.kr
+email.password=1234
 email.transport.protocol=smtp
 email.smtp.auth=true
 email.smtp.starttle.enable=true
 email.debug=true
-email.sendUrl=http://maprex.iptime.org:8081
+email.sendUrl=http://localhost:8081
 
 # \uD68C\uACC4 \uB2F4\uB2F9\uC790 \uACB0\uC81C \uCDE8\uC18C \uC54C\uB9BC - \uD68C\uACC4 \uB2F4\uB2F9\uC790\uB294 \uAF2D \uC2DC\uC2A4\uD15C\uC5D0 \uAC00\uC785 \uB418\uC5B4 \uC788\uC5B4\uC57C \uD55C\uB2E4.
-payment.cancel.manager.email=wisestoneowl@gmail.com
+payment.cancel.manager.email=jslee1@wisestone.kr
 
 # \uC0AC\uC6A9\uC790 \uAC00\uC785 \uC815\uBCF4 \uC54C\uB9BC - OWL ITS \uC9C1\uBB34 \uAD00\uB828\uC790\uC5D0\uAC8C \uC804\uC1A1
-user.join.statistics.email=saheo@wisestone.kr, yjlee1@wisestone.kr, twgoh@wisestone.kr, stone@wisestone.kr, bmkim2@wisestone.kr, seshin@wisestone.kr
+user.join.statistics.email=jslee1@wisestone.kr
 
 # \uC2DC\uC2A4\uD15C \uD604\uD669 \uC815\uBCF4 \uC54C\uB9BC
-total.statistics.email=saheo@wisestone.kr, bmkim2@wisestone.kr, seshin@wisestone.kr, yjlee1@wisestone.kr, twgoh@wisestone.kr, stone@wisestone.kr
-
+total.statistics.email=jslee1@wisestone.kr
 
 # saas service max user & use period
-saas.maxUser=10
-saas.period=180
+# packageteyp 1 : lite (~200 Users), 2 : medium (~500 users), 3 : Enterprice (~1000 users) (0 \uC740 demo version)
+saas.packagetype=1 
+
+saas.maxUser=200
+saas.period=3650
 
 # \uD658\uC728
-saas.usdkrw=1221
+saas.usdkrw=1183
 
 # use aws or not
 # added by zenith at 20200623
 use.aws=false
 
-# aws upload path
-attached.file.path=/prod-upload/
-profile.file.path=/prod-profile
+# upload path
+attached.file.path=/dev-upload/
+profile.file.path=/dev-profile
+
 # aws bucket name
-aws.bucket.name=wisestone
-
+aws.bucket.name=wisestone-test
 # aws bucket access key
-aws.access.key=AKIAIJ75KSHFO65GIVNA
-aws.access.password=7SfHA9wwWded9baqtnnGi230xhMjV5s/YilZbSjS
-
+aws.access.key=AKIARX6BJQMZKUYEEJVD
+aws.access.password=eAQvouvSJJFl47h2dkMJji/6OtzsGBGF4h9Df3qH
 # aws s3 url
-aws.s3.url=https://s3.ap-northeast-2.amazonaws.com/
+# aws.s3.url=https://s3.ap-northeast-2.amazonaws.com/
+aws.s3.url=http://localhost:8081/
 
-# OAuth 2.0 \uC778\uC99D \uC815\uBCF4
-OAuth.google.clientId=555830465708-9d50teb7cqgovfp9pqf3ouc4a3lc215f.apps.googleusercontent.com
-OAuth.google.clientSecret=49rssyY8Vv9PDCXKjxhHO7uf
-OAuth.google.redirectUri=https://owlsolution.io/googleOAuth2CallBack
+# OAuth 2.0 \uC778\uC99D \uC815\uBCF4 \uC124\uC815
+OAuth.google.clientId=545115864261-lumkhr0qhei643koiva5b130410s032e.apps.googleusercontent.com
+OAuth.google.clientSecret=olvwp9OipUzaAj86Hx5HKPE5
+OAuth.google.redirectUri=http://localhost:8080/googleOAuth2CallBack
 
 OAuth.naver.clientId=Trl8vV30ctsUDlgGoWqZ
 OAuth.naver.clientSecret=suJXIbB8dz
 
-OAuth.kakao.clientId=13d56a63b9b9b1003d779261ce1651e3
-OAuth.kakao.clientSecret=kumDB7dtnBumpjydGZPqScl7Vd1tezcq
+OAuth.kakao.clientId=8db70e7979edc86b76c7b1d33312282d
+OAuth.kakao.clientSecret=yIpsPh81H326UL7jdcXAu4OhfmKnmmpx
 
 OAuth.facebook.clientId=1967163700251105
 OAuth.facebook.clientSecret=34c4c009bc85caf08a6e27ecfe65744d
 OAuth.facebook.redirectUri=https://www.owlsolution.io/facebookOAuth2CallBack
 
 OAuth.common.state=state_parameter_owl_its_value
+
diff --git a/src/main/webapp/custom_components/js-autocomplete-multi/js-autocomplete-multi.js b/src/main/webapp/custom_components/js-autocomplete-multi/js-autocomplete-multi.js
index 8223853..8182c40 100644
--- a/src/main/webapp/custom_components/js-autocomplete-multi/js-autocomplete-multi.js
+++ b/src/main/webapp/custom_components/js-autocomplete-multi/js-autocomplete-multi.js
@@ -100,7 +100,7 @@
                             var target = e.target.parentElement;
                             var parentFound = false;
 
-                            while (angular.isDefined(target) && target !== null && !parentFound) {
+                            while (angular.isDefined(target) && target !== null && !parentFound && target.className !== null) {
                                 if (_.contains(target.className.split(' '), 'multiselect-parent') && !parentFound) {
                                     if (target === $dropdownTrigger) {
                                         parentFound = true;
diff --git a/src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js b/src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js
index bb4a776..54617fc 100644
--- a/src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js
+++ b/src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js
@@ -154,6 +154,22 @@
                                             makeTag += "</ul>";
                                             break;
 
+                                        case "WORKFLOW_DEPARTMENT_LIST" :
+                                            makeTag += "<ul class='ul-not-comma'>";
+
+                                            if(scope.data.issueStatusVos != null && scope.data.issueStatusVos.length > 0){
+                                                makeTag += "<div>";
+                                                angular.forEach(scope.data.issueStatusVos, function (issueStatusVo) {
+                                                    let workflowDepartments = new Set(issueStatusVo.workflowDepartmentVos);
+                                                    angular.forEach(workflowDepartments, function (workflowDepartmentVo) {
+                                                        makeTag += "<li>" + workflowDepartmentVo.departmentVo.departmentName + "</li>";
+                                                    });
+                                                });
+                                                makeTag += "</div>";
+                                            }
+                                            makeTag += "</ul>";
+                                            break;
+
                                         case "CONFIG" :
                                             makeTag += '<a ng-click="event.modify(data.id)"><i class="fa fa-pencil fa-lg" uib-tooltip="�닔�젙"></i></a>';
                                             break;
diff --git a/src/main/webapp/custom_components/js-workflow/js-workflow.directive.js b/src/main/webapp/custom_components/js-workflow/js-workflow.directive.js
index b96b1b7..a227475 100644
--- a/src/main/webapp/custom_components/js-workflow/js-workflow.directive.js
+++ b/src/main/webapp/custom_components/js-workflow/js-workflow.directive.js
@@ -5,8 +5,8 @@
 
 define(['app', 'angular', 'd3'],
     function (app, angular, d3) {
-        app.directive('jsWorkflow', ["$log", "$rootScope", "IssueStatus", "$resourceProvider", "SweetAlert", '$filter',
-            function ($log, $rootScope, IssueStatus, $resourceProvider, SweetAlert, $filter) {
+        app.directive('jsWorkflow', ["$log", "$rootScope", "IssueStatus", "$resourceProvider", "SweetAlert", '$filter', '$injector', '$controller',
+            function ($log, $rootScope, IssueStatus, $resourceProvider, SweetAlert, $filter, $injector, $controller) {
                 return {
                     scope : {
                         issueStatusList : '=issueStatusList',
@@ -15,6 +15,7 @@
                         firstStatusExist : "=firstStatusExist",
                         middleStatusExist : "=middleStatusExist",
                         lastStatusExist : "=lastStatusExist",
+                        departments : "=departments"
                     },
                     restrict : 'E',
                     replace : true,
@@ -54,12 +55,15 @@
                             defaultAddIssueStatusId : defaultAddIssueStatusId,   //  �씠�뒋 �긽�깭 異붽� ���젆�듃 諛뺤뒪�뿉�꽌 泥ル쾲吏� �샃�뀡 �빆紐⑹쓣 湲곕낯 �꽑�깮�릺寃� �븳�떎.
                             checkReadyType : checkReadyType,    //  �떎�씠�뼱洹몃옩�븞�뿉 �긽�깭 �냽�꽦 '��湲�'�씤 �씠�뒋 �긽�깭媛� 議댁옱�븯�뒗吏� �솗�씤�븳�떎.
                             getOptionColor : getOptionColor,  //  �씠�뒋 �긽�깭�쓽 �깋�긽 �젙蹂대�� 媛��졇�삩�떎.
+                            changeDepartment : changeDepartment,
+                            removeDepartment : removeDepartment
                         };
 
                         //  蹂��닔 紐⑥쓬
                         $scope.vm.targetIssueStatusList = [];
                         $scope.vm.issueStatuses = [];   //  �꽑�깮 媛��뒫�븳 �씠�뒋 �긽�깭 紐⑸줉
                         $scope.vm.addIssueStatusId = null;   //  異붽��븯�뒗 �씠�뒋 �긽�깭 �븘�씠�뵒
+                        $scope.vm.issueStatusVos = []; // �솕硫댁뿉 �엳�뒗 �씠�뒋 �긽�깭 紐⑸줉
                         $scope.vm.width = 0;  //  �꼻�씠
                         $scope.vm.height = 0;  //  �넂�씠
                         $scope.vm.svg = null;   //  svg �젙蹂�
@@ -76,12 +80,34 @@
                         $scope.vm.targetStatusId = null;    //  �뿰寃고븯�뒗 �씠�뒋 �긽�깭 �븘�씠�뵒
                         $scope.vm.transitionIdGenerator = 100;  //  �쟾�씠�꽑 �엫�떆 id 媛�
 
+                        $scope.vm.departments = []; // 遺��꽌 紐⑸줉
+                        $scope.vm.departmentName = "" // �꽑�깮�맂 遺��꽌 �씠由�
+
+                        angular.extend(this, $controller('autoCompleteController', {$scope : $scope, $injector : $injector}));
 
                         $scope.$watch("issueStatusList", function (newValue) {
                             if ($rootScope.isDefined(newValue)) {
                                 $scope.fn.startDiagram();
+                                setWorkflowDepartments();
                             }
-                        });
+                        })
+
+                        // ���옣�맂 �떞�떦遺��꽌 �꽕�젙�븯湲�
+                        function setWorkflowDepartments() {
+                            var workflowDepartmentVos = [];
+
+                            angular.forEach($scope.issueStatusList, function (issueStatus) {
+                                angular.forEach($scope.vm.issueStatusVos, function (issueStatusVo) {
+                                    if (issueStatusVo.id === issueStatus.id) {
+                                        var issueStatusWorkflowDepartments = {
+                                            workflowDepartmentVos : workflowDepartmentVos,
+                                            workflowDepartmentName : ""
+                                        }
+                                        issueStatusVo = Object.assign(issueStatusVo, issueStatusWorkflowDepartments);
+                                    }
+                                });
+                            })
+                        }
 
                         //  �씠�뒋 �긽�깭 異붽� ���젆�듃 諛뺤뒪�뿉�꽌 泥ル쾲吏� �샃�뀡 �빆紐⑹쓣 湲곕낯 �꽑�깮�릺寃� �븳�떎.
                         function defaultAddIssueStatusId() {
@@ -256,6 +282,7 @@
                             return color;
                         }
 
+
                         //  �씠�뒋 �긽�깭瑜� �떎�씠�뼱洹몃옩�뿉 異붽��븳�떎.
                         function addStatus() {
                             if ($rootScope.isDefined($scope.vm.addIssueStatusId)) {
@@ -278,6 +305,9 @@
                                         issueStatus.yLocation = Math.random() * ($scope.vm.height - 50);
 
                                         $scope.vm.issueStatusVos.push(issueStatus);
+
+                                        // �떞�떦 遺��꽌 異붽�
+                                        addWorkflowDepartment(issueStatus);
                                         break;
                                     }
                                 }
@@ -286,6 +316,8 @@
 
                                 $scope.fn.defaultAddIssueStatusId();
                                 $scope.fn.startDiagram();
+
+
                             }
                         }
 
@@ -333,6 +365,8 @@
                             $scope.fn.updateClientChangePosition();
 
                             $scope.fn.startDiagram();
+
+                            removeWorkflowDepartment(targetIssueStatus);
                         }
 
                         //  �쟾�씠�꽑�쓣 �떎�씠�뼱洹몃옩�뿉 異붽��븳�떎.
@@ -599,10 +633,96 @@
                             });
                         }
 
+                        // function  getWorkflowDepartments() {
+                        //     $scope.vm.departments = [];
+                        //
+                        //     if ($scope.vm.activeTarget != null) {
+                        //         return issueStatus.workflowDepartments;
+                        //     }
+                        //     return null;
+                        // }
+
+                        // �떞�떦遺��꽌 �꽕�젙
+                        function setWorkflowDepartment(targetIssueStatus) {
+                            if (targetIssueStatus != null) {
+                                angular.forEach($scope.vm.issueStatusVos, function (issueStatusVo) {
+                                    if (issueStatusVo.id === targetIssueStatus.id) {
+                                        $scope.vm.departmentName = issueStatusVo.workflowDepartmentName;
+                                        $scope.vm.departments = [];
+                                        angular.forEach(issueStatusVo.workflowDepartmentVos, function (workflowDepartment) {
+                                            $scope.vm.departments.push(workflowDepartment.departmentVo);
+                                        });
+                                    }
+                                });
+                            }
+                        }
+
+                        //  �꽑�깮 �븳 遺��꽌 �젣嫄�
+                        function removeDepartment(index) {
+                            if (index < $scope.vm.departments.length) {
+                                $scope.vm.departments.splice(index, 1);
+                                changeDepartment();
+                            }
+                        }
+
+                        function changeDepartment() {
+                            if ($scope.vm.activeTarget != null) {
+                                var targetIssueStatus = $scope.vm.activeTarget.issueStatus;
+
+                                var myIssueStatus = null;
+                                angular.forEach($scope.vm.issueStatusVos, function (issueStatusVo) {
+                                    if (issueStatusVo.id === targetIssueStatus.id) {
+                                        myIssueStatus = issueStatusVo;
+                                    }
+                                });
+
+                                if (myIssueStatus != null) {
+                                    if ($scope.vm.departments != null) {
+                                        var workflowDepartments = [];
+
+                                        angular.forEach($scope.vm.departments, function (department) {
+                                            var workflowDepartment = {
+                                                departmentVo : department
+                                            }
+                                            workflowDepartments.push(workflowDepartment);
+                                        });
+                                        myIssueStatus.workflowDepartmentVos = workflowDepartments;
+                                    }
+                                }
+                            }
+                        }
+
+                        // �떞�떦遺��꽌 異붽�
+                        function addWorkflowDepartment(targetIssueStatus)
+                        {
+                            if ($scope.departments != null && $scope.departments.length > 0) {
+                                var workflowDepartmentVos = [];
+                                angular.forEach($scope.vm.issueStatusVos, function (issueStatusVo) {
+                                    if (issueStatusVo.id === targetIssueStatus.id) {
+                                        var issueStatusWorkflowDepartments = {
+                                            workflowDepartmentVos : workflowDepartmentVos,
+                                            workflowDepartmentName : ""
+                                        }
+                                        issueStatusVo = Object.assign(issueStatusVo, issueStatusWorkflowDepartments);
+                                    }
+                                });
+                            }
+                        }
+
+                        // �떞�떦遺��꽌 �궘�젣
+                        function removeWorkflowDepartment(targetIssueStatus)
+                        {
+                            if ($scope.vm.workflowDepartmentVos != null && $scope.vm.workflowDepartmentVos.length > 0) {
+                                $scope.vm.workflowDepartmentVos = $scope.vm.workflowDepartmentVos.filter((el) => el.issueStatus.id === targetIssueStatus.id);
+                            }
+                        }
+
                         //  ��寃잛쓣 �겢由��뻽�쓣 �븣 �깋�긽�쓣 蹂�寃쏀븳�떎.
+                        //  �떞�떦 遺��꽌瑜� 遺덈윭�삩�떎
                         function targetClick(target) {
                             $scope.vm.activeTarget = angular.copy(target[0][0]["__data__"]);
 
+                            setWorkflowDepartment($scope.vm.activeTarget.issueStatus);
                             // node �씪寃쎌슦
                             if ($scope.vm.activeTarget.type == "01") {
                                 //  �끂�뱶, 留곹겕 �쟾泥� 珥덇린�솕
diff --git a/src/main/webapp/custom_components/js-workflow/js-workflow.html b/src/main/webapp/custom_components/js-workflow/js-workflow.html
index 38e42de..1b7aa7b 100644
--- a/src/main/webapp/custom_components/js-workflow/js-workflow.html
+++ b/src/main/webapp/custom_components/js-workflow/js-workflow.html
@@ -60,20 +60,23 @@
                 </div>
             </div>
 
-            <div class="form-group">
-                <label><span translate="project.projectDepartment">�떞�떦 遺��꽌</span></label>
-                <div class="input-group">
-                    <select class="form-control input-sm issue-select-label"
-                            name="targetStatusId"
-                            ng-style="{ 'color' : fn.getOptionColor(vm.targetIssueStatusList, vm.targetStatusId) }"
-                            ng-model="vm.targetStatusId">
-                        <option value="" translate="common.choose">�꽑�깮�븯�꽭�슂.</option>
-                        <option value="{{issueStatus.id}}"
-                                ng-style="{ 'color' : issueStatus.color, 'font-weight': 600 }"
-                                ng-repeat="issueStatus in vm.targetIssueStatusList">
-                            �뿈&nbsp;{{issueStatus.name}}
-                        </option>
-                    </select>
+            <div class="form-group" ng-if="vm.activeTarget != null">
+                <label><span translate="project.projectDepartment">遺��꽌紐�</span><span>[{{vm.activeTarget.name}}]</span></label>
+                <js-autocomplete-multi data-input-name="departments"
+                                       selected-model="vm.departments"
+                                       search="vm.departmentName"
+                                       source="fn.getUserDepartmentList(vm.departmentName, vm.departments)"
+                                       input-disabled="false"
+                                       change-event="fn.changeDepartment()"
+                                       translation-texts="{ count : 'common.userNum', empty : 'common.emptyDepartment' }"
+                                       extra-settings="{ displayProp : 'byName' , idProp : 'id', imageable : false, maxlength : 100, autoResize : true }"></js-autocomplete-multi>
+
+
+                <div class="select3-selection__choicediv mt-10">
+                    <span class="select3-selection__choice" ng-repeat="department in vm.departments">
+                        <span>{{department.byName}}</span> <!--�궗�슜�옄媛� �냽�빐 �엳�뒗 遺��꽌 �씠由� 異쒕젰-->
+                        <span class="select3-selection__choice__remove" ng-click="fn.removeDepartment($index)">횞</span>
+                    </span>
                 </div>
             </div>
 
diff --git a/src/main/webapp/scripts/app/workflow/workflowAdd.controller.js b/src/main/webapp/scripts/app/workflow/workflowAdd.controller.js
index 4c50550..df1c746 100644
--- a/src/main/webapp/scripts/app/workflow/workflowAdd.controller.js
+++ b/src/main/webapp/scripts/app/workflow/workflowAdd.controller.js
@@ -8,19 +8,25 @@
         'angular'
     ],
     function (app, angular) {
-        app.controller('workflowAddController', ['$scope', '$rootScope', '$log', '$resourceProvider', 'User', '$uibModalInstance', 'Workflow', 'SweetAlert', 'IssueStatus', '$filter',
+        app.controller('workflowAddController', ['$scope', '$rootScope', '$log', '$resourceProvider', 'User', '$uibModalInstance', 'Workflow', 'SweetAlert', 'IssueStatus', '$filter', '$injector','$controller',
             function ($scope, $rootScope, $log, $resourceProvider, User, $uibModalInstance, Workflow, SweetAlert, IssueStatus, $filter) {
 
                 $scope.fn = {
                     cancel : cancel,    //  �뙘�뾽 李� �떕湲�
                     formSubmit : formSubmit,    //  �뤌 �쟾�넚
                     formCheck : formCheck,  //  �뤌 泥댄겕
+                    getDepartments : getDepartments // 遺��꽌 紐⑸줉 媛��졇�삤湲�
                 };
 
                 $scope.vm = {
                     form : {
                         name : "",  //  �썙�겕�뵆濡쒖슦  紐�
-                        issueStatusVos : []    //  �떎�씠�뼱洹몃옩�뿉�꽌 留뚮뱾�뼱吏� �씠�뒋 �긽�깭 紐⑥쓬
+                        issueStatusVos : [],    //  �떎�씠�뼱洹몃옩�뿉�꽌 留뚮뱾�뼱吏� �씠�뒋 �긽�깭 紐⑥쓬
+                        WorkflowDepartmentVos : [
+                            {
+                                departmentVo : null
+                            }
+                        ]
                     },
                     issueStatusVos : [],    //  �떎�씠�뼱洹몃옩 �뿉�뵒�꽣�뿉�꽌 �씠 媛믪쓣 媛먯��븯硫댁꽌 議고쉶媛� �떆�옉�맂�떎.
                     step : "01",
@@ -28,7 +34,10 @@
                     firstStatusExist : true,    //  �썙�겕�뵆濡쒖슦�뿉 �긽�깭 �냽�꽦 '��湲�'�씤 �긽�깭媛� 議댁옱�븯�뒗吏� 泥댄겕�븳�떎.
                     middleStatusExist : true,   //  �썙�겕�뵆濡쒖슦�뿉 �긽�깭 �냽�꽦 '吏꾪뻾'�씤 �긽�깭媛� 議댁옱�븯�뒗吏� 泥댄겕�븳�떎.
                     lastStatusExist : true,  //  �썙�겕�뵆濡쒖슦�뿉 �긽�깭 �냽�꽦 '醫낅즺'�씤 �긽�깭媛� 議댁옱�븯�뒗吏� 泥댄겕�븳�떎.
+                    departments : []    // 遺��꽌 紐⑸줉
                 };
+
+
 
                 //  �뤌 泥댄겕
                 function formCheck(formInvalid) {
@@ -37,6 +46,26 @@
                     }
 
                     return false;
+                }
+
+                // 遺��꽌 紐⑸줉 媛��졇�삤湲�
+                function getDepartments() {
+                    var content = {
+                        // 異뷀썑 蹂�寃쎌쓣 �쐞�븿
+                    };
+
+                    Workflow.findDepartments($resourceProvider.getContent(
+                        content,
+                        $resourceProvider.getPageContent(0, 1000))).then(function (result) {
+
+                        if (result.data.message.status === "success") {
+                            $scope.vm.departments = result.data.data;
+                        }
+                        else {
+                            SweetAlert.error($filter("translate")("managementWorkflow.failedToSelectWorkspaceFullDepartmentList"), result.data.message.message); // 遺��꽌 紐⑸줉 議고쉶 �떎�뙣
+                        }
+                    });
+
                 }
 
                 //  �뤌 �쟾�넚
@@ -86,5 +115,7 @@
                     $uibModalInstance.dismiss('cancel');
                     $(document).unbind("keydown");  //  �떒異뺥궎 �씠踰ㅽ듃 �젣嫄�
                 }
+
+                $scope.fn.getDepartments();
             }]);
     });
diff --git a/src/main/webapp/scripts/app/workflow/workflowList.controller.js b/src/main/webapp/scripts/app/workflow/workflowList.controller.js
index d9e6ec6..2d6934b 100644
--- a/src/main/webapp/scripts/app/workflow/workflowList.controller.js
+++ b/src/main/webapp/scripts/app/workflow/workflowList.controller.js
@@ -77,6 +77,12 @@
                         .setDType("renderer")
                         .setDRenderer("COMMON_MODIFY"));
                     $scope.vm.tableConfigs.push($tableProvider.config()
+                        .setHName("common.assigneeTeam")
+                        .setHWidth("bold")
+                        .setDAlign("text-center")
+                        .setDType("renderer")
+                        .setDRenderer("WORKFLOW_DEPARTMENT_LIST"));
+                    $scope.vm.tableConfigs.push($tableProvider.config()
                         .setHName("managementWorkflow.connectedIssueType")
                         .setHWidth("width-300-p bold")
                         .setDAlign("text-center")
diff --git a/src/main/webapp/scripts/components/workflow/workflow.service.js b/src/main/webapp/scripts/components/workflow/workflow.service.js
index 01d9ce6..eda7004 100644
--- a/src/main/webapp/scripts/components/workflow/workflow.service.js
+++ b/src/main/webapp/scripts/components/workflow/workflow.service.js
@@ -38,6 +38,12 @@
                     return response;
                 });
             },
+            findDepartments : function (conditions) {
+                return $http.post("workflow/findDepartments", conditions).then(function (response) {
+                    $log.debug("遺��꽌 紐⑸줉 媛��졇�삤湲� 寃곌낵: ", response);
+                    return response;
+                });
+            },
             uploadImage : function (conditions) {
                 return $http.post("workflow/uploadImage", conditions).then(function (response) {
                     $log.debug("�썙�겕�뵆濡쒖슦 �씠誘몄� �뾽濡쒕뱶 寃곌낵 : ", response);
diff --git a/src/main/webapp/views/workflow/workflowAdd.html b/src/main/webapp/views/workflow/workflowAdd.html
index 9faf9cd..da877b7 100644
--- a/src/main/webapp/views/workflow/workflowAdd.html
+++ b/src/main/webapp/views/workflow/workflowAdd.html
@@ -39,7 +39,8 @@
                          first-status-exist="vm.firstStatusExist"
                          middle-status-exist="vm.middleStatusExist"
                          last-status-exist="vm.lastStatusExist"
-                         isolation-workflow="vm.isolationWorkflow"></js-workflow>
+                         isolation-workflow="vm.isolationWorkflow"
+                         departments="vm.departments"></js-workflow>
         </form>
     </div>
 

--
Gitblit v1.8.0