vue

국비 코딩 풀스택 수업 12일차(에어컨 안되는 날)

비루블 2022. 7. 6. 13:35

오전일과

Mypage1Page.vue(복습 + 핸들 기입)

ItemInsertPage.vue (물품 등록 개선)

itemPage.vue (물품 게시판 개선)

 


Mypage1Page.vue

<template>
  마이페이지1
  <div class="container">
    <el-tabs tab-position="left" style="height: 300px" class="demo-tabs">
      <el-tab-pane label="회원정보변경">
        <el-form-item label="이름">
          <el-input
            style="width: 150px"
            v-model="state.username"
            type="text"
            autocomplete="off"
          />
        </el-form-item>
        <el-form-item label="나이">
          <el-input
            style="width: 150px"
            v-model="state.userage"
            type="number"
            autocomplete="off"
          />
        </el-form-item>
        <el-button @click="handleUpdate">회원정보 수정</el-button>
      </el-tab-pane>
      <el-form label-width="150px">
        <el-tab-pane label="암호변경">
          <el-form-item label="현재 비밀번호">
            <el-input
              style="width: 200px"
              v-model="state.userpw"
              type="password"
              autocomplete="off"
            />
          </el-form-item>
          <el-form-item label="바꿀 비밀번호">
            <el-input
              style="width: 200px"
              v-model="state.userpw1"
              type="password"
              autocomplete="off"
            />
          </el-form-item>
          <el-form-item label="바꿀 비밀번호 확인">
            <el-input
              style="width: 200px"
              v-model="state.userpw2"
              type="password"
              autocomplete="off"
            />
          </el-form-item>
          <el-button @click="handleUpdatepw">비밀번호 변경</el-button>
        </el-tab-pane>
      </el-form>
      <el-tab-pane label="회원탈퇴">
        <el-form-item label="비밀번호">
          <el-input
            style="width: 200px"
            v-model="state.userpw"
            type="password"
            autocomplete="off"
          />
        </el-form-item>
        <el-button @click="handleDelete">회원탈퇴</el-button>
        <el-button>취소</el-button>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
import { reactive } from "@vue/reactivity";
import axios from "axios";
import { onMounted } from "@vue/runtime-core";
import { useRouter } from 'vue-router';
export default {
  setup() {
    const router = useRouter();

    const state = reactive({
      username: "",
      userage: 0,
      userpw: "",
      userpw1: "",
      userpw2: "",
      token: sessionStorage.getItem("TOKEN"),
    });

    const handleData = async () => {
      const url = `/member101/selectone.json`;
      const headers = {
        "Content-Type": "application.json",
        auth: state.token,
      };
      const { data } = await axios.get(url, { headers });
      console.log(data);
      //내 정보 데이터를 받아옴
      state.username = data.result.name;
      state.userage = data.result.age;
    };

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

    const handleUpdate = async () => {
      const url = `/member101/update.json`;
      const headers = {
        "Content-Type": "application/json",
        auth: state.token,
      };
      const body = {
        name: state.username,
        age: Number(state.userage),
      };
      const { data } = await axios.put(url, body, { headers });
      if (data.status === 200) {
        alert("변경되었습니다.");
      } else {
        alert("요청 실패되었습니다.");
      }
    };

    const handleUpdatepw = async () => {
      //유효성 검사
      if (state.userpw1 !== state.userpw2) {
        alert("변경할 비밀번호를 같게 입력해주세요");
        return false; // 펑션 종료됨
      }
      const url = `/member101/updatepw.json`;
      const headers = {
        "Content-Type": "application/json",
        auth: state.token,
      };
      const body = {
        pw: state.userpw,
        newpw: state.userpw1, //모르겠음
      };
      const { data } = await axios.put(url, body, { headers });
      if (data.status === 200) {
        alert("변경되었습니다.");
      } else {
        alert("요청 실패되었습니다.");
      }
    };

    const handleDelete = async () => {
      const url = `/member101/delete.json`;
      const headers = {
        "Content-Type": "application/json",
        auth: state.token,
      };
      const body = {
        pw: state.userpw,
      };
      const { data } = await axios.delete(url, {
        headers: headers,
        data: body,
      });
      console.log(data.status);
      if (data.status === 200) {
        alert("탈퇴 되었습니다.");
        // sessionStorage.removeItem("TOKEN");
        router.push({path:'/logout1'})
        //로그아웃 페이지로 가면 토큰 삭제됨.
      } else {
        alert("요청 실패되었습니다.");
      }
    };

    return { state, handleData, handleUpdate, handleUpdatepw, handleDelete };
  },
};
</script>

<style lang="css" scoped>
.container {
  width: 700px;
  border: 1px solid #cccccc;
  padding: 10px;
  margin: 0 auto;
}
</style>


handleUpdate
handleUpdatepw
handleDelete
만듬

 


iteminsertpage 개선

<template>
    <div class="container">

        <h3>물품등록</h3>

        <el-form label-width="120px">
            <el-form-item label="물품명">
                <el-input v-model="state.name" style="width:100px"/>
            </el-form-item>
            
            <el-form-item label="물품내용">
                <el-input v-model="state.content" type="textarea" rows="6" />
            </el-form-item>

            <el-form-item label="가격">
                <el-input v-model="state.price" type="number" />
            </el-form-item>

            <el-form-item label="수량">
                <el-input v-model="state.quantity" type="number" />
            </el-form-item>

            <el-form-item label="대표이미지">
                <img :src="state.img" style="width:100px" />
                <input type="file" @change="handleImage($event)" /><br />
            </el-form-item>

            {{state.uploadfiles}}
            <el-form-item label="대표이미지">
                <el-upload :file-list="state.uploadfiles" 
                    list-type="picture-card" :auto-upload="false">
                    <el-icon><Plus /></el-icon>

                    <template #file="{ file }">
                        <div>
                            <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
                            <span class="el-upload-list__item-actions">
                                <span class="el-upload-list__item-preview"
                                    @click="handlePictureCardPreview(file)">
                                    <el-icon><zoom-in /></el-icon>
                                </span>
            
                                <span v-if="!disabled" class="el-upload-list__item-delete"
                                    @click="handleRemove(file)">
                                    <el-icon><Delete /></el-icon>
                                </span>
                            </span>
                        </div>
                    </template>
                </el-upload>
            </el-form-item>

            <el-form-item>
                <el-button type="primary" @click="handleInsert">등록</el-button>
                <el-button>Cancel</el-button>
            </el-form-item>
        </el-form>
        <el-dialog  v-model="dialogVisible">
            <img style="width: 100%;" w-full :src="dialogImageUrl" alt="Preview Image" />
        </el-dialog>
    </div>
</template>

<script>
import { reactive, ref } from '@vue/reactivity'
import axios from 'axios';
import { useRouter } from 'vue-router';
import { Delete, Plus, ZoomIn } from '@element-plus/icons-vue'
export default {
    components : {
        Plus,
        Delete,
        ZoomIn
    },

    setup () {

        const router = useRouter();

        const dialogImageUrl = ref(''); // 다이얼로그에 표시할 이미지
        const dialogVisible = ref(false); // 다이얼로그 표시유무
        const disabled = ref(false);


        const state = reactive({
            img     : require('../assets/imgs/noimage.png'),
            name    : 'aaa',
            content : 'bbb',
            price   : '1000',
            quantity : '800',
            file    : '',
            uploadfiles : [], //첨부하는 이미지를 보관하는 배열
        });

        const handleImage = (e) => {
            //실제 첨부한 파일 정보는 e.target.files[0]
            console.log(e.target.files[0]);
            console.log(e.target.files.length);
            if(e.target.files.length > 0){
                state.file = e.target.files[0];
                state.img  = URL.createObjectURL( e.target.files[0] );
            }
            else {
                state.file = '';
                state.img  = require('../assets/imgs/noimage.png');
            }
        };

        const handleInsert = async() => {

            if(state.uploadfiles.length <= 0){
                alert('이미지 첨부해라')
                return false;
            }


            console.log('handleInsert');
            const url = `/item101/insert.json`;
            const headers = {"Content-Type":"multipart/form-data"};
            let body = new FormData();
            body.append("name", state.name);
            body.append("price", Number(state.price));
            body.append("quantity", Number(state.quantity));
            body.append("content", state.content);
            //body.append("image", state.file);
            body.append("image", state.uploadfiles[0].raw);

            //const body = {name:state.name ... , image:state.file};

            //response의 하위 객체 data
            const { data } = await axios.post(url, body, {headers});
            console.log(data);

            if(data.status === 200){
                router.push({path:'/item'});
            }
        };

        const handlePictureCardPreview = (file) =>{
            console.log(file);
            // 파일의 url의 정보 dialogImageUrl에 추가
            dialogImageUrl.value = file.url; 
            // 다이얼로그 표시 유무 변경
            dialogVisible.value = true;
        }

        const handleRemove = (file) => {
            console.log(file);

            // state.uploadfiles => [{}, {}, {}]
            for(let i=0; i<state.uploadfiles.length; i++) {
                if(state.uploadfiles[i].uid === file.uid){
                    // splice => 배열의 i번쨰의 1개 삭제
                    state.uploadfiles.splice(i, 1);
                    break;
                }
            }
        }

        return {state, 
            dialogImageUrl,
            dialogVisible,
            disabled,
            handleImage, 
            handleInsert, 
            handlePictureCardPreview,
            handleRemove
        }
    }
}
</script>

<style lang="css" scoped>
    .container {
        width : 700px;
        border:1px solid #cccccc;
        padding: 20px;
    }
</style>

el폼사용


다중 이미지 설정~~~@@@@@@@@@@@

<el-form-item label="대표이미지">
    <el-upload :file-list="state.uploadfiles" 
        list-type="picture-card" :auto-upload="false">
        <el-icon><Plus /></el-icon>

        <template #file="{ file }">
            <div>
                <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
                <span class="el-upload-list__item-actions">
                    <span class="el-upload-list__item-preview"
                        @click="handlePictureCardPreview(file)">
                        <el-icon><zoom-in /></el-icon>
                    </span>

                    <span v-if="!disabled" class="el-upload-list__item-delete"
                        @click="handleRemove(file)">
                        <el-icon><Delete /></el-icon>
                    </span>
                </span>
            </div>
        </template>
    </el-upload>
</el-form-item>


이미지란 + 나오게하기
import { Delete, Download, Plus, ZoomIn } from '@element-plus/icons-vue'
+ 컴포넌트 등록

components : {
    Plus,
    Delete,
    ZoomIn
}
const state = reactive({
    img     : require('../assets/imgs/noimage.png'),
    name    : 'aaa',
    content : 'bbb',
    price   : '1000',
    quantity : '800',
    file    : '',
    uploadfiles : [], //첨부하는 이미지를 보관하는 배열
});

 

uploadfiles : []

업로드한 이미지 배열로 보관

 


다중 이미지 보내기(서버가 하나만 받아서 그냥 [0])

body.append("image", state.uploadfiles[0].raw);


이미지 줌인시 해상도 큰 화면이면 튀어나가서 스타일 추가

<img style="width: 100%;" w-full :src="dialogImageUrl" alt="Preview Image" />



이미지 삭제
uid로 삭제(이름은 같을 수 있으니)

const handleRemove = (file) => {
    console.log(file);

    // state.uploadfiles => [{}, {}, {}]
    for(let i=0; i<state.uploadfiles.length; i++) {
        if(state.uploadfiles[i].uid === file.uid){
            // splice => 배열의 i번쨰의 1개 삭제
            state.uploadfiles.splice(i, 1);
            break;
        }
    }
}



다이얼로그 사용

ref는 사용할때 value 사용

const dialogImageUrl = ref(''); // 다이얼로그에 표시할 이미지
const dialogVisible = ref(false); // 다이얼로그 표시유무
const disabled = ref(false);
const handlePictureCardPreview = (file) =>{
    console.log(file);
    // 파일의 url의 정보 dialogImageUrl에 추가
    dialogImageUrl.value = file.url; 
    // 다이얼로그 표시 유무 변경
    dialogVisible.value = true;
}

 


ItemPage.vue
아이템페이지 개선

<template>
    <div class="container">
        <h3>물품목록</h3>
        <router-link to="/iteminsert">물품등록</router-link>


        <el-table :data="state.row" style="width: 100%"
            :default-sort="{ prop: 'name', order: 'ascending' }">
            <el-table-column prop="_id" label="번호" width="60" />
            <el-table-column sortable prop="name" label="물품명" />
            <el-table-column prop="content" label="내용" />
            <el-table-column prop="price" label="가격" width="100" />
            <el-table-column prop="quantity" label="수량" width="100" />
            <el-table-column prop="regdate" label="등록일" />

            <el-table-column label="이미지" width="120">
                <template #default="scope">
                    <img :src="scope.row.img" style="width:50px"/>
                </template>
            </el-table-column>

            <el-table-column label="버튼">
                <template #default="scope">
                    <el-button size="small" @click="handleEdit(scope.$index, scope.row)">Edit</el-button>
                    <el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)">Delete</el-button>
                </template>
            </el-table-column>
        </el-table>
        

        <el-pagination background layout="prev, pager, next" 
            :page-size="12"
            @current-change="handlePage" :total="state.total" />


        <!-- 삭제 확인용 다이얼로그 -->
        <el-dialog v-model="state.dialogVisible" 
            title="삭제" width="30%">
            <span>삭제 할까요?</span>
            <template #footer>
                <span class="dialog-footer">
                    <el-button type="primary" @click="handleDeleteAction">확인</el-button>
                    <el-button @click="state.dialogVisible=false">취소</el-button>
                </span>
            </template>
        </el-dialog>


        <!-- 수정용 다이얼로그 -->
        <el-dialog v-model="state.dialogVisible1" 
            title="수정" width="50%">

            <el-form label-width="120px">
                <el-form-item label="물품번호">
                    <el-input v-model="state.currentRow._id" readonly />
                </el-form-item>
                <el-form-item label="물품명">
                    <el-input v-model="state.currentRow.name" />
                </el-form-item>
                <el-form-item label="물품설명">
                    <el-input v-model="state.currentRow.content"
                        type="textarea" rows="6" />
                </el-form-item>
                <el-form-item label="가격">
                    <el-input v-model="state.currentRow.price"
                        type="number" />
                </el-form-item>
                <el-form-item label="수량">
                    <el-input v-model="state.currentRow.quantity" 
                        type="number" />
                </el-form-item>
            </el-form>


            <template #footer>
                <span class="dialog-footer">
                    <el-button type="primary" @click="handleUpdateAction">확인</el-button>
                    <el-button @click="state.dialogVisible1=false">취소</el-button>
                </span>
            </template>
        </el-dialog>

    </div>
</template>

<script>
import { reactive } from '@vue/reactivity'
import axios from 'axios';
import { onMounted } from '@vue/runtime-core';
export default {
    setup () {

        const state = reactive({
            dialogVisible : false,  // 삭제용 다이얼로그
            dialogVisible1 : false, // 수정용 다이얼로그

            page : 1,
            row  : [], //[{},{}...{}]   // 목록
            total : 0,    // 전체 개시물 개수
            pages : 0,   
            currentRow : '', 
        });

        const handleData = async() => {
            const url = `/item101/selectlistpage.json?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.row = response.data.result;
                state.total = response.data.total;
                state.pages 
                    = Math.floor( (response.data.total-1)/12 )+1;
            }
        };

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

        const handlePage = (page) => {
            console.log(page);
            state.page = page;
            handleData();
        };

        const handleDelete = (idx, row) =>{
            console.log(idx, row);
            state.currentRow = row; // 현재 클릭한 내용의 정보를 보관
            state.dialogVisible = true; // 다이얼로그 띄우기
        }

        const handleDeleteAction = async() => {
            const url = `/item101/delete.json?no=${state.currentRow._id}`;
            const headers = {"Content-Type":"application/json"};
            const { data } 
                = await axios.delete(url, {headers:headers, data:{}});
            console.log(data);
            if(data.status === 200){
                state.page = 1;
                handleData();
                state.dialogVisible = false;
            }
        }

        const handleEdit = (idx, row) =>{
            console.log(idx, row);
            state.currentRow = row; // 현재 클릭한 내용의 정보를 보관
            state.dialogVisible1 = true; // 다이얼로그 띄우기
        }

        const handleUpdateAction = async() =>{
            const url = `/item101/update.json`;
            const headers = {"Content-Type" : "application/json"};
            const body = {
                no : Number(state.currentRow._id),
                name : state.currentRow.name,
                content : state.currentRow.content,
                price : Number(state.currentRow.price),
                quantity : Number(state.currentRow.quantity),
            }


            const {data} = await axios.put(url, body, {headers});
            console.log(data);
            if(data.status === 200){
                handleData();
                state.dialogVisible1 = false; // 다이얼로그 숨기기
            }
        }

        return {
            state, 
            handlePage, 
            handleDelete,
            handleDeleteAction,
            handleEdit,
            handleUpdateAction
        }
    }
}
</script>

<style lang="css" scoped>
    .container {
        width   : 100%;
        padding : 20px;
    }
</style>

confirm 확인 절차
components data 컴포넌트 데이터의 이동을 배움

<el-table :data="state.row" style="width: 100%"
            :default-sort="{ prop: 'name', order: 'ascending' }">
            <el-table-column prop="_id" label="번호" width="60" />
            <el-table-column sortable prop="name" label="물품명" />
            <el-table-column prop="content" label="내용" />
            <el-table-column prop="price" label="가격" width="100" />
            <el-table-column prop="quantity" label="수량" width="100" />
            <el-table-column prop="regdate" label="등록일" />

            <el-table-column label="이미지" width="120">
                <template #default="scope">
                    <img :src="scope.row.img" style="width:50px"/>
                </template>
            </el-table-column>

            <el-table-column label="버튼">
                <template #default="scope">
                    <el-button size="small" @click="handleEdit(scope.$index, scope.row)">Edit</el-button>
                    <el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)">Delete</el-button>
                </template>
            </el-table-column>
        </el-table>
        

        <el-pagination background layout="prev, pager, next" 
            :page-size="12"
            @current-change="handlePage" :total="state.total" />


        <!-- 삭제 확인용 다이얼로그 -->
        <el-dialog v-model="state.dialogVisible" 
            title="삭제" width="30%">
            <span>삭제 할까요?</span>
            <template #footer>
                <span class="dialog-footer">
                    <el-button type="primary" @click="handleDeleteAction">확인</el-button>
                    <el-button @click="state.dialogVisible=false">취소</el-button>
                </span>
            </template>
        </el-dialog>


        <!-- 수정용 다이얼로그 -->
        <el-dialog v-model="state.dialogVisible1" 
            title="수정" width="50%">

            <el-form label-width="120px">
                <el-form-item label="물품번호">
                    <el-input v-model="state.currentRow._id" readonly />
                </el-form-item>
                <el-form-item label="물품명">
                    <el-input v-model="state.currentRow.name" />
                </el-form-item>
                <el-form-item label="물품설명">
                    <el-input v-model="state.currentRow.content"
                        type="textarea" rows="6" />
                </el-form-item>
                <el-form-item label="가격">
                    <el-input v-model="state.currentRow.price"
                        type="number" />
                </el-form-item>
                <el-form-item label="수량">
                    <el-input v-model="state.currentRow.quantity" 
                        type="number" />
                </el-form-item>
            </el-form>


            <template #footer>
                <span class="dialog-footer">
                    <el-button type="primary" @click="handleUpdateAction">확인</el-button>
                    <el-button @click="state.dialogVisible1=false">취소</el-button>
                </span>
            </template>
        </el-dialog>

해당 코드는 데이터를 들고와서 화면에 표시해줌

for(tmp in state.row)랑 같은 말임.

데이터를 하나씩 받아와서 한줄씩 출력

 

페이지네이션

<el-pagination style="width: 340px; margin: 0 auto;"
background layout="prev, pager, next" 
:page-size="12"
@current-change="handlePage" :total="state.total" />

에디트 버튼, 딜리트 버튼하고 끝냄

너무 더워서 죽을거같음