
File name
Commit message
Commit date
05-22
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
File name
Commit message
Commit date
<template>
<!-- 사용자 -->
<template v-if="pageRole === 'portal'" >
<div class="content w1400 pt50 pb50">
<div class="page-title point-font mb30">
<p>{{ bbsMng.bbsNm }}</p>
</div>
<table class="form-table mb30">
<colgroup>
<col width="10%" />
<col width="90%" />
</colgroup>
<tbody>
<tr>
<th class="text-lf point-font">
<span>제목</span>
</th>
<td>
<input type="text" class="full-input" v-model="bbsCn.bbsNm" placeholder="제목을 입력하세요." />
</td>
</tr>
<tr class="border-top">
<th colspan="4" class="text-lf point-font">
<span>내용</span>
</th>
</tr>
<tr style="max-height: 600px">
<td colspan="4" style="height: 100%">
<ckeditorComponent ref="ckeditor5" :bbsCn.sync="bbsCn"></ckeditorComponent>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<!-- 관리자 -->
<template v-else>
<div class="content-zone sch-full">
<div class="content">
<div class="scroll">
<div class="form-box h_100">
<div class="form-box-title">
<p>기본정보</p>
<p><span>*</span>필수입력</p>
</div>
<div class="form-content grid-none overflow-y">
<div class="layout">
<label for="" class="form-title"><span>*</span>제목</label>
<input type="text" class="form-control sm" v-model="bbsCn.bbsNm" placeholder="제목을 입력하세요." />
</div>
<div class="layout" ref="first">
<label for="" class="form-title"><span>*</span>내용</label>
<div class="w_100 h_100">
<ckeditorComponent ref="ckeditor5" :bbsCn.sync="bbsCn"></ckeditorComponent>
</div>
</div>
<div class="layout" ref="two" v-if="bbsMng.atchFileUseYn === 'Y'">
<label for="" class="form-title">첨부파일</label>
<div>
<label for="file" class="file-upload">파일찾기</label>
<input type="file" id="file" ref="file" @change="fnFileInsert" multiple class="sr-only"/>
<div v-if="fileList.length > 0">
<ul>
<li v-for="(file, idx) in fileList" :key="idx" class="file-wrap">
<div v-if="file['fileId'] != null" class="layout">
<p>{{ file["fileNm"] }}.{{ file["extnNm"] }}</p>
<button class="btn-ico ico-close sm ml10" @click="fnFileDelete(file, idx)"></button>
</div>
<div v-else class="layout">
<p>{{ file.name }}</p>
<button class="btn-ico ico-close sm ml10" @click="fnFileDelete(file, idx)"></button>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="layout" ref="three" v-if="bbsMng.ntcUseYn === 'Y'" >
<label for="" class="form-title">공지글</label>
<div class="check-area">
<div class="form-check">
<input
type="radio"
name="notice"
id="notice-y"
class="mr5"
value="Y"
v-model="bbsCn.ntcPstYn"
/>
<label for="notice-y">사용</label>
</div>
<div class="form-check">
<input
type="radio"
name="notice"
id="notice-n"
class="mr5"
value="N"
v-model="bbsCn.ntcPstYn"
/>
<label for="notice-n">미사용</label>
</div>
</div>
</div>
<div class="layout border-bottom" ref="four" v-if="bbsCn.ntcPstYn === 'Y'">
<label for="" class="form-title">공지글 게시기간</label>
<div class="input-group">
<div class="form-control sm cal" style="max-width: 200px;">
<VueDatePicker
InlineOptions
placeholder="시작일"
locale="ko"
:enable-time-picker="false"
:format="formatDate"
v-model="bbsCn.ntcBgngDt"
@update:model-value="checkDateValidity('ntcBgngDt',$event)"
/>
<!-- <input
type="datetime-local"
class="full-input ml0"
v-model="bbsCn.ntcBgngDt"
@change="checkDateValidity('ntcBgngDt', $event)"
/> -->
</div>
<div class="mark">~</div>
<div class="form-control sm cal" style="max-width: 200px;">
<VueDatePicker
InlineOptions
placeholder="종료일"
locale="ko"
:enable-time-picker="false"
:format="formatDate"
v-model="bbsCn.ntcEndDt"
@update:model-value="checkDateValidity('ntcEndDt',$event)"
/>
<!-- <input
type="datetime-local"
class="full-input ml0"
v-model="bbsCn.ntcEndDt"
@change="checkDateValidity('ntcEndDt', $event)"
/> -->
</div>
</div>
</div>
<div class="layout" ref="five" v-if="bbsMng.prvtPstUseYn === 'Y'">
<label for="" class="form-title">비밀글</label>
<div class="check-area">
<div class="form-check">
<input
type="radio"
name="private"
id="private-y"
class="mr5"
value="Y"
v-model="bbsCn.prvtPstYn"
/>
<label for="private-y">사용</label>
</div>
<div class="form-check">
<input
type="radio"
name="private"
id="private-n"
class="mr5"
value="N"
v-model="bbsCn.prvtPstYn"
/>
<label for="private-n">미사용</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="btn-wrap">
<button class="btn sm main" @click="fnInsert">{{ bbsCn.bbsId == null ? "등록" : "수정" }}</button>
<button class="btn sm tertiary" @click="fnCancel">취소</button>
</div>
</template>
</template>
<script>
import { mdiClose } from "@mdi/js";
import { findByBbsCn } from "../../../../../../resources/api/bbsCn.js";
import queryParams from "../../../../../../resources/js/queryParams";
import defaultAxios from "../../../../../../resources/js/defaultAxios";
// ckditor5
import ckeditorComponent from "../../../../../component/ckeditor5/ckeditorComponent.vue";
export default {
mixins: [queryParams],
data() {
return {
file: null,
iconPath: mdiClose,
pageRole: this.$store.state.userType,
path: this.$store.state.path,
pageAuth: this.$store.state.pageAuth,
bbsMngId: null,
bbsCn: {},
bbsMng: {},
// 파일 업로드
files: null,
fileList: [],
deleteFileList: [],
//이미지 업로드
imgFiles: null,
imgFileList: [],
deleteImgFileList: [],
//스마트 에디터
editor: null,
};
},
created() {
this.fnBbsIdExtraction();
this.fnSelectOne();
},
methods: {
test() {
this.Validation();
},
// 취소 버튼 동작
fnCancel() {
if (!confirm("작성을 취소하시겠습니까?")) {
return;
}
if (this.bbsCn.bbsId == null || this.bbsCn.bbsId == 0) {
this.$router.push({
path: this.path + "/list.page",
});
} else {
this.$router.push({
path: this.path + "/view.page",
query: {
pageId: this.bbsCn.bbsId,
},
});
}
},
// 상세조회
async fnSelectOne() {
try {
const params = {
bbsId: this.$route.query.pageId,
bbsMngId: this.bbsMngId,
};
const res = await findByBbsCn(params);
if (res.status == 200) {
this.bbsCn = res.data.data.bbsCn;
this.bbsMng = res.data.data.bbsMng;
this.bbsMng.byteLmt = res.data.data.bbsMng.fileSzLmt * 1024 * 1024;
this.fileList = res.data.data.fileList;
this.$refs.ckeditor5.createEditor();
}
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
}
},
// 첨부파일 등록
fnFileInsert() {
// files 개수 만큼 반복해서 type, size 체크
this.files = this.$refs.file.files;
for (let i = 0; i < this.files.length; i++) {
const file = this.files[i];
const extnNm = file.name.split(".").pop();
if (this.bbsMng.fileExtnNmList.length >= 1) {
if (!this.bbsMng.fileExtnNmList.includes(extnNm)) {
alert(
"첨부파일 확장자를 확인해주세요.\n등록가능 확장자: " +
this.bbsMng.fileExtnNmList
);
this.$refs.file.value = null;
return;
}
}
if (this.bbsMng.byteLmt != 0 && this.bbsMng.byteLmt != null) {
if (file.size > this.bbsMng.byteLmt) {
alert(this.bbsMng.fileSzLmt + "MB 이하의 파일만 등록 가능합니다.");
return;
}
}
}
this.fileList = [...this.fileList, ...Array.from(this.files)];
},
// 첨부파일 삭제
fnFileDelete(file, index) {
if (file["fileId"] != null) {
this.deleteFileList.push(file);
}
this.fileList.splice(index, 1);
},
fnInsert() {
if (this.bbsCn.bbsId == null || this.bbsCn.bbsId == 0) {
this.fnSave();
} else {
this.fnUpdate();
}
},
// 등록
async fnSave() {
if (!this.Validation()) {
return;
}
// 폼데이터 생성
this.bbsCn.bbsMngId = this.bbsMngId;
var formData = new FormData();
const paramsToBlob = new Blob([JSON.stringify(this.bbsCn)], {
type: "application/json; charset=UTF-8",
});
formData.append("bbsCn", paramsToBlob);
for (const file of this.fileList) {
formData.append("multipartFileList", file);
}
for (const imgFile of this.imgFileList) {
formData.append("multipartImgList", imgFile);
}
// axios 호출
console.log("등록 Authorization 확인: ", this.$store.state.authorization);
await defaultAxios({
url: this.$filters.ctxPath("/sys/bbsCn/saveBbsCn.file"),
method: "post",
headers: {
"Content-Type": "multipart/form-data; charset=UTF-8",
Authorization: this.$store.state.authorization,
},
data: formData,
})
.then((response) => {
const bbsId = response.data.data.bbsId;
alert("게시글이 등록되었습니다.");
this.$router.push({
// name: 'BoardManagementSelectListOne',
path: this.path + "/view.page",
query: {
pageId: bbsId,
},
});
})
.catch((error) => {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
});
},
// 수정
async fnUpdate() {
if (!this.Validation()) {
return;
}
// 폼데이터 생성
this.bbsCn.bbsMngId = this.bbsMngId;
var formData = new FormData();
const paramsToBlob = new Blob([JSON.stringify(this.bbsCn)], {
type: "application/json; charset=UTF-8",
});
formData.append("params", paramsToBlob);
const deleteFileListToBlob = new Blob(
[JSON.stringify(this.deleteFileList)],
{
type: "application/json; charset=UTF-8",
}
);
formData.append("deleteFileList", deleteFileListToBlob);
// 추가 첨부파일
for (const file of this.fileList) {
if (file["fileId"] == null) {
formData.append("multipartFileList", file);
}
}
// 이미지 파일
const deleteImgFileListToBlob = new Blob(
[JSON.stringify(this.deleteImgFileList)],
{
type: "application/json; charset=UTF-8",
}
);
formData.append("deleteImgFileList", deleteImgFileListToBlob);
for (const imgFile of this.imgFileList) {
formData.append("multipartImgList", imgFile);
}
console.log("수정 Authorization 확인: ", this.$store.state.authorization);
// axios 호출
defaultAxios({
url: this.$filters.ctxPath("/sys/bbsCn/updateBbsCn.file"),
method: "post",
headers: {
"Content-Type": "multipart/form-data; charset=UTF-8",
Authorization: this.$store.state.authorization,
},
data: formData,
})
.then((response) => {
// const bbsId = response.data.data;
this.$router.push({
// name: 'BoardManagementSelectListOne',
path: this.path + "/view.page",
query: {
pageId: this.bbsCn.bbsId,
},
});
})
.catch((error) => {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
});
},
// 유효성 검사
Validation() {
if (!this.bbsCn.bbsNm || this.bbsCn.bbsNm.trim() === "") {
alert("게시판 제목을 입력하세요.");
return false;
}
// const oEditors = this.oEditors;
// oEditors.getById["smart"].exec("UPDATE_CONTENTS_FIELD", []);
// // 스마트에디터의 iframe에 있는 내용을 textarea로.
// this.bbsCn.bbsCn = document.getElementById("smart").value;
// 내용 null검사
// if (!this.tagChecked() && (this.isEmpty(this.bbsCn.bbsCn) || this.removeHtmlAndSpace(this.bbsCn.bbsCn) === '')) {
// alert("내용을 입력하세요.");
// document.getElementById("smart").focus();
// return false;
// }
if (
!this.tagChecked() &&
(this.isEmpty(this.bbsCn.bbsCn) ||
this.removeHtmlAndSpace(this.bbsCn.bbsCn) === "")
) {
alert("게시판 내용을 입력하세요.");
return false;
}
if (
this.bbsCn.ntcPstYn === "Y" &&
(this.bbsCn.ntcBgngDt === null || this.bbsCn.ntcEndDt === null)
) {
alert("공지기간을 올바르게 설정하세요.");
return false;
}
return true;
},
// 태그 체크
tagChecked() {
const tag = this.bbsCn.bbsCn;
if (tag.indexOf("<img") != -1) {
return true;
} else {
return false;
}
},
/**
* 빈 객체 여부
*/
isEmpty: function (data) {
if (
data === undefined ||
data === null ||
data === "" ||
data.length === 0 ||
(data.constructor == Object && Object.keys(data).length === 0)
) {
return true;
} else {
return false;
}
},
removeHtmlAndSpace: function (str) {
return str
.replace(/<[^>]*>/g, "") // HTML 태그 제거
.replace(/ /gi, " ") // 를 공백으로 변환
.replace(/\s/g, ""); // 모든 공백 제거
},
// 공지기간 유효성 체크
checkDateValidity(changeDate, event) {
// const val = event.target.value; // 변경된 날짜 값
let val;
// 값이 Date 객체인지 확인
if (event instanceof Date) {
const year = event.getFullYear();
const month = ('00' + (event.getMonth() + 1)).slice(-2);
const day = ('00' + event.getDate()).slice(-2);
val = `${year}-${month}-${day}`;
}
// 값이 Event 객체인지 확인
else if (event instanceof Event) {
val = event.target.value; // input에서 직접 입력된 값
}
// 그 외의 경우 처리 불필요 (예외 처리)
else {
console.error("Invalid date input:", event);
return;
}
// 시작일 변경 시
if (changeDate === "ntcBgngDt") {
if (this.bbsCn.ntcEndDt !== null && this.bbsCn.ntcEndDt < val) {
alert("시작일은 종료일보다 클 수 없습니다.");
this.bbsCn.ntcBgngDt = null; // 유효하지 않은 경우, 시작일을 초기화
} else {
this.bbsCn.ntcBgngDt = val;
}
}
// 종료일 변경 시
else if (changeDate === "ntcEndDt") {
if (this.bbsCn.ntcBgngDt !== null && this.bbsCn.ntcBgngDt > val) {
alert("종료일은 시작일보다 작을 수 없습니다.");
this.bbsCn.ntcEndDt = null; // 유효하지 않은 경우, 종료일을 초기화
} else {
this.bbsCn.ntcEndDt = val;
}
}
},
// // 에디터 생성
// createEditor: function () {
// // ck에디터 적용
// ClassicEditor
// .create(document.querySelector('#editor4'), {
// extraPlugins: [this.MyCustomUploadAdapterPlugin],
// removePlugins: ['MediaEmbedToolbar'],
// image: {
// toolbar: ['imageTextAlternative', '|', 'imageStyle:alignLeft', 'imageStyle:alignCenter', 'imageStyle:alignRight','|','resizeImage:50','resizeImage:75', 'resizeImage:original','resizeImage:custom',],
// resizeOptions: [
// {
// name: 'resizeImage:original',
// value: null,
// icon: 'original'
// },
// {
// name: 'resizeImage:custom',
// value: 'custom',
// icon: 'custom'
// },
// {
// name: 'resizeImage:50',
// value: '50',
// icon: 'medium'
// },
// {
// name: 'resizeImage:75',
// value: '75',
// icon: 'large'
// }
// ],
// },
// })
// .then(editor => {
// this.editor = editor;
// editor.setData(this.bbsCn.bbsCn);
// editor.model.document.on('change', () => {
// this.bbsCn.bbsCn = editor.getData();
// });
// })
// .catch(error => {
// console.error('There was a problem initializing the editor.', error);
// });
// },
// beforeDestroy: function() {
// if (this.editor) {
// this.editor.destroy()
// .then(() => {
// this.editor = null;
// });
// }
// },
// MyCustomUploadAdapterPlugin: function(editor) {
// editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
// console.log('loader', loader);
// return new UploadAdapter(loader);
// }
// }
// 날짜포맷
formatDate(date) {
const year = date.getFullYear();
const month = ('00' + (date.getMonth() + 1)).slice(-2);
const day = ('00' + date.getDate()).slice(-2);
return `${year}-${month}-${day}`;
},
updateHeight() {
this.$nextTick(() => {
const first = this.$refs.first;
const two = this.$refs.two;
const three = this.$refs.three;
const fore = this.$refs.fore;
const five = this.$refs.five;
let total = 0;
if (two) total += two.offsetHeight;
if (three) total += three.offsetHeight;
if (fore) total += fore.offsetHeight;
if (five) total += five.offsetHeight;
if (first) {
first.style.height = `calc(100% - ${total}px - 51px)`;
}
});
},
},
watch: {
"bbsCn.ntcPstYn": function (val) {
if (val === "Y") {
const offset = new Date().getTimezoneOffset() * 60000;
const now = new Date(Date.now() - offset).toISOString().slice(0, 16);
this.bbsCn.ntcBgngDt =
this.bbsCn.ntcBgngDt == null ? now : this.bbsCn.ntcBgngDt;
this.bbsCn.ntcEndDt =
this.bbsCn.ntcEndDt == null ? now : this.bbsCn.ntcEndDt;
}
},
bbsMng: {
handler() {
this.$nextTick(() => {
this.updateHeight();
});
},
deep: true,
},
bbsCn: {
handler() {
this.$nextTick(() => {
this.updateHeight();
});
},
deep: true,
},
},
computed: {},
components: {
ckeditorComponent,
},
mounted() {
this.updateHeight();
// 창 크기 변경 시에도 대응하고 싶다면:
window.addEventListener('resize', this.updateHeight);
},
beforeUnmount() {
window.removeEventListener('resize', this.updateHeight);
},
};
</script>
<style scoped>
</style>