PreviewDetail.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. <script setup name="ReportPreview">
  2. import { ref,computed, nextTick, reactive,toRefs } from 'vue'
  3. import { useRoute, useRouter } from "vue-router";
  4. import {getSystemInfo,shareGenerate} from '@/api/common'
  5. import {Base64} from 'js-base64'
  6. import apiReport from '@/api/report'
  7. import AudioBox from './components/AudioBox.vue'
  8. import {showToast} from 'vant'
  9. import {reportManageBtn,useAuthBtn} from '@/hooks/useAuthBtn'
  10. import { copyText } from 'vue3-clipboard'
  11. import {usePublicSettingStore} from '@/store/modules/publicSetting'
  12. import vueQr from 'vue-qr/src/packages/vue-qr.vue'
  13. const {checkAuthBtn} = useAuthBtn()
  14. const publicSettingStore = usePublicSettingStore()
  15. const route=useRoute()
  16. const router=useRouter()
  17. // 智能布局移动端样式时内容排版全部变成1个1行的顺排
  18. function formatSmartStyle() {
  19. nextTick(() =>{
  20. const width=window.innerWidth;
  21. if(width>600) return
  22. $('.report-drag-item-wrap_child-wrap').css({
  23. 'flex-wrap': 'wrap',
  24. });
  25. $('.report-drag-item-wrap_child-wrap').children().css({
  26. 'flex': 'none',
  27. 'width': '100%'
  28. });
  29. document.querySelectorAll('div[comp-type="text"]').forEach(function(div) {
  30. div.style.height = 'auto';
  31. });
  32. })
  33. }
  34. // 获取报告详情
  35. let reportInfo=ref(null)
  36. let shareUrls=ref(null)
  37. const smartState = reactive({
  38. bgColor:'',
  39. headImgStyle:null,//版头style
  40. endImgStyle:null,//版尾style
  41. layoutBaseInfo:{
  42. 研报标题:'',
  43. 研报作者:'',
  44. 创建时间:''
  45. }
  46. })
  47. async function getReportDetail(){
  48. const res=await apiReport.getReportDetail({ReportId:Number(route.query.id)})
  49. if(res.Ret===200){
  50. reportInfo.value=res.Data
  51. document.title=res.Data.Title
  52. smartState.bgColor=res.Data.CanvasColor
  53. smartState.headImgStyle=reportInfo.value.HeadStyle?JSON.parse(reportInfo.value.HeadStyle):[]
  54. smartState.headImgStyle.map(st =>{
  55. st.value=st.value || st.label
  56. })
  57. smartState.endImgStyle=reportInfo.value.EndStyle?JSON.parse(reportInfo.value.EndStyle):[]
  58. smartState.endImgStyle.map(st =>{
  59. st.value=st.value || st.label
  60. })
  61. smartState.layoutBaseInfo['研报标题']=reportInfo.value.Title
  62. smartState.layoutBaseInfo['研报作者']=reportInfo.value.Author
  63. smartState.layoutBaseInfo['创建时间']=[2,6].includes(reportInfo.value.State)?reportInfo.value.PublishTime:''
  64. getSystemInfoFun()
  65. if(res.Data.ReportLayout===2){
  66. formatSmartStyle()
  67. }
  68. }
  69. }
  70. if(route.query.id==-1){
  71. //新增编辑报告时的预览
  72. const data=JSON.parse(sessionStorage.getItem('reportPreData'))
  73. reportInfo.value=data
  74. document.title=data.Title
  75. getSystemInfoFun()
  76. }else{
  77. getReportDetail()
  78. }
  79. const { bgColor,headImgStyle,endImgStyle,layoutBaseInfo } = toRefs(smartState)
  80. const showImgPop = ref(false)
  81. const linkUrl = (waterMarkStr) =>{
  82. console.log(publicSettingStore)
  83. let str=''
  84. let url=''
  85. const baseUrl= publicSettingStore.publicSetting.ReportViewUrl;
  86. if(reportInfo.value.ReportCode){
  87. str= reportInfo.value.ReportLayout===1
  88. ? `${baseUrl}/reportshare_crm_report?code=${reportInfo.value.ReportCode}&flag=${waterMarkStr}& ${reportInfo.value.Title}`
  89. : `${baseUrl}/reportshare_smart_report?code=${reportInfo.value.ReportCode}&flag=${waterMarkStr} ${reportInfo.value.Title}`
  90. const params={
  91. "Url":str,
  92. "ReportId":reportInfo.value.Id
  93. }
  94. shareGenerate(params).then(res=>{
  95. if(res.Ret===200){
  96. console.log(res)
  97. if(location.port=='5173'){
  98. url='http://8.136.199.33:8611'
  99. }else{
  100. url=location.origin
  101. }
  102. shareUrls.value=url+'/v1/share/'+res.Data.UrlToken
  103. }
  104. })
  105. }
  106. }
  107. function handleCopyLink() {
  108. copyText(shareUrls.value,undefined,(error,event)=>{
  109. if(error){
  110. showToast('复制链接成功')
  111. throw new Error('复制数据失败'+JSON.stringify(error))
  112. }else{
  113. showToast('复制链接成功')
  114. }
  115. })
  116. }
  117. const waterMarkStr=ref('')
  118. const getSystemInfoFun=()=>{
  119. getSystemInfo().then(res=>{
  120. if(res.Ret===200){
  121. const systemUserInfo=res.Data
  122. // 设置水印文案
  123. let waterMarkString=''
  124. if(systemUserInfo){
  125. waterMarkString=`${systemUserInfo.RealName}${systemUserInfo.Mobile?systemUserInfo.Mobile:systemUserInfo.Email}`
  126. waterMarkString=encodeURIComponent(waterMarkString)
  127. waterMarkStr.value=Base64.encode(waterMarkString)
  128. linkUrl(waterMarkStr.value)
  129. }
  130. }
  131. })
  132. }
  133. </script>
  134. <template>
  135. <div class="report-detail-page select-text-disabled" v-if="reportInfo" :style="{backgroundColor:bgColor}">
  136. <!-- <div class="top-stage-box" v-if="$route.query.id!=-1">
  137. <span class="stage">第{{reportInfo.Stage}}期 / {{reportInfo.Frequency}}</span>
  138. </div> -->
  139. <!-- 版头 -->
  140. <div class="html-head-img-box" v-if="reportInfo && reportInfo.HeadImg">
  141. <img :src="reportInfo.HeadImg" alt="" style="display:block;width:100%">
  142. <div class="head-layout-item" v-for="item in headImgStyle" :key="item.value"
  143. :style="{fontFamily:item.family,fontSize:(item.sizeMobile || item.size)+'px',fontWeight:item.weight,textAlign:item.align,color:item.color,
  144. width:item.width,height:item.height,left:item.left,top:item.top
  145. }">
  146. {{ layoutBaseInfo[item.value] }}
  147. </div>
  148. </div>
  149. <template v-if="reportInfo&&(!reportInfo.HeadImg) && (!reportInfo.EndImg)">
  150. <h1 class="report-title">{{reportInfo.Title}}</h1>
  151. <div class="auth-box">
  152. <span>{{reportInfo.Author}}</span>
  153. <span>{{reportInfo.PublishTime}}</span>
  154. </div>
  155. </template>
  156. <!-- 音频 -->
  157. <AudioBox :url="reportInfo.VideoUrl" v-if="reportInfo.VideoUrl"/>
  158. <div class="report-abstract" v-if="reportInfo.Abstract">摘要:{{reportInfo.Abstract}}</div>
  159. <!-- 章节 -->
  160. <template v-if="reportInfo.CollaborateType===2">
  161. <ul class="chapter-list-wrap">
  162. <li class="chapter-item-box" v-for="item in reportInfo.ChapterList" :key="item.ReportChapterId">
  163. <div class="type-box">
  164. <span class="tag">{{item.TypeName}}</span>
  165. <span>{{item.Title}}</span>
  166. </div>
  167. <!-- 音频 -->
  168. <!-- <AudioBox :url="item.VideoUrl" v-if="item.VideoUrl"/> -->
  169. <div class="report-html-wrap" v-html="item.Content"></div>
  170. </li>
  171. </ul>
  172. </template>
  173. <!-- 研报 -->
  174. <template v-else>
  175. <div class="report-html-wrap" v-html="reportInfo.Content"></div>
  176. </template>
  177. <!-- 板尾 -->
  178. <div class="html-end-img-box" v-if="reportInfo && reportInfo.EndImg">
  179. <img :src="reportInfo.EndImg" alt="" style="display:block;width:100%">
  180. <div class="head-layout-item" v-for="item in endImgStyle" :key="item.value"
  181. :style="{fontFamily:item.family,fontSize:(item.sizeMobile || item.size)+'px',fontWeight:item.weight,textAlign:item.align,color:item.color,
  182. width:item.width,height:item.height,left:item.left,top:item.top
  183. }">
  184. {{ layoutBaseInfo[item.value] }}
  185. </div>
  186. </div>
  187. <!-- 浮动操作 -->
  188. <div class="fix-bot-action-box">
  189. <div class="item" @click="handleCopyLink" v-permission="reportManageBtn.reportManage_reportView_copyWechat">
  190. <img class="icon" src="@/assets/imgs/report/icon_copy.png" alt="">
  191. <div>复制链接</div>
  192. </div>
  193. <div class="item" @click="showImgPop=true" v-permission="reportManageBtn.reportManage_reportView_wechartShare">
  194. <img class="icon" src="@/assets/imgs/report/icon_wx_black.png" alt="">
  195. <div>微信分享</div>
  196. </div>
  197. </div>
  198. </div>
  199. <van-popup
  200. v-model:show="showImgPop"
  201. round
  202. >
  203. <vue-qr :text="shareUrls" colorDark="#333" colorLight="#fff" :dotScale="1"></vue-qr>
  204. </van-popup>
  205. </template>
  206. <style lang="scss" scoped>
  207. .report-detail-page{
  208. padding: 30px 34px;
  209. margin-bottom: 112px;
  210. .report-title{
  211. margin: 30px 0;
  212. font-weight: 600;
  213. font-size: 42px;
  214. line-height: 56px;
  215. }
  216. .auth-box{
  217. display: flex;
  218. justify-content: space-between;
  219. font-size: $font-grey;
  220. font-size: 36px;
  221. margin-bottom: 40px;
  222. }
  223. .report-abstract{
  224. font-size: 34px;
  225. line-height: 54px;
  226. margin: 40px 0;
  227. }
  228. .audio-box{
  229. margin: 40px 0;
  230. }
  231. .chapter-list-wrap{
  232. .chapter-item-box{
  233. padding-bottom: 20px;
  234. border-bottom: 1px dashed $border-color;
  235. margin-bottom: 20px;
  236. .type-box{
  237. display: flex;
  238. align-items: center;
  239. .tag{
  240. display: inline-block;
  241. padding: 10px;
  242. font-size: 24px;
  243. background: rgba(0, 82, 217, 0.1);
  244. border-radius: 4px;
  245. color: $theme-color;
  246. margin-right: 20px;
  247. }
  248. }
  249. }
  250. }
  251. .report-drag-item-wrap{
  252. padding: 6px;
  253. margin-bottom: 3px;
  254. }
  255. .html-head-img-box,.html-end-img-box{
  256. position: relative;
  257. margin: 20px 0;
  258. .head-layout-item{
  259. position: absolute;
  260. overflow: hidden;
  261. box-sizing: border-box
  262. }
  263. }
  264. }
  265. .top-stage-box{
  266. .stage{
  267. display: inline-block;
  268. background-color: #F2F3FF;
  269. border-radius: 8px;
  270. height: 72px;
  271. line-height: 72px;
  272. padding: 0 20px;
  273. font-size: 28px;
  274. }
  275. .edit-icon{
  276. float: right;
  277. width: 70px;
  278. height: 70px;
  279. }
  280. }
  281. .fix-bot-action-box{
  282. position: fixed;
  283. left: 0;
  284. bottom: 0;
  285. right: 0;
  286. z-index: 99;
  287. background-color: #fff;
  288. border-top: 1px solid $border-color;
  289. height: 112px;
  290. display: flex;
  291. align-items: center;
  292. .item{
  293. height: 100%;
  294. flex: 1;
  295. display: flex;
  296. flex-direction: column;
  297. justify-content: center;
  298. align-items: center;
  299. font-size: 20px;
  300. .icon{
  301. width: 40px;
  302. height: 40px;
  303. margin-bottom: 5px;
  304. }
  305. }
  306. }
  307. @media screen and (min-width:$media-width){
  308. .report-detail-page{
  309. max-width: 800px;
  310. margin: 0 auto 110px;
  311. padding: 30px;
  312. .report-title{
  313. margin: 15px 0;
  314. font-size: 21px;
  315. line-height: 28px;
  316. }
  317. .auth-box{
  318. font-size: 18px;
  319. padding-bottom: 20px;
  320. margin-bottom: 20px;
  321. }
  322. .report-abstract{
  323. font-size: 17px;
  324. line-height: 27px;
  325. margin: 20px 0;
  326. }
  327. .chapter-list-wrap{
  328. .chapter-item-box{
  329. padding-bottom: 20px;
  330. margin-bottom: 20px;
  331. .type-box{
  332. .tag{
  333. padding: 5px;
  334. font-size: 12px;
  335. border-radius: 2px;
  336. margin-right: 10px;
  337. }
  338. }
  339. }
  340. }
  341. }
  342. .top-stage-box{
  343. .stage{
  344. border-radius: 4px;
  345. height: 36px;
  346. line-height: 36px;
  347. padding: 0 10px;
  348. font-size: 14px;
  349. }
  350. .edit-icon{
  351. width: 35px;
  352. height: 35px;
  353. }
  354. }
  355. .fix-bot-action-box{
  356. height: 110px;
  357. .item {
  358. font-size: 18px;
  359. .icon{
  360. width: 40px;
  361. height: 40px;
  362. }
  363. }
  364. }
  365. }
  366. </style>