瀏覽代碼

完成中文研报模块

jwyu 1 年之前
父節點
當前提交
8ad09ca831

+ 18 - 0
src/api/report.js

@@ -97,6 +97,24 @@ export default {
      */
      */
     getChapterDetail:params=>{
     getChapterDetail:params=>{
         return get('/report/getDayWeekChapter',params)
         return get('/report/getDayWeekChapter',params)
+    },
+    /**
+     * 编辑晨报周报
+     * @param ReportId
+     * @param Title
+     * @param ReportType
+     * @param CreateTime
+     * @param Author
+     */
+    editDayWeekReport:params=>{
+        return post('/report/editDayWeekReport',params)
+    },
+    /**
+     * 发布晨报\周报
+     * @param ReportId
+     */
+    publishDayOrWeekReport:params=>{
+        return post('/report/publishDayWeekReport',params)
     }
     }
 
 
 }
 }

二進制
src/assets/imgs/icon_audio_time_next.png


二進制
src/assets/imgs/icon_audio_time_prev.png


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


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


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


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


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


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


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


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


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


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


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


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


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

@@ -101,4 +101,15 @@ img {
         list-style: inherit !important;
         list-style: inherit !important;
         list-style-position: inside !important;
         list-style-position: inside !important;
     }   
     }   
+}
+@media screen and (min-width:650px){
+    .report-html-wrap{
+        font-size: 18px;
+        :deep(span){
+            font-size: 18px;
+        }
+        :deep(p){
+            font-size: 18px;
+        }
+    }
 }
 }

+ 54 - 7
src/views/report/Detail.vue

@@ -3,6 +3,7 @@ import {ref} from 'vue'
 import { useRoute } from "vue-router";
 import { useRoute } from "vue-router";
 import apiReport from '@/api/report'
 import apiReport from '@/api/report'
 import ReportPublishPop from './components/ReportPublishPop.vue'
 import ReportPublishPop from './components/ReportPublishPop.vue'
+import AudioBox from './components/AudioBox.vue'
 import { showToast,showDialog } from 'vant';
 import { showToast,showDialog } from 'vant';
 
 
 const route=useRoute()
 const route=useRoute()
@@ -67,7 +68,7 @@ function handleDelReport(){
 // 推送消息
 // 推送消息
 function handleReportSendMsg(){
 function handleReportSendMsg(){
     apiReport.reportMessageSend({
     apiReport.reportMessageSend({
-        ReportId:Number(props.reportId)
+        ReportId:Number(route.query.id)
     }).then(res=>{
     }).then(res=>{
         if(res.Ret===200){
         if(res.Ret===200){
             showToast('推送成功')
             showToast('推送成功')
@@ -84,7 +85,7 @@ function handleReportSendMsg(){
             <span class="stage">第{{reportInfo.Stage}}期 / {{reportInfo.Frequency}}</span>
             <span class="stage">第{{reportInfo.Stage}}期 / {{reportInfo.Frequency}}</span>
             <template v-if="reportInfo.State===1">
             <template v-if="reportInfo.State===1">
                 <!-- 删除 -->
                 <!-- 删除 -->
-                <div class="btn-item" @click="handleDelReport">
+                <div class="btn-item red-bg" @click="handleDelReport">
                     <img src="@/assets/imgs/icon_del.png" alt="">
                     <img src="@/assets/imgs/icon_del.png" alt="">
                 </div>
                 </div>
                 <!-- 发布 -->
                 <!-- 发布 -->
@@ -95,11 +96,11 @@ function handleReportSendMsg(){
             <template v-if="reportInfo.State===2">
             <template v-if="reportInfo.State===2">
                 <!-- 推送消息 -->
                 <!-- 推送消息 -->
                 <div class="btn-item" v-if="!reportInfo.MsgIsSend" @click="handleReportSendMsg">
                 <div class="btn-item" v-if="!reportInfo.MsgIsSend" @click="handleReportSendMsg">
-                    <img src="@/assets/imgs/icon_publish.png" alt="">
+                    <img src="@/assets/imgs/report/icon_sendmsg2.png" alt="">
                 </div>
                 </div>
                 <!-- 取消发布 -->
                 <!-- 取消发布 -->
-                <div class="btn-item" @click="handleReportPublishCancle">
-                    <img src="@/assets/imgs/report/icon_publish.png" alt="">
+                <div class="btn-item red-bg" @click="handleReportPublishCancle">
+                    <img src="@/assets/imgs/report/icon_publish_cancel2.png" alt="">
                 </div>
                 </div>
             </template>
             </template>
         </div>
         </div>
@@ -108,7 +109,8 @@ function handleReportSendMsg(){
             <span>{{reportInfo.Author}}</span>
             <span>{{reportInfo.Author}}</span>
             <span>{{reportInfo.PublishTime}}</span>
             <span>{{reportInfo.PublishTime}}</span>
         </div>
         </div>
-
+        <!-- 音频 -->
+        <AudioBox :url="reportInfo.VideoUrl" v-if="reportInfo.VideoUrl"/>
         <div class="report-abstract">{{reportInfo.Abstract}}</div>
         <div class="report-abstract">{{reportInfo.Abstract}}</div>
         <div class="report-html-wrap" v-html="reportInfo.Content"></div>
         <div class="report-html-wrap" v-html="reportInfo.Content"></div>
     </div>
     </div>
@@ -119,7 +121,7 @@ function handleReportSendMsg(){
         round
         round
     >
     >
         <ReportPublishPop :reportData="reportInfo" @close="handlePublishPopClose"/>
         <ReportPublishPop :reportData="reportInfo" @close="handlePublishPopClose"/>
-    </van-popup>
+    </van-popup> 
 </template>
 </template>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
@@ -138,6 +140,7 @@ function handleReportSendMsg(){
         font-size: 36px;
         font-size: 36px;
         padding-bottom: 40px;
         padding-bottom: 40px;
         border-bottom: 1px solid $border-color;
         border-bottom: 1px solid $border-color;
+        margin-bottom: 40px;
     }
     }
     .report-abstract{
     .report-abstract{
         font-size: 34px;
         font-size: 34px;
@@ -170,5 +173,49 @@ function handleReportSendMsg(){
             height: 48px;
             height: 48px;
         }
         }
     }
     }
+    .red-bg{
+        background-color: #FFF2F2;
+    }
+}
+
+@media screen and (min-width:$media-width){
+    .report-detail-page{
+        max-width: 800px;
+        margin: 0 auto;
+        padding: 30px;
+        .report-title{
+            margin: 15px 0;
+            font-size: 21px;
+            line-height: 28px;
+        }
+        .auth-box{
+            font-size: 18px;
+            padding-bottom: 20px;
+            margin-bottom: 20px;
+        }
+        .report-abstract{
+            font-size: 17px;
+            line-height: 27px;
+            margin: 20px 0;
+        }
+    }
+    .top-stage-box{
+        .stage{
+            border-radius: 4px;
+            height: 36px;
+            line-height: 36px;
+            padding: 0 10px;
+            font-size: 14px;
+        }
+        .btn-item{
+            width: 35px;
+            height: 35px;
+            margin-left: 20px;
+            img{
+                width: 24px;
+                height: 24px;
+            }
+        }
+    }
 }
 }
 </style>
 </style>

+ 96 - 30
src/views/report/List.vue

@@ -7,6 +7,9 @@ import ReportPublishPop from './components/ReportPublishPop.vue'
 import { showToast,showDialog,Dialog } from 'vant';
 import { showToast,showDialog,Dialog } from 'vant';
 import { useRouter } from 'vue-router';
 import { useRouter } from 'vue-router';
 import { OnLongPress  } from '@vueuse/components'
 import { OnLongPress  } from '@vueuse/components'
+import { useWindowSize } from '@vueuse/core'
+
+const { width, height } = useWindowSize()
 
 
 const router=useRouter()
 const router=useRouter()
 
 
@@ -385,7 +388,8 @@ function handleConfirmStatus(){
     <!-- 分类弹窗 -->
     <!-- 分类弹窗 -->
     <van-popup 
     <van-popup 
         v-model:show="showClassify"
         v-model:show="showClassify"
-        position="bottom"
+        :position="width>650?'center':'bottom'"
+        :style="width>650?{ width: '400px'}:''"
         round
         round
     >
     >
         <ListClassify @close="showClassify=false" @confirm="handleConfirmClassify"/>
         <ListClassify @close="showClassify=false" @confirm="handleConfirmClassify"/>
@@ -401,13 +405,22 @@ function handleConfirmStatus(){
     </van-popup>
     </van-popup>
 
 
     <!-- 日期筛选 -->
     <!-- 日期筛选 -->
-    <van-calendar 
-        v-model:show="showCalendar" 
-        type="range"
-        allow-same-day
-        :min-date="calendarMinDate"
-        @confirm="handleCalendarChange" 
-    />
+    <van-popup 
+        v-model:show="showCalendar"
+        :position="width>650?'center':'bottom'"
+        :style="width>650?{ width: '400px'}:''"
+        round
+    >
+        <van-calendar 
+            :poppable="false"
+            type="range"
+            allow-same-day
+            :min-date="calendarMinDate"
+            @confirm="handleCalendarChange" 
+            :style="{ height: '500px' }"
+        />
+    </van-popup>
+    
 </template>
 </template>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
@@ -558,31 +571,84 @@ function handleConfirmStatus(){
     }
     }
 }
 }
 
 
-.publish-report-pop-box{
-    padding: 48px;
-    .title{
-        font-size: 36px;
-        text-align: center;
-        margin-bottom: 32px;
+@media screen and (min-width:$media-width){
+    .sticky-box{
+        top: 60px;
+        .bot-btn-box{
+            padding: 32px;
+            justify-content: flex-end;
+            .btn{
+                width: 120px;
+                height: 40px;
+                border-radius: 6px;
+                font-size: 16px;
+                margin-left: 20px;
+            }
+        }
+        .frequency-opt-box{
+            ul{
+                padding: 32px;
+            }
+            .item{
+                width: 100px;
+                height: 40px;
+                margin-left: 6px;
+                margin-right: 6px;
+                margin-bottom: 12px;
+                border-radius: 6px;
+            }
+        }
+        .report-status-box{
+            ul{
+                padding: 32px;
+            }
+            .status-item{
+                line-height: 40px;
+                border-radius: 6px;
+                margin-bottom: 12px;
+            }
+        }
     }
     }
-    .tips{
-        color: $font-grey;
-        margin-bottom: 48px;
+    .top-box{
+        padding: 30px;
+        .menu-icon{
+            width: 40px;
+            height: 40px;
+            svg{
+                width: 28px;
+                height: 28px;
+            }
+        }
     }
     }
-    .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;
+
+    .list-wrap{
+        padding: 30px;
+        .item{
+            padding: 20px;
+            margin-bottom: 20px;
+            border-radius: 4px;
+            .title{
+                font-size: 16px;
+                line-height: 22px;
+            }
+            .inline-title{
+                margin-left: -14px;
+            }
+            .des{
+                margin-top: 5px;
+                margin-bottom: 10px;
+                font-size: 14px;
+                min-height: 30px;
+            }
+            .bot-info{
+                font-size: 14px;
+            }
         }
         }
-        .blue{
-            background-color: $theme-color;
-            color: #fff;
+    }
+
+    .report-item-action-box{
+        .item{
+            font-size: 16px;
         }
         }
     }
     }
 }
 }

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

@@ -155,4 +155,36 @@ function goDetail(item){
         background-color: #fff;
         background-color: #fff;
     }
     }
 }
 }
+
+@media screen and (min-width:$media-width){
+    .list-wrap{
+        padding: 30px;
+        .item{
+            padding: 20px;
+            margin-bottom: 20px;
+            border-radius: 4px;
+            .title{
+                font-size: 16px;
+                line-height: 22px;
+            }
+            .inline-title{
+                margin-left: -14px;
+            }
+            .des{
+                margin-top: 5px;
+                margin-bottom: 10px;
+                font-size: 14px;
+                min-height: 30px;
+            }
+            .bot-info{
+                font-size: 14px;
+            }
+        }
+    }
+    .report-search-page{
+        .search-box{
+            top: 60px;
+        }
+    }
+}
 </style>
 </style>

+ 80 - 4
src/views/report/chapter/Detail.vue

@@ -2,6 +2,8 @@
 import {ref} from 'vue'
 import {ref} from 'vue'
 import apiReport from '@/api/report'
 import apiReport from '@/api/report'
 import { useRoute } from 'vue-router'
 import { useRoute } from 'vue-router'
+import AudioBox from '../components/AudioBox.vue'
+import moment from 'moment'
 
 
 const route=useRoute()
 const route=useRoute()
 
 
@@ -12,6 +14,7 @@ function getChapterDetail(){
     }).then(res=>{
     }).then(res=>{
         if(res.Ret===200){
         if(res.Ret===200){
             info.value=res.Data
             info.value=res.Data
+            document.title=`${res.Data.ClassifyNameFirst}-${res.Data.Title}`
         }
         }
     })
     })
 }
 }
@@ -20,14 +23,87 @@ getChapterDetail()
 </script>
 </script>
 
 
 <template>
 <template>
-    <div class="chapter-report-detail-page report-detail-wrap">
-        <span>第{{info.Stage}}期</span>
-        <h2 class="title">{{info.Title}}</h2>
+    <div class="chapter-report-detail-page report-detail-wrap" v-if="info">
+        <div class="top-stage-box">
+            <span class="stage">第{{info.Stage}}期 / {{info.ClassifyNameFirst}}</span>
+        </div>
+        <h1 class="report-title">{{info.Title}}</h1>
+        <div class="auth-box">
+            <span>{{info.Author}}</span>
+            <span>{{moment(info.CreateTime).format('YYYY-MM-DD HH:mm:ss')}}</span>
+        </div>
+        <!-- 音频 -->
+        <AudioBox :url="info.VideoUrl" v-if="info.VideoUrl"/>
+        <div class="report-abstract">{{info.Abstract}}</div>
+        <div class="report-html-wrap" v-html="info.Content"></div>
     </div>
     </div>
 </template>
 </template>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
+.top-stage-box{
+    .stage{
+        display: inline-block;
+        background-color: #F2F3FF;
+        border-radius: 8px;
+        height: 72px;
+        line-height: 72px;
+        padding: 0 20px;
+        font-size: 28px;
+    }
+}
 .report-detail-wrap{
 .report-detail-wrap{
-    padding: 34px;
+    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;
+        margin-bottom: 40px;
+    }
+    .report-abstract{
+        font-size: 34px;
+        line-height: 54px;
+        margin: 40px 0;
+    }
+}
+
+@media screen and (min-width:$media-width){
+    .top-stage-box{
+        .stage{
+            border-radius: 4px;
+            height: 36px;
+            line-height: 36px;
+            padding: 0 10px;
+            font-size: 14px;
+        }
+    }
+    .report-detail-wrap{
+        padding: 30px;
+        max-width: 800px;
+        margin: 0 auto;
+        .report-title{
+            margin: 15px 0;
+            font-size: 21px;
+            line-height: 28px;
+        }
+        .auth-box{
+            font-size: 18px;
+            padding-bottom: 20px;
+            margin-bottom: 20px;
+        }
+        .report-abstract{
+            font-size: 17px;
+            line-height: 27px;
+            margin: 20px 0;
+        }
+    }
 }
 }
 </style>
 </style>

+ 369 - 32
src/views/report/chapter/List.vue

@@ -3,7 +3,10 @@ import {reactive, ref} from 'vue'
 import { useRoute, useRouter } from "vue-router";
 import { useRoute, useRouter } from "vue-router";
 import apiReport from '@/api/report'
 import apiReport from '@/api/report'
 import moment from 'moment';
 import moment from 'moment';
-import { showToast } from 'vant';
+import { showToast,showDialog } from 'vant';
+import { useWindowSize } from '@vueuse/core'
+
+const { width, height } = useWindowSize()
 
 
 
 
 const route=useRoute()
 const route=useRoute()
@@ -15,8 +18,10 @@ async function getReportDetail(){
     const res=await apiReport.getReportDetail({ReportId:Number(route.query.id)})
     const res=await apiReport.getReportDetail({ReportId:Number(route.query.id)})
     if(res.Ret===200){
     if(res.Ret===200){
         reportInfo.value=res.Data
         reportInfo.value=res.Data
+        currentDate.value=moment(res.Data.CreateTime).format('YYYY-MM-DD').split('-')
         document.title=res.Data.ClassifyNameFirst
         document.title=res.Data.ClassifyNameFirst
     }
     }
+    getChapterList()
 }
 }
 getReportDetail()
 getReportDetail()
 
 
@@ -29,7 +34,7 @@ async function getChapterList(){
         getChapterTrendTagList()
         getChapterTrendTagList()
     }
     }
 }
 }
-getChapterList()
+
 
 
 // 获取章节标签数据
 // 获取章节标签数据
 let tagOpts=ref([])
 let tagOpts=ref([])
@@ -42,6 +47,7 @@ function getChapterTrendTagList(){
 }
 }
 
 
 const showTagPop=ref(false)
 const showTagPop=ref(false)
+const isEditTag=ref(false)
 const customFieldName={
 const customFieldName={
     text: 'KeyWord',
     text: 'KeyWord',
     value: 'KeyWord',
     value: 'KeyWord',
@@ -52,8 +58,9 @@ const temTrendTagData=reactive({
 })
 })
 function handleShowTrendTag(item){
 function handleShowTrendTag(item){
     temTrendTagData.ReportChapterId=item.ReportChapterId
     temTrendTagData.ReportChapterId=item.ReportChapterId
-    temTrendTagData.tagVal[0]=item.Trend
+    temTrendTagData.tagVal[0]=item.Trend||tagOpts.value[0].KeyWord
     showTagPop.value=true
     showTagPop.value=true
+    isEditTag.value=item.Trend?true:false
 }
 }
 function handleConfirmEditTrendTag(){
 function handleConfirmEditTrendTag(){
     apiReport.editChapterTrendTag({
     apiReport.editChapterTrendTag({
@@ -79,33 +86,175 @@ function goChapterDetail(item){
     })
     })
 }
 }
 
 
+// 修改报告时间
+const showDate=ref(false)
+const currentDate=ref([])
+function handleConfirmDateChange(e){
+    reportInfo.value.CreateTime=e.selectedValues.join('-')
+    showDate.value=false
+}
+
+
+// 保存报告信息
+async function handleSaveReportInfo(){
+    if(!reportInfo.value.Title){
+        showToast('请填写报告标题')
+        return
+    }
+    const params={
+        ReportId:reportInfo.value.Id,
+        Title:reportInfo.value.Title,
+        ReportType:reportInfo.value.ClassifyNameFirst=='周报'?'week':'day',
+        CreateTime:moment(reportInfo.value.CreateTime).format('YYYY-MM-DD'),
+        Author:reportInfo.value.Author
+    }
+    const res=await apiReport.editDayWeekReport(params)
+    if(res.Ret===200){
+        showToast('保存成功')
+    }
+}
+
+// 周报校验音频是否都上传了
+async function handlePublishValid(){
+    if(reportInfo.value.ClassifyNameFirst==='周报'){
+        const validRes=await apiReport.weekReportValidAudio({ReportId:Number(reportInfo.value.Id)})
+        if(validRes.Ret===200){
+            if(validRes.Data){
+                showDialog({
+                    title: '发布提示',
+                    message: `报告未上传录音:${validRes.Data.join('、')},确定发布吗?`,
+                    showCancelButton:true
+                }).then(() => {
+                    // on close
+                    handlePublishReport()
+                }).catch(()=>{})
+            }
+        }
+        return
+    }else{
+        handlePublishReport()
+    }
+}
+
+// 发布报告 晨报提示是否推送客群
+async function handlePublishReport(){
+    const res=await apiReport.publishDayOrWeekReport({ReportId:Number(reportInfo.value.Id)})
+    if(res.Ret!=200)return
+    if(reportInfo.value.ClassifyNameFirst==='周报'){
+        showToast('发布成功')
+        getReportDetail()
+        return
+    }
+    // 晨报
+    if(res.Data){
+        showDialog({
+            title: '发布提示',
+            message: res.Data,
+        }).then(()=>{
+            showDialog({
+                title: '发布提示',
+                message: `发布后,是否推送模板消息和客户群?`,
+                showCancelButton:true,
+                confirmButtonText:'推送',
+                cancelButtonText:'不推送'
+            }).then(async() => {
+                // on close
+                const pushRes=await apiReport.reportMessageSend({ReportId:Number(reportInfo.value.Id)})
+                if(pushRes.Ret===200){
+                    showToast('推送成功')
+                    getReportDetail()
+                }
+            }).catch(()=>{
+                showToast('发布成功')
+                getReportDetail()
+            })
+        })
+    }else{
+        showDialog({
+            title: '发布提示',
+            message: `发布后,是否推送模板消息和客户群?`,
+            showCancelButton:true,
+            confirmButtonText:'推送',
+            cancelButtonText:'不推送'
+        }).then(async() => {
+            // on close
+            const pushRes=await apiReport.reportMessageSend({ReportId:Number(reportInfo.value.Id)})
+            if(pushRes.Ret===200){
+                showToast('推送成功')
+                getReportDetail()
+            }
+        }).catch(()=>{
+            showToast('发布成功')
+            getReportDetail()
+        })
+    }
+}
+
+// 推送消息
+function handleSendMsg(){
+    apiReport.reportMessageSend({ReportId:Number(reportInfo.value.Id)}).then(res=>{
+        if(res.Ret===200){
+            showToast('推送成功')
+            getReportDetail()
+        }
+    })
+}
+
+// 取消发布
+function handlePublishCancel(){
+    apiReport.reportPublishCancle({ReportIds:Number(reportInfo.value.Id)}).then(res=>{
+        if(res.Ret===200){
+            showToast('取消发布成功')
+            getReportDetail()
+        }
+    })
+}
 
 
 </script>
 </script>
 
 
 <template>
 <template>
     <div class="report-chapterlist-page" v-if="reportInfo">
     <div class="report-chapterlist-page" v-if="reportInfo">
         <div class="top-form-wrap">
         <div class="top-form-wrap">
-
-        </div>
-        <div>
-            <span>报告类型</span>
-            <span>{{reportInfo.ClassifyNameFirst}}</span>
-        </div>
-        <div>
-            <span>报告标题</span>
-            <span>{{reportInfo.Title}}</span>
-        </div>
-        <div>
-            <span>发布时间</span>
-            <span>{{moment(reportInfo.CreateTime).format('YYYY-MM-DD')}}</span>
-        </div>
-        <div>
-            <span>作者</span>
-            <span>{{reportInfo.Author}}</span>
+            <div class="form-item">
+                <span class="label">报告类型</span>
+                <span class="con" style="color:#999">{{reportInfo.ClassifyNameFirst}}</span>
+            </div>
+            <div :class="['form-item', reportInfo.State==1&&'edit-box']">
+                <span class="label">报告标题</span>
+                <input class="con" type="text" placeholder="请输入标题" v-model="reportInfo.Title" v-if="reportInfo.State==1">
+                <span class="con" style="color:#999" v-else>{{reportInfo.Title}}</span>
+            </div>
+            <div :class="['form-item', reportInfo.State==1&&'calendar-box']">
+                <span class="label">发布时间</span>
+                <span class="con" @click="showDate=true" v-if="reportInfo.State==1">{{moment(reportInfo.CreateTime).format('YYYY-MM-DD')}}</span>
+                <span class="con" style="color:#999" v-else>{{moment(reportInfo.CreateTime).format('YYYY-MM-DD')}}</span>
+            </div>
+            <div :class="['form-item', reportInfo.State==1&&'edit-box']">
+                <span class="label">作者</span>
+                <input class="con" type="text" placeholder="请输入作者" v-model="reportInfo.Author" v-if="reportInfo.State==1">
+                <span class="con" style="color:#999" v-else>{{reportInfo.Author}}</span>
+            </div>
         </div>
         </div>
 
 
         <div class="chapter-list-wrap">
         <div class="chapter-list-wrap">
-            <span class="list-lable">章节列表</span>
+            <div class="top-box">
+                <span class="list-lable">章节列表</span>
+                <!-- 未发布 -->
+                <div v-if="reportInfo.State==1">
+                    <!-- 保存 -->
+                    <img @click="handleSaveReportInfo" class="btn" src="@/assets/imgs/report/icon_save.png" alt="" style="margin-right:20px">
+                    <!-- 发布 -->
+                    <img @click="handlePublishValid" class="btn" src="@/assets/imgs/report/icon_publish2.png" alt="">
+                </div>
+                <!-- 已发布 -->
+                <div v-if="reportInfo.State==2">
+                    <!-- 推送消息 -->
+                    <img v-if="reportInfo.MsgIsSend==0" @click="handleSendMsg" class="btn" src="@/assets/imgs/report/icon_sendmsg.png" alt="推送消息" style="margin-right:20px">
+                    <!-- 取消发布 -->
+                    <img @click="handlePublishCancel" class="btn" src="@/assets/imgs/report/icon_publish_cancel.png" alt="取消发布">
+                </div>
+            </div>
+            
             <ul class="chapter-list">
             <ul class="chapter-list">
                 <li class="item" v-for="item in chapterList" :key="item.ReportChapterId" @click="goChapterDetail(item)">
                 <li class="item" v-for="item in chapterList" :key="item.ReportChapterId" @click="goChapterDetail(item)">
                     <div class="img-box">
                     <div class="img-box">
@@ -113,12 +262,16 @@ function goChapterDetail(item){
                         <span>{{item.TypeName}}</span>
                         <span>{{item.TypeName}}</span>
                     </div>
                     </div>
                     <div class="content">
                     <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 class="title">{{item.TypeName}}</div>
+                        <div 
+                            v-if="reportInfo.ClassifyNameFirst=='周报'" 
+                            :class="['audio-status',item.VideoUrl&&item.VideoKind==1?'audio-status-success':'']"
+                        >{{item.VideoUrl&&item.VideoKind==1?'已传录音':'未传录音'}}</div>
+                        <div class="time">{{item.ModifyTime}}</div>
+
+                        <div :class="['status',item.PublishState!=1&&'status-success']">{{item.PublishState==1?'未发布':'已发布'}}</div>
+                        <img @click.stop="handleShowTrendTag(item)" class="icon icon-tag" src="@/assets/imgs/report/icon_tag.png" alt="">
+                        <img v-if="item.PublishState==2" @click.stop="handleShowTrendTag(item)" class="icon icon-wx" src="@/assets/imgs/report/icon_wx.png" alt="">
                     </div>
                     </div>
                 </li>
                 </li>
             </ul>
             </ul>
@@ -129,9 +282,11 @@ function goChapterDetail(item){
     <van-popup 
     <van-popup 
         v-model:show="showTagPop" 
         v-model:show="showTagPop" 
         round 
         round 
-        position="bottom"
+        :position="width>650?'center':'bottom'"
+        :style="width>650?{ width: '400px'}:''"
     >
     >
-         <van-picker
+        <van-picker
+            :title="isEditTag?'编辑标签':'添加标签'"
             v-model="temTrendTagData.tagVal"
             v-model="temTrendTagData.tagVal"
             :columns="tagOpts"
             :columns="tagOpts"
             :columns-field-names="customFieldName"
             :columns-field-names="customFieldName"
@@ -139,28 +294,96 @@ function goChapterDetail(item){
             @confirm="handleConfirmEditTrendTag"
             @confirm="handleConfirmEditTrendTag"
         />
         />
     </van-popup>
     </van-popup>
+
+    <!-- 修改时间 -->
+    <van-popup 
+        v-model:show="showDate" 
+        round 
+        :position="width>650?'center':'bottom'"
+        :style="width>650?{ width: '400px'}:''"
+    >
+        <van-date-picker
+            v-model="currentDate"
+            title="选择日期"
+            @confirm="handleConfirmDateChange"
+            @cancel="showDate=false"
+        />
+    </van-popup>
 </template>
 </template>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
+.top-form-wrap{
+    padding: 32px 32px 0 32px;
+    .form-item{
+        display: flex;
+        align-items: center;
+        padding: 32px 0px;
+        font-size: 32px;
+        border-bottom: 1px solid $border-color;
+        .label{
+            color: #000;
+            display: inline-block;
+            width: 194px;
+        }
+        .con{
+            flex: 1;
+        }
+    }
+    .edit-box::after{
+        content: '';
+        display: block;
+        width: 48px;
+        height: 48px;
+        background-image: url('@/assets/imgs/report/icon_edit.png');
+        background-size: cover;
+        background-repeat: no-repeat;
+    }
+    .calendar-box::after{
+        content: '';
+        display: block;
+        width: 48px;
+        height: 48px;
+        background-image: url('@/assets/imgs/report/icon_calendar.png');
+        background-size: cover;
+        background-repeat: no-repeat;
+    }
+}
+
+
 .chapter-list-wrap{
 .chapter-list-wrap{
     border-top: 10px solid #F2F6FA;
     border-top: 10px solid #F2F6FA;
     padding: 60px 34px;
     padding: 60px 34px;
+    .top-box{
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 55px;
+        .btn{
+            width: 70px;
+            height: 70px;
+        }
+    }
     .list-lable{
     .list-lable{
         display: block;
         display: block;
         font-weight: 600;
         font-weight: 600;
         font-size: 32px;
         font-size: 32px;
-        margin-bottom: 55px;
     }
     }
 
 
 }
 }
 .chapter-list{
 .chapter-list{
     .item{
     .item{
         display: flex;
         display: flex;
+        padding:20px;
+        border: 1px solid $border-color;
+        border-radius: 8px;
+        margin-bottom: 20px;
         .img-box{
         .img-box{
             position: relative;
             position: relative;
-            width: 200px;
-            height: 200px;
+            width: 160px;
+            height: 160px;
             overflow: hidden;
             overflow: hidden;
+            border-radius: 8px;
             img{
             img{
                 width: 100%;
                 width: 100%;
                 height: 100%;
                 height: 100%;
@@ -170,6 +393,120 @@ function goChapterDetail(item){
                 top: 50%;
                 top: 50%;
                 left: 50%;
                 left: 50%;
                 transform: translate(-50%,-50%);
                 transform: translate(-50%,-50%);
+                color: #fff;
+                font-size: 24px;
+                display: inline-block;
+                width: 80%;
+                text-align: center;
+            }
+        }
+        .content{
+            padding-left: 20px;
+            flex: 1;
+            display: flex;
+            flex-direction: column;
+            justify-content: space-between;
+            position: relative;
+            .title{
+                font-size: 32px;
+                font-weight: 600;
+            }
+            .time{
+                color: $font-grey;
+            }
+            .audio-status{
+                color: $font-grey_999;
+                &.audio-status-success{
+                    color: $font-success;
+                }
+            }
+
+            .status{
+                position: absolute;
+                top: 0;
+                right: 0;
+                color: $font-grey_999;
+                &.status-success{
+                    color: $font-success;
+                }
+            }
+
+            .icon{
+                width: 70px;
+                height: 70px;
+                position: absolute;
+                bottom: 0;
+            }
+            .icon-tag{
+                right: 0;
+            }
+            .icon-wx{
+                right: 108px;
+            }
+
+        }
+    }
+}
+
+@media screen and (min-width:$media-width){
+    .top-form-wrap{
+        padding: 16px 30px;
+        .form-item{
+            padding: 16px 0;
+            font-size: 16px;
+            .label{
+                width: 100px;
+            }
+        }
+        .edit-box::after{
+            width: 24px;
+            height: 24px;
+        }
+        .calendar-box::after{
+            width: 24px;
+            height: 24px;
+        }
+    }
+    .chapter-list-wrap{
+        border: none;
+        padding: 30px;
+        .top-box{
+            margin-bottom: 27px;
+            .btn{
+                width: 35px;
+                height: 35px;
+            }
+        }
+        .list-lable{
+            font-size: 16px;
+        }
+    }
+    .chapter-list{
+        .item{
+            padding: 10px;
+            border-radius: 4px;
+            margin-bottom: 10px;
+            .img-box{
+                width: 80px;
+                height: 80px;
+                border-radius: 4px;
+                span{
+                    font-size: 12px;
+                }
+            }
+            .content{
+                padding-left: 10px;
+                .title{
+                    font-size: 16px;
+                }
+
+                .icon{
+                    width: 35px;
+                    height: 35px;
+                }
+                .icon-wx{
+                    right: 54px;
+                }
             }
             }
         }
         }
     }
     }

+ 208 - 0
src/views/report/components/AudioBox.vue

@@ -0,0 +1,208 @@
+<script setup>
+import {ref} from 'vue'
+const props=defineProps({
+    url:{
+        type:String,
+        defalut:''
+    }
+})
+
+// 格式化音频时间
+function formatDuration(e){
+    let minus = parseInt(e / 60);
+    let sec = parseInt(e % 60);
+    return `${minus > 9 ? minus : "0" + minus}分${sec > 9 ? sec : "0" + sec}秒`;
+}
+
+function formatTimeNum(e){
+    let minus = parseInt(e / 60);
+    let sec = parseInt(e % 60);
+    return `${minus > 9 ? minus : "0" + minus}:${sec > 9 ? sec : "0" + sec}`;
+}
+
+const currentTime=ref(0)//当前播放时间
+const play=ref(false)//是否在播放
+const audioIns=ref(null)//audio实例
+const duration=ref(0)//audio时长
+
+
+function audioCanplay(e){
+    duration.value=e.target.duration
+}
+
+function audioPlay(){
+    play.value=true
+}
+
+function audioPause(){
+    play.value=false
+}
+
+function audioTimeupdate(e){
+    currentTime.value=e.target.currentTime
+}
+
+function audioEnded(){
+    currentTime.value=0
+    play.value=false
+}
+
+function SliderChange(e){
+    audioIns.value.currentTime=e
+}
+
+function handleChangeAudioStatus(){
+    if(play.value){
+        audioIns.value.pause()
+    }else{
+        audioIns.value.play()
+    }
+}
+
+function handleAudioTimeChange(type){
+    if(type==='prev'){
+        if(currentTime.value<15){
+            audioIns.value.currentTime=0
+        }else{
+            audioIns.value.currentTime=currentTime.value-15
+        }
+    }else{
+        if(duration.value-currentTime.value<15){
+            audioIns.value.currentTime=duration.value
+        }else{
+            audioIns.value.currentTime=currentTime.value+15
+        }
+    }
+}
+
+</script>
+
+<template>
+    <div class="audio-box">
+        <audio
+            :src="url"
+            @canplay="audioCanplay"
+            @error="audioError"
+            @play="audioPlay"
+            @pause="audioPause"
+            @timeupdate="audioTimeupdate"
+            @ended="audioEnded"
+            ref="audioIns"
+        />
+        <div class="time">时长:{{formatDuration(duration)}}</div>
+        <div class="controls-box">
+            <img class="time-btn" src="@/assets/imgs/icon_audio_time_prev.png" alt="" @click="handleAudioTimeChange('prev')">
+            <div class="status-btn" @click="handleChangeAudioStatus">
+                <svg v-show="play" class="play-btn" width="36" height="40" viewBox="0 0 36 40" fill="none" xmlns="http://www.w3.org/2000/svg">
+                    <rect width="8" height="40" fill="white"/>
+                    <rect x="28" width="8" height="40" fill="white"/>
+                </svg>
+            </div>
+            <img class="time-btn" src="@/assets/imgs/icon_audio_time_next.png" alt="" @click="handleAudioTimeChange('next')">
+        </div>
+        <van-slider
+            v-model="currentTime"
+            :max="duration"
+            active-color="#0052D9" 
+            inactive-color="#DCDFE6"
+            bar-height="3px"
+            @change="SliderChange"
+            class="slider" 
+        >
+            <template #button>
+                <div class="slider-btn">{{formatTimeNum(currentTime)}}</div>
+            </template>
+        </van-slider>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.audio-box{
+    width: 100%;
+    height: 240px;
+    background: #FFFFFF;
+    box-shadow: 0px 4px 24px rgba(75, 74, 96, 0.16);
+    border-radius: 24px;
+    padding: 20px;
+    .time{
+        font-size: 28px;
+        color: $font-grey_999;
+    }
+    .controls-box{
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin-top: 10px;
+        margin-bottom: 30px;
+        .time-btn{
+            width: 60px;
+            height: 60px;
+        }
+        .status-btn{
+            margin: 0 62px;
+            width: 100px;
+            height: 100px;
+            border-radius: 50%;
+            background: linear-gradient(180deg, #0052D9 0%, #3682FF 100%);
+            transform: rotate(-180deg);
+            display: flex;
+            justify-content:center;
+            align-items: center;
+            .play-btn{
+                width: 36px;
+                height: 40px;
+            }
+        }
+    }
+    .slider{
+        width: 95%;
+        margin: 0 auto;
+        .slider-btn{
+            background: #333333;
+            border-radius: 999px;
+            color: #FFFFFF;
+            font-size: 18px;
+            padding: 0 14px;
+            height: 34px;
+            display: flex;
+            align-items: center;
+            line-height: 1;
+        }
+    }
+}
+@media screen and (min-width:$media-width){
+    .audio-box{
+        height: 120px;
+        border-radius: 12px;
+        padding: 10px;
+        box-shadow: 0px 2px 12px rgba(75, 74, 96, 0.16);
+        .time{
+            font-size: 14px;
+        }
+        .controls-box{
+            margin-top: 5px;
+            margin-bottom: 15px;
+            .time-btn{
+                width: 30px;
+                height: 30px;
+            }
+            .status-btn{
+                margin: 0 31px;
+                width: 50px;
+                height: 50px;
+                .play-btn{
+                    width: 18px;
+                    height: 20px;
+                }
+            }
+        }
+        .slider{
+            .slider-btn{
+                font-size: 10px;
+                padding: 0 7px;
+                height: 17px;
+            }
+        }
+    }
+}
+</style>

+ 8 - 0
src/views/report/components/ListClassify.vue

@@ -70,4 +70,12 @@ function handleConfirm(){
         padding: 0 34px;
         padding: 0 34px;
     }
     }
 }
 }
+@media screen and (min-width:$media-width){
+    .report-list-classify-wrap{
+        .top-box{
+            height: 50px;
+            padding: 0 16px;
+        }
+    }
+}
 </style>
 </style>

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

@@ -97,4 +97,25 @@ function handleReportMessageSend(publish){
         }
         }
     }
     }
 }
 }
+
+@media screen and (min-width:$media-width){
+    .publish-report-pop-box{
+        padding: 24px;
+        .title{
+            font-size: 18px;
+            margin-bottom: 16px;
+        }
+        .tips{
+            margin-bottom: 24px;
+        }
+        .btns{
+            .btn{
+                line-height: 48px;
+                border-radius: 12px;
+                font-size: 16px;
+                margin-bottom: 12px;
+            }
+        }
+    }
+}
 </style>
 </style>

+ 2 - 2
src/views/tabbar/Home.vue

@@ -17,11 +17,11 @@ if(!localStorage.getItem('token')){
     <div class="home-page">
     <div class="home-page">
         <div class="list">
         <div class="list">
             <div class="item-box" @click="goNext('/report/list')">
             <div class="item-box" @click="goNext('/report/list')">
-                <img src="@/assets/imgs/ppt/ppt_icon_zh.png" alt="">
+                <img src="@/assets/imgs/report/report_icon.png" alt="">
                 <div>中文研报</div>
                 <div>中文研报</div>
             </div>
             </div>
             <div class="item-box" @click="goNext('/reportEn/list')">
             <div class="item-box" @click="goNext('/reportEn/list')">
-                <img src="@/assets/imgs/ppt/ppt_icon_zh.png" alt="">
+                <img src="@/assets/imgs/report/report_icon_en.png" alt="">
                 <div>英文研报</div>
                 <div>英文研报</div>
             </div>
             </div>
             <div class="item-box" @click="goNext('/ppt/index')">
             <div class="item-box" @click="goNext('/ppt/index')">