jichoi / calendar star
박정하 박정하 07-18
250718 출장 현황, 출장 신청 추가
@8c5ba61dc44ddf60365a73dd5d7c37785eb746b6
 
client/resources/api/bsrp.js (added)
+++ client/resources/api/bsrp.js
@@ -0,0 +1,26 @@
+import apiClient from "./index";
+
+// 등록
+export const saveBsrpProc = data => {
+  return apiClient.post('/bsrp/saveBsrp.json', data);
+}
+
+// 목록 조회
+export const bsrpsProc = data => {
+  return apiClient.get('/bsrp/bsrps.json', { params: data });
+}
+
+// 상세 조회
+export const bsrpProc = data => {
+  return apiClient.get(`/bsrp/${data}/bsrp.json`);
+}
+
+// 수정
+export const updateBsrpProc = data => {
+  return apiClient.put('/bsrp/updateBsrp.json', data);
+}
+
+// 삭제
+export const deleteBsrpProc = data => {
+  return apiClient.delete(`/bsrp/${data}/deleteBsrp.json`);
+}(파일 끝에 줄바꿈 문자 없음)
client/resources/js/cmmnPlugin.js
--- client/resources/js/cmmnPlugin.js
+++ client/resources/js/cmmnPlugin.js
@@ -86,7 +86,7 @@
         sanctnCodeList: [],   // 결재 구분 (결재/대결/전결)
         confmCodeList: [],    // 상태 코드 (대기/결재대기/승인/반려)
         clsfCodeList: [],     // 직급 코드 (사원/주임/대리)
-        rspofcCodeList: [],   // 직책 코드 (사원/주임/대리)
+        rspofcCodeList: [],   // 직책 코드 (팀장)
       };
 
       // 휴가 종류 - depth 2 조회
client/views/component/Popup/CorpCarPopup.vue
--- client/views/component/Popup/CorpCarPopup.vue
+++ client/views/component/Popup/CorpCarPopup.vue
@@ -1,105 +1,160 @@
 <template>
-    <div  class="popup-overlay" @click.self="$emit('close')">
-                <div class="popup-content">
-                  <div class="card">
-                    <div class="card-body">
-                      <h2 class="card-title">법인차량 목록</h2>
-                      <div class="sch-form-wrap">
-                        <div class="input-group">
-                          <div class="sch-input">
-              <input type="text" class="form-control">
-              <button class="ico-sch"><SearchOutlined /></button>
-            </div>
-                        </div>
-                      </div>
-
-                      <!-- Table  -->
-                      <div class="tbl-wrap">
-                        <table id="myTable" class="tbl data">
-                          <!-- 동적으로 <th> 생성 -->
-                          <thead>
-                            <tr>
-                              <th>차량종류 </th>
-                              <th>차량번호</th>
-                              <th>선택</th>
-                            </tr>
-                          </thead>
-                          <!-- 동적으로 <td> 생성 -->
-                          <tbody>
-                            <tr v-for="(item, index) in popuplistData" :key="index">
-                                <td>{{ item.category }}</td>
-      <td>{{ item.name }}</td>
-      <td>
-        <button
-          type="button"
-          class="btn sm secondary"
-          @click="selectCar(item)"
-        >
-          선택
-        </button>
-      </td>
-                            </tr>
-                          </tbody>
-                        </table>
-
-                      </div>
-                      <div class="pagination">
-                        <ul>
-                          <!-- 왼쪽 화살표 (이전 페이지) -->
-                          <li class="arrow" :class="{ disabled: currentPage === 1 }"
-                            @click="changePage(currentPage - 1)">
-                            &lt;
-                          </li>
-
-                          <!-- 페이지 번호 -->
-                          <li v-for="page in totalPages" :key="page" :class="{ active: currentPage === page }"
-                            @click="changePage(page)">
-                            {{ page }}
-                          </li>
-
-                          <!-- 오른쪽 화살표 (다음 페이지) -->
-                          <li class="arrow" :class="{ disabled: currentPage === totalPages }"
-                            @click="changePage(currentPage + 1)">
-                            &gt;
-                          </li>
-                        </ul>
-                      </div>
-                      <!-- End Table -->
-                    </div>
-                  </div>
-                  <button @click="$emit('close')" class="close-btn">
-                    <CloseCircleFilled />
-                  </button>
-                </div>
+  <div class="popup-overlay" @click.self="$emit('close')">
+    <div class="popup-content">
+      <div class="card">
+        <div class="card-body">
+          <h2 class="card-title">법인차량 목록</h2>
+          <div class="sch-form-wrap">
+            <div class="input-group">
+              <div class="sch-input">
+                <input type="text" class="form-control" v-model="request.searchText" @keyup.enter="fnChangeCurrentPage(1)">
+                <button class="ico-sch" @click="fnChangeCurrentPage(1)">
+                  <SearchOutlined />
+                </button>
               </div>
+            </div>
+          </div>
+          <div class="tbl-wrap">
+            <table id="myTable" class="tbl data">
+              <thead>
+                <tr>
+                  <th>차량종류</th>
+                  <th>차량번호</th>
+                  <th>선택</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr v-for="(item, idx) in items" :key="idx">
+                  <td>{{ item.vhcty }}</td>
+                  <td>{{ item.vhcleNo }}</td>
+                  <td>
+                    <button type="button" class="btn sm secondary" @click="selectCar(item)" :disabled="isVhcleSelected(item.vhcleId)">선택</button>
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+          <Pagenation :search="request" @onChange="fnChangeCurrentPage" />
+        </div>
+      </div>
+      <button @click="$emit('close')" class="close-btn">
+        <CloseCircleFilled />
+      </button>
+    </div>
+  </div>
 </template>
 <script>
 import { SearchOutlined, CloseCircleFilled } from '@ant-design/icons-vue';
+import Pagenation from '../Pagenation.vue';
+// API
+import { findAllAsSetVhcle } from '../../../resources/api/asset'
 
 export default {
-    data() {
-        return {
-            popuplistData: [
-            {
-          category: 'ooo',
-          name: 'ooo허 oooo',
-        },
-      ],
-        }
+  components: {
+    SearchOutlined, CloseCircleFilled,
+    Pagenation
+  },
+
+  props: {
+    editData: {
+      type: Object,
+      default: () => ({}),
     },
-    components: {
-    SearchOutlined, CloseCircleFilled
+    lists: {
+      type: Array,
+      default: () => [],
+    }
   },
+
+  data() {
+    return {
+      items: [],
+
+      request: {
+        searchType: "vm",       // 검색조건 ( all: 전체, vm: 차량명, vn: 차량 번호 )
+        searchText: null,       // 검색어
+        useAt: null,            // 사용여부 ( N: 미사용, Y: 사용 )
+        selectedVhcleIds: null, // 선택된 차량 Id
+        bgnde: null,            // 시작 일
+        beginHour: null,        // 시작 시
+        beginMnt: null,         // 시작 분
+        endde: null,            // 종료 일
+        endHour: null,          // 종료 시
+        endMnt: null,           // 종료 분
+      },
+    }
+  },
+
+  computed: {
+    selectedVhcleIds() {
+      return new Set(this.lists.map(item => item.vhcleId));
+    }
+  },
+
+  watch: {
+    editData: {
+      handler(newVal) {
+        if (newVal) {
+          this.request.bgnde = newVal.bgnde;
+          this.request.beginHour = newVal.beginHour;
+          this.request.beginMnt = newVal.beginMnt;
+          this.request.endde = newVal.endde;
+          this.request.endHour = newVal.endHour;
+          this.request.endMnt = newVal.endMnt;
+
+          this.findDatas();
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+
+  mounted() {
+    this.findDatas();
+  },
+
   methods: {
+    // 목록 조회
+    async findDatas() {
+      try {
+        const response = await findAllAsSetVhcle(this.request);
+        const result = response.data.data;
+
+        this.items = result.vhcle;
+        this.request = result.search;
+      } catch (error) {
+        if (error.response) {
+          alert(error.response.data.message);
+        } else {
+          alert("에러가 발생했습니다.");
+        }
+        console.error(error.message);
+      }
+    },
+
+    // 차량 검증
+    isVhcleSelected(vhcleId) {
+      return this.selectedVhcleIds.has(vhcleId);
+    },
+
+    // 차량 선택
     selectCar(item) {
-    this.$emit('select', item); // 부모에게 데이터 전달
-  },
-    
+      this.$emit('onSelected', item);
+    },
+
+    // 페이지 이동
+    fnChangeCurrentPage(currentPage) {
+      this.request.currentPage = Number(currentPage);
+      this.$nextTick(() => {
+        this.findDatas();
+      });
+    },
   }
 }
 </script>
 <style scoped>
 .popup-content {
-    width: 50%;
+  width: 50%;
 }
 </style>
(파일 끝에 줄바꿈 문자 없음)
client/views/component/Popup/CorpCardPopup.vue
--- client/views/component/Popup/CorpCardPopup.vue
+++ client/views/component/Popup/CorpCardPopup.vue
@@ -1,102 +1,163 @@
 <template>
-    <div  class="popup-overlay" @click.self="$emit('close')">
-                <div class="popup-content">
-                  <div class="card">
-                    <div class="card-body">
-                      <h2 class="card-title">법인차량 목록</h2>
-                      <div class="sch-form-wrap">
-                        <div class="input-group">
-                          <div class="sch-input">
-              <input type="text" class="form-control">
-              <button class="ico-sch"><SearchOutlined /></button>
-            </div>
-                        </div>
-                      </div>
-
-                      <!-- Table  -->
-                      <div class="tbl-wrap">
-                        <table id="myTable" class="tbl data">
-                          <!-- 동적으로 <th> 생성 -->
-                          <thead>
-                            <tr>
-                              <th>카드명 </th>
-                              <th>선택</th>
-                            </tr>
-                          </thead>
-                          <!-- 동적으로 <td> 생성 -->
-                          <tbody>
-                            <tr v-for="(item, index) in popuplistData" :key="index">
-      <td>{{ item.name }}</td>
-      <td>
-        <button
-          type="button"
-          class="btn sm secondary"
-          @click="selectCard(item)"
-        >
-          선택
-        </button>
-      </td>
-                            </tr>
-                          </tbody>
-                        </table>
-
-                      </div>
-                      <div class="pagination">
-                        <ul>
-                          <!-- 왼쪽 화살표 (이전 페이지) -->
-                          <li class="arrow" :class="{ disabled: currentPage === 1 }"
-                            @click="changePage(currentPage - 1)">
-                            &lt;
-                          </li>
-
-                          <!-- 페이지 번호 -->
-                          <li v-for="page in totalPages" :key="page" :class="{ active: currentPage === page }"
-                            @click="changePage(page)">
-                            {{ page }}
-                          </li>
-
-                          <!-- 오른쪽 화살표 (다음 페이지) -->
-                          <li class="arrow" :class="{ disabled: currentPage === totalPages }"
-                            @click="changePage(currentPage + 1)">
-                            &gt;
-                          </li>
-                        </ul>
-                      </div>
-                      <!-- End Table -->
-                    </div>
-                  </div>
-                  <button @click="$emit('close')" class="close-btn">
-                    <CloseCircleFilled />
-                  </button>
-                </div>
+  <div class="popup-overlay" @click.self="$emit('close')">
+    <div class="popup-content">
+      <div class="card">
+        <div class="card-body">
+          <h2 class="card-title">법인카드 목록</h2>
+          <div class="sch-form-wrap">
+            <div class="input-group">
+              <div class="sch-input">
+                <input type="text" class="form-control" v-model="request.searchText" @keyup.enter="fnChangeCurrentPage(1)">
+                <button class="ico-sch" @click="fnChangeCurrentPage(1)">
+                  <SearchOutlined />
+                </button>
               </div>
+            </div>
+          </div>
+          <div class="tbl-wrap">
+            <table id="myTable" class="tbl data">
+              <thead>
+                <tr>
+                  <th>카드명</th>
+                  <th>선택</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr v-for="(item, idx) in items" :key="idx">
+                  <td>{{ item.cardNm }}</td>
+                  <td>
+                    <button type="button" class="btn sm secondary" @click="selectCard(item)" :disabled="isSelected(item.cardId)">선택</button>
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+          <Pagenation :search="request" @onChange="fnChangeCurrentPage" />
+        </div>
+      </div>
+      <button @click="$emit('close')" class="close-btn">
+        <CloseCircleFilled />
+      </button>
+    </div>
+  </div>
 </template>
 <script>
 import { SearchOutlined, CloseCircleFilled } from '@ant-design/icons-vue';
+import Pagenation from '../Pagenation.vue';
+// API
+import { findAllAsSetCard } from '../../../resources/api/asset'
 
 export default {
-    data() {
-        return {
-            popuplistData: [
-            {
-          name: '법인카드1',
-        },
-      ],
-        }
+  components: {
+    SearchOutlined, CloseCircleFilled,
+    Pagenation,
+  },
+
+  props: {
+    editData: {
+      type: Object,
+      default: () => ({}),
     },
-    components: {
-    SearchOutlined, CloseCircleFilled
+    lists: {
+      type: Array,
+      default: () => [],
+    }
   },
+
+  data() {
+    return {
+      items: [],
+
+      request: {
+        searchType: "vm",       // 검색조건 ( all: 전체, vm: 차량명, vn: 차량 번호 )
+        searchText: null,       // 검색어
+        useAt: null,            // 사용여부 ( N: 미사용, Y: 사용 )
+        selectedCardIds: null,  // 선택된 카드 Id
+        bgnde: null,            // 시작 일
+        beginHour: null,        // 시작 시
+        beginMnt: null,         // 시작 분
+        endde: null,            // 종료 일
+        endHour: null,          // 종료 시
+        endMnt: null,           // 종료 분
+      },
+    }
+  },
+
+  computed: {
+    selectedIds() {
+      return new Set(this.lists.map(item => item.cardId));
+    }
+  },
+
+  watch: {
+    editData: {
+      handler(newVal) {
+        if (newVal) {
+          this.request.bgnde = newVal.bgnde;
+          this.request.beginHour = newVal.beginHour;
+          this.request.beginMnt = newVal.beginMnt;
+          this.request.endde = newVal.endde;
+          this.request.endHour = newVal.endHour;
+          this.request.endMnt = newVal.endMnt;
+
+          this.findDatas();
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+
+  mounted() {
+    this.findDatas();
+  },
+
   methods: {
+    // 목록 조회
+    async findDatas() {
+      try {
+        const response = await findAllAsSetCard(this.request);
+        const result = response.data.data;
+
+        this.items = result.card;
+        this.request = result.search;
+      } catch (error) {
+        if (error.response) {
+          alert(error.response.data.message);
+        } else {
+          alert("에러가 발생했습니다.");
+        }
+        console.error(error.message);
+      }
+    },
+
+    // 카드 검증
+    isSelected(id) {
+      return this.selectedIds.has(id);
+    },
+
+    // 카드 선택
     selectCard(item) {
-    this.$emit('select', item); // 부모에게 데이터 전달
-  },
-    
+      this.$emit('onSelected', item);
+    },
+
+    // 페이지 이동
+    fnChangeCurrentPage(currentPage) {
+      this.request.currentPage = Number(currentPage);
+      this.$nextTick(() => {
+        this.findDatas();
+      });
+    },
   }
 }
 </script>
 <style scoped>
 .popup-content {
-    width: 50%;
+  width: 50%;
+}
+
+.btn:disabled {
+  opacity: 0.5;
+  cursor: not-allowed;
 }
 </style>
(파일 끝에 줄바꿈 문자 없음)
client/views/component/Popup/HrPopup.vue
--- client/views/component/Popup/HrPopup.vue
+++ client/views/component/Popup/HrPopup.vue
@@ -27,9 +27,9 @@
               </thead>
               <tbody>
                 <tr v-for="(item, idx) in users" :key="idx">
-                  <td>{{ getCodeName(item.clsf, 'clsfCodeList') }}</td>
-                  <td>{{ getCodeName(item.rspofc, 'rspofcCodeList') }}</td>
-                  <td>{{ item.userDeptInfo.deptVO.deptNm }}</td>
+                  <td>{{ item.clsfNm }}</td>
+                  <td>{{ item.rspofcNm }}</td>
+                  <td>{{ item.deptNm }}</td>
                   <td>{{ item.userNm }}</td>
                   <td>
                     <button type="button" class="btn sm secondary" @click="selectPerson(item)" :disabled="isUserSelected(item.userId)">선택</button>
@@ -60,7 +60,7 @@
   },
 
   props: {
-    sanctns: {
+    lists: {
       type: Array,
       default: () => [],
     }
@@ -76,23 +76,22 @@
         searchSttus: 1, // 회원상태 승인 고정
         searchUseAt: 'Y', // 사용여부 사용 고정
       },
-
-      cmmnCodes: {},
     }
   },
 
   computed: {
     selectedUserIds() {
-      return new Set(this.sanctns.map(sanctn => sanctn.confmerId));
+      return new Set(this.lists.map(sanctn => sanctn.confmerId));
     }
   },
 
-  async created() {
-    this.cmmnCodes = await this.$defaultCodes();
-  },
+  watch: {},
+
+  created() { },
 
   mounted() {
     this.findDatas(); // 목록 조회
+
   },
 
   methods: {
@@ -114,13 +113,6 @@
       }
     },
 
-    // 공통코드명 조회
-    getCodeName(code, codeListName) {
-      if (!code || !this.cmmnCodes[codeListName]) return '';
-      const codeItem = this.cmmnCodes[codeListName].find(item => item.code === code);
-      return codeItem ? codeItem.codeNm : null;
-    },
-
     // 사용자 검증
     isUserSelected(userId) {
       return this.selectedUserIds.has(userId);
@@ -128,16 +120,7 @@
 
     // 승인자 선택
     selectPerson(item) {
-      const data = {
-        confmerId: item.userId,
-        clsf: item.clsf,
-        sanctnOrdr: this.sanctns.length + 1,
-        sanctnSe: this.cmmnCodes.sanctnCodeList[0].code,
-
-        clsfNm: this.getCodeName(item.clsf, 'clsfCodeList'),
-        userNm: item.userNm,
-      };
-      this.$emit('onSelected', data);
+      this.$emit('onSelected', item);
     },
 
     // 페이지 이동
client/views/component/Sanctn/SanctnFormList.vue (Renamed from client/views/component/Sanctn/SanctnList.vue)
--- client/views/component/Sanctn/SanctnList.vue
+++ client/views/component/Sanctn/SanctnFormList.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <div v-for="(sanctns, idx) of sanctns" :key="sanctns.sanctnId || idx" class="draggable-item-wrapper">
+    <div v-for="(lists, idx) of lists" :key="lists.sanctnId || idx" class="draggable-item-wrapper">
       <div class="drop-zone" @dragover.prevent="handleDragEnter($event, idx)" @dragenter.prevent="handleDragEnter($event, idx)" @dragleave="handleDragLeave($event, idx)" @drop.prevent="handleDrop($event, idx)" :class="{
         'drop-active': dropTarget === idx,
         'drop-visible': draggedIndex !== null && shouldShowDropZone(idx),
@@ -9,19 +9,19 @@
         <div class="drop-indicator">여기에 놓기</div>
       </div>
       <div class="d-flex addapproval draggable-item" draggable="true" @dragstart="handleDragStart(idx, $event)" @dragend="handleDragEnd" :class="{ 'being-dragged': draggedIndex === idx }">
-        <select class="form-select" v-model="sanctns.sanctnSe" style="width: 110px;" @mousedown.stop>
+        <select class="form-select" v-model="lists.sanctnSe" style="width: 110px;" @mousedown.stop>
           <option v-for="(item, idx) of cmmnCodes.sanctnCodeList" :key="idx" :value="item.code"> {{ item.codeNm }} </option>
         </select>
         <div class="d-flex align-items-center border-x">
-          <p>{{ sanctns.userNm }} {{ formatClsf(sanctns.clsfNm) }} ({{ sanctns.sanctnOrdr }})</p>
+          <p>{{ lists.confmerNm }} {{ lists.clsfNm }} ({{ lists.sanctnOrdr }})</p>
           <button type="button" @click="$emit('delSanctn', idx)" @mousedown.stop>
             <CloseOutlined />
           </button>
         </div>
       </div>
     </div>
-    <div class="drop-zone" @dragover.prevent="handleDragEnter($event, sanctns.length)" @dragenter.prevent="handleDragEnter($event, sanctns.length)" @dragleave="handleDragLeave($event, sanctns.length)" @drop.prevent="handleDrop($event, sanctns.length)" :class="{
-      'drop-active': dropTarget === sanctns.length,
+    <div class="drop-zone" @dragover.prevent="handleDragEnter($event, lists.length)" @dragenter.prevent="handleDragEnter($event, lists.length)" @dragleave="handleDragLeave($event, lists.length)" @drop.prevent="handleDrop($event, lists.length)" :class="{
+      'drop-active': dropTarget === lists.length,
       'drop-visible': draggedIndex !== null && shouldShowLastDropZone(),
       'drop-hidden': draggedIndex !== null && !shouldShowLastDropZone()
     }">
@@ -38,7 +38,7 @@
   components: { CloseOutlined },
 
   props: {
-    sanctns: {
+    lists: {
       type: Array,
       default: () => [],
     }
@@ -57,11 +57,6 @@
   },
 
   methods: {
-    formatClsf(code) {
-      const clsfCode = this.cmmnCodes?.clsfCodeList?.find(item => item.code === code);
-      return clsfCode?.codeNm || code;
-    },
-
     shouldShowDropZone(index) {
       if (this.draggedIndex === null) return true;
       if (index === this.draggedIndex || index === this.draggedIndex + 1) return false;
@@ -70,7 +65,7 @@
 
     shouldShowLastDropZone() {
       if (this.draggedIndex === null) return true;
-      return this.draggedIndex !== this.sanctns.length - 1;
+      return this.draggedIndex !== this.lists.length - 1;
     },
 
     handleDragStart(index, event) {
@@ -105,7 +100,7 @@
           finalDropIndex = dropIndex - 1;
         }
 
-        const newSanctns = [...this.sanctns];
+        const newSanctns = [...this.lists];
         const draggedItem = newSanctns.splice(this.draggedIndex, 1)[0];
         newSanctns.splice(finalDropIndex, 0, draggedItem);
 
@@ -113,7 +108,7 @@
           item.sanctnOrdr = index + 1;
         });
 
-        this.$emit('update:sanctns', newSanctns);
+        this.$emit('update:lists', newSanctns);
       }
 
       this.dropTarget = null;
 
client/views/component/Sanctn/SanctnViewList.vue (added)
+++ client/views/component/Sanctn/SanctnViewList.vue
@@ -0,0 +1,36 @@
+<template>
+  <div class="approval-box tbl-wrap tbl2">
+    <table class="tbl data">
+      <tbody>
+        <tr class="thead">
+          <td rowspan="2" class="th">승인자</td>
+          <td v-for="(item, idx) of sanctns" :key="idx">{{ item.clsfNm }}</td>
+        </tr>
+        <tr>
+          <td v-for="(item, idx) of sanctns" :key="idx">
+            <template v-if="item.confmAt === 'A'">
+              <p v-if="item.sanctnSe === 'sanctn_agncy'">(대결)</p>
+              <p class="name">{{ item.confmerNm }}</p>
+              <small class="date">{{ new Date(item.sanctnDe).toISOString().split('T')[0] }}</small>
+            </template>
+            <template v-else-if="item.confmAt === 'R'">
+              <p class="name">반려</p>
+            </template>
+          </td>
+        </tr>
+      </tbody>
+    </table>
+  </div>
+</template>
+<script>
+export default {
+  name: 'SanctnViewList',
+
+  props: {
+    sanctns: {
+      type: Array,
+      default: () => [],
+    }
+  },
+}
+</script>(파일 끝에 줄바꿈 문자 없음)
client/views/pages/AppRouter.js
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
@@ -5,11 +5,6 @@
 import Join from '../pages/User/Join.vue';
 import MyPage from '../pages/User/MyPage.vue';
 
-// import Main2 from '../pages/main/Main2.vue';
-
-// import HomeView from "../pages/HomeView.vue";
-// import AboutView from "../pages/AboutView.vue";
-
 // 직원
 import ChuljangList from '../pages/Employee/ChuljangList.vue';
 import HyugaList from '../pages/Employee/HyugaList.vue';
@@ -23,19 +18,18 @@
 import Hyuga from '../pages/Manager/approval/Hyuga.vue';
 
 //근태관리
-import ChuljangPumuiDetail from '../pages/Manager/attendance/ChuljangPumuiDetail.vue';
 import ChuljangBokmyeongDetail from '../pages/Manager/attendance/ChuljangBokmyeongDetail.vue';
-import ChuljangDetailAll from '../pages/Manager/attendance/ChuljangDetailAll.vue';
-import attendance from '../pages/Manager/attendance/attendance.vue';
+import ChuljangDetailAll from './Manager/attendance/ChuljangDetailAll.vue';
+import ChuljangStatue from '../pages/Manager/attendance/ChuljangStatue.vue';
+import ChuljangInsert from '../pages/Manager/attendance/ChuljangInsert.vue';
 import myAttendance from '../pages/Manager/attendance/myAttendance.vue';
 import buseoAttendance from '../pages/Manager/attendance/buseoAttendance.vue';
+import attendance from '../pages/Manager/attendance/attendance.vue';
 import AttendanceDetail from '../pages/Manager/attendance/AttendanceDetail.vue';
 import hyugaStatue from '../pages/Manager/attendance/hyugaStatue.vue';
 import HyugaInsert from '../pages/Manager/attendance/HyugaInsert.vue';
 import HyugaDetail from '../pages/Manager/attendance/HyugaDetail.vue';
 import BokmyeongInsert from '../pages/Manager/attendance/BokmyeongInsert.vue';
-import ChuljangStatue from '../pages/Manager/attendance/ChuljangStatue.vue';
-import ChuljangInsert from '../pages/Manager/attendance/ChuljangInsert.vue';
 //업무관리
 import task from '../pages/Manager/task/task.vue';
 import projectStatue from '../pages/Manager/task/projectStatue.vue';
@@ -75,133 +69,129 @@
 import commonCodeDetail from '../pages/Manager/system/commonCodeDetail.vue';
 
 const routes = [
-    /* 메인화면 */
-    { path: '/', name: '/', component: Main},
-    { path: '/login.page', name: 'Login', component: Login},
-    { path: '/join.page', name: 'Join', component: Join},
-    { path: '/MyPage.page', name: 'MyPage', component: MyPage},
-    
-    { path: '/ChuljangList.page', name: 'ChuljangList', component: ChuljangList },
-    { path: '/HyugaList.page', name: 'HyugaList', component: HyugaList },
-    
-    { path: '/HyugaOk.page', name: 'HyugaOk', component: HyugaOk },
-    
-    { path: '/approval-management.page', name: 'approval', component: approval, redirect: '/approval-management.page/approvalRequest.page',
+  /* 메인화면 */
+  { path: '/', name: '/', component: Main },
+  { path: '/login.page', name: 'Login', component: Login },
+  { path: '/join.page', name: 'Join', component: Join },
+  { path: '/MyPage.page', name: 'MyPage', component: MyPage },
+  { path: '/ChuljangList.page', name: 'ChuljangList', component: ChuljangList },
+  { path: '/HyugaList.page', name: 'HyugaList', component: HyugaList },
+  { path: '/HyugaOk.page', name: 'HyugaOk', component: HyugaOk },
+  {
+    path: '/approval-management.page', name: 'approval', component: approval, redirect: '/approval-management.page/approvalRequest.page',
+    children: [
+      {
+        path: 'approvalRequest.page', // => /approval-management.page/list
+        name: 'approvalRequest',
+        component: approvalRequest,
         children: [
-            {
-              path: 'approvalRequest.page', // => /approval-management.page/list
-              name: 'approvalRequest',
-              component: approvalRequest,
-              children: [
-                
-              ]
-            },
-            {
-              path: 'approvalList.page', // => /approval-management.page/detail/123
-              name: 'approvalList',
-              component: approvalList,
-              children: [
-              ]
-            },
-            { path: 'ChuljangPumui.page', name: 'ChuljangPumui', component: ChuljangPumui },
-            { path: 'ChuljangBokmyeong.page', name: 'ChuljangBokmyeong', component: ChuljangBokmyeong },
-            { path: 'Hyuga.page', name: 'Hyuga', component: Hyuga },
-          
-           
-            
-        ]
-    }, //결재관리
-    { path: '/attendance-management.page', name: 'attendance', component: attendance, redirect: '/attendance-management.page/myAttendance.page',
-        children: [
-            { path: 'myAttendance.page', name: 'myAttendance', component: myAttendance },
-            { path: 'buseoAttendance.page', name: 'buseoAttendance', component: buseoAttendance },
-            { path: 'AttendanceDetail.page', name: 'AttendanceDetail', component: AttendanceDetail },
-            { path: 'hyugaStatue.page', name: 'hyugaStatue', component: hyugaStatue },
-            { path: 'HyugaDetail.page', name: 'HyugaDetail', component: HyugaDetail },
-            { path: 'hyugaInsert.page', name: 'hyugaInsert', component: HyugaInsert },
-            { path: 'ChuljangStatue.page', name: 'ChuljangStatue', component: ChuljangStatue },
-            { path: 'BokmyeongInsert.page', name: 'BokmyeongInsert', component: BokmyeongInsert },
-            { path: 'ChuljangInsert.page', name: 'ChuljangInsert', component: ChuljangInsert },
-            { path: 'ChuljangPumuiDetail.page', name: 'ChuljangPumuiDetail', component: ChuljangPumuiDetail },
-            { path: 'ChuljangBokmyeongDetail.page', name: 'ChuljangBokmyeongDetail', component: ChuljangBokmyeongDetail },
-            { path: 'ChuljangDetailAll.page', name: 'ChuljangDetailAll', component: ChuljangDetailAll },
 
         ]
-    }, //근태관리
-    { path: '/task-management.page', name: 'task', component: task, redirect: '/task-management.page/projectStatue.page',
+      },
+      {
+        path: 'approvalList.page', // => /approval-management.page/detail/123
+        name: 'approvalList',
+        component: approvalList,
         children: [
-            { path: 'projectStatue.page', name: 'projectStatue', component: projectStatue },
-            { path: 'projectDetail.page', name: 'projectDetail', component: projectDetail },
-            { path: 'meetingInsert.page', name: 'meetingInsert', component: meetingInsert },
-            { path: 'meetingDetail.page', name: 'meetingDetail', component: meetingDetail },
-            { path: 'projectInsert.page', name: 'projectInsert', component: projectInsert },
-            { path: 'projectTuib.page', name: 'projectTuib', component: projectTuib },
-            { path: 'projectTuibDetail.page', name: 'projectTuibDetail', component: projectTuibDetail },
         ]
-     }, //업무관리
-    { path: '/financial-management.page', name: 'financial', component: financial, redirect: '/financial-management.page/salaryList.page',
-        children: [
-            { path: 'salaryList.page', name: 'salaryList', component: salaryList },
-            { path: 'employeeSalaryList.page', name: 'employeeSalaryList', component: employeeSalaryList },
-            { path: 'employeeSalaryDetail.page', name: 'employeeSalaryDetail', component: employeeSalaryDetail },
-            { path: 'employeeSalaryInsert.page', name: 'employeeSalaryInsert', component: employeeSalaryInsert },
-            { path: 'ChuljangCostList.page', name: 'ChuljangCostList', component: ChuljangCostList },
-            { path: 'MeetingCostList.page', name: 'MeetingCostList', component: MeetingCostList },
-        ]
-     }, //재무관리
-    { path: '/asset-management.page', name: 'asset', component: asset, redirect: '/asset-management.page/VhcleList.page',
-      children: [
-        { path: 'VhcleList.page', name: 'VhcleList', component: VhcleList },
-        { path: 'VhcleInfoManagement.page', name: 'VhcleInfoManagement', component: VhcleInfoManagement },
-        { path: 'CardList.page', name: 'CardList', component: CardList },
-        { path: 'CardInfoManagement.page', name: 'CardInfoManagement', component: CardInfoManagement },
-        
-      ]
-     }, //자산관리
-    { path: '/hr-management.page', name: 'hr', component: hr, redirect: '/hr-management.page/hrSearch.page',
-      children: [
-        { path: 'hrSearch.page', name: 'hrSearch', component: hrSearch },
-        { path: 'hrManagement.page', name: 'hrManagement', component: hrManagement },
-        { path: 'hrDetail.page', name: 'hrDetail', component: hrDetail },
-        { path: 'hrInsert.page', name: 'hrInsert', component: hrInsert },
-        { path: 'buseoManagement.page', name: 'buseoManagement', component: buseoManagement },
-      ]
-    }, //인사관리
-    { path: '/system-management.page', name: 'system', component: system,  redirect: { name: 'userManagement' },
-      children:[
-        { path: 'userManagement.page', name: 'userManagement', component: userManagement },
-        { path: 'accessControlManagement.page', name: 'accessControlManagement', component: accessControlManagement },
-        { path: 'commonCodeManagement.page', name: 'commonCodeManagement', component: commonCodeManagement },
-        { path: 'commonCodeInsert.page', name: 'commonCodeInsert', component: commonCodeInsert },
-        { path: 'commonCodeDetail.page', name: 'commonCodeDetail', component: commonCodeDetail },
-        
-      ]
-     },  //시스템관리
+      },
+      { path: 'ChuljangPumui.page', name: 'ChuljangPumui', component: ChuljangPumui },
+      { path: 'ChuljangBokmyeong.page', name: 'ChuljangBokmyeong', component: ChuljangBokmyeong },
+      { path: 'Hyuga.page', name: 'Hyuga', component: Hyuga },
+    ]
+  }, //결재관리
+  {
+    path: '/attendance-management.page', name: 'attendance', component: attendance, redirect: '/attendance-management.page/myAttendance.page',
+    children: [
+      { path: 'myAttendance.page', name: 'myAttendance', component: myAttendance },
+      { path: 'buseoAttendance.page', name: 'buseoAttendance', component: buseoAttendance },
+      { path: 'AttendanceDetail.page', name: 'AttendanceDetail', component: AttendanceDetail },
+      { path: 'hyugaStatue.page', name: 'hyugaStatue', component: hyugaStatue },
+      { path: 'HyugaDetail.page', name: 'HyugaDetail', component: HyugaDetail },
+      { path: 'hyugaInsert.page', name: 'hyugaInsert', component: HyugaInsert },
+      { path: 'ChuljangStatue.page', name: 'ChuljangStatue', component: ChuljangStatue },
+      { path: 'BokmyeongInsert.page', name: 'BokmyeongInsert', component: BokmyeongInsert },
+      { path: 'ChuljangInsert.page', name: 'ChuljangInsert', component: ChuljangInsert },
+      { path: 'ChuljangBokmyeongDetail.page', name: 'ChuljangBokmyeongDetail', component: ChuljangBokmyeongDetail },
+      { path: 'ChuljangDetailAll.page', name: 'ChuljangDetailAll', component: ChuljangDetailAll },
+    ]
+  }, //근태관리
+  {
+    path: '/task-management.page', name: 'task', component: task, redirect: '/task-management.page/projectStatue.page',
+    children: [
+      { path: 'projectStatue.page', name: 'projectStatue', component: projectStatue },
+      { path: 'projectDetail.page', name: 'projectDetail', component: projectDetail },
+      { path: 'meetingInsert.page', name: 'meetingInsert', component: meetingInsert },
+      { path: 'meetingDetail.page', name: 'meetingDetail', component: meetingDetail },
+      { path: 'projectInsert.page', name: 'projectInsert', component: projectInsert },
+      { path: 'projectTuib.page', name: 'projectTuib', component: projectTuib },
+      { path: 'projectTuibDetail.page', name: 'projectTuibDetail', component: projectTuibDetail },
+    ]
+  }, //업무관리
+  {
+    path: '/financial-management.page', name: 'financial', component: financial, redirect: '/financial-management.page/salaryList.page',
+    children: [
+      { path: 'salaryList.page', name: 'salaryList', component: salaryList },
+      { path: 'employeeSalaryList.page', name: 'employeeSalaryList', component: employeeSalaryList },
+      { path: 'employeeSalaryDetail.page', name: 'employeeSalaryDetail', component: employeeSalaryDetail },
+      { path: 'employeeSalaryInsert.page', name: 'employeeSalaryInsert', component: employeeSalaryInsert },
+      { path: 'ChuljangCostList.page', name: 'ChuljangCostList', component: ChuljangCostList },
+      { path: 'MeetingCostList.page', name: 'MeetingCostList', component: MeetingCostList },
+    ]
+  }, //재무관리
+  {
+    path: '/asset-management.page', name: 'asset', component: asset, redirect: '/asset-management.page/VhcleList.page',
+    children: [
+      { path: 'VhcleList.page', name: 'VhcleList', component: VhcleList },
+      { path: 'VhcleInfoManagement.page', name: 'VhcleInfoManagement', component: VhcleInfoManagement },
+      { path: 'CardList.page', name: 'CardList', component: CardList },
+      { path: 'CardInfoManagement.page', name: 'CardInfoManagement', component: CardInfoManagement },
+
+    ]
+  }, //자산관리
+  {
+    path: '/hr-management.page', name: 'hr', component: hr, redirect: '/hr-management.page/hrSearch.page',
+    children: [
+      { path: 'hrSearch.page', name: 'hrSearch', component: hrSearch },
+      { path: 'hrManagement.page', name: 'hrManagement', component: hrManagement },
+      { path: 'hrDetail.page', name: 'hrDetail', component: hrDetail },
+      { path: 'hrInsert.page', name: 'hrInsert', component: hrInsert },
+      { path: 'buseoManagement.page', name: 'buseoManagement', component: buseoManagement },
+    ]
+  }, //인사관리
+  {
+    path: '/system-management.page', name: 'system', component: system, redirect: { name: 'userManagement' },
+    children: [
+      { path: 'userManagement.page', name: 'userManagement', component: userManagement },
+      { path: 'accessControlManagement.page', name: 'accessControlManagement', component: accessControlManagement },
+      { path: 'commonCodeManagement.page', name: 'commonCodeManagement', component: commonCodeManagement },
+      { path: 'commonCodeInsert.page', name: 'commonCodeInsert', component: commonCodeInsert },
+      { path: 'commonCodeDetail.page', name: 'commonCodeDetail', component: commonCodeDetail },
+    ]
+  },  //시스템관리
 ];
 
-
 const AppRouter = createRouter({
-    history: createWebHistory(),
-    routes,
+  history: createWebHistory(),
+  routes,
 });
 
 // Add navigation guard
 AppRouter.beforeEach((to, from, next) => {
-    // Check login status
-    const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true';
-  
-    // If not logged in and trying to access any page other than login, redirect to login page
-    if (!isLoggedIn && to.path !== '/login.page') {
-      next('/login.page');
-    } 
-    // If logged in and trying to access login page, redirect to main page
-    else if (isLoggedIn && to.path === '/login.page') {
-      next('/');
-    } 
-    else {
-      next(); // Proceed to requested route
-    }
-  });
-  
+  // Check login status
+  const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true';
+
+  // If not logged in and trying to access any page other than login, redirect to login page
+  if (!isLoggedIn && to.path !== '/login.page') {
+    next('/login.page');
+  }
+  // If logged in and trying to access login page, redirect to main page
+  else if (isLoggedIn && to.path === '/login.page') {
+    next('/');
+  }
+  else {
+    next(); // Proceed to requested route
+  }
+});
 
 export default AppRouter;
(파일 끝에 줄바꿈 문자 없음)
client/views/pages/Manager/attendance/ChuljangDetailAll.vue
--- client/views/pages/Manager/attendance/ChuljangDetailAll.vue
+++ client/views/pages/Manager/attendance/ChuljangDetailAll.vue
@@ -1,225 +1,262 @@
 <template>
-<div class="card ">
-      <div class="card-body">
-          <h2 class="card-title">출장 현황</h2>
-       
+  <div class="card">
+    <div class="card-body">
+      <h2 class="card-title">출장 현황</h2>
       <div class="form-card" style="margin-bottom: 20px;">
         <h1>출장품의서</h1>
-        <div class="approval-box tbl-wrap tbl2">
-         <table class="tbl data">
-          <tbody>
-            <tr class="thead">
-              <td rowspan="2" class="th">승인자</td>
-              <td>과장</td>
-              <td>소장</td>
-            </tr>
-            <tr>
-              <td><p class="name">홍길동</p><p class="date">2025/05/09</p></td>
-              <td><p class="name">홍길동</p><p class="date">2025/05/09</p></td>
-            </tr>
-          </tbody>
-
-         </table>
-        </div>
-          <form class="row g-3 needs-validation detail"  :class="{ 'was-validated': formSubmitted }" @submit.prevent="handleRegister" novalidate >
-                <div class="col-12 ">
-                  <div class="col-12 border-x">
-                    <label for="youremail" class="form-label ">출장구분<p class="require"><img :src="require" alt=""></p></label>
-                    <input  v-model="email" type="text" name="username" class="form-control"  readonly >
-                  </div>
-    
-                  <div class="col-12 border-x">
-                    <label for="yourPassword" class="form-label">이름</label>
-                    <input  v-model="password" type="password" name="password" class="form-control"  readonly   placeholder="주식회사 테이큰 소프트"> 
-                  </div>
-               </div>
-               <div class="col-12">
-                  <div class="col-12 border-x">
-                    <label for="youremail" class="form-label">부서</label>
-                    <input  v-model="email" type="text" name="username" class="form-control"  readonly  placeholder="과장">
-                  </div>
-    
-                  <div class="col-12 border-x">
-                    <label for="yourPassword" class="form-label">직급</label>
-                    <input  v-model="password" type="password" name="password" class="form-control"  readonly  placeholder="팀장"> 
-                  </div>
-               </div>
-               <div class="col-12">
-                  <label for="yourName" class="form-label">출장지</label>
-                  <input  v-model="name" type="text" name="name" class="form-control"  readonly>
-            </div>
-            <div class="col-12">
-                  <label for="yourName" class="form-label">출장목적</label>
-                  <input v-model="name" type="text" name="name" class="form-control "  readonly>
-            </div>
-            <div class="col-12">
-                  <label for="yourName" class="form-label">동행자</label>
-                  <input v-model="name" type="text" name="name" class="form-control "  readonly>
-            </div>
-            <div class="col-12 chuljang">
-                  <label for="yourName" class="form-label">품의내용</label>
-                  <input v-model="name" type="text" name="name" class="form-control textarea "  readonly>
-            </div>
-            <div class="col-12">
-                  <label for="yourName" class="form-label">법인카드</label>
-                  <input v-model="name" type="text" name="name" class="form-control "  readonly>
-            </div>
-            <div class="col-12">
-                  <label for="yourName" class="form-label">법인차량</label>
-                  <input v-model="name" type="text" name="name" class="form-control "  readonly>
+        <SanctnViewList v-if="bsrpCnsul.sanctnList.length > 0" :sanctns="bsrpCnsul.sanctnList" />
+        <form class="row g-3 needs-validation detail" :class="{ 'was-validated': formSubmitted }" @submit.prevent="handleRegister" novalidate>
+          <div class="col-12">
+            <div class="col-12 border-x">
+              <label class="form-label">출장구분</label>
+              <p>{{ bsrpInfo.bsrpSeNm }}</p>
             </div>
             <div class="col-12 border-x">
-                  <label for="yourName" class="form-label">품의 신청일</label>
-                  <input v-model="name" type="text" name="name" class="form-control " i readonly>
+              <label class="form-label">이름</label>
+              <p>{{ user.userNm }}</p>
             </div>
-              </form>
+          </div>
+          <div class="col-12">
+            <div class="col-12 border-x">
+              <label class="form-label">부서</label>
+              <p>{{ user.deptNm }}</p>
+            </div>
+            <div class="col-12 border-x">
+              <label class="form-label">직급</label>
+              <p>{{ user.clsfNm }}</p>
+            </div>
+          </div>
+          <div class="col-12">
+            <label class="form-label">출장지</label>
+            <p>{{ bsrpInfo.bsrpPlace }}</p>
+          </div>
+          <div class="col-12">
+            <label class="form-label">출장목적</label>
+            <p>{{ bsrpInfo.bsrpPurps }}</p>
+          </div>
+          <div class="col-12">
+            <label class="form-label">동행자</label>
+            <div v-if="bsrpInfo.bsrpNmprList.length > 0">
+              <span v-for="(item, idx) of bsrpInfo.bsrpNmprList" :key="idx">{{ item.triperNm }}</span>
+            </div>
+          </div>
+          <div class="col-12">
+            <label class="form-label">품의내용</label>
+            <ViewerComponent :content="bsrpCnsul.cn" />
+          </div>
+          <div class="col-12">
+            <label class="form-label">법인카드</label>
+            <div>
+              <p v-for="(item, idx) of cprCardList" :key="idx">
+                <span v-if="idx !== 0">, </span>
+                <span>{{ item.cardNm }}</span>
+              </p>
+            </div>
+          </div>
+          <div class="col-12">
+            <label class="form-label">법인차량</label>
+            <div>
+              <p v-for="(item, idx) of cprVhcleList" :key="idx">
+                <span v-if="idx !== 0">, </span>
+                <span>{{ item.vhcleNm }}</span>
+              </p>
+            </div>
+          </div>
+          <div class="col-12 border-x">
+            <label class="form-label">품의 신청일</label>
+            <p>{{ bsrpCnsul.rgsde }}</p>
+          </div>
+        </form>
       </div>
-      <div class="form-card">
+      <div v-if="!$isEmpty(bsrpRport.bsrpId)" class="form-card">
         <h1>출장복명서</h1>
-        <div class="approval-box tbl-wrap tbl2">
-         <table class="tbl data">
-          <tbody>
-            <tr class="thead">
-              <td rowspan="2" class="th">승인자</td>
-              <td>과장</td>
-              <td>소장</td>
-            </tr>
-            <tr>
-              <td><p class="name">홍길동</p><p class="date">2025/05/09</p></td>
-              <td><p class="name">홍길동</p><p class="date">2025/05/09</p></td>
-            </tr>
-          </tbody>
-
-         </table>
-        </div>
-          <form class="row g-3 needs-validation detail"  :class="{ 'was-validated': formSubmitted }" @submit.prevent="handleRegister" novalidate>
-               
-            <div class="col-12 chuljang">
-                  <label for="yourName" class="form-label">복명내용</label>
-                  <input v-model="name" type="text" name="name" class="form-control textarea " id="yourName" readonly>
-            </div>
-            <div class="col-12">
-                  <label for="yourName" class="form-label">여비계산</label>
-                  <input v-model="name" type="text" name="name" class="form-control " id="yourName" readonly>
-            </div>
-            <div class="col-12 ">
-                  <label for="yourName" class="form-label">복명 신청일</label>
-                  <input  v-model="name" type="text" name="name" class="form-control" id="yourName" readonly   placeholder="2025-01-01">
-            </div>
-            <div class="col-12 border-x return">
-                  <label for="yourName" class="form-label">반려사유</label>
-                  <input  v-model="name" type="text" name="name" class="form-control" readonly   placeholder="2025-01-01">
-            </div>
-           
-                
-              </form>
+        <SanctnViewList v-if="bsrpRport.sanctnList.length > 0" :sanctns="bsrpRport.sanctnList" />
+        <form class="row g-3 needs-validation detail" :class="{ 'was-validated': formSubmitted }" @submit.prevent="handleRegister" novalidate>
+          <div class="col-12">
+            <label class="form-label">복명내용</label>
+            <ViewerComponent :content="bsrpRport.cn" />
+          </div>
+          <div class="col-12">
+            <label class="form-label">여비계산</label>
+            <p>{{ bsrpInfo.applcntId }}</p>
+          </div>
+          <div class="col-12">
+            <label class="form-label">복명 신청일</label>
+            <p>{{ bsrpRport.rgsde }}</p>
+          </div>
+          <div class="col-12 border-x return">
+            <label class="form-label">반려사유</label>
+            <p>{{ bsrpInfo.applcntId }}</p>
+          </div>
+        </form>
       </div>
-            <div class="buttons">
-              <button class="btn btn-red "  type="submit">신청취소</button>
-              <button class="btn secondary"  type="submit">재신청</button>
-              <button class="btn secondary"  type="submit"> 수정</button>
-                <button class="btn tertiary "  type="submit">목록</button>
-              </div>
-
+      <div class="buttons">
+        <button v-if="sanctnStatus === 'waiting' && sanctnStatus !== 'approved'" type="button" class="btn btn-red" @click="deleteData">신청취소</button>
+        <button v-if="sanctnStatus === 'waiting'" type="button" class="btn secondary" @click="fnMoveTo('edit', pageId)">수정</button>
+        <button v-if="sanctnStatus === 'rejected'" type="button" class="btn secondary" @click="fnMoveTo('edit', pageId)">재신청</button>
+        <button v-if="sanctnStatus === 'approved'" type="button" class="btn primary" @click="fnMoveTo('plus', pageId)">복명서 작성</button>
+        <button type="button" class="btn tertiary" @click="fnMoveTo('list')">목록</button>
       </div>
     </div>
+  </div>
 </template>
-
 <script>
+import SanctnViewList from '../../../component/Sanctn/SanctnViewList.vue';
+import ViewerComponent from '../../../component/editor/ViewerComponent.vue';
+// API
+import { bsrpProc, deleteBsrpProc } from '../../../../resources/api/bsrp';
+
 export default {
+  components: {
+    SanctnViewList, ViewerComponent,
+  },
+
   data() {
-    const today = new Date().toISOString().split('T')[0];
     return {
-      isReturned: true,
-      startDate: today,
-      startTime: "09:00", // 기본 시작 시간 09:00
-      endDate: today,
-      endTime: "18:00", // 기본 종료 시간 18:00
-      category: "", 
-      dayCount: 1, 
-      reason: "", // 사유
-      listData: [
-  {
-    type: '연차',
-    approvalType: '결재',
-    applicant: '홍길동',
-    period: '2025-05-10 ~ 2025-15-03',
-    requestDate: '2025-04-25',
-    status: '대기'
-  },   {
-    type: '반차',
-    approvalType: '전결',
-    applicant: '홍길동',
-    period: '2025-05-01 ~ 2025-05-03',
-    requestDate: '2025-04-25',
-    status: '승인'
-  }],
+      pageId: null,
+
+      // 출장 정보
+      bsrpInfo: {
+        bsrpId: null,       // 출장 아이디
+        applcntId: null,    // 신청자 아이디
+        bsrpSe: null,       // 출장구분 (공통코드 : sanctn_mby_bsrp)
+        bsrpPlace: null,    // 출장지
+        bsrpPurps: null,    // 출장목적
+        bgnde: null,        // 시작일
+        beginHour: null,    // 시작시
+        beginMnt: null,     // 시작분
+        endde: null,        // 종료일
+        endHour: null,      // 종료시
+        endMnt: null,       // 종료분
+        bsrpSeNm: null,     // 출장구분 이름
+        bsrpNmprList: [],   // 출장 인원
+      },
+      // 품의서
+      bsrpCnsul: {
+        bsrpId: null,      // 출장 아이디
+        cn: null,          // 내용
+        confmAt: null,     // 승인 여부 (W: 대기, A: 승인, R 반려)
+        rgsde: null,       // 등록일
+        register: null,    // 등록자
+        updde: null,       // 수정일
+        updusr: null,      // 수정자
+        sanctnList: [],
+      },
+      // 복명서
+      bsrpRport: {
+        bsrpId: null,      // 출장 아이디
+        cn: null,          // 내용
+        confmAt: null,     // 승인 여부 (W: 대기, A: 승인, R 반려)
+        fileId: null,      // 파일 아이디
+        rgsde: null,       // 등록일
+        register: null,    // 등록자
+        updde: null,       // 수정일
+        updusr: null,      // 수정자
+        sanctnList: [],
+      },
+      // 신청자 정보
+      user: {},
     };
   },
-  computed: {
-    // Pinia Store의 상태를 가져옵니다.
-    loginUser() {
-      const authStore = useAuthStore();
-      return authStore.getLoginUser;
-    },
-  },
-  methods: {
-    // 폼 검증 메서드
-    validateForm() {
-      // 필수 입력 필드 체크
-      if (
-        this.category &&
-        this.startDate &&
-        this.startTime &&
-        this.endDate &&
-        this.endTime &&
-        this.dayCount > 0 &&
-        this.reason.trim() !== ""
-      ) {
-        this.isFormValid = true;
-      } else {
-        this.isFormValid = false;
-      }
-    },
-    calculateDayCount() {
-    const start = new Date(`${this.startDate}T${this.startTime}:00`);
-    const end = new Date(`${this.endDate}T${this.endTime}:00`);
-    
-    let totalHours = (end - start) / (1000 * 60 * 60);  // 밀리초를 시간 단위로 변환
-    
-    if (this.startDate !== this.endDate) {
-      // 시작일과 종료일이 다른경우
-      const startDateObj = new Date(this.startDate);
-      const endDateObj = new Date(this.endDate);
-      const daysDifference = (endDateObj - startDateObj) / (1000 * 60 * 60 * 24); // 두 날짜 사이의 차이를 일수로 계산
-      if (this.startTime !== "09:00" || this.endTime !== "18:00") {
-        this.dayCount = daysDifference + 0.5; // 시간 조건이 기준에서 벗어날 경우
-      } else {
-        this.dayCount = Math.ceil(daysDifference + 1); // 시간 조건이 기준에 맞을 경우
-      }
-    } else {
-      // 시작일과 종료일이 같은 경우
-      if (this.startTime !== "09:00" || this.endTime !== "18:00") {
-        this.dayCount = 0.5; // 시작 시간 또는 종료 시간이 기준과 다를 경우 0.5
-      } else {
-        this.dayCount = 1; // 기준 시간(09:00~18:00)이 맞으면 1일로 간주
-      }
-    }
 
-    this.validateForm(); // dayCount 변경 후 폼 재검증
+  computed: {
+    // 결재 상태 확인
+    sanctnStatus() {
+      const sanctnList = this.bsrpCnsul.sanctnList;
+
+      if (sanctnList.length === 0) return 'none'; // 결재 정보 없음
+
+      // 하나라도 반려가 있으면 '반려'
+      if (sanctnList.some(item => item.sanctnSttus === 'R')) {
+        return 'rejected';
+      }
+
+      // 모든 결재가 승인이면 '승인'
+      if (sanctnList.every(item => item.sanctnSttus === 'A')) {
+        return 'approved';
+      }
+
+      // 그 외에는 '대기'
+      return 'waiting';
+    }
   },
-    handleSubmit() {
-      this.validateForm(); // 제출 시 유효성 확인
-      if (this.isFormValid) {
-        localStorage.setItem('HyugaFormData', JSON.stringify(this.$data));
-        alert("승인 요청이 완료되었습니다.");
-        // 추가 처리 로직 (API 요청 등)
-      } else {
-        alert("모든 필드를 올바르게 작성해주세요.");
+
+  async created() {
+    this.pageId = this.$route.query.id;
+    if (this.$isEmpty(this.pageId)) {
+      alert("게시물이 존재하지 않습니다.");
+      this.fnMoveTo('list');
+    }
+  },
+
+  mounted() {
+    this.findDatas(); // 상세 조회
+  },
+
+  methods: {
+    // 상세 조회
+    async findDatas() {
+      try {
+        const response = await bsrpProc(this.pageId);
+        const result = response.data.data;
+
+        this.bsrpInfo = result.bsrpInfo;
+        this.bsrpInfo.bgnde = this.bsrpInfo.bgnde.split(' ')[0];
+        this.bsrpInfo.endde = this.bsrpInfo.endde.split(' ')[0];
+
+        this.cprCardList = result.cprCardList;
+        this.cprVhcleList = result.cprVhcleList;
+        this.user = result.user;
+
+        this.bsrpCnsul = result.bsrpCnsul;
+        this.bsrpRport = result.bsrpRport;
+      } catch (error) {
+        const message = error.response.data.message;
+        alert(message);
       }
     },
-    
-    
+
+    // 삭제
+    async deleteData() {
+      const isCheck = confirm("삭제하시겠습니까?");
+      if (!isCheck) {
+        return;
+      }
+
+      try {
+        const response = await deleteBsrpProc(this.pageId);
+
+        this.fnMoveTo('list');
+      } catch (error) {
+        if (error.response) {
+          alert(error.response.data.message);
+        } else {
+          alert("에러가 발생했습니다.");
+        }
+        console.error(error.message);
+        this.fnMoveTo('list');
+      }
+    },
+
+    // 페이지 이동
+    fnMoveTo(type, id) {
+      const routes = {
+        'list': { name: 'ChuljangStatue' },
+        'view': { name: 'ChuljangDetailAll', query: { id } },
+        'edit': { name: 'ChuljangInsert', query: this.$isEmpty(id) ? {} : { id } },
+        'plus': { name: 'ChuljangInsert', query: this.$isEmpty(id) ? {} : { id } },
+      };
+
+      if (routes[type]) {
+        if (!this.$isEmpty(this.pageId) && type === 'list') {
+          this.$router.push({ name: 'ChuljangDetailAll', query: { id: this.pageId } });
+        }
+        this.$router.push(routes[type]);
+      } else {
+        alert("올바르지 않은 경로를 요청하여 목록으로 이동합니다.");
+        this.$router.push(routes['list']);
+      }
+    },
   },
 };
 </script>
client/views/pages/Manager/attendance/ChuljangInsert.vue
--- client/views/pages/Manager/attendance/ChuljangInsert.vue
+++ client/views/pages/Manager/attendance/ChuljangInsert.vue
@@ -3,122 +3,94 @@
     <div class="card-body">
       <h2 class="card-title">출장 신청</h2>
       <p class="require"><img :src="require" alt=""> 필수입력</p>
-      <!-- Multi Columns Form -->
       <form class="row g-3 pt-3  needs-validation" @submit.prevent="handleSubmit">
-
-
         <div class="col-12">
-          <label for="where" class="form-label"><p>출장구분<p class="require"><img :src="require" alt=""></p></p></label>
-          <select class="form-select"  style="width: 110px;">
-                <option value="" selected>국내</option>
-                <option value="">국외</option>
-              </select>
+          <label for="where" class="form-label">
+            <p>출장구분 <span class="require"><img :src="require" alt=""></span></p>
+          </label>
+          <select class="form-select" style="width: 110px;" v-model="bsrpInfo.bsrpSe">
+            <option v-for="(item, idx) of cmmnCodes.bsrpCodeList" :key="idx" :value="item.code">{{ item.codeNm }}</option>
+          </select>
         </div>
         <div class="col-12">
-          <label for="where" class="form-label"><p>출장지<p class="require"><img :src="require" alt=""></p></p></label>
-          <input type="text" class="form-control" id="where" v-model="where" />
+          <label for="bsrpInfo.bsrpPlace" class="form-label">
+            <p>출장지 <span class="require"><img :src="require" alt=""></span></p>
+          </label>
+          <input type="text" class="form-control" id="bsrpInfo.bsrpPlace" v-model="bsrpInfo.bsrpPlace" />
         </div>
         <div class="col-12">
-          <label for="where" class="form-label"><p>출장목적<p class="require"><img :src="require" alt=""></p></p></label>
-          <input type="text" class="form-control" id="where" v-model="where" />
+          <label for="bsrpInfo.bsrpPurps" class="form-label">
+            <p>출장목적 <span class="require"><img :src="require" alt=""></span></p>
+          </label>
+          <input type="text" class="form-control" id="bsrpInfo.bsrpPurps" v-model="bsrpInfo.bsrpPurps" />
         </div>
         <div class="col-12">
-          <label for="where" class="form-label"><p>출장기간<p class="require"><img :src="require" alt=""></p></p></label>
+          <label for="where" class="form-label">
+            <p>출장기간 <span class="require"><img :src="require" alt=""></span></p>
+          </label>
           <div class="d-flex gap-1">
-            <input type="date" class="form-control" id="startDate" v-model="startDate" />
-            <!-- 시간 선택을 위한 select 사용 -->
-            <select class="form-control" id="startTime" v-model="startTime">
-              <option value="09:00">09:00</option>
-              <option value="10:00">10:00</option>
-              <option value="11:00">11:00</option>
-              <option value="12:00">12:00</option>
-              <option value="13:00">13:00</option>
-              <option value="14:00">14:00</option>
-              <option value="15:00">15:00</option>
-              <option value="16:00">16:00</option>
-              <option value="17:00">17:00</option>
-              <option value="18:00">18:00</option>
-            </select>
-            ~
+            <input type="date" class="form-control" id="bsrpInfo.bgnde" v-model="bsrpInfo.bgnde" />
+            <input type="text" class="form-control" id="bsrpInfo.beginHour" v-model="bsrpInfo.beginHour" style="width: 100px;" placeholder="시" />
+            <input type="text" class="form-control" id="bsrpInfo.beginMnt" v-model="bsrpInfo.beginMnt" style="width: 100px;" placeholder="분" />
           </div>
           <div class="d-flex gap-1">
-            <input type="date" class="form-control" id="endDate" v-model="endDate" />
-            <!-- 종료 시간을 위한 select 사용 -->
-            <select class="form-control" id="endTime" v-model="endTime">
-              <option value="09:00">09:00</option>
-              <option value="10:00">10:00</option>
-              <option value="11:00">11:00</option>
-              <option value="12:00">12:00</option>
-              <option value="13:00">13:00</option>
-              <option value="14:00">14:00</option>
-              <option value="15:00">15:00</option>
-              <option value="16:00">16:00</option>
-              <option value="17:00">17:00</option>
-              <option value="18:00">18:00</option>
-            </select>
+            <input type="date" class="form-control" id="bsrpInfo.endde" v-model="bsrpInfo.endde" />
+            <input type="text" class="form-control" id="bsrpInfo.endHour" v-model="bsrpInfo.endHour" style="width: 100px;" placeholder="시" />
+            <input type="text" class="form-control" id="bsrpInfo.endMnt" v-model="bsrpInfo.endMnt" style="width: 100px;" placeholder="분" />
           </div>
-          <div class="col-12 border-x">
-          <label for="dayCount" class="form-label">일수</label>
-          <input type="text" class="form-control" id="dayCount" v-model="dayCount" readonly />
         </div>
-        </div>
-
         <div class="col-12">
-          <label for="purpose" class="form-label">동행자 <button type="button" title="추가" @click="showPopup1 = true">
+          <label for="totalDays" class="form-label">일수</label>
+          <input type="text" class="form-control" id="totalDays" v-model="totalDays" readonly />
+        </div>
+        <div class="col-12">
+          <label for="purpose" class="form-label">동행자 <button type="button" title="추가" @click="isOpenNmprModal = true">
               <PlusCircleFilled />
-            </button></label>
-            <HrPopup v-if="showPopup1" @close="showPopup1 = false" @select="addMember"/>
-            <div v-for="(member, index) in members" :key="index" class="d-flex gap-2 addapproval mb-2">
-
-              <form class="d-flex align-items-center border-x">
-                <input type="text" class="form-control" v-model="member.name" style="max-width: 150px;" />
-                <button type="button" @click="removeMember(index)" class="delete-button">
+            </button>
+          </label>
+          <HrPopup v-if="isOpenNmprModal" :lists="bsrpInfo.bsrpNmprList" @onSelected="fnAddNmpr" @close="isOpenNmprModal = false" />
+          <div class="approval-container">
+            <div v-for="(item, idx) of bsrpInfo.bsrpNmprList" :key="idx" class="d-flex addapproval">
+              <div class="d-flex align-items-center border-x">
+                <p>{{ item.triperNm }} {{ item.clsfNm }}</p>
+                <button type="button" @click="fnDelNmpr(idx)" @mousedown.stop>
                   <CloseOutlined />
                 </button>
-              </form>
+              </div>
             </div>
+          </div>
         </div>
-       
         <div class="col-12">
           <label for="member" class="form-label">
-            <p>승인자<button type="button" title="추가" @click="showPopup = true">
+            <p>승인자 <span class="require"><img :src="require" alt=""></span></p>
+            <button type="button" title="추가" @click="isOpenSanctnModal = true">
               <PlusCircleFilled />
-            </button><p class="require"><img :src="require" alt=""></p></p>
-            
+            </button>
           </label>
-          <HrPopup v-if="showPopup" @close="showPopup = false" @select="addApproval"/>
+          <HrPopup v-if="isOpenSanctnModal" :lists="bsrpCnsul.sanctnList" @onSelected="fnAddSanctn" @close="isOpenSanctnModal = false" />
           <div class="approval-container">
-            <div v-for="(approval, index) in approvals" :key="index" class="d-flex gap-2 addapproval mb-2">
-              <select class="form-select" v-model="approval.category" style="width: 110px;">
-                <option value="결재">결재</option>
-                <option value="전결">전결</option>
-                <option value="대결">대결</option>
-              </select>
-
-              <form class="d-flex align-items-center border-x">
-                <input type="text" class="form-control" v-model="approval.name" style="max-width: 150px;" />
-                <button type="button" @click="removeApproval(index)" class="delete-button">
-                  <CloseOutlined />
-                </button>
-              </form>
-            </div>
+            <SanctnList v-model:lists="bsrpCnsul.sanctnList" @delSanctn="fnDelSanctn" />
           </div>
         </div>
-        <div class="col-12 chuljang">
-          <label for="prvonsh" class="form-label"><p>품의내용<p class="require"><img :src="require" alt=""></p></p></label>
-          <input type="text" class="form-control textarea" id="reason" v-model="reason" />
+        <div class="col-12">
+          <label for="prvonsh" class="form-label">
+            <p>품의내용 <span class="require"><img :src="require" alt=""></span></p>
+          </label>
+          <EditorComponent v-model:contents="bsrpCnsul.cn" />
         </div>
         <div class="col-12">
-          <label for="purpose" class="form-label">법인카드 <button type="button" title="추가" @click="showPopup3 = true">
+          <label for="purpose" class="form-label">
+            <span>법인카드</span>
+            <button type="button" title="추가" @click="isOpenCardModal = true">
               <PlusCircleFilled />
-            </button></label>
-            <CorpCardPopup v-if="showPopup3" @close="showPopup3 = false" @select="addCard"/>
-            <div class="approval-container">
-            <div v-for="(card, index) in cards" :key="index" class="d-flex gap-2 addapproval mb-2">
-
+            </button>
+          </label>
+          <CorpCardPopup v-if="isOpenCardModal" :bsrpInfo="bsrpInfo" :lists="cprCardList" @close="isOpenCardModal = false" @onSelected="fnAddCard" />
+          <div class="approval-container">
+            <div v-for="(card, idx) in cprCardList" :key="idx" class="d-flex gap-2 addapproval mb-2">
               <form class="d-flex align-items-center border-x">
-                <input type="text" class="form-control" v-model="card.name" style="max-width: 150px;" />
-                <button type="button" @click="removeCard(index)" class="delete-button">
+                <p>{{ card.cardNm }}</p>
+                <button type="button" @click="fnDelCard(idx)" class="delete-button">
                   <CloseOutlined />
                 </button>
               </form>
@@ -126,215 +98,316 @@
           </div>
         </div>
         <div class="col-12 border-x">
-          <label for="purpose" class="form-label">법인차량 <button type="button" title="추가" @click="showPopup2 = true">
+          <label for="purpose" class="form-label">
+            <span>법인차량</span>
+            <button type="button" title="추가" @click="isOpenVhcleModal = true">
               <PlusCircleFilled />
-            </button></label>
-            <CorpCarPopup v-if="showPopup2" @close="showPopup2 = false" @select="addCar"/>
-            <div class="approval-container">
-            <div v-for="(car, index) in cars" :key="index" class="d-flex gap-2 addapproval mb-2">
-              <input type="text" class="form-control" v-model="car.name" style="max-width: 150px;" />
-              <select class="form-select" v-model="car.category" style="width: 120px;">
-                <option value="운전자">운전자</option>
+            </button>
+          </label>
+          <CorpCarPopup v-if="isOpenVhcleModal" :bsrpInfo="bsrpInfo" :lists="cprVhcleList" @close="isOpenVhcleModal = false" @onSelected="fnAddVhcle" />
+          <div class="approval-container">
+            <div v-for="(vhcle, idx) in cprVhcleList" :key="idx" class="d-flex gap-2 addapproval mb-2">
+              <p>{{ vhcle.vhcleNm }}</p>
+              <select class="form-select" v-model="vhcle.drverId">
+                <option value="" disabled hidden>운전자 선택</option>
+                <option :value="userInfo.userId">{{ userInfo.userNm }}</option>
+                <option v-for="(item, idx) of bsrpInfo.bsrpNmprList" :key="idx" :value="item.userId">{{ item.userNm }}</option>
               </select>
-              <button type="button" @click="removeCar(index)" class="delete-button">
-                  <CloseOutlined />
-                </button>
+              <button type="button" @click="fnDelVhcle(idx)" class="delete-button">
+                <CloseOutlined />
+              </button>
             </div>
           </div>
         </div>
-
       </form>
       <div class="buttons">
-        <button type="submit" class="btn primary">신청</button>
-        <button type="reset" class="btn secondary">취소</button>
+        <button type="button" class="btn primary" @click="fnSave">신청</button>
+        <button v-if="$isEmpty(pageId)" type="button" class="btn secondary" @click="fnMoveTo('list')">목록</button>
+        <button v-else type="button" class="btn secondary" @click="fnMoveTo('view', pageId)">취소</button>
       </div>
-
     </div>
   </div>
 </template>
-
 <script>
 import { PlusCircleFilled, CloseOutlined } from '@ant-design/icons-vue';
 import HrPopup from '../../../component/Popup/HrPopup.vue';
 import CorpCarPopup from '../../../component/Popup/CorpCarPopup.vue';
 import CorpCardPopup from '../../../component/Popup/CorpCardPopup.vue';
+import SanctnList from '../../../component/Sanctn/SanctnFormList.vue';
+import EditorComponent from '../../../component/editor/EditorComponent.vue';
+// API
+import { saveBsrpProc, bsrpProc, updateBsrpProc } from '../../../../resources/api/bsrp';
+
 export default {
+  components: {
+    PlusCircleFilled, CloseOutlined,
+    HrPopup, CorpCarPopup, CorpCardPopup,
+    SanctnList, EditorComponent,
+  },
+
   data() {
-    const today = new Date().toISOString().split('T')[0];
     return {
-      showPopup: false,
-      showPopup1: false,
-      showPopup2: false,
-      showPopup3: false,
       require: "/client/resources/img/require.png",
-      fileName: '',
-      startDate: today,
-      startTime: '09:00',
-      endDate: today,
-      endTime: '18:00',
-      where: '',
-      purpose: '',
-      approvals: [        
-      ],
-      members: [        
-      ],
-      cards: [
-      ],
-      cars: [
-      ],
-     receipts: [
-        {
-          type: '개인결제',
-          category: '결재',
-          category1: '구분',
-        },
-      ],
+
+      pageId: null,
+      userInfo: this.$store.state.userInfo,
+      cmmnCodes: {},
+
+      isOpenNmprModal: false,
+      isOpenSanctnModal: false,
+      isOpenCardModal: false,
+      isOpenVhcleModal: false,
+
+      // 출장정보
+      bsrpInfo: {
+        applcntId: null,  // 신청자 아이디
+        bsrpSe: null,     // 출장구분
+        bsrpPlace: null,  // 출장지
+        bsrpPurps: null,  // 출장목적
+        bgnde: null,      // 시작일
+        beginHour: null,  // 시작시
+        beginMnt: null,   // 시작분
+        endde: null,      // 종료일
+        endHour: null,    // 종료시
+        endMnt: null,     // 종료분
+        bsrpNmprList: [], // 출장인원 목록
+      },
+      // 출장품의
+      bsrpCnsul: {
+        bsrpId: null,     // 출장 아이디
+        cn: null,         // 품의 내용
+        confmAt: null,    // 승인여부
+        rgsde: null,      // 등록일
+        register: null,   // 등록자
+        updde: null,      // 수정일
+        updusr: null,     // 수정자
+        sanctnList: [],   // 결재 목록
+      },
+      cprCardList: [],    // 법인카드 목록
+      cprVhcleList: [],   // 법인차량 목록
+
+      totalDays: 0, // 일수
     };
   },
-  components: {
-    PlusCircleFilled, CloseOutlined, HrPopup, CorpCarPopup, CorpCardPopup
-  },
-  computed: {
-    loginUser() {
-      const authStore = useAuthStore();
-      return authStore.getLoginUser;
+
+  computed: {},
+
+  watch: {
+    cmmnCodes(newVal) {
+      if (Object.keys(newVal).length > 0) {
+        this.bsrpInfo.bsrpSe = this.cmmnCodes.bsrpCodeList[0].code;
+      }
     },
+    'bsrpInfo.bgnde'(newVal, oldVal) {
+      if (newVal !== oldVal) {
+        this.calcDayCnt(); // 일수 계산
+      }
+    },
+    'bsrpInfo.endde'(newVal, oldVal) {
+      if (newVal !== oldVal) {
+        this.calcDayCnt(); // 일수 계산
+      }
+    },
+  },
+
+  async created() {
+    this.pageId = this.$route.query.id;
+    this.cmmnCodes = await this.$defaultCodes();
+  },
+
+  mounted() {
+    if (!this.$isEmpty(this.pageId)) {
+      this.findData();
+    }
   },
 
   methods: {
-    handleFileUpload(event) {
-      const file = event.target.files[0];
-      if (file) {
-        this.fileName = file.name;
+    // 상세 조회
+    async findData() {
+      try {
+        const response = await bsrpProc(this.pageId);
+        const result = response.data.data;
+
+        this.bsrpInfo = result.bsrpInfo;
+        this.bsrpInfo.bgnde = this.bsrpInfo.bgnde.split(' ')[0];
+        this.bsrpInfo.endde = this.bsrpInfo.endde.split(' ')[0];
+
+        this.bsrpCnsul = result.bsrpCnsul;
+        this.cprCardList = result.cprCardList;
+        this.cprVhcleList = result.cprVhcleList;
+      } catch (error) {
+        console.error('데이터 조회 실패:', error);
+        alert(error.response.data.message);
+
+        this.fnMoveTo('list');
       }
     },
-    addApproval(selectedUser) {
-      this.approvals.push({
-        category: '결재',
-        name: selectedUser.name, // or other fields if needed
-      });
-      this.showPopup = false; // 팝업 닫기
+
+    // 일수 계산
+    calcDayCnt() {
+      if (!this.bsrpInfo.bgnde || !this.bsrpInfo.endde) {
+        this.totalDays = 0;
+        return;
+      }
+
+      const startDate = new Date(this.bsrpInfo.bgnde);
+      const endDate = new Date(this.bsrpInfo.endde);
+
+      if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
+        this.totalDays = 0;
+        return;
+      }
+
+      const timeDiff = endDate.getTime() - startDate.getTime();
+      const dayDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24)) + 1;
+
+      this.totalDays = Math.max(0, dayDiff);
     },
-    addMember(selectedUser) {
-      this.members.push({
-        category: '결재',
-        name: selectedUser.name, // or other fields if needed
-      });
-      this.showPopup1 = false; // 팝업 닫기
+
+    // 동행자 추가
+    fnAddNmpr(user) {
+      const data = {
+        triperId: user.userId,  // 출장자 아이디
+        deptId: user.deptId,    // 부서 아이디
+        clsf: user.clsf,        // 직급
+
+        triperNm: user.userNm,  // 출장자 이름
+        deptNm: user.deptNm,    // 부서 이름
+        clsfNm: user.clsfNm,    // 직급 이름
+      };
+
+      this.bsrpInfo.bsrpNmprList.push(data);
+      this.isOpenNmprModal = false;
     },
-    addCard(selectedCard) {
-      this.cards.push({
-        category: '결재',
-        name: selectedCard.name, // or other fields if needed
-      });
-      this.showPopup3 = false; // 팝업 닫기
+
+    // 동행자 삭제
+    fnDelNmpr(idx) {
+      this.bsrpInfo.bsrpNmprList.splice(idx, 1);
     },
-    addCar(selectedCar) {
-      this.cars.push({
-        category: '결재',
-        name: selectedCar.name, // or other fields if needed
-      });
-      this.showPopup2 = false; // 팝업 닫기
+
+    // 승인자 추가
+    fnAddSanctn(user) {
+      const data = {
+        sanctnId: null,                                   // 결재 아이디
+        confmerId: user.userId,                           // 승인자 아이디
+        clsf: user.clsf,                                  // 직급
+        sanctnOrdr: this.bsrpCnsul.sanctnList.length + 1, // 결재 순서
+        sanctnIem: 'cnsul',                               // 결재 항목
+        sanctnMbyId: null,                                // 결재 주체 아이디
+        sanctnSe: this.cmmnCodes.sanctnCodeList[0].code,  // 결재구분
+
+        confmerNm: user.userNm,                           // 승인자 이름
+        clsfNm: user.clsfNm,                              // 직급 이름
+      };
+
+      this.bsrpCnsul.sanctnList.push(data);
+      this.isOpenSanctnModal = false;
     },
-    addReceipt() {
-  this.receipts.push({
-    type: '개인결제',
-    category: '결재',
-    category1: '',
-    name: '',
-    file: null,
-  });
-},
+
     // 승인자 삭제
-    removeApproval(index) {
-      this.approvals.splice(index, 1);
+    fnDelSanctn(idx) {
+      this.bsrpInfo.sanctnList.splice(idx, 1);
+      this.bsrpInfo.sanctnList.forEach((item, idx) => { item.sanctnOrdr = idx + 1; });
     },
-    removeMember(index) {
-      this.members.splice(index, 1);
+
+    // 법인카드 추가
+    fnAddCard(item) {
+      this.cprCardList.push(item);
+      this.isOpenCardModal = false;
     },
-    removeCard(index) {
-      this.cards.splice(index, 1);
+
+    // 법인카드 삭제
+    fnDelCard(idx) {
+      this.cprCardList.splice(idx, 1);
     },
-    removeCar(index) {
-      this.cars.splice(index, 1);
+
+    // 법인차량 추가
+    fnAddVhcle(item) {
+      item.drverId = '';
+      this.cprVhcleList.push(item);
+      this.isOpenVhcleModal = false;
     },
-    removeReceipt(index) {
-  this.receipts.splice(index, 1);
-},
+
+    // 법인차량 삭제
+    fnDelVhcle(idx) {
+      this.cprVhcleList.splice(idx, 1);
+    },
+
+    // 유효성 검사
     validateForm() {
-      // 필수 입력 필드 체크
-      if (
-        this.startDate &&
-        this.startTime &&
-        this.endDate &&
-        this.endTime &&
-        this.where &&
-        this.purpose.trim() !== ""
-      ) {
-        this.isFormValid = true;
-      } else {
-        this.isFormValid = false;
+      if (this.$isEmpty(this.bsrpInfo.bsrpSe)) {
+        return false;
       }
+      if (this.$isEmpty(this.bsrpInfo.bsrpPlace)) {
+        return false;
+      }
+      if (this.$isEmpty(this.bsrpInfo.bsrpPurps)) {
+        return false;
+      }
+      if (this.$isEmpty(this.bsrpInfo.bgnde) || this.$isEmpty(this.bsrpInfo.beginHour) || this.$isEmpty(this.bsrpInfo.beginMnt)) {
+        return false;
+      }
+      if (this.$isEmpty(this.bsrpInfo.endde) || this.$isEmpty(this.bsrpInfo.endHour) || this.$isEmpty(this.bsrpInfo.endMnt)) {
+        return false;
+      }
+      if (this.$isEmpty(this.bsrpInfo.bsrpNmprList) || this.bsrpInfo.bsrpNmprList.length === 0) {
+        return false;
+      }
+      if (this.$isEmpty(this.bsrpCnsul.cn)) {
+        return false;
+      }
+
+      return true;
     },
-    calculateDayCount() {
-      const start = new Date(`${this.startDate}T${this.startTime}:00`);
-      const end = new Date(`${this.endDate}T${this.endTime}:00`);
 
-      let totalHours = (end - start) / (1000 * 60 * 60);  // 밀리초를 시간 단위로 변환
-
-      if (this.startDate !== this.endDate) {
-        // 시작일과 종료일이 다른경우
-        const startDateObj = new Date(this.startDate);
-        const endDateObj = new Date(this.endDate);
-        const daysDifference = (endDateObj - startDateObj) / (1000 * 60 * 60 * 24); // 두 날짜 사이의 차이를 일수로 계산
-        if (this.startTime !== "09:00" || this.endTime !== "18:00") {
-          this.dayCount = daysDifference + 0.5; // 시간 조건이 기준에서 벗어날 경우
-        } else {
-          this.dayCount = Math.ceil(daysDifference + 1); // 시간 조건이 기준에 맞을 경우
+    // 신청
+    async fnSave() {
+      try {
+        if (!this.validateForm()) {
+          return;
         }
-      } else {
-        // 시작일과 종료일이 같은 경우
-        if (this.startTime !== "09:00" || this.endTime !== "18:00") {
-          this.dayCount = 0.5; // 시작 시간 또는 종료 시간이 기준과 다를 경우 0.5
-        } else {
-          this.dayCount = 1; // 기준 시간(09:00~18:00)이 맞으면 1일로 간주
-        }
-      }
 
-      this.validateForm(); // dayCount 변경 후 폼 재검증
+        let data = {
+          bsrpCnsulInsertDTO: this.bsrpCnsul,
+          cardDtlsList: this.cprCardList,
+          vhcleDtlsList: this.cprVhcleList,
+        }
+        if (this.$isEmpty(this.pageId)) {
+          data.bsrpInfoInsertDTO = this.bsrpInfo;
+        } else {
+          data.bsrpInfoUpdateDTO = this.bsrpInfo;
+        }
+
+        const response = this.$isEmpty(this.pageId) ? await saveBsrpProc(data) : await updateBsrpProc(data);
+        const message = this.$isEmpty(this.pageId) ? "등록되었습니다." : "수정되었습니다.";
+        alert(message);
+
+        this.fnMoveTo('view', response.data.data.pageId);
+      } catch (error) {
+        console.error('저장 실패:', error);
+        const message = error.response?.data?.message || "저장에 실패했습니다.";
+        alert(message);
+      }
     },
-    handleSubmit() {
-      this.validateForm(); // 제출 시 유효성 확인
-      if (this.isFormValid) {
-        localStorage.setItem('ChuljangFormData', JSON.stringify(this.$data));
-        alert("승인 요청이 완료되었습니다.");
-        // 추가 처리 로직 (API 요청 등)
+
+    fnMoveTo(type, id) {
+      const routes = {
+        'list': { name: 'ChuljangStatue' },
+        'view': { name: 'ChuljangDetailAll', query: { id } },
+        'edit': { name: 'ChuljangInsert', query: this.$isEmpty(id) ? {} : { id } },
+      };
+
+      if (routes[type]) {
+        if (!this.$isEmpty(this.pageId) && type === 'list') {
+          this.$router.push({ name: 'ChuljangDetailAll', query: { id: this.pageId } });
+          return;
+        }
+        this.$router.push(routes[type]);
       } else {
-        alert("모든 필드를 올바르게 작성해주세요.");
+        alert("올바르지 않은 경로를 요청하여 목록으로 이동합니다.");
+        this.$router.push(routes['list']);
       }
     },
-    loadFormData() {
-      const savedData = localStorage.getItem('ChuljangFormData');
-      if (savedData) {
-        this.$data = JSON.parse(savedData);
-      }
-    },
-  },
-  mounted() {
-    // Load the saved form data when the page is loaded
-    this.loadFormData();
-  },
-  watch: {
-    startDate: 'calculateDayCount',
-    startTime: 'calculateDayCount',
-    endDate: 'calculateDayCount',
-    endTime: 'calculateDayCount',
-    where: 'validateForm',
-    purpose: "validateForm",
   },
 };
-</script>
-
-<style scoped>
-/* 필요한 스타일 추가 */
-</style>
+</script>
(파일 끝에 줄바꿈 문자 없음)
 
client/views/pages/Manager/attendance/ChuljangPumuiDetail.vue (deleted)
--- client/views/pages/Manager/attendance/ChuljangPumuiDetail.vue
@@ -1,186 +0,0 @@
-<template>
-  <div class="card ">
-    <div class="card-body">
-      <h2 class="card-title">출장 현황</h2>
-
-      <div class="form-card">
-        <h1>출장품의서</h1>
-        <div class="approval-box tbl-wrap tbl2">
-          <table class="tbl data">
-            <tbody>
-              <tr class="thead">
-                <td rowspan="2" class="th">승인자</td>
-                <td v-for="(approver, index) in approvers" :key="index">
-                  <p class="position">{{ approver.position }}</p>
-                </td>
-              </tr>
-              <tr>
-                <td v-for="(approver, index) in approvers" :key="index">
-                  <p class="name">{{ approver.name }}</p>
-                  <p class="date">{{ approver.date }}</p>
-                </td>
-              </tr>
-
-            </tbody>
-
-          </table>
-        </div>
-        <form class="row g-3 needs-validation detail" :class="{ 'was-validated': formSubmitted }"
-          @submit.prevent="handleRegister" novalidate>
-          <div class="col-12 ">
-            <div class="col-12 border-x">
-              <label for="youremail" class="form-label ">출장구분<p class="require"><img :src="require" alt=""></p></label>
-              <input v-model="email" type="text" name="username" class="form-control" id="youremail" readonly>
-            </div>
-
-            <div class="col-12 border-x">
-              <label for="yourPassword" class="form-label">이름</label>
-              <input v-model="password" type="password" name="password" class="form-control" readonly
-                placeholder="주식회사 테이큰 소프트">
-            </div>
-          </div>
-          <div class="col-12">
-            <div class="col-12 border-x">
-              <label for="youremail" class="form-label">부서</label>
-              <input v-model="email" type="text" name="username" class="form-control" readonly placeholder="과장">
-            </div>
-
-            <div class="col-12 border-x">
-              <label for="yourPassword" class="form-label">직급</label>
-              <input v-model="password" type="password" name="password" class="form-control" readonly placeholder="팀장">
-            </div>
-          </div>
-          <div class="col-12">
-            <label for="yourName" class="form-label">출장지</label>
-            <input v-model="name" type="text" name="name" class="form-control" readonly>
-          </div>
-          <div class="col-12">
-            <label for="yourName" class="form-label">출장목적</label>
-            <input v-model="name" type="text" name="name" class="form-control " readonly>
-          </div>
-          <div class="col-12">
-            <label for="yourName" class="form-label">동행자</label>
-            <input v-model="name" type="text" name="name" class="form-control " readonly>
-          </div>
-          <div class="col-12 chuljang">
-            <label for="yourName" class="form-label">내용</label>
-            <input v-model="name" type="text" name="name" class="form-control textarea " readonly>
-          </div>
-          <div class="col-12">
-            <label for="yourName" class="form-label">법인카드</label>
-            <input v-model="name" type="text" name="name" class="form-control " readonly>
-          </div>
-          <div class="col-12">
-            <label for="yourName" class="form-label">법인차량</label>
-            <input v-model="name" type="text" name="name" class="form-control " readonly>
-          </div>
-          <div class="col-12">
-            <label for="yourName" class="form-label">품의 신청일</label>
-            <input v-model="name" type="text" name="name" class="form-control " readonly>
-          </div>
-          <div class="col-12 border-x return">
-            <label for="yourName" class="form-label">반려사유</label>
-            <input v-model="name" type="text" name="name" class="form-control" readonly placeholder="2025-01-01">
-          </div>
-
-
-        </form>
-      </div>
-      <div class="buttons">
-        <button class="btn  btn-red" type="submit">신청취소</button>
-        <button class="btn secondary" type="submit">재신청</button>
-        <button class="btn secondary" type="submit">수정</button>
-        <button v-if="hasAnyApprover" class="btn primary" type="submit" @click="goToBokmyeongInsert">
-          복명서 작성
-        </button>
-        <button class="btn tertiary " type="submit">목록</button>
-      </div>
-
-    </div>
-  </div>
-</template>
-
-<script>
-export default {
-  data() {
-    const today = new Date().toISOString().split('T')[0];
-    return {
-      showPopup: false,
-      startDate: today,
-      startTime: "09:00", // 기본 시작 시간 09:00
-      endDate: today,
-      endTime: "18:00", // 기본 종료 시간 18:00
-      category: "",
-      dayCount: 1,
-      reason: "", // 사유
-      approvers: [
-        { position: '', name: '', date: '' },
-        { position: '', name: '', date: '' },
-      ],
-      listData: [
-        {
-          type: '연차',
-          approvalType: '결재',
-          applicant: '홍길동',
-          period: '2025-05-10 ~ 2025-15-03',
-          requestDate: '2025-04-25',
-          status: '대기'
-        }, {
-          type: '반차',
-          approvalType: '전결',
-          applicant: '홍길동',
-          period: '2025-05-01 ~ 2025-05-03',
-          requestDate: '2025-04-25',
-          status: '승인'
-        }],
-    };
-  },
-  computed: {
-  },
-  methods: {
-    goToBokmyeongInsert() {
-    this.$router.push({ name: 'BokmyeongInsert' });
-  },
-    hasAnyApprover() {
-      return this.approvers.some(
-        (approver) =>
-          approver.name?.trim() !== '' && approver.date?.trim() !== ''
-      );
-    },
-    calculateDayCount() {
-      const start = new Date(`${this.startDate}T${this.startTime}:00`);
-      const end = new Date(`${this.endDate}T${this.endTime}:00`);
-
-      let totalHours = (end - start) / (1000 * 60 * 60);  // 밀리초를 시간 단위로 변환
-
-      if (this.startDate !== this.endDate) {
-        // 시작일과 종료일이 다른경우
-        const startDateObj = new Date(this.startDate);
-        const endDateObj = new Date(this.endDate);
-        const daysDifference = (endDateObj - startDateObj) / (1000 * 60 * 60 * 24); // 두 날짜 사이의 차이를 일수로 계산
-        if (this.startTime !== "09:00" || this.endTime !== "18:00") {
-          this.dayCount = daysDifference + 0.5; // 시간 조건이 기준에서 벗어날 경우
-        } else {
-          this.dayCount = Math.ceil(daysDifference + 1); // 시간 조건이 기준에 맞을 경우
-        }
-      } else {
-        // 시작일과 종료일이 같은 경우
-        if (this.startTime !== "09:00" || this.endTime !== "18:00") {
-          this.dayCount = 0.5; // 시작 시간 또는 종료 시간이 기준과 다를 경우 0.5
-        } else {
-          this.dayCount = 1; // 기준 시간(09:00~18:00)이 맞으면 1일로 간주
-        }
-      }
-
-    },
-
-
-
-  },
-};
-</script>
-<style scoped>
-td p {
-  width: 125px;
-}
-</style>
client/views/pages/Manager/attendance/ChuljangStatue.vue
--- client/views/pages/Manager/attendance/ChuljangStatue.vue
+++ client/views/pages/Manager/attendance/ChuljangStatue.vue
@@ -3,42 +3,23 @@
     <div class="card">
       <div class="card-body">
         <h2 class="card-title">출장 현황</h2>
-        <!-- 폼그룹 -->
         <div class="sch-form-wrap">
-        <div class="input-group">
-          <select name="" id="" class="form-select">
-              <option :value="currentYear">{{ currentYear }}년</option>
-  <option value="all">전체</option>
-  <option
-    v-for="year in remainingYears"
-    :key="year"
-    :value="year"
-    v-if="year !== currentYear"
-  >
-    {{ year }}년
-  </option>
+          <div class="input-group">
+            <select class="form-select" v-model="request.year" @change="fnChangeCurrentPage(1)">
+              <option value="">연도 전체</option>
+              <option v-for="year in years" :key="year" :value="year">{{ year }}년</option>
             </select>
-            <select name="" id="" class="form-select">
-              <option :value="currentMonth">{{ currentMonth }}월</option>
-  <option value="all">전체</option>
-  <option
-    v-for="month in remainingMonths"
-    :key="month"
-    :value="month"
-    v-if="month !== currentMonth"
-  >
-    {{ month }}월
-  </option>
+            <select class="form-select" v-model="request.month" @change="fnChangeCurrentPage(1)">
+              <option value="">월 전체</option>
+              <option v-for="month in months" :key="month" :value="month">{{ month }}월</option>
             </select>
-      </div>
-      </div>
-        <!-- Table  -->
+          </div>
+        </div>
         <div class="tbl-wrap">
           <table id="myTable" class="tbl data">
-            <!-- 동적으로 <th> 생성 -->
             <thead>
               <tr>
-                <th>출장구분 </th>
+                <th>출장구분</th>
                 <th>출장지</th>
                 <th>목적</th>
                 <th>출장기간</th>
@@ -47,201 +28,113 @@
                 <th>복명서 상태</th>
               </tr>
             </thead>
-            <!-- 동적으로 <td> 생성 -->
             <tbody>
-              <tr v-for="(item, index) in listData" :key="index" :class="{ 'expired': isPast(item) }" @click="handleClick(item)">
-                <td>{{ item.type }}</td>
-                <td>{{ item.where }}</td>
-                <td>{{ item.purpose }}</td>
-                <td >{{ item.period }}</td>
-<td
-  :class="getStatusClass(item.pumuiStatue)"
-  
->
-  {{ item.pumuiStatue }}
-</td>
-<td
-  :class="getBokmyeongClass(item.bokmyeong)"
->
-  {{ item.bokmyeong }}
-</td>
-
-<td :class="getStatusClass(item.status)">
-  {{ item.status }}
-</td>
+              <tr v-for="(item, idx) in lists" :key="idx" :class="{ 'expired': item.hasRport }" @click="fnMoveTo('view', item.bsrpId)">
+                <td>{{ item.bsrpSeNm }}</td>
+                <td>{{ item.bsrpPlace }}</td>
+                <td>{{ item.bsrpPurps }}</td>
+                <td>{{ item.bgnde }}</td>
+                <td>{{ item.bsrpCnsulDTO.confmAtNm }}</td>
+                <td>{{ item.hasRport ? '등록' : '미등록' }}</td>
+                <td>{{ item.hasRport ? item.bsrpRportDTO.confmAt : '-' }}</td>
               </tr>
             </tbody>
           </table>
-
         </div>
-        <div class="pagination">
-          <ul>
-            <!-- 왼쪽 화살표 (이전 페이지) -->
-            <li class="arrow" :class="{ disabled: currentPage === 1 }" @click="changePage(currentPage - 1)">
-              &lt;
-            </li>
-
-            <!-- 페이지 번호 -->
-            <li v-for="page in totalPages" :key="page" :class="{ active: currentPage === page }"
-              @click="changePage(page)">
-              {{ page }}
-            </li>
-
-            <!-- 오른쪽 화살표 (다음 페이지) -->
-            <li class="arrow" :class="{ disabled: currentPage === totalPages }" @click="changePage(currentPage + 1)">
-              &gt;
-            </li>
-          </ul>
-        </div>
-
+        <Pagenation :search="request" @onChange="fnChangeCurrentPage" />
       </div>
     </div>
   </div>
 </template>
-
 <script>
-import { ref } from 'vue';
 import { SearchOutlined } from '@ant-design/icons-vue';
-const currentYear = new Date().getFullYear();
-const currentMonth = new Date().getMonth() + 1;
+// API
+import { bsrpsProc } from '../../../../resources/api/bsrp';
+
 export default {
-  data() {
-    return {
-      currentMonth,
-      selectedMonth: currentMonth,
-      remainingMonths: Array.from({ length: 12 }, (_, i) => i + 1),
-      currentYear,
-      selectedYear: currentYear,
-      remainingYears: Array.from({ length: 10 }, (_, i) => currentYear - i),
-      showOptions: false,
-      currentPage: 1,
-      totalPages: 3,
-      photoicon: "/client/resources/img/photo_icon.png",
-      // 데이터 초기화
-      years: [2023, 2024, 2025], // 연도 목록
-      months: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], // 월 목록
-      selectedYear: '',
-      selectedMonth: '',
-      listData: [
-        {
-          type: '연차',
-          where: '상주시청',
-          purpose: '유지보수',
-          period: '2025-05-10 ~ 2025-05-23',
-          pumuiStatue: '대기',
-          bokmyeong: '미등록',          
-          status: '-'
-        },
-        {
-          type: '연차',
-          where: '상주시청',
-          purpose: '유지보수',
-          period: '2025-05-10 ~ 2025-05-23',
-          pumuiStatue: '승인',
-          bokmyeong: '미등록',          
-          status: '-'
-        },
-        {
-          type: '연차',
-          where: '상주시청',
-          purpose: '유지보수',
-          period: '2025-05-10 ~ 2025-05-23',
-          pumuiStatue: '승인',
-          bokmyeong: '등록',          
-          status: '대기'
-        }, {
-          type: '연차',
-          where: '상주시청',
-          purpose: '유지보수',
-          period: '2025-05-10 ~ 2025-05-10',
-          pumuiStatue: '승인',
-          bokmyeong: '등록',          
-          status: '승인'
-        },],
-      filteredData: [],
-    };
-  },
   components: {
     SearchOutlined
   },
-  computed: {
-  },
-  methods: {
-    goToAttendancePage(item) {
-      this.$router.push({ name: 'AttendanceDetail', query: { id: item.id } });
-    },
-    changePage(page) {
-      if (page < 1 || page > this.totalPages) return;
-      this.currentPage = page;
-      this.$emit('page-changed', page); // 필요 시 부모에 알림
-    },
-    async onClickSubmit() {
-      // `useMutation` 훅을 사용하여 mutation 함수 가져오기
-      const { mutate, onDone, onError } = useMutation(mygql);
 
-      try {
-        const result = await mutate();
-        console.log(result);
-      } catch (error) {
-        console.error('Mutation error:', error);
+  data() {
+    return {
+      photoicon: "/client/resources/img/photo_icon.png",
+
+      years: [],
+      months: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
+
+      cmmnCodes: {},
+      request: {
+        year: '',
+        month: '',
+      },
+      lists: [],
+    };
+  },
+
+  watch: {},
+
+  created() {
+    this.generateYears();
+  },
+
+  mounted() {
+    this.findList(); // 목록 조회
+  },
+
+  methods: {
+    generateYears() {
+      const startYear = 2020;
+      const currentYear = new Date().getFullYear();
+
+      for (let year = currentYear; year >= startYear; year--) {
+        this.years.push(year);
       }
     },
 
-    // 상태에 따른 클래스 반환 메소드
-    getStatusClass(status) {
-      return status === 'active' ? 'status-active' : 'status-inactive';
+    // 목록 조회
+    async findList() {
+      try {
+        const response = await bsrpsProc(this.request);
+        const result = response.data.data;
+
+        this.lists = result.lists;
+        this.request = result.search;
+      } catch (error) {
+        const message = error.response.data.message;
+        alert(message);
+      }
     },
-    getStatusClass(status, pumuiStatue) {
-  // Check the 'status' and 'pumuiStatue' to return the correct class
-  if (pumuiStatue === '승인') return 'status-approved'; 
-  if (pumuiStatue === '대기') return 'status-pending'; 
-  // If no match, fallback to status-based class
-  if (status === '대기') return 'status-pending';
-  if (status === '승인') return 'status-approved';
 
-  // Default empty string
-  return '';
-},
-getBokmyeongClass(bokmyeong) {
-  if (bokmyeong === '등록') return 'status-approved';
-  if (bokmyeong === '미등록') return 'status-pending';
-  return '';
-},
-isPast(item) {
-    return (
-      item.pumuiStatue === '승인' &&
-      item.bokmyeong === '등록' &&
-      item.status === '승인'
-    );
-  },
-  handleClick(item) {
-  const isCasePumui = (
-    (item.pumuiStatue === '대기' && item.bokmyeong === '미등록') ||
-    (item.pumuiStatue === '승인' && item.bokmyeong === '미등록')
-  );
+    // 페이지 이동
+    fnChangeCurrentPage(currentPage) {
+      this.request.currentPage = Number(currentPage);
+      this.$nextTick(() => {
+        this.findList();
+      });
+    },
 
-  if (item.bokmyeong === '등록') {
-    this.$router.push({ name: 'ChuljangDetailAll' });
-  } else if (isCasePumui) {
-    this.$router.push({ name: 'ChuljangPumuiDetail' });
-  } else {
-    console.log('이동 조건이 아닙니다.');
-  }
-},
-  handleBokmyeongClick(item) {
-    this.$router.push({ name: 'ChuljangBokmyeongDetail' });
-  },
-  },
-  created() {
-  },
-  mounted() {
+    fnMoveTo(type, id) {
+      const routes = {
+        'list': { name: 'ChuljangStatue' },
+        'view': { name: 'ChuljangDetailAll', query: { id } },
+        'edit': { name: 'ChuljangInsert', query: this.$isEmpty(id) ? {} : { id } },
+      };
 
-
+      if (routes[type]) {
+        if (!this.$isEmpty(this.pageId) && type === 'list') {
+          this.$router.push({ name: 'ChuljangDetailAll', query: { id: this.pageId } });
+          return;
+        }
+        this.$router.push(routes[type]);
+      } else {
+        alert("올바르지 않은 경로를 요청하여 목록으로 이동합니다.");
+        this.$router.push(routes['list']);
+      }
+    },
   },
-
 };
 </script>
-
 <style scoped>
 tr {
   cursor: pointer;
client/views/pages/Manager/attendance/HyugaDetail.vue
--- client/views/pages/Manager/attendance/HyugaDetail.vue
+++ client/views/pages/Manager/attendance/HyugaDetail.vue
@@ -76,7 +76,7 @@
       <div class="buttons">
         <button v-if="detailData.confmAt === 'W' || detailData.confmAt === 'R'" class="btn btn-red" type="button" @click="deleteData">신청취소</button>
         <button v-if="detailData.confmAt === 'W'" class="btn secondary" type="button" @click="fnMoveTo('edit', pageId)">수정</button>
-        <button v-if="detailData.confmAt === 'R'" class="btn secondary" type="button" @click="reSave">재신청</button>
+        <button v-if="detailData.confmAt === 'R'" class="btn secondary" type="button" @click="fnMoveTo('edit', pageId)">재신청</button>
         <button class="btn tertiary" type="button" @click="fnMoveTo('list')">목록</button>
       </div>
       <ReturnPopup v-if="showPopup" @close="showPopup = false" />
@@ -223,6 +223,11 @@
 
     // 삭제
     async deleteData() {
+      const isCheck = confirm("삭제하시겠습니까?");
+      if (!isCheck) {
+        return;
+      }
+
       try {
         const response = await deleteVcatnProc(this.pageId);
 
@@ -236,11 +241,6 @@
         console.error(error.message);
         this.fnMoveTo('list');
       }
-    },
-
-    // 재신청
-    reSave() {
-      this.$router.push({ name: 'hyugaInsert', query: { id: this.pageId } });
     },
 
     // 페이지 이동
client/views/pages/Manager/attendance/HyugaInsert.vue
--- client/views/pages/Manager/attendance/HyugaInsert.vue
+++ client/views/pages/Manager/attendance/HyugaInsert.vue
@@ -25,8 +25,8 @@
           </label>
           <div class="d-flex gap-1">
             <input type="date" class="form-control" id="bgnde" v-model="editData.bgnde" @keydown="preventKeyboard" />
-            <input type="text" class="form-control" placeholder="시" v-model="editData.beginHour" readonly />
-            <input type="text" class="form-control" placeholder="분" v-model="editData.beginMnt" readonly />
+            <input type="text" class="form-control" placeholder="시" style="width: 100px;" v-model="editData.beginHour" readonly />
+            <input type="text" class="form-control" placeholder="분" style="width: 100px;" v-model="editData.beginMnt" readonly />
           </div>
         </div>
         <div class="col-12">
@@ -35,8 +35,8 @@
           </label>
           <div class="d-flex gap-1">
             <input type="date" class="form-control" id="endde" v-model="editData.endde" :readonly="dayCnt === 0.5" @keydown="preventKeyboard" />
-            <input type="text" class="form-control" placeholder="시" v-model="editData.endHour" readonly />
-            <input type="text" class="form-control" placeholder="분" v-model="editData.endMnt" readonly />
+            <input type="text" class="form-control" placeholder="시" style="width: 100px;" v-model="editData.endHour" readonly />
+            <input type="text" class="form-control" placeholder="분" style="width: 100px;" v-model="editData.endMnt" readonly />
           </div>
         </div>
         <div class="col-12">
@@ -50,7 +50,7 @@
               <PlusCircleFilled />
             </button>
           </label>
-          <HrPopup v-if="isOpenModal" :sanctns="editData.sanctnList" @onSelected="fnAddSanctn" @close="isOpenModal = false" />
+          <HrPopup v-if="isOpenModal && isCodesLoaded" :sanctns="editData.sanctnList" :cmmnCodes="cmmnCodes" @onSelected="fnAddSanctn" @close="isOpenModal = false" />
           <div class="approval-container">
             <SanctnList v-model:sanctns="editData.sanctnList" @delSanctn="fnDelSanctn" />
           </div>
@@ -65,7 +65,7 @@
       <div class="buttons">
         <button type="button" class="btn btn-red" @click="fnRecord">이전 승인자 불러오기</button>
         <button type="button" class="btn primary" @click="fnSave">신청</button>
-        <button type="reset" class="btn tertiary" @click="fnMoveTo('list')">취소</button>
+        <button type="button" class="btn tertiary" @click="fnMoveTo('list')">취소</button>
       </div>
     </div>
   </div>
@@ -73,7 +73,7 @@
 <script>
 import { PlusCircleFilled, CloseOutlined } from '@ant-design/icons-vue';
 import HrPopup from '../../../component/Popup/HrPopup.vue';
-import SanctnList from '../../../component/Sanctn/SanctnList.vue';
+import SanctnList from '../../../component/Sanctn/SanctnFormList.vue';
 import EditorComponent from '../../../component/editor/EditorComponent.vue';
 // API
 import { findVcatnProc, saveVcatnProc, findLastVcatnProc, updateVcatnProc } from '../../../../resources/api/vcatn';
@@ -126,6 +126,11 @@
     // 세부 유형 선택박스를 보여줄지 여부
     showSubTypeSelect() {
       return this.dayCnt === 0.5 && this.subTypes.length > 0;
+    },
+
+    // cmmnCodes가 로드되었는지 확인
+    isCodesLoaded() {
+      return this.cmmnCodes && Object.keys(this.cmmnCodes).length > 0;
     }
   },
 
@@ -154,7 +159,7 @@
     },
     'editData.endde'(newVal, oldVal) {
       if (newVal !== oldVal) {
-        this.validateAndCalculateDays(); // calculateTotalDays 대신 validateAndCalculateDays 호출
+        this.validateAndCalculateDays();
       }
     },
   },
@@ -171,7 +176,6 @@
 
         let sanctns = [];
         for (let sanctn of this.editData.sanctnList) {
-          console.log("sanctn: ", sanctn);
           let data = {
             confmerId: sanctn.confmerId,
             clsf: sanctn.clsf,
@@ -184,12 +188,7 @@
         }
         this.editData.sanctnList = sanctns;
 
-        // cmmnCodes가 초기화되었는지 확인 후 호출
-        if (this.cmmnCodes && this.cmmnCodes.vcatnKndCodeList) {
-          await this.fnOnchangeVcatnKnd();
-        } else {
-          console.warn('cmmnCodes가 아직 초기화되지 않았습니다.');
-        }
+        await this.fnOnchangeVcatnKnd();
       } catch (error) {
         console.error('데이터 조회 실패:', error);
         const message = error.response?.data?.message || "데이터를 불러오는데 실패했습니다.";
@@ -200,9 +199,8 @@
 
     // 유형 변경
     async fnOnchangeVcatnKnd() {
-      // 안전성 검사 추가
-      if (!this.cmmnCodes || !this.cmmnCodes.vcatnKndCodeList || !Array.isArray(this.cmmnCodes.vcatnKndCodeList)) {
-        console.warn('cmmnCodes.vcatnKndCodeList가 초기화되지 않았거나 배열이 아닙니다.');
+      if (!this.isCodesLoaded || !Array.isArray(this.cmmnCodes.vcatnKndCodeList)) {
+        console.warn('cmmnCodes가 초기화되지 않았습니다.');
         return;
       }
 
@@ -217,7 +215,6 @@
       if (this.dayCnt === 0.5) {
         this.changeBgnde(); // 반차일 경우 종료일을 시작일과 동일하게 설정
       } else {
-        // 반차가 아닌 경우
         this.editData.vcatnSubKnd = ''; // 세부 유형 선택 초기화
 
         // 전체 근무시간으로 설정
@@ -314,7 +311,6 @@
 
       // 날짜 유효성 검사
       if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
-        console.warn('유효하지 않은 날짜입니다.');
         this.totalDays = 0;
         return;
       }
@@ -360,7 +356,18 @@
       }
     },
 
-    fnAddSanctn(data) {
+    // 승인자
+    fnAddSanctn(user) {
+      const data = {
+        confmerId: user.userId,
+        clsf: user.clsf,
+        sanctnOrdr: this.editData.nmprList.length + 1,
+        sanctnSe: this.cmmnCodes.sanctnCodeList[0].code,
+
+        clsfNm: this.formatClsf(user.clsf),
+        userNm: user.userNm,
+      };
+
       this.editData.sanctnList.push(data);
       this.isOpenModal = false;
     },
@@ -372,6 +379,12 @@
       });
     },
 
+    // 직급 매칭
+    formatClsf(code) {
+      const clsfCode = this.cmmnCodes?.clsfCodeList?.find(item => item.code === code);
+      return clsfCode?.codeNm || code;
+    },
+
     async fnRecord() {
       try {
         const response = await findLastVcatnProc();
Add a comment
List