본문 바로가기
2024 회사 프로젝트

객체 안에 배열 안에 객체가 있는 데이터에.. 타입스크립트를 곁들인..2

by Kimjoy 2025. 2. 15.

2025.01.18 - [2024 회사 프로젝트] - 컴포넌트 분리하기

2025.02.14 - [2024 회사 프로젝트] - 객체 안에 배열 안에 객체가 있는 데이터에.. 타입스크립트를 곁들인..1에 이은

2번째 포스팅이다!

이로 인해 내가 얼마나 무지했는지를 알게되어 버렸다..!

 

우선 화면에서 서버그룹 이름과 서버그룹을 클릭했을 때 하위서버들을 표현하는 팝업까지는 연결이 되었고, 이제 데이터를 받아와서 데이터를 표현해 주는 것을 고민해야 했다.

📌 화면 구현 계획

  1. 타입스크립트 인터페이스 정의 → 데이터 구조 명확화
  2. store 정의 → 서버 상태 및 API 통신
  3. vue 파일 작성 → 서버 그룹의 상태값 표현 + 팝업 내 데이터 표현

1️⃣ 데이터 구조를 명확하게 표현하기 위한 타입스크립트 인터페이스 정의

      📝 ServerVO (각 서버의 개별 정보)

            각 서버 그룹에 속하는 서버 개별 정보를 담는 객체이다.

export default interface ServerVO {
  seq: number;
  status: boolean | string;
  date: string;
  server_info: {
    seq: number;
    name: string;
    type: string;
    server_address: string;
    check_interval_sec: number;
  };
}

 

      📝 ServerGroupVO (서버 그룹 정보)

            ServerVO를 기반으로, 서버 그룹(server1~server5)을 배열로 관리하는 객체이다.

import ServerVO from '@/types/ServerVO';
export default interface ServerGroup {
  server1: ServerVO[];
  server2: ServerVO[];
  server3: ServerVO[];
  server4: ServerVO[];
  server5: ServerVO[];
}

 

2️⃣ 서버와 통신할 Store 정의 (Pinia 사용)

위에서 정의한 ServerGroupVO와 ServerVO를 사용하여 서버 그룹의 상태와 하위 서버 리스트의 상태를 관리했다.

export const useServerStore = defineStore({
  id: 'useServerStore',
  state: () => ({
    /** 서버 그룹 상태 */
    server: {} as ServerGroupVO,
    /** 하위 서버 리스트 */
    serverDetail: {} as ServerVO,
  }),
  actions: {
  	// 서버 그룹 상태 조회
    async getServerStatus() {
      try {
        const res = await httpHelperV2()
          .get(API.SERVER);
        this.server = res.data.data;
      } catch (e) {
        console.error(e);
      }
    },
    // 특정 서버 그룹의 하위 서버 목록 조회
	async getDetailServerStatus(type: string) {
      try {
        const res = await httpHelperV2().get(`${API.SERVER}/${type}`);
        this.serverDetail = res.data.data.map(server => ({
          ...server,
          date: new Date(server.date).toLocaleString(), // 날짜 변환
          status: server.status ? "Success" : "Fail"
        }));
      } catch (e) {
        console.error(e);
      }
    },
  },

 

🚨 타입스크립트 오류 경험

  • server를 배열로 정의했는데(server : [] as serverGroupVO), 실제 API 응답은 단일 객체였다.
  • API 응답 구조를 정확히 이해하지 못해 데이터를 제대로 표현할 수 없었음.(각각의 서버 그룹을 단일 객체로 받는 구조였다.)
  • 객체와 배열 구조를 올바르게 파악하는 것이 중요함을 깨달았다.

3️⃣ Vue 파일 정의

store에서 server와 serverDetail의 값을 가지고 와서, 내가 원하는 대로 화면에 뿌려 보겠다.

그리고 2025.01.18 - [2024 회사 프로젝트] - 컴포넌트 분리하기 이전 글에서 언급했던 바와 같이,부모 컴포넌트에서 자식 컴포넌트의 함수를 호출해서 사용해야 하기 때문에defineExpose()를 이용했다.

<template>
	<div
    	v-for="(serverGroupItem, index) in serverGroups"
    	:key="index"
    	@click="openServerDetail(serverGroupItem.key)"
  	>
    	<h2>{{ serverGroupItem.title }}</h2>
 		<div>
            <span
              v-bind="getStatusProps(serverGroupItem.key)"
              v-text="getStatusProps(serverGroupItem.key).title"
            ></span>
            <q-icon v-bind="getStatusProps(serverGroupItem.key)" />
      	</div>
    </div>
</template>

<script setup lang="ts">
import serverDetail from "@/components/ServerDetail.vue";

const serverGroups = ref([
  { title: "server1", key: "server1" },
  { title: "server2", key: "server2" },
  { title: "server3", key: "server3" },
  { title: "server4", key: "server4" },
  { title: "server5", key: "server5" },
]);

const openServerDetail = (type: string) => {
  dialog.open({
    component: serverDetail,
    componentProps: { type },
  });
};

const serverStore = useServerStore();
const { server } = storeToRefs(serverStore);

const status = computed(() => {
  const server1 = server.value.server1 || [];
  const server2 = server.value.server2 || [];
  const server3 = server.value.server3 || [];
  const server4 = server.value.server4 || [];
  const server5 = server.value.server5 || [];
  return {
    server1,
    server2,
    server3,
    server4,
    server5,
  };
});

const getStatusProps = (key) => {
  const statusArray = status.value[key] || [];
  const hasError = statusArray.some((item) => item.status === false);

  if (hasError) {
    return {
      name: 'report',
      color: 'red',
      size: '24px',
      title: '장애',
    };
  } else {
    return {
      name: 'lock',
      color: 'primary',
      size: '24px',
      title: '정상',
    };
  }
};

const loadServerStatus = async () => {
  try {
    await serverStore.getServerStatus();
  } catch (e) {
    notify.error('서버 상태를 불러오는데 실패했습니다.');
  }
};

defineExpose({
  loadServerStatus,
});

</script>

 

 

 

 결과

  • 서버 그룹별로 상태를 확인할 수 있다.
  • 데이터 구조를 명확히 이해하고, 타입스크립트를 활용하여 오류를 방지

🔥 배운 점

  • 객체와 배열의 구조를 정확히 파악하는 것이 중요함!
  • 타입스크립트를 활용해 API 응답을 올바르게 정의해야 함!

📢 다음 포스팅에서는 서버 그룹을 클릭했을 때 하위 서버의 값을 제대로 가져오는지도 확인해 보겠다!!