517 lines
15 KiB
Vue
517 lines
15 KiB
Vue
<template>
|
|
<div>
|
|
<v-toolbar dark>
|
|
<v-spacer />
|
|
<v-toolbar-title>시리즈 리스트</v-toolbar-title>
|
|
<v-spacer />
|
|
</v-toolbar>
|
|
|
|
<br>
|
|
|
|
<v-container>
|
|
<v-row>
|
|
<v-col class="text-left total-count">
|
|
전체 <span>{{ total_count }}</span> 개
|
|
</v-col>
|
|
</v-row>
|
|
<v-row>
|
|
<v-col>
|
|
<v-simple-table class="elevation-10">
|
|
<template>
|
|
<thead>
|
|
<tr>
|
|
<th class="text-center">
|
|
시리즈 번호
|
|
</th>
|
|
<th class="text-center">
|
|
썸네일
|
|
</th>
|
|
<th class="text-center">
|
|
제목
|
|
</th>
|
|
<th class="text-center">
|
|
내용
|
|
</th>
|
|
<th class="text-center">
|
|
크리에이터
|
|
</th>
|
|
<th class="text-center">
|
|
장르
|
|
</th>
|
|
<th class="text-center">
|
|
작품개수
|
|
</th>
|
|
<th class="text-center">
|
|
연재여부
|
|
</th>
|
|
<th class="text-center">
|
|
연재요일
|
|
</th>
|
|
<th class="text-center">
|
|
19금
|
|
</th>
|
|
<th class="text-center">
|
|
수정
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr
|
|
v-for="item in series_list"
|
|
:key="item.id"
|
|
>
|
|
<td>{{ item.id }}</td>
|
|
<td align="center">
|
|
<v-img
|
|
max-width="70"
|
|
max-height="70"
|
|
:src="item.coverImageUrl"
|
|
class="rounded-circle"
|
|
/>
|
|
<br>
|
|
<a
|
|
:href="item.coverImageUrl"
|
|
class="v-btn v-btn--outlined"
|
|
>
|
|
다운로드
|
|
</a>
|
|
</td>
|
|
<td>
|
|
<vue-show-more-text
|
|
:text="item.title"
|
|
:lines="2"
|
|
/>
|
|
</td>
|
|
<td style="max-width: 200px !important; word-break:break-all; height: auto;">
|
|
<vue-show-more-text
|
|
:text="item.introduction"
|
|
:lines="2"
|
|
/>
|
|
</td>
|
|
<td>{{ item.creatorNickname }}</td>
|
|
<td>{{ item.genre }}</td>
|
|
<td>{{ item.numberOfWorks }}</td>
|
|
<td>{{ item.state }}</td>
|
|
<td>{{ formatPublishedDays(item.publishedDaysOfWeek) }}</td>
|
|
<td>
|
|
<div v-if="item.isAdult">
|
|
O
|
|
</div>
|
|
<div v-else>
|
|
X
|
|
</div>
|
|
</td>
|
|
<td class="text-center">
|
|
<v-btn
|
|
small
|
|
color="#3bb9f1"
|
|
dark
|
|
depressed
|
|
@click="openEditDialog(item)"
|
|
>
|
|
수정
|
|
</v-btn>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</template>
|
|
</v-simple-table>
|
|
</v-col>
|
|
</v-row>
|
|
<v-row class="text-center">
|
|
<v-col>
|
|
<v-pagination
|
|
v-model="page"
|
|
:length="total_page"
|
|
circle
|
|
@input="next"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
</v-container>
|
|
|
|
<v-dialog
|
|
v-model="show_edit_dialog"
|
|
max-width="700px"
|
|
persistent
|
|
>
|
|
<v-card>
|
|
<v-card-title>
|
|
시리즈 수정
|
|
</v-card-title>
|
|
<v-card-text>
|
|
<v-row>
|
|
<v-col
|
|
cols="3"
|
|
class="text-center"
|
|
>
|
|
<v-img
|
|
:src="edit_target.coverImageUrl"
|
|
max-width="120"
|
|
max-height="120"
|
|
class="rounded-circle"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="9">
|
|
<div style="font-weight:600;">
|
|
{{ edit_target.title }}
|
|
</div>
|
|
<div
|
|
v-if="edit_target.introduction"
|
|
style="max-height:80px; overflow:auto; word-break:break-all;"
|
|
>
|
|
{{ edit_target.introduction }}
|
|
</div>
|
|
</v-col>
|
|
</v-row>
|
|
<v-divider class="my-4" />
|
|
<v-row align="center">
|
|
<v-col
|
|
cols="4"
|
|
class="d-flex align-center"
|
|
>
|
|
장르
|
|
</v-col>
|
|
<v-col
|
|
cols="8"
|
|
class="d-flex align-center"
|
|
>
|
|
<v-select
|
|
v-model="edit_form.genreId"
|
|
:items="genre_list"
|
|
item-text="genre"
|
|
item-value="id"
|
|
:loading="is_loading_genres"
|
|
:disabled="is_saving || is_loading_genres"
|
|
label="장르를 선택하세요"
|
|
dense
|
|
hide-details
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
<v-row align="center">
|
|
<v-col
|
|
cols="4"
|
|
class="d-flex align-center"
|
|
>
|
|
연재 요일
|
|
</v-col>
|
|
<v-col
|
|
cols="8"
|
|
class="d-flex align-center"
|
|
>
|
|
<v-row
|
|
dense
|
|
class="flex-grow-1"
|
|
>
|
|
<v-col
|
|
v-for="opt in daysOfWeekOptions"
|
|
:key="opt.value"
|
|
cols="6"
|
|
sm="4"
|
|
md="3"
|
|
class="py-0 my-0"
|
|
>
|
|
<v-checkbox
|
|
v-model="edit_form.publishedDaysOfWeek"
|
|
:label="opt.text"
|
|
:value="opt.value"
|
|
:disabled="is_saving"
|
|
dense
|
|
hide-details
|
|
class="ma-0 pa-0"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
</v-col>
|
|
</v-row>
|
|
<v-row align="center">
|
|
<v-col
|
|
cols="4"
|
|
class="d-flex align-center"
|
|
>
|
|
오리지널
|
|
</v-col>
|
|
<v-col
|
|
cols="8"
|
|
class="d-flex align-center"
|
|
>
|
|
<v-checkbox
|
|
v-model="edit_form.isOriginal"
|
|
:disabled="is_saving"
|
|
dense
|
|
hide-details
|
|
class="ma-0 pa-0"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
<v-row align="center">
|
|
<v-col
|
|
cols="4"
|
|
class="d-flex align-center"
|
|
>
|
|
19금
|
|
</v-col>
|
|
<v-col
|
|
cols="8"
|
|
class="d-flex align-center"
|
|
>
|
|
<v-checkbox
|
|
v-model="edit_form.isAdult"
|
|
:disabled="is_saving"
|
|
dense
|
|
hide-details
|
|
class="ma-0 pa-0"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer />
|
|
<v-btn
|
|
text
|
|
:disabled="is_saving"
|
|
@click="cancelEdit"
|
|
>
|
|
취소
|
|
</v-btn>
|
|
<v-btn
|
|
color="#3bb9f1"
|
|
dark
|
|
depressed
|
|
:loading="is_saving"
|
|
:disabled="is_saving"
|
|
@click="saveEdit"
|
|
>
|
|
저장
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import * as api from '@/api/audio_content_series'
|
|
|
|
import VueShowMoreText from 'vue-show-more-text'
|
|
|
|
export default {
|
|
name: "AudioContentSeriesList",
|
|
|
|
components: {VueShowMoreText},
|
|
|
|
data() {
|
|
return {
|
|
is_loading: false,
|
|
page: 1,
|
|
total_page: 0,
|
|
total_count: 0,
|
|
series_list: [],
|
|
// 수정 다이얼로그 상태/데이터
|
|
show_edit_dialog: false,
|
|
is_saving: false,
|
|
is_loading_genres: false,
|
|
genre_list: [],
|
|
edit_target: {},
|
|
edit_form: {
|
|
genreId: null,
|
|
isOriginal: false,
|
|
isAdult: false,
|
|
publishedDaysOfWeek: []
|
|
},
|
|
daysOfWeekOptions: [
|
|
{ value: 'RANDOM', text: '랜덤' },
|
|
{ value: 'SUN', text: '일' },
|
|
{ value: 'MON', text: '월' },
|
|
{ value: 'TUE', text: '화' },
|
|
{ value: 'WED', text: '수' },
|
|
{ value: 'THU', text: '목' },
|
|
{ value: 'FRI', text: '금' },
|
|
{ value: 'SAT', text: '토' }
|
|
]
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
'edit_form.publishedDaysOfWeek': {
|
|
handler(newVal, oldVal) {
|
|
if (!Array.isArray(newVal)) return;
|
|
const hasRandom = newVal.includes('RANDOM');
|
|
const hadRandom = Array.isArray(oldVal) && oldVal.includes('RANDOM');
|
|
const others = newVal.filter(v => v !== 'RANDOM');
|
|
|
|
// RANDOM과 특정 요일은 함께 설정될 수 없음
|
|
if (hasRandom && others.length > 0) {
|
|
if (hadRandom) {
|
|
// RANDOM 상태에서 다른 요일을 선택한 경우 → RANDOM 제거, 나머지만 유지
|
|
this.edit_form.publishedDaysOfWeek = others;
|
|
} else {
|
|
// 다른 요일이 선택된 상태에서 RANDOM을 선택한 경우 → RANDOM만 유지
|
|
this.edit_form.publishedDaysOfWeek = ['RANDOM'];
|
|
}
|
|
}
|
|
},
|
|
deep: true
|
|
}
|
|
},
|
|
|
|
async created() {
|
|
await this.getAudioContentSeries()
|
|
},
|
|
|
|
methods: {
|
|
notifyError(message) {
|
|
this.$dialog.notify.error(message)
|
|
},
|
|
|
|
notifySuccess(message) {
|
|
this.$dialog.notify.success(message)
|
|
},
|
|
|
|
// 연재 요일 표시용 포맷터
|
|
formatPublishedDays(days) {
|
|
if (!Array.isArray(days) || days.length === 0) return '-'
|
|
// RANDOM 우선 처리
|
|
if (days.includes('RANDOM')) return '랜덤'
|
|
const map = this.daysOfWeekOptions.reduce((acc, cur) => {
|
|
acc[cur.value] = cur.text
|
|
return acc
|
|
}, {})
|
|
const labels = days.map(d => map[d] || d)
|
|
return labels.join(', ')
|
|
},
|
|
|
|
async getAudioContentSeries() {
|
|
this.is_loading = true
|
|
|
|
try {
|
|
const res = await api.getAudioContentSeriesList(this.page)
|
|
if (res.status === 200 && res.data.success === true) {
|
|
const data = res.data.data
|
|
const total_page = Math.ceil(data.totalCount / 10)
|
|
this.series_list = data.items
|
|
this.total_count = data.totalCount
|
|
|
|
if (total_page <= 0)
|
|
this.total_page = 1
|
|
else
|
|
this.total_page = total_page
|
|
} else {
|
|
this.notifyError(res.data.message || '알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.')
|
|
}
|
|
|
|
this.is_loading = false
|
|
} catch (e) {
|
|
this.notifyError('알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.')
|
|
this.is_loading = false
|
|
}
|
|
},
|
|
|
|
async next() {
|
|
await this.getAudioContentSeries()
|
|
},
|
|
|
|
openEditDialog(item) {
|
|
this.edit_target = item
|
|
this.show_edit_dialog = true
|
|
this.is_saving = false
|
|
this.loadGenresThenInit()
|
|
},
|
|
|
|
async loadGenresThenInit() {
|
|
try {
|
|
this.is_loading_genres = true
|
|
if (!this.genre_list || this.genre_list.length === 0) {
|
|
const res = await api.getAudioContentSeriesGenreList()
|
|
if (res.status === 200 && res.data.success === true) {
|
|
this.genre_list = res.data.data || []
|
|
} else {
|
|
this.notifyError(res.data.message || '장르 목록을 불러오지 못했습니다.')
|
|
}
|
|
}
|
|
} catch (e) {
|
|
this.notifyError('장르 목록을 불러오지 못했습니다. 다시 시도해 주세요.')
|
|
} finally {
|
|
this.is_loading_genres = false
|
|
this.initEditForm()
|
|
}
|
|
},
|
|
|
|
initEditForm() {
|
|
const item = this.edit_target || {}
|
|
let genreId = item.genreId || null
|
|
if (!genreId && item.genre && this.genre_list && this.genre_list.length > 0) {
|
|
const found = this.genre_list.find(g => g.genre === item.genre)
|
|
if (found) genreId = found.id
|
|
}
|
|
// 초기 publishedDaysOfWeek 정규화 (RANDOM과 특정 요일 혼재 금지)
|
|
let published = Array.isArray(item.publishedDaysOfWeek) ? [...item.publishedDaysOfWeek] : []
|
|
if (published.includes('RANDOM')) {
|
|
const others = published.filter(v => v !== 'RANDOM')
|
|
published = others.length > 0 ? ['RANDOM'] : ['RANDOM']
|
|
}
|
|
this.edit_form = {
|
|
genreId: genreId,
|
|
isOriginal: typeof item.isOriginal === 'boolean' ? item.isOriginal : false,
|
|
isAdult: typeof item.isAdult === 'boolean' ? item.isAdult : false,
|
|
publishedDaysOfWeek: published
|
|
}
|
|
},
|
|
|
|
cancelEdit() {
|
|
this.show_edit_dialog = false
|
|
this.edit_target = {}
|
|
this.edit_form = {
|
|
genreId: null,
|
|
isOriginal: false,
|
|
isAdult: false,
|
|
publishedDaysOfWeek: []
|
|
}
|
|
},
|
|
|
|
async saveEdit() {
|
|
if (this.is_saving) return
|
|
if (!this.edit_form.genreId) {
|
|
this.notifyError('장르를 선택해 주세요.')
|
|
return
|
|
}
|
|
this.is_saving = true
|
|
try {
|
|
const days = Array.isArray(this.edit_form.publishedDaysOfWeek) ? this.edit_form.publishedDaysOfWeek : []
|
|
const payloadDays = days.includes('RANDOM') ? ['RANDOM'] : days
|
|
const request = {
|
|
seriesId: this.edit_target.id,
|
|
genreId: this.edit_form.genreId,
|
|
isOriginal: this.edit_form.isOriginal,
|
|
isAdult: this.edit_form.isAdult,
|
|
publishedDaysOfWeek: payloadDays
|
|
}
|
|
const res = await api.updateAudioContentSeries(request)
|
|
if (res.status === 200 && res.data.success === true) {
|
|
this.notifySuccess('수정되었습니다.')
|
|
this.show_edit_dialog = false
|
|
await this.getAudioContentSeries()
|
|
} else {
|
|
this.notifyError(res.data.message || '수정에 실패했습니다. 다시 시도해 주세요.')
|
|
}
|
|
} catch (e) {
|
|
this.notifyError('수정에 실패했습니다. 다시 시도해 주세요.')
|
|
} finally {
|
|
this.is_saving = false
|
|
}
|
|
},
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.total-count {
|
|
padding-bottom: 0;
|
|
}
|
|
|
|
.total-count > span {
|
|
color: #3bb9f1;
|
|
}
|
|
</style>
|