
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<template>
<div
v-show="isModalOpen"
class="modal-wrapper"
:style="isLoading ? { cursor: 'wait' } : {}"
>
<div v-if="isLoading" class="loading-overlay">
<div class="loading-div">
<span>LOADING </span>
<span class="anima">.</span>
<span class="anima">.</span>
<span class="anima">.</span>
</div>
</div>
<div class="modal-container list-modal">
<div class="modal-title">
<div class="flex justify-between align-center">
<h2 v-show="modeInfo == 'fileRead'">파일 읽기</h2>
<h2 v-show="modeInfo == 'fileWrite'">파일 쓰기</h2>
<button class="close-btn" @click="cancelModal()">X</button>
</div>
</div>
<div class="modal-content-monthly" v-show="currentPage == 1">
<div class="content-wrap">
<div class="content-box flex justify-between">
<div class="flex20 content-box">
<div class="left-content flex100 content-box">
<div class="content-box">
<div class="mb10">
<div class="content-titleZone">
<p class="box-title">호스트 선택</p>
</div>
<div class="flex align-center justify-between no-gutter">
<div class="flex100">
<select
name=""
id=""
class="only full-select"
v-model="selectedHostCode"
>
<option :value="null" disabled>선택</option>
<option
v-for="(host, idx) in hostList"
:key="idx"
:value="host.host_code"
>
{{ host.host_nm + " - (" + host.host_ip + ")" }}
</option>
</select>
</div>
<div class="flex100">
<button
class="blue-border-btn large-btn"
@click="connectionConfirm()"
>
연결
</button>
</div>
</div>
</div>
<div class="file-tree-zone">
<div
class="content-titleZone flex justify-between align-center"
>
<p class="box-title">폴더 리스트</p>
</div>
<div class="file-zone overflow-y">
<ul class="tree-wrap">
<TreeItem
:connection="connection"
:selectedNode="selectedNode"
:selectItem="currentItem"
v-for="(item, idx) in nodes"
:item="item"
:idx="item.id"
:key="idx"
@selectFolder="selectFolder"
@isLoading="handleIsLoading"
@selectItem="handleSelectItem"
/>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="flex80 content-box">
<div class="right-content flex100">
<div class="flex-column justify-between">
<div class="flex justify-between align-center no-gutter">
<div class="flex justify-end flex100">
<div class="search-bar">
<div class="flex justify-end align-center">
<select
name=""
id=""
class="square-select"
v-model="searchType"
>
<option value="all">전체</option>
<option value="folder">현재폴더</option>
</select>
<div class="search-square">
<div
class="flex justify-end align-center no-gutter"
>
<input
type="text"
class="square-input flex90"
placeholder="Search"
v-model="searchText"
@keyup.enter="searchFiles()"
/>
<button class="square-button blue-btn flex10">
<svg-icon
type="mdi"
:path="searchPath"
class="square-icon"
@click="searchFiles()"
></svg-icon>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="content-zone" style="overflow-y: auto">
<div class="table-zone file-table">
<div class="list-info flex justify-between align-center">
<div class="count-zone">
<p>
총
<span v-if="search.totalRows != 0">{{
search.totalRows
}}</span>
<span v-else>0</span>
건
</p>
<p>
현재경로 : <span>{{ connection.path }}</span>
</p>
</div>
</div>
<table class="list-table">
<!-- col 꼭 너비 기재해야함! 그래야 100%로 차지함 -->
<colgroup>
<col style="width: 5%" />
<col style="width: 45%" />
<col style="width: 10%" />
<col style="width: 20%" />
<col style="width: 10%" />
<col style="width: 10%" />
</colgroup>
<thead>
<tr>
<th></th>
<th>이름</th>
<th>타입</th>
<th>마지막 수정</th>
<th>크기</th>
<th>관리</th>
</tr>
</thead>
<tbody>
<tr
v-for="(file, index) in fileList"
:key="index"
@click="selectFileList(file)"
>
<td
v-if="file.text != '상위폴더로 이동'"
@click.stop=""
></td>
<td v-else @click.stop=""></td>
<td>
<div class="text-lf">
<span v-if="file.extension === 'txt'"
><img
src="../../../../resources/img/icon/txt.png"
ref=""
alt=""
/></span>
<span v-else-if="file.extension === 'pdf'"
><img
src="../../../../resources/img/icon/pdf.png"
alt=""
/></span>
<span
v-else-if="
file.extension === 'pptx' ||
file.extension === 'ppt'
"
><img
src="../../../../resources/img/icon/ppt.png"
alt=""
/></span>
<span v-else-if="file.extension === 'hwp'"
><img
src="../../../../resources/img/icon/hwp.png"
alt=""
/></span>
<span
v-else-if="
file.extension === 'xls' ||
file.extension === 'xlsx'
"
><img
src="../../../../resources/img/icon/xls.png"
alt=""
/></span>
<span v-else-if="file.extension === 'jpg'"
><img
src="../../../../resources/img/icon/img.png"
alt=""
/></span>
<span v-else-if="file.extension === 'png'"
><img
src="../../../../resources/img/icon/img.png"
ref=""
alt=""
/></span>
<span v-else>  </span>
<span> {{ file.text }}</span>
</div>
</td>
<td>{{ file.extension }}</td>
<td>{{ file.lastUpdate }}</td>
<td v-if="file.size != 0">
{{ $filters.bytesToSize(file.size) }}
</td>
<td v-else></td>
<td>
<div
v-if="!file.folder && modeInfo == 'fileWrite'"
>
<button
class="icon-btn orange-btn"
title="미리보기"
@click.stop="filePreview(file)"
>
<svg-icon
type="mdi"
:width="18"
:height="18"
:path="fileFindPath"
></svg-icon>
</button>
</div>
<div v-else></div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-if="modeInfo == 'fileRead'" class="table-zone">
<table class="form-table">
<!-- col 꼭 너비 기재해야함! 그래야 100%로 차지함 -->
<colgroup>
<col style="width: 20%" />
<col style="width: 80%" />
</colgroup>
<tbody>
<tr>
<th>폴더명</th>
<td>{{ jobItm.itm["path"] }}</td>
</tr>
<tr>
<th>파일명</th>
<td>{{ jobItm.itm["text"] }}</td>
</tr>
</tbody>
</table>
<div class="flex flex30 align-center justify-center">
<div class="input-container flex">
<label class="check-label">
<input type="checkbox" name="check" class="custom-checkbox" />
<span>마지막 파일만</span>
</label>
<label class="check-label">
<input type="checkbox" name="check" class="custom-checkbox" />
<span>업데이트일 이후</span>
</label>
</div>
</div>
</div>
<div v-else-if="modeInfo == 'fileWrite'" class="table-zone">
<table class="form-table">
<colgroup>
<col style="width: 10%" />
<col style="width: 40%" />
<col style="width: 10%" />
<col style="width: 40%" />
</colgroup>
<tbody>
<tr>
<th>폴더명</th>
<td>{{ jobItm.itm["path"] }}</td>
<th>쓰기유형</th>
<td>
<select name="" id="" class="full-select">
<option selected>엑셀</option>
</select>
</td>
</tr>
<tr>
<th>파일명</th>
<td>
<input
type="text"
name=""
id=""
class="full-input"
v-model="jobItm.itm.fileName"
/>
</td>
<th>쓰기옵션</th>
<td>
<div class="flex flex30 align-center justify-center">
<div class="input-container flex">
<label class="radio-label">
<input
type="radio"
name="radio"
checked=""
class="custom-radiobox"
v-model="selectedFile['streOptn']"
:value="false"
/>
<span>쓰기</span>
</label>
<label class="radio-label">
<input
type="radio"
name="radio"
class="custom-radiobox"
v-model="selectedFile['streOptn']"
:value="true"
/>
<span>suffix</span>
</label>
</div>
</div>
</td>
</tr>
<tr v-show="selectedFile['streOptn']">
<th>suffix</th>
<td>
<input
type="text"
name=""
id=""
class="full-input"
v-model="selectedFile['suffix']"
/>
</td>
<th>월변경</th>
<td>
<input
type="number"
name=""
id=""
class="full-input"
v-model="selectedFile['addMonth']"
/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="modal-content-monthly" v-show="currentPage == 2">
<div class="content-titleZone">
<p v-show="modeInfo == 'fileRead'" class="box-title">데이터셋 설정</p>
<p v-show="modeInfo == 'fileWrite'" class="box-title">
데이터 미리보기
</p>
</div>
<FileDataRead
v-if="isModalOpen"
v-model:isLoading="isLoading"
v-model:dataTable="dataTable"
:preview="preview"
@indexChange="indexChange"
></FileDataRead>
</div>
<div class="modal-end flex justify-end">
<button
class="blue-btn small-btn"
@click="setPage(1)"
v-show="currentPage == 2"
>
이전
</button>
<button
class="blue-btn small-btn"
@click="setPage(2)"
v-show="currentPage == 1 && modeInfo == 'fileRead'"
>
다음
</button>
<button
class="blue-btn small-btn"
@click="saveModal()"
v-show="
(currentPage == 2 && modeInfo == 'fileRead') ||
(currentPage == 1 && modeInfo == 'fileWrite')
"
>
완료
</button>
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
import TreeItem from "../../FileTree.vue";
import SvgIcon from "@jamescoyle/vue-icon";
import FileDataRead from "./fileDataRead.vue";
import { mdiMagnify, mdiFileFind } from "@mdi/js";
import store from "../../../pages/AppStore";
import _ from "lodash";
export default {
name: "database-connection",
props: {
openPopup: {
type: Boolean,
default: false,
},
jobItem: {
type: Boolean,
default: null,
},
mode: {
type: String,
default: null, // 읽기: fileRead, 쓰기: fileWrite
},
},
data() {
return {
// 로딩 상태
isLoading: false,
// 현재 모달창 관리
isModalOpen: this.openPopup,
jobItm: this.jobItem,
modeInfo: this.mode,
currentPage: 1,
searchPath: mdiMagnify, // 검색 아이콘 경로
fileFindPath: mdiFileFind, // 미리보기 아이콘 경로
// 검색 객체
search: this.$getDefaultSerchVO(),
search_data: this.$getDefaultSerchItem(null, "String"),
selectedHost: {},
selectedHostCode: null,
// 호스트 목록
hostList: [],
// 부서-호스트 목록
deptHostList: [],
connection: {
host_code: null,
path: null,
depth: null,
type: null,
},
nodes: [],
selectedNode: null,
fileList: [],
searchType: "all",
searchText: null,
selectItem: null,
currentItem: {
id: null,
},
selectedFile: {},
// 초기 빈 데이터 테이블
defaultDataTable: {},
// 임시 저장된 데이터
tempJobItm: this.jobItem,
tempCurrentPage: 1,
tempSearch: this.$getDefaultSerchVO(),
tempSearch_data: this.$getDefaultSerchItem(null, "String"),
tempSearchText: null,
tempConnection: {
host_code: null,
path: null,
depth: null,
type: null,
},
tempNodes: [],
tempSelectedNode: null,
tempFileList: [],
tempSelectedFile: {},
tempSelectedHostCode: null,
tempDataTable: {},
/** ************************************ 데이터 셋 읽기 ************************************ */
dataTable: {},
preview: false,
fileNameBeforeDot: null, // 파일명(확장자 제외)
};
},
methods: {
// 모달 닫기
closeModal: function () {
this.$emit("closePopup", this.jobItm);
},
// 화면전환
async setPage(val) {
if (val == 2) {
if (!this.jobItm.itm["text"]) {
this.$showAlert("파일 읽기", "파일을 선택해주세요.");
return;
}
await this.fileRead();
this.currentPage = val;
} else {
this.currentPage = val;
}
},
// 모달 취소
cancelModal: function () {
this.closeModal();
},
// 모달 저장
async saveModal() {
// 파일 쓰기용 데이터를 jobItm에 저장
if (this.modeInfo == "fileWrite") {
if (
!this.selectedFile["streOptn"] &&
this.$filters.removeExtension(this.selectedFile["text"]) ==
this.fileNameBeforeDot
) {
if (
!(await this.$showConfirm(
"파일 쓰기",
"파일명이 동일할 시 덮어쓰기 됩니다."
))
) {
return;
}
}
this.jobItm.itm["path"] = this.selectedFile["parent"];
this.jobItm.itm["text"] = this.selectedFile["text"];
this.fileNameBeforeDot + "." + this.selectedFile["fileFom"];
this.jobItm.itm["fileFom"] = this.selectedFile["fileFom"];
this.jobItm.itm["streOptn"] = this.selectedFile["streOptn"];
this.jobItm.itm["suffix"] = this.selectedFile["suffix"];
this.jobItm.itm["addMonth"] = this.selectedFile["addMonth"];
this.jobItm.dataTable = _.cloneDeep(this.defaultDataTable);
}
this.closeModal();
},
// 검색 객체 초기화
searchInit: function () {
this.search.searchObjectList.push(this.search_data);
},
// 파일 검색
searchFiles() {
const vm = this;
if (vm.searchText === null || vm.searchText === "") {
vm.$showAlert("파일 검색", "검색어를 입력해 주세요.");
return;
}
let path = vm.connection.path;
if (vm.searchType === "all") {
path = "#";
}
vm.isLoading = true; // 로딩 시작
axios({
url: "/files/search/" + vm.connection.host_code,
method: "post",
headers: {},
data: {
searchType: vm.searchType,
searchText: vm.searchText,
path: path,
},
})
.then(function (response) {
vm.isLoading = false; // 로딩 해제
vm.fileList = response.data.resultData.fileList;
if (vm.fileList.length == 0) {
vm.$showAlert("파일 검색", "검색 결과가 없습니다.");
}
})
.catch(function (error) {
vm.isLoading = false; // 로딩 해제
vm.$showAlert(
"파일 검색",
"파일 검색 오류, 관리자에게 문의바랍니다."
);
});
},
// 로딩 상태 변경
handleIsLoading(isLoadingValue) {
this.isLoading = isLoadingValue; // 부모 컴포넌트의 데이터 업데이트
},
// 호스트 목록 조회
selectHosts() {
const vm = this;
axios({
url: "/files/hosts",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
userId: store.state.loginUser.user_id,
authList: store.state.loginUser.user_auth,
author: store.state.loginUser.user_auth[0],
dept_code: store.state.loginUser.dept_code,
},
})
.then((response) => {
vm.hostList = response.data.resultData.hostList;
vm.deptHostList = response.data.resultData.deptHostList;
if (this.hostList.length > 0) {
vm.selectedHost = vm.hostList[0];
vm.selectedHostCode = vm.hostList[0].host_code;
for (let i = 0; i < vm.hostList.length; i++) {
for (let j = 0; j < vm.deptHostList.length; j++) {
if (vm.hostList[i].host_code === vm.deptHostList[j].host_code) {
vm.hostList[i].main_folder_path =
vm.deptHostList[j].main_folder_path;
}
}
}
vm.connectionConfirm();
} else {
vm.selectedHost = {};
}
})
.catch((error) => {
vm.$showAlert(
"호스트 조회",
"호스트 조회 오류, 관리자에게 문의하세요."
);
});
},
// 선택한 호스트 연결
async connectionConfirm() {
const vm = this;
if (vm.selectedHostCode === null || vm.selectedHostCode === undefined) {
vm.$showAlert("파일시스템 연결", "호스트를 선택해 주세요.");
return;
}
// 이전에 선택한 호스트 코드가 있으면 저장
let tempHostCode = null;
if (vm.connection.host_code) {
tempHostCode = _.cloneDeep(vm.connection.host_code);
}
vm.connection.host_code = vm.selectedHost.host_code;
vm.isLoading = true; // 로딩 시작
try {
const response = await axios.get("/files/connection", {
params: { host_code: vm.connection.host_code },
});
vm.isLoading = false; // 로딩 해제
if (response.data.status === 200) {
await this.fileTreeList();
} else {
// 이전에 선택한 호스트 코드로 변경
if (tempHostCode) {
vm.connection.host_code = tempHostCode;
vm.selectedHost.host_code = tempHostCode;
vm.selectedHostCode = tempHostCode;
}
}
vm.selectedFile = {};
vm.$showAlert("파일시스템 연결", response.data.message);
} catch (error) {
vm.isLoading = false; // 로딩 해제
vm.$showAlert(
"파일시스템 연결",
"파일시스템 연결 오류, 관리자에게 문의하세요."
);
vm.selectedFile = {};
// 이전에 선택한 호스트 코드로 변경
if (tempHostCode) {
vm.connection.host_code = tempHostCode;
vm.selectedHost.host_code = tempHostCode;
vm.selectedHostCode = tempHostCode;
}
}
},
// 폴더 리스트 조회
async fileTreeList() {
const vm = this;
vm.nodes = [];
vm.connection.path = vm.selectedHost.main_folder_path;
vm.connection.depth = 0;
vm.connection.type = "folder";
vm.isLoading = true; // 로딩 시작
try {
const response = await axios.get("/files/tree", {
params: vm.connection,
});
vm.nodes = response.data.resultData.fileTree;
// vm.connection.path = null;
vm.fileList = [];
vm.isLoading = false; // 로딩 해제
} catch (error) {
vm.$showAlert(
"파일리스트 조회",
"파일리스트 조회 오류, 관리자에게 문의하세요."
);
vm.fileList = [];
vm.isLoading = false; // 로딩 해제
vm.$showAlert(
"파일리스트 조회",
"파일리스트 조회 오류, 관리자에게 문의하세요."
);
}
},
// 폴더 선택
selectFolder(path) {
if (path === null || path === undefined) {
this.isLoading = false;
}
this.connection.path = path;
this.fileSelectList();
},
handleSelectItem(item, parentItem) {
// 현재 선택된 폴더와 클릭한 폴더가 같을 때
if (this.currentItem.id == item.id) {
this.selectItem = parentItem;
this.currentItem = parentItem;
} else {
this.selectItem = item;
this.currentItem = item;
}
},
// 파일 리스트 조회
fileSelectList() {
const vm = this;
if (vm.connection.path === null || vm.connection.path === "") {
vm.fileList = null;
return;
}
vm.connection.type = "all";
vm.connection.depth = 1;
axios
.get("/files/list", { params: vm.connection })
.then((response) => {
vm.fileList = response.data.resultData.fileList;
vm.search.totalRows = response.data.resultData.totalRow;
vm.isLoading = false;
})
.catch((error) => {
vm.$showAlert(
"파일리스트 조회",
"파일리스트 조회 오류, 관리자에게 문의하세요."
);
vm.isLoading = false;
});
},
// 파일 선택
async selectFile(file) {
if (
file.extension != "xlsx" &&
file.extension != "xls" &&
file.extension != "csv"
) {
this.$showAlert("파일 읽기", "엑셀 파일만 읽을 수 있습니다.");
return;
}
this.selectedFile = _.cloneDeep(file);
this.jobItm.itm = _.cloneDeep(file);
// 파일 쓰기용 데이터를 선택 파일에 추가
if (this.modeInfo == "fileWrite") {
this.jobItm.itm["path"] = file.path;
this.jobItm.itm["fileName"] = file.text;
this.jobItm.itm["fileFom"] = file.extension;
this.jobItm.itm["streOptn"] = false;
this.jobItm.itm["suffix"] = "_YYYYMMDDHHmmss";
this.jobItm.itm["addMonth"] = 0;
this.selectedFile["path"] = file.path;
this.selectedFile["fileName"] = file.text;
this.selectedFile["fileFom"] = file.extension;
this.selectedFile["streOptn"] = false;
this.selectedFile["suffix"] = "_YYYYMMDDHHmmss";
this.selectedFile["addMonth"] = 0;
}
},
// 파일/폴더 목록 선택
selectFileList(item) {
// 폴더가 선택된 경우, 선택된 노드와 경로를 업데이트하고 파일 리스트 조회
if (item.extension === "폴더" || item.extension === "") {
this.selectedNode = item.id;
this.connection.path = item.id;
this.fileSelectList();
} else {
this.selectFile(item); // 파일이 선택된 경우
}
},
// 파일 미리보기
async filePreview(file) {
if (this.selectedFile == null || file["id"] != this.selectedFile["id"]) {
await this.selectFile(file); // 선택 파일 정보 저장
}
this.preview = true; // 미리보기 활성화
await this.fileRead(); // 파일 읽기
this.currentPage = 2; // 데이터셋 설정 페이지로 이동
},
// 초기화 function
init: function () {
this.selectHosts();
this.searchInit();
},
// 파일 읽기
async fileRead() {
const vm = this;
vm.isLoading = true;
// 선택 파일 정보를 VO 형태로 변환
axios
.post("/files/read/" + vm.connection.host_code, {
path: vm.jobItm.itm.path,
fileName: vm.jobItm.itm.text,
extension: vm.jobItm.itm.extension,
type: "file",
datasetId: "",
viewMode: true,
})
.then((response) => {
// 잡아이템에 선택 파일 정보 저장
if (vm.modeInfo == "fileRead") {
vm.jobItm.itm.text = vm.selectedFile.text;
}
vm.jobItm.itm.path = vm.selectedFile.path;
vm.jobItm.itm.extension = vm.selectedFile.extension;
vm.jobItm.itm.type = "file";
vm.jobItm.itm.datasetId = vm.connection.host_code;
vm.jobItm.itm.viewMode = true;
vm.dataTable = response.data.resultData.dataTableMap;
vm.jobItm.dataTable = vm.dataTable; // 잡아이템에 데이터셋 정보 저장
vm.columnDatas = vm.dataTable.columnDatas;
vm.jobItm.front_dataTable.columnDatas = vm.columnDatas;
})
.catch(() => {
vm.isLoading = false;
});
},
// 데이터셋 시작 행, 열 정보 변경시
indexChange: function (v) {
this.jobItm.dataTable = v; // 잡아이템 데이터셋에 변경된 데이터셋 정보 저장
this.jobItm.itm.rowDataColumnIndex = v.rowDataColumnIndex;
this.jobItm.itm.startRowIndex = v.startRowIndex;
this.jobItm.itm.startCellIndex = v.startCellIndex;
},
},
watch: {
// 연결 호스트 변경 시
selectedHostCode: function (newValue, oldValue) {
for (let i = 0; i < this.hostList.length; i++) {
if (this.hostList[i].host_code === newValue) {
this.selectedHost = this.hostList[i];
break;
}
}
},
},
components: {
SvgIcon: SvgIcon,
TreeItem: TreeItem,
FileDataRead: FileDataRead,
},
mounted() {
this.init();
},
};
</script>