diff --git a/src/api/authApi.js b/src/api/authApi.js
index 706ec66..84e2e85 100644
--- a/src/api/authApi.js
+++ b/src/api/authApi.js
@@ -43,6 +43,10 @@ export const authApi = {
points() {
return http.get('/auth/points')
},
+ // 포인트 적립/차감 내역 (최신순)
+ pointHistory() {
+ return http.get('/auth/point-history')
+ },
// 현재 사용자 전체 프로필(아바타·포인트 포함) — 재로그인 없이 최신값 동기화
profile() {
return http.get('/auth/profile')
diff --git a/src/views/settings/AccountInfoView.vue b/src/views/settings/AccountInfoView.vue
index ec0bb8f..c5540b1 100644
--- a/src/views/settings/AccountInfoView.vue
+++ b/src/views/settings/AccountInfoView.vue
@@ -22,6 +22,33 @@ onMounted(async () => {
}
})
+// 포인트 적립내역 모달
+const POINT_REASONS = { BOARD_WRITE: '게시판 작성' }
+function reasonLabel(r) {
+ return POINT_REASONS[r] || r
+}
+const historyOpen = ref(false)
+const history = ref([])
+const historyLoading = ref(false)
+async function openHistory() {
+ historyOpen.value = true
+ historyLoading.value = true
+ try {
+ history.value = await authApi.pointHistory()
+ } catch {
+ history.value = []
+ } finally {
+ historyLoading.value = false
+ }
+}
+function fmtDateTime(s) {
+ if (!s) return ''
+ const d = new Date(s)
+ if (Number.isNaN(d.getTime())) return s
+ const p = (n) => String(n).padStart(2, '0')
+ return `${d.getFullYear()}.${p(d.getMonth() + 1)}.${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`
+}
+
const u = computed(() => auth.user || {})
const roleLabel = computed(() => (u.value.role === 'ADMIN' ? '관리자' : '일반회원'))
const isPremium = computed(() => auth.isPremium)
@@ -128,12 +155,38 @@ function goEdit() {
업그레이드 →
-
+
+
+ {{ points.toLocaleString('ko-KR') }} P
+ 내역 ›
+
+
+
+
+
+
+
+ 포인트 적립내역
+
+
+
불러오는 중…
+
적립 내역이 없습니다.
+
+
+
+
+
@@ -201,6 +254,107 @@ function goEdit() {
color: hsla(160, 100%, 37%, 1);
font-weight: 700;
}
+.row-point {
+ width: 100%;
+ border: 0;
+ border-bottom: 1px solid var(--color-border);
+ background: transparent;
+ cursor: pointer;
+ font: inherit;
+ text-align: left;
+}
+.row-point:last-child {
+ border-bottom: 0;
+}
+.row-point:hover {
+ background: var(--color-background-mute);
+}
+.point-more {
+ margin-left: 0.5rem;
+ font-size: 0.82rem;
+ font-weight: 600;
+ color: var(--color-text);
+ opacity: 0.55;
+}
+/* 포인트 내역 모달 */
+.ph-backdrop {
+ position: fixed;
+ inset: 0;
+ z-index: 2000;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 1rem;
+}
+.ph-modal {
+ width: 100%;
+ max-width: 380px;
+ max-height: 75vh;
+ display: flex;
+ flex-direction: column;
+ background: var(--color-background);
+ border: 1px solid var(--color-border);
+ border-radius: 10px;
+ overflow: hidden;
+}
+.ph-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0.85rem 1rem;
+ border-bottom: 1px solid var(--color-border);
+}
+.ph-close {
+ border: 0;
+ background: transparent;
+ color: var(--color-text);
+ font-size: 1.5rem;
+ line-height: 1;
+ cursor: pointer;
+}
+.ph-msg {
+ padding: 2rem 1rem;
+ text-align: center;
+ opacity: 0.7;
+}
+.ph-list {
+ list-style: none;
+ margin: 0;
+ padding: 0.25rem 0;
+ overflow-y: auto;
+}
+.ph-list li {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 0.75rem;
+ padding: 0.65rem 1rem;
+ border-bottom: 1px solid var(--color-border);
+}
+.ph-list li:last-child {
+ border-bottom: 0;
+}
+.ph-main {
+ display: flex;
+ flex-direction: column;
+ gap: 0.15rem;
+}
+.ph-reason {
+ font-size: 0.92rem;
+}
+.ph-date {
+ font-size: 0.78rem;
+ opacity: 0.6;
+}
+.ph-amount {
+ font-weight: 700;
+ color: hsla(160, 100%, 37%, 1);
+ white-space: nowrap;
+}
+.ph-amount.minus {
+ color: #c0392b;
+}
.up-link {
margin-left: 0.5rem;
font-size: 0.82rem;