📌 KH 정보교육원 세미 프로젝트
📌 조 장 : 백종국
📌 팀 원 : 김지연 신현아 이여진
📌 기 간 : 2022.07.19 ~ 2022.08.26
- 체육관 관리에 필요한 회원 전용 웹페이지 구현
- 회원제로 운영되는 체육관 관리 시스템 구현
- Intelligent + GYM, 당신이 찾던 똑똑한 운동 공간
: 고객을 만족시킬 수 있고, 고객이 필요로 하는 최적화된 운동 서비스를 제공하는 피트니스센터 웹페이지를 기획함
구현 기능 | 상세 기능 |
---|---|
로그인&회원가입 | * 가입 시 Firebase의 Authentication과 Firestore DB에 회원정보를 저장 * 로그인 상태 유지 기능 및 회원만 마이페이지에 접근 가능 |
메인 페이지 | * 부트스트랩 기반 반응형 UI 제작 * KakaoMap API 기반 지도 추가 * NavBar의 카테고리 주요 내용을 메인페이지에 컴팩트하게 담음 |
About 페이지 | * 사이드바 메뉴명 클릭 시 해당 좌표로 이동하는 스크롤스파이 기능 * 센터정보 소개 셀렉트박스 이벤트 |
운동일지 (마이페이지-1) |
* 오늘의 운동량과 신체변화 기록, 조회가 가능한 대시보드 형태로 구성 * Chart.js 등 총 3개의 차트와 최근 일주일의 기록을 볼 수 있는 테이블이 존재 * 기록된 테이블에서 입력, 수정, 상세보기 기능 * 현재까지 기록한 전체 내용을 불러오는 전체기록 페이지 조회 가능, 이외에 입력, 삭제 기능 |
문의게시판 (마이페이지-2) |
* 사용자 문의글 등록 및 입력 기능 - 최신글이 상단에 오도록 자동순번 매김, 제목-유형-내용 미입력 시 등록할 수 없도록 설정 * 게시글 조회 및 상세조회 - 페이징처리로 한페이지에 게시글 4개씩, 총 페이지수는 3개씩으로 처리, 제목 클릭시 작성한 내용 확인 가능 * 게시글 삭제 - 상세조회 페이지에서 삭제 버튼 클릭 시 해당글 삭제 후 리스트로 이동 |
수강신청 (마이페이지-3) |
* DB에 저장된 수강신청 목록 전체 조회 및 실시간 수강신청 인원 확인 * 신청한 수강 내역을 확인하고 취소할 수 있는 기능 |
회원정보 (마이페이지-4) |
* 로그인한 회원의 정보 상세 조회 및 수정, 회원 탈퇴 기능 |
HTML
과CSS
,Bootstrap
을 활용하여 UI 화면 구현JavaScript
를 활용한 Select 콤보박스 이벤트, 스크롤스파이 기능 등 구현JQuery
를 활용한 버튼 클릭 이벤트, 요소-속성 변경 이벤트 구현- NoSQL 기반
Firebase
를 활용한 데이터 읽기, 저장 등으로 편리한 백엔드 클라우드 환경 구현
- 회사소개(About)페이지 UI 구현
- 수강신청 페이지 UI 및 기능 구현
- 수강신청 내역 조회 및 수강인원 확인
- 수강신청 상세보기, 등록, 삭제 구현
회사소개 페이지는 HTML
과 CSS
, JavaScript
의 기본적인 문법을 활용하여 정적 페이지를 구성하였습니다.
기본적인 UI 구성은 Bootstrap
을 활용하였으며, 센터소개는 콤보박스 이벤트를 활용하였습니다.
오시는 길은 KakaoMap API
를 활용하여 지도에 위치를 표시하였으며, 사이드바의 제목을 누르면 해당 좌표로 이동하는 스크롤스파이 기능을 활용하였습니다.
Javascript 기본문법을 활용하여, 콤보박스에서 선택한 옵션에 해당하는 내용을 회색 박스인 <ul class="items">
에 출력하는 기능입니다.
const cmbbox = document.querySelector('#select_value'); // <select>
const items = document.querySelector('.items'); // <ul>
function addItem() {
if(cmbbox.selectedIndex==0) {
alert('찾으실 센터를 선택해주세요.')
} else {
const text = "IntelliGym "+ cmbbox.options[cmbbox.selectedIndex].text;
const item = createItem(text);
items.appendChild(item);
}
}
// 셀렉트 박스에서 아이템 선택했을 때 이벤트
cmbbox.addEventListener('change', () => {
document.querySelector('.items').innerHTML = "";
addItem(); // 함수 호출
});
center_gangnam
컬렉션 DB에 저장되어 있는 강의내역을 전체 레코드 수만큼 for문을 돌려 데이터를 가져오면, 위 이미지와 같이 콘솔창에 출력된 내용을 확인할 수 있습니다. 이를 ${snapshot.docs[i].data().강의명}
와 같이 데이터를 바인딩하고, HTML 테이블의 class-content
클래스 명을 가진 tbody
에 추가하면(append) 출력된 결과를 화면에서 확인할 수 있습니다.
수강신청 내역은 myclass
컬렉션에 저장되도록 설계를 해두었습니다. 먼저 이 컬렉션의 데이터를 .where("강의번호", "==", classNum)
와 같이 쿼리를 사용하여 myclass
컬렉션과 center_gangnam
컬렉션에 저장된 강의번호가 일치하는 데이터를 가져옵니다. 가져온 데이터를 applyTotal = querySnapshot.size;
와 같이 size로 개수를 구하고 applyTotal에 데이터를 담아 화면에 출력할 수 있습니다. 모든 회원이 수강신청을 할 때마다 개수는 변동되므로, 새로고침 시 화면에 반영된 것을 확인할 수 있습니다.
const db = firebase.firestore();
const storage = firebase.storage();
db.collection("center_gangnam")
.orderBy("강의번호", "asc")
.get()
.then((snapshot) => {
console.log(snapshot);
total = snapshot.docs.length;
console.log("전체 레코드 수 ===> " + total);
for (let i = 0; i < total; i++) {
if (total === i) break;
num = i;
classNum = snapshot.docs[i].data().강의번호;
////////////////////// 수강신청한 컬렉션의 강의번호와 for문으로 출력된 강의번호 쿼리 ////////////////////
db.collection("myclass")
.where("강의번호", "==", classNum)
.get()
.then((querySnapshot) => {
applyTotal = querySnapshot.size;
console.log(snapshot.docs[i].data().강의번호 + "신청인원 : " + applyTotal); /// 신청인원 출력 확인
console.log(snapshot.docs[i].data()); // 전체 데이터 출력 확인
const template = `
<tr>
<td>${snapshot.docs[i].data().강의번호}</td>
<td colspan="3">
<a href="./regiDetail.html?id=${
snapshot.docs[i].id
}" id="classname">
${snapshot.docs[i].data().강의명}
</a>
</td>
<td>${snapshot.docs[i].data().강사명}</td>
<td>${snapshot.docs[i].data().강의시간}</td>
<td>${applyTotal}</td>
<td>${snapshot.docs[i].data().제한인원}</td>
</tr>
`;
$(".class-content").append(template);
});////////////////////////////////////////////////////쿼리끝////////
} ////////////////////////////////////// end of for
}); /////////////////// end of callback (center_gangnam 수강신청 리스트 가져오기)
수강신청 페이지의 강의명을 클릭하면 수강신청 상세보기 화면으로 이동합니다. <a>
태그의 링크를 href="./regiDetail.html?id=${snapshot.docs[i].id}"
와 같이 설정하여 Firebase의 document id를 query string
으로 활용할 수 있습니다. 따라서 강의명을 클릭하면 해당 강의 document의 id와 일치하는 게시물을 찾아서 상세페이지에 위와 같이 출력할 수 있습니다.
아래 코드와 같이 jQuery
를 사용하여 id가 'regi_btn'인 신청하기 버튼을 클릭하면, myclass
컬렉션에 해당 데이터를 추가하는 코드를 수행하여 수강을 등록할 수 있습니다.
$(document).ready(function () {
let queryString = new URLSearchParams(document.location.search); // 쿼리스트링 선언
let id = queryString.get("id");
console.log("사용자가 선택한 item.id : " + id); // 아쉬탕가요가(화요일)_2
db.collection("center_gangnam")
.doc(id)
.get()
.then((result) => {
console.log(result.data());
classimage = result.data().이미지;
classname = result.data().강의명;
classnum = result.data().강의번호;
teacher = result.data().강사명;
classtime = result.data().강의시간;
classtype = result.data().강의분류;
$(".img-thumbnail").attr("src", classimage); // img태그 src 속성에 'classimage'값 추가
$(".classname").attr("value", classname); // input태그 value 속성에 'classname'값 추가
$(".classnum").attr("value", classnum);
$(".teacher").attr("value", teacher);
$(".classtime").attr("value", classtime);
});
// 신청하기 버튼 클릭 시 이벤트
$("#regi_btn").click(function (e) {
e.preventDefault() // 필수코드 - form태그 새로고침 방지
let data = {
이름: c_name,
성별: gender,
나이: age,
강의명: classname,
강의분류: classtype,
강의번호: classnum,
강사명: teacher,
강의시간: classtime,
신청일자: setClock(),
UID: myuid,
};
// 위에 선언한 data를 myclass 컬렉션에 추가
db.collection("myclass")
.add(data)
.then((result) => {
console.log(result);
alert("수강신청이 완료되었습니다! 수강내역에서 확인해 주세요.");
window.location.href = "./register.html"; // 수강신청 페이지로 이동
})
.catch((err) => {
console.log(err);
});
});
});
Firebase의 onSnapshot()
메서드를 사용하면 실시간 업데이트를 받을 수 있습니다. myclass
에 저장된 수강내역을 where('UID', '==', myuid)
와 같이 로그인한 회원의 uid와 일치하는 쿼리를 통해 데이터를 가져오는데, 삭제가 이루어져 DB가 변경되면 새로고침없이, 실시간으로 반영해줍니다.
위 이미지와 같이 수강내역의 <div>
카드를 클릭하면, <div class="card-id" style="display : none;">${a.id}</div>
와 같이 class명이 'card-id'인 요소의 내용을 가져올 수 있습니다. 따라서 clickId
변수에는 수강신청한 데이터의 고유 uid를 저장할 수 있으며, 이를 활용하여 myclass
컬렉션에서 clickId
에 일치하는 데이터를 삭제할 수 있습니다.
////// 수강내역(카드) 클릭 시 이벤트 - css효과
$('.card').click(function(e) {
// clickId는 전역변수로 빼고 클릭 이벤트에서 초기화
// a.id 값을 clickId에 담기
clickId = $(this).find('.card-id').text()
console.log(clickId);
$('.card').css("border","") // 나머지는 bordr 스타일X
$(this).css("border","3px solid #03a9f4") // 클릭한 카드만 스타일적용
})
////// 수강취소 버튼 클릭 시 이벤트
// unbind, bind -> 마지막에 클릭한 요소만 실행하기 위해(이거없으면 여러번 수행됨)
$('#btn_cancel').unbind("click");
$('#btn_cancel').bind("click",function() {
// yes, no 확인창
if(clickId) {
if(confirm("선택한 수강을 취소하시겠습니까?")) {
// yes -> DB에서 수강내역 삭제
db.collection('myclass').doc(clickId).delete().then(()=>{
console.log("Document successfully deleted!");
})
.catch((err)=>{
console.log(err);
})
} else {
// no
console.log("cancelled");
}
}
else {
alert("취소할 내역을 선택해 주세요.");
}
})
◼ 백종국(조장)
- 서버 사이드 담당
- 로그인, 회원가입 UI 및 기능 구현
- 마이페이지 UI 및 기능 구현
- 운동일지, 회원정보 담당
- Git 관리 및 코드리뷰 담당
- PPT 발표 및 영상제작
◼ 김지연
- 마이페이지 설계 담당
- 마이페이지 UI 및 기능 구현
- 문의게시판, 회원정보 담당
- 요구사항 정의서 담당
◼ 신현아
- 메인페이지 UI 및 기능 구현
- 마이페이지 회원정보 UI 제작
- 화면정의서 담당
- 회의 보고서 및 노션 총괄
◼ 이여진
- 회사소개 페이지, 사이드바 UI 제작
- 마이페이지 UI 및 기능 구현
- 수강신청 담당
- PPT 제작 및 공정표 담당
- Front-end :
HTML5
CSS3
JavaScript
jQuery
BootStrap
- Back-end & DB :
Firebase
Node.js
- 개발환경 :
Visual Studio Code
- 협업툴 :
GitHub
Notion
Slack
- 오픈 소스 :
Kakao Map API
Chart.js