// 파일명 : ItemUpdatePage.vue _ 수정:서브이미지 삭제
<template>
<div v-for="tmp of state.imageurl" :key="tmp" style="display:inline-block;">
<img :src="tmp.img" style="width:100px" />
<button @click="handleImageDelete(tmp._id)">X</button>
</div>
</template>
<script>
import { reactive, toRefs } from '@vue/reactivity';
import { useRoute } from 'vue-router'
import { onMounted } from '@vue/runtime-core';
import axios from 'axios';
export default {
setup () {
const route = useRoute();
const state = reactive({
no : Number( route.query.no ), //주소창 ?no=557
row : null,
cnt : 2,
images : [null, null, null, null, null ],
imageurl : [],
});
// 물품번호X, 서브이미지의번호
const handleImageDelete = async(no) =>{
// no는 서브이미지의 번호! 삭제 할때는 물품번호가 아니라 서브이미지의 번호가 필요함
// 물품번호를 넣으면 서브이미지 모두 삭제됨
console.log(no);
const url = `/item101/subimagedelete.json?no=${no}`;
const headers = {"Content-Type":"application/json"};
const body = {};
const { data } = await axios.delete(url, {headers:headers, data:body});
console.log(data);
if(data.status === 200) {
handleData1();
}
};
return {
state,
...toRefs(state),
FilePlus,
FileMinus,
handleSubImage,
handleImage,
handleImageDelete,
};
}
}
</script>
<style lang="css" scoped>
</style>
// 파일명 : ContentPage.vue
<template>
<div class="container">
<div class="grid">
<div class="item">
<p><img :src="state.row.img" style="width: 400px;" /></p>
<p><img :src="tmp.img" v-for="tmp of state.imageurl" :key="tmp" style="width: 100; height: 100px;"/></p>
</div>
<div class="item">
<p>물품명: {{ state.row.name }} </p>
<p>물품설명: {{ state.row.content }} </p>
<p>물품가격: {{ state.row.price }} </p>
<select v-model="state.cnt">
<option v-for="tmp of 100" :key="tmp" :value="tmp">{{ tmp }}</option>
</select>
<button @click="handleOrder">주문하기</button>
</div>
</div>
</div>
</template>
<script>
import { reactive } from '@vue/reactivity';
import { useRoute, useRouter } from 'vue-router'
import { onMounted } from '@vue/runtime-core';
import axios from 'axios';
export default {
setup () {
const route = useRoute();
const router = useRouter();
const state = reactive({
no : Number(route.query.no),
row : null,
imageurl : [],
cnt : 0,
});
// 물품 정보
const handleData = async() => {
const url = `/item101/selectone.json?no=${state.no}`;
const headers = {"Content-Type":"application/json"};
const { data } = await axios.get(url, {headers});
console.log(data);
if(data.status === 200) {
state.row = data.result;
}
};
// 서브 이미지 읽기
const handleData1 = async() => {
const url = `/item101/subimagecode.json?code=${state.no}`;
const headers = {"Content-Type":"application/json"};
const { data } = await axios.get(url, {headers});
console.log(data);
if(data.status === 200){
state.imageurl = data.result;
}
};
onMounted(() => {
handleData();
handleData1();
});
const handleOrder = () => {
router.push({
path:'/order',
query:{
no : state.no, // 물품정보(물품번호)
cnt : state.cnt, // 주문수량
userid : '주문자', // 주문자 -> 확보가 안됐으면 로그인페이지로 보내기
}
});
}
return {
state,
handleOrder,
};
}
}
</script>
<style lang="scss" scoped src="../assets/css/itemcontent.css">
</style>
// 파일명 : OrderPage.vue
<template>
<div>
<h3>주문페이지</h3>
{{ state }}
</div>
</template>
<script>
import { reactive } from '@vue/reactivity';
import { useRoute } from 'vue-router';
export default {
setup () {
const route = useRoute();
const state = reactive({
no : Number(route.query.no),
cnt : Number(route.query.cnt),
userid : route.query.userid
});
return {state};
}
}
</script>
<style lang="scss" scoped>
</style>
회원가입 => /member101/insert.json => 키정보 {id:"a", pw:"b", name:"c", email:"a@a.com", age:13 }
아이디중복확인 => /member101/idcheck.json?id=a
로그인 => /member101/select.json => 키정보 {id:"a", pw:"a"}
// 파일명 : JoinPage.vue _컴포넌트 적용시키는 연습
<template>
<div class="container">
<el-form :model="state" label-width="120px">
<el-form-item label="아이디">
<el-input v-model="state.id" style="width: 200px;" @keyup="handleIDCheck()"/>
<label style="padding: 0px 10px;" v-html="state.check"></label>
</el-form-item>
<el-form-item label="암호">
<el-input type="password" v-model="state.pw" style="width: 200px;" />
</el-form-item>
<el-form-item label="암호확인">
<el-input type="password" v-model="state.pw1" style="width: 200px;" />
</el-form-item>
<el-form-item label="이름">
<el-input v-model="state.name" style="width: 200px;" />
</el-form-item>
<el-form-item label="이메일">
<el-input v-model="state.email" style="width: 200px;" />
<label>@</label>
<el-select v-model="state.email1" placeholder="이메일 주소를 선택하세요">
<el-option value="google.com" />
<el-option value="naver.com" />
<el-option value="daum.net" />
</el-select>
</el-form-item>
<el-form-item label="나이">
<el-input type="number" v-model="state.age" style="width: 200px;" />
</el-form-item>
<el-form-item>
<el-button type="info" size="small" :plain="true" @click="handleJoin()">회원가입</el-button>
<el-button type="info" size="small"><router-link to="/" style="text-decoration: none; color: white;">홈으로</router-link></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { reactive } from '@vue/reactivity'
import axios from 'axios';
import { ElMessage } from 'element-plus';
import { useRouter } from 'vue-router';
export default {
setup () {
const router = useRouter();
const state = reactive({
id : '',
pw : '',
pw1 : '',
name : '',
email : '',
email1 : '이메일 주소를 선택하세요',
age : '',
check : '<label style="color: blue">중복확인</label>',
});
const handleIDCheck = async() => {
console.log('handleIDCheck');
if(state.id.length > 0){
const url=`/member101/idcheck.json?id=${state.id}`;
const headers={"Content-Type":"application/json"};
const { data } = await axios.get(url, {headers});
console.log(data);
//result가 1이면 사용불가 0이면 사용 가능
if(data.result === 1) {
state.check = '<label style="color: red">사용 불가</label>'
}
else if(data.result === 0) {
state.check = '<label style="color: greenyellow">사용 가능</label>'
}
else{
state.check = '<label style="color: blue">중복확인</label>'
}
}
else{
state.check = '<label style="color: blue">중복확인</label>'
}
};
const handleJoin = async() => {
if(state.id === '') {
ElMessage({
message: '아이디를 입력하세요',
type: 'warning',
});
return false;
}
if(state.pw === '') {
ElMessage({
message: '암호를 입력하세요',
type: 'warning',
});
return false;
}
if(state.pw1 === '') {
ElMessage({
message: '암호를 다시 입력하세요',
type: 'warning',
});
return false;
}
if(state.pw !== state.pw1) {
ElMessage({
message: '암호를 확인하세요',
type: 'warning',
});
return false;
}
if(state.name === '') {
ElMessage({
message: '이름을 입력하세요',
type: 'warning',
});
return false;
}
if(state.email === '') {
ElMessage({
message: '이메일을 입력하세요',
type: 'warning',
});
return false;
}
if(state.email1 === '이메일 주소를 선택하세요') {
ElMessage({
message: '이메일 주소를 선택하세요',
type: 'warning',
});
return false;
}
if(state.age === '') {
ElMessage({
message: '나이를 입력하세요',
type: 'warning',
});
return false;
}
const url = `/member101/insert.json`;
const headers = {"Content-Type":"application/json"};
const body = {
id : state.id,
pw : state.pw,
name : state.name,
email : `${state.email}@${state.email1}`,
age : state.age
}
const { data } = await axios.post(url, body, {headers});
console.log(data);
if(data.status === 200) {
ElMessage({
message: '회원 가입 성공!',
type: 'success',
});
router.push({path:"/"});
}
};
return {
state,
handleJoin,
handleIDCheck,
}
}
}
</script>
<style lang="css" scoped>
.container {
width: 900px;
padding: 10px;
margin: 10px auto;
}
</style>
============================================
// 파일명 : stores/index.js
import axios from "axios";
import { createStore } from "vuex";
const stores = createStore({
state (){ //변수지정
let tmp = false;
let tmp1 = '';
if(sessionStorage.getItem("TOKEN") !== null) {
tmp = true;
tmp1 = sessionStorage.getItem("ID");
}
return {
logged : tmp,
userid : tmp1,
defaultActive : '/',
}
},
getters:{ // 가지고 가는 내용
getLogged(state) {
return state.logged;
},
getUserid : (state) => {
return state.userid;
},
getDefaultActive(state){
return state.defaultActive;
}
},
mutations: { // 1. 변수값을 변경, 비동기 사용 불가
setDefaultActive(state, value){
state.defaultActive = value;
},
setLogged(state, value) {
state.logged = value;
},
setUserid(state, value) {
state.userid = value;
}
},
actions :{ // 2. 변수값을 변경, 비동기 호출 수행 (백엔드 연동)
async handleData(context) {
const url = ``;
const headers = {};
const {data} = await axios.get(url,{headers});
if(data.status === 200){
context.commit('setUserid', 'aaa');
}
}
}
// 백엔드로 갔다가 다시 받은 데이터를 userid에 넣고싶은데 mutation에 바로 넣을수가 없다!
// actions를 이용하면 mutation을 호출해서 setUserid를 변경가능
// 예시로 입력한 것이고 지금 사용되는것 아님
});
export default stores;
// 파일명 : LoginPage.vue
<template>
<div class="container">
<el-form :model="state" label-width="120px">
<el-form-item label="아이디">
<el-input v-model="state.id" style="width: 200px;"/>
</el-form-item>
<el-form-item label="암호">
<el-input type="password" v-model="state.pw" style="width: 200px;" />
</el-form-item>
<el-form-item>
<el-button type="info" size="small" :plain="true" @click="handleLogin()">로그인</el-button>
<el-button type="info" size="small"><router-link to="/join" style="text-decoration: none; color: white;">회원가입 하러가기</router-link></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { reactive } from '@vue/reactivity'
import axios from 'axios';
import { ElMessage } from 'element-plus';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
export default {
setup () {
const router = useRouter();
const store = useStore();
const state = reactive ({
id : '',
pw : '',
});
const handleLogin = async() => {
const url = `/member101/select.json`;
const headers = {"Content-type":"application/json"};
const body = {
id : state.id,
pw : state.pw,
}
const { data } = await axios.post(url, body, {headers});
console.log(data);
if(data.status === 200) {
// 저장소 보관
sessionStorage.setItem("TOKEN", data.result);
sessionStorage.setItem("ID", data.test._id);
// stores의 state 값을 변경
store.commit('setLogged', true);
store.commit('setUserid', data.test._id);
store.commit('setDefaultActive', "/");
ElMessage({
message: '로그인 성공!',
type: 'success',
});
router.push({path:"/"});
}
else {
ElMessage({
message: '아이디 또는 비밀번호를 확인하세요',
type: 'warning',
});
}
}
return {
state,
handleLogin,
}
}
}
</script>
<style lang="css" scoped>
.container {
width: 900px;
padding: 10px;
margin: 10px auto;
}
</style>
// 파일명 : LogoutPage.vue
<template>
<div>
</div>
</template>
<script>
import { onMounted } from '@vue/runtime-core';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
export default {
setup () {
const store = useStore()
const router = useRouter();
onMounted(async() => {
if(await confirm('로그아웃할까요?')) {
sessionStorage.removeItem("TOKEN");
sessionStorage.removeItem("ID");
//stores의 mutations state값을 변경
store.commit('setLogged', false);
store.commit('setUserid', '');
// 예시) stores의 action호출
// store.dispatch('handleData');
}
store.commit('setDefaultActive', "/")
router.push({path:'/'});
});
return {}
}
}
</script>
<style lang="scss" scoped>
</style>
https://antoniandre.github.io/vueper-slides/
npm i vueperslides
// 파일명 : HomePage.vue
<template>
<div class="container">
<h3>홈화면</h3>
<vueper-slides>
<vueper-slide v-for="tmp of slides" :key="tmp" :title="tmp.title" :image="tmp.image">
</vueper-slide>
</vueper-slides>
// 슬라이드 띄우기 위해 컴포넌트 설치
<div class="grid">
<div class="item" v-for="tmp of state.rows" :key="tmp" style="cursor:pointer;" @click="handleContent(tmp._id)">
<img :src="tmp.img" style="width:100%; height: 140px;" />
<p>{{ tmp.name }}</p>
<p>{{ tmp.price }}원</p>
</div>
</div>
</div>
</template>
<script>
import { reactive } from '@vue/reactivity'
import { onMounted } from '@vue/runtime-core';
import axios from 'axios';
import { useRouter } from 'vue-router';
import { VueperSlides, VueperSlide } from 'vueperslides'
import 'vueperslides/dist/vueperslides.css'
export default {
components: {
// 컴포넌트 표기법 VueperSlides(파스칼), vueper-slides(케밥)
VueperSlides, // vueper-slides
VueperSlide // vueper-slide
},
setup () {
const router = useRouter();
const state = reactive({
rows : [],
page : 1,
});
const slides = [
{ title: 'Slide #1', image:'https://picsum.photos/500/300?image=12' },
{ title: 'Slide #2', image:'https://picsum.photos/500/300?image=13' },
{ title: 'Slide #3', image:'https://picsum.photos/500/300?image=14' },
{ title: 'Slide #4', image:'https://picsum.photos/500/300?image=15' },
]
const handleData = async() => {
const url = `/item101/selectlistpage.json?page=${state.page}`;
const headers = {"Content-Type":"application/json"};
const { data } = await axios.get(url, {headers});
console.log(data);
if(data.status === 200){
state.rows = data.result;
}
};
const handleContent = async(no) => {
router.push({path:'/content', query:{no:no}});
};
onMounted(()=>{
handleData();
});
return {
state,
slides,
handleContent,
};
}
}
</script>
<style lang="css" scoped src="../assets/css/home.css">
// scoped는 이 페이지에서만 적용된다는 뜻
</style>
// 파일명 : App.vue _수정:메뉴 기본값 활성화
<template>
<div>
<el-menu :mode="state.mode" :router="state.router" :default-active="state.defaultActive" @select="handleSelect">
// 컴포넌트 event보고 select 써야겠다 정한것
<el-menu-item index="/">홈</el-menu-item>
<el-menu-item index="/seller">판매자</el-menu-item>
<el-menu-item index="/login" v-if="state.logged === false">로그인</el-menu-item>
<el-menu-item index="/join" v-if="state.logged === false">회원가입</el-menu-item>
<el-menu-item index="/logout" v-if="state.logged === true">{{ state.userid }}님 로그아웃</el-menu-item>
</el-menu>
<router-view></router-view>
</div>
</template>
<script>
import { reactive } from '@vue/reactivity'
import { useStore } from 'vuex';
import { computed } from '@vue/runtime-core';
export default {
setup () {
const store = useStore()
const state = reactive({
mode : 'horizontal',
router : true,
logged : computed(()=>store.getters.getLogged),
userid : computed(()=>store.getters.getUserid),
defaultActive : computed(()=>store.getters.getDefaultActive),
});
// 메뉴를 클릭할때 마다 defaultActive를 변경 -> 그렇게 되야지만 로그인, 로그아웃할때 홈으로 활성화됨
// element plus 썼더니 같은페이지에서는 활성화 안되네! 다른 메뉴 클릭할때마다 바꿔줘야함. 다른 component 썼으면 다른 방식으로 해야함...
const handleSelect = (e) => {
console.log(e);
// store의 값을 바꾸기
store.commit('setDefaultActive', e);
}
return {
state,
handleSelect
}
}
}
</script>
<style lang="css" scoped>
</style>
참고)) DOM이란 무엇인가? https://wit.nts-corp.com/2019/02/14/5522