BlogList.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <template>
  2. <content-with-sidebar v-if="Object.keys(blogList).length" class="blog-wrapper">
  3. <!-- blogs -->
  4. <b-row class="blog-list-wrapper">
  5. <b-col md="6">
  6. <b-col v-for="(blog, index) in blogList.slice(0, Math.ceil(blogList.length / 2))" :key="index" md="12">
  7. <b-card tag="article" no-body>
  8. <b-link :to="{ name: 'blog-detail', params: { id: blog.id } }">
  9. <b-img :src="defaultsImg()" :alt="defaultsImg().slice(5)" class="card-img-top" />
  10. </b-link>
  11. <b-card-body>
  12. <b-card-title>
  13. <b-link :to="{ name: 'blog-detail', params: { id: blog.id } }"
  14. class="blog-title-truncate text-body-heading">
  15. {{ blog.title }}
  16. </b-link>
  17. </b-card-title>
  18. <b-media no-body>
  19. <b-media-aside vertical-align="center" class="mr-50">
  20. <b-avatar href="javascript:void(0)" size="24" :src="getUserAvatar(blog.userId)" />
  21. </b-media-aside>
  22. <b-media-body>
  23. <small class="text-muted mr-50">by</small>
  24. <small>
  25. <b-link class="text-body">{{ blog.userFullName }}</b-link>
  26. </small>
  27. <span class="text-muted ml-75 mr-50">|</span>
  28. <small class="text-muted">{{ dateFormat(blog.blogPosted) }}</small>
  29. </b-media-body>
  30. </b-media>
  31. <div class="my-1 py-25">
  32. <b-link v-for="(tag, index) in JSON.parse(blog.tags)" :key="index">
  33. <b-badge pill class="mr-75" :variant="tagsColor(tag)">
  34. {{ tag }}
  35. </b-badge>
  36. </b-link>
  37. </div>
  38. <b-card-text class="blog-content-truncate">
  39. {{ blog.excerpt }}
  40. </b-card-text>
  41. <hr>
  42. <div class="d-flex justify-content-between align-items-center">
  43. <b-link :to="{ path: `/pages/blog/${blog.id}#blogComment` }">
  44. <div class="d-flex align-items-center text-body">
  45. <feather-icon icon="MessageSquareIcon" class="mr-50" />
  46. <span class="font-weight-bold">{{ blog.comment ? kFormatter(blog.comment) : 0 }} Comments</span>
  47. </div>
  48. </b-link>
  49. <b-link :to="{ name: 'blog-detail', params: { id: blog.id } }" class="font-weight-bold">
  50. Read More
  51. </b-link>
  52. </div>
  53. </b-card-body>
  54. </b-card>
  55. </b-col>
  56. </b-col>
  57. <b-col md="6">
  58. <b-col v-for="(blog, index) in blogList.slice(Math.ceil(blogList.length / 2))" :key="index" md="12">
  59. <b-card tag="article" no-body>
  60. <b-link :to="{ name: 'blog-detail', params: { id: blog.id } }">
  61. <b-img :src="defaultsImg()" :alt="defaultsImg().slice(5)" class="card-img-top" />
  62. </b-link>
  63. <b-card-body>
  64. <b-card-title>
  65. <b-link :to="{ name: 'blog-detail', params: { id: blog.id } }"
  66. class="blog-title-truncate text-body-heading">
  67. {{ blog.title }}
  68. </b-link>
  69. </b-card-title>
  70. <b-media no-body>
  71. <b-media-aside vertical-align="center" class="mr-50">
  72. <b-avatar href="javascript:void(0)" size="24" :src="getUserAvatar(blog.userId)" />
  73. </b-media-aside>
  74. <b-media-body>
  75. <small class="text-muted mr-50">by</small>
  76. <small>
  77. <b-link class="text-body">{{ blog.userFullName }}</b-link>
  78. </small>
  79. <span class="text-muted ml-75 mr-50">|</span>
  80. <small class="text-muted">{{ dateFormat(blog.blogPosted) }}</small>
  81. </b-media-body>
  82. </b-media>
  83. <div class="my-1 py-25">
  84. <b-link v-for="(tag, index) in JSON.parse(blog.tags)" :key="index">
  85. <b-badge pill class="mr-75" :variant="tagsColor(tag)">
  86. {{ tag }}
  87. </b-badge>
  88. </b-link>
  89. </div>
  90. <b-card-text class="blog-content-truncate">
  91. {{ blog.excerpt }}
  92. </b-card-text>
  93. <hr>
  94. <div class="d-flex justify-content-between align-items-center">
  95. <b-link :to="{ path: `/pages/blog/${blog.id}#blogComment` }">
  96. <div class="d-flex align-items-center text-body">
  97. <feather-icon icon="MessageSquareIcon" class="mr-50" />
  98. <span class="font-weight-bold">{{ blog.comment ? kFormatter(blog.comment) : 0 }} Comments</span>
  99. </div>
  100. </b-link>
  101. <b-link :to="{ name: 'blog-detail', params: { id: blog.id } }" class="font-weight-bold">
  102. Read More
  103. </b-link>
  104. </div>
  105. </b-card-body>
  106. </b-card>
  107. </b-col>
  108. </b-col>
  109. <b-col cols="12">
  110. <!-- pagination -->
  111. <div class="my-2">
  112. <b-pagination v-model="currentPage" align="center" :total-rows="rows" first-number last-number
  113. prev-class="prev-item" next-class="next-item">
  114. <template #prev-text>
  115. <feather-icon icon="ChevronLeftIcon" size="18" />
  116. </template>
  117. <template #next-text>
  118. <feather-icon icon="ChevronRightIcon" size="18" />
  119. </template>
  120. </b-pagination>
  121. </div>
  122. </b-col>
  123. </b-row>
  124. <!--/ blogs -->
  125. <!-- sidebar -->
  126. <div slot="sidebar" class="blog-sidebar py-2 py-lg-0">
  127. <!-- input search -->
  128. <b-form-group class="blog-search">
  129. <b-input-group class="input-group-merge">
  130. <b-form-input id="search-input" v-model="search_query" placeholder="Search here" />
  131. <b-input-group-append class="cursor-pointer" is-text>
  132. <feather-icon icon="SearchIcon" />
  133. </b-input-group-append>
  134. </b-input-group>
  135. </b-form-group>
  136. <!--/ input search -->
  137. <!-- recent posts -->
  138. <div class="blog-recent-posts mt-3">
  139. <h6 class="section-label mb-75">
  140. Recent Posts
  141. </h6>
  142. <b-media v-for="(recentpost, index) in blogSidebar.recentPosts" :key="index" no-body
  143. :class="index ? 'mt-2' : ''">
  144. <b-media-aside class="mr-2">
  145. <b-link :to="{ name: 'blog-detail', params: { id: recentpost.id } }">
  146. <b-img :src="defaultsImg()" :alt="defaultsImg().slice(6)" width="100" rounded height="70" />
  147. </b-link>
  148. </b-media-aside>
  149. <b-media-body>
  150. <h6 class="blog-recent-post-title">
  151. <b-link :to="{ name: 'blog-detail', params: { id: recentpost.id } }" class="text-body-heading">
  152. {{ recentpost.title }}
  153. </b-link>
  154. </h6>
  155. <span class="text-muted mb-0">
  156. {{ dateFormat(recentpost.createdTime) }}
  157. </span>
  158. </b-media-body>
  159. </b-media>
  160. </div>
  161. <!--/ recent posts -->
  162. <!-- categories -->
  163. <div class="blog-categories mt-3">
  164. <h6 class="section-label mb-1">
  165. Categories
  166. </h6>
  167. <div v-for="category in blogSidebar.categories" :key="category.icon"
  168. class="d-flex justify-content-start align-items-center mb-75">
  169. <b-link>
  170. <b-avatar rounded size="32" :variant="tagsColor(category.category)" class="mr-75">
  171. <feather-icon :icon="category.icon" size="16" />
  172. </b-avatar>
  173. </b-link>
  174. <b-link>
  175. <div class="blog-category-title text-body">
  176. {{ category.category }}
  177. </div>
  178. </b-link>
  179. </div>
  180. </div>
  181. <!--/ categories -->
  182. </div>
  183. <!--/ sidebar -->
  184. </content-with-sidebar>
  185. </template>
  186. <script>
  187. import {
  188. BRow,
  189. BCol,
  190. BCard,
  191. BFormInput,
  192. BCardText,
  193. BCardTitle,
  194. BMedia,
  195. BAvatar,
  196. BMediaAside,
  197. BMediaBody,
  198. BImg,
  199. BCardBody,
  200. BLink,
  201. BBadge,
  202. BFormGroup,
  203. BInputGroup,
  204. BInputGroupAppend,
  205. BPagination,
  206. } from 'bootstrap-vue'
  207. import { kFormatter } from '@core/utils/filter'
  208. import ContentWithSidebar from '@core/layouts/components/content-with-sidebar/ContentWithSidebar.vue'
  209. import useJwt from '@/auth/jwt/useJwt'
  210. import { format } from 'date-fns'
  211. import { zhTW } from 'date-fns/locale'
  212. export default {
  213. components: {
  214. BRow,
  215. BCol,
  216. BCard,
  217. BFormInput,
  218. BCardText,
  219. BCardBody,
  220. BCardTitle,
  221. BMedia,
  222. BAvatar,
  223. BMediaAside,
  224. BMediaBody,
  225. BLink,
  226. BBadge,
  227. BFormGroup,
  228. BInputGroup,
  229. BInputGroupAppend,
  230. BImg,
  231. BPagination,
  232. ContentWithSidebar,
  233. },
  234. data() {
  235. return {
  236. search_query: '',
  237. blogList: [],
  238. blogSidebar: {},
  239. currentPage: 1,
  240. perPage: 1,
  241. rows: 140,
  242. }
  243. },
  244. created() {
  245. useJwt.getPost('/api/get_blog/list').then(res => {
  246. this.blogList = res.data
  247. })
  248. useJwt.getPost('/api/get_blog/sidebar').then(res => {
  249. this.blogSidebar = res.data
  250. })
  251. },
  252. methods: {
  253. kFormatter,
  254. tagsColor(tag) {
  255. if (tag === 'Quote') return 'light-info'
  256. if (tag === 'Gaming') return 'light-danger'
  257. if (tag === 'Fashion') return 'light-primary'
  258. if (tag === 'Video') return 'light-warning'
  259. if (tag === 'Food') return 'light-success'
  260. return 'light-primary'
  261. },
  262. dateFormat(date) {
  263. return format(new Date(date), 'yyyy-MM-dd hh:mm', { locale: zhTW })
  264. },
  265. getUserAvatar(userId) {
  266. return require('@/assets/images/avatars/' + userId + '-small.png')
  267. },
  268. defaultsImg() {
  269. return require('@/assets/images/banner/banner-' + (Math.floor(Math.random() * 38) + 1) + '.jpg')
  270. },
  271. },
  272. }
  273. </script>
  274. <style lang="scss">
  275. @import '~@resources/scss/vue/pages/page-blog.scss';
  276. </style>