
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 class="container">
<div class="page-titleZone flex justify-between align-center">
<p class="main-title flex80">OpenAPI 등록</p>
<PageNavigation />
</div>
<div class="content-wrap">
<div class="content content-box flex-column no-gutter">
<div class="row flex50">
<div class="flex100">
<div class="content-titleZone">
<p class="box-title">
<span class="redfont">*</span>필수 입력 값입니다.
</p>
</div>
<div 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><span class="redfont">*</span>제목</th>
<td>
<input type="text" class="full-input" v-model="openApiInfo.export_ttl" />
</td>
<th><span class="redfont">*</span>데이터셋</th>
<td>
<button @click="datasetListOpen" class="blue-border-btn small-btn"> 데이터셋 선택 </button>
</td>
</tr>
<tr>
<th></th>
<td></td>
<th>카테고리</th>
<td>
<select class="full-input" v-model="openApiInfo.category_id">
<option :value="null">카테고리 없음</option>
<option v-for="(item, indx) in categoryList" :key="indx" :value="item.cmmnCode"> {{ item.codeNm }} </option>
</select>
</td>
</tr>
<tr>
<th>
<span class="redfont">*</span>공공데이터 포털 사용 유무
</th>
<td>
<div style="display: flex">
<input id="publicPortalIsUseTrue" name="publicPortalIsUse" type="radio" value="true" class="radio" v-model="openApiInfo.public_potal_is_use" />
<label for="publicPortalIsUseTrue" class="mr20">사용</label>
<input id="publicPortalIsUseFalse" name="publicPortalIsUse" type="radio" value="false" class="radio" v-model="openApiInfo.public_potal_is_use" />
<label for="publicPortalIsUseFalse">미사용</label>
</div>
</td>
<th><span class="redfont">*</span>데이터 사용 유무</th>
<td>
<div style="display: flex">
<input id="dataIsUse" name="dataIsUse" type="radio" value="true" class="radio" v-model="openApiInfo.data_is_use" />
<label for="dataIsUse" class="mr20">사용</label>
<input id="dataIsUse" name="dataIsUse" type="radio" value="false" class="radio" v-model="openApiInfo.data_is_use" />
<label for="dataIsUse">미사용</label>
</div>
</td>
</tr>
<tr>
<th><span class="redfont">*</span>배포형태</th>
<td>
<select class="full-input" v-model="openApiInfo.api_type">
<option :value="null">-- 선택 --</option>
<option value="restAPI">rest API</option>
</select>
<select class="full-input" v-model="openApiInfo.data_format_type">
<option :value="null">-- 선택 --</option>
</select>
</td>
<th><span class="redfont">*</span>검색키워드(3개)</th>
<td>
<div style="display: flex; justify-content: space-evenly">
<input type="text" class="full-input" v-model="inputKeyword" @keyup.enter="addKeyword" />
<button class="blue-border-btn small-btn" @click="addKeyword"> + </button>
</div>
<div v-if="openApiInfo.keywordList?.length > 0" class="flex justify-start">
<div v-for="(item, idx) in openApiInfo.keywordList" :key="idx">
<p>{{ item }}</p>
<button class="del-btn" @click="delKeyword(idx)"> X </button>
</div>
</div>
</td>
</tr>
<tr>
<th><span class="redfont">*</span>OPEN API 국문명</th>
<td>
<input type="text" class="full-input" v-model="openApiInfo.export_kor_nm" />
</td>
<th><span class="redfont">*</span>OPEN API 영문명</th>
<td>
<input type="text" class="full-input" v-model="openApiInfo.export_eng_nm" />
</td>
</tr>
<tr>
<th><span class="redfont">*</span>OPEN API 설명</th>
<td>
<input type="text" class="full-input" v-model="openApiInfo.export_explain" />
</td>
<th>첨부파일</th>
<td>
<div class="file_input">
<form name="fileForm" id="fileForm" method="post" enctype="multipart/form-data">
<label for="fileUp" class="green-border-btn small-btn">파일선택</label>
<input type="file" id="fileUp" @change="fileChange()" multiple style="display: none" />
</form>
</div>
<div class="filename">
<ul>
<li v-for="(file, i) in tempFiles" :key="i">
<span>{{ file.name }}</span>
<button @click="tempFiles.splice(i, 1)">X</button>
</li>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div v-for="(item, idx) in openApiInfo.apiExportList" :key="idx">
<div class="table-zone">
<table class="form-table">
<colgroup>
<col style="width: 20%" />
<col style="width: 80%" />
</colgroup>
<tbody>
<tr>
<th colspan="2">
<span class="custom-subtitle">{{ item.datasetPost.post_sj }}</span>
<img class="del-btn" src="../../../resources/img/delete.png" alt="삭제" @click="delSelectedDataset(idx)" />
</th>
</tr>
<tr>
<th>API 상세 국문명</th>
<td>
<input type="text" class="full-input" v-model="item.api_detail_kor_nm" />
</td>
</tr>
<tr>
<th>API 상세 영문명</th>
<td>
<input type="text" class="full-input" v-model="item.api_detail_eng_nm" />
</td>
</tr>
<tr>
<th>API 상세 설명</th>
<td>
<input type="text" class="full-input" v-model="item.api_detail_explain" />
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="flex5">
<div class="flex justify-end">
<button class="blue-btn small-btn" @click="dataValid">등록</button>
<button class="blue-border-btn small-btn" @click="moveList()">취소</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 모달 -->
<div v-show="openModal" class="modal-wrapper">
<div class="modal-container large-btn">
<div class="modal-title">
<div class="flex justify-between align-center">
<h2>데이터셋 선택</h2>
<button class="close-btn" @click="closeModal">
<svg-icon type="mdi" :width="20" :height="20" :path="closePath"></svg-icon>
</button>
</div>
</div>
<div class="modal-content-monthly">
<div class="overflow-y" style="height: 50%">
<div class="content-box flex justify-between">
<div class="flex20 content-box">
<div class="left-content flex100 content-box">
<div class="content-titleZone">
<p class="box-title">카테고리 리스트</p>
</div>
<div class="content-zone">
<CodeList :groupCode="'DATA_CTGRY'" @selectCode="selectCode" :categoryIdx="categoryIdx" />
</div>
</div>
</div>
<div class="flex80 content-box">
<div class="right-content content-box">
<div class="flex-column justify-between">
<div class="flex justify-end align-center flex5 no-gutter">
<div class="flex justify-end flex100">
<div class="flex justify-end align-center">
<input type="date" name="start-date" id="start-date" class="square-date" :class="{ 'date-placeholder': false }" data-placeholder="날짜 선택" v-model="search_date.value" />
<span class="coupler">~</span>
<input type="date" name="end-date" id="end-date" class="square-date ml5" :class="{ 'date-placeholder': false }" data-placeholder="날짜 선택" v-model="search_date.value2" />
<select class="square-select ml5" v-model="search_data1.value">
<option :value="null">공개여부</option>
<option :value="true">공개</option>
<option :value="false">비공개</option>
</select>
<select class="square-select ml5" v-model="search_data2.value">
<option :value="null">카테고리</option>
<option v-for="(item, indx) in categoryList" :key="indx" :value="item.cmmnCode"> {{ item.codeNm }} </option>
</select>
<select name="" id="searchItm1" class="square-select ml5" v-model="search_data3.key">
<option :value="null">검색조건</option>
<option value="post_sj">제목</option>
<option value="post_dc">내용</option>
</select>
<div class="search-square ml5">
<input type="text" class="square-input" placeholder="Search" v-model="search_data3.value" v-on:keyup.enter="searchData()" />
<button class="square-button blue-btn" @click="searchData()">
<svg-icon type="mdi" :path="this.$getIconPath()" class="square-icon"></svg-icon>
</button>
</div>
</div>
</div>
</div>
<div class="table-zone flex85">
<!-- <div class="list-info flex justify-between align-center">
<div class="count-zone">
<p>총 <span>40</span>건 중 <span>01</span>건 선택</p>
</div>
<div class="cunt-selectZone">
<select name="" id="">
<option value="">10개 보기</option>
<option value="">20개 보기</option>
</select>
</div>
</div> -->
<table class="list-table">
<!-- col 꼭 너비 기재해야함! 그래야 100%로 차지함 -->
<colgroup>
<col style="width: 10%" />
<col style="width: 40%" />
<col style="width: 10%" />
<col style="width: 10%" />
<col style="width: 10%" />
<col style="width: 30%" />
</colgroup>
<thead>
<tr>
<th>No</th>
<th>제목</th>
<th>생성자</th>
<th>부서</th>
<th>카테고리</th>
<th>등록일시</th>
</tr>
</thead>
<tbody>
<template v-if="dataPostList.length > 0">
<tr v-for="(item, indx) in dataPostList" :key="indx" @click="selectPost(item)">
<td> {{ search.totalRows - indx - (search.currentPage - 1) * search.perPage }} </td>
<td>{{ item.post_sj }}</td>
<td>{{ item.creat_id }}</td>
<td>{{ item.dept_code }}</td>
<td>{{ item.ctgry_id }}</td>
<td>{{ item.creat_dt }}</td>
</tr>
</template>
<template v-else>
<tr>
<td colspan="6">등록된 데이터가 없습니다.</td>
</tr>
</template>
</tbody>
</table>
<PaginationButton v-model:currentPage="search.currentPage" :perPage="search.perPage" :totalCount="search.totalRows" :maxRange="5" :click="searchData" />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="pd10">
<div class="flex justify-start align-center">
<div class="mr15">
<label for="">데이터명 : </label>
<p>{{ datasetPost.post_sj }}</p>
</div>
<div class="mr15">
<label for="">상태 : </label>
<p>선택한 데이터명</p>
</div>
</div>
</div>
<div class="overflow-y overflow-x mb20" style="height: 48%">
<div v-if="isPostClick" class="table-zone">
<table class="list-table">
<thead>
<th v-for="(itm, indx) in dataTable.columnDatas" :key="indx" style="min-width: 150px"> {{ itm.columnNm }} <button class="tp-btn" v-if="itm.pkAt">
<svg-icon type="mdi" :width="15" :height="15" :path="this.$getIconPath('mdiKeyVariant')" :color="'#213f99'"></svg-icon>
</button>
</th>
</thead>
<tbody>
<tr v-for="(row, rows) in dataTable.rowData" :key="rows">
<td v-for="(itm, indx) in row" :key="indx" style="
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"> {{ itm }} </td>
</tr>
</tbody>
</table>
<PaginationButton v-model:currentPage="postSearch.currentPage" :perPage="postSearch.perPage" :totalCount="postSearch.totalRows" :maxRange="5" :click="selectDataPost" />
</div>
<div v-else class="table-zone">
<div>조회된 데이터가 없습니다</div>
</div>
</div>
</div>
<div class="modal-end flex justify-end">
<!-- <button v-show="modalType === 'form-modal'" class="orange-btn small-btn">접속</button>
<button v-show="modalType === 'tab-modal'" class="blue-btn small-btn">확인</button> -->
<button v-if="!isUpdatePage" class="blue-border-btn small-btn" id="registerButton" @click="choicePostData"> 등록 </button>
</div>
</div>
</div>
</div>
</template>
<script>
import CodeList from "../../component/common/Component_CodeList.vue";
import PageNavigation from "../../component/PageNavigation.vue";
import PaginationButton from "../../component/PaginationButton.vue";
import SvgIcon from "@jamescoyle/vue-icon";
import store from "../AppStore";
import axios from "axios";
export default {
data() {
return {
openModal: false,
/** openAPI 등록 페이지 설정 */
// 선택한 데이터 셋 리스트
openApiInfo: _.cloneDeep(this.$getDefaultJobGroup().openApiInfo),
inputKeyword: "",
/** 모달 데이터 설정 */
selectedCategory: "",
categoryList: [],
dataPostList: [],
search: this.$getDefaultSerchVO(),
// 공개여부
search_data1: this.$getDefaultSerchItem("public_at", "bool"),
// 카테고리
search_data2: this.$getDefaultSerchItem("ctgry_id", "string"),
// 선택
search_data3: this.$getDefaultSerchItem("post_sj", "string"),
// 날짜
search_date: this.$getDefaultSerchItem("creat_dt", "dates"),
// 자식에게 보내주는 인덱스 값
postSearch: this.$getDefaultSerchVO(),
postSearch_data: this.$getDefaultSerchItem(null, "string"),
categoryIdx: null,
datasetPost: {},
dataTable: [],
dataset: {},
isPostClick: false,
tempFiles: [],
};
},
methods: {
datasetListOpen: function () {
this.openModal = true;
this.modalInit();
this.searchData();
},
closeModal: function () {
this.openModal = false;
},
searchData: function () {
const vm = this;
let idx = this.categoryList.findIndex(
(x) => x.cmmnCode === this.selectedCategory
);
axios({
url: "/dataset/selectDataPostList.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: JSON.stringify(vm.search),
})
.then(function (response) {
if (response.data.checkMessage.success) {
vm.dataPostList = response.data.resultData.dataPostList;
vm.search.totalRows = response.data.resultData.totalRow;
vm.categoryIdx = idx;
}
})
.catch(function (error) {
this.$showAlert(
"에러 발생",
"에러가 발생했습니다. 관리자에게 문의해 주세요."
);
});
},
selectCode: function (v) {
this.selectedCategory = v;
this.search_data2.value = v;
this.searchData();
},
selectPost: function (item) {
let vm = this;
axios({
url: "/dataset/selectDataPost.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
datapost_id: item.dataset_post_id,
search: vm.postSearch,
},
})
.then(function (response) {
let res = response.data.resultData;
if (response.data.checkMessage.success) {
vm.datasetPost = res.datasetPost;
vm.dataTable = res.dataTable;
vm.dataset = res.dataset;
vm.isPostClick = true;
vm.postSearch.totalRows = vm.dataTable.totalRows;
vm.postSearch.perPage = vm.dataTable.perPage;
vm.postSearch.currentPage = vm.dataTable.currentPage;
}
})
.catch(function (error) {
this.$showAlert(
"에러 발생",
"에러가 발생했습니다. 관리자에게 문의해 주세요."
);
});
},
choicePostData: function () {
if (Object.keys(this.datasetPost).length !== 0) {
const selectPostData = _.cloneDeep(
this.$getDefaultJobGroup().apiExport
);
selectPostData.datasetPost = this.datasetPost;
this.openApiInfo.apiExportList.push(selectPostData);
}
this.closeModal();
},
// 초기화
init: async function () {
this.categoryList = await this.$getCommonCode("DATA_CTGRY");
this.search.searchObjectList.push(this.search_date);
this.search.searchObjectList.push(this.search_data1);
this.search.searchObjectList.push(this.search_data2);
this.search.searchObjectList.push(this.search_data3);
this.postSearch.searchObjectList.push(this.postSearch_data);
this.openApiInfo = await _.cloneDeep(
this.$getDefaultJobGroup().openApiInfo
);
},
modalInit: function () {
this.datasetPost = {};
this.dataTable = [];
this.dataset = {};
this.isPostClick = false;
},
/** 페이지 내 기능 설정 */
moveList: function () {
this.$router.push({ path: "/openApiList.page", query: {} });
},
delSelectedDataset: function (idx) {
this.openApiInfo.apiExportList.splice(idx, 1);
},
addKeyword: function () {
if (this.openApiInfo.keywordList.length < 3) {
const isExist = this.openApiInfo.keywordList.find(
(x) => x === this.inputKeyword
);
if (this.inputKeyword === "") {
this.$showAlert("메세지", "키워드를 입력해주세요.");
return;
}
if (isExist) {
this.$showAlert("메세지", "이미 등록된 키워드 입니다.");
return;
}
this.openApiInfo.keywordList.push(this.inputKeyword);
this.inputKeyword = "";
return;
}
this.$showAlert("메세지", "키워드는 3개까지 등록 가능합니다.");
},
delKeyword: function (idx) {
this.openApiInfo.keywordList.splice(idx, 1);
},
// 유효성 검사
dataValid: function () {
let vm = this;
if (
vm.openApiInfo.export_ttl === null ||
vm.openApiInfo.export_ttl.trim() === ""
) {
vm.$showAlert("메세지", "제목을 입력해주세요.");
return;
}
if (vm.openApiInfo.apiExportList.length === 0) {
vm.$showAlert("메세지", "데이터셋을 선택해주세요.");
return;
}
if (vm.openApiInfo.api_type === null) {
vm.$showAlert("메세지", "배포형태를 선택해주세요.");
return;
}
if (vm.openApiInfo.keywordList.length === 0) {
vm.$showAlert("메세지", "검색키워드를 입력해주세요.");
return;
}
if (
vm.openApiInfo.export_kor_nm === null ||
vm.openApiInfo.export_kor_nm.trim() === ""
) {
vm.$showAlert("메세지", "OPEN API 국문명을 입력해주세요.");
return;
}
if (
vm.openApiInfo.export_eng_nm === null ||
vm.openApiInfo.export_eng_nm.trim() === ""
) {
vm.$showAlert("메세지", "OPEN API 영문명을 입력해주세요.");
return;
}
if (
vm.openApiInfo.export_explain === null ||
vm.openApiInfo.export_explain.trim() === ""
) {
vm.$showAlert("메세지", "OPEN API 설명을 입력해주세요.");
return;
}
// 데이터 셋 정보 유효성
for (let i = 0; i < vm.openApiInfo.apiExportList.length; i++) {
let detailInfo = vm.openApiInfo.apiExportList[i];
if (
detailInfo.api_detail_kor_nm === null ||
detailInfo.api_detail_kor_nm.trim() === ""
) {
vm.$showAlert(
"메세지",
detailInfo.datasetPost.post_sj + " API 상세 국문명을 입력해주세요."
);
return;
}
if (
detailInfo.api_detail_eng_nm === null ||
detailInfo.api_detail_eng_nm.trim() === ""
) {
vm.$showAlert(
"메세지",
detailInfo.datasetPost.post_sj + " API 상세 영문명을 입력해주세요."
);
return;
}
if (
detailInfo.api_detail_explain === null ||
detailInfo.api_detail_explain.trim() === ""
) {
vm.$showAlert(
"메세지",
detailInfo.datasetPost.post_sj + "API 상세 설명을 입력해주세요."
);
return;
}
}
if (vm.tempFiles.length !== 0) {
vm.fileUpload();
} else {
vm.openApiInsert();
}
},
openApiInsert: function () {
let vm = this;
vm.openApiInfo.export_creat_id = store.state.loginUser.user_id;
axios({
url: "/export/openApiInsert",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: vm.openApiInfo,
})
.then(function (response) {
if (response.data.checkMessage.success) {
vm.$showAlert("메세지", "OpenAPI 등록에 성공하였습니다.");
vm.$router.push({ path: "/openApiList.page" });
} else {
vm.$showAlert("메세지", "등록에 실패하였습니다.");
}
})
.catch(function (error) {
this.$showAlert(
"에러 발생",
"에러가 발생했습니다. 관리자에게 문의해 주세요."
);
});
},
// 등록할 파일 출력
fileChange: function () {
var files =
event.target.files ||
event.dataTransfer.files ||
window.event.target.files ||
window.event.dataTransfer.files;
for (var i = 0; i < files.length; i++) {
files[i].progress = 0;
this.tempFiles.push(files[i]);
}
},
fileUpload: function () {
const vm = this;
var formData = new FormData();
vm.tempFiles.forEach(function (file, index) {
formData.append("files", file);
});
axios
.post("/fileManage/read", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
onUploadProgress: function (progressEvent) {
if (progressEvent.lengthComputable) {
vm.tempFiles.attach.fileList.forEach(function (file, index) {
file.progress =
(progressEvent.loaded / progressEvent.total) * 100;
});
}
},
})
.then(function (response) {
vm.openApiInfo.file_manager_id =
response.data.resultData.fileManage.fileManagerId;
vm.openApiInsert();
})
.catch(function (error) {
console.error(error);
});
},
},
components: {
CodeList: CodeList,
PageNavigation: PageNavigation,
PaginationButton: PaginationButton,
SvgIcon: SvgIcon,
},
mounted() {
this.init();
},
};
</script>
<style scoped>
.redfont {
color: #eb3939;
}
.del-btn {
width: 20px;
height: 20px;
cursor: pointer;
}
</style>