|
@@ -1,12 +1,426 @@
|
|
|
<script setup>
|
|
|
+
|
|
|
+import subMenuBox from "./components/subMenuBox.vue"
|
|
|
+import menuBox from "./components/menubox.vue"
|
|
|
+import {apiGetHelpDocClassify,apiGetHelpDocDetail} from "@/api/helpApi.js"
|
|
|
+import {ref,nextTick,onMounted,onUnmounted } from 'vue'
|
|
|
+import {useRoute} from 'vue-router'
|
|
|
+const route = useRoute()
|
|
|
+
|
|
|
+const documentData=ref([])
|
|
|
+// const anchorData=ref([])
|
|
|
+const currentNodeKey=ref('')
|
|
|
+const defaultActiveId=ref(0)
|
|
|
+const isRightFold=ref(false)
|
|
|
+const helpDocument=ref({})
|
|
|
+const Content=ref('')
|
|
|
+let isFirstLoad=true
|
|
|
+
|
|
|
+let videoList=[]
|
|
|
+
|
|
|
+const businessCode = route.query.bus_code || ''
|
|
|
+
|
|
|
+const treeProp={
|
|
|
+ label:'text',
|
|
|
+ children: 'Child'
|
|
|
+}
|
|
|
+
|
|
|
+const getDocumentData=()=>{
|
|
|
+ apiGetHelpDocClassify({bus_code:businessCode}).then(res=>{
|
|
|
+ if(res.code == 200){
|
|
|
+ documentData.value=res.data || []
|
|
|
+ getFirstId(documentData.value[0])
|
|
|
+ getDocument(defaultActiveId.value)
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+// 获取第一个分类
|
|
|
+const getFirstId=(item)=>{
|
|
|
+ if(item.Children && item.Children.length>0){
|
|
|
+ getFirstId(item.Children[0])
|
|
|
+ }else{
|
|
|
+ defaultActiveId.value = item.ClassifyId
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const menuChange=(data,node)=>{
|
|
|
+ currentNodeKey.value = data.AnchorId
|
|
|
+}
|
|
|
+const getDocument=(id)=>{
|
|
|
+ apiGetHelpDocDetail({bus_code:businessCode,classify_id:id}).then(res=>{
|
|
|
+ if(res.code == 200){
|
|
|
+ helpDocument.value=res.data || {}
|
|
|
+ Content.value = helpDocument.value.Content + createBottomHref(helpDocument.value.Recommend)
|
|
|
+ if(!(helpDocument.value.Anchor && helpDocument.value.Anchor.length>0)) isRightFold.value=true
|
|
|
+ isRightFold.value=false
|
|
|
+ nextTick(()=>{
|
|
|
+ getScrollTopList(helpDocument.value.Anchor || [])
|
|
|
+ videoList=document.getElementsByTagName('video') || []
|
|
|
+ if(videoList && videoList.length>0){
|
|
|
+ for (let i = 0; i < videoList.length; i++) {
|
|
|
+ const element = videoList[i];
|
|
|
+ element.addEventListener('play',setVideosStatus(i))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ window.scrollTo(0, document.getElementById('operation-document-body').offsetTop)
|
|
|
+ }else if(res.code == 4001){
|
|
|
+ helpDocument.value={}
|
|
|
+ isRightFold.value=true
|
|
|
+ }
|
|
|
+ if(isFirstLoad){
|
|
|
+ isFirstLoad=false
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const setVideosStatus=(i)=>{
|
|
|
+ return ()=>{
|
|
|
+ // 暂停其他播放的视频,只能播放一个
|
|
|
+ for (let j = 0; j < videoList.length; j++) {
|
|
|
+ if(j==i) continue;
|
|
|
+ if(!videoList[j].paused){
|
|
|
+ videoList[j].pause()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 生成底部的两个链接
|
|
|
+const createBottomHref=(RecommendData)=>{
|
|
|
+ if(!(RecommendData && RecommendData.length>0)) return ''
|
|
|
+
|
|
|
+ let hrefStringBuiler='<ul style="margin-top:40px">'
|
|
|
+ RecommendData.map(item =>{
|
|
|
+ if(item.Name){
|
|
|
+ hrefStringBuiler+=`<li><a href="${item.Url}" target="_blank" style="text-decoration: underline;">${item.Name}</a></li>`
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return hrefStringBuiler+"</ul>"
|
|
|
+}
|
|
|
+
|
|
|
+getDocumentData()
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+const headerHeight = ref(0)
|
|
|
+const scrollTopList=ref([])
|
|
|
+const stop=ref(false)
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ document.addEventListener('scroll',scrollChange)
|
|
|
+ headerHeight.value=document.getElementById("operation-document-body").offsetTop
|
|
|
+})
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ document.removeEventListener('scroll',scrollChange)
|
|
|
+
|
|
|
+ if(videoList && videoList.length>0){
|
|
|
+ for (let i = 0; i < videoList.length; i++) {
|
|
|
+ const element = videoList[i];
|
|
|
+ element.removeEventListener('play',setVideosStatus(i))
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const getScrollTopList=(list)=>{
|
|
|
+ list.map(item =>{
|
|
|
+ scrollTopList.value.push({key:item.AnchorId,clientRectTop:document.getElementById(item.Anchor).offsetTop+headerHeight.value})
|
|
|
+ if(item.Child && item.Child.length>0) getScrollTopList(item.Child || [])
|
|
|
+ })
|
|
|
+}
|
|
|
+const navigate = (e,id)=>{
|
|
|
+ // 阻止滚动监听,防止右侧节点的定位 被滚动监听干扰
|
|
|
+ stop.value=true
|
|
|
+ e.preventDefault();
|
|
|
+ document.querySelector(id).scrollIntoView(true)
|
|
|
+ nextTick(()=>{
|
|
|
+ // 放开滚动监听
|
|
|
+ stop.value=false
|
|
|
+ })
|
|
|
+}
|
|
|
+const scrollChange=()=>{
|
|
|
+ if(stop.value) return
|
|
|
+ let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
|
|
|
+
|
|
|
+ let hashit=false
|
|
|
+ for (let i = scrollTopList.value.length ; i > 0; i--) {
|
|
|
+ const element = scrollTopList.value[i-1];
|
|
|
+ if(scrollTop - element.clientRectTop>-5){
|
|
|
+ hashit=true
|
|
|
+ currentNodeKey.value = element.key
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(!hashit){
|
|
|
+ currentNodeKey.value=''
|
|
|
+ }
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <div>
|
|
|
- help
|
|
|
+ <div class="operation-document-container" id="operation-document-container">
|
|
|
+ <div class="operation-document-neck">
|
|
|
+ <div class="banner-image">
|
|
|
+ <img src="@/assets/img//help/data.png">
|
|
|
+ <div class="banner-text">
|
|
|
+ <div class="text">数据源</div>
|
|
|
+ <div class="text">数据录入、更新</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <img src="@/assets/img/icon/line-arrow-blue.png" class="banner-line">
|
|
|
+ <div class="banner-image">
|
|
|
+ <img src="@/assets/img/help/database.png">
|
|
|
+ <div class="banner-text">
|
|
|
+ <div class="text">ETA指标库</div>
|
|
|
+ <div class="text">添加指标</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <img src="@/assets/img/icon/line-arrow-blue.png" class="banner-line">
|
|
|
+ <div class="banner-image">
|
|
|
+ <img src="@/assets/img/help/chart.png">
|
|
|
+ <div class="banner-text">
|
|
|
+ <div class="text">ETA图库</div>
|
|
|
+ <div class="text">指标作图</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <img src="@/assets/img/icon/line-arrow-blue.png" class="banner-line">
|
|
|
+ <div class="banner-image">
|
|
|
+ <img src="@/assets/img/help/report.png">
|
|
|
+ <div class="banner-text">
|
|
|
+ <div class="text">研报</div>
|
|
|
+ <div class="text">编辑研报/插入图表</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
+ <div class="operation-document-body" id="operation-document-body">
|
|
|
+ <div class="document-body-left">
|
|
|
+ <el-scrollbar style="height: 100%;">
|
|
|
+ <el-menu class="docuemnt-menu" text-color="#333333" :default-active="defaultActiveId+''">
|
|
|
+ <template v-for="menuItem in documentData" :key="menuItem.ClassifyId">
|
|
|
+ <subMenuBox @getDocument="getDocument" v-if="menuItem.Children && menuItem.Children.length>0"
|
|
|
+ :item="menuItem"></subMenuBox>
|
|
|
+ <menuBox @getDocument="getDocument" :item="menuItem" v-else></menuBox>
|
|
|
+ </template>
|
|
|
+ </el-menu>
|
|
|
+ </el-scrollbar>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="document-body-center" id="document-body-center" :style="{'border-right':isRightFold?'none':'solid 1px #DCDFE6'}">
|
|
|
+ <template v-if="helpDocument.Title">
|
|
|
+ <div class="body-center-title">
|
|
|
+ <div class="body-center-title-text">{{ helpDocument.Title }}</div>
|
|
|
+ <div class="body-center-title-signature">最后更新时间:{{ helpDocument.Author }} {{ helpDocument.ModifyTime }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="rich-text-box fr-view" id="rich-text-box" v-html="Content">
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <div class="nodata" style="text-align: center;">
|
|
|
+ <img src="~@/assets/img/nodata.png" style="width: 300px;"/>
|
|
|
+ <p>暂无信息</p>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <div class="document-body-right" :style="{'max-width': isRightFold?'0':'300px'}">
|
|
|
+ <div class="body-right-box">
|
|
|
+ <el-tree :data="helpDocument.Anchor" node-key="AnchorId" @current-change="menuChange" class="right-anchor-tree"
|
|
|
+ ref="rightTreeRef" :props="treeProp" :current-node-key="currentNodeKey" icon="none" empty-text="暂无数据"
|
|
|
+ default-expand-all :expand-on-click-node="false" >
|
|
|
+ <template #default="{ node, data }">
|
|
|
+ <a @click="(e)=>navigate(e,'#'+data.Anchor)" class="custom-tree-node" v-html="data.AnchorName"
|
|
|
+ :class="currentNodeKey==data.AnchorId?'active-node':''" :style="!node.isLeaf?'margin-top:12px':''" ></a>
|
|
|
+ </template>
|
|
|
+ </el-tree>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="fold-right-icon" @click="isRightFold=!isRightFold">
|
|
|
+ <img src="@/assets/img/icon/fold.png" v-if="!isRightFold" />
|
|
|
+ <img src="@/assets/img/icon/unfold.png" v-else />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
-<style scoped lang="scss">
|
|
|
+<style lang="scss" scoped>
|
|
|
+
|
|
|
+ .operation-document-container{
|
|
|
+ min-width: 1000px;
|
|
|
+ width: 100%;
|
|
|
+ .operation-document-neck{
|
|
|
+ padding: 60px 20px;
|
|
|
+ height: 140px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ .banner-image{
|
|
|
+ height: 140px;
|
|
|
+ width: 250px;
|
|
|
+ min-width: 200px;
|
|
|
+ position: relative;
|
|
|
+ .banner-text{
|
|
|
+ position: absolute;
|
|
|
+ top: 24px;
|
|
|
+ left: 24px;
|
|
|
+ .text{
|
|
|
+ color: white;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 28px;
|
|
|
+ font-size: 20px;
|
|
|
+ &:last-child{
|
|
|
+ margin-top: 20px;
|
|
|
+ line-height: 22px;
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ img{
|
|
|
+ height:100%;
|
|
|
+ width:100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .banner-line{
|
|
|
+ width: 40px;
|
|
|
+ margin: 0 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .operation-document-body{
|
|
|
+ width: 100%;
|
|
|
+ // min-height:100vh;
|
|
|
+ display: flex;
|
|
|
+ position: relative;
|
|
|
+ .document-body-left{
|
|
|
+ max-width: 300px;
|
|
|
+ flex:1;
|
|
|
+ max-height: 100vh;
|
|
|
+ position: sticky;
|
|
|
+ top: 0;
|
|
|
+ padding: 24px 24px 24px 12px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ align-self: flex-start;
|
|
|
+ .docuemnt-menu{
|
|
|
+ border-right: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .document-body-center{
|
|
|
+ flex: 3;
|
|
|
+ min-height: 100%;
|
|
|
+ padding: 20px;
|
|
|
+ border-left: solid 1px #DCDFE6;
|
|
|
+ // border-right: solid 1px #DCDFE6;
|
|
|
+ box-sizing: border-box;
|
|
|
+ min-height:100vh;
|
|
|
+ .body-center-title{
|
|
|
+ border-bottom: solid 1px #C0C4CC;
|
|
|
+ margin-bottom: 30px;
|
|
|
+ .body-center-title-text{
|
|
|
+ font-size: 34px;
|
|
|
+ line-height: 48px;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ .body-center-title-signature{
|
|
|
+ font-size: 14px;
|
|
|
+ color: #666666;
|
|
|
+ padding: 10px 0 10px 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .document-body-right{
|
|
|
+ flex: 1;
|
|
|
+ max-width: 300px;
|
|
|
+ max-height: 100vh;
|
|
|
+ position: sticky;
|
|
|
+ top: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ transition: all 0.1s ease;
|
|
|
+ box-sizing: border-box;
|
|
|
+ align-self: flex-start;
|
|
|
+ .body-right-box{
|
|
|
+ padding: 12px 24px 24px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ .custom-tree-node{
|
|
|
+ padding: 8px 12px;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 20px;
|
|
|
+ color: #333333;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .fold-right-icon{
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ position: sticky;
|
|
|
+ right: 10px;
|
|
|
+ top: 0;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|
|
|
+<style lang="scss">
|
|
|
+// froala-editor 预览时的样式,如需使用在展示富文本的节点上加上 fr-view 的类
|
|
|
+@import '/public/froala_style.min.css';
|
|
|
+// 因为富文本编辑的地方在hz_crm_web 项目,加入后台的样式保持两边看起来一致
|
|
|
+@import '/public/reset.min.css';
|
|
|
+
|
|
|
+p[data-f-id="pbf"] {
|
|
|
+ display: none;
|
|
|
+}
|
|
|
+
|
|
|
+.el-scrollbar__wrap {
|
|
|
+ overflow-x: hidden;
|
|
|
+}
|
|
|
+.el-sub-menu .el-menu-item{
|
|
|
+ padding-left:12px !important;
|
|
|
+}
|
|
|
+
|
|
|
+a{
|
|
|
+ text-decoration: none;
|
|
|
+}
|
|
|
+
|
|
|
+.el-tree-node:focus > .el-tree-node__content {
|
|
|
+background-color: transparent !important;
|
|
|
+}
|
|
|
+
|
|
|
+.el-tree-node__content{
|
|
|
+ height: unset!important;
|
|
|
+}
|
|
|
+.el-tree-node__content:hover {
|
|
|
+ background-color: transparent;
|
|
|
+ .custom-tree-node{
|
|
|
+ color: #366EF4!important;
|
|
|
+ }
|
|
|
+}
|
|
|
+.active-node{
|
|
|
+ color: #366EF4!important;
|
|
|
+}
|
|
|
+.el-tree-node__children{
|
|
|
+ .active-node{
|
|
|
+ color: #666666!important;
|
|
|
+ text-decoration:underline;
|
|
|
+ }
|
|
|
+ .custom-tree-node{
|
|
|
+ color: #666666!important;
|
|
|
+ padding: 0 8px!important;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
+.el-tree-node__children{
|
|
|
+ .el-tree-node__content:hover{
|
|
|
+ background-color: transparent;
|
|
|
+ text-decoration: underline;
|
|
|
+ .custom-tree-node{
|
|
|
+ color: #666666!important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.el-tree-node__expand-icon{
|
|
|
+ display: none;
|
|
|
+}
|
|
|
</style>
|