Browse Source

Merge branch 'htgj' of Karsa/raiwechat_link_h5 into master

hongze 2 years ago
parent
commit
ac2b54a889

+ 3 - 1
.env.development

@@ -7,4 +7,6 @@ VITE_APP_HZYB_BASEAPIURL="http://8.136.199.33:8612/api"
 
 
 VITE_APP_HZSL_BASEAPIURL="http://8.136.199.33:8608/api"
 VITE_APP_HZSL_BASEAPIURL="http://8.136.199.33:8608/api"
 
 
-VITE_APP_SSBG_BASEAPIURL="http://8.136.199.33:8607/h5adminapi"
+VITE_APP_HTGJ_BASEAPIURL="http://8.136.199.33:8500/api"
+
+VITE_APP_SSBG_BASEAPIURL="http://8.136.199.33:8607/h5adminapi"

+ 3 - 1
.env.product

@@ -7,4 +7,6 @@ VITE_APP_HZYB_BASEAPIURL="https://yanbao.hzinsights.com/api"
 
 
 VITE_APP_HZSL_BASEAPIURL="https://openapi.hzinsights.com/api"
 VITE_APP_HZSL_BASEAPIURL="https://openapi.hzinsights.com/api"
 
 
-VITE_APP_SSBG_BASEAPIURL="https://ficc.hzinsights.com/h5adminapi"
+VITE_APP_HTGJ_BASEAPIURL="https://cygx.hzinsights.com/api"
+
+VITE_APP_SSBG_BASEAPIURL="https://ficc.hzinsights.com/h5adminapi"

+ 4 - 1
.env.test

@@ -7,4 +7,7 @@ VITE_APP_HZYB_BASEAPIURL="http://8.136.199.33:8612/api"
 
 
 VITE_APP_HZSL_BASEAPIURL="http://8.136.199.33:8608/api"
 VITE_APP_HZSL_BASEAPIURL="http://8.136.199.33:8608/api"
 
 
-VITE_APP_SSBG_BASEAPIURL="https://xcxh5test.hzinsights.com/h5adminapi"
+VITE_APP_HTGJ_BASEAPIURL="http://8.136.199.33:8500/api"
+
+VITE_APP_SSBG_BASEAPIURL="https://xcxh5test.hzinsights.com/h5adminapi"
+

+ 37 - 0
src/api/htgj/api.js

@@ -0,0 +1,37 @@
+import { get, post } from "./http";
+export const report = {
+  /* 获取品种 */
+  Tab: (params) => {
+    return get("permission/allPublic", params);
+  },
+  /* 
+	列表
+	PageSize * CurrentIndex * ChartPermissionId *品类id,最新传0
+	*/
+  getList: (params) => {
+    return get("/home/listPublic", params);
+  },
+  /* 获取搜索推荐词 */
+  getKeys: (params) => {
+    return get("/config/detailPublic", params);
+  },
+  /* 搜索  KeyWord */
+  getResult: (params) => {
+    return get("/search/listPublic", params);
+  },
+};
+/* 权益链接 */
+export const RaiApi = {
+  /* 获取详情 */
+  reportDtl: (params) => {
+    return get("/article/detailPublic", params);
+  },
+  /* 页面复制监听*/
+  pageHistoryCopy: (params) => {
+    return post("/article/pageHistoryPublic", params, 1);
+  },
+  /*上传文章阅读时间接口*/
+  addStopTime: (params) => {
+    return post("/article/addStopTimePublic", params);
+  },
+};

+ 90 - 0
src/api/htgj/http.js

@@ -0,0 +1,90 @@
+"use strict";
+import axios from "axios";
+import { Toast } from "vant";
+import store from "@/store";
+// Full config:  https://github.com/axios/axios#request-config
+// axios.defaults.baseURL = process.env.baseURL || process.env.apiUrl || '';
+// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
+// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
+
+// 请求数
+let LOADINGCOUNT = 0;
+let LOADING;
+let config = {
+  baseURL: import.meta.env.VITE_APP_HTGJ_BASEAPIURL,
+  timeout: 60 * 1000, // Timeout
+  // withCredentials: true, // Check cross-site Access-Control
+};
+
+const _axios = axios.create(config);
+
+_axios.interceptors.request.use(
+  function (config) {
+    // Do something before request is sent
+    // 设置loading
+    if (LOADINGCOUNT === 0) {
+      LOADING = Toast.loading({
+        message: "loading...",
+        duration: 0,
+        forbidClick: true,
+      });
+    }
+    LOADINGCOUNT++;
+    let data = store.state.userData;
+
+    if (config.method == "get") {
+      config.params.CompanyCode = data.CompanyCode;
+      config.params.CompanyName = data.CompanyName;
+      config.params.Email = data.Email;
+      config.params.Sign = data.Sign;
+    } else {
+      config.data.CompanyCode = data.CompanyCode;
+      config.data.CompanyName = data.CompanyName;
+      config.data.Email = data.Email;
+      config.data.Sign = data.Sign;
+    }
+    return config;
+  },
+  function (error) {
+    // Do something with request error
+    return Promise.reject(error);
+  }
+);
+
+// Add a response interceptor
+_axios.interceptors.response.use(
+  function (response) {
+    // Do something with response data
+
+    //关闭loading
+    LOADINGCOUNT--;
+    if (LOADINGCOUNT === 0) {
+      LOADING.clear();
+    }
+
+    return response.data;
+  },
+  function (error) {
+    LOADING.clear();
+    // Do something with response error
+    return Promise.reject(error);
+  }
+);
+
+/**
+ * 导出get请求方法
+ * @url 请求地址
+ * @params get请求参数
+ */
+export const get = (url, params) => {
+  return _axios.get(url, { params });
+};
+
+/**
+ * 导出post请求方法
+ * @url 请求地址
+ * @params post请求参数
+ */
+export const post = (url, params) => {
+  return _axios.post(url, params);
+};

BIN
src/assets/cygx/go_icon.png


BIN
src/assets/cygx/noauth.png


+ 29 - 0
src/router/htgj/index.js

@@ -0,0 +1,29 @@
+export const htgjRoutes=[
+    {
+        path:'/htgj',
+        name:"htgj",
+        component: () => import("@/App.vue"),
+        children:[
+            {
+                path:"index",
+                name:"htgjIndex",
+                component: () => import("@/views/htgj/index.vue"),
+            },
+            {
+                path:"detail",
+                name:"htgjDetail",
+                component: () => import("@/views/htgj/report.vue"),
+            },
+            {
+                path:"strategyDetail",
+                name:"htgjStrategyDetail",
+                component: () => import("@/views/htgj/strategyDetail.vue"),
+            },
+            {
+                path:"search",
+                name:"htgjSearch",
+                component: () => import("@/views/htgj/search.vue"),
+            }
+        ]
+    }
+]

+ 24 - 5
src/router/index.js

@@ -1,14 +1,17 @@
+
 import { createRouter, createWebHistory } from 'vue-router'
 import { createRouter, createWebHistory } from 'vue-router'
 import {hzybRoutes} from './hzyb/index'// 弘则研报小程序路由
 import {hzybRoutes} from './hzyb/index'// 弘则研报小程序路由
 import {cygxRoutes} from './cygx/index'// 查研观向小程序路由
 import {cygxRoutes} from './cygx/index'// 查研观向小程序路由
 import {hzslRoutes} from './hzsl/index'// 弘则思路小程序路由
 import {hzslRoutes} from './hzsl/index'// 弘则思路小程序路由
+import { htgjRoutes } from "./htgj/index"; // 海通国际 APP 路由
 import { ssbgRoutes } from './ssbg';//随手办公
 import { ssbgRoutes } from './ssbg';//随手办公
-
+import store from "@/store";
 
 
 const routes=[
 const routes=[
     ...hzybRoutes,
     ...hzybRoutes,
     ...cygxRoutes,
     ...cygxRoutes,
     ...hzslRoutes,
     ...hzslRoutes,
+    ...htgjRoutes,
     ...ssbgRoutes,
     ...ssbgRoutes,
     //404
     //404
     {
     {
@@ -19,8 +22,24 @@ const routes=[
 ]
 ]
 
 
 const router = createRouter({
 const router = createRouter({
-   history: createWebHistory(import.meta.env.VITE_APP_BASE_URL),
-   routes
-})
+  history: createWebHistory(import.meta.env.VITE_APP_BASE_URL),
+  routes,
+});
+
+router.beforeEach((to, from, next) => {
+  if (to.fullPath.includes("htgj")) {
+    console.log(to.query);
+    let data = {
+      CompanyCode: to.query.CompanyCode, //编码
+      CompanyName: to.query.CompanyName, // 名称
+      Email: to.query.Email, //邮箱
+      Sign: to.query.Sign, //签名
+    };
+    if (!store.state.userData.CompanyCode || !store.state.userData.CompanyName || !store.state.userData.Email || !store.state.userData.Sign) {
+      store.commit("getUserData", data);
+    }
+  }
+  next();
+});
 
 
-export default router
+export default router;

+ 3 - 3
src/views/cygx/dlg.vue

@@ -2,10 +2,10 @@
   <div class="container-dlg" v-if="showTips">
   <div class="container-dlg" v-if="showTips">
     <div class="text">
     <div class="text">
       <h1>免责声明</h1>
       <h1>免责声明</h1>
-      <p v-if="reportInfo.IsResearch">
+      <p >
         本文为用户投稿,用户在平台中发表的所有资料、言论等仅代表个人观点,与本平台立场无关,不对您构成任何投资建议。上海察研对文中陈述、观点判断保持中立,不对所包含内容及数据的真实性、准确性、可靠性或完整性提供任何明示或暗示的保证。请读者仅作参考,并请自行承担全部责任。
         本文为用户投稿,用户在平台中发表的所有资料、言论等仅代表个人观点,与本平台立场无关,不对您构成任何投资建议。上海察研对文中陈述、观点判断保持中立,不对所包含内容及数据的真实性、准确性、可靠性或完整性提供任何明示或暗示的保证。请读者仅作参考,并请自行承担全部责任。
       </p>
       </p>
-      <template v-else>
+      <!-- <template>
         <p>1、本报告仅供弘则弥道(上海)投资咨询有限公司正式签约的机构客户使用,不会仅因接收人/接受机构收到本报告而将其视为客户。</p>
         <p>1、本报告仅供弘则弥道(上海)投资咨询有限公司正式签约的机构客户使用,不会仅因接收人/接受机构收到本报告而将其视为客户。</p>
         <p>
         <p>
           2、本报告根据国际和行业通行的准则,以合法渠道获得这些信息,尽可能保证可靠、准确和完整,但并不保证报告所述信息的准确性和完整性,也不保证本报告所包含的信息或建议在本报告发出后不会发生任何变更。本报告中所提供的信息仅供参考。
           2、本报告根据国际和行业通行的准则,以合法渠道获得这些信息,尽可能保证可靠、准确和完整,但并不保证报告所述信息的准确性和完整性,也不保证本报告所包含的信息或建议在本报告发出后不会发生任何变更。本报告中所提供的信息仅供参考。
@@ -14,7 +14,7 @@
           3、报告中的内容不对投资者做出的最终操作建议做任何的担保,也没有任何形式的分享投资收益或者分担投资损失的书面或口头承诺。不作为客户在投资、法律、会计或税务等方面的最终操作建议,也不作为道义的、责任的和法律的依据或者凭证,无论是否已经明示或者暗示。
           3、报告中的内容不对投资者做出的最终操作建议做任何的担保,也没有任何形式的分享投资收益或者分担投资损失的书面或口头承诺。不作为客户在投资、法律、会计或税务等方面的最终操作建议,也不作为道义的、责任的和法律的依据或者凭证,无论是否已经明示或者暗示。
         </p>
         </p>
         <p>4、在任何情况下,本公司不对客户/接受人/接受机构因使用报告中内容所引致的一切损失负责任,客户/接受人/接受机构需自行承担全部风险。</p>
         <p>4、在任何情况下,本公司不对客户/接受人/接受机构因使用报告中内容所引致的一切损失负责任,客户/接受人/接受机构需自行承担全部风险。</p>
-      </template>
+      </template> -->
       <p class="hide-tips" @click="isHide">知道了</p>
       <p class="hide-tips" @click="isHide">知道了</p>
     </div>
     </div>
   </div>
   </div>

+ 120 - 0
src/views/htgj/index.scss

@@ -0,0 +1,120 @@
+.top-box {
+  padding: 20px 14px 10px;
+  position: sticky;
+  left: 0;
+  top: 0;
+  z-index: 9;
+  background: #fff;
+  .seach {
+    padding: 0 20px;
+  }
+  .seach-top {
+    width: 100%;
+    height: 70px;
+    background: rgba(246, 246, 246, 0.39);
+    border: 1px solid #e5e5e5;
+    border-radius: 35px;
+    display: flex;
+    align-items: center;
+    padding-left: 34px;
+    font-size: 24px;
+    color: #8d8d8d;
+    box-sizing: border-box;
+    .van-icon-search {
+      font-size: 28px;
+      margin-right: 10px;
+    }
+  }
+}
+
+.data-cont {
+  display: flex;
+  margin-top: 15px;
+  padding: 0 10px;
+  .report-ul {
+    width: 50%;
+    &:first-child {
+      margin-right: 10px;
+    }
+    .report-item {
+      padding: 20px 20px 24px 20px;
+      margin-bottom: 20px;
+      border-radius: 8px;
+      box-shadow: 0 3px 6px rgba($color: #000000, $alpha: 0.16);
+      background: #fff;
+      .item-content-img {
+        display: flex;
+        align-items: center;
+        img {
+          width: 100%;
+          height: 232px;
+          vertical-align: middle;
+        }
+      }
+      .item-content {
+        height: 277px;
+        font-size: 24px;
+        line-height: 40px;
+        width: 99%;
+        color: #7f7f7f;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        display: -webkit-box;
+        -webkit-line-clamp: 7;
+        -webkit-box-orient: vertical;
+        img {
+          width: 100% !important;
+        }
+      }
+      .line {
+        margin: 18px 0;
+        content: "";
+        width: 100%;
+        height: 1px;
+        padding: 0 32px;
+        box-sizing: border-box;
+        background-color: #e5e5e5;
+        -webkit-transform: scale(1, 0.5);
+        transform: scale(1, 0.5);
+        -webkit-transform-origin: center bottom;
+        transform-origin: center bottom;
+      }
+      .item-title {
+        font-size: 28px;
+        color: #4a4a4a;
+        margin-bottom: 10px;
+      }
+      .item-abstract {
+        font-size: 26px;
+        color: #6a6a6a;
+        margin-bottom: 10px;
+        word-break:break-all;
+        .report_ico {
+          width: 32px;
+          height: 26px;
+          margin-right: 20px;
+          display: inline-block;
+        }
+      }
+      .item-createtime {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        color: #acacac;
+        font-size: 24px;
+        .item-examine {
+          display: flex;
+          align-items: center;
+          img {
+            width: 30px;
+            height: 24px;
+            margin: 0 10px 0 15px;
+          }
+        }
+      }
+    }
+  }
+}
+.van-tabs__line {
+    background: linear-gradient(268deg, #2ddbff 0%, #1599ff 49%, #005eff 100%);
+  }

+ 186 - 0
src/views/htgj/index.vue

@@ -0,0 +1,186 @@
+<template>
+  <div class="container-htgj-index">
+    <div class="top-box">
+      <topbar showText="查研观向" />
+      <div class="seach" @click="goSearch">
+        <div class="seach-top">
+          <Icon name="search" color="#8D8D8D" />
+          <span>搜索您想要的纪要</span>
+        </div>
+      </div>
+      <div>
+        <Tabs v-model:active="tabActive" title-active-color="#2C83FF" title-inactive-color="#707070" @click-tab="onClickTabs">
+          <Tab v-for="item in tabBars" :key="item.ChartPermissionId" :name="item.ChartPermissionId" :title="item.PermissionName"></Tab>
+          <template #nav-right v-if="tabBars.length">
+            <img class="tabs-img" src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/limit_icon.png" alt="" />
+          </template>
+        </Tabs>
+      </div>
+    </div>
+    <div>
+      <PullRefresh v-model="refreshing" @refresh="onRefresh">
+        <List v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
+          <div class="data-cont">
+            <div class="report-ul">
+              <template v-for="(report, index) in dataList" :key="index">
+                <div class="report-item" v-if="index % 2 === 0" @click="goDetail(report)">
+                  <div class="item-content-img" v-if="report.BodyHtml">
+                    <img :src="report.BodyHtml" mode="" />
+                  </div>
+                  <div class="item-content" v-else>{{ report.Body }}</div>
+                  <div class="line"></div>
+                  <text class="item-title">{{ report.Title }}</text>
+                  <div class="item-abstract text_twoLine" v-if="report.ExpertBackground">
+                    <img src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/fenxi_ico.png" class="report_ico" />
+                    {{ report.ExpertBackground }}
+                  </div>
+                  <div class="item-createtime">
+                    <text>{{ report.PublishDate }}</text>
+                    <div class="item-examine" v-if="report.IsResearch">
+                      <img src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/examine_icon.png" />
+                      <text>{{ report.Pv }}</text>
+                    </div>
+                  </div>
+                </div>
+              </template>
+            </div>
+            <div class="report-ul">
+              <template v-for="(report, index) in dataList" :key="index">
+                <div class="report-item" v-if="index % 2 != 0" @click="goDetail(report)">
+                  <div class="item-content-img" v-if="report.BodyHtml">
+                    <img :src="report.BodyHtml" />
+                  </div>
+                  <div class="item-content" v-else>{{ report.Body }}</div>
+                  <div class="line"></div>
+                  <text class="item-title">{{ report.Title }}</text>
+                  <div class="item-abstract text_twoLine" v-if="report.ExpertBackground">
+                    <img src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/fenxi_ico.png" class="report_ico" />
+                    {{ report.ExpertBackground }}
+                  </div>
+                  <div class="item-createtime">
+                    <text>{{ report.PublishDate }}</text>
+                    <div class="item-examine" v-if="report.IsResearch">
+                      <img src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/examine_icon.png" />
+                      <text>{{ report.Pv }}</text>
+                    </div>
+                  </div>
+                </div>
+              </template>
+            </div>
+          </div>
+        </List>
+      </PullRefresh>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { reactive, onMounted, toRefs, ref } from "vue";
+import { Icon, Tab, Tabs, List, PullRefresh } from "vant";
+import { report } from "@/api/htgj/api.js";
+import { useRoute, useRouter } from "vue-router";
+import topbar from "./topbar.vue";
+const router = useRouter();
+const tabState = reactive({
+  tabActive: 0,
+  tabBars: [],
+});
+/* 获取tab分类 */
+const getTabs = async () => {
+  const res = await report.Tab({});
+  if (res.Ret === 200) {
+    tabState.tabBars = res.Data.List || [];
+  }
+};
+/* tab点击 事件 */
+const onClickTabs = (e) => {
+  listState.finished = false;
+  listState.pageNum = 1;
+  listState.dataList = [];
+  onLoad();
+};
+
+const listState = reactive({
+  pageSize: 30,
+  pageNum: 1,
+  loading: false,
+  finished: false,
+  refreshing: false, //下拉组件
+  dataList: [],
+});
+
+/* 获取列表 */
+const getReportList = async () => {
+  const res = await report.getList({
+    PageSize: listState.pageSize,
+    CurrentIndex: listState.pageNum,
+    ChartPermissionId: tabState.tabActive,
+  });
+  if (res.Ret === 200) {
+    listState.loading = false;
+    listState.refreshing = false;
+    if (res.Data.Paging.IsEnd) {
+      listState.finished = true;
+    }
+    if (res.Data.List) {
+      listState.dataList = listState.dataList.concat(res.Data.List);
+    }
+  }
+};
+
+/* 下拉刷新 */
+const onRefresh = async () => {
+  listState.finished = false;
+  listState.pageNum = 1;
+  listState.dataList = [];
+  onLoad();
+};
+
+//触底加载
+const onLoad = () => {
+  getReportList();
+  listState.pageNum++;
+};
+
+/* 去往详情 */
+const goDetail = (item) => {
+  if (item.IsNeedJump) {
+    router.push({
+      path: "/htgj/strategyDetail",
+      query: {
+        id: item.ArticleId,
+      },
+    });
+  } else {
+    router.push({
+      path: "/htgj/detail",
+      query: {
+        id: item.ArticleId,
+      },
+    });
+  }
+};
+
+/* 去往搜索 */
+const goSearch = () => {
+  router.push("/htgj/search");
+};
+
+getTabs();
+
+const { tabActive, tabBars } = toRefs(tabState);
+const { dataList, refreshing, loading, finished } = toRefs(listState);
+</script>
+
+<style lang="scss">
+.container-htgj-index {
+  background: #f7f7f7;
+  @import "./index.scss";
+  .tabs-img {
+    padding-top: 16px;
+    margin-left: -15px;
+    width: 46px;
+    height: 26px;
+  }
+}
+</style>

+ 404 - 0
src/views/htgj/report.vue

@@ -0,0 +1,404 @@
+<template>
+  <div class="container-cygx" @copy="copyMonitor" v-if="haveData == 1" :class="reportInfo.IsResearch ? 'no-cv' : ''">
+    <canvas id="tutorial" ref="tutorial"></canvas>
+   <topbar class="top-box-bar" showText="弘则研究" />
+    <div class="search">
+      <div class="search-box" @click="btnSearch">
+        <Icon name="search" color="#8D8D8D" />
+        <span>搜索您想要的纪要</span>
+      </div>
+    </div>
+    <div class="z-index-content">
+      <div class="content-top">
+        <div class="report-title">{{ reportInfo.Title }}</div>
+        <div class="report-text">
+          <div class="report_desc">
+            <span class="author">{{ reportInfo.Department }}</span>
+            <span>{{ reportInfo.PublishDate }}</span>
+          </div>
+          <div class="seller-list" v-if="!reportInfo.IsResearch">
+            <span>联系人:</span>
+            <span v-for="(item, index) in reportInfo.SellerList" :key="index"> {{ item.SellerName }}({{ item.SellerMobile }})&nbsp;&nbsp; </span>
+          </div>
+          <div class="seller-list" v-else>
+            <span>作者:{{ reportInfo.SellerAndMobile }} </span>
+          </div>
+          <div>注:请务必阅读<span class="tip" @click="showTips = true"> &nbsp;免责声明</span></div>
+          <div class="container-abstract">&nbsp;&nbsp;摘要:&nbsp;{{ reportInfo.Abstract }}</div>
+        </div>
+      </div>
+      <div class="detail-report">
+        <div id="report-content" v-html="reportInfo.Body"></div>
+      </div>
+    </div>
+    <div class="btn-returntop">
+      <img src="~@/assets/cygx/returntop.png" @click="scrolltop" style="width: 40px" />
+    </div>
+    <dlg :showTips="showTips" :reportInfo="reportInfo" @hideDlg="showTips = false" />
+  </div>
+  <div v-else class="nodata">
+    <img src="@/assets/cygx/noauth.png" mode="" class="nodata_ico" />
+    <div v-if="haveData == 2">
+      <p>您暂无权限查看报告</p>
+      <p>若想查看可联系销售开通试用权限</p>
+    </div>
+    <div v-else>
+      <p>您的试用权限已到期</p>
+      <p>若想继续试用,请联系销售</p>
+    </div>
+  </div>
+  <topbar v-if="haveData != 1" class="top-haveData-bar" showText="弘则研究" />
+</template>
+
+<script setup>
+import { reactive, onMounted, toRefs, ref, onUnmounted } from "vue";
+import { useRouter, useRoute } from "vue-router";
+import { RaiApi } from "@/api/htgj/api.js";
+import { Icon, Dialog, Toast } from "vant";
+import dlg from "../cygx/dlg.vue";
+import store from "@/store";
+import topbar from "./topbar.vue";
+const router = useRouter();
+const route = useRoute();
+const state = reactive({
+  reportInfo: {},
+});
+const rerportId = ref(null);
+const haveData = ref(1);
+const fileLink = ref(false);
+const showTips = ref(false);
+const tutorial = ref(null);
+/* 访谈接口 */
+const interviewApi = () => {
+  RaiApi.applyRpt({
+    ArticleId: Number(rerportId.value),
+  }).then((res) => {
+    if (res.Ret === 200) {
+      state.reportInfo.IsInterviewApply = !state.reportInfo.IsInterviewApply;
+      state.reportInfo.InterviewApplyStatus = state.reportInfo.IsInterviewApply ? "待邀请" : "";
+      Toast(res.Msg);
+    }
+  });
+};
+
+const scrolltop = () => {
+  document.body.scrollTop = document.documentElement.scrollTop = 0;
+};
+
+/* 复制 */
+const copyMonitor = () => {
+  RaiApi.pageHistoryCopy({
+    DetailId: rerportId.value + "",
+  }).then((res) => {});
+};
+
+/* 打水印 */
+const waterMark = (text) => {
+  let canvas = document.createElement("canvas");
+  let ctx = canvas.getContext("2d");
+  ctx.font = "20px Arial";
+  ctx.rotate((-45 * Math.PI) / 200);
+  ctx.fillText(text, 30, 200);
+  ctx.fillText(text, -40, 100);
+
+  // 将canvas的内容转换为base64编码
+  let data = canvas.toDataURL("image/png");
+
+  // 将容器的的背景图片设置为生成的base64图片,并平铺
+  tutorial.value.style.background = "url(" + data + ") repeat";
+};
+
+//点击回到搜索页面
+const btnSearch = () => {
+  router.push("/htgj/search");
+};
+
+const timeState = reactive({
+  setIntervalTiem: null,
+  readTiem: 0,
+});
+
+/* 获取报告详情 */
+const getReport = (id) => {
+  RaiApi.reportDtl({
+    ArticleId: id,
+  }).then((res) => {
+    if (res.Ret === 200) {
+      haveData.value = res.Data.HasPermission;
+      if (res.Data.HasPermission === 1) {
+        //有访问权限
+        state.reportInfo = res.Data.Detail;
+        fileLink.value = res.Data.Detail.FileLink;
+        if (state.reportInfo.IsResearch || state.reportInfo.IsBelongSummary) {
+          waterMark( res.Data.CompanyName);
+        }
+        $(document).on("click", "#report-content img", function (event) {
+          let imgArray = [];
+          let src_tag = $(this).attr("src");
+          let parent_tag = $(this).parent();
+          if (src_tag && !parent_tag.attr("href")) {
+            $("#report-content img").each(function (index, el) {
+              let itemSrc = $(this).attr("src");
+              imgArray.push(itemSrc);
+            });
+            wx.previewImage({ current: src_tag, urls: imgArray });
+          }
+        });
+        timeState.readTiem = 0;
+        timeState.setIntervalTiem = setInterval(() => {
+          timeState.readTiem++;
+        }, 1000);
+      }
+    }
+  });
+};
+onMounted(() => {
+  if (route.query.id) {
+    rerportId.value = route.query.id;
+    getReport(rerportId.value);
+  }
+});
+onUnmounted(() => {
+  clearInterval(timeState.setIntervalTiem);
+  if (!rerportId.value || haveData.value !== 1) return;
+  RaiApi.addStopTime({
+    ArticleId: Number(rerportId.value),
+    StopTime: timeState.readTiem,
+    OutType: 1,
+    Source: "PC",
+  }).then((res) => {});
+});
+const { reportInfo } = toRefs(state);
+</script>
+
+<style lang="scss">
+.container-cygx {
+  padding: 54px 34px 34px 34px;
+  position: relative;
+  z-index: 5;
+  .z-index-content {
+    position: relative;
+    z-index: 5;
+  }
+  .top-box-bar {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 60px;
+    background-color: #fff;
+    margin: 0;
+    padding-top: 20px;
+    z-index: 10;
+    img {
+      margin-top: 10px;
+    }
+}
+  .search {
+    width: 100%;
+    padding: 20px 20px;
+    line-height: 70px;
+    position: fixed;
+    top: 60px;
+    left: 0;
+    background: #fff;
+    z-index: 9;
+    .search-box {
+      display: flex;
+      align-items: center;
+      padding-left: 20px;
+      width: 100%;
+      height: 70px;
+      border-radius: 35px;
+      background: #f6f6f6;
+      color: #8d8d8d;
+      font-size: 24px;
+    }
+  }
+  .content-top {
+    margin-top: 115px;
+    .report-title {
+      font-size: 34px;
+      font-weight: bold;
+      color: #4a4a4a;
+      margin: 60px 0 20px;
+    }
+    .report-text {
+      color: #999999;
+      font-size: 28px;
+      .seller-list {
+        margin: 20px 0;
+      }
+      .report_desc {
+        display: flex;
+        justify-content: space-between;
+      }
+      .tip {
+        color: #3385ff;
+      }
+      .container-abstract {
+        margin: 40px 0 20px;
+        padding-bottom: 40px;
+        border-bottom: 2px dashed #999;
+        position: relative;
+        line-height: 44px;
+        color: #333;
+        &::before {
+          content: "";
+          position: absolute;
+          top: 0;
+          left: 0;
+          width: 8px;
+          height: 44px;
+          background: #2a65f5;
+        }
+      }
+    }
+  }
+  .report-link {
+    font-size: 28px;
+    line-height: 80px;
+  }
+  .detail-report {
+    padding-bottom: 130px;
+    p,
+    span {
+      font-size: 28px !important;
+    }
+    img {
+      width: 100% !important;
+    }
+    a {
+      color: #333;
+    }
+    table {
+      border-collapse: collapse;
+      width: 100% !important;
+      margin-left: 0 !important;
+    }
+    tr td,
+    th {
+      border: 1px solid #333;
+    }
+  }
+  pre {
+    width: 100%;
+    overflow-y: auto;
+    overflow-x: hidden;
+    outline: none;
+    border: 0;
+    white-space: pre-wrap;
+    word-break: normal;
+  }
+  .btn-returntop {
+    position: fixed;
+    right: 40px;
+    bottom: 150px;
+    width: 88px;
+    height: 88px;
+    z-index: 10;
+  }
+  .fixed_cont {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    display: flex;
+    justify-content: space-around;
+    border-top: 1px solid #ddd;
+    padding-bottom: calc(5px + constant(safe-area-inset-bottom));
+    padding-bottom: calc(5px + env(safe-area-inset-bottom));
+    background-color: #fff;
+    z-index: 9;
+    box-sizing: border-box;
+    .handle-item {
+      padding-top: 14px;
+      text-align: center;
+      line-height: 33px;
+      font-size: 20px;
+      color: #888888;
+
+      img {
+        width: 44px;
+        height: 44px;
+        padding: 0;
+        margin: 0;
+      }
+      div {
+        padding: 0;
+        margin: 0;
+      }
+    }
+  }
+}
+.nodata {
+  width: 100%;
+  margin: 30% auto;
+  text-align: center;
+  img {
+    width: 50%;
+    margin-bottom: 30px;
+  }
+  p {
+    margin-top: 20px;
+  }
+}
+.no-cv {
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+.top-box-bar {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 40px;
+    background-color: #fff;
+    margin-top: 15px;
+    z-index: 10;
+}
+#tutorial {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1;
+  width: 100%;
+  height: 100%;
+  opacity: 0.1;
+  // transform: translateX(130px) rotate(-38deg);
+}
+.van-dialog--round-button .van-dialog__footer {
+  border-top: 1px solid rgba(0, 0, 0, 0.1) !important;
+  padding: 0 !important;
+  .van-button--warning {
+    color: #333 !important;
+    border-right: 1px solid rgba(0, 0, 0, 0.1) !important;
+  }
+  .van-button--danger {
+    color: #3385ff !important;
+  }
+  .van-button--warning,
+  .van-button--danger {
+    height: 80px !important;
+    border-radius: 0 !important;
+  }
+  .van-goods-action-button--first {
+    border-right: 1px solid rgba(0, 0, 0, 0.1) !important;
+  }
+}
+.van-icon-search {
+  font-size: 28px;
+  margin-right: 10px;
+}
+.top-haveData-bar {
+  position: absolute !important;
+  width: 100%;
+  margin-top: 20px;
+  top: 0;
+  left: 0;
+  z-index: 9;
+}
+</style>

+ 301 - 0
src/views/htgj/search.vue

@@ -0,0 +1,301 @@
+<template>
+  <div class="container-htgj-search" :class="isResult ? 'bg-content' : ''">
+    <div :class="isResult ? 'top-box' : ''">
+      <topbar class="top-box-bar" showText="搜索" />
+      <Search v-model="searchTxt" shape="round" clearable placeholder="请输入关键词" @clear="clearIpt" @search="searchHandle">
+        <template #right-icon>
+          <div class="search-p" @click="searchHandle"><span></span>搜索</div>
+        </template>
+      </Search>
+      <template v-if="isResult">
+        <Tabs v-model:active="orderColumn" title-active-color="#2C83FF" title-inactive-color="#707070" @click-tab="onClickTabs" line-width="85">
+          <Tab v-for="item in tabBars" :key="item.ChartPermissionId" :name="item.ChartPermissionId" :title="item.PermissionName"></Tab>
+        </Tabs>
+      </template>
+    </div>
+    <div class="search-cont">
+      <template v-if="!isResult">
+        <div class="search-cont-top" v-if="historySearchList.length">
+          <div class="cont-tit">
+            <p>搜索历史</p>
+            <img src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/empty_ico.png" class="empty_ico" @click="clearHistory" />
+          </div>
+          <div class="targetList">
+            <div class="target-item" v-for="(item, index) in historySearchList" :key="index" @click="chooseTarget(item)">{{ item }}</div>
+          </div>
+        </div>
+        <div class="search-cont-top">
+          <div class="cont-tit">
+            <p>弘则推荐</p>
+          </div>
+          <div class="targetList">
+            <div class="target-item" v-for="(item, index) in keywordList" :key="index" @click="chooseTarget(item)">{{ item }}</div>
+          </div>
+        </div>
+      </template>
+      <template v-else>
+        <PullRefresh v-model="refreshing" @refresh="onRefresh" v-if="haveResult">
+          <div class="data-cont">
+            <div class="report-ul">
+              <template v-for="(report, index) in resultList" :key="index">
+                <div class="report-item" v-if="index % 2 === 0" @click="goDetail(report)">
+                  <div class="item-content-img" v-if="report.BodyHtml">
+                    <img :src="report.BodyHtml" mode="" />
+                  </div>
+                  <div class="item-content" v-else v-html="report.Body"></div>
+                  <div class="line"></div>
+                  <text class="item-title" v-html="report.Title"></text>
+                  <div class="item-abstract text_twoLine" v-if="report.ExpertBackground">
+                    <img src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/fenxi_ico.png" class="report_ico" />
+                    {{ report.ExpertBackground }}
+                  </div>
+                  <div class="item-createtime">
+                    <text>{{ report.PublishDate }}</text>
+                    <div class="item-examine" v-if="report.IsResearch">
+                      <img src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/examine_icon.png" />
+                      <text>{{ report.Pv }}</text>
+                    </div>
+                  </div>
+                </div>
+              </template>
+            </div>
+            <div class="report-ul">
+              <template v-for="(report, index) in resultList" :key="index">
+                <div class="report-item" v-if="index % 2 != 0" @click="goDetail(report)">
+                  <div class="item-content-img" v-if="report.BodyHtml">
+                    <img :src="report.BodyHtml" />
+                  </div>
+                  <div class="item-content" v-else v-html="report.Body"></div>
+                  <div class="line"></div>
+                  <text class="item-title" v-html="report.Title"></text>
+                  <div class="item-abstract text_twoLine" v-if="report.ExpertBackground">
+                    <img src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/fenxi_ico.png" class="report_ico" />
+                    {{ report.ExpertBackground }}
+                  </div>
+                  <div class="item-createtime">
+                    <text>{{ report.PublishDate }}</text>
+                    <div class="item-examine" v-if="report.IsResearch">
+                      <img src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/czbk/examine_icon.png" />
+                      <text>{{ report.Pv }}</text>
+                    </div>
+                  </div>
+                </div>
+              </template>
+            </div>
+          </div>
+          <div class="finished-text" v-if="resultList.length">没有更多了</div>
+        </PullRefresh>
+        <div class="nodata" v-else>
+          <img src="@/assets/cygx/noauth.png" mode="" class="nodata_ico" />
+          <p>未找到您想搜索的内容</p>
+        </div>
+      </template>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { reactive, onMounted, toRefs, ref, watch } from "vue";
+import { Search, Toast, Tab, Tabs, PullRefresh } from "vant";
+import { report } from "@/api/htgj/api.js";
+import { useRoute, useRouter } from "vue-router";
+import topbar from "./topbar.vue";
+const router = useRouter();
+const searchState = reactive({
+  searchTxt: "", //搜索关键字
+  isResult: false, //显示搜索结果
+  haveResult: true, //是否有搜索数据
+  // 历史搜索列表
+  historySearchList: [],
+  // 关键字列表
+  keywordList: [],
+  targetList: [], //所有指标列表
+});
+/* 获取关键词 */
+const getKeyWord = async () => {
+  const res = await report.getKeys({});
+  if (res.Ret === 200) {
+    searchState.keywordList = res.Data.Item.ConfigValue ? res.Data.Item.ConfigValue.split(",") : [];
+  }
+};
+// 选择历史搜索 和推荐
+const chooseTarget = (item) => {
+  searchState.searchTxt = item;
+  getDataList();
+};
+
+const searchHandle = () => {
+  if (searchState.searchTxt) {
+    //添加搜索记录
+    if (!searchState.historySearchList.includes(searchState.searchTxt)) {
+      searchState.historySearchList.unshift(searchState.searchTxt);
+      localStorage.setItem("historySearchList", JSON.stringify(searchState.historySearchList));
+      dataState.resultList = [];
+      getDataList();
+    }
+  } else {
+    Toast("请输入关键字");
+  }
+};
+/* 表单清空 */
+const clearIpt = () => {
+  dataState.resultList = [];
+  dataState.orderColumn = "Matching";
+};
+/* 历史搜索清空 */
+const clearHistory = () => {
+  searchState.historySearchList = [];
+  localStorage.removeItem("historySearchList");
+};
+
+getKeyWord();
+const dataState = reactive({
+  resultList: [],
+  orderColumn: "Matching",
+  refreshing: false,
+  tabBars: [
+    {
+      PermissionName: "匹配度排序",
+      ChartPermissionId: "Matching",
+    },
+    {
+      PermissionName: "综合排序",
+      ChartPermissionId: "Comprehensive",
+    },
+    {
+      PermissionName: "发布时间排序",
+      ChartPermissionId: "PublishDate",
+    },
+  ],
+});
+
+// 查找数据
+const getDataList = async () => {
+  searchState.isResult = true;
+  const res = await report.getResult({
+    KeyWord: searchState.searchTxt,
+    OrderColumn: dataState.orderColumn,
+  });
+  if (res.Ret === 200) {
+    dataState.refreshing = false;
+    dataState.resultList = res.Data.List || [];
+    searchState.haveResult = dataState.resultList.length ? true : false;
+  }
+};
+
+/* 下拉刷新 */
+const onRefresh = async () => {
+  dataState.resultList = [];
+  getDataList();
+};
+
+/* tab点击 事件 */
+const onClickTabs = () => {
+  dataState.resultList = [];
+  getDataList();
+};
+
+/* 去往详情 */
+const goDetail = (item) => {
+  if (item.IsNeedJump) {
+    router.push({
+      path: "/htgj/strategyDetail",
+      query: {
+        id: item.ArticleId,
+      },
+    });
+  } else {
+    router.push({
+      path: "/htgj/detail",
+      query: {
+        id: item.ArticleId,
+      },
+    });
+  }
+};
+
+watch(
+  () => searchState.searchTxt,
+  (newValue) => {
+    if (newValue.length <= 0) {
+      searchState.isResult = false;
+    }
+  }
+);
+onMounted(() => {
+  // 获取历史搜索记录
+  if (localStorage.getItem("historySearchList")) {
+    let historyList = JSON.parse(localStorage.getItem("historySearchList"));
+    searchState.historySearchList = historyList;
+  }
+});
+const { searchTxt, isResult, haveResult, historySearchList, keywordList, targetList } = toRefs(searchState);
+const { resultList, tabBars, orderColumn, refreshing } = toRefs(dataState);
+</script>
+
+<style lang="scss">
+.container-htgj-search {
+  .top-box-bar {
+    margin: 15px 0 0 0;
+  }
+  @import "./index.scss";
+  .search-p {
+    display: flex;
+    align-items: center;
+    color: #3385ff;
+    span {
+      width: 0px;
+      height: 17px;
+      border: 1px solid #e0e0e0;
+      opacity: 1;
+      margin-right: 10px;
+    }
+  }
+  .search-cont-top {
+    padding: 0 34px 0;
+    margin-bottom: 10px;
+    padding-top: 20px;
+    &:last-child {
+      margin-bottom: 0;
+    }
+    .cont-tit {
+      color: #666;
+      font-size: 28px;
+      margin-bottom: 30px;
+      display: flex;
+      justify-content: space-between;
+      .empty_ico {
+        width: 32px;
+        height: 33px;
+      }
+    }
+    .targetList {
+      display: flex;
+      flex-wrap: wrap;
+      // justify-content: space-between;
+      .target-item {
+        padding: 4px 18px;
+        color: #4a4a4a;
+        font-size: 26px;
+        // border: 1px solid #3385ff;
+        background-color: #f7f7f7;
+        margin-bottom: 30px;
+        margin-right: 30px;
+        border-radius: 20px;
+      }
+    }
+  }
+  .finished-text {
+    width: 100%;
+    text-align: center;
+    padding: 30px;
+    color: #666;
+  }
+  .top-box {
+    padding: 0 0 10px !important;
+  }
+}
+.bg-content {
+  background: #f7f7f7 !important;
+}
+</style>

+ 196 - 0
src/views/htgj/strategyDetail.vue

@@ -0,0 +1,196 @@
+<script setup>
+import { reactive, onMounted, toRefs, ref, onUnmounted } from "vue";
+import { useRouter, useRoute } from "vue-router";
+import { RaiApi } from "@/api/htgj/api.js";
+import { Icon, Dialog, Toast } from "vant";
+import dlg from "../cygx/dlg.vue";
+import store from "@/store";
+import topbar from "./topbar.vue";
+const router = useRouter();
+const route = useRoute();
+const state = reactive({
+  reportInfo: {},
+});
+const rerportId = ref(null);
+const haveData = ref(1);
+const showTips = ref(false);
+
+//点击回到搜索页面
+const btnSearch = () => {
+  router.push("/htgj/search");
+};
+
+const timeState = reactive({
+  setIntervalTiem: null,
+  readTiem: 0,
+});
+
+/* 获取报告详情 */
+const getReport = (id) => {
+  RaiApi.reportDtl({
+    ArticleId: id,
+  }).then((res) => {
+    if (res.Ret === 200) {
+      haveData.value = res.Data.HasPermission;
+      if (res.Data.HasPermission === 1) {
+        //有访问权限
+        state.reportInfo = res.Data.Detail;
+        timeState.readTiem = 0;
+        timeState.setIntervalTiem = setInterval(() => {
+          timeState.readTiem++;
+        }, 1000);
+      }
+    }
+  });
+};
+onMounted(() => {
+  if (route.query.id) {
+    rerportId.value = route.query.id;
+    getReport(rerportId.value);
+  }
+});
+onUnmounted(() => {
+  clearInterval(timeState.setIntervalTiem);
+  if (!rerportId.value || haveData.value !== 1) return;
+  RaiApi.addStopTime({
+    ArticleId: Number(rerportId.value),
+    StopTime: timeState.readTiem,
+    OutType: 1,
+    Source: "PC",
+  }).then((res) => {});
+});
+const { reportInfo } = toRefs(state);
+</script>
+
+<template>
+  <div class="container-cygx-strategy" @copy="copyMonitor" v-if="haveData == 1" :class="reportInfo.IsResearch ? 'no-cv' : ''">
+    <topbar class="top-box-bar" showText="弘则研究" />
+    <div class="search">
+      <div class="search-box" @click="btnSearch">
+        <Icon name="search" color="#8D8D8D" />
+        <span>搜索您想要的纪要</span>
+      </div>
+    </div>
+    <iframe class="details-iframe" :src="reportInfo.HttpUrl" frameborder="0" />
+    <dlg :showTips="showTips" :reportInfo="reportInfo" @hideDlg="showTips = false" />
+  </div>
+  <div v-else class="nodata">
+    <img src="@/assets/cygx/noauth.png" mode="" class="nodata_ico" />
+    <div v-if="haveData == 2">
+      <p>您暂无权限查看报告</p>
+      <p>若想查看可联系销售开通试用权限</p>
+    </div>
+    <div v-else>
+      <p>您的试用权限已到期</p>
+      <p>若想继续试用,请联系销售</p>
+    </div>
+  </div>
+  <topbar v-if="haveData != 1" class="top-haveData-bar" showText="弘则研究" />
+</template>
+
+<style lang="scss">
+.container-cygx-strategy {
+  padding: 54px 34px 34px 34px;
+  position: relative;
+  z-index: 5;
+  .top-box-bar {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 60px;
+    background-color: #fff;
+    margin: 0;
+    padding-top: 20px;
+    z-index: 10;
+    img {
+      margin-top: 10px;
+    }
+  }
+  .search {
+    width: 100%;
+    padding: 20px 20px;
+    line-height: 70px;
+    position: fixed;
+    top: 60px;
+    left: 0;
+    background: #fff;
+    z-index: 9;
+    .search-box {
+      display: flex;
+      align-items: center;
+      padding-left: 20px;
+      width: 100%;
+      height: 70px;
+      border-radius: 35px;
+      background: #f6f6f6;
+      color: #8d8d8d;
+      font-size: 24px;
+    }
+  }
+  .details-iframe {
+    width: 100%;
+    height: calc(100vh - 100px);
+  }
+}
+.nodata {
+  width: 100%;
+  margin: 30% auto;
+  text-align: center;
+  img {
+    width: 50%;
+    margin-bottom: 30px;
+  }
+  p {
+    margin-top: 20px;
+  }
+}
+.no-cv {
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+.top-box-bar {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 40px;
+  background-color: #fff;
+  margin-top: 15px;
+  z-index: 10;
+}
+.van-dialog--round-button .van-dialog__footer {
+  border-top: 1px solid rgba(0, 0, 0, 0.1) !important;
+  padding: 0 !important;
+  .van-button--warning {
+    color: #333 !important;
+    border-right: 1px solid rgba(0, 0, 0, 0.1) !important;
+  }
+  .van-button--danger {
+    color: #3385ff !important;
+  }
+  .van-button--warning,
+  .van-button--danger {
+    height: 80px !important;
+    border-radius: 0 !important;
+  }
+  .van-goods-action-button--first {
+    border-right: 1px solid rgba(0, 0, 0, 0.1) !important;
+  }
+}
+.van-icon-search {
+  font-size: 28px;
+  margin-right: 10px;
+}
+.top-haveData-bar {
+  position: absolute !important;
+  width: 100%;
+  margin-top: 20px;
+  top: 0;
+  left: 0;
+  z-index: 9;
+}
+</style>

+ 34 - 0
src/views/htgj/topbar.vue

@@ -0,0 +1,34 @@
+<template>
+  <div class="container-top">
+    <img v-if="showText !== '查研观向'" src="~@/assets/cygx/go_icon.png" @click="router.back()" />
+    <span>{{ showText }}</span>
+  </div>
+</template>
+
+<script setup>
+import { useRouter } from "vue-router";
+const router = useRouter();
+const props = defineProps({
+  showText: {
+    type: String,
+    required: true,
+    default: false,
+  },
+});
+</script>
+
+<style lang="scss" scoped>
+.container-top {
+  position: relative;
+  align-items: center;
+  text-align: center;
+  margin-bottom: 15px;
+  img {
+    position: absolute;
+    top: 50%;
+    left: 60px;
+    width: 40px;
+    transform: translate(-50%, -50%);
+  }
+}
+</style>