123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767 |
- <script setup>
- import apiReport from '@/api/modules/report'
- import { useRoute } from 'vue-router'
- import { Message, Toast } from 'tdesign-mobile-vue';
- import apiUser from '@/api/modules/user'
- import { useThrottleFn } from '@vueuse/core'
- const route = useRoute()
- // 获取用户信息
- let userInfo = null
- async function getUserInfo() {
- const res = await apiUser.userInfo()
- if (res.Ret === 200 && res.ErrCode === 0) {
- userInfo = res.data
- }
- }
- getUserInfo()
- const defaultImg = new URL(`@/assets/imgs/default-author.png`, import.meta.url).href
- const reportId = route.query.reportid
- const reportInfo = ref(null)
- const reportContent = ref('')
- const isFollowed = ref(false)
- const authorInfoList=ref([])
- const isLogin=ref(true)
- const productId = route.query.productId
- const isSubscribe=ref(true)
- const isFree=ref(true)
- const priceNum=ref('')
- const visible = ref(false);
- const subscribeStatus = ref('')//expired --过期 unSubscribe--未订阅 subscribed--订阅中
- const riskLevelStatus=ref('')//expired过期的 unTest未测评 unMatch风险等级不匹配
- const headImgStyle = ref([])
- const endImgStyle = ref([])
- const layoutBaseInfo = ref({
- '研报标题': '',
- '研报作者': '',
- '创建时间': ''
- })
- // 报告内容分页
- const pageSize = 20
- let page = 0
- let endPageNum = 0
- let contentTotals = []
- const renderContentList = ref([])
- function splitReportContent(data) {
- const arr = data.split('</p>');
- contentTotals = arr.map(_ => _ + '</p>')
- renderContentList.value = contentTotals.slice(0, pageSize)
- endPageNum = parseInt(contentTotals.length / pageSize) + 1;
- }
- function handleLoadContent() {
- renderContentList.value = renderContentList.value.concat(contentTotals.slice(page * pageSize, (page + 1) * pageSize))
- }
- async function getReportInfo() {
- //获取研报详情
- if (!reportId || !productId) return
- const res = await apiReport.getReportDetail({
- reportId: reportId,
- productId: productId
- })
- if (res.Ret === 200 && res.ErrCode === 0) {
- const { detail, authorInfo, price } = res.data
- authorInfoList.value=authorInfo
- reportInfo.value = detail
- isLogin.value=res.data.login
- riskLevelStatus.value=res.data.riskLevelStatus
- headImgStyle.value = reportInfo.value.headResource.style ? JSON.parse(reportInfo.value.headResource.style) : []
- endImgStyle.value = reportInfo.value.endResource.style ? JSON.parse(reportInfo.value.endResource.style) : []
- layoutBaseInfo.value['研报标题'] = reportInfo.value.title
- layoutBaseInfo.value['研报作者'] = reportInfo.value.author
- layoutBaseInfo.value['创建时间'] = reportInfo.value.publishTime
- isSubscribe.value=res.data.isSubscribe
- isFree.value=res.data.isFree
- priceNum.value=price
- subscribeStatus.value=res.data.subscribeStatus
- getAuthorFollowState()
- nextTick(() => {
- handlePreviewImgs()
- })
- // 设置分享文案
- wx.miniProgram.postMessage({
- data: {
- title: reportInfo.value.title
- }
- });
- reportContent.value = reportInfo.value.content
- splitReportContent(reportContent.value)
- }
- }
- getReportInfo()
- function getAuthorFollowState() {
- apiUser.getFollowState({
- names: reportInfo.value.author
- }).then(res => {
- if (res.Ret === 200 && res.ErrCode === 0) {
- isFollowed.value = res.data.followStatus === 'following'
- }
- })
- }
- function changeFollowState() {
- if (authorInfoList.value.length > 1) {
- visible.value = true
- } else {
- apiUser.followAuthor({
- analystNames: reportInfo.value.author,
- followType: isFollowed.value ? 'unfollowed' : 'following',
- mobile: userInfo?.mobile || ''
- }).then(res => {
- if (res.Ret === 200 && res.ErrCode === 0) {
- isFollowed.value = !isFollowed.value
- Toast({
- theme: 'success',
- direction: 'row',
- message: isFollowed.value ? '关注成功' : '取消关注成功',
- })
- }
- })
- }
- }
- function onClose() {
- visible.value = false
- }
- // 关注列表
- function changeFollowStateList(item) {
- console.log(item);
- apiUser.followAuthor({
- analystNames: item.name,
- followType: item.following === 'unfollowed' ? 'following' : 'unfollowed',
- mobile: userInfo?.mobile || ''
- }).then(res => {
- if (res.Ret === 200 && res.ErrCode === 0) {
- item.following = item.following === 'unfollowed' ? 'following' : 'unfollowed'
- getAuthorFollowState()
- Toast({
- theme: 'success',
- direction: 'row',
- message: item.following === 'unfollowed' ? '取消关注成功' : '关注成功',
- })
- }
- })
- }
- // 显示免责声明
- const isShowMZSM = ref(false)
- // 显示返回顶部
- const showToTop = ref(false)
- const handlePageScroll = useThrottleFn(() => {
- const top = document.documentElement.scrollTop || document.body.scrollTop
- if (top > window.outerHeight) {
- showToTop.value = true
- } else {
- showToTop.value = false
- }
- if (page >= endPageNum) return
- const clientHeight = document.documentElement.clientHeight || document.body.clientHeight; // 可视高度
- const scrollHeight = document.body.scrollHeight; // 总高度
- const bufferHeight = 400;
- if ((scrollHeight - top - clientHeight) < bufferHeight + 100) {
- console.log('触底')
- page++
- handleLoadContent();
- }
- }, 300)
- function handleBackTop() {
- document.body.scrollTop = document.documentElement.scrollTop = 0
- }
- // 点击报告内容中的图片
- function handlePreviewImgs() {
- document.getElementById('rich-content').addEventListener('click', function (event) {
- let imgArray = [];
- let curImageSrc = event.target.src;
- let oParent = event.target.parentNode;
- if (curImageSrc && !oParent.hasAttribute('href')) {
- let imgs = document.querySelectorAll('.rich-content img');
- for (let i = 0; i < imgs.length; i++) {
- let itemSrc = imgs[i].src;
- imgArray.push(itemSrc);
- }
- wx.previewImage({ current: curImageSrc, urls: imgArray });
- }
- });
- }
- onMounted(() => {
- window.addEventListener('scroll', handlePageScroll)
- })
- onUnmounted(() => {
- window.removeEventListener('scroll', handlePageScroll)
- })
- function handleGoLogin() {
- const redirectUrl = encodeURIComponent(`/pages-report/reportDetail/index?id=${route.query.reportid}`)
- wx.miniProgram.reLaunch({
- url: `/pages/login/index?redirectUrl=${redirectUrl}`
- })
- }
- //跳转风险测评
- function handleGoTestRisk(){
- wx.miniProgram.reLaunch({
- url: `/pages/user/riskLevelPage`
- })
- }
- //跳转购买
- function goPrimary(){
- wx.miniProgram.reLaunch({
- url: `/pages-order/payPage/index?id=${productId}`
- })
- }
- // 跳转研究员详情页
- function goDetails(item){
- wx.miniProgram.reLaunch({
- url:'/pages-user/authordetail/index?id='+item.id
- })
- }
- </script>
- <template>
- <div :class="!isLogin||['expired','unTest','unMatch'].includes(riskLevelStatus) || (!isSubscribe && !isFree)? 'no-auth-box report-detail-page' : 'report-detail-page'" v-if="reportInfo">
- <!-- 智能研报有版头版尾 -->
- <div class="html-head-img-box" v-if="reportInfo.headResource.imgUrl">
- <img
- :src="reportInfo.headResource.imgUrl"
- alt=""
- style="display: block; width: 100%"
- />
- <div
- class="head-layout-item"
- v-for="item in headImgStyle"
- :key="item.value"
- :style="{
- fontFamily: item.family,
- fontSize: item.size,
- fontWeight: item.weight,
- textAlign: item.align,
- color: item.color,
- width: item.width,
- height: item.height,
- left: item.left,
- top: item.top,
- }"
- >
- {{ layoutBaseInfo[item.value] }}
- </div>
- </div>
- <div
- class="time-box"
- style="text-align: right"
- v-if="reportInfo.headResource.imgUrl"
- >
- <span>如有内容疑问 请查看 </span>
- <span class="btn" @click="isShowMZSM = true">免责声明</span>
- </div>
- <template
- v-if="!reportInfo.headResource.imgUrl && !reportInfo.endResource.imgUrl"
- >
- <div class="title-box">{{ reportInfo.title }}</div>
- <div class="author-box">
- <div class="img-box">
- <img
- :src="authorInfoList?.[0].headImgUrl|| defaultImg"
- />
- </div>
- <div class="author-info">
- <span class="name">
- <template v-for="(item, index) in authorInfoList" :key="index">
- {{ item.name }} {{ index === authorInfoList.length - 1 ? "" : "、" }}
- </template>
- </span>
- <span class="time">{{ reportInfo.publishTime }} {{reportInfo.riskLevel}}</span>
- </div>
- <div
- @click="changeFollowState"
- :class="['opt-btn', isFollowed ? 'followed' : '']"
- v-if="isLogin"
- >
- {{ isFollowed ? "取消关注" : "关注" }}
- </div>
- </div>
- <div class="time-box">
- <span class="btn" @click="isShowMZSM = true">免责声明</span>
- </div>
- </template>
- <div class="des-box" v-if="reportInfo.abstract">
- <svg-icon name="icon01"></svg-icon>
- <div>{{ reportInfo.abstract }}</div>
- </div>
- <div
- id="rich-content"
- class="report-content-box rich-content"
- v-html="reportContent"
- v-if="false"
- />
- <template v-else>
- <div
- id="rich-content"
- class="report-content-box rich-content"
- v-if="!reportInfo.hasChapter"
- >
- <div v-for="item in renderContentList" :key="item" v-html="item"></div>
- </div>
- <!-- 章节报告 -->
- <div
- id="rich-content"
- class="report-content-box rich-content"
- v-if="reportInfo.hasChapter"
- >
- <div
- class="chapter-item-wrap"
- v-for="(chapter, index) in reportInfo.chapters"
- :key="index"
- >
- <div class="chapter-title">
- <h3 class="chapter-title-text">{{ chapter.title }}</h3>
- </div>
- <div v-html="chapter.content"></div>
- </div>
- </div>
- </template>
- <!-- 拼接版尾 -->
- <div class="html-end-img-box" v-if="reportInfo.endResource.imgUrl">
- <img
- :src="reportInfo.endResource.imgUrl"
- alt=""
- style="display: block; width: 100%"
- />
- <div
- class="head-layout-item"
- v-for="item in endImgStyle"
- :key="item.value"
- :style="{
- fontFamily: item.family,
- fontSize: item.size * 2 + 'px',
- fontWeight: item.weight,
- textAlign: item.align,
- color: item.color,
- width: item.width,
- height: item.height,
- left: item.left,
- top: item.top,
- }"
- >
- {{ layoutBaseInfo[item.value] }}
- </div>
- </div>
- <!-- 右侧悬浮操作栏 -->
- <div class="right-fix-box">
- <!-- 返回顶部 -->
- <div class="item back-top-img">
- <svg-icon
- name="backtop"
- v-show="showToTop"
- @click="handleBackTop"
- class="back-top-img"
- />
- </div>
- </div>
- </div>
- <!-- 无权限\未登录 -->
- <div class="no-auth-wrap" v-if="!isLogin||['expired','unTest','unMatch'].includes(riskLevelStatus)">
- <div class="opcity-box"></div>
- <div class="content-box">
- <img class="icon" src="@/assets/imgs/lock-img.png" alt="" />
- <template v-if="!isLogin">
- <div class="text">您尚未登录,请登录后查看</div>
- <t-button
- theme="primary"
- block
- style="width: 300px; margin: 30px auto"
- @click="handleGoLogin"
- >去登陆</t-button
- >
- </template>
- <template v-else>
- <div class="text" v-if="riskLevelStatus==='expired'">您的风险测评已过期,请完成风险测评</div>
- <div class="text" v-if="riskLevelStatus==='unTest'">您尚未进行风险测评,请完成风险测评</div>
- <div class="text" v-if="riskLevelStatus==='unMatch'">您的风险等级无法查看此内容<br>请查看其他内容</div>
- <t-button
- theme="primary"
- block
- style="width: 300px; margin: 30px auto"
- v-if="['expired','unTest'].includes(riskLevelStatus)"
- @click="handleGoTestRisk"
- >风险测评</t-button
- >
- </template>
- </div>
- </div>
- <div class="no-auth-wrap" v-else-if="!isSubscribe && !isFree">
- <div class="opcity-box"></div>
- <div class="content-box subscribe-box">
- <div class="icon-box">
- <img class="icon subscribe" src="@/assets/imgs/lock.png" alt="" />
- <div class="text" v-if="subscribeStatus==='expired'">您的权限已过期<br>若需继续查看可点击【立即订阅】</div>
- <div class="text" v-if="subscribeStatus==='unSubscribe'">您暂无阅读权限<br>若感兴趣请点击【立即订阅】</div>
- </div>
- <div class="pay-btn">
- <div class="pay-btn-confirm">
- <div class="pay-btn-money">
- <span>合计</span>
- <span class="pay">¥{{ priceNum }}</span>
- </div>
- <t-button
- class="btn"
- theme="primary"
- shape="round"
- block
- @click="goPrimary"
- >立即订阅</t-button>
- </div>
- </div>
- </div>
- </div>
- <!-- 免责声明 -->
- <disclaimers-wrap v-model:show="isShowMZSM" />
- <!-- 关注弹窗 -->
- <t-popup v-model="visible" placement="center" style="width: 350px">
- <t-icon class="close-btn" name="close-circle" size="32" color="#fff" @click="onClose" />
- <div class="author-popup">
- <div class="title">作者详情</div>
- <div class="authorList-box" v-for="(item, index) in authorInfoList" :key="index">
- <div class="img-list-box" @click="goDetails(item)">
- <img
- :src="authorInfoList?.[0].headImgUrl|| defaultImg"
- />
- </div>
- <div class="name-list-box" @click="goDetails(item)">
- {{ item.name }}
- </div>
- <div
- @click="changeFollowStateList(item)"
- :class="['opt-btn', item.following === 'following' ? 'following' : '']"
- v-if="isLogin"
- >
- {{ item.following === 'following' ? "取消关注" : "关注" }}
- </div>
- </div>
- </div>
- </t-popup>
- </template>
- <style lang="scss" scoped>
- .report-detail-page {
- background-color: #fff;
- padding: var(--page-padding);
- .title-box {
- font-size: 36px;
- line-height: 44px;
- margin-bottom: 20px;
- }
- .author-box {
- display: flex;
- align-items: center;
- .img-box {
- width: 78px;
- height: 78px;
- border-radius: 50%;
- overflow: hidden;
- img {
- width: 100%;
- height: 100%;
- }
- }
- .author-info {
- margin-left: 30px;
- flex: 1;
- .name {
- /* display: block; */
- display: -webkit-box;
- overflow: hidden;
- text-overflow: ellipsis;
- -webkit-line-clamp: 2;
- line-break: anywhere;
- -webkit-box-orient: vertical;
- }
- .time {
- display: block;
- margin-top: 10px;
- font-size: var(--font-size-small);
- color: var(--text-color-grey);
- }
- }
- .opt-btn {
- margin-left: auto;
- align-self: flex-start;
- min-width: 140px;
- height: 40px;
- padding: 5px 10px;
- border-radius: 8px;
- background-color: var(--primary-color);
- color: var(--text-color-inverse);
- text-align: center;
- &.followed {
- background-color: var(--bg-disabled-color);
- color: var(--text-color-grey);
- }
- }
- }
- .time-box {
- font-size: var(--font-size-small);
- text-align: right;
- .btn {
- color: var(--primary-color);
- position: relative;
- top: -34px;
- }
- }
- .des-box {
- background-color: #f8f8f8;
- padding: 20px;
- margin: 20px 0;
- display: flex;
- gap: 0 10px;
- color: var(--text-color-sub);
- font-size: var(--font-size-small);
- line-height: 36px;
- }
- .report-content-box {
- margin-top: 20px;
- line-height: 1.8;
- font-size: 36px;
- :deep(img) {
- width: 100% !important;
- }
- :deep(span) {
- font-size: 36px !important;
- line-height: 1.8 !important;
- background-color: rgba(255, 255, 255, 0) !important;
- }
- :deep(p) {
- font-size: 36px !important;
- line-height: 1.8 !important;
- background-color: rgba(255, 255, 255, 0) !important;
- }
- :deep(ul) {
- font-size: 36px !important;
- line-height: 1.8 !important;
- background-color: rgba(255, 255, 255, 0) !important;
- }
- :deep(ol) {
- font-size: 36px !important;
- line-height: 1.8 !important;
- background-color: rgba(255, 255, 255, 0) !important;
- }
- :deep(iframe) {
- width: 100% !important;
- }
- :deep(li) {
- font-size: 36px !important;
- line-height: 1.8 !important;
- background-color: rgba(255, 255, 255, 0) !important;
- list-style: inherit !important;
- list-style-position: inside !important;
- }
- :deep(span.fr-emoticon) {
- width: 36px !important;
- height: 36px !important;
- background-repeat: no-repeat !important;
- background-size: cover !important;
- display: inline-block !important;
- vertical-align: middle !important;
- }
- .chapter-item-wrap {
- padding: 20px 0;
- .chapter-title {
- display: flex;
- align-items: center;
- font-size: 30px;
- .type {
- height: fit-content;
- display: inline-block;
- color: #fff;
- padding: 10px 20px;
- background-color: #e6a23c;
- border-radius: 8px;
- margin-right: 20px;
- }
- .chapter-title-text {
- font-size: 30px;
- }
- }
- }
- }
- .right-fix-box {
- position: fixed;
- z-index: 99;
- right: 34px;
- bottom: 130px;
- //加上这个保证back-top-img不会重复渲染
- transform: translateZ(0); //不知道什么原理
- .item {
- margin-top: 10px;
- }
- .back-top-img {
- width: 100px;
- height: 100px;
- display: block;
- }
- }
- .html-head-img-box,
- .html-end-img-box {
- margin-bottom: 10px;
- position: relative;
- overflow: hidden;
- .head-layout-item {
- position: absolute;
- overflow: hidden;
- box-sizing: border-box;
- }
- }
- }
- .no-auth-box {
- height: 100vh;
- overflow: hidden;
- }
- .no-auth-wrap {
- position: fixed;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 99;
- .opcity-box {
- height: 129px;
- background: linear-gradient(
- 360deg,
- #ffffff 0%,
- rgba(255, 255, 255, 0) 100%
- );
- }
- .content-box {
- background-color: #fff;
- padding-bottom: 240px;
- text-align: center;
- color: var(--primary-color);
- }
- .subscribe-box {
- padding-bottom: 0;
- }
- .icon {
- display: block;
- margin: 0 auto;
- width: 100%;
- }
- .subscribe {
- width: 200px;
- height: 200px;
- margin-bottom: 30px;
- }
- .icon-box {
- margin-bottom: 120px;
- }
- .pay-btn {
- width: 100%;
- margin: 0 auto;
- background-color: #fff;
- border-radius: 16px;
- padding: 40px;
- display: flex;
- justify-content: flex-end;
- align-items: center;
- border-top: #C0C0C0 1px solid;
- // position: absolute;
- // bottom: 0;
- .pay-btn-cancel {
- color: #0078E8;
- font-size: 28px;
- }
- .pay-btn-confirm{
- width: 100%;
- display: flex;
- justify-content: flex-end;
- align-items: center;
- .pay-btn-money {
- display: flex;
- justify-content: space-between;
- align-items: center;
- font-size: 32px;
- text-align: right;
- color: #999999;
- margin-right: 20px;
- .pay{
- font-size: 36px;
- color: #e54d42;
- margin-left: 10px;
- }
- }
- .btn {
- width: 40%;
- }
- }
- }
- }
- .close-btn {
- position: absolute;
- left: 100%;
- margin-left: -16px;
- top: calc(-1 * (24px + 32px));
- }
- .title {
- padding: 30rpx;
- font-size: 32px;
- color: #323233;
- text-align: center;
- }
- .author-popup {
- padding: 30px;
- .authorList-box {
- margin: 20px 0;
- display: flex;
- justify-content: space-between;
- align-items: center;
- .img-list-box {
- width: 78px;
- height: 78px;
- border-radius: 50%;
- overflow: hidden;
- img {
- width: 100%;
- height: 100%;
- }
- }
- .name-list-box {
- display: -webkit-box;
- -webkit-box-orient: vertical;
- overflow: hidden;
- text-overflow: ellipsis;
- -webkit-line-clamp: 2; /* 限制为2行 */
- }
- .opt-btn {
- margin-left: 40%;
- min-width: 140px;
- height: 40px;
- padding: 5px 10px;
- border-radius: 8px;
- background-color: var(--primary-color);
- color: var(--text-color-inverse);
- text-align: center;
- &.following {
- background-color: var(--bg-disabled-color);
- color: var(--text-color-grey);
- }
- }
- }
- }
- </style>
|