\newcommand{\thcodedouble}[1] {\color{red}{\textquotedbl{#1}\textquotedbl}}
\newcommand{\thcodesingle}[1] {\color{red}{\textquotesingle{#1}\textquotesingle}}

\newcommand{\thcodesingleleft}[1] {\color{red}{\textquotesingle{#1}}}
\newcommand{\thcodesingleright}[1] {\color{red}{{#1}\textquotesingle}}


\chapter{การพัฒนาระบบ}
ในบทนี้จะกล่าวถึงการสร้างระบบงานของระบบแนะนำสถานที่ท่องเที่ยวในจังหวัดอุบลราชธานี โดยนำผลที่ได้จากการวิเคราะห์และออกแบบระบบมาสร้างเป็นระบบงานซึ่งจะอธิบายถึงตัวอย่างการเขียน โปรแกรมการทำงานของระบบในส่วนต่างๆดังต่อไปนี้

\section{การพัฒนาในส่วนสมัครสมาชิก}
เมื่อผู้ใช้กรอกข้อมูลการสมัครเสร็จแล้วทำการกดปุ่มสมัครสมาชิก ระบบจะมีการทำงาน แสดงดังรูปที่ \ref{Fig:4-Register} - \ref{Fig:4-Register1}
\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript} //เปลี่ยนเป็นภาษาที่เขียน
  saveRegister() {
if (this.typeGender == "Male") { 
    this.selectGender = |\thcodedouble{ชาย}|;
}
else if (this.typeGender == "Female") { 
    this.selectGender = |\thcodedouble{หญิง}|;
}
this.data = {
  content: {
    profileIds: ["Ubontrip"],
      bookmarks: "[]",
      reviews: "[]",
      places: "[]",
      username: this.username,
      fulluser: this.fulluser,
      gender: this.selectGender,
      imageSrc: this.imageSrc
  },
  credentials: {
    local: {
      username: this.username,
      password: this.password
    }
 }
}
}
\end{minted}
\caption{การทำงานของระบบเมื่อกดปุ่มสมัครสมาชิก}
\label{Fig:4-Register}
\end{figure}
\newpage

จากภาพที่ \ref{Fig:4-Register} โครงสร้างของไฟล์ register.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 ฟังก์ชัน saveRegister() เป็นฟังก์ชันที่ใช้ควบคุมการทำงานในการสมัครสมาชิก
\item บรรทัดที่ 2 - 7 เป็นการกำหนดค่าข้อมูลเพศเมื่อผู้ใช้กรอกเข้ามาจะเช็คดูว่า value ที่ผู้ใช้เลือกเป็น Male หรือ Female
\item บรรทัดที่ 8 เก็บข้อมูลไว้ที่ data โดยรูปแบบที่เก็บจะต้องตรงกับรูปแบบที่อยู่ในฐานข้อมูล
\item บรรทัดที่ 9 content จะใช้เก็บข้อมูลทั่วไปที่เราต้องการจะบันทึก
\item บรรทัดที่ 10 เป็นการกำหนด roles ให้กับผู้ใช้
\item บรรทัดที่ 11 - 17 เป็นข้อมูลพื้นฐานที่จะใช้เก็บประวัติของผู้ใช้ bookmarks เก็บข้อมูลการบันทึกสถานที่ reviews เก็บข้อมูลการเขียนรีวิว places เก็บข้อมูลการเพิ่มสถานที่
\item บรรทัดที่ 19 - 24 เป็นการกำหนดให้ใช้ข้อมูล 2 อย่างนี้ในการเข้าสู่ระบบ คือ username และ password
\end{itemize}

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript} //เปลี่ยนเป็นภาษาที่เขียน
if (this.password === this.confirm) {
  this.http.post('${KUZZLE}:${KPORT}/users/${this.username}/_create',
  this.data)
  alert (|\thcodedouble{ลงทะเบียนสำเร็จ}|);
this.router.navigate(['/popular}']);
}else{ 
alert (|\thcodedouble{รหัสผ่านและยืนยันรหัสผ่านไม่ตรงกันกรุณากรอกรหัสผ่านใหม่อีกครั้ง}|);
}
\end{minted}
\caption{การทำงานของระบบเมื่อกดปุ่มสมัครสมาชิก (ต่อ)}
\label{Fig:4-Register1}
\end{figure}

จากภาพที่ \ref{Fig:4-Register1} โครงสร้างของไฟล์ register.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 - 3 เป็นการเช็คการกรอกข้อมูลรหัสผ่านและรหัสยืนยันว่าตรงกันไหมถ้าตรงกันระบบจะทำการสร้าง user เข้าไปในระบบฐานข้อมูล
\newpage
\item บรรทัดที่ 4 - 5 เมื่อสร้าง user สำเร็จจะแสดงข้อมความแจ้งผู้ใช้ว่า "ลงทะเบียนสำเร็จ" และทำการ router ไปยังหน้า popular
\item บรรทัดที่ 6 - 8 เป็นการเช็คเงื่อนไงในกรณีที่รหัสผ่านไม่ตรงกัน จะแสดงข้อความแจ้งผู้ใช้ว่า "รหัสผ่านและยืนยันรหัสผ่านไม่ตรงกัน กรุณากรอกรหัสผ่านใหม่อีกครั้ง" 
\end{itemize}

\section{การพัฒนาในส่วนการเข้าสู่ระบบ}
เมื่อผู้ใช้กรอกข้อมูลทั้งหมดเสร็จทำการกดปุ่มเข้าสู่ระบบ ระบบจะมีการทำงาน แสดงดังรูปที่ \ref{Fig:4-login}

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
Login(): void {
this.http.post(`${KUZZLE}:${KPORT}/_login/local?expiresIn=1y`,{
  username: this.username,
  password: this.password
})
.subscribe((res: any) => {
  localStorage.setItem('JWT', res.result.jwt);
  this.http.get(`${KUZZLE}:${KPORT}/users/_me`, {
    headers: {
      Authorization: "Bearer" + localStorage.getItem('JWT')
    }
  }).subscribe((_res: any) => {
  if (_res.status === 200) {
  localStorage.setItem("UserInfo", JSON.stringify(_res.result._source))
    this.loginService.isAuth({
        isAuth: true,
        data: _res.result 
      })
    this.dialogRef.close();
    }
  })
})
}
\end{minted}
\caption{การทำงานของระบบเมื่อกดเข้าสู่ระบบ}
\label{Fig:4-login}
\end{figure}
\newpage
จากภาพที่ \ref{Fig:4-login} โครงสร้างของไฟล์ dialoglogin.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1เมื่อผู้ใช้กดเข้าสู่ระบบจะเข้ามาทำงานในฟังก์ชัน Login()
\item บรรทัดที่ 2- 5 เป็นการยิงข้อมูล username และ password ที่ผู้ใช้กรอกเข้ามาเพื่อนำไปเช็คกับข้อมูลที่อยู่ในฐานข้อมูล
\item บรรทัดที่ 7 เป็นการสร้างตัวแปร JWT ขึ้นมาเก็บค่าของ token ไว้ใน localStorage
\item บรรทัดที่ 10 เป็นการอ่านค่าตัวแปร JWT 
\item บรรทัดที่ 13 เป็นการเช็คเงื่อนไขสเตตัสในการเข้าสู่ระบบ
\item บรรทัดที่ 14 ถ้าสเตตัสที่ล็อคอินเข้าสู่ระบบเป็น 200 จะสร้าง UserInfo ขึ้นมาเก็บค่าข้อมูลไว้ใน localStorage
\item บรรทัดที่ 15 - 18 เรียกใช้ service isAuth เพื่อเก็บค่าข้อมูลผู้ใช้ โดยข้อมูลจะถูกเก็บไว้ในตัวแปร data
\item บรรทัดที่ 19 เป็นการปิดหน้าการเข้าสู่ระบบลง
\end{itemize}
\newpage

\section{การพัฒนาในส่วนการจัดอันดับสถานที่}
เมื่อผู้ใช้กดเลือกหมวดเพื่อดูการจัดอับดับ ระบบจะมีการทำงาน แสดงดังรูปที่ \ref{Fig:4-pupular} - \ref{Fig:4-pupular1}
\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
selectGroup(event: any) {
this.select = event.value;
switch (this.select) {
  case "travel":
    this.results_populartravel = []
      const list_allTravel = [
        {
          type : "travelwaterfall",
          review : "review_waterfall"
        },{
          type : "travelwaterpark",
          review : "review_waterpark"
        },{
          type : "traveltemple",
          review : "review_temple"
        },{
          type : "travelnational",
          review : "review_national"
        },{
          type : "travelshop",
          review : "review_shop"
        },{
          type : "travelbar",
          review : "review_bar"
        }]
      list_allTravel.map(travels => {
        const query = {
          query: {
          }, size: 100
        }
this.http.post(`${KUZZLE}:${KPORT}/${KINDEX}/${travels.type}/_search`,query)
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดเลือกหมวด}
\label{Fig:4-pupular}
\end{figure}
\newpage

จากภาพที่ \ref{Fig:4-pupular} โครงสร้างของไฟล์ popular.component.ts อธิบายการทำงานได้ดังนี้ 
  โดยผู้พัฒนาจะของยกตัวอย่างการทำงานแค่ของหมวดสถานที่ท่องเที่ยว(case:travel) เนื่องจากว่าทั้ง 3 case มีการทำงานเหมือนกันได้แก่ case: "travel" case:"eat" case: "hotel"
\begin{itemize}[label={--}]
\item บรรทัดที่ 1เมื่อผู้ใช้กดเลือกหมวดสถานที่จะเข้ามาทำงานในฟังก์ชัน selectGroup()โดยรับค่าพารามิเตอร์มา1ตัว
\item บรรทัดที่ 2 เป็นการเช็ดค่าที่ผู้ใช้กดเลือกมาเก็บไว้ในตัวแปร select
\item บรรทัดที่ 3 เป็นการเขียน switch case เช็คค่าที่ผู้ใช้เลือก โดยจะมีด้วยกันทั้งหมด 3 case ได้แก case:"travel" , case:"eat", case:"hotel"
\item บรรทัดที่ 4 ถ้าผู้ใช้เลือกหมวดท่องเที่ยวก็จะเข้ามาทำงานใน case:"travel" แต่ถ้าผู้ใช่ไม่ได้เลือกหมวดท่องเที่ยวก็จะไปทำงานใน case อื่นที่ไม่ใช้ travel
\item บรรทัดที่ 6 - 25 เป็นการประกาศค่าเพื่อเก็บข้อมูลในรูปแบบ Object โดย type เก็บประเภทของสถานที่ และ review เก็บประเภทของรีวิว
\item บรรทัดที่ 26 นำข้อมูลที่ถูกเก็บไว้ใน listallTravel มาทำการ map เพื่อดูข้อมูลทั้งหมด
\item บรรทัดที่ 27 - 30 เป็นการกำหนดจำนวนของข้อมูลที่ต้องการค้นหาออกมาแสดง
\item บรรทัดที่ 31 เป็นการ query หาข้อมูลในฐานข้อมูลตามประเภทสถานที่ที่ผู้ใช้เลือก โดยใช้รูปแบบ method POST ในการค้นหา
\end{itemize}
\newpage

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
.subscribe((_res: any) => {
_res.result.hits.map(_travel => {
let total_place = 0; let avg = 0;
this.http.get(`${KUZZLE}:${KPORT}/${KINDEX}/${travels.review}/
${_travel._id}`)
.subscribe((res: any) => {
  res.result._source.review.map(_item => {
  total_place += _item.score
  })
  avg = total_place / res.result._source.review.length
  this.results_populartravel.push({
    ..._travel, avg,
    review: travels.review
  })
  this.results_populartravel.sort(
  (a, b) => (a.avg > b.avg) ? 1 : ((b.avg > a.avg) ? -1 : 0)
  ).reverse()
}, err => {
  this.results_populartravel.push({
    ..._travel, avg: 0,
    review: travels.review
  })
  this.results_populartravel.sort(
  (a, b) => (a.avg > b.avg) ? 1 : ((b.avg > a.avg) ? -1 : 0)
  ).reverse()
})
})
})
break;
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดเลือกหมวด (ต่อ)}
\label{Fig:4-pupular1}
\end{figure}
\newpage

จากภาพที่ \ref{Fig:4-pupular1} โครงสร้างของไฟล์ popular.component.ts อธิบายการทำงานได้ดังนี้(ต่อ)
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 เป็นการ subscribe เพื่อดูข้อมูลข้างในที่ได้จากการ query ข้อมูล
\item บรรทัดที่ 2 เป็นการจิ้มข้อมูลเข้าไปชั้นข้างในเพื่อให้ได้ข้อมูลที่ต้องการและทำการวนฟอดูข้อมูลข้างใน
\item บรรทัดที่ 3 เป็นการประกาศตัวแปรtotalPlace ใช้เก็บค่าผลรวม ส่วน avg ใช้เก็บค่าเฉลี่ยของการให้คะแนนสถานที่
\item บรรทัดที่ 4 - 7 เป็นการ ค้นหาข้อมูลจากฐานข้อมูล เมื่อได้ข้อมูลมาจะใช้ .subscribe ในการเข้าดูข้อมูลโดยจะประกาศ res ขึ้นมาเก็บค่าข้อมูลที่ได้ทำการค้นหาและทำการจิ้มข้อมูลใน res เข้าไปถึงส่วนของข้อมูลที่เราต้องการ
\item บรรทัดที่ 8 เป็นการนำค่าที่ได้ในการวนฟอในแต่ละรอบมาเก็บไว้ที่ totalplace
\item บรรทัดที่ 10 เป็นการคำนวณคะแนนเฉลี่ยในการรีวิวของแต่ละสถานที่และค่าที่จะนำมาเก็บไว้ในตัวแปร avg
\item บรรทัดที่ 11 - 13 เป็นการ push ค่าที่ได้ไปเก็บไว้ที่ resultspopulartravel 
\item บรรทัดที่ 15 - 17 เป็นการนำค่าที่ถูกเก็บไว้มาทำการจัดอันดับโดยจะเช็คว่า ค่าเฉลี่ยของตัวที่ 1 มีค่ามากกว่าตัวที่ 2 ถ้าใช่ก็ให้มีค่าเป็น 1 ถ้าค่าเฉลี่ยตัวที่ 2 มากกว่าตัวที่ 1 ก็ให้มีค่าเป็น -1 และทำการ reverse() ข้อมูลโดยจะเช็คไปแบบนี้จนครบถึงจะหยุดทำงาน
\item บรรทัดที่ 18 - 21 ถ้าข้อมูลสถานที่นั้นยังไม่มีรีวิว ก็จะทำการ push ข้อมูลสถานที่โดยจะกำหนดให้ค่าของ avg = 0
\item บรรทัดที่ 23 - 25 เป็นการนำค่าที่ถูกเก็บไว้มาทำการจัดอันดับโดยจะเช็คว่า ค่าเฉลี่ยของตัวที่ 1 มีค่ามากกว่าตัวที่ 2 ถ้าใช่ก็ให้มีค่าเป็น 1 ถ้าค่าเฉลี่ยตัวที่ 2 มากกว่าตัวที่ 1 ก็ให้มีค่าเป็น -1 และทำการ reverse() ข้อมูลโดยจะเช็คไปแบบนี้จนครบถึงจะหยุดทำงาน
\end{itemize}
\newpage

\section{การพัฒนาในส่วนของเขียนรีวิว}
เมื่อผู้ใช้กดปุ่มบันทึกรีวิว ระบบจะมีการทำงาน แสดงดังรูปที่ \ref{Fig:4-review} - \ref{Fig:4-review2}
\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
onClick(rating: number): void {
  this.rating = rating;
}
reviewPlace() {
const now = moment(moment().valueOf()).format("DD/MM/YYYY H:mm")
if (this.id_review === undefined) {
this.dataReview = {
review: [
{
  id: this.id_place,
  create_by: JSON.parse(localStorage.getItem("UserInfo")).username,
  imageUser: JSON.parse(localStorage.getItem("UserInfo")).imageSrc,
  title: this.title,
  description: this.description,
  image: this.imageReview,
  score: this.rating,
  timeReview: now
}]}
this.http.post(`${KUZZLE}:${KPORT}/${KINDEX}/${this.idReview}/
${this.id_place}/_create`,this.dataReview)
.subscribe((response) => {
})
this.reviews = [...this.reviews, {
  id: this.id_place,
  type: this.type_place,
  review: this.idReview
 }]
this.http.put(`${KUZZLE}:${KPORT}/users/${this.id_user}/_update`, {
reviews: JSON.stringify(this.reviews)
})
}
}
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มเขียนรีวิว}
\label{Fig:4-review}
\end{figure}
\newpage

จากภาพที่ \ref{Fig:4-review} โครงสร้างของไฟล์ dialog-review.component.ts อธิบายการทำงานได้ดังนี้(ต่อ)
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 - 3 ฟังก์ชัน onClick() เป็นฟังก์ชันของการให้คะแนนสถานที่ โดยจะเก็บคะแนนที่ผู้ใช้ให้ไว้ในต rating
\item บรรทัดที่ 4 ฟังก์ชัน reviewPlace() จะทำงานเมื่อผู้ใช้กดปุ่ม บันทุกรีวิว โดยจะทำการบันทึกข้อมูลรีวิว
\item บรรทัดที่ 5 เป็นการประกาศ now ขึ้นมาเก็บค่าของวันที่ในการเขียนรีวิว โดยจะมี format วันที่เป็น วัน/เดือน/ปี
\item บรรทัดที่ 6 เป็นเงื่อนไขในการเช็คว่า id ของรีวิวสถานที่นี้ว่า มีค่าเท่ากับ undefined หรือไม่ถ้าเท่าจะเข้ามาทำงานในเงื่อนไขนี้
\item บรรทัดที่ 7 - 8 เป็นการประกาศตัวแปรชื่อ dataReview มาเก็บข้อมูลการเขียนรีวิวโดยใน dataReview จะมีการเก็บเป็นอาเรย์ในตัวแปร review
\item บรรทัดที่ 10 เป็นการเก็บ id ของสถานที่รีวิวไว้ในตัวแปรชื่อ id 
\item บรรทัดที่ 11 เป็นการเก็บชื่อผู้ใช้ที่เขียนรีวิวโดยจะไปอ่านค่ามาจาก localStoragemใน filed ชื่อ username และเก็บไว้ในตัวแปรชื่อ createby
\item บรรทัดที่ 12 เป็นการเก็บรูปภาพของผู้ใช้ที่เขียนรีวิวโดยจะไปอ่านค่ามาจาก localStoragemใน filed ชื่อ imageSrc และเก็บไว้ในตัวแปรชื่อ imageUser
\item บรรทัดที่ 13 เป็นการเก็บหัวข้อของรีวิวไว้ในตัวแปรชื่อ title
\item บรรทัดที่ 14 เป็นการเก็บรายละเอียดของการเขียนรีวิวไว้ในตัวแปรชื่อ description
\item บรรทัดที่ 15 เป็นการเก็บรูปภาพรีวิวไว้ในตัวแปรชื่อ image
\item บรรทัดที่ 16 เป็นการเก็บค่าของคะแนนรีวิวไว้ในตัวแปร score
\item บรรทัดที่ 17 เป็นการเก็บเวลาของงการเขียนรีวิวไว้ในตัวแปรชื่อ timeReview
\item บรรทัดที่ 19 - 21 เป็นการทำงานโดยจะเอาข้อมูลที่ได้จากการเขียนรีวิวในตัวแปรชื่อ dataReview ไปทำการสร้าง document เพื่อเก็บข้อมูลรีวิวของสถานที่นั้นโดยใช้ method post ในการสร้าง หลังจากสร้างเสร็จจะ log ค่าออกมาดูเพื่อดูผลลัพธ์
\newpage
\item บรรทัดที่ 23 - 27 เป็นการประกาศตัวแปรชื่อ reviews มาเก็บประวัติของผู้ใช้ว่าเคยเขียนรีวิวสถานที่ไหนบ้าง โดยจะเก็บ id คือเก็บชื่อสถานที่ type คือประเภทสถานที่และ review คือประเภทของสถานที่ที่เขียนรีวิว
\item บรรทัดที่ 28 - 29 เป็นการนำข้อมูลที่อยู่ในก้อน reviews ไปทำการอัปเดทข้อมูลผู้ใช้ในส่วนของการเขียนรีวิว
\end{itemize}

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
else {
this.dataReview = {
review: [
...this.result_ReviewPlace,
{
  id : this.id_place,
  create_by: JSON.parse(localStorage.getItem("UserInfo")).username,
  imageUser: JSON.parse(localStorage.getItem("UserInfo")).imageSrc,
  title: this.title,
  description: this.description,
  image: this.imageReview,
  score: this.rating,
  timeReview: now
}
]
}
this.http.put(`${KUZZLE}:${KPORT}/${KINDEX}/${this.idReview}/
${this.id_place}/_update`,this.dataReview)
.subscribe((response) => {
console.log(response);
}, err => {
console.log({ ...err });
})
}
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มเขียนรีวิว(ต่อ)}
\label{Fig:4-review1}
\end{figure}
\newpage

จากภาพที่ \ref{Fig:4-review1} โครงสร้างของไฟล์ dialog-review.component.ts อธิบายการทำงานได้ดังนี้(ต่อ)
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 เป็นเงื่อนไขเช็คว่าถ้า id ของสถานที่ไม่เท่ากับ undefined ก็จะเข้ามาทำงานในส่วนนี้
\item บรรทัดที่ 2 - 3 เป็นการประกาศตัวแปรชื่อ dataReview มาเก็บข้อมูลการเขียนรีวิวโดยใน dataReview จะมีการเก็บเป็นอาเรย์ในตัวแปร review
\item บรรทัดที่ 4 เป็นนำค่ารีวิวเดิมเดิมที่มีอยู่ มาต่อกับรีวิวตัวใหม่
\item บรรทัดที่ 6 เป็นการเก็บ id ของสถานที่รีวิวไว้ในตัวแปรชื่อ id
\item บรรทัดที่ 7 เป็นการเก็บชื่อผู้ใช้ที่เขียนรีวิวโดยจะไปอ่านค่ามาจาก localStoragemใน filed ชื่อ username และเก็บไว้ในตัวแปรชื่อ createby
\item บรรทัดที่ 8 เป็นการเก็บรูปภาพของผู้ใช้ที่เขียนรีวิวโดยจะไปอ่านค่ามาจาก localStoragemใน filed ชื่อ imageSrc และเก็บไว้ในตัวแปรชื่อ imageUser
\item บรรทัดที่ 9 เป็นการเก็บหัวข้อของรีวิวไว้ในตัวแปรชื่อ title
\item บรรทัดที่ 10 เป็นการเก็บรายละเอียดของการเขียนรีวิวไว้ในตัวแปรชื่อ description
\item บรรทัดที่ 11 เป็นการเก็บรูปภาพรีวิวไว้ในตัวแปรชื่อ image
\item บรรทัดที่ 12 เป็นการเก็บค่าของคะแนนรีวิวไว้ในตัวแปร score
\item บรรทัดที่ 13 เป็นการเก็บเวลาของงการเขียนรีวิวไว้ในตัวแปรชื่อ timeReview
\item บรรทัดที่ 17 - 19 เป็นการทำงานโดยเอาข้อมูลที่ได้จาก dataReview ไปทำการอัปเดทข้อมูลการเขียนรีวิวของสถานที่นั้้นในฐานจข้อมูลโดยทำผ่าน method put และเมื่อทำสำเร็จจะแสดงข้อความบอกว่า เพิ่มคอมเม้นสำเร็จ ใน log
\item บรรทัดที่ 21 - 22 ถ้าทำงานล้มเหลวจะให้แสดง error
\end{itemize}
\newpage

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
const check = this.reviews.find(item => item.id == this.id_place) 
if (check) {
this.reviews.map((item, index) => {
  item.id === this.id_place ? this.reviews.splice(index, 1) : null 
})
this.reviews = [...this.reviews, {
  id: this.id_place,
  type: this.type_place,
  review: this.idReview
  }
]
this.http.put(`${KUZZLE}:${KPORT}/users/${this.id_user}/_update`,{
reviews: JSON.stringify(this.reviews)
})
.subscribe(res => {
console.log(res);
 }, err => {
console.log(err);
 })
}
onNoClick(): void {
this.dialogRef.close();
}
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มเขียนรีวิว(ต่อ)}
\label{Fig:4-review2}
\end{figure}
\newpage

จากภาพที่ \ref{Fig:4-review2} โครงสร้างของไฟล์ dialog-review.component.ts อธิบายการทำงานได้ดังนี้(ต่อ)
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 เป็นการประกาศ check ขึ้นมาเพื่อค้นหาข้อมูลการเขียนรีวิวทั้งหมดที่มีอยู่โดยใช้ item เป็นรับข้อมูลเข้าไปค้าหาต่อ
\item บรรทัดที่ 2 - 3 เป็นการเช็คเงื่อนไขว่าถ้าเช็ค เมื่อได้ข้อมูล reviews ก็จะทำการวนฟอเพื่อดูข้อมูล
\item บรรทัดที่ 4 - 5 เมื่อมันผ่านเงื่อนไขก็จะเข้ามาเช็คดูอีดครั้งว่าค่าของ id มีค่าเท่ากับ idplaceห ไหม ถ้าตรงกันก็จะให้รีวิวที่มีอยู่ออกไปแต่ถ้าไม่ใช้ก็จะให้ค่าตัวนั้นมี่ค่าเป็น null
\item บรรทัดที่ 6 - 11 เป็นการประกาศตัวแปรชื่อ review ขึ้นมาเพื่อเก็บประวัติข้อมูลการเขียนรีวิวของผูัใช้
\item บรรทัดที่ 12 - 14 นำข้อมูลที่ได้จาก reviews ไปทำการอัพเดทข้อมูลของผูัใช้
\item บรรทัดที่ 15 - 19 เป็นการ log ดูค่าเมื่ออัพเดทสำเร็จก็ และเมื่ออัปเดทไม่สำเร็จจะแสดง error
\item บรรทัดที่ 21 - 23 ฟังก์ชัน onNoClick เมื่อผู้ใช่ไม่ต้องทีจะเขียนเรีวิว ระบบก็จะปิดหน้าเขียนรีวิวลง
\end{itemize}
\newpage

\section{การพัฒนาในส่วนของการเพิ่มสถานที่}
เมื่อผู้ใช้กดปุ่มเพิ่มสถานที่ ระบบจะมีการทำงาน แสดงดังรูปที่ \ref{Fig:4-addplace} - \ref{Fig:4-addplace2}
\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
onFileSelected(e) {
var file = e.dataTransfer ? e.dataTransfer.files[0] : e.target.files[0];
var pattern = /image-*/;
var reader = new FileReader();
if (!file.type.match(pattern)) {
  alert('invalid format');
  return;
}
reader.onload = this._handleReaderLoaded.bind(this);
reader.readAsDataURL(file);
}
_handleReaderLoaded(e) {
  let reader = e.target;
  this.imageSrc = reader.result;
}
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มเพิ่มสถานที่}
\label{Fig:4-addplace}
\end{figure}

จากภาพที่ \ref{Fig:4-addplace} โครงสร้างของไฟล์ dialog-add.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 - 15 เป็นฟังก์ชันการการอัพโหลดรูปภาพแนวนำรูปภาพที่อัพโหลดมาแปลงเป็น base64 เพื่อที่จะไปเก็บไว้ใในฐานข้อมูล 
\end{itemize}
\newpage

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
addPlace() {
var selectplace = ''
if(this.typeplace == "hotelvilla"){
selectplace = |\thcodedouble{วิลล่า}|; } 
else if(this.typeplace == "hotelhostel"){
selectplace = |\thcodedouble{โรงแรม}|;}
else if(this.typeplace == "hotelresort"){
selectplace = |\thcodedouble{รีสอร์ท}|;} 
else if(this.typeplace == "hoteltent"){
selectplace = |\thcodedouble{กางเต้นท์}|;} 
else if(this.typeplace == "hotelgateshouse"){
selectplace = |\thcodedouble{บังกะโล/เกสท์เฮาส์}|;} 
else if(this.typeplace == "hotelhomestay"){
selectplace = |\thcodedouble{โฮมสเตย์}|;} 
else if(this.typeplace == "travelwaterfall"){
selectplace = |\thcodedouble{น้ำตก}|;} 
else if(this.typeplace == "travelwaterpark"){
selectplace = |\thcodedouble{สวนน้ำ/สวนสัตว์}|;} 
else if(this.typeplace == "traveltemple"){
selectplace = |\thcodedouble{สถานที่ทางศาสนา}|;} 
else if(this.typeplace == "travelnational"){
selectplace = |\thcodedouble{อุทยานและธรรมชาติ}|;}
else if(this.typeplace == "travelshop"){
selectplace = |\thcodedouble{ถนนคนเดิน}|;} 
else if(this.typeplace == "travelbar"){
selectplace = |\thcodedouble{สถานบันเทิง}|;} 
else if(this.typeplace == "eatgrill"){
selectplace = |\thcodedouble{บุฟเฟ่ต์/ปิ้งย่าง}|;} 
else if(this.typeplace == "eatdrinks"){
selectplace = |\thcodedouble{คาเฟ่}|;} 
else if(this.typeplace == "eatnoodle"){
selectplace = |\thcodedouble{เส้น}|;} 
else if(this.typeplace == "eatesan"){
selectplace = |\thcodedouble{อาหารท้องถิ่น}|;} 
else if(this.typeplace == "eatjapan"){
selectplace = |\thcodedouble{อาหารญี่ปุ่น}|;} 
else if(this.typeplace == "eatsteak"){
selectplace = |\thcodedouble{สเต็ก}|;} 
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มเพิ่มสถานที่(ต่อ)}
\label{Fig:4-addplace1}
\end{figure}
\newpage

จากภาพที่ \ref{Fig:4-addplace1} โครงสร้างของไฟล์ dialog-add.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 ฟังก์ชัน addPlace() เป็นฟังก์ชันที่ใช้ทำการเพิ่มข้อมูลสถานที่จะทำงานก็ต่อเมื่อผู้ใช้กดปุ่มบันทึก
\item บรรทัดที่ 2 เป็นการประกาศตัวแปร selectplace ที่มี type เป็น string เพื่อที่จะใช้เก็บค่าประเภทของสถานที่ที่ผู้ใช้เลือก
\item บรรทัดที่ 3 - 38 เป็นการเช็คเงื่อนไขเมื่อผู้ใช้เลือกประเภทของสถานที่เพื่อที่จะกำหนดค่าให้กับ selectplace 
\end{itemize}

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
this.data = {
  "image": this.imageSrc,
  "namelocation": this.namelocation,
  "group": selectplace,
  "address": this.address,
  "cityprovince": this.cityprovince,
  "lat": this.lat,
  "lng": this.lng,
  "openclose": this.openclose,
  "phonenumber": this.phonenumber,
  "price": this.price,
  "description": this.description,
  "facebook": this.facebook,
  "website": this.website
};
this.http.post(`${KUZZLE}:${KPORT}/${KINDEX}/${this.typeplace}/_create`,
this.data)
.subscribe((res:any) =>{
const idname =res.result._id
this.places = [...this.places,{
  id: idname,
  type: this.typeplace,
  review: this._typeReview
}]
this.http.put(`${KUZZLE}:${KPORT}/users/${this.id_user}/_update`,{
places: JSON.stringify(this.places)
})
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มเพิ่มสถานที่(ต่อ)}
\label{Fig:4-addplace2}
\end{figure}
\newpage
จากภาพที่ \ref{Fig:4-addplace2} โครงสร้างของไฟล์ dialog-add.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 เป็นการประกาศตัวแปรชื่อ data โดยมี type เป็น object เพื่อที่จะมาเก็บค่าของรายละเอียดข้อมูลสถานที่ที่ผู้ใช้กรอกเข้ามา
\item บรรทัดที่ 2 เป็นการประกาศ image ขึ้นมาเก็บรูปภาพของสถานที่โดยมีรูปแบการเก็บเป็น base64
\item บรรทัดที่ 3 เป็นการประกาศ namelocation ขึ้นมาเพื่อที่จะเก็บชื่อสถานที่
\item บรรทัดที่ 4 เป็นการเก็บประเภทของสถานที่ที่ได้จากการเลือกของผู้ใช้ไว้ใน group 
\item บรรทัดที่ 5 เป็นการเก็บที่อยู่ของสถานที่ที่ได้จากการกรอกเข้ามาจากผู้ใช้ไว้ใน address
\item บรรทัดที่ 6 เป็นการเก็บชื่ออำเภอและจังหวัดที่ได้จากการข้อมูลเข้ามาจากผู้ใชเไว้ใน cityprovince
\item บรรทัดที่ 7 เป็นการเก็บค่าละติจูดที่ได้จากการกรอกข้อมูลเข้ามาจากผู้ใช้ไว้ใน lat
\item บรรทัดที่ 8 เป็นการเก็บค่าลองจิจูดที่ได้จากการกรอกข้อมูลเข้ามาจากผู้ใช้ไว้ใน lng
\item บรรทัดที่ 9 เป็นการเก็บข้อมูลเวลาเปิด ปิด ของสถานที่ที่ได้จากการกรอกเข้ามาจากผู้ใช้ไว้ใน openclose
\item บรรทัดที่ 10 เป็นการเก็บข้อมูลเบอร์โทรของสถานที่ที่ได้จากการกรอกเข้ามาจากผู้ใช้ไว้ใน phonenumber
\item บรรทัดที่ 11 เป็นการเก็บข้อมูลราคาของอาหาร ราคาเข้าชมสถานที่ ที่ได้จากกการกรอกเข้ามาจากผู้ใช้ไว้ใน price
\item บรรทัดที่ 12 เป็นการเก็บข้อมูลรายละเอียดของสถานที่ที่ได้จากการกรอกเข้ามาจากผู้ใช้ไว้ใน description
\item บรรทัดที่ 13 เป็นการเก็บชื่อ facebook ของสถานที่ทีได้จากการกรอกเข้ามาจากผู้ใช้ไว้ใน facebook
\item บรรทัดที่ 14 เป็นการเก็บชื่อ website ของสถานที่ที่ได้จากกการกรอกเข้ามาจากผู้ใช้ไว้ใน website
\item บรรทัดที่ 16 เป็น การนำข้อมูลสถานที่ที่ได้จาก data ไปทำการเพิ่มข้อมูลลงในฐานข้อมูลตามเป็นเภทที่ผู้ใช้เลือก
\newpage
\item บรรทัดที่ 18 เป็นการประกาศตัวแปรชื่อ idname เพื่อมาเก็บค่าของ id สถานที่
\item บรรทัดที่ 20 เป็นการเรียกใช้ places เพื่อที่จะนำมาเก็บค่าข้อมูล
\item บรรทัดที่ 21 เป็นการเก็บชื่อ id สถานที่ไว้ใน id
\item บรรทัดที่ 22 เป็นการเก็บประเภทของสถานที่ไว้ใน type
\item บรรทัดที่ 23 เป็นการเก็บประเภทของรีวิวสถานที่ไว้ใน review
\item บรรทัดที่ 25 - 27 เป็นการนำข้อมูลที่ได้จาก places มาทำการอัพเดทข้อมูลในส่วนของผู้ใช้เพื่อที่จะเก็บประวัติการเพิ่มสถานที่ของผู้ใช้ไว้และนำข้อมูลที่ได้ไปแสดงในหน้าโปรไฟล์ผู้ใช้
\end{itemize}

\section{การพัฒนาในส่วนของการลบรีวิว}
เมื่อผู้ใช้กดปุ่มลบรีวิว ระบบจะมีการทำงาน แสดงดังรูปที่ \ref{Fig:4-deletere}
\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
deleteReview() {
this.http.delete(`${KUZZLE}:${KPORT}/${KINDEX}/${this.type_review}/
${this.id_place}`)
.subscribe((response) =>{
});
const check = this.reviews.find(item => item.id == this.id_place)
if (check) {
this.reviews.map((item, index) => {
  if( item.id === this.id_place ){
    this.reviews.splice(index, 1)
  this.http.put(`${KUZZLE}:${KPORT}/users/${this.id_user}/_update`,{
  reviews: JSON.stringify(this.reviews)})
.subscribe(res => {
}, err => {
console.log(err);
})
}
})
}
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มลบรีวิว}
\label{Fig:4-deletere}
\end{figure}
\newpage
จากภาพที่ \ref{Fig:4-addplace} โครงสร้างของไฟล์ delete-review.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 ฟังก์ชัน deleteReview()g เป็นฟังก์ชันที่ใช้ในการลบรีวิวจะถูกเรียกใช้เมื่อผู้ใช้กดปุ่มลบรีวิว
\item บรรทัดที่ 2 - 5 เป็นการลบข้อมูลรีวิวออกจากฐานข้อมูลโดยจะลบตามประเภทของสถานที่และ id ของสถานที่ที่ โดยใช้ method delete
\item บรรทัดที่ 6 เป็นการประกาศ check ขึ้นมาเพื่อค้นหาข้อมูลการเขียนรีวิวทั้งหมดที่มีอยู่ในฐานข้อมูลของผู้ใช้โดยใช้ item เป็นรับข้อมูลเข้าไปค้าหาต่อ
\item บรรทัดที่ 7 - 10  เป็นการเช็คเงื่อนไขเมื่อเข้าเงื่อนไขก็จะเข้ามาทำงานในส่วนนี้โดยใช้ข้อมูลที่เก็บไว้ใน reviews ทำการวนฟอเพื่อดูข้อมูล และก็เข้าเงื่อนไขก็จะเช็คดูอีกครั้งว่าค่าของ id มีค่าเท่ากับ idplaceห ไหม ถ้าตรงกันก็จะให้รีวิวลบรีวิวที่มีชื่อ id ตรงกับตัวที่ค้นหาออก
\item บรรทัดที่ 11 - 15 เป็นการอัพเดทข้อมูลในส่วนของผู้ใช้อีกครั้ง โดยใช้ method put เพื่อที่จะทำการอัพเดทข้อมูลการเขียนรีวิว
\item บรรทัดที่ 16 - 18 เป็นการ log ดูค่า error ในกรณีที่อัพเดทข้อมูลไม่สำเร็จ
\end{itemize}
\newpage

\section{การพัฒนาในส่วนของการบันทึกสถานที่}
เมื่อผู้ใช้กดปุ่มบันทึก ระบบจะมีการทำงาน แสดงดังรูปที่ \ref{Fig:4-bookmark}
\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
changeBookMark(place: any) {
if (this.loginData.isAuth === false) {
  this.modalService.info({
    nzTitle: 'กรุณาล็อคอินเข้าสู่ระบบก่อนกดปุ่มบันทึกสถานที่'
  });
}else {
  this.dataplace = {
    id: place._id,
    type: place._type,
    type_review: this.type_Review
  }
const check = this.bookmarks.find(item => item.id == place._id)
if (check) {
  this.bookmarks.map((item, index) => {
  item.id === place._id ? this.bookmarks.splice(index, 1) : null 
  })
}else {
this.bookmarks.push({
  id: place._id,
  type: place._type,
  review: this.type_Review
})
}
this.http.put(`${KUZZLE}:${KPORT}/users/${this.id_User}/_update`,{
bookmarks: JSON.stringify(this.bookmarks)
})
.subscribe(res => {
console.log(res);
this.bookmark = !this.bookmark
})
}
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มบันทึกสถานที่}
\label{Fig:4-bookmark}
\end{figure}
\newpage
จากภาพที่ \ref{Fig:4-addplace} โครงสร้างของไฟล์ detail-place.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 ฟังก์ชัน changeBookMark() ฟังก์ชันนี้จะถูกเรียกใช้ก็ต่อเมื่อผู้ใช้กดปุ่มบันทึก
\item บรรทัดที่ 2 - 5 เป็นการเช็คดูสถานะการล็อคอิน ถ้าสถานะการเข้าสู่ระบบเป็น false จะมีข้อความแจ้งผู้ใช้ให้เข้าสู่ระบบก่อนกดปุ่มบันทึกสถานที่
\item บรรทัดที่ 6 - 11 เป็นการเช็คดูสถานะการล็อคอิน ในกรณีเข้าสู่ระบบสำเร็จแล้วผู้ใช้สมารถกดปุ่มบันทึกสถานที่ได้ โดยจะเก็บค่าของ id สถานที่ type สถานที่ type ของรีวิว ไว้ในตัวแปรชื่อ dataplace 
\item บรรทัดที่ 12 เป็นการประกาศ check ขึ้นมาเพื่อเก็บค่าผลลัพธ์การค้นหาข้อมูลการบันทึกสถานที่ทั้งหมดที่มีอยู่ในฐานข้อมูลของผู้ใช้โดยใช้ item เป็นรับข้อมูลในการค้นหา
\item บรรทัดที่ 13 - 16 เป็นการเช็คเงื่อนไขเมื่อเข้าเงื่อนไขก็จะเข้ามาทำงานในส่วนนี้โดยใช้ข้อมูลที่เก็บไว้ใน bookmarks มาทำการวนฟอเพื่อดูข้อมูล และก็เข้าเงื่อนไขจะเช็คดูอีกครั้งว่าค่าของ item.id มีค่าเท่ากับ place.id ไหม ถ้าตรงกันก็จะให้ลบชื่อสถานที่ตัวนั้นทิ้ง
\item บรรทัดที่ 17 - 22 เป็นการเช็คเงื่อนไขในกรณีที่ข้อมูลการบันทึกสถานที่นั้นยังไม่เคยกดบันทึกก็จะทำการเพิ่มข้อมูลสถานที่นั้นลงไปใน bookmarks
\item บรรทัดที่ 24 - 28 เป็นการอัพเดทข้อมูลในส่วนของ filed ที่ชื่อ bookmarks ในฐานข้อมูลของผู้ใช้ โดยอัพเดทผ่าน method put 
\item บรรทัดที่ 29 เป็นการรีเซตค่าตรงปุ่มกดบันทึกให้เปลี่ยนเป็นบันทึก
\end{itemize}
\newpage

\section{การพัฒนาในส่วนของการแจ้งแก้ไขข้อมูล}
เมื่อผู้ใช้กดปุ่มแจ้งแก้ไข ระบบจะมีการทำงาน แสดงดังรูปที่ \ref{Fig:4-edit} - \ref{Fig:4-edit1}
\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
editDataPlace(){
if (this.id_place !== undefined) {
  this.dataPlace = {
    edit_by: this.edit_by,
    img_user: this.img_user,
    namelocation: this.editForm.value.namelocation,
    group: this.group,
    address: this.editForm.value.address,
    cityprovince: this.editForm.value.cityprovince,
    description: this.editForm.value.description,
    phonenumber: this.editForm.value.phonenumber,
    price: this.editForm.value.price,
    openclose: this.editForm.value.openclose,
    website: this.editForm.value.website,
    facebook: this.editForm.value.facebook,
    lat: this.editForm.value.lat,
    lng: this.editForm.value.lng,
    image: this.imgs,
    typeplace: this.typeplace
  }
this.http.put(`${KUZZLE}:${KPORT}/${KINDEX}/dataedit/${this._id}/_update`,
this.dataPlace)
.subscribe((response) => {
console.log(response);
})}
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มแจ้งแก้ไขสถานที่}
\label{Fig:4-edit}
\end{figure}
จากภาพที่ \ref{Fig:4-edit} โครงสร้างของไฟล์ detail-place.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 ฟังก์ชัน editDataPlace() ฟังก์ชันนี้จะทำงานก็ต่อเมื่อผู้ใช้กดปุ่มแจ้งแก้ไข
\item บรรทัดที่ 2 - 20 เป็นการเช็คเงือนไขดูว่าสถานที่จะแจ้งแก้ไขเคยมีประวัติการแจ้งแก้ไขไหม ถ้า this.idplace != undefined ก็จะเข้ามาทำงานในส่วนนี้โดยจะทำการเก็บข้อมูลรายละเอียดการแก้ไขไว้ในตัวแปรชื่อ dataplace
\newpage
\item บรรทัดที่ 21 - 24 เป็นการส่งข้อมูลที่ได้จาก dataplace ไปทำการอัพเดทข้อมูลการแจ้งแก้ไขเพื่อที่จะส่งไปให้แอดมินเป็นผู้อนุมัติแก้ไขข้อมูล
\end{itemize}

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
else{
this.dataPlace = {
    edit_by:this.edit_by,
    img_user: this.img_user,
    namelocation: this.editForm.value.namelocation,
    group: this.group,
    address: this.editForm.value.address,
    cityprovince: this.editForm.value.cityprovince,
    description: this.editForm.value.description,
    phonenumber: this.editForm.value.phonenumber,
    price: this.editForm.value.price,
    openclose: this.editForm.value.openclose,
    website: this.editForm.value.website,
    facebook: this.editForm.value.facebook,
    lat: this.editForm.value.lat,
    lng: this.editForm.value.lng,
    image: this.imgs,
    typeplace: this.typeplace
 }
this.http.post(`${KUZZLE}:${KPORT}/${KINDEX}/dataedit/${this._id}/_create`,
this.dataPlace)
.subscribe((response) => {
console.log(|\thcodedouble{เก็บข้อมูลการแจ้งแก้ไขเรียบร้อย}|,response);}) 
}
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มแจ้งแก้ไขสถานที่}
\label{Fig:4-edit1}
\end{figure}

จากภาพที่ \ref{Fig:4-edit1} โครงสร้างของไฟล์ detail-place.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 - 19 เป็นเช็คต่อจากภาพที่ \ref{Fig:4-edit} โดยในเงื่อนไขนี้คือถ้าของ idสถานที่ที่แจ้งแก้ไขมาเป็น undefined หมายความว่าสถานที่นี้ยังไม่เคยมีประวัติการแจ้งแก้ไขโดยจะทำการเก็บข้อมูลการแจ้งแก้ไขที่ได้จากผู้ใช้มาเก็บไว้ใน dataplace
\item บรรทัดที่ 20 - 24 เป็นการเรียกใช้ dataplace ที่เก็บข้อมูลการแจ้งแก้ไขไว้มาทำการเพิ่มลงไปในฐานข้อมูลของการแจ้งแก้ไข 
\end{itemize}
\newpage

\section{การพัฒนาในส่วนของการค้นหาสถานที่}
เมื่อผู้ใช้กดปุ่มค้นหา ระบบจะมีการทำงาน แสดงดังรูปที่ \ref{Fig:4-search} - \ref{Fig:4-search1}
\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
dataPlace(){
if (this.typeplace == "all") {
this._resultsPlace = []
const list = ["eatgrill","eatdrinks","eatnoodle",
              "eatesan","eatjapan","eatsteak"]
list.map(item => {
const query = {
  query: {
  },size: 100
}
this.http.post(`${KUZZLE}:${KPORT}/${KINDEX}/${item}/_search`,
query)
.subscribe((res: any) =>{
this._resultsPlace = [ ...this._resultsPlace,...res.result.hits]
})
})
} else {
const query = {
  query: {
  }, size: 100
}
this.http.post(`${KUZZLE}:${KPORT}/${KINDEX}/${this.typeplace}/_search`,query)
.subscribe((res: any) => {
this._resultsPlace = res.result.hits
})
}
}
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มเลือกประเภท}
\label{Fig:4-search}
\end{figure}

จากภาพที่ \ref{Fig:4-search} สามารถอธิบายการทำงานของฟังก์ชันการค้นหาสถานที่ได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 ฟังก์ชัน dataPlace() จะทำงานก็ต่อเมื่อผู้ใช้กดปุ่มเลือกประเภทสถานที่
\item บรรทัดที่ 2 เป็นการเช็คเงื่อนไขดูว่า ประเภทที่ผู้ใช้เลือกนั้นเป็นประเภทไหน ถ้าผู้ใช้เลือกทั้งหมด ก็จะมาเข้าเงื่อนไขนี้
\item บรรทัดที่ 4 - 5 เป็นการประกาศ list ขึ้นมาเก็บค่าของประเภท โดยมี type เป็น array
\item บรรทัดที่ 6 - 10 เป็นกานำข้อมูลที่อยู่ใน list มาทำการวนฟอเพื่อนำไปค้นหาข้อมูลในฐานข้อมูลตามประเภททั้งหมดที่มีอยู่ใน list
\item บรรทัดที่ 13 เป็นการทำงานหลังจากที่ค้นหาข้อมูลเสร็จจะนำข้อมูลที่ได้มาเก็บไว้ใน resultsPlace
\item บรรทัดที่ 17 - 24 เป็นการเช็คเงื่อนไขในกรณีที่ประเภทที่ผู้ใช้เลือกมาไม่ใช่ทั้งหมด ก็จะทำการค้นหาข้อมูลในฐานข้อมูลตามประเภทที่ผู้ใช้เลือก เมื่อค้นหาเสร็จก็จะนำข้อมูลที่ได้มาเก็บไว้ใน resultsPlace 
\end{itemize}

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
onClickplace(){
if(this.name == null){
  alert(|\thcodedouble{กรุณากรอกข้อมูลก่อนกดปุ่มค้นหา}|); 
}else{
let data = {
  id_place : this.dataplace.id ,
  type_place : this.dataplace.type,
  type_review : this.dataplace.type_review,
  name: this.name,
}
localStorage.setItem("dataPlace",JSON.stringify(data))
this.router.navigate(['/list-place'])
}
}
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กดปุ่มค้นหา(ต่อ)}
\label{Fig:4-search1}
\end{figure}

จากภาพที่ \ref{Fig:4-search1} สามารถอธิบายการทำงานของฟังก์ชันการค้นหาสถานที่ได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 ฟังก์ชัน onClickplace() จะทำงานก็ต่อเมื่อผู้ใช้กดปุ่มค้นหา
\item บรรทัดที่ 2 - 3 เป็นการเช็คเงื่อนไขว่าช่องให้กรอกชื่อสถานทีจะต้องไม่เป็น !null ถ้าเป็น null จะเข้าเงื่อนไขนี้ โดยจะมีความแจ้งผู้ใช้ว่ากรุณากรอกข้อมูลก่อนกดปุ่มค้นหา 
\item บรรทัดที่ 4 - 12 เป็นการเช็คเงื่อนไขในกรณีที่ผู้ใช้กรอกชื่อสถานที่เรียบร้อยก่อนกดปุ่มค้นหา ก็จะเข้ามาทำงานในส่วนนี้โดยจะประกาศต้วแปรชื่อ data ขึ้นมาเพื่อเก็บค่าของ id สถานที่ type สถานที่ type ของรีวิว โดยนำข้อมูลที่ได้ไปเขียนลง localStorage ที่มีชื่อว่า dataPlace หลังจากนั้นก็ router ไปหน้า  list-place  
\end{itemize}
\newpage

\section{การพัฒนาในส่วนของการทำแบบประเมิน}
เมื่อผู้ใช้ทำการกรอกแบบประเมิน ระบบจะมีการทำงาน แสดงดังรูปที่ \ref{Fig:4-question} - \ref{Fig:4-question2}
\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
userForm = new FormGroup({
  gender: new FormControl('', Validators.required),
  age: new FormControl('', Validators.required),
  job: new FormControl('', Validators.required),
  income: new FormControl('', Validators.required),
  live: new FormControl('', Validators.required),
  travel_purpose: new FormControl('', Validators.required),
  travel_style: new FormControl('', Validators.required),
  vehicle: new FormControl('', Validators.required),
  info: new FormControl('', Validators.required),
  frequency: new FormControl('', Validators.required),
  travelUbon: new FormControl('', Validators.required),
  goal: new FormControl('', Validators.required),
  environment: new FormControl('', Validators.required),
  decision: new FormControl('', Validators.required),
  convenience: new FormControl('', Validators.required),
  want: new FormControl('', Validators.required),
});
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กรอกแบบประเมิน}
\label{Fig:4-question}
\end{figure}

จากภาพที่ \ref{Fig:4-question} โครงสร้างไฟล์ questionnaire.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 - 18 เป็นฟอมที่ใช้เก็บค่าจากผู้ใช้เมื่อผู้ใช้เลือกช้อยส์ของแต่ละคำถามซึ่งจะมีด้วยกันทั้งหมด 16 ข้อ
\end{itemize}
\newpage

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}predict() {
this.isValidFormSubmitted = false;
if (this.userForm.invalid) {
return;
}
this.isValidFormSubmitted = true;
  this.user.q1 = this.userForm.get('gender').value;
  this.user.q2 = this.userForm.get('age').value;
  this.user.q3 = this.userForm.get('job').value;
  this.user.q4 = this.userForm.get('income').value;
  this.user.q5 = this.userForm.get('live').value;
  this.user.q6 = this.userForm.get('travel_purpose').value;
  this.user.q7 = this.userForm.get('travel_style').value;
  this.user.q8 = this.userForm.get('vehicle').value;
  this.user.q9 = this.userForm.get('info').value;
  this.user.q10 = this.userForm.get('frequency').value;
  this.user.q11 = this.userForm.get('travelUbon').value;
  this.user.q12 = this.userForm.get('goal').value;
  this.user.q13 = this.userForm.get('decision').value;
  this.user.q14 = this.userForm.get('environment').value;
  this.user.q15 = this.userForm.get('convenience').value;
  this.user.q16 = this.userForm.get('want').value;

this.resultModel = [
  this.user.q1,this.user.q2,this.user.q3,
  this.user.q4,this.user.q5,this.user.q6,
  this.user.q7,this.user.q8,this.user.q9,
  this.user.q10,this.user.q11,this.user.q12,
  this.user.q13,this.user.q14,this.user.q15,this.user.q16
]
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กรอกแบบประเมินเสร็จกดปุ่มส่งข้อมูล(ต่อ)}
\label{Fig:4-question1}
\end{figure}
\newpage

จากภาพที่ \ref{Fig:4-question1} โครงสร้างไฟล์ questionnaire.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 ฟังก์ชัน predict() ฟังก์ชันนี้จะทำงานก็ต่อเมื่อผู้ใช้กดปุ่มส่งข้อมูลโดยจะส่งข้อมูลที่ได้จากการกรอกแบบประเมินไปให้ฝั่ง server
\item บรรทัดที่ 2 - 5 เป็นการเช็คดูว่าฟอมที่ผู้ใช้กรอกมาตอบครบทุกข้อหรือไม ถ้ายังไม่ไม่ครบทุกข้อก็จะไม่สามารถกดส่งข้อมูลได้โดยระบบจะแจ้งข้อที่ผู้ใช้ข้าม
\item บรรทัดที่ 6 ในกรณีที่ผู้ใช้ตอบครบทุกข้อก็จะสามารถกดปุ่มส่งข้อมูลได้
\item บรรทัดที่ 7 - 22 เป็นการเก็บค่าข้อมูลคำตอบที่ผู้ใช้เลือกจาก userForm ไว้ใน user.q1 - user.q16 โดยเรียงตามข้อเริ่มจากข้อ 1 ถึง 16
\item บรรทัดที่ 24 - 30 เป็นการเรียกใช้ resultModel เพื่อเก็บค่าผลลัพธ์ของคำตอบที่ผู้ใช้เลือกซึ่งมีการเก็บเป็นแบบ array
\end{itemize}

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
this.http.post('http://10.80.29.22:8000/api/predict',{
questionnaire : this.resultModel
}).subscribe((res:any) =>{
let resultmodels = {
  result: this.resultModel1,
  name : res.results,
  number : res._predictOut
}
this.resultpredict.sendpredict(resultmodels) 
this.dialog.open(DialogResultComponent,{
});
})
}
\end{minted}
\caption{การทำงานของระบบเมื่อผู้ใช้กรอกแบบประเมินเสร็จกดปุ่มส่งข้อมูล(ต่อ)}
\label{Fig:4-question2}
\end{figure}

จากภาพที่ \ref{Fig:4-question2} โครงสร้างไฟล์ questionnaire.component.ts อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 - 2 เป็นการนำข้อมูลที่ได้จาก resultModel ส่งค่าไปให้ server ที่ port 8000 ทำงานต่อในส่วนของการ predict ข้อมูล
\newpage
\item บรรทัดที่ 4 - 8 เป็นการนำเรียกข้อมูลได้จากจากฝั่ง server มาเก็บไว้ใน resultmodels โดยจะเก็บผลลัพธ์ของการกรอกแบบสอบถามไว้ใน result เก็บ ข้อมูลผลลัพธ์การ predict ไว้ที่ number
\item บรรทัดที่ 9 เป็นการเรียกใช้ service ของ sendpredict เพื่อที่จะเอาค่าข้อมูลที่เก็บไว้ที่ resultmodels ไปบันทึกไว้ที่ sendpredict 
\item บรรทัดที่ 10 เป็นการเรียกใช้ dialog.open เพื่อเปิดหน้าของ DialogResultComponent มาแสดงผลลัพธ์การแนะนำ
\end{itemize}

\section{การพัฒนาในส่วนของ Server ที่ใช้ในการ train model}
เมื่อผู้ดูแลระบบกดปุ่ม train จะมีกระบวนการทำงาน แสดงดังรูปที่ \ref{Fig:4-train} - \ref{Fig:4-train2}
\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
app.get("/api/trian", (req, res) => {
const startTime = new Date()
axios.post('http://10.80.29.22:7512/dbpom/model/_search?size=1500',{})
.then((response) => {
const datamodel = response.data.result.hits.map((item, index) => {
var xTrains = [];
  xTrains.push(item._source.q1)
  xTrains.push(item._source.q2)
  xTrains.push(item._source.q3)
  xTrains.push(item._source.q4)
  xTrains.push(item._source.q5)
  xTrains.push(item._source.q6)
  xTrains.push(item._source.q7)
  xTrains.push(item._source.q8)
  xTrains.push(item._source.q9)
  xTrains.push(item._source.q10)
  xTrains.push(item._source.q11)
  xTrains.push(item._source.q12)
  xTrains.push(item._source.q13)
  xTrains.push(item._source.q14)
  xTrains.push(item._source.q15)
  xTrains.push(item._source.q16)
  xTrain.push(xTrains);
  yTrain.push(item._source.q17);
})
\end{minted}
\caption{ขั้นตอนกระบวนการ train model}
\label{Fig:4-train}
\end{figure}
\newpage
จากภาพที่ \ref{Fig:4-train} โครงสร้างของไฟล์ app.js อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 เมื่อผู้ดูแลระบบกดปุ่ม train ก็จะมาเรียกใช้งานที่ path:"api/train"
\item บรรทัดที่ 2 เป็นการกำหนดเวลาเริ่มต้นการเทรน
\item บรรทัดที่ 3 เป็นการค้นหาข้อมูลจากฐานข้อมูลของ model เพื่อนำข้อมูลที่ผู้ใช้กรอกแบบประเมินมาทำการ train
\item บรรทัดที่ 4 - 25 เป็นการใช้ .map ในการวนฟอค้นหาข้อมูลทั้งหมดที่มีอยู่ในฐานข้อมูลและทำการแยกค่าของ xTrain yTrain โดย xTrain จะเก็บค่าของ q1 - q16 ส่วน yTrain จะเก็บค่าของ q17
\end{itemize}

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
const XTrain = tf.tensor2d(xTrain)
const YTrain = tf.tensor2d(yTrain.map(item => [
  item === 0 ? 1 : 0,
  item === 1 ? 1 : 0,
  item === 2 ? 1 : 0,
  item === 3 ? 1 : 0,
  item === 4 ? 1 : 0,
  item === 5 ? 1 : 0
])); 
model = tf.sequential();
model.add(tf.layers.dense({
inputShape: [16],
activation: 'sigmoid',
units: 6,
}));
model.add(tf.layers.dense({
inputShape: [16],
activation: 'sigmoid',
units: 6,
}));
model.add(tf.layers.dense({
activation: 'softmax',
units: 6,
}));
model.summary();
\end{minted}
\caption{ขั้นตอนกระบวนการ train model(ต่อ)}
\label{Fig:4-train1}
\end{figure}
\newpage
จากภาพที่ \ref{Fig:4-train1} โครงสร้างของไฟล์ app.js อธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 - 9 เริ่ม load ข้อมูล xTrain , yTrain โดยค่าของ xTrain จะถูกเก็บไว้ที่ XTrain และค่าของ yTrain จะถูกเก็บไว้ที่ YTrain ซึ่งค่าของ yTrain จะมี 0,1,2,3,4,5
\item บรรทัดที่ 10 เป็นการสร้าง model จาก tf.sequential()
\item บรรทัดที่ 11 - 24 เป็นการเพิ่ม layer sigmoid และ layer softmax 
\item บรรทัดที่ 25 เป็นการแสดง summary ของ model
\end{itemize}

\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
const learningRate = 0.01 
const optimizer = tf.train.adam(learningRate);
model.compile({
  optimizer: optimizer,
  loss: 'meanSquaredError', 
  metrics: ['accuracy'],
});
let dataAcc = []
for(let i =0; i <= 1000; i++){
model.fit(XTrains, YTrains,{epochs:1000}).then((info) => {
  const endTime = new Date()
  dataAcc = [...dataAcc,...info.history.acc]
  const maxAcc = Math.max(...dataAcc)
  const modeljsonfile = `file://${__dirname}/models/model`
    model.save(modeljsonfile).then(() => {
    })
    .catch((error) => {
    })
});
}
\end{minted}
\caption{ขั้นตอนกระบวนการ train model(ต่อ)}
\label{Fig:4-train2}
\end{figure}
\newpage
จากภาพที่ \ref{Fig:4-train2} โครงสร้างของไฟล์ app.js สามารถอธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 - 7 เป็นการเริ่ม train model โดยใช้ adam ซึ่งค่า learningRate ที่ใช้ 0.01
\item บรรทัดที่ 8 เป็นการประกาศ dataAcc มาเก็บค่าของ accuracy
\item บรรทัดที่ 9 เป็นการเพิ่มรอบในการเทรน โดยจะเทรนทั้งหมด 1000 รอบ
\item บรรทัดที่ 10 เป็นการสิ้นสุดการเทรนได้โมเดล
\item บรรทัดที่ 11 เป็นการเก็บเวลาสิ้นสุดในการเทรน
\item บรรทัดที่ 12 เป็นการเก็บค่า accuracy มาไว้ใน array dataAcc 
\item บรรทัดที่ 13 เป็นการหาค่าสูงสุดของ accuracy
\item บรรทัดที่ 14 - 16 เป็นการนำโมเดลที่ได้มาบันทึกเป็นไฟล์ json ไว้ที่โฟล์เดอร์ models
\item บรรทัดที่ 17 - 18 เป็นการแสดงเออเร่อในกรณีที่บันทึกไฟล์โมเดลไม่สำเร็จ
\end{itemize}
\newpage

\section{การพัฒนาในส่วนของ Server ที่ใช้ในการ predict ข้อมูล}
เมื่อผู้ใช้กดปุ่มส่งข้อมูล จะมีกระบวนการทำงาน แสดงดังรูปที่ \ref{Fig:4-predict}
\begin{figure}[H]
\begin{minted}[escapeinside=||,frame=lines,framesep=2mm,baselinestretch=1.15,fontsize=\footnotesize,linenos]{javascript}
app.post("/api/predict",(req, res) => {
const result = req.body.questionnaire.map(item => parseInt(item)) 
const xTest = tf.tensor2d([result])
const modeljsonfile = `file://${__dirname}/models/model/model.json`
tf.loadLayersModel(modeljsonfile)
.then((_model) => {
const predictOut = _model.predict(xTest)
const category = predictOut.dataSync().map(_item => 
Math.round((parseInt(_item * 1000)/1000)*100));
  category.map((item,index)=> {
    dataShow.push({
      label : nameResult[index]+' '+item+'%',
      value : item,index
    })
  })
dataShow = dataShow.sort(
  (a, b) => (a.value > b.value) ? 1 : ((b.value > a.value) ? -1 : 0)
  ).reverse()
return res.send({
  predictOut: predictOut,
  category: category,
  data : req.body.questionnaire,
  results : dataShow
})
})
\end{minted}
\caption{ขั้นตอนกระบวนการ predict ข้อมูล}
\label{Fig:4-predict}
\end{figure}
\newpage
จากภาพที่ \ref{Fig:4-predict} โครงสร้างของไฟล์ app.js สามารถอธิบายการทำงานได้ดังนี้
\begin{itemize}[label={--}]
\item บรรทัดที่ 1 เมื่อผู้ใช้กดปุ่มส่งข้อมูล ก็จะมาเรียกใช้งานที่ path:"api/predict" เพื่อนำข้อมูลที่ได้ส่งให้ฝั่ง server ทำการประมวลให้
\item บรรทัดที่ 2 เป็นการประการ result ขึ้นมาเพื่อมาเก็บข้อมูลแบบประเมินที่ผู้ใช้กรอกเข้ามาในฝั่งของ Client ซึ่งค่าที่ส่งมาเป็น string เราจะต้องมาแปลงให้เป็นตัวเลขก่อนโดยใช้คำสั่ง parseInt()
\item บรรทัดที่ 3 เป็นการนำเอา result มาทำให้เป็นข้อมูล 2 มิติ และเก็บไว้ที่ xTest
\item บรรทัดที่ 4 - 6 เป็นการโหลดไฟล์โมเดลมาใช้งานในการทำนายผลลัพธ์
\item บรรทัดที่ 7 เป็นการนำเอาตัวแปร xTest มาทำการ predict ข้อมูลและเก็บไว้ที่ predictOut
\item บรรทัดที่ 8 - 9 เป็นการเรียกใช้ predictOut มาทำการวิเคราะห์ผลลัพธ์การแนะนำโคยค่าทีได้จะออกมาเป็นตัวเลขทศนิยมซึ่งจะต้องนำค่ามาคิดเป็นเปอร์เซ็นต์และเก็บไว้ที่ตัวแปร category
\item บรรทัดที่ 10 - 15 เป็นการนำค่าของ category มาค้นหาและไป push เก็บไว้ในรูปแบบ label และ value ซึ่ง label จะเก็บชื่อของหมวดและค่าเปอร์เซ็นต์ ส่วน value จะเก็บตำแหน่งของชื่อหมวด และเก็บไว้ใน dataShow
\item บรรทัดที่ 16 - 18 เป็นการนำเอาค่าข้อมูลที่เก็บไว้ใน dataShow มาทำการจัดอันดับซึ่งเรียงจากค่าที่มีเปอร์เซ็นต์มากสุดไปน้อยสุด
\item บรรทัดที่ 19 - 25 เป็นการส่งค่าผลลัพธ์ที่ได้กลับไปให้ฝั่ง Client เพื่อทำการแสดงผลข้อมูลการแนะนำให้กับผู้ใช้ได้ทราบ
\end{itemize}
\newpage