OWL ITS + 탐지시스템(인터넷 진흥원)
이민희
2021-11-16 ee65aa4472baee240808689a866866abb2e44608
담당자 -> 담당부서 변경 및 추가 기능 완료
* db날리고 실행
7개 파일 추가됨
17개 파일 변경됨
722 ■■■■ 파일 변경됨
src/main/java/kr/wisestone/owl/domain/Department.java 12 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/Issue.java 12 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/IssueDepartment.java 65 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/IssueUser.java 11 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/ProjectRoleDepartment.java 56 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/ProjectRoleUser.java 18 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/User.java 4 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/mapper/IssueDepartmentMapper.java 23 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/mapper/IssueMapper.java 2 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/mapper/IssueUserMapper.java 8 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/repository/IssueDepartmentRepository.java 11 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/repository/ProjectRoleUserRepository.java 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueDepartmentService.java 21 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueUserService.java 7 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/ProjectRoleUserService.java 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueDepartmentServiceImpl.java 128 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueHistoryServiceImpl.java 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java 100 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueUserServiceImpl.java 79 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/ProjectRoleUserServiceImpl.java 4 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/migration/V1_1__Initial_Setup.sql 43 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/mybatis/query-template/issue-template.xml 39 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/mybatis/query-template/issueDepartment-template.xml 42 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/mybatis/query-template/issueUser-template.xml 31 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/Department.java
@@ -17,7 +17,7 @@
    private String departmentDescription;
    @OneToMany(mappedBy = "department", cascade = {CascadeType.ALL}, orphanRemoval = true)
    private Set<ProjectRoleUser> projectRoleDepartments = new HashSet<>();
    private Set<ProjectRoleDepartment> projectRoleDepartments = new HashSet<ProjectRoleDepartment>();
    public Department() {
    }
@@ -46,12 +46,12 @@
        this.departmentDescription = departmentDescription;
    }
    /*public void addProjectRole(ProjectRole projectRole) {
    public void addProjectRole(ProjectRole projectRole) {
        if (this.projectRoleDepartments == null) {
            this.projectRoleDepartments = new HashSet<>();
            this.projectRoleDepartments = new HashSet<ProjectRoleDepartment>();
        }
        ProjectRoleUser projectRoleUser = new ProjectRoleUser(projectRole, this);
        ProjectRoleDepartment projectRoleDepartment = new ProjectRoleDepartment(projectRole, this);
        this.projectRoleDepartments.add(projectRoleUser);
    }*/
        this.projectRoleDepartments.add(projectRoleDepartment);
    }
}
src/main/java/kr/wisestone/owl/domain/Issue.java
@@ -54,6 +54,10 @@
    private Set<IssueUser> issueUsers = new HashSet<>();
    @OrderBy(value="id DESC")
    @OneToMany(mappedBy = "issue", cascade = { CascadeType.ALL }, orphanRemoval = true)
    private Set<IssueDepartment> issueDepartments = new HashSet<>();
    @OrderBy(value="id DESC")
    @OneToMany(mappedBy="issue", cascade={CascadeType.ALL}, orphanRemoval = true)
    private Set<AttachedFile> attachedFiles = new HashSet<>();
@@ -181,6 +185,14 @@
        this.issueUsers = issueUsers;
    }
    public Set<IssueDepartment> getIssueDepartments() {
        return issueDepartments;
    }
    public void setIssueDepartments(Set<IssueDepartment> issueDepartments) {
        this.issueDepartments = issueDepartments;
    }
    public Set<AttachedFile> getAttachedFiles() {
        return attachedFiles;
    }
src/main/java/kr/wisestone/owl/domain/IssueDepartment.java
New file
@@ -0,0 +1,65 @@
package kr.wisestone.owl.domain;
import javax.persistence.*;
import java.io.Serializable;
@Entity
public class IssueDepartment extends BaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "issue_id")
    private Issue issue;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "workspace_id")
    private Workspace workspace;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Department department;
    public IssueDepartment() {
    }
    public IssueDepartment(Issue issue, Department department) {
        this.issue = issue;
        this.department = department;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public Issue getIssue() {
        return issue;
    }
    public void setIssue(Issue issue) {
        this.issue = issue;
    }
    public Workspace getWorkspace() {
        return workspace;
    }
    public void setWorkspace(Workspace workspace) {
        this.workspace = workspace;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
}
src/main/java/kr/wisestone/owl/domain/IssueUser.java
@@ -23,10 +23,6 @@
    @JoinColumn(name = "workspace_id")
    private Workspace workspace;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Department department;
    public IssueUser() {
    }
@@ -67,11 +63,4 @@
        this.workspace = workspace;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
}
src/main/java/kr/wisestone/owl/domain/ProjectRoleDepartment.java
New file
@@ -0,0 +1,56 @@
package kr.wisestone.owl.domain;
import javax.persistence.*;
import java.io.Serializable;
/**
 * Created by jeong on 2017-12-30.
 */
@Entity
public class ProjectRoleDepartment extends BaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="project_role_id")
    private ProjectRole projectRole;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="department_id")
    private Department department;
    public ProjectRoleDepartment() {
    }
    public ProjectRoleDepartment(ProjectRole projectRole, Department department) {
        this.projectRole = projectRole;
        this.department = department;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public ProjectRole getProjectRole() {
        return projectRole;
    }
    public void setProjectRole(ProjectRole projectRole) {
        this.projectRole = projectRole;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
}
src/main/java/kr/wisestone/owl/domain/ProjectRoleUser.java
@@ -22,10 +22,6 @@
    @JoinColumn(name="user_id")
    private User user;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="department_id")
    private Department department;
    public ProjectRoleUser() {
    }
@@ -34,12 +30,6 @@
        this.user = user;
    }
    
    //부서로 변경
    /*public ProjectRoleUser(ProjectRole projectRole, Department department) {
        this.projectRole = projectRole;
        this.department = department;
    }*/
    public Long getId() {
        return id;
    }
@@ -62,13 +52,5 @@
    public void setUser(User user) {
        this.user = user;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
}
src/main/java/kr/wisestone/owl/domain/User.java
@@ -70,10 +70,6 @@
    @OneToMany(mappedBy = "user", cascade = {CascadeType.ALL}, orphanRemoval = true)
    private Set<ApiToken> apiTokens = new HashSet<>();
//    @ManyToOne(targetEntity = Department.class, fetch = FetchType.LAZY)
//    @JoinColumn(name="department_id")
//    private Department department;
    public User() {
    }
src/main/java/kr/wisestone/owl/mapper/IssueDepartmentMapper.java
New file
@@ -0,0 +1,23 @@
package kr.wisestone.owl.mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
/**
 * Created by wisestone on 2018-11-27.
 */
@Repository
public interface IssueDepartmentMapper {
    void insertIssueDepartment(List<Map<String, Long>> issueRoleUserMaps);
    void deleteIssueDepartmentByIssueIdAndMultiDepartmentId(Map<String, Object> removeIssueAssigneeMap);
    void deleteIssueDepartmentByDepartmentIdAndMultiIssueId(Map<String, Object> removeIssueAssigneeMap);
    List<Map<String, Object>> findByDepartmentIdAndProjectId(Map<String, Object> issueUserMap);
}
src/main/java/kr/wisestone/owl/mapper/IssueMapper.java
@@ -29,6 +29,8 @@
    List<Map<String, Object>> findIssueUser(IssueCondition issueCondition);
    List<Map<String, Object>> findIssueDepartment(IssueCondition issueCondition);
    Long countByIssueTypeId(Long issueTypeId);
    Long countByIssueStatusId(Long issueStatusId);
src/main/java/kr/wisestone/owl/mapper/IssueUserMapper.java
@@ -20,12 +20,4 @@
    
    List<Map<String, Object>> findByUserIdAndProjectId(Map<String, Object> issueUserMap);
    //담당부서
    void deleteIssueUserByIssueIdAndMultiDepartmentId(Map<String, Object> removeIssueAssigneeMap);
    void deleteIssueUserByDepartmentIdAndMultiIssueId(Map<String, Object> removeIssueAssigneeMap);
    List<Map<String, Object>> findByDepartmentIdAndProjectId(Map<String, Object> issueUserMap);
}
src/main/java/kr/wisestone/owl/repository/IssueDepartmentRepository.java
New file
@@ -0,0 +1,11 @@
package kr.wisestone.owl.repository;
import kr.wisestone.owl.domain.IssueDepartment;
import kr.wisestone.owl.domain.IssueUser;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface IssueDepartmentRepository extends JpaRepository<IssueDepartment, Long> {
    List<IssueDepartment> findByIssueId(Long issueId);
}
src/main/java/kr/wisestone/owl/repository/ProjectRoleUserRepository.java
@@ -11,6 +11,6 @@
    ProjectRoleUser findByProjectRoleIdAndUserId(@Param("projectRoleId") Long projectRoleId, @Param("userId") Long userId);
    ProjectRoleUser findByProjectRoleIdAndDepartmentId(@Param("projectRoleId") Long projectRoleId, @Param("departmentId") Long departmentId);
    //ProjectRoleUser findByProjectRoleIdAndDepartmentId(@Param("projectRoleId") Long projectRoleId, @Param("departmentId") Long departmentId);
}
src/main/java/kr/wisestone/owl/service/IssueDepartmentService.java
New file
@@ -0,0 +1,21 @@
package kr.wisestone.owl.service;
import kr.wisestone.owl.domain.Issue;
import kr.wisestone.owl.domain.IssueDepartment;
import kr.wisestone.owl.domain.Workspace;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.Map;
public interface IssueDepartmentService extends AbstractService<IssueDepartment, Long, JpaRepository<IssueDepartment, Long>>{
    //담당부서
    void modifyIssueDepartment(Issue issue, Workspace workspace, List<Long> departmentIds);
    void insertIssueDepartment(List<Map<String, Long>> issueAssigneeMaps);
    void removeIssueDepartment(Long projectId, List<Long> excludeUserIds);
    List<IssueDepartment> find(Issue issue);
}
src/main/java/kr/wisestone/owl/service/IssueUserService.java
@@ -18,12 +18,5 @@
    void removeIssueUser(Long projectId, List<Long> excludeUserIds);
    //담당부서
    void modifyIssueDepartment(Issue issue, Workspace workspace, List<Long> departmentIds);
    void insertIssueDepartment(List<Map<String, Long>> issueAssigneeMaps);
    void removeIssueDepartment(Long projectId, List<Long> excludeUserIds);
    List<IssueUser> find(Issue issue);
}
src/main/java/kr/wisestone/owl/service/ProjectRoleUserService.java
@@ -14,7 +14,7 @@
    ProjectRoleUser findByProjectRoleIdAndUserId(Long projectRoleId, Long userId); //담당자
    ProjectRoleUser findByProjectRoleIdAndDepartmentId(Long projectRoleId, Long departmentId); //담당부서
    //ProjectRoleUser findByProjectRoleIdAndDepartmentId(Long projectRoleId, Long departmentId); //담당부서
    void withDrawWorkspaceManagerModifyProjectRole(Workspace workspace, User user);
src/main/java/kr/wisestone/owl/service/impl/IssueDepartmentServiceImpl.java
New file
@@ -0,0 +1,128 @@
package kr.wisestone.owl.service.impl;
import com.google.common.collect.Lists;
import kr.wisestone.owl.domain.Issue;
import kr.wisestone.owl.domain.IssueDepartment;
import kr.wisestone.owl.domain.IssueUser;
import kr.wisestone.owl.domain.Workspace;
import kr.wisestone.owl.mapper.IssueDepartmentMapper;
import kr.wisestone.owl.mapper.IssueUserMapper;
import kr.wisestone.owl.repository.IssueDepartmentRepository;
import kr.wisestone.owl.service.IssueDepartmentService;
import kr.wisestone.owl.util.CommonUtil;
import kr.wisestone.owl.util.MapUtil;
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.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class IssueDepartmentServiceImpl extends AbstractServiceImpl<IssueDepartment, Long, JpaRepository<IssueDepartment, Long>> implements IssueDepartmentService {
    private static final Logger log = LoggerFactory.getLogger(IssueDepartmentServiceImpl.class);
    @Autowired
    private IssueDepartmentRepository issueDepartmentRepository;
    @Autowired
    private IssueDepartmentMapper issueDepartmentMapper;
    @Override
    protected JpaRepository<IssueDepartment, Long> getRepository() {
        return this.issueDepartmentRepository;
    }
    //  이슈 담당부서를 변경한다.
    @Override
    @Transactional
    public void modifyIssueDepartment(Issue issue, Workspace workspace, List<Long> departmentIds) {
        List<Long> oldDepartmentIds = Lists.newArrayList();
        //  이전 담당 부서
        for (IssueDepartment issueDepartment : issue.getIssueDepartments()) {
            oldDepartmentIds.add(issueDepartment.getDepartment().getId());
        }
        List<Long> newDepartmentIds = CommonUtil.searchChangeList(oldDepartmentIds, departmentIds); //  추가해야할 부서를 찾는다.
        List<Long> removeDepartmentIds = CommonUtil.searchChangeList(departmentIds, oldDepartmentIds); //  삭제해야할 부서를 찾는다.
        if (removeDepartmentIds.size() > 0) {
            Map<String, Object> removeIssueAssigneeMap = new HashMap<>();
            removeIssueAssigneeMap.put("issueId", issue.getId());
            removeIssueAssigneeMap.put("departmentIds", removeDepartmentIds);
            //  담당부서 삭제
            this.issueDepartmentMapper.deleteIssueDepartmentByIssueIdAndMultiDepartmentId(removeIssueAssigneeMap);
        }
        if (newDepartmentIds.size() > 0) {
            List<Map<String, Long>> addIssueAssigneeMaps = Lists.newArrayList();
            for (Long departmentId : newDepartmentIds) {
                Map<String, Long> issueAssigneeMap = new HashMap<>();
                issueAssigneeMap.put("departmentId", departmentId); //담당부서
                issueAssigneeMap.put("issueId", issue.getId());
                issueAssigneeMap.put("workspaceId", workspace.getId());
                issueAssigneeMap.put("registerId", this.webAppUtil.getLoginId());
                issueAssigneeMap.put("modifyId", this.webAppUtil.getLoginId());
                addIssueAssigneeMaps.add(issueAssigneeMap);
            }
            //  담당부서 추가
            this.issueDepartmentMapper.insertIssueDepartment(addIssueAssigneeMaps);
        }
    }
    //  이슈 담당부서 찾기
    @Override
    @Transactional
    public List<IssueDepartment> find(Issue issue) {
        return this.issueDepartmentRepository.findByIssueId(issue.getId());
    }
    @Override
    @Transactional
    public void insertIssueDepartment(List<Map<String, Long>> issueAssigneeMaps) {
        //  이슈 담당부서 벌크 등록
        this.issueDepartmentMapper.insertIssueDepartment(issueAssigneeMaps);
    }
    //  이슈 담당부서에서 제외한다.
    @Override
    @Transactional
    public void removeIssueDepartment(Long projectId, List<Long> excludeDepartmentIds) {
        for (Long departmentId : excludeDepartmentIds) {
            Map<String, Object> issueDepartmentMap = new HashMap<>();
            issueDepartmentMap.put("departmentId", departmentId);
            issueDepartmentMap.put("projectId", projectId);
            List<Map<String, Object>> results = this.issueDepartmentMapper.findByDepartmentIdAndProjectId(issueDepartmentMap);
            if (results.size() > 0) {
                List<Long> issueIds = Lists.newArrayList();
                for (Map<String, Object> result : results) {
                    Long id = MapUtil.getLong(result, "id");
                    if (id != null) {
                        issueIds.add(id);
                    }
                }
                if (issueIds.size() > 0) {
                    Map<String, Object> removeIssueAssigneeMap = new HashMap<>();
                    removeIssueAssigneeMap.put("departmentId", departmentId);
                    removeIssueAssigneeMap.put("issueIds", issueIds);
                    this.issueDepartmentMapper.deleteIssueDepartmentByDepartmentIdAndMultiIssueId(removeIssueAssigneeMap);
                }
            }
        }
    }
}
src/main/java/kr/wisestone/owl/service/impl/IssueHistoryServiceImpl.java
@@ -292,7 +292,7 @@
        //  이슈 기간 변경 정보를 기록한다.
        this.detectIssuePeriod(issue, issueForm, description);
        //  담당자 변경 정보를 기록한다.
        this.detectIssueManager(issue, issueForm, description);
        //this.detectIssueManager(issue, issueForm, description);
        //  사용자 정의 필드 변경 정보를 기록한다.
        this.detectCustomField(issue, issueForm, description);
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -85,6 +85,9 @@
    private IssueUserService issueUserService;
    @Autowired
    private IssueDepartmentService issueDepartmentService;
    @Autowired
    private CustomFieldService customFieldService;
    @Autowired
@@ -189,7 +192,7 @@
        //  담당자 지정
        //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds());
        //  담당부서 지정
        this.issueUserService.modifyIssueDepartment(issue, project.getWorkspace(), issueForm.getDepartmentIds());
        this.issueDepartmentService.modifyIssueDepartment(issue, project.getWorkspace(), issueForm.getDepartmentIds());
        //  multipartFile 을 file Map List 객체로 변경한다.
        List<Map<String, Object>> convertFileMaps = this.convertMultipartFileToFile(multipartFiles);
@@ -246,9 +249,9 @@
        //  담당부서
        StringBuilder assigneeBuilder = new StringBuilder();
        for (IssueUser issueUser : issue.getIssueUsers()) {
        for (IssueDepartment issueDepartment : issue.getIssueDepartments()) {
            //assigneeBuilder.append(issueUser.getUser().getName());
            assigneeBuilder.append(issueUser.getDepartment().getDepartmentName());
            assigneeBuilder.append(issueDepartment.getDepartment().getDepartmentName());
            /*assigneeBuilder.append("(");
            assigneeBuilder.append(CommonUtil.decryptAES128(issueUser.getUser().getAccount()));
            assigneeBuilder.append(")");*/
@@ -386,6 +389,7 @@
        issueCondition.setIssueIds(issueKeys);
        List<Map<String, Object>> results = this.issueMapper.find(issueCondition);
        //  튜닝 전 - 0.8, 0.9, 0.9, 0.9, 0.9
        StopWatch serviceStart = new StopWatch();
        serviceStart.start();
@@ -660,8 +664,8 @@
        return true;
    }
    //  이슈 담당자 정보를 셋팅한다. => 담당부서
    private void setIssueDepartmentList(List<IssueVo> issueVos, IssueCondition issueCondition) {
    //  이슈 담당자 정보를 셋팅한다.
    private void setIssueUserList(List<IssueVo> issueVos, IssueCondition issueCondition) {
        if (issueVos.size() < 1) {
            return;
        }
@@ -669,28 +673,61 @@
        List<Map<String, Object>> issueUsers = this.issueMapper.findIssueUser(issueCondition);
        Map<String, Object> issueConverterUsers = new HashMap<>();
        //  이슈에 해당하는 이슈 담당부서 정보 셋팅
        //  이슈에 해당하는 이슈 담당자 정보 셋팅
        for (Map<String, Object> issueUser : issueUsers) {
            String issueId = MapUtil.getString(issueUser, "issueId");
            if (MapUtil.getObject(issueConverterUsers, issueId) != null) {
                List<DepartmentVo> departments = (List) MapUtil.getObject(issueConverterUsers, issueId);
                departments.add(new DepartmentVo(MapUtil.getLong(issueUser, "id"), MapUtil.getString(issueUser, "departmentName"), MapUtil.getString(issueUser, "departmentDescription")));
                //List<UserVo> users = (List) MapUtil.getObject(issueConverterUsers, issueId);
                //users.add(new UserVo(MapUtil.getLong(issueUser, "id"), MapUtil.getString(issueUser, "name"), CommonUtil.decryptAES128(MapUtil.getString(issueUser, "account")), MapUtil.getString(issueUser, "profile")));
                List<UserVo> users = (List) MapUtil.getObject(issueConverterUsers, issueId);
                users.add(new UserVo(MapUtil.getLong(issueUser, "id"), MapUtil.getString(issueUser, "name"), CommonUtil.decryptAES128(MapUtil.getString(issueUser, "account")), MapUtil.getString(issueUser, "profile")));
            } else {
                List<DepartmentVo> departments = Lists.newArrayList(new DepartmentVo(MapUtil.getLong(issueUser, "id"), MapUtil.getString(issueUser, "departmentName"), MapUtil.getString(issueUser, "departmentDescription")));
                issueConverterUsers.put(issueId, departments);
                /*List<UserVo> users = Lists.newArrayList(new UserVo(MapUtil.getLong(issueUser, "id"), MapUtil.getString(issueUser, "name"), CommonUtil.decryptAES128(MapUtil.getString(issueUser, "account")),
                List<UserVo> users = Lists.newArrayList(new UserVo(MapUtil.getLong(issueUser, "id"), MapUtil.getString(issueUser, "name"), CommonUtil.decryptAES128(MapUtil.getString(issueUser, "account")),
                        MapUtil.getString(issueUser, "profile")));
                issueConverterUsers.put(issueId, users);*/
                issueConverterUsers.put(issueId, users);
            }
        }
        //  이슈Vo에 담당자 정보를 셋팅
        for (IssueVo issueVo : issueVos) {
            if (MapUtil.getObject(issueConverterUsers, String.valueOf(issueVo.getId())) != null) {
                List<UserVo> userVos = (List) MapUtil.getObject(issueConverterUsers, String.valueOf(issueVo.getId()));
                issueVo.setUserVos(userVos);
            }
            //  이슈 수정 권한을 갖고 있는지 확인
            if (this.checkHasPermission(issueVo, issueVo.getUserVos())) {
                issueVo.setModifyPermissionCheck(Boolean.TRUE);
            }
        }
    }
    //  이슈 담당부서 정보를 셋팅한다.
    private void setIssueDepartmentList(List<IssueVo> issueVos, IssueCondition issueCondition) {
        if (issueVos.size() < 1) {
            return;
        }
        List<Map<String, Object>> issueDepartments = this.issueMapper.findIssueDepartment(issueCondition);
        Map<String, Object> issueConverterDepartments = new HashMap<>();
        //  이슈에 해당하는 이슈 담당부서 정보 셋팅
        for (Map<String, Object> issueDepartment : issueDepartments) {
            String issueId = MapUtil.getString(issueDepartment, "issueId");
            if (MapUtil.getObject(issueConverterDepartments, issueId) != null) {
                List<DepartmentVo> departments = (List) MapUtil.getObject(issueConverterDepartments, issueId);
                departments.add(new DepartmentVo(MapUtil.getLong(issueDepartment, "id"), MapUtil.getString(issueDepartment, "departmentName"), MapUtil.getString(issueDepartment, "departmentDescription")));
            } else {
                List<DepartmentVo> departments = Lists.newArrayList(new DepartmentVo(MapUtil.getLong(issueDepartment, "id"), MapUtil.getString(issueDepartment, "departmentName"), MapUtil.getString(issueDepartment, "departmentDescription")));
                issueConverterDepartments.put(issueId, departments);
            }
        }
        //  이슈Vo에 담당부서 정보를 셋팅
        for (IssueVo issueVo : issueVos) {
            if (MapUtil.getObject(issueConverterUsers, String.valueOf(issueVo.getId())) != null) {
                List<DepartmentVo> departmentVos = (List) MapUtil.getObject(issueConverterUsers, String.valueOf(issueVo.getId()));
            if (MapUtil.getObject(issueConverterDepartments, String.valueOf(issueVo.getId())) != null) {
                List<DepartmentVo> departmentVos = (List) MapUtil.getObject(issueConverterDepartments, String.valueOf(issueVo.getId()));
                issueVo.setDepartmentVos(departmentVos);
            }
@@ -844,8 +881,8 @@
    private void setIssueDepartment(Issue issue, IssueVo issueVo) {
        List<DepartmentVo> departmentVos = Lists.newArrayList();
        for (IssueUser issueUser : issue.getIssueUsers()) {
            DepartmentVo departmentVo = ConvertUtil.copyProperties(issueUser.getDepartment(), DepartmentVo.class);
        for (IssueDepartment issueDepartment : issue.getIssueDepartments()) {
            DepartmentVo departmentVo = ConvertUtil.copyProperties(issueDepartment.getDepartment(), DepartmentVo.class);
            departmentVo.setByName(departmentVo.getByName());
            departmentVos.add(departmentVo);
        }
@@ -914,7 +951,7 @@
        this.checkStartCompleteDate(issueForm.getStartDate(), issueForm.getCompleteDate());
        //  담당자 유효성 체크 => 담당부서로 변경
        this.verifyIssueAssignee(project, issueForm);
        //this.verifyIssueAssignee(project, issueForm);
        Issue issue = this.getIssue(issueForm.getId());
@@ -942,9 +979,11 @@
        issue.setCompleteDate(issueForm.getCompleteDate());
        this.issueRepository.saveAndFlush(issue);
        //  담당부서 지정
        //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds());
        this.issueUserService.modifyIssueDepartment(issue, project.getWorkspace(), issueForm.getDepartmentIds());
        //  담당부서 지정
        if(issueForm.getDepartmentIds().size()>0){
            this.issueDepartmentService.modifyIssueDepartment(issue, project.getWorkspace(), issueForm.getDepartmentIds());
        }
        //  multipartFile 을 file Map List 객체로 변경한다.
        List<Map<String, Object>> convertFileMaps = this.convertMultipartFileToFile(multipartFiles);
@@ -1025,7 +1064,7 @@
            for (Long departmentId : issueForm.getDepartmentIds()) {
                boolean includeProject = false;
                for (ProjectRole projectRole : project.getProjectRoles()) {
                /*for (ProjectRole projectRole : project.getProjectRoles()) {
                    ProjectRoleUser projectRoleUser = this.projectRoleUserService.findByProjectRoleIdAndDepartmentId(projectRole.getId(), departmentId);
                    if (projectRoleUser != null) {
@@ -1033,7 +1072,7 @@
                        trustDepartmentIds.add(departmentId);
                        break;
                    }
                }
                }*/
                //  데이터 보정 작업 - 프로젝트에서 제외된 사용자는 담당자에서 제외 될 수 있도록 처리
                /*if (!includeProject) {
@@ -1075,7 +1114,7 @@
        }
    }*/
    /*//  이슈 수정 권한 체크
    //  이슈 수정 권한 체크
    private void verifyIssueModifyPermission(Long issueId) {
        Issue issue = this.getIssue(issueId);
@@ -1096,7 +1135,7 @@
        }
        return userVos;
    }*/
    }
    //  이슈 수정 권한을 갖고 있는지 확인
    private boolean checkHasPermission(IssueVo issueVo, List<UserVo> issueUserVos) {
@@ -1165,7 +1204,7 @@
        //  변경 이력 정보 추출
        StringBuilder detectIssueChange = new StringBuilder();
        //  이슈 수정 권한 체크
        //this.verifyIssueModifyPermission(issueForm.getId());
        this.verifyIssueModifyPermission(issueForm.getId());
        Issue issue = this.getIssue(issueForm.getId());
        IssueStatus issueStatus = this.issueStatusService.getIssueStatus(issueForm.getIssueStatusId());
@@ -1246,7 +1285,7 @@
        //  변경 이력 정보 추출
        StringBuilder detectIssueChange = new StringBuilder();
        //  이슈 수정 권한 체크
        //this.verifyIssueModifyPermission(issueForm.getId());
        this.verifyIssueModifyPermission(issueForm.getId());
        Issue issue = this.getIssue(issueForm.getId());
        issue.setProject(this.projectService.getProject(issueForm.getProjectId()));
@@ -1254,7 +1293,7 @@
        this.issueHistoryService.detectIssueManager(issue, issueForm, detectIssueChange);
        //this.issueUserService.modifyIssueUser(issue, issue.getProject().getWorkspace(), issueForm.getUserIds());
        this.issueUserService.modifyIssueDepartment(issue, issue.getProject().getWorkspace(), issueForm.getDepartmentIds());
        this.issueDepartmentService.modifyIssueDepartment(issue, issue.getProject().getWorkspace(), issueForm.getDepartmentIds());
        this.issueRepository.saveAndFlush(issue);
        //  이슈 이력 등록
@@ -1304,7 +1343,7 @@
    private Issue issueRemoves(Long issueId) {
        Issue issue = this.getIssue(issueId);
        //  이슈 수정 권한을 갖고 있는지 확인
        //this.verifyIssueModifyPermission(issueId);
        this.verifyIssueModifyPermission(issueId);
        //  이슈 첨부 파일을 삭제한다.
        if (issue.getAttachedFiles().size() > 0) {
@@ -1802,7 +1841,8 @@
        if (issueAssigneeMaps.size() > 0) {
            //  이슈 담당자 벌크 등록
            this.issueUserService.insertIssueUser(issueAssigneeMaps);
            //this.issueUserService.insertIssueUser(issueAssigneeMaps);
            this.issueDepartmentService.insertIssueDepartment(issueAssigneeMaps);
        }
    }
src/main/java/kr/wisestone/owl/service/impl/IssueUserServiceImpl.java
@@ -75,85 +75,6 @@
        }
    }
    //  이슈 담당부서를 변경한다.
    @Override
    @Transactional
    public void modifyIssueDepartment(Issue issue, Workspace workspace, List<Long> departmentIds) {
        List<Long> oldDepartmentIds = Lists.newArrayList();
        //  이전 담당 부서
        for (IssueUser issueUser : issue.getIssueUsers()) {
            oldDepartmentIds.add(issueUser.getDepartment().getId());
        }
        List<Long> newDepartmentIds = CommonUtil.searchChangeList(oldDepartmentIds, departmentIds); //  추가해야할 부서를 찾는다.
        List<Long> removeDepartmentIds = CommonUtil.searchChangeList(departmentIds, oldDepartmentIds); //  삭제해야할 부서를 찾는다.
        if (removeDepartmentIds.size() > 0) {
            Map<String, Object> removeIssueAssigneeMap = new HashMap<>();
            removeIssueAssigneeMap.put("issueId", issue.getId());
            removeIssueAssigneeMap.put("departmentIds", removeDepartmentIds);
            //  담당부서 삭제
            this.issueUserMapper.deleteIssueUserByIssueIdAndMultiDepartmentId(removeIssueAssigneeMap);
        }
        if (newDepartmentIds.size() > 0) {
            List<Map<String, Long>> addIssueAssigneeMaps = Lists.newArrayList();
            for (Long departmentId : newDepartmentIds) {
                Map<String, Long> issueAssigneeMap = new HashMap<>();
                issueAssigneeMap.put("departmentId", departmentId); //담당부서
                issueAssigneeMap.put("issueId", issue.getId());
                issueAssigneeMap.put("workspaceId", workspace.getId());
                issueAssigneeMap.put("registerId", this.webAppUtil.getLoginId());
                addIssueAssigneeMaps.add(issueAssigneeMap);
            }
            //  담당부서 추가
            this.issueUserMapper.insertIssueUser(addIssueAssigneeMaps);
        }
    }
    @Override
    @Transactional
    public void insertIssueDepartment(List<Map<String, Long>> issueAssigneeMaps) {
        //  이슈 담당부서 벌크 등록
        this.issueUserMapper.insertIssueUser(issueAssigneeMaps);
    }
    //  이슈 담당부서에서 제외한다.
    @Override
    @Transactional
    public void removeIssueDepartment(Long projectId, List<Long> excludeDepartmentIds) {
        for (Long departmentId : excludeDepartmentIds) {
            Map<String, Object> issueUserMap = new HashMap<>();
            issueUserMap.put("departmentId", departmentId);
            issueUserMap.put("projectId", projectId);
            List<Map<String, Object>> results = this.issueUserMapper.findByDepartmentIdAndProjectId(issueUserMap);
            if (results.size() > 0) {
                List<Long> issueIds = Lists.newArrayList();
                for (Map<String, Object> result : results) {
                    Long id = MapUtil.getLong(result, "id");
                    if (id != null) {
                        issueIds.add(id);
                    }
                }
                if (issueIds.size() > 0) {
                    Map<String, Object> removeIssueAssigneeMap = new HashMap<>();
                    removeIssueAssigneeMap.put("departmentId", departmentId);
                    removeIssueAssigneeMap.put("issueIds", issueIds);
                    this.issueUserMapper.deleteIssueUserByDepartmentIdAndMultiIssueId(removeIssueAssigneeMap);
                }
            }
        }
    }
    //  이슈 담당자 찾기
    @Override
    @Transactional
src/main/java/kr/wisestone/owl/service/impl/ProjectRoleUserServiceImpl.java
@@ -55,11 +55,11 @@
    }
    //  해당 부서가 특정 역할에 소속되어 있는지 확인한다.
    @Override
    /*@Override
    @Transactional(readOnly = true)
    public ProjectRoleUser findByProjectRoleIdAndDepartmentId(Long projectRoleId, Long departmentId) {
        return this.projectRoleUserRepository.findByProjectRoleIdAndDepartmentId(projectRoleId, departmentId);
    }
    }*/
    //  업무 공간을 탈퇴한 사용자가 다른 업무 공간의 프로젝트 관리자, 일반 사용자로 있을 경우 제거한다.
    @Override
src/main/resources/migration/V1_1__Initial_Setup.sql
@@ -80,6 +80,9 @@
    `project_id` bigint(20) DEFAULT NULL,
    `priority_id` bigint(20) DEFAULT NULL,
    `severity_id` bigint(20) DEFAULT NULL,
    `company_id` bigint(20) DEFAULT NULL,
    `hosting_id` bigint(20) DEFAULT NULL,
    `isp_id` bigint(20) DEFAULT NULL,
    `title` varchar(300) DEFAULT NULL,
    `description` mediumtext COMMENT 'description',
    `reverse_index` bigint(20) DEFAULT NULL,
@@ -304,7 +307,6 @@
CREATE TABLE IF NOT EXISTS `issue_user` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `user_id` bigint(20) NULL,
    `department_id` bigint(20) NOT NULL,
    `issue_id` bigint(20) NOT NULL,
    `workspace_id` bigint(20) NOT NULL,
    `register_id` bigint(20) NOT NULL,
@@ -315,7 +317,23 @@
    KEY `userIdAndIssueIdIndex` (`user_id`,`issue_id`),
    KEY `issueIdIndex` (`issue_id`),
    KEY `workspaceIdIndex` (`workspace_id`),
    KEY `userIdIndex` (`user_id`),
    KEY `userIdIndex` (`user_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 테이블 owl_en_1.5.issue_department 구조 내보내기
CREATE TABLE IF NOT EXISTS `issue_department` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `department_id` bigint(20) NOT NULL,
    `issue_id` bigint(20) NOT NULL,
    `workspace_id` bigint(20) NOT NULL,
    `register_id` bigint(20) NOT NULL,
    `modify_id` bigint(20) NOT NULL,
    `register_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `modify_date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
    PRIMARY KEY (`id`),
    KEY `departmentIdAndIssueIdIndex` (`department_id`,`issue_id`),
    KEY `issueIdIndex` (`issue_id`),
    KEY `workspaceIdIndex` (`workspace_id`),
    KEY `departmentIdIndex` (`department_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@@ -512,8 +530,7 @@
CREATE TABLE IF NOT EXISTS `project_role_user` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `project_role_id` bigint(20) NOT NULL,
    `user_id` bigint(20) NULL,
    `department_id` bigint(20) NULL,
    `user_id` bigint(20) NOT NULL,
    `register_id` bigint(20) NOT NULL,
    `register_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `modify_id` bigint(20) NOT NULL,
@@ -521,8 +538,22 @@
    PRIMARY KEY (`id`),
    KEY `projectRoleIdAndUserIdIndex` (`project_role_id`,`user_id`),
    KEY `userIdIndex` (`user_id`),
    KEY `projectRoleIdIndex` (`project_role_id`),
    KEY `departmentIdIndex` (`department_id`)
    KEY `projectRoleIdIndex` (`project_role_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 테이블 owl_en_1.5.project_role_department 구조 내보내기
CREATE TABLE IF NOT EXISTS `project_role_department` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `project_role_id` bigint(20) NOT NULL,
    `department_id` bigint(20) NULL,
    `register_id` bigint(20) NOT NULL,
    `register_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `modify_id` bigint(20) NOT NULL,
    `modify_date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
    PRIMARY KEY (`id`),
    KEY `projectRoleIdAndDepartmentIdIndex` (`project_role_id`,`department_id`),
    KEY `departmentIdIndex` (`department_id`),
    KEY `projectRoleIdIndex` (`project_role_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 테이블 데이터 owl_en_1.5.project_role_user:~0 rows (대략적) 내보내기
src/main/resources/mybatis/query-template/issue-template.xml
@@ -39,6 +39,7 @@
        INNER JOIN issue_type issue_type FORCE INDEX(PRIMARY) ON issue.issue_type_id = issue_type.id
        INNER JOIN priority priority FORCE INDEX(PRIMARY) ON issue.priority_id = priority.id
        INNER JOIN severity severity FORCE INDEX(PRIMARY) ON issue.severity_id = severity.id
        LEFT OUTER JOIN issue_department issued FORCE INDEX(issueIdIndex) ON issue.id = issued.issue_id
        LEFT OUTER JOIN issue_user issue_user FORCE INDEX(issueIdIndex) ON issue.id = issue_user.issue_id
        LEFT OUTER JOIN (SELECT issue_id, COUNT(id) as attachedFileCount FROM attached_file GROUP BY issue_id)
        temp_attached_file on (temp_attached_file.issue_id = issue.id)
@@ -131,6 +132,15 @@
            <when test="userIds.size != 0">
                AND issue_user.user_id IN
                <foreach collection="userIds" item="item" index="index" separator="," open="(" close=")">
                    #{item}
                </foreach>
            </when>
        </choose>
        <choose>
            <when test="departmentIds.size != 0">
                AND issue_department.department_id IN
                <foreach collection="departmentIds" item="item" index="index" separator="," open="(" close=")">
                    #{item}
                </foreach>
            </when>
@@ -260,6 +270,15 @@
            <when test="userIds.size != 0">
                AND issue_user.user_id IN
                <foreach collection="userIds" item="item" index="index" separator="," open="(" close=")">
                    #{item}
                </foreach>
            </when>
        </choose>
        <choose>
            <when test="departmentIds.size != 0">
                AND issue_department.department_id IN
                <foreach collection="departmentIds" item="item" index="index" separator="," open="(" close=")">
                    #{item}
                </foreach>
            </when>
@@ -409,6 +428,26 @@
        </choose>
    </select>
    <select id="findIssueDepartment" resultType="java.util.HashMap"
            parameterType="kr.wisestone.owl.web.condition.IssueCondition">
        SELECT
        i.id AS issueId,
        d.id AS id,
        d.department_name AS name
        FROM issue i
        INNER JOIN issue_department issued ON issued.issue_id = i.id
        INNER JOIN department d ON d.id = issued.department_id
        WHERE 1=1
        <choose>
            <when test="issueIds.size != 0">
                AND i.id IN
                <foreach collection="issueIds" item="item" index="index" separator="," open="(" close=")">
                    #{item}
                </foreach>
            </when>
        </choose>
    </select>
    <!--    이슈 유형을 사용하는 이슈 갯수를 조회한다 -->
    <select id="countByIssueTypeId" resultType="java.lang.Long" parameterType="java.lang.Long">
      SELECT COUNT(DISTINCT id) FROM
src/main/resources/mybatis/query-template/issueDepartment-template.xml
New file
@@ -0,0 +1,42 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.wisestone.owl.mapper.IssueDepartmentMapper">
    <!--    이슈 담당부서 bulk insert, import, modify, add 에서 사용 -->
    <insert id="insertIssueDepartment" keyColumn="id" keyProperty="id" useGeneratedKeys="true"
            parameterType="java.util.HashMap">
        INSERT INTO issue_department(department_id, issue_id, workspace_id, register_id, modify_id, register_date, modify_date)
        VALUES
        <foreach collection="list" item="map" index="index" separator="," open="" close="">
            (#{map.departmentId}, #{map.issueId}, #{map.workspaceId}, #{map.registerId}, #{map.registerId}, NOW(), NOW())
        </foreach>
    </insert>
    <!--담당부서-->
    <!--    이슈 담당부서 bulk 삭제 - modify, add 에서 사용  -->
    <delete id="deleteIssueDepartmentByIssueIdAndMultiDepartmentId" parameterType="java.util.HashMap">
        DELETE FROM issue_department WHERE issue_id = #{issueId} AND department_id IN (
        <foreach collection="map.departmentIds" item="item" index="index" separator="," open="" close="">
            #{item}
        </foreach>
        )
    </delete>
    <delete id="deleteIssueDepartmentByDepartmentIdAndMultiIssueId" parameterType="java.util.HashMap">
        DELETE FROM issue_department WHERE department_id = #{departmentId} AND issue_id IN (
        <foreach collection="issueIds" item="item" index="index" separator="," open="" close="">
            #{item}
        </foreach>
        )
    </delete>
    <!--    이슈 담당부서를 조회한다 -->
    <select id="findByDepartmentIdAndProjectId" resultType="java.util.HashMap" parameterType="java.util.HashMap">
        SELECT DISTINCT(i.id) FROM issue i
                                       INNER JOIN issue_department iu ON iu.issue_id = i.id
                                       INNER JOIN department d ON d.id = iu.department_id
        WHERE i.project_id = #{projectId} AND d.id = #{departmentId}
    </select>
</mapper>
src/main/resources/mybatis/query-template/issueUser-template.xml
@@ -6,39 +6,12 @@
    <!--    이슈 담당자 bulk insert, import, modify, add 에서 사용 -->
    <insert id="insertIssueUser" keyColumn="id" keyProperty="id" useGeneratedKeys="true"
            parameterType="java.util.HashMap">
        INSERT INTO issue_user(department_id, user_id, issue_id, workspace_id, register_id, modify_id, register_date, modify_date)
        INSERT INTO issue_user(user_id, issue_id, workspace_id, register_id, modify_id, register_date, modify_date)
        VALUES
        <foreach collection="list" item="map" index="index" separator="," open="" close="">
            (#{map.departmentId},#{map.userId}, #{map.issueId}, #{map.workspaceId}, #{map.registerId}, #{map.registerId}, NOW(), NOW())
            (#{map.userId}, #{map.issueId}, #{map.workspaceId}, #{map.registerId}, #{map.registerId}, NOW(), NOW())
        </foreach>
    </insert>
    <!--담당부서-->
    <!--    이슈 담당부서 bulk 삭제 - modify, add 에서 사용  -->
    <delete id="deleteIssueUserByIssueIdAndMultiDepartmentId" parameterType="java.util.HashMap">
        DELETE FROM issue_user WHERE issue_id = #{issueId} AND department_id IN (
        <foreach collection="map.departmentIds" item="item" index="index" separator="," open="" close="">
            #{item}
        </foreach>
        )
    </delete>
    <delete id="deleteIssueUserByDepartmentIdAndMultiIssueId" parameterType="java.util.HashMap">
        DELETE FROM issue_user WHERE department_id = #{departmentId} AND issue_id IN (
        <foreach collection="issueIds" item="item" index="index" separator="," open="" close="">
            #{item}
        </foreach>
        )
    </delete>
    <!--    이슈 담당부서를 조회한다 -->
    <select id="findByDepartmentIdAndProjectId" resultType="java.util.HashMap" parameterType="java.util.HashMap">
        SELECT DISTINCT(i.id) FROM issue i
                                       INNER JOIN issue_user iu ON iu.issue_id = i.id
                                       INNER JOIN department d ON d.id = iu.department_id
        WHERE i.project_id = #{projectId} AND d.id = #{departmentId}
    </select>
    <!--담당자-->
    <!--    이슈 담당자 bulk 삭제 - modify, add 에서 사용  -->