richdetail.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. <template>
  2. <view class="">
  3. <!-- 顶部导航 -->
  4. <fa-navbar title="详情"></fa-navbar>
  5. <!-- 内容 -->
  6. <view class="" v-if="isRender">
  7. <view class="u-p-30 u-bg-white">
  8. <view class="u-font-40"><text v-text="archivesInfo.title"></text></view>
  9. <view class="u-m-t-20 u-font-22 u-tips-color"><text v-text="archivesInfo.create_date"></text></view>
  10. <!-- -->
  11. <view class="u-flex u-row-between u-m-t-20 u-font-24 detail-tag">
  12. <view class="u-flex">
  13. <view class="u-flex u-col-center u-m-r-30" v-if="archivesInfo.user" @click="toUser(archivesInfo.user_id)">
  14. <u-avatar size="40" :src="archivesInfo.user.avatar"></u-avatar>
  15. <view class="u-font-22 u-m-l-10 u-line-1" style="max-width: 70px;">{{ archivesInfo.user.nickname }}</view>
  16. </view>
  17. <view class="">
  18. <u-icon name="thumb-up-fill" color="#aaa" size="20"></u-icon>
  19. <text class="u-m-l-5 u-m-r-5" v-text="archivesInfo.likes"></text>
  20. 点赞
  21. </view>
  22. <!-- <view class="u-m-l-30">
  23. <u-icon name="chat-fill" color="#aaa" size="20"></u-icon>
  24. <text class="u-m-l-5 u-m-r-5" v-text="archivesInfo.comments"></text>
  25. 评论
  26. </view> -->
  27. <view class="u-m-l-30">
  28. <u-icon name="eye-fill" color="#aaa" size="20"></u-icon>
  29. <text class="u-m-l-5 u-m-r-5" v-text="archivesInfo.views"></text>
  30. 浏览
  31. </view>
  32. </view>
  33. <view class="">
  34. <!-- #ifdef MP-WEIXIN -->
  35. <button class="share-btn" open-type="share">
  36. <u-icon name="share-fill"></u-icon>
  37. <text class="u-p-l-5">分享</text>
  38. </button>
  39. <!-- #endif -->
  40. <!-- #ifdef H5 -->
  41. <button class="share-btn" @click="copyUrl">
  42. <u-icon name="share-fill"></u-icon>
  43. <text class="u-p-l-5">分享</text>
  44. </button>
  45. <!-- #endif -->
  46. <!-- #ifdef APP-PLUS -->
  47. <button class="share-btn" @click="openShare">
  48. <u-icon name="share-fill"></u-icon>
  49. <text class="u-p-l-5">分享</text>
  50. </button>
  51. <!-- #endif -->
  52. </view>
  53. </view>
  54. </view>
  55. <view class="u-flex u-flex-wrap u-p-l-30 u-p-r-30 u-p-t-30" v-if="isShow">
  56. <view class="product-images" v-for="(item, index) in imagesList" :key="index">
  57. <u-image width="100%" height="220" :src="item" @click="lookImage(index)"></u-image>
  58. </view>
  59. </view>
  60. <u-gap height="10" bg-color="#f4f6f8"></u-gap>
  61. <view class="u-p-30 u-bg-white u-line-height">
  62. <u-parse
  63. :html="archivesInfo.content"
  64. :tag-style="vuex_parse_style"
  65. :domain="vuex_config.config ? vuex_config.config.upload.cdnurl : ''"
  66. @linkpress="navigate"
  67. ></u-parse>
  68. </view>
  69. <view class="u-p-30 u-bg-white">
  70. <view class="u-flex u-flex-wrap">
  71. <view class="u-m-r-10 u-m-b-15" v-for="(item, index) in archivesInfo.taglist" :key="index">
  72. <u-tag :text="item.name" shape="circle" type="info" mode="light" @click="goTag(item.name)" />
  73. </view>
  74. </view>
  75. <view class="u-flex u-row-right u-m-t-5">
  76. <view class="">
  77. <u-button
  78. type="primary"
  79. hover-class="none"
  80. :custom-style="{ backgroundColor: theme.bgColor, color: theme.color }"
  81. size="mini"
  82. shape="circle"
  83. @click="collection(id,'archives')"
  84. >
  85. <u-icon name="heart-fill"></u-icon>
  86. <text class="u-p-l-5" v-text="`收藏`"></text>
  87. </u-button>
  88. </view>
  89. <view class="u-m-l-15">
  90. <u-button
  91. type="primary"
  92. hover-class="none"
  93. :custom-style="{ backgroundColor: theme.bgColor, color: theme.color }"
  94. size="mini"
  95. shape="circle"
  96. @click="likes"
  97. >
  98. <u-icon name="thumb-up"></u-icon>
  99. <text class="u-p-l-5" v-text="`点赞(${archivesInfo.likes || 0})`"></text>
  100. </u-button>
  101. </view>
  102. </view>
  103. </view>
  104. <!-- 下载 -->
  105. <view class="u-flex u-border-top u-p-30 u-bg-white" v-if="archivesInfo.model_id == 3 && (archivesInfo.ispaid || archivesInfo.price == 0)">
  106. <view class="u-m-l-15" v-for="(item, index) in downloadurl" :key="index">
  107. <u-button
  108. hover-class="none"
  109. type="primary"
  110. :custom-style="{ backgroundColor: theme.bgColor, color: theme.color }"
  111. size="mini"
  112. shape="circle"
  113. @click="download(item)"
  114. >
  115. <text class="u-p-r-5" v-text="item.name == 'local' ? '本地下载' : item.name == 'baidu' ? '百度下载' : '其他下载'"></text>
  116. </u-button>
  117. </view>
  118. </view>
  119. <view class="u-p-30" v-if="downtips">
  120. <u-alert-tips
  121. type="warning"
  122. title="下载成功,保存路径为:"
  123. :close-able="true"
  124. :show="downtips"
  125. :description="description"
  126. @close="downtips = false"
  127. ></u-alert-tips>
  128. </view>
  129. <view class="u-border-top u-bg-white u-p-30 u-flex u-row-center" v-if="archivesInfo.price > 0 && !archivesInfo.ispaid">
  130. <u-button
  131. hover-class="none"
  132. type="primary"
  133. size="medium"
  134. :custom-style="{ backgroundColor: theme.bgColor, color: theme.color, width: '60vw' }"
  135. v-if="!vuex_token"
  136. @click="goLogin"
  137. >
  138. 请登录再进行付费
  139. </u-button>
  140. <u-button
  141. hover-class="none"
  142. type="primary"
  143. size="medium"
  144. :custom-style="{ backgroundColor: theme.bgColor, color: theme.color, width: '60vw' }"
  145. v-else
  146. @click="goPay"
  147. >
  148. 立即付费阅读
  149. </u-button>
  150. </view>
  151. <!-- <u-gap height="20" bg-color="#f4f6f8"></u-gap>
  152. <view class="u-bg-white u-p-30">
  153. <view class="u-p-b-10 u-tips-color">发表评论</view>
  154. <view class=""><u-input v-model="content" type="textarea" placeholder="请输入评论内容" :border="false" /></view>
  155. <view class="u-flex u-row-center">
  156. <u-button
  157. hover-class="none"
  158. type="primary"
  159. size="medium"
  160. :custom-style="{ backgroundColor: theme.bgColor, color: theme.color, width: '60vw' }"
  161. v-if="!vuex_token"
  162. @click="goLogin"
  163. >
  164. 立即登录
  165. </u-button>
  166. <u-button
  167. hover-class="none"
  168. type="primary"
  169. size="medium"
  170. :custom-style="{ backgroundColor: theme.bgColor, color: theme.color, width: '60vw' }"
  171. v-else
  172. @click="submit"
  173. >
  174. 立即评论
  175. </u-button>
  176. </view>
  177. </view> -->
  178. <!-- <u-gap height="20" bg-color="#f4f6f8"></u-gap>
  179. <view class="u-p-30 u-bg-white">
  180. <view class="u-p-b-10 u-tips-color">评论列表</view>
  181. <view class="comment" v-for="(item, index) in commentList" :key="item.id">
  182. <view class="left" @click="toUser(item.user_id)"><image :src="item.user && item.user.avatar" mode="aspectFill"></image></view>
  183. <view class="right">
  184. <view class="top">
  185. <view class="u-light-color">
  186. <u-icon name="account-fill" color="#c0c4cc"></u-icon>
  187. <text class="u-p-l-10 name u-line-1">{{ item.user && item.user.nickname }}</text>
  188. <text class="u-m-l-30">{{ item.create_date }}</text>
  189. </view>
  190. <view class="replay" @click="replay(item)">
  191. <u-icon name="chat" :size="30"></u-icon>
  192. <view class="opeate">回复</view>
  193. </view>
  194. </view>
  195. <view class="content"><rich-text :nodes="item.content"></rich-text></view>
  196. </view>
  197. </view>
  198. <view class="" v-if="!commentList.length"><u-empty text="暂无评论"></u-empty></view>
  199. </view> -->
  200. <!-- 支付 -->
  201. <fa-payment
  202. ref="faPayment"
  203. :article-id="id"
  204. :article-title="archivesInfo.title"
  205. :money="archivesInfo.price"
  206. :vip="(archivesInfo.channel && archivesInfo.channel.vip) || 0"
  207. @success="paySuccess"
  208. ></fa-payment>
  209. <!-- #ifdef APP-PLUS -->
  210. <view class="">
  211. <fa-app-share
  212. ref="faShare"
  213. :title="archivesInfo.title"
  214. :summary="archivesInfo.title"
  215. :imageUrl="archivesInfo.image"
  216. :href="archivesInfo.fullurl"
  217. ></fa-app-share>
  218. </view>
  219. <!-- #endif -->
  220. </view>
  221. <!-- 其他下载 -->
  222. <u-modal v-model="dowshow">
  223. <view class="u-p-30 u-flex u-row-center u-col-center">
  224. <u-link :href="downurl" font-size="35">点我下载</u-link>
  225. <text class="u-m-l-20 u-tips-color" v-if="baucode" v-text="'复制提取码:' + baucode" @click="copydown"></text>
  226. </view>
  227. </u-modal>
  228. <!-- 回到顶部 -->
  229. <u-back-top :scroll-top="scrollTop" :icon-style="{ color: theme.bgColor }" :custom-style="{ backgroundColor: lightColor }"></u-back-top>
  230. <!-- 底部导航 -->
  231. <fa-tabbar></fa-tabbar>
  232. </view>
  233. </template>
  234. <script>
  235. import { tools, vote } from '@/common/fa.mixin.js';
  236. // #ifdef H5
  237. import { weixinShare } from '@/common/fa.weixin.mixin.js';
  238. // #endif
  239. export default {
  240. mixins: [
  241. tools,
  242. vote,
  243. // #ifdef H5
  244. weixinShare
  245. // #endif
  246. ],
  247. onLoad(e) {
  248. let query = this.$Route.query || e || {};
  249. this.id = query.id || 0;
  250. this.diyname = query.diyname || '';
  251. this.getArchivesDetail();
  252. },
  253. onShow() {
  254. // #ifdef MP-BAIDU
  255. if(this.archivesInfo.id){
  256. this.setPagesInfo();
  257. }
  258. // #endif
  259. },
  260. computed: {
  261. isShow() {
  262. return this.archivesInfo.images != '';
  263. },
  264. isPay() {
  265. return parseInt(this.archivesInfo.price) > 0;
  266. }
  267. },
  268. watch: {
  269. content(newValue, oldValue) {
  270. if (!newValue) {
  271. this.pid = 0;
  272. }
  273. }
  274. },
  275. data() {
  276. return {
  277. id: 0,
  278. archivesInfo: {},
  279. channelInfo: {},
  280. commentList: [],
  281. imagesList: [],
  282. downloadurl: {},
  283. content: '',
  284. isRender: false,
  285. dowshow: false,
  286. downtips: false,
  287. pid: 0,
  288. description: '',
  289. downkey: '',
  290. downurl: '',
  291. baucode: '',
  292. diyname: '',
  293. scrollTop: 0,
  294. page: 1,
  295. has_more: true
  296. };
  297. },
  298. methods: {
  299. getArchivesDetail: async function() {
  300. let res = await this.$api.getArchivesDetail({ id: this.id, diyname: this.diyname });
  301. if (!res.code) {
  302. return;
  303. }
  304. this.archivesInfo = res.data.archivesInfo || {};
  305. this.channelInfo = res.data.channelInfo || [];
  306. this.commentList = res.data.commentList || [];
  307. this.downloadurl = res.data.archivesInfo.downloadurl || {};
  308. this.imagesList = res.data.archivesInfo.images.split(',');
  309. this.$u.mpShare.title = res.data.archivesInfo.title;
  310. this.isRender = true;
  311. this.$u.vuex('vuex__token__', res.data.__token__);
  312. uni.setNavigationBarTitle({
  313. title: this.archivesInfo.title
  314. });
  315. // #ifdef MP-BAIDU
  316. this.setPagesInfo();
  317. // #endif
  318. // #ifdef H5
  319. if (this.$util.isWeiXinBrowser()) {
  320. this.wxShare({
  321. title: this.archivesInfo.title,
  322. desc: this.archivesInfo.description,
  323. link: window.location.href,
  324. img: this.archivesInfo.image
  325. });
  326. }
  327. // #endif
  328. },
  329. // #ifdef MP-BAIDU
  330. setPagesInfo(){
  331. let sitename = (this.vuex_config && this.vuex_config.config && this.vuex_config.config.sitename) || '';
  332. swan.setPageInfo({
  333. title: this.archivesInfo.title+'-'+sitename,
  334. articleTitle: this.archivesInfo.title+'-'+sitename,
  335. keywords: this.archivesInfo.keywords,
  336. description: this.archivesInfo.description,
  337. releaseDate: this.$u.timeFormat(this.archivesInfo.publishtime, 'yyyy-mm-dd hh:MM:ss'),
  338. image: this.archivesInfo.images,
  339. likes: this.archivesInfo.likes,
  340. comments: this.archivesInfo.comments,
  341. collects: this.archivesInfo.views,
  342. success: res => {
  343. console.log('setPageInfo success', res);
  344. },
  345. fail: err => {
  346. console.log('setPageInfo fail', err);
  347. }
  348. });
  349. },
  350. // #endif
  351. goCommentIndex() {
  352. this.$api.goCommentIndex({ page: this.page, aid: this.archivesInfo.id }).then(res => {
  353. if (res.code == 1) {
  354. this.has_more = res.data.commentList.length > 0;
  355. this.commentList = [...this.commentList, ...res.data.commentList];
  356. }
  357. });
  358. },
  359. //回复
  360. replay(item) {
  361. if (!item.user) {
  362. this.$u.toast('用户不存在');
  363. return;
  364. }
  365. this.content = `@${item.user.nickname} `;
  366. this.pid = item.id;
  367. },
  368. //评论
  369. submit: async function() {
  370. if (!this.content) {
  371. this.$u.toast('请输入评论内容!');
  372. return;
  373. }
  374. let res = await this.$api.goCommentPost({
  375. content: this.content,
  376. aid: this.id,
  377. pid: this.pid //回复的用户上一条ID
  378. });
  379. this.$u.toast(res.msg);
  380. if (!res.code) {
  381. return;
  382. }
  383. this.content = '';
  384. if (res.data && res.data.comment) {
  385. this.commentList = [res.data.comment, ...this.commentList];
  386. }
  387. },
  388. //登录
  389. goLogin() {
  390. this.$Router.push('/pages/login/mobilelogin');
  391. },
  392. toUser(user_id) {
  393. this.$Router.push('/pages/user/user?user_id=' + user_id);
  394. },
  395. //支付
  396. goPay() {
  397. this.$refs.faPayment.show();
  398. },
  399. paySuccess() {
  400. this.getArchivesDetail();
  401. },
  402. //下载
  403. download(item) {
  404. let that = this;
  405. switch (item.name) {
  406. case 'local':
  407. // #ifndef H5
  408. uni.downloadFile({
  409. url: item.url,
  410. success: res => {
  411. if (res.statusCode === 200) {
  412. uni.saveFile({
  413. tempFilePath: res.tempFilePath,
  414. success: function(res) {
  415. that.downtips = true;
  416. that.description = res.savedFilePath;
  417. },
  418. fail(err) {
  419. console.log(err);
  420. }
  421. });
  422. }
  423. }
  424. });
  425. // #endif
  426. // #ifdef H5
  427. window.open(item.url);
  428. // #endif
  429. break;
  430. case 'baidu':
  431. // #ifdef APP-PLUS || H5
  432. if (item.password) {
  433. this.dowshow = true;
  434. this.downurl = item.url;
  435. this.baucode = item.password;
  436. } else {
  437. window.open(item.url);
  438. }
  439. // #endif
  440. // #ifdef MP
  441. this.dowshow = true;
  442. this.downurl = item.url;
  443. this.baucode = item.password;
  444. // #endif
  445. break;
  446. }
  447. },
  448. copydown() {
  449. this.$util.uniCopy({
  450. content: this.baucode,
  451. success: () => {
  452. this.$u.toast('提取码复制成功!');
  453. }
  454. });
  455. },
  456. goTag(name) {
  457. this.$Router.push({
  458. path: '/pages/tag/tag',
  459. query: { name: name }
  460. });
  461. },
  462. // #ifdef APP-PLUS
  463. openShare() {
  464. this.$refs.faShare.show();
  465. }
  466. // #endif
  467. },
  468. onPageScroll(e) {
  469. this.scrollTop = e.scrollTop;
  470. },
  471. onReachBottom() {
  472. if (this.has_more) {
  473. this.page += 1;
  474. this.goCommentIndex();
  475. }
  476. }
  477. };
  478. </script>
  479. <style lang="scss">
  480. page {
  481. background-color: #f4f6f8;
  482. }
  483. .detail-tag {
  484. color: #aaa;
  485. }
  486. .comment {
  487. background-color: #ffffff;
  488. display: flex;
  489. padding: 30rpx;
  490. .left {
  491. image {
  492. width: 64rpx;
  493. height: 64rpx;
  494. border-radius: 50%;
  495. background-color: #f2f2f2;
  496. }
  497. }
  498. .right {
  499. flex: 1;
  500. padding-left: 20rpx;
  501. .top {
  502. display: flex;
  503. justify-content: space-between;
  504. align-items: center;
  505. margin-bottom: 10rpx;
  506. .replay {
  507. display: flex;
  508. align-items: center;
  509. color: #9a9a9a;
  510. font-size: 26rpx;
  511. .opeate {
  512. margin-right: 4rpx;
  513. color: #9a9a9a;
  514. }
  515. }
  516. .name {
  517. max-width: 100rpx;
  518. }
  519. }
  520. .content {
  521. margin-bottom: 10rpx;
  522. word-break: break-word;
  523. }
  524. }
  525. }
  526. .comment:not(:last-child) {
  527. border-bottom: 1px solid #eee;
  528. }
  529. .product-images {
  530. width: 50%;
  531. margin-bottom: 30rpx;
  532. }
  533. .product-images:nth-child(2n) {
  534. padding-left: 15rpx;
  535. }
  536. .product-images:nth-child(2n + 1) {
  537. padding-right: 15rpx;
  538. }
  539. .u-alert-desc {
  540. word-break: break-word;
  541. }
  542. </style>