article-douban.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <template>
  2. <view class="card" :class="[loading]">
  3. <view v-if="loading !== 'success'" class="card-error" @click="fnGetData()">
  4. {{ loadingText }}
  5. </view>
  6. <template v-else>
  7. <view class="tag">豆瓣</view>
  8. <view class="flex w-full">
  9. <view v-if="posterEmpty" class="poster round-2">无封面</view>
  10. <image v-else class="poster round-2" :src="poster" mode="aspectFill" @error="onPosterError"></image>
  11. <view class="box">
  12. <view class="title text-overflow">{{ detail.spec.name }}{{ detail.spec.name }}</view>
  13. <view class="flex" style="align-items: center; margin-top: 12rpx">
  14. <text class="text-size-s">评分:</text>
  15. <tm-rate v-model="detail.spec.score / 2" color="orange" size="24" :margin="2" :num="5"></tm-rate>
  16. <text class="text-size-s" style="margin-left: 4rpx">{{ detail.spec.score }}</text>
  17. </view>
  18. <view class="content text-overflow-2">{{ detail.spec.cardSubtitle }}</view>
  19. <view class="flex flex-wrap" style="margin-left: -10rpx">
  20. <tm-tags color="orange" :shadow="0" size="s" model="fill">{{ types[detail.spec.type] }}</tm-tags>
  21. <tm-tags v-for="(gen, genIndex) in detail.spec.genres" :key="genIndex" color="light-blue" :shadow="0" size="s" model="fill">{{ gen }}</tm-tags>
  22. </view>
  23. </view>
  24. </view>
  25. <!-- 扩展内容 -->
  26. <view class="btn-group">
  27. <tm-button theme="bg-gradient-orange-accent" icon="icon-copy" :shadow="0" :dense="true" size="m" @click="copy('post')">原文地址</tm-button>
  28. <tm-button theme="bg-gradient-light-blue-accent" icon="icon-copy" :shadow="0" :dense="true" size="m" @click="copy('douban')">豆瓣地址</tm-button>
  29. <tm-button theme="bg-gradient-light-blue-accent" icon="icon-copy" :shadow="0" :dense="true" size="m" @click="copy('info')">资源信息</tm-button>
  30. </view>
  31. </template>
  32. </view>
  33. </template>
  34. <script>
  35. import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
  36. import tmTags from '@/tm-vuetify/components/tm-tags/tm-tags.vue';
  37. import tmRate from '@/tm-vuetify/components/tm-rate/tm-rate.vue';
  38. export default {
  39. name: 'ArticleDouban',
  40. components: {
  41. tmButton,
  42. tmTags,
  43. tmRate
  44. },
  45. props: {
  46. url: {
  47. type: String,
  48. default: ''
  49. },
  50. index: {
  51. type: Number,
  52. default: 0
  53. },
  54. article: {
  55. type: Object,
  56. default: () => ({})
  57. }
  58. },
  59. data() {
  60. return {
  61. loading: 'loading',
  62. loadingText: '加载中,请稍等...',
  63. detail: null,
  64. types: {
  65. movie: '电影',
  66. book: '图书',
  67. music: '音乐',
  68. game: '游戏',
  69. drama: '舞台剧'
  70. },
  71. poster: '',
  72. posterEmpty: false
  73. };
  74. },
  75. created() {
  76. this.fnGetData();
  77. },
  78. methods: {
  79. onPosterError() {
  80. if (!this.article.spec.cover) {
  81. this.poster = '';
  82. this.posterEmpty = true;
  83. } else {
  84. this.poster = this.$utils.checkImageUrl(this.article.spec.cover);
  85. this.posterEmpty = false;
  86. }
  87. },
  88. fnGetData() {
  89. this.loadingText = '加载中,请稍等...';
  90. this.loading = 'loading';
  91. this.$httpApi.v2
  92. .getDoubanDetail(this.url)
  93. .then((res) => {
  94. this.detail = res;
  95. this.poster = res.spec.poster;
  96. setTimeout(() => {
  97. this.loading = 'success';
  98. }, 200);
  99. })
  100. .catch((err) => {
  101. console.error(err);
  102. this.loading = 'error';
  103. this.loadingText = '豆瓣内容加载失败,点击重试';
  104. });
  105. },
  106. showToast(content) {
  107. uni.showToast({
  108. icon: 'none',
  109. title: content,
  110. mask: true
  111. });
  112. },
  113. copy(type) {
  114. if (type === 'post') {
  115. const articleUrl = this.$baseApiUrl + (this.article?.status?.permalink ?? '');
  116. this.$utils.copyText(articleUrl, '文章原文地址复制成功');
  117. return;
  118. }
  119. if (type === 'douban') {
  120. this.$utils.copyText(this.detail?.spec.link, '豆瓣资源地址复制成功');
  121. return;
  122. }
  123. if (type === 'info') {
  124. const content = `名称:${this.detail?.spec.name}丨其他:${this.detail?.spec.cardSubtitle}丨标签:${this.detail?.spec.genres.join('/')}丨时间:${
  125. this.detail?.spec.pubdate
  126. }丨评分:${this.detail?.spec.score}分丨链接:${this.detail?.spec.link}`;
  127. this.$utils.copyText(content, '资源信息复制成功');
  128. }
  129. }
  130. }
  131. };
  132. </script>
  133. <style lang="scss" scoped>
  134. .w-full {
  135. width: 100%;
  136. }
  137. .wp-50 {
  138. width: 50%;
  139. }
  140. .card {
  141. position: relative;
  142. display: flex;
  143. flex-direction: column;
  144. box-sizing: border-box;
  145. padding: 24rpx;
  146. border-radius: 12rpx;
  147. background-color: #ffff;
  148. overflow: hidden;
  149. margin-bottom: 12rpx;
  150. border: 1px solid #eee;
  151. &.error {
  152. padding: 0;
  153. border-style: dashed;
  154. border-color: #e88080;
  155. color: #e88080;
  156. background-color: rgba(232, 128, 128, 0.075);
  157. }
  158. &.loading {
  159. padding: 0;
  160. border-style: dashed;
  161. border-color: rgba(3, 174, 252, 1);
  162. color: rgba(3, 174, 252, 1);
  163. background-color: rgba(3, 174, 252, 0.075);
  164. }
  165. }
  166. .card-error {
  167. box-sizing: border-box;
  168. padding: 50rpx 24rpx;
  169. font-size: 24rpx;
  170. border-radius: 12rpx;
  171. text-align: center;
  172. }
  173. .poster {
  174. box-sizing: border-box;
  175. width: 180rpx;
  176. height: 220rpx;
  177. flex-shrink: 0;
  178. background-color: #eee;
  179. display: flex;
  180. align-items: center;
  181. justify-content: center;
  182. font-size: 24rpx;
  183. }
  184. .box {
  185. flex-grow: 1;
  186. box-sizing: border-box;
  187. font-size: 26rpx;
  188. padding-left: 24rpx;
  189. overflow: hidden;
  190. }
  191. .title {
  192. box-sizing: border-box;
  193. font-size: 32rpx;
  194. font-weight: bold;
  195. }
  196. .content {
  197. box-sizing: border-box;
  198. margin-top: 12rpx;
  199. line-height: 36rpx;
  200. color: rgba(0, 0, 0, 0.85);
  201. }
  202. .tag {
  203. box-sizing: border-box;
  204. position: absolute;
  205. right: 0;
  206. top: 0;
  207. font-size: 24rpx;
  208. padding: 2rpx 12rpx;
  209. background-color: #f5c618;
  210. border-radius: 0 6rpx 0 12rpx;
  211. }
  212. .btn-group {
  213. box-sizing: border-box;
  214. display: flex;
  215. align-items: center;
  216. justify-content: space-between;
  217. margin-top: 22rpx;
  218. gap: 0 22rpx;
  219. }
  220. </style>