From a568d12b3c5944d18d6e371513f8b4d9e409494e Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Thu, 13 Nov 2025 10:49:59 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat(admin-menu):=20=EC=8B=9C=EB=A6=AC?= =?UTF-8?q?=EC=A6=88=20=EA=B4=80=EB=A6=AC=20=ED=95=98=EC=9C=84=20=EB=A9=94?= =?UTF-8?q?=EB=89=B4=EB=A1=9C=20'=EB=B0=B0=EB=84=88=20=EB=93=B1=EB=A1=9D'?= =?UTF-8?q?=20=EB=A9=94=EB=89=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SideMenu.vue | 20 ++++++++++++++++++++ src/router/index.js | 5 +++++ src/views/Series/ContentSeriesBanner.vue | 18 ++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 src/views/Series/ContentSeriesBanner.vue diff --git a/src/components/SideMenu.vue b/src/components/SideMenu.vue index 722e4e7..de31dbf 100644 --- a/src/components/SideMenu.vue +++ b/src/components/SideMenu.vue @@ -97,6 +97,26 @@ export default { if (res.status === 200 && res.data.success === true && res.data.data.length > 0) { this.items = res.data.data + // '시리즈 관리' 메뉴에 '배너 등록' 하위 메뉴 추가 + try { + const seriesMenu = this.items.find(m => m && m.title === '시리즈 관리') + if (seriesMenu) { + if (!Array.isArray(seriesMenu.items)) { + seriesMenu.items = seriesMenu.items ? [].concat(seriesMenu.items) : [] + } + const exists = seriesMenu.items.some(ci => ci && ci.route === '/content/series/banner') + if (!exists) { + seriesMenu.items.push({ + title: '배너 등록', + route: '/content/series/banner', + items: null + }) + } + } + } catch (e) { + // ignore + } + // 캐릭터 챗봇 메뉴 추가 this.items.push({ title: '캐릭터 챗봇', diff --git a/src/router/index.js b/src/router/index.js index 7a01988..0b7b254 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -120,6 +120,11 @@ const routes = [ name: 'ContentSeriesRecommendFree', component: () => import(/* webpackChunkName: "series" */ '../views/Series/ContentSeriesRecommendFree.vue') }, + { + path: '/content/series/banner', + name: 'ContentSeriesBanner', + component: () => import(/* webpackChunkName: "series" */ '../views/Series/ContentSeriesBanner.vue') + }, { path: '/promotion/event', name: 'EventView', diff --git a/src/views/Series/ContentSeriesBanner.vue b/src/views/Series/ContentSeriesBanner.vue new file mode 100644 index 0000000..b41e2aa --- /dev/null +++ b/src/views/Series/ContentSeriesBanner.vue @@ -0,0 +1,18 @@ + + + + + From ee2ef50f2aaa606078a1bcb2082b5fc52bb85c72 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Thu, 13 Nov 2025 11:53:31 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat(admin-series-banner):=20=EC=8B=9C?= =?UTF-8?q?=EB=A6=AC=EC=A6=88=20=EB=B0=B0=EB=84=88=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A1=B0=ED=9A=8C,=20=EB=93=B1=EB=A1=9D,=20?= =?UTF-8?q?=EC=88=98=EC=A0=95,=20=EC=82=AD=EC=A0=9C,=20=EC=88=9C=EC=84=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/audio_content_series.js | 81 +++- src/views/Series/ContentSeriesBanner.vue | 513 ++++++++++++++++++++++- 2 files changed, 577 insertions(+), 17 deletions(-) diff --git a/src/api/audio_content_series.js b/src/api/audio_content_series.js index 8d940d6..5e11544 100644 --- a/src/api/audio_content_series.js +++ b/src/api/audio_content_series.js @@ -1,40 +1,89 @@ -import Vue from 'vue'; +import Vue from "vue"; async function getAudioContentSeriesList(page) { - return Vue.axios.get("/admin/audio-content/series?page=" + (page - 1) + "&size=10"); + return Vue.axios.get("/admin/audio-content/series?page=" + (page - 1) + "&size=10"); } async function getAudioContentSeriesGenreList() { - return Vue.axios.get('/admin/audio-content/series/genre'); + return Vue.axios.get("/admin/audio-content/series/genre"); } async function createAudioContentSeriesGenre(genre, is_adult) { - return Vue.axios.post('/admin/audio-content/series/genre', {genre: genre, isAdult: is_adult}) + return Vue.axios.post("/admin/audio-content/series/genre", { genre: genre, isAdult: is_adult }); } async function updateAudioContentSeriesGenre(request) { - return Vue.axios.put('/admin/audio-content/series/genre', request) + return Vue.axios.put("/admin/audio-content/series/genre", request); } async function updateAudioContentSeriesGenreOrders(ids) { - return Vue.axios.put('/admin/audio-content/series/genre/orders', {ids: ids}) + return Vue.axios.put("/admin/audio-content/series/genre/orders", { ids: ids }); } async function searchSeriesList(searchWord) { - return Vue.axios.get("/admin/audio-content/series/search?search_word=" + searchWord) + return Vue.axios.get("/admin/audio-content/series/search?search_word=" + searchWord); } // 시리즈 수정 async function updateAudioContentSeries(request) { - return Vue.axios.put('/admin/audio-content/series', request); + return Vue.axios.put("/admin/audio-content/series", request); +} + +// ======================== +// 시리즈 배너 API +// ======================== +// 배너 리스트 조회 +async function getSeriesBannerList(page = 1, size = 20) { + return Vue.axios.get("/admin/audio-content/series/banner/list", { + params: { page: page - 1, size } + }); +} + +// 배너 등록 +async function createSeriesBanner(bannerData) { + const formData = new FormData(); + if (bannerData.image) formData.append("image", bannerData.image); + const requestData = { seriesId: bannerData.seriesId }; + formData.append("request", JSON.stringify(requestData)); + return Vue.axios.post("/admin/audio-content/series/banner/register", formData, { + headers: { "Content-Type": "multipart/form-data" } + }); +} + +// 배너 수정 +async function updateSeriesBanner(bannerData) { + const formData = new FormData(); + if (bannerData.image) formData.append("image", bannerData.image); + const requestData = { seriesId: bannerData.seriesId, bannerId: bannerData.bannerId }; + formData.append("request", JSON.stringify(requestData)); + return Vue.axios.put("/admin/audio-content/series/banner/update", formData, { + headers: { "Content-Type": "multipart/form-data" } + }); +} + +// 배너 삭제 +async function deleteSeriesBanner(bannerId) { + // 백엔드 사양이 불명확하여 쿼리 파라미터로 전송 + return Vue.axios.delete("/admin/audio-content/series/banner/" + bannerId); +} + +// 배너 순서 변경 +async function updateSeriesBannerOrder(ids) { + return Vue.axios.put("/admin/audio-content/series/banner/orders", { ids }); } export { - getAudioContentSeriesList, - getAudioContentSeriesGenreList, - createAudioContentSeriesGenre, - updateAudioContentSeriesGenre, - updateAudioContentSeriesGenreOrders, - searchSeriesList, - updateAudioContentSeries -} + getAudioContentSeriesList, + getAudioContentSeriesGenreList, + createAudioContentSeriesGenre, + updateAudioContentSeriesGenre, + updateAudioContentSeriesGenreOrders, + searchSeriesList, + updateAudioContentSeries, + // series banner + getSeriesBannerList, + createSeriesBanner, + updateSeriesBanner, + deleteSeriesBanner, + updateSeriesBannerOrder +}; diff --git a/src/views/Series/ContentSeriesBanner.vue b/src/views/Series/ContentSeriesBanner.vue index b41e2aa..f52d3a3 100644 --- a/src/views/Series/ContentSeriesBanner.vue +++ b/src/views/Series/ContentSeriesBanner.vue @@ -1,18 +1,529 @@