- auth 스토어 isPremium/isAdmin 추가 (plan===PREMIUM 또는 관리자) - 사이드바: 통계·고정지출·예산·태그 메뉴에 무료 회원 잠금 배지(🔒) - 라우트 가드: 유료 전용 화면(requiresPremium) → 무료 회원은 /upgrade - UpgradeView: 무료/유료 기능 비교 + 업그레이드 안내 - http 인터셉터: 403 PREMIUM_REQUIRED → premium:required 이벤트 → 업그레이드 화면 - 무료 화면의 유료 API 호출 차단(홈 예산·내역 태그·OCR·카드알림 게이팅) - 회원관리: 멤버십 컬럼 + 무료/유료 토글(관리자) - 설정: 데이터 백업/복구 유료 게이팅, 계정정보에 멤버십 표시 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { RouterLink, useRouter } from 'vue-router'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
|
||||
const auth = useAuthStore()
|
||||
@@ -8,6 +8,8 @@ const router = useRouter()
|
||||
|
||||
const u = computed(() => auth.user || {})
|
||||
const roleLabel = computed(() => (u.value.role === 'ADMIN' ? '관리자' : '일반회원'))
|
||||
const isPremium = computed(() => auth.isPremium)
|
||||
const planLabel = computed(() => (isPremium.value ? '유료 멤버십' : '무료'))
|
||||
|
||||
function goEdit() {
|
||||
router.push('/settings/account/edit')
|
||||
@@ -30,6 +32,13 @@ function goEdit() {
|
||||
<span class="k">권한</span>
|
||||
<span class="v">{{ roleLabel }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="k">멤버십</span>
|
||||
<span class="v">
|
||||
<span :class="{ premium: isPremium }">{{ planLabel }}</span>
|
||||
<RouterLink v-if="!isPremium" to="/upgrade" class="up-link">업그레이드 →</RouterLink>
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<button type="button" class="primary-btn" @click="goEdit">이름 변경</button>
|
||||
@@ -92,6 +101,15 @@ function goEdit() {
|
||||
text-align: right;
|
||||
word-break: break-all;
|
||||
}
|
||||
.v .premium {
|
||||
color: #b8860b;
|
||||
}
|
||||
.up-link {
|
||||
margin-left: 0.5rem;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
}
|
||||
.primary-btn {
|
||||
width: 100%;
|
||||
margin-top: 1.25rem;
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { Preferences } from '@capacitor/preferences'
|
||||
import { useDialog } from '@/composables/dialog'
|
||||
import { useUiStore } from '@/stores/ui'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { exportBackup, importBackup } from '@/utils/backup'
|
||||
|
||||
const dialog = useDialog()
|
||||
const ui = useUiStore()
|
||||
const auth = useAuthStore()
|
||||
const isPremium = computed(() => auth.isPremium) // 데이터 백업/복구는 유료 전용
|
||||
|
||||
const exporting = ref(false)
|
||||
async function doExport() {
|
||||
@@ -143,23 +146,34 @@ async function clearAppData() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 데이터 백업 -->
|
||||
<!-- 데이터 백업 (유료 전용) -->
|
||||
<section class="card">
|
||||
<button type="button" class="row row-btn" :disabled="exporting" @click="doExport">
|
||||
<template v-if="isPremium">
|
||||
<button type="button" class="row row-btn" :disabled="exporting" @click="doExport">
|
||||
<div class="row-main">
|
||||
<span class="row-label">엑셀로 내보내기</span>
|
||||
<span class="row-sub">가계부 전체 데이터를 .xlsx 파일로 저장</span>
|
||||
</div>
|
||||
<span class="row-value">{{ exporting ? '내보내는 중…' : '내보내기' }}</span>
|
||||
</button>
|
||||
<button type="button" class="row row-btn" :disabled="importing" @click="pickImportFile">
|
||||
<div class="row-main">
|
||||
<span class="row-label">엑셀에서 가져오기</span>
|
||||
<span class="row-sub">백업 파일로 데이터 복구 (기존 데이터 덮어씀)</span>
|
||||
</div>
|
||||
<span class="row-value">{{ importing ? '복구 중…' : '가져오기' }}</span>
|
||||
</button>
|
||||
<input ref="fileInput" type="file" accept=".xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" class="hidden-file" @change="onImportFile" />
|
||||
</template>
|
||||
<RouterLink v-else to="/upgrade" class="row row-link">
|
||||
<div class="row-main">
|
||||
<span class="row-label">엑셀로 내보내기</span>
|
||||
<span class="row-sub">가계부 전체 데이터를 .xlsx 파일로 저장</span>
|
||||
<span class="row-label">데이터 백업 / 복구 👑</span>
|
||||
<span class="row-sub">엑셀 내보내기·가져오기는 유료 멤버십 기능입니다</span>
|
||||
</div>
|
||||
<span class="row-value">{{ exporting ? '내보내는 중…' : '내보내기' }}</span>
|
||||
</button>
|
||||
<button type="button" class="row row-btn" :disabled="importing" @click="pickImportFile">
|
||||
<div class="row-main">
|
||||
<span class="row-label">엑셀에서 가져오기</span>
|
||||
<span class="row-sub">백업 파일로 데이터 복구 (기존 데이터 덮어씀)</span>
|
||||
</div>
|
||||
<span class="row-value">{{ importing ? '복구 중…' : '가져오기' }}</span>
|
||||
</button>
|
||||
<input ref="fileInput" type="file" accept=".xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" class="hidden-file" @change="onImportFile" />
|
||||
<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M9 18l6-6-6-6" />
|
||||
</svg>
|
||||
</RouterLink>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
|
||||
Reference in New Issue
Block a user