raiReportDtl.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. <template>
  2. <div :class="['container-cygx', reportInfo.IsResearch && 'no-cv', reportInfo.IsSpecialArticle && 'container-cygx-bg']" v-show="haveData">
  3. <trackForm v-model:isShowFollowButton="reportInfo.IsShowFollowButton" :sourceId="rerportId" v-model:isFollowData="reportInfo.IsFollowButton" />
  4. <div class="z-index-content" ref="contentBox">
  5. <div class="content-top">
  6. <div class="report-title">{{ reportInfo.Title }}</div>
  7. <div class="report-text">
  8. <template v-if="!reportInfo.IsResearch">
  9. <div v-if="reportInfo.IsSpecialArticle">
  10. <span>{{ reportInfo.PublishDate }} &nbsp;&nbsp;&nbsp;&nbsp;</span>
  11. <span class="author">{{ reportInfo.SellerAndMobile }}</span>
  12. </div>
  13. <template v-else>
  14. <div class="report_desc">
  15. <span class="author">{{ reportInfo.Department }}</span>
  16. <span>{{ reportInfo.PublishDate }}</span>
  17. </div>
  18. <div class="seller-list" v-if="reportInfo.IsSpecialArticle">
  19. <span>联系人:</span>
  20. <span v-for="(item, index) in reportInfo.SellerList" :key="index"> {{ item.SellerName }}({{ item.SellerMobile }})&nbsp;&nbsp; </span>
  21. </div>
  22. </template>
  23. </template>
  24. <template v-else>
  25. <div class="report-research">
  26. <div style="display: flex">
  27. <img :src="reportInfo.DepartmentImgUrl" @click="goAuthorPages" />
  28. <div class="research-author">
  29. <p @click="goAuthorPages">{{ reportInfo.SellerAndMobile }}</p>
  30. <p class="time">{{ reportInfo.PublishDate }}</p>
  31. </div>
  32. </div>
  33. <div @click="attentionBtn" :style="{ 'background-color': isYanxuan ? '#F1A84A' : '#376CBB' }" class="is-follow" :class="reportInfo.IsFollow ? 'follow-cancel' : ''" v-if="isBinding">
  34. {{ reportInfo.IsFollow ? "取消关注" : "+ 关注" }}
  35. </div>
  36. </div>
  37. </template>
  38. <!-- <div v-if="!reportInfo.IsSpecialArticle">注:请务必阅读<span class="tip" @click="showTips = true"> &nbsp;免责声明</span></div> -->
  39. <div :class="['container-abstract', isYanxuan && 'container-abstract-yx']">&nbsp;&nbsp;摘要:&nbsp;{{ reportInfo.Abstract }}</div>
  40. </div>
  41. </div>
  42. <template v-if="isBinding">
  43. <div class="report-link" v-if="fileLink">
  44. 报告全文:
  45. <span style="color: #0808e5" @click="downloadFile">(PDF格式报告下载.pdf)</span>
  46. </div>
  47. <div class="detail-report" :class="reportInfo.IsResearch ? '' : 'detail-bottom'">
  48. <div id="report-content" v-html="reportInfo.Body"></div>
  49. </div>
  50. <div class="deeperReport" @click="lookDeeperReport" v-if="reportInfo.ReportLink">查看报告链接</div>
  51. <div class="host-collect" v-if="reportInfo.IsResearch && reportResearch.length">
  52. <h4>相关热门收藏:</h4>
  53. <div class="host-content" v-for="item in reportResearch" :key="item.ArticleId">
  54. <p class="host-title" @click="goDetail(item)">{{ item.Title }}</p>
  55. <div class="item-more">
  56. <p>{{ item.PublishDate }}</p>
  57. <div class="pv-ollect">
  58. <div>
  59. <img class="pv" src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/examine_icon.png" />
  60. {{ item.Pv }}
  61. </div>
  62. <div @click="collectClick(item)">
  63. <img v-if="item.IsCollect" src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/collect_act.png" />
  64. <img v-else src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/collect_ico.png" />
  65. {{ item.CollectNum }}人收藏
  66. </div>
  67. </div>
  68. </div>
  69. </div>
  70. </div>
  71. <!-- <div v-if="reportInfo.IsSpecialArticle" class="statement-content">
  72. <p class="title">免责声明</p>
  73. <p class="content">
  74. 本报告仅供弘则弥道(上海)投资咨询有限公司正式签约的机构客户使用,不会仅因接收人/接受机构收到本报告而将其视为客户。本报告根据国际和行业通行的准则,以合法渠道获得这些信息,尽可能保证可靠、准确和完整,但并不保证报告所述信息的准确性和完整性,也不保证本报告所包含的信息或建议在本报告发出后不会发生任何变更。本报告中所提供的信息仅供参考。报告中的内容不对投资者做出的最终操作建议做任何的担保,也没有任何形式的分享投资收益或者分担投资损失的书面或口头承诺。不作为客户在投资、法律、会计或税务等方面的最终操作建议,也不作为道义的、责任的和法律的依据或者凭证,无论是否已经明示或者暗示。在任何情况下,本公司不对客户/接受人/接受机构因使用报告中内容所引致的一切损失负责任,客户/接受人/接受机构需自行承担全部风险。
  75. </p>
  76. </div> -->
  77. </template>
  78. <template v-else>
  79. <div class="detail-report" :class="reportInfo.IsResearch ? '' : 'detail-bottom'" v-if="reportInfo.Body">
  80. <div id="report-content" v-html="reportInfo.Body.slice(0, 200)"></div>
  81. </div>
  82. <div class="please-login" @click="pleaseGoLogin">请登录后查看更多内容</div>
  83. </template>
  84. </div>
  85. <div class="statement-content-box" v-if="rerportId >= 1000000">
  86. <p>郑重声明:</p>
  87. 本文为用户投稿,用户在平台中发表的所有资料、言论等仅代表个人或嘉宾观点,与本网站、任何公司与任何机构立场无关。本平台对文中陈述、观点判断保持中立,不对所包含内容及数据的真实性、准确性、可靠性或完整性提供任何明示或暗示的保证。
  88. 股市波动与很多因素有关,任何用户或嘉宾的发言,都有其特定立场,投资决策是个人基于自己的研究分析所做的决定,本文章或会议目的在于事实、观点分享,不构成任何的投资建议。投资者应当自主进行投资决策,对投资者因依赖上述信息进行投资决策而导致的财产损失,本平台不承担法律责任。
  89. 本文章或会议未经本平台和作者的书面许可,任何机构和个人不得以任何形式转发、转载、翻版、复制、刊登、发表、修改、仿制或引用文章或会议的全部或部分内容。本平台对任何第三方的未经授权行为所产生的的影响不承担任何责任,同时保持实施法律行动的权利。
  90. </div>
  91. <div class="btn-returntop" v-if="isBinding">
  92. <img v-if="isYanxuan" src="~@/assets/cygx/returntop_yx.png" @click="scrolltop" style="width: 40px" />
  93. <img v-else src="~@/assets/cygx/returntop.png" @click="scrolltop" style="width: 40px" />
  94. </div>
  95. <div class="btn-freecharge" v-if="isShowFreeBtn && from_type == 'mpwechat'">
  96. <img @click="toggle" class="image" src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/free_icon.png" />
  97. <img @click="removeBton" class="remove-icon" src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/free_%20remove.png" />
  98. </div>
  99. <!-- 底部悬浮固定 -->
  100. <div class="fixed_cont" v-if="from_type == 'mpwechat' && isBinding">
  101. <div class="handle-item" @click="quizBtn">
  102. <img src="@/assets/cygx/leaving_message.png" class="img_ico" />
  103. <div>留言</div>
  104. </div>
  105. <div class="handle-item" v-if="reportInfo?.IsApplyAppointmentExpert" @click="appointment(reportInfo?.ArticleId)">
  106. <img src="@/assets/cygx/appointment-expert.png" class="img_ico" />
  107. <div>约访专家</div>
  108. </div>
  109. <div class="handle-item" @click="collectHandle">
  110. <template v-if="reportInfo.IsCollect">
  111. <img v-if="isYanxuan" src="https://hzstatic.hzinsights.com/yx_xcx/collect_act.png" />
  112. <img src="@/assets/cygx/collect_act.png" class="img_ico" v-else />
  113. </template>
  114. <img src="@/assets/cygx/collect_ico.png" class="img_ico" v-else />
  115. <div v-if="reportInfo.IsResearch">
  116. {{ `${reportInfo.CollectionNum} 人收藏` }}
  117. </div>
  118. <div v-else>{{ reportInfo.IsCollect ? "已收藏" : "收藏" }}</div>
  119. </div>
  120. </div>
  121. <dlg :showTips="showTips" :reportInfo="reportInfo" @hideDlg="showTips = false" />
  122. </div>
  123. </template>
  124. <script setup>
  125. import { reactive, onMounted, toRefs, ref } from "vue";
  126. import { useRouter, useRoute } from "vue-router";
  127. import { RaiApi, FreeButton } from "@/api/cygx/api.js";
  128. import { Icon, Dialog, Toast } from "vant";
  129. import dlg from "./dlg.vue";
  130. import trackForm from "./isTrackFollow.vue";
  131. const router = useRouter();
  132. const route = useRoute();
  133. const state = reactive({
  134. reportInfo: {},
  135. reportResearch: [],
  136. });
  137. const rerportId = ref(null);
  138. const from_type = ref(null);
  139. const haveData = ref(false);
  140. const fileLink = ref(false);
  141. const showTips = ref(false);
  142. const contentBox = ref(null);
  143. const isBinding = ref(true);
  144. const isSendWx = ref("");
  145. const isYanxuan = ref("");
  146. /* 访谈接口 */
  147. const interviewApi = () => {
  148. RaiApi.applyRpt({
  149. ArticleId: Number(rerportId.value),
  150. }).then((res) => {
  151. if (res.Ret === 200) {
  152. state.reportInfo.IsInterviewApply = !state.reportInfo.IsInterviewApply;
  153. state.reportInfo.InterviewApplyStatus = state.reportInfo.IsInterviewApply ? "待邀请" : "";
  154. Toast(res.Msg);
  155. }
  156. });
  157. };
  158. //跳转到免费送月卡页面
  159. const toggle = () => {
  160. wx.miniProgram.navigateTo({
  161. url: `/${isYanxuan.value ? "pages-user" : "pageMy"}/freeTrial/freeTrial`,
  162. });
  163. };
  164. const isShowFreeBtn = ref(false);
  165. //隐藏当天的按钮
  166. const removeBton = async () => {
  167. const res = await FreeButton.userFreeButtonUpdate();
  168. if (res.Ret === 200) {
  169. isShowFreeBtn.value = false;
  170. }
  171. };
  172. const userIsShowFreeButton = async () => {
  173. const res = await FreeButton.userIsShowFreeButton();
  174. if (res.Ret === 200) {
  175. isShowFreeBtn.value = res.Data.IsShow;
  176. }
  177. };
  178. // 跳转到作者页面
  179. const goAuthorPages = () => {
  180. wx.miniProgram.navigateTo({
  181. url: `/${isYanxuan.value ? "pages-report" : "reportPages"}/authorPages/authorPages?id=` + state.reportInfo.DepartmentId,
  182. });
  183. };
  184. const downloadFile = async () => {
  185. Toast.loading({
  186. message: "下载中...",
  187. duration: 0,
  188. forbidClick: true,
  189. });
  190. const res = await RaiApi.articlePdfwatermark({
  191. ArticleId: Number(rerportId.value),
  192. });
  193. if (res.Ret === 200) {
  194. Toast.clear();
  195. wx.miniProgram.navigateTo({
  196. url: `/${isYanxuan.value ? "pages-user" : "pageMy"}/downloadFile/downloadFile?url=` + res.Data.FileLink,
  197. });
  198. }
  199. };
  200. /* 访谈申请 */
  201. const applyHandle = () => {
  202. !state.reportInfo.IsInterviewApply &&
  203. Dialog.confirm({
  204. title: "",
  205. message: "专家访谈申请会提交给您的对口销售,销售会线下与您取得联系,确定申请吗?",
  206. confirmButtonColor: "#fff",
  207. cancelButtonColor: "#fff",
  208. theme: "round-button",
  209. }).then(() => {
  210. interviewApi();
  211. });
  212. // 取消申请访谈 区分状态 '待邀请','待访谈','已完成','已取消'
  213. if (state.reportInfo.IsInterviewApply) {
  214. Dialog.confirm({
  215. title: "",
  216. message:
  217. state.reportInfo.InterviewApplyStatus == "待访谈"
  218. ? "当前无法取消访谈,若有疑问,请联系对口销售" + state.reportInfo.SellerMobile
  219. : state.reportInfo.InterviewApplyStatus == "待邀请"
  220. ? "您要取消此次访谈申请吗?"
  221. : "该访谈已完成",
  222. confirmButtonColor: "#fff",
  223. cancelButtonColor: "#fff",
  224. theme: "round-button",
  225. }).then(() => {
  226. state.reportInfo.InterviewApplyStatus == "待邀请" ? interviewApi() : state.reportInfo.InterviewApplyStatus == "待访谈" ? (window.location.href = "tel://" + state.reportInfo.SellerMobile) : "";
  227. });
  228. }
  229. };
  230. const scrolltop = () => {
  231. document.body.scrollTop = document.documentElement.scrollTop = 0;
  232. };
  233. /* 文章相关热门 */
  234. const researcharticleHotList = async () => {
  235. const res = await FreeButton.researcharticleHotList({ ArticleId: Number(rerportId.value) });
  236. if (res.Ret === 200) {
  237. state.reportResearch = res.Data.List || [];
  238. }
  239. };
  240. //关注作者事件
  241. const attentionBtn = () => {
  242. RaiApi.fllowDepartment({
  243. DepartmentId: state.reportInfo.DepartmentId,
  244. }).then((res) => {
  245. if (res.Ret === 200) {
  246. state.reportInfo.IsFollow = !state.reportInfo.IsFollow;
  247. if (res.Data.Status == 1) {
  248. state.reportInfo.FollowNum += 1;
  249. if (res.Data.GoFollow) {
  250. Dialog.confirm({
  251. title: "作者关注成功",
  252. message: "想要及时获取该作者的报告更新提示,请关注【查研观向小助手】公众号",
  253. confirmButtonColor: "#fff",
  254. confirmButtonText: "去关注",
  255. cancelButtonColor: "#fff",
  256. theme: "round-button",
  257. })
  258. .then(() => {
  259. wx.miniProgram.navigateTo({
  260. url: `/${isYanxuan.value ? "pages-activity" : "activityPages"}/accountsOfficial/accountsOfficial`,
  261. });
  262. })
  263. .catch(() => {
  264. // on cancel
  265. });
  266. } else {
  267. Dialog.alert({
  268. title: "",
  269. message: "作者关注成功,请关注【查研观向小助手】公众号,及时获取作者的报告更新提示",
  270. confirmButtonColor: "#3385FF",
  271. confirmButtonText: "知道了",
  272. });
  273. }
  274. } else {
  275. state.reportInfo.FollowNum -= 1;
  276. Toast("已取消关注");
  277. }
  278. }
  279. });
  280. };
  281. /* 收藏 */
  282. const collectHandle = () => {
  283. RaiApi.collectRpt({
  284. ArticleId: Number(rerportId.value),
  285. }).then((res) => {
  286. if (res.Ret === 200) {
  287. state.reportInfo.IsCollect = !state.reportInfo.IsCollect;
  288. if (res.Data.Status == 2) {
  289. state.reportInfo.CollectionNum -= 1;
  290. } else {
  291. state.reportInfo.CollectionNum += 1;
  292. }
  293. Toast(res.Msg);
  294. }
  295. });
  296. };
  297. /* 文章相关热门跳转 */
  298. const goDetail = (item) => {
  299. wx.miniProgram.navigateTo({
  300. url: `/${isYanxuan.value ? "pages-user" : "pageMy"}/reportDetail/reportDetail?id=` + item.ArticleId,
  301. });
  302. };
  303. /* 文章相关热门收藏 */
  304. const collectClick = async (item) => {
  305. const res = await RaiApi.collectRpt({ ArticleId: item.ArticleId });
  306. if (res.Ret === 200) {
  307. item.IsCollect = !item.IsCollect;
  308. item.IsCollect ? (item.CollectNum += 1) && Toast("收藏成功") : (item.CollectNum -= 1);
  309. !item.IsCollect && Toast("已取消收藏");
  310. }
  311. };
  312. /* 复制 */
  313. const copyMonitor = () => {
  314. RaiApi.pageHistoryCopy({
  315. DetailId: rerportId.value + "",
  316. PageType: "ArticleCopy",
  317. }).then((res) => {});
  318. };
  319. const waterMark = (text) => {
  320. let canvas = document.createElement("canvas");
  321. let ctx = canvas.getContext("2d");
  322. ctx.font = "20px Arial";
  323. ctx.rotate((-45 * Math.PI) / 200);
  324. ctx.fillStyle = "#DCDCDC";
  325. ctx.fillText(text, 30, 160);
  326. ctx.fillText(text, -40, 80);
  327. // 将canvas的内容转换为base64编码
  328. let data = canvas.toDataURL("image/png");
  329. // 将容器的的背景图片设置为生成的base64图片,并平铺
  330. contentBox.value.style.background = "url(" + data + ") repeat";
  331. };
  332. //点击到提问页面
  333. const quizBtn = () => {
  334. wx.miniProgram.navigateTo({
  335. url: `/${isYanxuan.value ? "pages-activity" : "activityPages"}/generationAsk/generationAsk?id=` + state.reportInfo.ArticleId + "&type=文章",
  336. });
  337. };
  338. // 约访专家
  339. const appointment = (articleId) => {
  340. console.log(articleId);
  341. if (!articleId) {
  342. Toast("ArticleId 值错误");
  343. return;
  344. }
  345. Dialog.confirm({
  346. message: "约访专家的请求会提醒您的对口销售,确定要发起吗?",
  347. messageAlign: "left",
  348. showCancelButton: true,
  349. confirmButtonColor: isYanxuan.value ? "#F1A84A" : "#3385FF",
  350. })
  351. .then(() => {
  352. RaiApi.appointmentExpert({ ArticleId: articleId }).then((res) => {
  353. if (res.Ret === 200 || res.Ret === 403) {
  354. Dialog.confirm({
  355. message: "约访申请已提醒您的对口销售,请等待销售与您联系",
  356. messageAlign: "left",
  357. showConfirmButton: false,
  358. cancelButtonText: "知道了",
  359. })
  360. .then(() => {})
  361. .catch(() => {});
  362. }
  363. });
  364. })
  365. .catch(() => {});
  366. };
  367. /* 获取报告详情 */
  368. const getReport = (id, token, type) => {
  369. if (type == "mpwechat") {
  370. RaiApi.reportDtl({
  371. ArticleId: id,
  372. Authorization: token,
  373. IsSendWx: isSendWx.value,
  374. }).then((res) => {
  375. if (res.Ret === 200) {
  376. haveData.value = res.Data.HasPermission === 1 ? true : false;
  377. if (res.Data.HasPermission === 1) {
  378. //有访问权限
  379. state.reportInfo = res.Data.Detail;
  380. fileLink.value = res.Data.Detail.FileLink;
  381. if (state.reportInfo.IsResearch || state.reportInfo.IsBelongSummary) {
  382. waterMark(res.Data.Mobile);
  383. }
  384. $(document).on("click", "#report-content img", function (event) {
  385. let imgArray = [];
  386. let src_tag = $(this).attr("src");
  387. let parent_tag = $(this).parent();
  388. if (src_tag && !parent_tag.attr("href")) {
  389. $("#report-content img").each(function (index, el) {
  390. let itemSrc = $(this).attr("src");
  391. imgArray.push(itemSrc);
  392. });
  393. wx.previewImage({ current: src_tag, urls: imgArray });
  394. }
  395. });
  396. }
  397. }
  398. });
  399. } else {
  400. RaiApi.lookReport({
  401. ArticleIdMd5: id,
  402. }).then((res) => {
  403. if (res.Ret === 200) {
  404. haveData.value = res.Data.HasPermission === 1 ? true : false;
  405. if (res.Data.HasPermission === 1) {
  406. //有访问权限
  407. state.reportInfo = res.Data.Detail;
  408. $(document).on("click", "#report-content img", function (event) {
  409. let imgArray = [];
  410. let src_tag = $(this).attr("src");
  411. let parent_tag = $(this).parent();
  412. if (src_tag && !parent_tag.attr("href")) {
  413. $("#report-content img").each(function (index, el) {
  414. let itemSrc = $(this).attr("src");
  415. imgArray.push(itemSrc);
  416. });
  417. wx.previewImage({ current: src_tag, urls: imgArray });
  418. }
  419. });
  420. }
  421. }
  422. });
  423. }
  424. };
  425. const lookDeeperReport = () => {
  426. router.push({
  427. path: "/strategyReport",
  428. query: {
  429. url: state.reportInfo.ReportLink,
  430. },
  431. });
  432. };
  433. const pleaseGoLogin = () => {
  434. Dialog.alert({
  435. message: "即将前往登录页面,请确认是否继续",
  436. showCancelButton: true,
  437. confirmButtonColor: "#3385ff",
  438. }).then((res) => {
  439. if (res == "confirm") {
  440. wx.miniProgram.navigateTo({
  441. url: `/${isYanxuan.value ? "pages-user" : "pageMy"}/login/login`,
  442. });
  443. }
  444. });
  445. };
  446. onMounted(() => {
  447. document.title = "报告详情";
  448. if (route.query.id) {
  449. rerportId.value = +route.query.id;
  450. isSendWx.value = route.query.IsSendWx || "";
  451. from_type.value = route.query.fromType;
  452. let access_token = route.query.token || "";
  453. isBinding.value = route.query.isBinding == "true" ? true : false;
  454. isYanxuan.value = route.query.isYanxuan ? true : false;
  455. localStorage.setItem("access_token", access_token);
  456. getReport(rerportId.value, access_token, from_type.value);
  457. userIsShowFreeButton();
  458. if (from_type.value == "mpwechat") {
  459. document.addEventListener("copy", (e) => {
  460. copyMonitor();
  461. });
  462. } else if (from_type.value == "manage") {
  463. router.push({
  464. path: "/cygx/report",
  465. query: {
  466. id: rerportId.value,
  467. },
  468. });
  469. return;
  470. }
  471. researcharticleHotList();
  472. }
  473. });
  474. const { reportInfo, reportResearch } = toRefs(state);
  475. // url: raiReportDtl?id=3001&token=20ec44c7fe0e02ff597c324406ce49ca4b6b838e1988df75bd82084a6c0672fc&fromType=mpwechat
  476. </script>
  477. <style lang="scss">
  478. @import "./index.scss";
  479. .please-login {
  480. margin: 50px auto 150px;
  481. width: 556px;
  482. height: 64px;
  483. color: #fff;
  484. font-size: 24px;
  485. font-weight: 600;
  486. background-color: #376cbb;
  487. display: flex;
  488. align-items: center;
  489. justify-content: center;
  490. border-radius: 9px;
  491. }
  492. </style>