node 2022/02/21 // vuetify

무간·2022년 2월 21일

파일명 /routers/member.js의 일부

// 주소등록
// localhost:3000/member/insertaddr
// vue에서는 토큰 입력할 주소
router.post('/insertaddr', checkToken, async function(req, res, next) {
    try {
        // DB접속
        const dbconn     = await db.connect(dburl);
        // 2. DB선택 및 컬렉션 선택(sequence값 1씩 증가시키는 DB)
        const collection = dbconn.db(dbname).collection('sequence');
        const result     = await collection.findOneAndUpdate(
            { _id : 'SEQ_MEMBERADDR1_NO' }, // 가지고 오기 위한 조건
            { $inc : {seq : 1 } }      // seq값을 1증가씨킴
        );    
        const obj = {
            _id       : result.value.seq,  //시퀀스값
            address   : req.body.address, //주소정보
            memberid  : req.body.uid, // 토큰에서 꺼내기
            chk       : 0,  // 대표주소설정 (숫자크면 우선순위 부여)
            regdate   : new Date()
        }    
        const collection1 = dbconn.db(dbname).collection('memberaddr1');
        const result1 = await collection1.insertOne(obj);
        console.log(result1);
        
        if(result1.insertedId === result.value.seq){
            return res.send({ status : 200 });
        }
        return res.send({ status : 0 });
    }
    catch(e) {
      console.error(e);
      res.send({status : -1, message:e});
    }
  });
  
// 주소목록
// localhost:3000/member/selectaddr
router.get('/selectaddr', checkToken, async function(req, res, next) {
    try{
        const email      = req.body.uid; // 토큰에서 이메일 꺼내기
        const dbconn     = await db.connect(dburl);
        const collection = dbconn.db(dbname).collection('memberaddr1');  
        const result     = await collection.find(
            { memberid : email },
            { projection : { memberid : 0 } }
        ).sort({ _id : 1 }).toArray();
        
        // resutl => [{chk:0},{chk:0},{chk:0}]
        // 대표주소 설정
        let sum = 0;
        for( let i=0; i<result.length; i++){
            //sum = sum + Number(result[i].chk);            
            sum += Number(result[i].chk);
        }
        if(sum <= 0 ){ // 체크된 것이 없을 경우 첫번째 것을 1로 만듬
            result[0].chk = 1;
        }
        

        return res.send({status:200, result:result});

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

});

// 주소삭제
// localhost:3000/member/deleteaddr
router.delete('/deleteaddr', checkToken, async function(req, res, next) {
    try{
        const email = req.body.uid;
        const no = req.body.no;
        const dbconn = await db.connect(dburl);
        const collection = dbconn.db(dbname).collection('memberaddr1');
        const result = await collection.deleteOne(
            { _id : no, memberid : email }
        )
        console.log(result);
        if(result.deletedCount === 1 ){
            return res.send({status : 200});
        }
        return res.send({status : 0});
    }
    catch(e) {
        console.error(e);
        res.send({status : -1, message:e});
    }

});

// 주소수정
// localhost:3000/member/updateaddr
router.put('/updateaddr', checkToken, async function(req, res, next) {
    try{
        const email = req.body.uid;
        const no = req.body.no;        
        const address = req.body.address;
        
        const dbconn = await db.connect(dburl);
        const collection = dbconn.db(dbname).collection('memberaddr1');
        const result = await collection.updateOne(
            { _id : no , memberid : email },
            { $set : { address : address } }
        );
        console.log(result);
        
        if(result.modifiedCount === 1 ){
            return res.send({status : 200});
        }
    
        return res.send({status : 0});
    }
    catch(e) {
        console.error(e);
        res.send({status : -1, message:e});
    }


});

// 대표주소설정
// localhost:3000/member/updatechkaddr
router.put('/updatechkaddr', checkToken, async function(req, res, next) {
    try{
        const email = req.body.uid;
        const no = req.body.no;
        const dbconn = await db.connect(dburl);
        const collection = dbconn.db(dbname).collection('memberaddr1');
        
        // 전체적으로 chk를 0으로 변경
        const result = await collection.updateMany(
            { memberid : email },
            { $set : {chk : 0} }
        )
        console.log(result);

        if(result.matchedCount > 0 ){
            const result1 = await collection.updateOne(
                { _id : no, memberid : email },
                { $set : { chk : 1 } }
            );

            if(result1.modifiedCount === 1 ){
                return res.send({status : 200});
            }
        }
        return res.send({status : 0});
    }
    catch(e) {
        console.error(e);
        res.send({status : -1, message:e});
    }

});

파일명 src/components/mypage/Menu5.vue

<template>
    <div>
        <h3>주소관리</h3>

        <input type="text" v-model="state.address" placeholder="주소입력"/>
        <button @click="handleAddress">주소등록</button>
        <hr />
        <div v-if="state.items"></div>
        <table border="1">
            <tr>
                <th>선택</th>
                <th>주소</th>
                <th>버튼</th>
            </tr>
            <tr v-for="(item, idx) in state.items" :key="item">
                <td>{{item.chk}}</td>
                <td><input type="text" v-model="item.address"></td>
                <td>
                    <button @click="handleAddressUpdate(idx)">수정</button>
                    <button @click="handleAddressDelete(item._id)">삭제</button>
                    <button @click="handleChkUpdate(item._id)">대표주소설정</button>
                </td>
            </tr>
        </table>

    </div>
</template>

<script>
import { onMounted, reactive } from 'vue';
import axios from 'axios';
export default {
    setup () {
        const state = reactive({
            address : '',
            token : sessionStorage.getItem("TOKEN"),
        });


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

        const handleLoadData = async() =>{
            const url = `/member/selectaddr`;
            const headers = {"Content-Type":"application/json", "token":state.token};
            const response = await axios.get(url, {headers})
            console.log('M5 => handleLoadData',response.data.result);
            if( response.data.status === 200 ){
                state.items = response.data.result;
            }

        };

        const handleAddress = async() => {
            const url = `/member/insertaddr`;
            const headers = {"Content-Type":"application/json", "token":state.token};
            const body ={
                address : state.address
            }
            const response = await axios.post(url, body, {headers})
            if(response.data.status === 200 ){
                alert('주소가 등록 되었습니다.');
                handleLoadData();
            }
        };

        const handleAddressDelete = async(no) => {
            if(confirm('삭제 하시겠습니까?')){
                const url = `/member/deleteaddr`;
                const headers = {"Content-Type":"application/json", "token":state.token};
                const body = {no:no}

                const response = await axios.delete(url, {headers:headers, data:body})
                if(response.data.status === 200){
                    alert('삭제되었습니다.')
                    handleLoadData();
                }
            }
        };

        const handleChkUpdate = async(no) => {
            if(confirm('대표주소로 변경 하시겠습니까?')){
                const url = `/member/updatechkaddr`;
                const headers = {"Content-Type":"application/json", "token":state.token};
                const body = {no:no};

                const response = await axios.put(url, body, {headers:headers});
                if(response.data.status === 200){
                    alert('변경되었습니다.')
                    handleLoadData();
                }
            }
        };

        const handleAddressUpdate = async(idx) => {
            if(confirm('주소를 변경 하시겠습니까?')){
                const url = `member/updateaddr`;
                const headers = {"Content-Type":"application/json", "token":state.token};
                const body = { no:state.items[idx]._id, address : state.items[idx].address };

                const response = await axios.put(url, body, {headers});
                console.log(response);
                if(response.data.status === 200){
                    alert('변경되었습니다.')
                    handleLoadData();
                }
            }
        }

        return {state, handleAddress, handleAddressDelete, handleChkUpdate, handleAddressUpdate}
    }
}
</script>

<style lang="scss" scoped>

</style>

vue vuetify


vue의 CMD에서 npm run build 해서 vue 폴더에 dist파일 생성
dist파일 안에 있는 파일을 node의 public 폴더 안에 복사함
그후 백엔드 주소로 들어가면 vue 실행한 화면 실행


vue create vue_20220221
cd vue_20220221
vue add vuetify => Vuetify 3 Preview (Vuefity 3) 선택
npm update --force
npm run serve

vue create vue vue_20220221
3ver선택 vue_20220221폴더의 CMD창에서 vue add vuetify 실행3ver 사용
npm update --force후 npm run serve


파일명 routes/board.js의 일부

// CKEDitor내용 저장
// localhost:3000/board/ckeditor_save
router.post('/ckeditor_save', upload.single("image"), async function(req, res, next) { 
    console.log(req.body.content);
    return res.send({status : 200});
});


// CKEDitor에서 첨부하는 이미지를 보관하는 곳
// localhost:3000/board/ckeditor_image
router.post('/ckeditor_image', upload.single("image"), async function(req, res, next) { 
    //req로 데이터가 들어옴 res로 처리 결과가 나감
    try{
        // 1. DB접속
        const dbconn = await db.connect(dburl);
        // 2. DB선택 및 컬렉션 선택
        const collection = dbconn.db(dbname).collection('sequence');

        // 3. 시퀀스에서 값을 가져오고, 그 다음을 위해서 가지고 올때 값 증가
        const result = await collection.findOneAndUpdate(
            { _id  : 'SEQ_BOARD1_NO' }, // 가저오기 위한 조건
            { $inc : {seq : 1} }      // seq갑을 1 증가시킴
        );
        

        const obj = {
            _id      : result.value.seq,        
            filename : req.file.originalname,
            filedata : req.file.buffer,
            filetype : req.file.mimetype,
            filesize : req.file.size,            
        };

        // 추가할 컬렉션 선택
        const collection1 = dbconn.db(dbname).collection('boardimage1');
        // 추가하기
        const result1     = await collection1.insertOne(obj);
        // 결과 확인
        if(result1.insertedId === result.value.seq) {
            return res.send({status : 200});
        }
        // console.log(result1);
        // console.log(req.body);
        // console.log(req.file);
        return res.send({status : 0});
    }
    catch(e){
        console.error(e);
        res.send({status : -1, message:e});
    }  
});

파일명 src/components/UploadAdapter.js

export default class UploadAdapter {
    constructor( loader ) {
        // The file loader instance to use during the upload.
        this.loader = loader;
    }

    // Starts the upload process.
    upload() {
        return this.loader.file
            .then( file => new Promise( ( resolve, reject ) => {
                this._initRequest();
                this._initListeners( resolve, reject, file );
                this._sendRequest( file );
            } ) );
    }

    // Aborts the upload process.
    abort() {
        if ( this.xhr ) {
            this.xhr.abort();
        }
    }

    // Initializes the XMLHttpRequest object using the URL passed to the constructor.
    _initRequest() {
        const xhr = this.xhr = new XMLHttpRequest();

        xhr.open( 'POST', '/board/ckeditor_image', true );
        xhr.responseType = 'json';
    }

    // Initializes XMLHttpRequest listeners.
    _initListeners( resolve, reject, file ) {
        console.log(resolve);
        const xhr = this.xhr;
        const loader = this.loader;
        const genericErrorText = `Couldn't upload file: ${ file.name }.`;

        xhr.addEventListener( 'error', () => reject( genericErrorText ) );
        xhr.addEventListener( 'abort', () => reject() );
        xhr.addEventListener( 'load', () => {
            const response = xhr.response;
            console.log(response); // res.send({status:200, url:'aaa'}); url이 오면 url로 나타남 생략하면 자동으로 표시

            if ( !response || response.error ) {
                return reject( response && response.error ? response.error.message : genericErrorText );
            }

            resolve({
                default: response.url
            });
        } );

        if ( xhr.upload ) {
            xhr.upload.addEventListener( 'progress', evt => {
                if ( evt.lengthComputable ) {
                    loader.uploadTotal = evt.total;
                    loader.uploaded = evt.loaded;
                }
            } );
        }
    }

    // Prepares the data and sends the request.
    _sendRequest( file ) {
        // Prepare the form data.
        const data = new FormData();

        data.append( 'image', file );

        // Send the request.
        this.xhr.send( data );
    }
}

파일명 src/App.vue

<template>
  <v-app>
    <v-main >

      <v-btn depressed color="primary" @click="state.menu = 1"></v-btn>
      &nbsp;
      <v-btn depressed color="primary" @click="state.menu = 2">글쓰기</v-btn>
      <hr />
      
      <hello-world v-if="state.menu === 1"/>
      <board-write v-if="state.menu === 2"/>

    </v-main>
  </v-app>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue';
import BoardWrite from './components/BoardWrite.vue';
import { reactive } from 'vue';

export default {
  name: 'App',

  components: {
    HelloWorld,
    BoardWrite
  },

  setup(){
    const state = reactive({
      menu : 2,

    })
    return{state}
  }

}
</script>

파일명 vue.config.js

module.exports = {
  pluginOptions: {
    vuetify: {
			// https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vuetify-loader
		}
  },
  devServer : {      
    proxy : {
        '/board' :{
            target       : 'http://localhost:3000',
            changeOrigin : true,
            logLevel     : 'debug'
        },

    },
    port : 8080
  
  }
}

파일명 src/main.js

import { createApp } from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify'
import { loadFonts } from './plugins/webfontloader'

import CKEditor from '@ckeditor/ckeditor5-vue'

loadFonts()

createApp(App)
  .use(vuetify)
  .use(CKEditor)
  .mount('#app')

파일명 src/component/BoardWrite.vue

<template>
    <div>
        <h3>글쓰기</h3>

        {{ editorData }}
        <input type="text" placeholder="제목" />
        <textarea rows="6" placeholder="내용"/>

        <ckeditor :editor="editor" v-model="editorData"  :config="editorConfig"></ckeditor>

        <input type="buttom" value="저장하기" @click="handleSave">

    </div>
</template>

<script>

import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import UploadAdapter from './UploadAdapter.js';
import axios from 'axios';

export default {

    setup () {        

        return {}
    },

    
    data(){
        return{
            editor       :ClassicEditor,
            editorData   : '<p>미리추가되는 내용 테스트<p>',
            editorConfig : {
                 extraPlugins:[this.uploader],
            }
        }
    },

    methods : {
        async handleSave() {
            const url = `/board/ckeditor_save`;
            const headers = {"Content-Type":"application/json"};
            const body = {content:this.editorData}
            const response = await axios.post(url,body,{headers})
            console.log(response.data);
        },

        uploader(editor){
            editor.plugins.get( 'FileRepository' ).createUploadAdapter = ( loader ) => {
                return new UploadAdapter( loader );
            };            
        }
    }
}
</script>

<style lang="scss" scoped>

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

0개의 댓글