reportDetail.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. <template>
  2. <view class="container" :class="{noscroll: buyShow}">
  3. <view class="pay-wall" v-show="loginShow">
  4. <view class="title">
  5. {{ report.title }}
  6. </view>
  7. </view>
  8. <u-parse :html="report.content"></u-parse>
  9. <view class="bottom-box">
  10. <view class="menu-box">
  11. <button class="menu-item" @click="changeApplaud">
  12. <i class="iconfont icon-dianzan" :class="report.hasApplaud?'active':''"></i>
  13. </button>
  14. <button class="menu-item" @click="changeFavi">
  15. <i class="iconfont icon-shoucang1" :class="report.hasFavi?'active':''"></i>
  16. </button>
  17. <button class="menu-item" open-type="share">
  18. <i class="iconfont icon-zhuanfa"></i>
  19. </button>
  20. <!-- <button class="menu-item">
  21. <i class="iconfont icon-pengyouquan"></i>
  22. </button> -->
  23. <!-- <button class="menu-item">
  24. <i class="iconfont icon-xiaoxi"></i>
  25. </button> -->
  26. </view>
  27. </view>
  28. <u-popup v-model="buyShow" :mask="false" :closeable='false' mode="bottom" :mask-close-able='false'
  29. safe-area-inset-bottom>
  30. <view style="height: 70vh;padding: 40rpx;position: relative;">
  31. <view style="text-align: center;color: #cccccc;margin: 50rpx 0;">正文需付费后才可阅读</view>
  32. <view style="text-align: center;">
  33. <u-button size="medium" type="error" @click="toBuy">¥{{ payForm.amount }} 阅读全部</u-button>
  34. </view>
  35. <view style="text-align: center;
  36. color: #ff0000;
  37. position: absolute;
  38. bottom: 20%;
  39. left: 50%;
  40. width: 80%;
  41. transform: translateX(-50%);" @click="toJoin">个人会员或单位会员免费,点击现在入会></view>
  42. </view>
  43. </u-popup>
  44. <u-popup v-model="loginShow" :mask="false" :closeable='false' mode="bottom" :mask-close-able='false'
  45. safe-area-inset-bottom>
  46. <view style="height: 70vh;padding: 40rpx;position: relative;">
  47. <!-- <view style="text-align: center;color: #cccccc;margin: 50rpx 0;">正文需付费后才可阅读</view> -->
  48. <view style="text-align: center;margin: 70rpx 0;">
  49. <u-button size="medium" type="error" @click="toLogin">登录阅读原文</u-button>
  50. </view>
  51. </view>
  52. </u-popup>
  53. <canvas style="position: absolute; top: -1000px; left: -1000px; width: 875px; height: 700px; background: #fff;"
  54. canvas-id="canvas"></canvas>
  55. </view>
  56. </template>
  57. <script setup>
  58. import {
  59. ref,
  60. computed,
  61. onMounted
  62. } from 'vue'
  63. import {
  64. onLoad,
  65. onShareAppMessage,
  66. onShareTimeline
  67. } from '@dcloudio/uni-app'
  68. import {
  69. getToken
  70. } from '@/utils/auth.js'
  71. import {
  72. getReportDetail,
  73. reportFavi,
  74. cancelReportFavi,
  75. reportApplaud,
  76. cancelReportApplaud,
  77. payReport
  78. } from '@/api/report.js'
  79. import {
  80. msgError,
  81. msgSuccess
  82. } from "@/utils/common.js"
  83. import {
  84. useAuthStore
  85. } from '@/store/authStore'
  86. const authStore = useAuthStore();
  87. const isMember = computed(() => {
  88. authStore.loadUserInfo()
  89. return authStore.userInfo.isMember == '0' ? false : true
  90. })
  91. const openid = computed(() => {
  92. authStore.loadOpenid()
  93. console.log(authStore.openid, 1111)
  94. return authStore.openid
  95. })
  96. const buyShow = ref(false)
  97. const loginShow = ref(true)
  98. const webview = ref();
  99. const id = ref()
  100. const title = ref()
  101. const hasPermission = ref(false);
  102. const imgurl = ref(null)
  103. const report = ref({
  104. id: '01',
  105. title: '2025年2月从化区二手住宅市场交易简报',
  106. summary: "2025年2月从化区二手住宅市场交易简报",
  107. price: '9.9',
  108. memberFree: 1,
  109. free: 0,
  110. status: 0,
  111. markdown: ``
  112. })
  113. const compileMarkDown = computed(() => {
  114. if (!report.value.markdown) {
  115. return;
  116. }
  117. let htmlString = "";
  118. // 判断markdown中代码块标识符的数量是否为偶数
  119. if (report.value.markdown.split("```").length % 2) {
  120. let content = report.value.markdown;
  121. if (content[content.length - 1] != "\n") {
  122. content += "\n";
  123. }
  124. htmlString = content;
  125. } else {
  126. htmlString = report.value.markdown;
  127. }
  128. return htmlString;
  129. })
  130. // 是否登录
  131. const isLogin = computed(() => {
  132. return false
  133. // return getToken() ? true : false
  134. })
  135. // 是否购买/免费
  136. const free = computed(() => {
  137. return false
  138. })
  139. const showMask = computed(() => {
  140. // 是否登录
  141. // 是否已购买或者免费
  142. if (report.value.status || report.value.free) {
  143. return false
  144. }
  145. // 判断用户是否为会员免费
  146. if (report.value.memberFree) {
  147. //
  148. }
  149. return false
  150. })
  151. const payForm = ref({
  152. "id": null,
  153. "title": "",
  154. "desc": "",
  155. "amount": null,
  156. "openid": ""
  157. })
  158. function parseLoaded() {
  159. setTimeout(() => {
  160. this.$refs.uReadMore1.init();
  161. }, 10);
  162. }
  163. function changeFavi() {
  164. console.log(report.value.hasFavi)
  165. if (report.value.hasFavi) {
  166. cancelReportFavi(id.value).then(res => {
  167. if (res?.code == 0) {
  168. report.value.hasFavi = false
  169. }
  170. })
  171. } else {
  172. reportFavi(id.value).then(res => {
  173. if (res?.code == 0) {
  174. report.value.hasFavi = true
  175. }
  176. })
  177. }
  178. }
  179. function changeApplaud() {
  180. console.log(report.value.hasApplaud)
  181. if (report.value.hasApplaud) {
  182. cancelReportApplaud(id.value).then(res => {
  183. if (res?.code == 0) {
  184. report.value.hasApplaud = false
  185. }
  186. })
  187. } else {
  188. reportApplaud(id.value).then(res => {
  189. if (res?.code == 0) {
  190. report.value.hasApplaud = true
  191. }
  192. })
  193. }
  194. }
  195. function toBuy() {
  196. // console.log("点击购买")
  197. // 修改一下,如果是会员,用会员价格,
  198. // 如果不是会员就用普通价格
  199. payForm.value.openid = openid.value
  200. payReport(payForm.value).then(res => {
  201. if (res && res.code === 0) {
  202. const params = res.data
  203. wx.requestPayment({
  204. nonceStr: params.nonceStr,
  205. package: params.package,
  206. paySign: params.paySign,
  207. signType: params.signType,
  208. timeStamp: params.timeStamp,
  209. success(res) {
  210. buyShow.value = false
  211. msgSuccess("支付成功")
  212. },
  213. fail(res) {
  214. buyShow.value = true
  215. msgError("支付失败")
  216. }
  217. })
  218. }
  219. })
  220. }
  221. function toLogin() {
  222. let url = {
  223. url: '/pages/reportDetail/reportDetail',
  224. id: id.value,
  225. title: title.value
  226. }
  227. // const decodedRedirect = decodeURIComponent(url);
  228. uni.setStorageSync("redirect", url)
  229. uni.navigateTo({
  230. url: `/pages/login/login`
  231. })
  232. }
  233. const toJoin = () => {
  234. uni.navigateTo({
  235. url: '/pages/joinClub/joinClub'
  236. })
  237. }
  238. function init(id) {
  239. // 测试图片
  240. getReportDetail(id).then(res => {
  241. if (res.code === 0) {
  242. report.value = res.data
  243. payForm.value.id = res.data.id
  244. payForm.value.title = res.data.title
  245. payForm.value.desc = res.data.title
  246. payForm.value.amount = isMember.value ? report.value.priceMember : report.value.price
  247. report.value.content = ""
  248. if (!report.value.hasBuy && res.data.viewMode === '3') {
  249. buyShow.value = true
  250. } else if (!report.value.hasBuy && !isMember.value && res.data.viewMode === '2') {
  251. buyShow.value = true
  252. }
  253. // console.log(report.value.hasBuy, res.data.viewMode, buyShow.value, 100)
  254. if (res.data.imgData) {
  255. const path = res.data.imgData.path
  256. const type = res.data.imgData.type
  257. const size = res.data.imgData.size
  258. for (let i = 1; i <= size; i++) {
  259. let image = `${path}/${i}.${type}`
  260. report.value.content = report.value.content + `<img src='${image}'></img>`
  261. }
  262. } else {
  263. report.value.content = ''
  264. }
  265. imgurl.value = report.value.cover
  266. }
  267. })
  268. }
  269. function cutShareImg(imgUrl) {
  270. return new Promise((resolve) => {
  271. wx.getImageInfo({
  272. src: imgUrl, // 原图路径
  273. success: (res) => {
  274. let ctx = wx.createCanvasContext("canvas")
  275. let canvasW = 0
  276. let canvasH = res.height
  277. // 把比例设置为 宽比高 5:4
  278. canvasW = (res.height * 5) / 4
  279. // 为画框设置背景色,注意要放在画图前,图会覆盖在背景色上
  280. ctx.fillStyle = "#fff"
  281. ctx.fillRect(0, 0, canvasW, canvasH)
  282. // ctx.drawImage(res.path, (res.width - canvasW) / 2, 0, canvasW, canvasH, 0, 0, canvasW, canvasH)
  283. ctx.drawImage(
  284. res.path,
  285. 0,
  286. 0,
  287. canvasW,
  288. canvasH,
  289. (canvasW - res.width) / 2, // 宽度从中间向两边填充
  290. 0,
  291. canvasW,
  292. canvasH
  293. )
  294. ctx.draw(false, () => {
  295. wx.canvasToTempFilePath({
  296. width: canvasW,
  297. height: canvasH,
  298. destWidth: 750, // 标准的iphone6尺寸的两倍,生成高清图
  299. destHeight: 600,
  300. canvasId: "canvas",
  301. fileType: "jpg", // 注意jpg默认背景为透明
  302. success: (res) => {
  303. // 设置分享图片路径
  304. resolve(res.tempFilePath)
  305. },
  306. })
  307. })
  308. }
  309. })
  310. })
  311. }
  312. onLoad((load) => {
  313. if (load.id) {
  314. id.value = load.id
  315. title.value = load.title
  316. // console.log(openid.value, 2222)
  317. if (openid.value) {
  318. init(id.value)
  319. loginShow.value = false
  320. } else {
  321. loginShow.value = true
  322. }
  323. // loginShow.value = true
  324. }
  325. uni.setNavigationBarTitle({
  326. title: title.value
  327. })
  328. })
  329. onMounted(() => {
  330. console.log(uni.createSelectorQuery().select("#webview"))
  331. })
  332. onShareAppMessage(async (res) => {
  333. // if (res.from === 'button') {
  334. // console.log('来自按钮分享');
  335. // }
  336. // console.log(imgurl.value)
  337. return {
  338. title: title.value,
  339. path: `/pages/reportDetail/reportDetail?id=${id.value}&title=${title.value}`,
  340. imageUrl: await cutShareImg(imgurl.value)
  341. };
  342. })
  343. onShareTimeline(async () => {
  344. // console.log(imgurl.value)
  345. return {
  346. title: title.value,
  347. query: `id=${id.value}&title=${title.value}`,
  348. imageUrl: await cutShareImg(imgurl.value)
  349. };
  350. })
  351. </script>
  352. <style>
  353. /* 新增样式 */
  354. .noscroll {
  355. height: 100vh;
  356. overflow: hidden;
  357. position: fixed;
  358. width: 100%;
  359. }
  360. /* 兼容H5和小程序 */
  361. /* #ifdef H5 */
  362. .noscroll {
  363. touch-action: none;
  364. }
  365. /* #endif */
  366. </style>
  367. <style lang="scss" scoped>
  368. .container {
  369. height: 100vh;
  370. width: 100vw;
  371. background-color: $uni-bg-color;
  372. .title {
  373. font-size: 38rpx;
  374. text-align: center;
  375. width: 60%;
  376. margin: 0 auto;
  377. padding: 20rpx 0;
  378. }
  379. .content {
  380. padding: 0 20rpx;
  381. }
  382. .mask {
  383. height: 75vh;
  384. padding: 0 20rpx;
  385. background-color: $uni-bg-color-grey;
  386. -webkit-box-shadow: 0px -1rpx 5rpx 0px rgba(50, 50, 50, 0.25);
  387. -moz-box-shadow: 0px -1rpx 5rpx 0px rgba(50, 50, 50, 0.25);
  388. box-shadow: 0px -1rpx 5rpx 0px rgba(50, 50, 50, 0.25);
  389. border-radius: 20rpx 20rpx 0 0;
  390. @include bottomMagnet();
  391. .mask-box {
  392. height: 100%;
  393. width: 100%;
  394. position: relative;
  395. .button {
  396. margin: 0 auto;
  397. width: 45%;
  398. }
  399. }
  400. .member-box {
  401. padding-top: 210rpx;
  402. .remark {
  403. height: 90rpx;
  404. text-align: center;
  405. letter-spacing: 3rpx;
  406. font-size: 32rpx;
  407. color: $uni-text-color-grey;
  408. }
  409. .link {
  410. position: absolute;
  411. top: 70%;
  412. width: 100%;
  413. font-size: 32rpx;
  414. color: $uni-color-error;
  415. font-size: $uni-title-font-size-2;
  416. font-weight: bold;
  417. .text {
  418. text-align: center;
  419. letter-spacing: 5rpx;
  420. &:active {
  421. text-decoration: underline;
  422. }
  423. }
  424. }
  425. }
  426. .login-box {
  427. padding-top: 300rpx;
  428. }
  429. }
  430. .disable-scroll {
  431. position: fixed;
  432. top: 0;
  433. left: 0;
  434. width: 100%;
  435. height: 100%;
  436. }
  437. .bottom-block {
  438. height: 110rpx;
  439. }
  440. .bottom-box {
  441. padding: 5rpx 25rpx;
  442. background-color: $uni-bg-color-grey;
  443. @include bottomMagnet();
  444. -webkit-box-shadow: 0px -1rpx 5rpx 0px rgba(50, 50, 50, 0.25);
  445. -moz-box-shadow: 0px -1rpx 5rpx 0px rgba(50, 50, 50, 0.25);
  446. box-shadow: 0px -1rpx 5rpx 0px rgba(50, 50, 50, 0.25);
  447. .menu-box {
  448. height: 100rpx;
  449. display: flex;
  450. align-items: center;
  451. justify-content: flex-end;
  452. gap: 50rpx;
  453. .menu-item {
  454. background-color: transparent;
  455. margin: 0;
  456. border: none;
  457. padding: 0;
  458. }
  459. .menu-item::after {
  460. border: none !important;
  461. }
  462. .iconfont {
  463. font-size: 42rpx;
  464. color: $uni-text-color-grey;
  465. }
  466. .active {
  467. color: yellow;
  468. }
  469. }
  470. }
  471. }
  472. </style>