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" />
에디트 버튼, 딜리트 버튼하고 끝냄
너무 더워서 죽을거같음