파일명 /routes/seller.js
// 시간대별 주문수량
// localhost:3000/seller/grouphour
router.get('/grouphour', async function(req, res, next) {
try{
const dbconn = await db.connect(dburl);
const collection = dbconn.db(dbname).collection('order1');
const result = await collection.aggregate([
{
$project : {
orderdate: 1, //주문일자
ordercnt : 1, //주문수량
month : {$month : '$orderdate'}, // 주문일자를 이용해서 달
hour : {$hour : '$orderdate'}, // 주문일자를 이용해서 시
minute : {$minute : '$orderdate'} // 주문일자를 이용해서 분
}
},
{
$group : {
_id : '$hour', // 그룹할 항목
count : { $sum : '$ordercnt' }
}
},
]).toArray();
return res.send({status:200, result:result});
}
catch(e){
console.error(e);
return res.send({status:-1, message:e});
}
});
// 상품별 주문수량(판매자 정보가 필요하기 때문에)
// localhost:3000/seller/groupitem?code=1051
// item1(판매자내용만 꺼냄) + order1에 itemcode가 일치하는 것만
router.get('/groupitem', checkToken, async function(req, res, next) {
try{
const email = req.body.uid;
const dbconn = await db.connect(dburl);
// 물품에서 판매자가 email과 같은 것 => 물품코드
const collection = dbconn.db(dbname).collection('item1');
// 고유값 꺼내기 distinct(교유값컬럼명,조건)
const result = await collection.distinct("_id",{ seller : email });
console.log('groupitem',result);
const collection1 = dbconn.db(dbname).collection('order1');
// 그룹별 통계 aggregate
const result1 = await collection1.aggregate([
{ $match : { itemcode : { $in : result } } },
{ $project : { _id : 1, itemcode : 1, ordercnt : 1 } },//가져올 항목( 물품코드, 주문수량 )
{
$group : {
_id : '$itemcode', // 그룹할 항목
count : { $sum : '$ordercnt' }
}
},
]).toArray();
return res.send({status:200, result:result1});
}
catch(e){
console.error(e);
return res.send({status:-1, message:e});
}
});
// 주문회원 목록 : 판매자가 등록한 물품에 대해 주문한 고객 정보
// localhost:3000/seller/memberlist
router.get('/memberlist', checkToken, async function(req, res, next){
try{
const email = req.body.uid; // 판매자의 이메일
// DB접속
const dbconn = await db.connect(dburl);
// DB선택 및 컬렉션 선택
const collection = dbconn.db(dbname).collection('item1');
const result = await collection.find(
{ seller : email }, // 조건
{ projection : { _id : 1 } } // 가지고올 컬럼 설정
).toArray();
//console.log(result);
let code = [];
for(let tmp of result){
code.push(tmp._id);
}
const collection1 = dbconn.db(dbname).collection('order1');
// 고유값 꺼내기 distinct(교유값컬럼명,조건)
const result1 = await collection1.distinct("orderid",{ itemcode : { $in : code } });
// console.log(result1);
const collection2 = dbconn.db(dbname).collection('member1');
const result2 = await collection2.find(
{ _id : { $in : result1 } }, // 조건
{ projection : { pw : 0 } }
).toArray();
// console.log(result2);
return res.send({status:200, result:result2});
}
catch(e){
console.error(e);
return res.send({status : -1, message:e });
}
})
// 주문목록 : 판매자가 등록한 물품에 대해서 고객이 주문한 내역
// localhost:3000/seller/orderlist
router.get('/orderlist', checkToken, async function(req, res, next){
try{
const email = req.body.uid; // 판매자의 이메일
// DB접속
const dbconn = await db.connect(dburl);
// DB선택 및 컬렉션 선택
// 1. 판매자가 등록한 물품의 코드들 가져오기
const collection = dbconn.db(dbname).collection('item1');
const result = await collection.find(
{ seller : email }, // 조건
{ projection : { _id : 1 } } // 가지고올 컬럼 설정
).toArray();
console.log(result);
// result => [{_id:1051},{_id:1052},{_id:..}...]
// $in = [] => [1,2,3,4]
// 2. 받은 결과를 배열로 변경
// [ {_id:1},{_id:2},{_id:3} ] =>[1,2,3]
let code = [];
for(let tmp of result){
code.push(tmp._id);
}
//for(let i=0;i< result.length;i++){
// code.push(result[i]._id)
//}
// 3. 주문내역에서 자겨온 코드에 대한 정보만
const collection1 = dbconn.db(dbname).collection('order1');
const result1 = await collection1.find(
{ itemcode : { $in : code } }, // 조건
).toArray();
// 4. result1에 있는 내용을 리턴함
return res.send({status:200, result:result1});
}
catch(e){
console.error(e);
return res.send({status : -1, message:e });
}
})
===============================================
파일명 src/stores/index.js
// npm install vuex@next --save
// 파일명 : src/stores/index.js
import {createStore} from "vuex";
import axios from 'axios';
// 모든 컴포넌트에서 공통으로 사용할 변수 설정
// props 와 emit 를 여기에서 처리함
const stores = createStore({
// 공통 상태 변수
state : {
menu : sessionStorage.getItem("CURL"), // 선택된 메뉴
logged : false, // 로그인 상태
uid : '', // 로그인한 사용자의 이메일정보
uname : '', // 로그인한 사용자의 이름
token : '', // 토큰을 저장소에 보관하지 않고 사용
},
//가져가기 (getter)
getters : {
getMenu(state){
return state.menu;
},
getLogged(state){
return state.logged;
},
getUid(state) {
return state.uid;
},
getUname(state) {
return state.uname;
},
},
// 변경하기 (mutation) : 증시변경
mutations:{
setMenu(state,value){
state.menu = value;
},
setLogged(state,value){
state.logged = value;
},
setUid(state, val) {
state.uid = val;
},
setUname(state, val) {
state.uname = val;
},
},
// 변경하기(action) : 기다려야 되는 상황, 벡엔드 연동이 필요할 경우
actions:{
async handleData(context, payload){
console.log(payload);
const token = sessionStorage.getItem("TOKEN");
if(typeof token !== 'undefined'&& token !== null){
const url = `/member/validation`;
const headers = {"Content-Type":"application/json", "token":token };
const response = await axios.get(url, {headers:headers});
if(response.data.status === 200){
// mutations의 setUid, setUname을 호출해서 내용변경
context.commit("setUid", response.data.uid);
context.commit("setUname", response.data.uname);
}
else{
// 토큰의 유효성을 검사하여 통과하지 못할경우
context.commit("setLogged", false);
}
}
}
},
});
export default stores;
===============================================
파일명 src/component/Login.vue
<template>
<div>
<h3>src/component/Login.vue</h3>
{{state}}
<hr />
<input type="text" v-model="state.userid"/>
<input type="password" v-model="state.userpw"/>
<input type="button" value="로그인" @click="handleLogin"/>
</div>
</template>
<script>
import { reactive } from 'vue';
import axios from 'axios';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
export default {
// ver 3.0
setup () { // this를 사용할 수 없음
const router = useRouter();
const store = useStore();
const state = reactive({
userid : 'aaa@gmail.com',
userpw : 'aaa',
});
const handleLogin = async() => {
const url = `/member/select`;
const headers = {"Content-Type":"application/json"};
const body = {
email : state.userid,
password : state.userpw
};
const response = await axios.post(url, body, {headers});
console.log(response.data.status);
if(response.data.status === 200){
console.log(response.data.token)
// 저장소에 보관하기(공통변수)
sessionStorage.setItem("TOKEN", response.data.token);
alert('로그인 되었습니다.');
// 이메일, 이름정보 (공통변수)
store.commit("setUid",response.data.uid);
store.commit("setUname",response.data.uname);
const curl = sessionStorage.getItem("CURL");
if(curl === null){
// 주소창만 바뀜
router.push({name:'Home'});
// app.vue에 메뉴의 선택항목을 변경하도록 알려줌
// 메뉴 활성화
store.commit("setMenu","/");
}
else {
const query = JSON.parse(sessionStorage.getItem("CURL_QUERY"));
const params = JSON.parse(sessionStorage.getItem("CURL_PARAMS"));
router.push({name:curl, query:query, params:params});
}
// 로그인 상태
store.commit("setLogged",true);
}
else{
alert('아이디와 암호를 확인하세요');
}
};
return {state, handleLogin}
},
}
</script>
<style lang="scss" scoped>
</style>
===============================================
파일명 src/App.vue
<template>
<div>
<!-- ElMenu.vue -->
<!-- props로 default-active숫자값을 전달 -->
<!-- props로 router TRUE값을 전달 -->
<!-- 자식컴포넌트 emit 를 통해서 select이벤트 -->
<el-menu :default-active="state.activeIndex"
class="el-menu-demo"
mode="horizontal"
:router="true"
@select="handleSelect">
<el-menu-item index="/">Home</el-menu-item>
<el-menu-item v-show="logged === false" index="/login">Login</el-menu-item>
<el-menu-item v-show="logged === true" index="/logout">Logout</el-menu-item>
<el-menu-item v-show="logged === true" index="/seller">Seller</el-menu-item>
<el-menu-item v-show="logged === true" index="/mypage">Mypage</el-menu-item>
<el-menu-item index="/board">Board</el-menu-item>
<el-menu-item index="/admin">Admin</el-menu-item>
<el-menu-item index="/join">Join</el-menu-item>
<el-menu-item index="/chart">Chart</el-menu-item>
<div style="padding:17px" v-if="logged === true">{{uid}}//{{uname}}님 로그인</div>
</el-menu>
{{menu}},{{logged}}
<hr />
<router-view></router-view>
</div>
</template>
<script>
import {useStore} from 'vuex';
import {computed, reactive, onMounted } from 'vue';
export default {
setup () {
const store = useStore();
// store의 menu값 실시간으로 가져오기
// 마지막으로 방문한 페이지를 session저장소에 보관후에 변환
const menu = computed(()=>{
return store.getters.getMenu
});
// store의 logged값 실시간으로 확인
const logged = computed(()=>{
return store.getters.getLogged
});
const uid = computed(()=>{
return store.getters.getUid
});
const uname = computed(()=>{
return store.getters.getUname
});
// store에서 읽은 메뉴값으로 초기값으로 세팅
const state = reactive({
activeIndex : menu
})
onMounted( async () => {
// 저장소에 있는 TOKEN값을 읽어서 존재 유무 확인
// TOKEN을 추가하는 시점은 로그인이 완료 되었을때
// TOKEN의 값을 제거하는 시점은 로그아웃되었을때
if(sessionStorage.getItem("TOKEN")===null){
// store의 logged변수 값을 false
store.commit("setLogged", false);
}
else{
// mutation을 호출하는 경우
store.commit("setLogged", true);
// actions를 호출할 경우
store.dispatch("handleData", {});
}
})
// 메뉴를 클릭했을 떄
// store값 변경하기
const handleSelect = (idx) =>{
console.log(idx);
// 메소드명,value 값
store.commit("setMenu", idx);
}
// // store의 state 변수가 변경되는 시점을 바로 알 수 있음.
// store.subscribe((mutation, state) => {
// console.log('store.subscribe',mutation,state);
// })
return {state, menu, logged, handleSelect, uid, uname}
}
}
</script>
<style lang="scss" scoped>
</style>
===============================================
파일명 src/component/Seller.vue
<template>
<div style="padding:10px">
<h3>src/component/Seller.vue</h3>
<hr />
<button @click="handleMenu(1)">물품관리</button>
<button @click="handleMenu(2)">회원관리</button>
<button @click="handleMenu(3)">주문관리</button>
<button @click="handleMenu(4)">물품별 주문 수량 (차트)</button>
<button @click="handleMenu(5)">시간대별 주문 수량 (차트)</button>
<hr />
<menu-1 v-if="state.menu === 1"></menu-1>
<menu-2 v-if="state.menu === 2"></menu-2>
<menu-3 v-if="state.menu === 3"></menu-3>
<menu-4 v-if="state.menu === 4"></menu-4>
<menu-5 v-if="state.menu === 5"></menu-5>
</div>
</template>
<script>
import {onMounted, reactive} from 'vue';
import Menu1 from './seller/Menu1.vue';
import Menu2 from './seller/Menu2.vue';
import Menu3 from './seller/Menu3.vue';
import Menu4 from './seller/Menu4.vue';
import Menu5 from './seller/Menu5.vue';
import { useRouter } from 'vue-router';
import { useRoute } from 'vue-router';
export default {
components:{
Menu1,Menu2,Menu3,Menu4,Menu5
},
setup () {
const router = useRouter();
const route = useRoute();
const state = reactive({
menu: Number(route.query.menu)
});
onMounted( ()=>{
console.log('menu Number ===',route.query.menu)
if(typeof route.query.menu === 'undefined'){
state.menu = 1
}
})
const handleMenu = (idx)=> {
router.push({name:'Seller', query:{menu:idx}});
state.menu = idx;
}
return {state, handleMenu}
}
}
</script>
<style lang="scss" scoped>
</style>
===============================================
파일명 src/components/seller/Menu3.vue
<template>
<div>
<h3>주문관리</h3>
<div v-if="state.items">
<table border="1">
<tr>
<th>주문번호</th>
<th>물품코드</th>
<th>주문수량</th>
<th>주문자</th>
<th>주문일자</th>
</tr>
<tr v-for="item in state.items" :key="item">
<td>{{item._id}}</td>
<td>{{item.itemcode}}</td>
<td>{{item.ordercnt}}</td>
<td>{{item.orderid}}</td>
<td>{{item.orderdate}}</td>
</tr>
</table>
</div>
</div>
</template>
<script>
import axios from 'axios';
import { onMounted, reactive } from 'vue';
export default {
setup () {
const state = reactive({
token: sessionStorage.getItem("TOKEN")
})
const handleLoadData = async() =>{
const url =`/seller/orderlist`;
const headers = {"Content-Type":"application/json","token":state.token};
const response = await axios.get(url, {headers});
console.log('seller/Menu3/handleData',response.data);
if(response.data.status === 200){
state.items = response.data.result;
}
}
onMounted(()=>{
handleLoadData();
})
return {state}
}
}
</script>
<style lang="scss" scoped>
</style>
===============================================
파일명 src/components/seller/Menu2.vue
<template>
<div>
<h3>회원관리</h3>
<div v-if="state.items">
<table border="1">
<tr>
<th>아이디</th>
<th>이름</th>
<th>등록일</th>
</tr>
<tr v-for="item in state.items" :key="item">
<td>{{item._id}}</td>
<td>{{item.name}}</td>
<td>{{item.regdate}}</td>
</tr>
</table>
</div>
</div>
</template>
<script>
import axios from 'axios';
import { onMounted, reactive } from 'vue';
export default {
setup () {
const state = reactive({
token: sessionStorage.getItem("TOKEN")
})
const handleLoadData = async() =>{
const url =`/seller/memberlist`;
const headers = {"Content-Type":"application/json","token":state.token};
const response = await axios.get(url, {headers});
console.log('seller/Menu2/handleData',response.data);
if(response.data.status === 200){
state.items = response.data.result;
}
}
onMounted(()=>{
handleLoadData();
})
return {state}
}
}
</script>
<style lang="scss" scoped>
</style>
===============================================
파일명 src/components/seller/Menu4.vue
<template>
<div>
<h3>src/components/seller/Menu4.vue</h3>
<div style="width:500px; height:300px">
<vue3-chart-js
:id = "state.id"
:type = "state.type"
ref ="chartRef"
:data = "state.data">
</vue3-chart-js>
</div>
</div>
</template>
<script>
import { ref, onMounted, reactive } from 'vue';
import Vue3ChartJs from '@j-t-mcc/vue3-chartjs'
import axios from 'axios';
export default {
components:{
Vue3ChartJs
},
setup () {
const chartRef = ref(null); // 차트를 업데이트하기 위해서 연결
const state = reactive({ // Read
id :'doughnut',
type : 'doughnut',
data :{
labels : [],
datasets : [{
backgroundColor: [],
data : []
}],
},
token : sessionStorage.getItem("TOKEN")
})
// 현재 로그인한 판매자를 조건으로 물품별 주문수량
const handleLoadData = async () =>{
const url = `/seller/groupitem`;
const headers = {"Content-Type":"application/json", "token":state.token}
const response = await axios.get(url,{headers});
console.log("seller/Menu4/handleLoadData",response.data);
if(response.data.status === 200){
// [{_id:1051,count:2},{_id:1052,count:4}]
let label = []; // _id가 추가됨
let background = []; // '#41B883'
let data = []; // count 추가됨
for(let tmp of response.data.result){
label.push( tmp._id );
background.push( '#6569b5' );
data.push(tmp.count);
}
state.data.labels = label;
state.data.datasets[0]['backgroundColor'] = background;
state.data.datasets[0]['data'] = data;
chartRef.value.update(250);
}
}
onMounted(()=>{
handleLoadData();
})
// 리턴함
return {state,chartRef}
}
}
</script>
<style lang="scss" scoped>
</style>