CourseCard.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <script setup>
  2. import { ref, reactive, watch } from "vue";
  3. import { useMainStore } from "@/stores/store";
  4. import axios from "axios";
  5. const props = defineProps({
  6. data: {
  7. type: Object,
  8. },
  9. });
  10. const store = useMainStore();
  11. let progress = ref(false);
  12. let token = localStorage.getItem("token");
  13. // 收藏課程清單
  14. let favorites = reactive({
  15. list: [],
  16. });
  17. // 加入收藏課程
  18. async function setFavoriteClass(classId) {
  19. let isLogin = store.checkToken();
  20. if (!isLogin) {
  21. store.openLoginDialog();
  22. return;
  23. }
  24. progress.value = true;
  25. const url = `https://cmm.ai:8088/api/add_favorite_class?class_name_id=${classId}&access_token=${token}`;
  26. try {
  27. const response = await axios.post(url);
  28. getFavoriteClass();
  29. progress.value = false;
  30. } catch (error) {
  31. console.error(error);
  32. }
  33. }
  34. // 取得收藏課程
  35. async function getFavoriteClass() {
  36. try {
  37. const response = await axios.get(
  38. `https://cmm.ai:8088/api/get_favorite_class?access_token=${token}`
  39. );
  40. favorites.list = response.data.favorite_courses;
  41. } catch (error) {
  42. console.error(error);
  43. }
  44. }
  45. getFavoriteClass();
  46. // 刪除收藏課程
  47. async function deleteFavoriteClass(classId) {
  48. progress.value = true;
  49. try {
  50. const response = await axios.post(
  51. `https://cmm.ai:8088/api/delete_favorite_class?class_name_id=${classId}&access_token=${token}`
  52. );
  53. progress.value = false;
  54. getFavoriteClass();
  55. } catch (error) {
  56. console.error(error);
  57. }
  58. }
  59. // 檢查收藏狀態
  60. function isClassFavorite(classId) {
  61. if (favorites.list) {
  62. let list = favorites.list.map((e) => e.class_name_id);
  63. return list.includes(classId);
  64. }
  65. }
  66. // // 返回課程圖片網址
  67. // function getImageSrc(data) {
  68. // console.log("data", data);
  69. // if (data.is_inner === 0) {
  70. // return data.cover_img;
  71. // } else if (data.group_id === 9) {
  72. // return store.getImageUrl("cfa-default.jpg");
  73. // } else if (data.special_class_list_name === "one_day_class") {
  74. // return store.getImageUrl("default.png");
  75. // } else if (data.org === "Udemy") {
  76. // return data.cover_img;
  77. // } else {
  78. // return `https://ntcri.org/${data.cover_img}`;
  79. // }
  80. // }
  81. </script>
  82. <template>
  83. <div class="main-card">
  84. <section class="card-title">
  85. <h3>{{ data.org === "Udemy" ? data.title : data.name }}</h3>
  86. </section>
  87. <div class="card-info">
  88. <!-- <router-link :to="`/course-detail/${data.class_name_id}`"> -->
  89. <a
  90. :href="
  91. data.org !== 'Udemy'
  92. ? $router.resolve(`/course-detail/${data.class_name_id}`).href
  93. : data.video_url
  94. "
  95. target="_blank"
  96. >
  97. <div class="overflow-hidden">
  98. <v-img
  99. class="mx-auto cover-img"
  100. :lazy-src="store.getImageSrc(data)"
  101. height="13.75em"
  102. cover
  103. :src="store.getImageSrc(data)"
  104. alt="臺灣工藝學校全球學習共享平台"
  105. >
  106. <template v-slot:placeholder>
  107. <div class="d-flex align-center justify-center fill-height">
  108. <v-progress-circular
  109. color="grey-lighten-4"
  110. indeterminate
  111. ></v-progress-circular>
  112. </div>
  113. </template>
  114. </v-img>
  115. </div>
  116. </a>
  117. <div class="d-flex justify-end mt-3">
  118. <small class="text-gray">編號:{{ data.encode }}</small>
  119. </div>
  120. <!-- </router-link> -->
  121. <ul v-if="data.org !== 'Udemy'">
  122. <li class="d-flex align-center mb-5">
  123. <div class="description">
  124. <p
  125. class="text-gray pt-3"
  126. v-html="store.formatString(data.introduction)"
  127. ></p>
  128. </div>
  129. </li>
  130. <li class="d-flex align-center justify-space-between">
  131. <div class="d-flex align-center">
  132. <v-icon
  133. color="primary"
  134. icon="mdi-map-marker"
  135. class="me-1 mt-1"
  136. ></v-icon>
  137. <p class="mb-0 pe-3 location-item">
  138. {{ data.location_name }}
  139. </p>
  140. </div>
  141. <button aria-label="收藏課程">
  142. <v-icon
  143. v-if="isClassFavorite(data.class_name_id)"
  144. @click="deleteFavoriteClass(data.class_name_id)"
  145. color="primary"
  146. icon="mdi-bookmark"
  147. size="large"
  148. ></v-icon>
  149. <v-icon
  150. v-else
  151. @click="setFavoriteClass(data.class_name_id)"
  152. color="primary"
  153. icon="mdi-bookmark-outline"
  154. size="large"
  155. ></v-icon>
  156. </button>
  157. </li>
  158. </ul>
  159. <ul v-else class="justify-center">
  160. <li>
  161. <div class="description">
  162. <p
  163. class="text-gray pt-3"
  164. v-html="store.formatString(data.content)"
  165. ></p>
  166. </div>
  167. <!-- <p class="text-gray pt-3">
  168. {{ data.content }}
  169. </p> -->
  170. </li>
  171. </ul>
  172. </div>
  173. </div>
  174. </template>
  175. <style lang="scss" scoped>
  176. .description {
  177. height: 7em;
  178. overflow: hidden;
  179. }
  180. .location-item {
  181. -webkit-line-clamp: 2 !important;
  182. }
  183. </style>