jwyu 1 年之前
父節點
當前提交
b56e15c10b

+ 15 - 0
src/api/report.js

@@ -82,6 +82,21 @@ export default {
      */
     getChapterTagList:()=>{
         return get('/report/getChapterTrendTag',{})
+    },
+    /**
+     * 编辑章节标签
+     * @param ReportChapterId
+     * @param Trend
+     */
+    editChapterTrendTag:params=>{
+        return post('/report/editChapterTrendTag',params)
+    },
+    /**
+     * 获取章节详情
+     * @param ReportChapterId
+     */
+    getChapterDetail:params=>{
+        return get('/report/getDayWeekChapter',params)
     }
 
 }

+ 57 - 0
src/api/reportEn.js

@@ -0,0 +1,57 @@
+// 英文报告模块
+import { get,post } from "./index";
+
+export default {
+    /**
+     * 获取报告列表
+     * @param Frequency
+     * @param ClassifyNameFirst
+     * @param ClassifyNameSecond
+     * @param KeyWord
+     * @param EmailState
+     * @param State
+     * @param StartDate
+     * @param EndDate
+     */
+    getList:params=>{
+        return get('/english_report/list',params)
+    },
+    /**
+     * 获取报告分类
+     * @param CurrentIndex
+     * @param PageSize
+     * @param KeyWord
+     */
+    getClassifyList:params=>{
+        return get('/english_report/classify/list',params)
+    },
+    /**
+     * 删除报告
+     * @param ReportIds
+     */
+    reportDel:params=>{
+        return post('/english_report/delete',params)
+    },
+    /**
+     * 发布报告
+     * @param ReportIds 用,隔开
+     */
+    reportPublish:params=>{
+        return post('/english_report/publish',params)
+    },
+    /**
+     * 报告取消发布
+     * @param ReportIds
+     * @returns 
+     */
+    reportPublishCancle:params=>{
+        return post('/english_report/publish/cancel',params)
+    },
+    /**
+     * 报告详情
+     * @param ReportId
+     */
+    getReportDetail:params=>{
+        return get('/english_report/detail',params)
+    },
+}

二進制
src/assets/imgs/report/icon_publish.png


+ 26 - 0
src/assets/styles/common.scss

@@ -75,4 +75,30 @@ img {
     .bot-btn-box{
         border-top: 20px solid #F2F6FA;
     }
+}
+
+// 报告详情样式
+.report-html-wrap{
+    line-height: 1.8;
+    font-size: 36px;
+    :deep(img){
+        width: 100% !important;
+    }
+    :deep(span){
+        font-size: 36px !important;
+        line-height: 1.8 !important;
+        background-color: rgba(255, 255, 255, 0) !important;
+    }
+    :deep(p){
+        font-size: 36px !important;
+        line-height: 1.8 !important;
+        background-color: rgba(255, 255, 255, 0) !important;
+    }
+    :deep(iframe){
+        width: 100% !important;
+    }
+    :deep(li) {
+        list-style: inherit !important;
+        list-style-position: inside !important;
+    }   
 }

+ 1 - 0
src/assets/styles/var.scss

@@ -2,6 +2,7 @@
 $theme-color:#0052D9;//主题色
 $font-grey:#666666;
 $font-grey_999:#999;
+$font-success:#2BA471;
 $border-color:#DCDFE6;
 $theme-red:#C54322;
 $media-width:650px;

+ 3 - 0
src/router/index.js

@@ -3,6 +3,7 @@ import { pptRoutes } from "./ppt";
 import {pptENRoutes} from './pptEn'
 import {myETARoutes} from './myETA'
 import {reportRoutes} from './report'
+import {reportEnRoutes} from './reportEn'
 /**
  * 说明
  * 此文件为路由配置入口文件
@@ -55,6 +56,8 @@ const routes = [
 			...myETARoutes,
 			// 中文研报模块
 			...reportRoutes,
+			// 英文研报模块
+			...reportEnRoutes,
 		]
 	},
 	

+ 11 - 1
src/router/report.js

@@ -45,5 +45,15 @@
             hasBackHome:true,
             keepAlive:false
         },
-    }
+    },
+    {
+        path:"/report/search",
+        name:"ReportSearch",
+        component: () => import("@/views/report/Search.vue"),
+        meta: { 
+            title: "中文研报",
+            hasBackHome:true,
+            keepAlive:false
+        },
+    },
 ]

+ 39 - 0
src/router/reportEn.js

@@ -0,0 +1,39 @@
+// 英文研报路由模块
+/**
+ * meta:{
+ * noHead:pad端不需要顶部
+ * hasBackHome:pad端顶部有返回首页
+ * }
+ */
+ export const reportEnRoutes=[
+    {
+        path:"/reportEn/list",
+        name:"ReportEnList",
+        component: () => import("@/views/reportEn/List.vue"),
+        meta: { 
+            title: "英文研报",
+            hasBackHome:true,
+            keepAlive:false
+        },
+    },
+    {
+        path:"/reportEn/search",
+        name:"ReportEnSearchList",
+        component: () => import("@/views/reportEn/Search.vue"),
+        meta: { 
+            title: "英文研报",
+            hasBackHome:true,
+            keepAlive:false
+        },
+    },
+    {
+        path:"/reportEn/detail",
+        name:"ReportEnDetail",
+        component: () => import("@/views/reportEn/Detail.vue"),
+        meta: { 
+            title: "英文研报",
+            hasBackHome:true,
+            keepAlive:false
+        },
+    },
+]

+ 113 - 67
src/views/report/Detail.vue

@@ -2,6 +2,7 @@
 import {ref} from 'vue'
 import { useRoute } from "vue-router";
 import apiReport from '@/api/report'
+import ReportPublishPop from './components/ReportPublishPop.vue'
 import { showToast,showDialog } from 'vant';
 
 const route=useRoute()
@@ -20,49 +21,6 @@ getReportDetail()
 
 // 发布报告
 const showPublishPop=ref(false)
-// 确认发布报告
-// type 1 仅发布 2发布且推送
-function handleConfirmPublish(type){
-    apiReport.reportPublish({
-        ReportIds:route.query.id
-    }).then(res=>{
-        if(res.Ret==200){
-            if(type===2){
-                handleReportMessageSend(true)
-            }else{
-                if(res.Data){
-                    showDialog({
-                        title: '发布提示',
-                        message: res.Data,
-                    }).then(()=>{
-
-                    })
-                }else{
-                    showToast('发布成功')
-                }
-                showPublishPop.value=false
-                getReportDetail()
-            }
-        }
-    })
-}
-
-// 推送消息
-function handleReportMessageSend(publish){
-    apiReport.reportMessageSend({
-        ReportId:Number(route.query.id)
-    }).then(res=>{
-        if(res.Ret===200){
-            if(publish){
-                showToast('发布且推送成功')
-            }else{
-                showToast('推送成功')
-            }
-            getReportDetail()
-            showPublishPop.value=false
-        }
-    })
-}
 
 // 取消发布
 function handleReportPublishCancle(){
@@ -79,24 +37,73 @@ function handleReportPublishCancle(){
     })
 }
 
+// 发布弹窗关闭
+function handlePublishPopClose(refresh){
+    if(refresh){
+        getReportDetail()
+    }
+    showPublishPop.value=false
+}
+
+// 删除报告
+function handleDelReport(){
+    showDialog({
+        title: '提示',
+        message: '删除操作不可恢复,确认删除吗?',
+        showCancelButton:true
+    }).then(() => {
+        // on close
+        apiReport.reportDel({ReportIds:Number(route.query.id)}).then(res=>{
+            if(res.Ret===200){
+                showToast('删除成功')
+                setTimeout(() => {
+                    window.close()
+                }, 1500);
+            }
+        })
+    }).catch(()=>{})
+}
+
+// 推送消息
+function handleReportSendMsg(){
+    
+}
+
 </script>
 
 <template>
     <div class="report-detail-page" v-if="reportInfo">
-        <template v-if="reportInfo.State===1">
-            <van-button type="primary" @click="showPublishPop=true">发布</van-button>
-            <van-button type="primary">删除</van-button>
-        </template>
-        <template v-if="reportInfo.State===2">
-            <van-button type="primary" @click="handleReportPublishCancle">取消发布</van-button>
-            <van-button type="primary" @click="handleReportMessageSend">推送消息</van-button>
-        </template>
-       
-        <span>第{{reportInfo.Stage}}期/{{reportInfo.Frequency}}</span>
-        <div>{{reportInfo.Title}}</div>
-        <div><span>{{reportInfo.Author}}</span><span>{{reportInfo.PublishTime}}</span></div>
-        <div>{{reportInfo.Abstract}}</div>
-        <div v-html="reportInfo.Content"></div>
+        <div class="top-stage-box">
+            <span class="stage">第{{reportInfo.Stage}}期 / {{reportInfo.Frequency}}</span>
+            <template v-if="reportInfo.State===1">
+                <!-- 删除 -->
+                <div class="btn-item" @click="handleDelReport">
+                    <img src="@/assets/imgs/icon_del.png" alt="">
+                </div>
+                <!-- 发布 -->
+                <div class="btn-item" @click="showPublishPop=true">
+                    <img src="@/assets/imgs/report/icon_publish.png" alt="">
+                </div>
+            </template>
+            <template v-if="reportInfo.State===2">
+                <!-- 推送消息 -->
+                <div class="btn-item" @click="handleReportSendMsg">
+                    <img src="@/assets/imgs/icon_publish.png" alt="">
+                </div>
+                <!-- 取消发布 -->
+                <div class="btn-item" @click="showPublishPop=true">
+                    <img src="@/assets/imgs/report/icon_publish.png" alt="">
+                </div>
+            </template>
+        </div>
+        <h1 class="report-title">{{reportInfo.Title}}</h1>
+        <div class="auth-box">
+            <span>{{reportInfo.Author}}</span>
+            <span>{{reportInfo.PublishTime}}</span>
+        </div>
+
+        <div class="report-abstract">{{reportInfo.Abstract}}</div>
+        <div class="report-html-wrap" v-html="reportInfo.Content"></div>
     </div>
     <!-- 报告发布弹窗 -->
     <van-popup 
@@ -104,18 +111,57 @@ function handleReportPublishCancle(){
         position="center"
         round
     >
-        <div class="publish-report-pop-box">
-            <div>发布提示</div>
-            <p>是否发布报告,且推送模板消息和客户群?</p>
-            <div>
-                <van-button square type="primary" text="取消发布" @click="showPublishPop=false"/>
-                <van-button square type="primary" text="仅发布" @click="handleConfirmPublish(1)"/>
-                <van-button square type="primary" text="发布&推送" @click="handleConfirmPublish(2)"/>
-            </div>
-        </div>
+        <ReportPublishPop :reportId="$route.query.id" @close="handlePublishPopClose"/>
     </van-popup>
 </template>
 
 <style lang="scss" scoped>
-
+.report-detail-page{
+    padding: 30px 34px;
+    .report-title{
+        margin: 30px 0;
+        font-weight: 600;
+        font-size: 42px;
+        line-height: 56px;
+    }
+    .auth-box{
+        display: flex;
+        justify-content: space-between;
+        font-size: $font-grey;
+        font-size: 36px;
+        padding-bottom: 40px;
+        border-bottom: 1px solid $border-color;
+    }
+    .report-abstract{
+        font-size: 34px;
+        line-height: 54px;
+        margin: 40px 0;
+    }
+}
+.top-stage-box{
+    .stage{
+        display: inline-block;
+        background-color: #F2F3FF;
+        border-radius: 8px;
+        height: 72px;
+        line-height: 72px;
+        padding: 0 20px;
+        font-size: 28px;
+    }
+    .btn-item{
+        float: right;
+        width: 70px;
+        height: 70px;
+        border-radius: 50%;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        background-color: #F2F3FF;
+        margin-left: 40px;
+        img{
+            width: 48px;
+            height: 48px;
+        }
+    }
+}
 </style>

文件差異過大導致無法顯示
+ 116 - 85
src/views/report/List.vue


+ 158 - 0
src/views/report/Search.vue

@@ -0,0 +1,158 @@
+<script setup name="reportSearch">
+import {ref,reactive} from 'vue'
+import apiReport from '@/api/report'
+import { showToast } from 'vant'
+import moment from 'moment'
+import { useRouter } from 'vue-router'
+
+const router=useRouter()
+
+const keyword=ref('')
+const listState = reactive({
+    list:[],
+    page:1,
+    pageSize:20,
+    finished:false,
+    loading:false
+})
+async function getList(){
+    const res=await apiReport.getList({
+        CurrentIndex:listState.page,
+        PageSize:listState.pageSize,
+        KeyWord:keyword.value
+    })
+    if(res.Ret===200){
+        listState.loading=false
+        if(!res.Data){
+            listState.finished=true
+            return
+        }
+        
+        listState.finished=res.Data.Paging.IsEnd
+        const arr=res.Data.List||[]
+        listState.list=[...listState.list,...arr]
+    }
+}
+function onLoad(){
+    listState.page++
+    getList()
+}
+
+function handleSearch(){
+    if(!keyword.value){
+        showToast('请输入关键词')
+        return
+    }
+    listState.page=1
+    listState.list=[]
+    listState.finished=false
+    getList()
+}
+
+function goDetail(item){
+    let routerEl
+
+    if(['day','week'].includes(item.ChapterType)){
+        routerEl=router.resolve({
+            path:"/report/chapter/list",
+            query:{
+                id:item.Id
+            }
+        })
+    }else{
+        routerEl=router.resolve({
+            path:"/report/detail",
+            query:{
+                id:item.Id
+            }
+        })
+    }
+
+    window.open(routerEl.href,'_blank')
+}
+</script>
+
+<template>
+    <div class="report-search-page">
+        <div class="search-box">
+            <van-search 
+                shape="round"
+                placeholder="请输入报告标题或作者"
+                v-model="keyword"
+                @search="handleSearch"
+            />
+        </div>
+        <img v-if="listState.list.length==0&&listState.finished&&keyword" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+        <van-list
+            v-model:loading="listState.loading"
+            :finished="listState.finished"
+            :finished-text="listState.list.length>0?'没有更多了':'暂无图表'"
+            :immediate-check="false"
+            @load="onLoad"
+        >
+            <ul class="list-wrap">
+                <li 
+                    v-for="item in listState.list"
+                    :key="item.Id"
+                    class="item" 
+                    @click="goDetail(item)"
+                >
+                    <h2 :class="['van-ellipsis title',item.Title.startsWith('【')?'inline-title':'']">{{item.Title}}</h2>
+                    <p class="van-multi-ellipsis--l2 des">{{item.Abstract}}</p>
+                    <div class="bot-info">
+                        <div>
+                            <span style="margin-right:10px">{{moment(item.ModifyTime).format('YYYY-MM-DD HH:mm:ss')}}</span>
+                            <span>(第{{item.Stage}}期)</span>
+                        </div>
+                        <div>{{item.ClassifyNameFirst}}</div>
+                    </div>
+                </li>
+            </ul>
+        </van-list>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.list-wrap{
+    padding: 30px 34px;
+    .item{
+        padding: 20px;
+        margin-bottom: 20px;
+        border: 1px solid $border-color;
+        box-shadow: 0px 3px 12px rgba(52, 75, 120, 0.08);
+        border-radius: 8px;
+        .title{
+            font-size: 32px;
+            line-height: 44px;
+            margin: 0;
+        }
+        .inline-title{
+            margin-left: -14px;
+        }
+        .des{
+            margin-top: 10px;
+            margin-bottom: 20px;
+            font-size: 28px;
+            color: $font-grey;
+            min-height: 60px;
+        }
+        .bot-info{
+            display: flex;
+            justify-content: space-between;
+            color: $font-grey;
+            font-size: 28px;
+            .active-status{
+                color: $font-success;
+            }
+        }
+    }
+}
+.report-search-page{
+    .search-box{
+        position: sticky;
+        top: 0;
+        z-index: 99;
+        background-color: #fff;
+    }
+}
+</style>

+ 33 - 0
src/views/report/chapter/Detail.vue

@@ -0,0 +1,33 @@
+<script setup name="reportChapterDetail">
+import {ref} from 'vue'
+import apiReport from '@/api/report'
+import { useRoute } from 'vue-router'
+
+const route=useRoute()
+
+let info=ref(null)
+function getChapterDetail(){
+    apiReport.getChapterDetail({
+        ReportChapterId:(Number(route.query.id))
+    }).then(res=>{
+        if(res.Ret===200){
+            info.value=res.Data
+        }
+    })
+}
+getChapterDetail()
+
+</script>
+
+<template>
+    <div class="chapter-report-detail-page report-detail-wrap">
+        <span>第{{info.Stage}}期</span>
+        <h2 class="title">{{info.Title}}</h2>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.report-detail-wrap{
+    padding: 34px;
+}
+</style>

+ 81 - 4
src/views/report/chapter/List.vue

@@ -1,11 +1,13 @@
 <script setup name="reportChapterList">
-import {ref} from 'vue'
-import { useRoute } from "vue-router";
+import {reactive, ref} from 'vue'
+import { useRoute, useRouter } from "vue-router";
 import apiReport from '@/api/report'
 import moment from 'moment';
+import { showToast } from 'vant';
 
 
 const route=useRoute()
+const router=useRouter()
 
 // 获取报告详情
 let reportInfo=ref(null)
@@ -39,7 +41,43 @@ function getChapterTrendTagList(){
     })
 }
 
+const showTagPop=ref(false)
+const customFieldName={
+    text: 'KeyWord',
+    value: 'KeyWord',
+}
+const temTrendTagData=reactive({
+    ReportChapterId:'',
+    tagVal:['']
+})
+function handleShowTrendTag(item){
+    temTrendTagData.ReportChapterId=item.ReportChapterId
+    temTrendTagData.tagVal[0]=item.Trend
+    showTagPop.value=true
+}
+function handleConfirmEditTrendTag(){
+    apiReport.editChapterTrendTag({
+        ReportChapterId:Number(temTrendTagData.ReportChapterId),
+        Trend:temTrendTagData.tagVal[0]||''
+    }).then(res=>{
+        if(res.Ret===200){
+            showToast('修改成功')
+            showTagPop.value=false
+            getChapterList()
+        }
+    })
+}
+
 
+// 跳转章节详情
+function goChapterDetail(item){
+    router.push({
+        path:'/report/chapter/detail',
+        query:{
+            id:item.ReportChapterId
+        }
+    })
+}
 
 
 </script>
@@ -64,19 +102,58 @@ function getChapterTrendTagList(){
         </div>
         <div>章节列表</div>
         <ul class="chapter-list">
-            <li class="item" v-for="item in chapterList" :key="item.ReportChapterId">
+            <li class="item" v-for="item in chapterList" :key="item.ReportChapterId" @click="goChapterDetail(item)">
                 <div class="img-box">
                     <img :src="item.TypeEditImg" alt="">
                     <span>{{item.TypeName}}</span>
                 </div>
                 <div class="content">
                     <div>{{item.TypeName}}</div>
+                    <div>{{item.PublishState==1?'未发布':'已发布'}}</div>
+                    <div>{{item.ModifyTime}}</div>
+                    <div @click="handleShowTrendTag(item)">{{item.Trend||'添加标签'}}</div>
+                    <div v-if="item.PublishState==2">微信分享</div>
+                    <div v-if="reportInfo.ClassifyNameFirst=='周报'">{{item.VideoUrl&&item.VideoKind==1?'已传录音':'未传录音'}}</div>
                 </div>
             </li>
         </ul>
     </div>
+    <!-- 选择标签 -->
+    <van-popup 
+        v-model:show="showTagPop" 
+        round 
+        position="bottom"
+    >
+         <van-picker
+            v-model="temTrendTagData.tagVal"
+            :columns="tagOpts"
+            :columns-field-names="customFieldName"
+            @cancel="showTagPop = false"
+            @confirm="handleConfirmEditTrendTag"
+        />
+    </van-popup>
 </template>
 
 <style lang="scss" scoped>
-
+.chapter-list{
+    .item{
+        display: flex;
+        .img-box{
+            position: relative;
+            width: 200px;
+            height: 200px;
+            overflow: hidden;
+            img{
+                width: 100%;
+                height: 100%;
+            }
+            span{
+                position: absolute;
+                top: 50%;
+                left: 50%;
+                transform: translate(-50%,-50%);
+            }
+        }
+    }
+}
 </style>

+ 43 - 22
src/views/report/components/ListClassify.vue

@@ -2,6 +2,8 @@
 import {ref} from 'vue'
 import apiReport from '@/api/report'
 
+const emits=defineEmits(['close','confirm'])
+
 const list=ref([])
 function getClassifyList(){
     apiReport.getClassifyList({
@@ -10,43 +12,62 @@ function getClassifyList(){
         KeyWord:''
     }).then(res=>{
         if(res.Ret===200){
-            list.value=res.Data.List||[]
+            const arr=res.Data.List||[]
+            list.value=arr.map(item=>{
+                const child=item.Child?item.Child.map(e=>{
+                    return {
+                        text:e.ClassifyName,
+                        id:e.ClassifyName
+                    }
+                }):[]
+                return {
+                    text:item.ClassifyName,
+                    children:child
+                }
+            })
         }
     })
 }
 getClassifyList()
 
-const activeNames=ref([])
+const activeId = ref(null);
+const activeIndex = ref(0);
+
+function handleCancle(){
+    emits('close')
+}
 
+function handleConfirm(){
+    const firstClassify=list.value[activeIndex.value].text
+    const secondClassify=activeId.value||''
+    emits('confirm',{firstClassify,secondClassify})
+}
 </script>
 
 <template>
     <div class="report-list-classify-wrap">
-        <div>所有分类</div>
-        <div class="list-box">
-            <van-collapse v-model="activeNames">
-                <van-collapse-item 
-                    :title="item.ClassifyName" 
-                    :name="item.Id" 
-                    v-for="item in list" 
-                    :key="item.Id"
-                >
-                    <div 
-                        class="child-item" 
-                        v-for="child in item.Child" 
-                        :key="child.Id"
-                        @click="classifyChange(item.ClassifyName,child.ClassifyName)"
-                    >{{child.ClassifyName}}</div>
-                </van-collapse-item>
-            </van-collapse>
+        <div class="top-box">
+            <span style="color:#666666" @click="handleCancle">取消</span>
+            <span style="font-size:18px;font-weight:bold">选择分类</span>
+            <span style="color:#0052D9" @click="handleConfirm">确定</span>
         </div>
+        <van-tree-select
+            v-model:active-id="activeId"
+            v-model:main-active-index="activeIndex"
+            :items="list"
+        />
     </div>
 </template>
 
 <style lang="scss" scoped>
 .report-list-classify-wrap{
-    width: 600px;
-    height: 100%;
-    padding-top: 40px;
+    .top-box{
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        height: 116px;
+        border-bottom: 1px solid $border-color;
+        padding: 0 34px;
+    }
 }
 </style>

+ 3 - 0
src/views/report/components/ListFilter.vue

@@ -0,0 +1,3 @@
+<script setup>
+
+</script>

+ 96 - 0
src/views/report/components/ReportPublishPop.vue

@@ -0,0 +1,96 @@
+<script setup>
+import { showToast,showDialog } from 'vant';
+import apiReport from '@/api/report'
+
+const props=defineProps({
+    reportId:{
+        default:''
+    }
+})
+const emits=defineEmits(['close'])
+
+// 确认发布报告
+// type 1 仅发布 2发布且推送
+function handleConfirmPublish(type){
+    apiReport.reportPublish({
+        ReportIds:props.reportId
+    }).then(res=>{
+        if(res.Ret==200){
+            if(type===2){
+                handleReportMessageSend(true)
+            }else{
+                if(res.Data){
+                    showDialog({
+                        title: '发布提示',
+                        message: res.Data,
+                    }).then(()=>{
+
+                    })
+                }else{
+                    showToast('发布成功')
+                }
+                emits('close','refresh')
+            }
+        }
+    })
+}
+
+// 推送消息
+function handleReportMessageSend(publish){
+    apiReport.reportMessageSend({
+        ReportId:Number(props.reportId)
+    }).then(res=>{
+        if(res.Ret===200){
+            if(publish){
+                showToast('发布且推送成功')
+            }else{
+                showToast('推送成功')
+            }
+            emits('close','refresh')
+        }
+    })
+}
+</script>
+
+<template>
+    <div class="publish-report-pop-box">
+        <div class="title">发布提示</div>
+        <p class="tips">是否发布报告,且推送模板消息和客户群?</p>
+        <div class="btns">
+            <div class="btn blue" @click="handleConfirmPublish(2)">发布&推送</div>
+            <div class="btn" @click="handleConfirmPublish(1)">仅发布</div>
+            <div class="btn" @click="emits('close')">取消发布</div>
+        </div>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.publish-report-pop-box{
+    padding: 48px;
+    .title{
+        font-size: 36px;
+        text-align: center;
+        margin-bottom: 32px;
+    }
+    .tips{
+        color: $font-grey;
+        margin-bottom: 48px;
+    }
+    .btns{
+        .btn{
+            line-height: 96px;
+            border-radius: 12px;
+            text-align: center;
+            font-size: 32px;
+            font-weight: 600;
+            margin-bottom: 24px;
+            background-color: #F2F3FF;
+            color: $theme-color;
+        }
+        .blue{
+            background-color: $theme-color;
+            color: #fff;
+        }
+    }
+}
+</style>

+ 30 - 0
src/views/reportEn/Detail.vue

@@ -0,0 +1,30 @@
+<script setup name="reportEnDetail">
+import {ref} from 'vue'
+import { useRoute } from "vue-router";
+import apiReportEn from '@/api/reportEn'
+import { showToast,showDialog } from 'vant';
+
+const route=useRoute()
+
+// 获取报告详情
+let reportInfo=ref(null)
+async function getReportDetail(){
+    const res=await apiReportEn.getReportDetail({ReportId:Number(route.query.id)})
+    if(res.Ret===200){
+        reportInfo.value=res.Data
+        document.title=res.Data.Title
+    }
+}
+getReportDetail()
+
+</script>
+
+<template>
+    <div class="report-detail-page">
+        
+    </div>
+</template>
+
+<style lang="scss" scoped>
+
+</style>

文件差異過大導致無法顯示
+ 237 - 0
src/views/reportEn/List.vue


+ 146 - 0
src/views/reportEn/Search.vue

@@ -0,0 +1,146 @@
+<script setup name="reportSearch">
+import {ref,reactive} from 'vue'
+import apiReportEn from '@/api/reportEn'
+import { showToast } from 'vant'
+import moment from 'moment'
+import { useRouter } from 'vue-router'
+
+const router=useRouter()
+
+const keyword=ref('')
+const listState = reactive({
+    list:[],
+    page:1,
+    pageSize:20,
+    finished:false,
+    loading:false
+})
+async function getList(){
+    const res=await apiReportEn.getList({
+        CurrentIndex:listState.page,
+        PageSize:listState.pageSize,
+        KeyWord:keyword.value
+    })
+    if(res.Ret===200){
+        listState.loading=false
+        if(!res.Data){
+            listState.finished=true
+            return
+        }
+        
+        listState.finished=res.Data.Paging.IsEnd
+        const arr=res.Data.List||[]
+        listState.list=[...listState.list,...arr]
+    }
+}
+function onLoad(){
+    listState.page++
+    getList()
+}
+
+function handleSearch(){
+    if(!keyword.value){
+        showToast('请输入关键词')
+        return
+    }
+    listState.page=1
+    listState.list=[]
+    listState.finished=false
+    getList()
+}
+
+function goDetail(item){
+    let routerEl=router.resolve({
+        path:"/reportEn/detail",
+        query:{
+            id:item.Id
+        }
+    })
+    window.open(routerEl.href,'_blank')
+}
+</script>
+
+<template>
+    <div class="report-search-page">
+        <div class="search-box">
+            <van-search 
+                shape="round"
+                placeholder="请输入报告标题或作者"
+                v-model="keyword"
+                @search="handleSearch"
+            />
+        </div>
+        <img v-if="listState.list.length==0&&listState.finished&&keyword" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+        <van-list
+            v-model:loading="listState.loading"
+            :finished="listState.finished"
+            :finished-text="listState.list.length>0?'没有更多了':'暂无图表'"
+            :immediate-check="false"
+            @load="onLoad"
+        >
+            <ul class="list-wrap">
+                <li 
+                    v-for="item in listState.list"
+                    :key="item.Id"
+                    class="item" 
+                    @click="goDetail(item)"
+                >
+                    <h2 :class="['van-ellipsis title',item.Title.startsWith('【')?'inline-title':'']">{{item.Title}}</h2>
+                    <p class="van-multi-ellipsis--l2 des">{{item.Abstract}}</p>
+                    <div class="bot-info">
+                        <div>
+                            <span style="margin-right:10px">{{moment(item.ModifyTime).format('YYYY-MM-DD HH:mm:ss')}}</span>
+                            <span>(第{{item.Stage}}期)</span>
+                        </div>
+                        <div>{{item.ClassifyNameFirst}}</div>
+                    </div>
+                </li>
+            </ul>
+        </van-list>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.list-wrap{
+    padding: 30px 34px;
+    .item{
+        padding: 20px;
+        margin-bottom: 20px;
+        border: 1px solid $border-color;
+        box-shadow: 0px 3px 12px rgba(52, 75, 120, 0.08);
+        border-radius: 8px;
+        .title{
+            font-size: 32px;
+            line-height: 44px;
+            margin: 0;
+        }
+        .inline-title{
+            margin-left: -14px;
+        }
+        .des{
+            margin-top: 10px;
+            margin-bottom: 20px;
+            font-size: 28px;
+            color: $font-grey;
+            min-height: 60px;
+        }
+        .bot-info{
+            display: flex;
+            justify-content: space-between;
+            color: $font-grey;
+            font-size: 28px;
+            .active-status{
+                color: $font-success;
+            }
+        }
+    }
+}
+.report-search-page{
+    .search-box{
+        position: sticky;
+        top: 0;
+        z-index: 99;
+        background-color: #fff;
+    }
+}
+</style>

+ 73 - 0
src/views/reportEn/components/ListClassify.vue

@@ -0,0 +1,73 @@
+<script setup>
+import {ref} from 'vue'
+import apiReportEn from '@/api/reportEn'
+
+const emits=defineEmits(['close','confirm'])
+
+const list=ref([])
+function getClassifyList(){
+    apiReportEn.getClassifyList({
+        CurrentIndex:1,
+        PageSize:1000,
+        KeyWord:''
+    }).then(res=>{
+        if(res.Ret===200){
+            const arr=res.Data.List||[]
+            list.value=arr.map(item=>{
+                const child=item.Child?item.Child.map(e=>{
+                    return {
+                        text:e.ClassifyName,
+                        id:e.ClassifyName
+                    }
+                }):[]
+                return {
+                    text:item.ClassifyName,
+                    children:child
+                }
+            })
+        }
+    })
+}
+getClassifyList()
+
+const activeId = ref(null);
+const activeIndex = ref(0);
+
+function handleCancle(){
+    emits('close')
+}
+
+function handleConfirm(){
+    const firstClassify=list.value[activeIndex.value].text
+    const secondClassify=activeId.value||''
+    emits('confirm',{firstClassify,secondClassify})
+}
+</script>
+
+<template>
+    <div class="report-list-classify-wrap">
+        <div class="top-box">
+            <span style="color:#666666" @click="handleCancle">取消</span>
+            <span style="font-size:18px;font-weight:bold">选择分类</span>
+            <span style="color:#0052D9" @click="handleConfirm">确定</span>
+        </div>
+        <van-tree-select
+            v-model:active-id="activeId"
+            v-model:main-active-index="activeIndex"
+            :items="list"
+        />
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.report-list-classify-wrap{
+    .top-box{
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        height: 116px;
+        border-bottom: 1px solid $border-color;
+        padding: 0 34px;
+    }
+}
+</style>

+ 4 - 0
src/views/tabbar/Home.vue

@@ -20,6 +20,10 @@ if(!localStorage.getItem('token')){
                 <img src="@/assets/imgs/ppt/ppt_icon_zh.png" alt="">
                 <div>中文研报</div>
             </div>
+            <div class="item-box" @click="goNext('/reportEn/list')">
+                <img src="@/assets/imgs/ppt/ppt_icon_zh.png" alt="">
+                <div>英文研报</div>
+            </div>
             <div class="item-box" @click="goNext('/ppt/index')">
                 <img src="@/assets/imgs/ppt/ppt_icon_zh.png" alt="">
                 <div>智能PPT</div>

部分文件因文件數量過多而無法顯示