
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<template>
<div class="content">
<div class="sub-title-area mb-30">
<h2>미디어 영상</h2>
<div class="breadcrumb-list">
<ul>
<li><img :src="homeicon" alt="Home Icon">
<p>언론에서 바라본 구미시</p>
</li>
<li><img :src="righticon" alt=""></li>
<li>미디어 영상</li>
</ul>
</div>
</div>
<form class="insert-form mb-50" @submit.prevent>
<dl>
<dd>
<label for="sj" class="require">제목</label>
<div class="wfull"><input type="text" id="sj" placeholder="제목을 입력하세요." v-model="requestDTO.sj"></div>
</dd>
<div class="hr"></div>
<dd>
<label for="prdctnYear">생산연도</label>
<input type="text" id="prdctnYear" placeholder="생산연도를 입력하세요" v-model="requestDTO.prdctnYear" pattern="[0-9]{4}" maxlength="4" @input="onlyNumberInput">
</dd>
<div class="hr"></div>
<dd>
<label for="link">주소</label>
<input type="text" id="link" class="invalid-url" placeholder="유튜브 URL 주소를 입력하세요" v-model="requestDTO.link">
<div class="invalid-feedback border">
<img :src="erroricon" alt="">
<span>유튜브 URL만 입력 가능합니다.</span>
</div>
</dd>
<div class="hr"></div>
<dd>
<label for="text">내용</label>
<div class="wfull">
<EditorComponent v-model:contents="requestDTO.cn" v-model:plainContents="requestDTO.searchCn" />
</div>
</dd>
<div class="hr"></div>
<dd>
<label for="category" class="flex align-center">
<p>카테고리</p><button type="button" class="category-add" @click="fnToggleModal">추가하기</button>
</label>
<ul class="category">
<li v-for="(item, idx) of selectedCtgries" :key="idx">{{ item.ctgryNm }} <button type="button" class="cancel" @click="fnDelCtgry(item.ctgryId)"><b>✕</b></button></li>
</ul>
</dd>
</dl>
</form>
<div class="btn-group flex-center">
<button type="button" class="cancel" @click="fnMoveTo('list')">취소</button>
<button type="button" class="register" @click="submitForm">
<span v-if="$isEmpty(pageId)">등록</span>
<span v-else>수정</span>
</button>
</div>
</div>
<CategorySelectModal v-if="isModalOpen" :selectedCtgries="selectedCtgries" @toggleModal="fnToggleModal" @addCtgries="fnAddCtgries" />
</template>
<script>
import { DoubleLeftOutlined, LeftOutlined, RightOutlined, DoubleRightOutlined } from '@ant-design/icons-vue';
// COMPONENT
import EditorComponent from '../../component/editor/EditorComponent.vue';
import CategorySelectModal from '../../component/modal/CategorySelectModal.vue';
// API
import { findMediaVidoProc, saveMediaVidoProc, updateMediaVidoDcry } from '@/resources/api/mediaVido';
export default {
components: {
DoubleLeftOutlined,
LeftOutlined,
RightOutlined,
DoubleRightOutlined,
EditorComponent,
CategorySelectModal,
},
data() {
return {
// 아이콘 경로
homeicon: 'client/resources/images/icon/home.png',
erroricon: 'client/resources/images/icon/error.png',
righticon: 'client/resources/images/icon/right.png',
searchicon: 'client/resources/images/icon/search.png',
pageId: null,
isModalOpen: false,
isDragging: false,
// 등록/수정 요청 객체
requestDTO: {
mediaVidoId: null, // 미디어영상 아이디
sj: null, // 제목
cn: null, // 내용
searchCn: null,
link: null, // 주소
prdctnYear: null, // 생산연도
ctgryIds: [], // 카테고리 정보
},
isValidYoutubeURL: true,
selectedCtgries: [], // 카테고리 목록
};
},
created() {
this.pageId = this.$route.query.id;
if (!this.$isEmpty(this.pageId)) {
this.fnFindMediaVido(); // 상세 조회
}
},
methods: {
// 상세 조회
async fnFindMediaVido() {
try {
const response = await findMediaVidoProc(this.pageId);
this.copyToMediaVidoReqDTO(response.data.data.mediaVido);
} catch (error) {
alert('조회중 오류가 발생했습니다.');
this.fnMoveTo('list'); // 목록으로 이동
if (error.response) {
alert(error.response.data.message);
}
console.error(error.message);
}
},
// mediaVido > requestDTO
copyToMediaVidoReqDTO(mediaVido) {
const copyFields = Object.keys(this.requestDTO);
copyFields.forEach(field => {
this.requestDTO[field] = this.$isEmpty(mediaVido[field]) ? null : mediaVido[field];
});
this.selectedCtgries = mediaVido.ctgrys.length > 0 ? mediaVido.ctgrys : [];
},
// 카테고리 모달 열기/닫기
fnToggleModal() {
this.isModalOpen = !this.isModalOpen;
},
// 카테고리 등록
fnAddCtgries(selectedCtgries) {
this.selectedCtgries = [...this.selectedCtgries, ...selectedCtgries];
this.fnToggleModal(); // 카테고리 모달 닫기
},
// 카테고리 삭제
fnDelCtgry(id) {
this.selectedCtgries = this.selectedCtgries.filter(item => item.ctgryId !== id);
},
// 등록
async submitForm() {
// 공백제거
this.requestDTO.sj = this.$processTitle(this.requestDTO.sj);
// 유효성 검사
if (this.$isEmpty(this.requestDTO.sj)) {
alert("제목을 입력해 주세요.");
return;
}
if (!this.$isEmpty(this.requestDTO.prdctnYear)) {
if (!/^\d+$/.test(this.requestDTO.prdctnYear)) {
alert("생산연도는 숫자만 입력 가능합니다.");
return;
}
if (this.requestDTO.prdctnYear.length !== 4) {
alert("생산연도는 4자리로 입력해주세요.");
return;
}
}
if (!this.$isEmpty(this.requestDTO.link)) {
const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/shorts\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})(\S*)?$/;
if (!youtubeRegex.test(this.requestDTO.link)) {
alert("주소는 유튜브 URL만 입력 가능합니다.");
return;
}
}
try {
if (this.$isEmpty(this.pageId)) {
delete this.requestDTO.mediaVidoId;
}
// requestDTO에 카테고리 Id 추가
this.requestDTO.ctgryIds = this.selectedCtgries.map(ctgry => ctgry.ctgryId);
// API 통신
const response = this.$isEmpty(this.pageId) ? await saveMediaVidoProc(this.requestDTO) : await updateMediaVidoDcry(this.requestDTO);
let id = response.data.data.mediaVidoId;
alert(this.$isEmpty(this.pageId) ? "등록되었습니다." : "수정되었습니다.");
this.fnMoveTo('view', id); // 상세 페이지로 이동
} catch (error) {
if (error.response) {
alert(error.response.data.message);
} else {
alert("에러가 발생했습니다.");
}
console.error(error.message);
};
},
// 페이지 이동
fnMoveTo(type, id) {
const routes = {
'list': { name: 'MediaVideoSearch' },
'view': { name: 'MediaVideoDetail', query: { id } },
'edit': { name: 'MediaVideoInsert', query: this.$isEmpty(id) ? {} : { id } },
};
if (routes[type]) {
if (!this.$isEmpty(this.pageId) && type === 'list') {
this.$router.push({ name: 'PicHistoryDetail', query: { id: this.pageId } });
}
this.$router.push(routes[type]);
} else {
alert("올바르지 않은 경로를 요청하여 목록으로 이동합니다.");
this.$router.push(routes['list']);
}
},
// 생산연도 입력 제한
onlyNumberInput() {
this.requestDTO.prdctnYear = this.requestDTO.prdctnYear.replace(/[^0-9]/g, '');
},
}
};
</script>
<style scoped>
.invalid-url {
width: 50%;
}
</style>