Ver Fonte

完成pad端分类模块

jwyu há 2 anos atrás
pai
commit
180486babd

BIN
src/assets/imgs/ppt/ppt_icon_user1.png


BIN
src/assets/imgs/ppt/ppt_icon_user2.png


BIN
src/assets/imgs/ppt/ppt_icon_write02.png


+ 1 - 1
src/assets/styles/common.scss

@@ -10,7 +10,7 @@ html,body{
 
 @media screen and (min-width:650px){
     html,body{
-        font-size: 14px;
+        font-size: 16px;
         color: #333;
     }
 }

+ 26 - 2
src/layouts/Index.vue

@@ -7,7 +7,6 @@ let showUserInfo=ref(false)
 function getUserInfo(){
     const val=localStorage.getItem('userInfo')?JSON.parse(Base64.decode(localStorage.getItem('userInfo'))):null
     userInfo.value=val
-    console.log(val);
 }
 getUserInfo()
 
@@ -25,7 +24,13 @@ function handleLoginOut(){
 <template>
     <div class="layout-wrap">
         <div class="pad-header-box" v-if="!$route.meta.noHead">
-            <div></div>
+            <div>
+                <div 
+                    class="back-home-box" 
+                    v-if="$route.meta.hasBack"
+                    @click="$router.replace('/')"
+                >返回首页</div>
+            </div>
             <van-popover v-model:show="showUserInfo" placement="bottom-end">
                 <div class="userinfo-box_pad" v-if="userInfo">
                     <div class="info-item">
@@ -97,6 +102,8 @@ function handleLoginOut(){
         display: flex;
         align-items: center;
         justify-content: space-between;
+        z-index: 999;
+        background-color: #fff;
         .user-box{
             display: flex;
             align-items: center;
@@ -108,6 +115,23 @@ function handleLoginOut(){
                 margin-right: 5px;
             }
         }
+        .back-home-box{
+            color: $theme-color;
+            font-size: 16px;
+            display: flex;
+            align-items: center;
+            &::before{
+                content: '';
+                display: block;
+                width: 20px;
+                height: 20px;
+                background-image: url('@/assets/imgs/tabbar/home-s.png');
+                background-size: cover;
+                margin-right: 5px;
+                position: relative;
+                top: -4px;
+            }
+        }
     }
 }
 </style>

+ 14 - 2
src/router/ppt.js

@@ -1,10 +1,19 @@
 // ppt路由模块
+/**
+ * meta:{
+ * noHead:pad端不需要顶部
+ * hasBack:pad端顶部有返回首页
+ * }
+ */
 export const pptRoutes=[
     {
         path:"/ppt/index",
         name:"PPTIndex",
         component: () => import("@/views/ppt/Index.vue"),
-        meta: { title: "智能PPT" },
+        meta: { 
+            title: "智能PPT",
+            hasBack:true
+        },
     },
     {
         path:"/ppt/detail",
@@ -22,6 +31,9 @@ export const pptRoutes=[
         path:"/ppt/preview",
         name:"PPTPreview",
         component: () => import("@/views/ppt/Preview.vue"),
-        meta: { title: "智能PPT",noHead:true },
+        meta: { 
+            title: "智能PPT",
+            noHead:true 
+        },
     },
 ]

+ 26 - 5
src/views/ppt/Detail.vue

@@ -1,6 +1,6 @@
 <script setup>
 import { ref,nextTick} from 'vue'
-import { useRoute } from "vue-router";
+import { useRoute, useRouter } from "vue-router";
 import { vElementSize } from '@vueuse/components'
 import {apiPPTDetail} from '@/api/ppt'
 import {createPPTContent,getTemplate} from './hooks/createPPTContent'
@@ -10,13 +10,12 @@ import {useUserInfo} from '@/hooks/common'
 import moment from 'moment';
 
 const route=useRoute()
+const router=useRouter()
 
 const pptId=route.query.id
 
 const {userInfo} =useUserInfo()
 
-// let pptItemDom=null
-
 // 获取ppt详情
 let PPTInfo=ref(null)
 let conArr=ref([])
@@ -75,6 +74,20 @@ function handleShowPPTOpt(){
     PPTOptState.show=true
 }
 
+// 播放
+const playActions=[
+    {name:"从首页播放",type:1},
+    {name:"从当前页播放",type:2},
+]
+let showPlayOpt=ref(false)
+function onSelectPlayOpt(e){
+    router.push({
+        path:"/ppt/preview",
+        query:{
+            id:pptId
+        }
+    })
+}
 
 </script>
 
@@ -93,11 +106,11 @@ function handleShowPPTOpt(){
                 <img src="@/assets/imgs/ppt/icon_action_publish.png" alt="">
                 <span>发布</span>
             </div>
-            <div class="item-box">
+            <div class="item-box" @click="showPlayOpt=true">
                 <img src="@/assets/imgs/ppt/icon_action_play.png" alt="">
                 <span>播放</span>
             </div>
-            <div class="item-box" @click="handleShowPPTCopy($route.query.id)">
+            <div class="item-box" @click="handleShowPPTCopy({pptid:$route.query.id})">
                 <img src="@/assets/imgs/ppt/icon_action_copy.png" alt="">
                 <span>复制</span>
             </div>
@@ -163,6 +176,14 @@ function handleShowPPTOpt(){
             </van-popover>
         </div>
     </van-dialog>
+    <!-- 播放选项弹窗 -->
+    <van-action-sheet 
+        v-model:show="showPlayOpt" 
+        :actions="playActions" 
+        cancel-text="取消"
+        close-on-click-action
+        @select="onSelectPlayOpt" 
+    />
 </template>
 
 <style lang="scss" scoped>

+ 17 - 19
src/views/ppt/Index.vue

@@ -1,34 +1,32 @@
 <script setup>
 import {ref,reactive} from 'vue'
-import {apiPPTClassify} from '@/api/ppt'
 import MobileClassifyWrap from './components/MobileClassifyWrap.vue'
-import { useRouter } from 'vue-router'
-
-const router=useRouter()
-
-// 跳转搜索
-function goMobileSearch(){
-    router.push('/ppt/search')
-}
-
+import PadPPTIndexWrap from './components/PadPPTIndexWrap.vue'
 
 
 </script>
 
 <template>
     <div class="ppt-index-page">
-        <div class="search-box">
-            <van-search 
-                shape="round" 
-                readonly 
-                placeholder="请输入搜索关键词" 
-                @click="goMobileSearch"
-            />
+        <div class="ppt-index-page_mobile">
+            <MobileClassifyWrap />
+        </div>
+        <div class="ppt-index-page_pad">
+            <PadPPTIndexWrap/>
         </div>
-        <MobileClassifyWrap/>
     </div>
 </template>
 
 <style lang="scss" scoped>
-
+.ppt-index-page_pad{
+    display: none;
+}
+@media screen and (min-width:650px){
+    .ppt-index-page_mobile{
+        display: none;
+    }
+    .ppt-index-page_pad{
+        display: block;
+    }
+}
 </style>

+ 21 - 11
src/views/ppt/Preview.vue

@@ -4,7 +4,7 @@ import { useRoute } from "vue-router";
 import {apiPPTDetail} from '@/api/ppt'
 import {createPPTContent,getTemplate} from './hooks/createPPTContent'
 import { useWindowSize } from '@vueuse/core'
-import { Swipe, SwipeItem } from 'vant';
+import { Swipe, SwipeItem,showToast } from 'vant';
 
 const { width, height } = useWindowSize()
 
@@ -17,19 +17,24 @@ let conArr=ref([])
 async function getPPTDetail(){
     const res=await apiPPTDetail({PptId:Number(pptId)})
     conArr.value=createPPTContent(res.Data)
+    nextTick(()=>{
+        showToast('左右滑动可翻页')
+    })
 }
 getPPTDetail()
 
 // 计算缩放以及位置
 const scale=computed(()=>{
     if(width.value>height.value){
-        const topNum=(630-height.value)/2
-        const leftNum=(900-width.value)/2
-        return `transform: scale(${height.value/630});top:-${topNum}px;left:-${leftNum}px`
+        const scaleNum=height.value/630
+        const topNum=-((630-height.value)/2)
+        const leftNum=-((900-width.value)/2)
+        return `transform: scale(${scaleNum});top:${topNum}px;left:${leftNum}px`
     }else{
-        const topNum=-(630-height.value)/2
-        const leftNum=(900-width.value)/2
-        return `transform: scale(${width.value/900});top:${topNum}px;left:-${leftNum}px`
+        const scaleNum=width.value/900
+        const topNum=-((630-height.value)/2)
+        const leftNum=-((900-width.value)/2)
+        return `transform: scale(${scaleNum});top:${topNum}px;left:${leftNum}px`
     }
 })
 
@@ -37,6 +42,12 @@ const swipeIns=ref(null)
 let current=ref(0)
 function handleSwipeChange(index){
     current.value=index
+    if(index==conArr.value.length-1){
+        showToast('已是最后一页')
+    }
+    if(index==0){
+        showToast('第一页')
+    }
 }
 // 切换swipe到某个
 function handleSwipeTo(index){
@@ -48,11 +59,11 @@ let timeIns=null
 function handleShowAction(){
     if(showAction.value){
         showAction.value=false
+        clearTimeout(timeIns)
     }else{
         showAction.value=true
         timeIns=setTimeout(() => {
             showAction.value=false
-            clearTimeout(timeIns)
         }, 3000);
     }
 }
@@ -93,9 +104,9 @@ function handleShowAction(){
         </div>
         <div 
             :class="[showAction?'back-btn back-btn_show':'back-btn']"
+            @click="$router.back()"
         >退出播放</div>
     </div>
-    
 </template>
 
 <style lang="scss" scoped>
@@ -104,6 +115,7 @@ function handleShowAction(){
     height: 100vh;
     background-color: rgba($color: #000000, $alpha: 1.0);
     position: relative;
+    overflow: hidden;
     .swipe-wrap{
         width: 100vw;
         height: 100vh;
@@ -170,6 +182,4 @@ function handleShowAction(){
         top: 20PX;
     }
 }
-
-
 </style>

+ 14 - 0
src/views/ppt/components/MobileClassifyWrap.vue

@@ -1,6 +1,8 @@
 <script setup>
+import { useRouter } from 'vue-router'
 import {useClassify} from '../hooks/useClassify'
 
+const router=useRouter()
 const {
     classifyState,
     getPPTClassifyData,
@@ -24,11 +26,23 @@ const {
 getPPTClassifyData()
 
 
+// 跳转搜索
+function goMobileSearch(){
+    router.push('/ppt/search')
+}
 
 </script>
 
 <template>
     <div class="mobile-classify-wrap">
+        <div class="search-box">
+            <van-search 
+                shape="round" 
+                readonly 
+                placeholder="请输入搜索关键词" 
+                @click="goMobileSearch"
+            />
+        </div>
         <van-collapse v-model="classifyState.activeType" :border="false">
             <van-collapse-item class="level-one" name="myPPT" :is-link="false">
                 <template #title>

+ 352 - 0
src/views/ppt/components/PadPPTIndexWrap.vue

@@ -0,0 +1,352 @@
+<script setup>
+import {ref} from 'vue'
+import {useClassify} from '../hooks/useClassify'
+import openShareIcon from '@/assets/imgs/ppt/ppt_icon_user1.png'
+import closeShareIcon from '@/assets/imgs/ppt/ppt_icon_user2.png'
+
+const {
+    classifyState,
+    getPPTClassifyData,
+
+    fileOptState,
+    handleShowFileOpt,
+    handlePPTCatalogueCopy,
+    handlePPTCatalogueDel,
+    handlePPTCatalogueReName,
+    
+    PPTOptState,
+    handleShowPPTOpt,
+    handlePPTDel,
+    handlePPTShare,
+    handleShowPPTCopy,
+    handlePPTCopy,
+
+    goPPTDetail
+}=useClassify()
+getPPTClassifyData()
+
+const activeType=ref('myPPT')
+
+
+</script>
+
+<template>
+    <div class="pad-ppt-index-wrap">
+        <div class="left-classify-wrap">
+            <div class="classify-type-box">
+                <span 
+                    :class="activeType=='myPPT'&&'active'"
+                    @click="activeType='myPPT'"
+                >我的PPT</span>
+                <span
+                    :class="activeType=='pubPPT'&&'active'"
+                    @click="activeType='pubPPT'"
+                >公共PPT</span>
+            </div>
+            <div v-if="activeType=='myPPT'">
+                <van-collapse class="level-two" v-model="classifyState.myActiveType" :border="false">
+                    <van-collapse-item
+                        :name="item.GroupId"
+                        v-for="item in classifyState.privateList"
+                        :key="item.GroupId"
+                        :is-link="false"
+                    >
+                        <template #title>
+                            <div class="title-second">
+                                <img src="@/assets/imgs/ppt/ppt_icon_file.png" alt="">
+                                <span class="van-ellipsis">{{item.GroupName}}</span>
+                                <div @click.stop="handleShowFileOpt(item)">
+                                    <van-popover position="bottom-start">
+                                        <template #reference>
+                                            <img class="menu-icon" src="@/assets/imgs/ppt/ppt_icon_menu.png" alt="">
+                                        </template>
+                                        <div class="pad-classify-file-opt-box">
+                                            <div class="item" @click="handlePPTCatalogueCopy">
+                                                <img src="@/assets/imgs/ppt/icon_action_copy.png" alt="">
+                                                <span>复制</span>
+                                            </div>
+                                            <div class="item" @click="fileOptState.showReName=true">
+                                                <img src="@/assets/imgs/ppt/ppt_icon_write02.png" alt="">
+                                                <span>重命名</span>
+                                            </div>
+                                            <div class="item del" @click="handlePPTCatalogueDel">
+                                                <img src="@/assets/imgs/icon_del.png" alt="">
+                                                <span>删除</span>
+                                            </div>
+                                        </div>
+                                    </van-popover>
+                                </div>
+                            </div>
+                        </template>
+                        <div 
+                            class="ppt-item"
+                            v-for="_item in item.PptList" 
+                            :key="_item.GroupId"
+                            @click.stop="goPPTDetail(_item)"
+                        >
+                            <span class="van-ellipsis text">{{ _item.Title }}</span>
+                            <div @click.stop="handleShowPPTOpt(_item)">
+                                <van-popover position="bottom-start">
+                                    <template #reference>
+                                        <img class="share-icon" :src="_item.IsSingleShareBoolean?openShareIcon:closeShareIcon" alt="">
+                                    </template>
+                                    <div class="pad-classify-file-opt-box">
+                                        <div class="item" @click="handlePPTShare">
+                                            <img :src="closeShareIcon" alt="">
+                                            <span>仅自己可见</span>
+                                        </div>
+                                        <div class="item" @click="handlePPTShare">
+                                            <img :src="openShareIcon" alt="">
+                                            <span>所有人可见</span>
+                                        </div>
+                                    </div>
+                                </van-popover>
+                            </div>
+                            <div @click.stop="handleShowPPTOpt(_item)">
+                                <van-popover position="bottom-start">
+                                    <template #reference>
+                                        <img class="menu-icon" src="@/assets/imgs/ppt/ppt_icon_menu.png" alt="">
+                                    </template>
+                                    <div class="pad-classify-file-opt-box">
+                                        <div class="item" @click="handleShowPPTCopy">
+                                            <img src="@/assets/imgs/ppt/icon_action_copy.png" alt="">
+                                            <span>复制</span>
+                                        </div>
+                                        <div class="item del" @click="handlePPTDel">
+                                            <img src="@/assets/imgs/icon_del.png" alt="">
+                                            <span>删除</span>
+                                        </div>
+                                    </div>
+                                </van-popover>
+                            </div>
+                            
+                        </div>
+                    </van-collapse-item>
+                </van-collapse>
+            </div>
+            <div v-if="activeType=='pubPPT'">
+                <van-collapse class="level-two" v-model="classifyState.pubActiveType" :border="false">
+                    <van-collapse-item
+                        :name="item.GroupId"
+                        v-for="item in classifyState.publicList"
+                        :key="item.GroupId"
+                        :is-link="false"
+                    >
+                        <template #title>
+                            <div class="title-second">
+                                <img src="@/assets/imgs/ppt/ppt_icon_file.png" alt="">
+                                <span class="van-ellipsis">{{item.GroupName}}</span>
+                            </div>
+                        </template>
+                        <div 
+                            class="ppt-item"
+                            v-for="_item in item.PptList" 
+                            :key="_item.GroupId"
+                            @click.stop="goPPTDetail(_item)"
+                        >
+                            <span class="van-ellipsis text">{{ _item.Title }}</span>
+                            <div @click.stop="handleShowPPTOpt(_item)">
+                                <van-popover position="bottom-start">
+                                    <template #reference>
+                                        <img class="menu-icon" src="@/assets/imgs/ppt/ppt_icon_menu.png" alt="">
+                                    </template>
+                                    <div class="pad-classify-file-opt-box">
+                                        <div class="item" @click="handleShowPPTCopy">
+                                            <img src="@/assets/imgs/ppt/icon_action_copy.png" alt="">
+                                            <span>复制</span>
+                                        </div>
+                                    </div>
+                                </van-popover>
+                            </div>
+                        </div>
+                    </van-collapse-item>
+                </van-collapse>
+            </div>
+        </div>
+        <div class="right-list-wrap"></div>
+    </div>
+    <!-- 目录重命名 -->
+    <van-dialog 
+        v-model:show="fileOptState.showReName" 
+        title="重命名" 
+        show-cancel-button
+        confirmButtonText="保存"
+        @confirm="handlePPTCatalogueReName"
+    >
+        <div class="file-rename-wrap">
+            <span>目录名称</span>
+            <input type="text" placeholder="请输入目录名" v-model="fileOptState.reNameVal">
+        </div>
+    </van-dialog>
+    <!-- ppt复制弹窗 -->
+    <van-dialog 
+        v-model:show="PPTOptState.showCopy" 
+        title="PPT目录" 
+        show-cancel-button
+        confirmButtonText="保存"
+        @confirm="handlePPTCopy"
+    >
+        <div class="ppt-copy-wrap">
+            <span>选择目录</span>
+            <van-popover :actions="PPTOptState.copyActions" @select="e=>PPTOptState.copySelectData=e">
+                <template #reference>
+                    <span class="select-value-box">{{PPTOptState.copySelectData.GroupName||'请选择目录'}}</span>
+                </template>
+            </van-popover>
+        </div>
+    </van-dialog>
+</template>
+
+<style lang="scss">
+.van-collapse-item__content{
+    padding: 0;
+}
+.van-collapse-item--border:after{
+    display: none;
+}
+.van-collapse-item__title--expanded{
+    padding-bottom: 6px;
+}
+.van-collapse-item__wrapper{
+    margin-bottom: 20px;
+}
+.van-collapse-item__title--expanded:after{
+    display: none;
+}
+@media screen and (min-width:650px){
+    .pad-classify-file-opt-box{
+        border: 1px solid $border-color;
+        padding: 10px 0;
+        .item{
+            padding: 10px 20px;
+            display: flex;
+            align-items: center;
+            img{
+                width: 20px;
+                margin-right: 8px;
+            }
+        }
+        .del{
+            color: $theme-red;
+        }
+    }
+            
+}
+</style>
+<style lang="scss" scoped>
+@media screen and (min-width:650px){
+    .pad-ppt-index-wrap{
+        display: flex;
+        .left-classify-wrap{
+            max-width: 360px;
+            min-width: 300px;
+            min-height: 100vh;
+            border-right: 1px solid $border-color;
+            padding: 30px;
+            .classify-type-box{
+                span{
+                    display: inline-block;
+                    padding-bottom: 5px;
+                    margin-right: 30px;
+                }
+                .active{
+                    color: $theme-color;
+                    font-weight: bold;
+                    border-bottom: 2px solid $theme-color;
+                }
+            }
+            .level-two{
+                padding-top: 20px;
+                margin-left: -20px;
+            }
+            .title-second{
+                display: flex;
+                align-items: center;
+                position: relative;
+                img{
+                    width: 20px;
+                    margin-right: 8px;
+                }
+                span{
+                    display: block;
+                    width: 80%;
+                    font-size: 16px;
+                }
+                .menu-icon{
+                    width: 3px;
+                    position: absolute;
+                    right: 0;
+                    margin-right: 0;
+                    top: 5px;
+                }
+            }
+            .ppt-item{
+                border-bottom: 1px solid $border-color;
+                margin-left: 40px;
+                margin-right: var(--van-cell-horizontal-padding);
+                padding-top: 14px;
+                padding-bottom: 10px;
+                position: relative;
+                color: $font-grey;
+                display: flex;
+                .text{
+                    width: calc(100% - 55px);
+                    display: block;
+                }
+                .menu-icon{
+                    width: 3px;
+                    position: absolute;
+                    right: 0;
+                    top: 20px;
+                }
+                .share-icon{
+                    width: 16px;
+                    height: 16px;
+                    position: absolute;
+                    right: 35px;
+                    top: 17px;
+                }
+            }
+        }
+    }
+    .file-rename-wrap{
+        display: flex;
+        align-items: center;
+        padding: 50px 30px;
+        span{
+            flex-shrink: 0;
+            margin-right: 20px;
+        }
+        input{
+            flex: 1;
+            line-height: 35px;
+            padding: 0 30px;
+            border-radius: 35px;
+            border: 1px solid $border-color;
+            width: 150px;
+        }
+    }
+    .ppt-copy-wrap{
+        display: flex;
+        align-items: center;
+        padding: 50px 30px;
+        span{
+            flex-shrink: 0;
+            margin-right: 20px;
+        }
+        :deep(.van-popover__wrapper){
+            flex: 1;
+        }
+        .select-value-box{
+            display: block;
+            height: 35px;
+            line-height: 35px;
+            padding: 0 30px;
+            border-radius: 35px;
+            border: 1px solid $border-color;
+            // min-width: 150px;
+        }
+    }
+}
+
+</style>

+ 1 - 1
src/views/ppt/hooks/useClassify.js

@@ -152,7 +152,7 @@ export function useClassify(){
     }
     // 显示复制ppt选择目录弹窗
     // 如果是详情页中调用则会传一个pptid
-    const handleShowPPTCopy=(pptid)=>{
+    const handleShowPPTCopy=({pptid})=>{
         PPTOptState.copyActions=classifyState.privateList.map(item=>{
             return {
                 text:item.GroupName,