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

778 lines
31 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. <template>
  2. <div
  3. class="service-content tw-mb-[60px] tw-grid tw-grid-cols-1 tw-gap-[30px] md:tw-mb-[100px] xl:tw-px-[60px] xl:tw-max-w-screen-xl xl:tw-mx-auto xl:tw-grid-cols-[auto_364px]">
  4. <mobileFixTopBar ref="stickySwiper" :fixBar="fixBar" :currStep="currStep" :list="fixBarList"></mobileFixTopBar>
  5. <section class="step sercion-1 tw-w-full md:tw-px-[30px] xl:tw-px-0 xl:tw-col-span-2">
  6. <div class="tw-mt-[20px] md:tw-mb-[11px] md:tw-mt-[40px]">
  7. <Breadcrumbs></Breadcrumbs>
  8. </div>
  9. <div v-if="content.banners.length" class="tw-w-full">
  10. <slideshow :banners="content.banners"></slideshow>
  11. </div>
  12. </section>
  13. <section class="sercion-2 tw-px-[30px] md:tw-px-[30px] xl:tw-px-0 xl:tw-col-start-1 xl:tw-row-start-2">
  14. <h1 class="t16 tw-mb-[18px] md:t24">{{ content.name }}</h1>
  15. <div v-if="content.supplier"
  16. class="supplier tw-flex tw-items-center tw-mb-[20px] tw-text-base-primary t14 md:tw-mb-[30px] md:t16 md:tw-font-normal">
  17. <img :src="content.supplier.logo" class="tw-max-w-[40px] md:tw-max-w-[80px]" />
  18. <div class="t14 tw-font-normal tw-ml-[10px] md:t18 md:tw-font-normal">
  19. {{ content.supplier.brand }}
  20. </div>
  21. </div>
  22. <div class="editor-styleguide tw-text-base-primary" v-html="content.highlights"></div>
  23. </section>
  24. <section
  25. class="sercion-3 tw-grid tw-grid-cols-1 tw-gap-[30px] md:tw-gap-[40px] md:tw-px-[30px] xl:tw-px-0 xl:tw-col-start-1 xl:tw-row-start-3">
  26. <div ref="packageOptions" id="packageOptions" class="step">
  27. <div class="tw-px-[30px] md:tw-px-0">
  28. <h2 class="title-icon-left t16 tw-mb-[20px] md:t20">
  29. {{ $t("Package Options") }}
  30. </h2>
  31. <p>{{ $t("Select date and package options") }}</p>
  32. </div>
  33. <div class="tw-w-full tw-bg-neutrals-100 tw-p-[20px] md:tw-p-[30px]">
  34. <div class="">
  35. <div class="group tw-mb-[40px]" v-if="content.dateStatus == 'active'">
  36. <h3 class="t14 tw-font-bold tw-mb-[20px] md:t16">
  37. {{ $t("Select Date") }}
  38. </h3>
  39. <selectDate :start="content.start" :end="content.end" @selected="selectDates = $event"></selectDate>
  40. </div>
  41. <div class="group tw-mb-[40px]" v-if="content.timeStatus == 'active'">
  42. <h3 class="t14 tw-font-bold tw-mb-[20px] md:t16">
  43. {{ $t("Time") }}
  44. </h3>
  45. <timeButtonGroup v-if="content.times.length > 0" :list="content.times" @selected="selectTime = $event">
  46. </timeButtonGroup>
  47. </div>
  48. <div class="group tw-mb-[20px]">
  49. <h3 class="t14 tw-font-bold tw-mb-[20px] md:t16">
  50. {{ $t("Package Type") }}
  51. </h3>
  52. <typeGroup :packages="content.packages" @type="changeType($event)"></typeGroup>
  53. </div>
  54. <template v-for="(item, index) in content.packages">
  55. <div :key="index" v-if="index === activePackage" class="">
  56. <div v-if="index == 1">
  57. <div class="group tw-mb-[20px]">
  58. <h3 class="t14 tw-font-bold tw-mb-[20px] md:t16">
  59. {{ item.plan_title }}
  60. </h3>
  61. </div>
  62. <buttonGroup :list="item.choices" @choicesIdx="choicesIdx($event)"></buttonGroup>
  63. <customSelectGroup ref="customSelectGroup" :label="'Specification'" :package="item.specifications"
  64. :choices="item.choices" :choicesIndex="choicesIndex" @totalPrice="customPlanPrice = $event">
  65. </customSelectGroup>
  66. </div>
  67. <div v-else>
  68. <selectGroup :label="'Specification'" :package="item.specifications"
  69. @totalPrice="totalPrice = $event"></selectGroup>
  70. </div>
  71. </div>
  72. </template>
  73. <div v-show="content.additionalServices.length > 0" class="group tw-mb-[20px]">
  74. <additionalGroup :label="'Additional Services'" :package="content.additionalServices"
  75. @totalPrice="additionTotalPrice = $event"></additionalGroup>
  76. </div>
  77. <div class="md:tw-flex md:tw-justify-between md:tw-items-center">
  78. <div class="tw-flex tw-justify-between tw-items-start md:tw-w-full md:tw-basis-10/12">
  79. <div class="tw-flex tw-flex-col tw-justify-center">
  80. <div class="tw-flex tw-items-center tw-mb-[8px] md:tw-mb-0">
  81. <div class="tw-body-4 tw-text-neutrals-900 tw-mr-[10px] md:t24">
  82. ${{ finalPrice }} {{ currency }}
  83. </div>
  84. <!-- <div
  85. class="tw-body-4 tw-text-base-hint tw-line-through md:t20 md:tw-font-medium"
  86. >
  87. ${{ totalPrice.toLocaleString() }}
  88. </div> -->
  89. </div>
  90. <div class="tw-hidden tw-body-4 tw-text-neutrals-600 md:tw-hidden">
  91. Deposit fee: $5 {{ currency }} (10%)
  92. </div>
  93. </div>
  94. <like></like>
  95. </div>
  96. <button
  97. class="tw-transition tw-btn-md tw-text-white tw-border tw-border-solid tw-border-primary-default tw-bg-primary-default tw-py-[8.5px] tw-mt-[20px] tw-w-full tw-rounded-xl md:tw-mt-0 md:tw-ml-[36px] md:tw-w-auto md:tw-basis-2/12 disabled:tw-bg-neutral-100 disabled:tw-text-base-disable disabled:tw-border-neutral-200"
  98. @click="bookNow" :disabled="btnDisabled">
  99. {{ $t("Book Now") }}
  100. </button>
  101. </div>
  102. </div>
  103. </div>
  104. </div>
  105. <div id="serviceDetails" class="serviceDetails step">
  106. <div class="tw-px-[30px] md:tw-px-0">
  107. <h2 class="title-icon-left t16 tw-mb-[20px] md:t20 xl:tw-font-bold">
  108. {{ $t("Service Details") }}
  109. </h2>
  110. <div v-if="content.details.length < 800">
  111. <div ref="details" class="editor-styleguide tw-text-base-primary t14 md:t16 md:tw-font-normal"
  112. v-html="content.details"></div>
  113. </div>
  114. <div v-else>
  115. <div :class="[
  116. button.details ? 'seeMore-hide' : 'seeMore-show',
  117. 'editor-styleguide tw-text-base-primary tw-transition t14 md:t16 md:tw-font-normal',
  118. ]" ref="details" v-html="content.details"></div>
  119. <button v-show="seeMore.details" :class="[
  120. 'seeMore tw-transition tw-btn-md tw-text-primary-1 tw-border tw-border-solid tw-border-primary-1 tw-px-[30px] tw-py-[8.5px] tw-mt-[20px] tw-w-full tw-rounded-xl hover:tw-bg-primary-3 xl:hover:tw-bg-transparent xl:tw-border-none',
  121. button.details ? '' : 'open',
  122. ]" @click="opendetail()">
  123. {{ $t(seeMoreDetailsText) }}
  124. </button>
  125. </div>
  126. </div>
  127. </div>
  128. <div id="cancellationPolicy" class="cancellationPolicy step tw-px-[30px] md:tw-px-0">
  129. <h2 class="title-icon-left t16 tw-mb-[20px] md:t20 xl:tw-font-bold">
  130. {{ $t("Cancellation Policy") }}
  131. </h2>
  132. <div v-if="content.cancellation_policy.length < 800">
  133. <div ref="cancellation_policy" class="editor-styleguide tw-text-base-primary t14 md:t16 md:tw-font-normal"
  134. v-html="content.cancellation_policy">
  135. </div>
  136. </div>
  137. <div v-else>
  138. <div :class="[
  139. button.cancellation_policy ? 'seeMore-hide' : 'seeMore-show',
  140. 'editor-styleguide tw-text-base-primary tw-transition t14 md:t16 md:tw-font-normal',
  141. ]" ref="cancellation_policy" v-html="content.cancellation_policy"></div>
  142. <button v-show="seeMore.cancellation_policy" :class="[
  143. 'seeMore tw-transition tw-btn-md tw-text-primary-1 tw-border tw-border-solid tw-border-primary-1 tw-px-[30px] tw-py-[8.5px] tw-mt-[20px] tw-w-full tw-rounded-xl hover:tw-bg-primary-3 xl:hover:tw-bg-transparent xl:tw-border-none',
  144. button.cancellation_policy ? '' : 'open',
  145. ]" @click="openCancellationPolicy()">
  146. {{ $t(seeMoreCancellationPolicyText) }}
  147. </button>
  148. </div>
  149. </div>
  150. <div id="faq" ref="faq" class="step tw-px-[30px] md:tw-px-0">
  151. <h2 class="title-icon-left t16 tw-mb-[20px] md:t20 xl:tw-font-bold">
  152. {{ $t("FAQ") }}
  153. </h2>
  154. <faq :faq="content.faq" class="tw-z-[8]"></faq>
  155. </div>
  156. <div id="contactUs" class="step tw-px-[30px] md:tw-px-0">
  157. <h2 class="title-icon-left t16 tw-mb-[20px] md:t20 xl:tw-font-bold">
  158. {{ $t("Contact Us") }}
  159. </h2>
  160. <div class="tw-body-3 tw-text-base-primary tw-mb-[20px]">
  161. 886-2-2725-5000
  162. </div>
  163. <div class="tw-body-3 tw-text-base-primary">info@showeasy.com</div>
  164. </div>
  165. <div :class="[
  166. 'tw-bg-white tw-flex tw-flex-cols tw-justify-between tw-items-center tw-px-[30px] tw-py-[16px] tw-w-full',
  167. fixBar
  168. ? 'tw-fixed tw-left-[0px] tw-bottom-[0px] tw-z-[8] tw-shadow-[1px_0px_2px_rgba(0,0,0,0.25)]'
  169. : 'tw-hidden',
  170. ]">
  171. <div :class="[
  172. 'tw-flex tw-flex-col tw-justify-between tw-items-start tw-grow md:tw-w-full md:tw-flex-row md:tw-items-center',
  173. ]">
  174. <div class="tw-flex tw-items-center tw-mb-[12px] md:tw-mb-0">
  175. <div class="t16 tw-text-neutrals-900 tw-mr-[10px] md:t20 md:tw-mr-0">
  176. ${{ finalPrice }} {{ currency }}
  177. </div>
  178. </div>
  179. <div class="tw-flex tw-justify-center tw-items-center tw-w-full md:tw-w-fit">
  180. <like></like>
  181. <button
  182. class="tw-transition tw-whitespace-nowrap tw-body-4 tw-text-white tw-border tw-border-solid tw-border-primary-default tw-bg-primary-default tw-ml-[22px] tw-px-[24px] tw-py-[8.5px] tw-rounded-xl tw-w-full md:tw-body-2 md:tw-min-w-[130px] md:tw-max-w-[130px] md:tw-mt-0 disabled:tw-bg-neutral-100 disabled:tw-text-base-disable disabled:tw-border-neutral-200"
  183. @click="bookNow" :disabled="btnDisabled">
  184. {{ $t("Book Now") }}
  185. </button>
  186. </div>
  187. </div>
  188. </div>
  189. </section>
  190. <section
  191. class="sercion-4 tw-px-[30px] tw-grid tw-grid-cols-1 tw-gap-[40px] tw-z-[8] md:tw-px-[30px] xl:tw-px-0 xl:tw-col-start-1 xl:tw-row-start-4">
  192. <detailsModal :detail="content.details"></detailsModal>
  193. <cancellationPolicyModal :cancellationPolicy="content.cancellation_policy"></cancellationPolicyModal>
  194. </section>
  195. <section class="sercion-5 tw-hidden md:tw-px-[30px] xl:tw-px-0 xl:tw-block xl:tw-row-start-2 xl:tw-row-end-5">
  196. <div class="tw-mb-[40px]">
  197. <sidebarSelectOption :totalPrice="finalPrice" :currency="currency" :confirmationTime="content.confirmationTime">
  198. </sidebarSelectOption>
  199. </div>
  200. <sideBarMenu :fixBarList="fixBarList" :currStep="currStep"></sideBarMenu>
  201. </section>
  202. <section class="step sercion-6 tw-pl-[30px] tw-w-full xl:tw-px-0 xl:tw-col-span-2">
  203. <h2 class="title-icon-left t16 md:t20 xl:tw-font-bold">
  204. {{ $t("You might like ...") }}
  205. </h2>
  206. <youMightLikeslideshow :list="list" :countrycode="countrycode" :regionName="regionName"></youMightLikeslideshow>
  207. </section>
  208. </div>
  209. </template>
  210. <script>
  211. import Breadcrumbs from "@/components/Breadcrumbs";
  212. import slideshow from "@/components/swiper/serviceContent.vue";
  213. import detailsModal from "@/components/service/contentModal/DetailsModal.vue";
  214. import cancellationPolicyModal from "@/components/service/contentModal/cancellationPolicyModal.vue";
  215. import selectDate from "@/components/service/content/selectDate.vue";
  216. import typeGroup from "@/components/service/content/typeGroup.vue";
  217. import selectGroup from "@/components/service/content/selectGroup.vue";
  218. import customSelectGroup from "@/components/service/content/customSelectGroup.vue";
  219. import additionalGroup from "@/components/service/content/additionalGroup.vue";
  220. import faq from "@/components/service/content/faq.vue";
  221. import sidebarSelectOption from "@/components/service/content/sidebarSelectOption.vue";
  222. import sideBarMenu from "@/components/service/content/sideBarMenu.vue";
  223. import Swiper from "swiper/bundle";
  224. import { scrollama } from "scrollama";
  225. import youMightLikeslideshow from "@/components/swiper/youMightLike.vue";
  226. import mobileFixTopBar from "@/components/swiper/mobileFixTopBar.vue";
  227. import timeButtonGroup from "@/components/service/content/timeButtonGroup";
  228. import buttonGroup from "@/components/service/content/buttonGroup.vue";
  229. import like from "@/components/newComponent/like/like.vue";
  230. export default {
  231. auth: false,
  232. components: {
  233. Swiper,
  234. scrollama,
  235. Breadcrumbs,
  236. slideshow,
  237. detailsModal,
  238. cancellationPolicyModal,
  239. selectDate,
  240. typeGroup,
  241. timeButtonGroup,
  242. buttonGroup,
  243. selectGroup,
  244. customSelectGroup,
  245. additionalGroup,
  246. faq,
  247. sidebarSelectOption,
  248. sideBarMenu,
  249. youMightLikeslideshow,
  250. mobileFixTopBar,
  251. like,
  252. },
  253. data() {
  254. return {
  255. apiUrl: process.env.SERVICE_CONSOLE,
  256. btnDisabled: process.env.ENV == 'production',
  257. currStep: null,
  258. stickySwiper: null,
  259. content: {
  260. banners: [{
  261. banner_id: '123e41',
  262. image: require('/assets/img/service_banner.png')
  263. },{
  264. banner_id: '123e31',
  265. image: require('/assets/img/service_banner.png')
  266. },{
  267. banner_id: '123e12',
  268. image: require('/assets/img/service_banner.png')
  269. }],
  270. country: null,
  271. city: null,
  272. name: "科隆機場接送服務",
  273. highlights: '<ul><li>接送車輛皆為車況良好的八人座(含司機)賓士商務車。</li><li>安排熟悉路況及駕駛經驗豐富的當地專業導遊擔任司機,免費提供旅宿與交通安排基本諮詢服務。</li><li>司機精通德語與華語,可加價選購英文服務。</li><li>本服務包含於出關處舉牌迎賓,提供親切專業的接送服務。</li></ul>',
  274. details: '<div data-v-5da7b8eb="" class="seeMore-show tw-text-base-primary tw-transition t14 md:t16 md:tw-font-normal"><h2>經典服務經驗</h2><p><br></p><p>從2020起,柏林政府啟用新機場,此機場位於柏林東南郊區,離市中心遙遠,由機場出發至市中心,需要多次轉車,柏林公眾交通系統,播報站名以德文為主,容易因為聽不懂德文而錯失過站,此外地鐵超過百年,建造時間較早,諸多車站沒有規劃電梯,必須手搬著行李,自行上下樓梯,對旅客而言,行動非常不便。</p><p><br></p><p>為解決上述問題,本公司提供華人專業導遊接送服務,提前抵達機場,在您的出機口舉牌等待您的到來,接送車輛賓士8人座(含司機)商務車,駕駛人員接送經驗豐富,熟悉當地路況,華文與德文流利,以最舒適的方式,從機場送達您想去的地點</p><p><br></p><h2>商品詳細說明</h2><ul><li>預定接機服務請至少於5個日曆天之前完成訂購與付費手續。</li><li>八人座(含司機)賓士商務車,最多可以搭乘7位貴賓,行李數量因空間有限需限制,搭載行李的數量會因乘客人數增加而對應減少,</li></ul><p> 請參考如下資訊並請於訂購本服務時提供搭乘人數與行李數量:</p><p> 乘客1~4人,可搭載4件可置於腿上的隨身行李及4件28吋的托運行李。</p><p> 乘客5~7人,可搭載7件可置於腿上的隨身行李及2件28吋的托運行李。</p><ul><li>用車距離為30公里以內,每超過 一公里加收5歐元,費用請現場支付給司機。</li><li>機場接機等待時間為飛機落地起算1小時以內。</li><li>本服務限定一個下車地,可加價選購增加停靠地點服務,服務終止時間以最後一位乘客抵達下車地點為準。</li><li>搭車前24小時將以電子郵件及簡訊提供給客戶必要資訊,包括司機的名字、手機、車牌等,而司機會在事先約定好的位置手持歡迎牌等待。</li><li>若遇航班提早抵達,仍須依您原預約時間提供服務,請恕無法提前;若您選擇自行離開放棄服務則費用恕不退還。</li><li>若乘車現場發現與訂購人數或行李數不符,導致超載,司機有權拒絕提供服務,恕不退費。</li><li>因車輛安排考量,預約之貴賓如欲變更時間或預約資料,需於原預約時間(班機抵達時間)之 48小時前告知,如未於可受理異動時間之前告知,預約時間與接送資料無法變更。</li></ul><p><br></p><h2>商品購買說明</h2><p><br></p><ul><li>可加價指定司機具備英文溝通能力的服務 </li><li>可加價增加停靠地點(每新增一處停靠地點加收20歐元),若事前無訂購增加停靠地點,則請於當日現場給付現金給司機。 </li><li>提供兒童安全座椅及兒童增高墊加價租用服務,如有特殊需求(如兒童安全座椅)須事前告知,以便安排,當天現場恕無法追加。 </li><li>如需協助辦理飯店入住,請點選加值服務,現場須提供飯店飯店預定證明及入住人護照正本。 </li></ul><p><br></p></div>',
  275. cancellation_policy: "<ul><li>所選日期 5天(含)之前取消,收取手續費 0%</li><li>所選日期 4天(含)之前取消,收取手續費 50%</li><li>所選日期 3天(含)之前取消,收取手續費 100%</li></ul>",
  276. saved: false,
  277. confirmation_time: 24,
  278. supplier: {
  279. logo: require('/assets/img/Footer.png'),
  280. brand: 'ShowEasy'
  281. },
  282. available_sections: null,
  283. timeStatus: 'active',
  284. dateStatus: 'active',
  285. times: [{
  286. start_time: '2023-02-06',
  287. end_time: '2023-03-06',
  288. },{
  289. start_time: '2023-02-06',
  290. end_time: '2023-03-06',
  291. },{
  292. start_time: '2023-02-06',
  293. end_time: '2023-03-06',
  294. }],
  295. start: '2023-02-06',
  296. end: '2023-06-06',
  297. faq: [{
  298. question: '超過限定里程(30公里)如何計費加價?',
  299. answer: '每超過一公里加收5歐元,費用請現場支付給司機。',
  300. }],
  301. confirmationTime: '',
  302. packages: [{
  303. package_id: '1',
  304. name: '嘉義',
  305. photo: require('/assets/img/Frame.jpg'),
  306. is_customize: 1,
  307. choices:[{title: '接機服務',text: 'qweqweq'},{title: '送機服務',text: '13123'}],
  308. plan_title: '接送機服務',
  309. specifications: [{
  310. title: '123123',
  311. }]
  312. },{
  313. package_id: '1',
  314. name: '臺南',
  315. photo: require('/assets/img/Frame.jpg'),
  316. is_customize: 1,
  317. choices:[{title: '接機服務',text: 'qweqweq'},{title: '送機服務',text: '13123'}],
  318. plan_title: '接送機服務',
  319. specifications: [{
  320. title: '123123',
  321. }]
  322. }],
  323. additionalServices: [],
  324. },
  325. list: [],
  326. choicesIndex: 0,
  327. countrycode: [],
  328. regionName: [],
  329. elementHeight: {
  330. details: null,
  331. cancellation_policy: null,
  332. faq: null,
  333. },
  334. seeMore: {
  335. details: true,
  336. cancellation_policy: true,
  337. },
  338. button: {
  339. details: true,
  340. cancellation_policy: true,
  341. },
  342. offset: {
  343. packageOptions: 0,
  344. faq: 0,
  345. },
  346. contentId: "",
  347. packageId: "",
  348. packageName: "",
  349. window: {
  350. width: 0,
  351. },
  352. fixBar: false,
  353. fixBarList: [
  354. { id: "packageOptions", title: "Package Options", show: true },
  355. { id: "serviceDetails", title: "Service Details", show: true },
  356. { id: "cancellationPolicy", title: "Cancellation Policy", show: true },
  357. { id: "faq", title: "FAQ", show: true },
  358. { id: "contactUs", title: "Contact Us", show: true },
  359. ],
  360. activePackage: 0,
  361. totalPrice: [],
  362. additionTotalPrice: [],
  363. customPlanPrice: [],
  364. selectDates: '',
  365. selectTime: {
  366. start_time: '2023-02-06',
  367. end_time: '2023-03-06',
  368. },
  369. };
  370. },
  371. async created() {
  372. // await this.getServiceData();
  373. // await this.getFaq();
  374. // await this.getPackages();
  375. // await this.getAdditionalServices();
  376. // await this.addViewCount();
  377. // await this.getYouMightLikeData();
  378. // await this.getRegionName();
  379. // await this.getCountryCode();
  380. if (process.browser) {
  381. window.addEventListener("resize", this.handleResize);
  382. }
  383. this.handleResize();
  384. },
  385. mounted() {
  386. let vm = this;
  387. vm.contentId = vm.$route.params.id;
  388. vm.offset.packageOptions = vm.$refs.packageOptions.offsetTop;
  389. vm.offset.faq = vm.$refs.faq.offsetTop;
  390. vm.$nextTick(function () {
  391. // instantiate the scrollama
  392. const scrollama = require("scrollama");
  393. const scroller = scrollama();
  394. // setup the instance, pass callback functions
  395. scroller
  396. .setup({
  397. step: ".service-content .step",
  398. offset: 0.6,
  399. })
  400. .onStepEnter((response) => {
  401. // { element, index, direction }
  402. vm.currStep = response.element.id;
  403. let fb_messenger = document.querySelector(".fb_dialog_content");
  404. if (response.index > 3) {
  405. vm.$refs.stickySwiper.slideTo(4);
  406. } else {
  407. vm.$refs.stickySwiper.slideTo(0);
  408. }
  409. if (response.index >= 1 && response.index < 6) {
  410. vm.fixBar = true;
  411. if (fb_messenger) {
  412. fb_messenger.classList.add("hasBar");
  413. }
  414. } else {
  415. vm.fixBar = false;
  416. if (fb_messenger) {
  417. fb_messenger.classList.remove("hasBar");
  418. }
  419. }
  420. })
  421. .onStepExit((response) => {
  422. // { element, index, direction }
  423. vm.currStep = response.element.id;
  424. let fb_messenger = document.querySelector(".fb_dialog_content");
  425. if (response.index >= 1 && response.index < 6) {
  426. vm.fixBar = true;
  427. if (fb_messenger) {
  428. fb_messenger.classList.add("hasBar");
  429. }
  430. } else {
  431. vm.fixBar = false;
  432. if (fb_messenger) {
  433. fb_messenger.classList.remove("hasBar");
  434. }
  435. }
  436. });
  437. })
  438. },
  439. computed: {
  440. currency() {
  441. return this.$store.getters.getCurrency;
  442. },
  443. seeMoreDetailsText() {
  444. if (this.button.details == false) {
  445. return "See less";
  446. } else {
  447. return "See more";
  448. }
  449. },
  450. seeMoreCancellationPolicyText() {
  451. if (this.button.cancellation_policy == false) {
  452. return "See less";
  453. } else {
  454. return "See more";
  455. }
  456. },
  457. finalPrice() {
  458. let option = 0;
  459. let custom = 0;
  460. let addition = 0;
  461. if (this.additionTotalPrice) {
  462. this.additionTotalPrice.forEach((item) => {
  463. addition += Number(item.total);
  464. });
  465. }
  466. if (this.customPlanPrice) {
  467. this.customPlanPrice.forEach((item) => {
  468. custom += Number(item.total);
  469. });
  470. }
  471. if (this.totalPrice) {
  472. this.totalPrice.forEach((item) => {
  473. option += Number(item.total);
  474. });
  475. }
  476. if (this.currency == 'USD') {
  477. return Number(addition + custom + option).toFixed(2).toLocaleString();
  478. } else {
  479. return Number(addition + custom + option).toLocaleString();
  480. }
  481. },
  482. },
  483. watch: {
  484. currency: {
  485. handler: function () {
  486. this.getServiceData();
  487. this.getPackages();
  488. this.getAdditionalServices();
  489. },
  490. },
  491. activePackage: {
  492. handler: function (newVal, oldVal) {
  493. if (newVal !== oldVal) {
  494. this.customPlanPrice = [];
  495. this.totalPrice = [];
  496. }
  497. },
  498. },
  499. choicesIndex: {
  500. handler: function (newVal, oldVal) {
  501. if (newVal !== oldVal) {
  502. this.customPlanPrice = [];
  503. this.totalPrice = [];
  504. }
  505. },
  506. }
  507. },
  508. destroyed() {
  509. if (process.browser) {
  510. window.removeEventListener("resize", this.handleResize);
  511. }
  512. },
  513. methods: {
  514. async getServiceData() {
  515. await this.$axios
  516. .get(
  517. `${this.apiUrl}/user-services/content?service_id=${this.$route.params.id}&lang_code=${this.$i18n.localeProperties["langQuery"]}&currency=${this.currency}`
  518. )
  519. .then((res) => {
  520. this.content.banners = res.data.banners;
  521. this.content.name = res.data.name;
  522. this.content.country = res.data.country;
  523. this.content.city = res.data.city;
  524. this.content.highlights = res.data.highlights;
  525. this.content.details = res.data.details;
  526. this.content.cancellation_policy = res.data.cancellation_policy;
  527. this.content.supplier = res.data.supplier;
  528. this.content.available_sections = res.data.available_sections;
  529. this.content.times = res.data.available_sections.times;
  530. this.content.timeStatus = res.data.available_sections.time_status;
  531. this.content.dateStatus = res.data.available_sections.date_status;
  532. this.content.start = res.data.available_sections.start;
  533. this.content.end = res.data.available_sections.end;
  534. this.content.payment_currency = res.data.payment_currency;
  535. this.content.confirmationTime = res.data.confirmation_time.toString();
  536. })
  537. .catch((error) => console.log(error));
  538. },
  539. async getFaq() {
  540. await this.$axios
  541. .get(
  542. `${this.apiUrl}/user-services/faqs?service_id=${this.$route.params.id}&lang_code=${this.$i18n.localeProperties["langQuery"]}`
  543. )
  544. .then((res) => {
  545. this.content.faq = res.data;
  546. })
  547. .catch((error) => console.log(error));
  548. },
  549. async getPackages() {
  550. await this.$axios
  551. .get(
  552. `${this.apiUrl}/user-services/packages?service_id=${this.$route.params.id}&lang_code=${this.$i18n.localeProperties["langQuery"]}&currency=${this.currency}`
  553. )
  554. .then((res) => {
  555. this.content.packages = res.data;
  556. this.packageId = res.data[0].package_id ? res.data[0].package_id : "";
  557. })
  558. .catch((error) => console.log(error));
  559. },
  560. async getAdditionalServices() {
  561. await this.$axios
  562. .get(
  563. `${this.apiUrl}/user-services/additional?service_id=${this.$route.params.id}&lang_code=${this.$i18n.localeProperties["langQuery"]}&currency=${this.currency}`
  564. )
  565. .then((res) => {
  566. this.content.additionalServices =
  567. res.data.services == [] ? null : res.data;
  568. })
  569. .catch((error) => console.log(error));
  570. },
  571. async addViewCount() {
  572. let Obj = {
  573. service_id: `${this.$route.params.id}`,
  574. lang_code: `${this.$i18n.localeProperties["langQuery"]}`,
  575. add_number: 1,
  576. };
  577. await this.$axios
  578. .put(`${this.apiUrl}/user-services/view-counts`, Obj)
  579. .then((res) => { })
  580. .catch((error) => console.log(error));
  581. },
  582. opendetail() {
  583. if (this.window.width >= 1366) {
  584. this.button.details = !this.button.details;
  585. } else {
  586. this.$modal.show("Details");
  587. }
  588. },
  589. openCancellationPolicy() {
  590. if (this.window.width >= 1366) {
  591. this.button.cancellation_policy = !this.button.cancellation_policy;
  592. } else {
  593. this.$modal.show("cancellationPolicy");
  594. }
  595. },
  596. handleResize() {
  597. if (process.browser) {
  598. this.window.width = window.innerWidth;
  599. }
  600. },
  601. changeType(index) {
  602. let vm = this;
  603. vm.activePackage = index;
  604. vm.packageId = vm.content.packages[index].package_id
  605. ? vm.content.packages[index].package_id
  606. : "";
  607. vm.packageName = vm.content.packages[index].name
  608. ? vm.content.packages[index].name
  609. : "";
  610. },
  611. async getYouMightLikeData() {
  612. this.$axios
  613. .get(
  614. `${this.apiUrl}/user-services/advertisements?region=0&country=0&city=0&expo=0&counts=3&lang_code=${this.$i18n.localeProperties["langQuery"]}`
  615. )
  616. .then((res) => {
  617. this.list = res.data;
  618. })
  619. .catch((error) => console.log(error));
  620. },
  621. async getCountryCode() {
  622. this.$axios
  623. .get(
  624. `${this.apiUrl}/countries?lang_code=${this.$i18n.localeProperties["langQuery"]}`
  625. )
  626. .then((respone) => {
  627. this.countrycode = respone.data;
  628. })
  629. .catch((error) => console.log(error));
  630. },
  631. async getRegionName() {
  632. this.$axios
  633. .get(
  634. `/t/exhibitions/locations?lang=${this.$i18n.localeProperties["langQuery"]}&sort=False`
  635. )
  636. .then((respone) => {
  637. this.regionName = respone.data.region_ori;
  638. })
  639. .catch((error) => console.log(error));
  640. },
  641. bookNow() {
  642. let Obj = {
  643. service_id: this.$route.params.id,
  644. service_name: this.content.name,
  645. select_dates: this.selectDates,
  646. currency: this.currency,
  647. lang_code: this.$i18n.localeProperties["langQuery"],
  648. time: this.selectTime,
  649. package_id: this.packageId,
  650. package_name: this.packageName,
  651. specification: this.totalPrice ? this.totalPrice : {},
  652. additional_services: this.additionTotalPrice ? this.additionTotalPrice : {},
  653. custom_plan: this.customPlanPrice ? this.customPlanPrice : {},
  654. supplier_id: this.content.supplier.id ? this.content.supplier.id : '',
  655. };
  656. this.$axios
  657. .post(`/order?jwt=${this.$auth.$storage.getUniversal("jwt").token || ""
  658. }`, Obj)
  659. .then((res) => {
  660. if (res.status == "200") {
  661. this.$router.push(this.localePath("/service/checkout/" + res.data.order_display_id))
  662. }
  663. })
  664. .catch((error) => console.log(error));
  665. },
  666. choicesIdx(data) {
  667. let vm = this;
  668. vm.choicesIndex = data;
  669. }
  670. },
  671. };
  672. </script>
  673. <style lang="scss" scoped>
  674. :deep() {
  675. // .serviceDetails,
  676. // .cancellationPolicy {
  677. // p {
  678. // margin-bottom: 6px;
  679. // }
  680. // }
  681. }
  682. .service-content {
  683. .serviceDetails img {
  684. width: 100%;
  685. height: auto;
  686. }
  687. .fix-right {
  688. position: fixed;
  689. top: 120px;
  690. right: 0 px;
  691. max-width: 400px;
  692. height: auto;
  693. z-index: 100;
  694. }
  695. .title-icon-left {
  696. background-position: left 0px center;
  697. }
  698. ul {
  699. padding-left: 24px;
  700. }
  701. img {
  702. // image-rendering: pixelated;
  703. }
  704. }
  705. .seeMore {
  706. &-hide {
  707. position: relative;
  708. max-height: 295px;
  709. overflow: hidden;
  710. &::after {
  711. content: "";
  712. display: block;
  713. position: absolute;
  714. background: url("~/assets/img/gradient_white.png") repeat-x left bottom;
  715. width: 100%;
  716. height: 130px;
  717. left: 0;
  718. bottom: 0;
  719. z-index: 1;
  720. transition: bottom 0.5s;
  721. }
  722. }
  723. &-show {
  724. position: relative;
  725. max-height: 100%;
  726. overflow: initial;
  727. &::after {
  728. display: none;
  729. }
  730. }
  731. @media screen and (min-width: 1366px) {
  732. position: relative;
  733. display: flex;
  734. align-items: center;
  735. justify-content: center;
  736. &::after {
  737. content: "";
  738. display: inline-block;
  739. position: relative;
  740. background-image: url("~/assets/svg/arrow-down-primary.svg");
  741. background-position: center center;
  742. background-repeat: no-repeat;
  743. background-size: 100%;
  744. width: 9px;
  745. height: 6px;
  746. margin-left: 16px;
  747. }
  748. &.open {
  749. &::after {
  750. transform: rotate(180deg);
  751. }
  752. }
  753. }
  754. }
  755. .section-7 {
  756. >div {
  757. box-shadow: 1px 0px 2px rgba(0, 0, 0, 0.25), 0px 1px 2px rgba(0, 0, 0, 0.1);
  758. }
  759. }
  760. </style>