feat: 쿠폰등록

This commit is contained in:
최만억 (Jo)
2025-11-11 06:19:49 +00:00
committed by 김채린
parent 60b306ca90
commit 39fee9ef5f
2 changed files with 355 additions and 171 deletions

View File

@@ -5,7 +5,6 @@ import {
startOfDay, startOfDay,
globalDateFormat, globalDateFormat,
} from '@seed-next/date' } from '@seed-next/date'
import type { PublicMethods } from '@vuepic/vue-datepicker'
interface Props { interface Props {
date: Date | string | null date: Date | string | null
@@ -26,23 +25,27 @@ const emits = defineEmits(['update:date'])
const breakpoints = useResponsiveBreakpoints() const breakpoints = useResponsiveBreakpoints()
// Refs ----- // Refs -----
const { tm, locale } = useI18n() const { t, locale } = useI18n()
const datePickerRef = ref<any>(null) const datePickerRef = ref<any>(null)
const resultDate = ref('') const resultDate = ref('')
const formatDate = ref('') const formatDate = ref('')
const currentYear = ref(new Date().getFullYear()) const monthList = ref<Array<number>>([])
const currentMonth = ref(new Date().getMonth()) const currentYear = ref(getYear(new Date()))
const currentDecade = ref<{ start: number; end: number } | null>(null) const currentMonth = ref(getMonth(new Date()))
const currentDecade = ref<{ start: number; end: number; year: number }>({
start: 1970,
end: Math.floor(currentYear.value / 10) * 10 + 9,
year: currentYear.value,
})
const currentDecadeList = ref<Array<number> | null>(null)
// 상태값 // 상태값
const isMenuOpened = ref(false) const isMenuOpened = ref(false)
const isShowYearPicker = ref(false) const isShowYearPicker = ref(false)
const isShowMonthPicker = ref(false) const isShowMonthPicker = ref(false)
const isShowDecadePicker = ref(false) const isDisabledYearNav = ref({ prev: false, next: false })
const isDisabledDecadeNav = ref({ prev: false, next: false })
// Computed // Computed
const yearMonthText = computed(() => {
return `${currentYear.value}${currentMonth.value + 1}`
})
const formatMinDate = computed(() => { const formatMinDate = computed(() => {
if (props.minDate !== null) { if (props.minDate !== null) {
return globalDateFormat(props.minDate, locale.value) return globalDateFormat(props.minDate, locale.value)
@@ -68,6 +71,9 @@ const formatPlaceholder = computed(() => {
}) })
// Functions // Functions
/**
* @description 날짜 Computed값 포맷 셋팅 함수입니다.
*/
const setFormatDate = () => { const setFormatDate = () => {
const toDay = startOfDay(new Date()) const toDay = startOfDay(new Date())
resultDate.value = resultDate.value =
@@ -75,112 +81,242 @@ const setFormatDate = () => {
formatDate.value = globalDateFormat(resultDate.value, locale.value) as string formatDate.value = globalDateFormat(resultDate.value, locale.value) as string
const dateObj = props.date === null ? toDay : new Date(props.date) const dateObj = props.date === null ? toDay : new Date(props.date)
currentYear.value = dateObj.getFullYear() currentYear.value = getYear(dateObj)
currentMonth.value = dateObj.getMonth() currentMonth.value = getMonth(dateObj)
updateDecade(currentYear.value)
} }
/**
* @description 선택한 날짜로 업데이트하는 함수입니다.
* @param _date<Date | null> 선택한 날짜
*/
const updateDate = (_date: Date | null) => { const updateDate = (_date: Date | null) => {
if (_date != null) { if (_date != null) {
formatDate.value = globalDateFormat(_date, locale.value) as string formatDate.value = globalDateFormat(_date, locale.value) as string
currentYear.value = _date.getFullYear() currentYear.value = getYear(_date)
currentMonth.value = _date.getMonth() currentMonth.value = getMonth(_date)
emits('update:date', formatDate.value) emits('update:date', formatDate.value)
} }
} }
/**
* @description 월/년도가 변경되었을 때 업데이트하는 함수입니다.
* @param newDate<object<{ year: number, month: number }>> 변경된 월/년도
*/
const changeMonthYear = (newDate: any) => {
currentYear.value = newDate.year
currentMonth.value = newDate.month
}
/**
* @description 날짜 포맷 함수입니다.
* @param _date<Date> 날짜
*/
const format = (_date: Date) => { const format = (_date: Date) => {
return globalDateFormat(_date, locale.value) return globalDateFormat(_date, locale.value)
} }
/**
* @description 캘린더 메뉴 Open 함수입니다.
*/
const handleMenuOpen = () => { const handleMenuOpen = () => {
isMenuOpened.value = true isMenuOpened.value = true
} }
/**
* @description 캘린더 메뉴 Close 함수입니다.
*/
const handleMenuClose = () => { const handleMenuClose = () => {
isMenuOpened.value = false isMenuOpened.value = false
isShowMonthPicker.value = false isShowMonthPicker.value = false
isShowYearPicker.value = false isShowYearPicker.value = false
if (currentMonth.value !== getMonth(resultDate.value)) {
currentMonth.value = getMonth(resultDate.value)
} }
if (currentYear.value !== getYear(resultDate.value)) {
currentYear.value = getYear(resultDate.value)
}
}
/**
* @description 월 선택 창으로 이동하는 함수입니다.
*/
const handleOpenMonthPicker = () => { const handleOpenMonthPicker = () => {
isShowMonthPicker.value = true isShowMonthPicker.value = true
isShowYearPicker.value = false isShowYearPicker.value = false
updateYearList(currentYear.value)
} }
/**
* @description 년도 선택 창으로 이동하는 함수입니다.
*/
const handleOpenYearPicker = () => { const handleOpenYearPicker = () => {
isShowYearPicker.value = true isShowYearPicker.value = true
isShowMonthPicker.value = false isShowMonthPicker.value = false
} }
/**
* @description 월 선택 함수입니다.
* @param month<number> 선택 월
*/
const handleMonthSelect = (month: number) => { const handleMonthSelect = (month: number) => {
currentMonth.value = month currentMonth.value = month
isShowMonthPicker.value = false isShowMonthPicker.value = false
// 선택한 년도/월로 날짜 업데이트
const newDate = new Date(currentYear.value, currentMonth.value, 1)
if (props.minDate && newDate < props.minDate) {
newDate.setDate(props.minDate.getDate())
}
if (props.maxDate && newDate > props.maxDate) {
newDate.setDate(props.maxDate.getDate())
}
// DatePicker의 내부 상태 업데이트 // DatePicker의 내부 상태 업데이트
if (datePickerRef.value) { if (datePickerRef.value) {
datePickerRef.value.selectDate(newDate) datePickerRef.value.setMonthYear({ month: month, year: currentYear.value })
} }
updateDate(newDate)
} }
/**
* @description 년도 선택 함수입니다.
* @param year<number> 선택 년도
*/
const handleYearSelect = (year: number) => { const handleYearSelect = (year: number) => {
currentYear.value = year currentYear.value = year
isShowYearPicker.value = false isShowYearPicker.value = false
isShowMonthPicker.value = true
// 선택한 년도/월로 날짜 업데이트 updateYearList(currentYear.value)
const newDate = new Date(currentYear.value, currentMonth.value, 1)
if (props.minDate && newDate < props.minDate) {
newDate.setDate(props.minDate.getDate())
}
if (props.maxDate && newDate > props.maxDate) {
newDate.setDate(props.maxDate.getDate())
}
// DatePicker의 내부 상태 업데이트
if (datePickerRef.value) {
datePickerRef.value.selectDate(newDate)
}
updateDate(newDate)
}
const generateYearList = () => {
const years = []
const minYear = props.minDate ? props.minDate.getFullYear() : 1900
const maxYear = props.maxDate ? props.maxDate.getFullYear() : 2100
for (let year = minYear; year <= maxYear; year++) {
years.push(year)
}
return years
} }
/**
* @description 월 리스트 생성 함수입니다.
*/
const generateMonthList = () => { const generateMonthList = () => {
const months = []
const minMonth = const minMonth =
props.minDate && props.minDate.getFullYear() === currentYear.value props.minDate && getYear(props.minDate) === currentYear.value
? props.minDate.getMonth() ? getMonth(props.minDate)
: 0 : 0
const maxMonth = const maxMonth =
props.maxDate && props.maxDate.getFullYear() === currentYear.value props.maxDate && getYear(props.maxDate) === currentYear.value
? props.maxDate.getMonth() ? getMonth(props.maxDate)
: 11 : 11
const length = maxMonth - minMonth + 1
for (let month = minMonth; month <= maxMonth; month++) { monthList.value = Array.from({ length }, (_, i) => minMonth + i)
months.push(month)
} }
return months
/**
* @description 날짜 범위 차이 계산 함수입니다.
*/
const getDateRangeDifference = () => {
if (!props.minDate || !props.maxDate) {
return null
}
const minYear = getYear(props.minDate)
const maxYear = getYear(props.maxDate)
const yearDiff = maxYear - minYear
return {
yearDiff,
minYear,
maxYear,
minMonth: getMonth(props.minDate),
maxMonth: getMonth(props.maxDate),
isShortRange: yearDiff < 10, // 10년 미만인 경우 true, 10년 이상인 경우 false
}
}
/**
* @description 년도 리스트 생성 및 년도 네비게이션 버튼 비활성화 여부 체크 함수입니다.
* @param year<number> 선택 년도
*/
const updateYearList = (year: number) => {
const rangeInfo = getDateRangeDifference()
isDisabledYearNav.value.prev = false
isDisabledYearNav.value.next = false
if (year === (rangeInfo?.minYear ?? 1970)) {
isDisabledYearNav.value.prev = true
currentYear.value = rangeInfo?.minYear ?? 1970
generateMonthList()
return
} else if (year === (rangeInfo?.maxYear ?? getYear(new Date()))) {
isDisabledYearNav.value.next = true
currentYear.value = rangeInfo?.maxYear ?? getYear(new Date())
generateMonthList()
return
} else {
currentYear.value = year
generateMonthList()
}
}
/**
* @description 선택 년도가 속한 00 ~ 09년의 범위로 10년 단위 년도 리스트 업데이트 함수입니다.
* @param year<number> 선택 년도
*/
const updateDecade = (year: number) => {
const rangeInfo = getDateRangeDifference()
if (rangeInfo?.isShortRange) {
const minYear = rangeInfo.minYear
const maxYear = rangeInfo.maxYear
// 현재 년도가 범위를 벗어나면 조정
if (year < minYear) {
year = minYear
} else if (year > maxYear) {
year = maxYear
}
// decade가 아니라 실제 년도 범위만 사용
const start = minYear
const end = maxYear
isDisabledDecadeNav.value.prev = true
isDisabledDecadeNav.value.next = true
currentDecade.value = { start, end, year }
// 실제 년도 리스트 생성 (minYear부터 maxYear까지)
const length = end - start + 1
currentDecadeList.value = Array.from({ length }, (_, i) => start + i)
return
}
const firstYear = props.minDate
? Math.floor(getYear(props.minDate) / 10) * 10
: 1970
const lastYear = props.maxDate
? Math.floor(getYear(props.maxDate) / 10) * 10 + 9
: Math.floor(getYear(new Date()) / 10) * 10 + 9
const start = Math.floor(year / 10) * 10
const end = start + 9
if (start < firstYear) {
return
}
if (end > lastYear) {
return
}
isDisabledDecadeNav.value.prev = false
isDisabledDecadeNav.value.next = false
if (start <= firstYear) {
isDisabledDecadeNav.value.prev = true
}
if (end >= lastYear) {
isDisabledDecadeNav.value.next = true
}
const length = end - start + 1
currentDecade.value = { start: start, end: end, year }
currentDecadeList.value = Array.from({ length }, (_, i) => start + i)
} }
watch( watch(
@@ -199,25 +335,29 @@ onMounted(() => {
<template> <template>
<VueDatePicker <VueDatePicker
ref="datePickerRef" ref="datePickerRef"
v-model="resultDate" :model-value="new Date(resultDate)"
:locale="locale" :locale="locale"
week-start="0" week-start="0"
:year-first="true" :year-first="true"
:auto-apply="true" :auto-apply="true"
:hide-offset-dates="true"
:enable-time-picker="false" :enable-time-picker="false"
:preview-format="format" :preview-format="format"
:min-date="formatMinDate" :min-date="formatMinDate"
:max-date="formatMaxDate" :max-date="formatMaxDate"
:hide-offset-dates="true"
:prevent-min-max-navigation="true" :prevent-min-max-navigation="true"
:month-change-on-scroll="false" :month-change-on-scroll="false"
position="left" position="left"
:auto-position="true" :auto-position="true"
teleport="body"
:offset="8" :offset="8"
:config="{ :ui="{
shadowDom: true, menu:
isShowMonthPicker || isShowYearPicker
? 'date-picker-menu-wrap date-picker-menu-wrap-month-year'
: 'date-picker-menu-wrap',
}" }"
class="date-picker-wrap" @update-month-year="changeMonthYear"
@update:model-value="updateDate" @update:model-value="updateDate"
@date-update="updateDate" @date-update="updateDate"
@open="handleMenuOpen" @open="handleMenuOpen"
@@ -259,14 +399,12 @@ onMounted(() => {
</span> </span>
</template> </template>
<template <template
class="date-picker-calendar-wrap"
#month-year="{ #month-year="{
month, month,
year, year,
months,
years,
updateMonthYear, updateMonthYear,
handleMonthYearChange,
isDisabled, isDisabled,
}" }"
> >
@@ -297,8 +435,7 @@ onMounted(() => {
<span <span
class="inline-flex items-center justify-center text-[#1F1F1F] text-[18px] font-[500] leading-[26px] tracking-[-0.54px]" class="inline-flex items-center justify-center text-[#1F1F1F] text-[18px] font-[500] leading-[26px] tracking-[-0.54px]"
> >
{{ years.find(y => y.value === year)?.text }}. {{ t('Text_MonthYear', { month: month + 1, year: year }) }}
{{ months.find(m => m.value === month)?.text }}
</span> </span>
<AtomsIconsSelectArrowDownFill :size="10" color="#333333" /> <AtomsIconsSelectArrowDownFill :size="10" color="#333333" />
</button> </button>
@@ -330,18 +467,12 @@ onMounted(() => {
<button <button
type="button" type="button"
class="relative inline-flex items-center justify-center w-[32px] h-[32px]" class="relative inline-flex items-center justify-center w-[32px] h-[32px]"
:disabled="isDisabled(false)" :disabled="isDisabledYearNav.prev"
@click=" @click="updateYearList(currentYear - 1)"
updateMonthYear(
month,
year === getYear(minDate) ? year : year - 1,
false
)
"
> >
<AtomsIconsArrowRightLine <AtomsIconsArrowRightLine
:size="16" :size="16"
:color="isDisabled(false) ? '#CCCCCC' : '#333333'" :color="isDisabledYearNav.prev ? '#CCCCCC' : '#333333'"
class="relative rotate-180" class="relative rotate-180"
/> />
</button> </button>
@@ -353,24 +484,18 @@ onMounted(() => {
<span <span
class="inline-flex items-center justify-center text-[#1F1F1F] text-[18px] font-[500] leading-[26px] tracking-[-0.54px]" class="inline-flex items-center justify-center text-[#1F1F1F] text-[18px] font-[500] leading-[26px] tracking-[-0.54px]"
> >
{{ years.find(y => y.value === year)?.text }} {{ currentYear }}
</span> </span>
</button> </button>
<button <button
type="button" type="button"
class="relative inline-flex items-center justify-center w-[32px] h-[32px]" class="relative inline-flex items-center justify-center w-[32px] h-[32px]"
:disabled="isDisabled(true)" :disabled="isDisabledYearNav.next"
@click=" @click="updateYearList(currentYear + 1)"
updateMonthYear(
month,
year === getYear(maxDate) ? year : year + 1,
false
)
"
> >
<AtomsIconsArrowRightLine <AtomsIconsArrowRightLine
:size="16" :size="16"
:color="isDisabled(true) ? '#CCCCCC' : '#333333'" :color="isDisabledYearNav.next ? '#CCCCCC' : '#333333'"
class="relative" class="relative"
/> />
</button> </button>
@@ -378,7 +503,7 @@ onMounted(() => {
<div class="grid grid-cols-3 gap-[4px] w-full"> <div class="grid grid-cols-3 gap-[4px] w-full">
<button <button
v-for="month in generateMonthList()" v-for="month in monthList"
:key="month" :key="month"
type="button" type="button"
:class="[ :class="[
@@ -389,29 +514,76 @@ onMounted(() => {
]" ]"
@click="handleMonthSelect(month)" @click="handleMonthSelect(month)"
> >
{{ months.find(m => m.value === month)?.text }} {{ t('Text_Month', { month: month + 1 }) }}
</button> </button>
</div> </div>
</div> </div>
<div <div
v-if="isShowYearPicker && isMenuOpened" v-if="isShowYearPicker && isMenuOpened"
class="absolute z-[2] top-0 left-0 w-full h-full mt-[8px] overflow-y-auto bg-white" class="absolute z-[2] top-0 left-0 flex flex-col items-center justify-start w-full h-full overflow-y-auto bg-white"
> >
<div class="grid grid-cols-4 gap-[4px]"> <div class="flex items-center justify-between w-full py-[16px]">
<button <button
v-for="year in generateYearList()" type="button"
class="relative inline-flex items-center justify-center w-[32px] h-[32px]"
:disabled="isDisabledDecadeNav.prev"
@click="updateDecade(currentDecade.year - 10)"
>
<AtomsIconsArrowRightLine
:size="16"
:color="isDisabledDecadeNav.prev ? '#CCCCCC' : '#333333'"
class="relative rotate-180"
/>
</button>
<button
type="button"
class="relative inline-flex items-center justify-center gap-[8px] w-auto h-[32px] cursor-default"
:disabled="true"
>
<span
class="inline-flex items-center justify-center text-[#1F1F1F] text-[18px] font-[500] leading-[26px] tracking-[-0.54px]"
>
{{
t('Text_Decade', {
start: getDateRangeDifference()?.isShortRange
? getDateRangeDifference()?.minYear
: currentDecade.start,
end: getDateRangeDifference()?.isShortRange
? getDateRangeDifference()?.maxYear
: currentDecade.end,
})
}}
</span>
</button>
<button
type="button"
class="relative inline-flex items-center justify-center w-[32px] h-[32px]"
:disabled="isDisabledDecadeNav.next"
@click="updateDecade(currentDecade.year + 10)"
>
<AtomsIconsArrowRightLine
:size="16"
:color="isDisabledDecadeNav.next ? '#CCCCCC' : '#333333'"
class="relative"
/>
</button>
</div>
<div class="grid grid-cols-3 gap-[4px] w-full">
<button
v-for="year in currentDecadeList"
:key="year" :key="year"
type="button" type="button"
:class="[ :class="[
'px-[12px] py-[8px] text-center text-[14px] font-[400] leading-[20px] tracking-[-0.42px] rounded-[4px] transition-colors', 'inline-flex items-center justify-center w-full h-[52px] px-[12px] py-[8px] text-center text-[14px] font-[400] leading-[20px] tracking-[-0.42px] rounded-[4px] transition-colors',
year === currentYear year === currentYear
? 'bg-[#FC4420] text-white' ? 'bg-[#FC4420] text-white'
: 'text-[#333333] hover:bg-[#F5F5F5]', : 'text-[#333333] hover:bg-[#F5F5F5]',
]" ]"
@click="handleYearSelect(year)" @click="handleYearSelect(year)"
> >
{{ years.find(y => y.value === year)?.text }} {{ year }}
</button> </button>
</div> </div>
</div> </div>
@@ -419,20 +591,30 @@ onMounted(() => {
</VueDatePicker> </VueDatePicker>
</template> </template>
<style scoped> <style>
.date-picker-wrap :deep(.dp__calendar_header_separator) { body .date-picker-menu-wrap {
padding: 0 12px 8px !important;
border-radius: 8px !important;
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.1) !important;
}
body .date-picker-menu-wrap .dp__calendar_header_separator {
display: none !important; display: none !important;
} }
.date-picker-wrap :deep(.dp__menu) { body .date-picker-menu-wrap .dp__menu {
padding: 0 12px 8px !important;
}
.date-picker-wrap :deep(.dp__menu_inner) {
padding: 0 !important; padding: 0 !important;
} }
.date-picker-wrap :deep(.dp__calendar) { body .date-picker-menu-wrap .dp__menu,
body .date-picker-menu-wrap .dp__menu_wrap {
transform: translateZ(0) !important;
isolation: isolate !important;
}
body .date-picker-menu-wrap .dp__menu_inner {
padding: 0 !important; padding: 0 !important;
} }
.date-picker-wrap :deep(.dp__calendar_row) { body .date-picker-menu-wrap .dp__calendar {
padding: 0 !important;
}
body .date-picker-menu-wrap .dp__calendar_row {
-webkit-gap: 4px !important; -webkit-gap: 4px !important;
-moz-gap: 4px !important; -moz-gap: 4px !important;
-o-gap: 4px !important; -o-gap: 4px !important;
@@ -440,73 +622,75 @@ onMounted(() => {
gap: 4px !important; gap: 4px !important;
margin: 0 !important; margin: 0 !important;
} }
.date-picker-wrap :deep(.dp__calendar_item) { body .date-picker-menu-wrap .dp__calendar_item {
padding: 2px 4px !important; padding: 2px 4px !important;
} }
.date-picker-wrap :deep(.dp__cell_inner) { body .date-picker-menu-wrap .dp__cell_inner {
padding: 8px !important; padding: 8px !important;
border-radius: 100% !important; border-radius: 100% !important;
outline: none !important; outline: none !important;
border: none !important; border: none !important;
} }
.date-picker-wrap :deep(.dp__cell_inner.dp__date_hover:hover) { body .date-picker-menu-wrap .dp__cell_inner.dp__date_hover:hover {
background-color: rgba(0, 0, 0, 0.04) !important; background-color: rgba(0, 0, 0, 0.04) !important;
} }
.date-picker-wrap :deep(.dp__cell_inner.dp__today) { body .date-picker-menu-wrap .dp__cell_inner.dp__today {
border: 1px solid rgba(0, 0, 0, 0.15) !important; border: 1px solid rgba(0, 0, 0, 0.15) !important;
} }
.date-picker-wrap :deep(.dp__cell_inner.dp__active_date) { body .date-picker-menu-wrap .dp__cell_inner.dp__active_date {
background-color: #fc4420 !important; background-color: #fc4420 !important;
color: #ffffff !important; color: #ffffff !important;
} }
.date-picker-wrap :deep(.dp__cell_inner.dp__active_date span) { body .date-picker-menu-wrap .dp__cell_inner.dp__active_date span {
color: #ffffff !important; color: #ffffff !important;
} }
.date-picker-wrap :deep(.dp__cell_disabled:hover), body .date-picker-menu-wrap .dp__cell_disabled:hover,
.date-picker-wrap :deep(.dp__cell_disabled) { body .date-picker-menu-wrap .dp__cell_disabled {
cursor: default !important; cursor: default !important;
background-color: transparent !important; background-color: transparent !important;
} }
.date-picker-wrap :deep(.dp__menu), body .date-picker-menu-wrap .dp__menu,
.date-picker-wrap :deep(.dp__menu_wrap), body .date-picker-menu-wrap .dp__menu_wrap,
.date-picker-wrap :deep(.dp__overlay) { body .date-picker-menu-wrap .dp__overlay {
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.1) !important; box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.1) !important;
} }
.date-picker-wrap :deep(.dp__overlay_cell_pad) { body .date-picker-menu-wrap .dp__overlay_cell_pad {
color: #333333 !important; color: #333333 !important;
} }
.date-picker-wrap :deep(.dp__overlay_cell_pad:hover) { body .date-picker-menu-wrap .dp__overlay_cell_pad:hover {
background-color: #f5f5f5 !important; background-color: #f5f5f5 !important;
} }
.date-picker-wrap :deep(.dp__overlay_cell_pad.dp__overlay_cell_active) { body .date-picker-menu-wrap .dp__overlay_cell_pad.dp__overlay_cell_active {
background-color: #fc4420 !important; background-color: #fc4420 !important;
color: #ffffff !important; color: #ffffff !important;
} }
.date-picker-wrap :deep(.dp__overlay_cell_pad.dp__overlay_cell_disabled:hover), body
.date-picker-wrap :deep(.dp__overlay_cell_pad.dp__overlay_cell_disabled) { .date-picker-menu-wrap
.dp__overlay_cell_pad.dp__overlay_cell_disabled:hover,
body .date-picker-menu-wrap .dp__overlay_cell_pad.dp__overlay_cell_disabled {
cursor: default !important; cursor: default !important;
background-color: transparent !important; background-color: transparent !important;
opacity: 0.35 !important; opacity: 0.35 !important;
} }
.date-picker-wrap :deep(.dp__inner_nav) { body .date-picker-menu-wrap .dp__inner_nav {
color: #333333 !important; color: #333333 !important;
} }
.date-picker-wrap :deep(.dp__inner_nav:hover) { body .date-picker-menu-wrap .dp__inner_nav:hover {
background-color: transparent !important; background-color: transparent !important;
} }
.date-picker-wrap :deep(.dp__inner_nav.dp__inner_nav_disabled) { body .date-picker-menu-wrap .dp__inner_nav.dp__inner_nav_disabled {
background-color: transparent !important; background-color: transparent !important;
cursor: default !important; cursor: default !important;
opacity: 0.35 !important; opacity: 0.35 !important;
} }
.date-picker-wrap :deep(.dp__month_year_select), body .date-picker-menu-wrap .dp__month_year_select,
.date-picker-wrap :deep(.dp__month_year_select:hover) { body .date-picker-menu-wrap .dp__month_year_select:hover {
background-color: transparent !important; background-color: transparent !important;
} }
.date-picker-wrap :deep(.dp__arrow_bottom), body .date-picker-menu-wrap .dp__arrow_bottom,
.date-picker-wrap :deep(.dp__arrow_top), body .date-picker-menu-wrap .dp__arrow_top,
.date-picker-wrap :deep(.dp__arrow_left), body .date-picker-menu-wrap .dp__arrow_left,
.date-picker-wrap :deep(.dp__arrow_right) { body .date-picker-menu-wrap .dp__arrow_right {
display: none !important; display: none !important;
} }
@@ -518,7 +702,12 @@ onMounted(() => {
position: fixed !important; position: fixed !important;
} }
.date-picker-wrap :deep(.dp__month_year_select) { body .date-picker-menu-wrap .dp__month_year_select {
display: none !important; display: none !important;
} }
body .date-picker-menu-wrap.date-picker-menu-wrap-month-year {
height: 295px !important;
overflow: hidden !important;
}
</style> </style>

View File

@@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { import {
globalDateFormat,
getTime, getTime,
fromUnixTime, fromUnixTime,
addMonths, addMonths,
@@ -22,17 +23,13 @@ const props = defineProps<Props>()
// Configuration // Configuration
const runtimeConfig = useRuntimeConfig() const runtimeConfig = useRuntimeConfig()
const runType = runtimeConfig.public.runType as string
const staticUrl = runtimeConfig.public.staticUrl as string
const stoveApiUrl = runtimeConfig.public.stoveApiUrl as string const stoveApiUrl = runtimeConfig.public.stoveApiUrl as string
const stoveMaintenanceApiUrl = runtimeConfig.public const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
.stoveMaintenanceApiUrl as string const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_coupon.json'
const multilingualBaseApiUrl = `${staticUrl}/${runType}/test`
const multilingualFileName = 'test_homepage_brand_coupon.json'
// Multilingual // Multilingual
const resultGetMultilingual = await useGetMultilingual({ const resultGetMultilingual = await useGetMultilingual({
baseApiUrl: multilingualBaseApiUrl, baseApiUrl: dataResourcesUrl,
fileName: multilingualFileName, fileName: multilingualFileName,
}) })
const { t, tm, locale }: any = useI18n({ const { t, tm, locale }: any = useI18n({
@@ -41,7 +38,7 @@ const { t, tm, locale }: any = useI18n({
}) })
// Composables // Composables
const { isGameMaintenance, checkGameMaintenance } = useGetGameMaintenance() // const { isGameMaintenance, checkGameMaintenance } = useGetGameMaintenance()
const { isWebInspection, getInspectionDataExternal } = const { isWebInspection, getInspectionDataExternal } =
useGetInspectionDataExternal() useGetInspectionDataExternal()
const breakpoints = useResponsiveBreakpoints() const breakpoints = useResponsiveBreakpoints()
@@ -63,8 +60,7 @@ const {
setCouponDate, setCouponDate,
toUnixTimestamp, toUnixTimestamp,
} = useCouponDate() } = useCouponDate()
const { pageNo, pageSize, pageBlock, updatePagination, getPageBlock } = const { pageNo, pageSize, updatePagination, getPageBlock } = useCouponPaging()
useCouponPaging()
// Store // Store
const gameDataStore = useGameDataStore() const gameDataStore = useGameDataStore()
@@ -74,12 +70,7 @@ const { gameData } = storeToRefs(gameDataStore)
const { handleOpenAlert, handleOpenConfirm } = modalStore const { handleOpenAlert, handleOpenConfirm } = modalStore
const { couponNo, isSelectCharacter, selectCharacter } = const { couponNo, isSelectCharacter, selectCharacter } =
storeToRefs(couponStore) storeToRefs(couponStore)
const { const { updateCouponNo, updateSelectCharacter, isEmptyCouponNo } = couponStore
updateMemberNo,
updateCouponNo,
updateSelectCharacter,
isEmptyCouponNo,
} = couponStore
// Data // Data
const backgroundData = computed(() => const backgroundData = computed(() =>
@@ -92,17 +83,6 @@ const monthSelectList = ref<Array<number>>([1, 3, 6, 12])
const isSelectCharacterModalOpen = ref(false) const isSelectCharacterModalOpen = ref(false)
// Computed // Computed
const minDate = computed(() => {
const date = new Date()
date.setHours(0, 0, 0, 0)
date.setFullYear(date.getFullYear() - 1)
return date
})
const maxDate = computed(() => {
const date = new Date()
date.setHours(23, 59, 59, 999)
return date
})
const sortedCharacterList = computed(() => { const sortedCharacterList = computed(() => {
return characterList.value return characterList.value
.map(characterInfo => { .map(characterInfo => {
@@ -266,17 +246,23 @@ const handleCouponUse = async () => {
const validationCheckBeforeResult = await validationCheckBefore() const validationCheckBeforeResult = await validationCheckBefore()
if (validationCheckBeforeResult !== 0) { if (validationCheckBeforeResult !== 0) {
if ( if (validationCheckBeforeResult === COUPON_RESULT.LOGIN_REQUIRED) {
// 미로그인일 경우 : 이미 validationCheckBefore 함수에서 로그인 모달 팝업 노출했으므로 추가 처리 필요 없음
return
} else if (
validationCheckBeforeResult === COUPON_RESULT.SELECT_CHARACTER_REQUIRED validationCheckBeforeResult === COUPON_RESULT.SELECT_CHARACTER_REQUIRED
) { ) {
// 캐릭터 미선택일 경우 : 캐릭터 선택 모달 팝업 노출
openSelectCharacterModal() openSelectCharacterModal()
return false return
} else if (validationCheckBeforeResult === COUPON_RESULT.SYSTEM_ERROR) { } else if (validationCheckBeforeResult === COUPON_RESULT.SYSTEM_ERROR) {
// 시스템 에러일 경우 : 에러 팝업 노출 (에러코드)
openAlert(t('Coupon_Error', { code: validationCheckBeforeResult })) openAlert(t('Coupon_Error', { code: validationCheckBeforeResult }))
return false return
} else { } else {
// 그 외 오류 팝업 노출
openAlert(tm(`Coupon_Alert_(${validationCheckBeforeResult})`)) openAlert(tm(`Coupon_Alert_(${validationCheckBeforeResult})`))
return false return
} }
} else { } else {
openSelectCharacterModal() openSelectCharacterModal()
@@ -291,17 +277,23 @@ const handleCouponRegister = async () => {
const validationCheckBeforeResult = await validationCheckBefore() const validationCheckBeforeResult = await validationCheckBefore()
if (validationCheckBeforeResult !== 0) { if (validationCheckBeforeResult !== 0) {
if ( if (validationCheckBeforeResult === COUPON_RESULT.LOGIN_REQUIRED) {
// 미로그인일 경우 : 이미 validationCheckBefore 함수에서 로그인 모달 팝업 노출했으므로 추가 처리 필요 없음
return
} else if (
validationCheckBeforeResult === COUPON_RESULT.SELECT_CHARACTER_REQUIRED validationCheckBeforeResult === COUPON_RESULT.SELECT_CHARACTER_REQUIRED
) { ) {
// 캐릭터 미선택일 경우 : 캐릭터 선택 모달 팝업 노출
openSelectCharacterModal() openSelectCharacterModal()
return false return
} else if (validationCheckBeforeResult === COUPON_RESULT.SYSTEM_ERROR) { } else if (validationCheckBeforeResult === COUPON_RESULT.SYSTEM_ERROR) {
// 시스템 에러일 경우 : 에러 팝업 노출 (에러코드)
openAlert(t('Coupon_Error', { code: validationCheckBeforeResult })) openAlert(t('Coupon_Error', { code: validationCheckBeforeResult }))
return false return
} else { } else {
// 그 외 오류 팝업 노출
openAlert(tm(`Coupon_Alert_(${validationCheckBeforeResult})`)) openAlert(tm(`Coupon_Alert_(${validationCheckBeforeResult})`))
return false return
} }
} else { } else {
await getClientIp() await getClientIp()
@@ -356,8 +348,8 @@ const handlePeriodSearch = async () => {
} }
const result = differenceInDays(endDate.value, startDate.value) const result = differenceInDays(endDate.value, startDate.value)
if (result > 365) { if (result < 0 || result > 365) {
openAlert(tm('Coupon_Msg_OverDays')) openAlert(tm('Coupon_Alert_OverDays'))
return return
} }
@@ -588,8 +580,6 @@ onMounted(async () => {
<BlocksDatePicker <BlocksDatePicker
:key="getTime(startDate)" :key="getTime(startDate)"
:date="startDate" :date="startDate"
:min-date="minDate"
:max-date="maxDate"
@update:date=" @update:date="
(date: string) => setCouponDate(new Date(date), 'start') (date: string) => setCouponDate(new Date(date), 'start')
" "
@@ -602,8 +592,6 @@ onMounted(async () => {
<BlocksDatePicker <BlocksDatePicker
:key="getTime(endDate)" :key="getTime(endDate)"
:date="endDate" :date="endDate"
:min-date="minDate"
:max-date="maxDate"
@update:date=" @update:date="
(date: string) => setCouponDate(new Date(date), 'end') (date: string) => setCouponDate(new Date(date), 'end')
" "
@@ -690,7 +678,14 @@ onMounted(async () => {
couponIdx === couponList.length - 1 ? '!border-b-[0]' : '' couponIdx === couponList.length - 1 ? '!border-b-[0]' : ''
" "
> >
<p>{{ coupon.register_date }}</p> <p>
{{
globalDateFormat(
new Date(coupon.register_date),
locale.value
)
}}
</p>
</td> </td>
<td <td
:class=" :class="