사람들은 세 가지 부류로 나눌 수 있다. 첫째, 우리를 이용하려는 사람, 즉 원수이다. 둘째, 우리를 이용하려는 동시에 우리에게 이용되어지려는 사람, 즉 친지(親知)이다. 셋째, 우리가 존경하고 또 그를 위해 힘있는 대로 도우려고 하는 사람, 즉 친구이다. -소포클레스
3)register_page.vue(회원가입 페이지)

<template>
<v-container>
<v-row class="text-center">
<v-col col="12" class="text-center my-5">
<h1 class="display-1">회원가입 페이지</h1>
</v-col>
</v-row>
<v-row>
<!-- 반응형에 따라 다르게 너비 조절 -->
<v-col class="text-center" cols="8" offset="2" sm="6" offset-sm="3">
<!-- 양식의 입력이 제출되면 페이지를 새로 고침하지 않도록 prevent 사용 -->
<form @submit.prevent="fnRegisterUser">
<!-- 필수 입력 사항이 되도록 required 어트리뷰트 적용 -->
<v-text-field name="Email" label="이메일" type="email" v-model="sEmail" required ></v-text-field>
<v-text-field name="Password" label="비밀번호" type="password" v-model="sPassword" required ></v-text-field>
<!-- 비밀번호 확인이 맞는지 검사하도록 rules 어트리뷰트 사용 -->
<v-text-field name="ConfirmPassword" label="비밀번호 확인" type="password" v-model="sConfirmPassword" required
:rules="[fnCompasrePassword]"
></v-text-field>
<!-- 시간 지연 상태이면 버튼을 사라지게 함 -->
<v-btn type="submit" v-if="!fnGetLoading" color="orange" dark >회원가입</v-btn>
<!-- 시간 지연 상태이면 회전 프로그레스 원 표시 -->
<v-progress-circular
v-if="fnGetLoading"
:size="70"
:width="7"
color="grey lighten-1"
indeterminate
></v-progress-circular>
<v-alert type="error" class="mt-3"
dismissible v-model="fnAlert">{{fnGetErrMsg}}</v-alert>
</form>
</v-col>
</v-row>
</v-container>
</template>
<script>
console.log(" 현재 페이지 : register-page");
export default {
name: 'register_page',
mounted:function(){
//마운트시 초기화
this.$store.dispatch("setInitLoading");
},
data(){
return{
sEmail:"", //이메일 입력값 임시 저장
sPassword:"", //비밀번호 입력값 임시 저장
sConfirmPassword:"" //비밀번호 입력 확인값 임시 저장
}
},
computed:{
//비밀번호와 비밀번호 확인 값이 일치하는지 검사
fnCompasrePassword(){
if(this.sPassword ==this.sConfirmPassword)return true;
else return "비밀번호가 일치하지 않습니다.!"
},
//오류 메시지 스토어에서 읽어서 반환
fnGetErrMsg(){
//state.sErrorMessage
return this.$store.getters.fnGetErrorMessage;
},
//시간 지연 상태 스토어에서 읽어서 반환
fnGetLoading(){
return this.$store.getters.fnGetLoading
},
fnAlert(){
//오류 메시지 표시 여부
return this.$store.getters.fnGetErrorMessage.length===0?false:true;
}
},
methods:{
//스토어에 이메일 회원가입 처리 요청
fnRegisterUser(){
if(this.fnCompasrePassword==true){
this.$store.dispatch("fnRegisterUser", {
pEmail:this.sEmail,
pPassword:this.sPassword
})
}
}
},
//여기서는 다음 warch 를 사용하지 않고 오류 메시지를 처리를 진행봤다..
// watch:{
// //fnGetErrMag() 함수가 오류 메시지를 반환하면 오류 메시지 표시
// fnGetErrMsg(pMsg){
// if(pMsg) this.bAlert=true;
// },
// //bAlert값이 false 로 바뀌면 에러 페이지 초기화
// bAlert(pValue){
// if(pValue===false)this.$store.commit("fnSetErrorMessage", "");
// }
// }
}
</script>
4)login_page.vue(로그인 페이지)

<template>
<v-container flow>
<v-row>
<v-col cols="12" class="text-center my-5">
<h1 class="display-1">로그인 페이지</h1>
</v-col>
</v-row>
<v-row>
<!-- 반응형에 따라 다르게 너비 조절 -->
<v-col class="text-center" cols="8" offset="2" sm="6" offset-sm="3">
<!-- 양식의 입력이 제출 되면 페이지를 다시 로드 하지 않도록 prevent
사용 -->
<form @submit.prevent="fnDoLogin">
<!-- 필수 입력사항이 되도록 required 어트리뷰트 적용 -->
<v-text-field name="Email" label="이메일" type="email" v-model="sEmail" required>
</v-text-field>
<v-text-field name="Password" label="비밀번호" type="password" v-model="sPassword" required>
</v-text-field>
<!-- 시간지연상태인 경우 버튼은 사라지게 함 -->
<v-btn type="submit" v-if="!fnGetLoading" color="orange" dark>
로그인
</v-btn>
<!-- 시간지연의 경우 회전 프로그레스 원 표시 -->
<v-progress-circular v-if="fnGetLoading" indeterminate :width="7" :size="70" color="grey lighten-1">
</v-progress-circular>
<!-- 오류 메시지가 있을 경우 표시 -->
<v-alert class="mt-3" type="error" dismissible v-model="bAlert">
{{ fnGetErrMsg }}
</v-alert>
</form>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
data() {
return {
bAlert: false, // 오류 메시지 표시 여부
sEmail: '', // 이메일 입력값 임시 저장
sPassword: '' // 비밀번호 입력값 임시 저장
}
},
computed: {
// 오류메시지 스토어에서 읽어서 반환
fnGetErrMsg() {
return this.$store.getters.fnGetErrorMessage;
},
// 시간지연상태 스토어에서 읽어서 반환
fnGetLoading() {
return this.$store.getters.fnGetLoading;
}
},
methods: {
// 스토어에 이메일 로그인 처리 요청
fnDoLogin() {
this.$store.dispatch('fnDoLogin', {
pEmail: this.sEmail,
pPassword: this.sPassword
})
}
},
watch: {
// fnGetErrMsg 함수가 오류메시지를 반환하면 오류 메시지 표시
fnGetErrMsg(pMsg) {
if (pMsg) this.bAlert = true;
},
// bAlert 값이 false로 바뀌면 오류메시지 초기화
bAlert(pValue) {
if (pValue == false) this.$store.commit('fnSetErrorMessage', '');
}
}
}
</script>
5)error_page.vue(에러페이지)

<template>
<v-container>
<v-row class="text-center">
<v-col cols="12" class="text-center mt-5">
<h1 class="display-1 my-1">오류가 발생하였습니다!</h1>
<p class="body-1">페이지를 찾을 수 없습니다.</p>
</v-col>
</v-row>
</v-container>
</template>
<script>
console.log("현재 페이지 : error-page");
export default {
name: 'error_page',
data: () => ({
}),
}
</script>
7. 파이어베이스 호스팅 배포 하기
Vue-Cli 3 을 이용하여 빠르게 PWA( 웹앱 )생성 및 Https 로 파이어 베이스 호스팅 배포 하기
https://macaronics.net/m04/vue/view/2048
2023-04-01 13:55:11
Firebase Function 백엔드 서버 Nodejs 회원 레벨 설정
const functions = require("firebase-functions");
const admin = require('firebase-admin');
const { getAuth } = require('firebase-admin/auth');
const serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
//admin.initializeApp();
const db = admin.firestore();
console.log(functions.config().admin.email);
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// functions.logger.info("Hello logs!", {structuredData: true});
// response.send("Hello from Firebase!");
// });
//exports.createUserLevel = functions.https.onRequest(require('./test'));
// exports.createUser = functions.auth.user().onCreate(async (user) => {
// let set = {level:2}
// if (functions.config().admin.email === user.email && user.emailVerified) set.level = 0;
// console.log("레벨 생성 :");
// await getAuth().setCustomUserClaims(user.uid, set).then(() => {
// // The new custom claims will propagate to the user's ID token the
// // next time a new one is issued.
// });
// });
//등록 처리시
exports.createUser = functions.auth.user().onCreate(async (user) => {
let customClaims = {
admin: false,
accessLevel: 1
};
if (user.email && user.email.endsWith('braverokmc79@gmail.com') && user.emailVerified) {
//관리자일경우
customClaims = {
admin: true,
accessLevel: 9
};
}
await getAuth().setCustomUserClaims(user.uid, customClaims);
});
//firebase store 에 users 정보를 담는 collection 생성
// exports.createUser2 = functions.auth.user().onCreate(async (user) => {
// const { uid, email, displayName, emailVerified, photoURL, disabled } = user;
// let claims = { level: 2 };
// if (functions.config().admin.email === user.email && user.emailVerified) claims.level = 0;
// await getAuth().setCustomUserClaims(uid, claims);
// const d = {
// uid, email, displayName, emailVerified, photoURL, disabled
// }
// const r = await db.collection('users').doc(uid).set(d)
// return r
// });
//const r = await db.collection('users').doc(user.uid).delete();
exports.deleteUser = functions.auth.user().onDelete( (user) => {
return db.collection('users').doc(user.email).delete();
});
2022-04-05 13:07:38
mixins.js
import axios from 'axios';
export default {
methods: {
async $api(url, type, data) {
return (await axios({
method: type,
url,
data
}).catch(e => {
console.log(e);
})).data;
},
$base64(file) {
return new Promise(resolve => {
var a = new FileReader();
a.onload = e => resolve(e.target.result);
a.readAsDataURL(file);
});
},
$currencyFormat(value, format = '#,###') {
if (value == 0 || value == null) return 0;
var currency = format.substring(0, 1);
if (currency === '$' || currency === '₩') {
format = format.substring(1, format.length);
} else {
currency = '';
}
var groupingSeparator = ",";
var maxFractionDigits = 0;
var decimalSeparator = ".";
if (format.indexOf(".") == -1) {
groupingSeparator = ",";
} else {
if (format.indexOf(",") < format.indexOf(".")) {
groupingSeparator = ",";
decimalSeparator = ".";
maxFractionDigits = format.length - format.indexOf(".") - 1;
} else {
groupingSeparator = ".";
decimalSeparator = ",";
maxFractionDigits = format.length - format.indexOf(",") - 1;
}
}
var prefix = "";
var d = "";
// v = String(parseFloat(value).toFixed(maxFractionDigits));
var dec = 1;
for (var i = 0; i < maxFractionDigits; i++) {
dec = dec * 10;
}
var v = String(Math.round(parseFloat(value) * dec) / dec);
if (v.indexOf("-") > -1) {
prefix = "-";
v = v.substring(1);
}
if (maxFractionDigits > 0 && format.substring(format.length - 1, format.length) == '0') {
v = String(parseFloat(v).toFixed(maxFractionDigits));
}
if (maxFractionDigits > 0 && v.indexOf(".") > -1) {
d = v.substring(v.indexOf("."));
d = d.replace(".", decimalSeparator);
v = v.substring(0, v.indexOf("."));
}
var regExp = /\D/g;
v = v.replace(regExp, "");
var r = /(\d+)(\d{3})/;
while (r.test(v)) {
v = v.replace(r, '$1' + groupingSeparator + '$2');
}
return prefix + currency + String(v) + String(d);
}
}
}2021-12-14 03:18:44
macaronics.net 는 그어떠한 동영상, 이미지, 파일등을 직접적으로 업로드 제공을 하지 않습니다. 페이스북, 트위터 등 각종 SNS 처럼 macaronics.net 는 웹서핑을 통하여 각종 페이지위치등을 하이퍼링크, 다이렉트링크, 직접링크등으로 링크된 페이지 주소만을 수집 저장하여 제공하고 있습니다. 저장된 각각의 주소에 연결된 페이지등은 그 페이지에서 제공하는 "서버, 사이트" 상황에 따라 페이지와 내용이 삭제 중단 될 수 있으며 macaronics.net 과는 어떠한 연관 관련이 없음을 알려드립니다. 또한, 저작권에 관련된 문제있는 글이나 기타 저작권에 관련된 문제가 있는 것은 연락주시면 바로 삭제해 드리겠습니다.
댓글 ( 4)
댓글 남기기