공지사항 불필요한 리스트 수정 및 FAQ 추가 개발 진행

This commit is contained in:
kimjhjjang
2022-11-03 17:36:23 +09:00
parent 96d1b7e5b9
commit 46bd508b8e
25 changed files with 2027 additions and 21 deletions

View File

@@ -22,6 +22,9 @@
<li> <li>
<router-link to="/homeMgt/notice">공지사항</router-link> <router-link to="/homeMgt/notice">공지사항</router-link>
</li> </li>
<li>
<router-link to="/homeMgt/faq">자주하는 질문</router-link>
</li>
</ul> </ul>
</div> </div>
</li> </li>
@@ -175,7 +178,8 @@ export default {
this.menuList = null; this.menuList = null;
} }
}) })
.catch((rsponse) => { .catch((response) => {
console.log(response);
this.menuList = null; this.menuList = null;
}); });
}, },

View File

@@ -0,0 +1,480 @@
<template>
<!-- <div class="wrap bg-wrap"> -->
<div>
<div class="dimmed modal-insertFaq" @click="ModalClose()"></div>
<div class="popup-wrap modal-insertFaq">
<!-- 자주묻는 질문 신규 등록 -->
<div class="popup modal-insertFaq popup_form" style="width: 70vw">
<div class="pop-head">
<h3 class="pop-tit">자주묻는 질문 신규 등록</h3>
</div>
<form autocomplete="off">
<table>
<colgroup>
<col width="10%" />
<col width="40%" />
<col width="10%" />
<col width="40%" />
</colgroup>
<tbody>
<tr>
<th style="width: 10%">분류코드</th>
<td>
<div class="select_box">
<select name="" id="right" v-model="ctgCd" style="min-width: 500px" ref="_ctgCd">
<option v-for="(option, i) in ctgCdOption" :value="option.code" v-bind:key="i">
{{ option.codeNm }}
</option>
</select>
</div>
</td>
<th style="width: 10%">사용여부</th>
<td>
<div class="select_box">
<select name="" id="right" v-model="useYn" style="min-width: 150px">
<option value="Y">Y</option>
<option value="N">N</option>
</select>
</div>
</td>
</tr>
<tr>
<th style="width: 10%">질문</th>
<td colspan="3">
<input type="text" placeholder="질문을 입력하세요" v-model="title" ref="_title" />
</td>
</tr>
<tr>
<th style="width: 10%">답변</th>
<td class="sender" colspan="3">
<!-- <vue-editor
id="editor"
useCustomImageHandler
@imageAdded="handleImageAdded"
v-model="faqSbst"
ref="_faqSbst"
>
</vue-editor> -->
<div style="display: flex">
<textarea v-model="faqSbst" ref="_faqSbst" style="width: 100%"></textarea>
</div>
</td>
</tr>
</tbody>
</table>
</form>
<div class="popup-btn2">
<button class="btn-pcolor" @click="regisConfirm()">등록</button>
<button class="btn-default" @click="ModalClose()">취소</button>
</div>
</div>
<!-- <common-modal ref="commonModal"></common-modal> -->
<validation-confirm-popup ref="ValidationConfirmPopup"></validation-confirm-popup>
</div>
</div>
</template>
<script>
//import { VueEditor } from 'vue2-editor';
import api from '@/service/api';
import homeMgtApi from '../service/homeMgtApi';
import ValidationConfirmPopup from './ValidationConfirmPopup.vue';
import { utils_mixin, chkPattern2 } from '../service/mixins';
export default {
name: 'FaqPop',
mixins: [utils_mixin, chkPattern2],
data() {
return {
props: {},
row: {},
rsnType: [],
tpType: [],
// 자주묻는 질문
title: '',
faqSbst: '', //
useYn: 'Y',
ctgCd: 'null',
//updateFileList: [], // 업로드한 이미지 파일
ctgCdOption: [
{ code: 'null', codeNm: '분류코드를 선택하세요' },
{ code: '01', codeNm: '전송' },
{ code: '02', codeNm: '결제' },
{ code: '03', codeNm: '회원' },
{ code: '04', codeNm: '주소록' },
{ code: '05', codeNm: '서비스' },
{ code: '06', codeNm: '기타' },
],
// 자주묻는 질문
LINE_FEED: 10, // '\n',
maxByte: 2000,
// params: {
// 'blckSndrno' : ''
// ,'ctgCd' : '01'
// ,'blckRsnCd' : '02'
// ,'meno' : ''
// }
};
},
create() {
//this.setCodeDate();
this.formReset();
},
mounted() {
//this.ctgCd = '01'
},
components: {
//VueEditor,
ValidationConfirmPopup,
},
methods: {
handleImageAdded(file, Editor, cursorLocation, resetUploader) {
var fd = new FormData();
fd.append('files', file);
homeMgtApi
.getImageUrl(fd)
.then((response) => {
const url =
'/api/v1/bo/homeMgt/preview/' +
encodeURIComponent(response.data.data.replaceAll('\\', '/').replaceAll('/', '|')); // Get url from response
Editor.insertEmbed(cursorLocation, 'image', url);
resetUploader();
})
.catch((err) => {
console.log(err);
});
},
//모달 띄우기
ModalOpen() {
var dimmed = document.getElementsByClassName('modal-insertFaq');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'block';
}
this.setCodeDate();
},
// 모달 끄기
ModalClose() {
this.formReset();
var dimmed = document.getElementsByClassName('modal-insertFaq');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'none';
}
},
// 저장 후 부모창 호출
toComplete() {
this.$parent.$refs.table.reloadData();
this.ModalClose();
},
setCodeDate() {
// 발송타입
api.commCode({ grpCd: 'SNDBLCK_TP_CD' }).then((response) => {
this.tpType = response.data.data.list;
});
api.commCode({ grpCd: 'SNDBLCK_RSN_CD' }).then((response) => {
this.rsnType = response.data.data.list;
});
},
doValidate() {
if (this.isNull(this.ctgCd) || this.ctgCd === 'null') {
this.row.title = '자주묻는 질문 등록';
this.row.msg1 = '분류코드를 선택해 주세요.';
this.row.focusTaget = '_ctgCd';
this.$refs.ValidationConfirmPopup.alertModalOpen(this.row);
return false;
}
if (this.isNull(this.title)) {
this.row.title = '자주묻는 질문 등록';
this.row.msg1 = '질문을 입력해 주세요.';
this.row.focusTaget = '_title';
this.$refs.ValidationConfirmPopup.alertModalOpen(this.row);
return false;
}
if (this.isNull(this.faqSbst)) {
this.row.title = '자주묻는 질문 등록';
this.row.msg1 = '답변을 입력해 주세요.';
this.row.focusTaget = '_faqSbst';
this.$refs.ValidationConfirmPopup.alertModalOpen(this.row);
return false;
}
/* const hp = this.blckSndrno;
if (!this.isNull(hp) && !this.isSendnum(hp)) {
this.row.title = '자주묻는 질문';
this.row.msg1 = '발신번호 형식이 잘못되었습니다. 확인 해주세요.';
this.$parent.alertInsert(this.row);
this.$refs._blckSndrno.focus();
return false;
} */
this.row.ctgCd = this.ctgCd;
return true;
},
formReset() {
Object.assign(this.$data, this.$options.data());
},
regisConfirm() {
if (this.doValidate()) {
this.$refs.ValidationConfirmPopup.confirmInsertFaqOpen();
}
},
// 바이트길이 구하기
getByteLength: function (decimal) {
return decimal >> 7 || this.LINE_FEED === decimal ? 2 : 1;
},
getByte: function (str) {
return str
.split('')
.map((s) => s.charCodeAt(0))
.reduce((prev, unicodeDecimalValue) => prev + this.getByteLength(unicodeDecimalValue), 0);
},
getLimitedByteText: function (inputText, maxByte) {
const characters = inputText.split('');
let validText = '';
let totalByte = 0;
for (let i = 0; i < characters.length; i += 1) {
const character = characters[i];
const decimal = character.charCodeAt(0);
const byte = this.getByteLength(decimal); // 글자 한 개가 몇 바이트 길이인지 구해주기
// 현재까지의 바이트 길이와 더해 최대 바이트 길이를 넘지 않으면
if (totalByte + byte <= maxByte) {
totalByte += byte; // 바이트 길이 값을 더해 현재까지의 총 바이트 길이 값을 구함
validText += character; // 글자를 더해 현재까지의 총 문자열 값을 구함
} else {
// 최대 바이트 길이를 넘으면
break; // for 루프 종료
}
}
return validText;
},
memoLimitByte() {
this.meno = this.getLimitedByteText(this.meno, this.maxByte);
}, //END 바이트길이 구하기
insertFaq() {
// const fd = new FormData();
// for (let i = 0; i < this.updateFileList.length; i++) {
// fd.append('files', this.updateFileList[i]);
// }
const params = {
title: this.title,
faqSbst: this.faqSbst,
useYn: this.useYn,
ctgCd: this.ctgCd,
regId: this.$store.getters['login/userId'],
chgId: this.$store.getters['login/userId'],
};
//fd.append('key', new Blob([JSON.stringify(params)], { type: 'application/json' }));
/* for (var pair of fd.entries()) {
console.log(pair[0] + ' : ' + pair[1]);
} */
homeMgtApi.insertFaq(params).then((response) => {
if (response.data.retCode == '0000') {
this.row.title = '자주묻는 질문 등록';
this.row.msg1 = '등록이 완료되었습니다.';
this.row.type = 'complete';
//this.$refs.ValidationConfirmPopup.alertModalOpen(this.row);
this.toComplete();
} else {
this.row.title = '자주묻는 질문 등록 실패';
this.row.msg1 = response.retMsg;
this.row.type = '';
this.$refs.ValidationConfirmPopup.alertModalOpen(this.row);
}
});
},
checkFocus() {
if (this.row.focusTaget === '_title') {
this.$refs._title.focus();
} else if (this.row.focusTaget === '_faqSbst') {
//this.$refs._ntSbst.focus();
} else if (this.row.focusTaget === '_ctgCd') {
this.$refs._ctgCd.focus();
}
},
/////////////////////////////////// 파일 첨부 ////////////////////////////////////////
onFileChange(event) {
const files = event.target.files || event.dataTransfer.files;
if (!files.length) return;
/* if (files.length > 3) {
confirm.fnAlert(
// "이미지 첨부 기준 안내",
'',
'<li>최대 3장 첨부할 수 있습니다.</li>',
'info'
);
this.imageAddTitle = '이미지는 최대 3장까지 첨부할 수 있습니다.';
//confirm.fnAlert("알림", "첨부파일은 최대 3개까지 가능합니다.", "alert");
return;
} else if (this.updateFileList.length + files.length > 3) {
confirm.fnAlert(
// "이미지 첨부 기준 안내",
'',
'<li>최대 3장 첨부할 수 있습니다.</li>',
'info'
);
this.imageAddTitle = '이미지는 최대 3장까지 첨부할 수 있습니다.';
// confirm.fnAlert("알림", "첨부파일은 최대 3개까지 가능합니다.", "alert");
return;
} */
this.addFiles(files);
},
async addFiles(files) {
for (let i = 0; i < files.length; i++) {
const src = await this.readFiles(files[i]);
files[i].src = src;
files[i].status = 'update';
files[i].index = this.updateFileList.length;
this.updateFileList.push(files[i]);
/* if (!(files[i].name.indexOf('jpg') > -1 || files[i].name.indexOf('jpeg') > -1)) {
confirm.fnAlert('', '<li>jpg파일 형식만 첨부할 수 있습니다.</li>', 'info');
this.imageAddTitle = 'jpg파일 형식만 첨부할 수 있습니다.';
continue;
} else if (files[i].size > 300000) {
confirm.fnAlert(
// "이미지 첨부 기준 안내",
'',
'<li>전체 크기 합계가 300KB 이하여야 합니다.</li>',
'info'
);
this.imageAddTitle = '전체 크기 합계가 300KB 이하여야 합니다.';
//confirm.fnAlert("이미지 사이즈 초과", "300KB이하 이미지만 등록 가능합니다.", "alert");
continue;
} else if (files[i].size + this.totalFileSize > 300000) {
confirm.fnAlert(
// "이미지 첨부 기준 안내",
'',
'<li>전체 크기 합계가 300KB 이하여야 합니다.</li>',
'info'
);
this.imageAddTitle = '전체 크기 합계가 300KB 이하여야 합니다.';
//confirm.fnAlert("이미지 사이즈 초과", "전체 합계 300KB이하 이미지만 등록 가능합니다.", "alert");
continue;
} else if (this.getImageSize(src) === false) {
confirm.fnAlert(
// "이미지 첨부 기준 안내",
'',
'<li>1,500(가로)x1,440(세로)px 이하 크기만 첨부할 수 있습니다.</li>',
'info'
);
this.imageAddTitle = '1,500(가로)x1,440(세로)px 이하 크기만 첨부할 수 있습니다.';
//confirm.fnAlert("이미지 크기 초과", "1500 * 1440 이하 이미지만 등록 가능합니다.", "alert");
continue;
} else {
files[i].status = 'update';
files[i].index = this.updateFileList.length;
this.updateFileList.push(files[i]);
confirm.fnAlert('', '이미지가 정상적으로 추가 되었습니다.', 'alert');
this.imageAddTitle = '';
} */
}
this.$refs.imageUploader.value = ''; // 이미지 중복 가능하도록 input 초기화
},
// FileReader를 통해 파일을 읽어 thumbnail 영역의 src 값으로 셋팅
async readFiles(files) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = async (e) => {
resolve(e.target.result);
};
reader.readAsDataURL(files);
});
},
getImageSize(src) {
const img = new Image();
let _width = 0;
let _height = 0;
img.src = src;
img.onload = function () {
_width = img.width;
_height = img.height;
if (_width >= 1500 || _height >= 1440) {
return false;
} else {
return true;
}
};
},
popupHandleRemove(index) {
this.updateFileList.splice(index, 1);
},
},
};
</script>
<style scoped>
.popup-btn-wrap {
width: 500px;
margin: auto;
padding: 100px 0;
}
.popup-btn-wrap button {
width: 100%;
margin-bottom: 10px;
height: 50px;
border-radius: 5px;
box-shadow: none;
border: 1px solid #000;
}
.popup-btn-wrap button:hover {
background: #000;
color: #fff;
}
.btn.plus {
font-family: SpoqaHanSansNeo;
font-weight: 400;
font-size: 16px;
color: #fff;
background-color: #35354f;
border-radius: 4px;
text-align: center;
min-width: 89px;
height: 36px;
padding: 10px 20px;
letter-spacing: -0.025em;
border: none;
position: relative;
line-height: 1;
display: inline-block;
box-sizing: border-box;
transition: 0.3s;
}
.btn input {
width: 100%;
height: 100%;
opacity: 0;
position: absolute;
top: 0;
left: 0;
cursor: pointer;
z-index: 1;
}
.file_name {
display: inline-flex;
}
.btn_del {
background: #e4e4e4;
width: 15px;
height: 15px;
border-radius: 50%;
border: none;
font-size: 10px;
margin: 0 0 0 5px;
}
</style>

View File

@@ -0,0 +1,497 @@
<template>
<!-- <div class="wrap bg-wrap"> -->
<div>
<div class="dimmed modal52" @click="ModalClose()"></div>
<div class="popup-wrap modal52">
<!-- 자주묻는 질문 수정 -->
<div class="popup modal52 popup_form" style="width: 70vw">
<div class="pop-head">
<h3 class="pop-tit">자주묻는 질문 수정</h3>
</div>
<form autocomplete="off">
<table>
<colgroup>
<col width="10%" />
<col width="40%" />
<col width="10%" />
<col width="40%" />
</colgroup>
<tbody>
<tr>
<th style="width: 10%">분류코드</th>
<td>
<div class="select_box">
<select name="" id="right" v-model="ctgCd" style="min-width: 500px" ref="_ctgCd">
<option v-for="(option, i) in ctgCdOption" :value="option.code" v-bind:key="i">
{{ option.codeNm }}
</option>
</select>
</div>
</td>
<th style="width: 10%">사용여부</th>
<td>
<div class="select_box">
<select name="" id="right" v-model="useYn" style="min-width: 150px">
<option value="Y">Y</option>
<option value="N">N</option>
</select>
</div>
</td>
</tr>
<tr>
<th style="width: 10%">질문</th>
<td colspan="3">
<input type="text" placeholder="질문을 입력하세요" v-model="title" ref="_title" />
</td>
</tr>
<tr>
<th style="width: 10%">답변</th>
<td class="sender" colspan="3">
<!-- <vue-editor
id="editor"
useCustomImageHandler
@imageAdded="handleImageAdded"
v-model="faqSbst"
ref="_faqSbst"
>
</vue-editor> -->
<div style="display: flex">
<textarea v-model="faqSbst" ref="_faqSbst" style="width: 100%; min-height: 300px"></textarea>
</div>
</td>
</tr>
</tbody>
</table>
</form>
<div class="popup-btn2">
<button class="btn-pcolor" @click="updateConfirm()">수정</button>
<button class="btn-default" @click="ModalClose()">취소</button>
</div>
</div>
<!-- <common-modal ref="commonModal"></common-modal> -->
<validation-confirm-popup ref="ValidationConfirmPopup"></validation-confirm-popup>
</div>
</div>
</template>
<script>
import api from '@/service/api';
import homeMgtApi from '../service/homeMgtApi';
import ValidationConfirmPopup from './ValidationConfirmPopup.vue';
//import { VueEditor } from 'vue2-editor';
import { utils_mixin, chkPattern2 } from '../service/mixins';
export default {
name: 'FaqUpdatePop',
mixins: [utils_mixin, chkPattern2],
data() {
return {
props: {},
row: {},
rsnType: [],
tpType: [],
// FAQ
faqNo: '',
title: '',
faqSbst: '',
emgYn: 'N',
useYn: 'Y',
ctgCd: 'null',
fileNm: '',
filePath: '',
fileTitle: '',
fileNo: '',
updateFileList: [], // 업로드한 이미지 파일
delFileList: [],
ctgCdOption: [
{ code: 'null', codeNm: '분류코드를 선택하세요' },
{ code: '01', codeNm: '전송' },
{ code: '02', codeNm: '결제' },
{ code: '03', codeNm: '회원' },
{ code: '04', codeNm: '주소록' },
{ code: '05', codeNm: '서비스' },
{ code: '06', codeNm: '기타' },
],
// 자주묻는 질문
LINE_FEED: 10, // '\n',
maxByte: 2000,
// params: {
// 'blckSndrno' : ''
// ,'ctgCd' : '01'
// ,'blckRsnCd' : '02'
// ,'meno' : ''
// }
};
},
create() {
//this.setCodeDate();
this.formReset();
},
mounted() {
//this.ctgCd = '01'
},
components: {
//VueEditor,
ValidationConfirmPopup,
},
methods: {
handleImageAdded(file, Editor, cursorLocation, resetUploader) {
var fd = new FormData();
fd.append('files', file);
homeMgtApi
.getImageUrl(fd)
.then((response) => {
const url =
'/api/v1/bo/homeMgt/preview/' +
encodeURIComponent(response.data.data.replaceAll('\\', '/').replaceAll('/', '|')); // Get url from response
Editor.insertEmbed(cursorLocation, 'image', url);
resetUploader();
})
.catch((err) => {
console.log(err);
});
},
//모달 띄우기
ModalOpen(props) {
var dimmed = document.getElementsByClassName('modal52');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'block';
}
this.setCodeDate();
if (props) {
this.faqNo = props.faqNo;
this.title = props.title;
this.faqSbst = props.faqSbst;
this.useYn = props.useYn;
this.ctgCd = props.ctgCd;
// this.fileNm = props.fileNm.split(',');
// this.filePath = props.filePath.split(',');
// this.fileTitle = props.fileTitle.split(',');
// this.fileNo = props.fileNo.split(',');
// this.fileCount = props.fileCount;
}
/* for (let i = 0; i < this.fileCount; i++) {
this.updateFileList.push({
src: '' + encodeURIComponent(this.filePath[i].replaceAll('\\', '/')) + '/' + this.fileNm[i],
filePath: this.filePath[i],
fileNo: this.fileNo[i],
fileName: this.fileNm[i],
name: this.fileTitle[i],
});
} */
},
// 모달 끄기
ModalClose() {
this.formReset();
var dimmed = document.getElementsByClassName('modal52');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'none';
}
},
// 저장 후 부모창 호출
toComplete() {
this.$parent.$refs.table.reloadData();
this.ModalClose();
},
setCodeDate() {
// 발송타입
api.commCode({ grpCd: 'SNDBLCK_TP_CD' }).then((response) => {
this.tpType = response.data.data.list;
});
api.commCode({ grpCd: 'SNDBLCK_RSN_CD' }).then((response) => {
this.rsnType = response.data.data.list;
});
},
doValidate() {
if (this.isNull(this.ctgCd) || this.ctgCd === 'null') {
this.row.title = '자주묻는 질문 등록';
this.row.msg1 = '분류코드를 선택해 주세요.';
this.row.focusTaget = '_ctgCd';
this.$refs.ValidationConfirmPopup.alertModalOpen(this.row);
return false;
}
if (this.isNull(this.title)) {
this.row.title = '자주묻는 질문 등록';
this.row.msg1 = '질문을 입력해 주세요.';
this.row.focusTaget = '_title';
this.$refs.ValidationConfirmPopup.alertModalOpen(this.row);
return false;
}
if (this.isNull(this.faqSbst)) {
this.row.title = '자주묻는 질문 등록';
this.row.msg1 = '답변을 입력해 주세요.';
this.row.focusTaget = '_faqSbst';
this.$refs.ValidationConfirmPopup.alertModalOpen(this.row);
return false;
}
this.row.ctgCd = this.ctgCd;
return true;
},
formReset() {
Object.assign(this.$data, this.$options.data());
},
updateConfirm() {
if (this.doValidate()) {
this.$refs.ValidationConfirmPopup.confirmUpdateFaqOpen();
}
},
// 바이트길이 구하기
getByteLength: function (decimal) {
return decimal >> 7 || this.LINE_FEED === decimal ? 2 : 1;
},
getByte: function (str) {
return str
.split('')
.map((s) => s.charCodeAt(0))
.reduce((prev, unicodeDecimalValue) => prev + this.getByteLength(unicodeDecimalValue), 0);
},
getLimitedByteText: function (inputText, maxByte) {
const characters = inputText.split('');
let validText = '';
let totalByte = 0;
for (let i = 0; i < characters.length; i += 1) {
const character = characters[i];
const decimal = character.charCodeAt(0);
const byte = this.getByteLength(decimal); // 글자 한 개가 몇 바이트 길이인지 구해주기
// 현재까지의 바이트 길이와 더해 최대 바이트 길이를 넘지 않으면
if (totalByte + byte <= maxByte) {
totalByte += byte; // 바이트 길이 값을 더해 현재까지의 총 바이트 길이 값을 구함
validText += character; // 글자를 더해 현재까지의 총 문자열 값을 구함
} else {
// 최대 바이트 길이를 넘으면
break; // for 루프 종료
}
}
return validText;
},
memoLimitByte() {
this.meno = this.getLimitedByteText(this.meno, this.maxByte);
}, //END 바이트길이 구하기
updateFaq() {
const params = {
faqNo: this.faqNo,
title: this.title,
faqSbst: this.faqSbst,
useYn: this.useYn,
ctgCd: this.ctgCd,
chgId: this.$store.getters['login/userId'],
};
homeMgtApi.updateFaq(params).then((response) => {
if (response.data.retCode == '0000') {
this.row.title = '자주묻는 질문 수정';
this.row.msg1 = '수정이 완료되었습니다.';
this.row.type = 'update';
//this.$refs.ValidationConfirmPopup.alertModalOpen(this.row);
this.toComplete();
} else {
this.row.title = '자주묻는 질문 수정 실패';
this.row.msg1 = response.retMsg;
this.row.type = '';
this.$refs.ValidationConfirmPopup.alertModalOpen(this.row);
}
});
},
checkFocus() {
if (this.row.focusTaget === '_title') {
this.$refs._title.focus();
} else if (this.row.focusTaget === '_faqSbst') {
//this.$refs._faqSbst.focus();
} else if (this.row.focusTaget === '_ctgCd') {
this.$refs._ctgCd.focus();
}
},
/////////////////////////////////// 파일 첨부 ////////////////////////////////////////
onFileChange(event) {
const files = event.target.files || event.dataTransfer.files;
if (!files.length) return;
/* if (files.length > 3) {
confirm.fnAlert(
// "이미지 첨부 기준 안내",
'',
'<li>최대 3장 첨부할 수 있습니다.</li>',
'info'
);
this.imageAddTitle = '이미지는 최대 3장까지 첨부할 수 있습니다.';
//confirm.fnAlert("알림", "첨부파일은 최대 3개까지 가능합니다.", "alert");
return;
} else if (this.updateFileList.length + files.length > 3) {
confirm.fnAlert(
// "이미지 첨부 기준 안내",
'',
'<li>최대 3장 첨부할 수 있습니다.</li>',
'info'
);
this.imageAddTitle = '이미지는 최대 3장까지 첨부할 수 있습니다.';
// confirm.fnAlert("알림", "첨부파일은 최대 3개까지 가능합니다.", "alert");
return;
} */
this.addFiles(files);
},
async addFiles(files) {
for (let i = 0; i < files.length; i++) {
const src = await this.readFiles(files[i]);
files[i].src = src;
this.updateFileList.push(files[i]);
/* if (!(files[i].name.indexOf('jpg') > -1 || files[i].name.indexOf('jpeg') > -1)) {
confirm.fnAlert('', '<li>jpg파일 형식만 첨부할 수 있습니다.</li>', 'info');
this.imageAddTitle = 'jpg파일 형식만 첨부할 수 있습니다.';
continue;
} else if (files[i].size > 300000) {
confirm.fnAlert(
// "이미지 첨부 기준 안내",
'',
'<li>전체 크기 합계가 300KB 이하여야 합니다.</li>',
'info'
);
this.imageAddTitle = '전체 크기 합계가 300KB 이하여야 합니다.';
//confirm.fnAlert("이미지 사이즈 초과", "300KB이하 이미지만 등록 가능합니다.", "alert");
continue;
} else if (files[i].size + this.totalFileSize > 300000) {
confirm.fnAlert(
// "이미지 첨부 기준 안내",
'',
'<li>전체 크기 합계가 300KB 이하여야 합니다.</li>',
'info'
);
this.imageAddTitle = '전체 크기 합계가 300KB 이하여야 합니다.';
//confirm.fnAlert("이미지 사이즈 초과", "전체 합계 300KB이하 이미지만 등록 가능합니다.", "alert");
continue;
} else if (this.getImageSize(src) === false) {
confirm.fnAlert(
// "이미지 첨부 기준 안내",
'',
'<li>1,500(가로)x1,440(세로)px 이하 크기만 첨부할 수 있습니다.</li>',
'info'
);
this.imageAddTitle = '1,500(가로)x1,440(세로)px 이하 크기만 첨부할 수 있습니다.';
//confirm.fnAlert("이미지 크기 초과", "1500 * 1440 이하 이미지만 등록 가능합니다.", "alert");
continue;
} else {
files[i].status = 'update';
files[i].index = this.updateFileList.length;
this.updateFileList.push(files[i]);
confirm.fnAlert('', '이미지가 정상적으로 추가 되었습니다.', 'alert');
this.imageAddTitle = '';
} */
}
console.log(this.updateFileList);
this.$refs.imageUploader.value = ''; // 이미지 중복 가능하도록 input 초기화
},
// FileReader를 통해 파일을 읽어 thumbnail 영역의 src 값으로 셋팅
async readFiles(files) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = async (e) => {
resolve(e.target.result);
};
reader.readAsDataURL(files);
});
},
getImageSize(src) {
const img = new Image();
let _width = 0;
let _height = 0;
img.src = src;
img.onload = function () {
_width = img.width;
_height = img.height;
if (_width >= 1500 || _height >= 1440) {
return false;
} else {
return true;
}
};
},
popupHandleRemove(index, fileNo) {
this.delFileList.push(fileNo);
this.updateFileList.splice(index, 1);
},
download(filePath, fileName, fileTitle) {
this.row = {};
this.row.fileTitle = fileTitle;
this.row.filePath = filePath;
this.row.fileNm = fileName;
homeMgtApi.fileDownload(this.row);
},
},
};
</script>
<style scoped>
.popup-btn-wrap {
width: 500px;
margin: auto;
padding: 100px 0;
}
.popup-btn-wrap button {
width: 100%;
margin-bottom: 10px;
height: 50px;
border-radius: 5px;
box-shadow: none;
border: 1px solid #000;
}
.popup-btn-wrap button:hover {
background: #000;
color: #fff;
}
.btn.plus {
font-family: SpoqaHanSansNeo;
font-weight: 400;
font-size: 16px;
color: #fff;
background-color: #35354f;
border-radius: 4px;
text-align: center;
min-width: 89px;
height: 36px;
padding: 10px 20px;
letter-spacing: -0.025em;
border: none;
position: relative;
line-height: 1;
display: inline-block;
box-sizing: border-box;
transition: 0.3s;
}
.btn input {
width: 100%;
height: 100%;
opacity: 0;
position: absolute;
top: 0;
left: 0;
cursor: pointer;
z-index: 1;
}
.file_name {
display: inline-flex;
}
.btn_del {
background: #e4e4e4;
width: 15px;
height: 15px;
border-radius: 50%;
border: none;
font-size: 10px;
margin: 0 0 0 5px;
}
</style>

View File

@@ -95,11 +95,9 @@
href="javascript:void(0);" href="javascript:void(0);"
v-if="item.filePath" v-if="item.filePath"
@click="download(item.filePath, item.fileName, item.name)" @click="download(item.filePath, item.fileName, item.name)"
>{{ item.name }} (다운로드가능)</a >{{ item.name }}</a
> >
<p class="file_name" v-else> <p class="file_name" v-else>{{ item.name }} {{ item.fileNo ? `(${item.fileNo})` : '' }}</p>
{{ index + 1 }}. {{ item.name }} {{ item.fileNo ? `(${item.fileNo})` : '' }}
</p>
<button type="button" class="btn_del" @click="popupHandleRemove(index, item.fileNo)">X</button> <button type="button" class="btn_del" @click="popupHandleRemove(index, item.fileNo)">X</button>
</div> </div>

View File

@@ -53,6 +53,40 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 자주묻는 질문 등록-->
<div class="dimmed confirm-insert-faq" @click="confirmInsertFaqClose()"></div>
<div class="popup-wrap confirm-insert-faq">
<div class="popup confirm-insert-faq">
<div class="pop-head">
<h3 class="pop-tit">자주묻는 질문 등록</h3>
</div>
<div class="pop-cont">
<p>작성된 내용으로 등록 하시겠습니까?</p>
</div>
<div class="popup-btn2">
<button class="btn-pcolor" @click="confirmInsertFaq()">확인</button>
<button class="btn-default" @click="confirmInsertFaqClose()">취소</button>
</div>
</div>
</div>
<!-- 자주묻는 질문 수정-->
<div class="dimmed confirm-update-faq" @click="confirmUpdateFaqClose()"></div>
<div class="popup-wrap confirm-update-faq">
<div class="popup confirm-update-faq">
<div class="pop-head">
<h3 class="pop-tit">자주묻는 질문 수정</h3>
</div>
<div class="pop-cont">
<p>작성된 내용으로 수정 하시겠습니까?</p>
</div>
<div class="popup-btn2">
<button class="btn-pcolor" @click="confirmUpdateFaq()">확인</button>
<button class="btn-default" @click="confirmUpdateFaqClose()">취소</button>
</div>
</div>
</div>
</div> </div>
</template> </template>
@@ -154,6 +188,56 @@ export default {
dimmed[i].style.display = 'none'; dimmed[i].style.display = 'none';
} }
}, },
/* **************************************************************************************** */
//자주묻는 질문 등록 팝업
confirmInsertFaqOpen() {
var dimmed = document.getElementsByClassName('confirm-insert-faq');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'block';
}
},
//자주묻는 질문 등록
confirmInsertFaq() {
var dimmed = document.getElementsByClassName('confirm-insert-faq');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'none';
}
this.$parent.insertFaq();
},
//자주묻는 질문 등록 팝업 Close
confirmInsertFaqClose() {
var dimmed = document.getElementsByClassName('confirm-insert-faq');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'none';
}
},
//자주묻는 질문 수정 팝업
confirmUpdateFaqOpen() {
var dimmed = document.getElementsByClassName('confirm-update-faq');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'block';
}
},
//자주묻는 질문 수정
confirmUpdateFaq() {
var dimmed = document.getElementsByClassName('confirm-update-faq');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'none';
}
this.$parent.updateFaq();
},
//자주묻는 질문 수정 팝업 Close
confirmUpdateFaqClose() {
var dimmed = document.getElementsByClassName('confirm-update-faq');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'none';
}
},
}, },
}; };
</script> </script>

View File

@@ -1,4 +1,5 @@
import Notice from '../views/notice'; import Notice from '../views/notice';
import Faq from '../views/faq';
export default [ export default [
{ {
@@ -8,4 +9,11 @@ export default [
props: true, props: true,
meta: { public: false }, meta: { public: false },
}, },
{
path: '/homeMgt/faq',
component: Faq,
name: 'faq',
props: true,
meta: { public: false },
},
]; ];

View File

@@ -20,6 +20,21 @@ const deleteNotice = (params) => {
return httpClient.post('/api/v1/bo/homeMgt/deleteNotice', params, { withCredentials: false }); return httpClient.post('/api/v1/bo/homeMgt/deleteNotice', params, { withCredentials: false });
}; };
// 자주묻는 질문 등록
const insertFaq = (params) => {
return httpClient.post('/api/v1/bo/homeMgt/insertFaq', params, { withCredentials: false });
};
// 자주묻는 질문 수정
const updateFaq = (params) => {
return httpClient.post('/api/v1/bo/homeMgt/updateFaq', params, { withCredentials: false });
};
// 자주묻는 질문 삭제
const deleteFaq = (params) => {
return httpClient.post('/api/v1/bo/homeMgt/deleteFaq', params, { withCredentials: false });
};
const getImageUrl = (params) => { const getImageUrl = (params) => {
return httpClient.post('/api/v1/bo/homeMgt/getImageUrl', params, { return httpClient.post('/api/v1/bo/homeMgt/getImageUrl', params, {
headers: { headers: {
@@ -64,4 +79,7 @@ export default {
deleteNotice, deleteNotice,
fileDownload, fileDownload,
getImageUrl, getImageUrl,
insertFaq,
updateFaq,
deleteFaq,
}; };

View File

@@ -0,0 +1,266 @@
<template>
<div class="contents">
<div class="contents_wrap">
<div class="top_wrap">
<h3 class="title">자주하는 질문</h3>
<p class="breadcrumb">홈페이지 관리 &gt; 자주하는 질문</p>
</div>
<div class="search_wrap">
<div class="select_box">
<label for="right" class="label">분류코드</label>
<select name="" id="right" v-model="searchType1" @change="search">
<option value="">전체</option>
<option value="01">전송</option>
<option value="02">결제</option>
<option value="03">회원</option>
<option value="04">주소록</option>
<option value="05">서비스</option>
<option value="06">기타</option>
</select>
</div>
<div class="input_box id">
<label for="id1" class="label">제목</label>
<input
class="search-box"
type="text"
id="id1"
placeholder="제목 입력"
v-model="searchText1"
@keyup.enter="search"
/>
</div>
<button type="button" class="button grey" @click="search">조회</button>
</div>
<div class="info">
<div class="count">
<span>{{ totalItems.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') }}</span
>
<div class="select_box NumberSe">
<select name="" id="" v-model="perPageCnt" @change="changePerPage()">
<option v-for="option in options" v-bind:value="option.value" v-bind:key="option.value">
{{ option.text }}
</option>
</select>
</div>
</div>
<div class="button_group">
<button type="button" class="button blue admin add" @click="ModalOpen()">질문 등록</button>
<button type="button" class="button white del" @click="deleteFaq()">삭제</button>
</div>
</div>
<div class="table">
<custom-grid
ref="table"
:totalItems="'totalItems'"
:url="grid.url"
:pagePerRows="grid.pagePerRows"
:initialRequest="grid.initialRequest"
:pagination="grid.pagination"
:isCheckbox="grid.isCheckbox"
:columns="grid.columns"
:noDataStr="grid.noDataStr"
:addCls="grid.addCls"
:header="grid.headder"
></custom-grid>
</div>
</div>
<FaqPop ref="FaqPop" />
<FaqUpdatePop ref="FaqUpdatePop" />
<common-modal ref="commmonModal"></common-modal>
</div>
</template>
<script>
import httpClient from '../../../common/http-client';
import customGrid from '@/components/CustomGrid';
import commonModal from '@/components/modal/commonModal';
import FaqPop from '../components/FaqPop.vue';
import FaqUpdatePop from '../components/FaqUpdatePop.vue';
import homeMgtApi from '../service/homeMgtApi';
class CustomATagRenderer {
constructor(props) {
this.props = props;
const el = document.createElement('a');
el.href = 'javascript:void(0);';
el.className = 'btn_text';
el.innerText = String(props.colValue);
this.el = el;
}
getElement() {
return this.el;
}
addEvent(selEl) {
selEl.addEventListener('click', () => {
const { callback } = this.props['cgrido' + this.props.colName].options;
callback(this.props);
});
}
}
export default {
name: 'faq',
components: { customGrid, FaqPop, FaqUpdatePop, commonModal },
data() {
return {
row: {},
totalItems: 0,
perPageCnt: 50,
searchType1: '',
searchText1: '',
options: [
{ text: '20', value: 20 },
{ text: '50', value: 50 },
{ text: '100', value: 100 },
],
grid: {
url: '/api/v1/bo/homeMgt/faqList',
pagePerRows: 20,
pagination: true,
isCheckbox: true, // true:첫번째 컬럼 앞에 체크박스 생성 / false:체크박스 제거
initialRequest: true,
addCls: 'box_OFvis',
columns: [
{ name: 'no', header: 'No', align: 'center', width: '5%' },
{ name: 'faqNo', header: '게시물', align: 'center', width: '5%' },
{ name: 'ctgCdNm', header: '분류코드명', align: 'center', width: '10%' },
{
name: 'title',
header: '제목',
align: 'left',
width: '50%',
renderer: {
type: CustomATagRenderer,
options: {
callback: this.faqDetail,
},
},
},
{ name: 'useYn', header: '사용여부', align: 'center', width: '5%' },
{ name: 'regId', header: '등록자', align: 'center', width: '10%' },
{ name: 'regDt', header: '등록일자', align: 'center', width: '10%' },
],
noDataStr: '검색 결과가 없습니다.',
params: {
searchType1: '',
searchType2: '',
searchText1: '',
searchText2: '',
},
excelHeader: [],
},
};
},
mounted() {
// this.fnSelectFaqList();
//let page = 1;
// 페이지 정보 및 검색 조건
const getCondition = this.$store.getters['searchcondition/getSearchCondition'];
// store에 저장된 페이지 정보 및 검색 조건을 불러오기
let isKeep = false;
if (getCondition) {
this.grid.pagePerRows = getCondition.perPage;
this.grid.params = getCondition.params;
// page = getCondition.page;
isKeep = true;
}
this.search(isKeep);
},
beforeRouteLeave(to, from, next) {
const getP = this.$refs.table.getPagination();
this.$store.commit('searchcondition/updateSearchCondition', {
page: getP._currentPage,
perPage: this.perPageCnt,
params: this.grid.params,
});
// 라우트 하기전 실행
next();
},
methods: {
fnSelectFaqList() {
const params = { page: 1, pagePerRows: 10 };
httpClient.post('/api/v1/bo/homeMgt/faqList', params, { headers: { 'Show-Layer': 'Yes' } }).then((response) => {
console.log(response.data);
});
},
ModalOpen() {
this.$refs.FaqPop.ModalOpen();
},
faqDetail(props) {
//console.log(props);
this.$refs.FaqUpdatePop.ModalOpen(props);
},
search: function (isKeep) {
this.grid.params.searchType1 = this.searchType1;
this.grid.params.searchText1 = this.searchText1;
this.$refs.table.search(this.grid.params, isKeep);
this.sendStoreData();
},
sendStoreData: function () {
const getP = this.$refs.table.getPagination();
this.$store.commit('searchcondition/updateSearchCondition', {
page: getP._currentPage,
perPage: this.perPageCnt,
params: this.grid.params,
});
//const getCondition = this.$store.getters['searchcondition/getSearchCondition'];
},
changePerPage: function () {
// 페이지당 조회할 개수
this.grid.pagePerRows = this.perPageCnt;
this.search(true);
},
deleteFaq() {
var chkList = this.$refs.table.checkedElementDatas();
if (chkList.length == 0) {
this.row.title = '자주묻는 질문 관리';
this.row.msg1 = '삭제 대상을 체크를 해주세요.';
this.$refs.commmonModal.alertModalOpen(this.row);
return false;
}
//const param = chkList.map((row)=>({regReqNo:row.regReqNo} ));
const param = chkList.map((row) => ({ faqNo: row.faqNo }));
this.row.list = param;
this.row.title = '자주묻는 질문 관리';
this.row.msg1 = '삭제 하시겠습니까?';
this.$refs.commmonModal.confirmModalOpen2(this.row);
console.log(typeof this.row.list[0].faqNo);
//this.$refs.commmonModal.confirmModalOpen2(this.row);
},
confirmCalbackFnc(props) {
if (props.result) {
this.faqDelete();
}
},
async faqDelete() {
// this.row.title = '자주묻는 질문 관리';
// this.row.msg1 = '준비중입니다.';
// this.$refs.commmonModal.alertModalOpen(this.row);
try {
let response = await homeMgtApi.deleteFaq(this.row);
const result = response.data;
if (result != null && result.retCode == '0000') {
this.$refs.table.reloadData();
return;
} else {
this.row.title = '공지사항 관리';
this.row.msg1 = '실패 하였습니다.';
this.$refs.commmonModal.alertModalOpen(this.row);
}
} catch (err) {
this.row.title = '공지사항 관리';
this.row.msg1 = '실패 하였습니다.';
this.$refs.commmonModal.alertModalOpen(this.row);
}
},
},
};
</script>

View File

@@ -2,7 +2,7 @@
<div class="contents"> <div class="contents">
<div class="contents_wrap"> <div class="contents_wrap">
<div class="top_wrap"> <div class="top_wrap">
<h3 class="title">홈페이지 관리</h3> <h3 class="title">공지사항</h3>
<p class="breadcrumb">홈페이지 관리 &gt; 공지사항</p> <p class="breadcrumb">홈페이지 관리 &gt; 공지사항</p>
</div> </div>
<div class="search_wrap"> <div class="search_wrap">
@@ -125,14 +125,12 @@ export default {
columns: [ columns: [
{ name: 'no', header: 'No', align: 'center', width: '5%' }, { name: 'no', header: 'No', align: 'center', width: '5%' },
{ name: 'ntNo', header: 'ntNo', align: 'center', width: '5%' },
{ name: 'ctgCdNm', header: '분류코드명', align: 'center', width: '10%' }, { name: 'ctgCdNm', header: '분류코드명', align: 'center', width: '10%' },
{ name: 'emgYn', header: '긴급여부(Y/N)', align: 'center', width: '10%' },
{ {
name: 'title', name: 'title',
header: '제목', header: '제목',
align: 'left', align: 'left',
width: '50%', width: '45%',
renderer: { renderer: {
type: CustomATagRenderer, type: CustomATagRenderer,
options: { options: {
@@ -140,6 +138,7 @@ export default {
}, },
}, },
}, },
{ name: 'emgYn', header: '긴급여부(Y/N)', align: 'center', width: '10%' },
{ name: 'fileYn', header: '파일유무', align: 'center', width: '5%' }, { name: 'fileYn', header: '파일유무', align: 'center', width: '5%' },
{ name: 'useYn', header: '사용여부', align: 'center', width: '5%' }, { name: 'useYn', header: '사용여부', align: 'center', width: '5%' },
{ name: 'regr', header: '등록자', align: 'center', width: '10%' }, { name: 'regr', header: '등록자', align: 'center', width: '10%' },

View File

@@ -181,7 +181,7 @@ router.beforeEach((to, from, next) => {
} }
// url 홈페이지 관리 // url 홈페이지 관리
if (nextUrl == '/homeMgt/notice') { if (nextUrl == '/homeMgt/notice' || nextUrl == '/homeMgt/faq') {
moveFlag = true; moveFlag = true;
} }

View File

@@ -159,6 +159,13 @@ public class HomeMgtController {
} }
} }
/**
* date : 2022. 11. 02.
* auth : kjh
* desc : 이미지 미리보기.
* @param imgurl
* @return imgurl
*/
@ApiOperation(value = "이미지 미리보기", notes = "이미지 미리보기") @ApiOperation(value = "이미지 미리보기", notes = "이미지 미리보기")
@GetMapping(value = "/preview/{imgurl}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) @GetMapping(value = "/preview/{imgurl}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<byte[]> previewImageResource(@PathVariable @ApiParam(value = "이미지 경로") String imgurl) { public ResponseEntity<byte[]> previewImageResource(@PathVariable @ApiParam(value = "이미지 경로") String imgurl) {
@@ -189,4 +196,86 @@ public class HomeMgtController {
return new ResponseEntity<byte[]>(HttpStatus.NOT_FOUND); return new ResponseEntity<byte[]>(HttpStatus.NOT_FOUND);
} }
} }
/**
* date : 2022. 11. 03.
* auth : kjh
* desc : FAQ 조회.
* @param faqListReqDto
* @return FaqListResDto
*/
@ApiOperation(value = "/faqList", notes = "자주묻는 질문 조회")
@ApiResponses({ @ApiResponse(code = HttpServletResponse.SC_OK, message = "SUCESS") })
@RequestMapping(value = "/faqList", method = { RequestMethod.POST })
@ResponseBody
public FaqListResDto faqList(@RequestBody @Valid FaqListReqDto faqListReqDto,
BindingResult bindingResult, HttpServletResponse response) {
if (validComponents.validParameter(bindingResult)) {
return new FaqListResDto(ApiResponseCode.CM_PARAMETER_ERROR);
}
return homeService.faqList(faqListReqDto);
}
/**
* date : 2022. 11. 03.
* auth : kjh
* desc : FAQ 등록.
* @param insertFaqReqDto
* @return InsertFaqResDto
*/
@ApiOperation(value = "/insertFaq", notes = "자주묻는 질문 등록")
@ApiResponses({ @ApiResponse(code = HttpServletResponse.SC_OK, message = "SUCESS") })
@RequestMapping(value = "/insertFaq", method = { RequestMethod.POST })
@ResponseBody
public InsertFaqResDto insertFaq(@RequestBody @Valid InsertFaqReqDto insertFaqReqDto, BindingResult bindingResult) {
System.out.println("insertFaqReqDto ::::" + insertFaqReqDto);
if (validComponents.validParameter(bindingResult)) {
return new InsertFaqResDto(ApiResponseCode.CM_PARAMETER_ERROR);
}
return homeService.insertFaq(insertFaqReqDto);
}
/**
* date : 2022. 11. 03.
* auth : kjh
* desc : FAQ 수정.
* @param updateFaqReqDto
* @return UpdateFaqResDto
*/
@ApiOperation(value = "/updateFaq", notes = "자주묻는 질문 등록")
@ApiResponses({ @ApiResponse(code = HttpServletResponse.SC_OK, message = "SUCESS") })
@RequestMapping(value = "/updateFaq", method = { RequestMethod.POST })
@ResponseBody
public UpdateFaqResDto updateFaq(@RequestBody @Valid UpdateFaqReqDto updateFaqReqDto, BindingResult bindingResult) {
if (validComponents.validParameter(bindingResult)) {
return new UpdateFaqResDto(ApiResponseCode.CM_PARAMETER_ERROR);
}
return homeService.updateFaq(updateFaqReqDto);
}
/**
* date : 2022. 11. 03.
* auth : kjh
* desc : FAQ 삭제.
* @param deleteFaqReqDto
* @return DeleteFaqResDto
*/
@ApiOperation(value = "/deleteFaq", notes = "공지사항 삭제")
@ApiResponses({ @ApiResponse(code = HttpServletResponse.SC_OK, message = "SUCESS") })
@RequestMapping(value = "/deleteFaq", method = { RequestMethod.POST })
@ResponseBody
public DeleteFaqResDto deleteFaq(@RequestBody @Valid DeleteFaqReqDto deleteFaqReqDto, BindingResult bindingResult) {
if (validComponents.validParameter(bindingResult)) {
return new DeleteFaqResDto(ApiResponseCode.CM_PARAMETER_ERROR);
}
return homeService.deleteFaq(deleteFaqReqDto);
}
} }

View File

@@ -29,4 +29,16 @@ public interface HomeMgtMapper {
int deleteNotice(DeleteNoticeReqDto deleteNoticeReqDto); int deleteNotice(DeleteNoticeReqDto deleteNoticeReqDto);
int selectFaqTotalCnt(FaqListReqDto faqListReqDto);
List<FaqDto> selectFaqList(FaqListReqDto faqListReqDto);
int selectFaqNumber(FaqListReqDto faqListReqDto);
void insertFaq(InsertFaqReqDto insertFaqReqDto);
int updateFaq(UpdateFaqReqDto updateFaqReqDto);
int deleteFaq(DeleteFaqReqDto deleteFaqReqDto);
} }

View File

@@ -288,4 +288,111 @@ public class HomeMgtService {
return new DeleteNoticeResDto(ApiResponseCode.SUCCESS); return new DeleteNoticeResDto(ApiResponseCode.SUCCESS);
} }
/**
* date : 2022. 11. 03.
* auth : kjh
* desc : faq 목록 조회
* @param faqListReqDto
* @return FaqListResDto
*/
public FaqListResDto faqList(FaqListReqDto faqListReqDto) {
HomeMgtMapper homeMgtMapper = sqlSessionSlave.getMapper(HomeMgtMapper.class);
String nowPage = String.valueOf(faqListReqDto.getPage());
int totalCnt = homeMgtMapper.selectFaqTotalCnt(faqListReqDto);
if(totalCnt == 0) {
Paging paging = new Paging();
paging.setPage(nowPage);
paging.setTotalCnt(String.valueOf(totalCnt));
FaqListRes faqListRes = new FaqListRes();
faqListRes.setList(new ArrayList<>());
faqListRes.setPaging(paging);
return new FaqListResDto(ApiResponseCode.CM_NOT_FOUND, faqListRes);
}
int page = faqListReqDto.getPage();
int pagePerRows = faqListReqDto.getPagePerRows();
page = (page -1) * pagePerRows;
faqListReqDto.setPage(page);
List<FaqDto> faqDto = homeMgtMapper.selectFaqList(faqListReqDto);
Paging paging = new Paging();
paging.setPage(nowPage);
paging.setTotalCnt(String.valueOf(totalCnt));
FaqListRes faqListRes = new FaqListRes();
faqListRes.setList(faqDto);
faqListRes.setPaging(paging);
return new FaqListResDto(ApiResponseCode.SUCCESS, faqListRes);
}
/**
* date : 2022. 11. 03.
* auth : kjh
* desc : FAQ 등록
* @param insertFaqReqDto
* @return InsertFaqResDto
*/
public InsertFaqResDto insertFaq(InsertFaqReqDto insertFaqReqDto) {
HomeMgtMapper homeMgtMapper = sqlSessionSlave.getMapper(HomeMgtMapper.class);
//공지사항 등록
try {
insertFaqReqDto.setFaqSbst(insertFaqReqDto.getFaqSbst().replaceAll("\\n", "<br />"));
homeMgtMapper.insertFaq(insertFaqReqDto);
}catch(Exception e){
return new InsertFaqResDto(ApiResponseCode.CM_DB_QUERY_ERR);
}
return new InsertFaqResDto(ApiResponseCode.SUCCESS);
}
/**
* date : 2022. 11. 03.
* auth : kjh
* desc : FAQ 수정
* @param updateFaqReqDto
* @return UpdateFaqResDto
*/
public UpdateFaqResDto updateFaq(UpdateFaqReqDto updateFaqReqDto) {
HomeMgtMapper homeMgtMapper = sqlSessionSlave.getMapper(HomeMgtMapper.class);
//공지사항 수정
try {
updateFaqReqDto.setFaqSbst(updateFaqReqDto.getFaqSbst().replaceAll("\\n", "<br />"));
homeMgtMapper.updateFaq(updateFaqReqDto);
}catch(Exception e){
return new UpdateFaqResDto(ApiResponseCode.CM_DB_QUERY_ERR);
}
return new UpdateFaqResDto(ApiResponseCode.SUCCESS);
}
/**
* date : 2022. 11. 03.
* auth : kjh
* desc : FAQ 삭제
* @param deleteFaqReqDto
* @return
*/
public DeleteFaqResDto deleteFaq(DeleteFaqReqDto deleteFaqReqDto) {
HomeMgtMapper homeMgtMapper = sqlSessionSlave.getMapper(HomeMgtMapper.class);
try {
homeMgtMapper.deleteFaq(deleteFaqReqDto);
} catch (Exception e) {
return new DeleteFaqResDto(ApiResponseCode.CM_DB_QUERY_ERR);
}
return new DeleteFaqResDto(ApiResponseCode.SUCCESS);
}
} }

View File

@@ -0,0 +1,15 @@
package kr.co.uplus.ez.api.homeMgt.dto;
import java.io.Serializable;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@Data
public class DeleteFaq implements Serializable{
@ApiModelProperty(example = "FAQ 번호", name = "FAQ 번호", dataType = "int")
private int faqNo;
}

View File

@@ -0,0 +1,14 @@
package kr.co.uplus.ez.api.homeMgt.dto;
import java.io.Serializable;
import java.util.List;
import lombok.Data;
@SuppressWarnings("serial")
@Data
public class DeleteFaqReqDto implements Serializable{
private List<DeleteFaq> list;
}

View File

@@ -0,0 +1,31 @@
package kr.co.uplus.ez.api.homeMgt.dto;
import java.io.Serializable;
import kr.co.uplus.ez.common.data.ApiResponseCode;
import kr.co.uplus.ez.common.data.ResponseMessage;
import lombok.Data;
@SuppressWarnings("serial")
@Data
public class DeleteFaqResDto extends ResponseMessage implements Serializable{
// 데이터.
private Object data;
public DeleteFaqResDto() {
this.retCode = ApiResponseCode.SUCCESS.getResultCode();
this.retMsg = ApiResponseCode.SUCCESS.getResultMsg();
}
public DeleteFaqResDto(ApiResponseCode returnStr) {
this.retCode = returnStr.getResultCode();
this.retMsg = returnStr.getResultMsg();
}
public DeleteFaqResDto(ApiResponseCode returnStr, Object data) {
this.retCode = returnStr.getResultCode();
this.retMsg = returnStr.getResultMsg();
this.data = data;
}
}

View File

@@ -0,0 +1,54 @@
package kr.co.uplus.ez.api.homeMgt.dto;
import java.io.Serializable;
import javax.validation.constraints.NotNull;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@Data
public class FaqDto implements Serializable {
@ApiModelProperty(example = "리스트 번호", name = "리스트 번호", dataType = "Integer")
private Integer no;
@ApiModelProperty(example = "faq 번호", name = "faq 번호", dataType = "int")
private int faqNo;
@ApiModelProperty(example = "분류 코드", name = "분류 코드", dataType = "String")
private String ctgCd;
@ApiModelProperty(example = "분류코드명", name = "분류코드명", dataType = "String")
private String ctgCdNm;
@ApiModelProperty(example = "제목", name = "제목", dataType = "String")
private String title;
@ApiModelProperty(example = "내용", name = "내용", dataType = "String")
private String faqSbst;
@ApiModelProperty(example = "사용 여부", name = "사용 여부", dataType = "String")
private String useYn;
@ApiModelProperty(example = "등록 ID", name = "등록 ID", dataType = "String")
private String regId;
@ApiModelProperty(example = "등록 일시", name = "등록 일시", dataType = "String")
private String regDt;
@ApiModelProperty(example = "변경 ID", name = "변경 ID", dataType = "String")
private String chgId;
@ApiModelProperty(example = "변경 일시", name = "변경 일시", dataType = "String")
private String chgDt;
@NotNull
@ApiModelProperty(example = "페이지당 조회할 목록 수",notes = "페이지당 조회할 목록 수", name = "페이지당 조회할 목록 수", dataType = "int")
private int pagePerRows;
@NotNull
@ApiModelProperty(example = "현재 페이지", name = "현재 페이지", dataType = "int")
private int page;
}

View File

@@ -0,0 +1,50 @@
package kr.co.uplus.ez.api.homeMgt.dto;
import java.io.Serializable;
import javax.validation.constraints.NotNull;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@Data
public class FaqListReqDto implements Serializable {
@ApiModelProperty(example = "분류 코드", name = "분류 코드", dataType = "String")
private String searchType1;
@ApiModelProperty(example = "제목 검색어", name = "제목 검색어", dataType = "String")
private String searchText1;
@ApiModelProperty(example = "faq 번호", name = "faq 번호", dataType = "int")
private int faqNo;
@ApiModelProperty(example = "분류 코드", name = "분류 코드", dataType = "String")
private String ctgCd;
@ApiModelProperty(example = "제목", name = "제목", dataType = "String")
private String title;
@ApiModelProperty(example = "내용", name = "내용", dataType = "String")
private String faqSbst;
@ApiModelProperty(example = "사용 여부", name = "사용 여부", dataType = "String")
private String useYn;
@ApiModelProperty(example = "등록 ID", name = "등록 ID", dataType = "String")
private String regId;
@ApiModelProperty(example = "변경 ID", name = "변경 ID", dataType = "String")
private String chgId;
@NotNull
@ApiModelProperty(example = "페이지당 조회할 목록 수",notes = "페이지당 조회할 목록 수", name = "페이지당 조회할 목록 수", dataType = "int")
private int pagePerRows;
@NotNull
@ApiModelProperty(example = "현재 페이지", name = "현재 페이지", dataType = "int")
private int page;
}

View File

@@ -0,0 +1,15 @@
package kr.co.uplus.ez.api.homeMgt.dto;
import java.io.Serializable;
import java.util.List;
import kr.co.uplus.ez.common.data.Paging;
import lombok.Data;
@SuppressWarnings("serial")
@Data
public class FaqListRes implements Serializable {
private Paging paging;
private List<FaqDto> list;
}

View File

@@ -0,0 +1,30 @@
package kr.co.uplus.ez.api.homeMgt.dto;
import java.io.Serializable;
import kr.co.uplus.ez.common.data.ApiResponseCode;
import kr.co.uplus.ez.common.data.ResponseMessage;
import lombok.Data;
@SuppressWarnings("serial")
@Data
public class FaqListResDto extends ResponseMessage implements Serializable {
// 데이터.
private FaqListRes data;
public FaqListResDto() {
this.retCode = ApiResponseCode.SUCCESS.getResultCode();
this.retMsg = ApiResponseCode.SUCCESS.getResultMsg();
}
public FaqListResDto(ApiResponseCode returnStr) {
this.retCode = returnStr.getResultCode();
this.retMsg = returnStr.getResultMsg();
}
public FaqListResDto(ApiResponseCode returnStr, FaqListRes data) {
this.retCode = returnStr.getResultCode();
this.retMsg = returnStr.getResultMsg();
this.data = data;
}
}

View File

@@ -0,0 +1,30 @@
package kr.co.uplus.ez.api.homeMgt.dto;
import java.io.Serializable;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@Data
public class InsertFaqReqDto implements Serializable {
@ApiModelProperty(example = "분류 코드", name = "분류 코드", dataType = "String")
private String ctgCd;
@ApiModelProperty(example = "제목", name = "제목", dataType = "String")
private String title;
@ApiModelProperty(example = "자주묻는 질문 내용", name = "자주묻는 질문 내용", dataType = "String")
private String faqSbst;
@ApiModelProperty(example = "사용 여부", name = "사용 여부", dataType = "String")
private String useYn;
@ApiModelProperty(example = "등록 ID", name = "등록 ID", dataType = "String")
private String regId;
@ApiModelProperty(example = "변경 ID", name = "변경 ID", dataType = "String")
private String chgId;
}

View File

@@ -0,0 +1,31 @@
package kr.co.uplus.ez.api.homeMgt.dto;
import java.io.Serializable;
import kr.co.uplus.ez.common.data.ApiResponseCode;
import kr.co.uplus.ez.common.data.ResponseMessage;
import lombok.Data;
@SuppressWarnings("serial")
@Data
public class InsertFaqResDto extends ResponseMessage implements Serializable{
// 데이터.
private Object data;
public InsertFaqResDto() {
this.retCode = ApiResponseCode.SUCCESS.getResultCode();
this.retMsg = ApiResponseCode.SUCCESS.getResultMsg();
}
public InsertFaqResDto(ApiResponseCode returnStr) {
this.retCode = returnStr.getResultCode();
this.retMsg = returnStr.getResultMsg();
}
public InsertFaqResDto(ApiResponseCode returnStr, Object data) {
this.retCode = returnStr.getResultCode();
this.retMsg = returnStr.getResultMsg();
this.data = data;
}
}

View File

@@ -0,0 +1,29 @@
package kr.co.uplus.ez.api.homeMgt.dto;
import java.io.Serializable;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@Data
public class UpdateFaqReqDto implements Serializable{
@ApiModelProperty(example = "faq 번호", name = "faq 번호", dataType = "int")
private int faqNo;
@ApiModelProperty(example = "분류 코드", name = "분류 코드", dataType = "String")
private String ctgCd;
@ApiModelProperty(example = "제목", name = "제목", dataType = "String")
private String title;
@ApiModelProperty(example = "내용", name = "내용", dataType = "String")
private String faqSbst;
@ApiModelProperty(example = "사용 여부", name = "사용 여부", dataType = "String")
private String useYn;
@ApiModelProperty(example = "변경 ID", name = "변경 ID", dataType = "String")
private String chgId;
}

View File

@@ -0,0 +1,30 @@
package kr.co.uplus.ez.api.homeMgt.dto;
import java.io.Serializable;
import kr.co.uplus.ez.common.data.ApiResponseCode;
import kr.co.uplus.ez.common.data.ResponseMessage;
import lombok.Data;
@SuppressWarnings("serial")
@Data
public class UpdateFaqResDto extends ResponseMessage implements Serializable {
// 데이터.
private Object data;
public UpdateFaqResDto() {
this.retCode = ApiResponseCode.SUCCESS.getResultCode();
this.retMsg = ApiResponseCode.SUCCESS.getResultMsg();
}
public UpdateFaqResDto(ApiResponseCode returnStr) {
this.retCode = returnStr.getResultCode();
this.retMsg = returnStr.getResultMsg();
}
public UpdateFaqResDto(ApiResponseCode returnStr, Object data) {
this.retCode = returnStr.getResultCode();
this.retMsg = returnStr.getResultMsg();
this.data = data;
}
}

View File

@@ -13,14 +13,14 @@
FROM FROM
hubez_common.EZ_NTBBS N1 hubez_common.EZ_NTBBS N1
WHERE 1 = 1 WHERE 1 = 1
<include refid="NoticeListCondition"></include> <include refid="ListCondition"></include>
</select> </select>
<!-- 공지사항 조회 --> <!-- 공지사항 조회 -->
<select id="selectNoticeList" <select id="selectNoticeList"
parameterType="kr.co.uplus.ez.api.homeMgt.dto.NoticeListReqDto" parameterType="kr.co.uplus.ez.api.homeMgt.dto.NoticeListReqDto"
resultType="kr.co.uplus.ez.api.homeMgt.dto.NoticeDto"> resultType="kr.co.uplus.ez.api.homeMgt.dto.NoticeDto">
/* sysMgt-mapper.xml(selectNoticeList) */ /* homeMgt-mapper.xml(selectNoticeList) */
SELECT SELECT
@ROWNUM := @ROWNUM + 1 AS NO, @ROWNUM := @ROWNUM + 1 AS NO,
NT_NO, NT_NO,
@@ -79,7 +79,7 @@
FROM FROM
hubez_common.EZ_NTBBS N1 , ( SELECT @ROWNUM := #{page} ) AS R hubez_common.EZ_NTBBS N1 , ( SELECT @ROWNUM := #{page} ) AS R
WHERE 1=1 WHERE 1=1
<include refid="NoticeListCondition"></include> <include refid="ListCondition"></include>
ORDER BY N1.REG_DT DESC ORDER BY N1.REG_DT DESC
LIMIT #{page}, #{pagePerRows} LIMIT #{page}, #{pagePerRows}
</select> </select>
@@ -88,13 +88,13 @@
<select id="selectNoticeNumber" <select id="selectNoticeNumber"
parameterType="kr.co.uplus.ez.api.homeMgt.dto.NoticeListReqDto" parameterType="kr.co.uplus.ez.api.homeMgt.dto.NoticeListReqDto"
resultType="int"> resultType="int">
/* sysMgt-mapper.xml(selectNoticeList) */ /* homeMgt-mapper.xml(selectNoticeList) */
SELECT SELECT
NT_NO, NT_NO,
FROM FROM
hubez_common.EZ_NTBBS N1 hubez_common.EZ_NTBBS N1
WHERE 1=1 WHERE 1=1
<include refid="NoticeListCondition"></include> <include refid="ListCondition"></include>
ORDER BY N1.REG_DT DESC ORDER BY N1.REG_DT DESC
LIMIT #{page}, #{pagePerRows} LIMIT #{page}, #{pagePerRows}
</select> </select>
@@ -174,8 +174,7 @@
/* homeMgt-mapper.xml (updateNotice) */ /* homeMgt-mapper.xml (updateNotice) */
UPDATE hubez_common.EZ_NTBBS UPDATE hubez_common.EZ_NTBBS
SET SET
CHG_DT = now() CTG_CD = #{ctgCd}
,CTG_CD = #{ctgCd}
,EMG_YN = #{emgYn} ,EMG_YN = #{emgYn}
,USE_YN = #{useYn} ,USE_YN = #{useYn}
,TITLE = #{title} ,TITLE = #{title}
@@ -218,7 +217,123 @@
</delete> </delete>
<sql id="NoticeListCondition"> <!-- faq 개수 조회 -->
<select id="selectFaqTotalCnt"
parameterType="kr.co.uplus.ez.api.homeMgt.dto.FaqListReqDto"
resultType="int">
/* homeMgt-mapper.xml(selectFaqTotalCnt) */
SELECT
COUNT(*)
FROM
hubez_common.EZ_FAQ N1
WHERE 1 = 1
<include refid="ListCondition"></include>
</select>
<!-- faq 조회 -->
<select id="selectFaqList" parameterType="kr.co.uplus.ez.api.homeMgt.dto.FaqListReqDto"
resultType="kr.co.uplus.ez.api.homeMgt.dto.FaqDto">
/* homeMgt-mapper.xml(selectFaqList) */
SELECT
@ROWNUM := @ROWNUM + 1 AS NO,
FAQ_NO,
CTG_CD,
(
SELECT DTL_CD_NM
FROM hubez_common.EZ_CD_DTL
WHERE DTL_CD = N1.CTG_CD
AND GRP_CD = 'FAQ_CTG_CD' AND USE_YN = 'Y'
) AS CTG_CD_NM,
TITLE,
REPLACE(FAQ_SBST,<![CDATA['<br />']]>, '\n') AS FAQ_SBST,
USE_YN,
RETV_CNT,
REG_ID,
DATE_FORMAT(REG_DT, '%Y-%m-%d') AS REG_DT,
CHG_ID,
CHG_DT
FROM hubez_common.EZ_FAQ AS N1 , ( SELECT @ROWNUM := #{page} ) AS R
WHERE 1=1
<include refid="ListCondition"></include>
ORDER BY N1.REG_DT DESC
LIMIT #{page}, #{pagePerRows}
</select>
<!-- FAQ 채번 -->
<select id="selectFaqNumber"
parameterType="kr.co.uplus.ez.api.homeMgt.dto.FaqListReqDto"
resultType="int">
/* homeMgt-mapper.xml(selectFaqList) */
SELECT
FAQ_NO,
FROM
hubez_common.EZ_FAQ N1
WHERE 1=1
<include refid="ListCondition"></include>
ORDER BY N1.REG_DT DESC
LIMIT #{page}, #{pagePerRows}
</select>
<!-- FAQ 등록 -->
<insert id="insertFaq" parameterType="kr.co.uplus.ez.api.homeMgt.dto.InsertFaqReqDto">
/* homeMgt-mapper.xml (insertFaq) */
INSERT INTO
hubez_common.EZ_FAQ(
CTG_CD,
TITLE,
FAQ_SBST,
USE_YN,
RETV_CNT,
REG_ID,
REG_DT,
CHG_ID,
CHG_DT
)VALUES(
#{ctgCd},
#{title},
#{faqSbst},
#{useYn},
0,
#{regId},
NOW(),
#{chgId},
NOW()
);
</insert>
<!-- FAQ 변경 -->
<update id="updateFaq" parameterType="kr.co.uplus.ez.api.homeMgt.dto.UpdateFaqReqDto">
/* homeMgt-mapper.xml (updateFaq) */
UPDATE hubez_common.EZ_FAQ
SET
CTG_CD = #{ctgCd}
,USE_YN = #{useYn}
,TITLE = #{title}
,FAQ_SBST = #{faqSbst}
,CHG_DT = NOW()
,CHG_ID = #{chgId}
WHERE
FAQ_NO = #{faqNo}
</update>
<!-- 공지사항 삭제 -->
<delete id="deleteFaq" parameterType="kr.co.uplus.ez.api.homeMgt.dto.DeleteFaqReqDto">
/* homeMgt-mapper.xml(deleteFaq) */
DELETE
FROM
hubez_common.EZ_FAQ
<where>
FAQ_NO IN
<foreach collection="list" item="item" index="i" open="("
separator="," close=")">
#{item.faqNo}
</foreach>
</where>
</delete>
<sql id="ListCondition">
<if test="searchType1 != null and searchType1 != ''"> <if test="searchType1 != null and searchType1 != ''">
AND N1.CTG_CD = #{searchType1} AND N1.CTG_CD = #{searchType1}
</if> </if>