From 791d21d0522dbb3e90a0d83b111a24393281bf69 Mon Sep 17 00:00:00 2001 From: sohot8653 Date: Thu, 28 Aug 2025 16:59:15 +0900 Subject: [PATCH] =?UTF-8?q?[=EC=84=A4=EC=A0=95=20=EB=B0=8F=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EA=B4=80=EB=A6=AC=20=EA=B0=9C=EC=84=A0]=20Nuxt=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=EC=97=90=20pinia-plugin-persistedstate=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20package.json=20=EB=B0=8F=20package-lock.j?= =?UTF-8?q?son=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8,=20tab=20=EB=B0=8F?= =?UTF-8?q?=20user=20=EC=8A=A4=ED=86=A0=EC=96=B4=EC=97=90=20persist=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nuxt.config.ts | 21 +++-- package-lock.json | 42 +++++++++- package.json | 3 +- stores/tab.ts | 17 ++-- stores/user.ts | 207 ++++++++++++++++++++++++---------------------- 5 files changed, 168 insertions(+), 122 deletions(-) diff --git a/nuxt.config.ts b/nuxt.config.ts index ea1d861..c4baf2f 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -7,6 +7,7 @@ export default defineNuxtConfig({ "@nuxt/image", "@nuxt/icon", "@pinia/nuxt", + "pinia-plugin-persistedstate/nuxt", "@nuxtjs/tailwindcss", ], app: { @@ -17,14 +18,12 @@ export default defineNuxtConfig({ href: "https://fonts.googleapis.com/icon?family=Material+Icons", }, ], - script: [ - { src: '/dist/igv.js', defer: true } - ] + script: [{ src: "/dist/igv.js", defer: true }], }, }, vite: { optimizeDeps: { - include: ['cytoscape-overlays'], + include: ["cytoscape-overlays"], }, build: { commonjsOptions: { @@ -33,20 +32,20 @@ export default defineNuxtConfig({ }, }, nitro: { - logLevel: 'debug' + logLevel: "debug", }, runtimeConfig: { public: { - apiBase: process.env.API_BASE || 'http://localhost', - contextPath: process.env.CONTEXT_PATH || '/service', - } + apiBase: process.env.API_BASE || "http://localhost", + contextPath: process.env.CONTEXT_PATH || "/service", + }, }, typescript: { shim: false, strict: true, }, - plugins: ['~/plugins/vue3-tui-grid.client.ts'], + plugins: ["~/plugins/vue3-tui-grid.client.ts"], components: [ - { path: '~/components', pathPrefix: false }, // 경로 접두사 제거 - ] + { path: "~/components", pathPrefix: false }, // 경로 접두사 제거 + ], }); diff --git a/package-lock.json b/package-lock.json index 1b91b37..c936c16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "@nuxt/icon": "^1.14.0", "@nuxt/image": "^1.10.0", "@nuxtjs/tailwindcss": "^7.0.0-beta.0", - "@pinia/nuxt": "^0.11.1", + "@pinia/nuxt": "^0.11.2", "ag-grid-community": "^34.0.0", "ag-grid-vue3": "^34.0.0", "chart.js": "^4.5.0", @@ -22,6 +22,7 @@ "eslint": "^9.29.0", "nuxt": "^3.17.5", "pinia": "^3.0.3", + "pinia-plugin-persistedstate": "^4.5.0", "tui-code-snippet": "^2.3.3", "tui-grid": "^4.21.22", "vue": "^3.5.17", @@ -2827,9 +2828,9 @@ } }, "node_modules/@pinia/nuxt": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/@pinia/nuxt/-/nuxt-0.11.1.tgz", - "integrity": "sha512-tCD8ioWhhIHKwm8Y9VvyhBAV/kK4W5uGBIYbI5iM4N1t7duOqK6ECBUavrMxMolELayqqMLb9+evegrh3S7s2A==", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@pinia/nuxt/-/nuxt-0.11.2.tgz", + "integrity": "sha512-CgvSWpbktxxWBV7ModhAcsExsQZqpPq6vMYEe9DexmmY6959ev8ukL4iFhr/qov2Nb9cQAWd7niFDnaWkN+FHg==", "license": "MIT", "dependencies": { "@nuxt/kit": "^3.9.0" @@ -6086,6 +6087,12 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "license": "MIT" }, + "node_modules/deep-pick-omit": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/deep-pick-omit/-/deep-pick-omit-1.2.1.tgz", + "integrity": "sha512-2J6Kc/m3irCeqVG42T+SaUMesaK7oGWaedGnQQK/+O0gYc+2SP5bKh/KKTE7d7SJ+GCA9UUE1GRzh6oDe0EnGw==", + "license": "MIT" + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -10770,6 +10777,33 @@ } } }, + "node_modules/pinia-plugin-persistedstate": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-4.5.0.tgz", + "integrity": "sha512-QTkP1xJVyCdr2I2p3AKUZM84/e+IS+HktRxKGAIuDzkyaKKV48mQcYkJFVVDuvTxlI5j6X3oZObpqoVB8JnWpw==", + "license": "MIT", + "dependencies": { + "deep-pick-omit": "^1.2.1", + "defu": "^6.1.4", + "destr": "^2.0.5" + }, + "peerDependencies": { + "@nuxt/kit": ">=3.0.0", + "@pinia/nuxt": ">=0.10.0", + "pinia": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@pinia/nuxt": { + "optional": true + }, + "pinia": { + "optional": true + } + } + }, "node_modules/pkg-types": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz", diff --git a/package.json b/package.json index 111f51a..bb2e29b 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@nuxt/icon": "^1.14.0", "@nuxt/image": "^1.10.0", "@nuxtjs/tailwindcss": "^7.0.0-beta.0", - "@pinia/nuxt": "^0.11.1", + "@pinia/nuxt": "^0.11.2", "ag-grid-community": "^34.0.0", "ag-grid-vue3": "^34.0.0", "chart.js": "^4.5.0", @@ -27,6 +27,7 @@ "eslint": "^9.29.0", "nuxt": "^3.17.5", "pinia": "^3.0.3", + "pinia-plugin-persistedstate": "^4.5.0", "tui-code-snippet": "^2.3.3", "tui-grid": "^4.21.22", "vue": "^3.5.17", diff --git a/stores/tab.ts b/stores/tab.ts index 292de2b..2843d99 100644 --- a/stores/tab.ts +++ b/stores/tab.ts @@ -1,9 +1,9 @@ import { defineStore } from "pinia"; interface Tab { - key: number; // 1~10 + key: number; // 1~10 label: string; - to: string; // 페이지 라우트 + to: string; // 페이지 라우트 componentName: string; } @@ -12,7 +12,7 @@ const defaultTab = { key: 1, label: "홈", to: "/", componentName: "home" }; export const useTabsStore = defineStore("tabs", { state: () => ({ tabs: [defaultTab] as Tab[], - activeTab: 1 + activeTab: 1, }), actions: { // ✅ 새 탭 추가 (기본 페이지는 "/") @@ -27,7 +27,7 @@ export const useTabsStore = defineStore("tabs", { let key = 1; while (this.tabs.find(t => t.key === key)) key++; - this.tabs.push({...defaultTab, key : key}); + this.tabs.push({ ...defaultTab, key: key }); this.activeTab = key; $router.push(defaultTab.to); return key; @@ -49,7 +49,9 @@ export const useTabsStore = defineStore("tabs", { removeTab(key: number) { this.tabs = this.tabs.filter(t => t.key !== key); if (this.activeTab === key) { - this.activeTab = this.tabs.length ? this.tabs[this.tabs.length - 1].key : 0; + this.activeTab = this.tabs.length + ? this.tabs[this.tabs.length - 1].key + : 0; } }, @@ -59,6 +61,7 @@ export const useTabsStore = defineStore("tabs", { const tab = this.tabs.find(t => t.key === this.activeTab); $router.push(`/${tab?.key}${tab?.to}`); - } - } + }, + }, + persist: true, }); diff --git a/stores/user.ts b/stores/user.ts index 5695f2c..36bfc7c 100644 --- a/stores/user.ts +++ b/stores/user.ts @@ -1,103 +1,112 @@ -export const useUserStore = defineStore("user", () => { - // 상태 - const isLoggedIn = ref(false); - const user = ref<{ - userId?: string; - name?: string; - } | null>(null); - const token = ref(null); - - // 추후 제거 필요 - const isAdmin = true; - - interface LoginData { - userId: string; - } - // 액션 - const login = async (userId: string, password: string) => { - try { - // 실제 API 호출로 대체할 수 있습니다 - - const { success, data } = await useApi>("/login", { - method: "post", - body: { userId, password }, - }); - - if (success) { - user.value = data; - isLoggedIn.value = true; - } else { - throw new Error("아이디 또는 비밀번호가 올바르지 않습니다."); - } - - return { success }; - } catch (error: any) { - console.log(error); - return { - success: false, - error: - error?.response?.status === 401 - ? "아이디 또는 비밀번호가 올바르지 않습니다." - : error instanceof Error - ? error.message - : "로그인에 실패했습니다.", - }; - } - }; - - const logout = async () => { - try { - await useApi("/members/logout", { - method: "post", - }); - } catch (error) { - console.error("로그아웃 요청 실패:", error); - } finally { - // 로컬 상태 정리 - user.value = null; - isLoggedIn.value = false; - } - }; - - const checkAuth = () => { - // 페이지 로드 시 로컬 스토리지에서 사용자 정보 복원 - const savedUser = localStorage.getItem("user"); - const savedToken = localStorage.getItem("token"); - - if (savedUser && savedToken) { - user.value = JSON.parse(savedUser); - token.value = savedToken; - isLoggedIn.value = true; - } - }; - - const setToken = (accessToken: string) => { - token.value = accessToken; - }; - - const getToken = () => { - return token; - }; - - // 초기 인증 상태 확인 - if (import.meta.client) { - checkAuth(); - } - - return { +export const useUserStore = defineStore( + "user", + () => { // 상태 - isLoggedIn, - user, - token, + const isLoggedIn = ref(false); + const user = ref<{ + userId?: string; + name?: string; + } | null>(null); + const token = ref(null); - // 게터 - isAdmin, + // 추후 제거 필요 + const isAdmin = true; + interface LoginData { + userId: string; + } // 액션 - login, - logout, - checkAuth, - setToken, - getToken, - }; -}); + const login = async (userId: string, password: string) => { + try { + // 실제 API 호출로 대체할 수 있습니다 + + const { success, data } = await useApi>( + "/login", + { + method: "post", + body: { userId, password }, + } + ); + + if (success) { + user.value = data; + isLoggedIn.value = true; + } else { + throw new Error("아이디 또는 비밀번호가 올바르지 않습니다."); + } + + return { success }; + } catch (error: any) { + console.log(error); + return { + success: false, + error: + error?.response?.status === 401 + ? "아이디 또는 비밀번호가 올바르지 않습니다." + : error instanceof Error + ? error.message + : "로그인에 실패했습니다.", + }; + } + }; + + const logout = async () => { + try { + await useApi("/members/logout", { + method: "post", + }); + } catch (error) { + console.error("로그아웃 요청 실패:", error); + } finally { + // 로컬 상태 정리 + user.value = null; + isLoggedIn.value = false; + } + }; + + const checkAuth = () => { + // 페이지 로드 시 로컬 스토리지에서 사용자 정보 복원 + const savedUser = localStorage.getItem("user"); + const savedToken = localStorage.getItem("token"); + + if (savedUser && savedToken) { + user.value = JSON.parse(savedUser); + token.value = savedToken; + isLoggedIn.value = true; + } + }; + + const setToken = (accessToken: string) => { + token.value = accessToken; + }; + + const getToken = () => { + return token; + }; + + // 초기 인증 상태 확인 + if (import.meta.client) { + checkAuth(); + } + + return { + // 상태 + isLoggedIn, + user, + token, + + // 게터 + isAdmin, + + // 액션 + login, + logout, + checkAuth, + setToken, + getToken, + }; + }, + { + persist: true, + } +);