박정하 박정하 01-13
250113 박정하 부서, 부서 사용자, 부서 호스트, 호스트 수정
@e6e06481cdc474a3e3cc30ac25c34052c32c7823
client/views/component/DepartmentTree.vue
--- client/views/component/DepartmentTree.vue
+++ client/views/component/DepartmentTree.vue
@@ -1,64 +1,38 @@
 <template>
-  <li class="cursor">
-    <div
-      :class="{
+  <ul class="tree-wrap">
+    <li class="cursor" v-for="(item, idx) of treeList" :key="idx">
+      <div :class="{
         'tree-container flex align-center': true,
-        selected: node.dept_code === selectedId,
-      }"
-      @click="handleClick"
-    >
-      <p>
-        <svg-icon
-          type="mdi"
-          :width="18"
-          :height="18"
-          :path="arrowPath"
-        ></svg-icon>
-      </p>
-      <p>
-        <svg-icon
-          type="mdi"
-          :width="18"
-          :height="18"
-          :path="notePath"
-          :color="'#fbbe28'"
-        ></svg-icon>
-      </p>
-      <p class="node-text">{{ node.dept_nm }}</p>
-    </div>
-    <ul
-      v-if="node.children && node.children.length > 0"
-      class="children-node"
-      :style="{ height: toggleSelect === node.dept_code ? 'auto' : '0' }"
-    >
-      <DepartmentTree
-        v-for="(child, index) in node.children"
-        :node="child"
-        :key="index"
-        @selectedNode="parentSelectedNode"
-      />
-    </ul>
-  </li>
+        selected: node.id === selectedId,
+      }" @click="handleClick">
+        <p>
+          <svg-icon type="mdi" :width="18" :height="18" :path="arrowPath"></svg-icon>
+        </p>
+        <p>
+          <svg-icon type="mdi" :width="18" :height="18" :path="notePath" :color="'#fbbe28'"></svg-icon>
+        </p>
+        <p class="node-text">{{ node.nm }}</p>
+      </div>
+      <ul v-if="node.childList && node.childList.length > 0" class="children-node" :style="{ height: toggleSelect === node.id ? 'auto' : '0' }">
+        <DepartmentTree v-for="(item, idx) in node.childList" :node="item" :key="idx" @selectedNode="parentSelectedNode" />
+      </ul>
+    </li>
+  </ul>
 </template>
-
 <script>
-import axios from "axios";
 import SvgIcon from "@jamescoyle/vue-icon";
-import {
-  mdiNote,
-  mdiChevronRight,
-  mdiChevronDown,
-  mdiNoteOutline,
-} from "@mdi/js";
+import { mdiNote, mdiChevronRight, mdiChevronDown, mdiNoteOutline } from "@mdi/js";
 
 export default {
   name: "DepartmentTree",
+
   props: {
-    node: {
-      type: Object,
-      default: () => ({}),
+    treeList: {
+      type: Array,
+      default: [],
     },
   },
+
   data() {
     return {
       toggleSelect: null,
@@ -67,6 +41,7 @@
       selectedId: null,
     };
   },
+
   methods: {
     handleClick: function () {
       const vm = this;
@@ -78,8 +53,7 @@
       });
 
       // 노드 선택 시 하위 노드 표시 및 가리기
-      vm.$emit("selectedNode", vm.node);
-      if (vm.toggleSelect === vm.node.dept_code) {
+      if (vm.toggleSelect === vm.node.id) {
         vm.toggleSelect = null;
         vm.selectedId = null;
         vm.arrowPath = mdiChevronRight;
@@ -88,45 +62,35 @@
         if (!vm.node.children || vm.node.children.length === 0) {
           vm.getChildDepartment();
         }
-        vm.toggleSelect = vm.node.dept_code;
-        vm.selectedId = vm.node.dept_code;
+        vm.toggleSelect = vm.node.id;
+        vm.selectedId = vm.node.id;
         vm.arrowPath = mdiChevronDown;
         vm.notePath = mdiNoteOutline;
       }
+
+      vm.$emit("selectedNode", vm.node.id);
     },
     parentSelectedNode(node) {
       this.$emit("selectedNode", node);
     },
-    // 깊이 2 이상일 때 자식 노드 불러오기
-    getChildDepartment: function () {
-      axios
-        .get(`/department/tree/${this.node.dept_code}`)
-        .then((response) => {
-          this.node.children.push(...response.data.resultData.childDepartments);
-        })
-        .catch((error) => {
-          this.$showAlert(
-            "오류",
-            "목록 불러오기 오류, 관리자에게 문의바랍니다."
-          );
-        });
-    },
   },
+
   components: {
     SvgIcon: SvgIcon,
   },
 };
 </script>
-
 <style scoped>
 .tree-container {
   padding: 5px 10px;
 }
+
 .children-node {
   padding: 0 0 0 10px;
   overflow: hidden;
   transition: max-height 0.5s ease-in-out;
 }
+
 .node-text {
   font-size: 1.4rem;
   margin-left: 5px;
 
client/views/component/modal/Modal.vue (added)
+++ client/views/component/modal/Modal.vue
@@ -0,0 +1,89 @@
+<template>
+  <div v-show="isModalOpen" class="modal-wrapper">
+    <div class="modal-container">
+      <!-- 모달 HEAD (제목) -->
+      <div class="modal-title flex justify-between align-center">
+        <h2>{{ title }}</h2>
+        <button class="close-btn" @click="closeModal">
+          <svg-icon type="mdi" :width="20" :height="20" :path="closePath"></svg-icon>
+        </button>
+      </div>
+      <!-- 모달 BODY (본문) -->
+      <div class="modal-content-monthly">
+        <!-- 검색창 -->
+        <div class="search-bar flex justify-center mb10">
+          <div class="flex justify-between align-center">
+            <div class="flex25 pl0">
+              <select class="square-select full-select" v-model="searchData.key">
+                <option :value="null">선택</option>
+                <option value="user_nm">이름</option>
+                <option value="user_id">아이디</option>
+              </select>
+            </div>
+            <div class="pr0 flex75 flex align-center no-gutter">
+              <input type="text" class="square-input flex90" v-model="searchData.value" placeholder="검색어를 입력해주세요." @keyup.enter="searchList" />
+              <button class="square-button blue-btn flex10" @click="searchList">
+                <svg-icon type="mdi" :path="searchPath" class="square-icon"></svg-icon>
+              </button>
+            </div>
+          </div>
+        </div>
+        <!-- 목록: 본문 -->
+        <div class="overflow-y" style="max-height: 500px">
+          <table class="sticky-table list-table2">
+            <colgroup>
+              <col style="width: 10%" />
+              <col style="width: 10%" />
+              <col style="width: 40%" />
+              <col style="width: 40%" />
+            </colgroup>
+            <thead>
+              <tr>
+                <th><input type="checkbox" /></th>
+                <th>No</th>
+                <th>이름</th>
+                <th>아이디</th>
+              </tr>
+            </thead>
+            <tbody>
+              <tr>
+                <td></td>
+                <td></td>
+                <td></td>
+                <td></td>
+              </tr>
+            </tbody>
+          </table>
+        </div>
+        <!-- 목록: 페이지네이션 -->
+        <PaginationButton v-model:currentPage="search.currentPage" :perPage="search.perPage" :totalCount="search.totalRows" :click="selectUsers" />
+      </div>
+      <!-- 모달 FOOT (버튼) -->
+      <div class="modal-end flex justify-end">
+        <button class="blue-btn small-btn" @click="confirmSelection">등록</button>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+// icon용 svg import
+import SvgIcon from "@jamescoyle/vue-icon";
+import { mdiMagnify, mdiClose } from "@mdi/js";
+
+export default {
+  components: { SvgIcon },
+
+  data() {
+    return {
+      // icon용 svg path
+      searchPath: mdiMagnify,
+      closePath: mdiClose,
+
+      isModalOpen: true,
+
+      search: Object.assign({}, this.$getDefaultSerchVO()),
+      searchData: this.$getDefaultSerchItem(null, "string"),
+    }
+  }
+}
+</script>(No newline at end of file)
 
client/views/component/modal/UserSelectModal.vue (added)
+++ client/views/component/modal/UserSelectModal.vue
@@ -0,0 +1,174 @@
+<template>
+  <div v-show="isModalOpen" class="modal-wrapper">
+    <div class="modal-container">
+      <!-- 모달 HEAD -->
+      <div class="modal-title flex justify-between align-center">
+        <h2>멤버 추가</h2>
+        <button class="close-btn" @click="$emit('fnCloseModal')">
+          <svg-icon type="mdi" :width="20" :height="20" :path="closePath"></svg-icon>
+        </button>
+      </div>
+      <!-- 모달 BODY -->
+      <div class="modal-content-monthly">
+        <!-- 검색 -->
+        <div class="search-bar flex justify-between align-center mb10">
+          <div class="flex25 pl0">
+            <select class="square-select full-select" v-model="searchData.key">
+              <option :value="null">전체</option>
+              <option value="ui.user_nm">이름</option>
+              <option value="ui.user_id">아이디</option>
+            </select>
+          </div>
+          <div class="flex75 flex align-center no-gutter pr0">
+            <input type="text" class="square-input flex90" placeholder="검색어를 입력해주세요." v-model="searchData.value" @keyup.enter="fnSelectUserList" />
+            <button class="square-button blue-btn flex10" @click="fnSelectUserList">
+              <svg-icon type="mdi" :path="searchPath" class="square-icon"></svg-icon>
+            </button>
+          </div>
+        </div>
+        <!-- 목록 -->
+        <div>
+          <!-- 목록-본문 -->
+          <table class="list-table2">
+            <colgroup>
+              <col style="width: 10%" />
+              <col style="width: 35%" />
+              <col style="width: 35%" />
+              <col style="width: 20%" />
+            </colgroup>
+            <thead>
+              <tr>
+                <th>No</th>
+                <th>이름</th>
+                <th>아이디</th>
+                <th>선택</th>
+              </tr>
+            </thead>
+            <tbody class="overflow-y" style="max-height: 500px">
+              <template v-if="userList.length > 0">
+                <tr v-for="(item, idx) in userList" :key="idx">
+                  <td>{{ search.totalRows - idx - (search.currentPage - 1) * search.perPage }}</td>
+                  <td>{{ item.userNm }}</td>
+                  <td>{{ item.userId }}</td>
+                  <td><button type="button" class="blue-border-btn set-btn" @click="fnAddUser(item.userId)">선택</button></td>
+                </tr>
+              </template>
+              <tr v-else>
+                <td colspan="4">등록된 데이터가 없습니다.</td>
+              </tr>
+            </tbody>
+          </table>
+          <!-- 목록-페이지네이션 -->
+          <PaginationButton v-model:currentPage="search.currentPage" :perPage="search.perPage" :totalCount="search.totalRows" :click="fnSelectUserList" />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import axios from "axios";
+// icon용 svg import
+import SvgIcon from "@jamescoyle/vue-icon";
+import { mdiMagnify, mdiClose } from "@mdi/js";
+// 컴포넌트 import
+import PageNavigation from "../../component/PageNavigation.vue";
+import PaginationButton from "../../component/PaginationButton.vue";
+
+export default {
+  components: { SvgIcon, PageNavigation, PaginationButton },
+
+  props: {
+    deptCode: {
+      type: String,
+      default: null,
+    },
+    isModalOpen: {
+      type: Boolean,
+      default: false,
+    },
+  },
+
+  data() {
+    return {
+      // icon용 svg path
+      searchPath: mdiMagnify,
+      closePath: mdiClose,
+
+      // 검색용
+      search: Object.assign({}, this.$getDefaultSerchVO()),
+      searchData: Object.assign({}, this.$getDefaultSerchItem(null, "string")),
+
+      // 목록용
+      userList: [],
+    }
+  },
+
+  watch: {
+    isModalOpen(v) {
+      if (v) {
+        this.fnSelectUserList();
+      } else {
+        // 초기화
+        this.search = Object.assign({}, this.$getDefaultSerchVO());
+        this.searchData = Object.assign({}, this.$getDefaultSerchItem(null, "string"));
+        this.userList = []; // 사용자 목록
+      }
+    },
+  },
+
+  methods: {
+    // 사용자 목록 조회
+    fnSelectUserList() {
+      const vm = this;
+
+      // 데이터 세팅
+      let deptInfo = Object.assign({}, this.$getDefaultSerchItem(null, "string"));
+      deptInfo.key = 'deptCode';
+      deptInfo.value = null;
+
+      vm.search.searchObjectList = []; // 초기화
+      vm.search.searchObjectList.push(vm.searchData);
+      vm.search.searchObjectList.push(deptInfo);
+
+      // 실행
+      axios({
+        url: "/member/list",
+        method: "post",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+        data: vm.search,
+      })
+        .then(response => {
+          vm.search = response.data.resultData.searchVO;
+          vm.userList = response.data.resultData.members;
+        })
+        .catch(error => {
+          vm.$showAlert("사용자 관리", "목록 불러오기 오류, 관리자에게 문의바랍니다.");
+        });
+    },
+
+    // 사용자 추가 (선택 버튼 동작)
+    fnAddUser(userId) {
+      const vm = this;
+      // 데이터 세팅
+      let orgnztMember = {
+        userId: userId,
+        deptCode: this.deptCode
+      }
+      // 실행
+      axios({
+        url: "/orgnztMember",
+        method: "post",
+        headers: { "Content-Type": "application/json" },
+        data: orgnztMember,
+      })
+        .then(response => {
+          vm.$showAlert("사용자 추가", "사용자를 추가했습니다.");
+          vm.$emit('fnCloseModal'); // 모달 닫기
+        })
+        .catch(error => {
+          vm.$showAlert("오류", "부서 내 사용자 추가 오류, 관리자에게 문의바랍니다.");
+        });
+    },
+  }
+}
+</script>(No newline at end of file)
 
client/views/component/treeMenu/TreeMenu.vue (added)
+++ client/views/component/treeMenu/TreeMenu.vue
@@ -0,0 +1,102 @@
+<template>
+  <li>
+    <div :class="{
+      'tree-container flex align-center cursor': true,
+      selected: currentDeptCode.id === node.id,
+    }" @click="toggleNode(node)">
+      <div>
+        <svg-icon type="mdi" :width="18" :height="18" :path="arrowPath"></svg-icon>
+      </div>
+      <div>
+        <svg-icon type="mdi" :width="18" :height="18" :path="notePath" :color="'#fbbe28'"></svg-icon>
+      </div>
+      <p class="node-text">{{ node.nm }}</p>
+    </div>
+    <template v-if="node.childList.length > 0">
+      <ul v-if="isOpen" class="children-node">
+        <li v-for="(item, idx) of node.childList" :key="idx">
+          <TreeMenu :node="item" :currentDeptCode="currentDeptCode" @changeCurrent="changeCurrentNode" />
+        </li>
+      </ul>
+    </template>
+  </li>
+</template>
+<script>
+import SvgIcon from "@jamescoyle/vue-icon";
+import { mdiNote, mdiChevronRight, mdiChevronDown, mdiNoteOutline } from "@mdi/js";
+
+export default {
+  name: "TreeMenu",
+
+  components: {
+    SvgIcon: SvgIcon,
+  },
+
+  props: {
+    node: {
+      type: Object,
+      required: true,
+    },
+    currentDeptCode: {
+      type: Object,
+    },
+  },
+
+  data() {
+    return {
+      isOpen: false,
+
+      notePath: mdiNote,
+      arrowPath: mdiChevronRight,
+    };
+  },
+
+  watch: {
+    currentDeptCode: {
+      deep: true,
+      handler(v) {
+        if (this.$isEmpty(v)) {
+          this.isOpen = false;
+          this.notePath = mdiNote;
+          this.arrowPath = mdiChevronRight;
+        }
+      },
+    }
+  },
+
+  methods: {
+    toggleNode(node) {
+      this.isOpen = !this.isOpen;
+
+      if (this.isOpen) {
+        this.notePath = mdiNote;
+        this.arrowPath = mdiChevronRight;
+      } else {
+        this.notePath = mdiNoteOutline;
+        this.arrowPath = mdiChevronDown;
+      }
+
+      this.changeCurrentNode(node);
+    },
+    changeCurrentNode(node) {
+      this.$emit("changeCurrent", node);
+    }
+  },
+};
+</script>
+<style scoped>
+.tree-container {
+  padding: 5px 10px;
+}
+
+.children-node {
+  padding: 0 0 0 10px;
+  overflow: hidden;
+  transition: max-height 0.5s ease-in-out;
+}
+
+.node-text {
+  font-size: 1.4rem;
+  margin-left: 5px;
+}
+</style>(No newline at end of file)
client/views/pages/integrated/DepartmentManagement.vue
--- client/views/pages/integrated/DepartmentManagement.vue
+++ client/views/pages/integrated/DepartmentManagement.vue
@@ -10,177 +10,172 @@
           <div class="left-content flex100 content-box">
             <div class="content-box">
               <div class="content-titleZone">
-                <p class="box-title">부서리스트</p>
+                <p class="box-title">부서 목록</p>
               </div>
               <div class="content-zone overflow-y">
-                <ul class="tree-wrap">
-                  <DepartmentTree v-for="(node, index) in departmentTreeList" :node="node" :key="index" @selectedNode="loadDepartmentData" @click="deptHostUncheckAll" />
+                <ul class="tree-wrap" v-if="deptTreeList.length > 0">
+                  <TreeMenu v-for="(item, idx) in deptTreeList" :key="idx" :node="item" :currentDeptCode="selectedDept" @changeCurrent="fnSelectDept" />
                 </ul>
               </div>
             </div>
           </div>
         </div>
-        <div class="flex80 content-box">
-          <div class="right-content flex100">
-            <div class="content-titleZone">
-              <p v-if="departmentData.dept_nm" class="box-title"> {{ departmentData.dept_nm }} </p>
-              <p v-else class="box-title">부서 추가</p>
+        <div class="right-content flex80">
+          <!-- 부서 정보 -->
+          <div class="content-titleZone">
+            <p class="box-title">부서 정보</p>
+          </div>
+          <div class="table-zone">
+            <div class="form-box">
+              <table class="form-table2">
+                <colgroup>
+                  <col style="width: 10%" />
+                  <col style="width: 40%" />
+                  <col style="width: 10%" />
+                  <col style="width: 40%" />
+                </colgroup>
+                <tbody>
+                  <tr>
+                    <th>부서코드</th>
+                    <td style="display: flex">
+                      <input type="text" class="full-input" v-model="currentDept.dept_code" :disabled="editMode == 'update'" />
+                      <button style="flex-grow: 1" class="small-btn blue-border-btn" v-if="editMode == 'create'" @click="fnDeptCodeDupChk">중복확인</button>
+                    </td>
+                    <th>부서명</th>
+                    <td>
+                      <input type="text" class="full-input" v-model="currentDept.dept_nm" />
+                    </td>
+                  </tr>
+                  <tr>
+                    <th>부서설명</th>
+                    <td>
+                      <input type="text" class="full-input" v-model="currentDept.dept_dc" />
+                    </td>
+                    <th>상위부서</th>
+                    <td style="display: flex">
+                      <input type="text" class="full-input" v-model="currentDept.upper_dept_nm" readonly />
+                      <button style="flex-grow: 1" class="small-btn blue-border-btn" @click="fnOpenModalByDeptList">부서찾기</button>
+                    </td>
+                  </tr>
+                </tbody>
+              </table>
             </div>
-            <div class="content-zone overflow-y">
-              <div style="max-height: 35%">
-                <div class="table-zone">
-                  <div class="form-box">
-                    <table class="form-table2">
-                      <colgroup>
-                        <col style="width: 10%" />
-                        <col style="width: 40%" />
-                        <col style="width: 10%" />
-                        <col style="width: 40%" />
-                      </colgroup>
-                      <tbody>
-                        <tr>
-                          <th>부서코드</th>
-                          <td style="display: flex">
-                            <input type="text" v-model="departmentData.dept_code" id="dept_code" class="full-input" :disabled="dataLoaded" />
-                            <button v-if="!dataLoaded" @click="deptCodeDuplicateCheck()" style="flex-grow: 1" class="small-btn blue-border-btn" id="deptCodeDuplicateCheck">중복확인</button>
-                          </td>
-                          <th>부서명</th>
-                          <td>
-                            <input type="text" v-model="departmentData.dept_nm" id="dept_nm" class="full-input" />
-                          </td>
-                        </tr>
-                        <tr>
-                          <th>부서설명</th>
-                          <td>
-                            <input type="text" v-model="departmentData.dept_dc" id="dept_dc" class="full-input" />
-                          </td>
-                          <th>상위부서</th>
-                          <td style="display: flex">
-                            <input type="text" v-model="departmentData.upper_dept_nm" id="upper_dept_nm" class="full-input" readonly :disabled="departmentData.dept_code == '1000' && departmentData.upper_dept == null" />
-                            <button v-if="!dataLoaded || (departmentData.dept_code == '1000' && departmentData.upper_dept != null)" @click="openDeptSearchModal()" style="flex-grow: 1" class="small-btn blue-border-btn">부서찾기</button>
-                          </td>
-                        </tr>
-                        <tr v-if="departmentData.author == 'ROLE_ADMIN'">
-                          <th>권한</th>
-                          <td>
-                            <select name="" id="author" class="full-select" v-model="departmentData.author" :disabled="dataLoaded">
-                              <option :value="null" disabled> 권한을 선택해주세요. </option>
-                              <option v-for="(author, idx) in authorList" :key="idx" :value="author.author">{{ author.author_dc }}</option>
-                            </select>
-                          </td>
-                        </tr>
-                      </tbody>
-                    </table>
-                  </div>
-                </div>
-                <div class="flex justify-end">
-                  <template v-if="!dataLoaded">
-                    <button class="blue-btn small-btn" @click="departmentInsert">등록</button>
-                  </template>
-                  <template v-else>
-                    <button class="blue-btn small-btn" @click="updateDepartment()">수정</button>
-                    <button v-if="departmentData.upper_dept != null" class="red-border-btn small-btn" @click="deleteDepartments()">삭제</button>
-                    <button class="blue-border-btn small-btn" @click="insertForm()">취소</button>
-                  </template>
-                </div>
+          </div>
+          <div class="flex justify-end">
+            <button class="blue-btn small-btn" v-if="editMode == 'create'" @click="fnInsertDept">등록</button>
+            <button class="blue-btn small-btn" v-else @click="fnUpdateDept">수정</button>
+            <button class="red-border-btn small-btn" v-if="editMode == 'update'" @click="fnDeleteDept">삭제</button>
+            <button class="blue-border-btn small-btn" @click="fnCancelDept"><span v-if="editMode == 'create'">초기화</span><span v-else>취소</span></button>
+          </div>
+          <!-- 부서 내 사용자 목록 -->
+          <div class="content-titleZone">
+            <p class="box-title">사용자 목록</p>
+          </div>
+          <div class="table-zone">
+            <div class="list-info flex justify-between align-center">
+              <div class="count-zone">
+                <p> 총 <span>{{ userList.length }}</span>건 중 <span>{{ userSelectList.length }}</span>건 선택 </p>
               </div>
-              <div style="min-height: 32.5%">
-                <div class="table-zone">
-                  <div class="list-info flex justify-between align-center">
-                    <div class="count-zone">
-                      <p> 총 <span>{{ inDeptMemberList.length }}</span>건 중 <span>{{ selectedMembers.length }}</span>건 선택 </p>
-                    </div>
-                    <div class="cunt-selectZone">
-                      <select name="" id="">
-                        <option value="">10개 보기</option>
-                        <option value="">20개 보기</option>
-                      </select>
-                    </div>
-                  </div>
-                  <table class="list-table">
-                    <colgroup>
-                      <col style="width: 5%" />
-                      <col style="width: 10%" />
-                      <col style="width: 42.5%" />
-                      <col style="width: 42.5%" />
-                    </colgroup>
-                    <thead>
-                      <tr>
-                        <th>
-                          <input type="checkbox" @change="memberCheckAll" />
-                        </th>
-                        <th>No</th>
-                        <th>이름</th>
-                        <th>로그인아이디</th>
-                      </tr>
-                    </thead>
-                    <tbody>
-                      <tr v-for="(inDeptMember, idx) in inDeptMemberList" :key="idx">
-                        <td>
-                          <input type="checkbox" v-model="inDeptMember.selected" name="memberList" />
-                        </td>
-                        <td>{{ memberIdx - idx }}</td>
-                        <td>{{ inDeptMember.userNm }}</td>
-                        <td>{{ inDeptMember.userId }}</td>
-                      </tr>
-                    </tbody>
-                  </table>
-                </div>
-                <div class="flex justify-end">
-                  <button class="blue-btn small-btn" @click="openMemberModal">멤버추가</button>
-                  <button class="red-border-btn small-btn" @click="deleteSelection">멤버삭제</button>
-                </div>
-                <PaginationButton v-model:currentPage="memberSearch.currentPage" :perPage="memberSearch.perPage" :totalCount="memberSearch.totalRows" :maxRange="5" :click="selectMemberList" />
+              <div class="cunt-selectZone">
+                <select v-model="searchByUser.perPage" @change="fnSelectUserList">
+                  <option value="10">10개 보기</option>
+                  <option value="20">20개 보기</option>
+                </select>
               </div>
-              <!-- <div style="min-height: 32.5%">
-                <div class="table-zone">
-                  <div class="list-info flex justify-between align-center">
-                    <div class="count-zone">
-                      <p> 총 <span>{{ deptHostData.length }}</span>건 중 <span>{{ selectedDepts.length }}</span>건 선택 </p>
-                    </div>
-                    <div class="cunt-selectZone">
-                      <select name="" id="">
-                        <option value="">10개 보기</option>
-                        <option value="">20개 보기</option>
-                      </select>
-                    </div>
-                  </div>
-                  <table class="list-table">
-                    <colgroup>
-                      <col style="width: 5%" />
-                      <col style="width: 10%" />
-                      <col style="width: 42.5%" />
-                      <col style="width: 42.5%" />
-                    </colgroup>
-                    <thead>
-                      <tr>
-                        <th>
-                          <input type="checkbox" @click="deptHostCheckAll" v-model="deptCheckAll" />
-                        </th>
-                        <th>No</th>
-                        <th>호스트명</th>
-                        <th>메인폴더</th>
-                      </tr>
-                    </thead>
-                    <tbody>
-                      <tr v-for="(data, index) in deptHostData" :key="index" @click="chooseDeptHost(data, 'update')">
-                        <td>
-                          <input type="checkbox" v-model="selectedDepts" :value="data.host_code" @click.stop />
-                        </td>
-                        <td>{{ index + 1 }}</td>
-                        <td>{{ data.host_nm }}</td>
-                        <td>{{ data.main_folder_path }}</td>
-                      </tr>
-                    </tbody>
-                  </table>
-                  <PaginationButton v-model:currentPage="deptSearch.currentPage" :perPage="deptSearch.perPage" :totalCount="deptSearch.totalRows" :maxRange="5" :click="selectDeptHost" />
-                </div>
-                <div class="flex justify-end">
-                  <button class="orange-border-btn small-btn" @click="openHostModal"> 호스트추가 </button>
-                  <button class="blue-border-btn small-btn" @click="deleteSelectedDeptHosts"> 호스트삭제 </button>
-                </div>
-              </div> -->
             </div>
+            <table class="list-table">
+              <colgroup>
+                <col style="width: 5%" />
+                <col style="width: 10%" />
+                <col style="width: 42.5%" />
+                <col style="width: 42.5%" />
+              </colgroup>
+              <thead>
+                <tr>
+                  <th>
+                    <input type="checkbox" v-model="isChkUserAll" @change="fnChkAll()" />
+                  </th>
+                  <th>No</th>
+                  <th>이름</th>
+                  <th>아이디</th>
+                </tr>
+              </thead>
+              <tbody>
+                <template v-if="userList.length > 0">
+                  <tr v-for="(item, idx) of userList" :key="idx">
+                    <td>
+                      <input type="checkbox" :value="item" v-model="userSelectList" @click.stop="" @change="fnChangeChk" />
+                    </td>
+                    <td>{{ searchByUser.totalRows - idx - (searchByUser.currentPage - 1) * searchByUser.perPage }}</td>
+                    <td>{{ item.userNm }}</td>
+                    <td>{{ item.userId }}</td>
+                  </tr>
+                </template>
+                <tr v-else>
+                  <td colspan="4">등록된 데이터가 없습니다.</td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+          <div class="flex justify-end">
+            <button class="blue-btn small-btn" @click="fnOpenModalByUserList">사용자추가</button>
+            <button class="red-border-btn small-btn" @click="fnDeleteUser">사용자삭제</button>
+          </div>
+          <PaginationButton v-model:currentPage="searchByUser.currentPage" :perPage="searchByUser.perPage" :totalCount="searchByUser.totalRows" :maxRange="5" :click="selectMemberList" />
+          <!-- 부서 내 호스트 목록 -->
+          <div class="content-titleZone">
+            <p class="box-title">호스트 목록</p>
+          </div>
+          <DeptHostList :deptCode="selectedDept.id" />
+          <!-- 부서 내 디렉터리 목록 -->
+          <div class="content-titleZone">
+            <p class="box-title">디렉터리 목록</p>
+          </div>
+          <div class="table-zone">
+            <div class="list-info flex justify-between align-center">
+              <div class="count-zone">
+                <p> 총 <span></span>건 중 <span></span>건 선택 </p>
+              </div>
+              <div class="cunt-selectZone">
+                <select name="" id="">
+                  <option value="10">10개 보기</option>
+                  <option value="20">20개 보기</option>
+                </select>
+              </div>
+            </div>
+            <table class="list-table">
+              <colgroup>
+                <col style="width: 5%" />
+                <col style="width: 10%" />
+                <col style="width: 42.5%" />
+                <col style="width: 42.5%" />
+              </colgroup>
+              <thead>
+                <tr>
+                  <th>
+                    <input type="checkbox" />
+                  </th>
+                  <th>No</th>
+                  <th>호스트명</th>
+                  <th>메인폴더</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr>
+                  <td>
+                    <input type="checkbox" name="memberList" />
+                  </td>
+                  <td></td>
+                  <td></td>
+                  <td></td>
+                </tr>
+              </tbody>
+            </table>
+            <PaginationButton v-model:currentPage="searchByDirectory.currentPage" :perPage="searchByDirectory.perPage" :totalCount="searchByDirectory.totalRows" :maxRange="5" :click="selectDeptHost" />
+          </div>
+          <div class="flex justify-end">
+            <button class="blue-btn small-btn" @click="openHostModal">호스트추가</button>
+            <button class="blue-border-btn small-btn" @click="deleteSelectedDeptHosts">호스트삭제</button>
           </div>
         </div>
       </div>
@@ -191,7 +186,7 @@
     <div class="modal-container">
       <div class="modal-title flex justify-between align-center">
         <h2>부서 찾기</h2>
-        <button class="close-btn" @click="closeModal">
+        <button class="close-btn" @click="fnCloseModalByDeptList">
           <svg-icon type="mdi" :width="20" :height="20" :path="closePath"></svg-icon>
         </button>
       </div>
@@ -200,15 +195,15 @@
           <div class="search-bar w100">
             <div class="flex justify-between align-center">
               <div class="flex25 pl0">
-                <select class="square-select full-select" v-model="dept_search_data.key">
+                <select class="square-select full-select" v-model="searchDataByDept.key">
                   <option :value="null">전체</option>
                   <option value="dept_code">부서코드</option>
                   <option value="dept_nm">부서명</option>
                 </select>
               </div>
               <div class="flex75 flex align-center no-gutter pr0">
-                <input type="text" class="square-input flex90" placeholder="부서를 검색해주세요" v-model="dept_search_data.value" @keyup.enter="selectDepartmentList" />
-                <button class="square-button blue-btn flex10" @click="selectDepartmentList">
+                <input type="text" class="square-input flex90" placeholder="부서를 검색해주세요" v-model="searchDataByDept.value" @keyup.enter="fnSelectUpperDeptList" />
+                <button class="square-button blue-btn flex10" @click="fnSelectUpperDeptList">
                   <svg-icon type="mdi" :path="searchPath" class="square-icon"></svg-icon>
                 </button>
               </div>
@@ -218,94 +213,37 @@
         <div class="overflow-y" style="height: 500px">
           <table class="sticky-table list-table2">
             <colgroup>
-              <col style="width: 50%" />
-              <col style="width: 50%" />
+              <col style="width: 35%" />
+              <col style="width: 35%" />
+              <col style="width: 30%" />
             </colgroup>
             <thead>
               <tr>
                 <th>부서코드</th>
                 <th>부서명</th>
+                <th>비고</th>
               </tr>
             </thead>
             <tbody>
-              <template v-if="departmentList.length > 0">
-                <tr v-for="(department, idx) in departmentList" :key="idx" @click="intoUpperDept(department)">
-                  <td>{{ department.dept_code }}</td>
-                  <td>{{ department.dept_nm }}</td>
+              <template v-if="selectDeptList.length > 0">
+                <tr v-for="(item, idx) in selectDeptList" :key="idx" :class="{ red: item.isUsed == false }">
+                  <td>{{ item.dept_code }}</td>
+                  <td>{{ item.dept_nm }}</td>
+                  <td><button type="button" class="small-btn blue-border-btn" @click="fnSelectedUpperDept(item)">선택</button></td>
                 </tr>
               </template>
               <tr v-else>
-                <td colspan="2">데이터가 존재하지 않습니다.</td>
+                <td colspan="3">데이터가 존재하지 않습니다.</td>
               </tr>
             </tbody>
           </table>
         </div>
       </div>
-      <div class="modal-end flex justify-end">
-        <button class="gray-btn large-btn pd5" @click="closeModal()">취소</button>
-      </div>
     </div>
   </div>
-  <div v-show="isHostModalOpen" class="modal-wrapper">
-    <div class="modal-container">
-      <div class="modal-title">
-        <div class="flex justify-between align-center">
-          <h2>호스트 목록</h2>
-          <button class="close-btn" @click="closeHostModal">
-            <svg-icon type="mdi" :width="20" :height="20" :path="closePath"></svg-icon>
-          </button>
-        </div>
-      </div>
-      <div class="searchbar-zone modal-content-monthly">
-        <div class="flex justify-end align-center">
-          <select name="" id="" class="square-select" v-model="host_search_data.key">
-            <option :value="null" disabled>선택</option>
-            <option value="host_nm">호스트명</option>
-            <option value="host_ip">호스트(IP)</option>
-            <option value="rgtr_id">등록자</option>
-          </select>
-          <div class="search-square">
-            <input type="text" class="square-input" v-model="host_search_data.value" placeholder="검색어를 입력해주세요." @keyup.enter="selectHosts" />
-            <button class="square-button" @click="selectHosts">
-              <svg-icon type="mdi" :path="searchPath" class="square-icon"></svg-icon>
-            </button>
-          </div>
-        </div>
-        <div class="table-zone">
-          <table class="form-table" style="text-align: center">
-            <colgroup>
-              <col style="width: 10%" />
-              <col style="width: 30%" />
-              <col style="width: 30%" />
-              <col style="width: 20%" />
-              <col style="width: 10%" />
-            </colgroup>
-            <thead>
-              <tr>
-                <th>No</th>
-                <th>호스트명</th>
-                <th>호스트(IP)</th>
-                <th>사용자명</th>
-                <th>포트</th>
-              </tr>
-            </thead>
-            <tbody v-if="hosts.length > 0">
-              <tr v-for="(host, index) in hosts" :key="index" @click="axiosDeptHost(host)">
-                <td>{{ hostIdx - index }}</td>
-                <td>{{ host.host_nm }}</td>
-                <td>{{ host.host_ip }}</td>
-                <td>{{ host.host_id }}</td>
-                <td>{{ host.host_port }}</td>
-              </tr>
-            </tbody>
-          </table>
-        </div>
-      </div>
-      <PaginationButton v-model:currentPage="hostSearch.currentPage" :perPage="hostSearch.perPage" :totalCount="hostSearch.totalRows" :maxRange="5" :click="selectHosts" />
-    </div>
-  </div>
+  <UserSelectModal :deptCode="selectedDept.id" :isModalOpen="isUserModalOpen" @fnCloseModal="fnCloseModalByUserList" />
   <!-- 사용자 목록 모달 -->
-  <div v-show="isMemberModalOpen" class="modal-wrapper">
+  <!-- <div v-show="isMemberModalOpen" class="modal-wrapper">
     <div class="modal-container">
       <div class="modal-title flex justify-between align-center">
         <h2>멤버 추가</h2>
@@ -365,824 +303,410 @@
         <button class="blue-btn small-btn" @click="confirmSelection">등록</button>
       </div>
     </div>
-  </div>
-  <!-- // 사용자 목록 모달 -->
-  <TreeModal :modalOpen="treeModalOpen" :modalConnection="connection" :modalNodes="nodes" :selectType="selectModalType" @modalSelectFolder="selectFolder" @closeTreeModal="closeTreeModal" @modalSubmit="axiosDeptHost" />
+  </div> -->
+  <!-- <TreeModal :modalOpen="treeModalOpen" :modalConnection="connection" :modalNodes="nodes" :selectType="selectModalType" @modalSelectFolder="selectFolder" @closeTreeModal="closeTreeModal" @modalSubmit="axiosDeptHost" /> -->
 </template>
 <script>
-import PageNavigation from "../../component/PageNavigation.vue";
-import PaginationButton from "../../component/PaginationButton.vue";
+import axios from "axios";
+// icon용 svg import
 import SvgIcon from "@jamescoyle/vue-icon";
 import { mdiMagnify, mdiClose } from "@mdi/js";
-import axios from "axios";
+// 컴포넌트 import
+import PageNavigation from "../../component/PageNavigation.vue";
+import PaginationButton from "../../component/PaginationButton.vue";
 import DepartmentTree from "../../component/DepartmentTree.vue";
 import TreeModal from "../../component/FileTreeModal.vue";
+import TreeMenu from "../../component/treeMenu/TreeMenu.vue";
+import DeptHostList from "./department/DeptHostList.vue";
+
+import UserSelectModal from "../../component/modal/UserSelectModal.vue";
 
 export default {
+  components: { SvgIcon, PageNavigation, PaginationButton, DepartmentTree, TreeModal, TreeMenu, DeptHostList, UserSelectModal },
+
   data() {
     return {
+      // icon용 svg path
       searchPath: mdiMagnify,
-      startDate: true,
-      endDate: true,
-
-      departmentData: {
-        dept_code: null,
-        dept_nm: null,
-        dept_dc: null,
-        upper_dept: null,
-        upper_dept_nm: null,
-        dept_addr: null,
-        author: 'ROLE_USER', // 사용자 권한
-        dept_dp: null,
-      },
-
-      departmentList: [],
-      departmentTreeList: [],
-      //부서코드 중복확인 여부
-      isDuplicateChecked: false,
-      authorList: [],
-
-      // 부서 호스트 연결용 변수
-      modalType: "tab-modal",
       closePath: mdiClose,
-      isHostModalOpen: false,
-      hostSearch: this.$getDefaultSerchVO(),
-      host_search_data: this.$getDefaultSerchItem(null, "String"),
-      hosts: [],
-      hostIdx: 0,
-      selectedHost: null,
-      connection: {
-        host_code: null,
-        path: null,
-        depth: null,
-        type: null,
-      },
-      nodes: [],
-      treeModalOpen: false,
-      selectModalType: 0,
-      dept_search_data: this.$getDefaultSerchItem(null, "String"),
-      deptSearch: this.$getDefaultSerchVO(),
-      deptHostData: [],
-      deptIdx: 0,
-      deptCheckAll: false,
-      selectedDepts: [],
-      depthDepth: 0,
 
-      //사용자 추가
-      isMemberModalOpen: false,
-      addusers: [], // 선택된 사용자 정보를 저장할 배열
-      users: [],
-      usersIdx: 0,
-      usersSearch: this.$getDefaultSerchVO(),
-      search_data1: this.$getDefaultSerchItem(null, "string"),
-      search_data2: this.$getDefaultSerchItem(null, "string"),
-      selectedUsers: null,
+      // 검색
+      // 부서
+      searchByDept: Object.assign({}, this.$getDefaultSerchVO()),
+      searchDataByDept: this.$getDefaultSerchItem(null, "string"),
+      // 호스트
+      searchByHost: Object.assign({}, this.$getDefaultSerchVO()),
+      searchByDirectory: Object.assign({}, this.$getDefaultSerchVO()),
 
-      //세현 추가
+      // default
+      editMode: 'create',
+
+      deptTreeList: [],
+
+      deptVO: {},
+      originDept: {},
+      currentDept: {},
+      selectedDept: {
+        "upId": null,
+        "id": null,
+        "nm": null,
+        "dp": null,
+        "ordr": null,
+        "childList": [],
+      }, // 부서 목록에서 선택한 부서
+
+
+      // 부서 정보
+      isDeptCodeDupChk: false, // 부서코드 중복확인 여부
+
+      // 부서 찾기 모달 관련
       isDeptModalOpen: false,
-      memberSearch: this.$getDefaultSerchVO(),
-      member_search_data: this.$getDefaultSerchItem(null, "String"),
-      noDeptMemberList: [],
-      inDeptMemberList: [],
-      memberIdx: 0,
-      selectedMembers: [],
-      checkAll: false,
+      selectDeptList: [],
+
+      // 사용자 목록 관련
+      isChkUserAll: false,
+      userList: [],
+      userSelectList: [],
+      searchByUser: Object.assign({}, this.$getDefaultSerchVO()),
+      searchDataByUser: this.$getDefaultSerchItem(null, "string"),
+
+      // 사용자 추가 모달 관련
+      isUserModalOpen: false,
+      selectUserList: [],
+
     };
   },
 
+  mounted() {
+    this.fnSelectDeptListForTree();
+  },
+
+  watch: {
+    // 부서코드 변경 시 중복확인 여부 false로 변경
+    "currentDept.dept_code"() {
+      this.isDeptCodeDupChk = false;
+    },
+  },
+
   methods: {
-    deptSearchInit: function () {
-      this.deptSearch.searchObjectList.push(this.dept_search_data);
-    },
-
-    handleDateChange: function () {
-      if (this.startDate) {
-        this.startDate = false;
-      } else if (this.endDate) {
-        this.endDate = false;
-      }
-    },
-
-    insertForm: function () {
-      this.dataLoaded = false;
-      this.resetForm();
-    },
-
-    //부서 목록에서 선택 시
-    intoUpperDept: function (department) {
-      this.closeModal();
-      this.departmentData.upper_dept = department.dept_code;
-      this.departmentData.upper_dept_nm = department.dept_nm;
-    },
-
-    //부서코드 중복검사
-    deptCodeDuplicateCheck: function () {
+    // 부서 목록 조회 (트리형 목록 용도)
+    fnSelectDeptListForTree() {
       const vm = this;
-
-      // 1. 부서코드 null 검사
-      if (vm.$isEmpty(vm.departmentData.dept_code)) {
-        vm.$showAlert("부서 등록", "부서코드를 입력해주세요.");
-        document.getElementById("dept_code").focus();
-        return;
-      }
-
-      // 2. 부서코드 숫자만 검사
-      if (!/^\d+$/.test(vm.departmentData.dept_code)) {
-        vm.$showAlert("부서 등록", "부서코드는 숫자만 입력할 수 있습니다.");
-        document.getElementById("dept_code").focus();
-        return;
-      }
-
       axios({
-        url: "/department/" + vm.departmentData.dept_code,
+        url: "/department",
         method: "get",
-        headers: {
-          "Content-Type": "application/json;",
-        },
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
       })
-        .then((response) => {
-          if (response.data.resultData.checkDuplicateOrgCode) {
-            vm.$showAlert("부서코드 중복확인", "사용중인 부서코드입니다.");
-            vm.isDuplicateChecked = false; // 중복 확인이 실패하였으므로 중복 확인 상태를 false로 설정합니다.
-          } else {
-            vm.$showAlert(
-              "부서코드 중복확인",
-              "사용할 수 있는 부서코드입니다."
-            );
-            vm.isDuplicateChecked = true; // 중복 확인이 성공하였으므로 중복 확인 상태를 true로 설정합니다.
-          }
+        .then(response => {
+          vm.deptVO = response.data.resultData.departmentVO;
+          vm.deptTreeList = response.data.resultData.hierachyList;
         })
-        .catch((error) => {
-          this.$showAlert(
-            "에러 발생",
-            "에러가 발생했습니다. 관리자에게 문의해 주세요."
-          );
+        .catch(error => {
+          this.$showAlert("에러 발생", "에러가 발생했습니다. 관리자에게 문의해 주세요.");
         });
     },
 
-    // 부서등록 유효성 검사
-    insertDepartmentValidation() {
+    // 부서코드 중복확인
+    fnDeptCodeDupChk() {
       const vm = this;
-      // 1. 부서코드 중복 검사 여부 확인
-      if (!vm.isDuplicateChecked) {
-        vm.$showAlert("부서 등록", "부서코드 중복확인 후 등록해주세요.");
-        document.getElementById("deptCodeDuplicateCheck").focus();
+
+      // 유효성 검사
+      if (!vm.validationDeptCode()) {
+        return;
+      };
+
+      axios({
+        url: "/department/" + vm.currentDept.dept_code,
+        method: "get",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+      })
+        .then(response => {
+          if (response.data.resultData.checkDuplicateOrgCode) {
+            vm.$showAlert("부서코드 중복확인", "사용중인 부서코드입니다.");
+            vm.currentDept.dept_code = null;
+          } else {
+            vm.$showAlert("부서코드 중복확인", "사용할 수 있는 부서코드입니다.");
+            vm.isDeptCodeDupChk = true;
+          }
+        })
+        .catch(error => {
+          this.$showAlert("에러 발생", "에러가 발생했습니다. 관리자에게 문의해 주세요.");
+        });
+    },
+
+    // #부서찾기모달
+    // 부서찾기 모달 열기
+    fnOpenModalByDeptList() {
+      this.fnSelectUpperDeptList(); // 부서 목록 조회(자신 제외)
+      this.isDeptModalOpen = true;
+    },
+    // 부서찾기 모달 닫기
+    fnCloseModalByDeptList() {
+      this.isDeptModalOpen = false;
+    },
+    // 부서 목록 조회(자신 제외)
+    fnSelectUpperDeptList() {
+      const vm = this;
+      // 데이터 세팅
+      vm.searchByDept.searchObjectList = [];
+      vm.searchByDept.searchObjectList.push(vm.searchDataByDept);
+      // 실행
+      axios({
+        url: "/department/departments/" + vm.currentDept.dept_code,
+        method: "post",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+        data: vm.searchByDept,
+      })
+        .then(response => {
+          if (response.data != null) {
+            vm.selectDeptList = response.data.resultData.selectDeptList;
+            vm.searchByDept = response.data.resultData.searchVO;
+
+            // 하위 부서 선택을 제외하기 위한 옵션 추가
+            let selectChildDeptList = response.data.resultData.selectChildDeptList; // 하위 부서 목록
+            if (vm.selectDeptList.length > 0 && selectChildDeptList.length > 0) {
+              for (let dept of vm.selectDeptList) {
+                dept.isUsed = true;
+                for (let deptCode of selectChildDeptList) {
+                  if (dept.dept_code == deptCode) {
+                    dept.isUsed = false;
+                    break;
+                  }
+                }
+              }
+            }
+          } else {
+            this.$showAlert("사용자 관리", "에러가 발생했습니다. 관리자에게 문의해 주세요.");
+          }
+        })
+        .catch(error => {
+          vm.$showAlert("사용자 관리", "목록 불러오기 오류, 관리자에게 문의바랍니다.");
+        });
+    },
+    // 부서찾기 모달 내 부서 선택
+    fnSelectedUpperDept(dept) {
+      if (!dept.isUsed) {
+        this.$showAlert("부서 찾기", "자신의 하위 부서는 선택할 수 없습니다.");
+        return;
+      }
+      this.currentDept.upper_dept = dept.dept_code;
+      this.currentDept.upper_dept_nm = dept.dept_nm;
+
+      this.fnCloseModalByDeptList(); // 부서찾기 모달 닫기
+    },
+
+    // 부서 등록
+    fnInsertDept() {
+      const vm = this;
+      // 유효성 검사
+      if (!vm.insertDeptValidation()) {
+        return
+      };
+      // 실행
+      axios({
+        url: "/department",
+        method: "post",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+        data: vm.currentDept,
+      })
+        .then(response => {
+          vm.$showAlert("부서 등록", "부서 등록이 완료되었습니다.");
+
+          // 초기화
+          vm.fnCancelDept();
+          vm.fnSelectDeptListForTree() // 부서 목록 조회 (트리형 목록 용도)
+        })
+        .catch(error => {
+          this.$showAlert("에러 발생", "에러가 발생했습니다. 관리자에게 문의해 주세요.");
+        });
+    },
+
+    // 부서 수정
+    fnUpdateDept() {
+      const vm = this;
+      // 실행
+      axios({
+        url: "/department",
+        method: "put",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+        data: vm.currentDept,
+      })
+        .then(response => {
+          vm.$showAlert("부서 수정", "부서 정보가 수정되었습니다.");
+
+          // 초기화
+          vm.fnCancelDept();
+          vm.fnSelectDeptListForTree(); // 부서 목록 조회 (트리형 목록 용도)
+        })
+        .catch(error => {
+          this.$showAlert("에러 발생", "에러가 발생했습니다. 관리자에게 문의해 주세요.");
+        });
+    },
+
+    // 부서 삭제
+    async fnDeleteDept() {
+      const vm = this;
+
+      let isConfirmChk = await this.$showConfirm("경고", "선택한 부서를 삭제하시겠습니까?");
+      if (!isConfirmChk) {
+        return;
+      }
+
+      // 실행
+      axios({
+        url: `/department`,
+        method: "delete",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+        data: vm.currentDept,
+      })
+        .then(response => {
+          vm.$showAlert("부서 삭제", "부서 삭제에 성공했습니다.");
+
+          // 초기화
+          vm.fnCancelDept();
+          vm.fnSelectDeptListForTree(); // 부서 목록 조회 (트리형 목록 용도)
+        })
+        .catch(error => {
+          vm.$showAlert("부서 삭제", "삭제오류, 관리자에게 문의바랍니다.");
+        });
+    },
+
+    // 부서 취소
+    fnCancelDept() {
+      this.editMode = 'create';
+      this.currentDept = this.deptVO;
+      this.selectedDept = {};
+      this.isDeptCodeDupChk = false; // 부서코드 중복확인 여부
+
+      // 사용자 목록
+      this.userList = [];
+      this.userSelectList = [];
+      this.searchByUser = Object.assign({}, this.$getDefaultSerchVO());
+      this.searchDataByUser = this.$getDefaultSerchItem(null, "string");
+    },
+
+    // 부서 상세 조회
+    fnSelectDept(currentDept) {
+      const vm = this;
+      // 데이터 세팅
+      vm.selectedDept = currentDept;
+      // 실행
+      axios({
+        url: "/department/selectDept/" + currentDept.id,
+        method: "get",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+      })
+        .then(response => {
+          vm.editMode = 'update';
+          vm.originDept = response.data.resultData.departmentVO;
+          vm.currentDept = Object.assign({}, response.data.resultData.departmentVO);
+          // 부서 내부 목록 조회
+          vm.fnSelectUserList();
+        })
+        .catch(error => {
+          vm.$showAlert("사용자 관리", "불러오기 오류, 관리자에게 문의바랍니다.");
+        });
+    },
+
+    // 부서 내 사용자 목록 조회
+    fnSelectUserList() {
+      const vm = this;
+      // 데이터 세팅
+      vm.searchDataByUser.key = "deptCode";
+      vm.searchDataByUser.value = vm.selectedDept.id;
+      vm.searchByUser.searchObjectList = [];
+      vm.searchByUser.searchObjectList.push(vm.searchDataByUser);
+      // 실행
+      axios({
+        url: "/orgnztMember/selectOrgnztMemberList",
+        method: "post",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+        data: vm.searchByUser,
+      })
+        .then(response => {
+          vm.userList = response.data.resultData.list;
+          vm.searchByUser = response.data.resultData.searchVO;
+        })
+        .catch(error => {
+          vm.$showAlert("회원 목록", "목록 불러오기 오류, 관리자에게 문의바랍니다.");
+        });
+    },
+    // 사용자 목록 전체 선택
+    fnChkAll() {
+      if (this.isChkUserAll) {
+        this.userSelectList = this.userList;
+      } else {
+        this.userSelectList = [];
+      }
+    },
+    // 사용자 목록 상세 선택
+    fnChangeChk() {
+      if (this.userSelectList.length == this.userList.length) {
+        this.isChkUserAll = true;
+      } else {
+        this.isChkUserAll = false;
+      }
+    },
+    // 사용자 추가 모달 열기
+    fnOpenModalByUserList() {
+      this.isUserModalOpen = true;
+    },
+    // 사용자 추가 모달 닫기
+    fnCloseModalByUserList() {
+      this.isUserModalOpen = false;
+      this.fnSelectUserList(); // 사용자 목록 조회
+    },
+    // 사용자 삭제
+    fnDeleteUser() {
+      const vm = this;
+      // 실행
+      axios({
+        url: "/orgnztMember",
+        method: "delete",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+        data: vm.userSelectList,
+      })
+        .then(function (response) {
+          vm.$showAlert("작업 성공", "사용자 삭제에 성공했습니다.");
+          vm.fnSelectUserList(); // 사용자 목록 조회
+        })
+        .catch(function (error) {
+          vm.$showAlert("작업 실패", "사용자 삭제에 실패했습니다.\n관리자에게 문의바랍니다.");
+        });
+    },
+
+    // #유효성 검사
+    // 부서 등록용 유효성 검사
+    insertDeptValidation() {
+      // 부서코드 중복 검사 여부 확인
+      if (!this.isDeptCodeDupChk) {
+        this.$showAlert("부서 등록", "부서코드 중복확인 후 등록해주세요.");
         return false;
       }
 
-      // 2. 부서명 null 검사
-      if (vm.$isEmpty(vm.departmentData.dept_nm)) {
-        vm.$showAlert("부서 등록", "부서명을 입력해주세요.");
-        document.getElementById("dept_nm").focus();
-        return false;
-      }
-
-      // // 3. 상위 부서 검사 null 검사
-      // if (vm.$isEmpty(vm.departmentData.upper_dept) || vm.$isEmpty(vm.departmentData.upper_dept_nm)) {
-      //   vm.$showAlert("부서 등록", "상위 부서를 선택해주세요.");
-      //   return false;
-      // }
-
-      // 4. 권한 null 검사
-      if (vm.$isEmpty(vm.departmentData.author)) {
-        vm.$showAlert("부서 등록", "권한을 선택해주세요.");
-        document.getElementById("author").focus();
+      // 부서코드 유효성 검사
+      if (!this.validationDeptCode()) {
         return false;
       }
 
       return true;
     },
-
-    //부서 등록
-    departmentInsert() {
-      const vm = this;
-      if (!vm.insertDepartmentValidation()) return;
-
-      axios({
-        url: "/department",
-        method: "post",
-        headers: {
-          "Content-Type": "application/json;",
-        },
-        data: vm.departmentData,
-      })
-        .then(function (response) {
-          vm.$showAlert("부서 등록", "부서 등록이 완료되었습니다.");
-          vm.resetForm();
-
-          vm.selectDepartments(); // 부서 리스트 재조회
-        })
-        .catch(function (error) {
-          this.$showAlert(
-            "에러 발생",
-            "에러가 발생했습니다. 관리자에게 문의해 주세요."
-          );
-        });
-    },
-
-    // 부서 찾기 모달 열기
-    openDeptSearchModal() {
-      this.selectDepartmentList(); // 부서 목록 조회(전체)
-      this.isDeptModalOpen = true;
-    },
-    // 부서 찾기 모달 닫기
-    closeModal() {
-      this.departmentList = []; // 초기화
-      this.isDeptModalOpen = false;
-    },
-    // 부서 찾기 - 부서 목록 조회
-    selectDepartmentList() {
-      const vm = this;
-      axios({
-        url: "/department/departments",
-        method: "post",
-        data: vm.deptSearch,
-      })
-        .then(function (response) {
-          vm.departmentList = response.data.resultData.selectDeptList;
-        })
-        .catch(function (error) {
-          vm.$showAlert(
-            "부서 조회",
-            "목록 불러오기 오류, 관리자에게 문의바랍니다."
-          );
-        });
-    },
-
-    // 부서 리스트 조회
-    selectDepartments() {
-      const vm = this;
-      axios({
-        url: "/department",
-        method: "get",
-        params: {
-          user_id: vm.$store.state.loginUser.user_id,
-        },
-      })
-        .then(function (response) {
-          vm.departmentTreeList =
-            response.data.resultData.selectTreeDepartments;
-        })
-        .catch(function (error) {
-          this.$showAlert(
-            "에러 발생",
-            "에러가 발생했습니다. 관리자에게 문의해 주세요."
-          );
-        });
-    },
-
-    resetForm() {
-      this.departmentData = {
-        org_code: null,
-        dept_nm: null,
-        dept_dc: null,
-        upper_dept: null,
-        author: 'ROLE_USER', // 사용자 권한
-      };
-    },
-
-    // 권한 목록 조회
-    getAuthorList() {
-      const vm = this;
-      axios({
-        url: "/department/getAuthorInfo",
-        method: "get",
-      })
-        .then(function (response) {
-          vm.authorList = response.data.resultData.getAuthorInfo;
-        })
-        .catch(function (error) {
-          this.$showAlert(
-            "에러 발생",
-            "에러가 발생했습니다. 관리자에게 문의해 주세요."
-          );
-        });
-    },
-
-    loadDepartmentData(department) {
-      this.departmentData = Object.assign({}, department); // 클릭한 호스트의 데이터를 복사하여 저장합니다.
-      this.originaldepartmentData = Object.assign({}, department);
-      this.dataLoaded = true; // 데이터가 로드되었음을 표시합니다.
-      this.selectedDeptCode = department.dept_code;
-      this.selectMemberList();
-    },
-
-    //부서별 사용자 목록 조회
-    selectMemberList: function () {
-      const vm = this;
-      vm.member_search_data.key = "orgnzt_info.dept_code";
-      vm.member_search_data.value = vm.departmentData.dept_code;
-      vm.memberSearch.searchObjectList.push(vm.member_search_data);
-
-      axios({
-        url: "/member/list",
-        method: "post",
-        data: vm.memberSearch,
-      })
-        .then(function (response) {
-          if (response.data) {
-            vm.inDeptMemberList = response.data.resultData.selectMemberList;
-            vm.memberSearch.totalRows = response.data.resultData.totalRow;
-            vm.memberIdx =
-              vm.memberSearch.totalRows -
-              (vm.memberSearch.currentPage - 1) * vm.memberSearch.perPage;
-          } else {
-            this.$showAlert(
-              "에러 발생",
-              "에러가 발생했습니다. 관리자에게 문의해 주세요."
-            );
-          }
-        })
-        .catch(function (error) {
-          vm.$showAlert(
-            "회원 목록",
-            "목록 불러오기 오류, 관리자에게 문의바랍니다."
-          );
-        });
-    },
-
-    //사용자 선택 삭제용 선택 기능
-    check: function (member) {
-      this.selectedMembers.push(member.userId);
-    },
-
-    //사용자 선택 삭제용 전체 선택 기능
-    memberCheckAll(event) {
-      const isChecked = event.target.checked;
-      this.inDeptMemberList.forEach((inDeptMember) => {
-        inDeptMember.selected = isChecked; // 전체 선택/해제 기능
-      });
-    },
-
-    // 부서 수정
-    async updateDepartment() {
-      const vm = this;
-      if (
-        JSON.stringify(vm.departmentData) ===
-        JSON.stringify(vm.originaldepartmentData)
-      ) {
-        vm.$showAlert("부서 수정", "수정된 정보가 없습니다.");
-        return;
-      }
-      axios
-        .put("/department", vm.departmentData)
-        .then((response) => {
-          vm.$showAlert("부서 수정", "부서 정보가 수정되었습니다.");
-          vm.resetForm();
-
-          vm.selectDepartments(); // 부서 리스트 재조회
-        })
-        .catch((error) => {
-          vm.$showAlert(
-            "에러 발생",
-            "에러가 발생했습니다. 관리자에게 문의해 주세요.");
-        });
-    },
-
-    async deleteDepartments() {
-      const vm = this;
-
-      axios({
-        url: `/department`,
-        method: "delete",
-        headers: {
-          "Content-Type": "application/json",
-        },
-        data: vm.departmentData,
-      })
-        .then(function (response) {
-          // 삭제가 성공하면 화면에서도 호스트를 제거합니다.
-          if (response.data.resultData.deleteDepartment > 0) {
-            vm.$showAlert("부서 삭제", "선택한 부서가 삭제되었습니다.");
-            vm.selectDepartments();
-          } else {
-            vm.$showAlert(
-              "부서 삭제",
-              "선택한 부서 삭제에 실패하였습니다. 다시 시도해주세요."
-            );
-          }
-        })
-        .catch(function (error) {
-          vm.$showAlert("부서 삭제", "삭제오류, 관리자에게 문의바랍니다.");
-        });
-    },
-
-    // 호스트-부서 연결을 위한 메서드들
-    // 호스트 연결 모달창
-    openHostModal: function () {
-      // if (!this.departmentData.dept_code) {
-      //   this.$showAlert("호스트 연결", "선택된 부서가 없습니다.");
-      //   return;
-      // }
-
-      this.isHostModalOpen = true;
-      this.hostSearch.searchObjectList.push(this.host_search_data);
-      this.selectHosts();
-    },
-    closeHostModal: function () {
-      this.isHostModalOpen = false;
-      this.hosts = [];
-      this.hostIdx = 0;
-      this.hostSearch = this.$getDefaultSerchVO();
-      this.host_search_data = this.$getDefaultSerchItem(null, "String");
-      this.selectedHost = null;
-    },
-    // 호스트 목록 불러오기
-    selectHosts() {
-      const vm = this;
-      axios({
-        url: "/host/list",
-        method: "post",
-        headers: {},
-        data: vm.hostSearch,
-      })
-        .then(function (response) {
-          vm.hosts = response.data.resultData.hostList;
-          vm.hostSearch.totalRows = response.data.resultData.totalRow;
-          vm.hostIdx =
-            vm.hostSearch.totalRows -
-            (vm.hostSearch.currentPage - 1) * vm.hostSearch.perPage;
-          // 이미 부서에 등록된 호스트는 빠지게
-          if (vm.depthDepth === 0) {
-            vm.hosts = vm.hosts.filter(
-              (host) =>
-                !vm.deptHostData.some(
-                  (deptHost) => deptHost.host_code === host.host_code
-                )
-            );
-          }
-        })
-        .catch(function (error) {
-          vm.$showAlert(
-            "호스트 목록",
-            "목록 불러오기 오류, 관리자에게 문의바랍니다."
-          );
-        });
-    },
-
-    // 사용자 연결 모달창
-    openMemberModal: function () {
-      if (!this.departmentData.dept_code) {
-        this.$showAlert("호스트 연결", "선택된 부서가 없습니다.");
-        return;
+    // 부서코드 유효성 검사
+    validationDeptCode() {
+      // 부서코드 null 검사
+      if (this.$isEmpty(this.currentDept.dept_code)) {
+        this.$showAlert("부서 등록", "부서코드를 입력해주세요.");
+        return false;
       }
 
-      this.isMemberModalOpen = true;
-      this.usersSearch.searchObjectList.push(this.search_data1);
-      this.usersSearch.searchObjectList.push(this.search_data2);
-      this.selectUsers();
-    },
-    closeMemberModal: function () {
-      this.isMemberModalOpen = false;
-      this.users = [];
-      this.usersIdx = 0;
-      this.usersSearch = this.$getDefaultSerchVO();
-      this.search_data1 = this.$getDefaultSerchItem(null, "String");
-      this.search_data2 = this.$getDefaultSerchItem(null, "String");
-      this.selectedUsers = null;
-    },
-
-    // 사용자 목록 불러오기
-    selectUsers() {
-      const vm = this;
-      vm.usersSearch.searchObjectList = [];
-      if (
-        vm.departmentData.dept_code != null &&
-        vm.departmentData.dept_code != ""
-      ) {
-        vm.search_data1.key = "dept_code";
-        vm.search_data1.value = vm.departmentData.dept_code;
-        vm.usersSearch.searchObjectList.push(vm.search_data1);
-      }
-      if (vm.search_data2.value != null && vm.search_data2.value != "") {
-        vm.usersSearch.searchObjectList.push(vm.search_data2);
-        vm.usersSearch.currentPage = 1; // 첫 페이지로 초기화
+      // 부서코드 숫자만 검사
+      if (!/^\d+$/.test(this.currentDept.dept_code)) {
+        this.$showAlert("부서 등록", "부서코드는 숫자만 입력할 수 있습니다.");
+        return false;
       }
 
-      axios({
-        url: "/member/users",
-        method: "post",
-        headers: {},
-        data: vm.usersSearch,
-      })
-        .then(function (response) {
-          vm.users = response.data.resultData.selectMemberList;
-          vm.usersSearch.totalRows = response.data.resultData.totalRow;
-          vm.usersIdx =
-            vm.usersSearch.totalRows -
-            (vm.usersSearch.currentPage - 1) * vm.usersSearch.perPage;
-        })
-        .catch(function (error) {
-          vm.$showAlert(
-            "사용자 목록",
-            "목록 불러오기 오류, 관리자에게 문의바랍니다."
-          );
-        });
+      return true;
     },
-    addSelectUsers() {
-      const vm = this;
-      axios({
-        url: "/member/users/add",
-        method: "post",
-        headers: { "Content-Type": "application/json" },
-        data: JSON.stringify({ users: vm.addusers }),
-      })
-        .then(function (response) {
-          vm.closeMemberModal();
-          vm.selectMemberList();
-        })
-        .catch(function (error) {
-          vm.$showAlert(
-            "멤버추가 오류",
-            "멤버추가 오류, 관리자에게 문의바랍니다."
-          );
-        });
-    },
-    delSelectUsers() {
-      const vm = this;
-      axios({
-        url: "/member/users/del",
-        method: "post",
-        headers: { "Content-Type": "application/json" },
-        data: JSON.stringify({ users: vm.addusers }),
-      })
-        .then(function (response) {
-          vm.closeMemberModal();
-          vm.selectMemberList();
-        })
-        .catch(function (error) {
-          vm.$showAlert(
-            "멤버추가 오류",
-            "멤버추가 오류, 관리자에게 문의바랍니다."
-          );
-        });
-    },
-    toggleSelectAll(event) {
-      const isChecked = event.target.checked;
-      this.users.forEach((user) => {
-        user.selected = isChecked; // 전체 선택/해제 기능
-      });
-    },
-    async confirmSelection() {
-      this.addusers = this.users
-        .filter((user) => user.selected) // 선택된 사용자 필터링
-        .map((user) => ({
-          userId: user.userId,
-          dept_code: this.departmentData.dept_code,
-        })); // 필요한 데이터 추출
-      const confirmed = await this.$showConfirm(
-        "멤버추가",
-        "선택하신 멤버를 추가하시겠습니까?"
-      );
-
-      console.log("!! 1")
-      // 사용자가 확인했을 경우에만 추가 함수 실행
-      if (confirmed) {
-        console.log("!! 2")
-        this.addSelectUsers();
-      }
-    },
-    async deleteSelection() {
-      this.addusers = this.inDeptMemberList
-        .filter((inDeptMember) => inDeptMember.selected) // 선택된 사용자 필터링
-        .map((inDeptMember) => ({
-          userId: inDeptMember.userId,
-          dept_code: this.departmentData.dept_code,
-        })); // 필요한 데이터 추출
-      const deleteSele = await this.$showConfirm(
-        "멤버삭제",
-        "선택하신 멤버를 삭제하시겠습니까?"
-      );
-
-      // 사용자가 확인했을 경우에만 추가 함수 실행
-      if (deleteSele) {
-        this.delSelectUsers();
-      }
-    },
-    // 폴더 모달창 열기
-    selectAndConnect(hostCode) {
-      this.selectedHost = hostCode;
-      this.connectionConfirm("choose");
-    },
-    connectionConfirm(type) {
-      const vm = this;
-      vm.connection.host_code = vm.selectedHost || vm.connection.host_code;
-
-      axios
-        .get("/files/connection", {
-          params: { host_code: vm.connection.host_code },
-        })
-        .then((response) => {
-          vm.$showAlert("파일시스템 연결", response.data.message);
-          if (response.data.status === 200) {
-            this.fileTreeList(type);
-          }
-        })
-        .catch((error) => {
-          vm.$showAlert(
-            "파일시스템 연결",
-            "파일시스템 연결 오류, 관리자에게 문의하세요."
-          );
-          vm.$router.go(-1); // 오류 시 이전 페이지로 이동
-        });
-    },
-    // 폴더 가져오기
-    fileTreeList(type) {
-      const vm = this;
-      vm.nodes = [];
-      vm.connection.path = "#";
-      vm.connection.depth = 0;
-      vm.connection.type = "folder";
-
-      axios
-        .get("/files/tree", { params: vm.connection })
-        .then((response) => {
-          vm.nodes = response.data.resultData.fileTree;
-          vm.connection.path = null;
-          vm.selectedHost = null;
-          vm.openTreeModal();
-          vm.selectModalType = type;
-        })
-        .catch((error) => {
-          vm.$showAlert(
-            "파일리스트 조회",
-            "파일리스트 조회 오류, 관리자에게 문의하세요."
-          );
-          vm.connection.path = null;
-          vm.selectedHost = null;
-          vm.closeHostModal();
-        });
-    },
-    openTreeModal() {
-      this.treeModalOpen = true;
-    },
-    closeTreeModal() {
-      this.treeModalOpen = false;
-      this.modalSeletedNode = null;
-    },
-    selectFolder(path) {
-      this.connection.path = path;
-    },
-    // 폴더 모달창에서 선택한 것으로 삽입 혹은 수정
-    async axiosDeptHost(host) {
-      const vm = this;
-      if (
-        !(await this.$showConfirm("호스트 추가", "호스트 추가하시겠습니까?"))
-      ) {
-        return;
-      }
-      // if (type === "선택") {
-      axios({
-        url: "/DeptHost",
-        method: "post",
-        headers: {
-          "Content-Type": "application/json",
-        },
-        data: {
-          dept_code: vm.departmentData.dept_code,
-          host_code: host.host_code,
-          main_folder_path: host.path,
-        },
-      })
-        .then(function (response) {
-          if (response.data.resultData.insertDeptHost > 0) {
-            vm.$showAlert("호스트 추가", "선택한 호스트가 추가되었습니다.");
-            vm.selectDeptHost();
-          } else {
-            vm.$showAlert(
-              "호스트 추가",
-              "선택한 호스트 추가에 실패하였습니다. 다시 시도해주세요."
-            );
-          }
-          vm.connection.path = null;
-          vm.closeTreeModal();
-          vm.closeHostModal();
-        })
-        .catch(function (error) {
-          vm.$showAlert("호스트 추가", "추가오류, 관리자에게 문의바랍니다.");
-          vm.connection.path = null;
-          vm.closeTreeModal();
-          vm.closeHostModal();
-        });
-    },
-    // 호스트-부서 연결된 데이터 가져오기
-    selectDeptHost() {
-      const vm = this;
-      vm.dept_search_data.key = "dept_code";
-      vm.dept_search_data.value = vm.departmentData.dept_code;
-      vm.dept_search_data.type = "eq";
-      vm.deptSearch.searchObjectList.push(vm.dept_search_data);
-
-      axios({
-        url: "/DeptHost/list",
-        method: "post",
-        headers: {},
-        data: vm.deptSearch,
-      })
-        .then(function (response) {
-          vm.deptHostData = response.data.resultData.selectDeptHost;
-          // 상위부서에서 가져온 데이터인지 아닌지 구분
-          vm.depthDepth = response.data.resultData.selectDeptHost[0].depth;
-        })
-        .catch(function (error) { });
-    },
-    // 호스트-부서 연결된 데이터 수정하기
-    chooseDeptHost(data, type) {
-      const vm = this;
-      if (vm.depthDepth !== 0) {
-        vm.$showAlert("호스트 수정", "수정할 권한이 없습니다.");
-        return;
-      }
-      vm.connection.host_code = data.host_code;
-      vm.connectionConfirm(type);
-    },
-    // 호스트-부서 체크박스 일괄 체크
-    deptHostCheckAll() {
-      const vm = this;
-      vm.deptCheckAll = !vm.deptCheckAll;
-      vm.selectedDepts = [];
-
-      if (vm.deptCheckAll) {
-        vm.deptHostData.forEach((data) => {
-          vm.selectedDepts.push(data.host_code);
-        });
-      }
-    },
-    // 부서 변경 시 체크 해제
-    deptHostUncheckAll() {
-      this.deptCheckAll = null;
-      this.selectedDepts = [];
-    },
-    // 호스트-부서 삭제
-    async deleteSelectedDeptHosts() {
-      const vm = this;
-      if (vm.selectedDepts.length === 0) {
-        vm.$showAlert("호스트 삭제", "선택한 호스트가 없습니다.");
-        return;
-      }
-      if (vm.depthDepth !== 0) {
-        vm.$showAlert("호스트 삭제", "삭제할 권한이 없습니다.");
-        return;
-      }
-      if (
-        !(await vm.$showConfirm(
-          "호스트삭제",
-          "선택한 호스트를 삭제하시겠습니까?"
-        ))
-      ) {
-        return;
-      }
-      const deptHostsToDelete = vm.selectedDepts.map((host_code) => ({
-        dept_code: vm.departmentData.dept_code,
-        host_code: host_code,
-      }));
-
-      axios({
-        url: "/DeptHost",
-        method: "delete",
-        headers: {
-          "Content-Type": "application/json",
-        },
-        data: deptHostsToDelete,
-      })
-        .then(function (response) {
-          if (response.data.resultData.deleteResult > 0) {
-            vm.$showAlert("호스트 삭제", "선택한 호스트가 삭제되었습니다.");
-            vm.deptCheckAll = false;
-            vm.selectedDepts = [];
-            vm.selectDeptHost();
-          } else {
-            vm.$showAlert(
-              "호스트 삭제",
-              "선택한 호스트 삭제에 실패하였습니다. 다시 시도해주세요."
-            );
-          }
-        })
-        .catch(function (error) {
-          vm.$showAlert("호스트 삭제", "삭제오류, 관리자에게 문의바랍니다.");
-        });
-    },
-  },
-  watch: {
-    departmentData: {
-      handler: "selectDeptHost",
-    },
-    //부서코드 값 변경 시 중복체크여부 false로 변경
-    "departmentData.dept_code": function (newVal, oldVal) {
-      this.isDuplicateChecked = false;
-    },
-  },
-  components: {
-    PageNavigation: PageNavigation,
-    SvgIcon: SvgIcon,
-    PaginationButton: PaginationButton,
-    DepartmentTree: DepartmentTree,
-    TreeModal: TreeModal,
-  },
-  mounted() {
-    this.getAuthorList();
-    this.selectDepartments();
-    this.deptSearchInit();
   },
 };
 </script>
(No newline at end of file)
 
client/views/pages/integrated/department/DeptHostList.vue (added)
+++ client/views/pages/integrated/department/DeptHostList.vue
@@ -0,0 +1,298 @@
+<template>
+  <div class="table-zone">
+    <div class="list-info flex justify-between align-center">
+      <div class="count-zone">
+        <p> 총 <span>{{ list.length }}</span>건 중 <span>{{ selectedList.length }}</span>건 선택 </p>
+      </div>
+      <div class="cunt-selectZone">
+        <select v-model="search.perPage" @change="fnSelectList">
+          <option value="10">10개 보기</option>
+          <option value="20">20개 보기</option>
+        </select>
+      </div>
+    </div>
+    <table class="list-table">
+      <colgroup>
+        <col style="width: 5%" />
+        <col style="width: 10%" />
+        <col style="width: 42.5%" />
+        <col style="width: 42.5%" />
+      </colgroup>
+      <thead>
+        <tr>
+          <th>
+            <input type="checkbox" v-model="isChkUserAll" @change="fnChkAll()" />
+          </th>
+          <th>No</th>
+          <th>호스트명</th>
+          <th>메인폴더</th>
+        </tr>
+      </thead>
+      <tbody>
+        <template v-if="list.length > 0">
+          <tr v-for="(item, idx) of list" :key="idx">
+            <td>
+              <input type="checkbox" :value="item" v-model="selectedList" @click.stop="" @change="fnChangeChk" />
+            </td>
+            <td>{{ search.totalRows - idx - (search.currentPage - 1) * search.perPage }}</td>
+            <td>{{ item.hostNm }}</td>
+            <td>{{ item.mainFolderPath }}</td>
+          </tr>
+        </template>
+        <tr v-else>
+          <td colspan="4">등록된 데이터가 없습니다.</td>
+        </tr>
+      </tbody>
+    </table>
+    <PaginationButton v-model:currentPage="search.currentPage" :perPage="search.perPage" :totalCount="search.totalRows" :maxRange="5" :click="selectDeptHost" />
+  </div>
+  <div class="flex justify-end">
+    <button class="blue-btn small-btn" @click="fnOpenModal">호스트추가</button>
+    <button class="red-border-btn small-btn" @click="fnDelete">호스트삭제</button>
+  </div>
+  <!-- 호스트 추가 모달 -->
+  <div v-show="isModalOpen" class="modal-wrapper">
+    <div class="modal-container">
+      <div class="modal-title flex justify-between align-center">
+        <h2>호스트 추가</h2>
+        <button class="close-btn" @click="fnCloseModal">
+          <svg-icon type="mdi" :width="20" :height="20" :path="closePath"></svg-icon>
+        </button>
+      </div>
+      <div class="modal-content-monthly">
+        <div class="search-bar flex justify-between align-center mb10">
+          <div class="flex25 pl0">
+            <select class="square-select full-select" v-model="modalSearchData.key">
+              <option :value="null">전체</option>
+              <option value="host_nm">호스트명</option>
+              <option value="host_ip">호스트(IP)</option>
+              <option value="rgtr_id">등록자</option>
+            </select>
+          </div>
+          <div class="flex75 flex align-center no-gutter pr0">
+            <input type="text" class="square-input flex90" placeholder="검색어를 입력해주세요." v-model="modalSearchData.value" @keyup.enter="fnSelectUserList" />
+            <button class="square-button blue-btn flex10" @click="fnSelectUserList">
+              <svg-icon type="mdi" :path="searchPath" class="square-icon"></svg-icon>
+            </button>
+          </div>
+        </div>
+        <div>
+          <table class="list-table2">
+            <colgroup>
+              <col style="width: 10%" />
+              <col style="width: 20%" />
+              <col style="width: 20%" />
+              <col style="width: 20%" />
+              <col style="width: 20%" />
+              <col style="width: 10%" />
+            </colgroup>
+            <thead>
+              <tr>
+                <th>No</th>
+                <th>호스트명</th>
+                <th>호스트(IP)</th>
+                <th>사용자명</th>
+                <th>포트</th>
+                <th>선택</th>
+              </tr>
+            </thead>
+            <tbody class="overflow-y" style="max-height: 500px">
+              <template v-if="modalList.length > 0">
+                <tr v-for="(item, idx) in modalList" :key="idx">
+                  <td>{{ modalSearch.totalRows - idx - (modalSearch.currentPage - 1) * modalSearch.perPage }}</td>
+                  <td>{{ item.host_nm }}</td>
+                  <td>{{ item.host_ip }}</td>
+                  <td>{{ item.host_id }}</td>
+                  <td>{{ item.host_port }}</td>
+                  <td><button type="button" class="blue-border-btn set-btn" @click="fnAddUser(item.hostCode)">선택</button></td>
+                </tr>
+              </template>
+              <tr v-else>
+                <td colspan="6">등록된 데이터가 없습니다.</td>
+              </tr>
+            </tbody>
+          </table>
+          <PaginationButton v-model:currentPage="modalSearch.currentPage" :perPage="modalSearch.perPage" :totalCount="modalSearch.totalRows" :click="fnSelectUserList" />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import axios from "axios";
+// icon용 svg import
+import SvgIcon from "@jamescoyle/vue-icon";
+import { mdiMagnify, mdiClose } from "@mdi/js";
+// 컴포넌트 import
+import PageNavigation from "../../../component/PageNavigation.vue";
+import PaginationButton from "../../../component/PaginationButton.vue";
+
+export default {
+  components: { SvgIcon, PageNavigation, PaginationButton },
+
+  props: {
+    deptCode: {
+      type: String,
+      default: null,
+    },
+  },
+
+  data() {
+    return {
+      // icon용 svg path
+      searchPath: mdiMagnify,
+      closePath: mdiClose,
+
+      // 목록
+      list: [],
+      isChkUserAll: false, // 전체 선택 여부
+      selectedList: [], // 선택 항목 목록
+      search: Object.assign({}, this.$getDefaultSerchVO()),
+      searchData: Object.assign({}, this.$getDefaultSerchItem(null, "string")),
+
+      // 추가 모달
+      isModalOpen: false,
+      selectHostList: [],
+
+      // 검색용
+      modalSearch: Object.assign({}, this.$getDefaultSerchVO()),
+      modalSearchData: Object.assign({}, this.$getDefaultSerchItem(null, "string")),
+
+      // 목록용
+      modalList: [],
+    }
+  },
+
+  watch: {
+    deptCode(v) {
+      this.fnSelectList();
+    },
+  },
+
+  methods: {
+    // 목록 조회
+    fnSelectList() {
+      const vm = this;
+      // 데이터 세팅
+      vm.search.searchObjectList = [];
+      vm.search.searchObjectList.push(vm.searchData);
+      // 실행
+      axios({
+        url: "/deptHost/list/" + vm.deptCode,
+        method: "post",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+        data: vm.search,
+      })
+        .then(response => {
+          vm.list = response.data.resultData.list;
+          vm.search = response.data.resultData.searchVO;
+        })
+        .catch(error => {
+          vm.$showAlert("호스트 목록", "목록 불러오기 오류, 관리자에게 문의바랍니다.");
+        });
+    },
+
+    // 목록 전체 선택
+    fnChkAll() {
+      if (this.isChkUserAll) {
+        this.selectedList = this.list;
+      } else {
+        this.selectedList = [];
+      }
+    },
+
+    // 목록 상세 선택
+    fnChangeChk() {
+      if (this.selectedList.length == this.list.length) {
+        this.isChkUserAll = true;
+      } else {
+        this.isChkUserAll = false;
+      }
+    },
+
+    // 호스트 삭제
+    fnDelete() {
+      const vm = this;
+      // 실행
+      axios({
+        url: "/deptHost",
+        method: "delete",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+        data: vm.selectedList,
+      })
+        .then(response => {
+          vm.$showAlert("작업 성공", "삭제에 성공했습니다.");
+          vm.fnSelectList(); // 목록 조회
+        })
+        .catch(error => {
+          vm.$showAlert("작업 실패", "삭제에 실패했습니다.\n관리자에게 문의바랍니다.");
+        });
+    },
+
+
+    // **** 추가용 모달
+    // 추가용 모달 열기
+    fnOpenModal() {
+      this.fnSelectUserList();
+      // 모달 열기
+      this.isModalOpen = true;
+    },
+    // 추가용 모달 닫기
+    fnCloseModal() {
+      // 초기화
+      this.search = Object.assign({}, this.$getDefaultSerchVO());
+      this.modalSearchData = Object.assign({}, this.$getDefaultSerchItem(null, "string"));
+      this.modalList = []; // 목록
+      // 모달 닫기
+      this.isModalOpen = false;
+    },
+
+    // 모달 목록 조회
+    fnSelectUserList() {
+      const vm = this;
+
+      // 데이터 세팅
+      vm.modalSearch.searchObjectList = []; // 초기화
+      vm.modalSearch.searchObjectList.push(vm.modalSearchData);
+
+      // 실행
+      axios({
+        url: "/host/list/" + vm.deptCode,
+        method: "post",
+        headers: { "Content-Type": "application/json; charset=UTF-8" },
+        data: vm.modalSearch,
+      })
+        .then(response => {
+          vm.modalSearch = response.data.resultData.searchVO;
+          vm.modalList = response.data.resultData.list;
+        })
+        .catch(error => {
+          vm.$showAlert("관리", "목록 불러오기 오류, 관리자에게 문의바랍니다.");
+        });
+    },
+
+    // 모달용 호스트 추가 (선택 버튼 동작)
+    fnAddUser(hostCode) {
+      const vm = this;
+      // 데이터 세팅
+      let deptHost = {
+        hostCode: hostCode,
+        deptCode: this.deptCode
+      }
+      // 실행
+      axios({
+        url: "/deptHost",
+        method: "post",
+        headers: { "Content-Type": "application/json" },
+        data: deptHost,
+      })
+        .then(response => {
+          vm.$showAlert("추가", "사용자를 추가했습니다.");
+        })
+        .catch(error => {
+          vm.$showAlert("오류", "부서 내 추가 오류, 관리자에게 문의바랍니다.");
+        });
+    },
+  }
+}
+</script>(No newline at end of file)
Add a comment
List