node 2022/02/11

무간·2022년 2월 11일

파일명 routes/shop.js

// 파일명 : routes/shop.js
var express = require('express');
var router = express.Router();

const db     = require('mongodb').MongoClient;
const dburl  = require('../config/mongodb').URL;
const dbname = require('../config/mongodb').DB;

// 토큰 발행을 위한 필요 정보 가져오기
const checkToken = require('../config/auth').checkToken;

const itemCount = 16; // 페이지에 보여줄 개수



// 주문 목록
// localhost:3000/shop/orderlist
router.get('/orderlist', checkToken, async function(req, res, next){
    try{
        const email = req.body.uid;
        // DB접속
        const dbconn = await db.connect(dburl);
        // 2. DB선택 및 컬렉션 선택
        const collection = dbconn.db(dbname).collection('order1');

        const result = await collection.find(
            { orderid : email },
            { projection : { orderstep : 0, orderid : 0 } },
        ).toArray();       
        
        const collection1 = dbconn.db(dbname).collection('item1');
        for(let i=0; i<result.length; i++){
            const result1 = await collection1.findOne(
                { _id : result[i].itemcode },
                { projection : { name : 1, price : 1 } },
            );

            result[i]['itemname']  = result1['name'];
            result[i]['itemprice'] = result1['price'];
        }
        
        return res.send({status:200, result:result });
    }
    catch(e){
        console.error(e);
        return res.send({status : -1, message:e });
    }
});


// 시간대별 주문수량
// localhost:3000/shop/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/shop/groupitem
router.get('/groupitem', async function(req, res, next) {
    try{
        const dbconn = await db.connect(dburl);
        const collection = dbconn.db(dbname).collection('order1');

        // 그룹별 통계 aggregate
        const result = await collection.aggregate([
            { $match : { itemcode : 1052 } },
            { $project : { _id : 1, itemcode : 1, ordercnt : 1 } },//가져올 항목( 물품코드, 주문수량 )
            {
                $group : {
                    _id     : '$itemcode', // 그룹할 항목
                    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/shop/order

// _id       : (PK) 주문번호 시퀀스사용
// itemcode  : (FK) 물품내역 (물품번호, 물품과 관련된 모든 정보)
// ordercnt  : 주문수량 
// orderid   : (FK) 주문자 ( 이메일, 고객과 관련된 모든 정보 )
// orderdate : 주문일자
// orderstep : 100(카트), 101(주문), 102(결제), 103(배송중), 104(배송완료

// 주문목록(조인) : member1 + item1 + order1
// 주문하기 위해서 로그인시 사용자의 토큰, 물품번호, 주문수량 필요
router.post('/order', checkToken, async function(req, res, next){
    try{
        // DB접속
        const dbconn = await db.connect(dburl);
        // 2. DB선택 및 컬렉션 선택
        const collection = dbconn.db(dbname).collection('sequence');
        const result = await collection.findOneAndUpdate(
            { _id  : 'SEQ_ORDER1_NO' }, // sequence 값( _id 자동 생성)
            { $inc : {seq : 1} }        // 1씩 증가
        );    
        const obj = {
            _id         : result.value.seq, //주문번호
            itemcode    : Number( req.body.itemcode ), // 물품번호
            ordercnt    : Number( req.body.ordercnt ), // 주문수량
            orderid     : req.body.uid, // 주문자
            orderdate   : new Date(), // + ( 1000 * 60 *60 * 9 ), // 9시간 더하기
            orderstep   : 101,
        };

        const collection1 = dbconn.db(dbname).collection('order1');
        const result1 = await collection1.insertOne(obj);
        console.log(result1);
        if(result1.insertedId === obj._id) {
            return res.send({status:200});    
        }
        return res.send({status:0});

    }
    catch(e){
        console.error(e);
        return res.send({status : -1, message:e });
    }
});


// 상세화면 페이지
// localhost:3000/shop/selectone?code=1050
router.get('/selectone',async function(req, res, next) {
    try{
        const code = Number(req.query.code);
        // DB접속
        const dbconn = await db.connect(dburl);
        // 2. DB선택 및 컬렉션 선택
        const collection = dbconn.db(dbname).collection('item1');    
        
        
        const result = await collection.findOne(
            { _id : code },// 조건없음 (천체 가지고 오기)
            { projection : { filename:0, filedata:0, filesize:0, filetype:0, regdate:0 } },
        );

        // find     [{},{},{}]
        // findOne  {}
        result['imageUrl'] = `/shop/image?code=${code}`;

        // 서브이미지 정보가 필요함
        // 물품 1개를 조회할때 서브 이미지의 정보를 전송하는 부분
        const collection1 = dbconn.db(dbname).collection('itemimg1');

        const result1 = await collection1.find(
            { itemcode : code },
            { projection : { _id : 1 } }
        ).sort({ _id : 1 }).toArray();
        
        // 수동으로 서버이미지 PK정보를 저장함
        // result1 => [ { "_id": 10009 }, { "_id": 10010 }, { "_id": 10011 } ]
        let arr = [];
        for(let i=0; i<result1.length; i++){
            arr.push({
              imageUrl : `/shop/image1?code=${result1[i]._id}`
            });
        }

        result['subImage'] = arr;
        
        

        return res.send({status:200, result:result});
    }
    catch(e){
        console.error(e);
        return res.send({status : -1, message:e });
    }
});


// 메인화면 페이지
// localhost:3000/shop/select?page=1
router.get('/select',async function(req, res, next) {
    try{
        const page = Number(req.query.page);
        // DB접속
        const dbconn = await db.connect(dburl);
        // 2. DB선택 및 컬렉션 선택
        const collection = dbconn.db(dbname).collection('item1');    
        
        // SQL문 DB가 알아듣는 문법 (INSERT, UPDATE, DELETE, SELECT)
        // SQL문을 이용해서 DB연동 mybatis
        // SQL문을 저장소(함수)를 DB연동 jpa 
        const result = await collection.find(
            {},// 조건없음 (천체 가지고 오기)
            { projection : { filename:0, filedata:0, filesize:0, filetype:0, regdate:0 }  },
        ).sort({ _id : 1 }) // 정렬(물품코드를 오름차순으로)
        .skip( (page-1)*itemCount )// 생략할 개수
        .limit(itemCount)
        .toArray();

        // result === [ { },{ },{ } ]
        // for => [ { },{ },{ } ] => 위치를 i로 반복
        // for(let i=0; i<result.length; i++){
        //     result[i]['imageUrl'] = `/shop/image?code=${result[i]._id}`
        // }

        // foreach [ { },{ },{ } ]  => 내용을 tmp 로 반복
        for(let tmp of result){
            tmp['imageUrl'] = `/shop/image?code=${tmp._id}`
        }

        return res.send({status:200, result:result})
    }
    catch(e){
        console.error(e);
        return res.send({status : -1, message:e });
    }
});


// 이미지 가지고 오기
// localhost:3000/shop/image?code=1050
router.get('/image', async function(req, res, next) {
    try{
        const code       = Number(req.query.code);
        const dbconn     = await db.connect(dburl);
        const collection = dbconn.db(dbname).collection('item1');     
        // 조회하면 나오는 키정보확인
        const result     = await collection.findOne(
            { _id : code },
            { projection : { filename:1, filedata:1, filesize:1, filetype:1 } }
        );
        console.log(result);
        res.contentType(result.filetype);
        return res.send(result.filedata.buffer);
    }
    catch(e){
        console.error(e);
        res.send({status : -1, message:e});        
    }  
});

// localhost:3000/shop/image1?code=1050
router.get('/image1', async function(req, res, next) {
    try{
        const code       = Number(req.query.code);
        const dbconn     = await db.connect(dburl);
        const collection = dbconn.db(dbname).collection('itemimg1');     

        const result     = await collection.findOne(
            { _id : code },
            { projection : { filename:1, filedata:1, filesize:1, filetype:1 } }
        );
        console.log(result);
        res.contentType(result.filetype);
        return res.send(result.filedata.buffer);
    }
    catch(e){
        console.error(e);
        res.send({status : -1, message:e});        
    }  
});

module.exports = router;

===================================================

파일명 src/component/Home.vue

<template>
    <div style="padding:5px">
        <h3>src/component/Home.vue</h3>

        <vueper-slides autoplay>
            <vueper-slide v-for="tmp in state.slides" :key="tmp" :title="state.title" :image="tmp.image"></vueper-slide>
        </vueper-slides>        

        <div v-if="state.items" style="margin-top:10px;">
            <el-row :gutter="20" v-for="(i, idx1) in state.items.length/4" :key="i" >
                <el-col :span="6" :gutter="10" v-for="(j, idx2) in 4" :key="j">
                    <div style="border:1px solid #cccccc; padding:20px; cursor:pointer; " 
                         @click="handleDetailPage(state.items[(idx1 * 4) + idx2]._id)" >

                        {{ idx1 }} 
                        {{ idx2 }} 
                        {{ (idx1 * 4) + idx2 }}<br />
                        <img :src="state.items[ (idx1 * 4) + idx2 ].imageUrl" style="width:100%; height:200px;" />
                        {{ state.items[(idx1 * 4) + idx2 ].name }} <br />
                        {{ state.items[(idx1 * 4) + idx2 ].price }} <br />
                        {{ state.items[(idx1 * 4) + idx2 ].content }} <br />
                    </div>

                </el-col>    
            </el-row>    
        </div>

    </div>
</template>


<script>
import { VueperSlides, VueperSlide } from 'vueperslides';
import 'vueperslides/dist/vueperslides.css';
import {onMounted, reactive} from 'vue';
import axios from 'axios';
import { useRouter } from 'vue-router';

export default {
    components:{
        VueperSlides, VueperSlide
    },

    setup () { 
        const router = useRouter();

        const state = reactive({
            
            slides : [
                { title : 'a', image : 'https://picsum.photos/500/300?image=10'},
                { title : 'b', image : 'https://picsum.photos/500/300?image=20'},
                { title : 'c', image : 'https://picsum.photos/500/300?image=30'},
                { title : 'd', image : 'https://picsum.photos/500/300?image=40'},
                { title : 'e', image : 'https://picsum.photos/500/300?image=50'},
            ],
            page:1,
        });

        const handleLoadData = async() => {
            const url = `/shop/select?page=${state.page}`;
            const headers = {"Content-Type":"application/json"};
            const response = await axios.get(url,{headers});
            console.log(response.data);

            if(response.data.status === 200){
                state.items = response.data.result; 
                // 15 % 4 => 3 => 1
                // 14 % 4 => 2 => 2
                // 13 % 4 => 1 => 3
                // 12 % 4 => 0 => 0
                const mod = Math.floor(state.items.length % 4);
                if(mod !== 0 ){
                    for(let i=0;i< 4-mod ;i++){
                        state.items.push({
                            content: "준비중입니다.",
                            imageUrl: require('../assets/default.jpg'),
                            name: "준비중",
                            price: 0,
                            quantity: 0,
                            seller: "",
                            _id: 0,
                        });
                    }
                }
            }
        }

        const handleDetailPage = (code) => {           
            router.push({name:'ItemContent', query:{code:code}});
        }

        onMounted( async()=>{
            await handleLoadData();
        })

        
        return { state, handleDetailPage }
    }
}
</script>


<style lang="scss" scoped>
.el-row {
  margin-bottom: 20px;
}
.el-row:last-child {
  margin-bottom: 0;
}
.el-col {
  border-radius: 4px;
}
.bg-purple-dark {
  background: #99a9bf;
}
.bg-purple {
  background: #d3dce6;
}
.bg-purple-light {
  background: #e5e9f2;
}
.grid-content {
  border-radius: 4px;
  min-height: 36px;
}
.row-bg {
  padding: 10px 0;
  background-color: #f9fafc;
}
</style>

===================================================

파일명 /src/components/ItemContent.vue

<template>
    <div v-if="state.items">
        <h3>/src/components/ItemContent.vue</h3>
        {{state.items}}

        <table border="1">
            <thead>
                
                <tr>
                    <th>이미지</th>
                    <td>
                        <img :src="state.items.imageUrl" style="width:300px; heigh:300px" />
                    </td>
                </tr>
                <tr>
                    <th>이름</th>
                    <td>{{state.items.name}}</td>
                </tr>
                <tr>
                    <th>가격</th>
                    <td>{{state.items.price}}</td>
                </tr>
                <tr>
                    <th>수량</th>
                    <td>{{state.items.quantity}}</td>
                </tr>
                <tr>
                    <th>내용</th>
                    <td>{{state.items.content}}</td>
                </tr>                
                <tr>
                    <th>서브이미지</th>
                    <td>
                        <div v-for="tmp in state.items.subImage" :key="tmp" style="display:inline-block">
                            <img :src="tmp.imageUrl" style="width:50px; heigh:50px" />
                        </div>
                    </td>
                </tr>
            </thead>
            


        </table>


    </div>
</template>

<script>
import { onMounted, reactive } from 'vue'
import { useRoute } from 'vue-router';
import axios from 'axios';

export default {
    setup () {
        const route = useRoute();

        const state = reactive({
            code : route.query.code,
        })

        const handleLoadData = async() => {
            const url = `/shop/selectone?code=${state.code}`;
            const headers ={"Content-Type":"application/json"};
            const response = await axios.get(url, {headers});
            console.log(response.data);

            if(response.data.status === 200 ){
                state.items = response.data.result;
            }
            console.log(state.items);
        };

        onMounted( async()=>{
            await handleLoadData();
        });
        

        return {state}
    }
}
</script>

<style lang="scss" scoped>

</style>
profile
당신을 한 줄로 소개해보세요

0개의 댓글