ChamomileGuides 3.1.0 Help

Nuxt 컴포넌트

컴포넌트 > ChmmGrid (AG-Grid)

ChmmGrid

데이터를 테이블 형태로 표현할 때, 사용하는 그리드 컴포넌트 그리드 사용을 표준화를 위해서 아래의 기능을 제공하며, 상황 별 사용 표준을 제시합니다.

특징 Summary😎

☑ 2가지 표준 유형 (인피니티 스크롤, 페이지네이션)

☑ 그리드 관련 버튼 (행 추가/삭제, 엑셀 업/다운로드)

☑ 쉬운 데이터 조회 API 연결

☑ 그리드 유형 함수

Infinite Scroll (그리드 표준)

사용자가 스크롤을 내릴 때마다, 데이터를 더 로딩하는 방식이며, 정렬과 필터가 서버의 데이터를 대상으로 동작합니다.

selectApi 를 전달하여 그리드와 데이터 조회 API를 쉽게 연결할 수 있습니다.

admin_04_02_01
<template> <ChmmGrid ref="inactiveGridRef" :getRowId="getRowId" style="height: calc(100vh - 35.5rem); min-height: calc(100vh - 35.5rem); max-height: calc(100vh - 35.5rem); width: 100%" rowModelType="hybrid" :header-title="i18n.t('multilanguage.label.unused')" :default-col-def="{ cellClass: ['text-center'] }" :column-defs="activeGridcolumnDefs" :rowNumbers="false" :rowSelection="{ mode: 'multiRow' }" select-api="user/list" :select-params="userVO" @grid-ready="onInactiveGridReady" /> </template>

Pagination

사용자가 페이지 이동을 쉽게 할 수 있도록 페이징네이션 UI가 제공되며, 정렬과 필터가 현재 페이지 내의 데이터를 대상으로 동작합니다.

selectApi 를 전달하여 그리드와 데이터 조회 API를 쉽게 연결할 수 있습니다.

admin_04_02_02
<template> <ChmmGrid ref="agGridRef" row-model-type="hybrid" :header-title="i18n.t('multilanguage.label.multilingualList')" :column-defs="gridcolumnDefs" :pagination="true" :pagination-page-size="20" :pagination-page-size-selector="[10, 15, 20, 50, 100]" :row-numbers="true" :row-selection="{ mode: 'multiRow' }" select-api="message/list" :select-params="messageVO" @row-double-clicked="updateMessage" @row-selected="fnRowSelected" @grid-ready="onGridReady" /> </template>

Header Class

아래 두 가지 경우에는 UI/UX 표준에 정의된 header class를 자동 적용합니다.

1.편집 가능 표기

editable 은 boolean 또는 조건에 따라 row별로 editable 값을 설정하고 싶은 경우에는 함수 형태로 전달할 수도 있습니다.

※ 함수로 전달하는 경우, 특정 조건에 따라 "편집 가능한 컬럼"이므로, 실제 함수 return 결과와 상관없이 Header Class를 적용합니다.

→ 함수로 전달하는 경우, 모든 형의 컬럼이 편집 불가능이더라도 Header Class가 적용됩니다.

const columnDefs = {   ...,   // boolean   editable: true,   // function   editable: (params: EditableCallbackParams) => { ... }, }

2.필수입력 표기

필수입력 표기 클래스는 적용하기 위해서는 editable 도 반드시 true 여야 합니다.

required 속성은 header class를 적용하기 위한 속성입니다. (AG Grid ColumnDefs에 정의되지 않습니다.)

const columnDefs = {   ...,   editable: true,   required: true, }

CellRenderers

셀 렌더러는 셀에 표시되는 데이터의 모양을 커스터마이징하는 역할을 합니다.

공통에서 제공하는 셀 컴포넌트 유형은 다음과 같습니다.

1.BadgeRendererVue

  • 상태나 등급을 시각적으로 표시하는 배지를 렌더링하는 컴포넌트 (작은 문자 또는 숫자 데이터에 사용)

{   cellRenderer: BadgeRendererVue, cellRendererParams: (params: ValueFormatterParams<any, any>) => ({ value: params.value, label: params.value == '1' ? i18n.t('G1USE1') : params.value == '0' ? i18n.t('G1USE0') : '', }), }

2.ButtonRendererVue

  • 사용자 상호작용을 위한 버튼을 그리드 셀에 렌더링하는 컴포넌트

{   cellRenderer: ButtonRendererVue, cellRendererParams: () => ({ // 버튼명 buttonName: '다국어', // 버튼 클릭시 전달할 function onButtonClickFunction: () => { console.log('GridcolumnDefs call') }, }), }

3.CommonCodeRendererVue

  • 공통 코드 값을 텍스트로 변환해 그리드 셀에 표시하는 컴포넌트

{   cellRenderer: CommonCodeRendererVue, cellRendererParams: (params: ValueFormatterParams<any, any>) => ({ categoryId: 'category00053', codeId: 'code00001', codeItemId: params.value, }) }

ChmmGrid API

API 는 ChmmGrid 에서 제공하는 props, emit 등을 정의합니다.

ChmmGrid 는 AG-Grid 의 API 를 확장하지만, 본 문서에는 ChmmGrid 의 API 만 명시합니다.

Props

Name

Type

Required

Default

Description

Example

modeTypeApi

string

false

clientSide

모드 타입 설정

'clientSide' \| 'serverSide' \| 'hybrid'

pagination

boolean

false

false

페이지네이션 사용 여부

true \| false

rowData

Array

-

-

그리드 데이터 설정 옵션으로, selectAPI를 사용하지 않고, 직접 데이터 설정시 사용됨.

['code':"message",'message':"메시지"]

selectApi

string

false

-

조회 API URL 혹은 조회 함수. 함수인 경우, 반드시 응답객체의 data 를 반환해야함. 환경변수 NUXT_PUBLIC_API_BASE 의 값이 prefix 로 적용. 단 full path 를 필요시 'https' 로 시작하는 URL 입력 가능.

selectApi="/message/list"

selectParam

Object

false

-

조회 조건 객체

:selectParams="messageSearchRequestDto"

fetchOnReady

boolean

false

true

그리드 초기화 시 조회 여부

keyForSearchcode="searchcodecategory"

addButtonAddRow

boolean

false

false

[행 추가] 버튼 삽입 여부

true \| false

addButtonCopyRow

boolean

false

false

[행 복사] 버튼 삽입 여부

true \| false

addButtonDeleteRow

boolean

false

false

[행 삭제] 버튼 삽입 여부

true \| false

excelImportTarget

string

false

-

엑셀 업로드 API URL (환경변수 NUXT_PUBLIC_EXCEL_API_BASE의 값이 prefix로 적용됨. 단, full path 를 필요 시 'https'로 시작하는 URL 입력 가능)

message/upload

excelTemplateId

string

false

-

엑셀 양식 ID

excelTemplate001001

excelExportTarget

string

false

-

엑셀 다운로드 API URL (환경변수 NUXT_PUBLIC_EXCEL_API_BASE의 값이 prefix 로 적용. 단, full path 를 필요시 'https'로 시작하는 URL 입력 가능)

message/download

Emits

Name

Parameter

Description

dataFetched

Array \| undefined

데이터 조회 완료 후 발생

excelUploaded

string \| undefined

엑셀이 업로드 완료 후 발생

Slots

Name

Description

headerTooltip

그리드 추가 설명을 위한 아이콘 툴팁

textInfo

그리드 추가 안내문

beforeButton

그리드 버튼 왼쪽에 업무 버튼 추가 삽입

Exposes

Name

Description

fetchData

selectAPI로 등록한 API 호출

getPageInfo

페이지 정보 조회

getRows

그리드 행 데이터 조회

addRows

행 추가

copyRows

행 복사

deleteRows

행 삭제

clearRows

행 초기화

getSelectedRows

선택된 행 데이터 조회

getSelectedNodes

선택된 행 노드 조회

getChangedRows

변경된 행 데이터 조회

ChmmGridTree

트리 형태의 데이터를 로드하는 방식입니다.

정렬, 필터, 페이징은 불가합니다.

  • AgGrid 트리 그리드 주요 파라미터

파라미터명

설명

autoGroupColumnDef

트리 열 옆에 배치할 컬럼을 지정하여 전달 (트리 기능 활성화 후 autoGroupColumnDef를 설정하지 않으면 AG Grid가 자동으로 index로 그룹컬럼을 생성함)

columnDefs

autoGroupColumnDef 를 제외한 컬럼 리스트를 전달

rowData

children 자식 노드를 가진 트리 데이터

{ menuId: 'menu00000001', menuName: '자원관리', children: [{ menuId: 'menu00000003', menuName: '사용자관리' }] }

groupDefaultExpanded

-1이면 모두 펼친 상태로 로드됨

결과 & 전체 코드

admin_04_06_06
<template> <ChmmGridTree ref="treeRef" style="height: calc(100vh - 26.4rem); min-height: calc(100vh - 26.4rem); max-height: calc(100vh - 26.4rem);" :get-row-id="getRowId" :gridOptions="gridOptions" :auto-group-column-def="{ field: 'menuName', headerName: $t('multilanguage.grid.menuName'), tooltipField: 'menuName', minWidth: 170, cellRendererParams: { suppressCount: true }, sortable: false, flex: 1, }" :column-defs="treeColumnDefs" :row-data="treeValue" :group-default-expanded="-1" :row-selection="{ /* * AG-GRID 트리 rowSelection 옵션 * * mode : string (singleRow | multiRow ) : 하나만 Selection 가능 혹은 여러개 Selection 가능 여부 * checkboxes : boolean (true | false ) : Selection 을 위한 체크박스 생성 여부 * enableClickSelection : boolean (true | false ) : 사용자 클릭으로 Selection 여부 - false 면 체크박스를 눌러야만 Selection 이 됨 * headerCheckbox : boolean (true | false ) : 헤더에 SelectAll 을 위한 체크박스 여부 * groupSelects : string (self | descendants ) : 자식 노드까지 선택 여부 * checkboxLocation : string (selectionColumn | autoGroupColumn) : 체크박스 컬럼 신규 생성 혹은 autoGroupCloumn 으로 지정된 컬럼에 체크박스 생성 */ mode: 'multiRow', headerCheckbox: false, groupSelects: 'self', checkboxLocation: 'autoGroupColumn', }" @grid-ready="onTreeReady" @row-selected="toggleCheckbox" @row-clicked="treeValueSelectEvent" /> </template>

컴포넌트 > 공통코드

개요

시스템에서 사용하는 공통코드를 공통코드 컴포넌트를 통해서 쉽게 만들 수 있도록 지원한다.

사용방법

  • 공통코드 컴포넌트는 아래 3가지 타입을 지원한다.

    • dropdown (Dropdown)

    • radio (RadioButton Group)

    • checkbox (SelectButton)

  • 공통코드 컴포넌트는 공통코드 별 설정된 다국어 메시지로 표시한다.

  • props 정보는 아래와 같다.

    admin_04_05_01

예시

admin_04_05_02
  • dropdown 타입, radio 타입, checkbox 타입

코드

admin_04_05_03

컴포넌트 > V-Input

개요

텍스트 Input 박스에서 Validation 체크를 지원한다.

사용방법

  • validation Input 컴포넌트는 8가지의 패턴을 지원한다.

    • text (문자)

    • number (숫자)

    • email (이메일)

    • phone (휴대전화번호)

    • ip (IP)

    • bizRegister (사업자번호)

    • corpRegister (법인번호)

    • resident (주민등록번호)

  • min-length, max-length props 를 통해 문자와 숫자의 길이 체크를 할 수 있다.

  • required props 를 통해 필수여부를 설정할 수 있다.

  • props 정보는 아래와 같다.

    admin_04_06_01

예시

admin_04_06_02
  • 각 패턴 별 validation 체크

코드

admin_04_06_03
  • 패턴을 'text'로하고 최소길이를 5, 최대길이를 50, 필수여부를 'true'로 설정한 예제 코드

컴포넌트 > Error_Handler

개요

캐모마일 프레임워크에서는 FrontEnd 프레임워크로 Nuxt.js - 3.4.1 버전을 사용하였으며, Nuxt 에서 지원하는 errorHandling 을 바탕으로 에러처리를 하도록 개발환경을 구성하였다.

  1. 에러 페이지 처리

  2. 컴포넌트 에러 처리

  3. API 에러 처리

  4. 인증 권한 에러 처리

에러 페이지 처리

Nuxt 는 서버 생명 주기 동안 또는 Vue 애플리케이션(SSR 및 SPA 모두) 을 렌더링할 때 치명적인(fatal) 오류가 발생하면, JSON 응답(Accept: application/json 헤더로 요청한 경우) 또는 HTML 오류 페이지를 렌더링합니다.

소스 디렉터리에 app.vue 와 함께 ~/error.vue 를 추가하여 오류 페이지를 사용자 정의 할 수 있습니다.

error.vue 에서는 발생되는 에러에 따라 error.statusCode 를 감지하여 상태 별로 화면을 ** Redirect **하여 처리합니다.

오류 페이지 제거 시에는 Helper 함수 clearError 를 호출하여 Error 를 제거하고 정상 페이지로 전환합니다.

👉 Nuxt - Rending an Error Page (nuxt.com)

ErrorPage Handling Flow

  1. 사용자 요청 (페이지 이동)

  2. 서버 오류 발생

  3. error.vue 에서 error.statusCode 를 확인하여 에러 페이지로 이동

서버 오류 발생

statusCode : 403

statusCode : 404

statusCode : 500

사용자요청

error.vue

AccessDenied.vue

NotFound.vue

ServerError.vue

에러 페이지 목록

StatusCode

Component

Description

403

AccessDenied.vue

미들웨어에서 권한 없음 처리

404

NotFound.vue

라우터에 등록되지 않은 페이지 요청

500

ServerError.vue

서버 에러 (존재하지 않은 컴포넌트 사용, 서버사이드랜더링 오류 등)

error.vue ( src/error.vue )

<script lang="ts" setup> interface ErrorProps { error: { description?: string, message?: string, statusCode: string, statusMessage: string, url: string }; } const { error } = defineProps<ErrorProps>(); const component = computed(() => { if (parseInt(error.statusCode) === 403) { return defineAsyncComponent(() => import('~/components/layouts/error/AccessDenied.vue')); } return parseInt(error.statusCode) === 404 ? defineAsyncComponent(() => import('~/components/layouts/error/NotFound.vue')) : defineAsyncComponent(() => import('~/components/layouts/error/ServerError.vue')); }); definePageMeta({ layout: 'empty', title: 'Error' }); </script> <template> <div> <Head> <Title>{{ error.statusMessage }}</Title> </Head> <Component :is="component" :error="error" /> </div> </template>

컴포넌트 에러 처리

컴포넌트 에러처리는 랜더링 이후 Vue 컴포넌트 내부에서 개발자의 실수로 발생하는 에러 (Undefined 참조, 문법오류 등) 나 예외상황을 예측해서 던지는 에러 ( throw createError, throw new Error ) 에 대한 처리를 말한다.

  • 전역 애플리케이션 레벨에서 처리하는 방식

    • nuxtApp.vueApp.config.errorHandler 를 사용하여 선언하면 애플리케이션 전역에서 발생하는 모든 에러를 처리 (Promise 객체, 비동기처리 에러 제외)

    • Vue 애플리케이션 내부에서 에러가 발생하면 errorHandler 가 호출

    • 전역적인 에러처리 가능

    export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.config.errorHandler = (error: any, context: (globalThis.ComponentPublicInstance | null), info: string) => { console.error('[errorHandler]', error) // 에러 처리 } }
  • Vue 컴포넌트 레벨에서 처리하는 방식

    • 컴포넌트에서 errorCaptured 훅을 사용하여 에러를 캐치하고 처리

    • 에러가 발생한 컴포넌트에서 직접 에러를 처리할 수 있으며, 에러를 캐치하는 컴포넌트가 없으면 부모 컴포넌트로 에러가 전파

    • errorCaptured 를 사용해서 컴포넌트 레벨에서 에러 처리가 가능하고 에러처리 이후에 nuxtApp.vueApp.config.errorHandler 로 선언한 플러그인에서도 에러 처리 가능

    export default { errorCaptured(err, vm, info) { if (err) { console.error('Component Error:', err); // 에러를 캐치한 컴포넌트에서 에러를 처리하거나 부모 컴포넌트로 전파 } }, };
  • NuxtErrorBoundary

    Nuxt 는 전체 사이트를 오류 페이지로 바꾸지 않고도 앱 내에서 클라이언트 측 오류를 처리할 수 있는 <NuxtErrorBoundary> 컴포넌트를 제공합니다.

    <NuxtErrorBoundary> 로 자식 컴포넌트를 감싸면 자식 컴포넌트에서 발생되는 에러를 상위로 전달하지 않고 대체 페이지로 전환하여 에러에 대한 처리가 가능합니다.

    • @error : 컴포넌트에서 오류를 던질 때 이벤트 발생

    • \#error : 오류 발생 시 표시할 대체 컨텐츠를 지정

정상 화면

자식 컴포넌트에서 에러가 발생한 화면

admin_04_07_01
admin_04_07_02

errorPage.vue

<template> <h4>부모 컴포넌트 (errorPage.vue)</h4> <NuxtErrorBoundary > <errorChildComponent/> <template #error="{ error, clearError }"> <div> <h4>에러 발생</h4> <p>errorChildComponent 에서 에러가 발생했습니다!</p> <pre>{{ error }}</pre> <Button label="에러지우기" \@click="doClearError(error, clearError)"/> </div> </template> </NuxtErrorBoundary> </template> <script> import errorChildComponent from './errorPage/errorChildComponent.vue'; export default { components: { errorChildComponent }, methods: { doClearError(error, clearError) { error.value = null clearError() }, } }; </script>

errorChildComponent.vue

<template> <div> <h4>자식 컴포넌트 (errorChildComponent.vue) </h4> <Button @click="triggerError" label="에러 발생시키기" /> </div> </template> <script lang="ts"> import {defineComponent} from 'vue' export default defineComponent({ name: "errorChildComponent", methods: { triggerError() { const name = '캐모마일' name = 'New 캐모마일' } } }) </script>
  • 에러 발생

    Vue 컴포넌트 내부에서 발생할 수 있는 일반적인 에러 유형을 다음과 같이 나타낼 수 있다.

  • try/catch

    <script> 에서 발생할 수 있는 에러에 대해서 try/catch 로 감싸면 script 에러만 발생하고 catch 문에서 후속 에러 처리가 필요하며, 이 경우 errorCapturederrorHandler 로는 에러가 전달되지 않는다.

    에러유형 : ReferenceError, TypeError, SyntaxError, 무한 루프 및 스택 오버플로우

  • try/catch 처리

    try { const name = '캐모마일' name = 'New 캐모마일' // TypeError: Assignment to constant variable } catch(e) { console.error(e) // 에러 처리 }

    Result

    doTryCatch@ error.vue :74 <== error.vue 컴포넌트에서 에러 capture
    callWithErrorHandling @ chunk-3Q27KRJ5.js:213
    callWithAsyncErrorHandling @ chunk-3Q27KRJ5.js:221
    invoker @ chunk-MNWBZQKJ.js:322

  • try/catch 미처리

    const name = '캐모마일' name = 'New 캐모마일' // TypeError: Assignment to constant variable

    Result

    nuxtApp.vueApp.config.errorHandler@ error.ts :13 <== 전역 errorHandler 에서 에러 capture
    callWithErrorHandling @ chunk-3Q27KRJ5.js:213
    handleError @ chunk-3Q27KRJ5.js:254
    callWithErrorHandling @ chunk-3Q27KRJ5.js:215
    callWithAsyncErrorHandling @ chunk-3Q27KRJ5.js:221
    invoker @ chunk-MNWBZQKJ.js:322

  • throw createError Nuxt 의 헬퍼 메서드를 사용하여 에러 전달

    throw createError({ statusCode: 404, statusMessage: 'statusMessage', message: 'message' })

캐모마일 error.ts

어플리케이션에서 에러 발생시 전역적으로 필요한 처리가 있으면, errorHandler 에 추가적인 에러처리 작업이 필요합니다. 기본적으로 캐모마일의 errorHandler 에서는 에러 발생시 showAlert 를 사용하여 Dialog 로 에러메시지를 표시합니다. ( ※ 불필요시 제거 )

error.ts ( src/plugins/error.ts )

import {showAlert, showConfirm} from "~/utils/commonDialogUtil"; export default defineNuxtPlugin((nuxtApp) => { /** * 전역 애플리케이션 레벨에서 발생되는 에러 처리 * @param error * @param context * @param info * @description throw new Error, throw createError 발생이나 Component 상의 에러 발생시 * Promise 객체에서 발생되는 에러 확인 불가 */ nuxtApp.vueApp.config.errorHandler = (error: any, context: (globalThis.ComponentPublicInstance | null), info: string) => { console.error('vue:error ', error) showAlert(error.message, null, 'Error Message'); // 에러 발생시 공통 경고창으로 표시 } });

에러 메시지 다이얼로그

admin_04_07_03

API 에러 처리

Nuxt 에서 제공하는 useFetch 에 대한 API 에러 처리

  • onResponseError, onRequestError 에서 처리

<script lang="ts"> export default defineComponent({ methods: { async doApiError() { const { data, pending, error, refresh } = await useFetch('/api/auth/login', { onResponse({ request, response, options }) { // Process the response data localStorage.setItem('token', response._data.token) }, onResponseError({ request, response, options }) { // Handle the response errors console.log('[onResponseError]', response.status, response.statusText) }, }); }, }, }); </script>

인증 권한 에러 처리

error.global.ts ( src/middleware/error.global.ts )

  • Nuxt 프로젝트의 middleware 디렉토리에 defineNuxtRouteMiddleware 를 사용하여 선언

  • Nuxt.js에서 미들웨어는 라우팅 처리에 사용되는 기능으로, 페이지가 렌더링되기 전에 특정한 처리를 수행하고 싶을 때 유용하게 사용

  • 미들웨어는 라우트 전환 시점에 실행되며, 페이지 컴포넌트가 렌더링되기 전에 실행되는데, 이를 통해 인증, 권한 검사, 로깅 등과 같은 전역적인 작업을 처리할 수 있습니다.

export default defineNuxtRouteMiddleware ((to, from) => { if ('middleware' in to.query) { return showError('error in middleware') } })

Error Helper Methods

useError

  • function useError (): Ref<Error | { url, statusCode, statusMessage, message, description, data }>

이 함수는 처리 중인 전역 Nuxt 오류를 반환합니다.

👉 Docs > API > Composables > Use Error 에서 자세히 알아보세요 .

createError

  • function createError (err: { cause, data, message, name, stack, statusCode, statusMessage, fatal }): Error

이 기능을 사용하여 추가 메타데이터가 있는 오류 개체를 만들 수 있습니다. 앱의 Vue 및 Nitro 부분 모두에서 사용할 수 있으며 던져야 합니다.

createError 로 생성된 오류가 발생하는 경우 :

  • 서버 측에서는 clearError 로 지울 수 있는 전체 화면 오류 페이지를 트리거합니다.

  • 클라이언트 측에서는 처리할 치명적이지 않은 오류가 발생합니다. 전체 화면 오류 페이지를 트리거해야 하는 경우, fatal: true 를 설정하여 이를 수행할 수 있습니다 .

createError() 와 new Error()

fn name

createError()

new Error()

description

Nuxt.js 에서 제공하는 http-errors 라이브러리를 사용하여 간편하게 에러 객체 생성

JavaScript의 기본적인 에러 생성 방법으로 HTTP 상태코드 와 같은 추가적인 정보는 수동으로 설정

parameter

err: {
cause,
data,
message,
name,
stack,
statusCode,
statusMessage,
fatal
}

message?: string
options?: ErrorOptions

createError()

const error = throw createError({ statusCode: 404, statusMessage: 'Page Not Found !', message: '페이지를 찾을 수 없습니다.' }) console.log(error.statusCode); // 404 console.log(error.message); // "페이지를 찾을 수 없습니다."

new Error()

const error = new Error('예상치 못한 에러 발생'); console.log(error.message); // "예상치 못한 에러 발생"

showError

  • function showError (err: string | Error | { statusCode, statusMessage }): Error

이 함수는 클라이언트 측에서 또는 (서버 측에서) 미들웨어, 플러그인 또는 setup()기능 내에서 직접 호출할 수 있습니다. clearError 로 지울 수 있는 전체 화면 오류 페이지를 트리거합니다.

대신 throw createError() 를 사용하는 것이 좋습니다 .

👉Docs > API > Utils > Show Error 에서 자세히 알아보세요 .

컴포넌트 > CustomAPI

개요

useCustomFetch의 동작 방식을 설명한다. 어드민에서는 API를 호출하기 위해 Nuxt에 내장되어있는 useFetch를 사용 한다. useFetch는 useAsyncData와 $fetch를 감싼 Nuxt에서 제공하는 composable이다.

어드민에서는 useFetch를 한번 더 감싸서 useCustomFetch.ts를 composable로 등록하여 사용한다.

useCustomFetch 사용 이유

어드민에서 useFetch를 사용할 때 2개의 인자를 전달한다.

  • URL : Request RUL

  • Options : ofecth options + AsyncData options

어드민에서는 useFetch를 호출할 때마다 공통적으로 수행해야하는 로직이 존재하여 반복작업을 최소화 하기 위해서 useCustomFetch로 useFetch를 감싸서 사용한다.

공통로직은 useCustomFetch에 들어가 있지만, method구분을 위해서 아래와 같이 export하여 사용한다.

/** * useCustomFetch Get요청 * @param url API URL * @param params API 요청 파라미터 * @param options UseFetchOptions * @param errorAlert 오류 발생 시, alert 생성 유무 * @returns */ function useGetFetch(url: string, params?: any, options?: any, errorAlert?: boolean) { return useCustomFetch(url, 'GET', params, options, errorAlert); } function usePostFetch(url: string, params?: any, options?: any, errorAlert?: boolean) { return useCustomFetch(url, 'POST', params, options, errorAlert); } function usePutFetch(url: string, params?: any, options?: any, errorAlert?: boolean) { return useCustomFetch(url, 'PUT', params, options, errorAlert); } function useDeleteFetch(url: string, params?: any, options?: any, errorAlert?: boolean) { return useCustomFetch(url, 'DELETE', params, options, errorAlert); } export { useGetFetch, usePostFetch, usePutFetch, useDeleteFetch };

useCustomFetch 가 하는 일

  1. UseFetch Option 값 디폴트 세팅

const defaultFetchOptions: UseFetchOptions<T> = { // 1-1. baseURL, method, parameter 세팅 baseURL: config.public.apiBase, method, [method.toUpperCase() === 'GET' ? 'params' : 'body']: params, // 1-2. useFetch 응답을 처리하는 콜백함수 onResponse({ response }) { // 1-2-1. http 응답 상태코드가 200이 아니라면 return if (response.status / 10 !== 20) { return; } const contentType = response.headers.get('Content-Type'); // 1-2-2. 응답 헤더의 content-type이 'text/plain'이라면 JSON.parse() 처리 if (contentType?.includes('text/plain')) { try { response._data = JSON.parse(response._data); } catch(exception) { throw exception; } } }, // 1-3. useFecth 에러 발생 시, 실행되는 함수 onResponseError(response) { const { status, statusText, _data } = response.response; failHandler(status, _data.message, errorAlert); } };
  1. 권한 체크

const needAuth = !NO_AUTH_API.some((v: string) => url.includes(v)); // 2-1. 권한 체크가 필요한 API 요청인지 확인 if (needAuth) { const { accessToken, checkTokenTimeout, logUserOut } = useAuthStore(); // 2-2. 토큰 유효기간 확인 if (!checkTokenTimeout()) { logUserOut(); return {}; } // 2-3. 헤더에 토큰 추가 defaultFetchOptions.headers = { Authorization: `Bearer ${accessToken}` }; }
  1. 디폴트 세팅한 useFetch options과 인자로 받은 useFetch options을 merge

const mergedFetchOptions = defu(options, defaultFetchOptions);
  1. useFetch 호출

const { data, pending, error, status, refresh } = await useFetch(url, mergedFetchOptions);
  1. useFetch 호출 결과에 따른 분기

// 5-1. SSR시, 최초 useFetch가 pending되어 useFetch 재 호출 필요 if (pending.value) { return useCustomFetch(url, method, params, options, errorAlert); } // 5-2. useFetch 호출 결과가 성공이 아니라면 failHandler 호출 // (status type : 'idle' | 'pending' | 'success' | 'error') if (status.value !== 'success') { failHandler(error.value?.status, error.value?.message, errorAlert); } // 5-3. useFetch 호출 결과가 성공이라면, useFetch 응답 그대로 리턴 return { data, pending, error, status, refresh };

컴포넌트 > 다국어

개요

다국어를 적용하기 위한 개발 가이드를 제공한다. 어드민에서는 vue-i18n 플러그인을 사용하여, 다국어를 적용하였다.

  • 다국어를 적용하기 위해서는 key: message 형태의 값을 언어별로 가지고 있어야 한다.

다국어 설치 어드민에서는 npm을 이용하여 설치하였다.

※ vue3부터는 vue-i18n v9이상의 버전을 사용해야한다.

npm install vue-i18n@9

다국어 설정 plugins/i18n.ts 파일을 생성하여 다음과 같이 설정 하였다.

export default defineNuxtPlugin(async ({ vueApp }) => { // 1. 기본 다국어 메세지 파일을 조회 const defaultMessages: {[key: string]: { [key: string]: string }} = languageService.defaultMessages; // 2. i18n 옵션 세팅 const i18n = createI18n({ // 2-1. v8에서 제공하는 vue-i18n API legacy: false, // 2-2. i18n 프로퍼티와 함수를 각 컴포넌트에서 접근하게 할 지 여부 globalInjection: true, // 2-3. 기본 언어 설정 locale: "ko", // 2-4. 다국어 메세지 설정 (API를 통해 DB 다국어 메세지 조회) messages: await languageService.getLanguageMessageList(), // 2-5. i18n에 메세지가 없는 경우 실행되는 함수로, 1.번에서 조회한 파일에서 메세지를 다시 찾는다. missing: (locale, key): string => { if(defaultMessages[locale] && defaultMessages[locale][key]) { console.warn('[i18n]: Database에 메세지가 존재하지 않아, 기본 메세지 파일에서 조회합니다.', key, defaultMessages[locale][key]); return defaultMessages[locale][key] ?? key; } console.warn('[i18n]: 기본 메세지 파일에 메세지가 존재하지 않습니다.', key); return key; } }); vueApp.use(i18n); });

다국어 적용

  1. 다국어 적용

AS-IS <span>권한상하관계등록</span> TO-BE <span>{{ $t('menu.data.menu00000036') }}</span>
  1. 언어(locale) 변경

오른쪽 위의 국가를 선택하면 아래의 함수가 실행되어, 언어를 변경 한다.

admin_04_08_01

changeLanguage(event) { // i18n locale 변경 this.$i18n.locale = event.value.languageCode; },

admin_04_08_02
admin_04_08_03

  1. 다국어 적용

오른쪽 위의 국가를 선택하여 언어를 바꾸는 경우, 아래 코드가 실행되어 언어 설정 값을 변경 하게 된다.

async changeLanguage(locale: string) { const messages = await languageService.getLanguageMessageList({ searchLanguageCode: locale }) for (const locale in messages) this.setLocaleMessage(locale, messages[locale]) // i18n locale 변경 this.$i18n.locale = locale },

263x300
262x300

Last modified: 17 7월 2025