From 1fc619dfd03c8b1cc4b8ebc550054106835e49ce Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Thu, 2 Apr 2026 15:47:14 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat(character-banner):=20=EB=B0=B0?= =?UTF-8?q?=EB=84=88=20=EB=93=B1=EB=A1=9D=20=EC=96=B8=EC=96=B4=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 배너 등록/수정 다이얼로그에 언어 선택(ko/ja/en) UI를 추가 --- src/api/character.js | 5 +++-- src/views/Chat/CharacterBanner.vue | 35 +++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/api/character.js b/src/api/character.js index 5e46869..fbc21f7 100644 --- a/src/api/character.js +++ b/src/api/character.js @@ -115,9 +115,10 @@ async function createCharacterBanner(bannerData) { // 이미지 FormData에 추가 if (bannerData.image) formData.append('image', bannerData.image) - // 캐릭터 ID를 JSON 문자열로 변환하여 request 필드에 추가 + // 캐릭터 ID와 언어 코드를 JSON 문자열로 변환하여 request 필드에 추가 const requestData = { - characterId: bannerData.characterId + characterId: bannerData.characterId, + lang: bannerData.lang } formData.append('request', JSON.stringify(requestData)) diff --git a/src/views/Chat/CharacterBanner.vue b/src/views/Chat/CharacterBanner.vue index f1a0e84..66698ba 100644 --- a/src/views/Chat/CharacterBanner.vue +++ b/src/views/Chat/CharacterBanner.vue @@ -184,6 +184,19 @@ + + + + + !!v || this.isEdit || '이미지를 선택하세요' ] @@ -312,7 +331,7 @@ export default { computed: { isFormValid() { - return (this.bannerForm.image || (this.isEdit && this.bannerForm.imageUrl)) && this.selectedCharacter; + return (this.bannerForm.image || (this.isEdit && this.bannerForm.imageUrl)) && this.selectedCharacter && this.bannerForm.lang; } }, @@ -393,7 +412,8 @@ export default { image: null, imageUrl: '', characterId: null, - bannerId: null + bannerId: null, + lang: null }; this.previewImage = null; this.searchKeyword = ''; @@ -414,7 +434,8 @@ export default { image: null, imageUrl: banner.imageUrl, characterId: banner.characterId, - bannerId: banner.id + bannerId: banner.id, + lang: banner.lang || banner.language || null }; this.previewImage = null; this.searchKeyword = ''; @@ -430,7 +451,8 @@ export default { image: null, imageUrl: '', characterId: null, - bannerId: null + bannerId: null, + lang: null }; this.previewImage = null; this.searchKeyword = ''; @@ -501,7 +523,8 @@ export default { // 배너 추가 const response = await createCharacterBanner({ image: this.bannerForm.image, - characterId: this.selectedCharacter.id + characterId: this.selectedCharacter.id, + lang: this.bannerForm.lang }); if (response && response.status === 200 && response.data && response.data.success === true) { this.notifySuccess('배너가 추가되었습니다.'); -- 2.49.1 From ad5c27abc3078491f2c9c28d33849d5ab7f9909f Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Thu, 2 Apr 2026 15:56:37 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat(series-banner):=20=EB=B0=B0=EB=84=88?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D=20=EC=96=B8=EC=96=B4=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 배너 등록/수정 다이얼로그에 언어 선택(ko/ja/en) UI를 추가 --- src/api/audio_content_series.js | 2 +- src/views/Series/ContentSeriesBanner.vue | 41 ++++++++++++++++++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/api/audio_content_series.js b/src/api/audio_content_series.js index 5e11544..2d5ff84 100644 --- a/src/api/audio_content_series.js +++ b/src/api/audio_content_series.js @@ -43,7 +43,7 @@ async function getSeriesBannerList(page = 1, size = 20) { async function createSeriesBanner(bannerData) { const formData = new FormData(); if (bannerData.image) formData.append("image", bannerData.image); - const requestData = { seriesId: bannerData.seriesId }; + const requestData = { seriesId: bannerData.seriesId, lang: bannerData.lang }; formData.append("request", JSON.stringify(requestData)); return Vue.axios.post("/admin/audio-content/series/banner/register", formData, { headers: { "Content-Type": "multipart/form-data" } diff --git a/src/views/Series/ContentSeriesBanner.vue b/src/views/Series/ContentSeriesBanner.vue index f52d3a3..a30a583 100644 --- a/src/views/Series/ContentSeriesBanner.vue +++ b/src/views/Series/ContentSeriesBanner.vue @@ -66,6 +66,14 @@ />
{{ resolveSeriesTitle(banner) }}
+ + {{ banner.lang === 'ko' ? '한국어' : banner.lang === 'ja' ? '일본어' : '영어' }} +
@@ -146,6 +154,17 @@ />
+ + + + + !!v || this.isEdit || '이미지를 선택하세요' @@ -306,7 +331,7 @@ export default { }, computed: { isFormValid() { - return (this.bannerForm.image || (this.isEdit && this.bannerForm.imageUrl)) && this.selectedSeries + return (this.bannerForm.image || (this.isEdit && this.bannerForm.imageUrl)) && this.selectedSeries && (this.isEdit || this.bannerForm.lang) } }, watch: { @@ -368,7 +393,7 @@ export default { showAddDialog() { this.isEdit = false this.selectedSeries = null - this.bannerForm = { image: null, imageUrl: '', seriesId: null, bannerId: null } + this.bannerForm = { image: null, imageUrl: '', seriesId: null, bannerId: null, lang: 'ko' } this.previewImage = null this.searchKeyword = '' this.searchResults = [] @@ -387,7 +412,8 @@ export default { image: null, imageUrl: banner.imageUrl || banner.imagePath, seriesId: banner.seriesId, - bannerId: banner.id + bannerId: banner.id, + lang: banner.lang || 'ko' } this.previewImage = null this.searchKeyword = '' @@ -398,7 +424,7 @@ export default { closeDialog() { this.showDialog = false this.selectedSeries = null - this.bannerForm = { image: null, imageUrl: '', seriesId: null, bannerId: null } + this.bannerForm = { image: null, imageUrl: '', seriesId: null, bannerId: null, lang: 'ko' } this.previewImage = null this.searchKeyword = '' this.searchResults = [] @@ -450,13 +476,16 @@ export default { }) if (response && response.status === 200 && response.data && response.data.success === true) { this.notifySuccess('배너가 수정되었습니다.') + this.closeDialog() + this.refreshBanners() } else { this.notifyError('배너 수정을 실패했습니다.') } } else { const response = await createSeriesBanner({ image: this.bannerForm.image, - seriesId: this.selectedSeries.id + seriesId: this.selectedSeries.id, + lang: this.bannerForm.lang }) if (response && response.status === 200 && response.data && response.data.success === true) { this.notifySuccess('배너가 추가되었습니다.') -- 2.49.1 From 499d4e4432418ab037d8ee6a197f4bd19b5a6133 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Thu, 2 Apr 2026 16:25:52 +0900 Subject: [PATCH 3/8] =?UTF-8?q?fix(chat):=20=EC=BA=90=EB=A6=AD=ED=84=B0=20?= =?UTF-8?q?=EB=B0=B0=EB=84=88=20=EC=88=98=EC=A0=95=20=EC=8B=9C=20=EC=96=B8?= =?UTF-8?q?=EC=96=B4=20=EC=84=A0=ED=83=9D=20UI=20=EC=88=A8=EA=B9=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 수정 모드에서 언어 변경이 불가능하여 UI 비표시 처리\n- 불필요한 :disabled 속성 제거로 코드 명확화 Co-authored-by: Junie --- src/views/Chat/CharacterBanner.vue | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/views/Chat/CharacterBanner.vue b/src/views/Chat/CharacterBanner.vue index 66698ba..31de47e 100644 --- a/src/views/Chat/CharacterBanner.vue +++ b/src/views/Chat/CharacterBanner.vue @@ -184,7 +184,7 @@ - + -- 2.49.1 From fbc10e83da8db1d5dc5f52e557d044ed59c96d73 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Thu, 2 Apr 2026 16:41:17 +0900 Subject: [PATCH 4/8] =?UTF-8?q?feat(content-banner):=20=EB=B0=B0=EB=84=88?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D=20=EC=8B=9C=20=EC=96=B8=EC=96=B4=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D(ko/ja/en)=20=EC=B6=94=EA=B0=80=20=EB=B0=8F?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D=20=EC=9A=94=EC=B2=AD=EC=97=90=20lang=20?= =?UTF-8?q?=ED=8F=AC=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 등록 폼에 언어 v-select 추가(v-if="!is_modify") - 데이터 모델에 banner.lang 기본값 'ko'와 langItems(ko/ja/en) 추가 - submit 요청에 ISO 639 코드(lang) 포함 - 취소 시 초기화에 언어 기본값 유지 --- src/views/Content/ContentMainTopBanner.vue | 35 +++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/views/Content/ContentMainTopBanner.vue b/src/views/Content/ContentMainTopBanner.vue index a030ee0..5ee3e4f 100644 --- a/src/views/Content/ContentMainTopBanner.vue +++ b/src/views/Content/ContentMainTopBanner.vue @@ -109,6 +109,23 @@ + + + + + 언어 + + + + + + @@ -327,7 +344,7 @@ export default { show_write_dialog: false, show_delete_confirm_dialog: false, selected_banner: {}, - banner: {type: 'CREATOR', tab_id: 1}, + banner: {type: 'CREATOR', tab_id: 1, lang: 'ko'}, banners: [], events: [], creators: [], @@ -335,7 +352,12 @@ export default { search_query_creator: '', search_query_series: '', tabs: [], - selected_tab_id: 1 + selected_tab_id: 1, + langItems: [ + { text: '한국어', value: 'ko' }, + { text: '일본어', value: 'ja' }, + { text: '영어', value: 'en' } + ] } }, @@ -379,7 +401,7 @@ export default { this.is_selecting = false this.show_write_dialog = false this.show_delete_confirm_dialog = false - this.banner = {type: 'CREATOR', tab_id: 1} + this.banner = {type: 'CREATOR', tab_id: 1, lang: 'ko'} this.selected_banner = {} this.search_query_creator = '' this.search_query_series = '' @@ -432,6 +454,10 @@ export default { this.banner.link = banner.link this.banner.is_adult = banner.isAdult this.banner.tab_id = banner.tabId + // 수정 시 언어는 변경 불가하므로 UI를 표시하지 않음. 필요 시 내부 유지만 함 (기본값 또는 서버 값 사용) + if (banner.lang) { + this.banner.lang = banner.lang + } setTimeout(() => { this.is_selecting = false; // 선택 상태 해제 @@ -497,7 +523,8 @@ export default { let request = { type: this.banner.type, - isAdult: this.banner.is_adult + isAdult: this.banner.is_adult, + lang: this.banner.lang || 'ko' } if (this.banner.type === 'CREATOR') { -- 2.49.1 From ffd6e41767c83f80e83bb489aa640387c1032d50 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Thu, 2 Apr 2026 16:46:33 +0900 Subject: [PATCH 5/8] =?UTF-8?q?feat(live-recommend):=20=EC=B6=94=EC=B2=9C?= =?UTF-8?q?=20=ED=81=AC=EB=A6=AC=EC=97=90=EC=9D=B4=ED=84=B0=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=EC=8B=9C=20=EC=96=B8=EC=96=B4=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?(ko/ja/en)=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=EC=9A=94=EC=B2=AD=EC=97=90=20lang=20=ED=8F=AC?= =?UTF-8?q?=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 등록 폼에 언어 v-select 추가(v-if="!is_modify") - 데이터 모델에 banner.lang 기본값 'ko'와 langItems(ko/ja/en) 추가 - submit 요청에 ISO 639 코드(lang) 포함 - 취소 시 초기화에 언어 기본값 유지 --- src/views/Live/LiveRecommend.vue | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/views/Live/LiveRecommend.vue b/src/views/Live/LiveRecommend.vue index bdc4538..df76afb 100644 --- a/src/views/Live/LiveRecommend.vue +++ b/src/views/Live/LiveRecommend.vue @@ -153,6 +153,22 @@ + + + + 언어 + + + + + + @@ -234,6 +250,12 @@ export default { start_date: null, end_date: null, is_adult: false, + lang: 'ko', + languageOptions: [ + { label: '한국어', value: 'ko' }, + { label: '일본어', value: 'ja' }, + { label: '영어', value: 'en' }, + ], headers: [ { text: '이미지', @@ -358,6 +380,7 @@ export default { formData.append("start_date", this.start_date) formData.append("end_date", this.end_date) formData.append("is_adult", this.is_adult) + formData.append("lang", this.lang) const res = await api.createRecommendCreatorBanner(formData); if (res.status === 200 && res.data.success === true) { @@ -383,7 +406,8 @@ export default { this.image === null || this.creator_id === null || this.start_date === null || - this.end_date === null + this.end_date === null || + this.lang === null ) { this.notifyError('내용을 입력하세요') } else { @@ -398,6 +422,9 @@ export default { this.creator_id = null this.start_date = null this.end_date = null + this.is_adult = false + this.lang = 'ko' + this.selected_recommend_live = null }, notifyError(message) { @@ -471,6 +498,8 @@ export default { } }, showWriteDialog() { + this.selected_recommend_live = null + this.lang = 'ko' this.show_write_dialog = true }, } -- 2.49.1 From 71f71e9d77893831c8146869b26b2c96de79aa04 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Thu, 2 Apr 2026 16:48:39 +0900 Subject: [PATCH 6/8] =?UTF-8?q?fix(character-banner):=20=EB=B0=B0=EB=84=88?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D=20=EB=8B=A4=EC=9D=B4=EC=96=BC=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=97=90=EC=84=9C=20=EC=96=B8=EC=96=B4=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=EA=B0=92=EC=9D=84=20=ED=95=9C=EA=B5=AD=EC=96=B4(`ko`)?= =?UTF-8?q?=EB=A1=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/Chat/CharacterBanner.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/Chat/CharacterBanner.vue b/src/views/Chat/CharacterBanner.vue index 31de47e..5be3568 100644 --- a/src/views/Chat/CharacterBanner.vue +++ b/src/views/Chat/CharacterBanner.vue @@ -315,7 +315,7 @@ export default { imageUrl: '', characterId: null, bannerId: null, - lang: null + lang: 'ko' }, languageOptions: [ { text: '한국어', value: 'ko' }, @@ -412,7 +412,7 @@ export default { imageUrl: '', characterId: null, bannerId: null, - lang: null + lang: 'ko' }; this.previewImage = null; this.searchKeyword = ''; @@ -451,7 +451,7 @@ export default { imageUrl: '', characterId: null, bannerId: null, - lang: null + lang: 'ko' }; this.previewImage = null; this.searchKeyword = ''; -- 2.49.1 From 7fe6b3bb309df924a034c51d1704a6c9c520c173 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Tue, 7 Apr 2026 14:09:49 +0900 Subject: [PATCH 7/8] =?UTF-8?q?feat(content):=20=EC=A0=95=EC=82=B0?= =?UTF-8?q?=EC=9A=94=EC=9C=A8=20=ED=95=AD=EB=AA=A9=20=EB=B0=8F=20=EA=B0=9C?= =?UTF-8?q?=EB=B3=84=20=EC=82=AD=EC=A0=9C=20=ED=94=8C=EB=9E=98=EA=B7=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 콘텐츠 리스트 테이블에 정산요율 컬럼 표시(null/빈값은 공란) - 수정 다이얼로그에 정산요율 입력 필드 추가(number, 빈값 허용) - isSettlementRatioDeleted 플래그 추가: 체크 시 입력 비활성화 및 요청 전송 제외 - 수정 요청 시 변경된 값만 전송, 삭제 플래그 true면 settlementRatio 미포함 - created/show/cancel 시 데이터 모델 초기화 로직 반영 --- src/views/Content/ContentList.vue | 64 +++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/views/Content/ContentList.vue b/src/views/Content/ContentList.vue index b4a2775..c69d5e5 100644 --- a/src/views/Content/ContentList.vue +++ b/src/views/Content/ContentList.vue @@ -75,6 +75,9 @@ 가격 + + 정산요율 + 한정판 @@ -157,6 +160,12 @@ 무료 + + + + {{ item.settlementRatio }} + + + + 정산요율 + + + + + + + + + + 정산요율 삭제 + + + + + + @@ -497,6 +536,8 @@ export default { is_adult: false, is_comment_available: false, is_default_cover_image: false, + is_settlement_ratio_deleted: false, + settlement_ratio: "", }; await this.getAudioContentThemeList(); await this.getAudioContent(); @@ -531,6 +572,11 @@ export default { this.audio_content.is_adult = item.isAdult; this.audio_content.is_comment_available = item.isCommentAvailable; this.audio_content.is_default_cover_image = false; + this.audio_content.is_settlement_ratio_deleted = false; + this.audio_content.settlement_ratio = + item.settlementRatio !== null && item.settlementRatio !== undefined + ? String(item.settlementRatio) + : ""; this.image_preview = item.coverImageUrl; this.cover_image_file = null; @@ -590,6 +636,8 @@ export default { is_adult: false, is_comment_available: false, is_default_cover_image: false, + is_settlement_ratio_deleted: false, + settlement_ratio: "", }; this.image_preview = null; this.cover_image_file = null; @@ -629,6 +677,7 @@ export default { const request = { id: this.audio_content.id, isDefaultCoverImage: this.audio_content.is_default_cover_image, + isSettlementRatioDeleted: this.audio_content.is_settlement_ratio_deleted, }; if ( @@ -657,6 +706,21 @@ export default { request.isCommentAvailable = this.audio_content.is_comment_available; } + // settlementRatio 처리 (null/빈문자 케이스 포함) + const originalRatio = + this.selected_audio_content.settlementRatio !== null && + this.selected_audio_content.settlementRatio !== undefined + ? String(this.selected_audio_content.settlementRatio) + : ""; + const newRatio = + this.audio_content.settlement_ratio !== null && + this.audio_content.settlement_ratio !== undefined + ? String(this.audio_content.settlement_ratio) + : ""; + if (!this.audio_content.is_settlement_ratio_deleted && newRatio !== originalRatio) { + request.settlementRatio = newRatio; + } + const formData = new FormData(); formData.append("request", JSON.stringify(request)); -- 2.49.1 From 1bffedfd854fc905ffa40014a0143579a7f25a84 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Tue, 7 Apr 2026 14:36:37 +0900 Subject: [PATCH 8/8] =?UTF-8?q?feat(content):=20=EC=9C=A0=EB=A3=8C=20?= =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=EC=97=90=EB=A7=8C=20=EC=A0=95?= =?UTF-8?q?=EC=82=B0=EC=9A=94=EC=9C=A8=20=EC=84=A4=EC=A0=95=20UI=20?= =?UTF-8?q?=EB=85=B8=EC=B6=9C=20=EB=B0=8F=20=EC=9A=94=EC=B2=AD=20=EA=B0=80?= =?UTF-8?q?=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/Content/ContentList.vue | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/views/Content/ContentList.vue b/src/views/Content/ContentList.vue index c69d5e5..b759dec 100644 --- a/src/views/Content/ContentList.vue +++ b/src/views/Content/ContentList.vue @@ -364,7 +364,7 @@ - + 정산요율 @@ -381,7 +381,7 @@ - + 정산요율 삭제 @@ -677,9 +677,14 @@ export default { const request = { id: this.audio_content.id, isDefaultCoverImage: this.audio_content.is_default_cover_image, - isSettlementRatioDeleted: this.audio_content.is_settlement_ratio_deleted, }; + // 유료 콘텐츠인 경우에만 정산요율 관련 플래그/값 전송 고려 + const isPaid = this.selected_audio_content && this.selected_audio_content.price > 0; + if (isPaid) { + request.isSettlementRatioDeleted = this.audio_content.is_settlement_ratio_deleted; + } + if ( this.audio_content.title !== this.selected_audio_content.title && this.audio_content.title.trim().length > 0 @@ -717,7 +722,7 @@ export default { this.audio_content.settlement_ratio !== undefined ? String(this.audio_content.settlement_ratio) : ""; - if (!this.audio_content.is_settlement_ratio_deleted && newRatio !== originalRatio) { + if (isPaid && !this.audio_content.is_settlement_ratio_deleted && newRatio !== originalRatio) { request.settlementRatio = newRatio; } -- 2.49.1