
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
04-04
04-04
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">제목</label>
<input type="text" class="form-control sm" v-model="bbsCn.bbsNm" placeholder="제목을 입력하세요." />
</div>
<div class="layout" ref="first">
<label for="" class="form-title">내용</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="del-btn" @click="fnFileDelete(file, idx)">X</button>
</div>
<div v-else class="layout">
<p>{{ file.name }}</p>
<button class="del-btn" @click="fnFileDelete(file, idx)">X</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) {
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 호출
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 message = error.response.data.message;
alert(message);
});
},
// 수정
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);
}
// 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 message = error.response.data.message;
alert(message);
});
},
// 유효성 검사
Validation() {
if (this.bbsCn.bbsNm == null || 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>