CMD> nodemon --inspect ./bin/www
-----------------------------------
// 파일명 : item.js
var express = require('express');
var router = express.Router();
// CMD> npm i mongodb --save
const db = require('mongodb').MongoClient;
// config/db.js 파일의 내용 가져오기
const DBURL = require('../config/db').mongodbURL;
const DBNAME = require('../config/db').mongodbDB;
// CMD> npm i multer --save
const multer = require('multer');
// 특정폴더에 파일을 보관 or 메모리(DB에 저장)
const upload = multer({storage:multer.memoryStorage()});
/*
db.sequence.insert([
{_id : 'SEQ_BOARD_NO', seq : 1},
{_id : 'SEQ_BOARDREPLY_NO', seq : 1},
{_id : 'SEQ_ITEM_NO', seq : 10001}
]);
*/
// 물품등록 : http://localhost:3000/item/insert
// 이미지1, 물품코드(X), 물품명, 물품내용, 물품가격, 재고수량, 등록일(X)
router.post('/insert', upload.single("file"), async function(req, res, next) {
try {
const dbConn = await db.connect(DBURL);
const coll = dbConn.db(DBNAME).collection("sequence");
const result = await coll.findOneAndUpdate(
{ _id:'SEQ_ITEM_NO' }, { $inc : { seq : 1} }
);
//console.log(result.value.seq);
const obj = {
_id : result.value.seq, // 물품번호(자동부여)
name : req.body.name, //물품명, 물품내용, 가격, 수량
content : req.body.content,
price : req.body.price ,
quantity : req.body.quantity,
filename : req.file.originalname, //파일명
filetype : req.file.mimetype,
filedata : req.file.buffer,
filesize : req.file.size,
regdate : new Date()
};
const coll1 = dbConn.db(DBNAME).collection("item");
const result1 = await coll1.insertOne(obj);
if( result1.insertedId > 0 ){
return res.send({status:200});
}
return res.send({status:0});
}
catch(err) {
console.error(err);
return res.send({status:-1, result : err});
}
});
// 이미지(1개) : http://localhost:3000/item/image?no=2
router.get('/image', async function(req, res, next) {
try {
const no = Number(req.query.no);
const dbConn = await db.connect(DBURL);
const coll = dbConn.db(DBNAME).collection("item");
const result = await coll.findOne(
{ _id : no }, //조건
{ projection : {filedata:1, filetype:1} } //필요한 항목만
);
console.log(result);
res.contentType(result.filetype);// json ->image/jpeg
return res.send(result.filedata.buffer);
}
catch(err) {
console.error(err);
return res.send({status:-1, result : err});
}
});
// 물품목록 : http://localhost:3000/item/select?page=1
router.get('/select', async function(req, res, next) {
try {
const page = Number(req.query.page);
const dbConn = await db.connect(DBURL);
const coll = dbConn.db(DBNAME).collection("item");
// 물품코드, 물품명, 가격, 수량, 등록일
const result = await coll.find(
{}, // 조건
{ projection : {_id:1, name:1, price:1, quantity:1, regdate:1} } // 가져올 항목만
)
.sort({_id:-1}) // 1 오름차순, -1 내림차순
.skip((page-1) * 10 ) // 생략할 개수
.limit(10) // 10개 까지만
.toArray();
const total = await coll.countDocuments({});
return res.send({status:200, result:result, total:total});
}
catch(err) {
console.error(err);
return res.send({status:-1, result : err});
}
});
// 물품1개조회(이미지포함) : http://localhost:3000/item/selectone?code=10001
router.get('/selectone', async function(req, res, next) {
try {
const code = Number(req.query.code);
const dbConn = await db.connect(DBURL);
const coll = dbConn.db(DBNAME).collection("item");
const result = await coll.findOne(
{_id : code}, //조건
{projection : {filename:0, filedata:0, filesize:0, filetype:0 } } //필요한 항목만
);
console.log(result); // 확인
// 이미지 데이터를 전달X,
// 이미지를 볼수있는 URL정보 전달
result['image'] = '/item/image?no=' + code;
return res.send({status:200, result: result});
}
catch(err) {
console.error(err);
return res.send({status:-1, result : err});
}
});
// 물품삭제 : http://localhost:3000/item/delete?code=10004
router.delete('/delete', async function(req, res, next) {
try {
const code = Number(req.query.code);
const dbConn = await db.connect(DBURL);
const coll = dbConn.db(DBNAME).collection("item");
const result = await coll.deleteOne({_id:code});
if(result.deletedCount === 1){
return res.send({status:200});
}
return res.send({status:0});
}
catch(err) {
console.error(err);
return res.send({status:-1, result : err});
}
});
// 물품수정 : http://localhost:3000/item/update?code=10004
// query + body
router.put('/update', upload.single("file"),
async function(req, res, next) {
try {
const code = Number(req.query.code);
// 물품명, 물품내용, 물품가격, 재고수량, 이미지
// const 상수 처음만든 값에 +, - 안됨.
// let, var 변수 처음만든값에 +, - 가능함.
let obj = {
name : req.body.name,
content : req.body.content,
price : req.body.price,
quantity : req.body.quantity
};
if(typeof req.file !== 'undefined') {
obj['filename'] = req.file.originalname;
obj.filetype = req.file.mimetype;
obj.filedata = req.file.buffer;
obj.filesize = req.file.size;
}
console.log(code);
console.log(obj);
const dbConn = await db.connect(DBURL);
const coll = dbConn.db(DBNAME).collection("item");
const result = await coll.updateOne(
{ _id : code }, //조건
{ $set : obj } //실제변경할내용
);
console.log(result);
if(result.modifiedCount === 1) {
return res.send({status:200});
}
return res.send({status:0});
}
catch(err) {
console.error(err);
return res.send({status:-1, result : err});
}
});
module.exports = router;
-----------------------------------------
// 파일명 : Seller.vue
<template>
<div>
<el-card shadow="always">
<h4>판매자</h4>
<hr />
<p>물품목록</p>
<el-button size="small" type="primary">물품등록</el-button>
<el-table :data="items" size="mini" style="width: 100%">
<el-table-column prop="_id" label="코드" width="180" />
<el-table-column prop="name" label="물품명" width="180" />
<el-table-column prop="price" label="가격" />
<el-table-column prop="quantity" label="재고수량" />
<el-table-column prop="regdate" label="등록일" />
<el-table-column fixed="right" label="버튼" width="120">
<template #default="scope">
<el-button size="small" type="danger" @click.prevent="deleteRow(scope.$index, scope.row)">
삭제
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination layout="prev, pager, next" :total="total" @current-change="currentChange"></el-pagination>
</el-card>
</div>
</template>
<script>
export default {
created() {
this.handleData();
},
data() {
return{
items : [],
page : 1,
total : 0,
}
},
methods : {
async deleteRow(idx, row){
if( confirm('삭제할까요?') ) {
console.log('Seller.vue => deleteRow');
console.log(idx, row);
const url = `/item/delete?code=${row._id}`;
const headers = {"Content-Type":"application/json"};
const response = await this.axios.delete(url, {headers:headers});
if( response.data.status === 200 ){
alert('삭제되었습니다.');
this.page = 1;
this.handleData();
}
}
},
currentChange(page) {
this.page = page;
this.handleData();
},
async handleData() {
const url = `/item/select?page=${this.page}`;
const headers = {"Content-Type":"application/json"};
const response = await this.axios.get(url, {headers:headers});
if( response.data.status === 200 ){
this.items = response.data.result; // [{},{}]
this.total = response.data.total;
}
}
}
}
</script>
<style scoped>
</style>
----------------------------
// 파일명 : ItemInsert.vue
<template>
<div>
<el-card shadow="always">
<el-upload action="#"
list-type="picture-card"
:on-preview="handlePreview"
:on-remove="handleRemove"
:on-change="handleChange"
:auto-upload="false">
<el-icon><plus /></el-icon>
</el-upload>
<el-dialog v-model="dialogVisible">
<img style="width:100%" :src="dialogImageUrl" alt="" />
</el-dialog>
<input type="text" v-model="item.name" placeholder="물품명"/>
<input type="text" v-model="item.content" placeholder="내용" />
<input type="text" v-model="item.price" placeholder="가격" />
<input type="text" v-model="item.quantity" placeholder="수량" />
<button @click="handleInsert">등록</button>
</el-card>
</div>
</template>
<script>
import { Plus } from '@element-plus/icons-vue'
export default {
components: {
Plus,
},
data() {
return {
dialogImageUrl : '',
dialogVisible : false,
item : {
image : null,
name : '사과',
content : '사과내용',
price : 0,
quantity : 1000
}
}
},
methods: {
async handleInsert(){
// 유효성 검사
if(this.item.image === null){
alert('이미지 첨부하세요');
return false;
}
const url = `/item/insert`;
const headers = {"Content-Type":"multipart/form-data"};
let body = new FormData();
body.append("file", this.item.image);
body.append("name", this.item.name);
body.append("content", this.item.content);
body.append("price", this.item.price);
body.append("quantity", this.item.quantity);
const response
= await this.axios.post(url, body, {headers:headers});
console.log(response.data);
if(response.data.status === 200){
alert('등록되었습니다.');
this.$router.push({name:"Seller"});
}
},
handleChange(file, fileList) {
console.log('handleChange');
//console.log(URL.createObjectURL(file.raw));
console.log(file, fileList);
this.item.image = file.raw;
},
handleRemove(file, fileList) {
//삭제
console.log(file, fileList);
this.item.image = null;
},
handlePreview(file) {
console.log('handlePreview');
console.log(file);
// console.log(URL.createObjectURL(file.raw));
this.dialogImageUrl = file.url; //임시이미지주소
this.dialogVisible = true; //다이얼로그표시
},
},
}
</script>
<style scoped>
</style>
--------------------------------------
// 파일명 : ItemContent.vue
<template>
<div>
<el-card shadow="always">
<h4>물품상세정보</h4>
{{item._id}}
{{item.name}}
<img :src="item.image" style="width:100px;" />
</el-card>
</div>
</template>
<script>
export default {
created(){
this.handleData();
},
data(){
return{
item : '',
code : this.$route.query.code, // 목록에서 전달되는 코드를 보관
}
},
methods:{
async handleData(){
const url = `/item/selectone?code=${this.code}`;
const headers = {"Content-Type":"application/json"};
const response = await this.axios.get(url, {headers:headers});
// console.log(response.data);
if(response.data.status=== 200) {
// state변수 item에 보관
this.item = response.data.result;
console.log(this.item); //확인용
}
}
}
}
</script>
<style scoped>
</style>
=============================================
참고 : https://antoniandre.github.io/vueper-slides/
// 파일명 : Home.vue
<template>
<div>
<el-card shadow="always">
<h3>Home.vue</h3>
<vueper-slides>
<vueper-slide v-for="(tmp, idx) in items"
:key="idx" :title="tmp.title"
:content="tmp.content" :image="tmp.image" />
</vueper-slides>
</el-card>
</div>
</template>
<script>
import { VueperSlides, VueperSlide } from 'vueperslides';
import 'vueperslides/dist/vueperslides.css';
export default {
components: {
VueperSlides, VueperSlide
},
data(){
return {
items :[
{ title:'a', content:'b', image: 'https://picsum.photos/500/300?image=1'},
{ title:'a', content:'b', image: 'https://picsum.photos/500/300?image=2'},
{ title:'a', content:'b', image: 'https://picsum.photos/500/300?image=3'},
]
}
}
}
</script>
<style scoped>
</style>