🔧 웹훅 URL을 HTTPS로 수정
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled

- 웹훅 URL을 https://admin.youtooplay.com/webhook로 변경
- Nginx 리버스 프록시 설정 파일 추가
- 배포 가이드 업데이트
This commit is contained in:
2025-10-01 01:47:51 +09:00
parent f331b52e64
commit 83b162d2bd
713 changed files with 98449 additions and 38378 deletions

View File

@@ -0,0 +1,59 @@
<script lang="ts" setup>
import AccountSettingsAccount from '@/views/pages/account-settings/AccountSettingsAccount.vue'
import AccountSettingsNotification from '@/views/pages/account-settings/AccountSettingsNotification.vue'
import AccountSettingsSecurity from '@/views/pages/account-settings/AccountSettingsSecurity.vue'
const route = useRoute()
const activeTab = ref(route.params.tab)
// tabs
const tabs = [
{ title: 'Account', icon: 'bx-user', tab: 'account' },
{ title: 'Security', icon: 'bx-lock-open', tab: 'security' },
{ title: 'Notifications', icon: 'bx-bell', tab: 'notification' },
]
</script>
<template>
<div>
<VTabs
v-model="activeTab"
show-arrows
class="v-tabs-pill"
>
<VTab
v-for="item in tabs"
:key="item.icon"
:value="item.tab"
>
<VIcon
size="20"
start
:icon="item.icon"
/>
{{ item.title }}
</VTab>
</VTabs>
<VWindow
v-model="activeTab"
class="mt-5 disable-tab-transition"
>
<!-- Account -->
<VWindowItem value="account">
<AccountSettingsAccount />
</VWindowItem>
<!-- Security -->
<VWindowItem value="security">
<AccountSettingsSecurity />
</VWindowItem>
<!-- Notification -->
<VWindowItem value="notification">
<AccountSettingsNotification />
</VWindowItem>
</VWindow>
</div>
</template>

31
pages/cards.vue Normal file
View File

@@ -0,0 +1,31 @@
<script setup lang="ts">
definePageMeta({
middleware: 'auth'
})
import CardBasic from '@/views/pages/cards/card-basic/CardBasic.vue'
import CardNavigation from '@/views/pages/cards/card-basic/CardNavigation.vue'
import CardSolid from '@/views/pages/cards/card-basic/CardSolid.vue'
</script>
<template>
<div>
<p class="text-2xl mb-6">
Basic Cards
</p>
<CardBasic />
<p class="text-2xl mb-6 mt-14">
Navigation Cards
</p>
<CardNavigation />
<p class="text-2xl mt-14 mb-6 ">
Solid Cards
</p>
<CardSolid />
</div>
</template>

157
pages/dashboard.vue Normal file
View File

@@ -0,0 +1,157 @@
<script setup lang="ts">
import AnalyticsCongratulations from '@/views/dashboard/AnalyticsCongratulations.vue'
import AnalyticsFinanceTabs from '@/views/dashboard/AnalyticsFinanceTab.vue'
import AnalyticsOrderStatistics from '@/views/dashboard/AnalyticsOrderStatistics.vue'
import AnalyticsProfitReport from '@/views/dashboard/AnalyticsProfitReport.vue'
import AnalyticsTotalRevenue from '@/views/dashboard/AnalyticsTotalRevenue.vue'
import AnalyticsTransactions from '@/views/dashboard/AnalyticsTransactions.vue'
// 👉 Images
import chart from '@images/cards/chart-success.png'
import card from '@images/cards/credit-card-primary.png'
import paypal from '@images/cards/paypal-error.png'
import wallet from '@images/cards/wallet-info.png'
definePageMeta({
middleware: 'auth'
})
</script>
<template>
<VRow>
<!-- 👉 Congratulations -->
<VCol
cols="12"
md="8"
>
<AnalyticsCongratulations />
</VCol>
<VCol
cols="12"
sm="4"
>
<VRow>
<!-- 👉 Profit -->
<VCol
cols="12"
md="6"
>
<CardStatisticsVertical
v-bind="{
title: 'Profit',
image: chart,
stats: '$12,628',
change: 72.80,
}"
/>
</VCol>
<!-- 👉 Sales -->
<VCol
cols="12"
md="6"
>
<CardStatisticsVertical
v-bind="{
title: 'Sales',
image: wallet,
stats: '$4,679',
change: 28.42,
}"
/>
</VCol>
</VRow>
</VCol>
<!-- 👉 Total Revenue -->
<VCol
cols="12"
md="8"
order="2"
order-md="1"
>
<AnalyticsTotalRevenue />
</VCol>
<VCol
cols="12"
sm="8"
md="4"
order="1"
order-md="2"
>
<VRow>
<!-- 👉 Payments -->
<VCol
cols="12"
sm="6"
>
<CardStatisticsVertical
v-bind=" {
title: 'Payments',
image: paypal,
stats: '$2,468',
change: -14.82,
}"
/>
</VCol>
<!-- 👉 Revenue -->
<VCol
cols="12"
sm="6"
>
<CardStatisticsVertical
v-bind="{
title: 'Transactions',
image: card,
stats: '$14,857',
change: 28.14,
}"
/>
</VCol>
</VRow>
<VRow>
<!-- 👉 Profit Report -->
<VCol
cols="12"
sm="12"
>
<AnalyticsProfitReport />
</VCol>
</VRow>
</VCol>
<!-- 👉 Order Statistics -->
<VCol
cols="12"
md="4"
sm="6"
order="3"
>
<AnalyticsOrderStatistics />
</VCol>
<!-- 👉 Tabs chart -->
<VCol
cols="12"
md="4"
sm="6"
order="3"
>
<AnalyticsFinanceTabs />
</VCol>
<!-- 👉 Transactions -->
<VCol
cols="12"
md="4"
sm="6"
order="3"
>
<AnalyticsTransactions />
</VCol>
</VRow>
</template>

70
pages/form-layouts.vue Normal file
View File

@@ -0,0 +1,70 @@
<script setup lang="ts">
definePageMeta({
middleware: 'auth'
})
import DemoFormLayoutHorizontalForm from '@/views/pages/form-layouts/DemoFormLayoutHorizontalForm.vue'
import DemoFormLayoutHorizontalFormWithIcons from '@/views/pages/form-layouts/DemoFormLayoutHorizontalFormWithIcons.vue'
import DemoFormLayoutMultipleColumn from '@/views/pages/form-layouts/DemoFormLayoutMultipleColumn.vue'
import DemoFormLayoutVerticalForm from '@/views/pages/form-layouts/DemoFormLayoutVerticalForm.vue'
import DemoFormLayoutVerticalFormWithIcons from '@/views/pages/form-layouts/DemoFormLayoutVerticalFormWithIcons.vue'
</script>
<template>
<div>
<VRow>
<VCol
cols="12"
md="6"
>
<!-- 👉 Horizontal Form -->
<VCard title="Horizontal Form">
<VCardText>
<DemoFormLayoutHorizontalForm />
</VCardText>
</VCard>
</VCol>
<VCol
cols="12"
md="6"
>
<!-- 👉 Horizontal Form with Icons -->
<VCard title="Horizontal Form with Icons">
<VCardText>
<DemoFormLayoutHorizontalFormWithIcons />
</VCardText>
</VCard>
</VCol>
<VCol
cols="12"
md="6"
>
<!-- 👉 Vertical Form -->
<VCard title="Vertical Form">
<VCardText>
<DemoFormLayoutVerticalForm />
</VCardText>
</VCard>
</VCol>
<VCol
cols="12"
md="6"
>
<!-- 👉 Vertical Form with Icons -->
<VCard title="Vertical Form with Icons">
<VCardText>
<DemoFormLayoutVerticalFormWithIcons />
</VCardText>
</VCard>
</VCol>
<VCol cols="12">
<!-- 👉 Multiple Column -->
<VCard title="Multiple Column">
<VCardText>
<DemoFormLayoutMultipleColumn />
</VCardText>
</VCard>
</VCol>
</VRow>
</div>
</template>

91
pages/icons.vue Normal file
View File

@@ -0,0 +1,91 @@
<script lang="ts" setup>
const iconsList = [
'bx-abacus',
'bx-accessibility',
'bx-add-to-queue',
'bx-adjust',
'bx-alarm',
'bx-alarm-add',
'bx-alarm-exclamation',
'bx-alarm-off',
'bx-alarm-snooze',
'bx-album',
'bx-align-justify',
'bx-align-left',
'bx-align-middle',
'bx-align-right',
'bx-analyse',
'bx-anchor',
'bx-angry',
'bx-aperture',
'bx-arch',
'bx-archive',
'bx-archive-in',
'bx-archive-out',
'bx-area',
'bx-arrow-back',
'bx-arrow-from-bottom',
'bx-arrow-from-left',
'bx-arrow-from-right',
'bx-arrow-from-top',
'bx-arrow-to-bottom',
'bx-arrow-to-left',
'bx-arrow-to-right',
'bx-arrow-to-top',
'bx-at',
'bx-atom',
'bx-award',
'bx-badge',
'bx-badge-check',
'bx-baguette',
'bx-ball',
'bx-band-aid',
'bx-bar-chart',
'bx-bar-chart-alt',
'bx-bar-chart-alt-2',
'bx-bar-chart-square',
'bx-barcode',
'bx-barcode-reader',
'bx-baseball',
'bx-basket',
]
</script>
<template>
<div>
<div class="d-flex align-center flex-wrap">
<VCard
v-for="icon in iconsList"
:key="icon"
class="mb-6 me-6"
>
<VCardText class="py-3 px-4">
<VIcon
size="30"
:icon="icon"
/>
</VCardText>
<!-- tooltips -->
<VTooltip
location="top"
activator="parent"
>
{{ icon }}
</VTooltip>
</VCard>
</div>
<!-- more icons -->
<div class="text-center">
<VBtn
href="https://boxicons.com/"
rel="noopener noreferrer"
color="primary"
target="_blank"
>
View All Box Icons
</VBtn>
</div>
</div>
</template>

197
pages/login.vue Normal file
View File

@@ -0,0 +1,197 @@
<script setup lang="ts">
import AuthProvider from '@/views/pages/authentication/AuthProvider.vue'
import logo from '@images/logo.svg?raw'
import authV1BottomShape from '@images/svg/auth-v1-bottom-shape.svg?url'
import authV1TopShape from '@images/svg/auth-v1-top-shape.svg?url'
const form = ref({
user_id: '',
password: '',
remember: false,
})
const isPasswordVisible = ref(false)
const isLoading = ref(false)
const errorMessage = ref('')
const router = useRouter()
// 컴포넌트 마운트 시 테스트
onMounted(() => {
})
const handleLogin = async () => {
if (!form.value.user_id || !form.value.password) {
errorMessage.value = '아이디와 비밀번호를 입력해주세요.'
return
}
isLoading.value = true
errorMessage.value = ''
try {
const response = await $fetch('/api/auth/login', {
method: 'POST',
body: {
user_id: form.value.user_id,
password: form.value.password
}
})
if (response.success) {
// 토큰을 쿠키에 저장
const token = useCookie('auth-token', {
maxAge: 60 * 60 * 24, // 24시간
secure: true,
sameSite: 'strict'
})
token.value = response.token
// 사용자 정보를 쿠키에 저장
const user = useCookie('user-info', {
maxAge: 60 * 60 * 24,
secure: true,
sameSite: 'strict'
})
user.value = JSON.stringify(response.user)
// 대시보드로 리다이렉션
await router.push('/dashboard')
} else {
errorMessage.value = response.message || '로그인에 실패했습니다.'
}
} catch (error: any) {
console.error('Login error:', error)
console.error('Error details:', {
statusCode: error.statusCode,
statusMessage: error.statusMessage,
data: error.data
})
errorMessage.value = error.data?.statusMessage || error.statusMessage || '로그인 중 오류가 발생했습니다.'
} finally {
isLoading.value = false
}
}
definePageMeta({
layout: 'blank',
middleware: 'guest'
})
</script>
<template>
<div class="auth-wrapper d-flex align-center justify-center pa-4">
<div class="position-relative my-sm-16">
<!-- 👉 Top shape -->
<VImg
:src="authV1TopShape"
class="text-primary auth-v1-top-shape d-none d-sm-block"
/>
<!-- 👉 Bottom shape -->
<VImg
:src="authV1BottomShape"
class="text-primary auth-v1-bottom-shape d-none d-sm-block"
/>
<!-- 👉 Auth Card -->
<VCard
class="auth-card"
max-width="460"
:class="$vuetify.display.smAndUp ? 'pa-6' : 'pa-0'"
>
<VCardItem class="justify-center">
<NuxtLink
to="/"
class="app-logo"
>
<!-- eslint-disable vue/no-v-html -->
<div
class="d-flex"
v-html="logo"
/>
<h1 class="app-logo-title">
sneat
</h1>
</NuxtLink>
</VCardItem>
<VCardText>
<h4 class="text-h4 mb-1">
음악 관리 시스템👋🏻
</h4>
<p class="mb-0">
계정에 로그인하여 관리 시스템을 시작하세요
</p>
</VCardText>
<VCardText>
<VForm @submit.prevent="handleLogin">
<VRow>
<!-- 오류 메시지 -->
<VCol
v-if="errorMessage"
cols="12"
>
<VAlert
type="error"
variant="tonal"
closable
@click:close="errorMessage = ''"
>
{{ errorMessage }}
</VAlert>
</VCol>
<!-- 아이디 -->
<VCol cols="12">
<VTextField
:id="useId()"
v-model="form.user_id"
autofocus
label="아이디"
placeholder="아이디를 입력하세요"
/>
</VCol>
<!-- 비밀번호 -->
<VCol cols="12">
<VTextField
:id="useId()"
v-model="form.password"
label="비밀번호"
placeholder="············"
:type="isPasswordVisible ? 'text' : 'password'"
autocomplete="password"
:append-inner-icon="isPasswordVisible ? 'bx-hide' : 'bx-show'"
@click:append-inner="isPasswordVisible = !isPasswordVisible"
/>
</VCol>
<VCol cols="12">
<VBtn
block
type="button"
:loading="isLoading"
:disabled="isLoading"
@click="handleLogin"
>
로그인
</VBtn>
</VCol>
</VRow>
</VForm>
</VCardText>
</VCard>
</div>
</div>
</template>
<style lang="scss">
@use "@core/scss/template/pages/page-auth";
</style>

171
pages/register.vue Normal file
View File

@@ -0,0 +1,171 @@
<script setup lang="ts">
import AuthProvider from '@/views/pages/authentication/AuthProvider.vue'
import logo from '@images/logo.svg?raw'
import authV1BottomShape from '@images/svg/auth-v1-bottom-shape.svg?url'
import authV1TopShape from '@images/svg/auth-v1-top-shape.svg?url'
const form = ref({
username: '',
email: '',
password: '',
privacyPolicies: false,
})
const isPasswordVisible = ref(false)
definePageMeta({
layout: 'blank',
middleware: 'guest'
})
</script>
<template>
<div class="auth-wrapper d-flex align-center justify-center pa-4">
<div class="position-relative my-sm-16">
<!-- 👉 Top shape -->
<VImg
:src="authV1TopShape"
class="text-primary auth-v1-top-shape d-none d-sm-block"
/>
<!-- 👉 Bottom shape -->
<VImg
:src="authV1BottomShape"
class="text-primary auth-v1-bottom-shape d-none d-sm-block"
/>
<!-- 👉 Auth card -->
<VCard
class="auth-card"
max-width="460"
:class="$vuetify.display.smAndUp ? 'pa-6' : 'pa-0'"
>
<VCardItem class="justify-center">
<NuxtLink
to="/"
class="app-logo"
>
<!-- eslint-disable vue/no-v-html -->
<div
class="d-flex"
v-html="logo"
/>
<h1 class="app-logo-title">
sneat
</h1>
</NuxtLink>
</VCardItem>
<VCardText>
<h4 class="text-h4 mb-1">
Adventure starts here 🚀
</h4>
<p class="mb-0">
Make your app management easy and fun!
</p>
</VCardText>
<VCardText>
<VForm @submit.prevent="$router.push('/')">
<VRow>
<!-- Username -->
<VCol cols="12">
<VTextField
:id="useId()"
v-model="form.username"
autofocus
label="Username"
placeholder="Johndoe"
/>
</VCol>
<!-- email -->
<VCol cols="12">
<VTextField
:id="useId()"
v-model="form.email"
label="Email"
type="email"
placeholder="johndoe@email.com"
/>
</VCol>
<!-- password -->
<VCol cols="12">
<VTextField
:id="useId()"
v-model="form.password"
label="Password"
autocomplete="password"
placeholder="············"
:type="isPasswordVisible ? 'text' : 'password'"
:append-inner-icon="isPasswordVisible ? 'bx-hide' : 'bx-show'"
@click:append-inner="isPasswordVisible = !isPasswordVisible"
/>
<div class="d-flex align-center my-6">
<VCheckbox
id="privacy-policy"
v-model="form.privacyPolicies"
inline
/>
<VLabel
for="privacy-policy"
style="opacity: 1;"
>
<span class="me-1 text-high-emphasis">I agree to</span>
<a
href="javascript:void(0)"
class="text-primary"
>privacy policy & terms</a>
</VLabel>
</div>
<VBtn
block
type="submit"
>
Sign up
</VBtn>
</VCol>
<!-- login instead -->
<VCol
cols="12"
class="text-center text-base"
>
<span>Already have an account?</span>
<NuxtLink
class="text-primary ms-1"
to="/login"
>
Sign in instead
</NuxtLink>
</VCol>
<VCol
cols="12"
class="d-flex align-center"
>
<VDivider />
<span class="mx-4">or</span>
<VDivider />
</VCol>
<!-- auth providers -->
<VCol
cols="12"
class="text-center"
>
<AuthProvider />
</VCol>
</VRow>
</VForm>
</VCardText>
</VCard>
</div>
</div>
</template>
<style lang="scss">
@use "@core/scss/template/pages/page-auth";
</style>

57
pages/tables.vue Normal file
View File

@@ -0,0 +1,57 @@
<script setup lang="ts">
definePageMeta({
middleware: 'auth'
})
import DemoSimpleTableBasics from '@/views/pages/tables/DemoSimpleTableBasics.vue'
import DemoSimpleTableDensity from '@/views/pages/tables/DemoSimpleTableDensity.vue'
import DemoSimpleTableFixedHeader from '@/views/pages/tables/DemoSimpleTableFixedHeader.vue'
import DemoSimpleTableHeight from '@/views/pages/tables/DemoSimpleTableHeight.vue'
import DemoSimpleTableTheme from '@/views/pages/tables/DemoSimpleTableTheme.vue'
</script>
<template>
<VRow>
<VCol cols="12">
<VCard title="Basic">
<DemoSimpleTableBasics />
</VCard>
</VCol>
<VCol cols="12">
<VCard title="Theme">
<VCardText>
use <code>theme</code> prop to switch table to the dark theme.
</VCardText>
<DemoSimpleTableTheme />
</VCard>
</VCol>
<VCol cols="12">
<VCard title="Density">
<VCardText>
You can show a dense version of the table by using the <code>density</code> prop.
</VCardText>
<DemoSimpleTableDensity />
</VCard>
</VCol>
<VCol cols="12">
<VCard title="Height">
<VCardText>
You can set the height of the table by using the <code>height</code> prop.
</VCardText>
<DemoSimpleTableHeight />
</VCard>
</VCol>
<VCol cols="12">
<VCard title="Fixed Header">
<VCardText>
You can fix the header of table by using the <code>fixed-header</code> prop.
</VCardText>
<DemoSimpleTableFixedHeader />
</VCard>
</VCol>
</VRow>
</template>

178
pages/typography.vue Normal file
View File

@@ -0,0 +1,178 @@
<template>
<VRow>
<VCol cols="12">
<VCard title="Headlines">
<VCardText class="d-flex flex-column gap-y-8">
<div>
<h1 class="text-h1">
Heading 1
</h1>
<span>font-size: 6rem / line-height: 6rem / font-weight: 300</span>
</div>
<div>
<h2 class="text-h2">
Heading 2
</h2>
<span>font-size: 3.75rem / line-height: 3.75rem / font-weight: 300</span>
</div>
<div>
<h3 class="text-h3">
Heading 3
</h3>
<span>font-size: 3rem / line-height: 3.125rem / font-weight: 400</span>
</div>
<div>
<h4 class="text-h4">
Heading 4
</h4>
<span>font-size: 2.125rem / line-height: 2.5rem / font-weight: 400</span>
</div>
<div>
<h5 class="text-h5">
Heading 5
</h5>
<span>font-size: 1.5rem / line-height: 2rem / font-weight: 400</span>
</div>
<div>
<h6 class="text-h6">
Heading 6
</h6>
<span>font-size: 1.25rem / line-height: 2rem / font-weight: 500</span>
</div>
</VCardText>
</VCard>
</VCol>
<VCol cols="12">
<VCard title="Texts">
<VCardText>
<VRow no-gutters>
<VCol
cols="12"
md="2"
>
<span class="text-subtitle-1 text-no-wrap">text-subtitle-1</span>
</VCol>
<VCol
cols="12"
md="10"
class="mb-6"
>
<p class="text-subtitle-1 text-truncate mb-1">
Cupcake ipsum dolor sit amet fruitcake donut chocolate.
</p>
<span>font-size: 1rem / line-height: 1.75rem / font-weight: 400</span>
</VCol>
<VCol
cols="12"
md="2"
>
<span class="text-subtitle-2 text-no-wrap">text-subtitle-2</span>
</VCol>
<VCol
cols="12"
md="10"
class="mb-6"
>
<p class="text-subtitle-2 mb-1">
Cupcake ipsum dolor sit amet fruitcake donut chocolate.
</p>
<span>font-size: 0.875rem / line-height: 1.375rem / font-weight: 500</span>
</VCol>
<VCol
cols="12"
md="2"
>
<span class="text-body-1 text-no-wrap">text-body-1</span>
</VCol>
<VCol
cols="12"
md="10"
class="mb-6"
>
<p class="text-body-1 mb-1">
Cupcake ipsum dolor sit amet fruitcake donut chocolate.
</p>
<span>font-size: 1rem / line-height: 1.5rem / font-weight: 400</span>
</VCol>
<VCol
cols="12"
md="2"
>
<span class="text-body-2 text-no-wrap">text-body-2</span>
</VCol>
<VCol
cols="12"
md="10"
class="mb-6"
>
<p class="text-body-2 mb-1">
Cupcake ipsum dolor sit amet fruitcake donut chocolate.
</p>
<span>font-size: 0.875rem / line-height: 1.25rem / font-weight: 400</span>
</VCol>
<VCol
cols="12"
md="2"
>
<span class="text-caption">text-caption</span>
</VCol>
<VCol
cols="12"
md="10"
class="mb-6"
>
<p class="text-caption mb-1">
Cupcake ipsum dolor sit amet fruitcake donut chocolate.
</p>
<span>font-size: 0.75rem / line-height: 1.25rem / font-weight: 400</span>
</VCol>
<VCol
cols="12"
md="2"
>
<span class="text-overline text-no-wrap">text-overline</span>
</VCol>
<VCol
cols="12"
md="10"
class="mb-6"
>
<p class="text-overline mb-1">
Cupcake ipsum dolor sit amet fruitcake donut chocolate.
</p>
<span>font-size: 0.75rem / line-height: 2rem / font-weight: 500</span>
</VCol>
<VCol
cols="12"
md="2"
>
<span class="text-button">text-button</span>
</VCol>
<VCol
cols="12"
md="10"
class="mb-6"
>
<p class="text-button mb-1">
Cupcake ipsum dolor sit amet fruitcake donut chocolate.
</p>
<span>font-size: 0.875rem / line-height: 2.25rem / font-weight: 500</span>
</VCol>
</VRow>
</VCardText>
</VCard>
</VCol>
</VRow>
</template>