You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

539 lines
34 KiB
HTML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>One Minute Feedback - Help Us Serve You Better</title>
<style>body{font-family:Arial,sans-serif;color:#333}.text-primary{color:#b43c1a}h3,h5,p{margin:.5em 0}.header-m{background:#ad1818;color:#fff;padding:.5em}.header-pc{height:90px!important;display:flex;align-items:center;justify-content:flex-start;background:#ad1818;color:#fff;padding:0 20px}.header-pc img{position:absolute;top:0;margin-right:20px;height:104px;width:auto;border-radius:0 0 3px 3px;background-color:#fff;box-shadow:1px 1px 10px 1px rgba(77,77,77,.7);-webkit-box-shadow:1px 1px 10px 1px rgba(77,77,77,.7);-moz-box-shadow:1px 1px 10px 1px rgba(77,77,77,.7)}.header-pc h1{margin:0;margin-left:240px}.form-container{width:100%;max-width:768px;margin:0 auto;margin-top:1.5em}.question{display:flex;flex-direction:column;align-items:start;margin-bottom:10px}.question h4{position:sticky;top:0;background-color:#fff;margin-top:0;padding-top:1.33em}.question-items{display:flex;flex-direction:column;align-items:start;margin-bottom: 10px;}.options{display:flex;flex-direction:column;align-items:start;}.options-row{flex-direction:row;justify-content:flex-end;align-items:baseline}.options-row-reverse{flex-direction:row-reverse;justify-content:flex-end;align-items:baseline}.radio-container{display:flex;align-items:center;margin-bottom:5px;margin-top: 5px;}.radio-container input[type=radio]{display:none}.radio-container label{margin-left:8px}.radio-container input[type=radio]:checked+.radio-label{background-color:#d54e21;color:#fff}.radio-label{display:inline-block;padding:5px 10px;border:1px solid #d54e21;border-radius:20px;transition:all .3s ease;font-size:14px}label.radio-label svg{vertical-align:text-bottom}.feedback{margin-top:10px}.feedback textarea{width:90%;padding:10px;resize:vertical;border:1px solid #d54e21;border-radius:5px}.form-btn{display:block;width:100%;padding:10px;margin-top:20px;border:none;border-radius:20px;cursor:pointer;transition:all .3s ease;background:0 0;border:1px solid #d54e21;color:#d54e21}.submit-btn{background-color:#d54e21;color:#fff}.submit-btn:hover{background-color:#b43c1a}.cancel-btn:hover{background-color:#00000011}.info-container{display:flex;flex-direction:column;justify-content:space-between;margin-bottom:10px}.info-item{margin-bottom:10px}.info-item p{color:#b43c1a}.signature-pad{border:1px solid #d54e21;border-radius:5px;z-index:10}.signature-container{display:flex;flex-direction:column;justify-content:flex-start;align-items:flex-start;flex-wrap:wrap}.button-container{margin-left:.5em;display:flex;flex-direction:column;justify-content:flex-start}.button{margin-top:1em;padding:10px;background-color:#d54e21;color:#fff;border:none;border-radius:5px;cursor:pointer}@media (min-width:768px){body{margin-left:0;margin-right:0;margin-top:0;padding-left:0;padding-right:0;padding-top:0}.question-items{width:100%;flex-direction:row;justify-content:space-between;align-items:baseline}.question-items h5{max-width: 230px;}.question-items .options{flex:1 1 auto}.options{flex-direction:row;justify-content:flex-end;align-items: center;}.info-container{flex-direction:row}.info-item{flex:1;margin-right:10px;margin-bottom:0}.info-item:last-child{margin-right:0}.header-m{display:none}.signature-container{flex-direction:row}}@media (max-width:767px){.header-pc{display:none}}</style>
<style>
#result{text-align:center;padding:20px}.bi-check-circle-fill,.bi-exclamation-circle-fill,.bi-x-circle-fill{fill:#d54e21}.bi-x-circle-fill{fill:#d54e21}
</style>
<style>#loading-mask{width:100vw;height:100vh;background-color:#00000099;position:fixed;left:0;top:0;display:flex}.lds-facebook{display:inline-block;position:relative;width:80px;height:80px;margin:auto}.lds-facebook div{display:inline-block;position:absolute;left:8px;width:16px;background:#fff;animation:lds-facebook 1.2s cubic-bezier(0,.5,.5,1) infinite}.lds-facebook div:nth-child(1){left:8px;animation-delay:-.24s}.lds-facebook div:nth-child(2){left:32px;animation-delay:-.12s}.lds-facebook div:nth-child(3){left:56px;animation-delay:0}@keyframes lds-facebook{0%{top:8px;height:64px}100%,50%{top:24px;height:32px}}</style>
<style>.city-page{display:flex;flex-direction:column;align-items:center}.city-list{list-style-type:none;padding:0;width:260px;background-color:#fff;border-radius:5px;box-shadow:0 0 10px rgba(0,0,0,.1)}.city-list li{padding:20px;border-top:1px solid #d54e21;border-bottom:1px solid #d54e21;transition:background-color .3s;position:relative}.city-list li.filled::after{content:'✔';position:absolute;right:20px;color:#d54e21;transition:color .3s}.city-list li:hover{background-color:#d54e21;color:#fff}.city-list li.filled:hover::after{color:#fff}</style>
<style>.float-button{position:fixed;right:20px;bottom:120px;background-color:transparent;color:#d54e21;border:1px solid #d54e21;border-radius:50%;width:60px;height:60px;text-align:center;line-height:60px;font-size:24px;cursor:pointer;box-shadow:0 0 10px rgba(0,0,0,.1);z-index:1}.float-button:hover{background-color:#d54e21;color:#fff}.float-text{position:fixed;right:20px;bottom:190px;color:#d54e21;font-size:18px;text-align:right;z-index:-1;width: 100px;}.expand-list{list-style-type:none;position:fixed;right:20px;bottom:190px;width:260px;background-color:#fff;border-radius:5px;box-shadow:0 0 10px rgba(0,0,0,.1);padding:0;max-height:0;overflow:hidden;opacity:0;transition:max-height .5s ease,opacity .5s ease}.expand-list.open{max-height:500px;opacity:1;z-index: 99;}.expand-list li{padding:20px;border-bottom:1px solid #d54e21;transition:background-color .3s;position: relative;}.expand-list li:last-child{border-bottom:none}.expand-list li.active{color:#d54e21}.expand-list li.filled::after{content:'✔';position:absolute;right:20px;color:#d54e21;transition:color .3s}.expand-list li:hover{background-color:#d54e21;color:#fff}.expand-list li.filled:hover::after{color:#fff}</style>
<style>.star-rating{direction:rtl;display:inline-block}.star-rating input[type=radio]{display:none}.star-rating label{font-size:30px;color:#d3d3d3;cursor:pointer}.star-rating input[type=radio]:checked~label,.star-rating input[type=radio]~label.checked,.star-rating label:hover,.star-rating label:hover~label{color:#d54e21}.rate-meaning{display:inline-block;margin-left:15px;vertical-align:middle;color:#d54e21}</style>
<script src="./utils.js"></script>
<script src="./vue@2.js"></script>
<script src="./signature_pad.umd.min.js"></script>
</head>
<body>
<div id="app">
<div class="header-pc">
<a href="https://www.asiahighlights.com/" v-if="webcode=='ah'">
<img src="https://data.asiahighlights.com/pic/logo-ah.png" alt="Logo" width="130" height="104">
</a>
<a href="https://www.globalhighlights.com/" v-if="webcode=='gh'">
<img src="https://data.chinahighlights.com/image/aboutus/logo-gh.png" alt="Logo" width="130" height="104">
</a>
<h1>One Minute Feedback - Help Us Serve You Better</h1>
</div>
<div class="header-m">
<h1>One Minute Feedback - Help Us Serve You Better</h1>
</div>
<div class="form-container" id="main">
<div id="result" v-if="error">
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" fill="currentColor" class="bi bi-x-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.5-4.5a.5.5 0 0 0-.707 0L8 7.293 5.207 4.5a.5.5 0 0 0-.707.707L7.293 8l-2.793 2.793a.5.5 0 0 0 .707.707L8 8.707l2.793 2.793a.5.5 0 0 0 .707-.707L8.707 8l2.793-2.793a.5.5 0 0 0 0-.707z" />
</svg>
<h2>Error!</h2>
<p>{{errorMsg}}</p>
<button type="button" id="back0" class="form-btn cancel-btn" v-on:click="error=false;cityListPage=true;">Go Back</button>
</div>
<template v-else>
<div id="result" v-if="isFilled">
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" fill="currentColor" class="bi bi-check-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 10.417 5.384 8.323A.75.75 0 0 0 4.303 9.7l2.693 2.677a.75.75 0 0 0 1.086-.02l5.17-5.85a.75.75 0 0 0-.02-1.107z" />
</svg>
<h2>Thank you for your feedback!</h2>
<!-- <p>All actions are done.</p> -->
</div>
<template v-if="cityListPage">
<h4 v-if="!isFilled">Thank you for completing the Feedback Evaluation. Once submitted the tour guide would not be able to view your comments. </h4>
<div class="city-page">
<ul class="city-list" v-for="(city, index) in cityList" v-bind:key="city.cityName" v-on:click="selectCity(city)">
<li v-bind:class="[city.feedback_Filled ? 'filled' : '']">{{city.cityName}}</li>
</ul>
</div>
</template>
<template v-if="!cityListPage">
<!-- <h1>One Minute Feedback - Help Us Serve You Better</h1> -->
<p>Did you enjoy your stay in the <span class="text-primary">{{currentCity.cityName}}</span> area? Your honest feedback is appreciated to help us continually improve our service.</p>
<div class="info-container">
<div class="info-item">
<h3>Reference NO.:</h3>
<p id="referenceNo">{{group.groupNumber}}</p>
</div>
<div class="info-item">
<h3>Guide's Name:</h3>
<p id="guideName">{{group.tourGuideName}}</p>
</div>
<div class="info-item">
<h3>City:</h3>
<p id="city">{{currentCity.cityName}}</p>
</div>
</div>
<hr>
<p >Thank you for completing the Feedback Evaluation. Once submitted the tour guide would not be able to view your comments. </p>
<p v-if="!isWideScreen">Please rate by clicking the stars below.</p>
<form class="form-container" id="myForm" action="/sub" method="post" disabled>
<div class="question">
<h4>1. How satisfied were you with your tour guide?</h4>
<div class="question-items" v-for="(q, qi) in feedbackItem.guide" v-bind:key="q.id">
<h5>{{q.Describe}}</h5>
<options-item v-if="isWideScreen" question="guide" si="1" v-bind:qitem="q" v-bind:qi="qi" v-bind:key="q.id" v-bind:disabled="resultPage"></options-item>
<options-item-star v-else question="guide" si="1" v-bind:qitem="q" v-bind:qi="qi" v-bind:key="q.id" v-bind:disabled="resultPage"></options-item-star>
</div>
</div>
<div class="question">
<h4>2. How about the Driver and Car/Van?</h4>
<div class="question-items" v-for="(q, qi) in feedbackItem.driver" v-bind:key="q.id">
<h5>{{q.Describe}}</h5>
<options-item v-if="isWideScreen"question="Driver" v-bind:qitem="q" v-bind:si="2" v-bind:qi="qi" v-bind:key="q.id" v-bind:disabled="resultPage"></options-item>
<options-item-star v-else question="Driver" v-bind:qitem="q" v-bind:si="2" v-bind:qi="qi" v-bind:key="q.id" v-bind:disabled="resultPage"></options-item>
</div>
</div>
<div class="question" v-if="feedbackItem.experience.length > 0">
<h4>3. General Experience with:</h4>
<div class="question-items" v-for="(q, qi) in feedbackItem.experience" v-bind:key="q.id">
<h5>{{q.Describe}}</h5>
<options-item v-if="isWideScreen" question="Experience" v-bind:qitem="q" v-bind:si="3" v-bind:qi="qi" v-bind:key="q.id" v-bind:disabled="resultPage"></options-item>
<options-item-star v-else question="Experience" v-bind:qitem="q" v-bind:si="3" v-bind:qi="qi" v-bind:key="q.id" v-bind:disabled="resultPage"></options-item>
</div>
</div>
<div class="question " v-if="showPhotos">
<h4>4. Would you give Asia Highlights permission to use photos taken by your tour guide(s) that contain your picture?</h2>
<judgment-item question="photo" v-bind:qitem="{id: 'photo_permission', rate: feedbackEvaluation.usePhotos}" si="photo" qi="photo" key="photo" v-bind:disabled="resultPage"></judgment-item>
</div>
<div class="feedback question">
<h4>Any other comments that you would like to share with us?</h4>
<p v-if="resultPage">{{feedbackEvaluation.otherComments ? feedbackEvaluation.otherComments : '--'}}</p>
<textarea v-else name="comments" rows="4" v-bind:value="feedbackEvaluation.otherComments" v-bind:disabled="resultPage"></textarea>
</div>
<div class="signature">
<h4>Signature:</h4>
<div class="signature-container" v-if="!resultPage">
<canvas id="signature-pad" class="signature-pad" v-bind:width="drawWidth" height=200 ></canvas>
<div class="button-container">
<button type="button" id="clear" class="button" v-on:click="clearSignature()">Clear</button>
</div>
</div>
<div v-else>
<img id="signature-img" v-bind:src="feedbackEvaluation.signatureDataUrl" v-bind:width="drawWidth" />
</div>
</div>
<template v-if="!resultPage">
<button type="button" id="submit_a" class="form-btn submit-btn" v-on:click="submitForm">Finish & Submit</button>
<button type="button" id="back" class="form-btn cancel-btn" v-on:click="cancel" v-if="cityList.length > 1">Cancel</button>
</template>
</form>
<template v-if="cityList.length > 1">
<span id="currentCity" class="float-text" v-show="!cityListOpen">{{currentCity.cityName}}</span>
<button class="float-button" v-on:click="toggleCityList" ></button>
<ul v-bind:class="['expand-list', cityListOpen ? 'open' : '']">
<li v-for="city in cityList" v-bind:key="city.cityName" v-on:click="selectCity(city)" v-bind:class="{'active': city.cii_sn === currentCity.cii_sn, 'filled': (currentCity.feedback_Filled ? true : false)}">{{city.cityName}}</li>
</ul>
</template>
</template>
</template>
<div id="loading-mask" v-if="loading">
<div class="lds-facebook">
<div></div>
<div></div>
<div></div>
</div>
</div>
</div>
</div>
<script defer>
/**
*
*/
const thumbsUp = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 1024 1024" fill="currentColor" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><path d="M693.07 289.952v0.17l0.257-4.69-0.256 4.605z m309.823 164.932c-32.406-58.844-82.04-92.103-149.581-95.343-40.934-1.877-81.869-0.683-122.889-0.853l-5.543-0.17c0-0.939 0-1.45 0.17-1.962a778.607 778.607 0 0 0 11.855-88.35c2.302-28.143 3.837-56.37 4.35-84.598 0.425-24.39 2.728-48.866-0.854-73a121.95 121.95 0 0 0-69.247-96.281c-43.408-21.405-86.56-18.591-127.238 7.59-30.274 19.444-48.61 47.757-55.432 83.233-2.985 15.095-2.303 30.275-2.303 45.54 0.171 40.508-7.334 79.566-26.266 115.469-49.121 92.87-126.64 141.224-232.217 143.185-40.764 0.768-81.613 0.17-122.462 0.085-12.11 0-23.964 1.45-35.392 5.458C26.437 430.237 0 467.761 0 514.068v404.483c0 13.9 1.876 27.46 7.42 40.082 17.055 38.888 46.648 61.913 89.288 63.704 44.09 1.876 88.35 0.597 132.525 0.682 4.264 0 8.528-0.597 12.28-2.558 10.66-5.714 14.498-14.924 14.498-26.437-0.086-173.46 0-346.92 0-520.293 0-4.69-1.962-10.831 0.852-13.645 2.388-2.559 8.528-1.535 12.963-2.218a303.682 303.682 0 0 0 131.075-49.462 304.45 304.45 0 0 0 120.672-157.768c11.939-34.965 16.373-70.953 15.862-107.709-0.086-8.784-0.341-17.567 0.853-26.351a76.752 76.752 0 0 1 152.566 13.218c-0.086 45.71-1.28 91.335-5.288 136.875-3.155 36.67-6.822 73.34-18.761 108.561a25.072 25.072 0 0 0-0.939 13.56c2.815 13.048 12.793 20.637 27.29 20.723 49.377 0.17 98.584 0.511 147.876 0.597 16.885 0.085 33.43 1.705 49.292 7.93a128.346 128.346 0 0 1 76.41 156.575c-7.845 26.863-17.056 53.3-26.522 79.651-32.918 92.103-68.735 183.097-104.297 274.176a65.24 65.24 0 0 1-24.134 29.25c-15.692 11.258-33.686 14.157-52.448 14.157H388.536c-2.388 0-4.776 0-7.164 0.256a25.413 25.413 0 0 0-19.273 38.717c5.8 9.381 14.839 12.28 25.584 12.28 124.594-0.17 249.274-0.085 373.868-0.085 30.7 0 58.843-7.845 83.489-26.607 16.032-12.195 29.507-26.693 37.011-45.966 13.645-34.965 27.46-69.93 41.02-105.065a5069.898 5069.898 0 0 0 85.28-232.218c6.993-20.978 13.474-42.213 14.668-64.471a171.498 171.498 0 0 0-20.126-93.808zM199.214 972.022c-31.468-0.17-62.937 0-94.49-0.085-31.213 0-53.556-22.003-53.556-53.13v-405.08c0-30.616 22.002-52.874 52.703-53.044 32.15-0.256 64.301 0 96.452-0.17 4.434 0 4.35 1.96 4.35 5.116v250.723l0.084 250.297c0 4.605-1.194 5.373-5.543 5.373z"></path></svg>';
const thumbsDown = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 1024 1024" fill="currentColor" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><path d="M48.464 631.08700001c48.699 62.928 143.57 58.704 250.284 56.35599999-2.209 25.413-4.421 50.832-6.63 76.246-19.954 124.422 6.40100001 225.148 107.739 243.653 25.172 4.597 57.261 1.206 76.246-6.63 50.216-20.73 66.13900001-69.316 76.244-130.943 6.03-36.774-4.886-78.582 3.314-111.053 10.411-41.21899999 42.025-71.825 74.588-91.163 39.233-23.301 89.891-37.523 142.546-46.411 84.102-14.197 199.811 28.752 228.737-39.78 12.732-30.167 4.972-88.664 4.97199999-127.629 0-98.887 0-197.80700001 1e-8-296.694 0.005-56.361 3.995-104-28.178-127.629-32.115-23.589-175.184-12.1-232.052-11.602 0 183.962 0 367.98499999 0 551.951-108.558 5.808-220.308 82.921-245.311 174.039-18.901 68.882 15.14099999 176.963-44.751 203.87300001-126.281 56.74-118.138-130.886-104.42199999-217.13100001 3.316-33.147 6.63-66.303 9.94499999-99.451 0-1.65700001 0-3.314 0-4.97200001-88.64 3.39599999-225.769 27.517-270.174-31.49199999-24.46-32.502-25.201-96.493-11.603-142.546 25.901-87.719 115.413-308.391 174.039-354.708 35.045-27.688 60.869-9.38899999 114.369-18.232 97.231-1.658 194.49-3.314 291.721-4.972 0-18.784 0-37.573 0-56.354-131.482 1.657-263.004 3.314-394.486 4.971-26.544 7.717-60.47599999 39.373-76.246 59.671-25.17 32.401-38.386 72.814-59.67100001 109.396-42.378 72.842-80.09 159.218-104.42299999 246.97-18.87300001 68.061-11.397 147.559 23.206 192.269zM802.631 74.165c46.958 0 93.93099999 0 140.89-1e-8 15.929 26.039 6.63 94.318 6.62999999 132.60100001-0.553 117.671-1.106 235.37700001-1.65699999 353.05-22.059 12.835-111.344 5.428-145.861 4.972 0-163.524 0-327.101 0-490.623z"></path></svg>';
const happyFace = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="M8 14s1.5 2 4 2 4-2 4-2"></path><line x1="9" y1="9" x2="9.01" y2="9"></line><line x1="15" y1="9" x2="15.01" y2="9"></line></svg>';
const NeutralFace = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="9" y1="9" x2="9.01" y2="9"></line><line x1="15" y1="9" x2="15.01" y2="9"></line><line x1="9" y1="15" x2="15" y2="15"></line></svg>';
const sadFace = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="M16 16s-1.5-2-4-2-4 2-4 2"></path><line x1="9" y1="9" x2="9.01" y2="9"></line><line x1="15" y1="9" x2="15.01" y2="9"></line></svg>';
const rateList = [
{ name: 'Excellent', value: 5, url: './img/thumbsup.svg', svg: thumbsUp },
{ name: 'Very Good', value: 4, url: './img/happyface.svg', svg: happyFace },
{ name: 'Fair', value: 3, url: './img/neutralface.svg', svg: NeutralFace },
{ name: 'Poor', value: 2, url: './img/sadface.svg', svg: sadFace },
{ name: 'Unacceptable', value: 1, url: './img/thumbsdown.svg', svg: thumbsDown }
];
const rateListMapped = rateList.reduce((r, v) => Object.assign(r, { [v.value + '']: v }), {});
const trueFalseList = [
{ name: 'Yes', value: 1, url: './img/thumbsup.svg', svg: thumbsUp },
{ name: 'No', value: 0, url: './img/thumbsdown.svg', svg: thumbsDown },
];
const webList = {
"default": 'ah',
"www.asiahighlights.com": 'ah',
"www.globalhighlights.com": 'gh',
};
</script>
<script defer>
// 定义名为 options-item 的新组件
Vue.component('options-item', {
props: ['question', 'si', 'qi', 'qitem', 'disabled'],
template: '<div :class="[\'options\', isWideScreen ? \'\': \'options-row-reverse\']">' +
// template: '<div :class="[\'options\', isWideScreen ? \'\': \'options-row1\']">' +
'<span class="rate-meaning" v-if="!isWideScreen"><span>{{selectedRatingText}}</span></span>' +
'<div class="radio-container" v-for="item in rateList">' +
'<input type="radio" v-bind:id="item.value + \'-\' + si + \'-\' + qi" v-bind:name="\'rate-\'+qitem.type+\'-\'+qitem.syc_sn+\'-\'+qitem.sn" v-bind:value="item.value" v-bind:disabled="disabled" v-model="selectItem" >' +
'<label v-bind:for="item.value+\'-\' + si + \'-\' + qi" class="radio-label"><span v-html="item.svg"></span> {{isWideScreen ? item.name : ""}}</label>' +
'</div>' +
'</div>',
data() {
return {
rateList: rateList,
selectItem: String(this.qitem.rate || (this.disabled ? 0 : 5)),
}
},
computed: {
isWideScreen() {
return window.innerWidth >= 768; // Adjust the threshold as needed
},
selectedRatingText() {
return (rateListMapped[this.selectItem] && rateListMapped[this.selectItem].name) || '';
},
},
});
Vue.component('options-item-star', {
props: ['question', 'si', 'qi', 'qitem', 'disabled'],
template: '<div><div class="star-rating">' +
'<template v-for="item in rateList"><input type="radio" v-bind:id="item.value + \'-\' + si + \'-\' + qi" v-bind:name="\'rate-\'+qitem.type+\'-\'+qitem.syc_sn+\'-\'+qitem.sn" v-bind:value="item.value" v-bind:disabled="disabled" v-model="selectItem" >' +
'<label v-bind:for="item.value+\'-\' + si + \'-\' + qi" :class="{\'checked\': selectItem>=item.value}">★</label></template>' +
'</div>' +
'<span class="rate-meaning"><span id="rate-text">{{selectedRatingText}}</span></span>' +
'</div>',
data() {
return {
rateList: rateList,
selectItem: String(this.qitem.rate || (this.disabled ? 0 : 5)),
}
},
computed: {
selectedRatingText() {
return (rateListMapped[this.selectItem] && rateListMapped[this.selectItem].name) || '';
// return rateListMapped[this.selectItem]?.name || '';
},
},
});
// yes or no
Vue.component('judgment-item', {
props: ['question', 'si', 'qi', 'qitem', 'disabled'],
template: '<div class="options options-row">' +
'<div class="radio-container" v-for="item in rateList">' +
'<input type="radio" v-bind:id="item.value + \'-\' + si + \'-\' + qi" v-bind:name="qitem.id" v-bind:value="item.value" v-bind:checked="qitem.rate===item.value" v-bind:disabled="disabled">' +
'<label v-bind:for="item.value+\'-\' + si + \'-\' + qi" class="radio-label"><span v-html="item.svg"></span> {{item.name}}</label>' +
'</div>' +
'</div>',
data() {
return {
rateList: trueFalseList
}
},
});
const defaultHeaders = { mode: 'no-cors', 'Sec-Fetch-Mode': 'no-cors' };
// const HOST = `http://202.103.68.144:890/service-CooperateSOA`; // debug: 0
const HOST = `https://p9axztuwd7x8a7.mycht.cn/service-CooperateSOA`;
const index = new Vue({
el: '#app',
computed: {
isWideScreen() {
return window.innerWidth >= 768; // Adjust the threshold as needed
},
drawWidth() {
return window.innerWidth < 768 ? Math.floor(window.innerWidth-40) : 760; // Adjust the threshold as needed
},
},
data() {
return {
timer: null,
error: false,
errorMsg: '',
webcode: 'ah',
param: {},
loading: false,
cityListPage: true,
resultPage: false,
cityList: [],
currentCity: {},
cityListOpen: false,
feedbackCity: {},
isFilled: false,
feedbackItemList: [],
feedbackItem: { guide: [], driver: [], experience: [], hotel: [] },
tourGuideList: [],
feedbackEvaluation: {},
group: {},
showPhotos: false,
signaturePad: null,
};
},
created() {
console.log('invoke vue', typeof this);
this.initData();
},
methods: {
initData() {
var hostname = window.location.hostname.toLowerCase();
this.webcode = webList[hostname] || webList.default;
var urlParams = new URLSearchParams(window.location.search);
for (const param of urlParams) {
this.param[param[0]] = param[1];
}
this.resultPage = !isEmpty(this.param.r);
var urlPath = window.location.pathname.replace('/customerfeedback/', '').split('-').filter(s => s);
urlPath = urlPath.length >= 3 ? urlPath : window.location.pathname.replace('/customerfeedback/', '').split('/');
if (urlPath.length > 0 && isEmpty(this.param.g)) {
this.param.g = urlPath[0];
this.param.v = urlPath[1];
this.param.l = urlPath[2] || 1;
this.resultPage = !isEmpty(urlPath[3]);
}
if (!(this.param.v && this.param.g)) {
this.error = true;
this.errorMsg = 'Invalid URL';
return false;
}
this.loading = true;
// console.log(this.resultPage);
this.getCityList();
},
getCityList() {
if (!(this.param.v && this.param.g)) {
return false;
}
const that = this;
get(
`${HOST}/get_feedback_city`,
{ GRI_SN: that.param.g, VEI_SN: that.param.v, lgc: this.param.l },
{ headers: { ...{} } }
).then((res) => {
that.loading = false;
that.error = res.cityList.length === 0;
that.errorMsg = 'No city found';
const mergeCity = groupBy(res.cityList, ele => isEmpty(ele.tourGuideId) ? 'unknown' : ele.tourGuideId);
const mergeCityA = Object.keys(mergeCity).reduce((r, tgid) => {
if ( (tgid !== 'unknown')) {
const uniqueCII_SN = mergeCity[tgid].map(v => v.cii_sn).filter((v, i, a) => a.indexOf(v) === i);
const uniqueCII_Name = mergeCity[tgid].map(v => v.cityName).filter((v, i, a) => a.indexOf(v) === i);
return r.concat(mergeCity[tgid].length > 1 ? [{
...mergeCity[tgid][0],
cii_sn: uniqueCII_SN.join('_'),
cii_sn_arr: uniqueCII_SN,
cityName: uniqueCII_Name.join(' & '),
feedback_Filled: mergeCity[tgid].reduce((r, v) => r+v.feedback_Filled, 0) > 0,
// cities: mergeCity[tgid],
}] : mergeCity[tgid][0] );
}
return r.concat(mergeCity[tgid]);
}, []);
// console.log(mergeCityA);
that.cityList = mergeCityA;
if (mergeCityA.length === 1) {
that.selectCity(mergeCityA[0]);
}
});
},
selectCity(city) {
window.scrollTo({ top: 100, behavior: 'smooth' });
this.cityListOpen = false;
if (this.currentCity.cii_sn === city.cii_sn) {
return false;
}
this.cityListPage = false;
this.loading = true;
const _param = {
GRI_SN: this.param.g,
VEI_SN: this.param.v,
// CITY_SN: city.cii_sn,
lgc: this.param.l
};
const selectedCity = Object.assign({}, city, _param);
// console.log(selectedCity);
this.currentCity = selectedCity;
this.feedbackItem.hotel = [];
if (selectedCity.cii_sn_arr) {
for (const iterator of selectedCity.cii_sn_arr) {
this.getData(Object.assign({}, _param, { CITY_SN: iterator }), true);
}
} else {
this.getData(Object.assign({}, _param, { CITY_SN: selectedCity.cii_sn }));
}
},
initSignature() {
var canvas = document.getElementById('signature-pad');
this.signaturePad = new SignaturePad(canvas, {
penColor: "rgb(50, 50, 50)",
});
},
clearSignature() {
// var data = this.signaturePad.toDataURL("image/svg+xml");
// console.log(data);
this.signaturePad.clear();
},
getData(param, continually = false) {
const that = this;
get(
`${HOST}/get_feedback_service_item`,
param,
{ headers: { ...{} } }
).then((res) => {
that.loading = false;
if (res.errcode !== 0) {
that.error = true;
that.errorMsg = 'Data error.';
return false;
}
that.feedbackCity[`city_${res.feedbackEvaluation[0].feedback_cii_sn}`] = res;
const itemGroup = groupBy(res.feedbackItemList, ele => ele.type);
that.feedbackItem.guide = itemGroup.W ? itemGroup.W : [];
that.feedbackItem.driver = itemGroup.Y ? itemGroup.Y : [];
let experience = [];
if (itemGroup['7']) {
experience = experience.concat(itemGroup['7']);
}
if (itemGroup.C) {
experience = experience.concat(itemGroup.C);
}
if (itemGroup.G) {
experience = experience.concat(itemGroup.G);
}
let hotel = [];
if (itemGroup.A) {
hotel = hotel.concat(itemGroup.A.map(function (ele) {
var newEle = Object.assign({}, ele);
newEle.Describe = `${ele.name} ${res.group[0].cityName}`;
return newEle;
}));
that.currentCity[`city_${res.feedbackEvaluation[0].feedback_cii_sn}`] = hotel;
}
if (continually) {
const mergeHotel = [].concat(that.feedbackItem.hotel, hotel);
that.feedbackItem.experience = [].concat(experience, mergeHotel);
that.feedbackItem.hotel = mergeHotel;
} else {
that.feedbackItem.experience = [].concat(experience, hotel);
}
that.feedbackItemList = res.feedbackItemList;
that.tourGuideList = res.tourGuideList;
that.feedbackEvaluation = res.feedbackEvaluation[0];
that.group = res.group[0];
// 已经填写过了
// that.isFilled = !isEmpty(res.feedbackEvaluation[0].signatureDataUrl);
that.isFilled = that.currentCity.feedback_Filled || !isEmpty(res.feedbackEvaluation[0].signatureDataUrl);
that.cityListPage = that.resultPage ? false : that.isFilled;
if (that.resultPage || that.isFilled) {
// that.signaturePad.fromDataURL(that.feedbackEvaluation.signatureDataUrl);
} else {
that.initSignature();
}
that.showPhotos = res.group[0].inTheEnd;
// alert("Thank you for completing the Feedback Evaluation. Once submitted the tour guide would not be able to view your comments. ");
});
},
submitForm() {
const that = this;
event.preventDefault();
if (that.signaturePad?.isEmpty()) {
alert("Please provide a signature first.");
} else {
that.loading = true;
// var data = that.signaturePad.toDataURL(); // default: image/png
var data = that.signaturePad.toDataURL("image/svg+xml");
var form = document.getElementById('myForm');
// Create a FormData instance
var formData = new FormData(form);
formData.append('signature', data);
// Convert the FormData to a plain object
var formValues = Array.from(formData.entries()).reduce((obj, [key, value]) => {
obj[key] = value;
return obj;
}, {});
const citySNList = that.currentCity.cii_sn_arr || [that.currentCity.cii_sn]
for (const iterator of citySNList) {
const rateArr = that.feedbackCity[`city_${iterator}`].feedbackItemList.map(ele => {
return { id: ele.id, rate: formValues[`rate-${ele.type}-${ele.syc_sn}-${ele.sn}`] || 0, };
});
// Submit the form manually
// console.log(formValues, rateArr);
// continue;
postForm(
`${HOST}/save_feedback`,
{
EOI_SN: that.group.EOI_SN,
GRI_SN: that.currentCity.GRI_SN,
VEI_SN: that.currentCity.VEI_SN,
// country_id:,
// tour_guide_id: that.currentCity.tourGuideId,
tour_guide_id: that.feedbackCity[`city_${iterator}`].feedbackEvaluation[0]?.tourGuideId || undefined,
city_sn: iterator,
use_the_photos: formValues.photo_permission || -1,
other_comments: formValues.comments,
feedback_id: that.feedbackCity[`city_${iterator}`].feedbackEvaluation[0]?.feedbackId || undefined,
service_item_answer: JSON.stringify(rateArr),
signature_data_url: formValues.signature,
},
{ headers: { ...{} } }
).then(res => {
that.loading = false;
if (res.errcode == 0) {
that.isFilled = true;
that.cityListPage = true;
that.currentCity = {};
} else { }
});
}
}
},
cancel() {
this.cityListPage = true;
this.currentCity = {};
},
toggleCityList() {
this.cityListOpen = !this.cityListOpen;
},
},
});
</script>
</body>
</html>