feat: 多语种

main
Lei OT 3 months ago
parent a1a8cc2a0d
commit 19174f56ed

@ -0,0 +1,273 @@
/**
* 选项的小图标
*/
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>';
var urlParams = new URLSearchParams(window.location.search);
var params = {};
for (const param of urlParams) {
params[param[0]] = param[1];
}
const webList = {
'default': 'gh',
'www.asiahighlights.com': 'ah',
'www.globalhighlights.com': 'gh',
};
var hostname = window.location.hostname.toLowerCase();
var webcode = webList[hostname] || 'gh';
var LanGuageCode = [
{
'LGC_LGC': '1',
'LGC_Language': 'English',
title: 'One Minute Feedback - Help Us Serve You Better',
tips: 'Thank you for completing the Feedback Evaluation. Once submitted the tour guide would not be able to view your comments.',
start: 'Did you enjoy your stay in the {city} area? Your honest feedback is appreciated to help us continually improve our service.', //
reference_no: 'Reference NO.:',
guide_name: "Guide's Name:",
city: 'City:',
questions: [
'How satisfied were you with your tour guide?',
'How about the Driver and Car/Van?',
'General Experience with:',
'Would you give Global Highlights permission to use photos taken by your tour guide(s) that contain your picture?',
'Any other comments that you would like to share with us?',
'Where is your desired destination for your next trip?',
'Signature:',
],
options_text: ['Excellent', 'Very Good', 'Fair', 'Poor', 'Unacceptable'],
judgement_text: ['Yes', 'No'],
btns: { clear: 'Clear', submit: 'Submit & Finish', cancel: 'Cancel' },
},
{ 'LGC_LGC': '2', 'LGC_Language': 'Chinese', title: '', tips: '', questions: [], options_text: [], judgement_text: [], btns: { clear: '', submit: '', cancel: '' } },
{
'LGC_LGC': '3',
'LGC_Language': 'Japanese',
title: '1分フィードバック - サービス改善のためのご協力をお願いします。',
tips: 'フィードバックのご回答、誠にありがとうございます。ご回答内容はツアーガイドが閲覧することはできませんので、ご安心ください。',
start: '{city}でのご滞在はいかがでしたか?今後のサービス向上のため、率直なご意見をお聞かせください。', //
reference_no: '予約番号:',
guide_name: 'ガイドの名前:',
city: '都市:',
questions: [
'ツアーガイドのご対応はいかがでしたか?',
'ドライバーおよび車両のご利用状況はいかがでしたか?',
'以下の点について、ご感想をお聞かせください。',
'アーガイドが撮影した写真お客様が写っているものを、chinaHighlightsの広告や宣伝素材として使用することを許可されますか',
'その他、ご意見やご要望がございましたら、ご自由にお書きください。',
'次回のご旅行で行きたい目的地はどこですか?',
'署名:',
],
options_text: ['とてもいい', '良い', '普通', '悪い', '非常に悪い'],
judgement_text: ['はい', 'いいえ'],
btns: { clear: 'クリア', submit: '送信', cancel: 'キャンセル' },
},
{
'LGC_LGC': '4',
'LGC_Language': 'German',
title: 'Ein-Minuten-Feedback - Helfen Sie uns, Ihnen besser zu dienen',
tips: 'Vielen Dank, dass Sie das Feedback ausgefüllt haben. Sobald es abgeschickt wurde, kann der Reiseleiter Ihre Kommentare nicht einsehen.',
start: 'Haben Sie Ihren Aufenthalt im Bereich {city} genossen? Ihr ehrliches Feedback hilft uns, unseren Service ständig zu verbessern.', //
reference_no: 'Referenz-Nr.:',
guide_name: 'Name des Reiseleiters:',
city: 'Stadt:',
questions: [
'Wie zufrieden waren Sie mit Ihrem Reiseleiter oder Ihrer Reiseleiterin?',
'Wie war der Fahrer und das Auto/Van?',
'Allgemeine Erfahrung mit:',
'Würden Sie Global Highlights die Erlaubnis geben, Fotos zu verwenden, die von Ihrem Reiseleiter gemacht wurden und auf denen Sie abgebildet sind?',
'Gibt es weitere Kommentare, die Sie mit uns teilen möchten?',
'Wo liegt Ihr gewünschtes Ziel für Ihre nächste Reise?',
'Unterschrift:',
],
options_text: ['Ausgezeichnet', 'Sehr gut', 'Ausreichend', 'Schlecht', 'Inakzeptabel'],
judgement_text: ['Ja', 'Nein'],
btns: { clear: 'Löschen', submit: 'Fertig & Absenden', cancel: 'Abbrechen' },
},
{
'LGC_LGC': '5',
'LGC_Language': 'French',
title: "Retour d'une Minute - Aidez-nous à Mieux Vous Servir !",
tips: "Merci de compléter l'Évaluation de Retour. Une fois soumise, le guide touristique ne pourra pas voir vos commentaires.",
start: 'Avez-vous apprécié votre séjour dans la région de {city} ? Vos commentaires honnêtes sont appréciés pour nous aider à améliorer continuellement notre service.', //
reference_no: 'Numéro de Référence :',
guide_name: 'Nom du Guide :',
city: 'Ville :',
questions: [
'Êtes-vous satisfait(e) de votre guide touristique ?',
"Qu'en est-il du chauffeur et de la voiture/van ?",
'Expérience générale avec :',
"Donnez-vous à Asia Highlights la permission d'utiliser les photos prises par votre/vos guide(s) contenant votre image ?",
"Avez-vous d'autres commentaires que vous aimeriez partager avec nous ?",
'Quelle est votre destination souhaitée pour votre prochain voyage ?',
'Signature :',
],
options_text: ['Excellent', 'Très bien', 'Moyen', 'Médiocre', 'Inacceptable'],
judgement_text: ['Oui', 'Non'],
btns: { clear: 'Effacer', submit: 'Terminer & Soumettre', cancel: 'Annuler' },
},
{
'LGC_LGC': '6',
'LGC_Language': 'Spanish',
title: 'Comentarios de Un Minuto - ¡Ayúdenos a Ofrecerle Un Mejor Servicio!',
tips: 'Gracias por completar la Evaluación de Comentarios. Una vez enviada, el guía no podrá ver sus comentarios.',
start: '¿Disfrutó de su estancia en la zona de {city}? Agradecemos sus comentarios sinceros para ayudarnos a mejorar continuamente nuestro servicio.', //
reference_no: 'NO. de Referencia:',
guide_name: 'Nombre de Guía:',
city: 'Ciudad:',
questions: [
'¿Qué tan satisfecho estaba con su Guía?',
'¿Cómo estaba el Conductor y el Coche/Van?',
'Experiencia General con:',
'¿Le daría permiso a nuestra agencia para usar fotos tomadas por su(s) guía(s) que contengan su imagen?',
'¿Algún otro comentario que le gustaría compartir con nosotros?',
'¿Cuál es su destino deseado para su próximo viaje?',
'Firma:',
],
options_text: ['Excelente', 'Muy Bueno', 'Justo', 'Pobre', 'Inaceptable'],
judgement_text: ['Sí', 'No'],
btns: { clear: 'Limpiar', submit: 'Terminar & Enviar', cancel: 'Cancelar' },
},
{
'LGC_LGC': '7',
'LGC_Language': 'Russian',
title: 'Обратная связь за одну минуту - Поможет Нам лучше обслуживать Вас',
tips: 'Благодарим вас за заполнение формы обратной связи. После отправки Ваш гид не сможет просмотреть ваши комментарии. ',
start: 'Понравилось ли вам пребывание в {city}? Мы будем признательны за ваши честные отзывы, которые помогут нам постоянно улучшать наш сервис.',
reference_no: 'Номер запрос:',
guide_name: 'Имя гида',
city: 'Город',
questions: [
'Вы довольны работой Вашего гида?',
'Вы довольны работой Вашего водителя?',
'Оценка всего тура в целом',
'Разрешаете ли Вы нам использовать Ваши фотографии на веб-сайте Asia Highlights? ',
'Есть еще какие-нибудь комментарии, которыми Вы хотели бы поделиться с нами?',
'Куда бы вы хотели отправиться в свою следующую поездку?',
'Подпись:',
],
options_text: ['Отлично', 'Очень хорошо', 'Средне', 'Не оправдало ожиданий', 'Неприемлемо'],
judgement_text: ['Да', 'Нет'],
btns: { clear: 'Ясно', submit: 'Завершить и отправить', cancel: 'Отменить' },
},
{
'LGC_LGC': '8',
'LGC_Language': 'Italian',
title: 'Feedback in un Minuto Aiutaci a Servirti Meglio!',
tips: 'Grazie per aver completato la valutazione. Una volta inviato, la guida non potrà visualizzare i tuoi commenti.',
start: 'Ti sei divertito/a durante il tuo soggiorno a {city}? Apprezziamo il tuo feedback onesto per aiutarci a migliorare continuamente il nostro servizio.',
reference_no: 'Numero di riferimento:',
guide_name: 'Nome della guida:',
city: 'Città:',
questions: [
'Quanto sei soddisfatto/a della guida locale?',
"Come valuti l'autista e il veicolo (auto/pulmino)?",
'Esperienza generale con:',
'Autorizzi Global Highlights a utilizzare foto scattate dalla guida che ti ritraggono?',
'Altri commenti che vorresti condividere con noi?',
'Qual è la tua destinazione desiderata per il prossimo viaggio?',
'Firma:',
],
options_text: ['Ottimo', 'Molto buono', 'Sodddisfatto', 'Al di sotto delle aspettative', 'Inacettabile'],
judgement_text: ['Sì', 'No'],
btns: { clear: 'Azzera', submit: 'Termina e invia', cancel: 'Annulla' },
},
];
var lanCodeMapped = LanGuageCode.reduce((r, v) => Object.assign(r, { [v.LGC_LGC]: v }), {});
var i18n = lanCodeMapped[String(params.l || 1)];
start_template = i18n.start.replace('{city}', '<span class="text-primary">{{city}}</span>');
Vue.component('start-eva-text', {
props: ['city'],
template: '<p>' + start_template + '</p>',
});
const rateList = [
{ name: i18n.options_text[0], value: 5, url: './img/thumbsup.svg', svg: thumbsUp },
{ name: i18n.options_text[1], value: 4, url: './img/happyface.svg', svg: happyFace },
{ name: i18n.options_text[2], value: 3, url: './img/neutralface.svg', svg: NeutralFace },
{ name: i18n.options_text[3], value: 2, url: './img/sadface.svg', svg: sadFace },
{ name: i18n.options_text[4], value: 1, url: './img/thumbsdown.svg', svg: thumbsDown },
];
const rateListMapped = rateList.reduce((r, v) => Object.assign(r, { [v.value + '']: v }), {});
const trueFalseList = [
{ name: i18n.judgement_text[0], value: 1, url: './img/thumbsup.svg', svg: thumbsUp },
{ name: i18n.judgement_text[1], value: 0, url: './img/thumbsdown.svg', svg: thumbsDown },
];
// 定义名为 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,
};
},
});

@ -8,7 +8,7 @@
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<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}.form-container{counter-reset: hq;}h4::before {counter-increment: hq; content: counter(hq) ". ";}.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>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}form.form-container{counter-reset: hq;}form.form-container h4::before {counter-increment: hq; content: counter(hq) ". ";}.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;max-width: 140px;}.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: 8rem;}.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>
@ -27,13 +27,14 @@
<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'">
<a href="/" 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>
<!-- <h1>{{i18n.title}}</h1> -->
<h1></h1>
</div>
<div class="header-m">
<h1>One Minute Feedback - Help Us Serve You Better</h1>
<h1></h1>
</div>
<div class="form-container" id="main">
@ -59,7 +60,7 @@
</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>
<h4 v-if="!isFilled">{{i18n.tips}}</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.cii_sn === currentCity.cii_sn ? 'active' : '' ]">{{city.cityName}}</li>
@ -69,29 +70,30 @@
<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>
<!-- <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> -->
<start-eva-text :city="currentCity.cityName" ></start-eva-text>
<div class="info-container">
<div class="info-item">
<h3>Reference NO.:</h3>
<h3>{{i18n.reference_no}}</h3>
<p id="referenceNo">{{group.groupNumber}}</p>
</div>
<div class="info-item">
<h3>Guide's Name:</h3>
<h3>{{i18n.guide_name}}</h3>
<p id="guideName">{{group.tourGuideName}}</p>
</div>
<div class="info-item">
<h3>City:</h3>
<h3>{{i18n.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 >{{i18n.tips}}</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>How satisfied were you with your tour guide?</h4>
<h4>{{i18n.questions[0]}}</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>
@ -99,7 +101,7 @@
</div>
</div>
<div class="question">
<h4>How about the Driver and Car/Van?</h4>
<h4>{{i18n.questions[1]}}</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>
@ -107,7 +109,7 @@
</div>
</div>
<div class="question" v-if="feedbackItem.experience.length > 0">
<h4>General Experience with:</h4>
<h4>{{i18n.questions[2]}}</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>
@ -115,11 +117,11 @@
</div>
</div>
<div class="question ">
<h4>Would you give <span>{{webcode=='ah' ? 'Asia' : 'Global'}}</span> Highlights permission to use photos taken by your tour guide(s) that contain your picture?</h4>
<h4>{{i18n.questions[3]}}</h4>
<judgment-item question="photo" v-bind:qitem="{id: 'photo_permission', rate: feedbackEvaluation[0].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>
<h4>{{i18n.questions[4]}}</h4>
<div v-if="resultPage">
<p v-for="eva in feedbackEvaluation" v-bind:key="eva.feedbackId">
{{eva.otherComments ? eva.otherComments : ''}}
@ -128,7 +130,7 @@
<textarea v-else name="comments" rows="4" v-bind:value="feedbackEvaluation[0].otherComments" v-bind:disabled="resultPage"></textarea>
</div>
<div class="feedback question">
<h4>Where is your desired destination for your next trip?
<h4>{{i18n.questions[5]}}
</h4>
<div v-if="resultPage">
<p v-for="eva in feedbackEvaluation" v-bind:key="eva.feedbackId">
@ -137,11 +139,11 @@
<textarea v-else name="desired_next" rows="4" v-bind:value="feedbackEvaluation[0].desired_next" v-bind:disabled="resultPage"></textarea>
</div>
<div class="signature">
<h4>Signature:</h4>
<h4>{{i18n.questions[6]}}</h4>
<div class="signature-container" v-if="!resultPage">
<canvas id="signature-pad" class="signature-pad" v-bind:style="{'width': drawWidth+'px', 'height':'200px'}" ></canvas>
<div class="button-container">
<button type="button" id="clear" class="button" v-on:click="clearSignature()">Clear</button>
<button type="button" id="clear" class="button" v-on:click="clearSignature()">{{i18n.btns.clear}}</button>
</div>
</div>
<div v-else>
@ -149,8 +151,8 @@
</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>
<button type="button" id="submit_a" class="form-btn submit-btn" v-on:click="submitForm">{{i18n.btns.submit}}</button>
<button type="button" id="back" class="form-btn cancel-btn" v-on:click="cancel" v-if="cityList.length > 1">{{i18n.btns.cancel}}</button>
</template>
</form>
@ -177,103 +179,18 @@
</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>';
<script async>
var rnd = Math.random();
var script0 = document.createElement('script');
script0.src = './components.js?rnd=' + rnd;
document.head.appendChild(script0);
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',
script0.onload = function() {
var script = document.createElement('script');
script.src = './index.js?rnd=' + rnd;
document.head.appendChild(script);
};
</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
}
},
});
</script>
<script defer >
var script = document.createElement('script');
script.src = './index.js?rnd=' + Math.random();
document.head.appendChild(script);
</script>
</body>
</html>

@ -21,6 +21,8 @@ const index = new Vue({
errorMsg: '',
webcode: 'ah',
i18n: { title: ''},
param: {},
loading: false,
@ -53,10 +55,8 @@ const index = new Vue({
},
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];
}
@ -73,14 +73,20 @@ const index = new Vue({
this.debug = !isEmpty(urlPath[4]);
this.resultPage = !isEmpty(urlPath[4]) ? false : !isEmpty(urlPath[3]);
}
console.log(this.param, 'debug', this.debug);
console.log(this.param);
if (!(this.param.v && this.param.g)) {
this.error = true;
this.errorMsg = 'Invalid URL';
return false;
}
// console.log('resultPage', this.resultPage);
this.i18n = lanCodeMapped[String(this.param.l)];
var that = this;
Array.from(document.getElementsByTagName('h1')).forEach(function(ele){
ele.textContent = that.i18n.title;
});
this.loading = true;
console.log('resultPage', this.resultPage);
// console.log('resultPage', this.loading);
this.getCityList();
},
getCityList() {
@ -174,7 +180,7 @@ const index = new Vue({
},
clearSignature() {
var data = this.signaturePad.toDataURL('image/svg+xml');
console.log(data);
// console.log(data);
this.signaturePad.clear();
},
getData(param, continually = false) {

Loading…
Cancel
Save