BrandSearch.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. <script setup>
  2. import { ref, reactive, watch } from "vue";
  3. import { useMainStore } from "../stores/store";
  4. // i18n
  5. import { useI18n } from "vue-i18n";
  6. // Axios
  7. import axios from "axios";
  8. // Components
  9. import Navbar from "../components/Navbar.vue";
  10. const { t } = useI18n();
  11. const store = useMainStore();
  12. let loading = ref(false);
  13. let pageNum = ref(1); // 當前頁數(預設第一頁)
  14. let pageAmount = ref(10); // 每頁顯示筆數
  15. let totalPages = ref(1); // 總頁數
  16. let assignBrand = ref("");
  17. let searchKeyword = ref("");
  18. let noResults = ref(false);
  19. // 按鈕篩選
  20. function filterBrand(val) {
  21. if (val !== "全部") {
  22. assignBrand.value = val;
  23. } else {
  24. assignBrand.value = "";
  25. }
  26. getBrand();
  27. pageNum.value = 1;
  28. }
  29. watch(pageNum, () => {
  30. getBrand();
  31. });
  32. let data = reactive({
  33. list: [],
  34. });
  35. // 取得館外品牌
  36. async function getBrand() {
  37. loading.value = true;
  38. let keyword = "館外";
  39. let url = `https://cmm.ai:9101/find_brand?language=ch&page_num=${pageNum.value}&page_amount=${pageAmount.value}`;
  40. if (searchKeyword.value !== "") {
  41. url += `&search_name=${searchKeyword.value}`;
  42. }
  43. // 指定類別
  44. if (assignBrand.value !== "") {
  45. keyword += `,${assignBrand.value}`;
  46. }
  47. url += `&keyword=${keyword}`;
  48. try {
  49. const response = await axios.get(url);
  50. data.list = response.data.data;
  51. totalPages.value = getTotalPages(response.data.all_num, pageAmount.value); // 計算頁數
  52. loading.value = false;
  53. console.log("館外品牌", response.data.data);
  54. if (!response.data.data.length) {
  55. noResults.value = true;
  56. } else {
  57. noResults.value = false;
  58. }
  59. console.log("noResults.value", noResults.value);
  60. } catch (error) {
  61. console.error(error);
  62. }
  63. }
  64. getBrand();
  65. // 計算頁數
  66. function getTotalPages(totalRecords, recordsPerPage) {
  67. return Math.ceil(totalRecords / recordsPerPage);
  68. }
  69. // 截斷文字
  70. const truncateText = (text, maxLength) => {
  71. text = text.replace(/\s+/g, "");
  72. if (text.length <= maxLength) {
  73. return text;
  74. }
  75. return text.substring(0, maxLength) + "...";
  76. };
  77. let brandList = reactive([
  78. {
  79. value: "全部",
  80. text: "external.all",
  81. },
  82. {
  83. value: "伴手禮",
  84. text: "external.gifts",
  85. },
  86. {
  87. value: "餐飲",
  88. text: "external.dining",
  89. },
  90. {
  91. value: "住宿",
  92. text: "external.accommodation",
  93. },
  94. {
  95. value: "美髮",
  96. text: "external.hairdressing",
  97. },
  98. {
  99. value: "汽車用品",
  100. text: "external.car_supplies",
  101. },
  102. {
  103. value: "休閒娛樂",
  104. text: "external.entertainment",
  105. },
  106. {
  107. value: "寵物用品",
  108. text: "external.pet_supplies",
  109. },
  110. ]);
  111. function handleSearch() {
  112. console.log("Searching for:");
  113. searchKeyword.value;
  114. }
  115. </script>
  116. <template>
  117. <Navbar />
  118. <div class="brand-list">
  119. <v-text-field
  120. v-model="searchKeyword"
  121. append-inner-icon="mdi-magnify"
  122. density="compact"
  123. label="搜尋品牌"
  124. variant="outlined"
  125. hide-details
  126. single-line
  127. @click:append-inner="getBrand"
  128. @keydown.enter="getBrand"
  129. class="border-sm rounded"
  130. ></v-text-field>
  131. <v-row class="mt-3 px-1">
  132. <v-col
  133. cols="6"
  134. v-for="(item, index) in brandList"
  135. :key="index"
  136. class="pa-2"
  137. >
  138. <button
  139. @click="filterBrand(item.value)"
  140. :class="{ active: item.value === assignBrand }"
  141. class="rounded brand-btn"
  142. >
  143. {{ t(item.text) }}
  144. </button>
  145. </v-col>
  146. </v-row>
  147. <div v-if="loading" class="d-flex justify-center pt-15">
  148. <v-progress-circular color="primary" indeterminate></v-progress-circular>
  149. </div>
  150. <v-row v-else-if="!loading && !noResults" class="content mt-0">
  151. <v-col
  152. cols="12"
  153. class="card"
  154. v-for="(item, index) in data.list"
  155. :key="index"
  156. >
  157. <a :href="item.info.url" target="_blank">
  158. <img class="card-img" :src="item.info.img" :alt="item.info.name" />
  159. </a>
  160. <h2>{{ item.info.name }}</h2>
  161. <p>{{ truncateText(item.info.content, 100) }}</p>
  162. <div class="d-flex align-center mt-3 mb-5">
  163. <img src="../assets/img/location-dot-solid.svg" width="15" alt="" />
  164. <p class="ms-2">{{ item.info.address }}</p>
  165. </div>
  166. <div class="cta">
  167. <a :href="item.info.url" target="_blank">
  168. <button>立即前往</button>
  169. </a>
  170. </div>
  171. </v-col>
  172. </v-row>
  173. <p v-else-if="noResults" class="text-center mt-10">
  174. 找不到符合的資料,請重新搜尋。
  175. </p>
  176. <v-pagination
  177. v-if="!loading && !noResults"
  178. color="primary"
  179. v-model="pageNum"
  180. class="my-10"
  181. :length="totalPages"
  182. ></v-pagination>
  183. </div>
  184. </template>
  185. <style lang="scss">
  186. .brand-list {
  187. width: 90%;
  188. margin: 30px auto;
  189. .brand-btn {
  190. width: 100%;
  191. padding: 0.7rem;
  192. color: var(--main-color);
  193. background-color: #f5f2eb;
  194. letter-spacing: 1px;
  195. transition: all 0.3s;
  196. &:hover {
  197. opacity: 0.8;
  198. }
  199. &.active {
  200. color: #fff;
  201. background-color: var(--main-color);
  202. }
  203. }
  204. .content {
  205. text-align: center;
  206. .card {
  207. border-bottom: 1px solid #cea84d;
  208. padding: 2rem 1rem;
  209. &:last-child {
  210. border-bottom: none !important;
  211. }
  212. }
  213. .card {
  214. letter-spacing: 0.05rem;
  215. h2 {
  216. margin: 0.5rem 0;
  217. font-size: 1.2rem;
  218. font-weight: bold;
  219. text-align: left;
  220. }
  221. p {
  222. text-align: left;
  223. }
  224. .card-img {
  225. width: 100%;
  226. height: 220px;
  227. object-fit: contain;
  228. }
  229. .cta {
  230. text-align: right;
  231. button {
  232. padding: 10px 20px;
  233. border-radius: 100px;
  234. color: #fff;
  235. text-align: center;
  236. background-color: #b07843;
  237. letter-spacing: 0.05rem;
  238. text-decoration: none;
  239. transition: all 0.3s;
  240. }
  241. }
  242. }
  243. }
  244. .v-pagination {
  245. margin: auto;
  246. max-width: 300px;
  247. }
  248. .v-btn--icon.v-btn--density-default {
  249. width: 35px !important;
  250. }
  251. }
  252. </style>