Files
bio_frontend/README.md
2025-08-22 14:04:50 +09:00

301 lines
7.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# bio_frontend
## NUXT 3 (VUE 3) 환경
- data-list 와 dataList는 동일 변수명으로 인식
- compnenets 아래의 .vue는 자동 인식(template 내부에서만, 별도 script에서 필요시 선언 필요)
# 구성 요소
## components 구성
```
components
|- base // 기본 요소(button, input, grid, popup)
|- layout // 레이아웃 요소(header, footer, sidebar, wrapper)
|- module // 특정 기능 단위(card, form, list)
|- pages // 특정 페이지 전용
```
## page 구성
```
pages // 단일 화면(비 탭 요소)
|- popup // 팝업 요소
|- [tabId] // 탭 요소
|- admin // 관리자 페이지
```
# page(페이지) 생성 요소
## 공통 페이지 구성
```
<template>
<ContentsWrapper> <!-- wrapper(title) 추가 -->
<template #actions> <!--title 우측 버튼 설정-->
<button>추가</button>
<button>저장</button>
</template>
<!--메인 콘텐츠 영역-->
<input type="text" >
<!--메인 콘텐츠 영역-->
</ContentsWrapper>
</template>
<script setup lang="ts">
// title(wrapper) 설정
definePageMeta({
title: '리소스 관리'
})
</script>
```
## Toast(Tui) Grid 사용법
한글 설명: https://github.com/nhn/tui.grid/blob/master/packages/toast-ui.grid/docs/v4.0-migration-guide-kor.md
### 기본 설정
```
<template>
<button @click="onAddClick">추가</button>
<button @click="onUpdateClick">저장</button>
<!-- toast Grid 필수값 ref, data, columns(header) -->
<ToastGrid
ref="grid1Ref"
:data="data"
:columns="colDefs"
/>
</template>
<script setup lang="ts">
// 컬럼 항목 리스트
// composables폴더 아래에 생성
// 위 한글 성명 참조하여 생성
import {colDefs} from '../../composables/grids/resourceGrid'
// 데이터 항목
const data = [{}]
// ref 설정
// api : https://nhn.github.io/tui.grid/latest/Grid
const grid1Ref = ref();
onMounted(async () => {
await nextTick() // DOM 및 컴포넌트 렌더링 완료 대기
grid1Ref.value?.api()?.setBodyHeight('700') // ref api를 통해서 높이 지정
})
let no = 1;
// 항목 추가 버튼
function onAddClick() {
grid1Ref.value?.api()?.appendRow({'no': no}); // ref api를 통해서 항목 추가
++no;
}
// 저장 버튼
function onUpdateClick() {
//grid1Ref.value?.clearGrid();
const chageList = grid1Ref.value?.api()?.getModifiedRows(); // ref api를 통해서 변경점 읽어오기
console.log(changeList);
}
</script>
```
## tree data
```
<template>
<ToastGrid
ref="grid1Ref"
:data="data"
:columns="columns"
:treeColumnOptions="treeColumnOptions"
/>
</template>
<script setup lang="ts">
// data 설정시 _children: 항목으로 구성
const data = [
{
id: 549731,
name: 'Beautiful Lies',
price: 10000,
downloadCount: 1000,
listenCount: 5000,
_attributes: {
expanded: true,
},
_children: [
{
id: 491379,
name: 'Chaos And The Calm',
artist: 'James Bay',
grade: '5',
price: 12000,
downloadCount: 1000,
listenCount: 5000
},
{
id: 450720,
name: "I'm Not The Only One",
artist: 'Sam Smith',
release: '2014.09.15',
type: 'Single',
grade: '4',
price: 8000,
downloadCount: 1000,
listenCount: 5000,
_attributes: {
expanded: true,
},
_children: [
{
id: 587871,
name: 'This Is Acting',
artist: 'Sia',
release: '2016.10.22',
type: 'EP',
typeCode: '2',
genre: 'Pop',
_attributes: {
expanded: true,
},
_children: [
{
id: 490500,
name: 'Blue Skies',
release: '2015.03.18',
artist: 'Lenka',
type: 'Single',
typeCode: '3',
},
{
id: 317659,
name: "I Won't Give Up",
artist: 'Jason Mraz',
release: '2012.01.03',
type: 'Single',
typeCode: '3',
},
],
},
],
},
],
},
{
id: 436461,
name: 'X',
artist: 'Ed Sheeran',
release: '2014.06.24',
type: 'Deluxe',
typeCode: '1',
},
];
const columns = [
{ header: 'Name', name: 'name', width: 300 },
{ header: 'Artist', name: 'artist' },
{ header: 'Type', name: 'type' },
{ header: 'Release', name: 'release' },
{ header: 'Genre', name: 'genre' },
];
// tree column 설정
const treeColumnOptions = { name: 'name', useCascadingCheckbox: true };
const grid1Ref = ref();
</script>
```
## 팝업 구성
```
┌─────────────────────────────┐
│ customPopup.vue │
│ ┌─────────────────────────┐ │
│ │ poupWrapper.vue │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ <slot> │ │ │
│ │ └─────────────────────┘ │ │
│ └─────────────────────────┘ │
└─────────────────────────────┘
customPopup.vue - 기본 빈 팝업
poupWrapper.vue - top, middle, bottom으로 구성된 팝업 구조
1. 구조에 따라 customPopup, poupWrapper 기반으로 팝업 생성(/pages/popup/*.vue)
2. 사용할 페이지에서 생성한 팝업 추가
```
### 팝업 생성
```
// examplePopup.vue
<template>
<div>
<!--PopupWrapper 구성, 크기 지정, 숨김 여부 지정 -->
<PopupWrapper width="1000px" height="600px" v-model:show="show">
<template #top>
<h2>팝업 제목</h2>
</template>
<template #middle>
<!-- 팝업 본문 -->
</template>
<template #bottom>
<button>추가 버튼</button>
<!-- 닫기 버튼은 자동 생성 -->
</template>
</PopupWrapper>
</div>
</template>
<script setup lang="ts">
// 숨김 여부 지정
const show = defineModel('show', {type: Boolean, default:false});
</script>
```
### 팝업 사용
```
<template>
<button @click="popupShow = true">팝업 실행</button>
<examplePopup v-model:show="popupShow" />
</template>
<script setup lang="ts">
import addSamplePopup from '../popup/examplePopup.vue';
const popupShow = ref(false);
</script>
```
## 탭 구성
```
// layouts/default.vue
// stores/tab.ts
import { useTabsStore } from "../stores/tab";
const tabsStore = useTabsStore();
// 탭추가 (최대 10개)
tabsStore.addTab();
// 탭 갱신
tabsStore.updateActiveTab({ label, to, componentName});
// 탭 변경
tabsStore.setActiveTab(key);
// 탭 생성
<div
v-for="tab in tabsStore.tabs"
:key="tab.key"
class="tab-item"
:class="{ active: tabsStore.activeTab === tab.key }"
@click="tabsStore.setActiveTab(tab.key);"
>
{{ tab.label }}
<span v-show="tabsStore.activeTab !== tab.key" class="close-btn" @click.stop="tabsStore.removeTab(tab.key)"> × </span>
</div>
```