Browse Source

product detail page zishiying

fengchang 1 year ago
parent
commit
1ea5723845

+ 3 - 1
hichina-main-front-mobile-first/package.json

@@ -17,8 +17,10 @@
     "axios": "^1.4.0",
     "core-js": "^3.6.5",
     "quasar": "^2.6.0",
+    "unhead": "^1.1.30",
     "vue": "^3.0.0",
-    "vue-router": "^4.0.0"
+    "vue-router": "^4.0.0",
+    "vuejs3-datepicker": "^1.0.19"
   },
   "devDependencies": {
     "@babel/eslint-parser": "^7.13.14",

+ 0 - 1
hichina-main-front-mobile-first/src/pages/IndexPage.vue

@@ -360,7 +360,6 @@ export default defineComponent({
       homePostLink,
       homePostImageUrl,
       globalUnifiedItemList,
-      normalizeMultiImageUrl,
     };
   },
 });

+ 653 - 0
hichina-main-front-mobile-first/src/pages/ProductDetailPage.vue

@@ -0,0 +1,653 @@
+<template>
+  <q-page>
+    <div class="row" style="background-color: #e5f2fa; height: 50px">
+      <div class="col-md-3"></div>
+      <div
+        class="col-12 col-md-9 text-body1 q-pl-md flex"
+        style="align-items: center"
+      >
+        Travel shop > {{ productTypeName }} > {{ productName }}
+      </div>
+    </div>
+    <div class="row q-pa-md" style="min-height: 340px">
+      <div class="col-12 col-md-4" style="height: 340px">
+        <q-carousel
+          animated
+          v-model="slide"
+          navigation
+          infinite
+          height="100%"
+          :autoplay="autoplay"
+          arrows
+          transition-prev="slide-right"
+          transition-next="slide-left"
+          @mouseenter="autoplay = false"
+          @mouseleave="autoplay = 2000"
+        >
+          <q-carousel-slide
+            v-for="imageUrl in imageContainer.imageList"
+            :key="imageUrl"
+            :name="imageUrl"
+            :img-src="imageUrl"
+          >
+          </q-carousel-slide>
+        </q-carousel>
+      </div>
+      <div class="col-12 col-md-8 column" style="height: 340px">
+        <div class="text-h4 q-pl-md" style="height: 50px">
+          {{ productName }}
+        </div>
+        <div class="q-ml-md q-pl-md col" style="background-color: #fff9c6">
+          {{ removeHtmlTag(productDescription).substring(0, 300) }}...
+        </div>
+      </div>
+    </div>
+    <div class="row" style="min-height: 500px">
+      <div class="col-12 col-md-4 row justify-center" style="height: 500px">
+        <!-- https://github.com/shubhadip/vuejs3-datepicker#install -->
+        <datepicker
+          v-if="renderComponent && productTypeId != LOCALSPECIALTYPRODUCTTYPE"
+          @selected="handleSelectDate"
+          use-utc="true"
+          :disabled-dates="state.disabledDates"
+          v-model="selectedDate"
+          :prevent-disable-date-selection="true"
+          inline="true"
+          :icon-width="40"
+          calendar-class="calendarclass"
+        ></datepicker>
+      </div>
+      <div
+        class="col-12 col-md-8 q-pl-xl q-pt-md column"
+        style="min-height: 500px"
+      >
+        <div class="row">
+          <div class="col-3 col-md-2 text-weight-bold text-h4">Days:</div>
+          <div
+            v-if="productTypeId != FLIGHTPRODUCTTYPE"
+            class="col-11 col-md-10 flex text-h6 q-pl-sm"
+            style="align-items: center"
+          >
+            {{ days - 1 }} nights {{ days }} days
+          </div>
+          <div
+            v-if="productTypeId === FLIGHTPRODUCTTYPE"
+            class="col-11 col-md-10 flex text-h6 q-pl-sm"
+            style="align-items: center"
+          >
+            {{ days }} days
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-3 col-md-2 text-weight-bold text-h4">Option:</div>
+          <div
+            class="col-11 col-md-10 flex text-h6 q-pl-sm"
+            style="align-items: center"
+          >
+            <q-btn-toggle
+              v-model="activeIndex"
+              spread
+              no-caps
+              toggle-color="blue-6"
+              color="white"
+              text-color="black"
+              @click="
+                setActiveCate(packageCategories[activeIndex], activeIndex)
+              "
+              :options="labelValuePair(packageCategories)"
+            />
+          </div>
+        </div>
+        <div class="row text-weight-bold text-h4 q-mt-xl">Passengers</div>
+        <div class="row q-mt-md" style="border-top: 2px solid black">
+          <div
+            v-if="productTypeId != LOCALSPECIALTYPRODUCTTYPE"
+            class="row col-12 q-pr-md q-mt-md"
+          >
+            <div class="col-11 col-md-4 q-pr-md">
+              <q-input
+                label="Adult Count"
+                v-model.number="adultCount"
+                type="number"
+                min="1"
+                outlined
+              />
+            </div>
+            <div class="col-11 col-md-4 q-pr-md">
+              <q-input
+                label="Child Count"
+                v-model.number="childCount"
+                type="number"
+                min="0"
+                outlined
+              />
+            </div>
+            <div class="col-11 col-md-4 q-pr-md">
+              <q-input
+                label="Infant Count(less than 2 years old)"
+                v-model.number="infantCount"
+                type="number"
+                min="0"
+                outlined
+              />
+            </div>
+          </div>
+          <div
+            v-if="productTypeId === LOCALSPECIALTYPRODUCTTYPE"
+            class="row col-12 q-pr-md q-mt-md"
+          >
+            <div class="col-4 q-pr-md">
+              <q-input
+                label="Count"
+                v-model.number="buyCount"
+                type="number"
+                min="1"
+                outlined
+              />
+            </div>
+          </div>
+          <div class="row col-12" style="height: 50px"></div>
+          <div
+            class="row col-12 q-pr-md q-mt-md"
+            style="background-color: #e9e9e9; min-height: 50px"
+          >
+            <div
+              class="col-4 text-blue-6 text-h5 flex"
+              style="align-items: center; height: 50px"
+            >
+              CNY
+            </div>
+            <div
+              v-if="
+                productTypeId != LOCALSPECIALTYPRODUCTTYPE &&
+                productTypeId != HOTELPRODUCTTYPE
+              "
+              class="col-4 col-md-3 flex"
+              style="align-items: center; height: 50px"
+            >
+              {{
+                adultCount * adultUnitPrice +
+                childCount * childUnitPrice +
+                infantCount * infantUnitPrice
+              }}
+            </div>
+            <div
+              v-if="
+                productTypeId == LOCALSPECIALTYPRODUCTTYPE ||
+                productTypeId == HOTELPRODUCTTYPE
+              "
+              class="col-4 col-md-3 flex"
+              style="align-items: center; height: 50px"
+            >
+              {{ generalPrice * buyCount }}
+            </div>
+            <div
+              class="col-7 col-md-3 flex"
+              style="align-items: center; height: 50px"
+            >
+              <q-btn
+                class="glossy"
+                rounded
+                color="deep-orange"
+                label="Pre-book Consult"
+              />
+            </div>
+            <div
+              class="col-5 col-md-2 flex"
+              style="align-items: center; height: 50px"
+            >
+              <q-btn class="glossy" rounded color="blue-6" label="Book Now" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div
+      class="row q-pa-md"
+      style="min-height: 500px; background-color: #d9d9d9"
+    >
+      <div
+        class="col-12"
+        style="background-color: white"
+        v-html="productDescription"
+      ></div>
+    </div>
+  </q-page>
+</template>
+
+<script>
+import { ref, onMounted, nextTick } from "vue";
+import { api } from "boot/axios";
+import { useSeoMeta } from "unhead";
+import { useRoute } from "vue-router";
+import Datepicker from "vuejs3-datepicker";
+export default {
+  name: "ProductDetailPage",
+  components: {
+    Datepicker,
+  },
+  setup() {
+    const route = useRoute();
+    const buyCount = ref(1);
+    const adultCount = ref(1);
+    const childCount = ref(0);
+    const infantCount = ref(0);
+    const skusInGroup = { skus: [] };
+    const productName = ref("");
+    const productDescription = ref("");
+    const productTypeId = ref("");
+    const productTypeName = ref("");
+    const packageCategories = ref([]);
+    const imageList = ref([]);
+    const days = ref("");
+    const imageContainer = { imageList: [] };
+    const activeCategory = ref("");
+    const filteredSkuIndex = ref([]);
+    const activeIndex = ref(0);
+    const adultUnitPrice = ref(0);
+    const generalPrice = ref(0);
+    const childUnitPrice = ref(0);
+    const infantUnitPrice = ref(0);
+    const singleMatchedSku = ref({});
+    const selectedDate = ref(new Date());
+    const maxNum = ref(1000000);
+    const renderComponent = ref(true);
+
+    const TYPEOFPACKAGEPROP = "11cd8b32-c4f6-47db-8b8a-486c992bf43b";
+    const LOCALSPECIALTYPRODUCTTYPE = "fd264cab-ee8d-4571-a477-03d7e7c090b3";
+    const HOTELPRODUCTTYPE = "a9f5adbe-c09b-49bc-a614-8a1c5d5e5337";
+    const MAXNUM = "720f4f2e-e114-4003-9806-bc56a9366278";
+    const PRODUCTIMAGEURLPROP = "2dea54f4-9b9c-413a-8b3a-0caf273283d2";
+    const DAYSPROP = "8cc865ff-b30f-4f00-b426-9e64418e5100";
+    const AVAILABLEDATEPROP = "f0b807e5-d1a6-4454-a400-7905a4fea492";
+    const TOURPRODUCTTYPE = "3a53caed-b788-4290-896d-7922532ad769";
+    const FLIGHTHOTELPRODUCTTYPE = "e05d07a3-a717-45b8-b009-47a349890e41";
+    const FLIGHTPRODUCTTYPE = "d7b95089-e278-4522-8f71-dacac41ba32f";
+    const GENERALPRICE = "e16df480-b17d-4442-91c2-d6c30d0d7ab0";
+    const ADULTPRICEPROP = "e228b843-e054-41f8-91dd-19663460df54";
+    const CHILDPRICEPROP = "c4c845a7-4bef-46d8-a5ad-d72a5464e8b1";
+    const INFANTPRICEPROP = "448406cb-b68f-439e-9da8-148d78ae8404";
+
+    const forceRerender = async () => {
+      // Remove MyComponent from the DOM
+      renderComponent.value = false;
+
+      // Wait for the change to get flushed to the DOM
+      await nextTick();
+
+      // Add the component back in
+      renderComponent.value = true;
+    };
+
+    function handleSelectDate(dt) {
+      console.log("dt");
+      console.log(dt);
+      var matchedIndex = -1;
+      for (var i in filteredSkuIndex.value) {
+        var index = filteredSkuIndex.value[i];
+        var availableDatesInString =
+          extractAttributeValueFromProductPropertyBag(
+            skusInGroup.skus[index],
+            AVAILABLEDATEPROP
+          );
+        var dateObjArray = multiDateString2DateObjectArray(
+          availableDatesInString
+        );
+        console.log("dateObjArray");
+        console.log(dateObjArray);
+        if (dateObjArray.some((e) => e.getDate() == dt.getDate())) {
+          matchedIndex = index;
+          break;
+        }
+      }
+      console.log("matchedIndex");
+      console.log(matchedIndex);
+      singleMatchedSku.value = skusInGroup.skus[matchedIndex];
+
+      maxNum.value = extractAttributeValueFromProductPropertyBag(
+        singleMatchedSku.value,
+        MAXNUM
+      );
+
+      console.log("maxNum");
+      console.log(maxNum.value);
+      setPrice(singleMatchedSku.value);
+    }
+
+    var state = {
+      disabledDates: {
+        to: new Date(2023, 3, 15), // Disable all dates up to specific date
+        from: new Date(2023, 4, 20), // Disable all dates after specific date
+
+        dates: [
+          // Disable an array of dates
+          new Date(2016, 9, 16),
+          new Date(2016, 9, 17),
+          new Date(2016, 9, 18),
+        ],
+        preventDisableDateSelection: true,
+      },
+    };
+
+    function removeHtmlTag(input) {
+      var div = document.createElement("div");
+      div.innerHTML = input;
+      var text = div.textContent || div.innerText || "";
+      return text;
+    }
+
+    function logPv() {
+      api
+        .post(
+          "/api/public/pagestats/pv/product-detail-" + route.params.skuGroupId
+        )
+        .then((res) => {
+          console.log("log pv:");
+          console.log(res.data);
+        })
+        .catch((err) => {
+          console.error("Error:", err);
+        });
+    }
+
+    function logView() {
+      api
+        .post("/api/public/pagestats/view-product/" + route.params.skuGroupId)
+        .then((res) => {
+          console.log("view cnt of this product:");
+          console.log(res.data);
+        })
+        .catch((err) => {
+          console.error("Error:", err);
+        });
+    }
+
+    function extractAttributeValueFromProductPropertyBag(inputObject, attrId) {
+      var valArray = inputObject.productPropertyBag.filter((obj) => {
+        return obj.attributeId == attrId;
+      });
+      if (valArray.length > 0) {
+        return valArray[0].attributeValue;
+      }
+      return null;
+    }
+
+    function getFilteredSkuIndexAndSetActiveValue(item, index) {
+      activeCategory.value = item;
+      filteredSkuIndex.value = [];
+      for (var i in skusInGroup.skus) {
+        var sku = skusInGroup.skus[i];
+        var selectedSkuPropertyBags = sku["productPropertyBag"].filter(
+          (obj) => {
+            return obj.attributeId == TYPEOFPACKAGEPROP;
+          }
+        );
+        if (selectedSkuPropertyBags[0].attributeValue == item) {
+          filteredSkuIndex.value.push(i);
+        }
+      }
+      activeIndex.value = index;
+    }
+
+    function multiDateString2DateObjectArray(candidateAvailableDates) {
+      var dateObjArray = [];
+      var datestringArray = candidateAvailableDates.split(";");
+      for (var i in datestringArray) {
+        var datestr = datestringArray[i];
+        if (datestr != null && datestr.length > 0) {
+          var dateObj = new Date(datestr);
+          // console.log("...converting string to date:"+ datestr)
+          // console.log(dateObj)
+          dateObjArray.push(dateObj);
+        }
+      }
+      return dateObjArray;
+    }
+
+    function compareDate(a, b) {
+      if (a.getDate() < b.getDate()) {
+        return -1;
+      }
+      if (a.getDate() > b.getDate()) {
+        return 1;
+      }
+      return 0;
+    }
+
+    function setCandidateAvailableDates(indexArray) {
+      var candidateAvailableDates = "";
+      for (var i in indexArray) {
+        var availableDates = extractAttributeValueFromProductPropertyBag(
+          skusInGroup.skus[indexArray[i]],
+          AVAILABLEDATEPROP
+        );
+        candidateAvailableDates = candidateAvailableDates + availableDates;
+      }
+
+      var dateObjArray = multiDateString2DateObjectArray(
+        candidateAvailableDates
+      );
+
+      dateObjArray.sort(compareDate);
+
+      var minDate = dateObjArray[0];
+      var maxDate = dateObjArray.slice(-1)[0];
+
+      state.disabledDates.to = minDate;
+      var nextDayOfMax = new Date(maxDate);
+      nextDayOfMax.setDate(nextDayOfMax.getDate() + 1);
+      state.disabledDates.from = nextDayOfMax;
+
+      var segmentDisabledDates = [];
+      var pointer = new Date(minDate);
+
+      while (pointer < maxDate) {
+        // check contains
+        if (!dateObjArray.some((e) => e.getDate() == pointer.getDate())) {
+          segmentDisabledDates.push(new Date(pointer));
+        }
+        // update pointer
+        pointer.setDate(pointer.getDate() + 1);
+      }
+      state.disabledDates.dates = segmentDisabledDates;
+
+      forceRerender();
+    }
+
+    function setPrice(sku) {
+      if (sku == null) {
+        if (
+          productTypeId.value == LOCALSPECIALTYPRODUCTTYPE ||
+          productTypeId.value == HOTELPRODUCTTYPE
+        ) {
+          console.log("001");
+          generalPrice.value = 0;
+        } else {
+          adultUnitPrice.value = 0;
+          childUnitPrice.value = 0;
+          infantUnitPrice.value = 0;
+        }
+      } else {
+        if (
+          productTypeId.value == LOCALSPECIALTYPRODUCTTYPE ||
+          productTypeId.value == HOTELPRODUCTTYPE
+        ) {
+          console.log("003");
+          generalPrice.value = extractAttributeValueFromProductPropertyBag(
+            sku,
+            GENERALPRICE
+          );
+        } else {
+          console.log("004");
+          adultUnitPrice.value = extractAttributeValueFromProductPropertyBag(
+            sku,
+            ADULTPRICEPROP
+          );
+          childUnitPrice.value = extractAttributeValueFromProductPropertyBag(
+            sku,
+            CHILDPRICEPROP
+          );
+          infantUnitPrice.value = extractAttributeValueFromProductPropertyBag(
+            sku,
+            INFANTPRICEPROP
+          );
+        }
+      }
+    }
+
+    function setActiveDescription() {
+      var indexToFilter =
+        filteredSkuIndex.value.length < 1 ? 0 : filteredSkuIndex.value[0];
+      productDescription.value =
+        skusInGroup.skus[indexToFilter]["hichinaProductBasicDTO"][
+          "productContent"
+        ];
+    }
+
+    function setActiveCate(item, index) {
+      console.log("picking package cate: " + item);
+      console.log("index of it is:   " + index);
+      getFilteredSkuIndexAndSetActiveValue(item, index);
+      setCandidateAvailableDates(filteredSkuIndex.value);
+      setPrice(null);
+      selectedDate.value = new Date();
+      singleMatchedSku.value = null;
+      setActiveDescription();
+    }
+
+    function setTourProductData(inputArray) {
+      packageCategories.value = [];
+      imageList.value = [];
+      for (var index in inputArray) {
+        var packageCat = extractAttributeValueFromProductPropertyBag(
+          inputArray[index],
+          TYPEOFPACKAGEPROP
+        );
+        if (packageCat != null) {
+          packageCategories.value.push(packageCat);
+        }
+
+        var url = extractAttributeValueFromProductPropertyBag(
+          inputArray[index],
+          PRODUCTIMAGEURLPROP
+        );
+        if (url != null) {
+          imageContainer.imageList.push(url);
+        }
+
+        // this if means only need to calculate days once because all this property in the same sku group should be same
+        if (days.value == "") {
+          days.value = extractAttributeValueFromProductPropertyBag(
+            inputArray[index],
+            DAYSPROP
+          );
+        }
+      }
+      console.log("imageContainer");
+      console.log(imageContainer);
+      // trick: remove duplicates
+      packageCategories.value = [...new Set(packageCategories.value)];
+      // force select the first package category on entering page
+      setActiveCate(packageCategories.value[0], 0);
+    }
+
+    function labelValuePair(valArray) {
+      var ret = [];
+      valArray.forEach((x, i) => {
+        var obj = { label: x, value: i };
+        ret.push(obj);
+      });
+      return ret;
+    }
+
+    function processSkuGroups(inputArray) {
+      if (inputArray.length > 0) {
+        productName.value =
+          inputArray[0]["hichinaProductBasicDTO"]["productName"];
+        productTypeId.value =
+          inputArray[0]["hichinaProductBasicDTO"]["productTypeId"];
+        productTypeName.value =
+          inputArray[0]["hichinaProductBasicDTO"]["productTypeName"];
+
+        useSeoMeta({
+          title: productName.value,
+          description: productName.value,
+          ogDescription: productName.value,
+          ogTitle: productName.value,
+          ogImage: "https://www.hichinatravel.com/static/png/name-67280b81.png",
+          twitterCard: "summary_large_image",
+        });
+
+        if (productTypeId.value === TOURPRODUCTTYPE) {
+          // 跟团游,则按照跟团游的页面模板来设置各个参数
+          setTourProductData(inputArray);
+        } else if (productTypeId.value === FLIGHTHOTELPRODUCTTYPE) {
+          // 机票酒店套餐
+          setFlightHotelProductData(inputArray);
+        } else if (productTypeId.value === FLIGHTPRODUCTTYPE) {
+          // 机票
+          setFligtProductData(inputArray);
+        } else if (productTypeId.value === HOTELPRODUCTTYPE) {
+          // 酒店
+          setHotelProductData(inputArray);
+        } else if (productTypeId.value === LOCALSPECIALTYPRODUCTTYPE) {
+          // 本地土特产
+          setLocalSpecialtyProductData(inputArray);
+        }
+      }
+    }
+
+    function loadSkusInGroup() {
+      var params = {};
+      params.skuGroupId = route.params.skuGroupId;
+      api
+        .get("/api/public/productsku/bygroupidwithpropertybag", {
+          params: params,
+        })
+        .then(function (response) {
+          skusInGroup.skus = response.data.data;
+          processSkuGroups(skusInGroup.skus);
+        })
+        .catch(function (error) {
+          console.log(error);
+        });
+    }
+
+    onMounted(() => {
+      logPv();
+      logView();
+      loadSkusInGroup();
+    });
+    return {
+      productTypeName,
+      productName,
+      productTypeId,
+      days,
+      slide: ref(1),
+      autoplay: ref(true),
+      imageContainer,
+      productDescription,
+      removeHtmlTag,
+      handleSelectDate,
+      selectedDate,
+      state,
+      renderComponent,
+      LOCALSPECIALTYPRODUCTTYPE,
+      FLIGHTPRODUCTTYPE,
+      HOTELPRODUCTTYPE,
+      packageCategories,
+      labelValuePair,
+      setActiveCate,
+      activeIndex,
+      adultCount,
+      childCount,
+      infantCount,
+      adultUnitPrice,
+      childUnitPrice,
+      infantUnitPrice,
+      generalPrice,
+      buyCount,
+    };
+  },
+};
+</script>

+ 6 - 1
hichina-main-front-mobile-first/src/pages/TravelShopPage.vue

@@ -57,7 +57,12 @@
         v-bind:key="index"
       >
         <div class="q-pa-md">
-          <q-card class="cursor-pointer" flat bordered>
+          <q-card
+            @click="goPage('/product-detail/' + item.skuGroupId)"
+            class="cursor-pointer"
+            flat
+            bordered
+          >
             <q-img
               :src="item.imageUrl"
               placeholder-src="https://photoprism.hichinatravel.com/api/v1/t/2bfc32550ae040956f7e861566d26c487c0143e7/32mcf2k4/tile_224"

+ 7 - 0
hichina-main-front-mobile-first/src/router/routes.js

@@ -35,6 +35,13 @@ const routes = [
     component: () => import("layouts/MainLayout.vue"),
     children: [{ path: "", component: () => import("pages/LoginPage.vue") }],
   },
+  {
+    path: "/product-detail/:skuGroupId",
+    component: () => import("layouts/MainLayout.vue"),
+    children: [
+      { path: "", component: () => import("pages/ProductDetailPage.vue") },
+    ],
+  },
 
   // Always leave this as last one,
   // but you can also remove it

+ 64 - 0
hichina-main-front-mobile-first/yarn.lock

@@ -1018,6 +1018,13 @@
   resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
   integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
 
+"@babel/runtime@^7.12.5":
+  version "7.22.6"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438"
+  integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==
+  dependencies:
+    regenerator-runtime "^0.13.11"
+
 "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.0":
   version "7.22.3"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.3.tgz#0a7fce51d43adbf0f7b517a71f4c3aaca92ebcbb"
@@ -1581,6 +1588,29 @@
   dependencies:
     "@types/yargs-parser" "*"
 
+"@unhead/dom@1.1.30":
+  version "1.1.30"
+  resolved "https://registry.yarnpkg.com/@unhead/dom/-/dom-1.1.30.tgz#d4e8e97304c2f8de2e7774b1f4263b43c8f0f0aa"
+  integrity sha512-EvASOkk36lW5sRfIe+StCojpkPEExsQNt+cqcpdVr9iiRH54jziCDFxcLfjawc+jp4NO86KvmfHo86GIly3/SQ==
+  dependencies:
+    "@unhead/schema" "1.1.30"
+    "@unhead/shared" "1.1.30"
+
+"@unhead/schema@1.1.30":
+  version "1.1.30"
+  resolved "https://registry.yarnpkg.com/@unhead/schema/-/schema-1.1.30.tgz#aa77da28342a7e7ed0825896a48ebf7551fbe5d7"
+  integrity sha512-lgz0aw+OP1PlKHBhNWAVabV2iAHBhSXCt3Ynswu0m++MwJxOVXizYJRZOVKK7Zx3u7vwPRV/nweYc6rmNHv5gA==
+  dependencies:
+    hookable "^5.5.3"
+    zhead "^2.0.9"
+
+"@unhead/shared@1.1.30":
+  version "1.1.30"
+  resolved "https://registry.yarnpkg.com/@unhead/shared/-/shared-1.1.30.tgz#0ae2a78a1d118c0d2a852e2ca9981805c18f7bca"
+  integrity sha512-OPS+d4SZuYSWquQZVLfbyFYggdqKz8DtcdHXObRoKWnosrgVPyGJoOaFnjfkYYuvU6BFYnUtnZNMRQVUjmER1g==
+  dependencies:
+    "@unhead/schema" "1.1.30"
+
 "@vue/compiler-core@3.3.4":
   version "3.3.4"
   resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.3.4.tgz#7fbf591c1c19e1acd28ffd284526e98b4f581128"
@@ -3512,6 +3542,11 @@ he@^1.2.0:
   resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
   integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
 
+hookable@^5.5.3:
+  version "5.5.3"
+  resolved "https://registry.yarnpkg.com/hookable/-/hookable-5.5.3.tgz#6cfc358984a1ef991e2518cb9ed4a778bbd3215d"
+  integrity sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==
+
 hpack.js@^2.1.6:
   version "2.1.6"
   resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
@@ -4903,6 +4938,11 @@ pretty-error@^4.0.0:
     lodash "^4.17.20"
     renderkid "^3.0.0"
 
+prismjs@^1.22.0:
+  version "1.29.0"
+  resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12"
+  integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==
+
 process-nextick-args@~2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@@ -5682,6 +5722,16 @@ uglify-js@^3.5.1:
   resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c"
   integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==
 
+unhead@^1.1.30:
+  version "1.1.30"
+  resolved "https://registry.yarnpkg.com/unhead/-/unhead-1.1.30.tgz#10caa5966004a8f24b73f059d640c1779eaf744e"
+  integrity sha512-25N/P1GnnC8EYCDerzE0hl2nOdRqS1NOFh1STEyKWRo/Bi5dXn8Z2NTaqzkbr5ExJTZEAiDfZ+eALvMTmvlXlA==
+  dependencies:
+    "@unhead/dom" "1.1.30"
+    "@unhead/schema" "1.1.30"
+    "@unhead/shared" "1.1.30"
+    hookable "^5.5.3"
+
 unicode-canonical-property-names-ecmascript@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"
@@ -5817,6 +5867,15 @@ vue@^3.0.0:
     "@vue/server-renderer" "3.3.4"
     "@vue/shared" "3.3.4"
 
+vuejs3-datepicker@^1.0.19:
+  version "1.0.19"
+  resolved "https://registry.yarnpkg.com/vuejs3-datepicker/-/vuejs3-datepicker-1.0.19.tgz#33499b6ac77ad2f966c34e79a2f997390ec02d0e"
+  integrity sha512-DKy0PaT5nq319yc1sd9I66j4BeQMhvXp//IqmR3IcxePY/yRDQCFRriFS6xzuH1iCw239Zvbsf9vF77+j+gWIQ==
+  dependencies:
+    "@babel/runtime" "^7.12.5"
+    prismjs "^1.22.0"
+    vue "^3.0.0"
+
 watchpack@^2.4.0:
   version "2.4.0"
   resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
@@ -6036,6 +6095,11 @@ yocto-queue@^0.1.0:
   resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
   integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
 
+zhead@^2.0.9:
+  version "2.0.9"
+  resolved "https://registry.yarnpkg.com/zhead/-/zhead-2.0.9.tgz#3972a1f7485cc19fdfb25007fbef44e8d5a87405"
+  integrity sha512-Y3g6EegQc6PVrYXPq2OS7/s27UGVS5Y6NY6SY3XGH4Hg+yQWbQTtWsjCgmpR8kZnYrv8auB54sz+x5FEDrvqzQ==
+
 zip-stream@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79"

+ 11 - 7
hichina-main-front/src/views/product/detail.vue

@@ -152,12 +152,16 @@
   const totalPrice = ref(0)
 
   const TYPEOFPACKAGEPROP="11cd8b32-c4f6-47db-8b8a-486c992bf43b"
-  const LOCALSPECIALTYPRODUCTTYPE = "fd264cab-ee8d-4571-a477-03d7e7c090b3";
-  const HOTELPRODUCTTYPE="a9f5adbe-c09b-49bc-a614-8a1c5d5e5337";
-  const MAXNUM = "720f4f2e-e114-4003-9806-bc56a9366278";
+  const LOCALSPECIALTYPRODUCTTYPE = "fd264cab-ee8d-4571-a477-03d7e7c090b3"
+  const HOTELPRODUCTTYPE="a9f5adbe-c09b-49bc-a614-8a1c5d5e5337"
+  const MAXNUM = "720f4f2e-e114-4003-9806-bc56a9366278"
   const PRODUCTIMAGEURLPROP = "2dea54f4-9b9c-413a-8b3a-0caf273283d2"
   const DAYSPROP = "8cc865ff-b30f-4f00-b426-9e64418e5100"
   const AVAILABLEDATEPROP = "f0b807e5-d1a6-4454-a400-7905a4fea492"
+  const GENERALPRICE="e16df480-b17d-4442-91c2-d6c30d0d7ab0"
+  const ADULTPRICEPROP="e228b843-e054-41f8-91dd-19663460df54"
+  const CHILDPRICEPROP="c4c845a7-4bef-46d8-a5ad-d72a5464e8b1"
+  const INFANTPRICEPROP="448406cb-b68f-439e-9da8-148d78ae8404"
 
   const forceRerender = async () => {
     // Remove MyComponent from the DOM
@@ -243,12 +247,12 @@
     }else{
       if(productTypeId.value == LOCALSPECIALTYPRODUCTTYPE || productTypeId.value == HOTELPRODUCTTYPE){
         console.log("003")
-        generalPrice.value = extractAttributeValueFromProductPropertyBag(sku,"e16df480-b17d-4442-91c2-d6c30d0d7ab0")
+        generalPrice.value = extractAttributeValueFromProductPropertyBag(sku,GENERALPRICE)
       }else{
         console.log("004")
-        adultUnitPrice.value = extractAttributeValueFromProductPropertyBag(sku, "e228b843-e054-41f8-91dd-19663460df54")
-        childUnitPrice.value = extractAttributeValueFromProductPropertyBag(sku, "c4c845a7-4bef-46d8-a5ad-d72a5464e8b1")
-        infantUnitPrice.value = extractAttributeValueFromProductPropertyBag(sku, "448406cb-b68f-439e-9da8-148d78ae8404")
+        adultUnitPrice.value = extractAttributeValueFromProductPropertyBag(sku, ADULTPRICEPROP)
+        childUnitPrice.value = extractAttributeValueFromProductPropertyBag(sku, CHILDPRICEPROP)
+        infantUnitPrice.value = extractAttributeValueFromProductPropertyBag(sku, INFANTPRICEPROP)
       }
     }
   }