Bläddra i källkod

Merge branch 'yb11.6'

jwyu 2 år sedan
förälder
incheckning
f3eebd9ecd

+ 62 - 0
src/api/myChart.js

@@ -0,0 +1,62 @@
+/**
+ * 我的图库模块
+ */
+ import {get,post} from './http'
+
+ /**
+ * 我的图库列表
+ * @param keyword
+ * @param classify_id 分类ID
+ */
+export const apiMyChartList=params=>{
+    return get('/my_chart/list',params)
+}
+
+/**
+ * 我的图库分类列表
+ */
+export const apiMyChartClassifyList=()=>{
+    return get('/my_chart_classify/list',{})
+}
+
+/**
+ * 新增我的图库分类
+ * @param classify_name
+ */
+export const apiMyChartClassifyAdd=params=>{
+    return post('/my_chart_classify/add',params)
+}
+
+/**
+ * 编辑我的图库分类
+ * @param classify_name
+ * @param classify_id
+ */
+export const apiMyChartClassifyEdit=params=>{
+    return post('/my_chart_classify/edit',params)
+}
+
+/**
+ * 删除我的图库分类
+ * @param classify_id
+ */
+export const apiMyChartClassifyDel=params=>{
+    return post('/my_chart_classify/del',params)
+}
+
+/**
+ * 排序我的图库分类
+ * @param list<item>:{ "classify_id": 1, //分类ID "sort": 3 //排序}
+ */
+export const apiMyChartClassifySort=params=>{
+    return post('/my_chart_classify/sort',params)
+}
+
+/**
+ * 我的图表关联分类
+ * @param my_chart_id
+ * @param classify_id
+ */
+export const apiMyChartRelateClassify=params=>{
+    return post('/my_chart/relate_classify',params)
+}

BIN
src/assets/myChart/btn-img.png


BIN
src/assets/myChart/del-icon.png


BIN
src/assets/myChart/drag-icon.png


BIN
src/assets/myChart/edit-icon.png


+ 9 - 2
src/layout/component/Aside.vue

@@ -52,10 +52,17 @@ let menuList = reactive([
     icon_path: new URL('../../assets/leftNav/roadShowVideo-s.png', import.meta.url).href,
     children: null,
   },
+  // {
+  //   MenuId: 2,
+  //   name: "价格驱动",
+  //   path: "/pricedriven",
+  //   icon_path: new URL('../../assets/leftNav/chart-s.png', import.meta.url).href,
+  //   children: null,
+  // },
   {
     MenuId: 2,
-    name: "价格驱动",
-    path: "/pricedriven",
+    name: "我的图库",
+    path: "/mychart/list",
     icon_path: new URL('../../assets/leftNav/chart-s.png', import.meta.url).href,
     children: null,
   },

+ 43 - 0
src/router/index.js

@@ -418,6 +418,49 @@ const routes=[
       }
     ]
   },
+  // 我的图库模块
+  {
+    path:"/mychart",
+    name: "MyChart",
+    component: () => import("@/layout/Index.vue"),
+    meta: {
+      title:"我的图库"
+    },
+    children:[
+      {
+        path:"list",
+        name:"MyChartList",
+        component:()=>import('@/views/myChart/List.vue'),
+        meta: {
+          title: "我的图库",
+          keepAlive:false,
+          isRoot:true
+        }
+      },
+      {
+        path:"search",
+        name:"MyChartSearch",
+        component:()=>import('@/views/myChart/Search.vue'),
+        meta: {
+          title: "搜索",
+          keepAlive:true,
+          isRoot:false,
+          hasBack:true
+        }
+      },
+      {
+        path:"detail",
+        name:"MyChartDetail",
+        component:()=>import('@/views/myChart/Detail.vue'),
+        meta: {
+          title: "图表详情",
+          keepAlive:false,
+          isRoot:false,
+          hasBack:true
+        }
+      }
+    ]
+  },
 
   {
     path: '/:pathMatch(.*)',

+ 1 - 0
src/style/global.scss

@@ -16,6 +16,7 @@ body,
 
 :root{
   --el-color-primary:#F3A52F;
+  --el-color-primary-light-3:#F3A52F;
 }
 
 // 禁止页面打印

+ 17 - 0
src/utils/common.js

@@ -0,0 +1,17 @@
+// 公共工具方法
+
+/**
+ * 将报告详情字符串中的iframe加token,reportId参数
+ * @param str 报告详情
+ * @param reportId 
+ * @param chapterId
+ * @returns 
+ */
+export const addTokenToIframe=(str,reportId,chapterId=0)=>{
+    const token=localStorage.getItem('token')||''
+    if(import.meta.env.MODE==='production'){
+        return str.replace(/src="https:\/\/chartlib.hzinsights.com\/chartshow\?/g,`src="https://chartlib.hzinsights.com/chartshow?token=${token}&reportId=${reportId}&chapterId=${chapterId}&source=ybxcx&`)
+    }else{
+        return str.replace(/src="https:\/\/charttest.hzinsights.com\/chartshow\?/g,`src="https://charttest.hzinsights.com/chartshow?token=${token}&reportId=${reportId}&chapterId=${chapterId}&source=ybxcx&`)
+    }
+}

+ 197 - 0
src/views/myChart/Detail.vue

@@ -0,0 +1,197 @@
+<script setup>
+import {computed, ref} from 'vue'
+import { useRoute } from "vue-router";
+import {apiMyChartClassifyList,apiMyChartRelateClassify,apiMyChartClassifyAdd} from '@/api/myChart'
+import { ElMessage} from 'element-plus'
+
+const route=useRoute()
+
+let url=ref('')
+
+function init(){
+    const queryObj={
+        ChartInfoId:route.query.chartInfoId,
+        source:'ybxcx_my_chart',
+        token:localStorage.getItem('token'),
+        timestamp:new Date().getTime(),//防止缓存
+    }
+    let queryObjStr=''
+    for (const key in queryObj) {
+        if(!queryObjStr){
+                queryObjStr=`${key}=${queryObj[key]}`
+        }else{
+            queryObjStr=`${queryObjStr}&${key}=${queryObj[key]}`
+        }
+    }
+    console.log('拼接字符串:',queryObjStr);
+    url.value=`${import.meta.env.MODE==='production'?'https://details.hzinsights.com':'https://xcxh5test.hzinsights.com/xcx_h5'}/hzyb/chart/detail?${queryObjStr}`
+}
+init()
+
+let classifyList=ref([])
+let showTrans=ref(false)
+let currentClassifyId=ref(0)
+let currentClassifyName=ref('')
+let myChartId=0
+
+// 获取我的分类数据
+async function getMyClassifyList(){
+    const res=await apiMyChartClassifyList()
+    if(res.code===200){
+        classifyList.value=res.data||[]
+    }
+}
+getMyClassifyList()
+
+//添加分类
+let showAdd=ref(false)
+let inputText=ref('')
+
+async function handleConfirmAdd(){
+    if(!inputText.value){
+        ElMessage.warning('请填写分类名称')
+        return
+    }
+    const res=await apiMyChartClassifyAdd({
+        classify_name:inputText.value
+    })
+    if(res.code===200){
+        ElMessage.success(`新增成功`)
+        getMyClassifyList()
+        showAdd.value=false
+        inputText.value=''
+    }
+}
+
+
+// 获取当前图对应的分类
+// const currentClassifyItem=computed(()=>{
+//     return classifyList.value.filter(e=>e.my_chart_classify_id==currentClassifyId.value)[0]
+// })
+
+window.addEventListener('message',(e)=>{
+    // 监听转移分类
+    if(e.data?.opt=="pcShowTransClassify"){
+        currentClassifyId.value=e.data.classifyId
+        myChartId=e.data.myChartId
+        showTrans.value=true
+        if(classifyList.value.length>0){
+            classifyList.value.forEach(item=>{
+                if(item.my_chart_classify_id==e.data.classifyId){
+                    currentClassifyName.value=item.my_chart_classify_name
+                }
+            })
+        }
+    }
+})
+
+
+// 确定转移
+async function handleConfirm(){
+    if(!currentClassifyId)return
+    const res=await apiMyChartRelateClassify({
+        my_chart_id:myChartId,
+        classify_id:currentClassifyId.value
+    })
+    if(res.code===200){
+        ElMessage.success('设置成功')
+        showTrans.value=false
+        const target=document.getElementById('iframe')
+        target.contentWindow.postMessage({opt:'updateClassifyId',id:currentClassifyId.value},"*")
+    }
+}
+</script>
+
+<template>
+    <div class="mychart-detail-page">
+        <iframe id='iframe' :src="url"></iframe>
+    </div>
+    <!-- 转移分类弹窗 -->
+    <el-dialog
+        v-model="showTrans"
+        title="设置分类"
+        :width="450"
+        draggable
+        :close-on-click-modal="false"
+        append-to-body
+    >
+        <div class="trans-wrap">
+            <div v-if="classifyList.length!==0" style="margin-bottom:20px">所属分类:{{currentClassifyName}}</div>
+            <div v-if="classifyList.length==0">暂无分类,请先添加分类</div>
+            <div class="list-box">
+                <span 
+                    :class="['item',currentClassifyId==item.my_chart_classify_id?'active':'']" 
+                    v-for="item in classifyList" 
+                    :key="item.my_chart_classify_id"
+                    @click="currentClassifyId=item.my_chart_classify_id"
+                >{{item.my_chart_classify_name}}</span>
+            </div>
+            <div style="text-align:center;margin:40px 0 20px 0">
+                <el-button round plain size="large" style="width:100px" @click="showTrans=false">取消</el-button>
+                <el-button round size="large" type="primary" style="width:100px" @click="showAdd=true" v-if="classifyList.length==0">添加</el-button>
+                <el-button round size="large" type="primary" style="width:100px" @click="handleConfirm" v-else>确定</el-button>
+            </div>
+        </div>
+    </el-dialog>
+    <!-- 添加分类弹窗 -->
+    <el-dialog
+        v-model="showAdd"
+        title="添加分类"
+        :width="450"
+        draggable
+        :close-on-click-modal="false"
+        append-to-body
+    >
+        <div class="add-box">
+            <input v-model="inputText" type="text" placeholder="请输入分类名称" maxlength="10">
+            <p style="color:#999">注:字数控制在10个字以内</p>
+            <div style="text-align:center;margin:40px 0 20px 0">
+                <el-button round plain size="large" style="width:100px" @click="showAdd=false,inputText=''">取消</el-button>
+                <el-button round size="large" type="primary" style="width:100px" @click="handleConfirmAdd">确定</el-button>
+            </div>
+        </div>
+    </el-dialog>
+</template>
+
+<style lang="scss" scoped>
+.mychart-detail-page{
+    iframe{
+        width: 100%;
+        height: 800px;
+        border: none;
+    }
+}
+.trans-wrap{
+    .list-box{
+        .item{
+            display: inline-block;
+            padding: 5px 10px;
+            font-size: 14px;
+            background: #F4F4F5;
+            border: 1px solid #E9E9EB;
+            border-radius: 4px;
+            margin-right: 20px;
+            margin-bottom: 10px;
+            cursor: pointer;
+        }
+        .active{
+           background: #FDF6EC;
+           color: #E6A23C;
+        }
+    }
+}
+.add-box{
+    input{
+        width: 100%;
+        display: block;
+        line-height: 40px;
+        border: 1px solid #DCDFE6;
+        padding: 0 15px;
+        box-sizing: border-box;
+        border-radius: 40px;
+        &:focus{
+            outline: none;
+        }
+    }
+}
+</style>

+ 182 - 0
src/views/myChart/List.vue

@@ -0,0 +1,182 @@
+<script setup>
+import { onActivated, reactive,ref } from 'vue'
+import Search from '@/components/Search.vue'
+import SelfList from '@/components/SelfList.vue'
+import SortClassify from './components/SortClassify.vue'
+import {apiMyChartList,apiMyChartClassifyList} from '@/api/myChart'
+import { useRouter } from 'vue-router'
+
+const router=useRouter()
+
+
+let classifyOpts=ref([])//我的分类数据
+async function getMyClassifyOpt(){
+    const res=await apiMyChartClassifyList()
+    if(res.code===200){
+        classifyOpts.value=res.data||[]
+    }
+}
+getMyClassifyOpt()
+
+// 分类选择变化
+function classifyChange(){
+    listState.page=1
+    listState.finished=false
+    listState.list=[]
+    getChartList()
+}
+
+let listState=reactive({
+    loading:false,
+    finished:false,
+    page:1,
+    pageSize:20,
+    list:[],
+    sClassifyId:'',
+
+})
+// 获取列表数据
+async function getChartList(){
+    listState.loading=true
+    const res=await apiMyChartList({
+        keyword:'',
+        classify_id:listState.sClassifyId,
+        curr_page:listState.page,
+        page_size:listState.pageSize
+    })
+    listState.loading=false
+    if(res.code===200){
+        const arr=res.data.list||[]
+        listState.list=[...listState.list,...arr]
+        listState.finished=res.data.paging.is_end
+    }
+}
+getChartList()
+
+// 加载更多
+function onLoad(){
+    listState.page++
+    getChartList()
+}
+
+//查看详情
+function goDetail(item){
+    router.push({
+        path:'/mychart/detail',
+        query:{
+            chartInfoId:item.chart_info_id
+        }
+    })
+}
+
+// onActivated(()=>{
+//     getMyClassifyOpt()
+// })
+
+
+</script>
+
+
+<template>
+    <div class="mychart-list-page">
+        <div class="flex top-wrap">
+            <div class="flex">
+            <Search @click="$router.push('/mychart/search')" :disabled="true" placeholder="关键词搜索" style="background-color:#fff"/>
+            <el-select 
+                v-model="listState.sClassifyId" 
+                class="select-box" 
+                placeholder="选择分类" 
+                clearable
+                size="large"
+                @change="classifyChange"
+            >
+                <el-option
+                    v-for="item in classifyOpts"
+                    :key="item.my_chart_classify_id"
+                    :label="item.my_chart_classify_name"
+                    :value="item.my_chart_classify_id"
+                />
+            </el-select>
+            </div>
+            <SortClassify @change="getMyClassifyOpt"/>
+                
+        </div>
+        <SelfList 
+            :finished="listState.finished" 
+            :isEmpty="listState.list.length===0&&listState.finished"
+            :loading="listState.loading"
+            :count="listState.list.length"
+            emptyMsg="暂无图表收藏的信息"
+            @listOnload="onLoad"
+        >
+            <ul class="flex list-wrap">
+                <li class="item" v-for="item in listState.list" :key="item.chart_info_id" @click="goDetail(item)">
+                    <div class="multi-ellipsis-l2 title">{{item.chart_name}}</div>
+                    <img class="img" :src="item.chart_image" alt="">
+                </li>
+                <li class="last-add-item"></li>
+                <li class="last-add-item"></li>
+                <li class="last-add-item"></li>
+            </ul>
+        </SelfList>
+    </div>
+</template>
+
+
+<style lang="scss" scoped>
+
+.mychart-list-page{
+    .top-wrap{
+        position: sticky;
+        top: 60px;
+        z-index: 10;
+        padding-top: 20px;
+        padding-bottom: 20px;
+        margin-top: -20px;
+        background-color: #fff;
+        justify-content: space-between;
+    }
+    .select-box{
+        width: 228px;
+        margin-left: 30px;
+        :deep(.el-input__wrapper){
+            border-radius: 40px;
+        }
+    }
+
+
+    .list-wrap{
+        flex-wrap: wrap;
+        justify-content: center;
+        .last-add-item{
+            height:0;
+            flex-shrink: 0;
+            width: 285px;
+            margin-left: 10px;
+            margin-right: 10px;
+        }
+        .item{
+            flex-shrink: 0;
+            width: 285px;
+            background: #FFFFFF;
+            border: 1px solid #EBEBEB;
+            box-shadow: 0px 0px 12px rgba(167, 167, 167, 0.25);
+            border-radius: 4px;
+            padding: 10px;
+            margin-bottom: 20px;
+            margin-left: 10px;
+            margin-right: 10px;
+            overflow: hidden;
+            cursor: pointer;
+            .title{
+                margin-bottom: 20px;
+            }
+            .img{
+                width: 100%;
+                height: 229px;
+                object-fit: contain;
+            }
+        }
+    }
+}
+</style>

+ 176 - 0
src/views/myChart/Search.vue

@@ -0,0 +1,176 @@
+<script setup>
+import { onActivated, reactive,ref } from 'vue'
+import Search from '@/components/Search.vue'
+import SelfList from '@/components/SelfList.vue'
+import {apiMyChartList} from '@/api/myChart'
+import { useRoute ,onBeforeRouteLeave, useRouter} from 'vue-router'
+import { useStore } from 'vuex'
+
+const route=useRoute()
+const router=useRouter()
+const store=useStore()
+
+let autoFocus=ref(false)
+
+let listState=reactive({
+    loading:false,
+    finished:false,
+    page:1,
+    pageSize:20,
+    list:[],
+    sClassifyId:'',
+    keyword:''
+})
+// 获取列表数据
+async function getChartList(){
+    listState.loading=true
+    const res=await apiMyChartList({
+        keyword:listState.keyword,
+        classify_id:listState.sClassifyId,
+        curr_page:listState.page,
+        page_size:listState.pageSize
+    })
+    listState.loading=false
+    if(res.code===200){
+        const arr=res.data.list||[]
+        listState.list=[...listState.list,...arr]
+        listState.finished=res.data.paging.is_end
+    }
+}
+
+// 加载更多
+function onLoad(){
+    listState.page++
+    getChartList()
+}
+
+//搜索
+function handleSearch(e){
+    listState.keyword=e||''
+    listState.page=1
+    listState.list=[]
+    listState.finished=false
+    getChartList()
+}
+
+//查看详情
+function goDetail(item){
+    router.push({
+        path:'/mychart/detail',
+        query:{
+            chartInfoId:item.chart_info_id
+        }
+    })
+}
+
+onActivated(()=>{
+    console.log('onActivated');
+    if(route.query.cid){
+        if(route.query.cid==listState.sClassifyId)return
+        autoFocus.value=false
+        listState.sClassifyId=Number(route.query.cid)
+        store.commit('modifyBreadCrumb',route.query.cname)
+        getChartList()
+    }else{
+        autoFocus.value=true
+        store.commit('modifyBreadCrumb','搜索')
+    }
+})
+
+onBeforeRouteLeave((to)=>{
+    if(to.name!='MyChartDetail'){
+        listState.page=1
+        listState.list=[]
+        listState.finished=false
+        listState.keyword=''
+        listState.sClassifyId=''
+    }
+})
+
+
+
+</script>
+
+<template>
+    <div class="mychart-search-page">
+        <div class="top-wrap">
+            <h2 class="title" v-if="$route.query.cname">{{$route.query.cname}}</h2>
+            <Search 
+                :autoFocus="autoFocus" 
+                placeholder="关键词搜索" 
+                :defaultVal="listState.keyword"
+                style="background-color:#fff"
+                @search="handleSearch"
+                @clean="handleSearch"
+            />
+        </div>
+        <template v-if="listState.keyword||listState.sClassifyId">
+        <SelfList 
+            :finished="listState.finished" 
+            :isEmpty="listState.list.length===0&&listState.finished"
+            :loading="listState.loading"
+            :count="listState.list.length"
+            emptyMsg="暂无图表收藏的信息"
+            @listOnload="onLoad"
+        >
+            <ul class="flex list-wrap">
+                <li class="item" v-for="item in listState.list" :key="item.chart_info_id" @click="goDetail(item)">
+                    <div class="multi-ellipsis-l2 title">{{item.chart_name}}</div>
+                    <img class="img" :src="item.chart_image" alt="">
+                </li>
+                <li class="last-add-item"></li>
+                <li class="last-add-item"></li>
+                <li class="last-add-item"></li>
+            </ul>
+        </SelfList>
+        </template>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.top-wrap{
+    position: sticky;
+    top: 60px;
+    z-index: 10;
+    padding-top: 20px;
+    padding-bottom: 20px;
+    margin-top: -20px;
+    background-color: #fff;
+    .title{
+        font-size: 20px;
+    }
+}
+    .list-wrap{
+        flex-wrap: wrap;
+        justify-content: center;
+        .last-add-item{
+            height:0;
+            flex-shrink: 0;
+            width: 285px;
+            margin-left: 10px;
+            margin-right: 10px;
+        }
+        .item{
+            flex-shrink: 0;
+            width: 285px;
+            background: #FFFFFF;
+            border: 1px solid #EBEBEB;
+            box-shadow: 0px 0px 12px rgba(167, 167, 167, 0.25);
+            border-radius: 4px;
+            padding: 10px;
+            margin-bottom: 20px;
+            margin-left: 10px;
+            margin-right: 10px;
+            overflow: hidden;
+            cursor: pointer;
+            .title{
+                margin-bottom: 20px;
+            }
+            .img{
+                width: 100%;
+                height: 229px;
+                object-fit: contain;
+            }
+        }
+    }
+</style>

+ 249 - 0
src/views/myChart/components/SortClassify.vue

@@ -0,0 +1,249 @@
+<script setup>
+import {ref,watch} from 'vue'
+import draggable from 'vuedraggable'
+import {
+    apiMyChartClassifyList,
+    apiMyChartClassifySort,
+    apiMyChartClassifyDel,
+    apiMyChartClassifyAdd,
+    apiMyChartClassifyEdit
+} from '@/api/myChart'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { useRouter } from 'vue-router'
+
+const router=useRouter()
+const emit=defineEmits(['change'])
+
+let list=ref([])
+async function getMyClassifyOpt(){
+    const res=await apiMyChartClassifyList()
+    if(res.code===200){
+        list.value=res.data||[]
+    }
+}
+getMyClassifyOpt()
+
+
+// 排序结束
+function onSortEnd(){
+    // console.log('sort end');
+    updateClassifySort()
+}
+
+// 更新排序
+async function updateClassifySort(){
+    const arr=list.value.map((item,index)=>{
+        return {
+            sort:index+1,
+            classify_id:item.my_chart_classify_id
+        }
+    })
+    const res=await apiMyChartClassifySort(arr)
+    if(res.code===200){
+        ElMessage.success('移动成功')
+        emit('change')
+    }else{
+        ElMessage.warning(res.msg)
+    }
+}
+
+// 删除
+function handleDel(item){
+    ElMessageBox({
+        title:`操作提示`,
+        message:`是否确认删除分类“${item.my_chart_classify_name}”`,
+        center: true,
+        dangerouslyUseHTMLString: true,
+        confirmButtonText:'确定',
+        confirmButtonClass:'self-elmessage-confirm-btn',
+        showCancelButton:true,
+        cancelButtonText:'取消',
+        cancelButtonClass:'self-elmessage-cancel-btn'
+    }).then(()=>{
+        apiMyChartClassifyDel({classify_id:Number(item.my_chart_classify_id)}).then(res=>{
+            if(res.code===200){
+                ElMessage.success('删除成功')
+                emit('change')
+                getMyClassifyOpt()
+            }else if(res.code===4001){
+                ElMessageBox({
+                    title:`操作提示`,
+                    message:`删除失败,该分类下有图表`,
+                    center: false,
+                    dangerouslyUseHTMLString: true,
+                    confirmButtonText:'知道了',
+                    confirmButtonClass:'self-elmessage-confirm-btn',
+                    showCancelButton:false,
+                }) 
+            }else{
+                ElMessage.warning(res.msg)
+            }
+        })
+    }).catch(()=>{
+            
+    })
+}
+
+//编辑
+function handleEdit(item){
+    inputText.value=item.my_chart_classify_name
+    cid.value=item.my_chart_classify_id
+    showAdd.value=true
+}
+
+//添加分类
+let showAdd=ref(false)
+let inputText=ref('')
+let cid=ref(0)
+
+watch(
+    ()=>showAdd.value,
+    (n)=>{
+        if(!n){
+            inputText.value=''
+            cid.value=0
+        }
+    }
+)
+
+async function handleConfirmAdd(){
+    if(!inputText.value){
+        ElMessage.warning('请填写分类名称')
+        return
+    }
+    let res=null
+    if(cid.value){
+        res=await apiMyChartClassifyEdit({
+            classify_name:inputText.value,
+            classify_id:cid.value
+        })
+    }else{
+        res=await apiMyChartClassifyAdd({
+            classify_name:inputText.value
+        })
+    }
+    if(res.code===200){
+        ElMessage.success(`${cid?'编辑':'新增'}成功`)
+        emit('change')
+        getMyClassifyOpt()
+        showAdd.value=false
+    }
+}
+
+
+function goSearch(item){
+    router.push({
+        path:'/mychart/search',
+        query:{
+            cid:item.my_chart_classify_id,
+            cname:item.my_chart_classify_name
+        }
+    })
+}
+
+</script>
+
+<template>
+    <el-popover
+        placement="bottom-start"
+        :width="400"
+        trigger="hover"
+        popper-class="top-popper"
+    >
+        <template #reference>
+            <img style="width:109px;cursor: pointer;" src="@/assets/myChart/btn-img.png" alt="">
+        </template>
+        <template #default>
+            <div class="sort-classify-wrap">
+                <draggable 
+                    class="list"
+                    v-model="list" 
+                    item-key="my_chart_classify_id"
+                    animation="300"
+                    @end="onSortEnd"
+                    :disabled="true"
+                >
+                    <template #item="{element}">
+                        <div class="item" @click="goSearch(element)">
+                            <span>{{element.my_chart_classify_name}}</span>
+                            <img src="@/assets/myChart/edit-icon.png" @click.stop="handleEdit(element)" alt="">
+                            <img src="@/assets/myChart/del-icon.png" alt="" @click.stop="handleDel(element)">
+                            <!-- <img src="@/assets/myChart/drag-icon.png" alt=""> -->
+                        </div>
+                    </template>
+                </draggable>
+                <div class="add-btn" @click="showAdd=true">添加分类</div>
+            </div>
+        </template>
+    </el-popover>
+    
+    <!-- 添加分类弹窗 -->
+    <el-dialog
+        v-model="showAdd"
+        :title="cid?'编辑分类':'添加分类'"
+        :width="450"
+        draggable
+        :close-on-click-modal="false"
+        append-to-body
+    >
+        <div class="add-box">
+            <input v-model="inputText" type="text" placeholder="请输入分类名称" maxlength="10">
+            <p style="color:#999">注:字数控制在10个字以内</p>
+            <div style="text-align:center;margin:40px 0 20px 0">
+                <el-button round plain size="large" style="width:100px" @click="showAdd=false">取消</el-button>
+                <el-button round size="large" type="primary" style="width:100px" @click="handleConfirmAdd">确定</el-button>
+            </div>
+        </div>
+    </el-dialog>
+</template>
+
+<style>
+.top-popper{
+    padding: 0 !important;
+}    
+</style>
+<style lang="scss" scoped>
+.sort-classify-wrap{
+    .list{
+        min-height: 300px;
+        max-height: 500px;
+        .item{
+            cursor: pointer;
+            padding: 10px 20px;
+            font-size: 16px;
+            display: flex;
+            &:hover{
+                background-color: #FFFBF4;
+            }
+            span{
+                flex: 1;
+            }
+            img{
+                width: 20px;
+                margin-left: 20px;
+            }
+        }
+    }
+    .add-btn{
+        background: #F3A52F;
+        color: #fff;
+        text-align: center;
+        line-height: 40px;
+        cursor: pointer;
+    }
+}
+.add-box{
+    input{
+        width: 100%;
+        display: block;
+        line-height: 40px;
+        border: 1px solid #DCDFE6;
+        padding: 0 15px;
+        box-sizing: border-box;
+        border-radius: 40px;
+        &:focus{
+            outline: none;
+        }
+    }
+}
+</style>

+ 2 - 0
src/views/report/ChapterDetail.vue

@@ -22,6 +22,7 @@ import CollectBox from '@/components/CollectBox.vue'
 import collectIcon from '@/assets/collect2.png'
 import collectSIcon from '@/assets/collect2-s.png'
 import {useWaterMark} from '@/hooks/waterMark.js'
+import {addTokenToIframe} from '@/utils/common.js'
 
 const route=useRoute()
 const router=useRouter()
@@ -114,6 +115,7 @@ const getChapterReportDetail=async ()=>{
     })
     if(res.code===200){
         info.value=res.data
+        info.value.report_chapter_item.content=addTokenToIframe(res.data.report_chapter_item.content,res.data.report_chapter_item.report_id,res.data.report_chapter_item.report_chapter_id)
         audioData.value={
             auth_ok:res.data.auth_ok,
             video_name:res.data.report_chapter_item.video_name,

+ 2 - 0
src/views/report/Detail.vue

@@ -16,6 +16,7 @@ import {useWaterMark} from '@/hooks/waterMark.js'
 import CollectBox from '@/components/CollectBox.vue'
 import collectIcon from '@/assets/collect2.png'
 import collectSIcon from '@/assets/collect2-s.png'
+import {addTokenToIframe} from '@/utils/common.js'
 moment.locale('zh-cn')
 
 const route=useRoute()
@@ -52,6 +53,7 @@ const getReportDetail=async ()=>{
     })
     if(res.code===200){
         info.value=res.data 
+        info.value.report_info.content=addTokenToIframe(res.data.report_info.content,res.data.report_info.report_id,0)
         audioData.value={
             auth_ok:res.data.auth_ok,
             video_name:res.data.report_info.video_name,