Vue3 기초 예제 프로젝트 구조 및 소스 정리
*관련 글이 점점 늘어나 하나로 통합하기 위함
*이 글에서만 싱크 맞춤
*주석 이외 설명 생략
*자세한 설명 생략
▷ 프로젝트 전체 구조
< 파일 따라가기 >
*순서대로 나열
▷ Cmp.vue
@import url('https://fonts.googleapis.com/css2?family=Gugi&display=swap');
* {
font-family: 'Gugi', sans-serif;
}
.HeaderCmp {
margin-bottom: 50px;
text-align: center;
color: #2c3e50;
}
.ForTestCmp {
text-align: left;
font-size: small;
font-weight: lighter;
color: #41b883;
}
.IfTestCmp {
text-align: left;
font-size: small;
font-weight: lighter;
color: olive;
}
.CompositionTestCmp {
text-align: left;
font-size: small;
font-weight: lighter;
color: chocolate;
}
.APICallTestCmp {
text-align: left;
font-size: small;
font-weight: lighter;
color: purple;
}
.MenuCmp {
text-align: left;
margin-left: 100px;
}
.dataTable {
border-collapse: collapse;
text-align: left;
}
.dataTable th {
width: 200px;
background: #f3f6f7;
font-weight: bold;
color: #369;
border-bottom: 3px solid #036;
}
.dataTable td {
padding: 5px;
border-bottom: 1px solid #ccc;
}
.modal{
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
position: fixed;
width: 400px;
text-align: center;
background: white;
border: 5px solid #036;
}
.modalContent {
text-align: left;
margin-left: 20px;
}
.chart {
height: 500px;
width: 60%;
}
a {
text-decoration: none;
color: black;
}
▷ HeaderCmp.vue
<style>
@import url('@/assets/css/Cmp.css');
</style>
<template>
<div>
<img style="width: 50px;" alt="Vue logo" src="@/assets/img/logo.png">
<h1>😀 Hello Vue 😀</h1>
</div>
</template>
▷ LoginCmp.vue
<template>
<div class="APICallTestCmp">
<h1>🏠 HOME</h1><br /><br />
<div class="login">
<h2>Login</h2>
<input v-model="id" placeholder="아이디">
<input v-model="pwd" placeholder="패스워드">
<button @click="call(id, pwd);">Login</button>
</div><br />
<div>
<h4>JWTStore : </h4>
<div style="width: 700px; height: 150px; overflow: auto;">
{{ useLoginStore().JWT }}
</div>
</div>
<div>
<h4>API Response : </h4>
<div style="width: 700px; height: 150px; overflow: auto;">
{{ result }}
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useLoginStore } from '@/module/store/LoginStore.js'
import { API_LIST, sendPost } from '@/module/AxiosModule'
const id = ref("admin")
const pwd = ref("admin")
const result = ref("")
async function call(id, pwd) {
const REQ_DATA = {
"id": id,
"pwd": pwd
}
/** 로그인 요청 */
const resVO = await sendPost(API_LIST['BHS-CMM-LGN'], REQ_DATA);
if (resVO.resultCode == "0000") {
/* JWT 저장 */
useLoginStore().setUser(resVO.jwt)
result.value = resVO.jwt
alert("로그인 완료")
}
}
</script>
▷ MenuCmp.vue
<template>
<div class="MenuCmp">
<div>
<h3><router-link to="/">🏠HOME</router-link></h3>
</div><br />
<div>
<h3>💡TEST</h3>
<h5><router-link to="/1">▷ IF</router-link></h5>
<h5><router-link to="/2">▷ FOR</router-link></h5>
<h5><router-link to="/3">▷ Composition</router-link></h5>
</div><br />
<div>
<h3>👨💻 API</h3>
<h5><router-link to="/4">▷ 공간 코드 관리</router-link></h5>
<h5><router-link to="/5">▷ 컨텐츠 코드 관리</router-link></h5>
<h5><router-link to="/6">▷ 꽃한송이</router-link></h5>
</div>
</div>
</template>
▷ A01C01.vue
<template>
<div>
<h1>🌼 꽃한송이</h1><br />
</div>
<div>
<div>
<h6 style="color: red;">*원하는 조회기간을 선택하여 검색해주세요</h6>
<VDatePicker v-model.range="inputDate" mode="date" style="width: 60%;" /><br /><br />
<button @click="getSSC1001(); getSPC1001();" style="width: 60%; font-size: medium;">🔍조회</button>
</div><br /><br />
<div v-if="state">
<h5> [ 방문 추이 ]</h5>
<v-chart class="chart" :option="peopleCnt" />
</div><br /><br />
<div v-if="state">
<h5> [ 연령대 비중 ]</h5>
<h6 style="color: red;">*연령대 박스를 선택하여 필터링할 수 있습니다.</h6>
<v-chart class="chart" :option="ageRatio" />
</div><br /><br />
<div v-if="state">
<h5> [ 성별 비중 ]</h5>
<h6 style="color: red;">*성별 박스를 선택하여 필터링할 수 있습니다.</h6>
<v-chart class="chart" :option="genderRatio" />
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useLoginStore } from '@/module/store/LoginStore.js'
import { API_LIST, sendPost } from '@/module/AxiosModule.js'
import * as cmmUtil from "@/module/CmmUtil.js";
import VChart from 'vue-echarts'
onMounted(() => {
/** 로그인 체크 */
useLoginStore().checkUser()
})
const state = ref(false)
const ageList = [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90 ];
const inputDate = ref({ start: new Date(), end: new Date() });
/** Pie Chart 생성 */
const ageRatio = ref({
legend: {
top: "top",
},
tooltip: {
trigger: "item",
formatter: "{b} : {c} ({d}%)",
},
series: [
{
name: "AgeRatio",
type: "pie",
radius: [40, 150],
roseType: "area",
itemStyle: {
borderRadius: 8
},
data: []
},
]
});
/** Bar Chart 생성 */
const genderRatio = ref({
legend: {
top: "top",
},
tooltip: {
trigger: "item",
formatter: "{a} : {c}",
},
xAxis: {
name: "연령대",
data: []
},
yAxis: {
name: "방문객 수"
},
series: [
{
name: "MALE",
type: 'bar',
stack: 'x',
data: []
},
{
name: "FEMALE",
type: 'bar',
stack: 'x',
data: []
},
{
name: "UNCLASSIFIED",
type: 'bar',
stack: 'x',
data: []
}
]
});
/** Line Chart 생성 */
const peopleCnt = ref({
xAxis: {
name: "방문 날짜",
data: []
},
yAxis: {
name: "방문객 수"
},
tooltip: {
trigger: "item",
formatter: "{b} : {c}",
},
series: [
{
type: 'line',
smooth: true,
data: [],
}
]
});
/** 연령대/성별 비중 데이터 생성 */
async function getSSC1001() {
/* 요청 값 설정 */
const REQ_DATA = {
"areaCd": [
"A01" // 공간코드 고정
],
"contentsCd": [
"C01" // 컨텐츠코드 고정
],
"ages": ageList,
"startDate": cmmUtil.getFormatDate(inputDate.value.start),
"endDate": cmmUtil.getFormatDate(inputDate.value.end)
}
/* 방문객 스캔 특정 기간 통계 조회 요청 */
const resVO = await sendPost(API_LIST["BHS-SSC-1001"], REQ_DATA)
if (resVO.resultCode == "0000") {
const ageRatioList = [] // 연령대 비중 데이터 리스트
const maleRatioList = [] // 성별(MALE) 비중 데이터 리스트
const femaleRatioList = [] // 성별(FEMALE) 비중 데이터 리스트
const unclassifiedRatioList = [] // 성별(UNCLASSIFIED) 비중 데이터 리스트
/* Pie Chart Data + Bar Chart Data*/
for (const ages of ageList) {
const ageRatioResult = { name: ages, value: 0 }
const maleRatioResult = { value: 0 }
const femaleRatioResult = { value: 0 }
const unclassifiedRatioResult = { value: 0 }
for (const data of resVO.result) {
if (ages == data.visitorAges) {
ageRatioResult.value += data.visitorAgesCnt
maleRatioResult.value += data.visitorMlCnt
femaleRatioResult.value += data.visitorFmlCnt
unclassifiedRatioResult.value += data.visitorUncCnt
}
}
ageRatioList.push(ageRatioResult)
maleRatioList.push(maleRatioResult)
femaleRatioList.push(femaleRatioResult)
unclassifiedRatioList.push(unclassifiedRatioResult)
}
ageRatio.value.series[0].data = ageRatioList
genderRatio.value.xAxis.data = ageList
genderRatio.value.series[0].data = maleRatioList // MALE
genderRatio.value.series[1].data = femaleRatioList // FEMALE
genderRatio.value.series[2].data = unclassifiedRatioList // UNCLASSIFIED
state.value = true
} else {
state.value = false
}
}
/** 방문 추이 데이터 생성 */
async function getSPC1001() {
/* 요청 값 설정 */
const REQ_DATA = {
"areaCd": [
"A01" // 공간코드 고정
],
"contentsCd": [
"C01" // 컨텐츠코드 고정
],
"ages": ageList,
"startDate": cmmUtil.getFormatDate(inputDate.value.start),
"endDate": cmmUtil.getFormatDate(inputDate.value.end)
}
/* 방문객 카운터 특정 기간 통계 조회 */
const resVO = await sendPost(API_LIST["BHS-SPC-1001"], REQ_DATA)
if (resVO.resultCode == "0000") {
const rangeDateList = cmmUtil.getDatesStartToLast(inputDate.value.start, inputDate.value.end);
const accumCntList = [] // 방문 추이 데이터 리스트
/* Line Chart Data*/
for (const date of rangeDateList) {
const accumCntResult = { value: 0 }
for (const data of resVO.result) {
if (date == data.cntDates) {
accumCntResult.value += data.accumCnt
}
}
accumCntList.push(accumCntResult)
}
peopleCnt.value.xAxis.data = rangeDateList
peopleCnt.value.series[0].data = accumCntList
state.value = true
} else {
state.value = false
}
}
</script>
▷ ACM.vue
<template>
<div>
<h1>👤 공간 코드 관리</h1><br />
<div>
<h3>공간 코드 추가</h3>
<input v-model="inAreaCd" placeholder="공간코드(A00)">
<input v-model="inAreaNm" placeholder="공간이름">
<button @click="areaMerge('INSERT', inAreaCd, inAreaNm);">추가</button>
</div><br /><br />
<div style="width: 50%;">
<h3>공간코드</h3>
<table class="dataTable">
<th>NO</th>
<th>공간 코드</th>
<th>공간 이름</th>
<th>관리</th>
<tr v-for="(obj, i) in areaList" :key="obj">
<td> {{ i + 1 }} </td>
<td>{{ obj.areaCd }}</td>
<td>{{ obj.areaNm }}</td>
<td @click="openModal(obj.areaCd, obj.areaNm)">🔍 수정/삭제</td>
</tr>
</table>
</div>
</div>
<!-- modal -->
<div class="modal" v-if="modalState">
<h2>공간 코드 수정/삭제</h2><br />
<div class="modalContent">
<h4>공간 코드 : </h4>
<h1>{{ modalAreaCd }}</h1><br />
<h4>공간 이름 : </h4>
<p><input style="font-size:30px" v-model="modalAreaNm" placeholder="공간이름"></p>
<br />
</div><br /><br />
<div>
<button style="font-size: 30px;" @click="areaMerge('UPDATE', modalAreaCd, modalAreaNm)">👨🔧(수정)</button>
<button style="font-size: 30px; margin-left: 10px;" @click="areaDelete(modalAreaCd)">🧺(삭제)</button>
</div><br />
<div>
<h4 @click="colseModal()">❌(닫기)</h4>
</div>
</div>
<!-- /modal -->
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useLoginStore } from '@/module/store/LoginStore.js'
import { API_LIST, sendPost } from '@/module/AxiosModule'
onMounted(() => {
/** 로그인 체크 */
if (useLoginStore().checkUser()) {
/** 공간 코드 테이블 초기화 */
areaInit()
}
})
const areaList = ref([])
const inAreaCd = ref("")
const inAreaNm = ref("")
const modalState = ref(false)
const modalAreaCd = ref("")
const modalAreaNm = ref("")
/** modal open */
function openModal(areaCd, areaNm) {
modalState.value = true
modalAreaCd.value = areaCd
modalAreaNm.value = areaNm
}
/** modal close */
function colseModal() {
modalState.value = false
}
/** 공간 코드 테이블 초기화 */
async function areaInit() {
inAreaCd.value = ""
inAreaNm.value = ""
/* 공간 코드 전체 조회 요청 */
const resVO = await sendPost(API_LIST['BHS-ACM-1001'], {})
if (resVO.resultCode == "0000") {
areaList.value = resVO.result.sort((a, b) => a.areaCd.localeCompare(b.areaCd))
}
}
/** 공간 코드 추가/수정 */
async function areaMerge(action, areaCd, areaNm) {
/* 입력 값 확인 */
if (areaCd == "" || areaNm == "") {
alert("입력 값을 확인 해주세요.")
return
}
if (action == "INSERT") {
for (const data of areaList.value) {
if (data.areaCd == areaCd) {
alert("공간코드 중복입니다. 다시 입력해주세요.")
return
}
}
}
/* 요청 값 설정 */
const REQ_DATA = {
"areaCd": areaCd,
"areaNm": areaNm
}
/* 공간 코드 추가/수정 요청 */
const resVO = await sendPost(API_LIST['BHS-ACM-1003'], REQ_DATA)
if (resVO.resultCode == "0000") {
action == "INSERT" ? alert("공간 코드 추가 완료 됐습니다.") : alert("공간 코드 수정 완료 됐습니다.")
/** modal close */
colseModal()
/** 공간 코드 테이블 초기화 */
areaInit()
}
}
/** 공간 코드 삭제 */
async function areaDelete(areaCd) {
/* 요청 값 설정 */
const REQ_DATA = {
"areaCd": areaCd
}
/* 공간 코드 삭제 요청 */
const resVO = await sendPost(API_LIST['BHS-ACM-1004'], REQ_DATA)
if (resVO.resultCode == "0000") {
alert("공간 코드 삭제 완료 됐습니다.")
/** modal close */
colseModal()
/** 공간 코드 테이블 초기화 */
areaInit()
}
}
</script>
▷ CCM.vue
<template>
<div>
<h1>👤 컨텐츠 코드 관리</h1><br />
<div>
<h3>컨텐츠 코드 추가</h3>
<input v-model="inAreaCd" placeholder="공간코드(A00)">
<input v-model="inContentsCd" placeholder="컨텐츠코드(C00)">
<input v-model="inContentsNm" placeholder="컨텐츠이름">
<button @click="contentsMerge('INSERT', inAreaCd, inContentsCd, inContentsNm);">추가</button>
</div><br /><br />
<div style="width: 50%;">
<h3>컨텐츠코드</h3>
<DataTable
:value="ContentsList"
:rows="5"
:rowsPerPageOptions="[5, 10, 20, 50]"
paginator
selectionMode="single"
@row-select="openModal"
>
<Column header="공간 코드" field="areaCd" sortable />
<Column header="컨텐츠 코드" field="contentsCd" sortable />
<Column header="컨텐츠 이름" field="contentsNm" sortable />
</DataTable>
</div>
</div>
<!-- modal -->
<div class="modal" v-if="modalState">
<h2>컨텐츠 코드 수정/삭제</h2><br />
<div class="modalContent">
<h4>공간 코드 : </h4>
<h1>{{ modalAreaCd }}</h1><br />
<h4>컨텐츠 코드 : </h4>
<h1>{{ modalContentsCd }}</h1><br />
<h4>컨텐츠 이름 : </h4>
<p><input style="font-size:30px" v-model="modalContentsNm" placeholder="컨텐츠이름"></p>
<br />
</div><br /><br />
<div>
<button style="font-size: 30px;"
@click="contentsMerge('UPDATE', modalAreaCd, modalContentsCd, modalContentsNm)">👨🔧(수정)</button>
<button style="font-size: 30px; margin-left: 10px;"
@click="areaDelete(modalAreaCd, modalContentsCd)">🧺(삭제)</button>
</div><br />
<div>
<h4 @click="colseModal()">❌(닫기)</h4>
</div>
</div>
<!-- /modal -->
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useLoginStore } from '@/module/store/LoginStore.js'
import { API_LIST, sendPost } from '@/module/AxiosModule'
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
onMounted(() => {
/** 로그인 체크 */
if (useLoginStore().checkUser()) {
/** 컨텐츠 코드 테이블 초기화 */
areaInit()
}
})
const ContentsList = ref([])
const inAreaCd = ref("")
const inContentsCd = ref("")
const inContentsNm = ref("")
const modalState = ref(false)
const modalAreaCd = ref("")
const modalContentsCd = ref("")
const modalContentsNm = ref("")
/** modal open */
function openModal(row) {
modalState.value = true
modalAreaCd.value = row.data.areaCd
modalContentsCd.value = row.data.contentsCd
modalContentsNm.value = row.data.contentsNm
}
/** modal close */
function colseModal() {
modalState.value = false
}
/** 컨텐츠 코드 테이블 초기화 */
async function areaInit() {
inAreaCd.value = ""
inContentsCd.value = ""
inContentsNm.value = ""
/* 컨텐츠 코드 전체 조회 요청 */
const resVO = await sendPost(API_LIST['BHS-CCM-1001'], {})
if (resVO.resultCode == "0000") {
ContentsList.value = resVO.result.sort((a, b) => a.areaCd.localeCompare(b.areaCd))
}
}
/** 컨텐츠 코드 추가/수정 */
async function contentsMerge(action, areaCd, contentsCd, contentsNm) {
/* 입력 값 확인 */
if (areaCd == "" || contentsCd == "" || contentsNm == "") {
alert("입력 값을 확인 해주세요.")
return
}
if (action == "INSERT") {
for (const data of ContentsList.value) {
if (data.contentsCd == contentsCd) {
alert("컨텐츠코드 중복입니다. 다시 입력해주세요.")
return
}
}
}
/* 요청 값 설정 */
const REQ_DATA = {
"areaCd": areaCd,
"contentsCd": contentsCd,
"contentsNm": contentsNm
}
/* 컨텐츠 코드 추가/수정 요청 */
const resVO = await sendPost(API_LIST['BHS-CCM-1003'], REQ_DATA)
if (resVO.resultCode == "0000") {
action == "INSERT" ? alert("컨텐츠 코드 추가 완료 됐습니다.") : alert("컨텐츠 코드 수정 완료 됐습니다.")
/** modal close */
colseModal()
/** 컨텐츠 코드 테이블 초기화 */
areaInit()
}
}
/** 컨텐츠 코드 삭제 */
async function areaDelete(areaCd, contentsCd) {
/* 요청 값 설정 */
const REQ_DATA = {
"areaCd": areaCd,
"contentsCd": contentsCd
}
/* 컨텐츠 코드 삭제 요청 */
const resVO = await sendPost(API_LIST['BHS-CCM-1004'], REQ_DATA)
if (resVO.resultCode == "0000") {
alert("컨텐츠 코드 삭제 완료 됐습니다.")
/** modal close */
colseModal()
/** 컨텐츠 코드 테이블 초기화 */
areaInit()
}
}
</script>
▷ CompositionTestCmp.vue
<template>
<div class="CompositionTestCmp">
<h1>👨🏫 Composition Example</h1><br /><br />
<button @click="initTest();">초기화</button>
<div>
<h4> 입력 :
<input v-model="inData" @keyup.enter="addList(inData);" placeholder="아무거나 입력해주세요.">
</h4>
</div>
<div>
<h4> 선택 :
<select v-model="select">
<option value="-" selected>선택해주세요.</option>
<option v-for="(item, i) in list" :key="i" :value="item">{{ item }}</option>
</select>
</h4>
</div>
<div>
<h4> 확인 :
{{ select }}
</h4>
</div>
<div>
<h4> 리스트 현황</h4>
<div v-for="(item, i) in list" :key="item">
{{ i }} → {{ item }}
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useLoginStore } from '@/module/store/LoginStore.js'
/** 로그인 체크 */
onMounted(() => {
useLoginStore().checkUser()
})
let inData = ref("");
let list = ref([]);
let select = ref("-");
/** 리스트 값 추가 */
function addList(data) {
if (data == "" || data == null) {
alert("입력 값이 없습니다.");
} else {
list.value.push(data);
inData.value = "";
}
}
/** 초기화 */
function initTest() {
inData.value = "";
list.value = [];
select = "-";
}
</script>
▷ ForTestCmp.vue
<template>
<div class="ForTestCmp">
<h1>👨🏫 For Test </h1><br />
<h4>리스트</h4>
<div>{{ list }}</div>
<h4>리스트 값</h4>
<div v-for="(obj, i) in list" :key="obj">
{{ i }} → {{ obj }}
</div>
</div>
</template>
<script>
import { useLoginStore } from '@/module/store/LoginStore.js'
export default {
data: () => {
return {
list:
[
{ id: '001', message: 'Hello For' },
{ id: '002', message: 'Hello Test' },
{ id: '003', message: 'Hello World' }
]
}
},
/** 로그인 체크 */
mounted() { useLoginStore().checkUser() }
}
</script>
▷ IfTestCmp.vue
<template>
<div class="IfTestCmp">
<h1>👨🏫 If Test </h1><br />
<h4>리스트</h4>
<div>{{ list }}</div>
<h4>리스트 값</h4>
<div v-for="(obj, i) in list" :key="obj">
<div v-if="obj.id == '001'">
{{ i }} → {{ obj }}
</div>
<div v-else>
{{ i }} → None
</div>
</div>
</div>
</template>
<script>
import { useLoginStore } from '@/module/store/LoginStore.js'
export default {
data: () => {
return {
list:
[
{ id: '001', message: 'Hello If' },
{ id: '002', message: 'Hello Test' },
{ id: '003', message: 'Hello World' }
]
}
},
/** 로그인 체크 */
mounted() { useLoginStore().checkUser() }
}
</script>
▷ MenuNav.js
import { createRouter, createWebHistory } from 'vue-router'
// 연결 컴포넌트
import ForTestCmp from '@/components/test/ForTestCmp.vue'
import IfTestCmp from '@/components/test/IfTestCmp.vue'
import CompositionTestCmp from '@/components/test/CompositionTestCmp.vue'
import LoginCmp from '@/components/common/LoginCmp.vue'
import ACM from '@/components/service/ACM.vue'
import CCM from '@/components/service/CCM.vue'
import A01C01 from '@/components/service/A01C01.vue'
// 라우터 설계
const routes = [
{ path: '/', component: LoginCmp },
{ path: '/1', component: IfTestCmp },
{ path: '/2', component: ForTestCmp },
{ path: '/3', component: CompositionTestCmp },
{ path: '/4', component: ACM },
{ path: '/5', component: CCM },
{ path: '/6', component: A01C01 }
]
// 라우터 생성
const router = createRouter({
history: createWebHistory(),
routes
});
// 라우터 추출 (main.js에서 import)
export { router }
▷ LoginStore.js
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { router } from '@/module/router/MenuNav.js'
const useLoginStore = defineStore(
"LoginStore",
() => {
/** 인증토큰 */
const JWT = ref("")
/** SET */
function setUser(jwt) { JWT.value = jwt }
/** 로그인 체크 */
function checkUser() {
if (JWT.value == "") {
alert("로그인 후 이용해주세요.")
router.push({ path: "/" })
return false
}
return true
}
return { JWT, setUser, checkUser }
}
)
export { useLoginStore }
▷ AxiosModule.js
import Axios from "axios"
import { useLoginStore } from '@/module/store/LoginStore.js'
import { router } from '@/module/router/MenuNav.js'
const API_LIST = {
/** CMM */
/** 로그인 */
"BHS-CMM-LGN": "/bhs/cmm/login.do",
/** ACM */
/** 공간 코드 전체 조회 */
"BHS-ACM-1001": "/bhs/acm/acm1001.do",
/** 공간 코드 조회 */
"BHS-ACM-1002": "/bhs/acm/acm1002.do",
/** 공간 코드 추가/수정 */
"BHS-ACM-1003": "/bhs/acm/acm1003.do",
/** 공간 코드 삭제 */
"BHS-ACM-1004": "/bhs/acm/acm1004.do",
/** CCM */
/** 컨텐츠 코드 전체 조회 */
"BHS-CCM-1001": "/bhs/ccm/ccm1001.do",
/** 컨텐츠 코드 조회 */
"BHS-CCM-1002": "/bhs/ccm/ccm1002.do",
/** 컨텐츠 코드 추가/수정 */
"BHS-CCM-1003": "/bhs/ccm/ccm1003.do",
/** 컨텐츠 코드 삭제 */
"BHS-CCM-1004": "/bhs/ccm/ccm1004.do",
/** SSC */
/** 방문객 스캔 특정 기간 통계 조회 */
"BHS-SSC-1001": "/bhs/ssc/ssc1001.do",
/** SPC */
/** 방문객 카운터 특정 기간 통계 조회 */
"BHS-SPC-1001": "/bhs/spc/spc1001.do",
}
const API_SERVER = "http://192.168.100.10:1010";
function sendPost(API_URI, REQ_DATA) {
return Axios
.post(API_SERVER + API_URI, REQ_DATA,
{
headers: {
"Authorization": useLoginStore().JWT
}
})
.then((res) => {
if (res.data.resultCode == "0000") {
return res.data
}
if (res.data.resultCode == "9005" || res.data.resultCode == "9006") {
return router.push({ path: "/" }), alert("다시 로그인 해주세요."), res.data
}
if (!res.data.resultCode == "0000") {
return alert(res.data.resultMsg), res.data
}
})
.catch((res) => {
alert("잠시 후 다시 시도해주세요.")
return res.response.status
})
}
export {
API_LIST,
sendPost
}
▷ CmmUtil.js
/**
* Date Formater
*
* @param {*} date
* @returns YYYYMMdd
*/
function getFormatDate(date) {
const YYYY = String(date.getFullYear())
const MM = String((date.getMonth() + 1) >= 10 ? (date.getMonth() + 1) : "0" + (date.getMonth() + 1))
const dd = String(date.getDate() >= 10 ? date.getDate() : "0" + date.getDate())
return YYYY + MM + dd
}
/**
* Date Formater2
*
* @param {*} date
* @returns YYYY-MM-dd
*/
function getFormatDate2(date) {
const YYYY = String(date.getFullYear())
const MM = String((date.getMonth() + 1) >= 10 ? (date.getMonth() + 1) : "0" + (date.getMonth() + 1))
const dd = String(date.getDate() >= 10 ? date.getDate() : "0" + date.getDate())
return YYYY + "-" + MM + "-" + dd
}
/**
* Start to Last Date
* @param {*} startDate(Date)
* @param {*} lastDate(Date)
* @returns YYYY-MM-dd
*/
function getDatesStartToLast(startDate, lastDate) {
if (!(startDate instanceof Date && lastDate instanceof Date)) return "Not Date Object";
var result = [];
var curDate = startDate;
while (curDate <= lastDate) {
result.push(getFormatDate2(curDate));
curDate.setDate(curDate.getDate() + 1);
}
return result;
}
export {
getFormatDate,
getFormatDate2,
getDatesStartToLast,
}
▷ App.vue
<template>
<div class="HeaderCmp">
<HeaderCmp />
</div>
<div style="display: flex;">
<div style="flex: 1;">
<MenuCmp />
</div>
<div style="flex: 2;">
<router-view />
</div>
</div>
</template>
<script>
import HeaderCmp from '@/components/common/HeaderCmp.vue'
import MenuCmp from '@/components/common/MenuCmp.vue'
export default {
components: {
HeaderCmp,
MenuCmp
}
}
</script>
▷ main.js
/** Vue */
import { createApp } from 'vue'
import App from './App.vue'
/** Router */
import { router } from '@/module/router/MenuNav.js'
import { createPinia } from 'pinia'
/**Prime : 테이블 라이브러리 */
import PrimeVue from 'primevue/config';
import 'primevue/resources/themes/lara-light-teal/theme.css'
/** ECharts : 챠트 라이브러리 */
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart, BarChart, LineChart } from 'echarts/charts'
import { TooltipComponent, LegendComponent, GridComponent } from 'echarts/components';
import { use } from 'echarts/core'
use([CanvasRenderer, PieChart, BarChart, LineChart, TooltipComponent, LegendComponent, GridComponent])
/** Vcalendar : 달력 라이브러리 */
import VCalendar from 'v-calendar';
import 'v-calendar/style.css';
/** Vue Appicaiotn Setting */
createApp(App)
/** 모듈 사용 등록 */
.use(router)
.use(createPinia())
/** 라이브러리 사용 등록 */
.use(PrimeVue)
.use(VCalendar, {})
/** 연결 */
.mount('#app')
▷ 관련 글
Vue 설치 방법
▷ Vue 설치 방법 ① Node 설치 ② vue-cli 설치(-g) ① Node 설치 💡node -v 💡npm -v ② vue-cli 설치(global) *vue-cli : Vue 프로젝트를 빠르게 구성, build, Deploy 할 수 있게 도와주는 도구 💡npm install -g @vue/cli
coding-today.tistory.com
Vue3 Project 생성 및 실행
Vue3 Project 생성 후 실행 시켜 확인하고 간단한 태그 추가 후 변경된 내용 확인 *Vue.js 관련 개념 설명은 아래 참고 *VScode 사용 *자세한 설명 생략 ▷ Vue3 Project 생성 및 실행 ① Vue Workspace folder 생성
coding-today.tistory.com
Vue-CLI Project 기본 구조
vue-cli로 생성된 Project의 기본 디렉터리 구조 파악 *자세한 설명 생략 ▷ vue-cli Project 기본 구조 ▷ 관련 글 Vue3 Project 생성 및 실행 Vue3 Project 생성 후 실행 시켜 확인하고 간단한 태그 추가 후 변경
coding-today.tistory.com
Vue 기초 예제 - Directive(조건/반복)
Vue Directive에 대한 간단한 설명과 Vue 기본 구조 파악 및 기초 예제 *자세한 설명 생략 ▷ Vue Directive 란? *Vue에서 기본으로 제공되는 Directive List는 아래 링크 참고 - HTML 태그 안에 v- 접두사를 가지
coding-today.tistory.com
Composition API란?
Component의 로직을 유연하게 구성할 수 있도록 하는 함수 기반의 API *자세한 설명 생략 ▷ Composition API란? - Vue Component를 구성하는 데 사용 - Vue3에서 새로 추가된 함수 기반의 API *Vue3에 내장 - Options
coding-today.tistory.com
Vue3 <script setup> 이란?
Vue3 Composition API를 이용하는 두가지 방식 *자세한 설명 생략 ▷ setup() ▷ - 싱글 파일 컴포넌트(SRC) 내에서 Composition API를 사용하기 위한 문법 - SFC와 Composition API를 사용하는 경우 을 사용하라고 권
coding-today.tistory.com
Vue3 기초 예제 - Dynamic Select Box
화면에서 입력받은 값으로 Dynamic Select Box를 생성하는 기초 예제 *아래 예제는 전 예제에 이어서 진행(아래 링크 참고) *자세한 설명 생략 ▷ 기초 예제 - Dynamic Select Box 생성 *Event Handling 관련 아래
coding-today.tistory.com
Vue3 기초 예제 - Router(메뉴 네비게이션)
Vue Router 간단한 설명과 메뉴 네비게이션을 생성하는 기초 예제 *자세한 설명 생략 ▷ Vue Router란? 페이지 간에 이동하는 기능을 구현할 때 사용하는 Vue 라이브러리 ▷ Vue Router 설치 *vue-cli를 통해
coding-today.tistory.com
Vue3 기초 예제 - HTTP 통신(Axios)
Axios 간단한 설명과 API 통신 결과를 화면으로 보내는 기초 예제 *자세한 설명 생략 ▷ Axios 란? - Vue에서 권고하는 Promise 기반의 HTTP 라이브러리 *Promise : 비동기 처리 - 서버와 HTTP 통신 - Ajax, fetch와
coding-today.tistory.com
Vue3 기초 예제 - 로그인(pinia)
Pinia 간단한 설명과 로그인 기초 예제 *자세한 설명 생략 ▷ Pinia 란? *Store 관련 자세한 설명 아래 링크 참고 - 모든 컴포넌트들에 대한 데이터 저장소 역할 및 관리하는 Store - Vuex 보다 더 간단하
coding-today.tistory.com
Vue3 기초 예제 - Axios 모듈화(async/await)
async / await 간단한 설명과 Axios 모듈화 기초 예제 *자세한 설명 생략 ▷ async / await 이란? - Javascript의 싱글 스레드, 비동기 처리 방식( Callback, Promise )을 보안한 문법 *동기/비동기 설명 생략 - 가독
coding-today.tistory.com
Vue3 기초 예제 - CRUD 관리자 페이지
공통 코드를 관리하는 관리자 페이지 기초 예제 *동적 데이터 테이블 생성, Axios API 통신, Modal open/close *API 관련 설명 생략 *자세한 설명 생략 ▷ 프로젝트 전체 구조 ▷ 기초 예제 - CRUD - Cmp.css *dat
coding-today.tistory.com
Vue3 기초 예제 - 테이블 라이브러리 적용(PrimeVue)
"PrimeVue" 라이브러리를 사용하여 테이블을 생성하는 기초 예제 *동적 데이터 테이블 생성, Axios API 통신, Modal open/close *API 관련 설명 생략 *자세한 설명 생략 ▷ PrimeVue 설치 *vue-cli를 통해 Project 생
coding-today.tistory.com
Vue3 기초 예제 - 날짜 검색(v-calendar)
Vue3 기초 예제 - Pie Charts(Vue-ECharts)에 v-calendar를 사용하여 날짜 검색 조건 추가 *아래 관련 글 참고 *API 관련 설명 생략 *자세한 설명 생략 ▷ v-calendar 설치 *vue-cli를 통해 Project 생성 후 진행 💡npm i
coding-today.tistory.com
Vue3 기초 예제 - Bar Charts(Vue-ECharts)
Vue-Echarts 라이브러리를 사용하여 Bar Charts를 생성하는 기초 예제 *Vue3 기초 예제 - 날짜 검색(v-calendar)에 이어서 진행 *API 관련 설명 생략 *자세한 설명 생략 ▷ Vue-Echarts 설치 *vue-cli를 통해 Project
coding-today.tistory.com
Vue3 기초 예제 - Line Charts(Vue-ECharts)
Vue-Echarts 라이브러리를 사용하여 Line Charts를 생성하는 기초 예제 *Vue3 기초 예제 - Bar Charts(Vue-ECharts)에 이어서 진행 *API 관련 설명 생략 *자세한 설명 생략 ▷ Vue-Echarts 설치 *vue-cli를 통해 Project 생
coding-today.tistory.com
'▶ Front-End > Vue.js' 카테고리의 다른 글
Vue3 기초 예제 - Line Charts(Vue-ECharts) (0) | 2023.11.10 |
---|---|
Vue3 기초 예제 - Bar Charts(Vue-ECharts) (0) | 2023.11.09 |
Vue3 기초 예제 - 날짜 검색(v-calendar) (2) | 2023.11.06 |
Vue3 기초 예제 - 테이블 라이브러리 적용(PrimeVue) (0) | 2023.11.02 |
Vue3 기초 예제 - CRUD 관리자 페이지 (2) | 2023.11.02 |
댓글