
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>
<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">
<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">
<label for="" class="form-title">이미지 파일</label>
<div>
<label
for="imgFile"
:class="{
'large-btn text-ct': true,
'blue-border-btn': pageRole == 'adm',
'green-border-btn':
pageRole == 'portal',
}"
>
파일찾기
</label>
<input
type="file"
id="imgFile"
ref="imgFile"
@change="fnImgFileInsert"
multiple
accept="image/*"
/>
<ul v-if="imgFileList.length > 0">
<li
v-for="(file, idx) in imgFileList"
:key="idx"
class="file-wrap"
>
<div
v-if="file['fileId'] != null"
class="layout"
>
<p>{{ file["fileNm"] }}.{{ file["extnNm"] }}</p>
<button
class="del-btn"
@click="fnImgFileDelete(file, idx)"
>
X
</button>
</div>
<div
v-else
class="layout"
>
<p>{{ file.name }}</p>
<button
class="del-btn"
@click="fnImgFileDelete(file, idx)"
>
X
</button>
</div>
</li>
</ul>
</div>
</div>
<div class="layout" ref="two" v-if="bbsMng.atchFileUseYn === 'Y'" >
<label for="" class="form-title">첨부파일</label>
<div>
<label
for="file"
:class="{
'large-btn text-ct': true,
'blue-border-btn': pageRole == 'adm',
'green-border-btn':
pageRole == 'portal',
}"
>
파일찾기
</label>
<input
type="file"
id="file"
ref="file"
@change="fnFileInsert"
multiple
/>
<ul v-if="fileList.length > 0">
<li
v-for="(file, idx) in fileList"
:key="idx"
class="pd10 mt10 border radius"
>
<div
v-if="file['fileId'] != null"
class="flex align-center justify-between file-wrap"
>
<p>{{ file["fileNm"] }}.{{ file["extnNm"] }}</p>
<button class="del-btn" @click="fnFileDelete(file, idx)">
X
</button>
</div>
<div
v-else
class="flex align-center justify-between file-wrap"
>
<p>{{ file.name }}</p>
<button class="del-btn" @click="fnFileDelete(file, idx)">
X
</button>
</div>
</li>
</ul>
</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="y"
class="mr5"
value="Y"
v-model="bbsCn.ntcPstYn"
/>
<label for="y">사용</label>
</div>
<div class="form-check">
<input
type="radio"
name="notice"
id="n"
class="mr5"
value="N"
v-model="bbsCn.ntcPstYn"
/>
<label for="n">미사용</label>
</div>
</div>
</div>
<div class="layout" ref="four" v-if="bbsCn.ntcPstYn === 'Y'">
<label for="" class="form-title" >공지글 게시기간</label>
<div class="flex align-center no-gutters">
<div class="form-control sm cal">
<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">
<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="secret"
id="y"
class="mr5"
value="Y"
v-model="bbsCn.prvtPstYn"
/>
<label for="y">사용</label>
</div>
<div class="form-check">
<input
type="radio"
name="secret"
id="n"
class="mr5"
value="N"
v-model="bbsCn.prvtPstYn"
/>
<label for="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>
<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: [],
// 파일 업로드
imgFile: null,
imgFileList: [],
deleteImgFileList: [],
//스마트 에디터
editor: null,
};
},
created() {
this.fnBbsIdExtraction();
this.fnSelectOne();
},
methods: {
// 목록으로 이동
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.imgFileList = res.data.data.imgFileList;
this.$refs.ckeditor5.createEditor();
}
} catch (error) {
alert("에러가 발생했습니다.\n시스템관리자에게 문의하세요.");
}
},
// 이미지 파일 등록
fnImgFileInsert() {
// files 개수 만큼 반복해서 type, size 체크
this.imgFile = this.$refs.imgFile.files;
for (let i = 0; i < this.imgFile.length; i++) {
const file = this.imgFile[i];
const extnNm = file.name.split(".").pop();
// 파일이 이미지인지 체크
if (!file.type.startsWith("image/")) {
alert("이미지 파일만 업로드 가능합니다.");
return;
}
}
this.imgFileList = [...this.imgFileList, ...Array.from(this.imgFile)];
},
// 이미지파일 삭제
fnImgFileDelete(file, index) {
if (file["fileId"] != null) {
this.deleteImgFileList.push(file);
}
this.imgFileList.splice(index, 1);
},
// 첨부파일 등록
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.bbsMngId == null || this.bbsCn.bbsMngId == 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;
}
// 이미지 파일 null 검사
if (this.imgFileList.length < 1) {
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("<iframe") != -1 || 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; // 변경된 날짜 값
// 시작일 변경 시
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() {
// // 스마트 에디터 적용
// let vm = this;
// const oEditors = this.oEditors;
// nhn.husky.EZCreator.createInIFrame({
// oAppRef: oEditors,
// elPlaceHolder: "smart",
// sSkinURI: "/client/smarteditor2-2.8.2.3/SmartEditor2Skin.html",
// htParams: {
// bUseToolbar: true, // 툴바 사용 여부 (true:사용/ false:사용하지 않음)
// bSkipXssFilter: true,
// bUseVerticalResizer: true,
// bUseModeChanger: true
// },
// fOnAppLoad: function () {
// oEditors.getById["smart"].exec("PASTE_HTML", [vm.bbsCn.bbsCn]);
// },
// fCreator: "createSEditor2"
// });
// }
// 날짜포맷
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 - 48px)`;
}
});
},
},
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>