Commit cfaa58ab authored by Piyaphorn Arphornsri's avatar Piyaphorn Arphornsri

update

parent f8554879
......@@ -22,8 +22,8 @@
\item สามารถดูคิวที่ผู้ใช้บริการได้ทำการจองคิวไว้
\item สามารถ post ภาพผลงานทั้งหมดของร้านได้
\item สามารถเพิ่ม แก้ไข และลบรายการให้บริการประจำร้านได้
\item สามารถเพิ่ม แก้ไข และลบ ข้อมูลร้านได้
\item สามารถเพิ่ม แก้ไข และลบข้อมูลตำแหน่งร้านได้
\item สามารถเพิ่ม แก้ไข ข้อมูลร้านได้
\item สามารถเพิ่ม แก้ไข ข้อมูลตำแหน่งร้านได้
\end{itemize}
\item ช่างประจำร้าน
\begin{itemize}
......
......@@ -4,7 +4,7 @@
ได้แก่ ความรู้พื้นฐานเกี่ยวกับ React Node.js JavaScript MySQL Visual studio code Google maps API
และในส่วนที่สองเป็นเนื้อหาเกี่ยวกับเว็ปแอพพลิเคชันที่เกี่ยวข้องกับโครงงานนี้เว็บแอพพลิเคชัน Gowabi
\section{ความรู้พื้นฐานเกี่ยวกับ React}
React เป็น JavaScript Library ที่ถูกสร้างโดย Facebook ซึ่ง React ทำหน้าที่เป็นเพียง User Interface (UI) ที่สร้างมาจากพื้นฐานแนวความคิดแบบ Model View Controller (MVC)
React \cite{bib2} เป็น JavaScript Library ที่ถูกสร้างโดย Facebook ซึ่ง React ทำหน้าที่เป็นเพียง User Interface (UI) ที่สร้างมาจากพื้นฐานแนวความคิดแบบ Model View Controller (MVC)
React ทำหน้าที่เฉพาะส่วน View (จาก Model View Controller) เหมาะกับงาน Web Front-End ที่สามารถแบ่งออกเป็น Web Component ย่อยๆ โดยหลักการวิเคราะห์ควรแยกให้ย่อยที่สุดเท่าที่จะทำได้ ซึ่งสามารถแบ่ง Component ออกเป็น 2 รูปแบบ คือ
\begin{itemize}
......@@ -24,19 +24,6 @@ React ทำหน้าที่เฉพาะส่วน View (จาก Mod
\caption{concept หลักของ React}{ที่มา: https://www.designil.com/wp-content/uploads/2017/07/react-concept-designil.jpg}
\label{Fig:react-concept}
\end{figure}
\subsection{React Life Cycle}
การเขียน render() ฟังก์ชันใน component \cite{react3} นั้น ควรจะเขียนในแบบ pure function ซึ่งจะไม่มีการเปลี่ยน state และสร้าง side effect ต่อภายนอกทั้งสิ้น อย่างเช่น การ call extenal service แบบ Ajax request, Firebase calling เป็นต้น เพราะหน้าที่ของ render() มีแค่การ render UI เท่านั้น หากไม่สามารถทำสิ่งดังกล่าวภายใน render() แล้ว กิจกรรมเหล่านั้นจึงสามารถทำได้ที่ life cycle ของ React
ตลอดช่วงวงจรชีวิต \cite{react4} สามารถควบคุมเหตุการณ์ต่างๆ ที่เกิดขึ้นในการแสดงผล UI การอัพเดทข้อมูล และการ re-rendering จนกระทั้งข้อมูลนั้นหายไป โดยที่ React ได้มีการเตรียมฟังก์ชันต่างๆ ไว้ สามารถอธิบายการทำงานของฟังก์ชันได้ ดังนี้
\begin{itemize}
\item componentWillMount() : คุณสมบัติของ componentWillMount ไม่มีอะไรเกี่ยวกับการใช้งาน component เพราะยังไม่มีการ mount อะไรขึ้นมา โดยมีหน้าที่ คือ การกำหนดค่าเริ่มต้นสำหรับการใช้งาน
\item componentDidMount() : เกิดขึ้นเมื่อทำการ Mount เรียบร้อย พร้อมที่จะใช้งาน โดยปกติจะใช้ในการกำหนดค่าทุกอย่างที่ต้องใช้ DOM และรับข้อมูลที่ต้องการมาแสดงผล
\item componentWillReceiveProps(nextProps) : เมื่อ Component ทำงาน จนกระทั้งมี pro-ps ใหม่เข้ามา เพื่อทำการเปลี่ยนแปลงข้อมูล componentWillReceive Props จะถูกเรียก โดยมี nextProps เป็นตัวแปรที่ถูกส่งเข้ามา
\item shouldComponentUpdate(nextProps, nextState) : ถูกเรียกเมื่อ component มีการเปลี่ยนแปลงด้วย nextProps กับ nextState
\item componentWillUpdate(nextProps, nextState) : ถูกเรียกก่อนที่จะ render หลังจากได้รับค่าใหม่ของ props หรือ state คุณสมบัติของคล้ายกับ componentWillReveiveProps
\item componentDidUpdate(prevProps, prevState) : ถูกเรียกทันที่หลังจากเกิดการเปลี่ยนแปลงของ component แต่จะไม่ถูกเรียกตอนครั้งแรกที่ render โดยที่ componentDidUpd-ate สามารถใช้งานได้เหมือน componentDidMount
\item componentWillUnmount() : ถูกเรียกก่อนที่ component ทำการ unmount และ destroy โดยปกติแล้วจะใช้เพื่อทำการรีเซ็ต (reset) ค่าต่างๆ
\end{itemize}
\subsection{React Life Cycle}
การเขียน render() ฟังก์ชันใน component \cite{bib5} นั้น ควรจะเขียนในแบบ pure function ซึ่งจะไม่มีการเปลี่ยน state และสร้าง side effect ต่อภายนอกทั้งสิ้น อย่างเช่น การ call extenal service แบบ Ajax request, Firebase calling เป็นต้น เพราะหน้าที่ของ render() มีแค่การ render UI เท่านั้น หากไม่สามารถทำสิ่งดังกล่าวภายใน render() แล้ว กิจกรรมเหล่านั้นจึงสามารถทำได้ที่ life cycle ของ React
......@@ -55,16 +42,16 @@ React ทำหน้าที่เฉพาะส่วน View (จาก Mod
\section{ความรู้พื้นฐานเกี่ยวกับ Node.js}
Node.js \cite{nodejs} เป็นภาษาที่ทำงานอยู่ในฝั่งเซิร์ฟเวอร์ (server) ซึ่ง syntax ที่ใช้ในการเขียนคือ JavaScript และเป็นภาษาที่ออกแบบมาให้ทำงานแบบ Event-Driven หรือทำงานเมื่อเกิดเหตุการณ์ตามที่กำหนดไว้ และการทำงานแบบ Asynchronous ซึ่งสามารถทำงานในลำดับต่อไปโดยที่ไม่ต้องรอให้งานก่อนหน้าเสร็จก่อนแล้วจึงทำงานขั้นต่อไป แต่ก็สามารถกำหนดให้ทำงานแบบ Synchronous ได้เช่นกัน โดยการกำหนด Callback เมื่องานแรกทำงานเสร็จแล้ว นอกจากนี้ Node.js นั้นจะใช้ Compiler จาก Google JavaScript Engine V8
Node.js \cite{bib7} เป็นภาษาที่ทำงานอยู่ในฝั่งเซิร์ฟเวอร์ (server) ซึ่ง syntax ที่ใช้ในการเขียนคือ JavaScript และเป็นภาษาที่ออกแบบมาให้ทำงานแบบ Event-Driven หรือทำงานเมื่อเกิดเหตุการณ์ตามที่กำหนดไว้ และการทำงานแบบ Asynchronous ซึ่งสามารถทำงานในลำดับต่อไปโดยที่ไม่ต้องรอให้งานก่อนหน้าเสร็จก่อนแล้วจึงทำงานขั้นต่อไป แต่ก็สามารถกำหนดให้ทำงานแบบ Synchronous ได้เช่นกัน โดยการกำหนด Callback เมื่องานแรกทำงานเสร็จแล้ว นอกจากนี้ Node.js นั้นจะใช้ Compiler จาก Google JavaScript Engine V8
ส่วนใหญ่จะนิยมใช้ node.js ในงานที่ทำเป็นเบื้องหลัง คือ งานที่ประมวลผลสั่งเซิร์ฟเวอร์ซึ่งเป็นงานที่อาจจะต้อง interface กับผู้ใช้ หรือไม่ต้อง interface กับผู้ใช้ ตัวอย่างงานที่ต้อง interface กับผู้ใช้ เช่น การทำตัวเองเป็น http server ในการดึงหน้าเว็บมาแสดงผลให้กับ user หรือว่า การเปิด socket เพื่อรับส่งข้อมูลกันระหว่างเซิร์ฟเวอร์กับผู้ใช้งาน เช่น ทำเป็นห้อง chat ทำเกม ทำระบบที่ป้อนข้อมูลเพื่อคำนวณผลลัพธ์ เป็นต้น ตัวอย่างงานที่ไม่ต้อง interface กับผู้ใช้ เช่น ทำ spider crawler เว็บ คือ การเปิดเว็บแล้วเก็บข้อมูลไปเรื่อยๆ หรือ โปรแกรมที่ รอรับค่าจาก streaming ต่างๆ เพื่อนำมาบันทึกไว้ ซึ่งการทำงานเหล่านี้ไม่จำเป็นต้อง interface กับผู้ใช้
node.js มีส่วนเสริมที่ชื่อว่า node package management (npm) ซึ่งเปรียบเหมือน google play ใน android หรือ app store ใน iOS ที่สามารถเอา package ที่คนอื่นเขียนเอาไว้แล้ว เพื่อแจกฟรี (free) มาต่อยอดเพื่อใช้ในงานของตนได้ โดยตัวอย่างที่ได้รับความนิยมจะเป็น underscore, async, request และ express เป็นต้น สำหรับการติดตั้ง ใช้คำสั่ง npm install ตามด้วยชื่อ package ที่ต้องการติดตั้ง \cite{nodejs1}
node.js มีส่วนเสริมที่ชื่อว่า node package management (npm) ซึ่งเปรียบเหมือน google play ใน android หรือ app store ใน iOS ที่สามารถเอา package ที่คนอื่นเขียนเอาไว้แล้ว เพื่อแจกฟรี (free) มาต่อยอดเพื่อใช้ในงานของตนได้ โดยตัวอย่างที่ได้รับความนิยมจะเป็น underscore, async, request และ express เป็นต้น สำหรับการติดตั้ง ใช้คำสั่ง npm install ตามด้วยชื่อ package ที่ต้องการติดตั้ง \cite{bib8}
node.js มีการทำงานเป็น Asynchronous คือ การทำงานบางอย่างไม่ต้องรอให้บรรทัดนั้นทำงานเสร็จ เช่น ส่งคำสั่งไป query ข้อมูลจากฐานข้อมูล แล้วสามารถข้ามไปทำงานบรรทัดต่อไปโดยไม่ต้องรอผลจากฐานข้อมูล เมื่อการทำงานนั้นทำงานเสร็จจึงค่อยรอผลลัพธ์กลับมา ดังนั้นปัญหาจะเกิดทันที ถ้าการทำงานต่อไปนำผลลัพธ์จากคำสั่งก่อนหน้านั้นมาใช้ต่อ ซึ่งส่งผลให้เกิดการทำงานผิดพลาด เพราะผลลัพธ์ยังไม่ได้รับกลับมา
\subsection{node.js ทำงานแบบ event driven}
การทำงานของ node \cite{nodejs2} เรียกว่าเป็นการขับเคลื่อนด้วย event ต่างๆ ที่เกิดขึ้น ทำให้สามารถข้ามจาก event หนึ่งที่เสร็จแล้วไปยัง event อื่นได้ด้วยการสั่งงานต่อเนื่องกันไป หรือการสั่งให้ event หลาย event เริ่มทำงานในเวลาใกล้เคียงกัน ประโยชน์ที่ได้จาก event driven คือ การสั่งให้รอรับ event นั้นไปตลอดการณ์ โดยไม่เปลืองทรัพยากร เช่น การเชื่อมต่อไปยัง streaming channel ที่หนึ่ง ซึ่งอาจเป็น text หรือข้อมูลบางอย่าง เช่น ปริมาณน้ำฝน เอาไว้ หากต้นทางของ streaming ยังไม่มีข้อมูลส่งมา จะไม่เกิด event ใดๆ และ node.js จะรออยู่ แต่หากต้นทาง streaming มีข้อมูลมา node.js จะทำงานเพื่อตอบสนองต่อ event ที่เกิดขึ้นนั้นทันที สามารถแสดงการทำงานดังกล่าวได้ ดังรูปที่ \ref{Fig:event-driven}
การทำงานของ node \cite{bib9} เรียกว่าเป็นการขับเคลื่อนด้วย event ต่างๆ ที่เกิดขึ้น ทำให้สามารถข้ามจาก event หนึ่งที่เสร็จแล้วไปยัง event อื่นได้ด้วยการสั่งงานต่อเนื่องกันไป หรือการสั่งให้ event หลาย event เริ่มทำงานในเวลาใกล้เคียงกัน ประโยชน์ที่ได้จาก event driven คือ การสั่งให้รอรับ event นั้นไปตลอดการณ์ โดยไม่เปลืองทรัพยากร เช่น การเชื่อมต่อไปยัง streaming channel ที่หนึ่ง ซึ่งอาจเป็น text หรือข้อมูลบางอย่าง เช่น ปริมาณน้ำฝน เอาไว้ หากต้นทางของ streaming ยังไม่มีข้อมูลส่งมา จะไม่เกิด event ใดๆ และ node.js จะรออยู่ แต่หากต้นทาง streaming มีข้อมูลมา node.js จะทำงานเพื่อตอบสนองต่อ event ที่เกิดขึ้นนั้นทันที สามารถแสดงการทำงานดังกล่าวได้ ดังรูปที่ \ref{Fig:event-driven}
\begin{figure}[H]
\centering
\includegraphics[scale=0.5]{Figures/2/unnamed}
......@@ -83,7 +70,7 @@ node.js มีการทำงานเป็น Asynchronous คือ กา
\end{itemize}
\section{ความรู้พื้นฐานเกี่ยวกับ JavaScript}
JavaScript \cite{javascript} คือ ภาษาคอมพิวเตอร์สำหรับการเขียนโปรแกรมบนระบบอินเทอร์เน็ต (Internet) ที่กำลังได้รับความนิยมอย่างสูง JavaScript เป็น ภาษาสคริปต์ (script) เชิงวัตถุ ที่เรียกกันว่า "สคริปต์" ซึ่งการใช้ JavaScript ในการสร้างและพัฒนาเว็บไซต์ (ใช้ร่วมกับ HTML) จะช่วยให้เว็บไซต์ดูมีการเคลื่อนไหว สามารถตอบสนองผู้ใช้งานได้มากขึ้น โดยมีวิธีการทำงานในลักษณะ "แปลความและดำเนินงานไปทีละคำสั่ง" (interpret) หรือเรียกว่า โปรแกรมเชิงวัตถุ (Object Oriented Programming) ที่มีเป้าหมายในการ ออกแบบและพัฒนาโปรแกรมในระบบอินเทอร์เน็ต สำหรับผู้เขียนด้วยภาษา HTML สามารถทำงานข้ามแพลตฟอร์มได้ โดยทำงานร่วมกับ ภาษา HTML และภาษา Java ได้ทั้งทางฝั่งไคลเอนต์ (client) และ ทางฝั่งเซิร์ฟเวอร์
JavaScript \cite{bib12} คือ ภาษาคอมพิวเตอร์สำหรับการเขียนโปรแกรมบนระบบอินเทอร์เน็ต (Internet) ที่กำลังได้รับความนิยมอย่างสูง JavaScript เป็น ภาษาสคริปต์ (script) เชิงวัตถุ ที่เรียกกันว่า "สคริปต์" ซึ่งการใช้ JavaScript ในการสร้างและพัฒนาเว็บไซต์ (ใช้ร่วมกับ HTML) จะช่วยให้เว็บไซต์ดูมีการเคลื่อนไหว สามารถตอบสนองผู้ใช้งานได้มากขึ้น โดยมีวิธีการทำงานในลักษณะ "แปลความและดำเนินงานไปทีละคำสั่ง" (interpret) หรือเรียกว่า โปรแกรมเชิงวัตถุ (Object Oriented Programming) ที่มีเป้าหมายในการ ออกแบบและพัฒนาโปรแกรมในระบบอินเทอร์เน็ต สำหรับผู้เขียนด้วยภาษา HTML สามารถทำงานข้ามแพลตฟอร์มได้ โดยทำงานร่วมกับ ภาษา HTML และภาษา Java ได้ทั้งทางฝั่งไคลเอนต์ (client) และ ทางฝั่งเซิร์ฟเวอร์
JavaScript ถูกพัฒนาขึ้นโดย บริษัท เน็ตสเคปคอมมิวนิเคชันส์ (Netscape Communications Corporation) โดยใช้ชื่อว่า Live Script ออกมาพร้อมกับ Netscape Navigator 2.0 เพื่อใช้สร้างเว็บเพจ (Web page) โดยติดต่อกับเซิร์ฟเวอร์แบบ Live Wire ต่อมาเน็ตสเคปได้ร่วมมือกับ บริษัทซันไมโครซิสเต็มส์ (Sun Microsystems, Inc) ปรับปรุงระบบของเบราว์เซอร์ (Browser) เพื่อให้สามารถติดต่อใช้งานกับภาษาจาวา (Java) ได้ และได้ปรับปรุง LiveScript ใหม่เมื่อ ปี พ.ศ. 2538 แล้วตั้งชื่อใหม่ว่า JavaScript ซึ่ง JavaScript ทำให้การสร้างเว็บเพจมีลูกเล่นต่างๆ มากมาย และยังสามารถโต้ตอบกับผู้ใช้ได้อย่างทันที เช่น การใช้เมาส์คลิก หรือ การกรอกข้อความในฟอร์ม เป็นต้น
......@@ -98,13 +85,13 @@ JavaScript ถูกพัฒนาขึ้นโดย บริษัท เ
\item JavaScript สร้าง Cookies (เก็บข้อมูลของผู้ใช้ในคอมพิวเตอร์ของผู้ใช้เอง) ได้
\end{itemize}
\subsection{ข้อดีและข้อเสียของ Java JavaScript}
JavaScript \cite{javascript1} ทำงานบนเว็บบราวเซอร์ (client-side script) จึงไม่มีข้อจำกัดว่าจะใช้เซิร์ฟเวอร์แบบไหนก็ตาม เพราะ JavaScript ทำงานเฉพาะในเครื่องของผู้ใช้งานเท่านั้น ซึ่งต่างกับภาษาสคริปต์อื่น เช่น PHP , ASP, JSP หรือ Perl ซึ่งต้องประมวลผลและทำงานที่เครื่องเซิร์ฟเวอร์ (server-side script) จึงจำเป็นต้องใช้บนเซิร์ฟเวอร์ ที่สนับสนุนภาษาเหล่านี้เท่านั้นจึงจะสามารถใช้งาน server-side script ได้ แต่อย่างไรก็ตาม จากลักษณะการทำงานที่กล่าวมาก็ทำให้ JavaScript มีข้อจำกัด กล่าวคือคือไม่สามารถรับและส่งข้อมูลต่างๆ กับเซิร์ฟเวอร์โดยตรง เช่น การอ่านไฟล์จากเซิร์ฟเวอร์ เพื่อนำมาแสดงบนเว็บเพจ หรือรับข้อมูลจากผู้ชม เพื่อนำไปเก็บบนเซิร์ฟเวอร์ เป็นต้น ดังนั้นงานลักษณะนี้ จึงยังคงต้องอาศัยภาษา server-side script อยู่ (ความจริงมี JavaScript ที่ทำงานบนเซิร์ฟเวอร์เช่นกัน ซึ่งต้องอาศัยเซิร์ฟเวอร์ที่สนับสนุนโดยเฉพาะเช่นกัน แต่ไม่เป็นที่นิยมนัก)
JavaScript \cite{bib13} ทำงานบนเว็บบราวเซอร์ (client-side script) จึงไม่มีข้อจำกัดว่าจะใช้เซิร์ฟเวอร์แบบไหนก็ตาม เพราะ JavaScript ทำงานเฉพาะในเครื่องของผู้ใช้งานเท่านั้น ซึ่งต่างกับภาษาสคริปต์อื่น เช่น PHP , ASP, JSP หรือ Perl ซึ่งต้องประมวลผลและทำงานที่เครื่องเซิร์ฟเวอร์ (server-side script) จึงจำเป็นต้องใช้บนเซิร์ฟเวอร์ ที่สนับสนุนภาษาเหล่านี้เท่านั้นจึงจะสามารถใช้งาน server-side script ได้ แต่อย่างไรก็ตาม จากลักษณะการทำงานที่กล่าวมาก็ทำให้ JavaScript มีข้อจำกัด กล่าวคือคือไม่สามารถรับและส่งข้อมูลต่างๆ กับเซิร์ฟเวอร์โดยตรง เช่น การอ่านไฟล์จากเซิร์ฟเวอร์ เพื่อนำมาแสดงบนเว็บเพจ หรือรับข้อมูลจากผู้ชม เพื่อนำไปเก็บบนเซิร์ฟเวอร์ เป็นต้น ดังนั้นงานลักษณะนี้ จึงยังคงต้องอาศัยภาษา server-side script อยู่ (ความจริงมี JavaScript ที่ทำงานบนเซิร์ฟเวอร์เช่นกัน ซึ่งต้องอาศัยเซิร์ฟเวอร์ที่สนับสนุนโดยเฉพาะเช่นกัน แต่ไม่เป็นที่นิยมนัก)
นักพัฒนาเว็บส่วนใหญ่จึงนิยมใช้ JavaScript ร่วมกับ ภาษา Server Script เพื่อทำการส่งข้อมูลระหว่าง เซิร์ฟเวอร์กับเครื่องของผู้ใช้งาน ซึ่งทำให้การแสดงผลของหน้าเว็บมีความสวยงามและราบรื่นมากยิ่งขึ้น
\section{ความรู้พื้นฐานเกี่ยวกับ MySQL}
MySQL \cite{bib14} เป็นระบบจัดการฐานข้อมูลเชิงสัมพันธ์ (Relational Database Management System : RDBMS) ตัวหนึ่ง ซึ่งเป็นที่นิยมกันมากในปัจจุบัน โดยเฉพาะอย่างยิ่งในโลกของอินเตอร์เน็ต สาเหตุเพราะว่า MySQL เป็นฟรีแวร์ ทางด้านของฐานข้อมูลที่มีประสิทธิภาพสูง เป็นทางเลือกใหมจากผลิตภัณฑ์ระบบจัดการฐานข้อมูลในปัจจุบัน ที่มักจะเป็นการผูกขาดของผลิตภัณฑ์เพียงไม่กี่ตัว นักพัฒนาระบบฐานขอมูลที่เคยใช้ MySQL ต่างยอมรับในความสามารถความรวดเร็ว การรองรับจํานวนผู้ใช้ และขนาดของข้อมูลจํานวนมหาศาล ทั้งยังสนับสนุนการใช้งานบนระบบปฏิบัติการมากมาย ไม่ว่าจะเป็น Unix , OS/2 , Mac , OS หรือ Windows ก็ตาม นอกจากนี้ MySQL ยังสามารถใช้ งานร่วมกับ Web Development Platform ทั้งหลาย ไม่ว่าจะเป็น C, C++, Java, Perl, PHP, Python, Tcl หรือ ASP ดังนั้น MySQL จึงได้รับความนิยมอย่างมากในปัจจุบัน และมีแนวโน้มสูงยิ่งขึ้นต่อไปในอนาคต
MySQL \cite{bib15} เป็นระบบจัดการฐานข้อมูลเชิงสัมพันธ์ (Relational Database Management System : RDBMS) ตัวหนึ่ง ซึ่งเป็นที่นิยมกันมากในปัจจุบัน โดยเฉพาะอย่างยิ่งในโลกของอินเตอร์เน็ต สาเหตุเพราะว่า MySQL เป็นฟรีแวร์ ทางด้านของฐานข้อมูลที่มีประสิทธิภาพสูง เป็นทางเลือกใหมจากผลิตภัณฑ์ระบบจัดการฐานข้อมูลในปัจจุบัน ที่มักจะเป็นการผูกขาดของผลิตภัณฑ์เพียงไม่กี่ตัว นักพัฒนาระบบฐานขอมูลที่เคยใช้ MySQL ต่างยอมรับในความสามารถความรวดเร็ว การรองรับจํานวนผู้ใช้ และขนาดของข้อมูลจํานวนมหาศาล ทั้งยังสนับสนุนการใช้งานบนระบบปฏิบัติการมากมาย ไม่ว่าจะเป็น Unix , OS/2 , Mac , OS หรือ Windows ก็ตาม นอกจากนี้ MySQL ยังสามารถใช้ งานร่วมกับ Web Development Platform ทั้งหลาย ไม่ว่าจะเป็น C, C++, Java, Perl, PHP, Python, Tcl หรือ ASP ดังนั้น MySQL จึงได้รับความนิยมอย่างมากในปัจจุบัน และมีแนวโน้มสูงยิ่งขึ้นต่อไปในอนาคต
\subsection{โครงสร้างของ MySQL}
โครงสร้างภายในของ MySQL \cite{bib14} คือ การออกแบบการทํางานในลักษณะของ Client Server นั่นเอง ซึ่งประกอบด้วย 2 ส่วน คือ ส่วนของผู้ให้บริการ (Server) และ ส่วนของผู้ใช้บริการ (Client) โดยในแต่ละส่วนจะมีโปรแกรมสําหรับการทํางานตามหน้าที่ของโปรแกรมนั้น ส่วนของผู้ให้บริการ (Server) จะเป็นส่วนที่ทําหน้าที่บริหารจัดการระบบฐานข้อมูล (MySQL Server) และเป็นที่จัดเก็บข้อมูลทั้งหมด ข้อมูลที่เก็บไว้นี้มีข้อมูลที่จําเป็นสําหรับการทํางานกับระบบฐานข้อมูลและข้อมูลที่เกิดจากการที่ผู้ใช้แต่ละคนสร้างขึ้นมา ส่วนของผู้ใช้บริการ (Client) คือ ส่วนที่ผู้ใช้ใช้งาน โดยโปรแกรมสําหรับใช้งานในส่วนนี้ได้แก่ MySQL , Client , Access . Web Development เป็นต้น
......@@ -169,7 +156,7 @@ Google Maps API \cite{maps} เป็นชุด API ของ Google สำห
\newpage
\section{เอกสารและงานวิจัยที่เกี่ยวข้อง}
\subsection{เว็บแอพพลิเคชัน Gowabi}
Gowabi\cite{wongnai} เป็นเว็บไซต์และแอปพลิเคชันที่ให้บริการเกี่ยวกับการค้นหาและจองคิวร้านเสริมสวย มีฟังก์ชันการทำงานพื้นฐานอันได้แก่ การค้นหา การจองคิว ดูข้อมูล เป็นต้น
Gowabi\cite{gowabi} เป็นเว็บไซต์และแอปพลิเคชันที่ให้บริการเกี่ยวกับการค้นหาและจองคิวร้านเสริมสวย มีฟังก์ชันการทำงานพื้นฐานอันได้แก่ การค้นหา การจองคิว ดูข้อมูล เป็นต้น
\subsection{ข้อแตกต่างระหว่างเว็บแอปพลิเคชั่น Gowabi กับเว็บของโครงงาน}
เว็บแอปพลิเคชั่นของ Gowabi ยังไม่มีฟังก์ชันเลือกรายการ และช่างในการจองคิว ผู้พัฒนาจึงได้ทำฟังก์ชันเลือกรายหารและะช่างที่เหมาะสมตามรสนิยมของผู้ใช้เพิ่มลงในเว็บของโครงงาน
\begin{figure}[H]
......
......@@ -51,8 +51,8 @@
\item สามารถจัดการคิวได้
\item สามารถ post ภาพผลงานทั้งหมดของร้านได้
\item สามารถเพิ่ม แก้ไข และลบรายการให้บริการประจำร้านได้
\item สามารถเพิ่ม แก้ไข และลบ ข้อมูลร้านได้
\item สามารถเพิ่ม แก้ไข และลบข้อมูลตำแหน่งร้านได้
\item สามารถเพิ่ม แก้ไข ข้อมูลร้านได้
\item สามารถเพิ่ม แก้ไข ข้อมูลตำแหน่งร้านได้
\end{itemize}
\item ช่างประจำร้าน
\begin{itemize}[label={--}]
......@@ -635,38 +635,20 @@ User Interface Design ของระบบการจองคิวร้า
\newpage
%IMAGE of class
Class Diagram แสดงความสัมพันธ์ในรูปแบบต่างๆ ระหว่างคลาสของแอปพลิเคชันระบบกองทุนเงินให้กู้ยืมเพื่อการศึกษา คณะวิทยาศาสตร์ มหาวิทยาลัยอุบลราชธานี อธิบายได้ตามภาพที่ \ref{Fig:MainActivity20C} ดังต่อไปนี้
\begin{figure}[H]
\includegraphics[width=1.0\columnwidth]{Figures/3/Class/MainActivity}
\caption{Class Diagram ของแอปพลิเคชันระบบ XX}
\label{Fig:MainActivity20C}
\end{figure}
\begin{figure}[H]
\includegraphics[width=1.0\columnwidth]{Figures/3/Class/Feed}
\caption{Class Diagram ของแอปพลิเคชันระบบ XX}
\label{Fig:FeedC}
\end{figure}
Class Diagram แสดงความสัมพันธ์ในรูปแบบต่างๆ ระหว่างคลาสของแอปพลิเคชันระบบกองทุนเงินให้กู้ยืมเพื่อการศึกษา คณะวิทยาศาสตร์ มหาวิทยาลัยอุบลราชธานี อธิบายได้ตามภาพที่ \ref{Fig:classD} ดังต่อไปนี้
\begin{sidewaysfigure}
\begin{figure}[H]
\includegraphics[width=1.0\columnwidth]{Figures/3/Class/Doc}
\caption{Class Diagram ของแอปพลิเคชันระบบ XX}
\label{Fig:DocC}
\includegraphics[width=1.0\columnwidth]{Figures/3/Class/ClassDiagram}
\caption{Class Diagram ของแอปพลิเคชันระบบจองคิวร้านเสริมสวย}
\label{Fig:classD}
\end{figure}
\end{sidewaysfigure}
\begin{figure}[H]
\includegraphics[width=\columnwidth]{Figures/3/Class/Submit}
\caption{Class Diagram ของแอปพลิเคชันระบบ XX}
\label{Fig:SubmitC}
\end{figure}
\begin{figure}[H]
\includegraphics[width=1.0\columnwidth]{Figures/3/Class/UserChat}
\caption{Class Diagram ของแอปพลิเคชันระบบ XX}
\label{Fig:UserChatC}
\end{figure}
% TABLE of class
\newpage
จากรูปภาพที่ \ref{Fig:MainActivity20C} สามารถอธิบายแผนภาพ Class Diagram ได้ดังนี้
จากรูปภาพที่ \ref{Fig:classD} สามารถอธิบายแผนภาพ Class Diagram ได้ดังนี้
\begin{table}[H]
\centering
\caption{อธิบาย Class Diagram ของคลาสพื้นฐานของระบบ}
......@@ -674,89 +656,30 @@ User Interface Design ของระบบการจองคิวร้า
\begin{tabular}{|c|p{10cm}|}
\hline
\textbf{Class Diagram} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
\raisebox{-\totalheight}{MainApplication}
& \setstretch{1.5} {คลาส MainApplication จะถูกเรียกใช้งานทุกครั้งเมื่อผู้ใช้เปิดแอปพลิเคชัน โดยวัตถุประสงค์การทำงานของคลาสนี้คือ เพื่อใช้จัดการทรัพยากรที่จำเป็นสำหรับการใช้งานในคลาสอื่น ๆ } \\ \hline
\raisebox{-\totalheight}{SplashScreenActivity}
& \setstretch{1.5} {คลาส SplashScreenActivity จะถูกเรียกใช้งานทุกครั้งเมื่อผู้ใช้เปิดแอปพลิเคชัน โดยวัตถุประสงค์การทำงานของคลาสคือ เพื่อใช้ตรวจสอบสถานะการเข้าสู่ระบบของผู้ใช้} \\ \hline
\raisebox{-\totalheight}{MainActivity}
& \setstretch{1.5} {คลาส MainActivity เป็นคลาสหลักที่ใช้ในการทำงานของแอปพลิเคชันโดยการทำงานของคลาสนี้เน้นไปที่การสร้าง Fragment เพื่อใช้แสดงข้อมูลต่าง ๆ โดยองค์ประกอบการทำงานของคลาสนี้ประกอบบไปด้วยสองส่วนหลักๆ ได้แก่ เมนูนำทาง Drawer และ Fragment Container} \\ \hline
\raisebox{-\totalheight}{SignInActivity}
& \setstretch{1.5} {คลาส SignInActivity เป็นคลาสที่ใช้เพื่อให้สมาชิกที่ได้ลงทะเบียนกับระบบเข้าสู่ระบบเพื่อใช้งานบริการต่าง ๆ จากระบบ} \\ \hline
\end{tabular}
\end{table}
\newpage
จากรูปภาพที่ \ref{Fig:FeedC} สามารถอธิบายแผนภาพ Class Diagram ได้ดังนี้
\begin{table}[H]
\centering
\caption{อธิบาย Class Diagram ของส่วนของการแสดงข่าวสาร}
\label{tab:class}
\begin{tabular}{|c|p{10cm}|}
\hline
\textbf{Class Diagram} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
\raisebox{-\totalheight}{FeedFragment}
& \setstretch{1.5} {คลาส FeedFragment เป็นคลาสหลักที่ใช้ในการแสดงข้อมูลข่าวสาร มีการทำงานหลักคือสืบค้นฐานข้อมูลจากไฟร์เบสเพื่อนำมาแสดง} \\ \hline
\raisebox{-\totalheight}{FeedItemAdapter}
& \setstretch{1.5} {คลาส FeedItemAdapter เป็นคลาสที่มีหน้าที่ในการแปลงชุดข้อมูลที่ได้จากคลาส FeedFragment แล้วคืนค่ากลับเป็นลิสต์รายการของชุดข้อมูลนั้น ๆ} \\ \hline
\raisebox{-\totalheight}{Post}
& \setstretch{1.5} {คลาส Post เป็นคลาสโมเดลที่กำหนดค่าต่างๆที่จำเป็นสำหรับใช้ในการสร้างลิสต์รายการของคลาส FeedItemAdapter} \\ \hline
\raisebox{-\totalheight}{PostDetailActivity}
& \setstretch{1.5} {คลาส PostDetailActivity เป็นคลาสที่มีหน้าที่ในการแสดงข้อมูลรายละเอียดของข่าวสารแต่ละแถวที่ได้รับจากหน้า FeedFragment ที่จะส่งข้อมูลเมื่อผู้ใช้กดที่แถวรายการข่าวสาร} \\ \hline
\raisebox{-\totalheight}{RecyclerViewClickListener}
& \setstretch{1.5} {คลาส RecyclerViewClickListener เป็นคลาสอินเทอร์เฟส(Interface)ที่ใช้ในการสร้างแม่แบบเมื่อคลาสใด ๆ ต้องการใช้งานสำหรับการรับค่าเมื่อผู้ใช้กดแถวในลิสต์รายการ คลาสลูกที่ทำการสืบทอดคุณสมบัติจะสามารถรับข้อมูลตำแหน่งแถวที่ผู้ใช้กดบนลิสต์รายการได้} \\ \hline
\end{tabular}
\end{table}
\newpage
จากรูปภาพที่ \ref{Fig:DocC} สามารถอธิบายแผนภาพ Class Diagram ได้ดังนี้
\begin{table}[H]
\centering
\caption{อธิบาย Class Diagram ของส่วนของการแสดงรายการเอกสารในระบบ}
\label{tab:class}
\begin{tabular}{|c|p{10cm}|}
\hline
\textbf{Class Diagram} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
\raisebox{-\totalheight}{DocumentsFragment}
& \setstretch{1.5} {คลาส DocumentsFragment เป็นคลาสที่ใช้ในการแสดงข้อมูลเอกสารที่ถูกอัพโหลดเข้าสู่ระบบโดยเจ้าหน้าที่ซึ่งจะถูกแสดงเป็นลิสต์รายการ} \\ \hline
\raisebox{-\totalheight}{DocItemAdapter}
& \setstretch{1.5} {คลาส DocItemAdapter เป็นคลาสที่มีหน้าที่ในการแปลงชุดข้อมูลที่ได้รับจากคลาส DocumentsFragment เป็นลิสต์รายการแล้วคืนกลับไปยังคลาส DocumentsFragment} \\ \hline
\raisebox{-\totalheight}{Doc}
& \setstretch{1.5} {คลาส Doc เป็นคลาสโมเดลที่กำหนดค่าต่าง ๆ ที่จำเป็นสำหรับใช้ในการสร้างลิสต์รายการของคลาส DocItemAdapter} \\ \hline
\raisebox{-\totalheight}{RecyclerViewClickListener}
& \setstretch{1.5} {คลาส RecyclerViewClickListener เป็นคลาสอินเทอร์เฟสที่ใช้ในการสร้างแม่แบบเมื่อคลาสใด ๆ ต้องการใช้งานสำหรับการรับค่าเมื่อผู้ใช้กดแถวในลิสต์รายการ คลาสลูกที่ทำการสืบทอดคุณสมบัติจะสามารถรับข้อมูลตำแหน่งแถวที่ผู้ใช้กดบนลิสต์รายการได้} \\ \hline
\end{tabular}
\end{table}
\newpage
จากรูปภาพที่ \ref{Fig:SubmitC} สามารถอธิบายแผนภาพ Class Diagram ได้ดังนี้
\begin{table}[H]
\centering
\caption{อธิบาย Class Diagram ของส่วนของการส่งสำเนาเอกสาร}
\label{tab:class}
\begin{tabular}{|c|p{10cm}|}
\hline
\textbf{Class Diagram} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
\raisebox{-\totalheight}{SubmitFragment}
& \setstretch{1.5} {คลาส SubmitFragment เป็นคลาสที่ใช้ในการแสดงหน้าจอส่งสำเนาเอกสาร โดยมีการดำเนินการภายในคลาสหลัก ๆ ได้แก่ การถ่ายภาพ แปลงภาพและบันทึกภาพเข้าสู่ระบบ} \\ \hline
\end{tabular}
\end{table}
จากรูปภาพที่ \ref{Fig:UserChatC} สามารถอธิบายแผนภาพ Class Diagram ได้ดังนี้
\begin{table}[H]
\centering
\caption{อธิบาย Class Diagram ของส่วนของการสนทนา}
\label{tab:class}
\begin{tabular}{|c|p{10cm}|}
\hline
\textbf{Class Diagram} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
\raisebox{-\totalheight}{UserChatFragment}
& \setstretch{1.5} {คลาส UserChatFragment เป็นคลาสที่ใช้ในการแสดงหน้าจอสนทนาสำหรับนักศึกษา เพื่อติดต่อสอบถามข้อมูลกับเจ้าหน้าที่ มีการสืบค้นข้อมูลประวัติการสนทนาเพื่อส่งไปแปลงเป็นข้อมูลลิสต์รายการที่คลาส MessagesListAdapter} \\ \hline
\raisebox{-\totalheight}{MessagesListAdapter}
& \setstretch{1.5} {คลาส MessagesListAdapter เป็นคลาสที่ใช้ในการแปลงชุดข้อมูลที่ได้รับจากคลาส UserChatFragment เป็นลิสต์รายการแล้วทำการคืนค่าลิสต์รายการที่ได้กลับไปยังคลาส UserChatFragment} \\ \hline
\raisebox{-\totalheight}{MessagesList}
& \setstretch{1.5} {คลาส MessagesList เป็นคลาสที่ใช้ในการจัดเก็บข้อมูลภายในคลาส UserChatFragment หลังจากที่ได้ทำการสืบค้นข้อมูลการสนทนาจากไฟร์เบสเพื่อส่งไปยังคลาส MessagesListAdapter} \\ \hline
\raisebox{-\totalheight}{RecyclerViewClickListener}
& \setstretch{1.5} {คลาส RecyclerViewClickListener เป็นคลาสอินเทอร์เฟสที่ใช้ในการสร้างแม่แบบเมื่อคลาสใด ๆ ต้องการใช้งานสำหรับการรับค่าเมื่อผู้ใช้กดแถวในลิสต์รายการ คลาสลูกที่ทำการสืบทอดคุณสมบัติจะสามารถรับข้อมูลตำแหน่งแถวที่ผู้ใช้กดบนลิสต์รายการได้} \\ \hline
\raisebox{-\totalheight}{Server}
& \setstretch{1.5} {คลาส Server จะถูกเรียกใช้งานทุกครั้งเมื่อผู้ใช้เป็ดเว็บแอปพลิเคชัน โดยวัตถุประสงค์การทำงานของคลาสนี้คือ เพื่อใช้ในการเชื่อมต่อ api ระหว่างคลาสอื่นๆ กับฐานข้อมูล} \\ \hline
\raisebox{-\totalheight}{Register}
& \setstretch{1.5} {คลาส Register จะถูกเรียกใช้งานทุกครั้งเมื่อผู้ใช้เปิดเว็บแอปพลิเคชัน โดยวัตถุประสงค์การทำงานของคลาสคือ เพื่อใช้ในการลงทะเบียนขอใช้เว็บแอปพลิเคชัน} \\ \hline
\raisebox{-\totalheight}{Login}
& \setstretch{1.5} {คลาส Login เป็นคลาสที่ใช้เพื่อให้ผู้ใช้ที่ได้ลงทะเบียนกับระบบเข้าสู่ระบบเพื่อใช้งานบริการต่าง ๆ จากระบบ} \\ \hline
\raisebox{-\totalheight}{User}
& \setstretch{1.5} {คลาส User เป็นคลาสที่ใช้เก็บข้อมูลจากการลงทะเบียน} \\ \hline
\raisebox{-\totalheight}{BookingController}
& \setstretch{1.5} {คลาส BookingController เป็นคลาสที่ใช้เพิ่มข้อมูลช่าง} \\ \hline
\raisebox{-\totalheight}{Shop}
& \setstretch{1.5} {คลาส Shop เป็นคลาสที่ใช้จัดการการทำงาน Shop} \\ \hline
\raisebox{-\totalheight}{EditShop}
& \setstretch{1.5} {คลาส EditShop เป็นคลาสที่ใช้ในการจัดการการ update ข้อมูลร้าน} \\ \hline
\raisebox{-\totalheight}{List}
& \setstretch{1.5} {คลาส List เป็นคลาสที่ใช้จัดการการทำงานของรายการ} \\ \hline
\raisebox{-\totalheight}{EditList}
& \setstretch{1.5} {คลาส EditList เป็นคลาสที่ใช้จัดการการ update ข้อมูลรายการ} \\ \hline
\raisebox{-\totalheight}{Review}
& \setstretch{1.5} {คลาส Review เป็นคลาสที่ใช้จัดการการรีวิวของผู้ใช้งาน} \\ \hline
\raisebox{-\totalheight}{Booking}
& \setstretch{1.5} {คลาส Booking เป็นคลาสที่ใช้เก็บข้อมูลการจองคิว} \\ \hline
\raisebox{-\totalheight}{Bookingcontroller}
& \setstretch{1.5} {คลาส Bookingcontroller เป็นคลาสที่ใช้จัดการการจองคิว} \\ \hline
\end{tabular}
\end{table}
......@@ -792,396 +715,323 @@ User Interface Design ของระบบการจองคิวร้า
% Sequence Diagram ที่ใช้อธิบายการทำงานของระบบกองทุนเงินให้กู้ยืมเพื่อการศึกษา คณะวิทยสศาสตร์ มหาวิทยาลัยอุบลราชธานี มีรายละเอียดดังต่อไปนี้
\newpage
\begin{landscape}
\begin{figure}[H]
\centering
\includegraphics[width=0.95\columnwidth]
{Figures/3/Sequence/home}
\caption{Sequence Diagram ข้อมูลร้า}
\label{Fig:Sequence-home}
\includegraphics[width=1.0\columnwidth]
{Figures/3/Sequence/Register}
\caption{Sequence Diagram ลงทะเบีย}
\label{Fig:Sequence-register}
\end{figure}
\end{landscape}
\newpage
จากภาพที่ \ref{Fig:Sequence-register} สามารถอธิบายแผนภาพ Sequence Diagram การลงทะเบียน ได้ดังนี้ เมื่อ
ผู้ใช้กดปุ่ม register คลาส Register แสดงหน้าลงทะเบียน เมื่อผู้ใช้กรอกข้อมูลระบบจะเรียกใช้เมธอด onRegister() ที่คลาส Register เมื่อ ข้อมูลการลงทะเบียน ถูกติดตั้งบน api:Server เมธอด register จะทำการเพิ่มข้อมูลการลงทะเบียนลงในฐานข้อมูล และนำข้อมูลที่ได้เพิ่มลงมาเก็บในรูปแบบ response ที่คลาส api:Server โดยมีการสืบค้นข้อมูลเพื่อตรวจสอบการลงทะเบียนที่คลาส MySQL และเมื่อข้อมูลที่เพิ่มมีการลงทะเบียนแล้วจะแสดง error email ถูกใช้งานแล้ว แต่ถ้าลงทะเบียนสำเร็จจะส่งข้อมูลมาที่คลาส Register และคลาส Register จะส่งข้อมุลการลงทะเบียนแจ้งผูใช้ว่าลงทะเบียนสำเร็จและจะแสดงหน้าหลัก
จากภาพที่ \ref{Fig:Sequence-home} สามารถอธิบายแผนภาพ Sequence Diagram แสดงข้อมูลร้าน ได้ดังนี้ เมื่อ
ผู้ใช้เปิดโปรแกรมระบบจะเรียกใช้เมธอด onCreate() ที่คลาส WebBrowser เมื่อ Shopdata ถูกติดตั้งบน ShowShop เมธอด callData() จะสืบค้นข้อมูลจากฐานข้อมูลบน MySQL (node:shops) และส่งข้อมูลที่ได้ไปแปลงที่คลาส ShowShop โดยมีการคืนค่าเป็นข้อมูลร้านแต่ละแถวและในขั้นตอนสุดท้ายคลาส ShowShop จะทำการแสดงรายการข้อมูลร้านทั้งหมดออกทางหน้าจอ หากผู้ใช้มีการกดเลือกร้านบางแถวคลาส ShowShop จะทำการเรียกใช้ ShowShopDetail เพื่อแสดงรายละเอียดข้อมูลร้านของแถวที่ถูกเลือก
\begin{sidewaysfigure}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\columnwidth]
{Figures/3/Sequence/shop}
\caption{Sequence Diagram การแสดงข้อมูลโปรโมชั่น}
\label{Fig:Sequence-shop}
{Figures/3/Sequence/Login}
\caption{Sequence Diagram เข้าสู่ระบบ}
\label{Fig:Sequence-login}
\end{figure}
\end{sidewaysfigure}
\newpage
จากภาพที่ \ref{Fig:Sequence-login} สามารถอธิบายแผนภาพ Sequence Diagram การเข้าสู่ระบบ ได้ดังนี้ เมื่อ
เมื่อผู้ใช้กดปุ่ม Login ที่คลาส Login ระบบจะแสดงหน้า login ผู้ใช้ทำการกรอก email และ password ที่คลาส Login เมธอด onLogin() จะทำการเพิ่มข้อมูล Login โดยคลาส api:Server เมธอด login จะทำการสืบค้นข้อมูลจากฐานข้อมูลมาตรวจสอบสถานะการเข้าสู่ระบบ api:Server ทำการส่งข้อมูลการเข้าสู่ระบบไปยังคลาส Login และคลาส Login ส่งข้อมูลการเข้าสู้ระบบไปยังผู้ใช้แจ้งว่าเข้าสู่ระบบสำเร็จ
\newpage
จากภาพที่ \ref{Fig:Sequence-shop} สามารถอธิบายแผนภาพ Sequence Diagram แสดงโปรโมชั่น ได้ดังนี้ เมื่อ
ผู้ใช้เปิดโปรแกรมระบบจะเรียกใช้เมธอด onCreate() ที่คลาส WebBrowser ระบบจะทำการสร้าง
ข้อมูลโปรโมชั่น ขึ้นมาโดยใช้เมธอด onCreate() ที่คลาส WebBrowser เมื่อ ข้อมูลโปรโมชั่น ถูกติดตั้งบน ShowPromotion เมธอด callData() จะสืบค้นข้อมูลกำหนดการของวันปัจจุบันจากฐานข้อมูลบน MySQL node:promotions และส่งข้อมูลที่ได้ไปแปลงที่คลาส ShowPromotion โดยขั้นตอนสุดท้ายคลาส ShowPromotion จะทำการแสดงข้อมูลโปรโมชั่นออกทางหน้าจอ
\begin{sidewaysfigure}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\columnwidth]
{Figures/3/Sequence/review}
\caption{Sequence Diagram การแสดงข้อมูลรีวิว}
{Figures/3/Sequence/Review}
\caption{Sequence Diagram การรีวิว}
\label{Fig:Sequence-review}
\end{figure}
\end{sidewaysfigure}
\newpage
จากภาพที่ \ref{Fig:Sequence-review} สามารถอธิบายแผนภาพ Sequence Diagram แสดงข้อมูลรีวิว ได้ดังนี้ เมื่อผู้ใช้เปิดโปรแกรมระบบจะเรียกใช้เมธอด onCreate() ที่คลาส WebBrowser ระบบจะทำการสร้าง
ข้อมูลรีวิว ขึ้นมาโดยใช้เมธอด onCreate() ที่คลาส WebBrowser เมื่อ บ้อมูลรีวิว ถูกติดตั้งบน Showreview เมธอด callData() จะสืบค้นข้อมูลรีวิวทั้งหมดจากฐานข้อมูลบน MySQL node:reviews และส่งข้อมูลที่ได้ไปแปลงที่คลาส Showreview โดยจะทำการแสดงข้อมูลรีวิวออกทางหน้าจอ
จากภาพที่ \ref{Fig:Sequence-review} สามารถอธิบายแผนภาพ Sequence Diagram การรีวิว ได้ดังนี้ เมื่อผู้ใช้เปิดหน้า ShopPage ระบบจะเรียกใช้เมธอด componentDidMount() ที่คลาส Review ระบบจะแสดงข้อมูลการรีวิวออกทางหน้าจอ ผู้ใช้กดปุ่มเขียนรีวิวระบบจะแสดง model กรอกข้อมูลรีวิว และเมื่อผู้ใช้งานเลือกหัวข้อรีวิว กรอกข้อความรีวิว ให้คะแนนรีวิว และกด submit ระบบจะเรียกใช้เมธอด onAddReview() ที่คลาส Review โดยระบบจะส่งข้อมูลการรีวิวในรูปแบบ post ไปที่คลาส api:Server เมธอด review ทำการ insert ข้อมูลรีวิวลงฐานข้อมูล และระบบจะส่งสถานะการรีวิวมาที่คลาส api:Server และคลาส api:Server ทำการส่งสถานะการรีวิวสำเร็จมาที่คลาส Review ระบบจะแสดงข้อมูลการรีวิวออกทางหน้าจอ
\begin{sidewaysfigure}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\columnwidth]
{Figures/3/Sequence/addreview}
\caption{Sequence Diagram การเพิ่มรีวิว}
\label{Fig:Sequence-addreview}
{Figures/3/Sequence/addBeautician}
\caption{Sequence Diagram การเพิ่มข้อมูลช่าง}
\label{Fig:Sequence-addBeautician}
\end{figure}
\end{sidewaysfigure}
\newpage
จากภาพที่ \ref{Fig:Sequence-addreview} สามารถอธิบายแผนภาพ Sequence Diagram แสดงการสนทานา ได้ดังนี้ เมื่อผู้ใช้เปิดโปรแกรมระบบจะเรียกใช้เมธอด onCreate() ที่คลาส MainActivity ระบบจะทำการสร้าง
Fragment ขึ้นมาโดยใช้เมธอด onCreate() ที่คลาส UserChatFragment เมื่อ UserChatFrag-ment ถูกติดตั้งบน MainActivity เมธอด getMessage() จะสืบค้นข้อมูลประวัติการสนทนาของผู้ใช้คนปัจจุบันทั้งหมดจากฐานข้อมูลบน Firebase FireStore และส่งข้อมูลที่ได้ไปแปลงที่คลาส MessagesListAdapter โดยมีการคืนค่าเป็นข้อมูลรายการประวัติการสนทนาทั้งหมดและในขั้นตอนสุดท้ายคลาส User-ChatFragment จะทำการแสดงรายการประวัติการสนทนาทั้งหมดออกทางหน้าจอ เมื่อผู้ใช้พิมพ์ข้อความและกดปุ่มส่งระบบจะเรียกให้เมธอด send() เพื่อทำการบันทึกข้อมูลไว้บน Firebase FireStore และทำการแสดงข้อมูลรายการประวัติการสนทนาทั้งหมดที่ถูกอัพเดท
จากภาพที่ \ref{Fig:Sequence-addBeautician} สามารถอธิบายแผนภาพ Sequence Diagram การเพิ่มข้อมูลช่าง ได้ดังนี้ เมื่อเจ้าของร้านกดเครื่องหมายบอกระบบจะทำการแสดง model เพื่อกรอกข้อมูลเจ้าของร้านทำการกรอกข้อมูลและกดยืนยัน ระบบจะเรียกใช้เมธอด onAddBeautician ที่คลาส Beautician ระบบจะทำการส่งข้อมูลการลงทะเบียนช่างไปยังคลาส Register
โดยใช้เมธอด Onregister() ที่คลาส Register ส่งข้อมูลการลงทะเบียนระบบจะเรียกใช้เมธอด register ที่คลาส api:Server ทำการเชื่อม api insert ข้อมูลลงฐานข้อมูล ฐานข้อมูลจะส่งสถานะการลงทะเบียนมาที่คลาส api:Server ระบบจะแสดงสถานะการลงทะเบียนมายังคลาส Register และจะแสดงออกทางหน้าจอไปยังเจ้าของร้าน
\begin{sidewaysfigure}
\begin{figure}[H]
\centering
\includegraphics[width=0.99\columnwidth]
{Figures/3/Sequence/booking}
\caption{Sequence Diagram แสดงส่งเอกสารตรวจสอบ}
\label{Fig:Sequence-booking}
{Figures/3/Sequence/EditList}
\caption{Sequence Diagram การแก้ไขรายการ}
\label{Fig:Sequence-Editlist}
\end{figure}
\end{sidewaysfigure}
\newpage
จากภาพที่ \ref{Fig:Sequence-booking} สามารถอธิบายแผนภาพ Sequence Diagram แสดงส่งเอกสารตรวจสอบ ได้ดังนี้ เมื่อผู้ใช้เปิดโปรแกรมระบบจะเรียกใช้เมธอด onCreate() ที่คลาส MainActivity ระบบจะทำการสร้าง
Fragment ขึ้นมาโดยใช้เมธอด onCreate() ที่คลาส SubmitFragment เมื่อ Submit-Fragment ถูกติดตั้งบน MainActivity เมธอด initInstances() จะถูกเรียกเพื่อสร้างหน้าจอแสงดผลเมื่อผู้ใช้กดปุ่มถ่ายรูประบบจะเรียกใช้ไลบรารี่ ScanConstants เพื่อถ่ายภาพเอกสารและรอให้ผู้ใช้ถ่ายครบทั้งสองแผ่นจึงจะแสดงปุ่มกดส่งเอกสารเพื่อตรวจสอบ
\begin{sidewaysfigure}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\columnwidth]
{Figures/3/Sequence/addshop}
\caption{Sequence Diagram แสดงส่งเอกสารตรวจสอบ}
\label{Fig:Sequence-addshop}
\end{figure}
\end{sidewaysfigure}
\newpage
จากภาพที่ \ref{Fig:Sequence-addshop} สามารถอธิบายแผนภาพ Sequence Diagram แสดงส่งเอกสารตรวจสอบ ได้ดังนี้ เมื่อผู้ใช้เปิดโปรแกรมระบบจะเรียกใช้เมธอด onCreate() ที่คลาส MainActivity ระบบจะทำการสร้าง
Fragment ขึ้นมาโดยใช้เมธอด onCreate() ที่คลาส SubmitFragment เมื่อ Submit-Fragment ถูกติดตั้งบน MainActivity เมธอด initInstances() จะถูกเรียกเพื่อสร้างหน้าจอแสงดผลเมื่อผู้ใช้กดปุ่มถ่ายรูประบบจะเรียกใช้ไลบรารี่ ScanConstants เพื่อถ่ายภาพเอกสารและรอให้ผู้ใช้ถ่ายครบทั้งสองแผ่นจึงจะแสดงปุ่มกดส่งเอกสารเพื่อตรวจสอบ
จากภาพที่ \ref{Fig:Sequence-Editlist} สามารถอธิบายแผนภาพ Sequence Diagram การแก้ไขรายการ ได้ดังนี้ เมื่อเจ้าของร้านทำการ login เสร็จ เจ้าของร้านกดที่สัญลักษณ์แก้ไขระบบจะแสดงช่องให้กรอกข้อมูล และเมื่อเจ้าของร้านกรอกข้อมูลที่ต้องการแก้ไขเสร็จแล้วกดเครื่องหมายถูก ระบบจะทำการเรียกใช้เมธอด updateList() ที่คลาส Editlist ระบบจะทำการส่งข้อมูลแบบ put ไปยังคลาส api:Server ด้วยเมธอด list จะทำการ update ข้อมูลลงฐานข้อมูล ระบบจะทำการแจ้งเตือนแก้ไขข้อมูลสำเร็จและแสดงข้อมูลแก้ไขออกทางหน้าจอ
\begin{sidewaysfigure}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\columnwidth]
{Figures/3/Sequence/addlist}
\caption{Sequence Diagram แสดงส่งเอกสารตรวจสอบ}
\label{Fig:Sequence-addlist}
{Figures/3/Sequence/Editshop}
\caption{Sequence Diagram การแก้ไขข้อมูลร้าน }
\label{Fig:Sequence-editshop}
\end{figure}
\end{sidewaysfigure}
\newpage
จากภาพที่ \ref{Fig:Sequence-addlist} สามารถอธิบายแผนภาพ Sequence Diagram แสดงส่งเอกสารตรวจสอบ ได้ดังนี้ เมื่อผู้ใช้เปิดโปรแกรมระบบจะเรียกใช้เมธอด onCreate() ที่คลาส MainActivity ระบบจะทำการสร้าง
Fragment ขึ้นมาโดยใช้เมธอด onCreate() ที่คลาส SubmitFragment เมื่อ Submit-Fragment ถูกติดตั้งบน MainActivity เมธอด initInstances() จะถูกเรียกเพื่อสร้างหน้าจอแสงดผลเมื่อผู้ใช้กดปุ่มถ่ายรูประบบจะเรียกใช้ไลบรารี่ ScanConstants เพื่อถ่ายภาพเอกสารและรอให้ผู้ใช้ถ่ายครบทั้งสองแผ่นจึงจะแสดงปุ่มกดส่งเอกสารเพื่อตรวจสอบ
\begin{sidewaysfigure}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\columnwidth]
{Figures/3/Sequence/addpromotion}
\caption{Sequence Diagram แสดงส่งเอกสารตรวจสอบ}
\label{Fig:Sequence-addpromotion}
\end{figure}
\end{sidewaysfigure}
\newpage
จากภาพที่ \ref{Fig:Sequence-addpromotion} สามารถอธิบายแผนภาพ Sequence Diagram แสดงส่งเอกสารตรวจสอบ ได้ดังนี้ เมื่อผู้ใช้เปิดโปรแกรมระบบจะเรียกใช้เมธอด onCreate() ที่คลาส MainActivity ระบบจะทำการสร้าง
Fragment ขึ้นมาโดยใช้เมธอด onCreate() ที่คลาส SubmitFragment เมื่อ Submit-Fragment ถูกติดตั้งบน MainActivity เมธอด initInstances() จะถูกเรียกเพื่อสร้างหน้าจอแสงดผลเมื่อผู้ใช้กดปุ่มถ่ายรูประบบจะเรียกใช้ไลบรารี่ ScanConstants เพื่อถ่ายภาพเอกสารและรอให้ผู้ใช้ถ่ายครบทั้งสองแผ่นจึงจะแสดงปุ่มกดส่งเอกสารเพื่อตรวจสอบ
จากภาพที่ \ref{Fig:Sequence-editshop} สามารถอธิบายแผนภาพ Sequence Diagram การแก้ไขข้อมูลร้าน ได้ดังนี้ เเมื่อเจ้าของร้านทำการ login เสร็จ เจ้าของร้านกดที่สัญลักษณ์แก้ไขระบบจะแสดงช่องให้กรอกข้อมูล และเมื่อเจ้าของร้านกรอกข้อมูลที่ต้องการแก้ไขเสร็จแล้วกดยืนยัน ระบบจะทำการเรียกใช้เมธอด updateShop() ที่คลาส EditShop ระบบจะทำการส่งข้อมูลแบบ put ไปยังคลาส api:Server ด้วยเมธอด shop จะทำการ update ข้อมูลลงฐานข้อมูล ระบบจะทำการแจ้งเตือนแก้ไขข้อมูลสำเร็จและแสดงข้อมูลแก้ไขออกทางหน้าจอ
\begin{sidewaysfigure}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\columnwidth]
{Figures/3/Sequence/addbeautician}
\caption{Sequence Diagram แสดงส่งเอกสารตรวจสอบ}
\label{Fig:Sequence-addbeautician}
{Figures/3/Sequence/Booking}
\caption{Sequence Diagram การจองคิว}
\label{Fig:Sequence-booking}
\end{figure}
\end{sidewaysfigure}
\end{sidewaysfigure}
\newpage
จากภาพที่ \ref{Fig:Sequence-addbeautician} สามารถอธิบายแผนภาพ Sequence Diagram แสดงส่งเอกสารตรวจสอบ ได้ดังนี้ เมื่อผู้ใช้เปิดโปรแกรมระบบจะเรียกใช้เมธอด onCreate() ที่คลาส MainActivity ระบบจะทำการสร้าง
Fragment ขึ้นมาโดยใช้เมธอด onCreate() ที่คลาส SubmitFragment เมื่อ Submit-Fragment ถูกติดตั้งบน MainActivity เมธอด initInstances() จะถูกเรียกเพื่อสร้างหน้าจอแสงดผลเมื่อผู้ใช้กดปุ่มถ่ายรูประบบจะเรียกใช้ไลบรารี่ ScanConstants เพื่อถ่ายภาพเอกสารและรอให้ผู้ใช้ถ่ายครบทั้งสองแผ่นจึงจะแสดงปุ่มกดส่งเอกสารเพื่อตรวจสอบ
จากภาพที่ \ref{Fig:Sequence-booking} สามารถอธิบายแผนภาพ Sequence Diagram การจองคิว ได้ดังนี้ เมื่อผู้ใช้ทำการเข้าสู่ระบบสำเร็จ ทำการเลือกร้านที่ต้องการจองคิวที่คลาส Shop ระบบจะทำการแสดง model เพื่อจองคิว ผู้ใช้เรียกวันที่ รายการ ข้อมูลช่าง เวลา และกดยืนยัน ระบบจะเรียกใช้เมธอด addBooking() ที่คลาส BookingController เพิ่มข้อมูลวันที่ รายการ ข้อมูลช่าง เวลา แบบเมธอด post ในคลาส api:Server ด้วย เมธอด booking ทำการ insert ข้อมูลการจองคิวลงฐานข้อมูล ระบบจะทำการเช็คการจองคิวที่คลาส api:Server จะทำการตรวสอบข้อมูลการจองคิวกับฐานข้อมูลและส่งสถานะกับมาที่คลาส api:Server เพื่อแจ้งเตือนสถานะการจองคิว ถ้าการจองคิวไม่สำเร็จระบบจะแจ้งเตือนว่ายังไม่เข้าสู่ระบบและจะแสดงหน้าเข้าสู่ระบบ และเมื่อจองคิวสำเร็จระบบจะแจ้งเตือนว่าจองคิวสำเร็จระบบจะแสดงข้อมูลการจองคิวออกทางหน้าจอ
\begin{sidewaysfigure}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\columnwidth]
{Figures/3/Sequence/addshopimage}
\caption{Sequence Diagram แสดงส่งเอกสารตรวจสอบ}
\label{Fig:Sequence-addshopimage}
\end{figure}
\end{sidewaysfigure}
\newpage
จากภาพที่ \ref{Fig:Sequence-addshopimage} สามารถอธิบายแผนภาพ Sequence Diagram แสดงส่งเอกสารตรวจสอบ ได้ดังนี้ เมื่อผู้ใช้เปิดโปรแกรมระบบจะเรียกใช้เมธอด onCreate() ที่คลาส MainActivity ระบบจะทำการสร้าง
Fragment ขึ้นมาโดยใช้เมธอด onCreate() ที่คลาส SubmitFragment เมื่อ Submit-Fragment ถูกติดตั้งบน MainActivity เมธอด initInstances() จะถูกเรียกเพื่อสร้างหน้าจอแสงดผลเมื่อผู้ใช้กดปุ่มถ่ายรูประบบจะเรียกใช้ไลบรารี่ ScanConstants เพื่อถ่ายภาพเอกสารและรอให้ผู้ใช้ถ่ายครบทั้งสองแผ่นจึงจะแสดงปุ่มกดส่งเอกสารเพื่อตรวจสอบ
\begin{sidewaysfigure}
\section{ER-Diagram}
แผนภาพแสดงความสัมพันธ์ระหว่างข้อมูล (Entity Relationship Diagram : ERD) คือ แผนภาพที่ใช้เป็นเครื่องมือสําหรับจําลองข้อมูล ซึ่งจะประกอบไปด้วย เอนทิตี (Entity) แอททริบิว (Attribute) และความสัมพันธ์ (Relationship) ซึ่งการออกแบบฐานข้อมูลของเว็บบล็อกสำหรับวิจารณ์ภาพยนตร์ โดยใช้รูปแบบ ERD Chen Model ซึ่งมีสัญลักษณ์ดังตารางที่ \ref{tab:ER-Diagram}
\newpage
\begin{sidewaysfigure}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\columnwidth]
{Figures/3/Sequence/addbeauticianimage}
\caption{Sequence Diagram แสดงส่งเอกสารตรวจสอบ}
\label{Fig:Sequence-addbeauticianimage}
\includegraphics[width=1.0\columnwidth]
{Figures/3/DB/ER.png}
\caption{ER Diagram ระบบจองคิวร้านเสริมสวย}
\label{Fig:data}
\end{figure}
\end{sidewaysfigure}
\newpage
จากภาพที่ \ref{Fig:Sequence-addbeauticianimage} สามารถอธิบายแผนภาพ Sequence Diagram แสดงส่งเอกสารตรวจสอบ ได้ดังนี้ เมื่อผู้ใช้เปิดโปรแกรมระบบจะเรียกใช้เมธอด onCreate() ที่คลาส MainActivity ระบบจะทำการสร้าง
Fragment ขึ้นมาโดยใช้เมธอด onCreate() ที่คลาส SubmitFragment เมื่อ Submit-Fragment ถูกติดตั้งบน MainActivity เมธอด initInstances() จะถูกเรียกเพื่อสร้างหน้าจอแสงดผลเมื่อผู้ใช้กดปุ่มถ่ายรูประบบจะเรียกใช้ไลบรารี่ ScanConstants เพื่อถ่ายภาพเอกสารและรอให้ผู้ใช้ถ่ายครบทั้งสองแผ่นจึงจะแสดงปุ่มกดส่งเอกสารเพื่อตรวจสอบ
\newpage
\section{โครงสร้างฐานข้อมูลไฟร์เบส(Firebase Database Stucture)}
Firebase Database นั้นเป็น Database แบบ NoSQL และเป็น JSON database ที่มีโครงสร้างที่เป็น Key และ Value จัดเก็บข้อมูลในลักษณะโหนด หากต้องการเรียกงานจะเรียกใช้โดย
การท่องไปยังโหนดที่ต้องการ ส่วนประกอบสัญลักษณ์ที่ใช้ในการเขียนโครงสร้างฐานข้อมูลแบบ Firebase
แสดงดังตารางที่ \ref{tab:DB}
\end {sidewaysfigure}
\begin{table}[H]
\centering
\caption{สัญลักษณ์ของโครงสร้างฐานข้อมูลแบบ Firebase}
\label{tab:DB}
\begin{tabular}{| c | p{10cm} |}
\caption{สัญลักษณ์ของ ER-Diagram}
\label{tab:ER-Diagram}
\begin{tabular}{|c|p{10cm}|}
\hline
\textbf{สัญลักษณ์} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
\raisebox{-\totalheight}{\includegraphics[width=0.1\textwidth]{Figures/3/DB/dbroot}}
& \setstretch{1.5} {Database เป็นการเรียกชื่อแทนโหนด(Node)บนสุดที่ใช้ในการเก็บข้อมูล} \\ \hline
\raisebox{-\totalheight}{\includegraphics[width=0.1\textwidth]{Figures/3/DB/dbcollection}}
& \setstretch{1.5} {Collection เป็นการเรียกชื่อแทนของการเก็บหลาย ๆ เอกสารไว้ด้วยกัน} \\ \hline
\raisebox{-\totalheight}{\includegraphics[width=0.1\textwidth]{Figures/3/DB/dbdoc}}
& \setstretch{1.5} {Document เป็นการเรียกชื่อแทนหน่วยการเก็บของข้อมูลใน Cloud Firestore ภายในจะประกอบไปด้วย ชื่อของ Document ชื่อของคีย์ (key) และ ค่าข้อมูล (value) โดยชื่อของ Document ห้ามซ้ำกัน ซึ่งใน Cloud Firestore สามารถระบุประเภทของข้อมูลได้ 9 ประเภทได้แก่ boolean, number, string, geo point, timestamp, array, object, reference และ null} \\ \hline
\textbf{สัญลักษณ์} & \multicolumn{1}{c|}{\textbf{การใช้งาน}} \\ \hline
\raisebox{-\totalheight}{\includegraphics[height=2cm]{Figures/table/ER/1}}
& \setstretch{1.5} {การใช้งาน ใช้แสดงเอนทิตี้ เอนทิตี้ คือ กลุ่มของข้อมูลที่เป็นเรื่องเดียวกันที่ เกี่ยวข้องกัน} \\ \hline
\raisebox{-\totalheight}{\includegraphics[height=2cm]{Figures/table/ER/2}}
& \setstretch{1.5} {เอนทิตี้อ่อนแอ (Weak entity) คือ เอนทิตี้ที่มีการคงอยู่เกี่ยวข้อง กับเอนทิตี้อื่นในระบบฐานข้อมูล} \\ \hline
\raisebox{-\totalheight}{\includegraphics[width=3cm]{Figures/table/ER/3}}
& \setstretch{1.5} {เส้นความสัมพันธ์ (Relationship line ) คือ เส้นเชื่อมความสัมพันธ์ ระหว่าง เอนทิตี้} \\ \hline
\raisebox{-\totalheight}{\includegraphics[width=0.2\textwidth]{Figures/table/ER/4}}
& \setstretch{1.5} {ความสัมพันธ์ ใช้แสดงความสัมพันธ์ระหว่าง 2 เอนทิตี้ขึ้นไป} \\ \hline
\raisebox{-\totalheight}{\includegraphics[width=0.2\textwidth]{Figures/table/ER/5}}
& \setstretch{1.5} {Generalization แอททริบิว ใช้แสดง แอททริบิว ของ เอนทิตี้} \\ \hline
\raisebox{-\totalheight}{\includegraphics[width=0.2\textwidth]{Figures/table/ER/6}}
& \setstretch{1.5} {คีย์หลัก (Key Attribute) ใช้แสดงคีย์หลัก} \\ \hline
\raisebox{-\totalheight}{\includegraphics[width=0.2\textwidth]{Figures/table/ER/7}}
& \setstretch{1.5} {Multi-Value Attribute แอดที่นิ้วที่มีค่าของข้อมูลในแต่ละสมาชิกของเอนทิตี้ได้หลายค่า} \\ \hline
\raisebox{-\totalheight}{\includegraphics[width=0.3\textwidth]{Figures/table/ER/8}}
& \setstretch{1.5} {ความสัมพันธ์แบบหนึ่งต่อหนึ่ง} \\ \hline
\raisebox{-\totalheight}{\includegraphics[width=0.2\textwidth]{Figures/table/ER/9}}
& \setstretch{1.5} {ความสัมพันธ์แบบหนึ่งต่อกลุ่ม} \\ \hline
\raisebox{-\totalheight}{\includegraphics[width=0.2\textwidth]{Figures/table/ER/10}}
& \setstretch{1.5} {ความสัมพันธ์แบบกลุ่มต่อกลุ่ม} \\ \hline
\end{tabular}
\end{table}
\begin{figure}[H]
\centering
\includegraphics[width=0.7\columnwidth]
{Figures/3/DB/DB1}
\caption{โครงสร้างฐานข้อมูลแบบ Firebase}
\label{Fig:DB1}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=0.9\columnwidth]
{Figures/3/DB/DB2}
\caption{โครงสร้างฐานข้อมูลแบบ Firebase(ต่อ)}
\label{Fig:DB2}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=0.55\columnwidth]
{Figures/3/DB/DB3}
\caption{โครงสร้างฐานข้อมูลแบบ Firebase(ต่อ)}
\label{Fig:DB3}
\end{figure}
\begin{figure}[H]
\begin{table}[H]
\centering
\includegraphics[width=0.7\columnwidth]
{Figures/3/DB/DB4}
\caption{โครงสร้างฐานข้อมูลแบบ Firebase(ต่อ)}
\label{Fig:DB4}
\end{figure}
\caption{แสดงรายละเอียด Entity ของ ER-Diagram ระบบจองคิวร้านเสริมสวย}
\label{tab:แสดงรายละเอียด Entity}
\begin{tabular}{|p{3cm}|p{3cm}|p{4cm}|}
\hline
\multicolumn{1}{|c|}{\centering{ชื่อตาราง(ภาษาอังกฤษ)}} & \multicolumn{1}{c|}{\centering {ชื่อตาราง(ภาษาไทย)}} & \multicolumn{1}{c|}{\centering {อธิบาย}} \\ \hline
Users & ข้อมูลผู้ใช้ & ตารางเก็บข้อมูลผู้ใช้งาน \\ \hline
shops & ข้อมูลร้าน & ตารางเก็บข้อมูลร้าน \\ \hline
Lists & ข้อมูลรายการ & ตารางเก็บข้อมูลรายการ \\ \hline
Bookings & ข้อมูลการจอง & ตารางเก็บข้อมูการจองคิว \\ \hline
Beauticians & ข้อมูลผช่าง & ตารางเก็บข้อมูช่าง \\ \hline
Reviews & ข้อมูลรีวิว & ตารางเก็บข้อมูลรีวิว \\ \hline
Userimages & ข้อมูลรูปภาพผู้ใช้ & ตารางเก็บข้อมูลรูปภาพผู้ใช้งาน \\ \hline
Shopimages & ข้อมูลรูปภาพร้าน & ตารางเก็บข้อมูลรูปภาพร้าน \\ \hline
Workimages & ข้อมูลรูปภาพผลงานร้าน & ตารางเก็บข้อมูลรูปภาพผลงานร้าน \\ \hline
Beauticianimages & ข้อมูลรูปภาพผลงานช่าง & ตารางเก็บข้อมูลรูปภาพผลงานช่าง \\ \hline
\end{tabular}
\end{table}
\newpage
จากรูที่ \ref{Fig:DB1}-\ref{Fig:DB4} สามารถอธิบายโครงสร้างของข้อมูลได้ดังนี้
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]
{Figures/3/DB/nodePost}
\caption{โหนดเก็บข้อมูลประกาศ}
\label{Fig:DB4}
\end{figure}
\begin{table}[H]
\centering
\caption{อธิบายโหนดที่ใช้เก็บข้อมูลประกาศ}
\label{my-label1}
\begin{tabular}{|c|p{10cm}|}
\caption{แสดงรายละเอียด Attribute ของ Entity Users}
\label{tab:แสดงรายละเอียด users}
\begin{tabular}{|p{2cm}|p{2cm}|p{2cm}|p{2cm}|p{2cm}|}
\hline
\multicolumn{1}{|c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
Posts & โหนดสำหรับเก็บข้อมูลประกาศทั้งหมด \\ \hline
Post & สำหรับเก็บข้อมูลแต่ละประกาศ \\ \hline
title & สำหรับเก็บชื่อหัวข้อประกาศ \\ \hline
description & สำหรับเก็บรายละเอียดประกาศ \\ \hline
collection & สำหรับเก็บประเภทของประกาศได้แก่ สาธารณะและเฉพาะบุคคล \\ \hline
fileURL & สำหรับเก็บ url ของเอกสารแนบประกาศ \\ \hline
id & สำหรับเก็บรหัสของประกาศ \\ \hline
time & สำหรับเก็บเวลาที่ประกาศ \\ \hline
\multicolumn{1}{|c|}{\textbf{Field}} & \multicolumn{1}{c|}{\textbf{Type}} & \multicolumn{1}{c|}{\textbf{Description}} &
\multicolumn{1}{c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{Reference}} \\ \hline
id & int(11) & รหัสผู้ใช้งาน & PK & \\ \hline
name & varchar(50) & ชื่อ & & \\ \hline
email & varchar(255) & อีเมลล์ & & \\ \hline
password & varchar(255) & รหัสผ่าน & &\\ \hline
address & text & ที่อยู่ & &\\ \hline
tel & int(11) & เบอร์โทร & &\\ \hline
role & int (11)& บทบาท & &\\ \hline
\end{tabular}
\end{table}
\newpage
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]
{Figures/3/DB/nodeDoc}
\caption{โหนดเก็บข้อมูลเอกสารที่เกี่ยวข้อง}
\label{Fig:DB4}
\end{figure}
\begin{table}[H]
\centering
\caption{อธิบายโหนดที่ใช้เก็บข้อมูลเอกสารที่เกี่ยวข้อง}
\label{my-label1}
\begin{tabular}{|c|p{10cm}|}
\caption{แสดงรายละเอียด Attribute ของ Entity Shops}
\label{tab:แสดงรายละเอียดข้อมูล Shops}
\begin{tabular}{|p{2cm}|p{2cm}|p{2cm}|p{2cm}|p{2cm}|}
\hline
\multicolumn{1}{|c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
Docs & โหนดสำหรับเก็บข้อมูลของเอกสารที่เกี่ยวข้องทั้งหมด \\ \hline
Doc & สำหรับเก็บข้อมูลเอกสารแต่ละฉบับ \\ \hline
title & สำหรับเก็บชื่อหัวเรื่องของเอกสาร \\ \hline
description & สำหรับเก็บรายละเอียดของเอกสาร \\ \hline
fileType & สำหรับนามสกุลไฟล์เอกสาร เช่น .pdf .png เป็นต้น \\ \hline
fileURL & สำหรับเก็บ url ของเอกสาร\\ \hline
time & สำหรับเก็บเวลาที่ถูกอัพโหลดเข้าสู่ระบบโดยเจ้าหน้าที่\\ \hline
\multicolumn{1}{|c|}{\textbf{Field}} & \multicolumn{1}{c|}{\textbf{Type}} & \multicolumn{1}{c|}{\textbf{Description}} &
\multicolumn{1}{c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{Reference}} \\ \hline
id & int(11) & รหัสร้าน & PK & \\ \hline
name & varchar(50) & ชื่อ & & \\ \hline
nameeng & varchar(50) & ชื่อภาษาอังกฤษ & & \\ \hline
timeopen & time & เวลาเปิด & &\\ \hline
timeclose & time & เวลาปิด & &\\ \hline
address & text & ที่อยู่ & &\\ \hline
tel & varchar(20)& เบอร์โทร & &\\ \hline
detail & text & รายละเอียด & & \\ \hline
lat & double & ตำแหน่ง x & & \\ \hline
lng& double & ตำแหน่ง y & &\\ \hline
facebook & text & เฟซบุ๊ค & &\\ \hline
userId & int(11) & รหัสผู้ใช้ &FK & Users\\ \hline
type & text & บทบาท & &\\ \hline
\end{tabular}
\end{table}
\newpage
\begin{figure}[H]
\centering
\includegraphics[width=0.4\columnwidth]
{Figures/3/DB/nodeChat}
\caption{โหนดเก็บข้อมูลประวัติการสนทนา}
\label{Fig:DB4}
\end{figure}
\begin{table}[H]
\centering
\caption{อธิบายโหนดที่ใช้เก็บข้อมูลประวัติการสนทนา}
\label{my-label1}
\begin{tabular}{|c|p{10cm}|}
\caption{แสดงรายละเอียด Attribute ของ Entity Lists}
\label{tab:แสดงรายละเอียดข้อมูล Lists}
\begin{tabular}{|p{2cm}|p{2cm}|p{2cm}|p{2cm}|p{2cm}|}
\hline
\multicolumn{1}{|c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
Chats & โหนดสำหรับเก็บข้อมูลประวัติการสนทนาทั้งหมด \\ \hline
User\_id & สำหรับเก็บประวัติการสนทนาของผู้ใช้แต่ละคน \\ \hline
Messages & สำหรับเก็บประวัติการสนทนาทั้งหมดของผู้ใช้ \\ \hline
Message & สำหรับเก็บข้อมูลของแต่ละข้อความ \\ \hline
message & สำหรับเก็บข้อความ \\ \hline
name & สำหรับเก็บชื่อของผู้ส่งข้อความ\\ \hline
photo & สำหรับเก็บ url รูปภาพของผู้ส่งข้อความ\\ \hline
senderId & สำหรับเก็บรหัสของผู้ส่งข้อความ\\ \hline
time & สำหรับเก็บเวลาที่ข้อความถูกส่ง\\ \hline
\multicolumn{1}{|c|}{\textbf{Field}} & \multicolumn{1}{c|}{\textbf{Type}} & \multicolumn{1}{c|}{\textbf{Description}} &
\multicolumn{1}{c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{Reference}} \\ \hline
id & int(11) & รหัสรายการ & PK & \\ \hline
name & varchar(50) & ชื่อ & & \\ \hline
price & int(11) & ราคา & & \\ \hline
time & int(11) & เวลา & &\\ \hline
shop & int(11) & รหัสร้าน &FK &Shops\\ \hline
userId & int(11) & รหัสผู้ใช้งาน &FK &Users\\ \hline
\end{tabular}
\end{table}
\newpage
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]
{Figures/3/DB/nodeEvent}
\caption{โหนดเก็บข้อมูลกำหนดการ}
\label{Fig:DB4}
\end{figure}
\begin{table}[H]
\centering
\caption{อธิบายโหนดที่ใช้เก็บข้อมูลกำหนดการ}
\label{my-label1}
\begin{tabular}{|c|p{10cm}|}
\caption{แสดงรายละเอียด Attribute ของ Entity Bookings}
\label{tab:แสดงรายละเอียดข้อมูล Bookings}
\begin{tabular}{|p{2cm}|p{2cm}|p{2cm}|p{2cm}|p{2cm}|}
\hline
\multicolumn{1}{|c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
Events & โหนดสำหรับเก็บข้อมูลของกำหนดการทั้งหมด \\ \hline
Event & สำหรับเก็บข้อมูลของแต่ละกำหนดการ \\ \hline
title & สำหรับเก็บชื่อหัวข้อของกำหนดการ \\ \hline
description & สำหรับเก็บรายละเอียดของกำหนดการ\\ \hline
time & สำหรับเก็บเวลาของกำหนดการ\\ \hline
\multicolumn{1}{|c|}{\textbf{Field}} & \multicolumn{1}{c|}{\textbf{Type}} & \multicolumn{1}{c|}{\textbf{Description}} &
\multicolumn{1}{c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{Reference}} \\ \hline
id & int(11) & รหัสการจอง & PK & \\ \hline
name & varchar(50) & ชื่อ & & \\ \hline
shop & int(11) & รหัสร้าน & FK&Shops \\ \hline
list & int(11) & รหัสรายการ &FK &Lists\\ \hline
beautician & int(11) & รหัสช่าง &FK &Beauticians\\ \hline
date & int(11) & วันที่ & &\\ \hline
time & time & เวลา & &\\ \hline
\end{tabular}
\end{table}
\newpage
\begin{figure}[H]
\centering
\includegraphics[width=0.4\columnwidth]
{Figures/3/DB/nodeReq}
\caption{โหนดเก็บข้อมูลการยื่นสำเนาเอกสารเพื่อตรวจสอบของนักศึกษา}
\label{Fig:DB4}
\end{figure}
\begin{table}[H]
\centering
\caption{อธิบายโหนดที่ใช้เก็บข้อมูลการยื่นสำเนาเอกสารเพื่อตรวจสอบของนักศึกษา}
\label{my-label1}
\begin{tabular}{|c|p{10cm}|}
\caption{แสดงรายละเอียด Attribute ของ Entity Beauticians}
\label{tab:แสดงรายละเอียดข้อมูล Beauticians}
\begin{tabular}{|p{2cm}|p{2cm}|p{2cm}|p{2cm}|p{2cm}|}
\hline
\multicolumn{1}{|c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
RusetSubmitDocs & โหนดสำหรับเก็บข้อมูลการยื่นสำเนาเอกสารเพื่อตรวจสอบของนักศึกษาทั้งหมด \\ \hline
User\_id & สำหรับเก็บข้อมูลของแต่ละสำเนาเอกสารของนักศึกษาแต่ละคน \\ \hline
doc2 & สำหรับเก็บ url ของภาพถ่ายสำเนาเอกสารฉบับที่ 1\\ \hline
doc2 & สำหรับเก็บ url ของภาพถ่ายสำเนาเอกสารฉบับที่ 2\\ \hline
status & สำหรับเก็บผลการตรวจสอบของเจ้าหน้าที่ \\ \hline
time & สำหรับเก็บเวลาที่สำเนาเอกสารถูกเพิ่มเข้าสู่ระบบ \\ \hline
\multicolumn{1}{|c|}{\textbf{Field}} & \multicolumn{1}{c|}{\textbf{Type}} & \multicolumn{1}{c|}{\textbf{Description}} &
\multicolumn{1}{c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{Reference}} \\ \hline
id & int(11) & รหัสช่าง & PK & \\ \hline
name & varchar(50) & ชื่อ & & \\ \hline
userID & int(11) & รหัสผู้ใช้งาน & FK&Users\\ \hline
shopID & int (11)& รหัสร้าน &FK &Shops\\ \hline
\end{tabular}
\end{table}
\newpage
\begin{figure}[H]
\centering
\includegraphics[width=0.35\columnwidth]
{Figures/3/DB/nodeUser}
\caption{โหนดเก็บข้อมูลของนักศึกษา}
\label{Fig:DB4}
\end{figure}
\begin{table}[H]
\centering
\caption{อธิบายโหนดที่ใช้เก็บข้อมูลของนักศึกษา}
\label{my-label1}
\begin{tabular}{|c|p{10cm}|}
\caption{แสดงรายละเอียด Attribute ของ Entity Reviews}
\label{tab:แสดงรายละเอียดข้อมูล Reviews}
\begin{tabular}{|p{2cm}|p{2cm}|p{2cm}|p{2cm}|p{2cm}|}
\hline
\multicolumn{1}{|c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
Users & โหนดสำหรับเก็บข้อมูลของนักศึกษา \\ \hline
User\_id & สำหรับเก็บข้อมูลของนักศึกษาแต่ละคน \\ \hline
depart & สำหรับเก็บภาควิชาของนักศึกษา\\ \hline
major & สำหรับเก็บสาขาของนักศึกษา\\ \hline
sid & สำหรับเก็บรหัสประจำตัวนักศึกษา \\ \hline
name & สำหรับเก็บชื่อของนักศึกษา \\ \hline
year & สำหรับเก็บชั้นปีของนักศึกษา \\ \hline
lastChat & สำหรับเก็บเวลาที่สนทนากับเจ้าหน้าที่ล่าสุด \\ \hline
photoUrl & สำหรับเก็บ url รูปภาพโปรไฟล์ (Profile) \\ \hline
\multicolumn{1}{|c|}{\textbf{Field}} & \multicolumn{1}{c|}{\textbf{Type}} & \multicolumn{1}{c|}{\textbf{Description}} &
\multicolumn{1}{c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{Reference}} \\ \hline
id & int(11) & รหัสรีวิว & PK & \\ \hline
topic & text & หัวข้อรีวิว & & \\ \hline
message &text & ข้อความรีวิว & & \\ \hline
point & double & คะแนน & &\\ \hline
shop & int(11) & รหัสร้าน &FK &Shops\\ \hline
userID & int(11) & เบอร์โทร & FK&Users\\ \hline
\end{tabular}
\end{table}
\newpage
\begin{figure}[H]
\begin{table}[H]
\centering
\includegraphics[width=0.5\columnwidth]
{Figures/3/DB/nodeQueue}
\caption{โหนดเก็บข้อมูลการจองคิวของนักศึกษา}
\label{Fig:DB4}
\end{figure}
\caption{แสดงรายละเอียด Attribute ของ Entity Userimages}
\label{tab:แสดงรายละเอียดข้อมูล Userimages}
\begin{tabular}{|p{2cm}|p{2cm}|p{2cm}|p{2cm}|p{2cm}|}
\hline
\multicolumn{1}{|c|}{\textbf{Field}} & \multicolumn{1}{c|}{\textbf{Type}} & \multicolumn{1}{c|}{\textbf{Description}} &
\multicolumn{1}{c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{Reference}} \\ \hline
image_id & int(11) & รหัสรูปภาพ & PK & \\ \hline
user_id & int(11) & รหัสผู้ใช้งาน & PK& \\ \hline
image & longblob & รูปภาพผู้ใช้งาน & & \\ \hline
type& varchar(50) & ประเภทรูปภาพ & &\\ \hline
\end{tabular}
\end{table}
\begin{table}[H]
\centering
\caption{อธิบายโหนดที่ใช้เก็บข้อมูลการจองคิวของนักศึกษา}
\label{my-label1}
\begin{tabular}{|c|p{10cm}|}
\caption{แสดงรายละเอียด Attribute ของ Entity Shopimages}
\label{tab:แสดงรายละเอียดข้อมูล Shopimages}
\begin{tabular}{|p{2cm}|p{2cm}|p{2cm}|p{2cm}|p{2cm}|}
\hline
\multicolumn{1}{|c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
Queue & โหนดสำหรับเก็บข้อมูลการจองคิวของนักศึกษาทั้งหมด \\ \hline
q\_id & สำหรับเก็บข้อมูลของการจองคิวแต่ละครั้งที่เปิดจองคิว \\ \hline
Date & สำหรับเก็บวันที่สำหรับส่งเอกสาร\\ \hline
Time & สำหรับเก็บรายชื่อของนักศึกษาที่ทำการจองคิวในส่งเอกสารเวลานั้น ๆ\\ \hline
User\_id & สำหรับเก็บรหัสของนักศึกษา \\ \hline
title & สำหรับเก็บชื่อหัวเรื่องกำหนดการการจองคิว \\ \hline
studentPerHr & สำหรับเก็บจำนวนนักศึกษาต่อชั่วโมง \\ \hline
\multicolumn{1}{|c|}{\textbf{Field}} & \multicolumn{1}{c|}{\textbf{Type}} & \multicolumn{1}{c|}{\textbf{Description}} &
\multicolumn{1}{c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{Reference}} \\ \hline
image_id & int(11) & รหัสรูปภาพ & PK & \\ \hline
shop_id & int(11) & รหัสร้าน & PK& \\ \hline
image & longblob & รูปภาพร้าน & & \\ \hline
type& varchar(50) & ประเภทรูปภาพ & &\\ \hline
\end{tabular}
\end{table}
\newpagedr
\begin{figure}[H]
\begin{table}[H]
\centering
\includegraphics[width=0.4\columnwidth]
{Figures/3/DB/nodeFaq}
\caption{โหนดเก็บข้อมูลคำถามที่พบบ่อย}
\label{Fig:DB4}
\end{figure}
\caption{แสดงรายละเอียด Attribute ของ Entity Workimages}
\label{tab:แสดงรายละเอียดข้อมูล Workimages}
\begin{tabular}{|p{2cm}|p{2cm}|p{2cm}|p{2cm}|p{2cm}|}
\hline
\multicolumn{1}{|c|}{\textbf{Field}} & \multicolumn{1}{c|}{\textbf{Type}} & \multicolumn{1}{c|}{\textbf{Description}} &
\multicolumn{1}{c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{Reference}} \\ \hline
image_id & int(11) & รหัสรูปภาพ & PK & \\ \hline
shop_id & int(11) & รหัสร้าน & PK& \\ \hline
image & longblob & รูปภาพผลงานร้าน & & \\ \hline
type& varchar(50) & ประเภทรูปภาพ & &\\ \hline
\end{tabular}
\end{table}
\begin{table}[H]
\centering
\caption{อธิบายโหนดที่ใช้เก็บข้อมูลคำถามที่พบบ่อย}
\label{my-label1}
\begin{tabular}{|c|p{10cm}|}
\caption{แสดงรายละเอียด Attribute ของ Entity Beauticianimages}
\label{tab:แสดงรายละเอียดข้อมูล Beauticianimages}
\begin{tabular}{|p{2cm}|p{2cm}|p{2cm}|p{2cm}|p{2cm}|}
\hline
\multicolumn{1}{|c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{คำอธิบาย}} \\ \hline
Queue & โหนดสำหรับเก็บข้อมูลคำถามที่พบบ่อยทั้งหมด \\ \hline
Faq\_id & สำหรับเก็บข้อมูลคำถามที่พบบ่อยแต่ละรายการ \\ \hline
title & สำหรับเก็บคำถาม \\ \hline
description & สำหรับเก็บคำตอบ \\ \hline
\multicolumn{1}{|c|}{\textbf{Field}} & \multicolumn{1}{c|}{\textbf{Type}} & \multicolumn{1}{c|}{\textbf{Description}} &
\multicolumn{1}{c|}{\textbf{Key}} & \multicolumn{1}{c|}{\textbf{Reference}} \\ \hline
image_id & int(11) & รหัสรูปภาพ & PK & \\ \hline
beautician_id & int(11) & รหัสช่าง & PK& \\ \hline
image & longblob & รูปภาพผลงานช่าง & & \\ \hline
type& varchar(50) & ประเภทรูปภาพ & &\\ \hline
\end{tabular}
\end{table}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
\chapter{การทดสอบระบบ}
การทดสอบการทำงานของเว็บไซต์ โดยทำการทดสอบในลักษณะ Black-box Testing \cite{blackbox} หรือ Data-Driven testing ซึ่งเป็นการเทสแบบที่ไม่สนใจโปรเซส (Process) การทำงานภายในของโปรแกรมว่าทำงานอย่างไร แต่จะเน้นไปที่ Input และ Result ที่ได้มากกว่าว่าการทำงานต่าง ๆ ถูกต้องตามความต้องการ (Requirement) หรือไม่ ซึ่งการทดสอบการใช้งานแอนดรอยด์แอปพลิเคชัน และ การใช้งานเว็บแอปพลิเคชัน ได้ผลดังนี้
การทดสอบการทำงานของเว็บไซต์ โดยทำการทดสอบในลักษณะ Black-box Testing \cite{blackbox} หรือ Data-Driven testing ซึ่งเป็นการเทสแบบที่ไม่สนใจโปรเซส (Process) การทำงานภายในของโปรแกรมว่าทำงานอย่างไร แต่จะเน้นไปที่ Input และ Result ที่ได้มากกว่าว่าการทำงานต่าง ๆ ถูกต้องตามความต้องการ (Requirement) หรือไม่ ซึ่งการทดสอบการใช้งานเว็บแอปพลิเคชัน ได้ผลดังนี้
\section{การทดสอบการใช้งานแอนดรอยด์แอปพลิเคชัน}
\begin{itemize}
\item{การทดสอบการใช้งานเมนูนำทางของแอนดรอยด์แอปพลิเคชัน}
การทดสอบเมนูนำทางของแอปพลิเคชันในการนำทางผู้ใช้งาน ซึ่งเมนูหลักประกอบด้วย เมูนูหน้าประกาศ เมนูหน้าสนทนา เมนูหน้าปฏิทินกำหนดการ เมนูหน้าดาวน์โหลดเอกสาร เมนูส่งภาพถ่ายสำเนาเอกสาร เมนูหน้าจองคิวส่งเอกสาร เมนูหน้าคำถามทีพบบ่อย เมนูหน้าเกี่ยวกับ เมนูหน้าข้อมูลส่วนตัวและเมนูออกจากระบบ ผลทดสอบดังตารางที่ \ref{tab:ผลการทดเมนูหลัก}-\ref{tab:ผลการทดเมนูนำทาง2}
\begin{table}[H]
\caption{ผลการทดสอบเมนูนำทาง}
\centering
\label{tab:ผลการทดเมนูหลัก}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{เมนูประกาศ}
& \setstretch{1.0}{กดปุ่มเมนูประกาศ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการประกาศทั้งหมด} \\ \hline
\setstretch{1.0}{เมนูสนทนา}
& \setstretch{1.0}{กดปุ่มเมนูสนทนา}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอสนทนาพร้อมทั้งแสดงข้อมูลประวัติการสนทนา} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูหน้าปฏิทินกำหนดการ}
& \setstretch{1.0}{กดปุ่มเมนูปฏิทินกำหนดการ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอสนทนาพร้อมทั้งแสดงข้อมูลประวัติการสนทนา} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูหน้าดาวน์โหลดเอกสาร}
& \setstretch{1.0}{กดปุ่มเมนูหน้าดาวน์โหลดเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอรายการเอกสารในระบบพร้อมทั้งแสดงปุมดาวน์โหลด} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูหน้าส่งภาพถ่ายสำเนาเอกสาร}
& \setstretch{1.0}{กดปุ่มเมนูหน้าส่งภาพสำเนาเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลหน้าส่งเอกสารภาพสำเนาเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\end{tabular}
\end{table}
\begin{table}[H]
\caption{ผลการทดสอบเมนูนำทาง(ต่อ)}
\centering
\label{tab:ผลการทดเมนูนำทาง2}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{เมนูหน้าจองคิวส่งเอกสาร}
& \setstretch{1.0}{กดปุ่มเมนูหน้าจองคิวส่งเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลหน้าจองคิวส่งเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอข่าวสารพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูหน้าคำถามทีพบบ่อย}
& \setstretch{1.0}{กดปุ่มเมนูหน้าคำถามทีพบบ่อย}
& \setstretch{1.0}{ระบบแสดงหน้าจองคิวส่งเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูหน้าเกี่ยวกับ}
& \setstretch{1.0}{กดปุ่มเมนูหน้าเกี่ยวกับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าเกี่ยวกับซึ่งแสดงข้อมูลผู้พัฒนาวรมไปถึงแสดงเครดิต (credit) ไลบรารีต่าง ๆ ที่ใช้งานภายในแอปพลิเคชัน} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูหน้าบัญชีผู้ใช้}
& \setstretch{1.0}{กดปุ่มเมนูหน้าบัญชีผู้ใช้}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอข้อมูลส่วนตัวโดยมีข้อมูล รูปประจำตัว ชื่อผู้ใช้ สาขาวิชาและภาควิชา} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูออกจากระบบ}
& \setstretch{1.0}{กดปุ่มเมนูออกจากระบบ}
& \setstretch{1.0}{ทำการออกจากระบบและแสดงหน้าจอข่าวสาร} \\ \hline
\end{tabular}
\end{table}
\newpage
\item{การทดสอบหน้ารายละเอียดประกาศ}
ในการแสดงผลหน้าจอรายละเอียดประกาศนั้นจะประกอบไปด้วยหัวเรื่องประกาศ รายละเอียดประกาศ วันที่ประกาศและเอกสารแนบ ผลการทดสอบดังตารางที่ \ref{tab:การทดหน้ารายละเอียดประกาศ}
\begin{table}[H]
\caption{ผลการทดสอบหน้ารายละเอียดประกาศ}
\centering
\label{tab:การทดหน้ารายละเอียดประกาศ}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{หน้ารายละเอียดประกาศ}
& \setstretch{1.0}{กดปุ่มเมนูประกาศ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการประกาศทั้งหมด} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มอ่านรายละเอียดประกาศ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอรายละเอียดประกาศ} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มดาวน์โหลดเอกสารแนบ}
& \setstretch{1.0}{ระบบแสดงผลการดาวน์โหลดเอกสารแนบ} \\ \cline{2-3}
& \setstretch{1.0}{เมื่อดาวน์โหลดเสร็จ กดปุ่มเปิดเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอรายละเอียดประกาศ} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับอีกครั้ง}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\end{tabular}
\end{table}
\newpage
\item{การทดสอบหน้าสนทนา} ในการแสดงผลหน้าจอสนทนานั้นจะประกอบไปด้วยรายการประวิติการสนทนา ช่องกรอกข้อความและปุ่มส่งข้อความ ผลการทดสอบดังตารางที่ \ref{tab:การทดสอบหน้าสนทนา}
\begin{table}[H]
\caption{ผลการการทดสอบหน้าสนทนา}
\centering
\label{tab:การทดสอบหน้าสนทนา}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{หน้ารายละเอียดประกาศ}
& \setstretch{1.0}{กดปุ่มเมนูสนทนา}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอสนทนาพร้อมทั้งแสดงรายการประวัติการสนทนา} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มที่ช่องกรอกข้อความ}
& \setstretch{1.0}{ระบบแสดงตัวกระพริบ (cursor) เพื่อชี้ให้รู้ว่า ตำแหน่งของการพิมพ์อักขระ} \\ \cline{2-3}
& \setstretch{1.0}{พิมพ์อักขระ}
& \setstretch{1.0}{ระบบแสดงผลอัขระที่ถูกพิมพ์} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มส่งข้อความ}
& \setstretch{1.0}{ระบบแสดงข้อความที่ถูกพิมพ์บนรายการประวัติสนทนาล่าสุด} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\end{tabular}
\end{table}
\newpage
\item{การทดสอบหน้าปฏิทินกำหนดการ}
ในการแสดงผลหน้าปฏิทินกำหนดการนั้นจะประกอบไปด้วยรายการประวิติการสนทนา ช่องกรอกข้อความและปุ่มส่งข้อความ ผลการทดสอบดังตารางที่ \ref{tab:การทดสอบหน้าปฏิทินกำหนดการ}
\begin{table}[H]
\caption{ผลการการทดสอบหน้าปฏิทินกำหนดการ}
\centering
\label{tab:การทดสอบหน้าปฏิทินกำหนดการ}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{หน้าปฏิทินกำหนดการ}
& \setstretch{1.0}{กดปุ่มเมนูปฏิทินกำหนดการ}
& \setstretch{1.0}{ระบบแสดงหน้าจอปฏิทินกำหนดการโดยมีการแสดงกำหนดการของวันปัจจุบัน} \\ \cline{2-3}
& \setstretch{1.0}{กดเลือกวันที่ต้องการดูกำหนดการในปฏิทิน}
& \setstretch{1.0}{ระบบแสดงกำหนดการของวันที่ถูกเลือก} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\end{tabular}
\end{table}
\newpage
\item{การทดสอบหน้าดาวน์โหลดเอกสาร}
ในการแสดงผลหน้าจอดาวน์โหลดเอกสารนั้นจะประกอบไปด้วยรายการเอกสารโดยที่แต่ละฉบับบจะแสดงชื่อเอกสารและปุ่มดาวน์โหลดเอกสาร ผลการทดสอบดังตารางที่ \ref{tab:การทดสอบหน้าดาวน์โหลดเอกสาร}
\begin{table}[H]
\caption{ผลการการทดสอบหน้าดาวน์โหลดเอกสาร}
\centering
\label{tab:การทดสอบหน้าดาวน์โหลดเอกสาร}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{หน้าดาวน์โหลดเอกสาร}
& \setstretch{1.0}{กดปุ่มเมนูหน้าดาวน์โหลดเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอรายการเอกสารในระบบพร้อมทั้งแสดงปุมดาวน์โหลด} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มดาวน์โหลดเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลการดาวน์โหลดเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{เมื่อดาวน์โหลดเสร็จ กดปุ่มเปิดเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอรายการเอกสารในระบบพร้อมทั้งแสดงปุมดาวน์โหลด} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\end{tabular}
\end{table}
\newpage
\item{การทดสอบหน้าส่งภาพถ่ายสำเนาเอกสาร}
% \item การทดสอบหน้าส่งภาพถ่ายสำเนาเอกสาร\\
ในการแสดงผลหน้าส่งภาพถ่ายสำเนาเอกสารนั้นจะประกอบไปด้วยปุ่มเพิ่มเอกสารฉบับที่ 1 ปุ่มเพิ่มเอกสารฉบับที่ 2 และปุ่มส่งเอกสาร ผลการทดสอบดังตารางที่ \ref{tab:การทดสอบหน้าส่งภาพถ่ายสำเนาเอกสาร}
\begin{table}[H]
\caption{ผลการทดสอบหน้าส่งภาพถ่ายสำเนาเอกสาร}
\centering
\label{tab:การทดสอบหน้าส่งภาพถ่ายสำเนาเอกสาร}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{หน้าส่งภาพถ่ายสำเนาเอกสาร}
& \setstretch{1.0}{กดปุ่มเมนูหน้าจองคิวส่งเอกสาร}
& \setstretch{1.0}{ระบบแสดงหน้าจองคิวส่งเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มเพิ่มเอกสารฉบับที่ 1}
& \setstretch{1.0}{ระบบแสดงหน้าจอกล้องถ่ายภาพ} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มถ่ายภาพเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลภาพเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มถัดไป}
& \setstretch{1.0}{ระบบแสดงผลหน้าปรัปแต่งภาพเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มยืนยัน}
& \setstretch{1.0}{ระบบแสดงผลภาพหน้าส่งภาพถ่ายสำเนาเอกสารพร้อมทั้งแสดงผลภาพเอกสารฉบับที่ 1} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มเพิ่มเอกสารฉบับที่ 2}
& \setstretch{1.0}{ระบบแสดงหน้าจอกล้องถ่ายภาพ} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มถ่ายภาพเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลภาพเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มถัดไป}
& \setstretch{1.0}{ระบบแสดงผลหน้าปรัปแต่งภาพเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มยืนยัน}
& \setstretch{1.0}{ระบบแสดงผลภาพหน้าส่งภาพถ่ายสำเนาเอกสารพร้อมทั้งแสดงผลภาพเอกสารฉบับที่ 1 และฉบับที่ 2} \\ \cline{2-3}
& \setstretch{1.0}{กดส่งเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลการส่งเอกสารและแสดงสถานะการตรวจเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\end{tabular}
\end{table}
\newpage
\item{การทดสอบหน้าจองคิวส่งเอกสาร}
ในการแสดงผลหน้าจองคิวส่งเอกสารนั้นจะประกอบไปด้วยปุ่มกดเลือกวันที่ ปุ่มกดเลือเวลา ผลการทดสอบดังตารางที่ \ref{tab:การทดสอบหน้าจองคิวส่งเอกสาร}
\begin{table}[H]
\caption{ผลการทดสอบหน้าจองคิวส่งเอกสาร}
\centering
\label{tab:การทดสอบหน้าจองคิวส่งเอกสาร}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{หน้าจองคิวส่งเอกสาร}
& \setstretch{1.0}{กดปุ่มเมนูหน้าจองคิวส่งเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอกำหนดการส่งเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มเลือกวันที่ต้องการส่งเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลวันที่ถูกเลือก} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มเลือกเวลาที่ต้องการส่งเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลเวลาที่ถูกเลือกพร้อมทั้งแสดงปุ่มกดบันทึก} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มบันทึก}
& \setstretch{1.0}{ระบบแสดงผลการจองวันที่ส่งเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\end{tabular}
\end{table}
\end{itemize}
% \end{enumerate}
\section{การทดสอบการใช้งานเว็บแอปพลิเคชัน}
\begin{itemize}
\item{การทดสอบการใช้งานเมนูนำทางของเว็บแอปพลิเคชั}
การทดสอบเมนูนำทางของเว็บแอปพลิเคชันในการนำทางผู้ใช้งาน ซึ่งเมนูหลักประกอบด้วย เมูนูหน้าประกาศ เมนูหน้าสนทนา เมนูหน้าปฏิทินกำหนดการ เมนูหน้าดาวน์โหลดเอกสาร เมนูหน้าคำถามทีพบบ่อย เมนูหน้าเกี่ยวกับและเมนูออกจากระบบ ผลทดสอบดังตารางที่ \ref{tab:ผลการทดเมนูหลัก}-\ref{tab:ผลการทดเมนูนำทาง2}
\item{การทดสอบหน้ารายละเอียดร้า}
ในการแสดงผลหน้าจอรายละเอียดร้านนั้นจะประกอบไปด้วย ข้อมูลร้าน แผนที่ร้าน รายการร้าน การจองคิว รีวิว ผลการทดสอบดังตารางที่ \ref{tab:Shop}
\begin{table}[H]
\caption{ผลการทดสอบเมนูนำทาง}
\caption{ผลการทดสอบหน้ารายละเอียดร้าน}
\centering
\label{tab:ผลการทดเมนูหลัก}
\label{tab:Shop}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{เมนูประกาศ}
& \setstretch{1.0}{กดปุ่มเมนูประกาศ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการประกาศทั้งหมด} \\ \hline
\setstretch{1.0}{เมนูสนทนา}
& \setstretch{1.0}{กดปุ่มเมนูสนทนา}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอสนทนาพร้อมทั้งแสดงข้อมูลประวัติการสนทนา} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูหน้าปฏิทินกำหนดการ}
& \setstretch{1.0}{กดปุ่มเมนูปฏิทินกำหนดการ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอสนทนาพร้อมทั้งแสดงข้อมูลประวัติการสนทนา} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูหน้าดาวน์โหลดเอกสาร}
& \setstretch{1.0}{กดปุ่มเมนูหน้าดาวน์โหลดเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอตารางรายการเอกสารในระบบพร้อมทั้งแสดงปุมดาวน์โหลด} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูหน้าคำถามทีพบบ่อย}
& \setstretch{1.0}{กดปุ่มเมนูหน้าคำถามทีพบบ่อย}
& \setstretch{1.0}{ระบบแสดงหน้าจองคิวส่งเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูหน้าเกี่ยวกับ}
& \setstretch{1.0}{กดปุ่มเมนูหน้าเกี่ยวกับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าเกี่ยวกับซึ่งแสดงข้อมูลผู้พัฒนาวรมไปถึงแสดงเครดิต (credit) ไลบรารีต่าง ๆ ที่ใช้งานภายในแอปพลิเคชัน} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{
เมนูออกจากระบบ}
& \setstretch{1.0}{กดปุ่มเมนูออกจากระบบ}
& \setstretch{1.0}{ทำการออกจากระบบและแสดงหน้าจอข่าวสาร} \\ \hline
\setstretch{1.0}{หน้ารายละเอียดร้าน}
& \setstretch{1.0}{กดที่รูปภาพร้าน}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอร้านพร้อมทั้งแสดงรายการร้านทั้งหมด} \\ \cline{2-3}
& \setstretch{1.0}{กดที่แผ่นที่}
& \setstretch{1.0}{ระบบแสดงผลแผ่นที่} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มรายการ}
& \setstretch{1.0}{ระบบแสดงผลรายการ} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มจองคิว}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอจองคิว} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มจเขียนรีวิว}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอเขียนรีวิว} \\ \hline
\end{tabular}
\end{table}
\newpage
\item{การทดสอบหน้ารายละเอียดประกาศ}
ในการแสดงผลหน้าจอรายละเอียดประกาศนั้นจะประกอบไปด้วยหัวเรื่องประกาศ รายละเอียดประกาศ วันที่ประกาศและเอกสารแนบ ผลการทดสอบดังตารางที่ \ref{tab:การทดหน้ารายละเอียดประกาศ}
\item{การทดสอบหน้าเจ้าของร้าน} ในการแสดงผลหน้าจอเจ้าของร้านนั้นจะประกอบไปด้วย โปรไฟล์ ข้อมูลร้าน รายการ ข้อมูลช่าง ดูการจองคิว เพิ่มรูปภาพ ผลการทดสอบดังตารางที่ \ref{tab:datashop}
\begin{table}[H]
\caption{ผลการทดสอบหน้ารายละเอียดประกาศ}
\caption{ผลการการทดสอบหน้าเจ้าของร้าน}
\centering
\label{tab:การทดหน้ารายละเอียดประกาศ}
\label{tab:datashop}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{หน้ารายละเอียดประกาศ}
& \setstretch{1.0}{กดปุ่มเมนูประกาศ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการประกาศทั้งหมด} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มอ่านรายละเอียดประกาศ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอรายละเอียดประกาศ} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มดาวน์โหลดเอกสารแนบ}
& \setstretch{1.0}{ระบบแสดงผลการดาวน์โหลดเอกสารแนบ} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\setstretch{1.0}{หน้าจอเจ้าของร้าน}
& \setstretch{1.0}{กดปุ่มเมนูโปรไฟล์}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอโปรไฟล์ ทั้งแสดงรูปภาพโปรไฟล์} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มเมนูข้อมูลร้าน}
& \setstretch{1.0}{ระบบแสดงหน้าจอข้อมูลร้านทั้งหมด พร้แมทั้งแสดงรูปภาพร้าน} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มเมนูรายการ}
& \setstretch{1.0}{ระบบแสดงหน้ารายการ} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มเมนูข้อมูลช่าง}
& \setstretch{1.0}{ระบบแสดงหน้าข้อมูลช่าง} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มเมนูดูการจองคิว}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอการจองคิว} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มเมนูเฟิ่มรูปภาพ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอการเพิ่มรูปภาพ} \\ \hline
\end{tabular}
\end{table}
\newpage
\item{การทดสอบหน้าสนทนา} ในการแสดงผลหน้าจอสนทนานั้นจะประกอบไปด้วยรายการประวิติการสนทนา ช่องกรอกข้อความและปุ่มส่งข้อความ ผลการทดสอบดังตารางที่ \ref{tab:การทดสอบหน้าสนทนา}
\item{การทดสอบหน้าช่าง} ในการแสดงผลหน้าจอเจ้าของร้านนั้นจะประกอบไปด้วย โปรไฟล์ ตารางงาน เพิ่มรูปภาพ ผลการทดสอบดังตารางที่ \ref{tab:Work}
\begin{table}[H]
\caption{ผลการการทดสอบหน้าสนทนา}
\caption{ผลการการทดสอบหน้าเจ้าของร้าน}
\centering
\label{tab:การทดสอบหน้าสนทนา}
\label{tab:Work}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{หน้ารายละเอียดประกาศ}
& \setstretch{1.0}{กดปุ่มเมนูสนทนา}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอสนทนาพร้อมทั้งแสดงรายการประวัติการสนทนา} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มที่ช่องกรอกข้อความ}
& \setstretch{1.0}{ระบบแสดงตัวกระพริบ (cursor) เพื่อชี้ให้รู้ว่า ตำแหน่งของการพิมพ์อักขระ} \\ \cline{2-3}
& \setstretch{1.0}{พิมพ์อักขระ}
& \setstretch{1.0}{ระบบแสดงผลอัขระที่ถูกพิมพ์} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มส่งข้อความ}
& \setstretch{1.0}{ระบบแสดงข้อความที่ถูกพิมพ์บนรายการประวัติสนทนาล่าสุด} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\end{tabular}
\end{table}
\setstretch{1.0}{หน้าจอเจ้าของร้าน}
& \setstretch{1.0}{กดปุ่มเมนูโปรไฟล์}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอโปรไฟล์ ทั้งแสดงรูปภาพโปรไฟล์} \\ \cline{2-3}
\newpage
\item{การทดสอบหน้าปฏิทินกำหนดการ}
ในการแสดงผลหน้าปฏิทินกำหนดการนั้นจะประกอบไปด้วยรายการประวิติการสนทนา ช่องกรอกข้อความและปุ่มส่งข้อความ ผลการทดสอบดังตารางที่ \ref{tab:การทดสอบหน้าปฏิทินกำหนดการ}
\begin{table}[H]
\caption{ผลการการทดสอบหน้าปฏิทินกำหนดการ}
\centering
\label{tab:การทดสอบหน้าปฏิทินกำหนดการ}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{หน้าปฏิทินกำหนดการ}
& \setstretch{1.0}{กดปุ่มเมนูปฏิทินกำหนดการ}
& \setstretch{1.0}{ระบบแสดงตารางกำหนดารทั้งหมด} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
& \setstretch{1.0}{กดปุ่มเมนูตารางงาน}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอตารางงาน} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มเมนูเฟิ่มรูปภาพ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอการเพิ่มรูปภาพ} \\ \hline
\end{tabular}
\end{table}
\newpage
\item{การทดสอบหน้าดาวน์โหลดเอกสาร}
ในการแสดงผลหน้าจอดาวน์โหลดเอกสารนั้นจะประกอบไปด้วยรายการเอกสารโดยที่แต่ละฉบับบจะแสดงชื่อเอกสารและปุ่มดาวน์โหลดเอกสาร ผลการทดสอบดังตารางที่ \ref{tab:การทดสอบหน้าดาวน์โหลดเอกสาร}
\begin{table}[H]
\caption{ผลการการทดสอบหน้าดาวน์โหลดเอกสาร}
\centering
\label{tab:การทดสอบหน้าดาวน์โหลดเอกสาร}
\begin{tabular}{ | p{4.5cm} | p{4.5cm} | p{4.5cm} | }
\hline
% {\setstretch{1.0} }
{\multicolumn{1}{c}{\centering การทำงาน}} &
{\multicolumn{1}{c}{\centering เงื่อนไขการทดสอบ}} & {\multicolumn{1}{c}{\centering ผลการทดสอบ}} \\ \hline
\setstretch{1.0}{หน้าดาวน์โหลดเอกสาร}
& \setstretch{1.0}{กดปุ่มเมนูหน้าดาวน์โหลดเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอตารางรายการเอกสารในระบบพร้อมทั้งแสดงปุมดาวน์โหลด} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มดาวน์โหลดเอกสาร}
& \setstretch{1.0}{ระบบแสดงผลการดาวน์โหลดเอกสาร} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอรายการเอกสารในระบบพร้อมทั้งแสดงปุมดาวน์โหลด} \\ \cline{2-3}
& \setstretch{1.0}{กดปุ่มย้อนกลับ}
& \setstretch{1.0}{ระบบแสดงผลหน้าจอประกาศพร้อมทั้งแสดงรายการข่าวสารทั้งหมด} \\ \hline
\end{tabular}
\end{table}
\end{itemize}
......@@ -15,10 +15,10 @@
\item สามารถเพิ่ม แก้ไข และลบรายการให้บริการประจำร้านได้
\item สามารถเพิ่ม แก้ไข ข้อมูลร้านได้
\item สามารถเพิ่ม แก้ไข ข้อมูลตำแหน่งร้านได้
\item สามารถเพิ่ม ลบ ข้อมูลช่างได้
\end{itemize}
\item ช่างประจำร้าน
\begin{itemize}
\item ลงทะเบียนใช้ web ด้วย Email ได้
\item สามารถดูตารางการทำงานของตนเองได้
\item สามารถ post ภาพผลงานของตัวเองได้
\item สามารถแก้ไขข้อมูลส่วนตัวได้
......@@ -39,8 +39,13 @@
\section{ปัญหาและอุปสรรคในการพัฒนา}
\begin{enumerate}
\item เนื่องจากทางผู้พัฒนามีความประสงค์ให้ระบบนี้สามารถใช้งานได้จริง ดังนั้น การพัฒนาในตอนนี้ยังมีข้อจำกัดเรื่องขนาดของข้อมูลที่จัดเก็บบนไฟร์เบสที่สามารถอัพโหลดเข้าสู่ระบบสูงสุดเพียง 5 GB ซึ่งหากระบบถูกใช้งานจริงจำนวนข้อมูลในระบบจะเกินจำนวนที่ไฟร์เบสให้ใช้งานฟรี \\
แนวทางการแก้ไข : ทำการบีบอัดข้อมูลให้มีขนาดเล็กลง ส่วนในอนาคตอาจจำเป็นต้องศึกษาแนวทางการสร้างเซิฟเวอร์ (Server) เป็นของระบบเอง
\item เนื่องจากครั้งแรกที่ใช้ lalavel framework ไม่ค่อยสอดคล้องกับระบบ \\
แนวทางการแก้ไข : ทำการเปลี่ยน จาก lalavel framework เป็น React.js
\item เนื่องจากได้ทำการเปลี่ยน framework จึงทำให้ต้องเสียเวลา \\
แนวทางการแก้ไข : เร่งศึกษา และเร่งทำ
\item โรค covit 19 ทำให้การเข้าพบอาจารย์ไม่สะดวก\\
แนวทางการแก้ไข : พบทางออนไลน์แทนการเข้าพบแบบตัวต่อตัว
\end{enumerate}
......@@ -49,6 +54,8 @@
\item การพัฒนาช่องทางการติดต่อ
\item เจ้าของร้านสามารถยืนยันการจองคิวได้
\item การพัฒนาเป็นแอปพลิเคชัน
\item การเพิ่มข้อมูลโปรดมชั่น
\item การค้นหาร้านตามวันและเวลาว่างของร้าน
\end{enumerate}
......
Document/Latex/Figures/3/usecase.png

360 KB | W: | H:

Document/Latex/Figures/3/usecase.png

362 KB | W: | H:

Document/Latex/Figures/3/usecase.png
Document/Latex/Figures/3/usecase.png
Document/Latex/Figures/3/usecase.png
Document/Latex/Figures/3/usecase.png
  • 2-up
  • Swipe
  • Onion skin
\chapter{คู่มือการติดตั้งระบบ}
ในการติดตั้งเพื่อใช้งานแอปพลิเคชันระบบกองทุนเงินให้กู้ยืมเพื่อการศึกษา คณะวิทยาศาสตร์ มหาวิทยาลัยอุบลราชธานี หรือ ESP สามารถทำได้โดยมีขั้นตอนดังนี้
ในการติดตั้งเพื่อใช้งานเว็บแอปพลิเคชันระบบจองคิวร้านเสริมสวยสามารถทำได้โดยมีขั้นตอนดังนี้
\begin{enumerate}
\item สามารถดาวน์โหลด ESP installer package ได้ที่ https://drive.google.com/drive/folders/1k6HnoFgLAatgrfLAtFgnJYbRrpJHHwol ดังแสดงในรูปที่ \ref{Fig:dl1}
\item สามารถดาวน์โหลด และติดตั้งระบบ ได้ที่ http://projectcs.sci.ubu.ac.th/senior-prj-62/59110440259.git ดังแสดงในรูปที่ \ref{Fig:dl1} และรูปที่ \ref{Fig:dl2}
\begin{figure}[H]
\centering
\includegraphics[width=\columnwidth]{Figures/7/installApp/dl}
\caption{หน้าเว็บดาวน์โหลด ESP installer package}
{\setstretch{1.0}
\begin{lstlisting}[numbers=none]
git clone http://projectcs.sci.ubu.ac.th/senior-prj-62/59110440259.git
\end{lstlisting}}
\caption{คำสั่งดาวน์โหลด}
\label{Fig:dl1}
\end{figure}
\item ดัดลอกไฟล์ app-debug.apk ที่อยู่ในแฟ้มงาน(Folder)ที่อยู่บนคอมพิวเตอร์ไปไว้ในหน่วยความจำบนอุปกรณ์ที่ต้องการ ดังแสดงในรูปที่ \ref{Fig:dl2}
\begin{figure}[H]
\centering
\includegraphics[width=0.3\columnwidth]{Figures/7/installApp/1}
\caption{ไฟล์ app-debug.apk บนอุปรกรณ์}
{\setstretch{1.0}
\begin{lstlisting}[numbers=none]
npm install หรือ npm i
\end{lstlisting}}
\caption{คำสั่งติดตั้ง}
\label{Fig:dl2}
\end{figure}
\item ทำการเปิดไฟล์ app-debug.apk และกด INSTALL เพื่อทำการติดตั้ง ดังแสดงในรูปที่ \ref{Fig:dl3}
\begin{figure}[H]
\centering
\includegraphics[width=0.3\columnwidth]{Figures/7/installApp/2}
\caption{หน้าจอต้อนรับการติดตั้งแอปพลิเคชันบนอุปรกรณ์แอนดรอย์}
\label{Fig:dl3}
\end{figure}
\item เมื่อทำการติดตั้งแอปพลิเคชันสำเร็จระบบจะแสดงผล ดังแสดงในรูปที่ \ref{Fig:dl4}
\begin{figure}[H]
\centering
\includegraphics[width=0.3\columnwidth]{Figures/7/installApp/3}
\caption{หน้าจอต้อนรับการติดตั้งแอปพลิเคชันบนอุปรกรณ์แอนดรอย์}
\label{Fig:dl4}
\end{figure}
\end{figure}
\end{enumerate}
\chapter{คู่มือการใช้งานระบบ}
คู่มือการใช้งานทั้งหมดของระบบ สามารถแบ่งออกเป็น 2 ส่วน ดังนี้
คู่มือการใช้งานทั้งหมดของระบบ สามารถแบ่งออกเป็น 3 ส่วน ดังนี้
\begin{enumerate}
\item ส่วนของหน้าเมนูแอปพลิเคชันสำหรับนักศึกษา
\item ส่วนของหน้าเมนูเว็บแอปพลิเคชันสำหรับผู้ใช้บริการ
\begin{itemize}
\item หน้าจอต้อนรับแสดงผลทุกครั้งเมื่อผู้ใช้ทำการเปิดใช้งานแอปพลิเคชัน ดังแสดงในรูปที่ \ref{Fig:open}
\item หน้าจอหลักแสดงผลทุกครั้งเมื่อผู้ใช้ทำการเปิดใช้งานเว็บแอปพลิเคชัน ดังแสดงในรูปที่ \ref{Fig:home}
\begin{figure}[H]
\centering
\includegraphics[width=0.3\columnwidth]{Figures/7/Manual/open}
\caption{หน้าจอต้อนรับ}
\label{Fig:open}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/Home}
\caption{หน้าจอหลัก}
\label{Fig:home}
\end{figure}
\item เมื่อระบบทำการตรวจสอบว่ามีสิทธิ์(Permission)ในการใช้งานแอปพลิเคชันที่ผู้ใช้ยังไม่ได้อนุญาตให้เข้าถึง ระบบจะแสดงหน้าต่างขอสิทธิ์การเข้าถึง ดังแสดงในรูปที่ \ref{Fig:permission}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/permission}
\caption{หน้าต่างขอสิทธิ์การเข้าถึง}
\label{Fig:permission}
\end{figure}
จากรูปที่ \ref{Fig:permission} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:register} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ หน้าต่างขอสิทธิ์การเข้าถึงข้อมูล
\item หมายเลข 2 คือ ปุ่มให้สิทธิ์และยกเลิกการให้สิทธิ์
\item หมายเลข 1 คือ ปุ่มเข้าสู่ระบบ
\item หมายเลข 2 คือ ปุ่มลงทะเบียนสำหรับผู้ใช้งานทั่วไป
\item หมายเลข 3 คือ ปุ่มลงทะเบียนสำหรับเจ้าของร้าน
\item หมายเลข 4 คือ ฟอร์มสำหรับค้นหาร้าน
\item หมายเลข 5 คือ คลิ๊กที่รูปภาพเพื่อนเปิดหน้าต่างรายละเอียดร้าน
\item หมายเลข 6 คือ ปุ่มสำหรับจองคิว
\end{itemize}
\item ระบบทำการตรวจสอบทุกครั้งเมื่อผู้ใช้งานเปิดใช้งานแอปพลิเคชัน หากผู้ใช้งานคนปัจจุบันยังไม่ได้เข้าสู่ระบบ ระบบจะแสดงหน้าจอเข้าสู่ระบบโดยผู้ใช้งานจำเป็นต้องทำการกรอกข้อมูลคือ อีเมลและรหัสผ่าน ดังแสดงในรูปที่ \ref{Fig:signin}
\item เมื่อผู้ใช้งานกดที่ปุ่ม Register ระบบจะทำการแสดงหน้าต่างลงทะเบียน ดังแสดงในรูปที่ \ref{Fig:register}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/signin}
\caption{หน้าจอเข้าสู่ระบบ}
\label{Fig:signin}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/Register}
\caption{หน้าต่างลงทะเบียน}
\label{Fig:register}
\end{figure}
จากรูปที่ \ref{Fig:signin} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:register} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ ส่วนของฟอร์มในการกรอกข้อมูลอีเมลและรหัสผ่า
\item หมายเลข 2 คือ ปุ่มกดเข้าสู่ระบบ
\item หมายเลข 1 คือ กรอกข้อมูลในการลงทะเบียนแล้วกดยืนยั
\end{itemize}
\item หน้าแสดงข่าวสารประชาสัมพันธ์ซึ่งเป็นหน้าจอหลักของแอปพลิเคชัน ดังแสดงในรูปที่ \ref{Fig:feed}
\item ระบบทำการตรวจสอบทุกครั้งเมื่อผู้ใช้งานกดปุ่มเข้าสู่ระบบ ระบบจะแสดงหน้าจอเข้าสู่ระบบโดยผู้ใช้งานจำเป็นต้องทำการกรอกข้อมูลคือ อีเมลและรหัสผ่าน ดังแสดงในรูปที่ \ref{Fig:login}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/feed}
\caption{หน้าแสดงข่าวสาร}
\label{Fig:feed}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/Login}
\caption{หน้าจอเข้าสู่ระบบ}
\label{Fig:login}
\end{figure}
จากรูปที่ \ref{Fig:feed} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:login} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ ข่าวสารที่มีข้อมูล หัวข้อข่าวสาร แท็ก(Tag)และวันที่ประการข่าวสาร
\item หมายเลข 1 คือ ส่วนของฟอร์มในการกรอกข้อมูลอีเมลและรหัสผ่านและ ปุ่มกดเข้าสู่ระบบ
\end{itemize}
\item เมื่อผู้ใช้กดเลือกดูรายละเอียดของข่าวสาร ระบบจะแสดงหน้าจอรายละเอียดข่าวสาร ดังแสดงในรูปที่ \ref{Fig:viewpost}
\item หน้าแสดงรายละเอียดข้อมูลร้าน ดังแสดงในรูปที่ \ref{Fig:shop}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/viewpost}
\caption{หน้ารายละเอียดของข่าวสาร}
\label{Fig:viewpost}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/shop}
\caption{หน้าแสดงรายระเอียดร้าน}
\label{Fig:shop}
\end{figure}
จากรูปที่ \ref{Fig:viewpost} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:shop} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ หัวข้อข่าวสาร
\item หมายเลข 1 คือ รายละเอียดของข่าวสาร
\item หมายเลข 1 คือ ปุ่มสำหรับดูรายการร้าน
\item หมายเลข 2 คือ ปุ่มสำหรับจองคิว
\item หมายเลข 3 คือ ปุ่มสำหรับเขียนรีวิว
\end{itemize}
\item เมื่อผู้ใช้กดเลือกเมนู Drawer ระบบจะแสดงเมนูนำทางหลักของแอปพลิเคชันซึ่งประกอบไปด้วยเมนู ประชาสัมพันธ์ ข้อความ กำหนดการ เอกสาร ส่งเอกสาร จองคิว คำถามที่พบบ่อย เกี่ยวกับเรา บัญชีผู้ใช้และออกจากระบบ ดังแสดงในรูปที่ \ref{Fig:nav}
\item เมื่อผู้ใช้กดปุ่มจองคิว ระบบจะแสดง model จองคิว ดังแสดงในรูปที่ \ref{Fig:shopgueue}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/nav}
\caption{เมนูนำทางหลักของแอปพลิเคชัน}
\label{Fig:nav}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/shopgueue}
\caption{หน้าการจองคิว}
\label{Fig:shopgueue}
\end{figure}
จากรูปที่ \ref{Fig:nav} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:shopgueue} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ รายการเมนูนำทางหลักของแอปพลิเคชัน
\item หมายเลข 2 คือ เมนูนำทาง
\end{itemize}
\item หมายเลข 1 คือ สำหรับเลือกวันที่ในการจองคิว
\item หมายเลข 2 คือ เลือกรายการสำหรับจองคิว
\item หมายเลข 3 คือ เลือกช่างที่ต้องการจองคิว
\item หมายเลข 4 คือ เลือกเวลาในการจองคิว
\item เมื่อผู้ใช้เลือกเมนูกำหนดการ ระบบจะแสดงหน้าจอกำหนดการ ดังแสดงในรูปที่ \ref{Fig:event}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/event}
\caption{หน้าจอกำหนดการ}
\label{Fig:event}
\end{figure} \item ส่วนของหน้าเมนูแอปพลิเคชันสำหรับนักศึกษา
\item หน้าจอต้อนรับแสดงผลทุกครั้งเมื่อผู้ใช้ทำการเปิดใช้งานแอปพลิเคชัน ดังแสดงในรูปที่ \ref{Fig:open}
\begin{figure}[H]
\centering
\includegraphics[width=0.3\columnwidth]{Figures/7/Manual/open}
\caption{หน้าจอต้อนรับ}
\label{Fig:open}
\end{figure}
\end{itemize}
\item เมื่อระบบทำการตรวจสอบว่ามีสิทธิ์(Permission)ในการใช้งานแอปพลิเคชันที่ผู้ใช้ยังไม่ได้อนุญาตให้เข้าถึง ระบบจะแสดงหน้าต่างขอสิทธิ์การเข้าถึง ดังแสดงในรูปที่ \ref{Fig:permission}
\item เมื่อผู้ใช้กดปุ่มรายการ ระบบจะแสดง model รายการ ดังแสดงในรูปที่ \ref{Fig:shoplist}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/permission}
\caption{หน้าต่างขอสิทธิ์การเข้าถึง}
\label{Fig:permission}
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/shoplist}
\caption{เมนูดูรายการร้าน}
\label{Fig:shoplist}
\end{figure}
จากรูปที่ \ref{Fig:permission} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:shoplist} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ หน้าต่างขอสิทธิ์การเข้าถึงข้อมูล
\item หมายเลข 2 คือ ปุ่มให้สิทธิ์และยกเลิกการให้สิทธิ์
\item หมายเลข 1 คือ รายการประจำร้าน
\end{itemize}
\item เมื่อผู้ใช้กดปุ่มเขียนรีวิว ระบบจะแสดง model เพื่อให้ผู้ใช้งานเขียนรีวิว ดังแสดงในรูปที่ \ref{Fig:shopreview}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/event}
\caption{หน้าแสดงกำหนดการ}
\label{Fig:event}
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/shopreview}
\caption{หน้าจอเขียนรีวิว}
\label{Fig:shopreview}
\end{figure}
จากรูปที่ \ref{Fig:event} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:shopreview} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ ปฏิทินแสดงวันที่ปัจจุบันและผู้ใช้สามารถเลือกวันที่ต้องการเพื่อดูกำหนดการก่อนหน้า
\item หมายเลข 2 คือ แสดงรายการกำหนดการของวันนั้น ๆ
\item หมายเลข 1 คือ กรอกข้อมูลการรีวิวและกด submit
\end{itemize}
\item เมื่อผู้ใช้เลือกเมนูเอกสาร ระบบจะแสดงหน้าจอรายการเอกสาร ดังแสดงในรูปที่ \ref{Fig:doc}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/doc}
\caption{หน้าจอเอกสาร}
\label{Fig:doc}
\end{figure}
จากรูปที่ \ref{Fig:doc} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ รายการเอกสาร
\item หมายเลข 2 คือ ปุ่มดาวน์โหลดเอกสาร
\item หมายเลข 3 คือ สถานะการดาวน์โหลดเอกสาร
\end{itemize}
\item ส่วนของหน้าเมนูเว็บแอปพลิเคชันสำหรับเจ้าของร้าน
\begin{itemize}
\item เมื่อผู้ใช้เลือกเมนูข้อความ ระบบจะแสดงหน้าจอสนทนา ดังแสดงในรูปที่ \ref{Fig:chat}
\item เมื่อผู้ใช้งานกดที่ปุ่ม RegisterShop ระบบจะทำการแสดงหน้าต่างลงทะเบียน ดังแสดงในรูปที่ \ref{Fig:registershop}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/chat}
\caption{หน้าจอสนทนา}
\label{Fig:chat}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/registershop}
\caption{หน้าต่างลงทะเบียนธุรกิจ}
\label{Fig:registershop}
\end{figure}
จากรูปที่ \ref{Fig:chat} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:registershop} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ รายการประวัติการสนทนา
\item หมายเลข 2 คือ ช่องกรอกข้อความเพื่อสนทนา
\item หมายเลข 3 คือ ปุ่มส่งข้อความ
\item หมายเลข 1 คือ กรอกข้อมูลในการลงทะเบียนแล้วกดยืนยัน
\end{itemize}
\item เมื่อผู้ใช้เลือกเมนูส่งเอกสารระบบจะตรวจสอบข้อมูลว่าเจ้าหน้าที่ได้ทำการเปิดให้นักศึกษาส่งเอกสารได้หรือไม่ หากตรวจสอบแล้วพบว่าสามารถส่งได้ระบบจะแสดงหน้าจอส่งเอกสาร ดังแสดงในรูปที่ \ref{Fig:submit}
\item ระบบทำการตรวจสอบทุกครั้งเมื่อผู้ใช้งานกดปุ่มเข้าสู่ระบบ ระบบจะแสดงหน้าจอเข้าสู่ระบบโดยผู้ใช้งานจำเป็นต้องทำการกรอกข้อมูลคือ อีเมลและรหัสผ่าน ดังแสดงในรูปที่ \ref{Fig:loginshop}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/submit}
\caption{หน้าจอส่งเอกสาร}
\label{Fig:submit}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/Login}
\caption{หน้าจอเข้าสู่ระบบ}
\label{Fig:loginshop}
\end{figure}
จากรูปที่ \ref{Fig:submit} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:loginshop} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ เมื่อผู้ใช้เข้ามาครั้งแรกเมื่อผู้ใช้กดรูปภาพเอกสารระบบจะนำผู้ใช้ไปยังหน้าจอถ่ายภาพเอกสารและแสดงรูปภาพพรีวิว(Preview)ภาพถ่ายเอกสาร
\item หมายเลข 2 คือ ปุ่มกดส่งเอกสาร
\item หมายเลข 1 คือ ส่วนของฟอร์มในการกรอกข้อมูลอีเมลและรหัสผ่านและ ปุ่มกดเข้าสู่ระบบ
\end{itemize}
\item เมื่อผู้ใช้กดที่ปุ่มถ่ายภาพเอกสารระบบจะแสดงหน้าจอถ่ายภาพเอกสาร ดังแสดงในรูปที่ \ref{Fig:submit1}
\item เมื่อเจ้าของร้านเข้าสู่ระบบสำเร็จ ดังแสดงในรูปที่ \ref{Fig:shopprofile}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/submit1}
\caption{หน้าจอถ่ายภาพเอกสาร}
\label{Fig:submit1}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/shopprofile}
\caption{หน้าจอโปรไฟล์}
\label{Fig:shopprofile}
\end{figure}
จากรูปที่ \ref{Fig:submit1} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:shopprofile} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ ปุ่มกดถ่ายภาพสำเนาเอกสาร
\item หมายเลข 1 คือ ปุ่มสำหรับอัพโหลดรูปภาพ
\end{itemize}
\item หน้าจอแสดงภาพพรีวิวภาพถ่ายสำเนาเอกสาร ดังแสดงในรูปที่ \ref{Fig:submit2}
\item เมื่อเจ้าของร้านคลิ๊กที่เมนูข้อมูลร้าน ระบบจะแสดงหน้าข้อมูลร้าน ดังแสดงในรูปที่ \ref{Fig:datashop}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/submit2}
\caption{หน้าจอแสดงภาพพรีวิวภาพถ่ายสำเนาเอกสาร}
\label{Fig:submit2}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/datashop}
\caption{หน้าจอข้อมูลร้าน}
\label{Fig:datashop}
\end{figure}
จากรูปที่ \ref{Fig:submit2} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:datashop} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ ปุ่มปรับมุมภาพทั้ง 8 มุมเพื่อปรับขนาดภาพถ่ายเอกสาร
\item หมายเลข 1 คือ ปุ่มสำหรับเพิ่มรูปภาพ
\item หมายเลข 2 คือ ปุ่มสำหรับแก้ไขรูปภาพ
\item หมายเลข 3 คือ กรอกข้อมูลร้านทั้งหมด
\end{itemize}
\item หน้าจอแสดงปรับแต่งภาพถ่ายสำเนาเอกสาร ดังแสดงในรูปที่ \ref{Fig:submit3}
\item เมื่อเจ้าของร้านคลิ๊กที่เมนูรายการ ระบบจะแสดงหน้ารายการ ดังแสดงในรูปที่ \ref{Fig:list}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/submit3}
\caption{หน้าจอแสดงปรับแต่งภาพถ่ายสำเนาเอกสาร}
\label{Fig:submit3}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/list}
\caption{หน้าจอรายการร้าน}
\label{Fig:list}
\end{figure}
จากรูปที่ \ref{Fig:submit3} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:list} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ เมื่อผู้ใช้ต้องการปรับความคมชัดของภาพสามารถทำได้จาก 4 ปุ่ม คือ ปุ่มภาพต้นฉบับ ปุ่มปรับสีอัตโนมัติ ปุ่มปรับปรับสีเป็นสีเทา ปุ่มปรับสีเป็นสีขาวดำ
\item หมายเลข 1 คือ ปุ่มบวกใช้เพื่อเพิ่มข้อมูลรายการ
\item หมายเลข 2 คือ ปุ่มสำหรับแก้ไขข้อมูลรายการ
\item หมายเลข 3 คือ ปุ่มสำหรับลบข้อมูลรายการ
\end{itemize}
\item หน้าจอแสดงภาพพรีวิวภาพถ่ายสำเนาเอกสารทั้งสองฉบับ ดังแสดงในรูปที่ \ref{Fig:submit4}
\item เมื่อเจ้าของร้านกดที่ปุ่มข้อมูลช่าง ระบบจะทำการแสดงหน้าข้อมูลช่าง ดังแสดงในรูปที่ \ref{Fig:qely}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/submit4}
\caption{หน้าจอแสดงภาพพรีวิวภาพถ่ายสำเนาเอกสาร}
\label{Fig:submit4}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/qely}
\caption{หน้าจอข้อมูลช่าง}
\label{Fig:qely}
\end{figure}
จากรูปที่ \ref{Fig:submit4} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:qely} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ แสดงภาพพรีวิวภาพถ่ายสำเนาเอกสารทั้งสองฉบับ
\item หมายเลข 1 คือ กดปุ่มเพื่อเพิ่มข้อมูลช่าง
\end{itemize}
\item เมื่อผู้ใช้กดปุ่มส่งเอกสาร ระบบจะแสดงหน้าต่างแสดงสถานะการอัพโหลดเอกสาร ดังแสดงในรูปที่ \ref{Fig:submit5}
\item เมื่อเจ้าของร้านคลิ๊กที่เมนูดูคิวจอง ระบบจะแสดงหน้าข้อมูลการจองคิว ดังแสดงในรูปที่ \ref{Fig:shopqely}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/submit5}
\caption{หน้าต่างแสดงสถานะการอัพโหลดเอกสาร}
\label{Fig:submit5}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/shopqely}
\caption{หน้าจอดูการจองคิว}
\label{Fig:shopqely}
\end{figure}
จากรูปที่ \ref{Fig:submit5} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:shopqely} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ หน้าต่างสถานะการอัพโหลดเอกสาร
\item หมายเลข 1 คือ เลือกวันที่ที่ต้องการดูการจองคิว
\end{itemize}
\item เมื่อผู้ใช้กดเมนูจองคิว ระบบจะตรวจสอบถสานะการส่งเอกสารว่าถูกเจ้าหน้าที่ตรวจสอบแล้วหรือไม่ ถ้าเจ้าหน้าที่อนุมัติแล้วระบบจะแสดงหน้าจอจองวันที่ส่งเอกสาร ดังแสดงในรูปที่ \ref{Fig:checkin}
\item เมื่อเจ้าของร้านคลิ๊กที่เมนูเพิ่มรูปภาพ ดังแสดงในรูปที่ \ref{Fig:shoppic}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/checkin}
\caption{หน้าจอจองคิว}
\label{Fig:checkin}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/shoppic}
\caption{หน้าจอเพิ่มรูปภาพ}
\label{Fig:shoppic}
\end{figure}
จากรูปที่ \ref{Fig:checkin} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:shoppic} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ รายละเอียด
\item หมายเลข 2 คือ ส่วนของการเลือกวันที่ที่ต้องการส่งเอกสาร
\item หมายเลข 3 คือ ส่วนของการเลือกเวลาที่ต้องการส่งเอกสาร
\item หมายเลข 4 คือ ปุ่มกดส่งเอกสาร
\item หมายเลข 1 คือ กดปุ่มเพื่อเพิ่มรูปภาพ
\end{itemize}
\item เมื่อผู้ใช้กดปุ่มเลือกวันที่ที่ต้องการส่งเอกสารระบบจะแสดงหน้าต่างเลือกวันที่โดยจะแสดงเฉพาะวันที่ที่เจ้าหน้าที่เลือกไว้เท่านั้น ดังแสดงในรูปที่ \ref{Fig:date}
\end{itemize}
\item ส่วนของหน้าเมนูเว็บแอปพลิเคชันสำหรับช่าง
\begin{itemize}
\item ระบบทำการตรวจสอบทุกครั้งเมื่อผู้ใช้งานกดปุ่มเข้าสู่ระบบ ระบบจะแสดงหน้าจอเข้าสู่ระบบโดยผู้ใช้งานจำเป็นต้องทำการกรอกข้อมูลคือ อีเมลและรหัสผ่าน ดังแสดงในรูปที่ \ref{Fig:loginb}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/date}
\caption{หน้าต่างปฏิทินเลือกวันที่ต้องการส่งเอกสาร}
\label{Fig:date}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/Login}
\caption{หน้าจอเข้าสู่ระบบ}
\label{Fig:loginb}
\end{figure}
จากรูปที่ \ref{Fig:date} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:loginb} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ หน้าต่างปฏิทินเลือกวันที่ต้องการส่งเอกสาร
\item หมายเลข 1 คือ ส่วนของฟอร์มในการกรอกข้อมูลอีเมลและรหัสผ่านและ ปุ่มกดเข้าสู่ระบบ
\end{itemize}
\item เมื่อผู้ใช้กดปุ่มเลือกเวลาที่ต้องการส่งเอกสารระบบจะแสดงหน้าต่างเลือกเวลาโดยจะแสดงเฉพาะเวลาที่เจ้าหน้าที่เลือกไว้เท่านั้น ดังแสดงในรูปที่ \ref{Fig:time}
\item หน้าช่างเข้าสู่ระบบสำเร็จ ระบบจะแสดงหน้าโปรไฟล์ ดังแสดงในรูปที่ \ref{Fig:bprofile}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/time}
\caption{หน้าต่างนาฬิกาเลือกเวลาที่ต้องการส่งเอกสาร}
\label{Fig:time}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/bprofile}
\caption{หน้าโปรไฟล์}
\label{Fig:bprofile}
\end{figure}
จากรูปที่ \ref{Fig:time} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:bprofile} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ หน้าต่างนาฬิกาเลือกเวลาที่ต้องการส่งเอกสาร
\item หมายเลข 1 คือ กดปุ่มเพื่ออัพโหลดรูปภาพ
\end{itemize}
\item เมื่อผู้ใช้กดเมนูคำถามที่พบบ่อยระบบจะแสดงหน้าจอคำถามที่พบบ่อย ดังแสดงในรูปที่ \ref{Fig:faq2}
\item เมื่อช่างคลิ๊กที่เมนูตารางงาน ระบบจะแสดงหน้าดูตารางงาน ดังแสดงในรูปที่\ref{Fig:work}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/faq2}
\caption{หน้าจอคำถามที่พบบ่อย}
\label{Fig:faq2}
\includegraphics[width=0.7\columnwidth]{Figures/7/Manual/work}
\caption{หน้าตารางงาน}
\label{Fig:work}
\end{figure}
จากรูปที่ \ref{Fig:faq2} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:work} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ คำถาม
\item หมายเลข 2 คือ คำตอบ
\item หมายเลข 1 คือ เลือกวันที่ที่ต้องการให้แสดงตารางงาน
\end{itemize}
\item เมื่อผู้ใช้กดปุ่มเมนูเกี่ยวกับเราระบบจะแสดงข้อมูลรายะเอียดของงานพัฒนานักศึกษา คณะวิทยาศาสตร์ มหาวิทยาลัยอุบลราชธานี ดังแสดงในรูปที่ \ref{Fig:about}
\item เมื่อช่างคลิ๊กที่เมนูภาพผลงาน ระบบจะแสดงหน้าเพิ่มผลงานช่าง ดังแสดงในรูปที่ \ref{Fig:bpic}
\begin{figure}[H]
\centering
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/about}
\caption{หน้าเกี่ยวกับ}
\label{Fig:about}
\includegraphics[width=0.5\columnwidth]{Figures/7/Manual/bpic}
\caption{หน้าจอภาพผลงานช่าง}
\label{Fig:bpic}
\end{figure}
จากรูปที่ \ref{Fig:about} สามารถอธิบายการใช้งานได้ดังนี้
จากรูปที่ \ref{Fig:bpic} สามารถอธิบายการใช้งานได้ดังนี้
\begin{itemize}[label={--}]
\item หมายเลข 1 คือ ข้อมูลติดต่องานพัฒนานักศึกษา คณะวิทยาศาสตร์ มหาวิทยาลัยอุบลราชธานี
\item ปุ่มกดสำหรับเปิดกลุ่มงานพัฒนานักศึกษา คณะวิทยาศาสตร์ มหาวิทยาลัยอุบลราชธานีบน Facebook
\item หมายเลข 1 คือ กดปุ่มเพื่อเพิ่มรูปภาพผลงานช่าง
\end{itemize}
\end{itemize}
......
......@@ -7,148 +7,157 @@
publisher = {กรุงเทพฯ: ซีเอ็ดยูเคชั่น}
}
@book{androidbook1,
author = {{กอบเกียรติ สระอุบล.}},
title = {การพัฒนา App Android},
date = {},
month = {},
year = {2549},
publisher= {กรุงเทพฯ: มีเดีย เนทเวิร์ค}
@book{bib1,
author = {{ประชา พฤกษ์ประเสริฐ}},
title = {สร้างเว็บและลูกเล่นด้วย JavaScript DHTML},
publisher = {{สำนักพิมพ์ ซิมพลิฟาย}},
month = {มีนาคม},
year = {2558},
}
@misc{bib1,
author = {{ทศพล ต้นสมบัติ.}},
title = {ระบบปฏิบัติการ ANDROID},
date = {},
@misc{bib2,
author = {Chai Phonbopit},
title = {React คืออะไร เริ่มต้นเขียน React},
month = {},
year = {ม.ป.ป.},
note = {12 พฤษภาคม 2561},
url = {https://beerkung.wordpress.com/ระบบปฏิบัติการรุ่นล่าส/ระบบปฏิบัติการ-android.html}
year = {2558},
note = {09 เมษายน 2562},
url = {https://devahoy.com/posts/getting-started-with-reactjs}
}
@misc{bib2,
author = {{MarcusCode.}},
title = {การเขียนโปรแกรมเชิงวัตถุ},
date = {},
author = {Chai Phonbopit},
title = {React คืออะไร เริ่มต้นเขียน React},
month = {},
year = {2018},
note = {12 พฤษภาคม 2561},
url = {http://marcuscode.com/lang/java/introduction}
year = {2558},
note = {09 เมษายน 2562},
url = {https://devahoy.com/posts/getting-started-with-reactjs}
}
@misc{vuejs,
author = {{Vue.js Team.}},
title = {Introduction},
url = {https://vuejs.org/v2/guide/},
date = {},
@misc{bib3,
author = {vittayasak},
title = {ReactJS Path1 พื้นฐานการสร้าง Web Component},
month = {},
year = {2560},
note = {2 พฤษภาคม 2561}
year = {2559},
note = {09 เมษายน 2562},
url = {http://ajbee.me/2016/10/04/reactjs-part1-basic-component}
}
@misc{ActivityLifeCycle,
author = {{Sleeping For Less.}},
title = {Activity Life Cycle},
url = {http://www.akexorcist.com/2016/04/why-do-we-need-to-know-about-activity-life-cycle-th.html},
date = {},
@misc{bib4,
author = {DESIGNIL},
title = {React คืออะไร ไขข้อสงสัยสำหรับมือใหม่ แนวทางการหัด React ตั้งแต่เริ่มต้น},
month = {},
year = {2557},
note = {12 พฤษภาคม 2561}
year = {ม.ป.ป.},
note = {09 เมษายน 2562},
url = {https://www.designil.com/react-คืออะไร.html}
}
@misc{openhandsetalliance,
author = {{Google.}},
title = {Open Handset Alliance},
url = {http://www.openhandsetalliance.com/},
date = {},
@misc{bib5,
author = {him aeng},
title = {React Life Cycle},
month = {},
year = {2557},
note = {20 พฤษภาคม 2561}
year = {2559},
note = {09 เมษายน 2562},
url = {http://www.forminit.com/react-basic-07}
}
@misc{PSU,
author = {{งานกองทุนเงินให้กู้ยืมเพื่อการศึกษา มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตหาดใหญ่.}},
title = {กยศ.ม.อ(PSU Studentloan)},
url = {https://studentloan.psu.ac.th/home},
date = {},
@misc{bib6,
author = {Nattawut Ruangvivattanaroj},
title = {อธิบาย React Lifecycle แต่ละอันมีหน้าที่อย่างไร},
month = {},
year = {2554},
note = {20 พฤษภาคม 2561}
year = {2560},
note = {09 เมษายน 2562},
url = {https://igokuz.com/อธิบาย-react-lifecycle-แต่ละอันมีหน้าที่อย่างไร-48e65c922af1}
}
@misc{blackbox,
author = {{Atthaboon S.}},
title = {BLACK-BOX TESTING STRATEGY
},
url = {http://everybitsconsult.com/blog/2015/06/22/black-box-testing.html},
date = {},
@misc{bib7,
author = {M.D.Soft},
title = {Node.js คืออะไร},
month = {},
year = {ม.ป.ป.},
note = {09 เมษายน 2562},
url = {https://www.mdsoft.co.th/ความรู้/140-what-node-js.html}
}
@misc{bib8,
author = {BeYourCyber},
title = {เจาะลึกกับ node.js แบบเริ่มต้นทำความรู้จัก},
month = {},
year = {2555},
note = {20 พฤษภาคม 2561}
year = {2556},
note = {09 เมษายน 2562},
url = {http://meewebfree.com/site/nodejs/441-learn-about-node-js-with-basic-of-node-js}
}
@misc{eStudentloan,
author = {{Tni.Student.}},
title = {แอปพลิเคชัน eStudentloan},
url = {https://play.google.com/store/apps/details?id=th.co.dest.anek.studentloan},
date = {},
@misc{bib9,
author = {อมรเดช คีรีพัฒนานนท์},
title = {node.js คืออะไร คือ programming language ที่เขียนด้วย JavaScript},
month = {},
year = {2560},
note = {20 พฤษภาคม 2561}
year = {2559},
note = {09 เมษายน 2562},
url = {https://beyourcyber.com/2016/node-js-is-programming-language-by-javascript/}
}
@misc{กยศ,
author = {{กองทุนเงินให้กู้ยืมเพื่อการศึกษา(กยศ.).}},
title = {กองทุนเงินให้กู้ยืมเพื่อการศึกษา(กยศ.)},
url = {https://www.studentloan.or.th/index.php/aboutus},
date = {},
@misc{bib12,
author = {mindphp},
title = {JavaScript คืออะไร},
month = {},
year = {2554},
note = {20 พฤษภาคม 2561}
year = {2560},
note = {09 เมษายน 2562},
url = {http://www.mindphp.com/คู่มือ/73-คืออะไร/2187-java-javascript-คืออะไร.html}
}
@misc{ScanLibrary,
author = {{jhansireddy.}},
title = {AndroidScannerDemo},
url = {https://www.studentloan.or.th/index.php/aboutus},
date = {},
@misc{bib13,
author = {admin},
title = {JavaScript คืออะไร},
month = {},
year = {2557},
note = {3 เมษายา 2561}
year = {2558},
note = {09 เมษายน 2562},
url = {https://nokhookstudio.com/javascript-คืออะไร}
}
@misc{firestore,
author = {{Thanongkiat Tamtai.}},
title = {เข้มข้นกับ Firebase Cloud Firestore},
date = {},
@misc{bib14,
author = {easyhostdomain},
title = {MySQL มีความสำคัญอย่างไรกับเซิร์ฟเวอร์},
month = {},
year = {2557},
url = {https://goo.gl/ZmqY3g},
note = {18 เมษายา 2561}
note = {08 มกราคม 2562},
url = {http://th.easyhostdomain.com/dedicated-servers/mysql.html}
}
@misc{scenario,
author = {{ Inflectra. }},
title = {Software Testing Methodologies},
date = {},
@misc{bib15,
author = {itgenius},
title = {จุดเด่นและหลักการทำงาน MySQL},
month = {},
year = {2018},
url = {https://www.inflectra.com/ideas/topic/testing-methodologies.aspx},
note = {14 พฤษภาคม 2561}
year = {2556},
note = {08 มกราคม 2562},
url = {https://www.itgenius.co.th/article/%20MySQL.html}
}
@misc{js,
author = {{mindphp.}},
title = {JavaScript คืออะไร},
@misc{ActivityLifeCycle,
author = {{Sleeping For Less.}},
title = {Activity Life Cycle},
url = {http://www.akexorcist.com/2016/04/why-do-we-need-to-know-about-activity-life-cycle-th.html},
date = {},
month = {},
year = {2555},
url = {https://goo.gl/FAeTb2},
year = {2557},
note = {12 พฤษภาคม 2561}
}
@internet{vscode,
author = {mindphp},
title = {รู้จักกับ Visual Studio Code (วิชวล สตูดิโอ โค้ด) โปรแกรมฟรีจากค่ายไมโครซอฟท์},
date = {6},
month = {เมษายน},
year = {2562},
url = {https://www.mindphp.com/บทความ/microsoft/4829-visual-studio-code.html},
}
@internet{gowabi,
author = {gowabi},
title = {gowabi},
date = {6},
month = {เมษายน},
year = {2563},
url = {https://www.gowabi.com},
}
@internet{maps,
author = {google map api},
title = {google map api},
date = {28},
month = {มีนาคม},
year = {2562},
url = {https://cloud.google.com/maps-platform/},
}
@misc{architecture,
author = {{Kunchit Phiu-Nual.}},
title = {ความหมายและความสำคัญของ System Architecture},
......
......@@ -2,6 +2,7 @@ const User = require("../../models/user");
const bcryptjs = require("bcryptjs");
const JWT = require("jsonwebtoken");
const config = require("../../config");
const Beautician = require("../../models/beautician")
exports.getUserById = async (req, res) => {
console.log("here");
......@@ -24,6 +25,7 @@ createToken = id => {
exports.register = async (req, res) => {
try {
const registerData = req.body;
const user = await User.findOne({
where: { email: registerData.email }
});
......@@ -40,6 +42,7 @@ exports.register = async (req, res) => {
tel: registerData.tel,
role: registerData.role
});
const token = await createToken(newUser.id);
res.status(200).send("success");
}
......@@ -48,6 +51,7 @@ exports.register = async (req, res) => {
res.sendStatus(401);
}
};
exports.login = async (req, res) => {
const loginData = req.body;
const user = await User.findOne({
......
const Beautician = require("../../models/beautician");
exports.add = async (req, res) => {
try {
const addbeauticianData = req.body;
console.log(addbeauticianData);
await Beautician.create({
name: addbeauticianData.name,
email: addbeauticianData.email,
address: addbeauticianData.address,
tel: addbeauticianData.tel,
shopID: addbeauticianData.shopID
});
res.send("create");
} catch (err) {
console.log(err);
res.sendStatus(401);
}
};
exports.getbeauticianShopId = async (req, res) => {
try {
const id = req.params.shopID;
let beautician = await Beautician.findAll({
where: {
shopID: id
}
});
console.log('beautician', beautician)
res.status(200).send(beautician);
} catch (err) {
res.send({
error: err.message
});
}
};
exports.deletelist = async (req, res) => {
try {
const listId = req.params.listId;
await List.destroy({
where: {
id: listId
}
});
res.status(200).send("success");
} catch (err) {
console.log(err);
res.sendStatus(401);
}
};
\ No newline at end of file
......@@ -51,7 +51,20 @@ exports.getPromotionId = async (req, res) => {
res.sendStatus(401);
}
};
exports.getUserId = async (req, res) => {
try {
const userId = req.params.id;
let promotion = await Promotion.findOne({
where: {
id: userId
}
});
res.status(200).send("success");
} catch (err) {
console.log(err);
res.sendStatus(401);
}
};
exports.updatePromotion = async (req, res) => {
try {
const promotionData = req.body;
......
......@@ -88,3 +88,17 @@ exports.updateuserId = async (req, res) => {
res.sendStatus(401);
}
};
exports.searchShop= async (req, res) => {
const name = req.body.name;
console.log('name', name);
if(name !== undefined) {
console.log('called1');
var condition = name ? { name: { [Op.like]: `%${name}%` } } : null;
const datasearch = await Shop.findAll({
where: condition
})
res.status(200).send(datasearch)
}
}
const Sequelize = require("sequelize");
const db = require("../../db");
const User = require('../user')
module.exports = db.sequelize.define("beauticians", {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.TEXT,
},
email: {
type: Sequelize.TEXT,
},
address: {
type: Sequelize.TEXT,
},
tel: {
type: Sequelize.TEXT,
},
shopID: {
type: Sequelize.INTEGER,
references: 'shops',
referencesKey: 'id'
}
});
......@@ -7,6 +7,10 @@ module.exports = db.sequelize.define("beauticianImages", {
primaryKey: true,
autoIncrement: true
},
beautician_id:{
type: Sequelize.INTEGER,
primaryKey: true
},
image: {
type: Sequelize.BLOB
......
......@@ -27,10 +27,12 @@ module.exports = db.sequelize.define("bookings", {
references: 'users',
referencesKey: 'id'
},
dete: {
date: {
type: Sequelize.DATE
},
time: {
type: Sequelize.TIME
}
});
......@@ -9,7 +9,7 @@ module.exports = db.sequelize.define("reviews", {
},
topic: {
type: Sequelize.INTEGER
type: Sequelize.STRING
},
message: {
type: Sequelize.STRING
......@@ -22,7 +22,7 @@ module.exports = db.sequelize.define("reviews", {
references: 'shops',
referencesKey: 'id'
},
user: {
userID: {
type: Sequelize.INTEGER,
references: 'users',
referencesKey: 'id'
......
const Sequelize = require("sequelize");
const db = require("../../db");
const ShopImage = require("../shopimage");
const WorkImage = require("../workimage")
module.exports = db.sequelize.define("shops", {
const Shop = db.sequelize.define("shops", {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
......@@ -55,3 +56,7 @@ module.exports = db.sequelize.define("shops", {
)
}
});
Shop.hasMany(ShopImage, { foreignKey: 'image_id' });
// Shop.hasMany(ShopImage, { foreignKey: 'image_id' });
module.exports = Shop;
\ No newline at end of file
const Sequelize = require("sequelize");
const db = require("../../db");
const User =require("../user")
const ShopImage = db.sequelize.define("shopimages", {
module.exports = db.sequelize.define("shopimages", {
image_id: {
type: Sequelize.INTEGER,
primaryKey: true,
......@@ -10,19 +11,14 @@ module.exports = db.sequelize.define("shopimages", {
shop_id: {
type: Sequelize.INTEGER,
primaryKey: true,
references: 'shops',
referencesKey: 'id'
},
userId:{
type: Sequelize.INTEGER,
references: 'users',
referencesKey: 'id'
},
image: {
type: Sequelize.BLOB('long')
type: Sequelize.BLOB
},
type: {
type: Sequelize.STRING
}
});
module.exports = ShopImage;
\ No newline at end of file
const Sequelize = require("sequelize");
const db = require("../../db");
module.exports = db.sequelize.define(
"users",
{
const UserImage = require("../userimage");
const WorkImage = require("../workimage")
const User = db.sequelize.define("users", {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
autoIncrement: true,
},
name: {
type: Sequelize.STRING
type: Sequelize.STRING,
},
email: {
type: Sequelize.STRING
type: Sequelize.STRING,
},
password: {
type: Sequelize.STRING
type: Sequelize.STRING,
},
address: {
type: Sequelize.STRING
type: Sequelize.STRING,
},
tel: {
type: Sequelize.STRING
type: Sequelize.STRING,
},
role: {
type: Sequelize.INTEGER
}
type: Sequelize.INTEGER,
},
);
\ No newline at end of file
});
User.hasMany(UserImage, { foreignKey: "image_id" });
// User.hasMany(WorkImage, { foreignKey: "image_id" });
module.exports = User;
const Sequelize = require("sequelize");
const db = require("../../db");
const UserImage = db.sequelize.define("userimages", {
image_id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: Sequelize.INTEGER,
primaryKey: true,
},
image: {
type: Sequelize.BLOB
},
type: {
type: Sequelize.STRING
}
});
module.exports = UserImage;
\ No newline at end of file
const Sequelize = require("sequelize");
const db = require("../../db");
const WorkImage = db.sequelize.define("workimages", {
image_id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
shop_id: {
type: Sequelize.INTEGER,
primaryKey: true,
},
// user_id: {
// type: Sequelize.INTEGER,
// primaryKey: true,
// },
image: {
type: Sequelize.BLOB,
},
type: {
type: Sequelize.STRING,
},
});
module.exports = WorkImage;
......@@ -567,6 +567,16 @@
"vary": "~1.1.2"
}
},
"express-promise-router": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/express-promise-router/-/express-promise-router-3.0.3.tgz",
"integrity": "sha1-Xm0ipaPwE9cYMxcv6NereAw/a3A=",
"requires": {
"is-promise": "^2.1.0",
"lodash.flattendeep": "^4.0.0",
"methods": "^1.0.0"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
......@@ -848,6 +858,11 @@
"path-is-inside": "^1.0.1"
}
},
"is-promise": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
"integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
},
"is-property": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
......@@ -955,6 +970,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"lodash.flattendeep": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
"integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI="
},
"lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
......@@ -1068,17 +1088,17 @@
"dev": true
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"requires": {
"minimist": "0.0.8"
"minimist": "^1.2.5"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}
}
},
......
......@@ -12,13 +12,14 @@
"multer": "^1.4.2",
"mysql2": "^2.1.0",
"sequelize": "^5.21.3",
"util": "^0.12.1"
"util": "^0.12.1",
"express-promise-router": "3.0.3"
},
"devDependencies": {
"nodemon": "^2.0.2"
},
"scripts": {
"start": "node server.js",
"start": "nodemon server.js",
"start-dev": "nodemon server.js"
},
"author": "",
......
......@@ -8,7 +8,6 @@ router.get("/get", (req, res) => {
});
router.get("/getUserById/:id", authController.getUserById);
router.post("/register", authController.register);
router.post("/login", authController.login);
router.get('/currentuser', authController.currentUser);
......
const express = require("express");
const router = express.Router();
const BeauticianController = require("../../controllers/beautician");
router.post("/add", BeauticianController.add);
router.get("/getbeauticianShopId/:shopID", BeauticianController.getbeauticianShopId);
module.exports = router;
......@@ -4,7 +4,11 @@ const shop = require("./shop");
const promotion = require("./promotion");
const review = require("./review");
const booking = require("./booking");
const storage = require("./storage")
const storage = require("./storage");
const storageprofile= require("./storageprofile");
const storageshop = require("./storageshop")
const storagebeautician = require("./storagebeautician")
const Beautician = require("./beautician")
module.exports = {
auth,
list,
......@@ -12,5 +16,9 @@ module.exports = {
promotion,
review,
booking,
storage
storage,
storageprofile,
storageshop,
storagebeautician,
Beautician
};
......@@ -8,6 +8,7 @@ router.post("/add",promotiomController.addpromotion);
router.get('/all',promotiomController.getPromotion);
router.delete('/delete/:promotionId',promotiomController.deletePromotion);
router.get('/getPromotionId/:id',promotiomController.getPromotionId);
router.get('/getUserId/:id', promotiomController.getUserId)
router.put('/updatePromotion/id',promotiomController.updatePromotion);
......
const express = require('express');
const router = express.Router();
const router = require('express-promise-router')();
const storage = require('../../multer');
const ShopImage = require('../../models/shopimage');
const User = require('../../models/user');
router.post('/upload/shop/:shopId', storage.single('images'), async (req, res) => {
// console.log(req.body.shopId);
const images = req.file;
const shop_id = req.body.shopId
router.post('/upload/shop/:shopId', storage.array('images', 5), async (req, res) => {
console.log(images)
// const images = req.files;
// for (let i = 0; i < images.length; i++) {
// await ShopImage.create({
// shop_id: req.params.productId,
// userId: req.params.productId,
// image: images[i].buffer,
// type: images[i].mimetype
// });
// }
// res.send('success')
// console.log(req);
await ShopImage.create({
shop_id: req.params.shopId,
image: images.buffer,
type: images.mimetype
});
res.send('success')
})
//get file
router.get('/file/product/:imageId', async (req, res) => {
const existingImage = await ProductImage.findOne({
router.get('/file/shop/:shopId', async (req, res) => {
const existingImage = await ShopImage.findOne({
where: {
image_id: req.params.imageId
shop_id: req.params.shopId
}
})
const url = existingImage.image.toString('base64');
res.status(200).send(url);
const urlimg = existingImage.image.toString('base64');
const dataimg = {
url: urlimg,
type: existingImage.type
}
res.status(200).send(dataimg);
})
router.put('/file/shop/:shopId', storage.single('images') ,async (req, res) => {
const editImage = req.file;
const profileimage = {
image: editImage.buffer
}
module.exports = router;
const shopId = req.params.shopId;
await ShopImage.update(
profileimage,
{ where: { shop_id: shopId } }
)
res.send('success')
})
module.exports = router;
const router = require("express-promise-router")();
const storagebeautician = require("../../multer");
const BeauticianImage = require("../../models/beauticianImg");
const User = require("../../models/user");
router.post(
"/upload/beautician/:beauticianId",storagebeautician.single("images"),async (req, res) => {
// console.log(req.body.shopId);
const images = req.file;
const shop_id = req.body.shopId;
const beautician_id = req.params.beauticianId;
// console.log(req);
await BeauticianImage.create({
beautician_id: req.params.beauticianId,
image: images.buffer,
type: images.mimetype,
});
res.send("success");
}
);
//get file
router.get('/file/beautician/:beauticianId', async (req, res) => {
const existingImage = await ShopImage.findAll({
where: {
beautician_id: req.params.beauticianId
}
})
const urlimg = existingImage.image.toString('base64');
const dataimg = {
url: urlimg,
type: existingImage.type
}
res.status(200).send(dataimg);
})
module.exports = router;
const router = require('express-promise-router')();
const storageprofile = require('../../multer');
const UserImage = require('../../models/userimage');
router.post('/upload/user/:userId', storageprofile.single('images'), async (req, res) => {
// console.log(req.body.shopId);
const images = req.file;
const user_id = req.body.userId
// console.log(req);
await UserImage.create({
user_id: req.params.userId,
image: images.buffer,
type: images.mimetype
});
res.send('success')
})
//get file
router.get('/file/user/:userId', async (req, res) => {
const existingImage = await ShopImage.findOne({
where: {
user_id: req.params.userId
}
})
const urlimg = existingImage.image.toString('base64');
const dataimg = {
url: urlimg,
type: existingImage.type
}
res.status(200).send(dataimg);
})
router.put('/file/user/:userId', storageprofile.single('images') ,async (req, res) => {
const editImage = req.file;
const profileimage = {
image: editImage.buffer
}
const userId = req.params.shopId;
await UserImage.update(
profileimage,
{ where: {user_id: userId } }
)
res.send('success')
})
module.exports = router;
\ No newline at end of file
const router = require('express-promise-router')();
const storageshop = require('../../multer');
const WorkImage = require('../../models/workimage');
const Shop = require('../../models/shop')
router.post('/upload/work/:shopId', storageshop.single('images'), async (req, res) => {
// console.log(req.body.shopId);
const images = req.file;
const shop_id = req.body.shopId
// const user_id = req.body.userId
// console.log(req);
await WorkImage.create({
shop_id: req.params.shopId,
// user_id: req.params.userId,
image: images.buffer,
type: images.mimetype
});
res.send('success')
})
//get file
router.get('/file/shop/:shopId', async (req, res) => {
const existingImage = await ShopImage.findAll({
where: {
shop_id: req.params.shopId
}
})
const urlimg = existingImage.image.toString('base64');
const dataimg = {
url: urlimg,
type: existingImage.type
}
res.status(200).send(dataimg);
})
module.exports = router;
......@@ -16,7 +16,10 @@ app.use("/api/promotion", router.promotion);
app.use("/api/review", router.review);
app.use("/api/booking", router.booking);
app.use("/api/storage", router.storage);
app.use("/api/storageprofile", router.storageprofile);
app.use("/api/storageshop", router.storageshop);
app.use("/api/storagebeautician", router.storagebeautician)
app.use("/api/beautician", router.Beautician)
app.listen(port, () => {
console.log("Express server listening on port " + port);
});
......@@ -7,7 +7,7 @@ import {
DialogContent,
DialogTitle,
TextField,
InputAdornment
InputAdornment,
} from "@material-ui/core";
import { withRouter } from "react-router-dom";
......@@ -16,9 +16,9 @@ import Fab from "@material-ui/core/Fab";
import AddIcon from "@material-ui/icons/Add";
import AddPhotoAlternateIcon from "@material-ui/icons/AddPhotoAlternate";
import MaterialTable from "material-table";
const styles = theme => ({
import axios from "axios";
import { connect } from "react-redux";
const styles = (theme) => ({
root: {
height: 150,
flexGrow: 1,
......@@ -26,54 +26,47 @@ const styles = theme => ({
// The position fixed scoping doesn't work in IE 11.
// Disable this demo to preserve the others.
"@media all and (-ms-high-contrast: none)": {
display: "none"
}
display: "none",
},
},
modal: {
display: "flex",
padding: theme.spacing(1),
alignItems: "center",
justifyContent: "center"
justifyContent: "center",
},
fab: {
position: "absolute",
bottom: theme.spacing(2),
right: theme.spacing(2)
}
right: theme.spacing(2),
},
});
class Databeautician extends Component {
class AddImage extends Component {
state = {
open: false,
columns: [
{ title: "รูปภาพ", field: "img" }
],
data: [
{ img: "Mehmet"},
{
img: "Zerya Betül"
}
]
columns: [{ title: "รูปภาพ", field: "img" }],
data: [],
file: null,
shop: [],
};
handleClickOpen = () => {
this.setState({
open: true
open: true,
});
};
handleClose = () => {
this.setState({
open: false
open: false,
});
};
handleCloseAndSave = () => {
//Save to db
this.setState(prevState => {
this.setState((prevState) => {
const data = [...prevState.data];
const newData = {
img: "Mehmet",
};
data.push(newData);
return { ...prevState, data: data, open: false };
......@@ -83,16 +76,50 @@ class Databeautician extends Component {
// open: false
// });
};
componentDidMount = () => {
let { pathname } = this.props.location;
pathname = pathname.substring(1, pathname.length);
// console.log('pathname', pathname)
// componentDidMount = () => {
// let { pathname } = this.props.location;
// pathname = pathname.substring(1, pathname.length);
// // console.log('pathname', pathname)
// };
componentDidMount = async () => {
const { location, userInfo } = this.props;
const { shop } = this.state;
// const id = location.state.id;
// const response = await axios.get(
// `http://localhost:9000/api/shop/getUserId/${userInfo.id}`
// );
// console.log("response.data", response.data);
// if (response.data)
// this.setState({
// shop: response.data,
// data: response.data,
// });
const response = await axios.get(
`http://localhost:9000/api/shop/getUserId/${userInfo.id}`
);
const resposeimgshop = await axios.get(`http://localhost:9000/api/storage/file/shop/${response.data.id}`)
// console.log(resposeimgshop);
response.data.image = ('data:' + resposeimgshop.data.type+';base64,'+resposeimgshop.data.url)
console.log("response.data",response.data);
// console.log("response.data",b.data);
if (response.data)
this.setState({
shop: response.data,
data: response.data
});
// if (b.data)
// this.setState({
// data: b.data,
// });
};
render() {
const { classes } = this.props;
const { open, columns, data } = this.state;
const { open, columns, data, file, shop } = this.state;
return (
<div>
<MaterialTable
......@@ -100,44 +127,20 @@ class Databeautician extends Component {
columns={columns}
data={data}
options={{
selection: false
selection: false,
}}
editable={{
// onRowAdd: newData =>
// new Promise(resolve => {
// setTimeout(() => {
// resolve();
// this.setState(prevState => {
// const data = [...prevState.data];
// data.push(newData);
// return { ...prevState, data };
// });
// }, 600);
// }),
// onRowUpdate: (newData, oldData) =>
// new Promise(resolve => {
// setTimeout(() => {
// resolve();
// if (oldData) {
// this.setState(prevState => {
// const data = [...prevState.data];
// data[data.indexOf(oldData)] = newData;
// return { ...prevState, data };
// });
// }
// }, 600);
// }),
onRowDelete: oldData =>
new Promise(resolve => {
onRowDelete: (oldData) =>
new Promise((resolve) => {
setTimeout(() => {
resolve();
this.setState(prevState => {
this.setState((prevState) => {
const data = [...prevState.data];
data.splice(data.indexOf(oldData), 1);
return { ...prevState, data };
});
}, 600);
})
}),
}}
/>
<div className="row">
......@@ -158,7 +161,6 @@ class Databeautician extends Component {
>
<DialogTitle id="alert-dialog-title">{"เพิ่มรูปภาพ"}</DialogTitle>
<DialogContent>
<TextField
className={classes.margin}
id="outlined-file-input"
......@@ -171,7 +173,12 @@ class Databeautician extends Component {
<InputAdornment position="start">
<AddPhotoAlternateIcon />
</InputAdornment>
)
),
}}
onChange={(e) => {
this.setState({
file: e.target.files[0],
});
}}
/>
</DialogContent>
......@@ -180,7 +187,29 @@ class Databeautician extends Component {
ยกเลิก
</Button>
<Button
onClick={this.handleCloseAndSave}
onClick={() => {
const { location, userInfo } = this.props;
const formData = new FormData();
console.log(file);
formData.append("images", file);
formData.append("shop_id", shop.id);
// formData.append('userId', userInfo.id)
axios
.post(
`http://localhost:9000/api/storageshop/upload/work/${shop.id}`,
formData
)
.then((response) => {
console.log("เพิ่มรูปภาพสำเร็จ", response);
alert("เพิ่มรูปภาพสำเร็จ");
this.handleClose();
})
.catch((error) => {
console.log(error);
});
}}
color="primary"
autoFocus
>
......@@ -193,5 +222,13 @@ class Databeautician extends Component {
);
}
}
const mapStateToProps = (state) => ({
userInfo: state.user,
});
const mapDispatchToProps = (dispatch) => {};
export default compose(withStyles(styles), withRouter)(Databeautician);
export default connect(
mapStateToProps,
mapDispatchToProps
)(compose(withStyles(styles), withRouter)(AddImage));
......@@ -8,7 +8,7 @@ import {
DialogTitle,
InputAdornment,
TextField,
Fab
Fab,
} from "@material-ui/core";
import { withRouter } from "react-router-dom";
import compose from "recompose/compose";
......@@ -21,9 +21,10 @@ import BusinessIcon from "@material-ui/icons/Business";
import MaterialTable from "material-table";
import { connect } from "react-redux";
import axios from "axios";
const styles = theme => ({
const styles = (theme) => ({
root: {
height: 150,
flexGrow: 1,
......@@ -31,23 +32,23 @@ const styles = theme => ({
// The position fixed scoping doesn't work in IE 11.
// Disable this demo to preserve the others.
"@media all and (-ms-high-contrast: none)": {
display: "none"
}
display: "none",
},
},
modal: {
display: "flex",
padding: theme.spacing(1),
alignItems: "center",
justifyContent: "center"
justifyContent: "center",
},
fab: {
position: "absolute",
bottom: theme.spacing(2),
right: theme.spacing(2)
right: theme.spacing(2),
},
table: {
minWidth: 700
}
minWidth: 700,
},
});
class Databeautician extends Component {
......@@ -57,19 +58,9 @@ class Databeautician extends Component {
{ title: "Name", field: "name" },
{ title: "E-mail", field: "email" },
{ title: "Address", field: "address" },
{
title: "Phone number",
field: "phone"
}
],
data: [
{
name: "ปิยพร อาภรศรี",
email: "piyaphorn.ar@gmail.com",
address: "7/1 ต.หนองบก",
phone: "0647183784"
}
{title: "Phone number", field: "tel",}
],
data: [],
name: "",
email: "",
......@@ -77,34 +68,35 @@ class Databeautician extends Component {
password2: "",
address: "",
tel: "",
rolr: ""
rolr: "",
shops: [],
};
handleChange = event => {
handleChange = (event) => {
console.log("name : ", event.target.name);
console.log("value : ", event.target.value);
this.setState({
[event.target.name]: event.target.value
[event.target.name]: event.target.value,
});
};
handleClickOpen = () => {
this.setState({
open: true
open: true,
});
};
handleClose = () => {
this.setState({
open: false
open: false,
});
};
handleCloseAndSave = () => {
this.setState(prevState => {
this.setState((prevState) => {
const data = [...prevState.data];
const newData = {
name: "Mehmet",
surname: "Baran",
birthYear: 1987,
birthCity: 63
birthCity: 63,
};
data.push(newData);
return { ...prevState, data: data, open: false };
......@@ -114,14 +106,26 @@ class Databeautician extends Component {
// open: false
// });
};
componentDidMount = () => {
let { pathname } = this.props.location;
pathname = pathname.substring(1, pathname.length);
// console.log('pathname', pathname)
componentDidMount = async () => {
const { location, userInfo } = this.props;
const { shops } = this.state;
const response = await axios.get(
`http://localhost:9000/api/shop/getUserId/${userInfo.id}`
);
const responsedata = await axios.get(
`http://localhost:9000/api/beautician/getbeauticianShopId/${shops.id}`
);
console.log(response.data);
console.log(responsedata.data);
this.setState({
shops: response.data,
data: responsedata.data
});
};
render() {
const { classes } = this.props;
const { classes, userInfo } = this.props;
const {
open,
......@@ -133,8 +137,9 @@ class Databeautician extends Component {
password2,
address,
tel,
shops,
role
role,
} = this.state;
return (
<div>
......@@ -143,44 +148,20 @@ class Databeautician extends Component {
columns={columns}
data={data}
options={{
selection: false
selection: false,
}}
editable={{
// onRowAdd: newData =>
// new Promise(resolve => {
// setTimeout(() => {
// resolve();
// this.setState(prevState => {
// const data = [...prevState.data];
// data.push(newData);
// return { ...prevState, data };
// });
// }, 600);
// }),
onRowUpdate: (newData, oldData) =>
new Promise(resolve => {
setTimeout(() => {
resolve();
if (oldData) {
this.setState(prevState => {
const data = [...prevState.data];
data[data.indexOf(oldData)] = newData;
return { ...prevState, data };
});
}
}, 600);
}),
onRowDelete: oldData =>
new Promise(resolve => {
onRowDelete: (oldData) =>
new Promise((resolve) => {
setTimeout(() => {
resolve();
this.setState(prevState => {
this.setState((prevState) => {
const data = [...prevState.data];
data.splice(data.indexOf(oldData), 1);
return { ...prevState, data };
});
}, 600);
})
}),
}}
/>
<div className="row">
......@@ -207,14 +188,14 @@ class Databeautician extends Component {
id="name"
name="name"
value={name}
label="ชื่อ-สกุล"
label="ชื่อ-สกุล*"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AccountCircle />
</InputAdornment>
)
),
}}
onChange={this.handleChange}
/>
......@@ -226,14 +207,14 @@ class Databeautician extends Component {
id="email"
name="email"
value={email}
label="E_mail"
label="E_mail*"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<MailOutlineIcon />
</InputAdornment>
)
),
}}
onChange={this.handleChange}
/>
......@@ -245,7 +226,7 @@ class Databeautician extends Component {
id="password"
name="password"
value={password}
label="Password"
label="Password*"
type="password"
autoComplete="current-password"
variant="outlined"
......@@ -254,7 +235,7 @@ class Databeautician extends Component {
<InputAdornment position="start">
<VpnKeyIcon />
</InputAdornment>
)
),
}}
onChange={this.handleChange}
/>
......@@ -266,7 +247,7 @@ class Databeautician extends Component {
id="password2"
name="password2"
value={password2}
label="Confirm-Password"
label="Confirm-Password*"
type="password"
autoComplete="current-password"
variant="outlined"
......@@ -275,7 +256,7 @@ class Databeautician extends Component {
<InputAdornment position="start">
<VpnKeyIcon />
</InputAdornment>
)
),
}}
onChange={this.handleChange}
/>
......@@ -295,7 +276,7 @@ class Databeautician extends Component {
<InputAdornment position="start">
<BusinessIcon />
</InputAdornment>
)
),
}}
onChange={this.handleChange}
/>
......@@ -315,7 +296,7 @@ class Databeautician extends Component {
<InputAdornment position="start">
<ContactPhoneIcon />
</InputAdornment>
)
),
}}
onChange={this.handleChange}
/>
......@@ -330,20 +311,30 @@ class Databeautician extends Component {
autoFocus
onClick={() => {
if (password === password2) {
axios
.post("http://localhost:9000/api/auth/register", {
const register = axios.post(
"http://localhost:9000/api/auth/register",
{
name: name,
email: email,
password: password,
address: address,
tel: tel,
role: "2",
}
);
const Beautician = axios
.post("http://localhost:9000/api/beautician/add", {
name: name,
email: email,
address: address,
tel: tel,
role: "2"
shopID: shops.id,
})
.then(response => {
.then((response) => {
console.log("สร้างผู้ใช้สำเร็จ", response);
this.handleClose();
})
.catch(error => {
.catch((error) => {
console.log(error);
});
// alert("ลงทะเบียนสำเร็จ");
......@@ -362,4 +353,13 @@ class Databeautician extends Component {
}
}
export default compose(withStyles(styles), withRouter)(Databeautician);
const mapStateToProps = (state) => ({
userInfo: state.user,
});
const mapDispatchToProps = (dispatch) => {};
export default connect(
mapStateToProps,
mapDispatchToProps
)(compose(withStyles(styles), withRouter)(Databeautician));
......@@ -36,8 +36,7 @@ import PlaceIcon from '@material-ui/icons/Place';
import FacebookIcon from '@material-ui/icons/Facebook';
import MergeTypeIcon from '@material-ui/icons/MergeType';
import axios from "axios";
import MuiAlert from "@material-ui/lab/Alert";
import Avatar from "react-avatar";
import { connect } from "react-redux";
const styles = theme => ({
......@@ -104,8 +103,9 @@ class Datashop extends Component {
},
file: null,
promotion: "",
open: false
promotion: {detail:""},
open: false,
openupdate: false
};
handleClickOpen = () => {
this.setState({
......@@ -117,6 +117,16 @@ class Datashop extends Component {
open: false
});
};
handleClickOpenupdate = () => {
this.setState({
openupdate: true
});
};
handleCloseupdate = () => {
this.setState({
openupdate: false
});
};
handleChange = event => {
let { shop } = this.state;
console.log("name : ", event.target.name);
......@@ -135,14 +145,21 @@ class Datashop extends Component {
const response = await axios.get(
`http://localhost:9000/api/shop/getUserId/${userInfo.id}`
);
const resposeimgshop = await axios.get(`http://localhost:9000/api/storage/file/shop/${response.data.id}`)
// console.log(resposeimgshop);
const responsepromotion = await axios.get(
`http://localhost:9000/api/promotion/getuserId/${userInfo.id}`
);
response.data.image = ('data:' + resposeimgshop.data.type+';base64,'+resposeimgshop.data.url)
if (response.data) this.setState({ shop: response.data });
if (responsepromotion.data) this.setState({ promotion: responsepromotion.data });
};
render() {
const { classes, userInfo } = this.props;
const { currency, shop, promotion, open, file } = this.state;
const { currency, shop, promotion, open, file ,openupdate} = this.state;
return (
<div className="row center">
<div className="row mt-2 mb-2">
......@@ -150,14 +167,14 @@ class Datashop extends Component {
</div>
<br />
<div className="row mt-2 mb-2">
<div className="col s12 m6 l12">
<div className="col s12 m12 l12">
<div className="row center">
<h3>ข้อมูลทั่วไป</h3>
</div>
<div className="row center">
<br />
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcRGzUPvW-KAdZI6KiIyh-HHSKtqKRGSWcP3vDqHUd2Sn2F3SHwr" />
<img src={shop.image} width="60%"/>
</div>
<div className="row center">
......@@ -205,20 +222,22 @@ class Datashop extends Component {
</Button>
<Button
onClick={() => {
const { location, userInfo } = this.props;
const formData = new FormData();
formData.append("images", file);
console.log(file);
formData.append('images', file)
formData.append('shop_id', shop.id)
// formData.append('userId', userInfo.id)
axios
.post(
`http://localhost:9000/api/storage/upload/shop/${shop.id}`,
formData,
shop.id,
userInfo.id
)
`http://localhost:9000/api/storage/upload/shop/${shop.id}`,formData)
.then(response => {
console.log("เพิ่มรูปภาพสำเร็จ", response);
alert("เพิ่มรูปภาพสำเร็จ");
this.handleClose();
})
.catch(error => {
console.log(error);
......@@ -232,20 +251,84 @@ class Datashop extends Component {
</DialogActions>
</Dialog>
&nbsp; &nbsp; &nbsp;
<Button variant="outlined" color="primary">
<Button variant="outlined" onClick={this.handleClickOpenupdate} color="primary">
<PhotoCameraIcon />
แก้ไขรูปภาพร้าน
</Button>
<Dialog
open={openupdate}
onClose={this.handleCloseupdate}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"แก้ไขรูปภาพ"}
</DialogTitle>
<DialogContent>
<TextField
className={classes.margin}
id="outlined-file-input"
label="แก้ไขรูปภาพ"
type="file"
autoComplete="current-password"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AddPhotoAlternateIcon />
</InputAdornment>
)
}}
onChange={e => {
this.setState({
file: e.target.files[0]
});
}}
/>
</DialogContent>
<DialogActions>
<Button onClick={this.handleCloseupdate} color="primary">
ยกเลิก
</Button>
<Button
onClick={() => {
const { location, userInfo } = this.props;
const formData = new FormData();
// console.log(file);
formData.append('images', file)
formData.append('shop_id', shop.id)
// // formData.append('userId', userInfo.id)
axios
.put(
`http://localhost:9000/api/storage/file/shop/${shop.id}`,formData)
.then(response => {
console.log("แก้ไขรรูปภาพสำเร็จ", response);
alert("แกไขรูปภาพสำเร็จ");
this.handleCloseupdate();
})
.catch(error => {
console.log(error);
});
}}
color="primary"
autoFocus
>
ยืนยัน
</Button>
</DialogActions>
</Dialog>
</div>
</div>
<div className="col s12 m6 l12">
<div className="col s12 m12 l12">
<div ClassName="row">
<TextField
className={classes.margin}
id="name"
name="name"
value={shop.name}
label="ชื่อร้าน"
label="ชื่อร้าน*"
variant="outlined"
InputProps={{
startAdornment: (
......@@ -261,7 +344,7 @@ class Datashop extends Component {
id="nameeng"
name="nameeng"
value={shop.nameeng}
label="Name"
label="Name*"
variant="outlined"
InputProps={{
startAdornment: (
......@@ -277,7 +360,7 @@ class Datashop extends Component {
id="timeopen"
name="timeopen"
value={shop.timeopen}
label="เวลาเปิดร้าน"
label="เวลาเปิดร้าน*"
autoComplete="timeopen"
variant="outlined"
InputProps={{
......@@ -289,15 +372,13 @@ class Datashop extends Component {
}}
onChange={this.handleChange}
/>
</div>
<br />
<div>
<TextField
className={classes.margin}
id="timeclose"
name="timeclose"
value={shop.timeclose}
label="เวลาปิดร้าน"
label="เวลาปิดร้าน*"
autoComplete="timeclose"
variant="outlined"
InputProps={{
......@@ -314,7 +395,7 @@ class Datashop extends Component {
id="tel"
name="tel"
value={shop.tel}
label="เบอร์โทรร้าน"
label="เบอร์โทรร้าน*"
autoComplete="tel"
variant="outlined"
InputProps={{
......@@ -331,7 +412,7 @@ class Datashop extends Component {
id="address"
name="address"
value={shop.address}
label="ที่อยู่ร้าน"
label="ที่อยู่ร้าน*"
autoComplete="address"
variant="outlined"
InputProps={{
......@@ -343,15 +424,13 @@ class Datashop extends Component {
}}
onChange={this.handleChange}
/>
</div>
<br />
<div>
<TextField
className={classes.margin}
id="detail"
name="detail"
value={shop.detail}
label="รายละเอียดร้าน"
label="รายละเอียดร้าน*"
autoComplete="detail"
variant="outlined"
InputProps={{
......@@ -368,7 +447,7 @@ class Datashop extends Component {
id="lat"
name="lat"
value={shop.lat}
label="lat"
label="lat*"
autoComplete="lat"
variant="outlined"
InputProps={{
......@@ -385,7 +464,7 @@ class Datashop extends Component {
id="lng"
name="lng"
value={shop.lng}
label="lng"
label="lng*"
autoComplete="lng"
variant="outlined"
InputProps={{
......@@ -420,7 +499,7 @@ class Datashop extends Component {
name="type"
value={shop.type}
select
label="ประเภทของร้าน"
label="ประเภทของร้าน*"
onChange={this.handleChange}
SelectProps={{
native: true
......@@ -460,13 +539,13 @@ class Datashop extends Component {
userId: userInfo.id
})
.then(response => {
console.log("สร้างผู้ใช้สำเร็จ", response);
alert("เพิ่มข้อมูลสำเร็จ");
console.log("เพิ่มข้อมูลร้านสำเร็จ", response);
alert("กรอกข้อมูลไม่ครบ");
})
.catch(error => {
console.log(error);
});
// alert("ลงทะเบียนสำเร็จ");
}}
>
ตกลง
......@@ -479,61 +558,7 @@ class Datashop extends Component {
</div>
</div>
</div>
<div className="row center">
<div className="row">
<h3>ข้อมูลโปรโมชั่น</h3>
</div>
<div>
<TextField
className={classes.margin}
id="promotion"
name="promotion"
value={promotion}
label="ข้อมูลโปรโมชั่น"
autoComplete="promotion"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<PostAddIcon />
</InputAdornment>
)
}}
onChange={this.handleChange}
/>
&nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;
<Button variant="contained" color="secondary">
ยกเลิก
</Button>{" "}
&nbsp; &nbsp; &nbsp;
<Button
variant="contained"
color="primary"
onClick={() => {
axios
.post("http://localhost:9000/api/promotion/add", {
shop: shop
})
.then(response => {
console.log("สร้างผู้ใช้สำเร็จ", response);
alert("เพิ่มข้อมูลสำเร็จ");
// window.location.href = "/";
})
.catch(error => {
console.log(error);
});
// alert("ลงทะเบียนสำเร็จ");
}}
>
ตกลง
</Button>
&nbsp; &nbsp; &nbsp;
<Fab color="secondary" aria-label="edit">
<EditIcon />
</Fab>
</div>
<br></br>
</div>
</div>
);
}
......
......@@ -4,8 +4,8 @@ import { withRouter } from "react-router-dom";
import compose from "recompose/compose";
import MaterialTable from "material-table";
import axios from "axios";
const styles = theme => ({
import { connect } from "react-redux";
const styles = (theme) => ({
root: {
height: 150,
flexGrow: 1,
......@@ -13,20 +13,20 @@ const styles = theme => ({
// The position fixed scoping doesn't work in IE 11.
// Disable this demo to preserve the others.
"@media all and (-ms-high-contrast: none)": {
display: "none"
}
display: "none",
},
},
modal: {
display: "flex",
padding: theme.spacing(1),
alignItems: "center",
justifyContent: "center"
justifyContent: "center",
},
fab: {
position: "absolute",
bottom: theme.spacing(2),
right: theme.spacing(2)
}
right: theme.spacing(2),
},
});
class List extends Component {
......@@ -35,23 +35,28 @@ class List extends Component {
{ title: "ชื่อรายการ", field: "name" },
{ title: "ราคา", field: "price" },
{ title: "เวลาที่จอง", field: "time" }
{ title: "เวลาที่จอง", field: "time" },
],
data: [],
shop: null,
userId: null
userId: null,
lists: {
id:"",
name:"",
price:"",
time:""
},
};
handleCloseAndSave = () => {
//Save to db
this.setState(prevState => {
this.setState((prevState) => {
const data = [...prevState.data];
const newData = {
name: "Mehmet",
surname: "Baran",
birthYear: 1987,
birthCity: 63
birthCity: 63,
};
data.push(newData);
return { ...prevState, data: data, open: false };
......@@ -62,26 +67,29 @@ class List extends Component {
// });
};
componentDidMount = async () => {
let { pathname } = this.props.location;
let { pathname} = this.props.location;
const { userInfo } = this.props;
pathname = pathname.substring(1, pathname.length);
const { shop } = this.state;
// get shop
const shop = 5;
const userId = 36;
const responseshop = await axios.get(
`http://localhost:9000/api/shop/getUserId/${userInfo.id}`
);
const response = await axios.get(
`http://localhost:9000/api/list/getListuser/${userId}`
`http://localhost:9000/api/list/getListshop/${responseshop.data.id}`
);
console.log("response.data", response.data);
if (response.data) {
console.log("response.data", responseshop.data);
this.setState({
shop: 5,
userId: 36,
data: response.data
shop: responseshop.data,
data: response.data,
list: response.data,
});
} else {
console.log("cannot get shop data");
}
// console.log('pathname', pathname)
};
......@@ -89,7 +97,7 @@ class List extends Component {
render() {
const { classes } = this.props;
const { columns, data, shop, userId } = this.state;
const { columns, data, shop, userId, lists } = this.state;
return (
<div>
<div className="row">
......@@ -98,55 +106,74 @@ class List extends Component {
columns={columns}
data={data}
options={{
selection: false
selection: false,
}}
editable={{
onRowAdd: newData =>
new Promise(resolve => {
newData = { ...newData, shop: shop, userId: userId };
onRowAdd: (newData) =>
new Promise((resolve) => {
const { userInfo } = this.props;
newData = { ...newData, shop: shop.id, userId: shop.userId };
axios
.post(`http://localhost:9000/api/list/add/`, newData)
.then(response => {
.then((response) => {
console.log("เพิ่ม list สำเร็จ", response);
alert("เพิ่ม list สำเร็จ");
resolve();
this.setState(prevState => {
this.setState((prevState) => {
let data = [...prevState.data];
data = [newData, ...data];
return { ...prevState, data };
});
})
.catch(error => {
.catch((error) => {
console.log(error);
alert(`เพิ่ม list ไม่สำเร็จ ${error.message}`);
});
}),
onRowUpdate: (newData, oldData) =>
new Promise(resolve => {
new Promise((resolve) => {
setTimeout(() => {
newData = { ...newData, shop: shop, userId: userId };
axios
.post(`http://localhost:9000/api/list/updateList/${oldData.id}`, newData)
.then((response) => {
console.log("แก้ไข list สำเร็จ", response);
alert("แก้ไขรายการสำเร็จ");
resolve();
if (oldData) {
this.setState(prevState => {
this.setState((prevState) => {
const data = [...prevState.data];
data[data.indexOf(oldData)] = newData;
return { ...prevState, data };
});
}
}, 600);
})
.catch((error) => {
console.log(error);
alert(`เพิ่ม list ไม่สำเร็จ ${error.message}`);
});
}),
onRowDelete: oldData =>
new Promise(resolve => {
onRowDelete: (oldData) =>
new Promise((resolve) => {
setTimeout(() => {
axios.delete(
`http://localhost:9000/api/list/delete/${oldData.id}`
);
console.log("ลบ list สำเร็จ");
alert("ลบรายการสำเร็จ");
resolve();
this.setState(prevState => {
this.setState((prevState) => {
const data = [...prevState.data];
data.splice(data.indexOf(oldData), 1);
return { ...prevState, data };
});
}, 600);
})
}),
}}
/>
</div>
......@@ -154,5 +181,14 @@ class List extends Component {
);
}
}
const mapStateToProps = state => ({
userInfo: state.user
});
const mapDispatchToProps = dispatch => {};
export default connect(
mapStateToProps,
mapDispatchToProps
)(compose(withStyles(styles), withRouter)(List));
export default compose(withStyles(styles), withRouter)(List);
......@@ -114,45 +114,7 @@ class Managequeue extends Component {
options={{
selection: false
}}
editable={{
// onRowAdd: newData =>
// new Promise(resolve => {
// setTimeout(() => {
// resolve();
// this.setState(prevState => {
// const data = [...prevState.data];
// data.push(newData);
// return { ...prevState, data };
// });
// }, 600);
// }),
// onRowUpdate: (newData, oldData) =>
// new Promise(resolve => {
// setTimeout(() => {
// resolve();
// if (oldData) {
// this.setState(prevState => {
// const data = [...prevState.data];
// data[data.indexOf(oldData)] = newData;
// return { ...prevState, data };
// });
// }
// }, 600);
// }),
// onRowDelete: oldData =>
// new Promise(resolve => {
// setTimeout(() => {
// resolve();
// this.setState(prevState => {
// const data = [...prevState.data];
// data.splice(data.indexOf(oldData), 1);
// return { ...prevState, data };
// });
// }, 600);
// })
}}
/>
</div>
</div>
......
......@@ -6,7 +6,21 @@ import {
InputAdornment,
TextField,
Button,
Fab
Fab,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
FormControl,
TextareaAutosize,
Paper,
CardMedia,
MenuItem,
Snackbar,
} from "@material-ui/core";
import AccountCircle from "@material-ui/icons/AccountCircle";
import MailOutlineIcon from "@material-ui/icons/MailOutline";
......@@ -16,32 +30,49 @@ import EditIcon from "@material-ui/icons/Edit";
import { connect } from "react-redux";
import PhotoCameraIcon from "@material-ui/icons/PhotoCamera";
import Avatar from "react-avatar";
import AddAPhotoIcon from "@material-ui/icons/AddAPhoto";
import AddPhotoAlternateIcon from "@material-ui/icons/AddPhotoAlternate";
import axios from "axios";
const styles = theme => ({
const styles = (theme) => ({
margin: {
margin: theme.spacing(1)
}
margin: theme.spacing(1),
},
});
class Profile extends Component {
state = {
user: ""
user: "",
file: null,
open: false
};
handleClickOpen = () => {
this.setState({
open: true
});
};
handleClose = () => {
this.setState({
open: false
});
};
componentDidMount = async () => {
const { location, userInfo } = this.props;
// const id = userInfo.id;
const response = await axios.get(
`http://localhost:9000/api/auth/getUserById/${userInfo.id}`
);
// const resposeimguser = await axios.get(`http://localhost:9000/api/storageprofile/file/user/${userInfo.id}`)
// // console.log(resposeimgshop);
// response.data.image = ('data:' + resposeimguser.data.type+';base64,'+resposeimguser.data.url)
console.log(response.data);
this.setState({
user: response.data
user: response.data,
});
};
render() {
const { classes, userInfo } = this.props;
const { user } = this.state;
const { user, file ,shop,open} = this.state;
return (
<div className="row center">
<div className="row mt-2 mb-2">
......@@ -49,24 +80,99 @@ class Profile extends Component {
</div>
<br />
<div className="row mt-2 mb-2">
<div className="col s12 m6 l4">
<div className="col s12 m12 l4">
<div className="row center">
<br />
<Avatar
skypeId="sitebase"
src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQZeSPYraiTcEz6JxyXy8ITsaGldAqDjX6860m7eCpYhYeQDQkL"
src={user.image}
size="200"
round={true}
/>
</div>
<div className="row center">
<Button
variant="outlined"
color="primary"
onClick={this.handleClickOpen}
>
<AddAPhotoIcon />
เพิ่มรูปภาพร้าน
</Button>
<Dialog
open={open}
onClose={this.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"เพิ่มรูปภาพ"}
</DialogTitle>
<DialogContent>
<TextField
className={classes.margin}
id="outlined-file-input"
label="เพิ่มรูปภาพ"
type="file"
autoComplete="current-password"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AddPhotoAlternateIcon />
</InputAdornment>
),
}}
onChange={(e) => {
this.setState({
file: e.target.files[0],
});
}}
/>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color="primary">
ยกเลิก
</Button>
<Button
onClick={() => {
const { location, userInfo } = this.props;
const formData = new FormData();
console.log(file);
formData.append("images", file);
// formData.append("shop_id", shop.id);
formData.append('userId', userInfo.id)
axios
.post(
`http://localhost:9000/api/storageprofile/upload/user/${userInfo.id}`,
formData
)
.then((response) => {
console.log("เพิ่มรูปภาพสำเร็จ", response);
alert("เพิ่มรูปภาพสำเร็จ");
this.handleClose();
})
.catch((error) => {
console.log(error);
});
}}
color="primary"
autoFocus
>
ยืนยัน
</Button>
</DialogActions>
</Dialog>
&nbsp; &nbsp; &nbsp;
<Button variant="outlined" color="primary">
<PhotoCameraIcon />
แก้ไขรูปโปรไฟล์
แก้ไขรูปภาพร้าน
</Button>
</div>
</div>
<div className="col s12 m6 l8">
<div className="col s12 m12 l8">
<br />
<div ClassName="row">
<TextField
......@@ -81,7 +187,7 @@ class Profile extends Component {
<InputAdornment position="start">
<AccountCircle />
</InputAdornment>
)
),
}}
/>
......@@ -97,7 +203,7 @@ class Profile extends Component {
<InputAdornment position="start">
<MailOutlineIcon />
</InputAdornment>
)
),
}}
/>
</div>
......@@ -116,7 +222,7 @@ class Profile extends Component {
<InputAdornment position="start">
<BusinessIcon />
</InputAdornment>
)
),
}}
/>
......@@ -133,7 +239,7 @@ class Profile extends Component {
<InputAdornment position="start">
<ContactPhoneIcon />
</InputAdornment>
)
),
}}
/>
</div>
......@@ -160,11 +266,11 @@ class Profile extends Component {
);
}
}
const mapStateToProps = state => ({
userInfo: state.user
const mapStateToProps = (state) => ({
userInfo: state.user,
});
const mapDispatchToProps = dispatch => {};
const mapDispatchToProps = (dispatch) => {};
export default connect(
mapStateToProps,
......
......@@ -136,6 +136,7 @@ class HomePage extends Component {
shops: [],
columns: [{ title: "เวลา", field: "time" }],
data: [],
};
handleClickOpen = () => {
this.setState({
......@@ -179,21 +180,39 @@ class HomePage extends Component {
// 7
const response = await axios.get("http://localhost:9000/api/shop/all");
console.warn(response.data);
for (let i = 0; i < response.data.length; i++) {
const resposeimgshop = await axios.get(`http://localhost:9000/api/storage/file/shop/${response.data[i].id}`)
// console.log(resposeimgshop);
response.data[i].image = ('data:' + resposeimgshop.data.type+';base64,'+resposeimgshop.data.url)
}
console.log("response", response.data);
this.setState({
tab: tab,
shops: response.data
shops: response.data,
// data: result,
});
};
calculate = (endTime, timeopen) => {
let timeStops = [];
let dateOpen = new Date();
dateOpen.setHours(parseInt(timeopen[0]));
dateOpen.setMinutes(parseInt(timeopen[1]));
let startTime = moment(dateOpen).add(
"m",
15 - (moment(dateOpen).minute() % 15)
);
while (startTime < endTime) {
timeStops.push({
time: new moment(startTime).format("LT"),
});
// console.log("response", response.data);
// let { timeopen, timeclose } = response.data;
// timeopen = timeopen.split(":");
// timeclose = timeclose.split(":");
// let dateClose = new Date();
// dateClose.setHours(parseInt(timeclose[0]));
// dateClose.setMinutes(parseInt(timeclose[1]));
// const result = this.calculate(moment(dateClose), timeopen);
startTime.add("m", 15);
}
return timeStops;
};
handleChangeTab = (event, newValue) => {
......@@ -237,9 +256,7 @@ class HomePage extends Component {
<div className="row ">
<center>
<Paper component="form" className={classes.root}>
{/* <IconButton className={classes.iconButton} aria-label="menu">
<MenuIcon />
</IconButton> */}
<InputBase
className={classes.input}
inputProps={{ "aria-label": "ค้นหาร้าน" }}
......@@ -251,14 +268,7 @@ class HomePage extends Component {
>
<SearchIcon />
</IconButton>
{/* <Divider className={classes.divider} orientation="vertical" /> */}
{/* <IconButton
color="primary"
className={classes.iconButton}
aria-label="directions"
>
<DirectionsIcon />
</IconButton> */}
</Paper>
</center>
</div>
......@@ -269,7 +279,7 @@ class HomePage extends Component {
<div className="col s12 m6 l6">
<div className="row mt-3 mb-2 center">
<img
src="https://www.smeleader.com/wp-content/uploads/2018/05/%E0%B9%81%E0%B8%9F%E0%B8%A3%E0%B8%99%E0%B9%84%E0%B8%8A%E0%B8%AA%E0%B9%8C%E0%B8%A3%E0%B9%89%E0%B8%B2%E0%B8%99%E0%B9%80%E0%B8%AA%E0%B8%A3%E0%B8%B4%E0%B8%A1%E0%B8%AA%E0%B8%A7%E0%B8%A2-%E0%B8%A3%E0%B8%A7%E0%B8%A1%E0%B9%81%E0%B8%9A%E0%B8%A3%E0%B8%99%E0%B8%94%E0%B9%8C%E0%B8%A3%E0%B9%89%E0%B8%B2%E0%B8%99%E0%B8%8B%E0%B8%B2%E0%B8%A5%E0%B8%AD%E0%B8%99-%E0%B8%AA%E0%B8%B2%E0%B8%99%E0%B8%9D%E0%B8%B1%E0%B8%99%E0%B8%98%E0%B8%B8%E0%B8%A3%E0%B8%81%E0%B8%B4%E0%B8%88%E0%B8%97%E0%B8%A3%E0%B8%87%E0%B8%9C%E0%B8%A1.jpg"
src={shop.image}
width="60%"
onClick={() => {
this.props.history.push("/ShopPage", { id: shop.id});
......
// let timeopen = ["10", "00", "00"];
// let timeclose = ["19", "30", "00"];
// let timeInTable = [];
// while (timeopen[0] !== timeclose[0] && timeopen[1] !== timeopen[1]) {
// let tmpTimeHourOpen = parseInt(timeopen[0]);
// let tmpTimeMinuteOpen = parseInt(timeopen[1]);
// let tableTimeHour = tmpTimeHourOpen;
// let tableTimeMinute = tmpTimeMinuteOpen;
// if (tmpTimeMinuteOpen === 45) {
// tableTimeHour = tableTimeHour + 1;
// tableTimeHour = 0
// }else{
// }
// let timeTable = Number(timeopen[0]);
// let timeTable = Number(timeopen[0]);
// timeInTable.push();
// }
// console.log("test");
// ================================ 2 ===========================
// function addMinutes(date, minutes) {
// return new Date(date.getTime() + minutes * 60000);
// }
// let date = new Date();
// let result = "";
// for (let index = 0; index < 30; index++) {
// let m = ((((date.getMinutes() + 7.5) / 15) | 0) * 15) % 60;
// let h = (((date.getMinutes() / 105 + 0.5) | 0) + date.getHours()) % 24;
// date = new Date(date.getYear(), date.getMonth(), date.getDay(), h, m, 0, 0);
// if (index > 0) result += ", ";
// result += ("0" + h).slice(-2) + ":" + ("0" + m).slice(-2);
// date = addMinutes(date, 15);
// }
// console.log('result', result)
// import moment from 'moment'
const moment = require("moment");
function calculate(endTime) {
let timeStops = [];
let timeopen = ["10", "00", "00"];
let dateOpen = new Date();
dateOpen.setHours(parseInt(timeopen[0]));
dateOpen.setMinutes(parseInt(timeopen[1]));
console.log("dateOpen", dateOpen);
let startTime = moment(dateOpen).add(
"m",
15 - (moment(dateOpen).minute() % 15)
);
while (startTime < endTime) {
timeStops.push(new moment(startTime));
startTime.add("m", 15);
}
return timeStops;
}
let timeclose = ["19", "30", "00"];
let dateClose = new Date();
dateClose.setHours(parseInt(timeclose[0]));
dateClose.setMinutes(parseInt(timeclose[1]));
console.log("dateClose", dateClose);
// const result = calculate(moment().add("h", 1));
const result = calculate(moment(dateClose));
console.log("result : ", result.length);
......@@ -39,8 +39,7 @@ class Login extends Component {
return (
<div>
<div className="row center">
<br />
<br />
<div className="row mt-5 ">
<h2>เข้าสู่ระบบ</h2>
</div>
......@@ -62,8 +61,8 @@ class Login extends Component {
onChange={this.handleChange}
/>
</div>
<br></br>
<div>
<div className="row mt-3 ">
<TextField
className={classes.margin}
id="password"
......@@ -83,8 +82,8 @@ class Login extends Component {
onChange={this.handleChange}
/>
</div>
<br></br>
<div>
<div className="row mt-3 ">
<Button
variant="contained"
color="primary"
......@@ -112,8 +111,10 @@ class Login extends Component {
this.props.history.push("/BeauticianShopPage");
}
}
alert("เข้าสู่ระบบสำเร็จ");
})
.catch(error => {
alert("email หรือ password ไม่ถูกต้อง");
console.log(error);
});
// alert("ลงทะเบียนสำเร็จ");
......@@ -124,12 +125,8 @@ class Login extends Component {
</div>
<br />
<br />
<div className="row center">
<h4>
คุณลืมรหัสผ่าน ? <Link href="/">Forgot Password</Link>
</h4>
</div>
<div className="row center">
<div className="row center mt-5">
<h4>
คุณยังไม่ลงทะเบียน ? <Link href="/RegisterPage">ลงทะเบียน</Link>
</h4>
......
......@@ -64,7 +64,7 @@ class RegisterPage extends Component {
id="name"
name="name"
value={name}
label="ชื่อ-สกุล"
label="ชื่อ-สกุล*"
variant="outlined"
InputProps={{
startAdornment: (
......@@ -81,7 +81,7 @@ class RegisterPage extends Component {
id="email"
name="email"
value={email}
label="E_mail"
label="E_mail*"
variant="outlined"
InputProps={{
startAdornment: (
......@@ -100,7 +100,7 @@ class RegisterPage extends Component {
id="password"
name="password"
value={password}
label="Password"
label="Password*"
type="password"
autoComplete="current-password"
variant="outlined"
......@@ -119,7 +119,7 @@ class RegisterPage extends Component {
id="password2"
name="password2"
value={password2}
label="Confirm-Password"
label="Confirm-Password*"
type="password"
autoComplete="current-password"
variant="outlined"
......
......@@ -50,7 +50,7 @@ class RegisterShopPage extends Component {
id="name"
name="name"
value={name}
label="ชื่อ-สกุล"
label="ชื่อ-สกุล*"
variant="outlined"
InputProps={{
startAdornment: (
......@@ -67,7 +67,7 @@ class RegisterShopPage extends Component {
id="email"
name="email"
value={email}
label="E_mail"
label="E_mail*"
variant="outlined"
InputProps={{
startAdornment: (
......@@ -86,7 +86,7 @@ class RegisterShopPage extends Component {
id="password"
name="password"
value={password}
label="Password"
label="Password*"
type="password"
autoComplete="current-password"
variant="outlined"
......@@ -105,7 +105,7 @@ class RegisterShopPage extends Component {
id="password2"
name="password2"
value={password2}
label="Confirm-Password"
label="Confirm-Password*"
type="password"
autoComplete="current-password"
variant="outlined"
......
......@@ -21,7 +21,7 @@ import {
DialogTitle,
InputAdornment,
TextField,
InputBase
InputBase,
} from "@material-ui/core";
import GoogleMapReact from "google-map-react";
import Marker from "./marker";
......@@ -39,7 +39,7 @@ import MaterialTable from "material-table";
import moment from "moment";
import "moment/locale/th";
const styles = theme => ({
const styles = (theme) => ({
root: {
minWidth: 275,
height: 150,
......@@ -48,169 +48,169 @@ const styles = theme => ({
// The position fixed scoping doesn't work in IE 11.
// Disable this demo to preserve the others.
"@media all and (-ms-high-contrast: none)": {
display: "none"
}
display: "none",
},
},
bullet: {
display: "inline-block",
margin: "0 2px",
transform: "scale(0.8)"
transform: "scale(0.8)",
},
title: {
fontSize: 14
fontSize: 14,
},
pos: {
marginBottom: 12
marginBottom: 12,
},
modal: {
display: "flex",
padding: theme.spacing(1),
alignItems: "center",
justifyContent: "center"
justifyContent: "center",
},
fab: {
position: "absolute",
bottom: theme.spacing(2),
right: theme.spacing(2)
}
right: theme.spacing(2),
},
});
const currencieslist = [
{
value: "1",
label: " กรุณาเลือกรายการ "
label: " กรุณาเลือกรายการ ",
},
{
value: "2",
label: "อบไอน้ำ 30 นาที"
label: "อบไอน้ำ 30 นาที",
},
{
value: "3",
label: "นวดหน้า 60 นาที "
label: "นวดหน้า 60 นาที ",
},
{
value: "4",
label: "สระได 20 นาที"
label: "สระได 20 นาที",
},
{
value: "5",
label: "ทำเล็บ 60 นาที"
label: "ทำเล็บ 60 นาที",
},
{
value: "6",
label: "ยืดผมถาวร 120 นาที"
label: "ยืดผมถาวร 120 นาที",
},
{
value: "7",
label: "ทำสีผม 60 นาที"
}
label: "ทำสีผม 60 นาที",
},
];
const currencies = [
{
value: "1",
label: " กรุณาเลือกช่าง "
label: " กรุณาเลือกช่าง ",
},
{
value: "2",
label: "ช่าง ก"
label: "ช่าง ก",
},
{
value: "3",
label: "ช่าง ข"
label: "ช่าง ข",
},
{
value: "4",
label: "ช่าง ค"
label: "ช่าง ค",
},
{
value: "5",
label: "ช่าง ง"
label: "ช่าง ง",
},
{
value: "6",
label: "ช่าง จ"
label: "ช่าง จ",
},
{
value: "7",
label: "ช่าง"
}
label: "ช่าง",
},
];
const currenciesreview = [
{
value: "1",
label: " กรุณาเลือกหัวข้อการรีวิว "
label: " กรุณาเลือกหัวข้อการรีวิว ",
},
{
value: "2",
label: "รีวิวช่าง"
value: "รีวิวช่าง",
label: "รีวิวช่าง",
},
{
value: "3",
label: "รีวิวร้าน"
value: "รีวิวร้าน",
label: "รีวิวร้าน",
},
{
value: "4",
label: "การให้บริการ"
value: "การให้บริการ",
label: "การให้บริการ",
},
{
value: "5",
label: "การต้อนรับ"
value: "การต้อนรับ",
label: "การต้อนรับ",
},
{
value: "6",
label: "บรรยากาศ"
value: "บรรยากาศ",
label: "บรรยากาศ",
},
{
value: "7",
label: "อื่นๆ"
}
value: "อื่นๆ",
label: "อื่นๆ",
},
];
const currenciespoint = [
{
value: "1",
label: " กรุณาเลือกคะแนน "
value: "0",
label: " กรุณาเลือกคะแนน ",
},
{
value: "2",
label: "0.5"
value: "0.5",
label: "0.5",
},
{
value: "3",
label: "1"
value: "1",
label: "1",
},
{
value: "4",
label: "1.5"
value: "1.5",
label: "1.5",
},
{
value: "5",
label: "2"
value: "2",
label: "2",
},
{
value: "6",
label: "2.5"
value: "2.5",
label: "2.5",
},
{
value: "7",
label: "3"
value: "3",
label: "3",
},
{
value: "8",
label: "3.5"
value: "3.5",
label: "3.5",
},
{
value: "9",
label: "4"
value: "4",
label: "4",
},
{
value: "10",
label: "4.5"
value: "4.5",
label: "4.5",
},
{
value: "11",
label: "5"
}
value: "5",
label: "5",
},
];
class ShopPage extends Component {
state = {
......@@ -220,89 +220,92 @@ class ShopPage extends Component {
// open: true,
open: false,
shop: null,
reviwe: {
topic: "",
nameeng: "",
point: ""
review: {
topic: null,
message: null,
point: null,
},
columns: [{ title: "เวลา", field: "time" }],
columnslist: [
{ title: "ชื่อรายการ", field: "name" },
{ title: "ราคา", field: "price" },
{ title: "เวลาที่จอง", field: "time" }
{ title: "เวลาที่จอง", field: "time" },
],
data: [],
selectedRow: null,
datalist: []
datalist: [],
};
handleClickOpenreview = () => {
this.setState({
reviweOpen: true
reviweOpen: true,
});
};
handleClosereview = () => {
this.setState({
reviweOpen: false
reviweOpen: false,
});
};
handleClickOpenQ = () => {
this.setState({
open: true
open: true,
});
};
handleCloseQ = () => {
this.setState({
open: false
open: false,
});
};
handleSaveQ = () => {
this.setState({
open: false
open: false,
});
};
ClickOpen = () => {
this.setState({
list: true
list: true,
});
};
Close = () => {
this.setState({
list: false
list: false,
});
};
handleChange = event => {
let { shop } = this.state;
handleChange = (event) => {
let { review } = this.state;
console.log("name : ", event.target.name);
console.log("value : ", event.target.value);
shop[event.target.name] = event.target.value;
review[event.target.name] = event.target.value;
this.setState({
shop
review,
});
};
handleChangeDate = newDate => {
handleChangeDate = (newDate) => {
console.log("newDate: ", newDate);
this.setState({
date: newDate
date: newDate,
});
};
componentDidMount = async () => {
const { location } = this.props;
const { location, userInfo } = this.props;
const id = location.state.id;
const response = await axios.get(
const response1 = await axios.get(
`http://localhost:9000/api/shop/getShopId/${id}`
// `http://localhost:9000/api/list//getListshop/${id}`
);
console.log("response", response.data);
let { timeopen, timeclose } = response.data;
const response2 = await axios.get(
`http://localhost:9000/api/list/getListshop/${id}`
);
console.log("response", response1.data);
console.log("response", response2.data);
let { timeopen, timeclose } = response1.data;
timeopen = timeopen.split(":");
timeclose = timeclose.split(":");
let dateClose = new Date();
......@@ -310,21 +313,13 @@ class ShopPage extends Component {
dateClose.setMinutes(parseInt(timeclose[1]));
const result = this.calculate(moment(dateClose), timeopen);
// console.log("response.data", response.data);
// if (response.data) {
// this.setState({
// datalist: response.data
// });
// } else {
// console.log("cannot get shop data");
// }
this.setState({
shop: response.data,
data: result
shop: response1.data,
data: result,
datalist: response2.data
});
// console.log(this.state.shop);
};
calculate = (endTime, timeopen) => {
......@@ -339,7 +334,7 @@ class ShopPage extends Component {
while (startTime < endTime) {
timeStops.push({
time: new moment(startTime).format("LT")
time: new moment(startTime).format("LT"),
});
startTime.add("m", 15);
}
......@@ -348,11 +343,11 @@ class ShopPage extends Component {
};
render() {
const { classes } = this.props;
const { classes, userInfo } = this.props;
const bull = <span className={classes.bullet}></span>;
const {
shop,
reviwe,
review,
reviweOpen,
list,
date,
......@@ -361,7 +356,7 @@ class ShopPage extends Component {
data,
datalist,
selectedRow,
columnslist
columnslist,
} = this.state;
return (
......@@ -379,7 +374,7 @@ class ShopPage extends Component {
{shop.address}
</div>
</div>
<div className="row mt-4 mb-2">
<div c>
<div className="col s12 m6 l8">
<div className="row center">
<img
......@@ -413,7 +408,7 @@ class ShopPage extends Component {
columns={columnslist}
data={datalist}
options={{
selection: false
selection: false,
}}
/>
</div>
......@@ -449,7 +444,7 @@ class ShopPage extends Component {
<div className="col s12 m5">
<div
style={{
maxWidth: "fit-content"
maxWidth: "fit-content",
}}
>
<DatePicker
......@@ -467,7 +462,7 @@ class ShopPage extends Component {
<Typography>
วันที่ที่เลือกคือ{" "}
{format(new Date(date), "dd MMMM yyyy", {
locale: th
locale: th,
})}
</Typography>
<div className="mt-2">
......@@ -479,10 +474,10 @@ class ShopPage extends Component {
id="list"
name="list"
select
label="เลือกรายการ"
label="เลือกรายการ*"
onChange={this.handleChange}
SelectProps={{
native: true
native: true,
}}
variant="outlined"
InputProps={{
......@@ -490,15 +485,15 @@ class ShopPage extends Component {
<InputAdornment position="start">
<ListIcon />
</InputAdornment>
)
),
}}
>
{currencieslist.map(option => (
{datalist.map((datalist) => (
<option
key={option.value}
value={option.value}
key={datalist.id}
value={datalist.id}
>
{option.label}
{datalist.name}
</option>
))}
</TextField>
......@@ -509,10 +504,10 @@ class ShopPage extends Component {
id="list"
name="list"
select
label="เลือกช่าง"
label="เลือกช่าง*"
onChange={this.handleChange}
SelectProps={{
native: true
native: true,
}}
variant="outlined"
InputProps={{
......@@ -520,10 +515,10 @@ class ShopPage extends Component {
<InputAdornment position="start">
<AssignmentIndIcon />
</InputAdornment>
)
),
}}
>
{currencies.map(option => (
{currencies.map((option) => (
<option
key={option.value}
value={option.value}
......@@ -547,14 +542,14 @@ class ShopPage extends Component {
search: false,
showTitle: false,
toolbar: false,
rowStyle: rowData => ({
rowStyle: (rowData) => ({
backgroundColor:
this.state.selectedRow &&
this.state.selectedRow.tableData.id ===
rowData.tableData.id
? "#EEE"
: "#FFF"
})
: "#FFF",
}),
}}
/>
</div>
......@@ -589,11 +584,11 @@ class ShopPage extends Component {
<div style={{ height: "50vh", width: "100%" }}>
<GoogleMapReact
bootstrapURLKeys={{
key: "AIzaSyBJWuQmrf6UgrkGbMJF6-m1GwTZrazBFBo"
key: "AIzaSyBJWuQmrf6UgrkGbMJF6-m1GwTZrazBFBo",
}}
defaultCenter={{
lat: shop.lat * 1,
lng: shop.lng * 1
lng: shop.lng * 1,
}}
defaultZoom={16}
>
......@@ -619,44 +614,20 @@ class ShopPage extends Component {
</div>
<div className="row mt-2 mb-2">
<div className="col s12 m6 l7">
<div className="col s12 m5 l7">
<div className="row center">
<h4>ผลงานช่าง ปิยพร อาภรศรี</h4>
<div className="col s12 m6 l4">
<div className="col s12 m12 l6 mb-5">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcSAaEt_unwBuDLyqCP_bW3PBawVHkjZrNq-F3u7mAKtSjmBTrHE"></img>
</div>
<div className="col s12 m6 l4">
<div className="col s12 m12 l6 mb-5">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcSAaEt_unwBuDLyqCP_bW3PBawVHkjZrNq-F3u7mAKtSjmBTrHE"></img>
</div>
</div>
</div>
<div className="col s12 m6 l1"></div>
<div className="col s12 m1 l1"></div>
<div className="col s12 m6 l4">
<div className="row">
<center></center>
</div>
<div className="row">
<Card className={classes.root} variant="outlined">
<CardContent>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
<h3>โปรโมชั่น</h3>
</Typography>
<Typography variant="body2" component="p">
<h4> จองคิวผ่าน B Beauty ลด 5 %</h4>
{'"12/02/2020 18:00"'}
</Typography>
</CardContent>
{/* <CardActions>
<Button size="small">Learn More</Button>
</CardActions> */}
</Card>
</div>
<div className="row">
<Card className={classes.root} variant="outlined">
<CardHeader
......@@ -723,16 +694,17 @@ class ShopPage extends Component {
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-slide-description">
<div className={classes.root}>
<div className="row mt-4 mb-2">
<TextField
className={classes.margin}
id="topic"
name="topic"
value={review.topic}
select
label="หัวข้อรีวิว"
onChange={this.handleChange}
SelectProps={{
native: true
native: true,
}}
variant="outlined"
InputProps={{
......@@ -740,25 +712,45 @@ class ShopPage extends Component {
<InputAdornment position="start">
<ListIcon />
</InputAdornment>
)
),
}}
>
{currenciesreview.map(option => (
{currenciesreview.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</TextField>
<br /> <br />
</div>
<div className="row mt-4 mb-2">
<TextField
className={classes.margin}
id="message"
name="message"
value={review.message}
label="ข้อความรีวิว"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
{/* <AccountCircle /> */}
</InputAdornment>
),
}}
onChange={this.handleChange}
/>
</div>
<div className="row mt-4 mb-2">
<TextField
className={classes.margin}
id="point"
name="point"
value={review.point}
select
label="คะแนน"
onChange={this.handleChange}
SelectProps={{
native: true
native: true,
}}
variant="outlined"
InputProps={{
......@@ -766,40 +758,52 @@ class ShopPage extends Component {
<InputAdornment position="start">
<ListIcon />
</InputAdornment>
)
),
}}
>
{currenciespoint.map(option => (
{currenciespoint.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</TextField>
<br /> <br />
<TextField
className={classes.margin}
id="messagee"
name="messagee"
// value={shop.name}
label="ข้อความรีวิว"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
{/* <AccountCircle /> */}
</InputAdornment>
)
}}
onChange={this.handleChange}
/>
</div>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClickOpenreview} color="primary">
<Button
onClick={this.handleCloserevie}
color="primary"
>
ยกเลิก
</Button>
<Button onClick={this.handleClickOpenreview} color="primary">
<Button
onClick={() => {
if(userInfo.id){
axios
.post("http://localhost:9000/api/review/add", {
...review,
shop: shop.id,
userID: userInfo.id,
})
.then((response) => {
console.log("เขียนรีวิวสำเร็จ", response);
alert("เขียนรีวิวสำเร็จ");
})
.catch((error) => {
console.log(error);
alert("คุณยังไม่ได้ทำการ login ");
this.props.history.push("/LoginPage");
});
}
else{
alert("คุณยังไม่ได้ทำการ login ");
this.props.history.push("/LoginPage");
}
}}
color="primary"
>
ยันยัน
</Button>
</DialogActions>
......@@ -814,11 +818,11 @@ class ShopPage extends Component {
}
}
const mapStateToProps = state => ({
userInfo: state.user
const mapStateToProps = (state) => ({
userInfo: state.user,
});
const mapDispatchToProps = dispatch => {};
const mapDispatchToProps = (dispatch) => {};
export default connect(
mapStateToProps,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment