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.

499 lines
17 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
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
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
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="tw-px-[30px] tw-mt-[30px] tw-mb-[60px] md:tw-mb-[100px] xl:tw-px-[60px] xl:tw-max-w-screen-xl xl:tw-mx-auto xl:tw-grid xl:tw-grid-cols-[380px_auto] xl:tw-gap-[30px]">
  4. <section class="xl:tw-col-span-2 tw-mb-[36px] md:tw-mb-[24px] lg:tw-mb-[34px]">
  5. <Breadcrumbs></Breadcrumbs>
  6. <sort :results="result" :sortType="sortType" :sortBy="sortBy" @sort="updateSortBy($event)"
  7. @filter="$modal.show(`sidebar-filter-modal`)"></sort>
  8. </section>
  9. <section class="tw-grid tw-grid-cols-1 tw-gap-[30px] tw-auto-rows-min">
  10. <div v-if="$vuetify.breakpoint.xl">
  11. <multipleLevel :label="'Categories'" :placeholder="$t('Find category/subcategory ...')" :list="categoryList" :queryItem="categoryQueryFilter"
  12. @update="updateCategoryFilter"></multipleLevel>
  13. </div>
  14. <div v-if="$vuetify.breakpoint.xl">
  15. <multipleLevel :label="'Location'" :placeholder="$t('Find country/city ...')" :list="locationList"
  16. :queryItem="locationQueryFilter" @update="updateLocationFilter"></multipleLevel>
  17. </div>
  18. <!-- <div v-if="$vuetify.breakpoint.xl">
  19. <price :max="maxPrice" :currentValue="priceRangeFilter" @update="updatePriceRange"></price>
  20. </div> -->
  21. <!-- <div v-if="$vuetify.breakpoint.xl">
  22. <rating @update="updateRatingRange"></rating>
  23. </div> -->
  24. </section>
  25. <section class="">
  26. <ServiceListCard class="tw-mb-[30px]" v-for="(item, index) in serviceList" :key="index" :service="item">
  27. </ServiceListCard>
  28. <div class="tw-mt-[34px] tw-flex tw-justify-end">
  29. <pagination :pageLength="pageLength" @update="updateCurrentPage"></pagination>
  30. </div>
  31. </section>
  32. <div v-if="!$vuetify.breakpoint.xl">
  33. <sidebarFilterModal :max="maxPrice" :locationList="locationList"
  34. :locationChecked="locationNameFilter" :categoryChecked="categoryFilter" :priceChecked="priceRangeFilter"
  35. @updatePriceRange="updatePriceRange" @updateCategoryFilter="updateCategoryFilter"
  36. @updateLocationFilter="updateLocationFilter"></sidebarFilterModal>
  37. </div>
  38. <loading :isLoading="isPageLoading"></loading>
  39. </div>
  40. </template>
  41. <script>
  42. import Breadcrumbs from "@/components/Breadcrumbs";
  43. import sort from "@/components/newComponent/sort/sort";
  44. import oneLevel from "@/components/newComponent/filter/oneLevel";
  45. import multipleLevel from "@/components/newComponent/filter/multipleLevel";
  46. import price from "@/components/newComponent/filter/price";
  47. import rating from "@/components/newComponent/filter/rating.vue";
  48. import pagination from "@/components/newComponent/pagination/pagination.vue";
  49. import sidebarFilterModal from "@/components/newComponent/modal/sidebarFilterModal.vue";
  50. import ServiceListCard from "@/components/service/ServiceListCard";
  51. import loading from "@/components/newComponent/loading/loading.vue";
  52. export default {
  53. name: "ServiceList",
  54. auth: false,
  55. components: {
  56. Breadcrumbs,
  57. sort,
  58. oneLevel,
  59. multipleLevel,
  60. price,
  61. rating,
  62. sidebarFilterModal,
  63. ServiceListCard,
  64. pagination,
  65. loading,
  66. },
  67. meta: {
  68. pageName: "Service List",
  69. },
  70. data() {
  71. return {
  72. renderList: [],
  73. serviceList: [],
  74. sortType: [
  75. // { name: "Ratings", value: "Ratings" },
  76. // { name: "ShowEasy Recommended", value: "ShowEasy Recommended" },
  77. { name: "Popularity", value: "CreateDate" },
  78. { name: "Price (Low to High)", value: "MinPrice" },
  79. { name: "Recently Added", value: "LaunchDateS" },
  80. ],
  81. locationList: [],
  82. categoryList: [],
  83. // regionNameList: ['123'],
  84. countryNameList: ['Asia','Asia1'],
  85. cityNameList: ['Taiwan','Taiwan1'],
  86. categoryNameList: ['Rental cars','Rental cars1'],
  87. subcategoryNameList: ['子類1'],
  88. sortBy: "CreateDate",
  89. maxPrice: 100,
  90. priceRangeFilter: [0,100],
  91. ratingRangeFilter: [0, 5],
  92. locationNameFilter: ['Asia','Taiwan'],
  93. categoryFilter: ['Rental cars','Rental cars1'],
  94. perPageItems: 10,
  95. currentPage: 1,
  96. total: 0,
  97. locationQueryFilter: "",
  98. categoryQueryFilter: "",
  99. isPageLoading: false,
  100. mainCategoryMap: new Map(),
  101. subCategoryMap: new Map(),
  102. mainLocationMap: new Map(),
  103. subLocationMap: new Map(),
  104. subLocationMap2: new Map(),
  105. mainCategoryQuery: '',
  106. subCategoryQuery: '',
  107. };
  108. },
  109. async created() {
  110. this.isPageLoading = true;
  111. await this.getQuery();
  112. await this.getServiceList();
  113. await this.getCategoryList();
  114. await this.getLocationList();
  115. // await this.getPriceRange();
  116. // this.renderList = this.sliceRenderList(this.serviceFilter);
  117. this.$nextTick(()=>{
  118. this.isPageLoading = false;
  119. });
  120. },
  121. mounted() { },
  122. computed: {
  123. // serviceFilter() {
  124. // var vm = this;
  125. // if (Array.isArray(vm.serviceList)) {
  126. // let priceList = vm.filterByPrice(
  127. // vm.serviceList,
  128. // vm.priceRangeFilter[0],
  129. // vm.priceRangeFilter[1]
  130. // );
  131. // priceList = priceList == undefined ? [] : priceList;
  132. // let locationList = vm.filterByLocation(
  133. // priceList,
  134. // vm.locationNameFilter
  135. // );
  136. // locationList = locationList == undefined ? [] : locationList;
  137. // let categoryList = vm.filterByCategory(
  138. // locationList,
  139. // vm.categoryFilter
  140. // );
  141. // categoryList = categoryList == undefined ? [] : categoryList;
  142. // if(categoryList.length<1){
  143. // return [];
  144. // }
  145. // let sortedList = vm.sortServiceList(categoryList);
  146. // return sortedList;
  147. // } else {
  148. // return [];
  149. // }
  150. // },
  151. result() {
  152. return this.total;
  153. },
  154. pageLength() {
  155. return Math.ceil(this.result / this.perPageItems);
  156. },
  157. // renderList() {
  158. // let arr = this.sliceRenderList(this.serviceFilter);
  159. // return arr;
  160. // },
  161. currency() {
  162. return this.$store.getters.getCurrency;
  163. },
  164. },
  165. watch: {
  166. currency: {
  167. handler: async function (newVal, oldVal) {
  168. let vm = this;
  169. if (newVal !== oldVal) {
  170. vm.isPageLoading = true;
  171. await vm.getServiceList();
  172. // let data =await vm.mapServiceLocationName(
  173. // vm.serviceList,
  174. // vm.countryNameList,
  175. // vm.cityNameList
  176. // );
  177. // vm.serviceList = data == undefined ? [] : data;
  178. // vm.serviceList =await vm.mapServiceCategoryName(
  179. // vm.serviceList,
  180. // vm.categoryNameList
  181. // );
  182. // vm.serviceList = data == undefined ? [] : data;
  183. // vm.renderList =await vm.serviceList;
  184. // await vm.getPriceRange();
  185. vm.isPageLoading = false;
  186. }
  187. },
  188. },
  189. // $route: {
  190. // handler: function () {
  191. // this.getQuery();
  192. // },
  193. // },
  194. },
  195. methods: {
  196. async getServiceList() {
  197. let vm = this;
  198. let keyword = "";
  199. let subcatg = "";
  200. let sortField = "CreateDate";
  201. if(vm.sortBy){
  202. sortField = vm.sortBy;
  203. }
  204. let location = "";
  205. // let category = "";
  206. let currency = this.$store.getters.getCurrency;
  207. if (vm.$route.query.q) {
  208. keyword = vm.$route.query.q;
  209. }
  210. // if (vm.$route.query.category) {
  211. // category = "&category=" + vm.$route.query.category;
  212. // }
  213. // if (vm.categoryQueryFilter) {
  214. // subcatg = vm.categoryQueryFilter;
  215. // }else if(vm.$route.query.subcatg){
  216. // subcatg = vm.$route.query.subcatg;
  217. // }
  218. // if(vm.locationQueryFilter){
  219. // location = vm.locationQueryFilter;
  220. // }
  221. await vm.$axios.get(`/trending/api/Onsite/ServiceLists?Lang=${vm.$i18n.localeProperties["langQuery"]}&PageIndex=${vm.currentPage}
  222. &PageSize=${vm.perPageItems}&SortField=${sortField}&sortOrder=desc&KeyWord=${keyword}&Categories=${subcatg}&Locations=${location}
  223. &Currency=${currency}&MinPrice=0&MaxPrice=0`).then((response) => {
  224. if(response && response.data && response.data.DATA && response.data.DATA.rel){
  225. let data = response.data.DATA.rel
  226. if(data.DataList.length>0){
  227. vm.total = data.Total;
  228. vm.serviceList = data.DataList;
  229. }
  230. }
  231. })
  232. .catch((err) => {
  233. console.log(err);
  234. });
  235. },
  236. async getCategoryList() {
  237. await this.$axios
  238. .get(`/trending/api/Onsite/Categories?Lang=${this.$i18n.localeProperties["langQuery"]}`)
  239. .then((response) => {
  240. if(response && response.data && response.data.DATA && response.data.DATA.rel){
  241. let data = response.data.DATA.rel
  242. if(data.length>0){
  243. this.categoryList = data.map((item) => {
  244. this.mainCategoryMap.set(item.CategoryID, item);
  245. if(item.SubCategoryList && item.SubCategoryList.length>0){
  246. item.SubCategoryList = item.SubCategoryList.map(
  247. (children) => {
  248. this.subCategoryMap.set(children.CategoryID, children);
  249. return {
  250. title: children.CategoryName,
  251. key: children.CategoryID,
  252. };
  253. }
  254. );
  255. }else{
  256. item.SubCategoryList = [];
  257. }
  258. return {
  259. title: item.CategoryName,
  260. key: item.CategoryID,
  261. children: item.SubCategoryList,
  262. };
  263. });
  264. }
  265. }
  266. })
  267. .catch((error) =>
  268. console.log(error)
  269. );
  270. },
  271. async getLocationList() {
  272. await this.$axios
  273. .get(`/trending/api/Onsite/Locations?Lang=${this.$i18n.localeProperties["langQuery"]}`)
  274. .then((response) => {
  275. if(response && response.data && response.data.DATA && response.data.DATA.rel){
  276. let data = response.data.DATA.rel
  277. if(data.length>0){
  278. // this.locationList = data;
  279. this.locationList = data.map((item) => {
  280. this.mainLocationMap.set(item.RegionID, item);
  281. if(item.CountryList && item.CountryList.length>0){
  282. item.CountryList = item.CountryList.map(
  283. (children) => {
  284. this.subLocationMap.set(children.CountryID, children);
  285. if(children.CityList && children.CityList.length>0){
  286. children.CityList = children.CityList.map(
  287. (children2) => {
  288. this.subLocationMap2.set(children2.CityID, children2);
  289. return {
  290. title: children2.CityName,
  291. key: children2.CityID,
  292. };
  293. }
  294. );
  295. }else{
  296. children.CityList = [];
  297. }
  298. return {
  299. title: children.CountryName,
  300. key: children.CountryID,
  301. children: children.CityList,
  302. };
  303. }
  304. );
  305. }else{
  306. item.CountryList = [];
  307. }
  308. return {
  309. title: item.RegionName,
  310. key: item.RegionID,
  311. children: item.CountryList,
  312. };
  313. });
  314. }
  315. }
  316. })
  317. .catch((error) =>
  318. console.log(error)
  319. );
  320. },
  321. updateSortBy(data) {
  322. this.sortBy = data;
  323. // console.log("排序:"+this.sortBy);
  324. this.getServiceList();
  325. },
  326. // sortServiceList(data) {
  327. // switch (this.sortBy) {
  328. // // case "Ratings":
  329. // // function Ratings(a, b) {
  330. // // if (Number(a.rating) < Number(b.rating)) return 1;
  331. // // if (Number(a.rating) > Number(b.rating)) return -1;
  332. // // return 0;
  333. // // }
  334. // // return data.sort(Ratings);
  335. // // case "ShowEasy Recommended":
  336. // // return data;
  337. // case "Popularity":
  338. // function Views(a, b) {
  339. // if (Number(a.view_counts) < Number(b.view_counts)) return 1;
  340. // if (Number(a.view_counts) > Number(b.view_counts)) return -1;
  341. // return 0;
  342. // }
  343. // return data.sort(Views);
  344. // case "Price":
  345. // function Price(a, b) {
  346. // if (Number(a.price) < Number(b.price)) return -1;
  347. // if (Number(a.price) > Number(b.price)) return 1;
  348. // return 0;
  349. // }
  350. // return data.sort(Price);
  351. // case "Recently Added":
  352. // function Date(a, b) {
  353. // if (
  354. // a.launch_dates[0].replace(/-/g, "") <
  355. // b.launch_dates[0].replace(/-/g, "")
  356. // )
  357. // return 1;
  358. // if (
  359. // a.launch_dates[0].replace(/-/g, "") >
  360. // b.launch_dates[0].replace(/-/g, "")
  361. // )
  362. // return -1;
  363. // return 0;
  364. // }
  365. // return data.sort(Date);
  366. // default:
  367. // return data;
  368. // }
  369. // },
  370. mapSavedService(data, savedList) {
  371. return data.map((item) => {
  372. item.liked = false;
  373. if (savedList.includes(item.id)) {
  374. item.liked = true;
  375. }
  376. return item;
  377. });
  378. },
  379. mapServiceLocationName(data, countryList, cityList) {
  380. data = data.map((item) => {
  381. Number(item.country) > 0
  382. ? (item.countryName = countryList[item.country])
  383. : (item.countryName = "");
  384. return item;
  385. });
  386. data = data.map((item) => {
  387. Number(item.city) > 0
  388. ? (item.cityName = cityList[item.city])
  389. : (item.cityName = "");
  390. return item;
  391. });
  392. return data;
  393. },
  394. mapServiceCategoryName(data, categoryList) {
  395. data = data.map((item) => {
  396. Number(item.category) > 0
  397. ? (item.categoryName = categoryList[item.category])
  398. : (item.categoryName = "");
  399. return item;
  400. });
  401. return data;
  402. },
  403. async getPriceRange() {
  404. let max = 0;
  405. let vm = this;
  406. if(vm.serviceList){
  407. vm.serviceList.forEach((element) => {
  408. if (element.price > max) {
  409. max = element.price;
  410. }
  411. });
  412. }
  413. vm.maxPrice = max;
  414. vm.priceRangeFilter = [0, max];
  415. },
  416. filterByPrice(data, min, max) {
  417. let item = data.filter((item) => item.price >= min && item.price <= max);
  418. return item;
  419. },
  420. updatePriceRange(value) {
  421. this.priceRangeFilter = [...value];
  422. },
  423. filterByRating(data, min, max) {
  424. return data.filter((item) => item.price >= min && item.price <= max);
  425. },
  426. updateRatingRange(value) {
  427. // console.log(value);
  428. },
  429. filterByLocation(data, locations) {
  430. let list = data.filter(
  431. (item) =>
  432. locations.includes(item.cityName) ||
  433. locations.includes(item.countryName)
  434. );
  435. return list;
  436. },
  437. updateLocationFilter(value) {
  438. // console.log("位置勾選");
  439. this.locationQueryFilter = "";
  440. // this.getServiceList();
  441. },
  442. filterByCategory(data, categories) {
  443. return data.filter((item) => categories.includes(item.categoryName));
  444. },
  445. updateCategoryFilter(value) {
  446. // console.log("類型勾選:" + value);
  447. this.categoryQueryFilter = "";
  448. // this.getServiceList();
  449. },
  450. updateCurrentPage(value) {
  451. // console.log("分頁變化");
  452. this.currentPage = value;
  453. this.getServiceList();
  454. },
  455. sliceRenderList(data) {
  456. return data.slice(
  457. (this.currentPage - 1) * this.perPageItems,
  458. this.currentPage * this.perPageItems
  459. );
  460. },
  461. async getQuery() {
  462. let vm = this;
  463. // this.locationQueryFilter = "";
  464. this.categoryQueryFilter = "";
  465. // if (this.$route.query.hasOwnProperty("country") && this.countryNameList.length>0) {
  466. // this.locationQueryFilter =
  467. // this.countryNameList[Number(this.$route.query.country)];
  468. // }
  469. // if (this.$route.query.hasOwnProperty("city") && this.cityNameList.length>0) {
  470. // this.locationQueryFilter =
  471. // this.cityNameList[Number(this.$route.query.city)];
  472. // }
  473. // if (this.$route.query.hasOwnProperty("region")) {
  474. // this.locationQueryFilter =
  475. // this.regionNameList[Number(this.$route.query.region)];
  476. // }
  477. // if (this.$route.query.hasOwnProperty("category") && this.categoryNameList.length>0) {
  478. // this.categoryQueryFilter =
  479. // this.categoryNameList[Number(this.$route.query.category)];
  480. // }
  481. // if (this.$route.query.hasOwnProperty("subcategory")) {
  482. // this.categoryQueryFilter =
  483. // this.unsortSubcategoryList[Number(this.$route.query.subcategory)];
  484. // }
  485. if(vm.$route.query.hasOwnProperty("category")){
  486. // vm.categoryQueryFilter = vm.$route.query.category;
  487. }else if(vm.$route.query.hasOwnProperty("subcatg")){
  488. vm.categoryQueryFilter = vm.$route.query.subcatg;
  489. }
  490. },
  491. },
  492. };
  493. </script>
  494. <style lang="scss" scoped>
  495. </style>