
--- client/views/component/common/AlertModal.vue
+++ client/views/component/common/AlertModal.vue
... | ... | @@ -2,12 +2,12 @@ |
2 | 2 |
<div v-show="isModalOpen" class="modal-wrapper"> |
3 | 3 |
<div class="modal-container small-modal"> |
4 | 4 |
<div class="modal-title text-ct"> |
5 |
- <h2>{{ title }}</h2> |
|
5 |
+ <h2>{{ modalTitle }}</h2> |
|
6 | 6 |
</div> |
7 | 7 |
<div class="modal-content-monthly"> |
8 |
- <p class="alert-write text-ct" v-html="message"> |
|
8 |
+ <p class="alert-write text-ct" v-html="modalMessage"> |
|
9 | 9 |
</p> |
10 |
- <div v-if="radioAt"> |
|
10 |
+ <div v-if="modalType === 'radio'"> |
|
11 | 11 |
<p>원본파일 : </p> |
12 | 12 |
<label></label> |
13 | 13 |
<p>동작 : </p> |
... | ... | @@ -17,15 +17,14 @@ |
17 | 17 |
</div> |
18 | 18 |
</div> |
19 | 19 |
<div class="modal-end flex justify-center" style="flex-wrap: nowrap;"> |
20 |
- <button class="blue-btn large-btn" id="confirmOk" @click="closeModal" @keyup.enter="closeModal">확인</button> |
|
21 |
- <button class="gray-btn large-btn" id="confirmCancel" @click="closeModal" v-show="confirmAt">취소</button> |
|
22 |
- <button class="gray-btn large-btn" id="confirmRadioCancel" @click="closeModal" v-show="radioAt">취소</button> |
|
20 |
+ <button class="blue-btn large-btn" @click="onConfirm" @keyup.enter="onConfirm" autofocus v-if="isModalOpen">확인</button> |
|
21 |
+ <button class="gray-btn large-btn" @click="onCancel" v-show="modalType === 'confirm'">취소</button> |
|
22 |
+ <button class="gray-btn large-btn" @click="onRadioCancel" v-show="modalType === 'radio'">취소</button> |
|
23 | 23 |
</div> |
24 | 24 |
</div> |
25 | 25 |
</div> |
26 | 26 |
</template> |
27 | 27 |
<script> |
28 |
- |
|
29 | 28 |
export default { |
30 | 29 |
props: { |
31 | 30 |
title: { |
... | ... | @@ -40,112 +39,112 @@ |
40 | 39 |
data() { |
41 | 40 |
return { |
42 | 41 |
isModalOpen: false, |
43 |
- activeTab: 'tab1', |
|
44 |
- modalType: 'tab-modal', |
|
45 |
- title: this.title, |
|
46 |
- message: this.message, |
|
47 |
- confirmAt: false, |
|
48 |
- radioAt: false, |
|
42 |
+ modalType: 'alert', // 'alert', 'confirm', 'radio' 중 하나 |
|
43 |
+ modalTitle: this.title, |
|
44 |
+ modalMessage: this.message, |
|
49 | 45 |
moveOrCopy: { |
50 |
- type: null, |
|
51 |
- checkBox: null |
|
46 |
+ type: "move", |
|
47 |
+ checkBox: false |
|
52 | 48 |
}, |
49 |
+ currentPromise: null |
|
53 | 50 |
} |
54 | 51 |
}, |
55 | 52 |
methods: { |
56 |
- // 탭 변경 |
|
57 |
- showTab: function (tabName) { |
|
58 |
- this.activeTab = tabName; |
|
59 |
- }, |
|
60 |
- |
|
61 |
- // 닫기 |
|
62 |
- closeModal: function () { |
|
53 |
+ // 모달 닫기 |
|
54 |
+ closeModal() { |
|
63 | 55 |
this.isModalOpen = false; |
64 |
- this.confirmAt = false; |
|
65 |
- this.radioAt = false; |
|
56 |
+ this.modalType = 'alert'; |
|
66 | 57 |
}, |
67 | 58 |
|
68 |
- // 모달 호출 |
|
69 |
- showModal: function () { |
|
70 |
- |
|
59 |
+ // 일반 모달 표시 |
|
60 |
+ showModal() { |
|
61 |
+ this.modalType = 'alert'; |
|
71 | 62 |
this.isModalOpen = true; |
72 |
- document.getElementById("confirmOk").focus() |
|
73 | 63 |
}, |
74 | 64 |
|
75 |
- // confirm 호출 |
|
76 |
- showConfirm: async function () { |
|
77 |
- this.confirmAt = true; |
|
78 |
- this.isModalOpen = true; |
|
79 |
- document.getElementById("confirmOk").focus() |
|
80 |
- const promise = new Promise((resolve, reject) => { |
|
81 |
- document.getElementById("confirmCancel").addEventListener("click", async () => { |
|
82 |
- resolve('cancel') |
|
83 |
- }); |
|
65 |
+ // 확인 버튼 클릭 핸들러 |
|
66 |
+ onConfirm() { |
|
67 |
+ if (this.modalType === 'alert') { |
|
68 |
+ // 단순 알림 모달은 그냥 닫기 |
|
69 |
+ this.closeModal(); |
|
70 |
+ } else if (this.modalType === 'confirm') { |
|
71 |
+ // confirm 모달은 true 반환 |
|
72 |
+ this.resolvePromise(true); |
|
73 |
+ } else if (this.modalType === 'radio') { |
|
74 |
+ // radio 모달은 현재 선택된 값 반환 |
|
75 |
+ this.resolvePromise(this.moveOrCopy); |
|
76 |
+ } |
|
77 |
+ }, |
|
84 | 78 |
|
85 |
- document.getElementById("confirmOk").addEventListener("click", async () => { |
|
86 |
- resolve('ok') |
|
87 |
- }); |
|
79 |
+ // 취소 버튼 클릭 핸들러 (일반 confirm용) |
|
80 |
+ onCancel() { |
|
81 |
+ this.resolvePromise(false); |
|
82 |
+ }, |
|
83 |
+ |
|
84 |
+ // 취소 버튼 클릭 핸들러 (라디오 confirm용) |
|
85 |
+ onRadioCancel() { |
|
86 |
+ this.resolvePromise({ |
|
87 |
+ type: "cancel", |
|
88 |
+ checkBox: false |
|
89 |
+ }); |
|
90 |
+ }, |
|
91 |
+ |
|
92 |
+ // Promise 해결 및 모달 닫기 |
|
93 |
+ resolvePromise(value) { |
|
94 |
+ if (this.currentPromise && this.currentPromise.resolve) { |
|
95 |
+ this.currentPromise.resolve(value); |
|
96 |
+ this.currentPromise = null; |
|
97 |
+ } |
|
98 |
+ this.closeModal(); |
|
99 |
+ }, |
|
100 |
+ |
|
101 |
+ // Promise 생성 |
|
102 |
+ createPromise() { |
|
103 |
+ let resolve, reject; |
|
104 |
+ const promise = new Promise((res, rej) => { |
|
105 |
+ resolve = res; |
|
106 |
+ reject = rej; |
|
88 | 107 |
}); |
89 | 108 |
|
90 |
- return promise.then( |
|
91 |
- (id) => { |
|
92 |
- if (id == 'cancel') { |
|
93 |
- return false; |
|
94 |
- } else if (id == 'ok') { |
|
95 |
- return true; |
|
96 |
- } |
|
97 |
- } |
|
98 |
- ); |
|
109 |
+ this.currentPromise = { promise, resolve, reject }; |
|
110 |
+ return promise; |
|
99 | 111 |
}, |
100 | 112 |
|
101 |
- // radio confirm 호출 |
|
102 |
- showRadioConfirm: async function () { |
|
103 |
- this.radioAt = true; |
|
113 |
+ // confirm 모달 표시 (확인/취소) |
|
114 |
+ async showConfirm() { |
|
115 |
+ this.modalType = 'confirm'; |
|
116 |
+ this.isModalOpen = true; |
|
117 |
+ return this.createPromise(); |
|
118 |
+ }, |
|
119 |
+ |
|
120 |
+ // radio confirm 모달 표시 (라디오 옵션) |
|
121 |
+ async showRadioConfirm() { |
|
122 |
+ this.modalType = 'radio'; |
|
104 | 123 |
this.isModalOpen = true; |
105 | 124 |
this.moveOrCopy.type = "move"; |
106 | 125 |
this.moveOrCopy.checkBox = false; |
107 |
- |
|
108 |
- document.getElementById("confirmOk").focus() |
|
109 |
- const promise = new Promise((resolve, reject) => { |
|
110 |
- document.getElementById("confirmRadioCancel").addEventListener("click", async () => { |
|
111 |
- resolve('cancel') |
|
112 |
- }); |
|
113 |
- |
|
114 |
- document.getElementById("confirmOk").addEventListener("click", async () => { |
|
115 |
- resolve('ok') |
|
116 |
- }); |
|
117 |
- }); |
|
118 |
- |
|
119 |
- return promise.then( |
|
120 |
- (id) => { |
|
121 |
- if (id == 'cancel') { |
|
122 |
- this.moveOrCopy.type = "cancel" |
|
123 |
- this.moveOrCopy.checkBox = false |
|
124 |
- return this.moveOrCopy; |
|
125 |
- } else if (id == 'ok') { |
|
126 |
- return this.moveOrCopy; |
|
127 |
- } |
|
128 |
- } |
|
129 |
- ); |
|
126 |
+ return this.createPromise(); |
|
130 | 127 |
}, |
131 | 128 |
|
132 |
- setTitle: function (Title) { |
|
133 |
- this.title = Title; |
|
129 |
+ // 제목 설정 |
|
130 |
+ setTitle(title) { |
|
131 |
+ this.modalTitle = title; |
|
134 | 132 |
}, |
135 | 133 |
|
136 |
- setMessage: function (message) { |
|
137 |
- this.message = message; |
|
134 |
+ // 메시지 설정 |
|
135 |
+ setMessage(message) { |
|
136 |
+ this.modalMessage = message; |
|
138 | 137 |
}, |
139 |
- |
|
140 | 138 |
}, |
141 | 139 |
watch: { |
142 |
- |
|
143 |
- }, |
|
144 |
- computed: { |
|
145 |
- |
|
146 |
- }, |
|
147 |
- components: { |
|
148 |
- |
|
149 |
- }, |
|
140 |
+ // props로 전달된 title이 변경되면 modalTitle 업데이트 |
|
141 |
+ title(newVal) { |
|
142 |
+ this.modalTitle = newVal; |
|
143 |
+ }, |
|
144 |
+ // props로 전달된 message가 변경되면 modalMessage 업데이트 |
|
145 |
+ message(newVal) { |
|
146 |
+ this.modalMessage = newVal; |
|
147 |
+ } |
|
148 |
+ } |
|
150 | 149 |
} |
151 | 150 |
</script>(파일 끝에 줄바꿈 문자 없음) |
--- client/views/component/connection/itm/fileDataRead.vue
+++ client/views/component/connection/itm/fileDataRead.vue
... | ... | @@ -1,163 +1,64 @@ |
1 | 1 |
<template> |
2 | 2 |
<div> |
3 |
- <div |
|
4 |
- v-show="!preview" |
|
5 |
- class="data_control flexCenter mt10" |
|
6 |
- style="display: flex; justify-content: space-evenly" |
|
7 |
- > |
|
3 |
+ <div v-show="!preview" class="data_control flexCenter mt10" style="display: flex; justify-content: space-evenly"> |
|
8 | 4 |
<div class="col-4 fl alignC"> |
9 | 5 |
<label for="datastart"> 데이터 시작 행 </label> |
10 | 6 |
<div class="flexBox" style="align-items: center !important"> |
11 |
- <input |
|
12 |
- type="text" |
|
13 |
- name="datastart" |
|
14 |
- v-model="rowIndex" |
|
15 |
- @blur="updateRowIndex" |
|
16 |
- @keyup.enter="updateRowIndex" |
|
17 |
- /> |
|
7 |
+ <input type="text" name="datastart" v-model="rowIndex" @blur="updateRowIndex" @keyup.enter="updateRowIndex" /> |
|
18 | 8 |
<div class="updownbox flexBox"> |
19 |
- <input |
|
20 |
- type="button" |
|
21 |
- value="▲" |
|
22 |
- class="input_up" |
|
23 |
- @click="dataTableInfo.startRowIndex++" |
|
24 |
- /> |
|
25 |
- <input |
|
26 |
- type="button" |
|
27 |
- value="▼" |
|
28 |
- class="input_down" |
|
29 |
- @click="dataTableInfo.startRowIndex--" |
|
30 |
- /> |
|
9 |
+ <input type="button" value="▲" class="input_up" @click="dataTableInfo.startRowIndex++" /> |
|
10 |
+ <input type="button" value="▼" class="input_down" @click="dataTableInfo.startRowIndex--" /> |
|
31 | 11 |
</div> |
32 | 12 |
</div> |
33 | 13 |
</div> |
34 | 14 |
<div class="col-4 fl alignL"> |
35 | 15 |
<label for="dataend"> 데이터 시작 열 </label> |
36 | 16 |
<div class="flexBox" style="align-items: center !important"> |
37 |
- <input |
|
38 |
- type="text" |
|
39 |
- name="dataend" |
|
40 |
- v-model="cellIndex" |
|
41 |
- @blur="updateCellIndex" |
|
42 |
- @keyup.enter="updateCellIndex" |
|
43 |
- /> |
|
17 |
+ <input type="text" name="dataend" v-model="cellIndex" @blur="updateCellIndex" @keyup.enter="updateCellIndex" /> |
|
44 | 18 |
<div class="updownbox flexBox"> |
45 |
- <input |
|
46 |
- type="button" |
|
47 |
- value="▲" |
|
48 |
- class="input_up" |
|
49 |
- @click="dataTableInfo.startCellIndex++" |
|
50 |
- /> |
|
51 |
- <input |
|
52 |
- type="button" |
|
53 |
- value="▼" |
|
54 |
- class="input_down" |
|
55 |
- @click="dataTableInfo.startCellIndex--" |
|
56 |
- /> |
|
19 |
+ <input type="button" value="▲" class="input_up" @click="dataTableInfo.startCellIndex++" /> |
|
20 |
+ <input type="button" value="▼" class="input_down" @click="dataTableInfo.startCellIndex--" /> |
|
57 | 21 |
</div> |
58 | 22 |
</div> |
59 | 23 |
</div> |
60 | 24 |
</div> |
61 |
- <div class="datatableInfoBox" style="max-height: 550px; overflow: auto"> |
|
25 |
+ <div class="datatableInfoBox" style="min-height: 550px; overflow: auto"> |
|
62 | 26 |
<div class="table-zone"> |
63 |
- <!-- <div class="list-info flex justify-between align-center"> |
|
64 |
- <div class="count-zone"> |
|
65 |
- <p>총 <span>40</span>건 중 <span>01</span>건 선택</p> |
|
66 |
- </div> |
|
67 |
- </div> --> |
|
68 | 27 |
<table class="list-table"> |
69 | 28 |
<!-- col 꼭 너비 기재해야함! 그래야 100%로 차지함 --> |
70 | 29 |
<colgroup> |
71 | 30 |
<col style="width: 10%" /> |
72 |
- <col |
|
73 |
- v-for="(info, i) in dataTableInfo.changeColumnDatas" |
|
74 |
- :key="i" |
|
75 |
- :style="changeWidth()" |
|
76 |
- /> |
|
31 |
+ <col v-for="(info, i) in dataTableInfo.changeColumnDatas" :key="i" :style="changeWidth()" /> |
|
77 | 32 |
</colgroup> |
78 | 33 |
<thead> |
79 | 34 |
<tr> |
80 | 35 |
<th>No</th> |
81 |
- <th |
|
82 |
- v-for="(info, i) in dataTableInfo.changeColumnDatas" |
|
83 |
- :key="i" |
|
84 |
- :style=" |
|
85 |
- i < dataTableInfo.startCellIndex |
|
86 |
- ? 'background-color: #dfdfdf;' |
|
87 |
- : null |
|
88 |
- " |
|
89 |
- > |
|
90 |
- [{{ i + 1 }}] |
|
91 |
- </th> |
|
36 |
+ <th v-for="(info, i) in dataTableInfo.changeColumnDatas" :key="i" :style="i < dataTableInfo.startCellIndex |
|
37 |
+ ? 'background-color: #dfdfdf;' |
|
38 |
+ : null |
|
39 |
+ "> [{{ i + 1 }}] </th> |
|
92 | 40 |
</tr> |
93 | 41 |
</thead> |
94 |
- <!-- <tbody> |
|
95 |
- <tr> |
|
96 |
- <th :class="{ selected: getRowDataColumnIndex < 0 }">[1]</th> |
|
97 |
- <td :class="{ |
|
98 |
- selected: getRowDataColumnIndex < 0 |
|
99 |
- , disabled: getStartRowIndex >= 0 || dataTableInfo.startCellIndex > j |
|
100 |
- }" |
|
101 |
- v-for="(info, j) in dataTableInfo.changeColumnDatas"> |
|
102 |
- {{ dataTableInfo.columnDatas[j].displyColumnNm }} |
|
103 |
- </td> |
|
104 |
- </tr> |
|
105 |
- <tr v-for="(cells, i) in dataTableInfo.rowData" v-if="i < viewCount"> |
|
106 |
- <th :class="{ selected: getRowDataColumnIndex == i }">[{{ i + 2 }}]</th> |
|
107 |
- <td :class="{ |
|
108 |
- selected: getRowDataColumnIndex == i |
|
109 |
- , disabled: getStartRowIndex > i || dataTableInfo.startCellIndex > j |
|
110 |
- }" |
|
111 |
- v-for="(value, j) in cells" :title="value"> |
|
112 |
- {{ value }} |
|
113 |
- </td> |
|
114 |
- </tr> |
|
115 |
- <tr v-if="postList === 0"> |
|
116 |
- <td colspan="5" class="no-list">검색조건에 해당하는 데이터가 없습니다.</td> |
|
117 |
- </tr> |
|
118 |
- </tbody> --> |
|
119 | 42 |
<tbody> |
120 | 43 |
<tr> |
121 | 44 |
<th>[1]</th> |
122 |
- <td |
|
123 |
- v-for="(info, j) in dataTableInfo.changeColumnDatas" |
|
124 |
- :key="j" |
|
125 |
- :style=" |
|
126 |
- j < dataTableInfo.startCellIndex |
|
127 |
- ? 'background-color: #dfdfdf;' |
|
128 |
- : 'background-color: #fdd2d2;' |
|
129 |
- " |
|
130 |
- > |
|
131 |
- {{ dataTableInfo.columnDatas[j].displyColumnNm }} |
|
132 |
- </td> |
|
45 |
+ <td v-for="(info, j) in dataTableInfo.changeColumnDatas" :key="j" :style="j < dataTableInfo.startCellIndex |
|
46 |
+ ? 'background-color: #dfdfdf;' |
|
47 |
+ : 'background-color: #fdd2d2;' |
|
48 |
+ "> {{ dataTableInfo.columnDatas[j].displyColumnNm }} </td> |
|
133 | 49 |
</tr> |
134 |
- <tr |
|
135 |
- v-for="(cells, i) in dataTableInfo.rowData" |
|
136 |
- :key="i" |
|
137 |
- :style=" |
|
138 |
- i + 1 < dataTableInfo.startRowIndex |
|
139 |
- ? 'background-color: #dfdfdf;' |
|
140 |
- : null |
|
141 |
- " |
|
142 |
- > |
|
50 |
+ <tr v-for="(cells, i) in dataTableInfo.rowData" :key="i" :style="i + 1 < dataTableInfo.startRowIndex |
|
51 |
+ ? 'background-color: #dfdfdf;' |
|
52 |
+ : null |
|
53 |
+ "> |
|
143 | 54 |
<th>[{{ i + 2 }}]</th> |
144 |
- <td |
|
145 |
- v-for="(value, j) in cells" |
|
146 |
- :key="j" |
|
147 |
- :title="value" |
|
148 |
- :style=" |
|
149 |
- j < dataTableInfo.startCellIndex |
|
150 |
- ? 'background-color: #dfdfdf;' |
|
151 |
- : null |
|
152 |
- " |
|
153 |
- > |
|
154 |
- {{ value }} |
|
155 |
- </td> |
|
55 |
+ <td v-for="(value, j) in cells" :key="j" :title="value" :style="j < dataTableInfo.startCellIndex |
|
56 |
+ ? 'background-color: #dfdfdf;' |
|
57 |
+ : null |
|
58 |
+ "> {{ value }} </td> |
|
156 | 59 |
</tr> |
157 | 60 |
<tr v-if="postList === 0"> |
158 |
- <td colspan="5" class="no-list"> |
|
159 |
- 검색조건에 해당하는 데이터가 없습니다. |
|
160 |
- </td> |
|
61 |
+ <td colspan="5" class="no-list"> 검색조건에 해당하는 데이터가 없습니다. </td> |
|
161 | 62 |
</tr> |
162 | 63 |
</tbody> |
163 | 64 |
</table> |
... | ... | @@ -165,8 +66,6 @@ |
165 | 66 |
</div> |
166 | 67 |
</div> |
167 | 68 |
</template> |
168 |
- |
|
169 |
- |
|
170 | 69 |
<script> |
171 | 70 |
import _ from "lodash"; |
172 | 71 |
|
--- client/views/component/connection/modalContents/DbRead.vue
+++ client/views/component/connection/modalContents/DbRead.vue
... | ... | @@ -1,6 +1,6 @@ |
1 | 1 |
<template> |
2 | 2 |
<div class="modal-content-monthly"> |
3 |
- <div v-if="currentPage == 1"> |
|
3 |
+ <template v-if="currentPage == 1"> |
|
4 | 4 |
<div class="table-zone"> |
5 | 5 |
<table class="form-table"> |
6 | 6 |
<colgroup> |
... | ... | @@ -103,134 +103,106 @@ |
103 | 103 |
</tbody> |
104 | 104 |
</table> |
105 | 105 |
</div> |
106 |
- </div> |
|
107 |
- <div v-if="currentPage == 2"> |
|
108 |
- <Splitter style="min-height: 60dvh; border: 0px solid #e5e7eb"> |
|
109 |
- <SplitterPanel class="flex align-items-center justify-content-center" :size="20" :minSize="10"> |
|
110 |
- <div class="content-box"> |
|
111 |
- <div class="file-zone"> |
|
112 |
- <div class="content-titleZone" style="height: 60px"> |
|
113 |
- <p class="box-title">테이블 정보</p> |
|
106 |
+ </template> |
|
107 |
+ <template v-if="currentPage == 2"> |
|
108 |
+ <div class="flex content-box" style="min-height: 60dvh; flex-wrap: nowrap;"> |
|
109 |
+ <div class="content-box pd10" style="width: 20%;"> |
|
110 |
+ <div class="content-titleZone flex justy justify-between align-center" style="height: 45px"> |
|
111 |
+ <p class="box-title">데이터베이스 정보</p> |
|
112 |
+ </div> |
|
113 |
+ <div class="content-zone2"> |
|
114 |
+ <ul class="content-list" v-if="tableList.length > 0"> |
|
115 |
+ <li class="cursor" v-for="(item, indx) in tableList" :key="indx"> |
|
116 |
+ <a @click="getTableData(item)" :class="{ |
|
117 |
+ 'file-list': true, |
|
118 |
+ selected: selectTable === item, |
|
119 |
+ }"> |
|
120 |
+ <div class="flex align-center"> |
|
121 |
+ <p> {{ item.tableNmKr != null && item.tableNmKr != "" ? item.tableNmKr : item.tableNm }} </p> |
|
122 |
+ </div> |
|
123 |
+ </a> |
|
124 |
+ </li> |
|
125 |
+ </ul> |
|
126 |
+ </div> |
|
127 |
+ </div> |
|
128 |
+ <div class="content-box" style="width: 80%;"> |
|
129 |
+ <div class="flex-column"> |
|
130 |
+ <div class="content-box pd10" style="height: 50%;"> |
|
131 |
+ <div class="content-titleZone flex justy justify-between align-center" style="height: 45px"> |
|
132 |
+ <p class="box-title">쿼리 작업</p> |
|
133 |
+ <button class="icon-btn" @click="executeQuery" title="실행"> |
|
134 |
+ <svg-icon type="mdi" :path="playPath" :color="'#fbbe28'"></svg-icon> |
|
135 |
+ </button> |
|
114 | 136 |
</div> |
115 |
- <div class="content-zone2"> |
|
116 |
- <ul class="content-list" v-if="tableList.length > 0"> |
|
117 |
- <li class="cursor" v-for="(item, indx) in tableList" :key="indx"> |
|
118 |
- <a @click="getTableData(item)" :class="{ |
|
119 |
- 'file-list': true, |
|
120 |
- selected: selectTable === item, |
|
121 |
- }"> |
|
122 |
- <div class="flex align-center"> |
|
123 |
- <p> {{ item.tableNmKr != null && item.tableNmKr != "" ? item.tableNmKr : item.tableNm }} </p> |
|
124 |
- </div> |
|
125 |
- </a> |
|
126 |
- </li> |
|
127 |
- </ul> |
|
137 |
+ <div class="flex" style="height: calc(100% - 60px)"> |
|
138 |
+ <textarea style="resize: none; width: 100%; height: 100%; padding: 10px;" v-model="jobItm.itm.query"></textarea> |
|
128 | 139 |
</div> |
129 | 140 |
</div> |
130 |
- </div> |
|
131 |
- </SplitterPanel> |
|
132 |
- <SplitterPanel class="flex align-items-center justify-content-center" :size="80"> |
|
133 |
- <div class="content-box"> |
|
134 |
- <div class="content-titleZone" style="height: 60px"> |
|
135 |
- <div class="flex justify-between aling-center"> |
|
136 |
- <p class="box-title">쿼리 작업</p> |
|
137 |
- <div> |
|
138 |
- <button class="icon-btn" @click="executeQuery" title="실행"> |
|
139 |
- <svg-icon type="mdi" :path="playPath" :color="'#fbbe28'"></svg-icon> |
|
140 |
- </button> |
|
141 |
+ <div class="content-box pd10" style="height: 50%;"> |
|
142 |
+ <ul class="tab-nav flex justify-start"> |
|
143 |
+ <li @click="showTab('tab1')"> |
|
144 |
+ <a href="#tab01" :class="{ activeTab: activeTab === 'tab1' }">작업결과</a> |
|
145 |
+ </li> |
|
146 |
+ <li @click="showTab('tab2')"> |
|
147 |
+ <a href="#tab02" :class="{ activeTab: activeTab === 'tab2' }">작업log</a> |
|
148 |
+ </li> |
|
149 |
+ </ul> |
|
150 |
+ <div v-show="activeTab === 'tab1'" class="content-box" style="height: calc(100% - 45px); padding: 10px;"> |
|
151 |
+ <div class="count-zone mb10" v-if="jobItm.dataTable.columnDatas.length > 0"> |
|
152 |
+ <p> 총 <span>{{ jobItm.dataTable.totalRows }}</span>건 중 <span>{{ jobItm.dataTable.rowData.length }}</span>건 조회 </p> |
|
153 |
+ </div> |
|
154 |
+ <div style="height: calc(100% - 15px); overflow: auto;"> |
|
155 |
+ <table class="list-table"> |
|
156 |
+ <thead> |
|
157 |
+ <tr v-if="jobItm.dataTable.columnDatas.length > 0"> |
|
158 |
+ <th v-for="(itm, indx) in jobItm.dataTable |
|
159 |
+ .columnDatas" :key="indx" style="min-width: 150px !important"> {{ itm.columnNm }} <label class="check-label"> |
|
160 |
+ <input type="checkbox" class="custom-checkbox" v-model="itm.pkAt" /> |
|
161 |
+ </label> |
|
162 |
+ </th> |
|
163 |
+ </tr> |
|
164 |
+ </thead> |
|
165 |
+ <tbody v-if="jobItm.dataTable.rowData.length > 0"> |
|
166 |
+ <tr v-for="(row, rows) in jobItm.dataTable.rowData" :key="rows"> |
|
167 |
+ <td v-for="(itm, indx) in row" :key="indx" style="overflow: hidden; white-space: nowrap; text-overflow: ellipsis;"> {{ itm }} </td> |
|
168 |
+ </tr> |
|
169 |
+ </tbody> |
|
170 |
+ </table> |
|
171 |
+ </div> |
|
172 |
+ </div> |
|
173 |
+ <div v-show="activeTab === 'tab2'" class=" content-box" style="height: calc(100% - 45px); padding: 10px;"> |
|
174 |
+ <div style="height: calc(100% - 15px); overflow: auto;"> |
|
175 |
+ <table class="list-table"> |
|
176 |
+ <colgroup> |
|
177 |
+ <col width="10%" /> |
|
178 |
+ <col width="60%" /> |
|
179 |
+ <col width="20%" /> |
|
180 |
+ <col width="10%" /> |
|
181 |
+ </colgroup> |
|
182 |
+ <thead> |
|
183 |
+ <tr> |
|
184 |
+ <th>No</th> |
|
185 |
+ <th>접속시간</th> |
|
186 |
+ <th>접속결과</th> |
|
187 |
+ <th>접속내용</th> |
|
188 |
+ </tr> |
|
189 |
+ </thead> |
|
190 |
+ <tbody> |
|
191 |
+ <tr v-for="(itm, indx) in executeMessage" :key="indx"> |
|
192 |
+ <td>{{ indx + 1 }}</td> |
|
193 |
+ <td>{{ itm.message }}</td> |
|
194 |
+ <td>{{ itm.time }}</td> |
|
195 |
+ <td>{{ itm.result }}</td> |
|
196 |
+ </tr> |
|
197 |
+ </tbody> |
|
198 |
+ </table> |
|
141 | 199 |
</div> |
142 | 200 |
</div> |
143 | 201 |
</div> |
144 |
- <div class="content-zone"> |
|
145 |
- <Splitter style="height: 100%" layout="vertical"> |
|
146 |
- <SplitterPanel class="flex align-items-center justify-content-center" :size="50" :minSize="20"> |
|
147 |
- <textarea style=" |
|
148 |
- resize: none; |
|
149 |
- max-width: 100%; |
|
150 |
- max-height: 100%; |
|
151 |
- padding: 10px; |
|
152 |
- " v-model="jobItm.itm.query"></textarea> |
|
153 |
- </SplitterPanel> |
|
154 |
- <SplitterPanel class="align-items-center justify-content-center" :size="50"> |
|
155 |
- <ul class="tab-nav flex justify-start"> |
|
156 |
- <li @click="showTab('tab1')"> |
|
157 |
- <a href="#tab01" :class="{ activeTab: activeTab === 'tab1' }">작업결과</a> |
|
158 |
- </li> |
|
159 |
- <li @click="showTab('tab2')"> |
|
160 |
- <a href="#tab02" :class="{ activeTab: activeTab === 'tab2' }">작업log</a> |
|
161 |
- </li> |
|
162 |
- </ul> |
|
163 |
- <div v-show="activeTab === 'tab1'" style=" |
|
164 |
- height: calc(100% - 60px); |
|
165 |
- overflow: auto; |
|
166 |
- padding: 10px; |
|
167 |
- "> |
|
168 |
- <div class="count-zone" v-if="jobItm.dataTable.columnDatas.length > 0"> |
|
169 |
- <p> 총 <span>{{ jobItm.dataTable.totalRows }}</span>건 중 <span>{{ jobItm.dataTable.rowData.length }}</span>건 조회 </p> |
|
170 |
- </div> |
|
171 |
- <div class="table-zone"> |
|
172 |
- <table class="list-table"> |
|
173 |
- <!-- col 꼭 너비 기재해야함! 그래야 100%로 차지함 --> |
|
174 |
- <thead> |
|
175 |
- <tr v-if="jobItm.dataTable.columnDatas.length > 0"> |
|
176 |
- <th v-for="(itm, indx) in jobItm.dataTable |
|
177 |
- .columnDatas" :key="indx" style="min-width: 150px !important"> {{ itm.columnNm }} <label class="check-label"> |
|
178 |
- <input type="checkbox" class="custom-checkbox" v-model="itm.pkAt" /> |
|
179 |
- </label> |
|
180 |
- </th> |
|
181 |
- </tr> |
|
182 |
- </thead> |
|
183 |
- <tbody v-if="jobItm.dataTable.rowData.length > 0"> |
|
184 |
- <tr v-for="(row, rows) in jobItm.dataTable.rowData" :key="rows"> |
|
185 |
- <td v-for="(itm, indx) in row" :key="indx" style=" |
|
186 |
- overflow: hidden; |
|
187 |
- white-space: nowrap; |
|
188 |
- text-overflow: ellipsis; |
|
189 |
- "> {{ itm }} </td> |
|
190 |
- </tr> |
|
191 |
- </tbody> |
|
192 |
- </table> |
|
193 |
- </div> |
|
194 |
- </div> |
|
195 |
- <div v-show="activeTab === 'tab2'" style=" |
|
196 |
- height: calc(100% - 60px); |
|
197 |
- overflow: auto; |
|
198 |
- padding: 10px; |
|
199 |
- "> |
|
200 |
- <div class="table-zone"> |
|
201 |
- <table class="list-table"> |
|
202 |
- <colgroup> |
|
203 |
- <col width="10%" /> |
|
204 |
- <col width="10%" /> |
|
205 |
- <col width="" /> |
|
206 |
- <col width="10%" /> |
|
207 |
- </colgroup> |
|
208 |
- <thead> |
|
209 |
- <tr> |
|
210 |
- <th>No</th> |
|
211 |
- <th>접속시간</th> |
|
212 |
- <th>접속결과</th> |
|
213 |
- <th>접속내용</th> |
|
214 |
- </tr> |
|
215 |
- </thead> |
|
216 |
- <tbody> |
|
217 |
- <tr v-for="(itm, indx) in executeMessage" :key="indx"> |
|
218 |
- <td>{{ indx + 1 }}</td> |
|
219 |
- <td>{{ itm.time }}</td> |
|
220 |
- <td>{{ itm.message }}</td> |
|
221 |
- <td>{{ itm.result }}</td> |
|
222 |
- </tr> |
|
223 |
- </tbody> |
|
224 |
- </table> |
|
225 |
- </div> |
|
226 |
- </div> |
|
227 |
- </SplitterPanel> |
|
228 |
- </Splitter> |
|
229 |
- </div> |
|
230 | 202 |
</div> |
231 |
- </SplitterPanel> |
|
232 |
- </Splitter> |
|
233 |
- </div> |
|
203 |
+ </div> |
|
204 |
+ </div> |
|
205 |
+ </template> |
|
234 | 206 |
</div> |
235 | 207 |
<DBConSearch :openPopup="openSearchModal" @modalclose="dbConSearchOpen" @selectItm="selectDbcon" /> |
236 | 208 |
</template> |
... | ... | @@ -514,4 +486,4 @@ |
514 | 486 |
overflow-y: auto; |
515 | 487 |
overflow-x: hidden; |
516 | 488 |
} |
517 |
-</style>(파일 끝에 줄바꿈 문자 없음) |
|
489 |
+</style> |
--- client/views/component/connection/modalContents/FileRead.vue
+++ client/views/component/connection/modalContents/FileRead.vue
... | ... | @@ -1,11 +1,11 @@ |
1 | 1 |
<template> |
2 | 2 |
<template v-if="currentPage == 1"> |
3 | 3 |
<div class="modal-content-monthly"> |
4 |
- <FileManagementMain type="modal" @onSelected="fnChangeTarget" /> |
|
4 |
+ <div style="height: 100%; min-height: 60dvh;"> |
|
5 |
+ <FileManagementMain type="modal" @onSelected="fnChangeTarget" /> |
|
6 |
+ </div> |
|
5 | 7 |
</div> |
6 |
- <div |
|
7 |
- style="margin-bottom: 15px; padding-top: 15px; border-top: 1px solid #eee" |
|
8 |
- > |
|
8 |
+ <div style="margin-bottom: 15px; padding-top: 15px; border-top: 1px solid #eee"> |
|
9 | 9 |
<table class="form-table"> |
10 | 10 |
<colgroup> |
11 | 11 |
<col style="width: 20%" /> |
... | ... | @@ -34,17 +34,13 @@ |
34 | 34 |
<thead> |
35 | 35 |
<tr> |
36 | 36 |
<th>No</th> |
37 |
- <th v-for="(rowKey, index) of rowKeys" :key="index"> |
|
38 |
- {{ rowKey }} |
|
39 |
- </th> |
|
37 |
+ <th v-for="(rowKey, index) of rowKeys" :key="index"> {{ rowKey }} </th> |
|
40 | 38 |
</tr> |
41 | 39 |
</thead> |
42 | 40 |
<tbody> |
43 | 41 |
<tr v-for="(items, indexI) of rowData" :key="indexI"> |
44 | 42 |
<td>{{ indexI + 1 }}</td> |
45 |
- <td v-for="(item, indexJ) of items" :key="indexJ"> |
|
46 |
- {{ item }} |
|
47 |
- </td> |
|
43 |
+ <td v-for="(item, indexJ) of items" :key="indexJ"> {{ item }} </td> |
|
48 | 44 |
</tr> |
49 | 45 |
</tbody> |
50 | 46 |
</template> |
... | ... | @@ -55,7 +51,6 @@ |
55 | 51 |
</div> |
56 | 52 |
</template> |
57 | 53 |
</template> |
58 |
- |
|
59 | 54 |
<script> |
60 | 55 |
import axios from "axios"; |
61 | 56 |
import FileManagementMain from "../../../pages/data/filemanger/FileManagementMain.vue"; |
... | ... | @@ -84,9 +79,9 @@ |
84 | 79 |
}; |
85 | 80 |
}, |
86 | 81 |
|
87 |
- created() {}, |
|
82 |
+ created() { }, |
|
88 | 83 |
|
89 |
- mounted() {}, |
|
84 |
+ mounted() { }, |
|
90 | 85 |
|
91 | 86 |
watch: { |
92 | 87 |
jobItem(value) { |
--- client/views/component/dataComponent/DbConnectionSearchModal.vue
+++ client/views/component/dataComponent/DbConnectionSearchModal.vue
... | ... | @@ -13,18 +13,15 @@ |
13 | 13 |
<div class="flex justify-end flex100"> |
14 | 14 |
<div class="search-bar"> |
15 | 15 |
<div class="flex justify-end align-center"> |
16 |
- <input type="date" name="start-date" id="start-date" class="square-date" |
|
17 |
- :class="{ 'date-placeholder': false }" data-placeholder="날짜 선택" v-model="search_date.value" /> |
|
16 |
+ <input type="date" name="start-date" id="start-date" class="square-date" :class="{ 'date-placeholder': false }" data-placeholder="날짜 선택" v-model="search_date.value" /> |
|
18 | 17 |
<span class="coupler">~</span> |
19 |
- <input type="date" name="end-date" id="end-date" class="square-date" |
|
20 |
- :class="{ 'date-placeholder': false }" data-placeholder="날짜 선택" v-model="search_date.value2" /> |
|
18 |
+ <input type="date" name="end-date" id="end-date" class="square-date" :class="{ 'date-placeholder': false }" data-placeholder="날짜 선택" v-model="search_date.value2" /> |
|
21 | 19 |
<select name="" id="searchItm1" class="square-select" v-model="search_data.key"> |
22 | 20 |
<option value="conect_nm">연계명</option> |
23 | 21 |
<option value="conect_ip">접속IP</option> |
24 | 22 |
</select> |
25 | 23 |
<div class="search-square"> |
26 |
- <input type="text" class="square-input" placeholder="Search" v-model="search_data.value" |
|
27 |
- v-on:keyup.enter="searchData()" /> |
|
24 |
+ <input type="text" class="square-input" placeholder="Search" v-model="search_data.value" v-on:keyup.enter="searchData()" /> |
|
28 | 25 |
<button class="square-button" @click="searchData()"> |
29 | 26 |
<svg-icon type="mdi" :path="this.$getIconPath()" class="square-icon"></svg-icon> |
30 | 27 |
</button> |
... | ... | @@ -36,9 +33,7 @@ |
36 | 33 |
<div class="table-zone flex90"> |
37 | 34 |
<div class="list-info flex justify-between align-center"> |
38 | 35 |
<div class="count-zone"> |
39 |
- <p> |
|
40 |
- 총 <span>{{ search.totalRows }}</span>건 |
|
41 |
- </p> |
|
36 |
+ <p> 총 <span>{{ search.totalRows }}</span>건 </p> |
|
42 | 37 |
</div> |
43 | 38 |
<div class="cunt-selectZone"> |
44 | 39 |
<select id="pageCount" v-model="search.perPage"> |
... | ... | @@ -84,15 +79,12 @@ |
84 | 79 |
<td>{{ itm.creatId }}</td> |
85 | 80 |
<td>{{ $filters.dateTime(itm.creatDt) }}</td> |
86 | 81 |
<td> |
87 |
- <button class="blue-border-btn small-btn" @click="selectItm(itm)"> |
|
88 |
- 선택 |
|
89 |
- </button> |
|
82 |
+ <button class="blue-border-btn small-btn" @click="selectItm(itm)"> 선택 </button> |
|
90 | 83 |
</td> |
91 | 84 |
</tr> |
92 | 85 |
</tbody> |
93 | 86 |
</table> |
94 |
- <PaginationButton v-model:currentPage="search.currentPage" :perPage="search.perPage" |
|
95 |
- :totalCount="search.totalRows" :maxRange="5" :click="searchData" /> |
|
87 |
+ <PaginationButton v-model:currentPage="search.currentPage" :perPage="search.perPage" :totalCount="search.totalRows" :maxRange="5" :click="searchData" /> |
|
96 | 88 |
</div> |
97 | 89 |
</div> |
98 | 90 |
</div> |
... | ... | @@ -102,14 +94,10 @@ |
102 | 94 |
</div> |
103 | 95 |
</div> |
104 | 96 |
</template> |
105 |
- |
|
106 | 97 |
<script> |
107 |
-import CodeList from "../../component/common/Component_CodeList.vue"; |
|
108 | 98 |
import axios from "axios"; |
109 | 99 |
import SvgIcon from "@jamescoyle/vue-icon"; |
110 |
-import PageNavigation from "../../component/PageNavigation.vue"; |
|
111 | 100 |
import PaginationButton from "../../component/PaginationButton.vue"; |
112 |
-import moment from "moment"; |
|
113 | 101 |
|
114 | 102 |
export default { |
115 | 103 |
name: "dbcon-search", |
... | ... | @@ -185,8 +173,6 @@ |
185 | 173 |
}, |
186 | 174 |
}, |
187 | 175 |
computed: { |
188 |
- CodeList: CodeList, |
|
189 |
- PageNavigation: PageNavigation, |
|
190 | 176 |
SvgIcon: SvgIcon, |
191 | 177 |
PaginationButton: PaginationButton, |
192 | 178 |
}, |
+++ client/views/component/modal/connection/DbReadModal.vue
... | ... | @@ -0,0 +1,593 @@ |
1 | +<template> | |
2 | + <div class="modal-wrapper"> | |
3 | + <div class="modal-container large-modal"> | |
4 | + <div class="modal-title flex justify-between align-center"> | |
5 | + <h2>데이터베이스 읽기</h2> | |
6 | + <button class="close-btn" @click="$emit('onClose')"> | |
7 | + <svg-icon type="mdi" :width="20" :height="20" :path="closePath"></svg-icon> | |
8 | + </button> | |
9 | + </div> | |
10 | + <div class="modal-content-monthly"> | |
11 | + <!-- 페이지 1: 데이터베이스 연결 설정 --> | |
12 | + <template v-if="currentPage == 1"> | |
13 | + <!-- 데이터베이스 정보 --> | |
14 | + <div class="content-titleZone flex justy justify-between align-center"> | |
15 | + <p class="box-title">데이터베이스 정보</p> | |
16 | + </div> | |
17 | + <table class="form-table"> | |
18 | + <colgroup> | |
19 | + <col style="width: 20%" /> | |
20 | + <col style="width: 80%" /> | |
21 | + </colgroup> | |
22 | + <tbody> | |
23 | + <tr> | |
24 | + <th>연계정보 타입</th> | |
25 | + <td> | |
26 | + <div class="input-container flex"> | |
27 | + <label class="radio-label"> | |
28 | + <input type="radio" name="radio" :value="false" class="custom-radiobox" @change="onConnectionTypeChange(false)" v-model="jobItm.itm_option_bool" /> | |
29 | + <span>직접입력</span> | |
30 | + </label> | |
31 | + <label class="radio-label"> | |
32 | + <input type="radio" name="radio" :value="true" class="custom-radiobox" @change="onConnectionTypeChange(true)" v-model="jobItm.itm_option_bool" /> | |
33 | + <span>불러오기</span> | |
34 | + </label> | |
35 | + </div> | |
36 | + </td> | |
37 | + </tr> | |
38 | + <!-- 연계정보 불러오기 선택 시 --> | |
39 | + <tr v-show="jobItm.itm_option_bool"> | |
40 | + <th>연계정보</th> | |
41 | + <td> | |
42 | + <input type="text" class="half-input" disabled :value="getConnectionDisplayText()" /> | |
43 | + <button class="blue-border-btn small-btn" @click="dbConSearchOpen(true)">검색</button> | |
44 | + </td> | |
45 | + </tr> | |
46 | + <tr> | |
47 | + <th>DMBS</th> | |
48 | + <td> | |
49 | + <select id="databaseType" @change="successAt = false" class="square-select half-input" v-model="currentConnectionDB.databaseType" :disabled="jobItm.itm_option_bool"> | |
50 | + <option v-for="(itm, index) in databaseTypeList" :key="index" :value="itm.key">{{ itm.value }}</option> | |
51 | + </select> | |
52 | + </td> | |
53 | + </tr> | |
54 | + <tr> | |
55 | + <th>IP</th> | |
56 | + <td> | |
57 | + <input id="conectIp" type="text" @input="successAt = false" class="half-input" v-model="currentConnectionDB.conectIp" placeholder="ex. 127.0.0.1" :disabled="jobItm.itm_option_bool" /> | |
58 | + </td> | |
59 | + </tr> | |
60 | + <tr> | |
61 | + <th>PORT</th> | |
62 | + <td> | |
63 | + <input id="conectPort" type="text" @input="successAt = false" class="half-input" v-model="currentConnectionDB.conectPort" :disabled="jobItm.itm_option_bool" /> | |
64 | + </td> | |
65 | + </tr> | |
66 | + <tr> | |
67 | + <th>DB 명</th> | |
68 | + <td> | |
69 | + <input id="databaseNm" type="text" @input="successAt = false" class="half-input" v-model="currentConnectionDB.databaseNm" placeholder="데이터베이스명 OR 스키마명" :disabled="jobItm.itm_option_bool" /> | |
70 | + </td> | |
71 | + </tr> | |
72 | + <tr> | |
73 | + <th>접속ID</th> | |
74 | + <td> | |
75 | + <input type="text" class="half-input" @input="successAt = false" v-model="currentConnectionDB.userId" placeholder="접속 ID" :disabled="jobItm.itm_option_bool" /> | |
76 | + </td> | |
77 | + </tr> | |
78 | + <tr> | |
79 | + <th>접속PW</th> | |
80 | + <td> | |
81 | + <input type="password" class="half-input" @input="successAt = false" v-model="currentConnectionDB.userPassword" placeholder="접속 PW" autocomplete="new-password" :disabled="jobItm.itm_option_bool" /> | |
82 | + </td> | |
83 | + </tr> | |
84 | + </tbody> | |
85 | + </table> | |
86 | + <!-- 데이터베이스 연결 결과 --> | |
87 | + <div class="content-titleZone flex justy justify-between align-center mt20"> | |
88 | + <p class="box-title">데이터베이스 연결 결과</p> | |
89 | + <button class="blue-border-btn small-btn" @click="dataBaseConnectionCheck">접속확인</button> | |
90 | + </div> | |
91 | + <div class="table-zone"> | |
92 | + <table class="list-table"> | |
93 | + <colgroup> | |
94 | + <col width="10%" /> | |
95 | + <col width="70%" /> | |
96 | + <col width="20%" /> | |
97 | + </colgroup> | |
98 | + <thead> | |
99 | + <tr> | |
100 | + <th>No</th> | |
101 | + <th>접속결과</th> | |
102 | + <th>접속시간</th> | |
103 | + </tr> | |
104 | + </thead> | |
105 | + <tbody> | |
106 | + <tr v-for="(itm, idx) in resultMessage" :key="idx"> | |
107 | + <td>{{ idx + 1 }}</td> | |
108 | + <td>{{ itm.message }}</td> | |
109 | + <td>{{ itm.time }}</td> | |
110 | + </tr> | |
111 | + </tbody> | |
112 | + </table> | |
113 | + </div> | |
114 | + </template> | |
115 | + <!-- 페이지 2: 쿼리 관리 --> | |
116 | + <template v-if="currentPage == 2"> | |
117 | + <div class="flex content-box" style="min-height: 60dvh; flex-wrap: nowrap;"> | |
118 | + <div class="content-box pd10" style="width: 20%;"> | |
119 | + <div class="content-titleZone flex justy justify-between align-center" style="height: 45px"> | |
120 | + <p class="box-title">데이터베이스 정보</p> | |
121 | + </div> | |
122 | + <div class="content-zone2"> | |
123 | + <ul class="content-list" v-if="tableList.length > 0"> | |
124 | + <li class="cursor" v-for="(item, indx) in tableList" :key="indx"> | |
125 | + <a @click="getTableData(item)" :class="{ | |
126 | + 'file-list': true, | |
127 | + selected: selectTable === item, | |
128 | + }"> | |
129 | + <div class="flex align-center"> | |
130 | + <p>{{ getTableDisplayName(item) }}</p> | |
131 | + </div> | |
132 | + </a> | |
133 | + </li> | |
134 | + </ul> | |
135 | + </div> | |
136 | + </div> | |
137 | + <div class="content-box" style="width: 80%;"> | |
138 | + <div class="flex-column"> | |
139 | + <div class="content-box pd10" style="height: 50%;"> | |
140 | + <div class="content-titleZone flex justy justify-between align-center" style="height: 45px"> | |
141 | + <p class="box-title">쿼리 작업</p> | |
142 | + <button class="icon-btn" @click="executeQuery" title="실행"> | |
143 | + <svg-icon type="mdi" :path="playPath" :color="'#fbbe28'"></svg-icon> | |
144 | + </button> | |
145 | + </div> | |
146 | + <div class="flex" style="height: calc(100% - 60px)"> | |
147 | + <textarea style="resize: none; width: 100%; height: 100%; padding: 10px;" v-model="jobItm.itm.query"></textarea> | |
148 | + </div> | |
149 | + </div> | |
150 | + <div class="content-box pd10" style="height: 50%;"> | |
151 | + <ul class="tab-nav flex justify-start"> | |
152 | + <li @click="showTab('tab1')"> | |
153 | + <a href="#tab01" :class="{ activeTab: activeTab === 'tab1' }">작업결과</a> | |
154 | + </li> | |
155 | + <li @click="showTab('tab2')"> | |
156 | + <a href="#tab02" :class="{ activeTab: activeTab === 'tab2' }">작업log</a> | |
157 | + </li> | |
158 | + </ul> | |
159 | + <div v-show="activeTab === 'tab1'" class="content-box" style="height: calc(100% - 45px); padding: 10px;"> | |
160 | + <div class="count-zone mb10" v-if="jobItm.dataTable.columnDatas.length > 0"> | |
161 | + <p>총 <span>{{ jobItm.dataTable.totalRows }}</span>건 중 <span>{{ jobItm.dataTable.rowData.length }}</span>건 조회</p> | |
162 | + </div> | |
163 | + <div style="height: calc(100% - 15px); overflow: auto;"> | |
164 | + <table class="list-table"> | |
165 | + <thead> | |
166 | + <tr v-if="jobItm.dataTable.columnDatas.length > 0"> | |
167 | + <th v-for="(itm, indx) in jobItm.dataTable.columnDatas" :key="indx" style="min-width: 150px !important"> {{ itm.columnNm }} <label class="check-label"> | |
168 | + <input type="checkbox" class="custom-checkbox" v-model="itm.pkAt" /> | |
169 | + </label> | |
170 | + </th> | |
171 | + </tr> | |
172 | + </thead> | |
173 | + <tbody v-if="jobItm.dataTable.rowData.length > 0"> | |
174 | + <tr v-for="(row, rows) in jobItm.dataTable.rowData" :key="rows"> | |
175 | + <td v-for="(itm, indx) in row" :key="indx" style="overflow: hidden; white-space: nowrap; text-overflow: ellipsis;"> {{ itm }} </td> | |
176 | + </tr> | |
177 | + </tbody> | |
178 | + </table> | |
179 | + </div> | |
180 | + </div> | |
181 | + <div v-show="activeTab === 'tab2'" class=" content-box" style="height: calc(100% - 45px); padding: 10px;"> | |
182 | + <div style="height: calc(100% - 15px); overflow: auto;"> | |
183 | + <table class="list-table"> | |
184 | + <colgroup> | |
185 | + <col width="10%" /> | |
186 | + <col width="60%" /> | |
187 | + <col width="20%" /> | |
188 | + <col width="10%" /> | |
189 | + </colgroup> | |
190 | + <thead> | |
191 | + <tr> | |
192 | + <th>No</th> | |
193 | + <th>접속내용</th> | |
194 | + <th>접속시간</th> | |
195 | + <th>접속결과</th> | |
196 | + </tr> | |
197 | + </thead> | |
198 | + <tbody> | |
199 | + <tr v-for="(itm, indx) in executeMessage" :key="indx"> | |
200 | + <td>{{ indx + 1 }}</td> | |
201 | + <td>{{ itm.message }}</td> | |
202 | + <td>{{ itm.time }}</td> | |
203 | + <td>{{ itm.result }}</td> | |
204 | + </tr> | |
205 | + </tbody> | |
206 | + </table> | |
207 | + </div> | |
208 | + </div> | |
209 | + </div> | |
210 | + </div> | |
211 | + </div> | |
212 | + </div> | |
213 | + </template> | |
214 | + </div> | |
215 | + <!-- 모달 하단 버튼 영역 --> | |
216 | + <div class="modal-end flex justify-end"> | |
217 | + <button class="blue-border-btn small-btn" v-if="currentPage == 2" @click="moveTo('prev')">이전</button> | |
218 | + <button class="blue-border-btn small-btn" v-if="currentPage == 1" @click="moveTo('next')">다음</button> | |
219 | + <button class="blue-btn small-btn" v-if="isDataSet" @click="fnSave">등록</button> | |
220 | + <button class="blue-border-btn small-btn" @click="$emit('onClose')">취소</button> | |
221 | + </div> | |
222 | + </div> | |
223 | + </div> | |
224 | + <DBConSearch :openPopup="openSearchModal" @modalclose="dbConSearchOpen" @selectItm="selectDbcon" /> | |
225 | +</template> | |
226 | +<script> | |
227 | +import _ from "lodash"; | |
228 | +import axios from "axios"; | |
229 | + | |
230 | +// icon용 svg import | |
231 | +import SvgIcon from "@jamescoyle/vue-icon"; | |
232 | +import { mdiMagnify, mdiClose, mdiPlay } from "@mdi/js"; | |
233 | + | |
234 | +// 컴포넌트 | |
235 | +import DBConSearch from "../../dataComponent/DbConnectionSearchModal.vue"; | |
236 | + | |
237 | +export default { | |
238 | + name: "DatabaseConnectionModal", | |
239 | + | |
240 | + components: { | |
241 | + SvgIcon, | |
242 | + DBConSearch | |
243 | + }, | |
244 | + | |
245 | + props: { | |
246 | + currentJobItm: String, | |
247 | + jobItem: Object | |
248 | + }, | |
249 | + | |
250 | + data() { | |
251 | + return { | |
252 | + // icon용 svg path | |
253 | + searchPath: mdiMagnify, | |
254 | + closePath: mdiClose, | |
255 | + playPath: mdiPlay, | |
256 | + | |
257 | + // 페이지 관련 | |
258 | + currentPage: 1, | |
259 | + activeTab: "tab1", | |
260 | + | |
261 | + // 상태 관리 | |
262 | + successAt: false, // 연결 성공 여부 | |
263 | + isDataSet: false, // 데이터 설정 여부 추가 | |
264 | + | |
265 | + // 데이터 객체들 | |
266 | + jobItm: { | |
267 | + itm: null, | |
268 | + itm_option_bool: false, | |
269 | + dataTable: { | |
270 | + columnDatas: [], | |
271 | + rowData: [], | |
272 | + totalRows: 0, | |
273 | + perPage: 10, | |
274 | + query: "" | |
275 | + } | |
276 | + }, | |
277 | + | |
278 | + // 연계정보 관리 | |
279 | + openSearchModal: false, | |
280 | + linkConnectionDB: {}, | |
281 | + inputConnectionDB: { | |
282 | + databaseType: "", | |
283 | + conectIp: "", | |
284 | + conectPort: "", | |
285 | + databaseNm: "", | |
286 | + userId: "", | |
287 | + userPassword: "" | |
288 | + }, | |
289 | + // 현재 표시되는 연결 정보 (직접입력/불러오기 모두 대응) | |
290 | + currentConnectionDB: { | |
291 | + databaseType: "", | |
292 | + conectIp: "", | |
293 | + conectPort: "", | |
294 | + databaseNm: "", | |
295 | + userId: "", | |
296 | + userPassword: "" | |
297 | + }, | |
298 | + | |
299 | + // 데이터 목록 | |
300 | + databaseTypeList: [], | |
301 | + tableList: [], | |
302 | + selectTable: {}, | |
303 | + | |
304 | + // 로그 메시지 | |
305 | + resultMessage: [], | |
306 | + executeMessage: [] | |
307 | + }; | |
308 | + }, | |
309 | + | |
310 | + watch: { | |
311 | + jobItem: { | |
312 | + handler(newVal) { | |
313 | + if (newVal) { | |
314 | + this.jobItm = _.cloneDeep(newVal); | |
315 | + if (this.jobItm.itm_option_bool) { | |
316 | + this.linkConnectionDB = this.jobItm.itm || {}; | |
317 | + this.currentConnectionDB = _.cloneDeep(this.linkConnectionDB); | |
318 | + } else { | |
319 | + this.inputConnectionDB = this.jobItm.itm || {}; | |
320 | + this.currentConnectionDB = _.cloneDeep(this.inputConnectionDB); | |
321 | + } | |
322 | + } | |
323 | + }, | |
324 | + immediate: true | |
325 | + }, | |
326 | + }, | |
327 | + | |
328 | + created() { | |
329 | + this.initializeComponent(); | |
330 | + }, | |
331 | + | |
332 | + mounted() { | |
333 | + this.init(); | |
334 | + }, | |
335 | + | |
336 | + methods: { | |
337 | + // 초기화 함수들 | |
338 | + initializeComponent() { | |
339 | + if (!this.$isEmpty(this.currentJobItm)) { | |
340 | + let currentJobItm = JSON.parse(this.currentJobItm); | |
341 | + if (!this.$isEmpty(currentJobItm)) { | |
342 | + this.jobItm = _.cloneDeep(currentJobItm); | |
343 | + } | |
344 | + } | |
345 | + | |
346 | + if (!this.jobItm.itm) { | |
347 | + this.jobItm.itm = _.cloneDeep(this.$getDefaultJobGroup().connectionDb || {}); | |
348 | + } | |
349 | + }, | |
350 | + | |
351 | + async init() { | |
352 | + this.databaseTypeList = await this.$getDataBaseTypeList(); | |
353 | + | |
354 | + if (this.jobItm == null) { | |
355 | + this.jobItm = _.cloneDeep(this.$getDefaultJobGroup().node || {}); | |
356 | + this.linkConnectionDB = _.cloneDeep(this.$getDefaultJobGroup().connectionDb || {}); | |
357 | + this.inputConnectionDB = _.cloneDeep(this.$getDefaultJobGroup().connectionDb || {}); | |
358 | + this.jobItm.itm = _.cloneDeep(this.$getDefaultJobGroup().connectionDb || {}); | |
359 | + } else { | |
360 | + if (this.jobItm.itm_option_bool) { | |
361 | + this.linkConnectionDB = _.cloneDeep(this.jobItm.itm) || {}; | |
362 | + this.currentConnectionDB = _.cloneDeep(this.linkConnectionDB); | |
363 | + } else { | |
364 | + this.inputConnectionDB = _.cloneDeep(this.jobItm.itm) || {}; | |
365 | + this.currentConnectionDB = _.cloneDeep(this.inputConnectionDB); | |
366 | + } | |
367 | + } | |
368 | + | |
369 | + if (!this.inputConnectionDB.databaseType && this.databaseTypeList.MARIADB) { | |
370 | + this.inputConnectionDB.databaseType = this.databaseTypeList.MARIADB.key; | |
371 | + if (!this.jobItm.itm_option_bool) { | |
372 | + this.currentConnectionDB.databaseType = this.databaseTypeList.MARIADB.key; | |
373 | + } | |
374 | + } | |
375 | + }, | |
376 | + | |
377 | + // 연결 타입 변경 시(직접입력/불러오기) 입력 필드 업데이트 | |
378 | + onConnectionTypeChange(isImport) { | |
379 | + this.successAt = false; | |
380 | + if (isImport) { | |
381 | + // 불러오기 선택 시 | |
382 | + this.currentConnectionDB = _.cloneDeep(this.linkConnectionDB); | |
383 | + } else { | |
384 | + // 직접입력 선택 시 | |
385 | + this.currentConnectionDB = _.cloneDeep(this.inputConnectionDB); | |
386 | + } | |
387 | + }, | |
388 | + | |
389 | + // 유틸리티 함수들 | |
390 | + getConnectionDisplayText() { | |
391 | + return this.linkConnectionDB.conectNm | |
392 | + ? `${this.linkConnectionDB.conectNm}(${this.linkConnectionDB.conectIp})` | |
393 | + : ""; | |
394 | + }, | |
395 | + | |
396 | + getTableDisplayName(item) { | |
397 | + return item.tableNmKr && item.tableNmKr !== "" ? item.tableNmKr : item.tableNm; | |
398 | + }, | |
399 | + | |
400 | + // 데이터베이스 연결 관리 | |
401 | + dataBaseConnectionCheck() { | |
402 | + if (this.jobItm.itm_option_bool) { | |
403 | + // 불러오기 모드일 때 linkConnectionDB 사용 | |
404 | + this.jobItm.itm = _.cloneDeep(this.linkConnectionDB); | |
405 | + } else { | |
406 | + // 직접입력 모드일 때 currentConnectionDB에서 업데이트된 값 가져옴 | |
407 | + this.inputConnectionDB = _.cloneDeep(this.currentConnectionDB); | |
408 | + this.jobItm.itm = _.cloneDeep(this.inputConnectionDB); | |
409 | + } | |
410 | + | |
411 | + this.jobItm.itm.loadAt = this.jobItm.itm_option_bool; | |
412 | + | |
413 | + if (this.jobItm.itm.type) { | |
414 | + delete this.jobItm.itm.type; | |
415 | + } | |
416 | + | |
417 | + axios({ | |
418 | + url: "/data/dataBaseConnectionCheck.json", | |
419 | + method: "post", | |
420 | + headers: { "Content-Type": "application/json; charset=UTF-8" }, | |
421 | + data: this.jobItm.itm | |
422 | + }) | |
423 | + .then(response => { | |
424 | + const checkMessage = response.data.checkMessage || {}; | |
425 | + this.successAt = checkMessage.success === true; | |
426 | + this.$emit("onDfltSetChange", checkMessage.success); | |
427 | + this.$showAlert("결과내용", checkMessage.message); | |
428 | + | |
429 | + this.resultMessage.push({ | |
430 | + time: this.$getFullTime(), | |
431 | + message: checkMessage.message, | |
432 | + result: checkMessage.success ? "접속성공" : "접속실패" | |
433 | + }); | |
434 | + }) | |
435 | + .catch(error => { | |
436 | + console.error("Database connection check error:", error); | |
437 | + this.successAt = false; | |
438 | + this.$emit("onDfltSetChange", false); | |
439 | + }); | |
440 | + }, | |
441 | + | |
442 | + // 연계정보 관리 | |
443 | + dbConSearchOpen(val) { | |
444 | + this.openSearchModal = val; | |
445 | + }, | |
446 | + | |
447 | + selectDbcon(dbcon) { | |
448 | + this.linkConnectionDB = _.cloneDeep(dbcon); | |
449 | + // 불러오기 모드이면 현재 표시되는 필드 업데이트 | |
450 | + if (this.jobItm.itm_option_bool) { | |
451 | + this.currentConnectionDB = _.cloneDeep(this.linkConnectionDB); | |
452 | + } | |
453 | + }, | |
454 | + | |
455 | + getTableData(item) { | |
456 | + this.selectTable = item; | |
457 | + | |
458 | + const requestData = { | |
459 | + dataset: { ...item, perPage: this.jobItm.dataTable.perPage }, | |
460 | + connectionDB: { ...this.jobItm.itm, creatDt: null } | |
461 | + }; | |
462 | + | |
463 | + axios({ | |
464 | + url: "/data/getTableData.json", | |
465 | + method: "post", | |
466 | + headers: { "Content-Type": "application/json; charset=UTF-8" }, | |
467 | + data: requestData | |
468 | + }) | |
469 | + .then(response => { | |
470 | + if (response.data.checkMessage.success) { | |
471 | + this.jobItm.dataTable = response.data.resultData.dataTable; | |
472 | + this.jobItm.itm_id = this.jobItm.itm.dbConectId; | |
473 | + this.jobItm.itm.query = this.jobItm.dataTable.query; | |
474 | + this.isDataSet = true; | |
475 | + } else { | |
476 | + this.isDataSet = false; | |
477 | + } | |
478 | + | |
479 | + const checkMessage = response.data.resultData.dataTable.checkMessage || {}; | |
480 | + this.executeMessage.push({ | |
481 | + time: this.$getFullTime(), | |
482 | + message: checkMessage.message, | |
483 | + result: checkMessage.success ? "성공" : "실패" | |
484 | + }); | |
485 | + }) | |
486 | + .catch(error => { | |
487 | + console.error("Get table data error:", error); | |
488 | + this.isDataSet = false; | |
489 | + }); | |
490 | + }, | |
491 | + | |
492 | + executeQuery() { | |
493 | + const requestData = { | |
494 | + dataTable: { | |
495 | + ...this.jobItm.dataTable, | |
496 | + query: this.jobItm.itm.query | |
497 | + }, | |
498 | + connectionDB: { | |
499 | + ...this.jobItm.itm, | |
500 | + creatDt: null | |
501 | + } | |
502 | + }; | |
503 | + | |
504 | + axios({ | |
505 | + url: "/data/getTableDataByQuery.json", | |
506 | + method: "post", | |
507 | + headers: { "Content-Type": "application/json; charset=UTF-8" }, | |
508 | + data: requestData | |
509 | + }) | |
510 | + .then(response => { | |
511 | + if (response.data.checkMessage.success) { | |
512 | + this.jobItm.dataTable = response.data.resultData.dataTable; | |
513 | + this.jobItm.itm_id = this.jobItm.itm.dbConectId; | |
514 | + this.jobItm.itm.query = this.jobItm.dataTable.query; | |
515 | + this.isDataSet = true; | |
516 | + } else { | |
517 | + this.isDataSet = false; | |
518 | + } | |
519 | + | |
520 | + const checkMessage = response.data.resultData.dataTable.checkMessage || {}; | |
521 | + this.executeMessage.push({ | |
522 | + time: this.$getFullTime(), | |
523 | + message: checkMessage.message, | |
524 | + result: checkMessage.success ? "성공" : "실패" | |
525 | + }); | |
526 | + }) | |
527 | + .catch(error => { | |
528 | + console.error("Execute query error:", error); | |
529 | + this.isDataSet = false; | |
530 | + }); | |
531 | + }, | |
532 | + | |
533 | + showTab(tabName) { | |
534 | + this.activeTab = tabName; | |
535 | + }, | |
536 | + | |
537 | + moveTo(type) { | |
538 | + if (type === 'prev') { | |
539 | + this.currentPage = 1; | |
540 | + this.tableList = []; // 초기화 | |
541 | + this.jobItm.dataTable = { | |
542 | + columnDatas: [], | |
543 | + rowData: [], | |
544 | + totalRows: 0, | |
545 | + perPage: 10, | |
546 | + query: "" | |
547 | + }; // 초기화 | |
548 | + } else if (type === 'next') { | |
549 | + if (!this.successAt) { | |
550 | + this.$showAlert("경고", "접속에 성공한 경우에만 진행할 수 있습니다."); | |
551 | + } else { | |
552 | + this.getDbConnectionTableList(); // 테이블 및 쿼리 관리 | |
553 | + } | |
554 | + } else { | |
555 | + this.$showAlert("오류", "올바르지 않은 요청입니다."); | |
556 | + } | |
557 | + }, | |
558 | + | |
559 | + // 테이블 및 쿼리 관리 | |
560 | + getDbConnectionTableList() { | |
561 | + axios({ | |
562 | + url: "/data/selectTableList.json", | |
563 | + method: "post", | |
564 | + headers: { "Content-Type": "application/json; charset=UTF-8" }, | |
565 | + data: this.jobItm.itm | |
566 | + }) | |
567 | + .then(response => { | |
568 | + if (response.data.checkMessage.success) { | |
569 | + this.tableList = response.data.resultData.tableList || []; | |
570 | + this.currentPage = 2; | |
571 | + } | |
572 | + }) | |
573 | + .catch(error => { | |
574 | + console.error("Get table list error:", error); | |
575 | + this.tableList = []; | |
576 | + }); | |
577 | + }, | |
578 | + | |
579 | + // 저장 | |
580 | + fnSave() { | |
581 | + this.$emit("onSave", this.jobItm); | |
582 | + } | |
583 | + } | |
584 | +}; | |
585 | +</script> | |
586 | +<style> | |
587 | +.content-zone2 { | |
588 | + height: calc(100% - 57px); | |
589 | + max-height: calc(100% - 57px); | |
590 | + overflow-y: auto; | |
591 | + overflow-x: hidden; | |
592 | +} | |
593 | +</style>(파일 끝에 줄바꿈 문자 없음) |
--- client/views/component/treeMenu/FileTreeModal.vue
+++ client/views/component/treeMenu/FileTreeModal.vue
... | ... | @@ -6,14 +6,12 @@ |
6 | 6 |
<h2>폴더 선택</h2> |
7 | 7 |
<button class="close-btn" @click="closeModal()"><svg-icon type="mdi" :width="20" :height="20" :path="closePath"></svg-icon></button> |
8 | 8 |
</div> |
9 |
- <div> |
|
10 |
- <h2>현재 경로</h2> |
|
11 |
- <p> |
|
12 |
- <span>{{ selectedPath }}</span> |
|
13 |
- </p> |
|
14 |
- </div> |
|
15 | 9 |
</div> |
16 | 10 |
<div class="modal-content-monthly"> |
11 |
+ <div class="content-titleZone flex justify-between align-center align-start"> |
|
12 |
+ <p class="box-title">현재 경로</p> |
|
13 |
+ <p>{{ selectedPath }}</p> |
|
14 |
+ </div> |
|
17 | 15 |
<TreeItem :connection="modalConnection" :closeModal="isCloseModal" v-for="(item, idx) in modalNodes" :item="item" :idx="item.id" :key="idx" @selectFolder="selectFolder" @selectItem="handleSelectItem" /> |
18 | 16 |
</div> |
19 | 17 |
<div class="modal-end flex justify-end"> |
... | ... | @@ -28,7 +26,6 @@ |
28 | 26 |
</div> |
29 | 27 |
</template> |
30 | 28 |
<script> |
31 |
-import axios from 'axios'; |
|
32 | 29 |
import SvgIcon from '@jamescoyle/vue-icon'; |
33 | 30 |
import TreeItem from './FileTree.vue'; |
34 | 31 |
import { mdiClose } from '@mdi/js'; |
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
... | ... | @@ -73,16 +73,17 @@ |
73 | 73 |
{ path: "/push.page", name: "Push", component: Push }, |
74 | 74 |
{ path: "/insertDBConnection.page", name: "InsertDBConnection", component: InsertDBConnection }, |
75 | 75 |
{ path: "/DBConnectionDetail.page", name: "DBConnectionDetail", component: DBConnectionDetail }, |
76 |
- { path: "/openApiList.page", name: "OpenApiList", component: OpenApiList }, |
|
77 |
- { path: "/openApiInsert.page", name: "OpenApiInsert", component: OpenApiInsert }, |
|
78 |
- { path: "/openApiListOne.page", name: "OpenApiSelectListOne", component: OpenApiSelectListOne }, |
|
79 |
- { path: "/openApiKeyList.page", name: "OpenApiKeyList", component: OpenApiKeyList }, |
|
80 | 76 |
{ path: "/gisInfoList.page", name: "GisInfoList", component: GisInfoList }, |
81 | 77 |
{ path: "/gisInfoInsert.page", name: "GisInfoInsert", component: GisInfoInsert }, |
82 | 78 |
{ path: "/gisInfoListOne.page", name: "GisInfoSelectListOne", component: GisInfoSelectListOne }, |
83 | 79 |
{ path: "/myPage.page", name: "myPage", component: myPage }, |
84 | 80 |
{ path: "/myPagePwd.page", name: "myPagePwd", component: myPagePwd }, |
85 | 81 |
{ path: "/login.page", name: "Login", component: Login }, |
82 |
+ // OPEN API |
|
83 |
+ { path: "/openApiList.page", name: "OpenApiList", component: OpenApiList }, |
|
84 |
+ { path: "/openApiInsert.page", name: "OpenApiInsert", component: OpenApiInsert }, |
|
85 |
+ { path: "/openApiListOne.page", name: "OpenApiSelectListOne", component: OpenApiSelectListOne }, |
|
86 |
+ { path: "/openApiKeyList.page", name: "OpenApiKeyList", component: OpenApiKeyList }, |
|
86 | 87 |
// 데이터활용관리 |
87 | 88 |
{ path: "/customSelectList.page", name: "CustomSelectList", component: CustomSelectList }, |
88 | 89 |
{ path: "/customSelectOne.page", name: "CustomSelectOne", component: CustomSelectOne }, |
--- client/views/pages/data/filemanger/FileManagementMain.vue
+++ client/views/pages/data/filemanger/FileManagementMain.vue
... | ... | @@ -1210,32 +1210,38 @@ |
1210 | 1210 |
async fileConfirm(type) { |
1211 | 1211 |
const vm = this; |
1212 | 1212 |
|
1213 |
- if ( |
|
1214 |
- !(await vm.$showConfirm( |
|
1215 |
- "파일 " + type, |
|
1216 |
- "선택한 파일을 " + type + " 하시겠습니까?" |
|
1217 |
- )) |
|
1218 |
- ) { |
|
1213 |
+ if (!(await vm.$showConfirm("파일 " + type, "선택한 파일을 " + type + " 하시겠습니까?"))) { |
|
1219 | 1214 |
return; |
1220 | 1215 |
} |
1221 | 1216 |
|
1222 | 1217 |
let file = vm.selectedFiles[0]; |
1223 | 1218 |
let index = file.path.lastIndexOf("/"); |
1224 | 1219 |
|
1225 |
- if (file.path.substring(0, index) === file.movePath) { |
|
1226 |
- vm.$showAlert( |
|
1227 |
- "파일 " + type, |
|
1228 |
- "현재 파일 경로와 동일합니다. 다른 경로를 선택해주세요." |
|
1229 |
- ); |
|
1220 |
+ // modalSeletedNode가 없으면 오류 메시지 표시 |
|
1221 |
+ if (!vm.modalSeletedNode) { |
|
1222 |
+ vm.$showAlert("파일 " + type, "대상 폴더를 선택해주세요."); |
|
1230 | 1223 |
return; |
1231 | 1224 |
} |
1232 | 1225 |
|
1226 |
+ // 현재 경로와 대상 경로가 같은지 확인 |
|
1227 |
+ if (file.path.substring(0, index) === vm.modalSeletedNode) { |
|
1228 |
+ vm.$showAlert("파일 " + type, "현재 파일 경로와 동일합니다. 다른 경로를 선택해주세요."); |
|
1229 |
+ return; |
|
1230 |
+ } |
|
1231 |
+ |
|
1232 |
+ let result; |
|
1233 | 1233 |
if (type === "복사") { |
1234 |
- vm.copy(vm.selectedFiles, "confirm", false); |
|
1234 |
+ result = await vm.copy(vm.selectedFiles, "confirm", false); |
|
1235 | 1235 |
} else { |
1236 |
- vm.move(vm.selectedFiles, [], "confirm", false); |
|
1236 |
+ result = await vm.move(vm.selectedFiles, [], "confirm", false); |
|
1237 |
+ } |
|
1238 |
+ |
|
1239 |
+ // 작업이 취소되었거나 실패한 경우 추가 메시지를 표시하지 않음 |
|
1240 |
+ if (result === false) { |
|
1241 |
+ return; |
|
1237 | 1242 |
} |
1238 | 1243 |
}, |
1244 |
+ |
|
1239 | 1245 |
async move(fileList, removeFolderList, type, check) { |
1240 | 1246 |
const vm = this; |
1241 | 1247 |
|
... | ... | @@ -1265,7 +1271,15 @@ |
1265 | 1271 |
"파일 이동", |
1266 | 1272 |
response.data.checkMessage.message |
1267 | 1273 |
); |
1268 |
- vm.move( |
|
1274 |
+ |
|
1275 |
+ // 취소 버튼 클릭 시 처리 |
|
1276 |
+ if (moveOrCopy && moveOrCopy.type === "cancel") { |
|
1277 |
+ vm.closeTreeModal(); |
|
1278 |
+ return false; // 취소 시 false 반환 |
|
1279 |
+ } |
|
1280 |
+ |
|
1281 |
+ // 계속 진행 |
|
1282 |
+ return vm.move( |
|
1269 | 1283 |
returnFileList, |
1270 | 1284 |
folderList, |
1271 | 1285 |
moveOrCopy.type, |
... | ... | @@ -1283,6 +1297,7 @@ |
1283 | 1297 |
} |
1284 | 1298 |
vm.$showAlert("파일 이동", response.data.checkMessage.message); |
1285 | 1299 |
vm.closeTreeModal(); |
1300 |
+ return true; // 성공 시 true 반환 |
|
1286 | 1301 |
} |
1287 | 1302 |
} catch (error) { |
1288 | 1303 |
vm.isLoading = false; // 로딩 해제 |
... | ... | @@ -1290,6 +1305,7 @@ |
1290 | 1305 |
vm.checkAll = false; |
1291 | 1306 |
vm.selectedFiles = []; |
1292 | 1307 |
vm.closeTreeModal(); |
1308 |
+ return false; // 오류 시 false 반환 |
|
1293 | 1309 |
} |
1294 | 1310 |
}, |
1295 | 1311 |
|
... | ... | @@ -1316,23 +1332,29 @@ |
1316 | 1332 |
"파일 복사", |
1317 | 1333 |
response.data.checkMessage.message |
1318 | 1334 |
); |
1319 |
- if (!moveOrCopy) { |
|
1320 |
- return; |
|
1321 |
- } else { |
|
1322 |
- vm.copy(returnFileList, moveOrCopy.type, moveOrCopy.checkBox); |
|
1335 |
+ |
|
1336 |
+ // 취소 버튼 클릭 시 처리 |
|
1337 |
+ if (moveOrCopy && moveOrCopy.type === "cancel") { |
|
1338 |
+ vm.closeTreeModal(); |
|
1339 |
+ return false; // 취소 시 false 반환 |
|
1323 | 1340 |
} |
1341 |
+ |
|
1342 |
+ // 계속 진행 |
|
1343 |
+ return vm.copy(returnFileList, moveOrCopy.type, moveOrCopy.checkBox); |
|
1324 | 1344 |
} else { |
1325 | 1345 |
vm.$showAlert("파일 복사", response.data.checkMessage.message); |
1326 | 1346 |
vm.checkAll = false; |
1327 | 1347 |
vm.selectedFiles = []; |
1328 | 1348 |
vm.closeTreeModal(); |
1349 |
+ return true; // 성공 시 true 반환 |
|
1329 | 1350 |
} |
1330 | 1351 |
} catch (error) { |
1331 | 1352 |
vm.isLoading = false; // 로딩 해제 |
1332 |
- vm.$showAlert("파일 복사", "파일 이동 오류, 관리자에게 문의하세요."); |
|
1353 |
+ vm.$showAlert("파일 복사", "파일 복사 오류, 관리자에게 문의하세요."); |
|
1333 | 1354 |
vm.checkAll = false; |
1334 | 1355 |
vm.selectedFiles = []; |
1335 | 1356 |
vm.closeTreeModal(); |
1357 |
+ return false; // 오류 시 false 반환 |
|
1336 | 1358 |
} |
1337 | 1359 |
}, |
1338 | 1360 |
|
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?