BookPage.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. <template>
  2. <q-page>
  3. <div class="row" style="height: 50px; background-color: #e5f2fa">
  4. <div class="col-sm-1"></div>
  5. <div
  6. class="col-12 col-sm flex text-subtitle1"
  7. style="align-items: center"
  8. >
  9. Travel shop > {{ productName }}
  10. </div>
  11. </div>
  12. <div class="row text-weight-bold text-h5 q-pa-md">
  13. Product Name: {{ productName }}
  14. </div>
  15. <div class="text-body1 q-px-md">
  16. <div>Package Category: {{ packageCategory }}</div>
  17. <div v-if="selectedDate != null && selectedDate.length > 0">
  18. Start Date: {{ selectedDate }}
  19. </div>
  20. <div v-if="adultCount != null && adultCount > 0">
  21. Adults: {{ adultCount }}
  22. </div>
  23. <div v-if="childCount != null && childCount > 0">
  24. Child: {{ childCount }}
  25. </div>
  26. <div v-if="infantCount != null && infantCount > 0">
  27. Infant: {{ infantCount }}
  28. </div>
  29. <div v-if="buyCount != null && buyCount > 0">
  30. Purchase Count: {{ buyCount }}
  31. </div>
  32. </div>
  33. <div class="row">
  34. <div
  35. class="q-pa-md col-12"
  36. v-for="index in parseInt(adultCount) +
  37. parseInt(childCount) +
  38. parseInt(infantCount)"
  39. :key="index"
  40. >
  41. <div class="text-weight-bold text-h6">Traveler: {{ index }}</div>
  42. <div class="row">
  43. <q-input
  44. class="col-12 col-sm-6 col-md-4"
  45. rounded
  46. dense
  47. outlined
  48. v-model="peopleform.value[index - 1]['surName']"
  49. label="Surname*"
  50. :rules="[(val) => !!val || 'Field is required']"
  51. />
  52. </div>
  53. <div class="row">
  54. <q-input
  55. class="col-12 col-sm-6 col-md-4"
  56. rounded
  57. dense
  58. outlined
  59. v-model="peopleform.value[index - 1]['givenName']"
  60. label="Given Name*"
  61. :rules="[(val) => !!val || 'Field is required']"
  62. />
  63. </div>
  64. <div>
  65. <div class="q-pb-sm text-weight-bold">Birthday</div>
  66. <q-date v-model="peopleform.value[index - 1]['birthday']" />
  67. </div>
  68. <div class="row q-mt-md">
  69. <q-select
  70. outlined
  71. dense
  72. class="col-12 col-sm-6 col-md-4"
  73. v-model="peopleform.value[index - 1]['gender']"
  74. :options="genderOption"
  75. label="Gender"
  76. />
  77. </div>
  78. <div class="row q-mt-md">
  79. Nationality:
  80. <country-select
  81. v-model="peopleform.value[index - 1]['nationality']"
  82. :country="country"
  83. topCountry="US"
  84. />
  85. </div>
  86. <div class="row q-mt-md">
  87. <q-input
  88. class="col-12 col-sm-6 col-md-4"
  89. rounded
  90. dense
  91. outlined
  92. v-model="peopleform.value[index - 1]['passportNo']"
  93. label="Passport Number*"
  94. :rules="[(val) => !!val || 'Field is required']"
  95. />
  96. </div>
  97. <div>
  98. <div class="q-pb-sm text-weight-bold">Expiry date of Passport</div>
  99. <q-date v-model="peopleform.value[index - 1]['passportExpireDate']" />
  100. </div>
  101. </div>
  102. </div>
  103. <div class="row text-h6 text-weight-bold q-pa-md">Contact Info</div>
  104. <div class="row">
  105. <q-input
  106. class="q-pa-md col-12 col-sm-6 col-md-4"
  107. dense
  108. outlined
  109. v-model="contactform['name']"
  110. label="Name*"
  111. :rules="[(val) => !!val || 'Field is required']"
  112. />
  113. </div>
  114. <div class="row">
  115. <q-input
  116. class="q-pa-md col-12 col-sm-6 col-md-4"
  117. dense
  118. outlined
  119. v-model="contactform['email']"
  120. label="Email Address*"
  121. :rules="[(val) => !!val || 'Field is required']"
  122. />
  123. </div>
  124. <div class="row">
  125. <q-input
  126. class="q-pa-md col-12 col-sm-6 col-md-4"
  127. dense
  128. outlined
  129. v-model="contactform['phone']"
  130. label="Phone Number*"
  131. :rules="[(val) => !!val || 'Field is required']"
  132. />
  133. </div>
  134. <div class="row">
  135. <q-input
  136. class="q-pa-md col-12 col-sm-6 col-md-4"
  137. dense
  138. outlined
  139. v-model="contactform['address']"
  140. label="Address in China*"
  141. :rules="[(val) => !!val || 'Field is required']"
  142. />
  143. </div>
  144. <div class="row text-h6 text-weight-bold q-pa-md">Coupon Code</div>
  145. <div class="row">
  146. <q-input
  147. class="q-px-md col-12 col-sm-6 col-md-4"
  148. dense
  149. outlined
  150. v-model="coupon"
  151. label="Have Coupon? Enter code here"
  152. />
  153. </div>
  154. <div class="row q-pa-md">
  155. <div class="row col-6">
  156. <div
  157. class="col-6 col-sm-4 text-blue-6 text-h5 q-py-md"
  158. style="border-bottom: 1px solid black"
  159. >
  160. Payment CNY:
  161. </div>
  162. <div class="col-6 col-sm-8 text-red text-h3 q-py-md">
  163. {{ totalPrice }}¥
  164. </div>
  165. </div>
  166. </div>
  167. <div class="row">
  168. <q-btn
  169. icon="lab la-alipay"
  170. glossy
  171. color="blue-6"
  172. label="Pay with Alipay"
  173. class="q-ma-sm"
  174. @click="submitOrder('alipay')"
  175. />
  176. <q-btn
  177. icon="lab la-weixin"
  178. glossy
  179. color="green-6"
  180. label="Pay with Wechat Pay"
  181. class="q-ma-sm"
  182. @click="submitOrder('wechatpay')"
  183. />
  184. </div>
  185. </q-page>
  186. </template>
  187. <script>
  188. import { ref, onMounted, getCurrentInstance, reactive } from "vue";
  189. import { useQuasar } from "quasar";
  190. import { useRoute } from "vue-router";
  191. import { api } from "boot/axios";
  192. import { bookParamStore } from "stores/bookParamStore";
  193. import { orderPaymentParamStore } from "stores/orderPaymentParamStore";
  194. export default {
  195. name: "BookPage",
  196. setup() {
  197. const bStore = bookParamStore();
  198. const oStore = orderPaymentParamStore();
  199. const instance = getCurrentInstance();
  200. const app = instance.appContext.app;
  201. const gp = app.config.globalProperties;
  202. const $q = useQuasar();
  203. const route = useRoute();
  204. const coupon = ref("");
  205. const country = ref("");
  206. const productName = ref("");
  207. const productTypeId = ref("");
  208. const productSkuId = ref("");
  209. const packageCategory = ref("");
  210. const selectedDate = ref(new Date());
  211. const adultCount = ref(0);
  212. const childCount = ref(0);
  213. const infantCount = ref(0);
  214. const buyCount = ref(1);
  215. const totalPrice = ref(0);
  216. const peopleform = reactive([]);
  217. const contactform = ref({});
  218. function checkPassenger(passenger) {
  219. if (
  220. gp.$checkEmpty(passenger.birthday) ||
  221. gp.$checkEmpty(passenger.gender) ||
  222. gp.$checkEmpty(passenger.givenName) ||
  223. gp.$checkEmpty(passenger.surName) ||
  224. gp.$checkEmpty(passenger.nationality) ||
  225. gp.$checkEmpty(passenger.passportExpireDate) ||
  226. gp.$checkEmpty(passenger.passportNo) ||
  227. gp.$checkEmpty(passenger.surName)
  228. ) {
  229. return false;
  230. }
  231. return true;
  232. }
  233. function validatePreOrderParams(finalParams) {
  234. console.log("validating finalParams");
  235. console.log(finalParams);
  236. // must have CNY value valid
  237. if (
  238. gp.$checkEmpty(finalParams.productInfo["totalPrice"]) ||
  239. !Number.isInteger(parseInt(finalParams.productInfo["totalPrice"]))
  240. ) {
  241. gp.$generalNotify($q, false, "something wrong with price");
  242. return false;
  243. }
  244. // must have full contact info
  245. if (
  246. gp.$checkEmpty(finalParams.contactInfo["email"]) ||
  247. gp.$checkEmpty(finalParams.contactInfo["phone"]) ||
  248. gp.$checkEmpty(finalParams.contactInfo["name"]) ||
  249. gp.$checkEmpty(finalParams.contactInfo["address"])
  250. ) {
  251. gp.$generalNotify(
  252. $q,
  253. false,
  254. "Please check your contact info is filled correctly"
  255. );
  256. return false;
  257. }
  258. // must have full product info
  259. if (gp.$checkEmpty(finalParams.productInfo)) {
  260. gp.$generalNotify(
  261. $q,
  262. false,
  263. "Please check your product info is correct"
  264. );
  265. return false;
  266. }
  267. // must have full passenger info if not localspecialty type, if no passenger , no check
  268. for (var index in finalParams.passengerInfo) {
  269. if (!checkPassenger(finalParams.passengerInfo[index])) {
  270. gp.$generalNotify(
  271. $q,
  272. false,
  273. "Please check your passenger info has been filled correctly"
  274. );
  275. return false;
  276. }
  277. }
  278. return true;
  279. }
  280. function submitOrder(paymethod) {
  281. var finalParams = {};
  282. if (LOCALSPECIALTYPRODUCTTYPE != productTypeId.value) {
  283. finalParams.passengerInfo = peopleform.value;
  284. }
  285. finalParams.contactInfo = contactform.value;
  286. finalParams.coupon = coupon.value;
  287. finalParams.productInfo = bStore.getOrderDetail;
  288. console.log("finalParams");
  289. console.log(finalParams);
  290. if (validatePreOrderParams(finalParams)) {
  291. // do submit
  292. var params = {};
  293. params.meta = JSON.stringify(finalParams);
  294. params.skuId = productSkuId.value;
  295. params.status = "SUBMITTED";
  296. params.price = totalPrice.value;
  297. params.payMethod = paymethod;
  298. api
  299. .post("/api/v1/order", params)
  300. .then((res) => {
  301. gp.$generalNotify($q, true, "Succeed creating order");
  302. if (paymethod == "wechatpay") {
  303. alert("not available, will be on line soon");
  304. return;
  305. // go to we chat pay page
  306. // go to alipay page
  307. console.log(res.data.data);
  308. var param2Pass = {};
  309. param2Pass.price = res.data.data.price;
  310. param2Pass.orderId = res.data.data.orderId;
  311. param2Pass.codeUrl = res.data.data.codeUrl;
  312. param2Pass.productName = productName.value;
  313. oStore.setPaymentDetail(param2Pass);
  314. gp.$goPage("/wechatpay");
  315. } else if (paymethod == "alipay") {
  316. // go to alipay page
  317. console.log(res.data.data);
  318. var param2Pass = {};
  319. param2Pass.price = res.data.data.price;
  320. param2Pass.orderId = res.data.data.orderId;
  321. param2Pass.codeUrl = res.data.data.codeUrl;
  322. oStore.setPaymentDetail(param2Pass);
  323. gp.$goPage("/alipay");
  324. }
  325. })
  326. .catch((err) => {
  327. gp.$generalNotify($q, false, "Fail creating order" + err);
  328. });
  329. }
  330. }
  331. function whoami() {
  332. api
  333. .get("/api/v1/user/whoami")
  334. .then(function (response) {
  335. console.log("current user in book page: " + response.data);
  336. })
  337. .catch(function (error) {
  338. console.log("currently not logged in setup: " + error);
  339. gp.$goPage("/auth/login");
  340. });
  341. }
  342. function todayString() {
  343. const today = new Date();
  344. const year = today.getFullYear();
  345. const month = String(today.getMonth() + 1).padStart(2, "0");
  346. const day = String(today.getDate()).padStart(2, "0");
  347. return `${year}/${month}/${day}`;
  348. }
  349. function initPeopleform() {
  350. peopleform.value = [];
  351. for (
  352. let index = 0;
  353. index <
  354. parseInt(adultCount.value) +
  355. parseInt(childCount.value) +
  356. parseInt(infantCount.value);
  357. index++
  358. ) {
  359. peopleform.value.push({
  360. surName: "",
  361. givenName: "",
  362. birthday: ref(todayString()),
  363. gender: "",
  364. nationality: "",
  365. passportNo: "",
  366. passportExpireDate: ref(todayString()),
  367. });
  368. }
  369. }
  370. onMounted(() => {
  371. whoami();
  372. console.log("allParamsFromPreviousPage");
  373. var allParamsFromPreviousPage = bStore.getOrderDetail;
  374. console.log(allParamsFromPreviousPage);
  375. productName.value = allParamsFromPreviousPage.productName;
  376. packageCategory.value = allParamsFromPreviousPage.packageCategory;
  377. selectedDate.value = allParamsFromPreviousPage.selectedDate;
  378. adultCount.value = allParamsFromPreviousPage.adultCount;
  379. childCount.value = allParamsFromPreviousPage.childCount;
  380. infantCount.value = allParamsFromPreviousPage.infantCount;
  381. buyCount.value = allParamsFromPreviousPage.buyCount;
  382. totalPrice.value = allParamsFromPreviousPage.totalPrice;
  383. console.log("productName.value");
  384. console.log(productName.value);
  385. initPeopleform();
  386. contactform.value = {
  387. name: "",
  388. email: "",
  389. phone: "",
  390. address: "",
  391. };
  392. // if (
  393. // route.params.productName == null ||
  394. // route.params.productName.length < 1 ||
  395. // route.params.productSkuId == null ||
  396. // route.params.productSkuId.length < 1 ||
  397. // route.params.packageCategory == null ||
  398. // route.params.packageCategory.length < 1
  399. // ) {
  400. // gp.$goPage("/");
  401. // return;
  402. // }
  403. // productName.value = route.params.productName;
  404. // packageCategory.value = route.params.packageCategory;
  405. // selectedDate.value = route.params.selectedDate;
  406. // totalPrice.value = route.params.totalPrice;
  407. // productSkuId.value = route.params.productSkuId;
  408. // adultCount.value =
  409. // route.params.adultCount == null ? 0 : route.params.adultCount;
  410. // childCount.value =
  411. // route.params.childCount == null ? 0 : route.params.childCount;
  412. // infantCount.value =
  413. // route.params.infantCount == null ? 0 : route.params.infantCount;
  414. // buyCount.value =
  415. // route.params.buyCount == null ? 0 : route.params.buyCount;
  416. // productTypeId.value = route.params.productTypeId;
  417. });
  418. return {
  419. productName,
  420. packageCategory,
  421. selectedDate,
  422. adultCount,
  423. childCount,
  424. infantCount,
  425. buyCount,
  426. peopleform,
  427. genderOption: [
  428. { label: "Male", value: 1 },
  429. { label: "Female", value: 0 },
  430. ],
  431. country,
  432. contactform,
  433. coupon,
  434. totalPrice,
  435. submitOrder,
  436. };
  437. },
  438. };
  439. </script>