OWL ITS + 탐지시스템(인터넷 진흥원)
jhjang
2021-11-25 e50b78db2f5e74f88b7e5c736f1fca4ca3cbe29b
- 워크플로우 담당부서 설정 기능 추가
8개 파일 추가됨
16개 파일 변경됨
784 ■■■■■ 파일 변경됨
src/main/java/kr/wisestone/owl/constant/MsgConstants.java 2 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/WorkflowDepartment.java 61 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/WorkflowTransition.java 2 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/mapper/WorkflowDepartmentMapper.java 14 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/repository/WorkflowDepartmentRepository.java 12 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/WorkflowDepartmentService.java 26 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/WorkflowDepartmentServiceImpl.java 134 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/WorkflowServiceImpl.java 49 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/vo/IssueStatusVo.java 9 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/vo/WorkflowDepartmentVo.java 46 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/vo/WorkflowVo.java 6 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/condition/WorkflowDepartmentCondition.java 42 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/controller/WorkflowController.java 20 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/form/WorkflowForm.java 29 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/mybatis/query-template/workflow-department-template.xml 24 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/system_prod.properties 85 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-autocomplete-multi/js-autocomplete-multi.js 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js 16 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-workflow/js-workflow.directive.js 124 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-workflow/js-workflow.html 31 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/workflow/workflowAdd.controller.js 35 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/workflow/workflowList.controller.js 6 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/components/workflow/workflow.service.js 6 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/workflow/workflowAdd.html 3 ●●●● 패치 | 보기 | raw | blame | 히스토리
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글자까지 입력할 수 있습니다.
src/main/java/kr/wisestone/owl/domain/WorkflowDepartment.java
New file
@@ -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;
    }
}
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;
src/main/java/kr/wisestone/owl/mapper/WorkflowDepartmentMapper.java
New file
@@ -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);
}
src/main/java/kr/wisestone/owl/repository/WorkflowDepartmentRepository.java
New file
@@ -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);
}
src/main/java/kr/wisestone/owl/service/WorkflowDepartmentService.java
New file
@@ -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);
}
src/main/java/kr/wisestone/owl/service/impl/WorkflowDepartmentServiceImpl.java
New file
@@ -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);
    }
}
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);
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;
    }
}
src/main/java/kr/wisestone/owl/vo/WorkflowDepartmentVo.java
New file
@@ -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;
    }
}
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);
        }
    }
}
src/main/java/kr/wisestone/owl/web/condition/WorkflowDepartmentCondition.java
New file
@@ -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;
    }
}
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);
    }
}
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;
    }
}
src/main/resources/mybatis/query-template/workflow-department-template.xml
New file
@@ -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>
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
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;
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;
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") {
                                //  노드, 링크 전체 초기화
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>
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();
            }]);
    });
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")
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);
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>